1 /* -*- mode: C; c-basic-offset: 3; indent-tabs-mode: nil; -*- */
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-2011 Bart Van Assche <bvanassche@acm.org>.
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 <stdint.h> /* uintptr_t */
55 #include <stdio.h> /* fprintf() */
56 #include <stdlib.h> /* malloc(), free() */
57 #include <unistd.h> /* confstr() */
58 #include "config.h" /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP etc. */
59 #include "drd_basics.h" /* DRD_() */
60 #include "drd_clientreq.h"
61 #include "pub_tool_redir.h" /* VG_WRAP_FUNCTION_ZZ() */
65 * Notes regarding thread creation:
66 * - sg_init() runs on the context of the created thread and copies the vector
67 * clock of the creator thread. This only works reliably if the creator
68 * thread waits until this copy has been performed.
69 * - DRD_(thread_compute_minimum_vc)() does not take the vector clocks into
70 * account that are involved in thread creation and for which the
71 * corresponding thread has not yet been created. So not waiting until the
72 * created thread has been started would make it possible that segments get
73 * discarded that should not yet be discarded. Or: some data races are not
78 * Macro for generating a Valgrind interception function.
79 * @param[in] ret_ty Return type of the function to be generated.
80 * @param[in] zf Z-encoded name of the interception function.
81 * @param[in] implf Name of the function that implements the intercept.
82 * @param[in] arg_decl Argument declaration list enclosed in parentheses.
83 * @param[in] argl Argument list enclosed in parentheses.
86 static int never_true;
87 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
88 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
89 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
91 ret_ty pth_func_result = implf argl; \
92 /* Apparently inserting a function call in wrapper functions */ \
93 /* is sufficient to avoid misaligned stack errors. */ \
96 return pth_func_result; \
99 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
100 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
101 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
102 { return implf argl; }
106 * Macro for generating three Valgrind interception functions: one with the
107 * Z-encoded name zf, one with ZAZa ("@*") appended to the name zf and one
108 * with ZDZa ("$*") appended to the name zf. The second generated interception
109 * function will intercept versioned symbols on Linux, and the third will
110 * intercept versioned symbols on Darwin.
112 #define PTH_FUNCS(ret_ty, zf, implf, argl_decl, argl) \
113 PTH_FUNC(ret_ty, zf, implf, argl_decl, argl); \
114 PTH_FUNC(ret_ty, zf ## ZAZa, implf, argl_decl, argl); \
115 PTH_FUNC(ret_ty, zf ## ZDZa, implf, argl_decl, argl);
118 * Not inlining one of the intercept functions will cause the regression
119 * tests to fail because this would cause an additional stackfram to appear
120 * in the output. The __always_inline macro guarantees that inlining will
121 * happen, even when compiling with optimization disabled.
123 #undef __always_inline /* since already defined in <cdefs.h> */
124 #if __GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 2
125 #define __always_inline __inline__ __attribute__((always_inline))
127 #define __always_inline __inline__
130 /* Local data structures. */
134 void* (*start)(void*);
138 } DrdPosixThreadArgs;
141 /* Local function declarations. */
143 static void DRD_(init)(void) __attribute__((constructor));
144 static void DRD_(check_threading_library)(void);
145 static void DRD_(set_main_thread_state)(void);
148 /* Function definitions. */
151 * Shared library initialization function. The function init() is called after
152 * dlopen() has loaded the shared library with DRD client intercepts because
153 * the constructor attribute was specified in the declaration of this function.
154 * Note: do specify the -nostdlib option to gcc when linking this code into a
155 * shared library because doing so would cancel the effect of the constructor
156 * attribute ! Using the gcc option -nodefaultlibs is fine because this last
157 * option preserves the shared library initialization code that calls
158 * constructor and destructor functions.
160 static void DRD_(init)(void)
162 DRD_(check_threading_library)();
163 DRD_(set_main_thread_state)();
167 * POSIX threads and DRD each have their own mutex type identification.
168 * Convert POSIX threads' mutex type to DRD's mutex type. In the code below
169 * if-statements are used to test the value of 'kind' instead of a switch
170 * statement because some of the PTHREAD_MUTEX_ macro's may have the same
173 static MutexT DRD_(pthread_to_drd_mutex_type)(const int kind)
175 if (kind == PTHREAD_MUTEX_RECURSIVE)
176 return mutex_type_recursive_mutex;
177 else if (kind == PTHREAD_MUTEX_ERRORCHECK)
178 return mutex_type_errorcheck_mutex;
179 else if (kind == PTHREAD_MUTEX_NORMAL)
180 return mutex_type_default_mutex;
181 else if (kind == PTHREAD_MUTEX_DEFAULT)
182 return mutex_type_default_mutex;
183 #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
184 else if (kind == PTHREAD_MUTEX_ADAPTIVE_NP)
185 return mutex_type_default_mutex;
189 return mutex_type_invalid_mutex;
193 #define IS_ALIGNED(p) (((uintptr_t)(p) & (sizeof(*(p)) - 1)) == 0)
196 * Read the mutex type stored in the client memory used for the mutex
199 * @note This function depends on the implementation of the POSIX threads
200 * library -- the POSIX standard does not define the name of the member in
201 * which the mutex type is stored.
202 * @note The function mutex_type() has been declared inline in order
203 * to avoid that it shows up in call stacks (drd/tests/...exp* files).
204 * @note glibc stores the mutex type in the lowest two bits, and uses the
205 * higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
206 * PTHREAD_MUTEXATTR_FLAG_PSHARED.
208 static __always_inline MutexT DRD_(mutex_type)(pthread_mutex_t* mutex)
210 #if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
211 /* glibc + LinuxThreads. */
212 if (IS_ALIGNED(&mutex->__m_kind))
214 const int kind = mutex->__m_kind & 3;
215 return DRD_(pthread_to_drd_mutex_type)(kind);
217 #elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
219 if (IS_ALIGNED(&mutex->__data.__kind))
221 const int kind = mutex->__data.__kind & 3;
222 return DRD_(pthread_to_drd_mutex_type)(kind);
226 * Another POSIX threads implementation. The mutex type won't be printed
227 * when enabling --trace-mutex=yes.
230 return mutex_type_unknown;
234 * Tell DRD whether 'tid' is a joinable thread or a detached thread.
236 static void DRD_(set_joinable)(const pthread_t tid, const int joinable)
238 assert(joinable == 0 || joinable == 1);
239 VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__SET_JOINABLE,
240 tid, joinable, 0, 0, 0);
243 /** Tell DRD that the calling thread is about to enter pthread_create(). */
244 static __always_inline void DRD_(entering_pthread_create)(void)
246 VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__ENTERING_PTHREAD_CREATE,
250 /** Tell DRD that the calling thread has left pthread_create(). */
251 static __always_inline void DRD_(left_pthread_create)(void)
253 VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__LEFT_PTHREAD_CREATE,
258 * Entry point for newly created threads. This function is called from the
259 * thread created by pthread_create().
261 static void* DRD_(thread_wrapper)(void* arg)
263 DrdPosixThreadArgs* arg_ptr;
264 DrdPosixThreadArgs arg_copy;
266 arg_ptr = (DrdPosixThreadArgs*)arg;
269 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__SET_PTHREADID,
270 pthread_self(), 0, 0, 0, 0);
272 DRD_(set_joinable)(pthread_self(),
273 arg_copy.detachstate == PTHREAD_CREATE_JOINABLE);
276 * Only set 'wrapper_started' after VG_USERREQ__SET_PTHREADID and
277 * DRD_(set_joinable)() have been invoked to avoid a race with
278 * a pthread_detach() invocation for this thread from another thread.
280 arg_ptr->wrapper_started = 1;
282 return (arg_copy.start)(arg_copy.arg);
286 * Return 1 if the LinuxThreads implementation of POSIX Threads has been
287 * detected, and 0 otherwise.
289 * @see For more information about the confstr() function, see also
290 * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
292 static int DRD_(detected_linuxthreads)(void)
295 #if defined(_CS_GNU_LIBPTHREAD_VERSION)
296 /* Linux with a recent glibc. */
299 len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
300 assert(len <= sizeof(buffer));
301 return len > 0 && buffer[0] == 'l';
303 /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
307 /* Another OS than Linux, hence no LinuxThreads. */
313 * Stop and print an error message in case a non-supported threading
314 * library implementation (LinuxThreads) has been detected.
316 static void DRD_(check_threading_library)(void)
318 if (DRD_(detected_linuxthreads)())
320 if (getenv("LD_ASSUME_KERNEL"))
323 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
324 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
325 "after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
331 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
332 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
333 "after having upgraded to a newer version of your Linux distribution.\n"
342 * The main thread is the only thread not created by pthread_create().
343 * Update DRD's state information about the main thread.
345 static void DRD_(set_main_thread_state)(void)
347 // Make sure that DRD knows about the main thread's POSIX thread ID.
348 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__SET_PTHREADID,
349 pthread_self(), 0, 0, 0, 0);
353 * Note: as of today there exist three different versions of pthread_create
355 * - pthread_create@GLIBC_2.0
356 * - pthread_create@@GLIBC_2.1
357 * - pthread_create@@GLIBC_2.2.5
358 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
359 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
360 * versions have been implemented. In any glibc version where more than one
361 * pthread_create function has been implemented, older versions call the
362 * newer versions. Or: the pthread_create* wrapper defined below can be
363 * called recursively. Any code in this wrapper should take this in account.
364 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
365 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
366 * See also the implementation of pthread_create@GLIBC_2.0 in
367 * glibc-2.9/nptl/pthread_create.c.
370 static __always_inline
371 int pthread_create_intercept(pthread_t* thread, const pthread_attr_t* attr,
372 void* (*start)(void*), void* arg)
376 DrdPosixThreadArgs thread_args;
378 VALGRIND_GET_ORIG_FN(fn);
380 thread_args.start = start;
381 thread_args.arg = arg;
382 DRD_IGNORE_VAR(thread_args.wrapper_started);
383 thread_args.wrapper_started = 0;
385 * Find out whether the thread will be started as a joinable thread
386 * or as a detached thread. If no thread attributes have been specified,
387 * this means that the new thread will be started as a joinable thread.
389 thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
392 if (pthread_attr_getdetachstate(attr, &thread_args.detachstate) != 0)
395 assert(thread_args.detachstate == PTHREAD_CREATE_JOINABLE
396 || thread_args.detachstate == PTHREAD_CREATE_DETACHED);
398 DRD_(entering_pthread_create)();
399 CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), &thread_args);
400 DRD_(left_pthread_create)();
404 /* Wait until the thread wrapper started. */
405 while (!thread_args.wrapper_started)
409 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__DRD_START_NEW_SEGMENT,
410 pthread_self(), 0, 0, 0, 0);
415 PTH_FUNCS(int, pthreadZucreate, pthread_create_intercept,
416 (pthread_t *thread, const pthread_attr_t *attr,
417 void *(*start) (void *), void *arg),
418 (thread, attr, start, arg));
420 static __always_inline
421 int pthread_join_intercept(pthread_t pt_joinee, void **thread_return)
426 VALGRIND_GET_ORIG_FN(fn);
427 CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
430 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_THREAD_JOIN,
431 pt_joinee, 0, 0, 0, 0);
436 PTH_FUNCS(int, pthreadZujoin, pthread_join_intercept,
437 (pthread_t pt_joinee, void **thread_return),
438 (pt_joinee, thread_return));
440 static __always_inline
441 int pthread_detach_intercept(pthread_t pt_thread)
446 VALGRIND_GET_ORIG_FN(fn);
447 CALL_FN_W_W(ret, fn, pt_thread);
448 DRD_(set_joinable)(pt_thread, 0);
453 PTH_FUNCS(int, pthreadZudetach, pthread_detach_intercept,
454 (pthread_t thread), (thread));
456 // NOTE: be careful to intercept only pthread_cancel() and not
457 // pthread_cancel_init() on Linux.
459 static __always_inline
460 int pthread_cancel_intercept(pthread_t pt_thread)
464 VALGRIND_GET_ORIG_FN(fn);
465 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_THREAD_CANCEL,
466 pt_thread, 0, 0, 0, 0);
467 CALL_FN_W_W(ret, fn, pt_thread);
468 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_THREAD_CANCEL,
469 pt_thread, ret==0, 0, 0, 0);
473 PTH_FUNCS(int, pthreadZucancel, pthread_cancel_intercept,
474 (pthread_t thread), (thread))
476 static __always_inline
477 int pthread_once_intercept(pthread_once_t *once_control,
478 void (*init_routine)(void))
482 VALGRIND_GET_ORIG_FN(fn);
484 * Ignore any data races triggered by the implementation of pthread_once().
485 * Necessary for Darwin. This is not necessary for Linux but doesn't have
486 * any known adverse effects.
488 DRD_IGNORE_VAR(*once_control);
489 CALL_FN_W_WW(ret, fn, once_control, init_routine);
490 DRD_STOP_IGNORING_VAR(*once_control);
494 PTH_FUNCS(int, pthreadZuonce, pthread_once_intercept,
495 (pthread_once_t *once_control, void (*init_routine)(void)),
496 (once_control, init_routine));
498 static __always_inline
499 int pthread_mutex_init_intercept(pthread_mutex_t *mutex,
500 const pthread_mutexattr_t* attr)
505 VALGRIND_GET_ORIG_FN(fn);
506 mt = PTHREAD_MUTEX_DEFAULT;
508 pthread_mutexattr_gettype(attr, &mt);
509 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_MUTEX_INIT,
510 mutex, DRD_(pthread_to_drd_mutex_type)(mt),
512 CALL_FN_W_WW(ret, fn, mutex, attr);
513 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_MUTEX_INIT,
518 PTH_FUNCS(int, pthreadZumutexZuinit, pthread_mutex_init_intercept,
519 (pthread_mutex_t *mutex, const pthread_mutexattr_t* attr),
522 static __always_inline
523 int pthread_mutex_destroy_intercept(pthread_mutex_t* mutex)
527 VALGRIND_GET_ORIG_FN(fn);
528 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_MUTEX_DESTROY,
530 CALL_FN_W_W(ret, fn, mutex);
531 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_MUTEX_DESTROY,
532 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
536 PTH_FUNCS(int, pthreadZumutexZudestroy, pthread_mutex_destroy_intercept,
537 (pthread_mutex_t *mutex), (mutex));
539 static __always_inline
540 int pthread_mutex_lock_intercept(pthread_mutex_t* mutex)
544 VALGRIND_GET_ORIG_FN(fn);
545 VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRE_MUTEX_LOCK,
546 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
547 CALL_FN_W_W(ret, fn, mutex);
548 VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__POST_MUTEX_LOCK,
549 mutex, ret == 0, 0, 0, 0);
553 PTH_FUNCS(int, pthreadZumutexZulock, pthread_mutex_lock_intercept,
554 (pthread_mutex_t *mutex), (mutex));
556 static __always_inline
557 int pthread_mutex_trylock_intercept(pthread_mutex_t* mutex)
561 VALGRIND_GET_ORIG_FN(fn);
562 VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRE_MUTEX_LOCK,
563 mutex, DRD_(mutex_type)(mutex), 1, 0, 0);
564 CALL_FN_W_W(ret, fn, mutex);
565 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_MUTEX_LOCK,
566 mutex, ret == 0, 0, 0, 0);
570 PTH_FUNCS(int, pthreadZumutexZutrylock, pthread_mutex_trylock_intercept,
571 (pthread_mutex_t *mutex), (mutex));
573 static __always_inline
574 int pthread_mutex_timedlock_intercept(pthread_mutex_t *mutex,
575 const struct timespec *abs_timeout)
579 VALGRIND_GET_ORIG_FN(fn);
580 VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRE_MUTEX_LOCK,
581 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
582 CALL_FN_W_WW(ret, fn, mutex, abs_timeout);
583 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_MUTEX_LOCK,
584 mutex, ret == 0, 0, 0, 0);
588 PTH_FUNCS(int, pthreadZumutexZutimedlock, pthread_mutex_timedlock_intercept,
589 (pthread_mutex_t *mutex, const struct timespec *abs_timeout),
590 (mutex, abs_timeout));
592 static __always_inline
593 int pthread_mutex_unlock_intercept(pthread_mutex_t *mutex)
597 VALGRIND_GET_ORIG_FN(fn);
598 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_MUTEX_UNLOCK,
599 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
600 CALL_FN_W_W(ret, fn, mutex);
601 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_MUTEX_UNLOCK,
606 PTH_FUNCS(int, pthreadZumutexZuunlock, pthread_mutex_unlock_intercept,
607 (pthread_mutex_t *mutex), (mutex));
609 static __always_inline
610 int pthread_cond_init_intercept(pthread_cond_t* cond,
611 const pthread_condattr_t* attr)
615 VALGRIND_GET_ORIG_FN(fn);
616 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_COND_INIT,
618 CALL_FN_W_WW(ret, fn, cond, attr);
619 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_COND_INIT,
624 PTH_FUNCS(int, pthreadZucondZuinit, pthread_cond_init_intercept,
625 (pthread_cond_t* cond, const pthread_condattr_t* attr),
628 static __always_inline
629 int pthread_cond_destroy_intercept(pthread_cond_t* cond)
633 VALGRIND_GET_ORIG_FN(fn);
634 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_COND_DESTROY,
636 CALL_FN_W_W(ret, fn, cond);
637 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_COND_DESTROY,
642 PTH_FUNCS(int, pthreadZucondZudestroy, pthread_cond_destroy_intercept,
643 (pthread_cond_t* cond), (cond));
645 static __always_inline
646 int pthread_cond_wait_intercept(pthread_cond_t *cond, pthread_mutex_t *mutex)
650 VALGRIND_GET_ORIG_FN(fn);
651 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_COND_WAIT,
652 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
653 CALL_FN_W_WW(ret, fn, cond, mutex);
654 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_COND_WAIT,
655 cond, mutex, 1, 0, 0);
659 PTH_FUNCS(int, pthreadZucondZuwait, pthread_cond_wait_intercept,
660 (pthread_cond_t *cond, pthread_mutex_t *mutex),
663 static __always_inline
664 int pthread_cond_timedwait_intercept(pthread_cond_t *cond,
665 pthread_mutex_t *mutex,
666 const struct timespec* abstime)
670 VALGRIND_GET_ORIG_FN(fn);
671 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_COND_WAIT,
672 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
673 CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
674 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_COND_WAIT,
675 cond, mutex, 1, 0, 0);
679 PTH_FUNCS(int, pthreadZucondZutimedwait, pthread_cond_timedwait_intercept,
680 (pthread_cond_t *cond, pthread_mutex_t *mutex,
681 const struct timespec* abstime),
682 (cond, mutex, abstime));
684 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
685 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
686 // two. Intercepting all pthread_cond_signal* functions will cause only one
687 // argument to be passed to pthread_cond_signal_np() and hence will cause this
688 // last function to crash.
690 static __always_inline
691 int pthread_cond_signal_intercept(pthread_cond_t* cond)
695 VALGRIND_GET_ORIG_FN(fn);
696 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_COND_SIGNAL,
698 CALL_FN_W_W(ret, fn, cond);
699 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_COND_SIGNAL,
704 PTH_FUNCS(int, pthreadZucondZusignal, pthread_cond_signal_intercept,
705 (pthread_cond_t* cond), (cond));
707 static __always_inline
708 int pthread_cond_broadcast_intercept(pthread_cond_t* cond)
712 VALGRIND_GET_ORIG_FN(fn);
713 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_COND_BROADCAST,
715 CALL_FN_W_W(ret, fn, cond);
716 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_COND_BROADCAST,
721 PTH_FUNCS(int, pthreadZucondZubroadcast, pthread_cond_broadcast_intercept,
722 (pthread_cond_t* cond), (cond));
724 #if defined(HAVE_PTHREAD_SPIN_LOCK)
725 static __always_inline
726 int pthread_spin_init_intercept(pthread_spinlock_t *spinlock, int pshared)
730 VALGRIND_GET_ORIG_FN(fn);
731 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
732 spinlock, 0, 0, 0, 0);
733 CALL_FN_W_WW(ret, fn, spinlock, pshared);
734 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
735 spinlock, 0, 0, 0, 0);
739 PTH_FUNCS(int, pthreadZuspinZuinit, pthread_spin_init_intercept,
740 (pthread_spinlock_t *spinlock, int pshared), (spinlock, pshared));
742 static __always_inline
743 int pthread_spin_destroy_intercept(pthread_spinlock_t *spinlock)
747 VALGRIND_GET_ORIG_FN(fn);
748 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_MUTEX_DESTROY,
749 spinlock, 0, 0, 0, 0);
750 CALL_FN_W_W(ret, fn, spinlock);
751 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_MUTEX_DESTROY,
752 spinlock, mutex_type_spinlock, 0, 0, 0);
756 PTH_FUNCS(int, pthreadZuspinZudestroy, pthread_spin_destroy_intercept,
757 (pthread_spinlock_t *spinlock), (spinlock));
759 static __always_inline
760 int pthread_spin_lock_intercept(pthread_spinlock_t *spinlock)
764 VALGRIND_GET_ORIG_FN(fn);
765 VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRE_MUTEX_LOCK,
766 spinlock, mutex_type_spinlock, 0, 0, 0);
767 CALL_FN_W_W(ret, fn, spinlock);
768 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_MUTEX_LOCK,
769 spinlock, ret == 0, 0, 0, 0);
773 PTH_FUNCS(int, pthreadZuspinZulock, pthread_spin_lock_intercept,
774 (pthread_spinlock_t *spinlock), (spinlock));
776 static __always_inline
777 int pthread_spin_trylock_intercept(pthread_spinlock_t *spinlock)
781 VALGRIND_GET_ORIG_FN(fn);
782 VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRE_MUTEX_LOCK,
783 spinlock, mutex_type_spinlock, 0, 0, 0);
784 CALL_FN_W_W(ret, fn, spinlock);
785 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_MUTEX_LOCK,
786 spinlock, ret == 0, 0, 0, 0);
790 PTH_FUNCS(int, pthreadZuspinZutrylock, pthread_spin_trylock_intercept,
791 (pthread_spinlock_t *spinlock), (spinlock));
793 static __always_inline
794 int pthread_spin_unlock_intercept(pthread_spinlock_t *spinlock)
798 VALGRIND_GET_ORIG_FN(fn);
799 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
800 spinlock, mutex_type_spinlock, 0, 0, 0);
801 CALL_FN_W_W(ret, fn, spinlock);
802 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
803 spinlock, 0, 0, 0, 0);
807 PTH_FUNCS(int, pthreadZuspinZuunlock, pthread_spin_unlock_intercept,
808 (pthread_spinlock_t *spinlock), (spinlock));
809 #endif // HAVE_PTHREAD_SPIN_LOCK
812 #if defined(HAVE_PTHREAD_BARRIER_INIT)
813 static __always_inline
814 int pthread_barrier_init_intercept(pthread_barrier_t* barrier,
815 const pthread_barrierattr_t* attr,
820 VALGRIND_GET_ORIG_FN(fn);
821 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_BARRIER_INIT,
822 barrier, pthread_barrier, count, 0, 0);
823 CALL_FN_W_WWW(ret, fn, barrier, attr, count);
824 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_BARRIER_INIT,
825 barrier, pthread_barrier, 0, 0, 0);
829 PTH_FUNCS(int, pthreadZubarrierZuinit, pthread_barrier_init_intercept,
830 (pthread_barrier_t* barrier, const pthread_barrierattr_t* attr,
831 unsigned count), (barrier, attr, count));
833 static __always_inline
834 int pthread_barrier_destroy_intercept(pthread_barrier_t* barrier)
838 VALGRIND_GET_ORIG_FN(fn);
839 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_BARRIER_DESTROY,
840 barrier, pthread_barrier, 0, 0, 0);
841 CALL_FN_W_W(ret, fn, barrier);
842 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_BARRIER_DESTROY,
843 barrier, pthread_barrier, 0, 0, 0);
847 PTH_FUNCS(int, pthreadZubarrierZudestroy, pthread_barrier_destroy_intercept,
848 (pthread_barrier_t* barrier), (barrier));
850 static __always_inline
851 int pthread_barrier_wait_intercept(pthread_barrier_t* barrier)
855 VALGRIND_GET_ORIG_FN(fn);
856 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_BARRIER_WAIT,
857 barrier, pthread_barrier, 0, 0, 0);
858 CALL_FN_W_W(ret, fn, barrier);
859 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_BARRIER_WAIT,
860 barrier, pthread_barrier,
861 ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD,
862 ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
866 PTH_FUNCS(int, pthreadZubarrierZuwait, pthread_barrier_wait_intercept,
867 (pthread_barrier_t* barrier), (barrier));
868 #endif // HAVE_PTHREAD_BARRIER_INIT
871 static __always_inline
872 int sem_init_intercept(sem_t *sem, int pshared, unsigned int value)
876 VALGRIND_GET_ORIG_FN(fn);
877 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_SEM_INIT,
878 sem, pshared, value, 0, 0);
879 CALL_FN_W_WWW(ret, fn, sem, pshared, value);
880 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_SEM_INIT,
885 PTH_FUNCS(int, semZuinit, sem_init_intercept,
886 (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
888 static __always_inline
889 int sem_destroy_intercept(sem_t *sem)
893 VALGRIND_GET_ORIG_FN(fn);
894 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_SEM_DESTROY,
896 CALL_FN_W_W(ret, fn, sem);
897 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_SEM_DESTROY,
902 PTH_FUNCS(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
904 static __always_inline
905 sem_t* sem_open_intercept(const char *name, int oflag, mode_t mode,
910 VALGRIND_GET_ORIG_FN(fn);
911 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_SEM_OPEN,
912 name, oflag, mode, value, 0);
913 CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value);
914 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_SEM_OPEN,
915 ret != SEM_FAILED ? ret : 0,
916 name, oflag, mode, value);
920 PTH_FUNCS(sem_t *, semZuopen, sem_open_intercept,
921 (const char *name, int oflag, mode_t mode, unsigned int value),
922 (name, oflag, mode, value));
924 static __always_inline int sem_close_intercept(sem_t *sem)
928 VALGRIND_GET_ORIG_FN(fn);
929 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_SEM_CLOSE,
931 CALL_FN_W_W(ret, fn, sem);
932 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_SEM_CLOSE,
937 PTH_FUNCS(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
939 static __always_inline int sem_wait_intercept(sem_t *sem)
943 VALGRIND_GET_ORIG_FN(fn);
944 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_SEM_WAIT,
946 CALL_FN_W_W(ret, fn, sem);
947 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_SEM_WAIT,
948 sem, ret == 0, 0, 0, 0);
952 PTH_FUNCS(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
954 static __always_inline int sem_trywait_intercept(sem_t *sem)
958 VALGRIND_GET_ORIG_FN(fn);
959 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_SEM_WAIT,
961 CALL_FN_W_W(ret, fn, sem);
962 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_SEM_WAIT,
963 sem, ret == 0, 0, 0, 0);
967 PTH_FUNCS(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
969 static __always_inline
970 int sem_timedwait_intercept(sem_t *sem, const struct timespec *abs_timeout)
974 VALGRIND_GET_ORIG_FN(fn);
975 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_SEM_WAIT,
977 CALL_FN_W_WW(ret, fn, sem, abs_timeout);
978 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_SEM_WAIT,
979 sem, ret == 0, 0, 0, 0);
983 PTH_FUNCS(int, semZutimedwait, sem_timedwait_intercept,
984 (sem_t *sem, const struct timespec *abs_timeout),
987 static __always_inline int sem_post_intercept(sem_t *sem)
991 VALGRIND_GET_ORIG_FN(fn);
992 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_SEM_POST,
994 CALL_FN_W_W(ret, fn, sem);
995 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_SEM_POST,
996 sem, ret == 0, 0, 0, 0);
1000 PTH_FUNCS(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
1002 static __always_inline
1003 int pthread_rwlock_init_intercept(pthread_rwlock_t* rwlock,
1004 const pthread_rwlockattr_t* attr)
1008 VALGRIND_GET_ORIG_FN(fn);
1009 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_RWLOCK_INIT,
1010 rwlock, 0, 0, 0, 0);
1011 CALL_FN_W_WW(ret, fn, rwlock, attr);
1016 pthreadZurwlockZuinit, pthread_rwlock_init_intercept,
1017 (pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr),
1020 static __always_inline
1021 int pthread_rwlock_destroy_intercept(pthread_rwlock_t* rwlock)
1025 VALGRIND_GET_ORIG_FN(fn);
1026 CALL_FN_W_W(ret, fn, rwlock);
1027 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_RWLOCK_DESTROY,
1028 rwlock, 0, 0, 0, 0);
1033 pthreadZurwlockZudestroy, pthread_rwlock_destroy_intercept,
1034 (pthread_rwlock_t* rwlock), (rwlock));
1036 static __always_inline
1037 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t* rwlock)
1041 VALGRIND_GET_ORIG_FN(fn);
1042 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_RWLOCK_RDLOCK,
1043 rwlock, 0, 0, 0, 0);
1044 CALL_FN_W_W(ret, fn, rwlock);
1045 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_RWLOCK_RDLOCK,
1046 rwlock, ret == 0, 0, 0, 0);
1051 pthreadZurwlockZurdlock, pthread_rwlock_rdlock_intercept,
1052 (pthread_rwlock_t* rwlock), (rwlock));
1054 static __always_inline
1055 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t* rwlock)
1059 VALGRIND_GET_ORIG_FN(fn);
1060 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_RWLOCK_WRLOCK,
1061 rwlock, 0, 0, 0, 0);
1062 CALL_FN_W_W(ret, fn, rwlock);
1063 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_RWLOCK_WRLOCK,
1064 rwlock, ret == 0, 0, 0, 0);
1069 pthreadZurwlockZuwrlock, pthread_rwlock_wrlock_intercept,
1070 (pthread_rwlock_t* rwlock), (rwlock));
1072 static __always_inline
1073 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t* rwlock)
1077 VALGRIND_GET_ORIG_FN(fn);
1078 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_RWLOCK_RDLOCK,
1079 rwlock, 0, 0, 0, 0);
1080 CALL_FN_W_W(ret, fn, rwlock);
1081 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_RWLOCK_RDLOCK,
1082 rwlock, ret == 0, 0, 0, 0);
1087 pthreadZurwlockZutimedrdlock, pthread_rwlock_timedrdlock_intercept,
1088 (pthread_rwlock_t* rwlock), (rwlock));
1090 static __always_inline
1091 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t* rwlock)
1095 VALGRIND_GET_ORIG_FN(fn);
1096 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_RWLOCK_WRLOCK,
1097 rwlock, 0, 0, 0, 0);
1098 CALL_FN_W_W(ret, fn, rwlock);
1099 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_RWLOCK_WRLOCK,
1100 rwlock, ret == 0, 0, 0, 0);
1105 pthreadZurwlockZutimedwrlock, pthread_rwlock_timedwrlock_intercept,
1106 (pthread_rwlock_t* rwlock), (rwlock));
1108 static __always_inline
1109 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t* rwlock)
1113 VALGRIND_GET_ORIG_FN(fn);
1114 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_RWLOCK_RDLOCK,
1115 rwlock, 0, 0, 0, 0);
1116 CALL_FN_W_W(ret, fn, rwlock);
1117 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_RWLOCK_RDLOCK,
1118 rwlock, ret == 0, 0, 0, 0);
1123 pthreadZurwlockZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1124 (pthread_rwlock_t* rwlock), (rwlock));
1126 static __always_inline
1127 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t* rwlock)
1131 VALGRIND_GET_ORIG_FN(fn);
1132 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_RWLOCK_WRLOCK,
1133 rwlock, 0, 0, 0, 0);
1134 CALL_FN_W_W(ret, fn, rwlock);
1135 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_RWLOCK_WRLOCK,
1136 rwlock, ret == 0, 0, 0, 0);
1141 pthreadZurwlockZutrywrlock, pthread_rwlock_trywrlock_intercept,
1142 (pthread_rwlock_t* rwlock), (rwlock));
1144 static __always_inline
1145 int pthread_rwlock_unlock_intercept(pthread_rwlock_t* rwlock)
1149 VALGRIND_GET_ORIG_FN(fn);
1150 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_RWLOCK_UNLOCK,
1151 rwlock, 0, 0, 0, 0);
1152 CALL_FN_W_W(ret, fn, rwlock);
1153 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_RWLOCK_UNLOCK,
1154 rwlock, ret == 0, 0, 0, 0);
1159 pthreadZurwlockZuunlock, pthread_rwlock_unlock_intercept,
1160 (pthread_rwlock_t* rwlock), (rwlock));