blob: 8c9028845cb1ceaa18f2a2953fdda861dbd1860f [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
59#include "pthread_object_size.h" // PTHREAD_MUTEX_SIZE etc.
60
61
62// Defines.
63
64#define PTH_FUNC(ret_ty, f, args...) \
65 ret_ty VG_WRAP_FUNCTION_ZZ(libpthreadZdsoZd0,f)(args); \
66 ret_ty VG_WRAP_FUNCTION_ZZ(libpthreadZdsoZd0,f)(args)
67
68
69// Local data structures.
70
71typedef struct
72{
73 void* (*start)(void*);
74 void* arg;
75 int detachstate;
76#if 0
77 pthread_mutex_t mutex;
78 pthread_cond_t cond;
79#else
80 int wrapper_started;
81#endif
82} VgPosixThreadArgs;
83
84
85// Local variables.
86
87static int vg_main_thread_state_is_set = 0;
88
89
90// Function definitions.
91
92static void vg_start_suppression(const void* const p, size_t const size)
93{
94 int res;
95 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__DRD_START_SUPPRESSION,
96 p, size, 0, 0, 0);
97}
98
99#if 0
100static void vg_finish_suppression(const void* const p, size_t const size)
101{
102 int res;
103 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__DRD_FINISH_SUPPRESSION,
104 p, size, 0, 0, 0);
105}
106#endif
107
108static void vg_start_recording(void)
109{
110 int res;
111 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__DRD_START_RECORDING,
112 pthread_self(), 0, 0, 0, 0);
113}
114
115static void vg_stop_recording(void)
116{
117 int res;
118 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__DRD_STOP_RECORDING,
119 pthread_self(), 0, 0, 0, 0);
120}
121
122static void vg_set_joinable(const pthread_t tid, const int joinable)
123{
124 int res;
125 assert(joinable == 0 || joinable == 1);
126#if 0
127 printf("vg_set_joinable(%ld, %d)\n", tid, joinable);
128#endif
129 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__SET_JOINABLE,
130 tid, joinable, 0, 0, 0);
131}
132
133static void* vg_thread_wrapper(void* arg)
134{
135 int res;
136 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__DRD_SUPPRESS_CURRENT_STACK,
137 0, 0, 0, 0, 0);
138
139 {
140 VgPosixThreadArgs* const arg_ptr = (VgPosixThreadArgs*)arg;
141 VgPosixThreadArgs const arg_copy = *arg_ptr;
142 void* result;
143
144#if 0
145 pthread_mutex_lock(arg_ptr->mutex);
146 pthread_cond_signal(arg_ptr->cond);
147 pthread_mutex_unlock(arg_ptr->mutex);
148#else
149 arg_ptr->wrapper_started = 1;
150#endif
151
152 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__SET_PTHREADID,
153 pthread_self(), 0, 0, 0, 0);
154 vg_set_joinable(pthread_self(),
155 arg_copy.detachstate == PTHREAD_CREATE_JOINABLE);
156 result = (arg_copy.start)(arg_copy.arg);
157 return result;
158 }
159}
160
161static void vg_set_main_thread_state(void)
162{
163 int res;
164
165 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__DRD_SUPPRESS_CURRENT_STACK,
166 0, 0, 0, 0, 0);
167
168 // Sanity checks.
169 assert(sizeof(pthread_mutex_t) == PTHREAD_MUTEX_SIZE);
170 assert(sizeof(pthread_spinlock_t) == PTHREAD_SPINLOCK_SIZE);
171
172 // Make sure that DRD knows about the main thread's POSIX thread ID.
173 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__SET_PTHREADID,
174 pthread_self(), 0, 0, 0, 0);
175
176}
177
178// pthread_create
179PTH_FUNC(int, pthreadZucreateZAZa, // pthread_create@*
180 pthread_t *thread, const pthread_attr_t *attr,
181 void *(*start) (void *), void *arg)
182{
183 int ret;
184 OrigFn fn;
185 VgPosixThreadArgs vgargs;
186
187 VALGRIND_GET_ORIG_FN(fn);
188
189 if (vg_main_thread_state_is_set == 0)
190 {
191 vg_set_main_thread_state();
192 vg_main_thread_state_is_set = 1;
193 }
194 vg_start_suppression(&vgargs.wrapper_started,
195 sizeof(vgargs.wrapper_started));
196 vgargs.start = start;
197 vgargs.arg = arg;
198 vgargs.wrapper_started = 0;
199 vgargs.detachstate = PTHREAD_CREATE_JOINABLE;
200 if (attr)
201 {
202 if (pthread_attr_getdetachstate(attr, &vgargs.detachstate) != 0)
203 {
204 assert(0);
205 }
206#if 0
207 printf("[%ld] Requested detach state for new thread: %d\n",
208 pthread_self(), vgargs.detachstate);
209#endif
210 }
211 assert(vgargs.detachstate == PTHREAD_CREATE_JOINABLE
212 || vgargs.detachstate == PTHREAD_CREATE_DETACHED);
213#if 0
214 pthread_mutex_init(&vgargs.mutex, 0);
215 pthread_cond_init(&vgargs.cond, 0);
216 pthread_mutex_lock(&vgargs.mutex);
217#endif
218 vg_stop_recording();
219 CALL_FN_W_WWWW(ret, fn, thread, attr, vg_thread_wrapper, &vgargs);
220 vg_start_recording();
221#if 0
222 pthread_cond_wait(&vgargs.cond, &vgargs.mutex);
223 pthread_mutex_unlock(&vgargs.mutex);
224 pthread_cond_destroy(&vgargs.cond);
225 pthread_mutex_destroy(&vgargs.mutex);
226#else
227 // Yes, you see it correctly, busy waiting ... The problem is that
228 // POSIX threads functions cannot be called here -- the functions defined
229 // in this file (vg_preloaded.c) would be called instead of those in
230 // libpthread.so. This loop is necessary because vgargs is allocated on the
231 // stack, and the created thread reads it.
232 while (! vgargs.wrapper_started)
233 {
234 sched_yield();
235 }
236#endif
237 return ret;
238}
239
240// pthread_join
241PTH_FUNC(int, pthreadZujoin, // pthread_join
242 pthread_t pt_joinee, void **thread_return)
243{
244 int ret;
245 int res;
246 OrigFn fn;
247
248 VALGRIND_GET_ORIG_FN(fn);
249 CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
250 if (ret == 0)
251 {
252 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_THREAD_JOIN,
253 pt_joinee, 0, 0, 0, 0);
254 }
255 return ret;
256}
257
258// pthread_detach
259PTH_FUNC(int, pthreadZudetach, pthread_t pt_thread)
260{
261 int ret;
262 OrigFn fn;
263 VALGRIND_GET_ORIG_FN(fn);
264 {
265 CALL_FN_W_W(ret, fn, pt_thread);
266 if (ret == 0)
267 {
268 vg_set_joinable(pt_thread, 0);
269 }
270 }
271 return ret;
272}
273
274// pthread_mutex_init
275PTH_FUNC(int, pthreadZumutexZuinit,
276 pthread_mutex_t *mutex,
277 const pthread_mutexattr_t* attr)
278{
279 int ret;
280 int res;
281 OrigFn fn;
282 VALGRIND_GET_ORIG_FN(fn);
283 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_MUTEX_INIT,
284 mutex, sizeof(*mutex), 0, 0, 0);
285 CALL_FN_W_WW(ret, fn, mutex, attr);
286 return ret;
287}
288
289// pthread_mutex_destroy
290PTH_FUNC(int, pthreadZumutexZudestroy,
291 pthread_mutex_t *mutex)
292{
293 int ret;
294 int res;
295 OrigFn fn;
296 VALGRIND_GET_ORIG_FN(fn);
297 CALL_FN_W_W(ret, fn, mutex);
298 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_DESTROY,
299 mutex, sizeof(*mutex), 0, 0, 0);
300 return ret;
301}
302
303// pthread_mutex_lock
304PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock
305 pthread_mutex_t *mutex)
306{
307 int ret;
308 int res;
309 OrigFn fn;
310 VALGRIND_GET_ORIG_FN(fn);
311 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_PTHREAD_MUTEX_LOCK,
312 mutex, sizeof(*mutex), 0, 0, 0);
313#if 1
314 // The only purpose of the system call below is to make drd work on AMD64
315 // systems. Without this system call, clients crash (SIGSEGV) in
316 // std::locale::locale().
317 write(1, "", 0);
318#endif
319 CALL_FN_W_W(ret, fn, mutex);
320 if (ret == 0)
321 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__POST_PTHREAD_MUTEX_LOCK,
322 mutex, sizeof(*mutex), 0, 0, 0);
323 return ret;
324}
325
326// pthread_mutex_trylock
327PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock
328 pthread_mutex_t *mutex)
329{
330 int ret;
331 int res;
332 OrigFn fn;
333 VALGRIND_GET_ORIG_FN(fn);
334 CALL_FN_W_W(ret, fn, mutex);
335 if (ret == 0)
336 {
337 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_PTHREAD_MUTEX_LOCK,
338 mutex, sizeof(*mutex), 0, 0, 0);
339 }
340 return ret;
341}
342
343// pthread_mutex_unlock
344PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock
345 pthread_mutex_t *mutex)
346{
347 int ret;
348 int res;
349 OrigFn fn;
350 VALGRIND_GET_ORIG_FN(fn);
351 VALGRIND_DO_CLIENT_REQUEST(res, -1,
352 VG_USERREQ__PRE_PTHREAD_MUTEX_UNLOCK,
353 mutex, sizeof(*mutex), 0, 0, 0);
354 CALL_FN_W_W(ret, fn, mutex);
355 return ret;
356}
357
358// pthread_cond_init
359PTH_FUNC(int, pthreadZucondZuinitZAZa, // pthread_cond_init@*
360 pthread_cond_t* cond,
361 const pthread_condattr_t* attr)
362{
363 int ret;
364 int res;
365 OrigFn fn;
366 VALGRIND_GET_ORIG_FN(fn);
367 CALL_FN_W_WW(ret, fn, cond, attr);
368 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_PTHREAD_COND_INIT,
369 cond, sizeof(*cond), 0, 0, 0);
370 return ret;
371}
372
373// pthread_cond_destroy
374PTH_FUNC(int, pthreadZucondZudestroyZAZa, // pthread_cond_destroy@*
375 pthread_cond_t* cond)
376{
377 int ret;
378 int res;
379 OrigFn fn;
380 VALGRIND_GET_ORIG_FN(fn);
381 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_PTHREAD_COND_DESTROY,
382 cond, sizeof(*cond), 0, 0, 0);
383 CALL_FN_W_W(ret, fn, cond);
384 return ret;
385}
386
387// pthread_cond_wait
388PTH_FUNC(int, pthreadZucondZuwaitZAZa, // pthread_cond_wait@*
389 pthread_cond_t *cond,
390 pthread_mutex_t *mutex)
391{
392 int ret;
393 int res;
394 OrigFn fn;
395 VALGRIND_GET_ORIG_FN(fn);
396 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_PTHREAD_COND_WAIT,
397 cond, mutex, 0, 0, 0);
398 CALL_FN_W_WW(ret, fn, cond, mutex);
399 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_PTHREAD_COND_WAIT,
400 cond, mutex, 0, 0, 0);
401 return ret;
402}
403
404// pthread_cond_timedwait
405PTH_FUNC(int, pthreadZucondZutimedwaitZAZa, // pthread_cond_timedwait@*
406 pthread_cond_t *cond,
407 pthread_mutex_t *mutex,
408 const struct timespec* abstime)
409{
410 int ret;
411 int res;
412 OrigFn fn;
413 VALGRIND_GET_ORIG_FN(fn);
414 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_PTHREAD_COND_WAIT,
415 cond, mutex, 0, 0, 0);
416 CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
417 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_PTHREAD_COND_WAIT,
418 cond, mutex, 0, 0, 0);
419 return ret;
420}
421
422// pthread_cond_signal
423PTH_FUNC(int, pthreadZucondZusignalZAZa, // pthread_cond_signal@*
424 pthread_cond_t* cond)
425{
426 int ret;
427 int res;
428 OrigFn fn;
429 VALGRIND_GET_ORIG_FN(fn);
430 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_PTHREAD_COND_SIGNAL,
431 cond, 0, 0, 0, 0);
432 CALL_FN_W_W(ret, fn, cond);
433 return ret;
434}
435
436// pthread_cond_broadcast
437PTH_FUNC(int, pthreadZucondZubroadcastZAZa, // pthread_cond_broadcast@*
438 pthread_cond_t* cond)
439{
440 int ret;
441 int res;
442 OrigFn fn;
443 VALGRIND_GET_ORIG_FN(fn);
444 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_PTHREAD_COND_BROADCAST,
445 cond, 0, 0, 0, 0);
446 CALL_FN_W_W(ret, fn, cond);
447 return ret;
448}
449
450
451// pthread_spin_init
452PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
453 pthread_spinlock_t *spinlock,
454 int pshared)
455{
456 int ret;
457 int res;
458 OrigFn fn;
459 VALGRIND_GET_ORIG_FN(fn);
460 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__SPIN_INIT_OR_UNLOCK,
461 spinlock, sizeof(*spinlock), 0, 0, 0);
462 CALL_FN_W_WW(ret, fn, spinlock, pshared);
463 return ret;
464}
465
466// pthread_spin_destroy
467PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy
468 pthread_spinlock_t *spinlock)
469{
470 int ret;
471 int res;
472 OrigFn fn;
473 VALGRIND_GET_ORIG_FN(fn);
474 CALL_FN_W_W(ret, fn, spinlock);
475 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_DESTROY,
476 spinlock, sizeof(*spinlock), 0, 0, 0);
477 return ret;
478}
479
480// pthread_spin_lock
481PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
482 pthread_spinlock_t *spinlock)
483{
484 int ret;
485 int res;
486 OrigFn fn;
487 VALGRIND_GET_ORIG_FN(fn);
488 CALL_FN_W_W(ret, fn, spinlock);
489 if (ret == 0)
490 {
491 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_PTHREAD_MUTEX_LOCK,
492 spinlock, sizeof(*spinlock), 0, 0, 0);
493 }
494 return ret;
495}
496
497// pthread_spin_trylock
498PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
499 pthread_spinlock_t *spinlock)
500{
501 int ret;
502 int res;
503 OrigFn fn;
504 VALGRIND_GET_ORIG_FN(fn);
505 CALL_FN_W_W(ret, fn, spinlock);
506 if (ret == 0)
507 {
508 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_PTHREAD_MUTEX_LOCK,
509 spinlock, sizeof(*spinlock), 0, 0, 0);
510 }
511 return ret;
512}
513
514// pthread_spin_unlock
515PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
516 pthread_spinlock_t *spinlock)
517{
518 int ret;
519 int res;
520 OrigFn fn;
521 VALGRIND_GET_ORIG_FN(fn);
522 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__SPIN_INIT_OR_UNLOCK,
523 spinlock, sizeof(*spinlock), 0, 0, 0);
524 CALL_FN_W_W(ret, fn, spinlock);
525 return ret;
526}
527
528/*
529 * Local variables:
530 * c-basic-offset: 3
531 * End:
532 */