memcheck/tests/sh-mem-random.c: Set huge_addr to 240GB
[valgrind.git] / drd / drd_pthread_intercepts.c
blob7f20b0b4c21414766b76b3763a03308e15b2f58b
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 #include <osreldate.h>
63 #endif
65 #if defined(VGO_solaris)
67 * Solaris usually provides pthread_* functions on top of Solaris threading
68 * and synchronization functions. Usually both need to be intercepted because
69 * pthread_* ones might not call the Solaris ones (see for example sem_wait()).
70 * Such approach is required to correctly report misuse of the POSIX threads
71 * API.
72 * Therefore DRD intercepts and instruments all such functions but due to
73 * DRD_(thread_enter_synchr)() and DRD_(thread_leave_synchr)() guards in
74 * handle_client_request(), only the top-most function is handled.
75 * So the right thing(TM) happens, as expected.
76 * The only exception is when pthread_* function is a weak alias to the Solaris
77 * threading/synchronization function. In such case only one needs to be
78 * intercepted to avoid redirection ambiguity.
80 * Intercepted functions rely on the fact that:
81 * - pthread_mutex_t == mutex_t
82 * - pthread_cond_t == cond_t
83 * - sem_t == sema_t
84 * - pthread_rwlock_t == rwlock_t
86 * It is necessary to intercept also internal libc synchronization functions
87 * for two reasons:
88 * - For read-write locks the unlocking function is shared
89 * - Functions lmutex_lock/lmutex_unlock guard many critical sections in libc
90 * which will be otherwise reported by DRD
92 #include <synch.h>
93 #include <thread.h>
94 #include "pub_tool_vki.h"
97 * Solaris provides higher throughput, parallelism and scalability than other
98 * operating systems, at the cost of more fine-grained locking activity.
99 * This means for example that when a thread is created under Linux, just one
100 * big lock in glibc is used for all thread setup. Solaris libc uses several
101 * fine-grained locks and the creator thread resumes its activities as soon
102 * as possible, leaving for example stack and TLS setup activities to the
103 * created thread.
105 * This situation confuses DRD as it assumes there is some false ordering
106 * in place between creator and created thread; and therefore many types of
107 * race conditions in the application would not be reported. To prevent such
108 * false ordering, command line option --ignore-thread-creation is set to
109 * 'yes' by default on Solaris. All activity (loads, stores, client requests)
110 * is therefore ignored during:
111 * - pthread_create() call in the creator thread [libc.so]
112 * - thread creation phase (stack and TLS setup) in the created thread [libc.so]
114 * As explained in the comments for _ti_bind_guard(), whenever the runtime
115 * linker has to perform any activity (such as resolving a symbol), it protects
116 * its data structures by calling into rt_bind_guard() which in turn invokes
117 * _ti_bind_guard() in libc. Pointers to _ti_bind_guard() and _ti_bind_clear()
118 * are passed from libc to runtime linker in _ld_libc() call during libc_init().
119 * All activity is also ignored during:
120 * - runtime dynamic linker work between rt_bind_guard() and rt_bind_clear()
121 * calls [ld.so]
123 * This also means that DRD does not report race conditions in libc (when
124 * --ignore-thread-creation=yes) and runtime linker itself (unconditionally)
125 * during these ignored sequences.
129 * Original function pointers for _ti_bind_guard() and _ti_bind_clear()
130 * from libc. They are intercepted in function wrapper of _ld_libc().
132 typedef int (*drd_rtld_guard_fn)(int flags);
133 static drd_rtld_guard_fn DRD_(rtld_bind_guard) = NULL;
134 static drd_rtld_guard_fn DRD_(rtld_bind_clear) = NULL;
135 #endif
139 * Notes regarding thread creation:
140 * - sg_init() runs on the context of the created thread and copies the vector
141 * clock of the creator thread. This only works reliably if the creator
142 * thread waits until this copy has been performed.
143 * - DRD_(thread_compute_minimum_vc)() does not take the vector clocks into
144 * account that are involved in thread creation and for which the
145 * corresponding thread has not yet been created. So not waiting until the
146 * created thread has been started would make it possible that segments get
147 * discarded that should not yet be discarded. Or: some data races are not
148 * detected.
152 * Macro for generating a Valgrind interception function.
153 * @param[in] ret_ty Return type of the function to be generated.
154 * @param[in] zf Z-encoded name of the interception function.
155 * @param[in] implf Name of the function that implements the intercept.
156 * @param[in] arg_decl Argument declaration list enclosed in parentheses.
157 * @param[in] argl Argument list enclosed in parentheses.
159 #if defined(VGO_darwin)
161 * Note here VGO_darwin is used rather than VG_WRAP_THREAD_FUNCTION_LIBPTHREAD_ONLY
162 * because of the special-case code adding a function call
164 static int never_true;
165 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
166 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
167 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
169 ret_ty pth_func_result = implf argl; \
170 /* Apparently inserting a function call in wrapper functions */ \
171 /* is sufficient to avoid misaligned stack errors. */ \
172 if (never_true) \
173 fflush(stdout); \
174 return pth_func_result; \
176 #elif defined(VG_WRAP_THREAD_FUNCTION_LIBPTHREAD_ONLY)
177 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
178 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
179 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
180 { return implf argl; }
181 #elif defined(VG_WRAP_THREAD_FUNCTION_LIBC_ONLY)
182 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
183 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl; \
184 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl \
185 { return implf argl; }
186 #elif defined(VG_WRAP_THREAD_FUNCTION_LIBC_AND_LIBPTHREAD)
187 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
188 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl; \
189 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl \
190 { return implf argl; } \
191 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
192 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
193 { return implf argl; }
194 #else
195 # error "Unknown platform/thread wrapping"
196 #endif
198 #if defined(VGO_freebsd)
199 #define LIBC_FUNC(ret_ty, zf, implf, argl_decl, argl) \
200 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl; \
201 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl \
202 { return implf argl; }
203 #endif
206 * Macro for generating three Valgrind interception functions: one with the
207 * Z-encoded name zf, one with ZAZa ("@*") appended to the name zf and one
208 * with ZDZa ("$*") appended to the name zf. The second generated interception
209 * function will intercept versioned symbols on Linux, and the third will
210 * intercept versioned symbols on Darwin.
212 #define PTH_FUNCS(ret_ty, zf, implf, argl_decl, argl) \
213 PTH_FUNC(ret_ty, zf, implf, argl_decl, argl); \
214 PTH_FUNC(ret_ty, zf ## ZAZa, implf, argl_decl, argl); \
215 PTH_FUNC(ret_ty, zf ## ZDZa, implf, argl_decl, argl);
218 * Not inlining one of the intercept functions will cause the regression
219 * tests to fail because this would cause an additional stackfram to appear
220 * in the output. The __always_inline macro guarantees that inlining will
221 * happen, even when compiling with optimization disabled.
223 #undef __always_inline /* since already defined in <cdefs.h> */
224 #if __GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 2
225 #define __always_inline __inline__ __attribute__((always_inline))
226 #else
227 #define __always_inline __inline__
228 #endif
230 /* Local data structures. */
232 typedef struct {
233 pthread_mutex_t mutex;
234 pthread_cond_t cond;
235 int counter;
236 } DrdSema;
238 typedef struct
240 void* (*start)(void*);
241 void* arg;
242 int detachstate;
243 DrdSema* wrapper_started;
244 } DrdPosixThreadArgs;
247 /* Local function declarations. */
249 static void DRD_(init)(void) __attribute__((constructor));
250 static void DRD_(check_threading_library)(void);
251 static void DRD_(set_pthread_id)(void);
252 static void DRD_(sema_init)(DrdSema* sema);
253 static void DRD_(sema_destroy)(DrdSema* sema);
254 static void DRD_(sema_down)(DrdSema* sema);
255 static void DRD_(sema_up)(DrdSema* sema);
258 /* Function definitions. */
261 * Shared library initialization function. The function init() is called after
262 * dlopen() has loaded the shared library with DRD client intercepts because
263 * the constructor attribute was specified in the declaration of this function.
264 * Note: do specify the -nostdlib option to gcc when linking this code into a
265 * shared library because doing so would cancel the effect of the constructor
266 * attribute ! Using the gcc option -nodefaultlibs is fine because this last
267 * option preserves the shared library initialization code that calls
268 * constructor and destructor functions.
270 static void DRD_(init)(void)
272 #if defined(VGO_freebsd)
275 * On FreeBSD, pthead functions are all in libthr.so
276 * However libc.so contains stubs. In this ctor function,
277 * calling DRD_(set_pthread_id)() results in a call to
278 * pthread_self() resolving to the libc.so stub which
279 * returns a junk value for the tid. Subsequent calls
280 * to pthread_create() then also cause calls to
281 * DRD_(set_pthread_id)(), but this time with pthread_self()
282 * resolving to the good libthr.so version (since this is later
283 * and libthr.so has been loaded). That causes an assert
284 * since we expect the tid to either be INVALID_POSIX_THREADID
285 * or the same as the current tid, and the junk value
286 * is neither. So we force loading of libthr.so, which
287 * avoids this junk tid value.
289 #if (__FreeBSD_version >= 1500013)
290 void* libsys = dlopen("/lib/libsys.so.7", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
291 #endif
292 dlclose(dlopen("/lib/libthr.so.3", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE));
293 #if (__FreeBSD_version >= 1500013)
294 if (libsys) {
295 dlclose(libsys);
297 #endif
299 #endif
301 DRD_(check_threading_library)();
302 DRD_(set_pthread_id)();
303 #if defined(VGO_solaris)
304 if ((DRD_(rtld_bind_guard) == NULL) || (DRD_(rtld_bind_clear) == NULL)) {
305 fprintf(stderr,
306 "Bind guard functions for the runtime linker (ld.so.1) were not intercepted.\n"
307 "This means the interface between libc and runtime linker changed and DRD\n"
308 "needs to be ported properly. Giving up.\n");
309 abort();
311 #endif
314 static __always_inline void DRD_(ignore_mutex_ordering)(pthread_mutex_t *mutex)
316 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_IGNORE_MUTEX_ORDERING,
317 mutex, 0, 0, 0, 0);
320 static void DRD_(sema_init)(DrdSema* sema)
322 DRD_IGNORE_VAR(*sema);
323 pthread_mutex_init(&sema->mutex, NULL);
324 DRD_(ignore_mutex_ordering)(&sema->mutex);
325 pthread_cond_init(&sema->cond, NULL);
326 sema->counter = 0;
329 static void DRD_(sema_destroy)(DrdSema* sema)
331 pthread_mutex_destroy(&sema->mutex);
332 pthread_cond_destroy(&sema->cond);
335 static void DRD_(sema_down)(DrdSema* sema)
337 pthread_mutex_lock(&sema->mutex);
338 while (sema->counter == 0)
339 pthread_cond_wait(&sema->cond, &sema->mutex);
340 sema->counter--;
341 pthread_mutex_unlock(&sema->mutex);
344 static void DRD_(sema_up)(DrdSema* sema)
346 pthread_mutex_lock(&sema->mutex);
347 sema->counter++;
348 pthread_cond_signal(&sema->cond);
349 pthread_mutex_unlock(&sema->mutex);
353 * POSIX threads and DRD each have their own mutex type identification.
354 * Convert POSIX threads' mutex type to DRD's mutex type. In the code below
355 * if-statements are used to test the value of 'kind' instead of a switch
356 * statement because some of the PTHREAD_MUTEX_ macro's may have the same
357 * value.
359 static MutexT DRD_(pthread_to_drd_mutex_type)(int kind)
362 * Static checkers don't like this as there are repeated branch
363 * but because there is variation between different platforms
364 * it's messy to make something without repetition.
366 * See also PTHREAD_MUTEX_KIND_MASK_NP in glibc source file
367 * <nptl/pthreadP.h>.
369 kind &= PTHREAD_MUTEX_RECURSIVE | PTHREAD_MUTEX_ERRORCHECK |
370 PTHREAD_MUTEX_NORMAL | PTHREAD_MUTEX_DEFAULT;
372 if (kind == PTHREAD_MUTEX_RECURSIVE) {
373 return mutex_type_recursive_mutex;
375 if (kind == PTHREAD_MUTEX_ERRORCHECK) {
376 return mutex_type_errorcheck_mutex;
378 if (kind == PTHREAD_MUTEX_NORMAL) {
379 return mutex_type_default_mutex;
381 if (kind == PTHREAD_MUTEX_DEFAULT) {
382 // On FreeBSD PTHREAD_MUTEX_DEFAULT is the same as PTHREAD_MUTEX_ERRORCHECK
383 // so this code is unreachable, but that's not true for all platforms
384 // so just ignore the warning
385 // coverity[DEADCODE:FALSE]
386 return mutex_type_default_mutex;
388 #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
389 if (kind == PTHREAD_MUTEX_ADAPTIVE_NP) {
390 return mutex_type_default_mutex;
392 #endif
393 return mutex_type_invalid_mutex;
396 #if defined(VGO_solaris)
398 * Solaris threads and DRD each have their own mutex type identification.
399 * Convert Solaris threads' mutex type to DRD's mutex type.
401 static MutexT DRD_(thread_to_drd_mutex_type)(int type)
403 if (type & LOCK_RECURSIVE) {
404 return mutex_type_recursive_mutex;
405 } else if (type & LOCK_ERRORCHECK) {
406 return mutex_type_errorcheck_mutex;
407 } else {
408 return mutex_type_default_mutex;
411 #endif /* VGO_solaris */
413 #define IS_ALIGNED(p) (((uintptr_t)(p) & (sizeof(*(p)) - 1)) == 0)
416 * Read the mutex type stored in the client memory used for the mutex
417 * implementation.
419 * @note This function depends on the implementation of the POSIX threads
420 * library -- the POSIX standard does not define the name of the member in
421 * which the mutex type is stored.
422 * @note The function mutex_type() has been declared inline in order
423 * to avoid that it shows up in call stacks (drd/tests/...exp* files).
424 * @note glibc stores the mutex type in the lowest two bits, and uses the
425 * higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
426 * PTHREAD_MUTEXATTR_FLAG_PSHARED.
428 static __always_inline MutexT DRD_(mutex_type)(pthread_mutex_t* mutex)
430 MutexT mutex_type = mutex_type_unknown;
432 ANNOTATE_IGNORE_READS_BEGIN();
433 #if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
434 /* glibc + LinuxThreads. */
435 if (IS_ALIGNED(&mutex->__m_kind))
437 const int kind = mutex->__m_kind & 3;
438 mutex_type = DRD_(pthread_to_drd_mutex_type)(kind);
440 #elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
441 /* glibc + NPTL. */
442 if (IS_ALIGNED(&mutex->__data.__kind))
444 const int kind = mutex->__data.__kind & 3;
445 mutex_type = DRD_(pthread_to_drd_mutex_type)(kind);
447 #elif defined(VGO_solaris)
449 const int type = ((mutex_t *) mutex)->vki_mutex_type;
450 mutex_type = DRD_(thread_to_drd_mutex_type)(type);
452 #else
454 * Another POSIX threads implementation. The mutex type won't be printed
455 * when enabling --trace-mutex=yes.
457 #endif
458 ANNOTATE_IGNORE_READS_END();
460 return mutex_type;
464 * Tell DRD whether 'tid' is a joinable thread or a detached thread.
466 static void DRD_(set_joinable)(const pthread_t tid, const int joinable)
468 assert(joinable == 0 || joinable == 1);
469 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_SET_JOINABLE,
470 tid, joinable, 0, 0, 0);
473 /** Tell DRD that the calling thread is about to enter pthread_create(). */
474 static __always_inline void DRD_(entering_pthread_create)(void)
476 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_ENTERING_PTHREAD_CREATE,
477 0, 0, 0, 0, 0);
480 /** Tell DRD that the calling thread has left pthread_create(). */
481 static __always_inline void DRD_(left_pthread_create)(void)
483 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_LEFT_PTHREAD_CREATE,
484 0, 0, 0, 0, 0);
488 * Entry point for newly created threads. This function is called from the
489 * thread created by pthread_create().
491 static void* DRD_(thread_wrapper)(void* arg)
493 DrdPosixThreadArgs* arg_ptr;
494 DrdPosixThreadArgs arg_copy;
496 arg_ptr = (DrdPosixThreadArgs*)arg;
497 arg_copy = *arg_ptr;
499 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_SET_PTHREADID,
500 pthread_self(), 0, 0, 0, 0);
502 DRD_(set_joinable)(pthread_self(),
503 arg_copy.detachstate == PTHREAD_CREATE_JOINABLE);
506 * Only set 'wrapper_started' after VG_USERREQ__SET_PTHREADID and
507 * DRD_(set_joinable)() have been invoked to avoid a race with
508 * a pthread_detach() invocation for this thread from another thread.
510 DRD_(sema_up)(arg_copy.wrapper_started);
512 return (arg_copy.start)(arg_copy.arg);
516 * Return 1 if the LinuxThreads implementation of POSIX Threads has been
517 * detected, and 0 otherwise.
519 * @see For more information about the confstr() function, see also
520 * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
522 static int DRD_(detected_linuxthreads)(void)
524 #if defined(linux)
525 #if defined(_CS_GNU_LIBPTHREAD_VERSION)
526 /* Linux with a recent glibc. */
527 HChar buffer[256];
528 unsigned len;
529 len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
530 assert(len <= sizeof(buffer));
531 return len > 0 && buffer[0] == 'l';
532 #else
533 /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
534 return 1;
535 #endif
536 #else
537 /* Another OS than Linux, hence no LinuxThreads. */
538 return 0;
539 #endif
543 * Stop and print an error message in case a non-supported threading
544 * library implementation (LinuxThreads) has been detected.
546 static void DRD_(check_threading_library)(void)
548 if (DRD_(detected_linuxthreads)())
550 if (getenv("LD_ASSUME_KERNEL"))
552 fprintf(stderr,
553 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
554 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
555 "after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
558 else
560 fprintf(stderr,
561 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
562 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
563 "after having upgraded to a newer version of your Linux distribution.\n"
564 "Giving up.\n"
567 abort();
572 * Update DRD's state information about the current thread.
574 static void DRD_(set_pthread_id)(void)
576 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_SET_PTHREADID,
577 pthread_self(), 0, 0, 0, 0);
581 * Note: as of today there exist three different versions of pthread_create
582 * in Linux:
583 * - pthread_create@GLIBC_2.0
584 * - pthread_create@@GLIBC_2.1
585 * - pthread_create@@GLIBC_2.2.5
586 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
587 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
588 * versions have been implemented. In any glibc version where more than one
589 * pthread_create function has been implemented, older versions call the
590 * newer versions. Or: the pthread_create* wrapper defined below can be
591 * called recursively. Any code in this wrapper should take this in account.
592 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
593 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
594 * See also the implementation of pthread_create@GLIBC_2.0 in
595 * glibc-2.9/nptl/pthread_create.c.
598 static __always_inline
599 int pthread_create_intercept(pthread_t* thread, const pthread_attr_t* attr,
600 void* (*start)(void*), void* arg)
602 int ret;
603 OrigFn fn;
604 DrdSema wrapper_started;
605 DrdPosixThreadArgs thread_args;
607 VALGRIND_GET_ORIG_FN(fn);
609 DRD_(sema_init)(&wrapper_started);
610 thread_args.start = start;
611 thread_args.arg = arg;
612 thread_args.wrapper_started = &wrapper_started;
614 * Find out whether the thread will be started as a joinable thread
615 * or as a detached thread. If no thread attributes have been specified,
616 * this means that the new thread will be started as a joinable thread.
618 thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
619 /* The C11 thrd_create() implementation passes -1 as 'attr' argument. */
620 if (attr && (uintptr_t)attr + 1 != 0)
622 if (pthread_attr_getdetachstate(attr, &thread_args.detachstate) != 0)
623 assert(0);
625 assert(thread_args.detachstate == PTHREAD_CREATE_JOINABLE
626 || thread_args.detachstate == PTHREAD_CREATE_DETACHED);
629 * The DRD_(set_pthread_id)() from DRD_(init)() may encounter that
630 * pthread_self() == 0, e.g. when the main program is not linked with the
631 * pthread library and when a pthread_create() call occurs from within a
632 * shared library. Hence call DRD_(set_pthread_id)() again to ensure that
633 * DRD knows the identity of the current thread. See also B.Z. 356374.
635 DRD_(set_pthread_id)();
636 DRD_(entering_pthread_create)();
637 CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), &thread_args);
638 DRD_(left_pthread_create)();
640 if (ret == 0) {
641 /* Wait until the thread wrapper started. */
642 DRD_(sema_down)(&wrapper_started);
645 DRD_(sema_destroy)(&wrapper_started);
647 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_START_NEW_SEGMENT,
648 pthread_self(), 0, 0, 0, 0);
650 return ret;
653 PTH_FUNCS(int, pthreadZucreate, pthread_create_intercept,
654 (pthread_t *thread, const pthread_attr_t *attr,
655 void *(*start) (void *), void *arg),
656 (thread, attr, start, arg));
658 #if defined(VGO_solaris)
659 /* Solaris also provides thr_create() in addition to pthread_create().
660 * Both pthread_create(3C) and thr_create(3C) are based on private
661 * _thrp_create().
663 static __always_inline
664 int thr_create_intercept(void *stk, size_t stksize, void *(*start)(void *),
665 void *arg, long flags, thread_t *new_thread)
667 int ret;
668 OrigFn fn;
669 DrdSema wrapper_started;
670 DrdPosixThreadArgs thread_args;
672 VALGRIND_GET_ORIG_FN(fn);
674 DRD_(sema_init)(&wrapper_started);
675 thread_args.start = start;
676 thread_args.arg = arg;
677 thread_args.wrapper_started = &wrapper_started;
679 * Find out whether the thread will be started as a joinable thread
680 * or as a detached thread.
682 if (flags & THR_DETACHED)
683 thread_args.detachstate = PTHREAD_CREATE_DETACHED;
684 else
685 thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
687 DRD_(entering_pthread_create)();
688 CALL_FN_W_6W(ret, fn, stk, stksize, DRD_(thread_wrapper), &thread_args,
689 flags, new_thread);
690 DRD_(left_pthread_create)();
692 if (ret == 0) {
693 /* Wait until the thread wrapper started. */
694 DRD_(sema_down)(&wrapper_started);
697 DRD_(sema_destroy)(&wrapper_started);
699 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_START_NEW_SEGMENT,
700 pthread_self(), 0, 0, 0, 0);
702 return ret;
705 PTH_FUNCS(int, thrZucreate, thr_create_intercept,
706 (void *stk, size_t stksize, void *(*start)(void *), void *arg,
707 long flags, thread_t *new_thread),
708 (stk, stksize, start, arg, flags, new_thread));
709 #endif /* VGO_solaris */
711 #if defined(VGO_solaris)
713 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
714 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
715 * and CI_BIND_CLEAR, to provide resilience against function renaming.
717 static __always_inline
718 int DRD_(_ti_bind_guard_intercept)(int flags) {
719 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_RTLD_BIND_GUARD,
720 flags, 0, 0, 0, 0);
721 return DRD_(rtld_bind_guard)(flags);
724 static __always_inline
725 int DRD_(_ti_bind_clear_intercept)(int flags) {
726 int ret = DRD_(rtld_bind_clear)(flags);
727 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_RTLD_BIND_CLEAR,
728 flags, 0, 0, 0, 0);
729 return ret;
733 * Wrapped _ld_libc() from the runtime linker ld.so.1.
735 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr);
736 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr)
738 OrigFn fn;
739 int tag;
741 VALGRIND_GET_ORIG_FN(fn);
743 vki_Lc_interface *funcs = ptr;
744 for (tag = funcs->ci_tag; tag != 0; tag = (++funcs)->ci_tag) {
745 switch (tag) {
746 case VKI_CI_BIND_GUARD:
747 if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_guard_intercept)) {
748 DRD_(rtld_bind_guard) = funcs->vki_ci_un.ci_func;
749 funcs->vki_ci_un.ci_func = DRD_(_ti_bind_guard_intercept);
751 break;
752 case VKI_CI_BIND_CLEAR:
753 if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_clear_intercept)) {
754 DRD_(rtld_bind_clear) = funcs->vki_ci_un.ci_func;
755 funcs->vki_ci_un.ci_func = DRD_(_ti_bind_clear_intercept);
757 break;
761 CALL_FN_v_W(fn, ptr);
763 #endif /* VGO_solaris */
765 static __always_inline
766 int pthread_join_intercept(pthread_t pt_joinee, void **thread_return)
768 int ret;
769 OrigFn fn;
771 VALGRIND_GET_ORIG_FN(fn);
773 * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
774 * implementation triggers a (false positive) race report.
776 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
777 CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
778 if (ret == 0)
780 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_THREAD_JOIN,
781 pt_joinee, 0, 0, 0, 0);
783 ANNOTATE_IGNORE_READS_AND_WRITES_END();
784 return ret;
787 PTH_FUNCS(int, pthreadZujoin, pthread_join_intercept,
788 (pthread_t pt_joinee, void **thread_return),
789 (pt_joinee, thread_return));
791 #if defined(VGO_solaris)
792 /* Solaris also provides thr_join() in addition to pthread_join().
793 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
795 * :TODO: No functionality is currently provided for joinee == 0 and departed.
796 * This would require another client request, of course.
798 static __always_inline
799 int thr_join_intercept(thread_t joinee, thread_t *departed, void **thread_return)
801 int ret;
802 OrigFn fn;
804 VALGRIND_GET_ORIG_FN(fn);
805 CALL_FN_W_WWW(ret, fn, joinee, departed, thread_return);
806 if (ret == 0)
808 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_THREAD_JOIN,
809 joinee, 0, 0, 0, 0);
811 return ret;
814 PTH_FUNCS(int, thrZujoin, thr_join_intercept,
815 (thread_t joinee, thread_t *departed, void **thread_return),
816 (joinee, departed, thread_return));
817 #endif /* VGO_solaris */
819 static __always_inline
820 int pthread_detach_intercept(pthread_t pt_thread)
822 int ret;
823 OrigFn fn;
825 VALGRIND_GET_ORIG_FN(fn);
826 CALL_FN_W_W(ret, fn, pt_thread);
827 DRD_(set_joinable)(pt_thread, 0);
829 return ret;
832 PTH_FUNCS(int, pthreadZudetach, pthread_detach_intercept,
833 (pthread_t thread), (thread));
835 // NOTE: be careful to intercept only pthread_cancel() and not
836 // pthread_cancel_init() on Linux.
838 static __always_inline
839 int pthread_cancel_intercept(pthread_t pt_thread)
841 int ret;
842 OrigFn fn;
843 VALGRIND_GET_ORIG_FN(fn);
844 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_THREAD_CANCEL,
845 pt_thread, 0, 0, 0, 0);
846 CALL_FN_W_W(ret, fn, pt_thread);
847 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_THREAD_CANCEL,
848 pt_thread, ret==0, 0, 0, 0);
849 return ret;
852 PTH_FUNCS(int, pthreadZucancel, pthread_cancel_intercept,
853 (pthread_t thread), (thread))
855 static __always_inline
856 int pthread_once_intercept(pthread_once_t *once_control,
857 void (*init_routine)(void))
859 int ret;
860 OrigFn fn;
861 VALGRIND_GET_ORIG_FN(fn);
863 * Ignore any data races triggered by the implementation of pthread_once().
864 * Necessary for Darwin. This is not necessary for Linux but doesn't have
865 * any known adverse effects.
867 DRD_IGNORE_VAR(*once_control);
868 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
869 CALL_FN_W_WW(ret, fn, once_control, init_routine);
870 ANNOTATE_IGNORE_READS_AND_WRITES_END();
871 DRD_STOP_IGNORING_VAR(*once_control);
872 return ret;
875 PTH_FUNCS(int, pthreadZuonce, pthread_once_intercept,
876 (pthread_once_t *once_control, void (*init_routine)(void)),
877 (once_control, init_routine));
879 static __always_inline
880 int pthread_mutex_init_intercept(pthread_mutex_t *mutex,
881 const pthread_mutexattr_t* attr)
883 int ret;
884 OrigFn fn;
885 int mt;
886 VALGRIND_GET_ORIG_FN(fn);
887 mt = PTHREAD_MUTEX_DEFAULT;
888 if (attr)
889 pthread_mutexattr_gettype(attr, &mt);
890 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_INIT,
891 mutex, DRD_(pthread_to_drd_mutex_type)(mt),
892 0, 0, 0);
893 CALL_FN_W_WW(ret, fn, mutex, attr);
894 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_INIT,
895 mutex, 0, 0, 0, 0);
896 return ret;
899 PTH_FUNCS(int, pthreadZumutexZuinit, pthread_mutex_init_intercept,
900 (pthread_mutex_t *mutex, const pthread_mutexattr_t* attr),
901 (mutex, attr));
903 #if defined(VGO_solaris)
904 static __always_inline
905 int mutex_init_intercept(mutex_t *mutex, int type, void *arg)
907 int ret;
908 OrigFn fn;
909 VALGRIND_GET_ORIG_FN(fn);
911 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_INIT,
912 mutex, DRD_(thread_to_drd_mutex_type)(type),
913 0, 0, 0);
914 CALL_FN_W_WWW(ret, fn, mutex, type, arg);
915 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_INIT,
916 mutex, 0, 0, 0, 0);
917 return ret;
920 PTH_FUNCS(int, mutexZuinit, mutex_init_intercept,
921 (mutex_t *mutex, int type, void *arg),
922 (mutex, type, arg));
923 #endif /* VGO_solaris */
925 static __always_inline
926 int pthread_mutex_destroy_intercept(pthread_mutex_t* mutex)
928 int ret;
929 OrigFn fn;
930 VALGRIND_GET_ORIG_FN(fn);
931 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_DESTROY,
932 mutex, 0, 0, 0, 0);
933 CALL_FN_W_W(ret, fn, mutex);
934 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_DESTROY,
935 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
936 return ret;
939 #if defined(VGO_solaris)
940 /* On Solaris, pthread_mutex_destroy is a weak alias to mutex_destroy. */
941 PTH_FUNCS(int, mutexZudestroy, pthread_mutex_destroy_intercept,
942 (pthread_mutex_t *mutex), (mutex));
943 #else
944 PTH_FUNCS(int, pthreadZumutexZudestroy, pthread_mutex_destroy_intercept,
945 (pthread_mutex_t *mutex), (mutex));
946 #endif /* VGO_solaris */
948 static __always_inline
949 int pthread_mutex_lock_intercept(pthread_mutex_t* mutex)
951 int ret;
952 OrigFn fn;
953 VALGRIND_GET_ORIG_FN(fn);
954 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK,
955 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
956 CALL_FN_W_W(ret, fn, mutex);
957 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK,
958 mutex, ret == 0, 0, 0, 0);
959 return ret;
962 #if defined(VGO_solaris)
963 /* On Solaris, pthread_mutex_lock is a weak alias to mutex_lock. */
964 PTH_FUNCS(int, mutexZulock, pthread_mutex_lock_intercept,
965 (pthread_mutex_t *mutex), (mutex));
966 #else
967 PTH_FUNCS(int, pthreadZumutexZulock, pthread_mutex_lock_intercept,
968 (pthread_mutex_t *mutex), (mutex));
969 #endif /* VGO_solaris */
971 #if defined(VGO_solaris)
972 /* Internal to libc. Mutex is usually initialized only implicitly,
973 * by zeroing mutex_t structure.
975 static __always_inline
976 void lmutex_lock_intercept(mutex_t *mutex)
978 OrigFn fn;
979 VALGRIND_GET_ORIG_FN(fn);
980 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK,
981 mutex,
982 DRD_(mutex_type)((pthread_mutex_t *) mutex),
983 False /* try_lock */, 0, 0);
984 CALL_FN_v_W(fn, mutex);
985 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK,
986 mutex, True /* took_lock */, 0, 0, 0);
989 PTH_FUNCS(void, lmutexZulock, lmutex_lock_intercept,
990 (mutex_t *mutex), (mutex));
991 #endif /* VGO_solaris */
993 static __always_inline
994 int pthread_mutex_trylock_intercept(pthread_mutex_t* mutex)
996 int ret;
997 OrigFn fn;
998 VALGRIND_GET_ORIG_FN(fn);
999 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK,
1000 mutex, DRD_(mutex_type)(mutex), 1, 0, 0);
1001 CALL_FN_W_W(ret, fn, mutex);
1002 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK,
1003 mutex, ret == 0, 0, 0, 0);
1004 return ret;
1007 #if defined(VGO_solaris)
1008 /* On Solaris, pthread_mutex_trylock is a weak alias to mutex_trylock. */
1009 PTH_FUNCS(int, mutexZutrylock, pthread_mutex_trylock_intercept,
1010 (pthread_mutex_t *mutex), (mutex));
1011 #else
1012 PTH_FUNCS(int, pthreadZumutexZutrylock, pthread_mutex_trylock_intercept,
1013 (pthread_mutex_t *mutex), (mutex));
1014 #endif /* VGO_solaris */
1016 static __always_inline
1017 int pthread_mutex_timedlock_intercept(pthread_mutex_t *mutex,
1018 const struct timespec *abs_timeout)
1020 int ret;
1021 OrigFn fn;
1022 VALGRIND_GET_ORIG_FN(fn);
1023 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK,
1024 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
1025 CALL_FN_W_WW(ret, fn, mutex, abs_timeout);
1026 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK,
1027 mutex, ret == 0, 0, 0, 0);
1028 return ret;
1031 PTH_FUNCS(int, pthreadZumutexZutimedlock, pthread_mutex_timedlock_intercept,
1032 (pthread_mutex_t *mutex, const struct timespec *abs_timeout),
1033 (mutex, abs_timeout));
1034 #if defined(VGO_solaris)
1035 PTH_FUNCS(int,
1036 pthreadZumutexZureltimedlockZunp, pthread_mutex_timedlock_intercept,
1037 (pthread_mutex_t *mutex, const struct timespec *timeout),
1038 (mutex, timeout));
1039 #endif /* VGO_solaris */
1041 #if defined(HAVE_CLOCKID_T)
1042 static __always_inline
1043 int pthread_mutex_clocklock_intercept(pthread_mutex_t *mutex,
1044 clockid_t clockid,
1045 const struct timespec *abs_timeout)
1047 int ret;
1048 OrigFn fn;
1049 VALGRIND_GET_ORIG_FN(fn);
1050 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK,
1051 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
1052 CALL_FN_W_WWW(ret, fn, mutex, clockid, abs_timeout);
1053 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK,
1054 mutex, ret == 0, 0, 0, 0);
1055 return ret;
1058 PTH_FUNCS(int, pthreadZumutexZuclocklock, pthread_mutex_clocklock_intercept,
1059 (pthread_mutex_t *mutex, clockid_t clockid, const struct timespec *abs_timeout),
1060 (mutex, clockid, abs_timeout));
1061 #endif
1063 static __always_inline
1064 int pthread_mutex_unlock_intercept(pthread_mutex_t *mutex)
1066 int ret;
1067 OrigFn fn;
1068 VALGRIND_GET_ORIG_FN(fn);
1069 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_UNLOCK,
1070 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
1071 CALL_FN_W_W(ret, fn, mutex);
1072 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_UNLOCK,
1073 mutex, 0, 0, 0, 0);
1074 return ret;
1077 #if defined(VGO_solaris)
1078 /* On Solaris, pthread_mutex_unlock is a weak alias to mutex_unlock. */
1079 PTH_FUNCS(int, mutexZuunlock, pthread_mutex_unlock_intercept,
1080 (pthread_mutex_t *mutex), (mutex));
1081 #else
1082 PTH_FUNCS(int, pthreadZumutexZuunlock, pthread_mutex_unlock_intercept,
1083 (pthread_mutex_t *mutex), (mutex));
1084 #endif /* VGO_solaris */
1086 #if defined(VGO_solaris)
1087 /* Internal to libc. */
1088 static __always_inline
1089 void lmutex_unlock_intercept(mutex_t *mutex)
1091 OrigFn fn;
1092 VALGRIND_GET_ORIG_FN(fn);
1093 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_UNLOCK,
1094 mutex,
1095 DRD_(mutex_type)((pthread_mutex_t *) mutex),
1096 0, 0, 0);
1097 CALL_FN_v_W(fn, mutex);
1098 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_UNLOCK,
1099 mutex, 0, 0, 0, 0);
1102 PTH_FUNCS(void, lmutexZuunlock, lmutex_unlock_intercept,
1103 (mutex_t *mutex), (mutex));
1104 #endif /* VGO_solaris */
1106 static __always_inline
1107 int pthread_cond_init_intercept(pthread_cond_t* cond,
1108 const pthread_condattr_t* attr)
1110 int ret;
1111 OrigFn fn;
1112 VALGRIND_GET_ORIG_FN(fn);
1113 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_INIT,
1114 cond, 0, 0, 0, 0);
1115 CALL_FN_W_WW(ret, fn, cond, attr);
1116 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_INIT,
1117 cond, 0, 0, 0, 0);
1118 return ret;
1121 PTH_FUNCS(int, pthreadZucondZuinit, pthread_cond_init_intercept,
1122 (pthread_cond_t* cond, const pthread_condattr_t* attr),
1123 (cond, attr));
1125 #if defined(VGO_solaris)
1126 static __always_inline
1127 int cond_init_intercept(cond_t *cond, int type, void *arg)
1129 int ret;
1130 OrigFn fn;
1131 VALGRIND_GET_ORIG_FN(fn);
1132 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_INIT,
1133 cond, 0, 0, 0, 0);
1134 CALL_FN_W_WWW(ret, fn, cond, type, arg);
1135 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_INIT,
1136 cond, 0, 0, 0, 0);
1137 return ret;
1140 PTH_FUNCS(int, condZuinit, cond_init_intercept,
1141 (cond_t *cond, int type, void *arg),
1142 (cond, type, arg));
1143 #endif /* VGO_solaris */
1145 static __always_inline
1146 int pthread_cond_destroy_intercept(pthread_cond_t* cond)
1148 int ret;
1149 OrigFn fn;
1150 VALGRIND_GET_ORIG_FN(fn);
1151 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_DESTROY,
1152 cond, 0, 0, 0, 0);
1153 CALL_FN_W_W(ret, fn, cond);
1154 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_DESTROY,
1155 cond, ret==0, 0, 0, 0);
1156 return ret;
1159 #if defined(VGO_solaris)
1160 /* On Solaris, pthread_cond_destroy is a weak alias to cond_destroy. */
1161 PTH_FUNCS(int, condZudestroy, pthread_cond_destroy_intercept,
1162 (pthread_cond_t *cond), (cond));
1163 #else
1164 PTH_FUNCS(int, pthreadZucondZudestroy, pthread_cond_destroy_intercept,
1165 (pthread_cond_t* cond), (cond));
1166 #endif /* VGO_solaris */
1168 static __always_inline
1169 int pthread_cond_wait_intercept(pthread_cond_t *cond, pthread_mutex_t *mutex)
1171 int ret;
1172 OrigFn fn;
1173 VALGRIND_GET_ORIG_FN(fn);
1174 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_WAIT,
1175 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1176 CALL_FN_W_WW(ret, fn, cond, mutex);
1177 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_WAIT,
1178 cond, mutex, 1, 0, 0);
1179 return ret;
1182 PTH_FUNCS(int, pthreadZucondZuwait, pthread_cond_wait_intercept,
1183 (pthread_cond_t *cond, pthread_mutex_t *mutex),
1184 (cond, mutex));
1185 #if defined(VGO_solaris)
1186 PTH_FUNCS(int, condZuwait, pthread_cond_wait_intercept,
1187 (pthread_cond_t *cond, pthread_mutex_t *mutex),
1188 (cond, mutex));
1189 #endif /* VGO_solaris */
1191 static __always_inline
1192 int pthread_cond_timedwait_intercept(pthread_cond_t *cond,
1193 pthread_mutex_t *mutex,
1194 const struct timespec* abstime)
1196 int ret;
1197 OrigFn fn;
1198 VALGRIND_GET_ORIG_FN(fn);
1199 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_WAIT,
1200 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1201 CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
1202 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_WAIT,
1203 cond, mutex, 1, 0, 0);
1204 return ret;
1207 PTH_FUNCS(int, pthreadZucondZutimedwait, pthread_cond_timedwait_intercept,
1208 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1209 const struct timespec* abstime),
1210 (cond, mutex, abstime));
1211 #if defined(VGO_solaris)
1212 PTH_FUNCS(int, condZutimedwait, pthread_cond_timedwait_intercept,
1213 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1214 const struct timespec *timeout),
1215 (cond, mutex, timeout));
1216 PTH_FUNCS(int, condZureltimedwait, pthread_cond_timedwait_intercept,
1217 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1218 const struct timespec *timeout),
1219 (cond, mutex, timeout));
1220 #endif /* VGO_solaris */
1223 #if defined(HAVE_CLOCKID_T)
1224 static __always_inline
1225 int pthread_cond_clockwait_intercept(pthread_cond_t *cond,
1226 pthread_mutex_t *mutex,
1227 clockid_t clockid,
1228 const struct timespec* abstime)
1230 int ret;
1231 OrigFn fn;
1232 VALGRIND_GET_ORIG_FN(fn);
1233 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_WAIT,
1234 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1235 CALL_FN_W_WWWW(ret, fn, cond, mutex, clockid, abstime);
1236 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_WAIT,
1237 cond, mutex, 1, 0, 0);
1238 return ret;
1241 PTH_FUNCS(int, pthreadZucondZuclockwait, pthread_cond_clockwait_intercept,
1242 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1243 clockid_t clockid, const struct timespec* abstime),
1244 (cond, mutex, clockid, abstime));
1245 #endif
1248 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
1249 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
1250 // two. Intercepting all pthread_cond_signal* functions will cause only one
1251 // argument to be passed to pthread_cond_signal_np() and hence will cause this
1252 // last function to crash.
1254 static __always_inline
1255 int pthread_cond_signal_intercept(pthread_cond_t* cond)
1257 int ret;
1258 OrigFn fn;
1259 VALGRIND_GET_ORIG_FN(fn);
1260 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_SIGNAL,
1261 cond, 0, 0, 0, 0);
1262 CALL_FN_W_W(ret, fn, cond);
1263 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_SIGNAL,
1264 cond, 0, 0, 0, 0);
1265 return ret;
1268 #if defined(VGO_solaris)
1269 /* On Solaris, pthread_cond_signal is a weak alias to cond_signal. */
1270 PTH_FUNCS(int, condZusignal, pthread_cond_signal_intercept,
1271 (pthread_cond_t *cond), (cond));
1272 #else
1273 PTH_FUNCS(int, pthreadZucondZusignal, pthread_cond_signal_intercept,
1274 (pthread_cond_t* cond), (cond));
1275 #endif /* VGO_solaris */
1277 static __always_inline
1278 int pthread_cond_broadcast_intercept(pthread_cond_t* cond)
1280 int ret;
1281 OrigFn fn;
1282 VALGRIND_GET_ORIG_FN(fn);
1283 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_BROADCAST,
1284 cond, 0, 0, 0, 0);
1285 CALL_FN_W_W(ret, fn, cond);
1286 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_BROADCAST,
1287 cond, 0, 0, 0, 0);
1288 return ret;
1291 #if defined(VGO_solaris)
1292 /* On Solaris, pthread_cond_broadcast is a weak alias to cond_broadcast. */
1293 PTH_FUNCS(int, condZubroadcast, pthread_cond_broadcast_intercept,
1294 (pthread_cond_t *cond), (cond));
1295 #else
1296 PTH_FUNCS(int, pthreadZucondZubroadcast, pthread_cond_broadcast_intercept,
1297 (pthread_cond_t* cond), (cond));
1298 #endif /* VGO_solaris */
1300 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1301 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1302 static __always_inline
1303 int pthread_spin_init_intercept(pthread_spinlock_t *spinlock, int pshared)
1305 int ret;
1306 OrigFn fn;
1307 VALGRIND_GET_ORIG_FN(fn);
1308 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SPIN_INIT_OR_UNLOCK,
1309 spinlock, 0, 0, 0, 0);
1310 CALL_FN_W_WW(ret, fn, spinlock, pshared);
1311 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SPIN_INIT_OR_UNLOCK,
1312 spinlock, 0, 0, 0, 0);
1313 return ret;
1316 PTH_FUNCS(int, pthreadZuspinZuinit, pthread_spin_init_intercept,
1317 (pthread_spinlock_t *spinlock, int pshared), (spinlock, pshared));
1319 static __always_inline
1320 int pthread_spin_destroy_intercept(pthread_spinlock_t *spinlock)
1322 int ret;
1323 OrigFn fn;
1324 VALGRIND_GET_ORIG_FN(fn);
1325 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_DESTROY,
1326 spinlock, 0, 0, 0, 0);
1327 CALL_FN_W_W(ret, fn, spinlock);
1328 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_DESTROY,
1329 spinlock, mutex_type_spinlock, 0, 0, 0);
1330 return ret;
1333 PTH_FUNCS(int, pthreadZuspinZudestroy, pthread_spin_destroy_intercept,
1334 (pthread_spinlock_t *spinlock), (spinlock));
1336 static __always_inline
1337 int pthread_spin_lock_intercept(pthread_spinlock_t *spinlock)
1339 int ret;
1340 OrigFn fn;
1341 VALGRIND_GET_ORIG_FN(fn);
1342 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK,
1343 spinlock, mutex_type_spinlock, 0, 0, 0);
1344 CALL_FN_W_W(ret, fn, spinlock);
1345 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK,
1346 spinlock, ret == 0, 0, 0, 0);
1347 return ret;
1350 PTH_FUNCS(int, pthreadZuspinZulock, pthread_spin_lock_intercept,
1351 (pthread_spinlock_t *spinlock), (spinlock));
1353 static __always_inline
1354 int pthread_spin_trylock_intercept(pthread_spinlock_t *spinlock)
1356 int ret;
1357 OrigFn fn;
1358 VALGRIND_GET_ORIG_FN(fn);
1359 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK,
1360 spinlock, mutex_type_spinlock, 0, 0, 0);
1361 CALL_FN_W_W(ret, fn, spinlock);
1362 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK,
1363 spinlock, ret == 0, 0, 0, 0);
1364 return ret;
1367 PTH_FUNCS(int, pthreadZuspinZutrylock, pthread_spin_trylock_intercept,
1368 (pthread_spinlock_t *spinlock), (spinlock));
1370 static __always_inline
1371 int pthread_spin_unlock_intercept(pthread_spinlock_t *spinlock)
1373 int ret;
1374 OrigFn fn;
1375 VALGRIND_GET_ORIG_FN(fn);
1376 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SPIN_INIT_OR_UNLOCK,
1377 spinlock, mutex_type_spinlock, 0, 0, 0);
1378 CALL_FN_W_W(ret, fn, spinlock);
1379 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SPIN_INIT_OR_UNLOCK,
1380 spinlock, 0, 0, 0, 0);
1381 return ret;
1384 PTH_FUNCS(int, pthreadZuspinZuunlock, pthread_spin_unlock_intercept,
1385 (pthread_spinlock_t *spinlock), (spinlock));
1386 #endif // HAVE_PTHREAD_SPIN_LOCK
1389 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1390 static __always_inline
1391 int pthread_barrier_init_intercept(pthread_barrier_t* barrier,
1392 const pthread_barrierattr_t* attr,
1393 unsigned count)
1395 int ret;
1396 OrigFn fn;
1397 VALGRIND_GET_ORIG_FN(fn);
1398 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_BARRIER_INIT,
1399 barrier, pthread_barrier, count, 0, 0);
1400 CALL_FN_W_WWW(ret, fn, barrier, attr, count);
1401 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_BARRIER_INIT,
1402 barrier, pthread_barrier, 0, 0, 0);
1403 return ret;
1406 PTH_FUNCS(int, pthreadZubarrierZuinit, pthread_barrier_init_intercept,
1407 (pthread_barrier_t* barrier, const pthread_barrierattr_t* attr,
1408 unsigned count), (barrier, attr, count));
1410 static __always_inline
1411 int pthread_barrier_destroy_intercept(pthread_barrier_t* barrier)
1413 int ret;
1414 OrigFn fn;
1415 VALGRIND_GET_ORIG_FN(fn);
1416 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_BARRIER_DESTROY,
1417 barrier, pthread_barrier, 0, 0, 0);
1418 CALL_FN_W_W(ret, fn, barrier);
1419 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_BARRIER_DESTROY,
1420 barrier, pthread_barrier, 0, 0, 0);
1421 return ret;
1424 PTH_FUNCS(int, pthreadZubarrierZudestroy, pthread_barrier_destroy_intercept,
1425 (pthread_barrier_t* barrier), (barrier));
1427 static __always_inline
1428 int pthread_barrier_wait_intercept(pthread_barrier_t* barrier)
1430 int ret;
1431 OrigFn fn;
1432 VALGRIND_GET_ORIG_FN(fn);
1433 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_BARRIER_WAIT,
1434 barrier, pthread_barrier, 0, 0, 0);
1435 CALL_FN_W_W(ret, fn, barrier);
1436 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_BARRIER_WAIT,
1437 barrier, pthread_barrier,
1438 ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD,
1439 ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
1440 return ret;
1443 PTH_FUNCS(int, pthreadZubarrierZuwait, pthread_barrier_wait_intercept,
1444 (pthread_barrier_t* barrier), (barrier));
1445 #endif // HAVE_PTHREAD_BARRIER_INIT
1448 static __always_inline
1449 int sem_init_intercept(sem_t *sem, int pshared, unsigned int value)
1451 int ret;
1452 OrigFn fn;
1453 VALGRIND_GET_ORIG_FN(fn);
1454 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_INIT,
1455 sem, pshared, value, 0, 0);
1456 CALL_FN_W_WWW(ret, fn, sem, pshared, value);
1457 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_INIT,
1458 sem, 0, 0, 0, 0);
1459 return ret;
1462 #if defined(VGO_freebsd)
1463 LIBC_FUNC(int, semZuinit, sem_init_intercept,
1464 (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
1465 #else
1466 PTH_FUNCS(int, semZuinit, sem_init_intercept,
1467 (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
1468 #endif
1470 #if defined(VGO_solaris)
1471 static __always_inline
1472 int sema_init_intercept(sema_t *sem, unsigned int value, int type, void *arg)
1474 int ret;
1475 OrigFn fn;
1476 VALGRIND_GET_ORIG_FN(fn);
1477 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_INIT,
1478 sem, type == USYNC_PROCESS ? 1 : 0,
1479 value, 0, 0);
1480 CALL_FN_W_WWWW(ret, fn, sem, value, type, arg);
1481 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_INIT,
1482 sem, 0, 0, 0, 0);
1483 return ret;
1486 PTH_FUNCS(int, semaZuinit, sema_init_intercept,
1487 (sema_t *sem, unsigned int value, int type, void *arg),
1488 (sem, value, type, arg));
1489 #endif /* VGO_solaris */
1491 static __always_inline
1492 int sem_destroy_intercept(sem_t *sem)
1494 int ret;
1495 OrigFn fn;
1496 VALGRIND_GET_ORIG_FN(fn);
1497 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_DESTROY,
1498 sem, 0, 0, 0, 0);
1499 CALL_FN_W_W(ret, fn, sem);
1500 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_DESTROY,
1501 sem, 0, 0, 0, 0);
1502 return ret;
1505 #if defined(VGO_freebsd)
1506 LIBC_FUNC(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1507 #else
1508 PTH_FUNCS(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1509 #endif
1511 #if defined(VGO_solaris)
1512 PTH_FUNCS(int, semaZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1513 #endif /* VGO_solaris */
1515 static __always_inline
1516 sem_t* sem_open_intercept(const char *name, int oflag, mode_t mode,
1517 unsigned int value)
1519 sem_t *ret;
1520 OrigFn fn;
1521 VALGRIND_GET_ORIG_FN(fn);
1522 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_OPEN,
1523 name, oflag, mode, value, 0);
1524 CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value);
1525 // To do: figure out why gcc 9.2.1 miscompiles this function if the printf()
1526 // call below is left out.
1527 printf("");
1528 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_OPEN,
1529 ret != SEM_FAILED ? ret : 0,
1530 name, oflag, mode, value);
1531 return ret;
1534 #if defined(VGO_freebsd)
1535 LIBC_FUNC(sem_t *, semZuopen, sem_open_intercept,
1536 (const char *name, int oflag, mode_t mode, unsigned int value),
1537 (name, oflag, mode, value));
1538 #else
1539 PTH_FUNCS(sem_t *, semZuopen, sem_open_intercept,
1540 (const char *name, int oflag, mode_t mode, unsigned int value),
1541 (name, oflag, mode, value));
1542 #endif
1544 static __always_inline int sem_close_intercept(sem_t *sem)
1546 int ret;
1547 OrigFn fn;
1548 VALGRIND_GET_ORIG_FN(fn);
1549 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_CLOSE,
1550 sem, 0, 0, 0, 0);
1551 CALL_FN_W_W(ret, fn, sem);
1552 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_CLOSE,
1553 sem, 0, 0, 0, 0);
1554 return ret;
1557 #if defined(VGO_freebsd)
1558 LIBC_FUNC(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
1559 #else
1560 PTH_FUNCS(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
1561 #endif
1563 static __always_inline int sem_wait_intercept(sem_t *sem)
1565 int ret;
1566 OrigFn fn;
1567 VALGRIND_GET_ORIG_FN(fn);
1568 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT,
1569 sem, 0, 0, 0, 0);
1570 CALL_FN_W_W(ret, fn, sem);
1571 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT,
1572 sem, ret == 0, 0, 0, 0);
1573 return ret;
1576 #if defined(VGO_freebsd)
1577 LIBC_FUNC(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1578 #else
1579 PTH_FUNCS(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1580 #endif
1582 #if defined(VGO_solaris)
1583 PTH_FUNCS(int, semaZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1584 #endif /* VGO_solaris */
1586 static __always_inline int sem_trywait_intercept(sem_t *sem)
1588 int ret;
1589 OrigFn fn;
1590 VALGRIND_GET_ORIG_FN(fn);
1591 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT,
1592 sem, 0, 0, 0, 0);
1593 CALL_FN_W_W(ret, fn, sem);
1594 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT,
1595 sem, ret == 0, 0, 0, 0);
1596 return ret;
1599 #if defined(VGO_freebsd)
1600 LIBC_FUNC(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1601 #else
1602 PTH_FUNCS(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1603 #endif
1604 #if defined(VGO_solaris)
1605 PTH_FUNCS(int, semaZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1606 #endif /* VGO_solaris */
1608 static __always_inline
1609 int sem_timedwait_intercept(sem_t *sem, const struct timespec *abs_timeout)
1611 int ret;
1612 OrigFn fn;
1613 VALGRIND_GET_ORIG_FN(fn);
1614 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT,
1615 sem, 0, 0, 0, 0);
1616 CALL_FN_W_WW(ret, fn, sem, abs_timeout);
1617 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT,
1618 sem, ret == 0, 0, 0, 0);
1619 return ret;
1622 #if defined(VGO_freebsd)
1623 LIBC_FUNC(int, semZutimedwait, sem_timedwait_intercept,
1624 (sem_t *sem, const struct timespec *abs_timeout),
1625 (sem, abs_timeout));
1626 #else
1627 PTH_FUNCS(int, semZutimedwait, sem_timedwait_intercept,
1628 (sem_t *sem, const struct timespec *abs_timeout),
1629 (sem, abs_timeout));
1630 #endif
1631 #if defined(VGO_solaris)
1632 PTH_FUNCS(int, semaZutimedwait, sem_timedwait_intercept,
1633 (sem_t *sem, const struct timespec *timeout),
1634 (sem, timeout));
1635 PTH_FUNCS(int, semaZureltimedwait, sem_timedwait_intercept,
1636 (sem_t *sem, const struct timespec *timeout),
1637 (sem, timeout));
1638 #endif /* VGO_solaris */
1640 #if defined(VGO_freebsd)
1641 static __always_inline
1642 int sem_clockwait_np_intercept(sem_t* sem, clockid_t clock_id, int flags,
1643 const struct timespec * rqtp, struct timespec * rmtp)
1645 int ret;
1646 OrigFn fn;
1647 VALGRIND_GET_ORIG_FN(fn);
1648 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT,
1649 sem, 0, 0, 0, 0);
1650 CALL_FN_W_5W(ret, fn, sem, clock_id, flags, rqtp, rmtp);
1651 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT,
1652 sem, ret == 0, 0, 0, 0);
1653 return ret;
1656 LIBC_FUNC(int, semZuclockwaitZunp, sem_clockwait_np_intercept,
1657 (sem_t* sem, clockid_t clock_id, int flags,
1658 const struct timespec * rqtp, struct timespec * rmtp),
1659 (sem, clock_id, flags, rqtp, rmtp));
1660 #endif
1662 static __always_inline int sem_post_intercept(sem_t *sem)
1664 int ret;
1665 OrigFn fn;
1666 VALGRIND_GET_ORIG_FN(fn);
1667 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_POST,
1668 sem, 0, 0, 0, 0);
1669 CALL_FN_W_W(ret, fn, sem);
1670 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_POST,
1671 sem, ret == 0, 0, 0, 0);
1672 return ret;
1675 #if defined(VGO_freebsd)
1676 LIBC_FUNC(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
1677 #else
1678 PTH_FUNCS(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
1679 #endif
1680 #if defined(VGO_solaris)
1681 PTH_FUNCS(int, semaZupost, sem_post_intercept, (sem_t *sem), (sem));
1682 #endif /* VGO_solaris */
1684 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1685 functions have to be conditionally compiled. */
1686 #if defined(HAVE_PTHREAD_RWLOCK_T)
1688 static __always_inline
1689 int pthread_rwlock_init_intercept(pthread_rwlock_t* rwlock,
1690 const pthread_rwlockattr_t* attr)
1692 int ret;
1693 OrigFn fn;
1694 VALGRIND_GET_ORIG_FN(fn);
1695 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_INIT,
1696 rwlock, 0, 0, 0, 0);
1697 CALL_FN_W_WW(ret, fn, rwlock, attr);
1698 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_INIT,
1699 rwlock, 0, 0, 0, 0);
1700 return ret;
1703 PTH_FUNCS(int,
1704 pthreadZurwlockZuinit, pthread_rwlock_init_intercept,
1705 (pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr),
1706 (rwlock, attr));
1708 #if defined(VGO_solaris)
1709 static __always_inline
1710 int rwlock_init_intercept(rwlock_t *rwlock, int type, void *arg)
1712 int ret;
1713 OrigFn fn;
1714 VALGRIND_GET_ORIG_FN(fn);
1715 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_INIT,
1716 rwlock, 0, 0, 0, 0);
1717 CALL_FN_W_WWW(ret, fn, rwlock, type, arg);
1718 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_INIT,
1719 rwlock, 0, 0, 0, 0);
1720 return ret;
1723 PTH_FUNCS(int, rwlockZuinit, rwlock_init_intercept,
1724 (rwlock_t *rwlock, int type, void *arg),
1725 (rwlock, type, arg));
1726 #endif /* VGO_solaris */
1728 static __always_inline
1729 int pthread_rwlock_destroy_intercept(pthread_rwlock_t* rwlock)
1731 int ret;
1732 OrigFn fn;
1733 VALGRIND_GET_ORIG_FN(fn);
1734 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_DESTROY,
1735 rwlock, 0, 0, 0, 0);
1736 CALL_FN_W_W(ret, fn, rwlock);
1737 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_DESTROY,
1738 rwlock, 0, 0, 0, 0);
1739 return ret;
1742 #if defined(VGO_solaris)
1743 /* On Solaris, pthread_rwlock_destroy is a weak alias to rwlock_destroy. */
1744 PTH_FUNCS(int,
1745 rwlockZudestroy, pthread_rwlock_destroy_intercept,
1746 (pthread_rwlock_t *rwlock), (rwlock));
1747 #else
1748 PTH_FUNCS(int,
1749 pthreadZurwlockZudestroy, pthread_rwlock_destroy_intercept,
1750 (pthread_rwlock_t* rwlock), (rwlock));
1751 #endif /* VGO_solaris */
1753 static __always_inline
1754 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t* rwlock)
1756 int ret;
1757 OrigFn fn;
1758 VALGRIND_GET_ORIG_FN(fn);
1759 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK,
1760 rwlock, 0, 0, 0, 0);
1761 CALL_FN_W_W(ret, fn, rwlock);
1762 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK,
1763 rwlock, ret == 0, 0, 0, 0);
1764 return ret;
1767 #if defined(VGO_solaris)
1768 /* On Solaris, pthread_rwlock_rdlock is a weak alias to rw_rdlock. */
1769 PTH_FUNCS(int,
1770 rwZurdlock, pthread_rwlock_rdlock_intercept,
1771 (pthread_rwlock_t *rwlock), (rwlock));
1772 #else
1773 PTH_FUNCS(int,
1774 pthreadZurwlockZurdlock, pthread_rwlock_rdlock_intercept,
1775 (pthread_rwlock_t* rwlock), (rwlock));
1776 #endif /* VGO_solaris */
1778 #if defined(VGO_solaris)
1779 /* Internal to libc. */
1780 static __always_inline
1781 void lrw_rdlock_intercept(rwlock_t *rwlock)
1783 OrigFn fn;
1784 VALGRIND_GET_ORIG_FN(fn);
1785 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK,
1786 rwlock, 0, 0, 0, 0);
1787 CALL_FN_v_W(fn, rwlock);
1788 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK,
1789 rwlock, True /* took_lock */, 0, 0, 0);
1792 PTH_FUNCS(void, lrwZurdlock, lrw_rdlock_intercept,
1793 (rwlock_t *rwlock), (rwlock));
1794 #endif /* VGO_solaris */
1796 static __always_inline
1797 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t* rwlock)
1799 int ret;
1800 OrigFn fn;
1801 VALGRIND_GET_ORIG_FN(fn);
1802 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK,
1803 rwlock, 0, 0, 0, 0);
1804 CALL_FN_W_W(ret, fn, rwlock);
1805 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK,
1806 rwlock, ret == 0, 0, 0, 0);
1807 return ret;
1810 #if defined(VGO_solaris)
1811 /* On Solaris, pthread_rwlock_wrlock is a weak alias to rw_wrlock. */
1812 PTH_FUNCS(int,
1813 rwZuwrlock, pthread_rwlock_wrlock_intercept,
1814 (pthread_rwlock_t *rwlock), (rwlock));
1815 #else
1816 PTH_FUNCS(int,
1817 pthreadZurwlockZuwrlock, pthread_rwlock_wrlock_intercept,
1818 (pthread_rwlock_t* rwlock), (rwlock));
1819 #endif /* VGO_solaris */
1821 #if defined(VGO_solaris)
1822 /* Internal to libc. */
1823 static __always_inline
1824 void lrw_wrlock_intercept(rwlock_t *rwlock)
1826 OrigFn fn;
1827 VALGRIND_GET_ORIG_FN(fn);
1828 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK,
1829 rwlock, 0, 0, 0, 0);
1830 CALL_FN_v_W(fn, rwlock);
1831 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK,
1832 rwlock, True /* took_lock */, 0, 0, 0);
1835 PTH_FUNCS(void, lrwZuwrlock, lrw_wrlock_intercept,
1836 (rwlock_t *rwlock), (rwlock));
1837 #endif /* VGO_solaris */
1839 static __always_inline
1840 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t* rwlock,
1841 const struct timespec *timeout)
1843 int ret;
1844 OrigFn fn;
1845 VALGRIND_GET_ORIG_FN(fn);
1846 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK,
1847 rwlock, 0, 0, 0, 0);
1848 CALL_FN_W_WW(ret, fn, rwlock, timeout);
1849 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK,
1850 rwlock, ret == 0, 0, 0, 0);
1851 return ret;
1854 PTH_FUNCS(int,
1855 pthreadZurwlockZutimedrdlock, pthread_rwlock_timedrdlock_intercept,
1856 (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1857 (rwlock, timeout));
1858 #if defined(VGO_solaris)
1859 PTH_FUNCS(int, pthreadZurwlockZureltimedrdlockZunp,
1860 pthread_rwlock_timedrdlock_intercept,
1861 (pthread_rwlock_t *rwlock, const struct timespec *timeout),
1862 (rwlock, timeout));
1863 #endif /* VGO_solaris */
1866 #if defined(HAVE_CLOCKID_T)
1867 static __always_inline
1868 int pthread_rwlock_clockrdlock_intercept(pthread_rwlock_t* rwlock,
1869 clockid_t clockid,
1870 const struct timespec *timeout)
1872 int ret;
1873 OrigFn fn;
1874 VALGRIND_GET_ORIG_FN(fn);
1875 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK,
1876 rwlock, 0, 0, 0, 0);
1877 CALL_FN_W_WWW(ret, fn, rwlock, clockid, timeout);
1878 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK,
1879 rwlock, ret == 0, 0, 0, 0);
1880 return ret;
1883 PTH_FUNCS(int,
1884 pthreadZurwlockZuclockrdlock, pthread_rwlock_clockrdlock_intercept,
1885 (pthread_rwlock_t* rwlock, clockid_t clockid, const struct timespec *timeout),
1886 (rwlock, clockid, timeout));
1887 #endif
1889 static __always_inline
1890 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t* rwlock,
1891 const struct timespec *timeout)
1893 int ret;
1894 OrigFn fn;
1895 VALGRIND_GET_ORIG_FN(fn);
1896 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK,
1897 rwlock, 0, 0, 0, 0);
1898 CALL_FN_W_WW(ret, fn, rwlock, timeout);
1899 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK,
1900 rwlock, ret == 0, 0, 0, 0);
1901 return ret;
1904 PTH_FUNCS(int,
1905 pthreadZurwlockZutimedwrlock, pthread_rwlock_timedwrlock_intercept,
1906 (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1907 (rwlock, timeout));
1908 #if defined(VGO_solaris)
1909 PTH_FUNCS(int, pthreadZurwlockZureltimedwrlockZunp,
1910 pthread_rwlock_timedwrlock_intercept,
1911 (pthread_rwlock_t *rwlock, const struct timespec *timeout),
1912 (rwlock, timeout));
1913 #endif /* VGO_solaris */
1916 #if defined(HAVE_CLOCKID_T)
1917 static __always_inline
1918 int pthread_rwlock_clockwrlock_intercept(pthread_rwlock_t* rwlock,
1919 clockid_t clockid,
1920 const struct timespec *timeout)
1922 int ret;
1923 OrigFn fn;
1924 VALGRIND_GET_ORIG_FN(fn);
1925 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK,
1926 rwlock, 0, 0, 0, 0);
1927 CALL_FN_W_WWW(ret, fn, rwlock, clockid, timeout);
1928 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK,
1929 rwlock, ret == 0, 0, 0, 0);
1930 return ret;
1933 PTH_FUNCS(int,
1934 pthreadZurwlockZuclockwrlock, pthread_rwlock_clockwrlock_intercept,
1935 (pthread_rwlock_t* rwlock, clockid_t clockid, const struct timespec *timeout),
1936 (rwlock, clockid, timeout));
1937 #endif
1940 static __always_inline
1941 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t* rwlock)
1943 int ret;
1944 OrigFn fn;
1945 VALGRIND_GET_ORIG_FN(fn);
1946 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK,
1947 rwlock, 0, 0, 0, 0);
1948 CALL_FN_W_W(ret, fn, rwlock);
1949 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK,
1950 rwlock, ret == 0, 0, 0, 0);
1951 return ret;
1954 #if defined(VGO_solaris)
1955 /* On Solaris, pthread_rwlock_tryrdlock is a weak alias to rw_tryrdlock. */
1956 PTH_FUNCS(int,
1957 rwZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1958 (pthread_rwlock_t *rwlock), (rwlock));
1959 #else
1960 PTH_FUNCS(int,
1961 pthreadZurwlockZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1962 (pthread_rwlock_t* rwlock), (rwlock));
1963 #endif /* VGO_solaris */
1965 static __always_inline
1966 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t* rwlock)
1968 int ret;
1969 OrigFn fn;
1970 VALGRIND_GET_ORIG_FN(fn);
1971 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK,
1972 rwlock, 0, 0, 0, 0);
1973 CALL_FN_W_W(ret, fn, rwlock);
1974 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK,
1975 rwlock, ret == 0, 0, 0, 0);
1976 return ret;
1979 #if defined(VGO_solaris)
1980 /* On Solaris, pthread_rwlock_trywrlock is a weak alias to rw_trywrlock. */
1981 PTH_FUNCS(int,
1982 rwZutrywrlock, pthread_rwlock_trywrlock_intercept,
1983 (pthread_rwlock_t *rwlock), (rwlock));
1984 #else
1985 PTH_FUNCS(int,
1986 pthreadZurwlockZutrywrlock, pthread_rwlock_trywrlock_intercept,
1987 (pthread_rwlock_t* rwlock), (rwlock));
1988 #endif /* VGO_solaris */
1990 static __always_inline
1991 int pthread_rwlock_unlock_intercept(pthread_rwlock_t* rwlock)
1993 int ret;
1994 OrigFn fn;
1995 VALGRIND_GET_ORIG_FN(fn);
1996 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_UNLOCK,
1997 rwlock, 0, 0, 0, 0);
1998 CALL_FN_W_W(ret, fn, rwlock);
1999 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_UNLOCK,
2000 rwlock, ret == 0, 0, 0, 0);
2001 return ret;
2004 #if defined(VGO_solaris)
2005 /* On Solaris, pthread_rwlock_unlock is a weak alias to rw_unlock. */
2006 PTH_FUNCS(int,
2007 rwZuunlock, pthread_rwlock_unlock_intercept,
2008 (pthread_rwlock_t *rwlock), (rwlock));
2009 #else
2010 PTH_FUNCS(int,
2011 pthreadZurwlockZuunlock, pthread_rwlock_unlock_intercept,
2012 (pthread_rwlock_t* rwlock), (rwlock));
2013 #endif /* VGO_solaris */
2015 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */