Don't include pub_tool_tooliface.h in priv_types_n_macros.h
[valgrind.git] / drd / drd_pthread_intercepts.c
bloba4000b467ce4abee9c91272a01de7a5fdc318fdc
1 /*--------------------------------------------------------------------*/
2 /*--- Client-space code for DRD. drd_pthread_intercepts.c ---*/
3 /*--------------------------------------------------------------------*/
5 /*
6 This file is part of DRD, a thread error detector.
8 Copyright (C) 2006-2020 Bart Van Assche <bvanassche@acm.org>.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2 of the
13 License, or (at your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, see <http://www.gnu.org/licenses/>.
23 The GNU General Public License is contained in the file COPYING.
26 /* ---------------------------------------------------------------------
27 ALL THE CODE IN THIS FILE RUNS ON THE SIMULATED CPU.
29 These functions are not called directly - they're the targets of code
30 redirection or load notifications (see pub_core_redir.h for info).
31 They're named weirdly so that the intercept code can find them when the
32 shared object is initially loaded.
34 Note that this filename has the "drd_" prefix because it can appear
35 in stack traces, and the "drd_" makes it a little clearer that it
36 originates from Valgrind.
37 ------------------------------------------------------------------ */
40 * Define _GNU_SOURCE to make sure that pthread_spinlock_t is available when
41 * compiling with older glibc versions (2.3 or before).
43 #ifndef _GNU_SOURCE
44 #define _GNU_SOURCE
45 #endif
47 #include <assert.h> /* assert() */
48 #include <errno.h>
49 #include <pthread.h> /* pthread_mutex_t */
50 #include <semaphore.h> /* sem_t */
51 #include <stdint.h> /* uintptr_t */
52 #include <stdio.h> /* fprintf() */
53 #include <stdlib.h> /* malloc(), free() */
54 #include <unistd.h> /* confstr() */
55 #include "config.h" /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP etc. */
56 #include "drd_basics.h" /* DRD_() */
57 #include "drd_clientreq.h"
58 #include "pub_tool_redir.h" /* VG_WRAP_FUNCTION_ZZ() */
60 #if defined(VGO_freebsd)
61 #include <dlfcn.h>
62 #endif
64 #if defined(VGO_solaris)
66 * Solaris usually provides pthread_* functions on top of Solaris threading
67 * and synchronization functions. Usually both need to be intercepted because
68 * pthread_* ones might not call the Solaris ones (see for example sem_wait()).
69 * Such approach is required to correctly report misuse of the POSIX threads
70 * API.
71 * Therefore DRD intercepts and instruments all such functions but due to
72 * DRD_(thread_enter_synchr)() and DRD_(thread_leave_synchr)() guards in
73 * handle_client_request(), only the top-most function is handled.
74 * So the right thing(TM) happens, as expected.
75 * The only exception is when pthread_* function is a weak alias to the Solaris
76 * threading/synchronization function. In such case only one needs to be
77 * intercepted to avoid redirection ambiguity.
79 * Intercepted functions rely on the fact that:
80 * - pthread_mutex_t == mutex_t
81 * - pthread_cond_t == cond_t
82 * - sem_t == sema_t
83 * - pthread_rwlock_t == rwlock_t
85 * It is necessary to intercept also internal libc synchronization functions
86 * for two reasons:
87 * - For read-write locks the unlocking function is shared
88 * - Functions lmutex_lock/lmutex_unlock guard many critical sections in libc
89 * which will be otherwise reported by DRD
91 #include <synch.h>
92 #include <thread.h>
93 #include "pub_tool_vki.h"
96 * Solaris provides higher throughput, parallelism and scalability than other
97 * operating systems, at the cost of more fine-grained locking activity.
98 * This means for example that when a thread is created under Linux, just one
99 * big lock in glibc is used for all thread setup. Solaris libc uses several
100 * fine-grained locks and the creator thread resumes its activities as soon
101 * as possible, leaving for example stack and TLS setup activities to the
102 * created thread.
104 * This situation confuses DRD as it assumes there is some false ordering
105 * in place between creator and created thread; and therefore many types of
106 * race conditions in the application would not be reported. To prevent such
107 * false ordering, command line option --ignore-thread-creation is set to
108 * 'yes' by default on Solaris. All activity (loads, stores, client requests)
109 * is therefore ignored during:
110 * - pthread_create() call in the creator thread [libc.so]
111 * - thread creation phase (stack and TLS setup) in the created thread [libc.so]
113 * As explained in the comments for _ti_bind_guard(), whenever the runtime
114 * linker has to perform any activity (such as resolving a symbol), it protects
115 * its data structures by calling into rt_bind_guard() which in turn invokes
116 * _ti_bind_guard() in libc. Pointers to _ti_bind_guard() and _ti_bind_clear()
117 * are passed from libc to runtime linker in _ld_libc() call during libc_init().
118 * All activity is also ignored during:
119 * - runtime dynamic linker work between rt_bind_guard() and rt_bind_clear()
120 * calls [ld.so]
122 * This also means that DRD does not report race conditions in libc (when
123 * --ignore-thread-creation=yes) and runtime linker itself (unconditionally)
124 * during these ignored sequences.
128 * Original function pointers for _ti_bind_guard() and _ti_bind_clear()
129 * from libc. They are intercepted in function wrapper of _ld_libc().
131 typedef int (*drd_rtld_guard_fn)(int flags);
132 static drd_rtld_guard_fn DRD_(rtld_bind_guard) = NULL;
133 static drd_rtld_guard_fn DRD_(rtld_bind_clear) = NULL;
134 #endif
138 * Notes regarding thread creation:
139 * - sg_init() runs on the context of the created thread and copies the vector
140 * clock of the creator thread. This only works reliably if the creator
141 * thread waits until this copy has been performed.
142 * - DRD_(thread_compute_minimum_vc)() does not take the vector clocks into
143 * account that are involved in thread creation and for which the
144 * corresponding thread has not yet been created. So not waiting until the
145 * created thread has been started would make it possible that segments get
146 * discarded that should not yet be discarded. Or: some data races are not
147 * detected.
151 * Macro for generating a Valgrind interception function.
152 * @param[in] ret_ty Return type of the function to be generated.
153 * @param[in] zf Z-encoded name of the interception function.
154 * @param[in] implf Name of the function that implements the intercept.
155 * @param[in] arg_decl Argument declaration list enclosed in parentheses.
156 * @param[in] argl Argument list enclosed in parentheses.
158 #if defined(VGO_darwin)
160 * Note here VGO_darwin is used rather than VG_WRAP_THREAD_FUNCTION_LIBPTHREAD_ONLY
161 * because of the special-case code adding a function call
163 static int never_true;
164 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
165 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
166 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
168 ret_ty pth_func_result = implf argl; \
169 /* Apparently inserting a function call in wrapper functions */ \
170 /* is sufficient to avoid misaligned stack errors. */ \
171 if (never_true) \
172 fflush(stdout); \
173 return pth_func_result; \
175 #elif defined(VG_WRAP_THREAD_FUNCTION_LIBPTHREAD_ONLY)
176 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
177 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
178 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
179 { return implf argl; }
180 #elif defined(VG_WRAP_THREAD_FUNCTION_LIBC_ONLY)
181 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
182 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl; \
183 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl \
184 { return implf argl; }
185 #elif defined(VG_WRAP_THREAD_FUNCTION_LIBC_AND_LIBPTHREAD)
186 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
187 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl; \
188 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl \
189 { return implf argl; } \
190 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
191 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
192 { return implf argl; }
193 #else
194 # error "Unknown platform/thread wrapping"
195 #endif
197 #if defined(VGO_freebsd)
198 #define LIBC_FUNC(ret_ty, zf, implf, argl_decl, argl) \
199 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl; \
200 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl \
201 { return implf argl; }
202 #endif
205 * Macro for generating three Valgrind interception functions: one with the
206 * Z-encoded name zf, one with ZAZa ("@*") appended to the name zf and one
207 * with ZDZa ("$*") appended to the name zf. The second generated interception
208 * function will intercept versioned symbols on Linux, and the third will
209 * intercept versioned symbols on Darwin.
211 #define PTH_FUNCS(ret_ty, zf, implf, argl_decl, argl) \
212 PTH_FUNC(ret_ty, zf, implf, argl_decl, argl); \
213 PTH_FUNC(ret_ty, zf ## ZAZa, implf, argl_decl, argl); \
214 PTH_FUNC(ret_ty, zf ## ZDZa, implf, argl_decl, argl);
217 * Not inlining one of the intercept functions will cause the regression
218 * tests to fail because this would cause an additional stackfram to appear
219 * in the output. The __always_inline macro guarantees that inlining will
220 * happen, even when compiling with optimization disabled.
222 #undef __always_inline /* since already defined in <cdefs.h> */
223 #if __GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 2
224 #define __always_inline __inline__ __attribute__((always_inline))
225 #else
226 #define __always_inline __inline__
227 #endif
229 /* Local data structures. */
231 typedef struct {
232 pthread_mutex_t mutex;
233 pthread_cond_t cond;
234 int counter;
235 } DrdSema;
237 typedef struct
239 void* (*start)(void*);
240 void* arg;
241 int detachstate;
242 DrdSema* wrapper_started;
243 } DrdPosixThreadArgs;
246 /* Local function declarations. */
248 static void DRD_(init)(void) __attribute__((constructor));
249 static void DRD_(check_threading_library)(void);
250 static void DRD_(set_pthread_id)(void);
251 static void DRD_(sema_init)(DrdSema* sema);
252 static void DRD_(sema_destroy)(DrdSema* sema);
253 static void DRD_(sema_down)(DrdSema* sema);
254 static void DRD_(sema_up)(DrdSema* sema);
257 /* Function definitions. */
260 * Shared library initialization function. The function init() is called after
261 * dlopen() has loaded the shared library with DRD client intercepts because
262 * the constructor attribute was specified in the declaration of this function.
263 * Note: do specify the -nostdlib option to gcc when linking this code into a
264 * shared library because doing so would cancel the effect of the constructor
265 * attribute ! Using the gcc option -nodefaultlibs is fine because this last
266 * option preserves the shared library initialization code that calls
267 * constructor and destructor functions.
269 static void DRD_(init)(void)
271 #if defined(VGO_freebsd)
274 * On FreeBSD, pthead functions are all in libthr.so
275 * However libc.so contains stubs. In this ctor function,
276 * calling DRD_(set_pthread_id)() results in a call to
277 * pthread_self() resolving to the libc.so stub which
278 * returns a junk value for the tid. Subsequent calls
279 * to pthread_create() then also cause calls to
280 * DRD_(set_pthread_id)(), but this time with pthread_self()
281 * resolving to the good libthr.so version (since this is later
282 * and libthr.so has been loaded). That causes an assert
283 * since we expect the tid to either be INVALID_POSIX_THREADID
284 * or the same as the current tid, and the junk value
285 * is neither. So we force loading of libthr.so, which
286 * avoids this junk tid value.
288 #if (FREEBSD_VERS >= FREEBSD_15)
289 void* libsys = dlopen("/lib/libsys.so.7", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
290 #endif
291 dlclose(dlopen("/lib/libthr.so.3", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE));
292 #if (FREEBSD_VERS >= FREEBSD_15)
293 if (libsys) {
294 dlclose(libsys);
296 #endif
298 #endif
300 DRD_(check_threading_library)();
301 DRD_(set_pthread_id)();
302 #if defined(VGO_solaris)
303 if ((DRD_(rtld_bind_guard) == NULL) || (DRD_(rtld_bind_clear) == NULL)) {
304 fprintf(stderr,
305 "Bind guard functions for the runtime linker (ld.so.1) were not intercepted.\n"
306 "This means the interface between libc and runtime linker changed and DRD\n"
307 "needs to be ported properly. Giving up.\n");
308 abort();
310 #endif
313 static __always_inline void DRD_(ignore_mutex_ordering)(pthread_mutex_t *mutex)
315 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_IGNORE_MUTEX_ORDERING,
316 mutex, 0, 0, 0, 0);
319 static void DRD_(sema_init)(DrdSema* sema)
321 DRD_IGNORE_VAR(*sema);
322 pthread_mutex_init(&sema->mutex, NULL);
323 DRD_(ignore_mutex_ordering)(&sema->mutex);
324 pthread_cond_init(&sema->cond, NULL);
325 sema->counter = 0;
328 static void DRD_(sema_destroy)(DrdSema* sema)
330 pthread_mutex_destroy(&sema->mutex);
331 pthread_cond_destroy(&sema->cond);
334 static void DRD_(sema_down)(DrdSema* sema)
336 pthread_mutex_lock(&sema->mutex);
337 while (sema->counter == 0)
338 pthread_cond_wait(&sema->cond, &sema->mutex);
339 sema->counter--;
340 pthread_mutex_unlock(&sema->mutex);
343 static void DRD_(sema_up)(DrdSema* sema)
345 pthread_mutex_lock(&sema->mutex);
346 sema->counter++;
347 pthread_cond_signal(&sema->cond);
348 pthread_mutex_unlock(&sema->mutex);
352 * POSIX threads and DRD each have their own mutex type identification.
353 * Convert POSIX threads' mutex type to DRD's mutex type. In the code below
354 * if-statements are used to test the value of 'kind' instead of a switch
355 * statement because some of the PTHREAD_MUTEX_ macro's may have the same
356 * value.
358 static MutexT DRD_(pthread_to_drd_mutex_type)(int kind)
361 * Static checkers don't like this as there are repeated branch
362 * but because there is variation between different platforms
363 * it's messy to make something without repetition.
365 * See also PTHREAD_MUTEX_KIND_MASK_NP in glibc source file
366 * <nptl/pthreadP.h>.
368 kind &= PTHREAD_MUTEX_RECURSIVE | PTHREAD_MUTEX_ERRORCHECK |
369 PTHREAD_MUTEX_NORMAL | PTHREAD_MUTEX_DEFAULT;
371 if (kind == PTHREAD_MUTEX_RECURSIVE) {
372 return mutex_type_recursive_mutex;
374 if (kind == PTHREAD_MUTEX_ERRORCHECK) {
375 return mutex_type_errorcheck_mutex;
377 if (kind == PTHREAD_MUTEX_NORMAL) {
378 return mutex_type_default_mutex;
380 if (kind == PTHREAD_MUTEX_DEFAULT) {
381 // On FreeBSD PTHREAD_MUTEX_DEFAULT is the same as PTHREAD_MUTEX_ERRORCHECK
382 // so this code is unreachable, but that's not true for all platforms
383 // so just ignore the warning
384 // coverity[DEADCODE:FALSE]
385 return mutex_type_default_mutex;
387 #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
388 if (kind == PTHREAD_MUTEX_ADAPTIVE_NP) {
389 return mutex_type_default_mutex;
391 #endif
392 return mutex_type_invalid_mutex;
395 #if defined(VGO_solaris)
397 * Solaris threads and DRD each have their own mutex type identification.
398 * Convert Solaris threads' mutex type to DRD's mutex type.
400 static MutexT DRD_(thread_to_drd_mutex_type)(int type)
402 if (type & LOCK_RECURSIVE) {
403 return mutex_type_recursive_mutex;
404 } else if (type & LOCK_ERRORCHECK) {
405 return mutex_type_errorcheck_mutex;
406 } else {
407 return mutex_type_default_mutex;
410 #endif /* VGO_solaris */
412 #define IS_ALIGNED(p) (((uintptr_t)(p) & (sizeof(*(p)) - 1)) == 0)
415 * Read the mutex type stored in the client memory used for the mutex
416 * implementation.
418 * @note This function depends on the implementation of the POSIX threads
419 * library -- the POSIX standard does not define the name of the member in
420 * which the mutex type is stored.
421 * @note The function mutex_type() has been declared inline in order
422 * to avoid that it shows up in call stacks (drd/tests/...exp* files).
423 * @note glibc stores the mutex type in the lowest two bits, and uses the
424 * higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
425 * PTHREAD_MUTEXATTR_FLAG_PSHARED.
427 static __always_inline MutexT DRD_(mutex_type)(pthread_mutex_t* mutex)
429 MutexT mutex_type = mutex_type_unknown;
431 ANNOTATE_IGNORE_READS_BEGIN();
432 #if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
433 /* glibc + LinuxThreads. */
434 if (IS_ALIGNED(&mutex->__m_kind))
436 const int kind = mutex->__m_kind & 3;
437 mutex_type = DRD_(pthread_to_drd_mutex_type)(kind);
439 #elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
440 /* glibc + NPTL. */
441 if (IS_ALIGNED(&mutex->__data.__kind))
443 const int kind = mutex->__data.__kind & 3;
444 mutex_type = DRD_(pthread_to_drd_mutex_type)(kind);
446 #elif defined(VGO_solaris)
448 const int type = ((mutex_t *) mutex)->vki_mutex_type;
449 mutex_type = DRD_(thread_to_drd_mutex_type)(type);
451 #else
453 * Another POSIX threads implementation. The mutex type won't be printed
454 * when enabling --trace-mutex=yes.
456 #endif
457 ANNOTATE_IGNORE_READS_END();
459 return mutex_type;
463 * Tell DRD whether 'tid' is a joinable thread or a detached thread.
465 static void DRD_(set_joinable)(const pthread_t tid, const int joinable)
467 assert(joinable == 0 || joinable == 1);
468 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_SET_JOINABLE,
469 tid, joinable, 0, 0, 0);
472 /** Tell DRD that the calling thread is about to enter pthread_create(). */
473 static __always_inline void DRD_(entering_pthread_create)(void)
475 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_ENTERING_PTHREAD_CREATE,
476 0, 0, 0, 0, 0);
479 /** Tell DRD that the calling thread has left pthread_create(). */
480 static __always_inline void DRD_(left_pthread_create)(void)
482 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_LEFT_PTHREAD_CREATE,
483 0, 0, 0, 0, 0);
487 * Entry point for newly created threads. This function is called from the
488 * thread created by pthread_create().
490 static void* DRD_(thread_wrapper)(void* arg)
492 DrdPosixThreadArgs* arg_ptr;
493 DrdPosixThreadArgs arg_copy;
495 arg_ptr = (DrdPosixThreadArgs*)arg;
496 arg_copy = *arg_ptr;
498 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_SET_PTHREADID,
499 pthread_self(), 0, 0, 0, 0);
501 DRD_(set_joinable)(pthread_self(),
502 arg_copy.detachstate == PTHREAD_CREATE_JOINABLE);
505 * Only set 'wrapper_started' after VG_USERREQ__SET_PTHREADID and
506 * DRD_(set_joinable)() have been invoked to avoid a race with
507 * a pthread_detach() invocation for this thread from another thread.
509 DRD_(sema_up)(arg_copy.wrapper_started);
511 return (arg_copy.start)(arg_copy.arg);
515 * Return 1 if the LinuxThreads implementation of POSIX Threads has been
516 * detected, and 0 otherwise.
518 * @see For more information about the confstr() function, see also
519 * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
521 static int DRD_(detected_linuxthreads)(void)
523 #if defined(linux)
524 #if defined(_CS_GNU_LIBPTHREAD_VERSION)
525 /* Linux with a recent glibc. */
526 HChar buffer[256];
527 unsigned len;
528 len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
529 assert(len <= sizeof(buffer));
530 return len > 0 && buffer[0] == 'l';
531 #else
532 /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
533 return 1;
534 #endif
535 #else
536 /* Another OS than Linux, hence no LinuxThreads. */
537 return 0;
538 #endif
542 * Stop and print an error message in case a non-supported threading
543 * library implementation (LinuxThreads) has been detected.
545 static void DRD_(check_threading_library)(void)
547 if (DRD_(detected_linuxthreads)())
549 if (getenv("LD_ASSUME_KERNEL"))
551 fprintf(stderr,
552 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
553 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
554 "after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
557 else
559 fprintf(stderr,
560 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
561 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
562 "after having upgraded to a newer version of your Linux distribution.\n"
563 "Giving up.\n"
566 abort();
571 * Update DRD's state information about the current thread.
573 static void DRD_(set_pthread_id)(void)
575 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_SET_PTHREADID,
576 pthread_self(), 0, 0, 0, 0);
580 * Note: as of today there exist three different versions of pthread_create
581 * in Linux:
582 * - pthread_create@GLIBC_2.0
583 * - pthread_create@@GLIBC_2.1
584 * - pthread_create@@GLIBC_2.2.5
585 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
586 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
587 * versions have been implemented. In any glibc version where more than one
588 * pthread_create function has been implemented, older versions call the
589 * newer versions. Or: the pthread_create* wrapper defined below can be
590 * called recursively. Any code in this wrapper should take this in account.
591 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
592 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
593 * See also the implementation of pthread_create@GLIBC_2.0 in
594 * glibc-2.9/nptl/pthread_create.c.
597 static __always_inline
598 int pthread_create_intercept(pthread_t* thread, const pthread_attr_t* attr,
599 void* (*start)(void*), void* arg)
601 int ret;
602 OrigFn fn;
603 DrdSema wrapper_started;
604 DrdPosixThreadArgs thread_args;
606 VALGRIND_GET_ORIG_FN(fn);
608 DRD_(sema_init)(&wrapper_started);
609 thread_args.start = start;
610 thread_args.arg = arg;
611 thread_args.wrapper_started = &wrapper_started;
613 * Find out whether the thread will be started as a joinable thread
614 * or as a detached thread. If no thread attributes have been specified,
615 * this means that the new thread will be started as a joinable thread.
617 thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
618 /* The C11 thrd_create() implementation passes -1 as 'attr' argument. */
619 if (attr && (uintptr_t)attr + 1 != 0)
621 if (pthread_attr_getdetachstate(attr, &thread_args.detachstate) != 0)
622 assert(0);
624 assert(thread_args.detachstate == PTHREAD_CREATE_JOINABLE
625 || thread_args.detachstate == PTHREAD_CREATE_DETACHED);
628 * The DRD_(set_pthread_id)() from DRD_(init)() may encounter that
629 * pthread_self() == 0, e.g. when the main program is not linked with the
630 * pthread library and when a pthread_create() call occurs from within a
631 * shared library. Hence call DRD_(set_pthread_id)() again to ensure that
632 * DRD knows the identity of the current thread. See also B.Z. 356374.
634 DRD_(set_pthread_id)();
635 DRD_(entering_pthread_create)();
636 CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), &thread_args);
637 DRD_(left_pthread_create)();
639 if (ret == 0) {
640 /* Wait until the thread wrapper started. */
641 DRD_(sema_down)(&wrapper_started);
644 DRD_(sema_destroy)(&wrapper_started);
646 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_START_NEW_SEGMENT,
647 pthread_self(), 0, 0, 0, 0);
649 return ret;
652 PTH_FUNCS(int, pthreadZucreate, pthread_create_intercept,
653 (pthread_t *thread, const pthread_attr_t *attr,
654 void *(*start) (void *), void *arg),
655 (thread, attr, start, arg));
657 #if defined(VGO_solaris)
658 /* Solaris also provides thr_create() in addition to pthread_create().
659 * Both pthread_create(3C) and thr_create(3C) are based on private
660 * _thrp_create().
662 static __always_inline
663 int thr_create_intercept(void *stk, size_t stksize, void *(*start)(void *),
664 void *arg, long flags, thread_t *new_thread)
666 int ret;
667 OrigFn fn;
668 DrdSema wrapper_started;
669 DrdPosixThreadArgs thread_args;
671 VALGRIND_GET_ORIG_FN(fn);
673 DRD_(sema_init)(&wrapper_started);
674 thread_args.start = start;
675 thread_args.arg = arg;
676 thread_args.wrapper_started = &wrapper_started;
678 * Find out whether the thread will be started as a joinable thread
679 * or as a detached thread.
681 if (flags & THR_DETACHED)
682 thread_args.detachstate = PTHREAD_CREATE_DETACHED;
683 else
684 thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
686 DRD_(entering_pthread_create)();
687 CALL_FN_W_6W(ret, fn, stk, stksize, DRD_(thread_wrapper), &thread_args,
688 flags, new_thread);
689 DRD_(left_pthread_create)();
691 if (ret == 0) {
692 /* Wait until the thread wrapper started. */
693 DRD_(sema_down)(&wrapper_started);
696 DRD_(sema_destroy)(&wrapper_started);
698 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_START_NEW_SEGMENT,
699 pthread_self(), 0, 0, 0, 0);
701 return ret;
704 PTH_FUNCS(int, thrZucreate, thr_create_intercept,
705 (void *stk, size_t stksize, void *(*start)(void *), void *arg,
706 long flags, thread_t *new_thread),
707 (stk, stksize, start, arg, flags, new_thread));
708 #endif /* VGO_solaris */
710 #if defined(VGO_solaris)
712 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
713 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
714 * and CI_BIND_CLEAR, to provide resilience against function renaming.
716 static __always_inline
717 int DRD_(_ti_bind_guard_intercept)(int flags) {
718 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_RTLD_BIND_GUARD,
719 flags, 0, 0, 0, 0);
720 return DRD_(rtld_bind_guard)(flags);
723 static __always_inline
724 int DRD_(_ti_bind_clear_intercept)(int flags) {
725 int ret = DRD_(rtld_bind_clear)(flags);
726 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_RTLD_BIND_CLEAR,
727 flags, 0, 0, 0, 0);
728 return ret;
732 * Wrapped _ld_libc() from the runtime linker ld.so.1.
734 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr);
735 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr)
737 OrigFn fn;
738 int tag;
740 VALGRIND_GET_ORIG_FN(fn);
742 vki_Lc_interface *funcs = ptr;
743 for (tag = funcs->ci_tag; tag != 0; tag = (++funcs)->ci_tag) {
744 switch (tag) {
745 case VKI_CI_BIND_GUARD:
746 if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_guard_intercept)) {
747 DRD_(rtld_bind_guard) = funcs->vki_ci_un.ci_func;
748 funcs->vki_ci_un.ci_func = DRD_(_ti_bind_guard_intercept);
750 break;
751 case VKI_CI_BIND_CLEAR:
752 if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_clear_intercept)) {
753 DRD_(rtld_bind_clear) = funcs->vki_ci_un.ci_func;
754 funcs->vki_ci_un.ci_func = DRD_(_ti_bind_clear_intercept);
756 break;
760 CALL_FN_v_W(fn, ptr);
762 #endif /* VGO_solaris */
764 static __always_inline
765 int pthread_join_intercept(pthread_t pt_joinee, void **thread_return)
767 int ret;
768 OrigFn fn;
770 VALGRIND_GET_ORIG_FN(fn);
772 * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
773 * implementation triggers a (false positive) race report.
775 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
776 CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
777 if (ret == 0)
779 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_THREAD_JOIN,
780 pt_joinee, 0, 0, 0, 0);
782 ANNOTATE_IGNORE_READS_AND_WRITES_END();
783 return ret;
786 PTH_FUNCS(int, pthreadZujoin, pthread_join_intercept,
787 (pthread_t pt_joinee, void **thread_return),
788 (pt_joinee, thread_return));
790 #if defined(VGO_solaris)
791 /* Solaris also provides thr_join() in addition to pthread_join().
792 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
794 * :TODO: No functionality is currently provided for joinee == 0 and departed.
795 * This would require another client request, of course.
797 static __always_inline
798 int thr_join_intercept(thread_t joinee, thread_t *departed, void **thread_return)
800 int ret;
801 OrigFn fn;
803 VALGRIND_GET_ORIG_FN(fn);
804 CALL_FN_W_WWW(ret, fn, joinee, departed, thread_return);
805 if (ret == 0)
807 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_THREAD_JOIN,
808 joinee, 0, 0, 0, 0);
810 return ret;
813 PTH_FUNCS(int, thrZujoin, thr_join_intercept,
814 (thread_t joinee, thread_t *departed, void **thread_return),
815 (joinee, departed, thread_return));
816 #endif /* VGO_solaris */
818 static __always_inline
819 int pthread_detach_intercept(pthread_t pt_thread)
821 int ret;
822 OrigFn fn;
824 VALGRIND_GET_ORIG_FN(fn);
825 CALL_FN_W_W(ret, fn, pt_thread);
826 DRD_(set_joinable)(pt_thread, 0);
828 return ret;
831 PTH_FUNCS(int, pthreadZudetach, pthread_detach_intercept,
832 (pthread_t thread), (thread));
834 // NOTE: be careful to intercept only pthread_cancel() and not
835 // pthread_cancel_init() on Linux.
837 static __always_inline
838 int pthread_cancel_intercept(pthread_t pt_thread)
840 int ret;
841 OrigFn fn;
842 VALGRIND_GET_ORIG_FN(fn);
843 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_THREAD_CANCEL,
844 pt_thread, 0, 0, 0, 0);
845 CALL_FN_W_W(ret, fn, pt_thread);
846 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_THREAD_CANCEL,
847 pt_thread, ret==0, 0, 0, 0);
848 return ret;
851 PTH_FUNCS(int, pthreadZucancel, pthread_cancel_intercept,
852 (pthread_t thread), (thread))
854 static __always_inline
855 int pthread_once_intercept(pthread_once_t *once_control,
856 void (*init_routine)(void))
858 int ret;
859 OrigFn fn;
860 VALGRIND_GET_ORIG_FN(fn);
862 * Ignore any data races triggered by the implementation of pthread_once().
863 * Necessary for Darwin. This is not necessary for Linux but doesn't have
864 * any known adverse effects.
866 DRD_IGNORE_VAR(*once_control);
867 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
868 CALL_FN_W_WW(ret, fn, once_control, init_routine);
869 ANNOTATE_IGNORE_READS_AND_WRITES_END();
870 DRD_STOP_IGNORING_VAR(*once_control);
871 return ret;
874 PTH_FUNCS(int, pthreadZuonce, pthread_once_intercept,
875 (pthread_once_t *once_control, void (*init_routine)(void)),
876 (once_control, init_routine));
878 static __always_inline
879 int pthread_mutex_init_intercept(pthread_mutex_t *mutex,
880 const pthread_mutexattr_t* attr)
882 int ret;
883 OrigFn fn;
884 int mt;
885 VALGRIND_GET_ORIG_FN(fn);
886 mt = PTHREAD_MUTEX_DEFAULT;
887 if (attr)
888 pthread_mutexattr_gettype(attr, &mt);
889 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_INIT,
890 mutex, DRD_(pthread_to_drd_mutex_type)(mt),
891 0, 0, 0);
892 CALL_FN_W_WW(ret, fn, mutex, attr);
893 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_INIT,
894 mutex, 0, 0, 0, 0);
895 return ret;
898 PTH_FUNCS(int, pthreadZumutexZuinit, pthread_mutex_init_intercept,
899 (pthread_mutex_t *mutex, const pthread_mutexattr_t* attr),
900 (mutex, attr));
902 #if defined(VGO_solaris)
903 static __always_inline
904 int mutex_init_intercept(mutex_t *mutex, int type, void *arg)
906 int ret;
907 OrigFn fn;
908 VALGRIND_GET_ORIG_FN(fn);
910 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_INIT,
911 mutex, DRD_(thread_to_drd_mutex_type)(type),
912 0, 0, 0);
913 CALL_FN_W_WWW(ret, fn, mutex, type, arg);
914 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_INIT,
915 mutex, 0, 0, 0, 0);
916 return ret;
919 PTH_FUNCS(int, mutexZuinit, mutex_init_intercept,
920 (mutex_t *mutex, int type, void *arg),
921 (mutex, type, arg));
922 #endif /* VGO_solaris */
924 static __always_inline
925 int pthread_mutex_destroy_intercept(pthread_mutex_t* mutex)
927 int ret;
928 OrigFn fn;
929 VALGRIND_GET_ORIG_FN(fn);
930 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_DESTROY,
931 mutex, 0, 0, 0, 0);
932 CALL_FN_W_W(ret, fn, mutex);
933 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_DESTROY,
934 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
935 return ret;
938 #if defined(VGO_solaris)
939 /* On Solaris, pthread_mutex_destroy is a weak alias to mutex_destroy. */
940 PTH_FUNCS(int, mutexZudestroy, pthread_mutex_destroy_intercept,
941 (pthread_mutex_t *mutex), (mutex));
942 #else
943 PTH_FUNCS(int, pthreadZumutexZudestroy, pthread_mutex_destroy_intercept,
944 (pthread_mutex_t *mutex), (mutex));
945 #endif /* VGO_solaris */
947 static __always_inline
948 int pthread_mutex_lock_intercept(pthread_mutex_t* mutex)
950 int ret;
951 OrigFn fn;
952 VALGRIND_GET_ORIG_FN(fn);
953 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK,
954 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
955 CALL_FN_W_W(ret, fn, mutex);
956 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK,
957 mutex, ret == 0, 0, 0, 0);
958 return ret;
961 #if defined(VGO_solaris)
962 /* On Solaris, pthread_mutex_lock is a weak alias to mutex_lock. */
963 PTH_FUNCS(int, mutexZulock, pthread_mutex_lock_intercept,
964 (pthread_mutex_t *mutex), (mutex));
965 #else
966 PTH_FUNCS(int, pthreadZumutexZulock, pthread_mutex_lock_intercept,
967 (pthread_mutex_t *mutex), (mutex));
968 #endif /* VGO_solaris */
970 #if defined(VGO_solaris)
971 /* Internal to libc. Mutex is usually initialized only implicitly,
972 * by zeroing mutex_t structure.
974 static __always_inline
975 void lmutex_lock_intercept(mutex_t *mutex)
977 OrigFn fn;
978 VALGRIND_GET_ORIG_FN(fn);
979 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK,
980 mutex,
981 DRD_(mutex_type)((pthread_mutex_t *) mutex),
982 False /* try_lock */, 0, 0);
983 CALL_FN_v_W(fn, mutex);
984 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK,
985 mutex, True /* took_lock */, 0, 0, 0);
988 PTH_FUNCS(void, lmutexZulock, lmutex_lock_intercept,
989 (mutex_t *mutex), (mutex));
990 #endif /* VGO_solaris */
992 static __always_inline
993 int pthread_mutex_trylock_intercept(pthread_mutex_t* mutex)
995 int ret;
996 OrigFn fn;
997 VALGRIND_GET_ORIG_FN(fn);
998 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK,
999 mutex, DRD_(mutex_type)(mutex), 1, 0, 0);
1000 CALL_FN_W_W(ret, fn, mutex);
1001 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK,
1002 mutex, ret == 0, 0, 0, 0);
1003 return ret;
1006 #if defined(VGO_solaris)
1007 /* On Solaris, pthread_mutex_trylock is a weak alias to mutex_trylock. */
1008 PTH_FUNCS(int, mutexZutrylock, pthread_mutex_trylock_intercept,
1009 (pthread_mutex_t *mutex), (mutex));
1010 #else
1011 PTH_FUNCS(int, pthreadZumutexZutrylock, pthread_mutex_trylock_intercept,
1012 (pthread_mutex_t *mutex), (mutex));
1013 #endif /* VGO_solaris */
1015 static __always_inline
1016 int pthread_mutex_timedlock_intercept(pthread_mutex_t *mutex,
1017 const struct timespec *abs_timeout)
1019 int ret;
1020 OrigFn fn;
1021 VALGRIND_GET_ORIG_FN(fn);
1022 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK,
1023 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
1024 CALL_FN_W_WW(ret, fn, mutex, abs_timeout);
1025 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK,
1026 mutex, ret == 0, 0, 0, 0);
1027 return ret;
1030 PTH_FUNCS(int, pthreadZumutexZutimedlock, pthread_mutex_timedlock_intercept,
1031 (pthread_mutex_t *mutex, const struct timespec *abs_timeout),
1032 (mutex, abs_timeout));
1033 #if defined(VGO_solaris)
1034 PTH_FUNCS(int,
1035 pthreadZumutexZureltimedlockZunp, pthread_mutex_timedlock_intercept,
1036 (pthread_mutex_t *mutex, const struct timespec *timeout),
1037 (mutex, timeout));
1038 #endif /* VGO_solaris */
1040 #if defined(HAVE_CLOCKID_T)
1041 static __always_inline
1042 int pthread_mutex_clocklock_intercept(pthread_mutex_t *mutex,
1043 clockid_t clockid,
1044 const struct timespec *abs_timeout)
1046 int ret;
1047 OrigFn fn;
1048 VALGRIND_GET_ORIG_FN(fn);
1049 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK,
1050 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
1051 CALL_FN_W_WWW(ret, fn, mutex, clockid, abs_timeout);
1052 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK,
1053 mutex, ret == 0, 0, 0, 0);
1054 return ret;
1057 PTH_FUNCS(int, pthreadZumutexZuclocklock, pthread_mutex_clocklock_intercept,
1058 (pthread_mutex_t *mutex, clockid_t clockid, const struct timespec *abs_timeout),
1059 (mutex, clockid, abs_timeout));
1060 #endif
1062 static __always_inline
1063 int pthread_mutex_unlock_intercept(pthread_mutex_t *mutex)
1065 int ret;
1066 OrigFn fn;
1067 VALGRIND_GET_ORIG_FN(fn);
1068 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_UNLOCK,
1069 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
1070 CALL_FN_W_W(ret, fn, mutex);
1071 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_UNLOCK,
1072 mutex, 0, 0, 0, 0);
1073 return ret;
1076 #if defined(VGO_solaris)
1077 /* On Solaris, pthread_mutex_unlock is a weak alias to mutex_unlock. */
1078 PTH_FUNCS(int, mutexZuunlock, pthread_mutex_unlock_intercept,
1079 (pthread_mutex_t *mutex), (mutex));
1080 #else
1081 PTH_FUNCS(int, pthreadZumutexZuunlock, pthread_mutex_unlock_intercept,
1082 (pthread_mutex_t *mutex), (mutex));
1083 #endif /* VGO_solaris */
1085 #if defined(VGO_solaris)
1086 /* Internal to libc. */
1087 static __always_inline
1088 void lmutex_unlock_intercept(mutex_t *mutex)
1090 OrigFn fn;
1091 VALGRIND_GET_ORIG_FN(fn);
1092 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_UNLOCK,
1093 mutex,
1094 DRD_(mutex_type)((pthread_mutex_t *) mutex),
1095 0, 0, 0);
1096 CALL_FN_v_W(fn, mutex);
1097 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_UNLOCK,
1098 mutex, 0, 0, 0, 0);
1101 PTH_FUNCS(void, lmutexZuunlock, lmutex_unlock_intercept,
1102 (mutex_t *mutex), (mutex));
1103 #endif /* VGO_solaris */
1105 static __always_inline
1106 int pthread_cond_init_intercept(pthread_cond_t* cond,
1107 const pthread_condattr_t* attr)
1109 int ret;
1110 OrigFn fn;
1111 VALGRIND_GET_ORIG_FN(fn);
1112 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_INIT,
1113 cond, 0, 0, 0, 0);
1114 CALL_FN_W_WW(ret, fn, cond, attr);
1115 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_INIT,
1116 cond, 0, 0, 0, 0);
1117 return ret;
1120 PTH_FUNCS(int, pthreadZucondZuinit, pthread_cond_init_intercept,
1121 (pthread_cond_t* cond, const pthread_condattr_t* attr),
1122 (cond, attr));
1124 #if defined(VGO_solaris)
1125 static __always_inline
1126 int cond_init_intercept(cond_t *cond, int type, void *arg)
1128 int ret;
1129 OrigFn fn;
1130 VALGRIND_GET_ORIG_FN(fn);
1131 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_INIT,
1132 cond, 0, 0, 0, 0);
1133 CALL_FN_W_WWW(ret, fn, cond, type, arg);
1134 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_INIT,
1135 cond, 0, 0, 0, 0);
1136 return ret;
1139 PTH_FUNCS(int, condZuinit, cond_init_intercept,
1140 (cond_t *cond, int type, void *arg),
1141 (cond, type, arg));
1142 #endif /* VGO_solaris */
1144 static __always_inline
1145 int pthread_cond_destroy_intercept(pthread_cond_t* cond)
1147 int ret;
1148 OrigFn fn;
1149 VALGRIND_GET_ORIG_FN(fn);
1150 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_DESTROY,
1151 cond, 0, 0, 0, 0);
1152 CALL_FN_W_W(ret, fn, cond);
1153 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_DESTROY,
1154 cond, ret==0, 0, 0, 0);
1155 return ret;
1158 #if defined(VGO_solaris)
1159 /* On Solaris, pthread_cond_destroy is a weak alias to cond_destroy. */
1160 PTH_FUNCS(int, condZudestroy, pthread_cond_destroy_intercept,
1161 (pthread_cond_t *cond), (cond));
1162 #else
1163 PTH_FUNCS(int, pthreadZucondZudestroy, pthread_cond_destroy_intercept,
1164 (pthread_cond_t* cond), (cond));
1165 #endif /* VGO_solaris */
1167 static __always_inline
1168 int pthread_cond_wait_intercept(pthread_cond_t *cond, pthread_mutex_t *mutex)
1170 int ret;
1171 OrigFn fn;
1172 VALGRIND_GET_ORIG_FN(fn);
1173 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_WAIT,
1174 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1175 CALL_FN_W_WW(ret, fn, cond, mutex);
1176 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_WAIT,
1177 cond, mutex, 1, 0, 0);
1178 return ret;
1181 PTH_FUNCS(int, pthreadZucondZuwait, pthread_cond_wait_intercept,
1182 (pthread_cond_t *cond, pthread_mutex_t *mutex),
1183 (cond, mutex));
1184 #if defined(VGO_solaris)
1185 PTH_FUNCS(int, condZuwait, pthread_cond_wait_intercept,
1186 (pthread_cond_t *cond, pthread_mutex_t *mutex),
1187 (cond, mutex));
1188 #endif /* VGO_solaris */
1190 static __always_inline
1191 int pthread_cond_timedwait_intercept(pthread_cond_t *cond,
1192 pthread_mutex_t *mutex,
1193 const struct timespec* abstime)
1195 int ret;
1196 OrigFn fn;
1197 VALGRIND_GET_ORIG_FN(fn);
1198 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_WAIT,
1199 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1200 CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
1201 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_WAIT,
1202 cond, mutex, 1, 0, 0);
1203 return ret;
1206 PTH_FUNCS(int, pthreadZucondZutimedwait, pthread_cond_timedwait_intercept,
1207 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1208 const struct timespec* abstime),
1209 (cond, mutex, abstime));
1210 #if defined(VGO_solaris)
1211 PTH_FUNCS(int, condZutimedwait, pthread_cond_timedwait_intercept,
1212 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1213 const struct timespec *timeout),
1214 (cond, mutex, timeout));
1215 PTH_FUNCS(int, condZureltimedwait, pthread_cond_timedwait_intercept,
1216 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1217 const struct timespec *timeout),
1218 (cond, mutex, timeout));
1219 #endif /* VGO_solaris */
1222 #if defined(HAVE_CLOCKID_T)
1223 static __always_inline
1224 int pthread_cond_clockwait_intercept(pthread_cond_t *cond,
1225 pthread_mutex_t *mutex,
1226 clockid_t clockid,
1227 const struct timespec* abstime)
1229 int ret;
1230 OrigFn fn;
1231 VALGRIND_GET_ORIG_FN(fn);
1232 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_WAIT,
1233 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1234 CALL_FN_W_WWWW(ret, fn, cond, mutex, clockid, abstime);
1235 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_WAIT,
1236 cond, mutex, 1, 0, 0);
1237 return ret;
1240 PTH_FUNCS(int, pthreadZucondZuclockwait, pthread_cond_clockwait_intercept,
1241 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1242 clockid_t clockid, const struct timespec* abstime),
1243 (cond, mutex, clockid, abstime));
1244 #endif
1247 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
1248 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
1249 // two. Intercepting all pthread_cond_signal* functions will cause only one
1250 // argument to be passed to pthread_cond_signal_np() and hence will cause this
1251 // last function to crash.
1253 static __always_inline
1254 int pthread_cond_signal_intercept(pthread_cond_t* cond)
1256 int ret;
1257 OrigFn fn;
1258 VALGRIND_GET_ORIG_FN(fn);
1259 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_SIGNAL,
1260 cond, 0, 0, 0, 0);
1261 CALL_FN_W_W(ret, fn, cond);
1262 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_SIGNAL,
1263 cond, 0, 0, 0, 0);
1264 return ret;
1267 #if defined(VGO_solaris)
1268 /* On Solaris, pthread_cond_signal is a weak alias to cond_signal. */
1269 PTH_FUNCS(int, condZusignal, pthread_cond_signal_intercept,
1270 (pthread_cond_t *cond), (cond));
1271 #else
1272 PTH_FUNCS(int, pthreadZucondZusignal, pthread_cond_signal_intercept,
1273 (pthread_cond_t* cond), (cond));
1274 #endif /* VGO_solaris */
1276 static __always_inline
1277 int pthread_cond_broadcast_intercept(pthread_cond_t* cond)
1279 int ret;
1280 OrigFn fn;
1281 VALGRIND_GET_ORIG_FN(fn);
1282 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_BROADCAST,
1283 cond, 0, 0, 0, 0);
1284 CALL_FN_W_W(ret, fn, cond);
1285 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_BROADCAST,
1286 cond, 0, 0, 0, 0);
1287 return ret;
1290 #if defined(VGO_solaris)
1291 /* On Solaris, pthread_cond_broadcast is a weak alias to cond_broadcast. */
1292 PTH_FUNCS(int, condZubroadcast, pthread_cond_broadcast_intercept,
1293 (pthread_cond_t *cond), (cond));
1294 #else
1295 PTH_FUNCS(int, pthreadZucondZubroadcast, pthread_cond_broadcast_intercept,
1296 (pthread_cond_t* cond), (cond));
1297 #endif /* VGO_solaris */
1299 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1300 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1301 static __always_inline
1302 int pthread_spin_init_intercept(pthread_spinlock_t *spinlock, int pshared)
1304 int ret;
1305 OrigFn fn;
1306 VALGRIND_GET_ORIG_FN(fn);
1307 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SPIN_INIT_OR_UNLOCK,
1308 spinlock, 0, 0, 0, 0);
1309 CALL_FN_W_WW(ret, fn, spinlock, pshared);
1310 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SPIN_INIT_OR_UNLOCK,
1311 spinlock, 0, 0, 0, 0);
1312 return ret;
1315 PTH_FUNCS(int, pthreadZuspinZuinit, pthread_spin_init_intercept,
1316 (pthread_spinlock_t *spinlock, int pshared), (spinlock, pshared));
1318 static __always_inline
1319 int pthread_spin_destroy_intercept(pthread_spinlock_t *spinlock)
1321 int ret;
1322 OrigFn fn;
1323 VALGRIND_GET_ORIG_FN(fn);
1324 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_DESTROY,
1325 spinlock, 0, 0, 0, 0);
1326 CALL_FN_W_W(ret, fn, spinlock);
1327 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_DESTROY,
1328 spinlock, mutex_type_spinlock, 0, 0, 0);
1329 return ret;
1332 PTH_FUNCS(int, pthreadZuspinZudestroy, pthread_spin_destroy_intercept,
1333 (pthread_spinlock_t *spinlock), (spinlock));
1335 static __always_inline
1336 int pthread_spin_lock_intercept(pthread_spinlock_t *spinlock)
1338 int ret;
1339 OrigFn fn;
1340 VALGRIND_GET_ORIG_FN(fn);
1341 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK,
1342 spinlock, mutex_type_spinlock, 0, 0, 0);
1343 CALL_FN_W_W(ret, fn, spinlock);
1344 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK,
1345 spinlock, ret == 0, 0, 0, 0);
1346 return ret;
1349 PTH_FUNCS(int, pthreadZuspinZulock, pthread_spin_lock_intercept,
1350 (pthread_spinlock_t *spinlock), (spinlock));
1352 static __always_inline
1353 int pthread_spin_trylock_intercept(pthread_spinlock_t *spinlock)
1355 int ret;
1356 OrigFn fn;
1357 VALGRIND_GET_ORIG_FN(fn);
1358 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK,
1359 spinlock, mutex_type_spinlock, 0, 0, 0);
1360 CALL_FN_W_W(ret, fn, spinlock);
1361 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK,
1362 spinlock, ret == 0, 0, 0, 0);
1363 return ret;
1366 PTH_FUNCS(int, pthreadZuspinZutrylock, pthread_spin_trylock_intercept,
1367 (pthread_spinlock_t *spinlock), (spinlock));
1369 static __always_inline
1370 int pthread_spin_unlock_intercept(pthread_spinlock_t *spinlock)
1372 int ret;
1373 OrigFn fn;
1374 VALGRIND_GET_ORIG_FN(fn);
1375 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SPIN_INIT_OR_UNLOCK,
1376 spinlock, mutex_type_spinlock, 0, 0, 0);
1377 CALL_FN_W_W(ret, fn, spinlock);
1378 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SPIN_INIT_OR_UNLOCK,
1379 spinlock, 0, 0, 0, 0);
1380 return ret;
1383 PTH_FUNCS(int, pthreadZuspinZuunlock, pthread_spin_unlock_intercept,
1384 (pthread_spinlock_t *spinlock), (spinlock));
1385 #endif // HAVE_PTHREAD_SPIN_LOCK
1388 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1389 static __always_inline
1390 int pthread_barrier_init_intercept(pthread_barrier_t* barrier,
1391 const pthread_barrierattr_t* attr,
1392 unsigned count)
1394 int ret;
1395 OrigFn fn;
1396 VALGRIND_GET_ORIG_FN(fn);
1397 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_BARRIER_INIT,
1398 barrier, pthread_barrier, count, 0, 0);
1399 CALL_FN_W_WWW(ret, fn, barrier, attr, count);
1400 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_BARRIER_INIT,
1401 barrier, pthread_barrier, 0, 0, 0);
1402 return ret;
1405 PTH_FUNCS(int, pthreadZubarrierZuinit, pthread_barrier_init_intercept,
1406 (pthread_barrier_t* barrier, const pthread_barrierattr_t* attr,
1407 unsigned count), (barrier, attr, count));
1409 static __always_inline
1410 int pthread_barrier_destroy_intercept(pthread_barrier_t* barrier)
1412 int ret;
1413 OrigFn fn;
1414 VALGRIND_GET_ORIG_FN(fn);
1415 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_BARRIER_DESTROY,
1416 barrier, pthread_barrier, 0, 0, 0);
1417 CALL_FN_W_W(ret, fn, barrier);
1418 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_BARRIER_DESTROY,
1419 barrier, pthread_barrier, 0, 0, 0);
1420 return ret;
1423 PTH_FUNCS(int, pthreadZubarrierZudestroy, pthread_barrier_destroy_intercept,
1424 (pthread_barrier_t* barrier), (barrier));
1426 static __always_inline
1427 int pthread_barrier_wait_intercept(pthread_barrier_t* barrier)
1429 int ret;
1430 OrigFn fn;
1431 VALGRIND_GET_ORIG_FN(fn);
1432 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_BARRIER_WAIT,
1433 barrier, pthread_barrier, 0, 0, 0);
1434 CALL_FN_W_W(ret, fn, barrier);
1435 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_BARRIER_WAIT,
1436 barrier, pthread_barrier,
1437 ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD,
1438 ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
1439 return ret;
1442 PTH_FUNCS(int, pthreadZubarrierZuwait, pthread_barrier_wait_intercept,
1443 (pthread_barrier_t* barrier), (barrier));
1444 #endif // HAVE_PTHREAD_BARRIER_INIT
1447 static __always_inline
1448 int sem_init_intercept(sem_t *sem, int pshared, unsigned int value)
1450 int ret;
1451 OrigFn fn;
1452 VALGRIND_GET_ORIG_FN(fn);
1453 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_INIT,
1454 sem, pshared, value, 0, 0);
1455 CALL_FN_W_WWW(ret, fn, sem, pshared, value);
1456 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_INIT,
1457 sem, 0, 0, 0, 0);
1458 return ret;
1461 #if defined(VGO_freebsd)
1462 LIBC_FUNC(int, semZuinit, sem_init_intercept,
1463 (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
1464 #else
1465 PTH_FUNCS(int, semZuinit, sem_init_intercept,
1466 (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
1467 #endif
1469 #if defined(VGO_solaris)
1470 static __always_inline
1471 int sema_init_intercept(sema_t *sem, unsigned int value, int type, void *arg)
1473 int ret;
1474 OrigFn fn;
1475 VALGRIND_GET_ORIG_FN(fn);
1476 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_INIT,
1477 sem, type == USYNC_PROCESS ? 1 : 0,
1478 value, 0, 0);
1479 CALL_FN_W_WWWW(ret, fn, sem, value, type, arg);
1480 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_INIT,
1481 sem, 0, 0, 0, 0);
1482 return ret;
1485 PTH_FUNCS(int, semaZuinit, sema_init_intercept,
1486 (sema_t *sem, unsigned int value, int type, void *arg),
1487 (sem, value, type, arg));
1488 #endif /* VGO_solaris */
1490 static __always_inline
1491 int sem_destroy_intercept(sem_t *sem)
1493 int ret;
1494 OrigFn fn;
1495 VALGRIND_GET_ORIG_FN(fn);
1496 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_DESTROY,
1497 sem, 0, 0, 0, 0);
1498 CALL_FN_W_W(ret, fn, sem);
1499 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_DESTROY,
1500 sem, 0, 0, 0, 0);
1501 return ret;
1504 #if defined(VGO_freebsd)
1505 LIBC_FUNC(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1506 #else
1507 PTH_FUNCS(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1508 #endif
1510 #if defined(VGO_solaris)
1511 PTH_FUNCS(int, semaZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1512 #endif /* VGO_solaris */
1514 static __always_inline
1515 sem_t* sem_open_intercept(const char *name, int oflag, mode_t mode,
1516 unsigned int value)
1518 sem_t *ret;
1519 OrigFn fn;
1520 VALGRIND_GET_ORIG_FN(fn);
1521 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_OPEN,
1522 name, oflag, mode, value, 0);
1523 CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value);
1524 // To do: figure out why gcc 9.2.1 miscompiles this function if the printf()
1525 // call below is left out.
1526 printf("");
1527 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_OPEN,
1528 ret != SEM_FAILED ? ret : 0,
1529 name, oflag, mode, value);
1530 return ret;
1533 #if defined(VGO_freebsd)
1534 LIBC_FUNC(sem_t *, semZuopen, sem_open_intercept,
1535 (const char *name, int oflag, mode_t mode, unsigned int value),
1536 (name, oflag, mode, value));
1537 #else
1538 PTH_FUNCS(sem_t *, semZuopen, sem_open_intercept,
1539 (const char *name, int oflag, mode_t mode, unsigned int value),
1540 (name, oflag, mode, value));
1541 #endif
1543 static __always_inline int sem_close_intercept(sem_t *sem)
1545 int ret;
1546 OrigFn fn;
1547 VALGRIND_GET_ORIG_FN(fn);
1548 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_CLOSE,
1549 sem, 0, 0, 0, 0);
1550 CALL_FN_W_W(ret, fn, sem);
1551 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_CLOSE,
1552 sem, 0, 0, 0, 0);
1553 return ret;
1556 #if defined(VGO_freebsd)
1557 LIBC_FUNC(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
1558 #else
1559 PTH_FUNCS(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
1560 #endif
1562 static __always_inline int sem_wait_intercept(sem_t *sem)
1564 int ret;
1565 OrigFn fn;
1566 VALGRIND_GET_ORIG_FN(fn);
1567 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT,
1568 sem, 0, 0, 0, 0);
1569 CALL_FN_W_W(ret, fn, sem);
1570 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT,
1571 sem, ret == 0, 0, 0, 0);
1572 return ret;
1575 #if defined(VGO_freebsd)
1576 LIBC_FUNC(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1577 #else
1578 PTH_FUNCS(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1579 #endif
1581 #if defined(VGO_solaris)
1582 PTH_FUNCS(int, semaZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1583 #endif /* VGO_solaris */
1585 static __always_inline int sem_trywait_intercept(sem_t *sem)
1587 int ret;
1588 OrigFn fn;
1589 VALGRIND_GET_ORIG_FN(fn);
1590 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT,
1591 sem, 0, 0, 0, 0);
1592 CALL_FN_W_W(ret, fn, sem);
1593 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT,
1594 sem, ret == 0, 0, 0, 0);
1595 return ret;
1598 #if defined(VGO_freebsd)
1599 LIBC_FUNC(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1600 #else
1601 PTH_FUNCS(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1602 #endif
1603 #if defined(VGO_solaris)
1604 PTH_FUNCS(int, semaZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1605 #endif /* VGO_solaris */
1607 static __always_inline
1608 int sem_timedwait_intercept(sem_t *sem, const struct timespec *abs_timeout)
1610 int ret;
1611 OrigFn fn;
1612 VALGRIND_GET_ORIG_FN(fn);
1613 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT,
1614 sem, 0, 0, 0, 0);
1615 CALL_FN_W_WW(ret, fn, sem, abs_timeout);
1616 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT,
1617 sem, ret == 0, 0, 0, 0);
1618 return ret;
1621 #if defined(VGO_freebsd)
1622 LIBC_FUNC(int, semZutimedwait, sem_timedwait_intercept,
1623 (sem_t *sem, const struct timespec *abs_timeout),
1624 (sem, abs_timeout));
1625 #else
1626 PTH_FUNCS(int, semZutimedwait, sem_timedwait_intercept,
1627 (sem_t *sem, const struct timespec *abs_timeout),
1628 (sem, abs_timeout));
1629 #endif
1630 #if defined(VGO_solaris)
1631 PTH_FUNCS(int, semaZutimedwait, sem_timedwait_intercept,
1632 (sem_t *sem, const struct timespec *timeout),
1633 (sem, timeout));
1634 PTH_FUNCS(int, semaZureltimedwait, sem_timedwait_intercept,
1635 (sem_t *sem, const struct timespec *timeout),
1636 (sem, timeout));
1637 #endif /* VGO_solaris */
1639 #if defined(VGO_freebsd)
1640 static __always_inline
1641 int sem_clockwait_np_intercept(sem_t* sem, clockid_t clock_id, int flags,
1642 const struct timespec * rqtp, struct timespec * rmtp)
1644 int ret;
1645 OrigFn fn;
1646 VALGRIND_GET_ORIG_FN(fn);
1647 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT,
1648 sem, 0, 0, 0, 0);
1649 CALL_FN_W_5W(ret, fn, sem, clock_id, flags, rqtp, rmtp);
1650 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT,
1651 sem, ret == 0, 0, 0, 0);
1652 return ret;
1655 LIBC_FUNC(int, semZuclockwaitZunp, sem_clockwait_np_intercept,
1656 (sem_t* sem, clockid_t clock_id, int flags,
1657 const struct timespec * rqtp, struct timespec * rmtp),
1658 (sem, clock_id, flags, rqtp, rmtp));
1659 #endif
1661 static __always_inline int sem_post_intercept(sem_t *sem)
1663 int ret;
1664 OrigFn fn;
1665 VALGRIND_GET_ORIG_FN(fn);
1666 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_POST,
1667 sem, 0, 0, 0, 0);
1668 CALL_FN_W_W(ret, fn, sem);
1669 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_POST,
1670 sem, ret == 0, 0, 0, 0);
1671 return ret;
1674 #if defined(VGO_freebsd)
1675 LIBC_FUNC(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
1676 #else
1677 PTH_FUNCS(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
1678 #endif
1679 #if defined(VGO_solaris)
1680 PTH_FUNCS(int, semaZupost, sem_post_intercept, (sem_t *sem), (sem));
1681 #endif /* VGO_solaris */
1683 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1684 functions have to be conditionally compiled. */
1685 #if defined(HAVE_PTHREAD_RWLOCK_T)
1687 static __always_inline
1688 int pthread_rwlock_init_intercept(pthread_rwlock_t* rwlock,
1689 const pthread_rwlockattr_t* attr)
1691 int ret;
1692 OrigFn fn;
1693 VALGRIND_GET_ORIG_FN(fn);
1694 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_INIT,
1695 rwlock, 0, 0, 0, 0);
1696 CALL_FN_W_WW(ret, fn, rwlock, attr);
1697 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_INIT,
1698 rwlock, 0, 0, 0, 0);
1699 return ret;
1702 PTH_FUNCS(int,
1703 pthreadZurwlockZuinit, pthread_rwlock_init_intercept,
1704 (pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr),
1705 (rwlock, attr));
1707 #if defined(VGO_solaris)
1708 static __always_inline
1709 int rwlock_init_intercept(rwlock_t *rwlock, int type, void *arg)
1711 int ret;
1712 OrigFn fn;
1713 VALGRIND_GET_ORIG_FN(fn);
1714 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_INIT,
1715 rwlock, 0, 0, 0, 0);
1716 CALL_FN_W_WWW(ret, fn, rwlock, type, arg);
1717 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_INIT,
1718 rwlock, 0, 0, 0, 0);
1719 return ret;
1722 PTH_FUNCS(int, rwlockZuinit, rwlock_init_intercept,
1723 (rwlock_t *rwlock, int type, void *arg),
1724 (rwlock, type, arg));
1725 #endif /* VGO_solaris */
1727 static __always_inline
1728 int pthread_rwlock_destroy_intercept(pthread_rwlock_t* rwlock)
1730 int ret;
1731 OrigFn fn;
1732 VALGRIND_GET_ORIG_FN(fn);
1733 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_DESTROY,
1734 rwlock, 0, 0, 0, 0);
1735 CALL_FN_W_W(ret, fn, rwlock);
1736 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_DESTROY,
1737 rwlock, 0, 0, 0, 0);
1738 return ret;
1741 #if defined(VGO_solaris)
1742 /* On Solaris, pthread_rwlock_destroy is a weak alias to rwlock_destroy. */
1743 PTH_FUNCS(int,
1744 rwlockZudestroy, pthread_rwlock_destroy_intercept,
1745 (pthread_rwlock_t *rwlock), (rwlock));
1746 #else
1747 PTH_FUNCS(int,
1748 pthreadZurwlockZudestroy, pthread_rwlock_destroy_intercept,
1749 (pthread_rwlock_t* rwlock), (rwlock));
1750 #endif /* VGO_solaris */
1752 static __always_inline
1753 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t* rwlock)
1755 int ret;
1756 OrigFn fn;
1757 VALGRIND_GET_ORIG_FN(fn);
1758 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK,
1759 rwlock, 0, 0, 0, 0);
1760 CALL_FN_W_W(ret, fn, rwlock);
1761 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK,
1762 rwlock, ret == 0, 0, 0, 0);
1763 return ret;
1766 #if defined(VGO_solaris)
1767 /* On Solaris, pthread_rwlock_rdlock is a weak alias to rw_rdlock. */
1768 PTH_FUNCS(int,
1769 rwZurdlock, pthread_rwlock_rdlock_intercept,
1770 (pthread_rwlock_t *rwlock), (rwlock));
1771 #else
1772 PTH_FUNCS(int,
1773 pthreadZurwlockZurdlock, pthread_rwlock_rdlock_intercept,
1774 (pthread_rwlock_t* rwlock), (rwlock));
1775 #endif /* VGO_solaris */
1777 #if defined(VGO_solaris)
1778 /* Internal to libc. */
1779 static __always_inline
1780 void lrw_rdlock_intercept(rwlock_t *rwlock)
1782 OrigFn fn;
1783 VALGRIND_GET_ORIG_FN(fn);
1784 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK,
1785 rwlock, 0, 0, 0, 0);
1786 CALL_FN_v_W(fn, rwlock);
1787 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK,
1788 rwlock, True /* took_lock */, 0, 0, 0);
1791 PTH_FUNCS(void, lrwZurdlock, lrw_rdlock_intercept,
1792 (rwlock_t *rwlock), (rwlock));
1793 #endif /* VGO_solaris */
1795 static __always_inline
1796 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t* rwlock)
1798 int ret;
1799 OrigFn fn;
1800 VALGRIND_GET_ORIG_FN(fn);
1801 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK,
1802 rwlock, 0, 0, 0, 0);
1803 CALL_FN_W_W(ret, fn, rwlock);
1804 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK,
1805 rwlock, ret == 0, 0, 0, 0);
1806 return ret;
1809 #if defined(VGO_solaris)
1810 /* On Solaris, pthread_rwlock_wrlock is a weak alias to rw_wrlock. */
1811 PTH_FUNCS(int,
1812 rwZuwrlock, pthread_rwlock_wrlock_intercept,
1813 (pthread_rwlock_t *rwlock), (rwlock));
1814 #else
1815 PTH_FUNCS(int,
1816 pthreadZurwlockZuwrlock, pthread_rwlock_wrlock_intercept,
1817 (pthread_rwlock_t* rwlock), (rwlock));
1818 #endif /* VGO_solaris */
1820 #if defined(VGO_solaris)
1821 /* Internal to libc. */
1822 static __always_inline
1823 void lrw_wrlock_intercept(rwlock_t *rwlock)
1825 OrigFn fn;
1826 VALGRIND_GET_ORIG_FN(fn);
1827 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK,
1828 rwlock, 0, 0, 0, 0);
1829 CALL_FN_v_W(fn, rwlock);
1830 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK,
1831 rwlock, True /* took_lock */, 0, 0, 0);
1834 PTH_FUNCS(void, lrwZuwrlock, lrw_wrlock_intercept,
1835 (rwlock_t *rwlock), (rwlock));
1836 #endif /* VGO_solaris */
1838 static __always_inline
1839 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t* rwlock,
1840 const struct timespec *timeout)
1842 int ret;
1843 OrigFn fn;
1844 VALGRIND_GET_ORIG_FN(fn);
1845 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK,
1846 rwlock, 0, 0, 0, 0);
1847 CALL_FN_W_WW(ret, fn, rwlock, timeout);
1848 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK,
1849 rwlock, ret == 0, 0, 0, 0);
1850 return ret;
1853 PTH_FUNCS(int,
1854 pthreadZurwlockZutimedrdlock, pthread_rwlock_timedrdlock_intercept,
1855 (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1856 (rwlock, timeout));
1857 #if defined(VGO_solaris)
1858 PTH_FUNCS(int, pthreadZurwlockZureltimedrdlockZunp,
1859 pthread_rwlock_timedrdlock_intercept,
1860 (pthread_rwlock_t *rwlock, const struct timespec *timeout),
1861 (rwlock, timeout));
1862 #endif /* VGO_solaris */
1865 #if defined(HAVE_CLOCKID_T)
1866 static __always_inline
1867 int pthread_rwlock_clockrdlock_intercept(pthread_rwlock_t* rwlock,
1868 clockid_t clockid,
1869 const struct timespec *timeout)
1871 int ret;
1872 OrigFn fn;
1873 VALGRIND_GET_ORIG_FN(fn);
1874 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK,
1875 rwlock, 0, 0, 0, 0);
1876 CALL_FN_W_WWW(ret, fn, rwlock, clockid, timeout);
1877 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK,
1878 rwlock, ret == 0, 0, 0, 0);
1879 return ret;
1882 PTH_FUNCS(int,
1883 pthreadZurwlockZuclockrdlock, pthread_rwlock_clockrdlock_intercept,
1884 (pthread_rwlock_t* rwlock, clockid_t clockid, const struct timespec *timeout),
1885 (rwlock, clockid, timeout));
1886 #endif
1888 static __always_inline
1889 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t* rwlock,
1890 const struct timespec *timeout)
1892 int ret;
1893 OrigFn fn;
1894 VALGRIND_GET_ORIG_FN(fn);
1895 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK,
1896 rwlock, 0, 0, 0, 0);
1897 CALL_FN_W_WW(ret, fn, rwlock, timeout);
1898 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK,
1899 rwlock, ret == 0, 0, 0, 0);
1900 return ret;
1903 PTH_FUNCS(int,
1904 pthreadZurwlockZutimedwrlock, pthread_rwlock_timedwrlock_intercept,
1905 (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1906 (rwlock, timeout));
1907 #if defined(VGO_solaris)
1908 PTH_FUNCS(int, pthreadZurwlockZureltimedwrlockZunp,
1909 pthread_rwlock_timedwrlock_intercept,
1910 (pthread_rwlock_t *rwlock, const struct timespec *timeout),
1911 (rwlock, timeout));
1912 #endif /* VGO_solaris */
1915 #if defined(HAVE_CLOCKID_T)
1916 static __always_inline
1917 int pthread_rwlock_clockwrlock_intercept(pthread_rwlock_t* rwlock,
1918 clockid_t clockid,
1919 const struct timespec *timeout)
1921 int ret;
1922 OrigFn fn;
1923 VALGRIND_GET_ORIG_FN(fn);
1924 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK,
1925 rwlock, 0, 0, 0, 0);
1926 CALL_FN_W_WWW(ret, fn, rwlock, clockid, timeout);
1927 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK,
1928 rwlock, ret == 0, 0, 0, 0);
1929 return ret;
1932 PTH_FUNCS(int,
1933 pthreadZurwlockZuclockwrlock, pthread_rwlock_clockwrlock_intercept,
1934 (pthread_rwlock_t* rwlock, clockid_t clockid, const struct timespec *timeout),
1935 (rwlock, clockid, timeout));
1936 #endif
1939 static __always_inline
1940 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t* rwlock)
1942 int ret;
1943 OrigFn fn;
1944 VALGRIND_GET_ORIG_FN(fn);
1945 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK,
1946 rwlock, 0, 0, 0, 0);
1947 CALL_FN_W_W(ret, fn, rwlock);
1948 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK,
1949 rwlock, ret == 0, 0, 0, 0);
1950 return ret;
1953 #if defined(VGO_solaris)
1954 /* On Solaris, pthread_rwlock_tryrdlock is a weak alias to rw_tryrdlock. */
1955 PTH_FUNCS(int,
1956 rwZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1957 (pthread_rwlock_t *rwlock), (rwlock));
1958 #else
1959 PTH_FUNCS(int,
1960 pthreadZurwlockZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1961 (pthread_rwlock_t* rwlock), (rwlock));
1962 #endif /* VGO_solaris */
1964 static __always_inline
1965 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t* rwlock)
1967 int ret;
1968 OrigFn fn;
1969 VALGRIND_GET_ORIG_FN(fn);
1970 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK,
1971 rwlock, 0, 0, 0, 0);
1972 CALL_FN_W_W(ret, fn, rwlock);
1973 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK,
1974 rwlock, ret == 0, 0, 0, 0);
1975 return ret;
1978 #if defined(VGO_solaris)
1979 /* On Solaris, pthread_rwlock_trywrlock is a weak alias to rw_trywrlock. */
1980 PTH_FUNCS(int,
1981 rwZutrywrlock, pthread_rwlock_trywrlock_intercept,
1982 (pthread_rwlock_t *rwlock), (rwlock));
1983 #else
1984 PTH_FUNCS(int,
1985 pthreadZurwlockZutrywrlock, pthread_rwlock_trywrlock_intercept,
1986 (pthread_rwlock_t* rwlock), (rwlock));
1987 #endif /* VGO_solaris */
1989 static __always_inline
1990 int pthread_rwlock_unlock_intercept(pthread_rwlock_t* rwlock)
1992 int ret;
1993 OrigFn fn;
1994 VALGRIND_GET_ORIG_FN(fn);
1995 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_UNLOCK,
1996 rwlock, 0, 0, 0, 0);
1997 CALL_FN_W_W(ret, fn, rwlock);
1998 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_UNLOCK,
1999 rwlock, ret == 0, 0, 0, 0);
2000 return ret;
2003 #if defined(VGO_solaris)
2004 /* On Solaris, pthread_rwlock_unlock is a weak alias to rw_unlock. */
2005 PTH_FUNCS(int,
2006 rwZuunlock, pthread_rwlock_unlock_intercept,
2007 (pthread_rwlock_t *rwlock), (rwlock));
2008 #else
2009 PTH_FUNCS(int,
2010 pthreadZurwlockZuunlock, pthread_rwlock_unlock_intercept,
2011 (pthread_rwlock_t* rwlock), (rwlock));
2012 #endif /* VGO_solaris */
2014 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */