blob: 0a0b30035b403f017d2b5972b31a111a2cb1fce5 [file] [log] [blame]
sewardjaf44c822007-11-25 14:01:38 +00001
2/*--------------------------------------------------------------------*/
3/*--- Client-space code for drd. drd_preloaded.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
7 This file is part of drd, a data race detector.
8
9 Copyright (C) 2006-2007 Bart Van Assche
10 bart.vanassche@gmail.com
11
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation; either version 2 of the
15 License, or (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful, but
18 WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
25 02111-1307, USA.
26
27 The GNU General Public License is contained in the file COPYING.
28*/
29
30/* ---------------------------------------------------------------------
31 ALL THE CODE IN THIS FILE RUNS ON THE SIMULATED CPU.
32
33 These functions are not called directly - they're the targets of code
34 redirection or load notifications (see pub_core_redir.h for info).
35 They're named weirdly so that the intercept code can find them when the
36 shared object is initially loaded.
37
38 Note that this filename has the "drd_" prefix because it can appear
39 in stack traces, and the "drd_" makes it a little clearer that it
40 originates from Valgrind.
41 ------------------------------------------------------------------ */
42
43// Make sure pthread_spinlock_t is available on glibc 2.3.2 systems.
44#ifndef _GNU_SOURCE
45#define _GNU_SOURCE
46#endif
47
48#include <assert.h>
49#include <inttypes.h> // uintptr_t
50#include <stdio.h>
51#include <unistd.h>
52#include <pthread.h>
53#include "drd_clientreq.h"
54#include "pub_core_basics.h"
55#include "pub_core_clreq.h"
56#include "pub_core_debuginfo.h" // Needed for pub_core_redir.h
57#include "pub_core_redir.h" // For VG_NOTIFY_ON_LOAD
58#include "pub_tool_threadstate.h"// VG_N_THREADS
sewardjaf44c822007-11-25 14:01:38 +000059
60
61// Defines.
62
63#define PTH_FUNC(ret_ty, f, args...) \
64 ret_ty VG_WRAP_FUNCTION_ZZ(libpthreadZdsoZd0,f)(args); \
65 ret_ty VG_WRAP_FUNCTION_ZZ(libpthreadZdsoZd0,f)(args)
66
67
68// Local data structures.
69
70typedef struct
71{
72 void* (*start)(void*);
73 void* arg;
74 int detachstate;
75#if 0
76 pthread_mutex_t mutex;
77 pthread_cond_t cond;
78#else
79 int wrapper_started;
80#endif
81} VgPosixThreadArgs;
82
83
84// Local variables.
85
86static int vg_main_thread_state_is_set = 0;
87
88
89// Function definitions.
90
91static void vg_start_suppression(const void* const p, size_t const size)
92{
93 int res;
94 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__DRD_START_SUPPRESSION,
95 p, size, 0, 0, 0);
96}
97
98#if 0
99static void vg_finish_suppression(const void* const p, size_t const size)
100{
101 int res;
102 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__DRD_FINISH_SUPPRESSION,
103 p, size, 0, 0, 0);
104}
105#endif
106
107static void vg_start_recording(void)
108{
109 int res;
110 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__DRD_START_RECORDING,
111 pthread_self(), 0, 0, 0, 0);
112}
113
114static void vg_stop_recording(void)
115{
116 int res;
117 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__DRD_STOP_RECORDING,
118 pthread_self(), 0, 0, 0, 0);
119}
120
121static void vg_set_joinable(const pthread_t tid, const int joinable)
122{
123 int res;
124 assert(joinable == 0 || joinable == 1);
125#if 0
126 printf("vg_set_joinable(%ld, %d)\n", tid, joinable);
127#endif
128 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__SET_JOINABLE,
129 tid, joinable, 0, 0, 0);
130}
131
132static void* vg_thread_wrapper(void* arg)
133{
134 int res;
135 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__DRD_SUPPRESS_CURRENT_STACK,
136 0, 0, 0, 0, 0);
137
138 {
139 VgPosixThreadArgs* const arg_ptr = (VgPosixThreadArgs*)arg;
140 VgPosixThreadArgs const arg_copy = *arg_ptr;
141 void* result;
142
143#if 0
144 pthread_mutex_lock(arg_ptr->mutex);
145 pthread_cond_signal(arg_ptr->cond);
146 pthread_mutex_unlock(arg_ptr->mutex);
147#else
148 arg_ptr->wrapper_started = 1;
149#endif
150
151 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__SET_PTHREADID,
152 pthread_self(), 0, 0, 0, 0);
153 vg_set_joinable(pthread_self(),
154 arg_copy.detachstate == PTHREAD_CREATE_JOINABLE);
155 result = (arg_copy.start)(arg_copy.arg);
156 return result;
157 }
158}
159
160static void vg_set_main_thread_state(void)
161{
162 int res;
163
164 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__DRD_SUPPRESS_CURRENT_STACK,
165 0, 0, 0, 0, 0);
166
sewardjaf44c822007-11-25 14:01:38 +0000167 // Make sure that DRD knows about the main thread's POSIX thread ID.
168 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__SET_PTHREADID,
169 pthread_self(), 0, 0, 0, 0);
170
171}
172
173// pthread_create
174PTH_FUNC(int, pthreadZucreateZAZa, // pthread_create@*
175 pthread_t *thread, const pthread_attr_t *attr,
176 void *(*start) (void *), void *arg)
177{
178 int ret;
179 OrigFn fn;
180 VgPosixThreadArgs vgargs;
181
182 VALGRIND_GET_ORIG_FN(fn);
183
184 if (vg_main_thread_state_is_set == 0)
185 {
186 vg_set_main_thread_state();
187 vg_main_thread_state_is_set = 1;
188 }
189 vg_start_suppression(&vgargs.wrapper_started,
190 sizeof(vgargs.wrapper_started));
191 vgargs.start = start;
192 vgargs.arg = arg;
193 vgargs.wrapper_started = 0;
194 vgargs.detachstate = PTHREAD_CREATE_JOINABLE;
195 if (attr)
196 {
197 if (pthread_attr_getdetachstate(attr, &vgargs.detachstate) != 0)
198 {
199 assert(0);
200 }
201#if 0
202 printf("[%ld] Requested detach state for new thread: %d\n",
203 pthread_self(), vgargs.detachstate);
204#endif
205 }
206 assert(vgargs.detachstate == PTHREAD_CREATE_JOINABLE
207 || vgargs.detachstate == PTHREAD_CREATE_DETACHED);
208#if 0
209 pthread_mutex_init(&vgargs.mutex, 0);
210 pthread_cond_init(&vgargs.cond, 0);
211 pthread_mutex_lock(&vgargs.mutex);
212#endif
213 vg_stop_recording();
214 CALL_FN_W_WWWW(ret, fn, thread, attr, vg_thread_wrapper, &vgargs);
215 vg_start_recording();
216#if 0
217 pthread_cond_wait(&vgargs.cond, &vgargs.mutex);
218 pthread_mutex_unlock(&vgargs.mutex);
219 pthread_cond_destroy(&vgargs.cond);
220 pthread_mutex_destroy(&vgargs.mutex);
221#else
222 // Yes, you see it correctly, busy waiting ... The problem is that
223 // POSIX threads functions cannot be called here -- the functions defined
224 // in this file (vg_preloaded.c) would be called instead of those in
225 // libpthread.so. This loop is necessary because vgargs is allocated on the
226 // stack, and the created thread reads it.
227 while (! vgargs.wrapper_started)
228 {
229 sched_yield();
230 }
231#endif
232 return ret;
233}
234
235// pthread_join
236PTH_FUNC(int, pthreadZujoin, // pthread_join
237 pthread_t pt_joinee, void **thread_return)
238{
239 int ret;
240 int res;
241 OrigFn fn;
242
243 VALGRIND_GET_ORIG_FN(fn);
244 CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
245 if (ret == 0)
246 {
247 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_THREAD_JOIN,
248 pt_joinee, 0, 0, 0, 0);
249 }
250 return ret;
251}
252
253// pthread_detach
254PTH_FUNC(int, pthreadZudetach, pthread_t pt_thread)
255{
256 int ret;
257 OrigFn fn;
258 VALGRIND_GET_ORIG_FN(fn);
259 {
260 CALL_FN_W_W(ret, fn, pt_thread);
261 if (ret == 0)
262 {
263 vg_set_joinable(pt_thread, 0);
264 }
265 }
266 return ret;
267}
268
269// pthread_mutex_init
270PTH_FUNC(int, pthreadZumutexZuinit,
271 pthread_mutex_t *mutex,
272 const pthread_mutexattr_t* attr)
273{
274 int ret;
275 int res;
276 OrigFn fn;
277 VALGRIND_GET_ORIG_FN(fn);
278 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_MUTEX_INIT,
sewardj721ad7b2007-11-30 08:30:29 +0000279 mutex, sizeof(*mutex), mutex_type_mutex, 0, 0);
sewardjaf44c822007-11-25 14:01:38 +0000280 CALL_FN_W_WW(ret, fn, mutex, attr);
281 return ret;
282}
283
284// pthread_mutex_destroy
285PTH_FUNC(int, pthreadZumutexZudestroy,
286 pthread_mutex_t *mutex)
287{
288 int ret;
289 int res;
290 OrigFn fn;
291 VALGRIND_GET_ORIG_FN(fn);
292 CALL_FN_W_W(ret, fn, mutex);
293 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_DESTROY,
sewardj721ad7b2007-11-30 08:30:29 +0000294 mutex, mutex_type_mutex, 0, 0, 0);
sewardjaf44c822007-11-25 14:01:38 +0000295 return ret;
296}
297
298// pthread_mutex_lock
299PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock
300 pthread_mutex_t *mutex)
301{
302 int ret;
303 int res;
304 OrigFn fn;
305 VALGRIND_GET_ORIG_FN(fn);
306 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_PTHREAD_MUTEX_LOCK,
sewardj721ad7b2007-11-30 08:30:29 +0000307 mutex, sizeof(*mutex), mutex_type_mutex, 0, 0);
sewardjaf44c822007-11-25 14:01:38 +0000308#if 1
309 // The only purpose of the system call below is to make drd work on AMD64
310 // systems. Without this system call, clients crash (SIGSEGV) in
311 // std::locale::locale().
312 write(1, "", 0);
313#endif
314 CALL_FN_W_W(ret, fn, mutex);
315 if (ret == 0)
316 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__POST_PTHREAD_MUTEX_LOCK,
sewardj721ad7b2007-11-30 08:30:29 +0000317 mutex, sizeof(*mutex), mutex_type_mutex, 0, 0);
sewardjaf44c822007-11-25 14:01:38 +0000318 return ret;
319}
320
321// pthread_mutex_trylock
322PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock
323 pthread_mutex_t *mutex)
324{
325 int ret;
326 int res;
327 OrigFn fn;
328 VALGRIND_GET_ORIG_FN(fn);
329 CALL_FN_W_W(ret, fn, mutex);
330 if (ret == 0)
331 {
332 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_PTHREAD_MUTEX_LOCK,
sewardj721ad7b2007-11-30 08:30:29 +0000333 mutex, sizeof(*mutex), mutex_type_mutex, 0, 0);
sewardjaf44c822007-11-25 14:01:38 +0000334 }
335 return ret;
336}
337
338// pthread_mutex_unlock
339PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock
340 pthread_mutex_t *mutex)
341{
342 int ret;
343 int res;
344 OrigFn fn;
345 VALGRIND_GET_ORIG_FN(fn);
346 VALGRIND_DO_CLIENT_REQUEST(res, -1,
347 VG_USERREQ__PRE_PTHREAD_MUTEX_UNLOCK,
sewardj721ad7b2007-11-30 08:30:29 +0000348 mutex, sizeof(*mutex), mutex_type_mutex, 0, 0);
sewardjaf44c822007-11-25 14:01:38 +0000349 CALL_FN_W_W(ret, fn, mutex);
350 return ret;
351}
352
353// pthread_cond_init
354PTH_FUNC(int, pthreadZucondZuinitZAZa, // pthread_cond_init@*
355 pthread_cond_t* cond,
356 const pthread_condattr_t* attr)
357{
358 int ret;
359 int res;
360 OrigFn fn;
361 VALGRIND_GET_ORIG_FN(fn);
362 CALL_FN_W_WW(ret, fn, cond, attr);
363 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_PTHREAD_COND_INIT,
364 cond, sizeof(*cond), 0, 0, 0);
365 return ret;
366}
367
368// pthread_cond_destroy
369PTH_FUNC(int, pthreadZucondZudestroyZAZa, // pthread_cond_destroy@*
370 pthread_cond_t* cond)
371{
372 int ret;
373 int res;
374 OrigFn fn;
375 VALGRIND_GET_ORIG_FN(fn);
376 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_PTHREAD_COND_DESTROY,
sewardj721ad7b2007-11-30 08:30:29 +0000377 cond, 0, 0, 0, 0);
sewardjaf44c822007-11-25 14:01:38 +0000378 CALL_FN_W_W(ret, fn, cond);
379 return ret;
380}
381
382// pthread_cond_wait
383PTH_FUNC(int, pthreadZucondZuwaitZAZa, // pthread_cond_wait@*
384 pthread_cond_t *cond,
385 pthread_mutex_t *mutex)
386{
387 int ret;
388 int res;
389 OrigFn fn;
390 VALGRIND_GET_ORIG_FN(fn);
391 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_PTHREAD_COND_WAIT,
sewardj721ad7b2007-11-30 08:30:29 +0000392 cond, sizeof(*cond), mutex, sizeof(*mutex), 0);
sewardjaf44c822007-11-25 14:01:38 +0000393 CALL_FN_W_WW(ret, fn, cond, mutex);
394 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_PTHREAD_COND_WAIT,
sewardj721ad7b2007-11-30 08:30:29 +0000395 cond, sizeof(*cond), mutex, sizeof(*mutex), 0);
sewardjaf44c822007-11-25 14:01:38 +0000396 return ret;
397}
398
399// pthread_cond_timedwait
400PTH_FUNC(int, pthreadZucondZutimedwaitZAZa, // pthread_cond_timedwait@*
401 pthread_cond_t *cond,
402 pthread_mutex_t *mutex,
403 const struct timespec* abstime)
404{
405 int ret;
406 int res;
407 OrigFn fn;
408 VALGRIND_GET_ORIG_FN(fn);
409 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_PTHREAD_COND_WAIT,
sewardj721ad7b2007-11-30 08:30:29 +0000410 cond, sizeof(*cond), mutex, sizeof(*mutex), 0);
sewardjaf44c822007-11-25 14:01:38 +0000411 CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
412 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_PTHREAD_COND_WAIT,
sewardj721ad7b2007-11-30 08:30:29 +0000413 cond, sizeof(*cond), mutex, sizeof(*mutex), 0);
sewardjaf44c822007-11-25 14:01:38 +0000414 return ret;
415}
416
417// pthread_cond_signal
418PTH_FUNC(int, pthreadZucondZusignalZAZa, // pthread_cond_signal@*
419 pthread_cond_t* cond)
420{
421 int ret;
422 int res;
423 OrigFn fn;
424 VALGRIND_GET_ORIG_FN(fn);
425 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_PTHREAD_COND_SIGNAL,
426 cond, 0, 0, 0, 0);
427 CALL_FN_W_W(ret, fn, cond);
428 return ret;
429}
430
431// pthread_cond_broadcast
432PTH_FUNC(int, pthreadZucondZubroadcastZAZa, // pthread_cond_broadcast@*
433 pthread_cond_t* cond)
434{
435 int ret;
436 int res;
437 OrigFn fn;
438 VALGRIND_GET_ORIG_FN(fn);
439 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_PTHREAD_COND_BROADCAST,
440 cond, 0, 0, 0, 0);
441 CALL_FN_W_W(ret, fn, cond);
442 return ret;
443}
444
445
446// pthread_spin_init
447PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
448 pthread_spinlock_t *spinlock,
449 int pshared)
450{
451 int ret;
452 int res;
453 OrigFn fn;
454 VALGRIND_GET_ORIG_FN(fn);
455 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__SPIN_INIT_OR_UNLOCK,
sewardj721ad7b2007-11-30 08:30:29 +0000456 spinlock, sizeof(*spinlock),
457 mutex_type_spinlock, 0, 0);
sewardjaf44c822007-11-25 14:01:38 +0000458 CALL_FN_W_WW(ret, fn, spinlock, pshared);
459 return ret;
460}
461
462// pthread_spin_destroy
463PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy
464 pthread_spinlock_t *spinlock)
465{
466 int ret;
467 int res;
468 OrigFn fn;
469 VALGRIND_GET_ORIG_FN(fn);
470 CALL_FN_W_W(ret, fn, spinlock);
471 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_DESTROY,
sewardj721ad7b2007-11-30 08:30:29 +0000472 spinlock, mutex_type_spinlock, 0, 0, 0);
sewardjaf44c822007-11-25 14:01:38 +0000473 return ret;
474}
475
476// pthread_spin_lock
477PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
478 pthread_spinlock_t *spinlock)
479{
480 int ret;
481 int res;
482 OrigFn fn;
483 VALGRIND_GET_ORIG_FN(fn);
484 CALL_FN_W_W(ret, fn, spinlock);
485 if (ret == 0)
486 {
487 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_PTHREAD_MUTEX_LOCK,
sewardj721ad7b2007-11-30 08:30:29 +0000488 spinlock, sizeof(*spinlock),
489 mutex_type_spinlock, 0, 0);
sewardjaf44c822007-11-25 14:01:38 +0000490 }
491 return ret;
492}
493
494// pthread_spin_trylock
495PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
496 pthread_spinlock_t *spinlock)
497{
498 int ret;
499 int res;
500 OrigFn fn;
501 VALGRIND_GET_ORIG_FN(fn);
502 CALL_FN_W_W(ret, fn, spinlock);
503 if (ret == 0)
504 {
505 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_PTHREAD_MUTEX_LOCK,
sewardj721ad7b2007-11-30 08:30:29 +0000506 spinlock, sizeof(*spinlock),
507 mutex_type_spinlock, 0, 0);
sewardjaf44c822007-11-25 14:01:38 +0000508 }
509 return ret;
510}
511
512// pthread_spin_unlock
513PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
514 pthread_spinlock_t *spinlock)
515{
516 int ret;
517 int res;
518 OrigFn fn;
519 VALGRIND_GET_ORIG_FN(fn);
520 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__SPIN_INIT_OR_UNLOCK,
sewardj721ad7b2007-11-30 08:30:29 +0000521 spinlock, sizeof(*spinlock),
522 mutex_type_spinlock, 0, 0);
sewardjaf44c822007-11-25 14:01:38 +0000523 CALL_FN_W_W(ret, fn, spinlock);
524 return ret;
525}
526
527/*
528 * Local variables:
529 * c-basic-offset: 3
530 * End:
531 */