1 /* -*- mode: C; c-basic-offset: 3; -*- */
3 /*--------------------------------------------------------------------*/
4 /*--- Client-space code for DRD. drd_pthread_intercepts.c ---*/
5 /*--------------------------------------------------------------------*/
8 This file is part of DRD, a thread error detector.
10 Copyright (C) 2006-2010 Bart Van Assche <bart.vanassche@gmail.com>.
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.
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.
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
27 The GNU General Public License is contained in the file COPYING.
30 /* ---------------------------------------------------------------------
31 ALL THE CODE IN THIS FILE RUNS ON THE SIMULATED CPU.
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.
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 ------------------------------------------------------------------ */
44 * Define _GNU_SOURCE to make sure that pthread_spinlock_t is available when
45 * compiling with older glibc versions (2.3 or before).
51 #include <assert.h> /* assert() */
52 #include <pthread.h> /* pthread_mutex_t */
53 #include <semaphore.h> /* sem_t */
54 #include <stdio.h> /* fprintf() */
55 #include <stdlib.h> /* malloc(), free() */
56 #include <unistd.h> /* confstr() */
57 #include "config.h" /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP etc. */
58 #include "drd_basics.h" /* DRD_() */
59 #include "drd_clientreq.h"
60 #include "pub_tool_redir.h" /* VG_WRAP_FUNCTION_ZZ() */
66 * Do not undefine the two macro's below, or the following two subtle race
67 * conditions will be introduced in the data race detection algorithm:
68 * - sg_init() runs on the context of the created thread and copies the
69 * vector clock of the creator thread. This only works reliably if
70 * the creator thread waits until this copy has been performed.
71 * - Since DRD_(thread_compute_minimum_vc)() does not take the vector
72 * clocks into account that are involved in thread creation but
73 * for which the corresponding thread has not yet been created, by
74 * undefining the macro below it becomes possible that segments get
75 * discarded that should not yet be discarded. Or: some data races
78 #define WAIT_UNTIL_CREATED_THREAD_STARTED
79 #define ALLOCATE_THREAD_ARGS_ON_THE_STACK
82 * Macro for generating a Valgrind interception function.
83 * @param[in] ret_ty Return type of the function to be generated.
84 * @param[in] zf Z-encoded name of the interception function.
85 * @param[in] implf Name of the function that implements the intercept.
86 * @param[in] arg_decl Argument declaration list enclosed in parentheses.
87 * @param[in] argl Argument list enclosed in parentheses.
89 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
90 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
91 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
92 { return implf argl; }
95 * Macro for generating three Valgrind interception functions: one with the
96 * Z-encoded name zf, one with ZAZa ("@*") appended to the name zf and one
97 * with ZDZa ("$*") appended to the name zf. The second generated interception
98 * function will intercept versioned symbols on Linux, and the third will
99 * intercept versioned symbols on Darwin.
101 #define PTH_FUNCS(ret_ty, zf, implf, argl_decl, argl) \
102 PTH_FUNC(ret_ty, zf, implf, argl_decl, argl); \
103 PTH_FUNC(ret_ty, zf ## ZAZa, implf, argl_decl, argl); \
104 PTH_FUNC(ret_ty, zf ## ZDZa, implf, argl_decl, argl);
107 * Not inlining one of the intercept functions will cause the regression
108 * tests to fail because this would cause an additional stackfram to appear
109 * in the output. The __always_inline macro guarantees that inlining will
110 * happen, even when compiling with optimization disabled.
112 #undef __always_inline /* since already defined in <cdefs.h> */
113 #if __GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 2
114 #define __always_inline __inline__ __attribute__((always_inline))
116 #define __always_inline __inline__
119 /* Local data structures. */
123 void* (*start)(void*);
126 #if defined(WAIT_UNTIL_CREATED_THREAD_STARTED)
129 } DrdPosixThreadArgs;
132 /* Local function declarations. */
134 static void DRD_(init)(void) __attribute__((constructor));
135 static void DRD_(check_threading_library)(void);
136 static void DRD_(set_main_thread_state)(void);
139 /* Function definitions. */
142 * Shared library initialization function. The function init() is called after
143 * dlopen() has loaded the shared library with DRD client intercepts because
144 * the constructor attribute was specified in the declaration of this function.
145 * Note: do specify the -nostdlib option to gcc when linking this code into a
146 * shared library because doing so would cancel the effect of the constructor
147 * attribute ! Using the gcc option -nodefaultlibs is fine because this last
148 * option preserves the shared library initialization code that calls
149 * constructor and destructor functions.
151 static void DRD_(init)(void)
153 DRD_(check_threading_library)();
154 DRD_(set_main_thread_state)();
158 * POSIX threads and DRD each have their own mutex type identification.
159 * Convert POSIX threads' mutex type to DRD's mutex type. In the code below
160 * if-statements are used to test the value of 'kind' instead of a switch
161 * statement because some of the PTHREAD_MUTEX_ macro's may have the same
164 static MutexT DRD_(pthread_to_drd_mutex_type)(const int kind)
166 if (kind == PTHREAD_MUTEX_RECURSIVE)
167 return mutex_type_recursive_mutex;
168 else if (kind == PTHREAD_MUTEX_ERRORCHECK)
169 return mutex_type_errorcheck_mutex;
170 else if (kind == PTHREAD_MUTEX_NORMAL)
171 return mutex_type_default_mutex;
172 else if (kind == PTHREAD_MUTEX_DEFAULT)
173 return mutex_type_default_mutex;
174 #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
175 else if (kind == PTHREAD_MUTEX_ADAPTIVE_NP)
176 return mutex_type_default_mutex;
180 return mutex_type_invalid_mutex;
185 * Read the mutex type stored in the client memory used for the mutex
188 * @note This function depends on the implementation of the POSIX threads
189 * library -- the POSIX standard does not define the name of the member in
190 * which the mutex type is stored.
191 * @note The function mutex_type() has been declared inline in order
192 * to avoid that it shows up in call stacks (drd/tests/...exp* files).
193 * @note glibc stores the mutex type in the lowest two bits, and uses the
194 * higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
195 * PTHREAD_MUTEXATTR_FLAG_PSHARED.
197 static __always_inline MutexT DRD_(mutex_type)(pthread_mutex_t* mutex)
199 #if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
200 /* glibc + LinuxThreads. */
201 const int kind = mutex->__m_kind & 3;
202 return DRD_(pthread_to_drd_mutex_type)(kind);
203 #elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
205 const int kind = mutex->__data.__kind & 3;
206 return DRD_(pthread_to_drd_mutex_type)(kind);
209 * Another POSIX threads implementation. The mutex type won't be printed
210 * when enabling --trace-mutex=yes.
212 return mutex_type_unknown;
217 * Tell DRD whether 'tid' is a joinable thread or a detached thread.
219 static void DRD_(set_joinable)(const pthread_t tid, const int joinable)
222 assert(joinable == 0 || joinable == 1);
223 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__SET_JOINABLE,
224 tid, joinable, 0, 0, 0);
227 /** Tell DRD that the calling thread is about to enter pthread_create(). */
228 static __always_inline void DRD_(entering_pthread_create)(void)
231 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__ENTERING_PTHREAD_CREATE,
235 /** Tell DRD that the calling thread has left pthread_create(). */
236 static __always_inline void DRD_(left_pthread_create)(void)
239 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__LEFT_PTHREAD_CREATE,
244 * Entry point for newly created threads. This function is called from the
245 * thread created by pthread_create().
247 static void* DRD_(thread_wrapper)(void* arg)
250 DrdPosixThreadArgs* arg_ptr;
251 DrdPosixThreadArgs arg_copy;
253 arg_ptr = (DrdPosixThreadArgs*)arg;
255 #if defined(WAIT_UNTIL_CREATED_THREAD_STARTED)
256 arg_ptr->wrapper_started = 1;
258 #if defined(ALLOCATE_THREAD_ARGS_ON_THE_STACK)
259 #error Defining ALLOCATE_THREAD_ARGS_ON_THE_STACK but not \
260 WAIT_UNTIL_CREATED_THREAD_STARTED is not supported.
266 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__SET_PTHREADID,
267 pthread_self(), 0, 0, 0, 0);
269 DRD_(set_joinable)(pthread_self(),
270 arg_copy.detachstate == PTHREAD_CREATE_JOINABLE);
272 return (arg_copy.start)(arg_copy.arg);
276 * Return 1 if the LinuxThreads implementation of POSIX Threads has been
277 * detected, and 0 otherwise.
279 * @see For more information about the confstr() function, see also
280 * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
282 static int DRD_(detected_linuxthreads)(void)
285 #if defined(_CS_GNU_LIBPTHREAD_VERSION)
286 /* Linux with a recent glibc. */
289 len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
290 assert(len <= sizeof(buffer));
291 return len > 0 && buffer[0] == 'l';
293 /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
297 /* Another OS than Linux, hence no LinuxThreads. */
303 * Stop and print an error message in case a non-supported threading
304 * library implementation (LinuxThreads) has been detected.
306 static void DRD_(check_threading_library)(void)
308 if (DRD_(detected_linuxthreads)())
310 if (getenv("LD_ASSUME_KERNEL"))
313 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
314 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
315 "after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
321 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
322 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
323 "after having upgraded to a newer version of your Linux distribution.\n"
332 * The main thread is the only thread not created by pthread_create().
333 * Update DRD's state information about the main thread.
335 static void DRD_(set_main_thread_state)(void)
339 // Make sure that DRD knows about the main thread's POSIX thread ID.
340 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__SET_PTHREADID,
341 pthread_self(), 0, 0, 0, 0);
345 * Note: as of today there exist three different versions of pthread_create
347 * - pthread_create@GLIBC_2.0
348 * - pthread_create@@GLIBC_2.1
349 * - pthread_create@@GLIBC_2.2.5
350 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
351 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
352 * versions have been implemented. In any glibc version where more than one
353 * pthread_create function has been implemented, older versions call the
354 * newer versions. Or: the pthread_create* wrapper defined below can be
355 * called recursively. Any code in this wrapper should take this in account.
356 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
357 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
358 * See also the implementation of pthread_create@GLIBC_2.0 in
359 * glibc-2.9/nptl/pthread_create.c.
362 static __always_inline
363 int pthread_create_intercept(pthread_t* thread, const pthread_attr_t* attr,
364 void* (*start)(void*), void* arg)
369 #if defined(ALLOCATE_THREAD_ARGS_ON_THE_STACK)
370 DrdPosixThreadArgs thread_args;
372 DrdPosixThreadArgs* thread_args_p;
374 VALGRIND_GET_ORIG_FN(fn);
376 #if defined(ALLOCATE_THREAD_ARGS_ON_THE_STACK)
377 thread_args_p = &thread_args;
379 thread_args_p = malloc(sizeof(*thread_args_p));
381 assert(thread_args_p);
383 thread_args_p->start = start;
384 thread_args_p->arg = arg;
385 #if defined(WAIT_UNTIL_CREATED_THREAD_STARTED)
386 DRD_IGNORE_VAR(thread_args_p->wrapper_started);
387 thread_args_p->wrapper_started = 0;
390 * Find out whether the thread will be started as a joinable thread
391 * or as a detached thread. If no thread attributes have been specified,
392 * this means that the new thread will be started as a joinable thread.
394 thread_args_p->detachstate = PTHREAD_CREATE_JOINABLE;
397 if (pthread_attr_getdetachstate(attr, &thread_args_p->detachstate) != 0)
402 assert(thread_args_p->detachstate == PTHREAD_CREATE_JOINABLE
403 || thread_args_p->detachstate == PTHREAD_CREATE_DETACHED);
406 DRD_(entering_pthread_create)();
407 CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), thread_args_p);
408 DRD_(left_pthread_create)();
410 #if defined(WAIT_UNTIL_CREATED_THREAD_STARTED)
414 * Wait until the thread wrapper started.
415 * @todo Find out why some regression tests fail if thread arguments are
416 * passed via dynamically allocated memory and if the loop below is
419 while (! thread_args_p->wrapper_started)
425 #if defined(ALLOCATE_THREAD_ARGS_DYNAMICALLY)
431 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__DRD_START_NEW_SEGMENT,
432 pthread_self(), 0, 0, 0, 0);
437 PTH_FUNCS(int, pthreadZucreate, pthread_create_intercept,
438 (pthread_t *thread, const pthread_attr_t *attr,
439 void *(*start) (void *), void *arg),
440 (thread, attr, start, arg));
442 static __always_inline
443 int pthread_join_intercept(pthread_t pt_joinee, void **thread_return)
449 VALGRIND_GET_ORIG_FN(fn);
450 CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
453 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_THREAD_JOIN,
454 pt_joinee, 0, 0, 0, 0);
459 PTH_FUNCS(int, pthreadZujoin, pthread_join_intercept,
460 (pthread_t pt_joinee, void **thread_return),
461 (pt_joinee, thread_return));
463 static __always_inline
464 int pthread_detach_intercept(pthread_t pt_thread)
468 VALGRIND_GET_ORIG_FN(fn);
470 CALL_FN_W_W(ret, fn, pt_thread);
473 DRD_(set_joinable)(pt_thread, 0);
479 PTH_FUNCS(int, pthreadZudetach, pthread_detach_intercept,
480 (pthread_t thread), (thread));
482 // NOTE: be careful to intercept only pthread_cancel() and not
483 // pthread_cancel_init() on Linux.
485 static __always_inline
486 int pthread_cancel_intercept(pthread_t pt_thread)
491 VALGRIND_GET_ORIG_FN(fn);
492 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_THREAD_CANCEL,
493 pt_thread, 0, 0, 0, 0);
494 CALL_FN_W_W(ret, fn, pt_thread);
495 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_THREAD_CANCEL,
496 pt_thread, ret==0, 0, 0, 0);
500 PTH_FUNCS(int, pthreadZucancel, pthread_cancel_intercept,
501 (pthread_t thread), (thread))
503 static __always_inline
504 int pthread_once_intercept(pthread_once_t *once_control,
505 void (*init_routine)(void))
509 VALGRIND_GET_ORIG_FN(fn);
511 * Ignore any data races triggered by the implementation of pthread_once().
512 * Necessary for Darwin. This is not necessary for Linux but doesn't have
513 * any known adverse effects.
515 DRD_IGNORE_VAR(*once_control);
516 CALL_FN_W_WW(ret, fn, once_control, init_routine);
517 DRD_STOP_IGNORING_VAR(*once_control);
521 PTH_FUNCS(int, pthreadZuonce, pthread_once_intercept,
522 (pthread_once_t *once_control, void (*init_routine)(void)),
523 (once_control, init_routine));
525 static __always_inline
526 int pthread_mutex_init_intercept(pthread_mutex_t *mutex,
527 const pthread_mutexattr_t* attr)
533 VALGRIND_GET_ORIG_FN(fn);
534 mt = PTHREAD_MUTEX_DEFAULT;
536 pthread_mutexattr_gettype(attr, &mt);
537 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_MUTEX_INIT,
538 mutex, DRD_(pthread_to_drd_mutex_type)(mt),
540 CALL_FN_W_WW(ret, fn, mutex, attr);
541 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_INIT,
546 PTH_FUNCS(int, pthreadZumutexZuinit, pthread_mutex_init_intercept,
547 (pthread_mutex_t *mutex, const pthread_mutexattr_t* attr),
550 static __always_inline
551 int pthread_mutex_destroy_intercept(pthread_mutex_t* mutex)
556 VALGRIND_GET_ORIG_FN(fn);
557 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_MUTEX_DESTROY,
559 CALL_FN_W_W(ret, fn, mutex);
560 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_DESTROY,
561 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
565 PTH_FUNCS(int, pthreadZumutexZudestroy, pthread_mutex_destroy_intercept,
566 (pthread_mutex_t *mutex), (mutex));
568 static __always_inline
569 int pthread_mutex_lock_intercept(pthread_mutex_t* mutex)
574 VALGRIND_GET_ORIG_FN(fn);
575 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
576 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
577 CALL_FN_W_W(ret, fn, mutex);
578 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__POST_MUTEX_LOCK,
579 mutex, ret == 0, 0, 0, 0);
583 PTH_FUNCS(int, pthreadZumutexZulock, pthread_mutex_lock_intercept,
584 (pthread_mutex_t *mutex), (mutex));
586 static __always_inline
587 int pthread_mutex_trylock_intercept(pthread_mutex_t* mutex)
592 VALGRIND_GET_ORIG_FN(fn);
593 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
594 mutex, DRD_(mutex_type)(mutex), 1, 0, 0);
595 CALL_FN_W_W(ret, fn, mutex);
596 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_LOCK,
597 mutex, ret == 0, 0, 0, 0);
601 PTH_FUNCS(int, pthreadZumutexZutrylock, pthread_mutex_trylock_intercept,
602 (pthread_mutex_t *mutex), (mutex));
604 static __always_inline
605 int pthread_mutex_timedlock_intercept(pthread_mutex_t *mutex,
606 const struct timespec *abs_timeout)
611 VALGRIND_GET_ORIG_FN(fn);
612 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
613 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
614 CALL_FN_W_WW(ret, fn, mutex, abs_timeout);
615 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_LOCK,
616 mutex, ret == 0, 0, 0, 0);
620 PTH_FUNCS(int, pthreadZumutexZutimedlock, pthread_mutex_timedlock_intercept,
621 (pthread_mutex_t *mutex, const struct timespec *abs_timeout),
622 (mutex, abs_timeout));
624 static __always_inline
625 int pthread_mutex_unlock_intercept(pthread_mutex_t *mutex)
630 VALGRIND_GET_ORIG_FN(fn);
631 VALGRIND_DO_CLIENT_REQUEST(res, -1,
632 VG_USERREQ__PRE_MUTEX_UNLOCK,
633 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
634 CALL_FN_W_W(ret, fn, mutex);
635 VALGRIND_DO_CLIENT_REQUEST(res, -1,
636 VG_USERREQ__POST_MUTEX_UNLOCK,
641 PTH_FUNCS(int, pthreadZumutexZuunlock, pthread_mutex_unlock_intercept,
642 (pthread_mutex_t *mutex), (mutex));
644 static __always_inline
645 int pthread_cond_init_intercept(pthread_cond_t* cond,
646 const pthread_condattr_t* attr)
651 VALGRIND_GET_ORIG_FN(fn);
652 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_INIT,
654 CALL_FN_W_WW(ret, fn, cond, attr);
655 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_INIT,
660 PTH_FUNCS(int, pthreadZucondZuinit, pthread_cond_init_intercept,
661 (pthread_cond_t* cond, const pthread_condattr_t* attr),
664 static __always_inline
665 int pthread_cond_destroy_intercept(pthread_cond_t* cond)
670 VALGRIND_GET_ORIG_FN(fn);
671 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_DESTROY,
673 CALL_FN_W_W(ret, fn, cond);
674 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_DESTROY,
679 PTH_FUNCS(int, pthreadZucondZudestroy, pthread_cond_destroy_intercept,
680 (pthread_cond_t* cond), (cond));
682 static __always_inline
683 int pthread_cond_wait_intercept(pthread_cond_t *cond, pthread_mutex_t *mutex)
688 VALGRIND_GET_ORIG_FN(fn);
689 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_WAIT,
690 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
691 CALL_FN_W_WW(ret, fn, cond, mutex);
692 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_WAIT,
693 cond, mutex, 1, 0, 0);
697 PTH_FUNCS(int, pthreadZucondZuwait, pthread_cond_wait_intercept,
698 (pthread_cond_t *cond, pthread_mutex_t *mutex),
701 static __always_inline
702 int pthread_cond_timedwait_intercept(pthread_cond_t *cond,
703 pthread_mutex_t *mutex,
704 const struct timespec* abstime)
709 VALGRIND_GET_ORIG_FN(fn);
710 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_WAIT,
711 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
712 CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
713 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_WAIT,
714 cond, mutex, 1, 0, 0);
718 PTH_FUNCS(int, pthreadZucondZutimedwait, pthread_cond_timedwait_intercept,
719 (pthread_cond_t *cond, pthread_mutex_t *mutex,
720 const struct timespec* abstime),
721 (cond, mutex, abstime));
723 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
724 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
725 // two. Intercepting all pthread_cond_signal* functions will cause only one
726 // argument to be passed to pthread_cond_signal_np() and hence will cause this
727 // last function to crash.
729 static __always_inline
730 int pthread_cond_signal_intercept(pthread_cond_t* cond)
735 VALGRIND_GET_ORIG_FN(fn);
736 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_SIGNAL,
738 CALL_FN_W_W(ret, fn, cond);
739 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_SIGNAL,
744 PTH_FUNCS(int, pthreadZucondZusignal, pthread_cond_signal_intercept,
745 (pthread_cond_t* cond), (cond));
747 static __always_inline
748 int pthread_cond_broadcast_intercept(pthread_cond_t* cond)
753 VALGRIND_GET_ORIG_FN(fn);
754 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_BROADCAST,
756 CALL_FN_W_W(ret, fn, cond);
757 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_BROADCAST,
762 PTH_FUNCS(int, pthreadZucondZubroadcast, pthread_cond_broadcast_intercept,
763 (pthread_cond_t* cond), (cond));
765 #if defined(HAVE_PTHREAD_SPIN_LOCK)
766 static __always_inline
767 int pthread_spin_init_intercept(pthread_spinlock_t *spinlock, int pshared)
772 VALGRIND_GET_ORIG_FN(fn);
773 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
774 spinlock, 0, 0, 0, 0);
775 CALL_FN_W_WW(ret, fn, spinlock, pshared);
776 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
777 spinlock, 0, 0, 0, 0);
781 PTH_FUNCS(int, pthreadZuspinZuinit, pthread_spin_init_intercept,
782 (pthread_spinlock_t *spinlock, int pshared), (spinlock, pshared));
784 static __always_inline
785 int pthread_spin_destroy_intercept(pthread_spinlock_t *spinlock)
790 VALGRIND_GET_ORIG_FN(fn);
791 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_MUTEX_DESTROY,
792 spinlock, 0, 0, 0, 0);
793 CALL_FN_W_W(ret, fn, spinlock);
794 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_DESTROY,
795 spinlock, mutex_type_spinlock, 0, 0, 0);
799 PTH_FUNCS(int, pthreadZuspinZudestroy, pthread_spin_destroy_intercept,
800 (pthread_spinlock_t *spinlock), (spinlock));
802 static __always_inline
803 int pthread_spin_lock_intercept(pthread_spinlock_t *spinlock)
808 VALGRIND_GET_ORIG_FN(fn);
809 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
810 spinlock, mutex_type_spinlock, 0, 0, 0);
811 CALL_FN_W_W(ret, fn, spinlock);
812 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_LOCK,
813 spinlock, ret == 0, 0, 0, 0);
817 PTH_FUNCS(int, pthreadZuspinZulock, pthread_spin_lock_intercept,
818 (pthread_spinlock_t *spinlock), (spinlock));
820 static __always_inline
821 int pthread_spin_trylock_intercept(pthread_spinlock_t *spinlock)
826 VALGRIND_GET_ORIG_FN(fn);
827 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
828 spinlock, mutex_type_spinlock, 0, 0, 0);
829 CALL_FN_W_W(ret, fn, spinlock);
830 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_LOCK,
831 spinlock, ret == 0, 0, 0, 0);
835 PTH_FUNCS(int, pthreadZuspinZutrylock, pthread_spin_trylock_intercept,
836 (pthread_spinlock_t *spinlock), (spinlock));
838 static __always_inline
839 int pthread_spin_unlock_intercept(pthread_spinlock_t *spinlock)
844 VALGRIND_GET_ORIG_FN(fn);
845 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
846 spinlock, mutex_type_spinlock, 0, 0, 0);
847 CALL_FN_W_W(ret, fn, spinlock);
848 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
849 spinlock, 0, 0, 0, 0);
853 PTH_FUNCS(int, pthreadZuspinZuunlock, pthread_spin_unlock_intercept,
854 (pthread_spinlock_t *spinlock), (spinlock));
855 #endif // HAVE_PTHREAD_SPIN_LOCK
858 #if defined(HAVE_PTHREAD_BARRIER_INIT)
859 static __always_inline
860 int pthread_barrier_init_intercept(pthread_barrier_t* barrier,
861 const pthread_barrierattr_t* attr,
867 VALGRIND_GET_ORIG_FN(fn);
868 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_BARRIER_INIT,
869 barrier, pthread_barrier, count, 0, 0);
870 CALL_FN_W_WWW(ret, fn, barrier, attr, count);
871 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_BARRIER_INIT,
872 barrier, pthread_barrier, 0, 0, 0);
876 PTH_FUNCS(int, pthreadZubarrierZuinit, pthread_barrier_init_intercept,
877 (pthread_barrier_t* barrier, const pthread_barrierattr_t* attr,
878 unsigned count), (barrier, attr, count));
880 static __always_inline
881 int pthread_barrier_destroy_intercept(pthread_barrier_t* barrier)
886 VALGRIND_GET_ORIG_FN(fn);
887 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_BARRIER_DESTROY,
888 barrier, pthread_barrier, 0, 0, 0);
889 CALL_FN_W_W(ret, fn, barrier);
890 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_BARRIER_DESTROY,
891 barrier, pthread_barrier, 0, 0, 0);
895 PTH_FUNCS(int, pthreadZubarrierZudestroy, pthread_barrier_destroy_intercept,
896 (pthread_barrier_t* barrier), (barrier));
898 static __always_inline
899 int pthread_barrier_wait_intercept(pthread_barrier_t* barrier)
904 VALGRIND_GET_ORIG_FN(fn);
905 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_BARRIER_WAIT,
906 barrier, pthread_barrier, 0, 0, 0);
907 CALL_FN_W_W(ret, fn, barrier);
908 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_BARRIER_WAIT,
909 barrier, pthread_barrier,
910 ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD,
911 ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
915 PTH_FUNCS(int, pthreadZubarrierZuwait, pthread_barrier_wait_intercept,
916 (pthread_barrier_t* barrier), (barrier));
917 #endif // HAVE_PTHREAD_BARRIER_INIT
920 static __always_inline
921 int sem_init_intercept(sem_t *sem, int pshared, unsigned int value)
926 VALGRIND_GET_ORIG_FN(fn);
927 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_INIT,
928 sem, pshared, value, 0, 0);
929 CALL_FN_W_WWW(ret, fn, sem, pshared, value);
930 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_INIT,
935 PTH_FUNCS(int, semZuinit, sem_init_intercept,
936 (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
938 static __always_inline
939 int sem_destroy_intercept(sem_t *sem)
944 VALGRIND_GET_ORIG_FN(fn);
945 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_DESTROY,
947 CALL_FN_W_W(ret, fn, sem);
948 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_DESTROY,
953 PTH_FUNCS(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
955 static __always_inline
956 sem_t* sem_open_intercept(const char *name, int oflag, mode_t mode,
962 VALGRIND_GET_ORIG_FN(fn);
963 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_OPEN,
964 name, oflag, mode, value, 0);
965 CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value);
966 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_OPEN,
967 ret != SEM_FAILED ? ret : 0,
968 name, oflag, mode, value);
972 PTH_FUNCS(sem_t *, semZuopen, sem_open_intercept,
973 (const char *name, int oflag, mode_t mode, unsigned int value),
974 (name, oflag, mode, value));
976 static __always_inline int sem_close_intercept(sem_t *sem)
981 VALGRIND_GET_ORIG_FN(fn);
982 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_CLOSE,
984 CALL_FN_W_W(ret, fn, sem);
985 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_CLOSE,
990 PTH_FUNCS(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
992 static __always_inline int sem_wait_intercept(sem_t *sem)
997 VALGRIND_GET_ORIG_FN(fn);
998 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_WAIT,
1000 CALL_FN_W_W(ret, fn, sem);
1001 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
1002 sem, ret == 0, 0, 0, 0);
1006 PTH_FUNCS(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1008 static __always_inline int sem_trywait_intercept(sem_t *sem)
1013 VALGRIND_GET_ORIG_FN(fn);
1014 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_WAIT,
1016 CALL_FN_W_W(ret, fn, sem);
1017 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
1018 sem, ret == 0, 0, 0, 0);
1022 PTH_FUNCS(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1024 static __always_inline
1025 int sem_timedwait_intercept(sem_t *sem, const struct timespec *abs_timeout)
1030 VALGRIND_GET_ORIG_FN(fn);
1031 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_WAIT,
1033 CALL_FN_W_WW(ret, fn, sem, abs_timeout);
1034 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
1035 sem, ret == 0, 0, 0, 0);
1039 PTH_FUNCS(int, semZutimedwait, sem_timedwait_intercept,
1040 (sem_t *sem, const struct timespec *abs_timeout),
1041 (sem, abs_timeout));
1043 static __always_inline int sem_post_intercept(sem_t *sem)
1048 VALGRIND_GET_ORIG_FN(fn);
1049 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_POST,
1051 CALL_FN_W_W(ret, fn, sem);
1052 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_POST,
1053 sem, ret == 0, 0, 0, 0);
1057 PTH_FUNCS(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
1059 static __always_inline
1060 int pthread_rwlock_init_intercept(pthread_rwlock_t* rwlock,
1061 const pthread_rwlockattr_t* attr)
1066 VALGRIND_GET_ORIG_FN(fn);
1067 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_INIT,
1068 rwlock, 0, 0, 0, 0);
1069 CALL_FN_W_WW(ret, fn, rwlock, attr);
1074 pthreadZurwlockZuinit, pthread_rwlock_init_intercept,
1075 (pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr),
1078 static __always_inline
1079 int pthread_rwlock_destroy_intercept(pthread_rwlock_t* rwlock)
1084 VALGRIND_GET_ORIG_FN(fn);
1085 CALL_FN_W_W(ret, fn, rwlock);
1086 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_DESTROY,
1087 rwlock, 0, 0, 0, 0);
1092 pthreadZurwlockZudestroy, pthread_rwlock_destroy_intercept,
1093 (pthread_rwlock_t* rwlock), (rwlock));
1095 static __always_inline
1096 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t* rwlock)
1101 VALGRIND_GET_ORIG_FN(fn);
1102 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_RDLOCK,
1103 rwlock, 0, 0, 0, 0);
1104 CALL_FN_W_W(ret, fn, rwlock);
1105 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_RDLOCK,
1106 rwlock, ret == 0, 0, 0, 0);
1111 pthreadZurwlockZurdlock, pthread_rwlock_rdlock_intercept,
1112 (pthread_rwlock_t* rwlock), (rwlock));
1114 static __always_inline
1115 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t* rwlock)
1120 VALGRIND_GET_ORIG_FN(fn);
1121 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_WRLOCK,
1122 rwlock, 0, 0, 0, 0);
1123 CALL_FN_W_W(ret, fn, rwlock);
1124 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_WRLOCK,
1125 rwlock, ret == 0, 0, 0, 0);
1130 pthreadZurwlockZuwrlock, pthread_rwlock_wrlock_intercept,
1131 (pthread_rwlock_t* rwlock), (rwlock));
1133 static __always_inline
1134 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t* rwlock)
1139 VALGRIND_GET_ORIG_FN(fn);
1140 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_RDLOCK,
1141 rwlock, 0, 0, 0, 0);
1142 CALL_FN_W_W(ret, fn, rwlock);
1143 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_RDLOCK,
1144 rwlock, ret == 0, 0, 0, 0);
1149 pthreadZurwlockZutimedrdlock, pthread_rwlock_timedrdlock_intercept,
1150 (pthread_rwlock_t* rwlock), (rwlock));
1152 static __always_inline
1153 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t* rwlock)
1158 VALGRIND_GET_ORIG_FN(fn);
1159 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_WRLOCK,
1160 rwlock, 0, 0, 0, 0);
1161 CALL_FN_W_W(ret, fn, rwlock);
1162 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_WRLOCK,
1163 rwlock, ret == 0, 0, 0, 0);
1168 pthreadZurwlockZutimedwrlock, pthread_rwlock_timedwrlock_intercept,
1169 (pthread_rwlock_t* rwlock), (rwlock));
1171 static __always_inline
1172 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t* rwlock)
1177 VALGRIND_GET_ORIG_FN(fn);
1178 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_RDLOCK,
1179 rwlock, 0, 0, 0, 0);
1180 CALL_FN_W_W(ret, fn, rwlock);
1181 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_RDLOCK,
1182 rwlock, ret == 0, 0, 0, 0);
1187 pthreadZurwlockZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1188 (pthread_rwlock_t* rwlock), (rwlock));
1190 static __always_inline
1191 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t* rwlock)
1196 VALGRIND_GET_ORIG_FN(fn);
1197 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_WRLOCK,
1198 rwlock, 0, 0, 0, 0);
1199 CALL_FN_W_W(ret, fn, rwlock);
1200 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_WRLOCK,
1201 rwlock, ret == 0, 0, 0, 0);
1206 pthreadZurwlockZutrywrlock, pthread_rwlock_trywrlock_intercept,
1207 (pthread_rwlock_t* rwlock), (rwlock));
1209 static __always_inline
1210 int pthread_rwlock_unlock_intercept(pthread_rwlock_t* rwlock)
1215 VALGRIND_GET_ORIG_FN(fn);
1216 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_UNLOCK,
1217 rwlock, 0, 0, 0, 0);
1218 CALL_FN_W_W(ret, fn, rwlock);
1219 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_UNLOCK,
1220 rwlock, ret == 0, 0, 0, 0);
1225 pthreadZurwlockZuunlock, pthread_rwlock_unlock_intercept,
1226 (pthread_rwlock_t* rwlock), (rwlock));