regtest: silence a few warnings
[valgrind.git] / drd / drd_pthread_intercepts.c
blobb3895ea34f0f89063a401215ed6842f50c348a46
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;
365 else if (kind == PTHREAD_MUTEX_ERRORCHECK)
366 return mutex_type_errorcheck_mutex;
367 else if (kind == PTHREAD_MUTEX_NORMAL)
368 return mutex_type_default_mutex;
369 else if (kind == PTHREAD_MUTEX_DEFAULT)
370 // @todo PJF what about Solaris?
371 #if defined(VGO_freebsd)
372 return mutex_type_errorcheck_mutex;
373 #else
374 return mutex_type_default_mutex;
375 #endif
376 #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
377 else if (kind == PTHREAD_MUTEX_ADAPTIVE_NP)
378 return mutex_type_default_mutex;
379 #endif
380 else
381 return mutex_type_invalid_mutex;
384 #if defined(VGO_solaris)
386 * Solaris threads and DRD each have their own mutex type identification.
387 * Convert Solaris threads' mutex type to DRD's mutex type.
389 static MutexT DRD_(thread_to_drd_mutex_type)(int type)
391 if (type & LOCK_RECURSIVE) {
392 return mutex_type_recursive_mutex;
393 } else if (type & LOCK_ERRORCHECK) {
394 return mutex_type_errorcheck_mutex;
395 } else {
396 return mutex_type_default_mutex;
399 #endif /* VGO_solaris */
401 #define IS_ALIGNED(p) (((uintptr_t)(p) & (sizeof(*(p)) - 1)) == 0)
404 * Read the mutex type stored in the client memory used for the mutex
405 * implementation.
407 * @note This function depends on the implementation of the POSIX threads
408 * library -- the POSIX standard does not define the name of the member in
409 * which the mutex type is stored.
410 * @note The function mutex_type() has been declared inline in order
411 * to avoid that it shows up in call stacks (drd/tests/...exp* files).
412 * @note glibc stores the mutex type in the lowest two bits, and uses the
413 * higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
414 * PTHREAD_MUTEXATTR_FLAG_PSHARED.
416 static __always_inline MutexT DRD_(mutex_type)(pthread_mutex_t* mutex)
418 MutexT mutex_type = mutex_type_unknown;
420 ANNOTATE_IGNORE_READS_BEGIN();
421 #if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
422 /* glibc + LinuxThreads. */
423 if (IS_ALIGNED(&mutex->__m_kind))
425 const int kind = mutex->__m_kind & 3;
426 mutex_type = DRD_(pthread_to_drd_mutex_type)(kind);
428 #elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
429 /* glibc + NPTL. */
430 if (IS_ALIGNED(&mutex->__data.__kind))
432 const int kind = mutex->__data.__kind & 3;
433 mutex_type = DRD_(pthread_to_drd_mutex_type)(kind);
435 #elif defined(VGO_solaris)
437 const int type = ((mutex_t *) mutex)->vki_mutex_type;
438 mutex_type = DRD_(thread_to_drd_mutex_type)(type);
440 #else
442 * Another POSIX threads implementation. The mutex type won't be printed
443 * when enabling --trace-mutex=yes.
445 #endif
446 ANNOTATE_IGNORE_READS_END();
448 return mutex_type;
452 * Tell DRD whether 'tid' is a joinable thread or a detached thread.
454 static void DRD_(set_joinable)(const pthread_t tid, const int joinable)
456 assert(joinable == 0 || joinable == 1);
457 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_JOINABLE,
458 tid, joinable, 0, 0, 0);
461 /** Tell DRD that the calling thread is about to enter pthread_create(). */
462 static __always_inline void DRD_(entering_pthread_create)(void)
464 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__ENTERING_PTHREAD_CREATE,
465 0, 0, 0, 0, 0);
468 /** Tell DRD that the calling thread has left pthread_create(). */
469 static __always_inline void DRD_(left_pthread_create)(void)
471 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LEFT_PTHREAD_CREATE,
472 0, 0, 0, 0, 0);
476 * Entry point for newly created threads. This function is called from the
477 * thread created by pthread_create().
479 static void* DRD_(thread_wrapper)(void* arg)
481 DrdPosixThreadArgs* arg_ptr;
482 DrdPosixThreadArgs arg_copy;
484 arg_ptr = (DrdPosixThreadArgs*)arg;
485 arg_copy = *arg_ptr;
487 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
488 pthread_self(), 0, 0, 0, 0);
490 DRD_(set_joinable)(pthread_self(),
491 arg_copy.detachstate == PTHREAD_CREATE_JOINABLE);
494 * Only set 'wrapper_started' after VG_USERREQ__SET_PTHREADID and
495 * DRD_(set_joinable)() have been invoked to avoid a race with
496 * a pthread_detach() invocation for this thread from another thread.
498 DRD_(sema_up)(arg_copy.wrapper_started);
500 return (arg_copy.start)(arg_copy.arg);
504 * Return 1 if the LinuxThreads implementation of POSIX Threads has been
505 * detected, and 0 otherwise.
507 * @see For more information about the confstr() function, see also
508 * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
510 static int DRD_(detected_linuxthreads)(void)
512 #if defined(linux)
513 #if defined(_CS_GNU_LIBPTHREAD_VERSION)
514 /* Linux with a recent glibc. */
515 HChar buffer[256];
516 unsigned len;
517 len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
518 assert(len <= sizeof(buffer));
519 return len > 0 && buffer[0] == 'l';
520 #else
521 /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
522 return 1;
523 #endif
524 #else
525 /* Another OS than Linux, hence no LinuxThreads. */
526 return 0;
527 #endif
531 * Stop and print an error message in case a non-supported threading
532 * library implementation (LinuxThreads) has been detected.
534 static void DRD_(check_threading_library)(void)
536 if (DRD_(detected_linuxthreads)())
538 if (getenv("LD_ASSUME_KERNEL"))
540 fprintf(stderr,
541 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
542 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
543 "after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
546 else
548 fprintf(stderr,
549 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
550 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
551 "after having upgraded to a newer version of your Linux distribution.\n"
552 "Giving up.\n"
555 abort();
560 * Update DRD's state information about the current thread.
562 static void DRD_(set_pthread_id)(void)
564 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
565 pthread_self(), 0, 0, 0, 0);
569 * Note: as of today there exist three different versions of pthread_create
570 * in Linux:
571 * - pthread_create@GLIBC_2.0
572 * - pthread_create@@GLIBC_2.1
573 * - pthread_create@@GLIBC_2.2.5
574 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
575 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
576 * versions have been implemented. In any glibc version where more than one
577 * pthread_create function has been implemented, older versions call the
578 * newer versions. Or: the pthread_create* wrapper defined below can be
579 * called recursively. Any code in this wrapper should take this in account.
580 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
581 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
582 * See also the implementation of pthread_create@GLIBC_2.0 in
583 * glibc-2.9/nptl/pthread_create.c.
586 static __always_inline
587 int pthread_create_intercept(pthread_t* thread, const pthread_attr_t* attr,
588 void* (*start)(void*), void* arg)
590 int ret;
591 OrigFn fn;
592 DrdSema wrapper_started;
593 DrdPosixThreadArgs thread_args;
595 VALGRIND_GET_ORIG_FN(fn);
597 DRD_(sema_init)(&wrapper_started);
598 thread_args.start = start;
599 thread_args.arg = arg;
600 thread_args.wrapper_started = &wrapper_started;
602 * Find out whether the thread will be started as a joinable thread
603 * or as a detached thread. If no thread attributes have been specified,
604 * this means that the new thread will be started as a joinable thread.
606 thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
607 if (attr)
609 if (pthread_attr_getdetachstate(attr, &thread_args.detachstate) != 0)
610 assert(0);
612 assert(thread_args.detachstate == PTHREAD_CREATE_JOINABLE
613 || thread_args.detachstate == PTHREAD_CREATE_DETACHED);
616 * The DRD_(set_pthread_id)() from DRD_(init)() may encounter that
617 * pthread_self() == 0, e.g. when the main program is not linked with the
618 * pthread library and when a pthread_create() call occurs from within a
619 * shared library. Hence call DRD_(set_pthread_id)() again to ensure that
620 * DRD knows the identity of the current thread. See also B.Z. 356374.
622 DRD_(set_pthread_id)();
623 DRD_(entering_pthread_create)();
624 CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), &thread_args);
625 DRD_(left_pthread_create)();
627 if (ret == 0) {
628 /* Wait until the thread wrapper started. */
629 DRD_(sema_down)(&wrapper_started);
632 DRD_(sema_destroy)(&wrapper_started);
634 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT,
635 pthread_self(), 0, 0, 0, 0);
637 return ret;
640 PTH_FUNCS(int, pthreadZucreate, pthread_create_intercept,
641 (pthread_t *thread, const pthread_attr_t *attr,
642 void *(*start) (void *), void *arg),
643 (thread, attr, start, arg));
645 #if defined(VGO_solaris)
646 /* Solaris also provides thr_create() in addition to pthread_create().
647 * Both pthread_create(3C) and thr_create(3C) are based on private
648 * _thrp_create().
650 static __always_inline
651 int thr_create_intercept(void *stk, size_t stksize, void *(*start)(void *),
652 void *arg, long flags, thread_t *new_thread)
654 int ret;
655 OrigFn fn;
656 DrdSema wrapper_started;
657 DrdPosixThreadArgs thread_args;
659 VALGRIND_GET_ORIG_FN(fn);
661 DRD_(sema_init)(&wrapper_started);
662 thread_args.start = start;
663 thread_args.arg = arg;
664 thread_args.wrapper_started = &wrapper_started;
666 * Find out whether the thread will be started as a joinable thread
667 * or as a detached thread.
669 if (flags & THR_DETACHED)
670 thread_args.detachstate = PTHREAD_CREATE_DETACHED;
671 else
672 thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
674 DRD_(entering_pthread_create)();
675 CALL_FN_W_6W(ret, fn, stk, stksize, DRD_(thread_wrapper), &thread_args,
676 flags, new_thread);
677 DRD_(left_pthread_create)();
679 if (ret == 0) {
680 /* Wait until the thread wrapper started. */
681 DRD_(sema_down)(&wrapper_started);
684 DRD_(sema_destroy)(&wrapper_started);
686 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT,
687 pthread_self(), 0, 0, 0, 0);
689 return ret;
692 PTH_FUNCS(int, thrZucreate, thr_create_intercept,
693 (void *stk, size_t stksize, void *(*start)(void *), void *arg,
694 long flags, thread_t *new_thread),
695 (stk, stksize, start, arg, flags, new_thread));
696 #endif /* VGO_solaris */
698 #if defined(VGO_solaris)
700 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
701 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
702 * and CI_BIND_CLEAR, to provide resilience against function renaming.
704 static __always_inline
705 int DRD_(_ti_bind_guard_intercept)(int flags) {
706 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_GUARD,
707 flags, 0, 0, 0, 0);
708 return DRD_(rtld_bind_guard)(flags);
711 static __always_inline
712 int DRD_(_ti_bind_clear_intercept)(int flags) {
713 int ret = DRD_(rtld_bind_clear)(flags);
714 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_CLEAR,
715 flags, 0, 0, 0, 0);
716 return ret;
720 * Wrapped _ld_libc() from the runtime linker ld.so.1.
722 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr);
723 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr)
725 OrigFn fn;
726 int tag;
728 VALGRIND_GET_ORIG_FN(fn);
730 vki_Lc_interface *funcs = ptr;
731 for (tag = funcs->ci_tag; tag != 0; tag = (++funcs)->ci_tag) {
732 switch (tag) {
733 case VKI_CI_BIND_GUARD:
734 if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_guard_intercept)) {
735 DRD_(rtld_bind_guard) = funcs->vki_ci_un.ci_func;
736 funcs->vki_ci_un.ci_func = DRD_(_ti_bind_guard_intercept);
738 break;
739 case VKI_CI_BIND_CLEAR:
740 if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_clear_intercept)) {
741 DRD_(rtld_bind_clear) = funcs->vki_ci_un.ci_func;
742 funcs->vki_ci_un.ci_func = DRD_(_ti_bind_clear_intercept);
744 break;
748 CALL_FN_v_W(fn, ptr);
750 #endif /* VGO_solaris */
752 static __always_inline
753 int pthread_join_intercept(pthread_t pt_joinee, void **thread_return)
755 int ret;
756 OrigFn fn;
758 VALGRIND_GET_ORIG_FN(fn);
760 * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
761 * implementation triggers a (false positive) race report.
763 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
764 CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
765 if (ret == 0)
767 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN,
768 pt_joinee, 0, 0, 0, 0);
770 ANNOTATE_IGNORE_READS_AND_WRITES_END();
771 return ret;
774 PTH_FUNCS(int, pthreadZujoin, pthread_join_intercept,
775 (pthread_t pt_joinee, void **thread_return),
776 (pt_joinee, thread_return));
778 #if defined(VGO_solaris)
779 /* Solaris also provides thr_join() in addition to pthread_join().
780 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
782 * :TODO: No functionality is currently provided for joinee == 0 and departed.
783 * This would require another client request, of course.
785 static __always_inline
786 int thr_join_intercept(thread_t joinee, thread_t *departed, void **thread_return)
788 int ret;
789 OrigFn fn;
791 VALGRIND_GET_ORIG_FN(fn);
792 CALL_FN_W_WWW(ret, fn, joinee, departed, thread_return);
793 if (ret == 0)
795 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN,
796 joinee, 0, 0, 0, 0);
798 return ret;
801 PTH_FUNCS(int, thrZujoin, thr_join_intercept,
802 (thread_t joinee, thread_t *departed, void **thread_return),
803 (joinee, departed, thread_return));
804 #endif /* VGO_solaris */
806 static __always_inline
807 int pthread_detach_intercept(pthread_t pt_thread)
809 int ret;
810 OrigFn fn;
812 VALGRIND_GET_ORIG_FN(fn);
813 CALL_FN_W_W(ret, fn, pt_thread);
814 DRD_(set_joinable)(pt_thread, 0);
816 return ret;
819 PTH_FUNCS(int, pthreadZudetach, pthread_detach_intercept,
820 (pthread_t thread), (thread));
822 // NOTE: be careful to intercept only pthread_cancel() and not
823 // pthread_cancel_init() on Linux.
825 static __always_inline
826 int pthread_cancel_intercept(pthread_t pt_thread)
828 int ret;
829 OrigFn fn;
830 VALGRIND_GET_ORIG_FN(fn);
831 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_THREAD_CANCEL,
832 pt_thread, 0, 0, 0, 0);
833 CALL_FN_W_W(ret, fn, pt_thread);
834 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_CANCEL,
835 pt_thread, ret==0, 0, 0, 0);
836 return ret;
839 PTH_FUNCS(int, pthreadZucancel, pthread_cancel_intercept,
840 (pthread_t thread), (thread))
842 static __always_inline
843 int pthread_once_intercept(pthread_once_t *once_control,
844 void (*init_routine)(void))
846 int ret;
847 OrigFn fn;
848 VALGRIND_GET_ORIG_FN(fn);
850 * Ignore any data races triggered by the implementation of pthread_once().
851 * Necessary for Darwin. This is not necessary for Linux but doesn't have
852 * any known adverse effects.
854 DRD_IGNORE_VAR(*once_control);
855 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
856 CALL_FN_W_WW(ret, fn, once_control, init_routine);
857 ANNOTATE_IGNORE_READS_AND_WRITES_END();
858 DRD_STOP_IGNORING_VAR(*once_control);
859 return ret;
862 PTH_FUNCS(int, pthreadZuonce, pthread_once_intercept,
863 (pthread_once_t *once_control, void (*init_routine)(void)),
864 (once_control, init_routine));
866 static __always_inline
867 int pthread_mutex_init_intercept(pthread_mutex_t *mutex,
868 const pthread_mutexattr_t* attr)
870 int ret;
871 OrigFn fn;
872 int mt;
873 VALGRIND_GET_ORIG_FN(fn);
874 mt = PTHREAD_MUTEX_DEFAULT;
875 if (attr)
876 pthread_mutexattr_gettype(attr, &mt);
877 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
878 mutex, DRD_(pthread_to_drd_mutex_type)(mt),
879 0, 0, 0);
880 CALL_FN_W_WW(ret, fn, mutex, attr);
881 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
882 mutex, 0, 0, 0, 0);
883 return ret;
886 PTH_FUNCS(int, pthreadZumutexZuinit, pthread_mutex_init_intercept,
887 (pthread_mutex_t *mutex, const pthread_mutexattr_t* attr),
888 (mutex, attr));
890 #if defined(VGO_solaris)
891 static __always_inline
892 int mutex_init_intercept(mutex_t *mutex, int type, void *arg)
894 int ret;
895 OrigFn fn;
896 VALGRIND_GET_ORIG_FN(fn);
898 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
899 mutex, DRD_(thread_to_drd_mutex_type)(type),
900 0, 0, 0);
901 CALL_FN_W_WWW(ret, fn, mutex, type, arg);
902 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
903 mutex, 0, 0, 0, 0);
904 return ret;
907 PTH_FUNCS(int, mutexZuinit, mutex_init_intercept,
908 (mutex_t *mutex, int type, void *arg),
909 (mutex, type, arg));
910 #endif /* VGO_solaris */
912 static __always_inline
913 int pthread_mutex_destroy_intercept(pthread_mutex_t* mutex)
915 int ret;
916 OrigFn fn;
917 VALGRIND_GET_ORIG_FN(fn);
918 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
919 mutex, 0, 0, 0, 0);
920 CALL_FN_W_W(ret, fn, mutex);
921 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
922 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
923 return ret;
926 #if defined(VGO_solaris)
927 /* On Solaris, pthread_mutex_destroy is a weak alias to mutex_destroy. */
928 PTH_FUNCS(int, mutexZudestroy, pthread_mutex_destroy_intercept,
929 (pthread_mutex_t *mutex), (mutex));
930 #else
931 PTH_FUNCS(int, pthreadZumutexZudestroy, pthread_mutex_destroy_intercept,
932 (pthread_mutex_t *mutex), (mutex));
933 #endif /* VGO_solaris */
935 static __always_inline
936 int pthread_mutex_lock_intercept(pthread_mutex_t* mutex)
938 int ret;
939 OrigFn fn;
940 VALGRIND_GET_ORIG_FN(fn);
941 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
942 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
943 CALL_FN_W_W(ret, fn, mutex);
944 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
945 mutex, ret == 0, 0, 0, 0);
946 return ret;
949 #if defined(VGO_solaris)
950 /* On Solaris, pthread_mutex_lock is a weak alias to mutex_lock. */
951 PTH_FUNCS(int, mutexZulock, pthread_mutex_lock_intercept,
952 (pthread_mutex_t *mutex), (mutex));
953 #else
954 PTH_FUNCS(int, pthreadZumutexZulock, pthread_mutex_lock_intercept,
955 (pthread_mutex_t *mutex), (mutex));
956 #endif /* VGO_solaris */
958 #if defined(VGO_solaris)
959 /* Internal to libc. Mutex is usually initialized only implicitly,
960 * by zeroing mutex_t structure.
962 static __always_inline
963 void lmutex_lock_intercept(mutex_t *mutex)
965 OrigFn fn;
966 VALGRIND_GET_ORIG_FN(fn);
967 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
968 mutex,
969 DRD_(mutex_type)((pthread_mutex_t *) mutex),
970 False /* try_lock */, 0, 0);
971 CALL_FN_v_W(fn, mutex);
972 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
973 mutex, True /* took_lock */, 0, 0, 0);
976 PTH_FUNCS(void, lmutexZulock, lmutex_lock_intercept,
977 (mutex_t *mutex), (mutex));
978 #endif /* VGO_solaris */
980 static __always_inline
981 int pthread_mutex_trylock_intercept(pthread_mutex_t* mutex)
983 int ret;
984 OrigFn fn;
985 VALGRIND_GET_ORIG_FN(fn);
986 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
987 mutex, DRD_(mutex_type)(mutex), 1, 0, 0);
988 CALL_FN_W_W(ret, fn, mutex);
989 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
990 mutex, ret == 0, 0, 0, 0);
991 return ret;
994 #if defined(VGO_solaris)
995 /* On Solaris, pthread_mutex_trylock is a weak alias to mutex_trylock. */
996 PTH_FUNCS(int, mutexZutrylock, pthread_mutex_trylock_intercept,
997 (pthread_mutex_t *mutex), (mutex));
998 #else
999 PTH_FUNCS(int, pthreadZumutexZutrylock, pthread_mutex_trylock_intercept,
1000 (pthread_mutex_t *mutex), (mutex));
1001 #endif /* VGO_solaris */
1003 static __always_inline
1004 int pthread_mutex_timedlock_intercept(pthread_mutex_t *mutex,
1005 const struct timespec *abs_timeout)
1007 int ret;
1008 OrigFn fn;
1009 VALGRIND_GET_ORIG_FN(fn);
1010 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
1011 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
1012 CALL_FN_W_WW(ret, fn, mutex, abs_timeout);
1013 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
1014 mutex, ret == 0, 0, 0, 0);
1015 return ret;
1018 PTH_FUNCS(int, pthreadZumutexZutimedlock, pthread_mutex_timedlock_intercept,
1019 (pthread_mutex_t *mutex, const struct timespec *abs_timeout),
1020 (mutex, abs_timeout));
1021 #if defined(VGO_solaris)
1022 PTH_FUNCS(int,
1023 pthreadZumutexZureltimedlockZunp, pthread_mutex_timedlock_intercept,
1024 (pthread_mutex_t *mutex, const struct timespec *timeout),
1025 (mutex, timeout));
1026 #endif /* VGO_solaris */
1028 #if defined(HAVE_CLOCKID_T)
1029 static __always_inline
1030 int pthread_mutex_clocklock_intercept(pthread_mutex_t *mutex,
1031 clockid_t clockid,
1032 const struct timespec *abs_timeout)
1034 int ret;
1035 OrigFn fn;
1036 VALGRIND_GET_ORIG_FN(fn);
1037 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
1038 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
1039 CALL_FN_W_WWW(ret, fn, mutex, clockid, abs_timeout);
1040 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
1041 mutex, ret == 0, 0, 0, 0);
1042 return ret;
1045 PTH_FUNCS(int, pthreadZumutexZuclocklock, pthread_mutex_clocklock_intercept,
1046 (pthread_mutex_t *mutex, clockid_t clockid, const struct timespec *abs_timeout),
1047 (mutex, clockid, abs_timeout));
1048 #endif
1050 static __always_inline
1051 int pthread_mutex_unlock_intercept(pthread_mutex_t *mutex)
1053 int ret;
1054 OrigFn fn;
1055 VALGRIND_GET_ORIG_FN(fn);
1056 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
1057 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
1058 CALL_FN_W_W(ret, fn, mutex);
1059 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
1060 mutex, 0, 0, 0, 0);
1061 return ret;
1064 #if defined(VGO_solaris)
1065 /* On Solaris, pthread_mutex_unlock is a weak alias to mutex_unlock. */
1066 PTH_FUNCS(int, mutexZuunlock, pthread_mutex_unlock_intercept,
1067 (pthread_mutex_t *mutex), (mutex));
1068 #else
1069 PTH_FUNCS(int, pthreadZumutexZuunlock, pthread_mutex_unlock_intercept,
1070 (pthread_mutex_t *mutex), (mutex));
1071 #endif /* VGO_solaris */
1073 #if defined(VGO_solaris)
1074 /* Internal to libc. */
1075 static __always_inline
1076 void lmutex_unlock_intercept(mutex_t *mutex)
1078 OrigFn fn;
1079 VALGRIND_GET_ORIG_FN(fn);
1080 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
1081 mutex,
1082 DRD_(mutex_type)((pthread_mutex_t *) mutex),
1083 0, 0, 0);
1084 CALL_FN_v_W(fn, mutex);
1085 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
1086 mutex, 0, 0, 0, 0);
1089 PTH_FUNCS(void, lmutexZuunlock, lmutex_unlock_intercept,
1090 (mutex_t *mutex), (mutex));
1091 #endif /* VGO_solaris */
1093 static __always_inline
1094 int pthread_cond_init_intercept(pthread_cond_t* cond,
1095 const pthread_condattr_t* attr)
1097 int ret;
1098 OrigFn fn;
1099 VALGRIND_GET_ORIG_FN(fn);
1100 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT,
1101 cond, 0, 0, 0, 0);
1102 CALL_FN_W_WW(ret, fn, cond, attr);
1103 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT,
1104 cond, 0, 0, 0, 0);
1105 return ret;
1108 PTH_FUNCS(int, pthreadZucondZuinit, pthread_cond_init_intercept,
1109 (pthread_cond_t* cond, const pthread_condattr_t* attr),
1110 (cond, attr));
1112 #if defined(VGO_solaris)
1113 static __always_inline
1114 int cond_init_intercept(cond_t *cond, int type, void *arg)
1116 int ret;
1117 OrigFn fn;
1118 VALGRIND_GET_ORIG_FN(fn);
1119 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT,
1120 cond, 0, 0, 0, 0);
1121 CALL_FN_W_WWW(ret, fn, cond, type, arg);
1122 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT,
1123 cond, 0, 0, 0, 0);
1124 return ret;
1127 PTH_FUNCS(int, condZuinit, cond_init_intercept,
1128 (cond_t *cond, int type, void *arg),
1129 (cond, type, arg));
1130 #endif /* VGO_solaris */
1132 static __always_inline
1133 int pthread_cond_destroy_intercept(pthread_cond_t* cond)
1135 int ret;
1136 OrigFn fn;
1137 VALGRIND_GET_ORIG_FN(fn);
1138 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_DESTROY,
1139 cond, 0, 0, 0, 0);
1140 CALL_FN_W_W(ret, fn, cond);
1141 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_DESTROY,
1142 cond, ret==0, 0, 0, 0);
1143 return ret;
1146 #if defined(VGO_solaris)
1147 /* On Solaris, pthread_cond_destroy is a weak alias to cond_destroy. */
1148 PTH_FUNCS(int, condZudestroy, pthread_cond_destroy_intercept,
1149 (pthread_cond_t *cond), (cond));
1150 #else
1151 PTH_FUNCS(int, pthreadZucondZudestroy, pthread_cond_destroy_intercept,
1152 (pthread_cond_t* cond), (cond));
1153 #endif /* VGO_solaris */
1155 static __always_inline
1156 int pthread_cond_wait_intercept(pthread_cond_t *cond, pthread_mutex_t *mutex)
1158 int ret;
1159 OrigFn fn;
1160 VALGRIND_GET_ORIG_FN(fn);
1161 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
1162 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1163 CALL_FN_W_WW(ret, fn, cond, mutex);
1164 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
1165 cond, mutex, 1, 0, 0);
1166 return ret;
1169 PTH_FUNCS(int, pthreadZucondZuwait, pthread_cond_wait_intercept,
1170 (pthread_cond_t *cond, pthread_mutex_t *mutex),
1171 (cond, mutex));
1172 #if defined(VGO_solaris)
1173 PTH_FUNCS(int, condZuwait, pthread_cond_wait_intercept,
1174 (pthread_cond_t *cond, pthread_mutex_t *mutex),
1175 (cond, mutex));
1176 #endif /* VGO_solaris */
1178 static __always_inline
1179 int pthread_cond_timedwait_intercept(pthread_cond_t *cond,
1180 pthread_mutex_t *mutex,
1181 const struct timespec* abstime)
1183 int ret;
1184 OrigFn fn;
1185 VALGRIND_GET_ORIG_FN(fn);
1186 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
1187 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1188 CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
1189 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
1190 cond, mutex, 1, 0, 0);
1191 return ret;
1194 PTH_FUNCS(int, pthreadZucondZutimedwait, pthread_cond_timedwait_intercept,
1195 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1196 const struct timespec* abstime),
1197 (cond, mutex, abstime));
1198 #if defined(VGO_solaris)
1199 PTH_FUNCS(int, condZutimedwait, pthread_cond_timedwait_intercept,
1200 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1201 const struct timespec *timeout),
1202 (cond, mutex, timeout));
1203 PTH_FUNCS(int, condZureltimedwait, pthread_cond_timedwait_intercept,
1204 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1205 const struct timespec *timeout),
1206 (cond, mutex, timeout));
1207 #endif /* VGO_solaris */
1210 #if defined(HAVE_CLOCKID_T)
1211 static __always_inline
1212 int pthread_cond_clockwait_intercept(pthread_cond_t *cond,
1213 pthread_mutex_t *mutex,
1214 clockid_t clockid,
1215 const struct timespec* abstime)
1217 int ret;
1218 OrigFn fn;
1219 VALGRIND_GET_ORIG_FN(fn);
1220 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
1221 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1222 CALL_FN_W_WWWW(ret, fn, cond, mutex, clockid, abstime);
1223 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
1224 cond, mutex, 1, 0, 0);
1225 return ret;
1228 PTH_FUNCS(int, pthreadZucondZuclockwait, pthread_cond_clockwait_intercept,
1229 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1230 clockid_t clockid, const struct timespec* abstime),
1231 (cond, mutex, clockid, abstime));
1232 #endif
1235 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
1236 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
1237 // two. Intercepting all pthread_cond_signal* functions will cause only one
1238 // argument to be passed to pthread_cond_signal_np() and hence will cause this
1239 // last function to crash.
1241 static __always_inline
1242 int pthread_cond_signal_intercept(pthread_cond_t* cond)
1244 int ret;
1245 OrigFn fn;
1246 VALGRIND_GET_ORIG_FN(fn);
1247 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_SIGNAL,
1248 cond, 0, 0, 0, 0);
1249 CALL_FN_W_W(ret, fn, cond);
1250 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_SIGNAL,
1251 cond, 0, 0, 0, 0);
1252 return ret;
1255 #if defined(VGO_solaris)
1256 /* On Solaris, pthread_cond_signal is a weak alias to cond_signal. */
1257 PTH_FUNCS(int, condZusignal, pthread_cond_signal_intercept,
1258 (pthread_cond_t *cond), (cond));
1259 #else
1260 PTH_FUNCS(int, pthreadZucondZusignal, pthread_cond_signal_intercept,
1261 (pthread_cond_t* cond), (cond));
1262 #endif /* VGO_solaris */
1264 static __always_inline
1265 int pthread_cond_broadcast_intercept(pthread_cond_t* cond)
1267 int ret;
1268 OrigFn fn;
1269 VALGRIND_GET_ORIG_FN(fn);
1270 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_BROADCAST,
1271 cond, 0, 0, 0, 0);
1272 CALL_FN_W_W(ret, fn, cond);
1273 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_BROADCAST,
1274 cond, 0, 0, 0, 0);
1275 return ret;
1278 #if defined(VGO_solaris)
1279 /* On Solaris, pthread_cond_broadcast is a weak alias to cond_broadcast. */
1280 PTH_FUNCS(int, condZubroadcast, pthread_cond_broadcast_intercept,
1281 (pthread_cond_t *cond), (cond));
1282 #else
1283 PTH_FUNCS(int, pthreadZucondZubroadcast, pthread_cond_broadcast_intercept,
1284 (pthread_cond_t* cond), (cond));
1285 #endif /* VGO_solaris */
1287 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1288 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1289 static __always_inline
1290 int pthread_spin_init_intercept(pthread_spinlock_t *spinlock, int pshared)
1292 int ret;
1293 OrigFn fn;
1294 VALGRIND_GET_ORIG_FN(fn);
1295 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
1296 spinlock, 0, 0, 0, 0);
1297 CALL_FN_W_WW(ret, fn, spinlock, pshared);
1298 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
1299 spinlock, 0, 0, 0, 0);
1300 return ret;
1303 PTH_FUNCS(int, pthreadZuspinZuinit, pthread_spin_init_intercept,
1304 (pthread_spinlock_t *spinlock, int pshared), (spinlock, pshared));
1306 static __always_inline
1307 int pthread_spin_destroy_intercept(pthread_spinlock_t *spinlock)
1309 int ret;
1310 OrigFn fn;
1311 VALGRIND_GET_ORIG_FN(fn);
1312 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
1313 spinlock, 0, 0, 0, 0);
1314 CALL_FN_W_W(ret, fn, spinlock);
1315 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
1316 spinlock, mutex_type_spinlock, 0, 0, 0);
1317 return ret;
1320 PTH_FUNCS(int, pthreadZuspinZudestroy, pthread_spin_destroy_intercept,
1321 (pthread_spinlock_t *spinlock), (spinlock));
1323 static __always_inline
1324 int pthread_spin_lock_intercept(pthread_spinlock_t *spinlock)
1326 int ret;
1327 OrigFn fn;
1328 VALGRIND_GET_ORIG_FN(fn);
1329 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
1330 spinlock, mutex_type_spinlock, 0, 0, 0);
1331 CALL_FN_W_W(ret, fn, spinlock);
1332 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
1333 spinlock, ret == 0, 0, 0, 0);
1334 return ret;
1337 PTH_FUNCS(int, pthreadZuspinZulock, pthread_spin_lock_intercept,
1338 (pthread_spinlock_t *spinlock), (spinlock));
1340 static __always_inline
1341 int pthread_spin_trylock_intercept(pthread_spinlock_t *spinlock)
1343 int ret;
1344 OrigFn fn;
1345 VALGRIND_GET_ORIG_FN(fn);
1346 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
1347 spinlock, mutex_type_spinlock, 0, 0, 0);
1348 CALL_FN_W_W(ret, fn, spinlock);
1349 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
1350 spinlock, ret == 0, 0, 0, 0);
1351 return ret;
1354 PTH_FUNCS(int, pthreadZuspinZutrylock, pthread_spin_trylock_intercept,
1355 (pthread_spinlock_t *spinlock), (spinlock));
1357 static __always_inline
1358 int pthread_spin_unlock_intercept(pthread_spinlock_t *spinlock)
1360 int ret;
1361 OrigFn fn;
1362 VALGRIND_GET_ORIG_FN(fn);
1363 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
1364 spinlock, mutex_type_spinlock, 0, 0, 0);
1365 CALL_FN_W_W(ret, fn, spinlock);
1366 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
1367 spinlock, 0, 0, 0, 0);
1368 return ret;
1371 PTH_FUNCS(int, pthreadZuspinZuunlock, pthread_spin_unlock_intercept,
1372 (pthread_spinlock_t *spinlock), (spinlock));
1373 #endif // HAVE_PTHREAD_SPIN_LOCK
1376 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1377 static __always_inline
1378 int pthread_barrier_init_intercept(pthread_barrier_t* barrier,
1379 const pthread_barrierattr_t* attr,
1380 unsigned count)
1382 int ret;
1383 OrigFn fn;
1384 VALGRIND_GET_ORIG_FN(fn);
1385 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_INIT,
1386 barrier, pthread_barrier, count, 0, 0);
1387 CALL_FN_W_WWW(ret, fn, barrier, attr, count);
1388 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_INIT,
1389 barrier, pthread_barrier, 0, 0, 0);
1390 return ret;
1393 PTH_FUNCS(int, pthreadZubarrierZuinit, pthread_barrier_init_intercept,
1394 (pthread_barrier_t* barrier, const pthread_barrierattr_t* attr,
1395 unsigned count), (barrier, attr, count));
1397 static __always_inline
1398 int pthread_barrier_destroy_intercept(pthread_barrier_t* barrier)
1400 int ret;
1401 OrigFn fn;
1402 VALGRIND_GET_ORIG_FN(fn);
1403 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_DESTROY,
1404 barrier, pthread_barrier, 0, 0, 0);
1405 CALL_FN_W_W(ret, fn, barrier);
1406 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_DESTROY,
1407 barrier, pthread_barrier, 0, 0, 0);
1408 return ret;
1411 PTH_FUNCS(int, pthreadZubarrierZudestroy, pthread_barrier_destroy_intercept,
1412 (pthread_barrier_t* barrier), (barrier));
1414 static __always_inline
1415 int pthread_barrier_wait_intercept(pthread_barrier_t* barrier)
1417 int ret;
1418 OrigFn fn;
1419 VALGRIND_GET_ORIG_FN(fn);
1420 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_WAIT,
1421 barrier, pthread_barrier, 0, 0, 0);
1422 CALL_FN_W_W(ret, fn, barrier);
1423 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_WAIT,
1424 barrier, pthread_barrier,
1425 ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD,
1426 ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
1427 return ret;
1430 PTH_FUNCS(int, pthreadZubarrierZuwait, pthread_barrier_wait_intercept,
1431 (pthread_barrier_t* barrier), (barrier));
1432 #endif // HAVE_PTHREAD_BARRIER_INIT
1435 static __always_inline
1436 int sem_init_intercept(sem_t *sem, int pshared, unsigned int value)
1438 int ret;
1439 OrigFn fn;
1440 VALGRIND_GET_ORIG_FN(fn);
1441 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT,
1442 sem, pshared, value, 0, 0);
1443 CALL_FN_W_WWW(ret, fn, sem, pshared, value);
1444 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT,
1445 sem, 0, 0, 0, 0);
1446 return ret;
1449 #if defined(VGO_freebsd)
1450 LIBC_FUNC(int, semZuinit, sem_init_intercept,
1451 (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
1452 #else
1453 PTH_FUNCS(int, semZuinit, sem_init_intercept,
1454 (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
1455 #endif
1457 #if defined(VGO_solaris)
1458 static __always_inline
1459 int sema_init_intercept(sema_t *sem, unsigned int value, int type, void *arg)
1461 int ret;
1462 OrigFn fn;
1463 VALGRIND_GET_ORIG_FN(fn);
1464 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT,
1465 sem, type == USYNC_PROCESS ? 1 : 0,
1466 value, 0, 0);
1467 CALL_FN_W_WWWW(ret, fn, sem, value, type, arg);
1468 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT,
1469 sem, 0, 0, 0, 0);
1470 return ret;
1473 PTH_FUNCS(int, semaZuinit, sema_init_intercept,
1474 (sema_t *sem, unsigned int value, int type, void *arg),
1475 (sem, value, type, arg));
1476 #endif /* VGO_solaris */
1478 static __always_inline
1479 int sem_destroy_intercept(sem_t *sem)
1481 int ret;
1482 OrigFn fn;
1483 VALGRIND_GET_ORIG_FN(fn);
1484 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_DESTROY,
1485 sem, 0, 0, 0, 0);
1486 CALL_FN_W_W(ret, fn, sem);
1487 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_DESTROY,
1488 sem, 0, 0, 0, 0);
1489 return ret;
1492 #if defined(VGO_freebsd)
1493 LIBC_FUNC(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1494 #else
1495 PTH_FUNCS(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1496 #endif
1498 #if defined(VGO_solaris)
1499 PTH_FUNCS(int, semaZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1500 #endif /* VGO_solaris */
1502 static __always_inline
1503 sem_t* sem_open_intercept(const char *name, int oflag, mode_t mode,
1504 unsigned int value)
1506 sem_t *ret;
1507 OrigFn fn;
1508 VALGRIND_GET_ORIG_FN(fn);
1509 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_OPEN,
1510 name, oflag, mode, value, 0);
1511 CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value);
1512 // To do: figure out why gcc 9.2.1 miscompiles this function if the printf()
1513 // call below is left out.
1514 printf("");
1515 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_OPEN,
1516 ret != SEM_FAILED ? ret : 0,
1517 name, oflag, mode, value);
1518 return ret;
1521 #if defined(VGO_freebsd)
1522 LIBC_FUNC(sem_t *, semZuopen, sem_open_intercept,
1523 (const char *name, int oflag, mode_t mode, unsigned int value),
1524 (name, oflag, mode, value));
1525 #else
1526 PTH_FUNCS(sem_t *, semZuopen, sem_open_intercept,
1527 (const char *name, int oflag, mode_t mode, unsigned int value),
1528 (name, oflag, mode, value));
1529 #endif
1531 static __always_inline int sem_close_intercept(sem_t *sem)
1533 int ret;
1534 OrigFn fn;
1535 VALGRIND_GET_ORIG_FN(fn);
1536 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_CLOSE,
1537 sem, 0, 0, 0, 0);
1538 CALL_FN_W_W(ret, fn, sem);
1539 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_CLOSE,
1540 sem, 0, 0, 0, 0);
1541 return ret;
1544 #if defined(VGO_freebsd)
1545 LIBC_FUNC(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
1546 #else
1547 PTH_FUNCS(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
1548 #endif
1550 static __always_inline int sem_wait_intercept(sem_t *sem)
1552 int ret;
1553 OrigFn fn;
1554 VALGRIND_GET_ORIG_FN(fn);
1555 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1556 sem, 0, 0, 0, 0);
1557 CALL_FN_W_W(ret, fn, sem);
1558 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1559 sem, ret == 0, 0, 0, 0);
1560 return ret;
1563 #if defined(VGO_freebsd)
1564 LIBC_FUNC(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1565 #else
1566 PTH_FUNCS(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1567 #endif
1569 #if defined(VGO_solaris)
1570 PTH_FUNCS(int, semaZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1571 #endif /* VGO_solaris */
1573 static __always_inline int sem_trywait_intercept(sem_t *sem)
1575 int ret;
1576 OrigFn fn;
1577 VALGRIND_GET_ORIG_FN(fn);
1578 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1579 sem, 0, 0, 0, 0);
1580 CALL_FN_W_W(ret, fn, sem);
1581 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1582 sem, ret == 0, 0, 0, 0);
1583 return ret;
1586 #if defined(VGO_freebsd)
1587 LIBC_FUNC(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1588 #else
1589 PTH_FUNCS(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1590 #endif
1591 #if defined(VGO_solaris)
1592 PTH_FUNCS(int, semaZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1593 #endif /* VGO_solaris */
1595 static __always_inline
1596 int sem_timedwait_intercept(sem_t *sem, const struct timespec *abs_timeout)
1598 int ret;
1599 OrigFn fn;
1600 VALGRIND_GET_ORIG_FN(fn);
1601 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1602 sem, 0, 0, 0, 0);
1603 CALL_FN_W_WW(ret, fn, sem, abs_timeout);
1604 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1605 sem, ret == 0, 0, 0, 0);
1606 return ret;
1609 #if defined(VGO_freebsd)
1610 LIBC_FUNC(int, semZutimedwait, sem_timedwait_intercept,
1611 (sem_t *sem, const struct timespec *abs_timeout),
1612 (sem, abs_timeout));
1613 #else
1614 PTH_FUNCS(int, semZutimedwait, sem_timedwait_intercept,
1615 (sem_t *sem, const struct timespec *abs_timeout),
1616 (sem, abs_timeout));
1617 #endif
1618 #if defined(VGO_solaris)
1619 PTH_FUNCS(int, semaZutimedwait, sem_timedwait_intercept,
1620 (sem_t *sem, const struct timespec *timeout),
1621 (sem, timeout));
1622 PTH_FUNCS(int, semaZureltimedwait, sem_timedwait_intercept,
1623 (sem_t *sem, const struct timespec *timeout),
1624 (sem, timeout));
1625 #endif /* VGO_solaris */
1627 static __always_inline int sem_post_intercept(sem_t *sem)
1629 int ret;
1630 OrigFn fn;
1631 VALGRIND_GET_ORIG_FN(fn);
1632 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_POST,
1633 sem, 0, 0, 0, 0);
1634 CALL_FN_W_W(ret, fn, sem);
1635 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_POST,
1636 sem, ret == 0, 0, 0, 0);
1637 return ret;
1640 #if defined(VGO_freebsd)
1641 LIBC_FUNC(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
1642 #else
1643 PTH_FUNCS(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
1644 #endif
1645 #if defined(VGO_solaris)
1646 PTH_FUNCS(int, semaZupost, sem_post_intercept, (sem_t *sem), (sem));
1647 #endif /* VGO_solaris */
1649 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1650 functions have to be conditionally compiled. */
1651 #if defined(HAVE_PTHREAD_RWLOCK_T)
1653 static __always_inline
1654 int pthread_rwlock_init_intercept(pthread_rwlock_t* rwlock,
1655 const pthread_rwlockattr_t* attr)
1657 int ret;
1658 OrigFn fn;
1659 VALGRIND_GET_ORIG_FN(fn);
1660 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT,
1661 rwlock, 0, 0, 0, 0);
1662 CALL_FN_W_WW(ret, fn, rwlock, attr);
1663 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT,
1664 rwlock, 0, 0, 0, 0);
1665 return ret;
1668 PTH_FUNCS(int,
1669 pthreadZurwlockZuinit, pthread_rwlock_init_intercept,
1670 (pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr),
1671 (rwlock, attr));
1673 #if defined(VGO_solaris)
1674 static __always_inline
1675 int rwlock_init_intercept(rwlock_t *rwlock, int type, void *arg)
1677 int ret;
1678 OrigFn fn;
1679 VALGRIND_GET_ORIG_FN(fn);
1680 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT,
1681 rwlock, 0, 0, 0, 0);
1682 CALL_FN_W_WWW(ret, fn, rwlock, type, arg);
1683 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT,
1684 rwlock, 0, 0, 0, 0);
1685 return ret;
1688 PTH_FUNCS(int, rwlockZuinit, rwlock_init_intercept,
1689 (rwlock_t *rwlock, int type, void *arg),
1690 (rwlock, type, arg));
1691 #endif /* VGO_solaris */
1693 static __always_inline
1694 int pthread_rwlock_destroy_intercept(pthread_rwlock_t* rwlock)
1696 int ret;
1697 OrigFn fn;
1698 VALGRIND_GET_ORIG_FN(fn);
1699 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_DESTROY,
1700 rwlock, 0, 0, 0, 0);
1701 CALL_FN_W_W(ret, fn, rwlock);
1702 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_DESTROY,
1703 rwlock, 0, 0, 0, 0);
1704 return ret;
1707 #if defined(VGO_solaris)
1708 /* On Solaris, pthread_rwlock_destroy is a weak alias to rwlock_destroy. */
1709 PTH_FUNCS(int,
1710 rwlockZudestroy, pthread_rwlock_destroy_intercept,
1711 (pthread_rwlock_t *rwlock), (rwlock));
1712 #else
1713 PTH_FUNCS(int,
1714 pthreadZurwlockZudestroy, pthread_rwlock_destroy_intercept,
1715 (pthread_rwlock_t* rwlock), (rwlock));
1716 #endif /* VGO_solaris */
1718 static __always_inline
1719 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t* rwlock)
1721 int ret;
1722 OrigFn fn;
1723 VALGRIND_GET_ORIG_FN(fn);
1724 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1725 rwlock, 0, 0, 0, 0);
1726 CALL_FN_W_W(ret, fn, rwlock);
1727 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1728 rwlock, ret == 0, 0, 0, 0);
1729 return ret;
1732 #if defined(VGO_solaris)
1733 /* On Solaris, pthread_rwlock_rdlock is a weak alias to rw_rdlock. */
1734 PTH_FUNCS(int,
1735 rwZurdlock, pthread_rwlock_rdlock_intercept,
1736 (pthread_rwlock_t *rwlock), (rwlock));
1737 #else
1738 PTH_FUNCS(int,
1739 pthreadZurwlockZurdlock, pthread_rwlock_rdlock_intercept,
1740 (pthread_rwlock_t* rwlock), (rwlock));
1741 #endif /* VGO_solaris */
1743 #if defined(VGO_solaris)
1744 /* Internal to libc. */
1745 static __always_inline
1746 void lrw_rdlock_intercept(rwlock_t *rwlock)
1748 OrigFn fn;
1749 VALGRIND_GET_ORIG_FN(fn);
1750 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1751 rwlock, 0, 0, 0, 0);
1752 CALL_FN_v_W(fn, rwlock);
1753 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1754 rwlock, True /* took_lock */, 0, 0, 0);
1757 PTH_FUNCS(void, lrwZurdlock, lrw_rdlock_intercept,
1758 (rwlock_t *rwlock), (rwlock));
1759 #endif /* VGO_solaris */
1761 static __always_inline
1762 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t* rwlock)
1764 int ret;
1765 OrigFn fn;
1766 VALGRIND_GET_ORIG_FN(fn);
1767 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1768 rwlock, 0, 0, 0, 0);
1769 CALL_FN_W_W(ret, fn, rwlock);
1770 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1771 rwlock, ret == 0, 0, 0, 0);
1772 return ret;
1775 #if defined(VGO_solaris)
1776 /* On Solaris, pthread_rwlock_wrlock is a weak alias to rw_wrlock. */
1777 PTH_FUNCS(int,
1778 rwZuwrlock, pthread_rwlock_wrlock_intercept,
1779 (pthread_rwlock_t *rwlock), (rwlock));
1780 #else
1781 PTH_FUNCS(int,
1782 pthreadZurwlockZuwrlock, pthread_rwlock_wrlock_intercept,
1783 (pthread_rwlock_t* rwlock), (rwlock));
1784 #endif /* VGO_solaris */
1786 #if defined(VGO_solaris)
1787 /* Internal to libc. */
1788 static __always_inline
1789 void lrw_wrlock_intercept(rwlock_t *rwlock)
1791 OrigFn fn;
1792 VALGRIND_GET_ORIG_FN(fn);
1793 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1794 rwlock, 0, 0, 0, 0);
1795 CALL_FN_v_W(fn, rwlock);
1796 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1797 rwlock, True /* took_lock */, 0, 0, 0);
1800 PTH_FUNCS(void, lrwZuwrlock, lrw_wrlock_intercept,
1801 (rwlock_t *rwlock), (rwlock));
1802 #endif /* VGO_solaris */
1804 static __always_inline
1805 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t* rwlock,
1806 const struct timespec *timeout)
1808 int ret;
1809 OrigFn fn;
1810 VALGRIND_GET_ORIG_FN(fn);
1811 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1812 rwlock, 0, 0, 0, 0);
1813 CALL_FN_W_WW(ret, fn, rwlock, timeout);
1814 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1815 rwlock, ret == 0, 0, 0, 0);
1816 return ret;
1819 PTH_FUNCS(int,
1820 pthreadZurwlockZutimedrdlock, pthread_rwlock_timedrdlock_intercept,
1821 (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1822 (rwlock, timeout));
1823 #if defined(VGO_solaris)
1824 PTH_FUNCS(int, pthreadZurwlockZureltimedrdlockZunp,
1825 pthread_rwlock_timedrdlock_intercept,
1826 (pthread_rwlock_t *rwlock, const struct timespec *timeout),
1827 (rwlock, timeout));
1828 #endif /* VGO_solaris */
1831 #if defined(HAVE_CLOCKID_T)
1832 static __always_inline
1833 int pthread_rwlock_clockrdlock_intercept(pthread_rwlock_t* rwlock,
1834 clockid_t clockid,
1835 const struct timespec *timeout)
1837 int ret;
1838 OrigFn fn;
1839 VALGRIND_GET_ORIG_FN(fn);
1840 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1841 rwlock, 0, 0, 0, 0);
1842 CALL_FN_W_WWW(ret, fn, rwlock, clockid, timeout);
1843 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1844 rwlock, ret == 0, 0, 0, 0);
1845 return ret;
1848 PTH_FUNCS(int,
1849 pthreadZurwlockZuclockrdlock, pthread_rwlock_clockrdlock_intercept,
1850 (pthread_rwlock_t* rwlock, clockid_t clockid, const struct timespec *timeout),
1851 (rwlock, clockid, timeout));
1852 #endif
1854 static __always_inline
1855 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t* rwlock,
1856 const struct timespec *timeout)
1858 int ret;
1859 OrigFn fn;
1860 VALGRIND_GET_ORIG_FN(fn);
1861 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1862 rwlock, 0, 0, 0, 0);
1863 CALL_FN_W_WW(ret, fn, rwlock, timeout);
1864 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1865 rwlock, ret == 0, 0, 0, 0);
1866 return ret;
1869 PTH_FUNCS(int,
1870 pthreadZurwlockZutimedwrlock, pthread_rwlock_timedwrlock_intercept,
1871 (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1872 (rwlock, timeout));
1873 #if defined(VGO_solaris)
1874 PTH_FUNCS(int, pthreadZurwlockZureltimedwrlockZunp,
1875 pthread_rwlock_timedwrlock_intercept,
1876 (pthread_rwlock_t *rwlock, const struct timespec *timeout),
1877 (rwlock, timeout));
1878 #endif /* VGO_solaris */
1881 #if defined(HAVE_CLOCKID_T)
1882 static __always_inline
1883 int pthread_rwlock_clockwrlock_intercept(pthread_rwlock_t* rwlock,
1884 clockid_t clockid,
1885 const struct timespec *timeout)
1887 int ret;
1888 OrigFn fn;
1889 VALGRIND_GET_ORIG_FN(fn);
1890 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1891 rwlock, 0, 0, 0, 0);
1892 CALL_FN_W_WWW(ret, fn, rwlock, clockid, timeout);
1893 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1894 rwlock, ret == 0, 0, 0, 0);
1895 return ret;
1898 PTH_FUNCS(int,
1899 pthreadZurwlockZuclockwrlock, pthread_rwlock_clockwrlock_intercept,
1900 (pthread_rwlock_t* rwlock, clockid_t clockid, const struct timespec *timeout),
1901 (rwlock, clockid, timeout));
1902 #endif
1905 static __always_inline
1906 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t* rwlock)
1908 int ret;
1909 OrigFn fn;
1910 VALGRIND_GET_ORIG_FN(fn);
1911 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1912 rwlock, 0, 0, 0, 0);
1913 CALL_FN_W_W(ret, fn, rwlock);
1914 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1915 rwlock, ret == 0, 0, 0, 0);
1916 return ret;
1919 #if defined(VGO_solaris)
1920 /* On Solaris, pthread_rwlock_tryrdlock is a weak alias to rw_tryrdlock. */
1921 PTH_FUNCS(int,
1922 rwZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1923 (pthread_rwlock_t *rwlock), (rwlock));
1924 #else
1925 PTH_FUNCS(int,
1926 pthreadZurwlockZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1927 (pthread_rwlock_t* rwlock), (rwlock));
1928 #endif /* VGO_solaris */
1930 static __always_inline
1931 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t* rwlock)
1933 int ret;
1934 OrigFn fn;
1935 VALGRIND_GET_ORIG_FN(fn);
1936 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1937 rwlock, 0, 0, 0, 0);
1938 CALL_FN_W_W(ret, fn, rwlock);
1939 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1940 rwlock, ret == 0, 0, 0, 0);
1941 return ret;
1944 #if defined(VGO_solaris)
1945 /* On Solaris, pthread_rwlock_trywrlock is a weak alias to rw_trywrlock. */
1946 PTH_FUNCS(int,
1947 rwZutrywrlock, pthread_rwlock_trywrlock_intercept,
1948 (pthread_rwlock_t *rwlock), (rwlock));
1949 #else
1950 PTH_FUNCS(int,
1951 pthreadZurwlockZutrywrlock, pthread_rwlock_trywrlock_intercept,
1952 (pthread_rwlock_t* rwlock), (rwlock));
1953 #endif /* VGO_solaris */
1955 static __always_inline
1956 int pthread_rwlock_unlock_intercept(pthread_rwlock_t* rwlock)
1958 int ret;
1959 OrigFn fn;
1960 VALGRIND_GET_ORIG_FN(fn);
1961 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_UNLOCK,
1962 rwlock, 0, 0, 0, 0);
1963 CALL_FN_W_W(ret, fn, rwlock);
1964 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_UNLOCK,
1965 rwlock, ret == 0, 0, 0, 0);
1966 return ret;
1969 #if defined(VGO_solaris)
1970 /* On Solaris, pthread_rwlock_unlock is a weak alias to rw_unlock. */
1971 PTH_FUNCS(int,
1972 rwZuunlock, pthread_rwlock_unlock_intercept,
1973 (pthread_rwlock_t *rwlock), (rwlock));
1974 #else
1975 PTH_FUNCS(int,
1976 pthreadZurwlockZuunlock, pthread_rwlock_unlock_intercept,
1977 (pthread_rwlock_t* rwlock), (rwlock));
1978 #endif /* VGO_solaris */
1980 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */