linux arm regtest: leak_cpp_interior try again
[valgrind.git] / drd / drd_pthread_intercepts.c
blob806aee74aa3ea79919b0bd03b3be5449aef760b3
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 dlclose(dlopen("/lib/libthr.so.3", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE));
290 #endif
292 DRD_(check_threading_library)();
293 DRD_(set_pthread_id)();
294 #if defined(VGO_solaris)
295 if ((DRD_(rtld_bind_guard) == NULL) || (DRD_(rtld_bind_clear) == NULL)) {
296 fprintf(stderr,
297 "Bind guard functions for the runtime linker (ld.so.1) were not intercepted.\n"
298 "This means the interface between libc and runtime linker changed and DRD\n"
299 "needs to be ported properly. Giving up.\n");
300 abort();
302 #endif
305 static __always_inline void DRD_(ignore_mutex_ordering)(pthread_mutex_t *mutex)
307 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_IGNORE_MUTEX_ORDERING,
308 mutex, 0, 0, 0, 0);
311 static void DRD_(sema_init)(DrdSema* sema)
313 DRD_IGNORE_VAR(*sema);
314 pthread_mutex_init(&sema->mutex, NULL);
315 DRD_(ignore_mutex_ordering)(&sema->mutex);
316 pthread_cond_init(&sema->cond, NULL);
317 sema->counter = 0;
320 static void DRD_(sema_destroy)(DrdSema* sema)
322 pthread_mutex_destroy(&sema->mutex);
323 pthread_cond_destroy(&sema->cond);
326 static void DRD_(sema_down)(DrdSema* sema)
328 pthread_mutex_lock(&sema->mutex);
329 while (sema->counter == 0)
330 pthread_cond_wait(&sema->cond, &sema->mutex);
331 sema->counter--;
332 pthread_mutex_unlock(&sema->mutex);
335 static void DRD_(sema_up)(DrdSema* sema)
337 pthread_mutex_lock(&sema->mutex);
338 sema->counter++;
339 pthread_cond_signal(&sema->cond);
340 pthread_mutex_unlock(&sema->mutex);
344 * POSIX threads and DRD each have their own mutex type identification.
345 * Convert POSIX threads' mutex type to DRD's mutex type. In the code below
346 * if-statements are used to test the value of 'kind' instead of a switch
347 * statement because some of the PTHREAD_MUTEX_ macro's may have the same
348 * value.
350 static MutexT DRD_(pthread_to_drd_mutex_type)(int kind)
353 * Static checkers don't like this as there are repeated branch
354 * but because there is variation between different platforms
355 * it's messy to make something without repetition.
357 * See also PTHREAD_MUTEX_KIND_MASK_NP in glibc source file
358 * <nptl/pthreadP.h>.
360 kind &= PTHREAD_MUTEX_RECURSIVE | PTHREAD_MUTEX_ERRORCHECK |
361 PTHREAD_MUTEX_NORMAL | PTHREAD_MUTEX_DEFAULT;
363 if (kind == PTHREAD_MUTEX_RECURSIVE) {
364 return mutex_type_recursive_mutex;
366 if (kind == PTHREAD_MUTEX_ERRORCHECK) {
367 return mutex_type_errorcheck_mutex;
369 if (kind == PTHREAD_MUTEX_NORMAL) {
370 return mutex_type_default_mutex;
372 if (kind == PTHREAD_MUTEX_DEFAULT) {
373 // On FreeBSD PTHREAD_MUTEX_DEFAULT is the same as PTHREAD_MUTEX_ERRORCHECK
374 // so this code is unreachable, but that's not true for all platforms
375 // so just ignore the warning
376 // coverity[DEADCODE:FALSE]
377 return mutex_type_default_mutex;
379 #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
380 if (kind == PTHREAD_MUTEX_ADAPTIVE_NP) {
381 return mutex_type_default_mutex;
383 #endif
384 return mutex_type_invalid_mutex;
387 #if defined(VGO_solaris)
389 * Solaris threads and DRD each have their own mutex type identification.
390 * Convert Solaris threads' mutex type to DRD's mutex type.
392 static MutexT DRD_(thread_to_drd_mutex_type)(int type)
394 if (type & LOCK_RECURSIVE) {
395 return mutex_type_recursive_mutex;
396 } else if (type & LOCK_ERRORCHECK) {
397 return mutex_type_errorcheck_mutex;
398 } else {
399 return mutex_type_default_mutex;
402 #endif /* VGO_solaris */
404 #define IS_ALIGNED(p) (((uintptr_t)(p) & (sizeof(*(p)) - 1)) == 0)
407 * Read the mutex type stored in the client memory used for the mutex
408 * implementation.
410 * @note This function depends on the implementation of the POSIX threads
411 * library -- the POSIX standard does not define the name of the member in
412 * which the mutex type is stored.
413 * @note The function mutex_type() has been declared inline in order
414 * to avoid that it shows up in call stacks (drd/tests/...exp* files).
415 * @note glibc stores the mutex type in the lowest two bits, and uses the
416 * higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
417 * PTHREAD_MUTEXATTR_FLAG_PSHARED.
419 static __always_inline MutexT DRD_(mutex_type)(pthread_mutex_t* mutex)
421 MutexT mutex_type = mutex_type_unknown;
423 ANNOTATE_IGNORE_READS_BEGIN();
424 #if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
425 /* glibc + LinuxThreads. */
426 if (IS_ALIGNED(&mutex->__m_kind))
428 const int kind = mutex->__m_kind & 3;
429 mutex_type = DRD_(pthread_to_drd_mutex_type)(kind);
431 #elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
432 /* glibc + NPTL. */
433 if (IS_ALIGNED(&mutex->__data.__kind))
435 const int kind = mutex->__data.__kind & 3;
436 mutex_type = DRD_(pthread_to_drd_mutex_type)(kind);
438 #elif defined(VGO_solaris)
440 const int type = ((mutex_t *) mutex)->vki_mutex_type;
441 mutex_type = DRD_(thread_to_drd_mutex_type)(type);
443 #else
445 * Another POSIX threads implementation. The mutex type won't be printed
446 * when enabling --trace-mutex=yes.
448 #endif
449 ANNOTATE_IGNORE_READS_END();
451 return mutex_type;
455 * Tell DRD whether 'tid' is a joinable thread or a detached thread.
457 static void DRD_(set_joinable)(const pthread_t tid, const int joinable)
459 assert(joinable == 0 || joinable == 1);
460 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_SET_JOINABLE,
461 tid, joinable, 0, 0, 0);
464 /** Tell DRD that the calling thread is about to enter pthread_create(). */
465 static __always_inline void DRD_(entering_pthread_create)(void)
467 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_ENTERING_PTHREAD_CREATE,
468 0, 0, 0, 0, 0);
471 /** Tell DRD that the calling thread has left pthread_create(). */
472 static __always_inline void DRD_(left_pthread_create)(void)
474 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_LEFT_PTHREAD_CREATE,
475 0, 0, 0, 0, 0);
479 * Entry point for newly created threads. This function is called from the
480 * thread created by pthread_create().
482 static void* DRD_(thread_wrapper)(void* arg)
484 DrdPosixThreadArgs* arg_ptr;
485 DrdPosixThreadArgs arg_copy;
487 arg_ptr = (DrdPosixThreadArgs*)arg;
488 arg_copy = *arg_ptr;
490 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_SET_PTHREADID,
491 pthread_self(), 0, 0, 0, 0);
493 DRD_(set_joinable)(pthread_self(),
494 arg_copy.detachstate == PTHREAD_CREATE_JOINABLE);
497 * Only set 'wrapper_started' after VG_USERREQ__SET_PTHREADID and
498 * DRD_(set_joinable)() have been invoked to avoid a race with
499 * a pthread_detach() invocation for this thread from another thread.
501 DRD_(sema_up)(arg_copy.wrapper_started);
503 return (arg_copy.start)(arg_copy.arg);
507 * Return 1 if the LinuxThreads implementation of POSIX Threads has been
508 * detected, and 0 otherwise.
510 * @see For more information about the confstr() function, see also
511 * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
513 static int DRD_(detected_linuxthreads)(void)
515 #if defined(linux)
516 #if defined(_CS_GNU_LIBPTHREAD_VERSION)
517 /* Linux with a recent glibc. */
518 HChar buffer[256];
519 unsigned len;
520 len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
521 assert(len <= sizeof(buffer));
522 return len > 0 && buffer[0] == 'l';
523 #else
524 /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
525 return 1;
526 #endif
527 #else
528 /* Another OS than Linux, hence no LinuxThreads. */
529 return 0;
530 #endif
534 * Stop and print an error message in case a non-supported threading
535 * library implementation (LinuxThreads) has been detected.
537 static void DRD_(check_threading_library)(void)
539 if (DRD_(detected_linuxthreads)())
541 if (getenv("LD_ASSUME_KERNEL"))
543 fprintf(stderr,
544 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
545 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
546 "after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
549 else
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 upgraded to a newer version of your Linux distribution.\n"
555 "Giving up.\n"
558 abort();
563 * Update DRD's state information about the current thread.
565 static void DRD_(set_pthread_id)(void)
567 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_SET_PTHREADID,
568 pthread_self(), 0, 0, 0, 0);
572 * Note: as of today there exist three different versions of pthread_create
573 * in Linux:
574 * - pthread_create@GLIBC_2.0
575 * - pthread_create@@GLIBC_2.1
576 * - pthread_create@@GLIBC_2.2.5
577 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
578 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
579 * versions have been implemented. In any glibc version where more than one
580 * pthread_create function has been implemented, older versions call the
581 * newer versions. Or: the pthread_create* wrapper defined below can be
582 * called recursively. Any code in this wrapper should take this in account.
583 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
584 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
585 * See also the implementation of pthread_create@GLIBC_2.0 in
586 * glibc-2.9/nptl/pthread_create.c.
589 static __always_inline
590 int pthread_create_intercept(pthread_t* thread, const pthread_attr_t* attr,
591 void* (*start)(void*), void* arg)
593 int ret;
594 OrigFn fn;
595 DrdSema wrapper_started;
596 DrdPosixThreadArgs thread_args;
598 VALGRIND_GET_ORIG_FN(fn);
600 DRD_(sema_init)(&wrapper_started);
601 thread_args.start = start;
602 thread_args.arg = arg;
603 thread_args.wrapper_started = &wrapper_started;
605 * Find out whether the thread will be started as a joinable thread
606 * or as a detached thread. If no thread attributes have been specified,
607 * this means that the new thread will be started as a joinable thread.
609 thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
610 /* The C11 thrd_create() implementation passes -1 as 'attr' argument. */
611 if (attr && (uintptr_t)attr + 1 != 0)
613 if (pthread_attr_getdetachstate(attr, &thread_args.detachstate) != 0)
614 assert(0);
616 assert(thread_args.detachstate == PTHREAD_CREATE_JOINABLE
617 || thread_args.detachstate == PTHREAD_CREATE_DETACHED);
620 * The DRD_(set_pthread_id)() from DRD_(init)() may encounter that
621 * pthread_self() == 0, e.g. when the main program is not linked with the
622 * pthread library and when a pthread_create() call occurs from within a
623 * shared library. Hence call DRD_(set_pthread_id)() again to ensure that
624 * DRD knows the identity of the current thread. See also B.Z. 356374.
626 DRD_(set_pthread_id)();
627 DRD_(entering_pthread_create)();
628 CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), &thread_args);
629 DRD_(left_pthread_create)();
631 if (ret == 0) {
632 /* Wait until the thread wrapper started. */
633 DRD_(sema_down)(&wrapper_started);
636 DRD_(sema_destroy)(&wrapper_started);
638 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_START_NEW_SEGMENT,
639 pthread_self(), 0, 0, 0, 0);
641 return ret;
644 PTH_FUNCS(int, pthreadZucreate, pthread_create_intercept,
645 (pthread_t *thread, const pthread_attr_t *attr,
646 void *(*start) (void *), void *arg),
647 (thread, attr, start, arg));
649 #if defined(VGO_solaris)
650 /* Solaris also provides thr_create() in addition to pthread_create().
651 * Both pthread_create(3C) and thr_create(3C) are based on private
652 * _thrp_create().
654 static __always_inline
655 int thr_create_intercept(void *stk, size_t stksize, void *(*start)(void *),
656 void *arg, long flags, thread_t *new_thread)
658 int ret;
659 OrigFn fn;
660 DrdSema wrapper_started;
661 DrdPosixThreadArgs thread_args;
663 VALGRIND_GET_ORIG_FN(fn);
665 DRD_(sema_init)(&wrapper_started);
666 thread_args.start = start;
667 thread_args.arg = arg;
668 thread_args.wrapper_started = &wrapper_started;
670 * Find out whether the thread will be started as a joinable thread
671 * or as a detached thread.
673 if (flags & THR_DETACHED)
674 thread_args.detachstate = PTHREAD_CREATE_DETACHED;
675 else
676 thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
678 DRD_(entering_pthread_create)();
679 CALL_FN_W_6W(ret, fn, stk, stksize, DRD_(thread_wrapper), &thread_args,
680 flags, new_thread);
681 DRD_(left_pthread_create)();
683 if (ret == 0) {
684 /* Wait until the thread wrapper started. */
685 DRD_(sema_down)(&wrapper_started);
688 DRD_(sema_destroy)(&wrapper_started);
690 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_START_NEW_SEGMENT,
691 pthread_self(), 0, 0, 0, 0);
693 return ret;
696 PTH_FUNCS(int, thrZucreate, thr_create_intercept,
697 (void *stk, size_t stksize, void *(*start)(void *), void *arg,
698 long flags, thread_t *new_thread),
699 (stk, stksize, start, arg, flags, new_thread));
700 #endif /* VGO_solaris */
702 #if defined(VGO_solaris)
704 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
705 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
706 * and CI_BIND_CLEAR, to provide resilience against function renaming.
708 static __always_inline
709 int DRD_(_ti_bind_guard_intercept)(int flags) {
710 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_RTLD_BIND_GUARD,
711 flags, 0, 0, 0, 0);
712 return DRD_(rtld_bind_guard)(flags);
715 static __always_inline
716 int DRD_(_ti_bind_clear_intercept)(int flags) {
717 int ret = DRD_(rtld_bind_clear)(flags);
718 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_RTLD_BIND_CLEAR,
719 flags, 0, 0, 0, 0);
720 return ret;
724 * Wrapped _ld_libc() from the runtime linker ld.so.1.
726 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr);
727 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr)
729 OrigFn fn;
730 int tag;
732 VALGRIND_GET_ORIG_FN(fn);
734 vki_Lc_interface *funcs = ptr;
735 for (tag = funcs->ci_tag; tag != 0; tag = (++funcs)->ci_tag) {
736 switch (tag) {
737 case VKI_CI_BIND_GUARD:
738 if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_guard_intercept)) {
739 DRD_(rtld_bind_guard) = funcs->vki_ci_un.ci_func;
740 funcs->vki_ci_un.ci_func = DRD_(_ti_bind_guard_intercept);
742 break;
743 case VKI_CI_BIND_CLEAR:
744 if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_clear_intercept)) {
745 DRD_(rtld_bind_clear) = funcs->vki_ci_un.ci_func;
746 funcs->vki_ci_un.ci_func = DRD_(_ti_bind_clear_intercept);
748 break;
752 CALL_FN_v_W(fn, ptr);
754 #endif /* VGO_solaris */
756 static __always_inline
757 int pthread_join_intercept(pthread_t pt_joinee, void **thread_return)
759 int ret;
760 OrigFn fn;
762 VALGRIND_GET_ORIG_FN(fn);
764 * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
765 * implementation triggers a (false positive) race report.
767 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
768 CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
769 if (ret == 0)
771 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_THREAD_JOIN,
772 pt_joinee, 0, 0, 0, 0);
774 ANNOTATE_IGNORE_READS_AND_WRITES_END();
775 return ret;
778 PTH_FUNCS(int, pthreadZujoin, pthread_join_intercept,
779 (pthread_t pt_joinee, void **thread_return),
780 (pt_joinee, thread_return));
782 #if defined(VGO_solaris)
783 /* Solaris also provides thr_join() in addition to pthread_join().
784 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
786 * :TODO: No functionality is currently provided for joinee == 0 and departed.
787 * This would require another client request, of course.
789 static __always_inline
790 int thr_join_intercept(thread_t joinee, thread_t *departed, void **thread_return)
792 int ret;
793 OrigFn fn;
795 VALGRIND_GET_ORIG_FN(fn);
796 CALL_FN_W_WWW(ret, fn, joinee, departed, thread_return);
797 if (ret == 0)
799 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_THREAD_JOIN,
800 joinee, 0, 0, 0, 0);
802 return ret;
805 PTH_FUNCS(int, thrZujoin, thr_join_intercept,
806 (thread_t joinee, thread_t *departed, void **thread_return),
807 (joinee, departed, thread_return));
808 #endif /* VGO_solaris */
810 static __always_inline
811 int pthread_detach_intercept(pthread_t pt_thread)
813 int ret;
814 OrigFn fn;
816 VALGRIND_GET_ORIG_FN(fn);
817 CALL_FN_W_W(ret, fn, pt_thread);
818 DRD_(set_joinable)(pt_thread, 0);
820 return ret;
823 PTH_FUNCS(int, pthreadZudetach, pthread_detach_intercept,
824 (pthread_t thread), (thread));
826 // NOTE: be careful to intercept only pthread_cancel() and not
827 // pthread_cancel_init() on Linux.
829 static __always_inline
830 int pthread_cancel_intercept(pthread_t pt_thread)
832 int ret;
833 OrigFn fn;
834 VALGRIND_GET_ORIG_FN(fn);
835 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_THREAD_CANCEL,
836 pt_thread, 0, 0, 0, 0);
837 CALL_FN_W_W(ret, fn, pt_thread);
838 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_THREAD_CANCEL,
839 pt_thread, ret==0, 0, 0, 0);
840 return ret;
843 PTH_FUNCS(int, pthreadZucancel, pthread_cancel_intercept,
844 (pthread_t thread), (thread))
846 static __always_inline
847 int pthread_once_intercept(pthread_once_t *once_control,
848 void (*init_routine)(void))
850 int ret;
851 OrigFn fn;
852 VALGRIND_GET_ORIG_FN(fn);
854 * Ignore any data races triggered by the implementation of pthread_once().
855 * Necessary for Darwin. This is not necessary for Linux but doesn't have
856 * any known adverse effects.
858 DRD_IGNORE_VAR(*once_control);
859 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
860 CALL_FN_W_WW(ret, fn, once_control, init_routine);
861 ANNOTATE_IGNORE_READS_AND_WRITES_END();
862 DRD_STOP_IGNORING_VAR(*once_control);
863 return ret;
866 PTH_FUNCS(int, pthreadZuonce, pthread_once_intercept,
867 (pthread_once_t *once_control, void (*init_routine)(void)),
868 (once_control, init_routine));
870 static __always_inline
871 int pthread_mutex_init_intercept(pthread_mutex_t *mutex,
872 const pthread_mutexattr_t* attr)
874 int ret;
875 OrigFn fn;
876 int mt;
877 VALGRIND_GET_ORIG_FN(fn);
878 mt = PTHREAD_MUTEX_DEFAULT;
879 if (attr)
880 pthread_mutexattr_gettype(attr, &mt);
881 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_INIT,
882 mutex, DRD_(pthread_to_drd_mutex_type)(mt),
883 0, 0, 0);
884 CALL_FN_W_WW(ret, fn, mutex, attr);
885 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_INIT,
886 mutex, 0, 0, 0, 0);
887 return ret;
890 PTH_FUNCS(int, pthreadZumutexZuinit, pthread_mutex_init_intercept,
891 (pthread_mutex_t *mutex, const pthread_mutexattr_t* attr),
892 (mutex, attr));
894 #if defined(VGO_solaris)
895 static __always_inline
896 int mutex_init_intercept(mutex_t *mutex, int type, void *arg)
898 int ret;
899 OrigFn fn;
900 VALGRIND_GET_ORIG_FN(fn);
902 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_INIT,
903 mutex, DRD_(thread_to_drd_mutex_type)(type),
904 0, 0, 0);
905 CALL_FN_W_WWW(ret, fn, mutex, type, arg);
906 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_INIT,
907 mutex, 0, 0, 0, 0);
908 return ret;
911 PTH_FUNCS(int, mutexZuinit, mutex_init_intercept,
912 (mutex_t *mutex, int type, void *arg),
913 (mutex, type, arg));
914 #endif /* VGO_solaris */
916 static __always_inline
917 int pthread_mutex_destroy_intercept(pthread_mutex_t* mutex)
919 int ret;
920 OrigFn fn;
921 VALGRIND_GET_ORIG_FN(fn);
922 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_DESTROY,
923 mutex, 0, 0, 0, 0);
924 CALL_FN_W_W(ret, fn, mutex);
925 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_DESTROY,
926 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
927 return ret;
930 #if defined(VGO_solaris)
931 /* On Solaris, pthread_mutex_destroy is a weak alias to mutex_destroy. */
932 PTH_FUNCS(int, mutexZudestroy, pthread_mutex_destroy_intercept,
933 (pthread_mutex_t *mutex), (mutex));
934 #else
935 PTH_FUNCS(int, pthreadZumutexZudestroy, pthread_mutex_destroy_intercept,
936 (pthread_mutex_t *mutex), (mutex));
937 #endif /* VGO_solaris */
939 static __always_inline
940 int pthread_mutex_lock_intercept(pthread_mutex_t* mutex)
942 int ret;
943 OrigFn fn;
944 VALGRIND_GET_ORIG_FN(fn);
945 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK,
946 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
947 CALL_FN_W_W(ret, fn, mutex);
948 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK,
949 mutex, ret == 0, 0, 0, 0);
950 return ret;
953 #if defined(VGO_solaris)
954 /* On Solaris, pthread_mutex_lock is a weak alias to mutex_lock. */
955 PTH_FUNCS(int, mutexZulock, pthread_mutex_lock_intercept,
956 (pthread_mutex_t *mutex), (mutex));
957 #else
958 PTH_FUNCS(int, pthreadZumutexZulock, pthread_mutex_lock_intercept,
959 (pthread_mutex_t *mutex), (mutex));
960 #endif /* VGO_solaris */
962 #if defined(VGO_solaris)
963 /* Internal to libc. Mutex is usually initialized only implicitly,
964 * by zeroing mutex_t structure.
966 static __always_inline
967 void lmutex_lock_intercept(mutex_t *mutex)
969 OrigFn fn;
970 VALGRIND_GET_ORIG_FN(fn);
971 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK,
972 mutex,
973 DRD_(mutex_type)((pthread_mutex_t *) mutex),
974 False /* try_lock */, 0, 0);
975 CALL_FN_v_W(fn, mutex);
976 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK,
977 mutex, True /* took_lock */, 0, 0, 0);
980 PTH_FUNCS(void, lmutexZulock, lmutex_lock_intercept,
981 (mutex_t *mutex), (mutex));
982 #endif /* VGO_solaris */
984 static __always_inline
985 int pthread_mutex_trylock_intercept(pthread_mutex_t* mutex)
987 int ret;
988 OrigFn fn;
989 VALGRIND_GET_ORIG_FN(fn);
990 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK,
991 mutex, DRD_(mutex_type)(mutex), 1, 0, 0);
992 CALL_FN_W_W(ret, fn, mutex);
993 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK,
994 mutex, ret == 0, 0, 0, 0);
995 return ret;
998 #if defined(VGO_solaris)
999 /* On Solaris, pthread_mutex_trylock is a weak alias to mutex_trylock. */
1000 PTH_FUNCS(int, mutexZutrylock, pthread_mutex_trylock_intercept,
1001 (pthread_mutex_t *mutex), (mutex));
1002 #else
1003 PTH_FUNCS(int, pthreadZumutexZutrylock, pthread_mutex_trylock_intercept,
1004 (pthread_mutex_t *mutex), (mutex));
1005 #endif /* VGO_solaris */
1007 static __always_inline
1008 int pthread_mutex_timedlock_intercept(pthread_mutex_t *mutex,
1009 const struct timespec *abs_timeout)
1011 int ret;
1012 OrigFn fn;
1013 VALGRIND_GET_ORIG_FN(fn);
1014 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK,
1015 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
1016 CALL_FN_W_WW(ret, fn, mutex, abs_timeout);
1017 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK,
1018 mutex, ret == 0, 0, 0, 0);
1019 return ret;
1022 PTH_FUNCS(int, pthreadZumutexZutimedlock, pthread_mutex_timedlock_intercept,
1023 (pthread_mutex_t *mutex, const struct timespec *abs_timeout),
1024 (mutex, abs_timeout));
1025 #if defined(VGO_solaris)
1026 PTH_FUNCS(int,
1027 pthreadZumutexZureltimedlockZunp, pthread_mutex_timedlock_intercept,
1028 (pthread_mutex_t *mutex, const struct timespec *timeout),
1029 (mutex, timeout));
1030 #endif /* VGO_solaris */
1032 #if defined(HAVE_CLOCKID_T)
1033 static __always_inline
1034 int pthread_mutex_clocklock_intercept(pthread_mutex_t *mutex,
1035 clockid_t clockid,
1036 const struct timespec *abs_timeout)
1038 int ret;
1039 OrigFn fn;
1040 VALGRIND_GET_ORIG_FN(fn);
1041 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK,
1042 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
1043 CALL_FN_W_WWW(ret, fn, mutex, clockid, abs_timeout);
1044 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK,
1045 mutex, ret == 0, 0, 0, 0);
1046 return ret;
1049 PTH_FUNCS(int, pthreadZumutexZuclocklock, pthread_mutex_clocklock_intercept,
1050 (pthread_mutex_t *mutex, clockid_t clockid, const struct timespec *abs_timeout),
1051 (mutex, clockid, abs_timeout));
1052 #endif
1054 static __always_inline
1055 int pthread_mutex_unlock_intercept(pthread_mutex_t *mutex)
1057 int ret;
1058 OrigFn fn;
1059 VALGRIND_GET_ORIG_FN(fn);
1060 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_UNLOCK,
1061 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
1062 CALL_FN_W_W(ret, fn, mutex);
1063 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_UNLOCK,
1064 mutex, 0, 0, 0, 0);
1065 return ret;
1068 #if defined(VGO_solaris)
1069 /* On Solaris, pthread_mutex_unlock is a weak alias to mutex_unlock. */
1070 PTH_FUNCS(int, mutexZuunlock, pthread_mutex_unlock_intercept,
1071 (pthread_mutex_t *mutex), (mutex));
1072 #else
1073 PTH_FUNCS(int, pthreadZumutexZuunlock, pthread_mutex_unlock_intercept,
1074 (pthread_mutex_t *mutex), (mutex));
1075 #endif /* VGO_solaris */
1077 #if defined(VGO_solaris)
1078 /* Internal to libc. */
1079 static __always_inline
1080 void lmutex_unlock_intercept(mutex_t *mutex)
1082 OrigFn fn;
1083 VALGRIND_GET_ORIG_FN(fn);
1084 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_UNLOCK,
1085 mutex,
1086 DRD_(mutex_type)((pthread_mutex_t *) mutex),
1087 0, 0, 0);
1088 CALL_FN_v_W(fn, mutex);
1089 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_UNLOCK,
1090 mutex, 0, 0, 0, 0);
1093 PTH_FUNCS(void, lmutexZuunlock, lmutex_unlock_intercept,
1094 (mutex_t *mutex), (mutex));
1095 #endif /* VGO_solaris */
1097 static __always_inline
1098 int pthread_cond_init_intercept(pthread_cond_t* cond,
1099 const pthread_condattr_t* attr)
1101 int ret;
1102 OrigFn fn;
1103 VALGRIND_GET_ORIG_FN(fn);
1104 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_INIT,
1105 cond, 0, 0, 0, 0);
1106 CALL_FN_W_WW(ret, fn, cond, attr);
1107 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_INIT,
1108 cond, 0, 0, 0, 0);
1109 return ret;
1112 PTH_FUNCS(int, pthreadZucondZuinit, pthread_cond_init_intercept,
1113 (pthread_cond_t* cond, const pthread_condattr_t* attr),
1114 (cond, attr));
1116 #if defined(VGO_solaris)
1117 static __always_inline
1118 int cond_init_intercept(cond_t *cond, int type, void *arg)
1120 int ret;
1121 OrigFn fn;
1122 VALGRIND_GET_ORIG_FN(fn);
1123 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_INIT,
1124 cond, 0, 0, 0, 0);
1125 CALL_FN_W_WWW(ret, fn, cond, type, arg);
1126 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_INIT,
1127 cond, 0, 0, 0, 0);
1128 return ret;
1131 PTH_FUNCS(int, condZuinit, cond_init_intercept,
1132 (cond_t *cond, int type, void *arg),
1133 (cond, type, arg));
1134 #endif /* VGO_solaris */
1136 static __always_inline
1137 int pthread_cond_destroy_intercept(pthread_cond_t* cond)
1139 int ret;
1140 OrigFn fn;
1141 VALGRIND_GET_ORIG_FN(fn);
1142 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_DESTROY,
1143 cond, 0, 0, 0, 0);
1144 CALL_FN_W_W(ret, fn, cond);
1145 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_DESTROY,
1146 cond, ret==0, 0, 0, 0);
1147 return ret;
1150 #if defined(VGO_solaris)
1151 /* On Solaris, pthread_cond_destroy is a weak alias to cond_destroy. */
1152 PTH_FUNCS(int, condZudestroy, pthread_cond_destroy_intercept,
1153 (pthread_cond_t *cond), (cond));
1154 #else
1155 PTH_FUNCS(int, pthreadZucondZudestroy, pthread_cond_destroy_intercept,
1156 (pthread_cond_t* cond), (cond));
1157 #endif /* VGO_solaris */
1159 static __always_inline
1160 int pthread_cond_wait_intercept(pthread_cond_t *cond, pthread_mutex_t *mutex)
1162 int ret;
1163 OrigFn fn;
1164 VALGRIND_GET_ORIG_FN(fn);
1165 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_WAIT,
1166 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1167 CALL_FN_W_WW(ret, fn, cond, mutex);
1168 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_WAIT,
1169 cond, mutex, 1, 0, 0);
1170 return ret;
1173 PTH_FUNCS(int, pthreadZucondZuwait, pthread_cond_wait_intercept,
1174 (pthread_cond_t *cond, pthread_mutex_t *mutex),
1175 (cond, mutex));
1176 #if defined(VGO_solaris)
1177 PTH_FUNCS(int, condZuwait, pthread_cond_wait_intercept,
1178 (pthread_cond_t *cond, pthread_mutex_t *mutex),
1179 (cond, mutex));
1180 #endif /* VGO_solaris */
1182 static __always_inline
1183 int pthread_cond_timedwait_intercept(pthread_cond_t *cond,
1184 pthread_mutex_t *mutex,
1185 const struct timespec* abstime)
1187 int ret;
1188 OrigFn fn;
1189 VALGRIND_GET_ORIG_FN(fn);
1190 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_WAIT,
1191 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1192 CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
1193 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_WAIT,
1194 cond, mutex, 1, 0, 0);
1195 return ret;
1198 PTH_FUNCS(int, pthreadZucondZutimedwait, pthread_cond_timedwait_intercept,
1199 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1200 const struct timespec* abstime),
1201 (cond, mutex, abstime));
1202 #if defined(VGO_solaris)
1203 PTH_FUNCS(int, condZutimedwait, pthread_cond_timedwait_intercept,
1204 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1205 const struct timespec *timeout),
1206 (cond, mutex, timeout));
1207 PTH_FUNCS(int, condZureltimedwait, pthread_cond_timedwait_intercept,
1208 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1209 const struct timespec *timeout),
1210 (cond, mutex, timeout));
1211 #endif /* VGO_solaris */
1214 #if defined(HAVE_CLOCKID_T)
1215 static __always_inline
1216 int pthread_cond_clockwait_intercept(pthread_cond_t *cond,
1217 pthread_mutex_t *mutex,
1218 clockid_t clockid,
1219 const struct timespec* abstime)
1221 int ret;
1222 OrigFn fn;
1223 VALGRIND_GET_ORIG_FN(fn);
1224 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_WAIT,
1225 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1226 CALL_FN_W_WWWW(ret, fn, cond, mutex, clockid, abstime);
1227 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_WAIT,
1228 cond, mutex, 1, 0, 0);
1229 return ret;
1232 PTH_FUNCS(int, pthreadZucondZuclockwait, pthread_cond_clockwait_intercept,
1233 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1234 clockid_t clockid, const struct timespec* abstime),
1235 (cond, mutex, clockid, abstime));
1236 #endif
1239 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
1240 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
1241 // two. Intercepting all pthread_cond_signal* functions will cause only one
1242 // argument to be passed to pthread_cond_signal_np() and hence will cause this
1243 // last function to crash.
1245 static __always_inline
1246 int pthread_cond_signal_intercept(pthread_cond_t* cond)
1248 int ret;
1249 OrigFn fn;
1250 VALGRIND_GET_ORIG_FN(fn);
1251 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_SIGNAL,
1252 cond, 0, 0, 0, 0);
1253 CALL_FN_W_W(ret, fn, cond);
1254 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_SIGNAL,
1255 cond, 0, 0, 0, 0);
1256 return ret;
1259 #if defined(VGO_solaris)
1260 /* On Solaris, pthread_cond_signal is a weak alias to cond_signal. */
1261 PTH_FUNCS(int, condZusignal, pthread_cond_signal_intercept,
1262 (pthread_cond_t *cond), (cond));
1263 #else
1264 PTH_FUNCS(int, pthreadZucondZusignal, pthread_cond_signal_intercept,
1265 (pthread_cond_t* cond), (cond));
1266 #endif /* VGO_solaris */
1268 static __always_inline
1269 int pthread_cond_broadcast_intercept(pthread_cond_t* cond)
1271 int ret;
1272 OrigFn fn;
1273 VALGRIND_GET_ORIG_FN(fn);
1274 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_BROADCAST,
1275 cond, 0, 0, 0, 0);
1276 CALL_FN_W_W(ret, fn, cond);
1277 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_BROADCAST,
1278 cond, 0, 0, 0, 0);
1279 return ret;
1282 #if defined(VGO_solaris)
1283 /* On Solaris, pthread_cond_broadcast is a weak alias to cond_broadcast. */
1284 PTH_FUNCS(int, condZubroadcast, pthread_cond_broadcast_intercept,
1285 (pthread_cond_t *cond), (cond));
1286 #else
1287 PTH_FUNCS(int, pthreadZucondZubroadcast, pthread_cond_broadcast_intercept,
1288 (pthread_cond_t* cond), (cond));
1289 #endif /* VGO_solaris */
1291 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1292 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1293 static __always_inline
1294 int pthread_spin_init_intercept(pthread_spinlock_t *spinlock, int pshared)
1296 int ret;
1297 OrigFn fn;
1298 VALGRIND_GET_ORIG_FN(fn);
1299 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SPIN_INIT_OR_UNLOCK,
1300 spinlock, 0, 0, 0, 0);
1301 CALL_FN_W_WW(ret, fn, spinlock, pshared);
1302 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SPIN_INIT_OR_UNLOCK,
1303 spinlock, 0, 0, 0, 0);
1304 return ret;
1307 PTH_FUNCS(int, pthreadZuspinZuinit, pthread_spin_init_intercept,
1308 (pthread_spinlock_t *spinlock, int pshared), (spinlock, pshared));
1310 static __always_inline
1311 int pthread_spin_destroy_intercept(pthread_spinlock_t *spinlock)
1313 int ret;
1314 OrigFn fn;
1315 VALGRIND_GET_ORIG_FN(fn);
1316 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_DESTROY,
1317 spinlock, 0, 0, 0, 0);
1318 CALL_FN_W_W(ret, fn, spinlock);
1319 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_DESTROY,
1320 spinlock, mutex_type_spinlock, 0, 0, 0);
1321 return ret;
1324 PTH_FUNCS(int, pthreadZuspinZudestroy, pthread_spin_destroy_intercept,
1325 (pthread_spinlock_t *spinlock), (spinlock));
1327 static __always_inline
1328 int pthread_spin_lock_intercept(pthread_spinlock_t *spinlock)
1330 int ret;
1331 OrigFn fn;
1332 VALGRIND_GET_ORIG_FN(fn);
1333 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK,
1334 spinlock, mutex_type_spinlock, 0, 0, 0);
1335 CALL_FN_W_W(ret, fn, spinlock);
1336 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK,
1337 spinlock, ret == 0, 0, 0, 0);
1338 return ret;
1341 PTH_FUNCS(int, pthreadZuspinZulock, pthread_spin_lock_intercept,
1342 (pthread_spinlock_t *spinlock), (spinlock));
1344 static __always_inline
1345 int pthread_spin_trylock_intercept(pthread_spinlock_t *spinlock)
1347 int ret;
1348 OrigFn fn;
1349 VALGRIND_GET_ORIG_FN(fn);
1350 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK,
1351 spinlock, mutex_type_spinlock, 0, 0, 0);
1352 CALL_FN_W_W(ret, fn, spinlock);
1353 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK,
1354 spinlock, ret == 0, 0, 0, 0);
1355 return ret;
1358 PTH_FUNCS(int, pthreadZuspinZutrylock, pthread_spin_trylock_intercept,
1359 (pthread_spinlock_t *spinlock), (spinlock));
1361 static __always_inline
1362 int pthread_spin_unlock_intercept(pthread_spinlock_t *spinlock)
1364 int ret;
1365 OrigFn fn;
1366 VALGRIND_GET_ORIG_FN(fn);
1367 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SPIN_INIT_OR_UNLOCK,
1368 spinlock, mutex_type_spinlock, 0, 0, 0);
1369 CALL_FN_W_W(ret, fn, spinlock);
1370 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SPIN_INIT_OR_UNLOCK,
1371 spinlock, 0, 0, 0, 0);
1372 return ret;
1375 PTH_FUNCS(int, pthreadZuspinZuunlock, pthread_spin_unlock_intercept,
1376 (pthread_spinlock_t *spinlock), (spinlock));
1377 #endif // HAVE_PTHREAD_SPIN_LOCK
1380 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1381 static __always_inline
1382 int pthread_barrier_init_intercept(pthread_barrier_t* barrier,
1383 const pthread_barrierattr_t* attr,
1384 unsigned count)
1386 int ret;
1387 OrigFn fn;
1388 VALGRIND_GET_ORIG_FN(fn);
1389 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_BARRIER_INIT,
1390 barrier, pthread_barrier, count, 0, 0);
1391 CALL_FN_W_WWW(ret, fn, barrier, attr, count);
1392 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_BARRIER_INIT,
1393 barrier, pthread_barrier, 0, 0, 0);
1394 return ret;
1397 PTH_FUNCS(int, pthreadZubarrierZuinit, pthread_barrier_init_intercept,
1398 (pthread_barrier_t* barrier, const pthread_barrierattr_t* attr,
1399 unsigned count), (barrier, attr, count));
1401 static __always_inline
1402 int pthread_barrier_destroy_intercept(pthread_barrier_t* barrier)
1404 int ret;
1405 OrigFn fn;
1406 VALGRIND_GET_ORIG_FN(fn);
1407 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_BARRIER_DESTROY,
1408 barrier, pthread_barrier, 0, 0, 0);
1409 CALL_FN_W_W(ret, fn, barrier);
1410 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_BARRIER_DESTROY,
1411 barrier, pthread_barrier, 0, 0, 0);
1412 return ret;
1415 PTH_FUNCS(int, pthreadZubarrierZudestroy, pthread_barrier_destroy_intercept,
1416 (pthread_barrier_t* barrier), (barrier));
1418 static __always_inline
1419 int pthread_barrier_wait_intercept(pthread_barrier_t* barrier)
1421 int ret;
1422 OrigFn fn;
1423 VALGRIND_GET_ORIG_FN(fn);
1424 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_BARRIER_WAIT,
1425 barrier, pthread_barrier, 0, 0, 0);
1426 CALL_FN_W_W(ret, fn, barrier);
1427 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_BARRIER_WAIT,
1428 barrier, pthread_barrier,
1429 ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD,
1430 ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
1431 return ret;
1434 PTH_FUNCS(int, pthreadZubarrierZuwait, pthread_barrier_wait_intercept,
1435 (pthread_barrier_t* barrier), (barrier));
1436 #endif // HAVE_PTHREAD_BARRIER_INIT
1439 static __always_inline
1440 int sem_init_intercept(sem_t *sem, int pshared, unsigned int value)
1442 int ret;
1443 OrigFn fn;
1444 VALGRIND_GET_ORIG_FN(fn);
1445 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_INIT,
1446 sem, pshared, value, 0, 0);
1447 CALL_FN_W_WWW(ret, fn, sem, pshared, value);
1448 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_INIT,
1449 sem, 0, 0, 0, 0);
1450 return ret;
1453 #if defined(VGO_freebsd)
1454 LIBC_FUNC(int, semZuinit, sem_init_intercept,
1455 (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
1456 #else
1457 PTH_FUNCS(int, semZuinit, sem_init_intercept,
1458 (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
1459 #endif
1461 #if defined(VGO_solaris)
1462 static __always_inline
1463 int sema_init_intercept(sema_t *sem, unsigned int value, int type, void *arg)
1465 int ret;
1466 OrigFn fn;
1467 VALGRIND_GET_ORIG_FN(fn);
1468 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_INIT,
1469 sem, type == USYNC_PROCESS ? 1 : 0,
1470 value, 0, 0);
1471 CALL_FN_W_WWWW(ret, fn, sem, value, type, arg);
1472 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_INIT,
1473 sem, 0, 0, 0, 0);
1474 return ret;
1477 PTH_FUNCS(int, semaZuinit, sema_init_intercept,
1478 (sema_t *sem, unsigned int value, int type, void *arg),
1479 (sem, value, type, arg));
1480 #endif /* VGO_solaris */
1482 static __always_inline
1483 int sem_destroy_intercept(sem_t *sem)
1485 int ret;
1486 OrigFn fn;
1487 VALGRIND_GET_ORIG_FN(fn);
1488 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_DESTROY,
1489 sem, 0, 0, 0, 0);
1490 CALL_FN_W_W(ret, fn, sem);
1491 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_DESTROY,
1492 sem, 0, 0, 0, 0);
1493 return ret;
1496 #if defined(VGO_freebsd)
1497 LIBC_FUNC(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1498 #else
1499 PTH_FUNCS(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1500 #endif
1502 #if defined(VGO_solaris)
1503 PTH_FUNCS(int, semaZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1504 #endif /* VGO_solaris */
1506 static __always_inline
1507 sem_t* sem_open_intercept(const char *name, int oflag, mode_t mode,
1508 unsigned int value)
1510 sem_t *ret;
1511 OrigFn fn;
1512 VALGRIND_GET_ORIG_FN(fn);
1513 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_OPEN,
1514 name, oflag, mode, value, 0);
1515 CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value);
1516 // To do: figure out why gcc 9.2.1 miscompiles this function if the printf()
1517 // call below is left out.
1518 printf("");
1519 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_OPEN,
1520 ret != SEM_FAILED ? ret : 0,
1521 name, oflag, mode, value);
1522 return ret;
1525 #if defined(VGO_freebsd)
1526 LIBC_FUNC(sem_t *, semZuopen, sem_open_intercept,
1527 (const char *name, int oflag, mode_t mode, unsigned int value),
1528 (name, oflag, mode, value));
1529 #else
1530 PTH_FUNCS(sem_t *, semZuopen, sem_open_intercept,
1531 (const char *name, int oflag, mode_t mode, unsigned int value),
1532 (name, oflag, mode, value));
1533 #endif
1535 static __always_inline int sem_close_intercept(sem_t *sem)
1537 int ret;
1538 OrigFn fn;
1539 VALGRIND_GET_ORIG_FN(fn);
1540 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_CLOSE,
1541 sem, 0, 0, 0, 0);
1542 CALL_FN_W_W(ret, fn, sem);
1543 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_CLOSE,
1544 sem, 0, 0, 0, 0);
1545 return ret;
1548 #if defined(VGO_freebsd)
1549 LIBC_FUNC(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
1550 #else
1551 PTH_FUNCS(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
1552 #endif
1554 static __always_inline int sem_wait_intercept(sem_t *sem)
1556 int ret;
1557 OrigFn fn;
1558 VALGRIND_GET_ORIG_FN(fn);
1559 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT,
1560 sem, 0, 0, 0, 0);
1561 CALL_FN_W_W(ret, fn, sem);
1562 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT,
1563 sem, ret == 0, 0, 0, 0);
1564 return ret;
1567 #if defined(VGO_freebsd)
1568 LIBC_FUNC(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1569 #else
1570 PTH_FUNCS(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1571 #endif
1573 #if defined(VGO_solaris)
1574 PTH_FUNCS(int, semaZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1575 #endif /* VGO_solaris */
1577 static __always_inline int sem_trywait_intercept(sem_t *sem)
1579 int ret;
1580 OrigFn fn;
1581 VALGRIND_GET_ORIG_FN(fn);
1582 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT,
1583 sem, 0, 0, 0, 0);
1584 CALL_FN_W_W(ret, fn, sem);
1585 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT,
1586 sem, ret == 0, 0, 0, 0);
1587 return ret;
1590 #if defined(VGO_freebsd)
1591 LIBC_FUNC(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1592 #else
1593 PTH_FUNCS(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1594 #endif
1595 #if defined(VGO_solaris)
1596 PTH_FUNCS(int, semaZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1597 #endif /* VGO_solaris */
1599 static __always_inline
1600 int sem_timedwait_intercept(sem_t *sem, const struct timespec *abs_timeout)
1602 int ret;
1603 OrigFn fn;
1604 VALGRIND_GET_ORIG_FN(fn);
1605 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT,
1606 sem, 0, 0, 0, 0);
1607 CALL_FN_W_WW(ret, fn, sem, abs_timeout);
1608 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT,
1609 sem, ret == 0, 0, 0, 0);
1610 return ret;
1613 #if defined(VGO_freebsd)
1614 LIBC_FUNC(int, semZutimedwait, sem_timedwait_intercept,
1615 (sem_t *sem, const struct timespec *abs_timeout),
1616 (sem, abs_timeout));
1617 #else
1618 PTH_FUNCS(int, semZutimedwait, sem_timedwait_intercept,
1619 (sem_t *sem, const struct timespec *abs_timeout),
1620 (sem, abs_timeout));
1621 #endif
1622 #if defined(VGO_solaris)
1623 PTH_FUNCS(int, semaZutimedwait, sem_timedwait_intercept,
1624 (sem_t *sem, const struct timespec *timeout),
1625 (sem, timeout));
1626 PTH_FUNCS(int, semaZureltimedwait, sem_timedwait_intercept,
1627 (sem_t *sem, const struct timespec *timeout),
1628 (sem, timeout));
1629 #endif /* VGO_solaris */
1631 static __always_inline int sem_post_intercept(sem_t *sem)
1633 int ret;
1634 OrigFn fn;
1635 VALGRIND_GET_ORIG_FN(fn);
1636 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_POST,
1637 sem, 0, 0, 0, 0);
1638 CALL_FN_W_W(ret, fn, sem);
1639 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_POST,
1640 sem, ret == 0, 0, 0, 0);
1641 return ret;
1644 #if defined(VGO_freebsd)
1645 LIBC_FUNC(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
1646 #else
1647 PTH_FUNCS(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
1648 #endif
1649 #if defined(VGO_solaris)
1650 PTH_FUNCS(int, semaZupost, sem_post_intercept, (sem_t *sem), (sem));
1651 #endif /* VGO_solaris */
1653 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1654 functions have to be conditionally compiled. */
1655 #if defined(HAVE_PTHREAD_RWLOCK_T)
1657 static __always_inline
1658 int pthread_rwlock_init_intercept(pthread_rwlock_t* rwlock,
1659 const pthread_rwlockattr_t* attr)
1661 int ret;
1662 OrigFn fn;
1663 VALGRIND_GET_ORIG_FN(fn);
1664 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_INIT,
1665 rwlock, 0, 0, 0, 0);
1666 CALL_FN_W_WW(ret, fn, rwlock, attr);
1667 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_INIT,
1668 rwlock, 0, 0, 0, 0);
1669 return ret;
1672 PTH_FUNCS(int,
1673 pthreadZurwlockZuinit, pthread_rwlock_init_intercept,
1674 (pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr),
1675 (rwlock, attr));
1677 #if defined(VGO_solaris)
1678 static __always_inline
1679 int rwlock_init_intercept(rwlock_t *rwlock, int type, void *arg)
1681 int ret;
1682 OrigFn fn;
1683 VALGRIND_GET_ORIG_FN(fn);
1684 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_INIT,
1685 rwlock, 0, 0, 0, 0);
1686 CALL_FN_W_WWW(ret, fn, rwlock, type, arg);
1687 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_INIT,
1688 rwlock, 0, 0, 0, 0);
1689 return ret;
1692 PTH_FUNCS(int, rwlockZuinit, rwlock_init_intercept,
1693 (rwlock_t *rwlock, int type, void *arg),
1694 (rwlock, type, arg));
1695 #endif /* VGO_solaris */
1697 static __always_inline
1698 int pthread_rwlock_destroy_intercept(pthread_rwlock_t* rwlock)
1700 int ret;
1701 OrigFn fn;
1702 VALGRIND_GET_ORIG_FN(fn);
1703 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_DESTROY,
1704 rwlock, 0, 0, 0, 0);
1705 CALL_FN_W_W(ret, fn, rwlock);
1706 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_DESTROY,
1707 rwlock, 0, 0, 0, 0);
1708 return ret;
1711 #if defined(VGO_solaris)
1712 /* On Solaris, pthread_rwlock_destroy is a weak alias to rwlock_destroy. */
1713 PTH_FUNCS(int,
1714 rwlockZudestroy, pthread_rwlock_destroy_intercept,
1715 (pthread_rwlock_t *rwlock), (rwlock));
1716 #else
1717 PTH_FUNCS(int,
1718 pthreadZurwlockZudestroy, pthread_rwlock_destroy_intercept,
1719 (pthread_rwlock_t* rwlock), (rwlock));
1720 #endif /* VGO_solaris */
1722 static __always_inline
1723 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t* rwlock)
1725 int ret;
1726 OrigFn fn;
1727 VALGRIND_GET_ORIG_FN(fn);
1728 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK,
1729 rwlock, 0, 0, 0, 0);
1730 CALL_FN_W_W(ret, fn, rwlock);
1731 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK,
1732 rwlock, ret == 0, 0, 0, 0);
1733 return ret;
1736 #if defined(VGO_solaris)
1737 /* On Solaris, pthread_rwlock_rdlock is a weak alias to rw_rdlock. */
1738 PTH_FUNCS(int,
1739 rwZurdlock, pthread_rwlock_rdlock_intercept,
1740 (pthread_rwlock_t *rwlock), (rwlock));
1741 #else
1742 PTH_FUNCS(int,
1743 pthreadZurwlockZurdlock, pthread_rwlock_rdlock_intercept,
1744 (pthread_rwlock_t* rwlock), (rwlock));
1745 #endif /* VGO_solaris */
1747 #if defined(VGO_solaris)
1748 /* Internal to libc. */
1749 static __always_inline
1750 void lrw_rdlock_intercept(rwlock_t *rwlock)
1752 OrigFn fn;
1753 VALGRIND_GET_ORIG_FN(fn);
1754 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK,
1755 rwlock, 0, 0, 0, 0);
1756 CALL_FN_v_W(fn, rwlock);
1757 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK,
1758 rwlock, True /* took_lock */, 0, 0, 0);
1761 PTH_FUNCS(void, lrwZurdlock, lrw_rdlock_intercept,
1762 (rwlock_t *rwlock), (rwlock));
1763 #endif /* VGO_solaris */
1765 static __always_inline
1766 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t* rwlock)
1768 int ret;
1769 OrigFn fn;
1770 VALGRIND_GET_ORIG_FN(fn);
1771 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK,
1772 rwlock, 0, 0, 0, 0);
1773 CALL_FN_W_W(ret, fn, rwlock);
1774 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK,
1775 rwlock, ret == 0, 0, 0, 0);
1776 return ret;
1779 #if defined(VGO_solaris)
1780 /* On Solaris, pthread_rwlock_wrlock is a weak alias to rw_wrlock. */
1781 PTH_FUNCS(int,
1782 rwZuwrlock, pthread_rwlock_wrlock_intercept,
1783 (pthread_rwlock_t *rwlock), (rwlock));
1784 #else
1785 PTH_FUNCS(int,
1786 pthreadZurwlockZuwrlock, pthread_rwlock_wrlock_intercept,
1787 (pthread_rwlock_t* rwlock), (rwlock));
1788 #endif /* VGO_solaris */
1790 #if defined(VGO_solaris)
1791 /* Internal to libc. */
1792 static __always_inline
1793 void lrw_wrlock_intercept(rwlock_t *rwlock)
1795 OrigFn fn;
1796 VALGRIND_GET_ORIG_FN(fn);
1797 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK,
1798 rwlock, 0, 0, 0, 0);
1799 CALL_FN_v_W(fn, rwlock);
1800 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK,
1801 rwlock, True /* took_lock */, 0, 0, 0);
1804 PTH_FUNCS(void, lrwZuwrlock, lrw_wrlock_intercept,
1805 (rwlock_t *rwlock), (rwlock));
1806 #endif /* VGO_solaris */
1808 static __always_inline
1809 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t* rwlock,
1810 const struct timespec *timeout)
1812 int ret;
1813 OrigFn fn;
1814 VALGRIND_GET_ORIG_FN(fn);
1815 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK,
1816 rwlock, 0, 0, 0, 0);
1817 CALL_FN_W_WW(ret, fn, rwlock, timeout);
1818 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK,
1819 rwlock, ret == 0, 0, 0, 0);
1820 return ret;
1823 PTH_FUNCS(int,
1824 pthreadZurwlockZutimedrdlock, pthread_rwlock_timedrdlock_intercept,
1825 (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1826 (rwlock, timeout));
1827 #if defined(VGO_solaris)
1828 PTH_FUNCS(int, pthreadZurwlockZureltimedrdlockZunp,
1829 pthread_rwlock_timedrdlock_intercept,
1830 (pthread_rwlock_t *rwlock, const struct timespec *timeout),
1831 (rwlock, timeout));
1832 #endif /* VGO_solaris */
1835 #if defined(HAVE_CLOCKID_T)
1836 static __always_inline
1837 int pthread_rwlock_clockrdlock_intercept(pthread_rwlock_t* rwlock,
1838 clockid_t clockid,
1839 const struct timespec *timeout)
1841 int ret;
1842 OrigFn fn;
1843 VALGRIND_GET_ORIG_FN(fn);
1844 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK,
1845 rwlock, 0, 0, 0, 0);
1846 CALL_FN_W_WWW(ret, fn, rwlock, clockid, timeout);
1847 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK,
1848 rwlock, ret == 0, 0, 0, 0);
1849 return ret;
1852 PTH_FUNCS(int,
1853 pthreadZurwlockZuclockrdlock, pthread_rwlock_clockrdlock_intercept,
1854 (pthread_rwlock_t* rwlock, clockid_t clockid, const struct timespec *timeout),
1855 (rwlock, clockid, timeout));
1856 #endif
1858 static __always_inline
1859 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t* rwlock,
1860 const struct timespec *timeout)
1862 int ret;
1863 OrigFn fn;
1864 VALGRIND_GET_ORIG_FN(fn);
1865 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK,
1866 rwlock, 0, 0, 0, 0);
1867 CALL_FN_W_WW(ret, fn, rwlock, timeout);
1868 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK,
1869 rwlock, ret == 0, 0, 0, 0);
1870 return ret;
1873 PTH_FUNCS(int,
1874 pthreadZurwlockZutimedwrlock, pthread_rwlock_timedwrlock_intercept,
1875 (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1876 (rwlock, timeout));
1877 #if defined(VGO_solaris)
1878 PTH_FUNCS(int, pthreadZurwlockZureltimedwrlockZunp,
1879 pthread_rwlock_timedwrlock_intercept,
1880 (pthread_rwlock_t *rwlock, const struct timespec *timeout),
1881 (rwlock, timeout));
1882 #endif /* VGO_solaris */
1885 #if defined(HAVE_CLOCKID_T)
1886 static __always_inline
1887 int pthread_rwlock_clockwrlock_intercept(pthread_rwlock_t* rwlock,
1888 clockid_t clockid,
1889 const struct timespec *timeout)
1891 int ret;
1892 OrigFn fn;
1893 VALGRIND_GET_ORIG_FN(fn);
1894 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK,
1895 rwlock, 0, 0, 0, 0);
1896 CALL_FN_W_WWW(ret, fn, rwlock, clockid, timeout);
1897 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK,
1898 rwlock, ret == 0, 0, 0, 0);
1899 return ret;
1902 PTH_FUNCS(int,
1903 pthreadZurwlockZuclockwrlock, pthread_rwlock_clockwrlock_intercept,
1904 (pthread_rwlock_t* rwlock, clockid_t clockid, const struct timespec *timeout),
1905 (rwlock, clockid, timeout));
1906 #endif
1909 static __always_inline
1910 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t* rwlock)
1912 int ret;
1913 OrigFn fn;
1914 VALGRIND_GET_ORIG_FN(fn);
1915 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK,
1916 rwlock, 0, 0, 0, 0);
1917 CALL_FN_W_W(ret, fn, rwlock);
1918 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK,
1919 rwlock, ret == 0, 0, 0, 0);
1920 return ret;
1923 #if defined(VGO_solaris)
1924 /* On Solaris, pthread_rwlock_tryrdlock is a weak alias to rw_tryrdlock. */
1925 PTH_FUNCS(int,
1926 rwZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1927 (pthread_rwlock_t *rwlock), (rwlock));
1928 #else
1929 PTH_FUNCS(int,
1930 pthreadZurwlockZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1931 (pthread_rwlock_t* rwlock), (rwlock));
1932 #endif /* VGO_solaris */
1934 static __always_inline
1935 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t* rwlock)
1937 int ret;
1938 OrigFn fn;
1939 VALGRIND_GET_ORIG_FN(fn);
1940 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK,
1941 rwlock, 0, 0, 0, 0);
1942 CALL_FN_W_W(ret, fn, rwlock);
1943 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK,
1944 rwlock, ret == 0, 0, 0, 0);
1945 return ret;
1948 #if defined(VGO_solaris)
1949 /* On Solaris, pthread_rwlock_trywrlock is a weak alias to rw_trywrlock. */
1950 PTH_FUNCS(int,
1951 rwZutrywrlock, pthread_rwlock_trywrlock_intercept,
1952 (pthread_rwlock_t *rwlock), (rwlock));
1953 #else
1954 PTH_FUNCS(int,
1955 pthreadZurwlockZutrywrlock, pthread_rwlock_trywrlock_intercept,
1956 (pthread_rwlock_t* rwlock), (rwlock));
1957 #endif /* VGO_solaris */
1959 static __always_inline
1960 int pthread_rwlock_unlock_intercept(pthread_rwlock_t* rwlock)
1962 int ret;
1963 OrigFn fn;
1964 VALGRIND_GET_ORIG_FN(fn);
1965 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_UNLOCK,
1966 rwlock, 0, 0, 0, 0);
1967 CALL_FN_W_W(ret, fn, rwlock);
1968 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_UNLOCK,
1969 rwlock, ret == 0, 0, 0, 0);
1970 return ret;
1973 #if defined(VGO_solaris)
1974 /* On Solaris, pthread_rwlock_unlock is a weak alias to rw_unlock. */
1975 PTH_FUNCS(int,
1976 rwZuunlock, pthread_rwlock_unlock_intercept,
1977 (pthread_rwlock_t *rwlock), (rwlock));
1978 #else
1979 PTH_FUNCS(int,
1980 pthreadZurwlockZuunlock, pthread_rwlock_unlock_intercept,
1981 (pthread_rwlock_t* rwlock), (rwlock));
1982 #endif /* VGO_solaris */
1984 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */