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);
347 * Note: as of today there exist three different versions of pthread_create
349 * - pthread_create@GLIBC_2.0
350 * - pthread_create@@GLIBC_2.1
351 * - pthread_create@@GLIBC_2.2.5
352 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
353 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
354 * versions have been implemented. In any glibc version where more than one
355 * pthread_create function has been implemented, older versions call the
356 * newer versions. Or: the pthread_create* wrapper defined below can be
357 * called recursively. Any code in this wrapper should take this in account.
358 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
359 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
360 * See also the implementation of pthread_create@GLIBC_2.0 in
361 * glibc-2.9/nptl/pthread_create.c.
364 static __always_inline
365 int pthread_create_intercept(pthread_t* thread, const pthread_attr_t* attr,
366 void* (*start)(void*), void* arg)
371 #if defined(ALLOCATE_THREAD_ARGS_ON_THE_STACK)
372 DrdPosixThreadArgs thread_args;
374 DrdPosixThreadArgs* thread_args_p;
376 VALGRIND_GET_ORIG_FN(fn);
378 #if defined(ALLOCATE_THREAD_ARGS_ON_THE_STACK)
379 thread_args_p = &thread_args;
381 thread_args_p = malloc(sizeof(*thread_args_p));
383 assert(thread_args_p);
385 thread_args_p->start = start;
386 thread_args_p->arg = arg;
387 #if defined(WAIT_UNTIL_CREATED_THREAD_STARTED)
388 DRD_IGNORE_VAR(thread_args_p->wrapper_started);
389 thread_args_p->wrapper_started = 0;
392 * Find out whether the thread will be started as a joinable thread
393 * or as a detached thread. If no thread attributes have been specified,
394 * this means that the new thread will be started as a joinable thread.
396 thread_args_p->detachstate = PTHREAD_CREATE_JOINABLE;
399 if (pthread_attr_getdetachstate(attr, &thread_args_p->detachstate) != 0)
404 assert(thread_args_p->detachstate == PTHREAD_CREATE_JOINABLE
405 || thread_args_p->detachstate == PTHREAD_CREATE_DETACHED);
408 DRD_(entering_pthread_create)();
409 CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), thread_args_p);
410 DRD_(left_pthread_create)();
412 #if defined(WAIT_UNTIL_CREATED_THREAD_STARTED)
416 * Wait until the thread wrapper started.
417 * @todo Find out why some regression tests fail if thread arguments are
418 * passed via dynamically allocated memory and if the loop below is
421 while (! thread_args_p->wrapper_started)
427 #if defined(ALLOCATE_THREAD_ARGS_DYNAMICALLY)
433 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__DRD_START_NEW_SEGMENT,
434 pthread_self(), 0, 0, 0, 0);
439 PTH_FUNCS(int, pthreadZucreate, pthread_create_intercept,
440 (pthread_t *thread, const pthread_attr_t *attr,
441 void *(*start) (void *), void *arg),
442 (thread, attr, start, arg));
444 static __always_inline
445 int pthread_join_intercept(pthread_t pt_joinee, void **thread_return)
451 VALGRIND_GET_ORIG_FN(fn);
452 CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
455 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_THREAD_JOIN,
456 pt_joinee, 0, 0, 0, 0);
461 PTH_FUNCS(int, pthreadZujoin, pthread_join_intercept,
462 (pthread_t pt_joinee, void **thread_return),
463 (pt_joinee, thread_return));
465 static __always_inline
466 int pthread_detach_intercept(pthread_t pt_thread)
470 VALGRIND_GET_ORIG_FN(fn);
472 CALL_FN_W_W(ret, fn, pt_thread);
475 DRD_(set_joinable)(pt_thread, 0);
481 PTH_FUNCS(int, pthreadZudetach, pthread_detach_intercept,
482 (pthread_t thread), (thread));
484 // NOTE: be careful to intercept only pthread_cancel() and not
485 // pthread_cancel_init() on Linux.
487 static __always_inline
488 int pthread_cancel_intercept(pthread_t pt_thread)
493 VALGRIND_GET_ORIG_FN(fn);
494 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_THREAD_CANCEL,
495 pt_thread, 0, 0, 0, 0);
496 CALL_FN_W_W(ret, fn, pt_thread);
497 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_THREAD_CANCEL,
498 pt_thread, ret==0, 0, 0, 0);
502 PTH_FUNCS(int, pthreadZucancel, pthread_cancel_intercept,
503 (pthread_t thread), (thread))
505 static __always_inline
506 int pthread_once_intercept(pthread_once_t *once_control,
507 void (*init_routine)(void))
511 VALGRIND_GET_ORIG_FN(fn);
513 * Ignore any data races triggered by the implementation of pthread_once().
514 * Necessary for Darwin. This is not necessary for Linux but doesn't have
515 * any known adverse effects.
517 DRD_IGNORE_VAR(*once_control);
518 CALL_FN_W_WW(ret, fn, once_control, init_routine);
519 DRD_STOP_IGNORING_VAR(*once_control);
523 PTH_FUNCS(int, pthreadZuonce, pthread_once_intercept,
524 (pthread_once_t *once_control, void (*init_routine)(void)),
525 (once_control, init_routine));
527 static __always_inline
528 int pthread_mutex_init_intercept(pthread_mutex_t *mutex,
529 const pthread_mutexattr_t* attr)
535 VALGRIND_GET_ORIG_FN(fn);
536 mt = PTHREAD_MUTEX_DEFAULT;
538 pthread_mutexattr_gettype(attr, &mt);
539 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_MUTEX_INIT,
540 mutex, DRD_(pthread_to_drd_mutex_type)(mt),
542 CALL_FN_W_WW(ret, fn, mutex, attr);
543 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_INIT,
548 PTH_FUNCS(int, pthreadZumutexZuinit, pthread_mutex_init_intercept,
549 (pthread_mutex_t *mutex, const pthread_mutexattr_t* attr),
552 static __always_inline
553 int pthread_mutex_destroy_intercept(pthread_mutex_t* mutex)
558 VALGRIND_GET_ORIG_FN(fn);
559 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_MUTEX_DESTROY,
561 CALL_FN_W_W(ret, fn, mutex);
562 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_DESTROY,
563 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
567 PTH_FUNCS(int, pthreadZumutexZudestroy, pthread_mutex_destroy_intercept,
568 (pthread_mutex_t *mutex), (mutex));
570 static __always_inline
571 int pthread_mutex_lock_intercept(pthread_mutex_t* mutex)
576 VALGRIND_GET_ORIG_FN(fn);
577 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
578 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
579 CALL_FN_W_W(ret, fn, mutex);
580 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__POST_MUTEX_LOCK,
581 mutex, ret == 0, 0, 0, 0);
585 PTH_FUNCS(int, pthreadZumutexZulock, pthread_mutex_lock_intercept,
586 (pthread_mutex_t *mutex), (mutex));
588 static __always_inline
589 int pthread_mutex_trylock_intercept(pthread_mutex_t* mutex)
594 VALGRIND_GET_ORIG_FN(fn);
595 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
596 mutex, DRD_(mutex_type)(mutex), 1, 0, 0);
597 CALL_FN_W_W(ret, fn, mutex);
598 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_LOCK,
599 mutex, ret == 0, 0, 0, 0);
603 PTH_FUNCS(int, pthreadZumutexZutrylock, pthread_mutex_trylock_intercept,
604 (pthread_mutex_t *mutex), (mutex));
606 static __always_inline
607 int pthread_mutex_timedlock_intercept(pthread_mutex_t *mutex,
608 const struct timespec *abs_timeout)
613 VALGRIND_GET_ORIG_FN(fn);
614 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
615 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
616 CALL_FN_W_WW(ret, fn, mutex, abs_timeout);
617 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_LOCK,
618 mutex, ret == 0, 0, 0, 0);
622 PTH_FUNCS(int, pthreadZumutexZutimedlock, pthread_mutex_timedlock_intercept,
623 (pthread_mutex_t *mutex, const struct timespec *abs_timeout),
624 (mutex, abs_timeout));
626 static __always_inline
627 int pthread_mutex_unlock_intercept(pthread_mutex_t *mutex)
632 VALGRIND_GET_ORIG_FN(fn);
633 VALGRIND_DO_CLIENT_REQUEST(res, -1,
634 VG_USERREQ__PRE_MUTEX_UNLOCK,
635 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
636 CALL_FN_W_W(ret, fn, mutex);
637 VALGRIND_DO_CLIENT_REQUEST(res, -1,
638 VG_USERREQ__POST_MUTEX_UNLOCK,
643 PTH_FUNCS(int, pthreadZumutexZuunlock, pthread_mutex_unlock_intercept,
644 (pthread_mutex_t *mutex), (mutex));
646 static __always_inline
647 int pthread_cond_init_intercept(pthread_cond_t* cond,
648 const pthread_condattr_t* attr)
653 VALGRIND_GET_ORIG_FN(fn);
654 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_INIT,
656 CALL_FN_W_WW(ret, fn, cond, attr);
657 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_INIT,
662 PTH_FUNCS(int, pthreadZucondZuinit, pthread_cond_init_intercept,
663 (pthread_cond_t* cond, const pthread_condattr_t* attr),
666 static __always_inline
667 int pthread_cond_destroy_intercept(pthread_cond_t* cond)
672 VALGRIND_GET_ORIG_FN(fn);
673 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_DESTROY,
675 CALL_FN_W_W(ret, fn, cond);
676 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_DESTROY,
681 PTH_FUNCS(int, pthreadZucondZudestroy, pthread_cond_destroy_intercept,
682 (pthread_cond_t* cond), (cond));
684 static __always_inline
685 int pthread_cond_wait_intercept(pthread_cond_t *cond, pthread_mutex_t *mutex)
690 VALGRIND_GET_ORIG_FN(fn);
691 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_WAIT,
692 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
693 CALL_FN_W_WW(ret, fn, cond, mutex);
694 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_WAIT,
695 cond, mutex, 1, 0, 0);
699 PTH_FUNCS(int, pthreadZucondZuwait, pthread_cond_wait_intercept,
700 (pthread_cond_t *cond, pthread_mutex_t *mutex),
703 static __always_inline
704 int pthread_cond_timedwait_intercept(pthread_cond_t *cond,
705 pthread_mutex_t *mutex,
706 const struct timespec* abstime)
711 VALGRIND_GET_ORIG_FN(fn);
712 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_WAIT,
713 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
714 CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
715 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_WAIT,
716 cond, mutex, 1, 0, 0);
720 PTH_FUNCS(int, pthreadZucondZutimedwait, pthread_cond_timedwait_intercept,
721 (pthread_cond_t *cond, pthread_mutex_t *mutex,
722 const struct timespec* abstime),
723 (cond, mutex, abstime));
725 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
726 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
727 // two. Intercepting all pthread_cond_signal* functions will cause only one
728 // argument to be passed to pthread_cond_signal_np() and hence will cause this
729 // last function to crash.
731 static __always_inline
732 int pthread_cond_signal_intercept(pthread_cond_t* cond)
737 VALGRIND_GET_ORIG_FN(fn);
738 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_SIGNAL,
740 CALL_FN_W_W(ret, fn, cond);
741 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_SIGNAL,
746 PTH_FUNCS(int, pthreadZucondZusignal, pthread_cond_signal_intercept,
747 (pthread_cond_t* cond), (cond));
749 static __always_inline
750 int pthread_cond_broadcast_intercept(pthread_cond_t* cond)
755 VALGRIND_GET_ORIG_FN(fn);
756 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_BROADCAST,
758 CALL_FN_W_W(ret, fn, cond);
759 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_BROADCAST,
764 PTH_FUNCS(int, pthreadZucondZubroadcast, pthread_cond_broadcast_intercept,
765 (pthread_cond_t* cond), (cond));
767 #if defined(HAVE_PTHREAD_SPIN_LOCK)
768 static __always_inline
769 int pthread_spin_init_intercept(pthread_spinlock_t *spinlock, int pshared)
774 VALGRIND_GET_ORIG_FN(fn);
775 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
776 spinlock, 0, 0, 0, 0);
777 CALL_FN_W_WW(ret, fn, spinlock, pshared);
778 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
779 spinlock, 0, 0, 0, 0);
783 PTH_FUNCS(int, pthreadZuspinZuinit, pthread_spin_init_intercept,
784 (pthread_spinlock_t *spinlock, int pshared), (spinlock, pshared));
786 static __always_inline
787 int pthread_spin_destroy_intercept(pthread_spinlock_t *spinlock)
792 VALGRIND_GET_ORIG_FN(fn);
793 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_MUTEX_DESTROY,
794 spinlock, 0, 0, 0, 0);
795 CALL_FN_W_W(ret, fn, spinlock);
796 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_DESTROY,
797 spinlock, mutex_type_spinlock, 0, 0, 0);
801 PTH_FUNCS(int, pthreadZuspinZudestroy, pthread_spin_destroy_intercept,
802 (pthread_spinlock_t *spinlock), (spinlock));
804 static __always_inline
805 int pthread_spin_lock_intercept(pthread_spinlock_t *spinlock)
810 VALGRIND_GET_ORIG_FN(fn);
811 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
812 spinlock, mutex_type_spinlock, 0, 0, 0);
813 CALL_FN_W_W(ret, fn, spinlock);
814 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_LOCK,
815 spinlock, ret == 0, 0, 0, 0);
819 PTH_FUNCS(int, pthreadZuspinZulock, pthread_spin_lock_intercept,
820 (pthread_spinlock_t *spinlock), (spinlock));
822 static __always_inline
823 int pthread_spin_trylock_intercept(pthread_spinlock_t *spinlock)
828 VALGRIND_GET_ORIG_FN(fn);
829 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
830 spinlock, mutex_type_spinlock, 0, 0, 0);
831 CALL_FN_W_W(ret, fn, spinlock);
832 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_LOCK,
833 spinlock, ret == 0, 0, 0, 0);
837 PTH_FUNCS(int, pthreadZuspinZutrylock, pthread_spin_trylock_intercept,
838 (pthread_spinlock_t *spinlock), (spinlock));
840 static __always_inline
841 int pthread_spin_unlock_intercept(pthread_spinlock_t *spinlock)
846 VALGRIND_GET_ORIG_FN(fn);
847 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
848 spinlock, mutex_type_spinlock, 0, 0, 0);
849 CALL_FN_W_W(ret, fn, spinlock);
850 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
851 spinlock, 0, 0, 0, 0);
855 PTH_FUNCS(int, pthreadZuspinZuunlock, pthread_spin_unlock_intercept,
856 (pthread_spinlock_t *spinlock), (spinlock));
857 #endif // HAVE_PTHREAD_SPIN_LOCK
860 #if defined(HAVE_PTHREAD_BARRIER_INIT)
861 static __always_inline
862 int pthread_barrier_init_intercept(pthread_barrier_t* barrier,
863 const pthread_barrierattr_t* attr,
869 VALGRIND_GET_ORIG_FN(fn);
870 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_BARRIER_INIT,
871 barrier, pthread_barrier, count, 0, 0);
872 CALL_FN_W_WWW(ret, fn, barrier, attr, count);
873 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_BARRIER_INIT,
874 barrier, pthread_barrier, 0, 0, 0);
878 PTH_FUNCS(int, pthreadZubarrierZuinit, pthread_barrier_init_intercept,
879 (pthread_barrier_t* barrier, const pthread_barrierattr_t* attr,
880 unsigned count), (barrier, attr, count));
882 static __always_inline
883 int pthread_barrier_destroy_intercept(pthread_barrier_t* barrier)
888 VALGRIND_GET_ORIG_FN(fn);
889 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_BARRIER_DESTROY,
890 barrier, pthread_barrier, 0, 0, 0);
891 CALL_FN_W_W(ret, fn, barrier);
892 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_BARRIER_DESTROY,
893 barrier, pthread_barrier, 0, 0, 0);
897 PTH_FUNCS(int, pthreadZubarrierZudestroy, pthread_barrier_destroy_intercept,
898 (pthread_barrier_t* barrier), (barrier));
900 static __always_inline
901 int pthread_barrier_wait_intercept(pthread_barrier_t* barrier)
906 VALGRIND_GET_ORIG_FN(fn);
907 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_BARRIER_WAIT,
908 barrier, pthread_barrier, 0, 0, 0);
909 CALL_FN_W_W(ret, fn, barrier);
910 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_BARRIER_WAIT,
911 barrier, pthread_barrier,
912 ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD,
913 ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
917 PTH_FUNCS(int, pthreadZubarrierZuwait, pthread_barrier_wait_intercept,
918 (pthread_barrier_t* barrier), (barrier));
919 #endif // HAVE_PTHREAD_BARRIER_INIT
922 static __always_inline
923 int sem_init_intercept(sem_t *sem, int pshared, unsigned int value)
928 VALGRIND_GET_ORIG_FN(fn);
929 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_INIT,
930 sem, pshared, value, 0, 0);
931 CALL_FN_W_WWW(ret, fn, sem, pshared, value);
932 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_INIT,
937 PTH_FUNCS(int, semZuinit, sem_init_intercept,
938 (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
940 static __always_inline
941 int sem_destroy_intercept(sem_t *sem)
946 VALGRIND_GET_ORIG_FN(fn);
947 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_DESTROY,
949 CALL_FN_W_W(ret, fn, sem);
950 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_DESTROY,
955 PTH_FUNCS(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
957 static __always_inline
958 sem_t* sem_open_intercept(const char *name, int oflag, mode_t mode,
964 VALGRIND_GET_ORIG_FN(fn);
965 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_OPEN,
966 name, oflag, mode, value, 0);
967 CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value);
968 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_OPEN,
969 ret != SEM_FAILED ? ret : 0,
970 name, oflag, mode, value);
974 PTH_FUNCS(sem_t *, semZuopen, sem_open_intercept,
975 (const char *name, int oflag, mode_t mode, unsigned int value),
976 (name, oflag, mode, value));
978 static __always_inline int sem_close_intercept(sem_t *sem)
983 VALGRIND_GET_ORIG_FN(fn);
984 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_CLOSE,
986 CALL_FN_W_W(ret, fn, sem);
987 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_CLOSE,
992 PTH_FUNCS(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
994 static __always_inline int sem_wait_intercept(sem_t *sem)
999 VALGRIND_GET_ORIG_FN(fn);
1000 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_WAIT,
1002 CALL_FN_W_W(ret, fn, sem);
1003 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
1004 sem, ret == 0, 0, 0, 0);
1008 PTH_FUNCS(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1010 static __always_inline int sem_trywait_intercept(sem_t *sem)
1015 VALGRIND_GET_ORIG_FN(fn);
1016 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_WAIT,
1018 CALL_FN_W_W(ret, fn, sem);
1019 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
1020 sem, ret == 0, 0, 0, 0);
1024 PTH_FUNCS(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1026 static __always_inline
1027 int sem_timedwait_intercept(sem_t *sem, const struct timespec *abs_timeout)
1032 VALGRIND_GET_ORIG_FN(fn);
1033 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_WAIT,
1035 CALL_FN_W_WW(ret, fn, sem, abs_timeout);
1036 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
1037 sem, ret == 0, 0, 0, 0);
1041 PTH_FUNCS(int, semZutimedwait, sem_timedwait_intercept,
1042 (sem_t *sem, const struct timespec *abs_timeout),
1043 (sem, abs_timeout));
1045 static __always_inline int sem_post_intercept(sem_t *sem)
1050 VALGRIND_GET_ORIG_FN(fn);
1051 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_POST,
1053 CALL_FN_W_W(ret, fn, sem);
1054 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_POST,
1055 sem, ret == 0, 0, 0, 0);
1059 PTH_FUNCS(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
1061 static __always_inline
1062 int pthread_rwlock_init_intercept(pthread_rwlock_t* rwlock,
1063 const pthread_rwlockattr_t* attr)
1068 VALGRIND_GET_ORIG_FN(fn);
1069 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_INIT,
1070 rwlock, 0, 0, 0, 0);
1071 CALL_FN_W_WW(ret, fn, rwlock, attr);
1076 pthreadZurwlockZuinit, pthread_rwlock_init_intercept,
1077 (pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr),
1080 static __always_inline
1081 int pthread_rwlock_destroy_intercept(pthread_rwlock_t* rwlock)
1086 VALGRIND_GET_ORIG_FN(fn);
1087 CALL_FN_W_W(ret, fn, rwlock);
1088 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_DESTROY,
1089 rwlock, 0, 0, 0, 0);
1094 pthreadZurwlockZudestroy, pthread_rwlock_destroy_intercept,
1095 (pthread_rwlock_t* rwlock), (rwlock));
1097 static __always_inline
1098 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t* rwlock)
1103 VALGRIND_GET_ORIG_FN(fn);
1104 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_RDLOCK,
1105 rwlock, 0, 0, 0, 0);
1106 CALL_FN_W_W(ret, fn, rwlock);
1107 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_RDLOCK,
1108 rwlock, ret == 0, 0, 0, 0);
1113 pthreadZurwlockZurdlock, pthread_rwlock_rdlock_intercept,
1114 (pthread_rwlock_t* rwlock), (rwlock));
1116 static __always_inline
1117 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t* rwlock)
1122 VALGRIND_GET_ORIG_FN(fn);
1123 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_WRLOCK,
1124 rwlock, 0, 0, 0, 0);
1125 CALL_FN_W_W(ret, fn, rwlock);
1126 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_WRLOCK,
1127 rwlock, ret == 0, 0, 0, 0);
1132 pthreadZurwlockZuwrlock, pthread_rwlock_wrlock_intercept,
1133 (pthread_rwlock_t* rwlock), (rwlock));
1135 static __always_inline
1136 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t* rwlock)
1141 VALGRIND_GET_ORIG_FN(fn);
1142 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_RDLOCK,
1143 rwlock, 0, 0, 0, 0);
1144 CALL_FN_W_W(ret, fn, rwlock);
1145 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_RDLOCK,
1146 rwlock, ret == 0, 0, 0, 0);
1151 pthreadZurwlockZutimedrdlock, pthread_rwlock_timedrdlock_intercept,
1152 (pthread_rwlock_t* rwlock), (rwlock));
1154 static __always_inline
1155 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t* rwlock)
1160 VALGRIND_GET_ORIG_FN(fn);
1161 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_WRLOCK,
1162 rwlock, 0, 0, 0, 0);
1163 CALL_FN_W_W(ret, fn, rwlock);
1164 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_WRLOCK,
1165 rwlock, ret == 0, 0, 0, 0);
1170 pthreadZurwlockZutimedwrlock, pthread_rwlock_timedwrlock_intercept,
1171 (pthread_rwlock_t* rwlock), (rwlock));
1173 static __always_inline
1174 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t* rwlock)
1179 VALGRIND_GET_ORIG_FN(fn);
1180 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_RDLOCK,
1181 rwlock, 0, 0, 0, 0);
1182 CALL_FN_W_W(ret, fn, rwlock);
1183 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_RDLOCK,
1184 rwlock, ret == 0, 0, 0, 0);
1189 pthreadZurwlockZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1190 (pthread_rwlock_t* rwlock), (rwlock));
1192 static __always_inline
1193 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t* rwlock)
1198 VALGRIND_GET_ORIG_FN(fn);
1199 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_WRLOCK,
1200 rwlock, 0, 0, 0, 0);
1201 CALL_FN_W_W(ret, fn, rwlock);
1202 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_WRLOCK,
1203 rwlock, ret == 0, 0, 0, 0);
1208 pthreadZurwlockZutrywrlock, pthread_rwlock_trywrlock_intercept,
1209 (pthread_rwlock_t* rwlock), (rwlock));
1211 static __always_inline
1212 int pthread_rwlock_unlock_intercept(pthread_rwlock_t* rwlock)
1217 VALGRIND_GET_ORIG_FN(fn);
1218 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_UNLOCK,
1219 rwlock, 0, 0, 0, 0);
1220 CALL_FN_W_W(ret, fn, rwlock);
1221 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_UNLOCK,
1222 rwlock, ret == 0, 0, 0, 0);
1227 pthreadZurwlockZuunlock, pthread_rwlock_unlock_intercept,
1228 (pthread_rwlock_t* rwlock), (rwlock));