drd: Rename a function
[valgrind.git] / drd / drd_pthread_intercepts.c
blobe5078eec5d06f2f15783a86416b98f6f0eeb6837
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-2017 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, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
23 02111-1307, USA.
25 The GNU General Public License is contained in the file COPYING.
28 /* ---------------------------------------------------------------------
29 ALL THE CODE IN THIS FILE RUNS ON THE SIMULATED CPU.
31 These functions are not called directly - they're the targets of code
32 redirection or load notifications (see pub_core_redir.h for info).
33 They're named weirdly so that the intercept code can find them when the
34 shared object is initially loaded.
36 Note that this filename has the "drd_" prefix because it can appear
37 in stack traces, and the "drd_" makes it a little clearer that it
38 originates from Valgrind.
39 ------------------------------------------------------------------ */
42 * Define _GNU_SOURCE to make sure that pthread_spinlock_t is available when
43 * compiling with older glibc versions (2.3 or before).
45 #ifndef _GNU_SOURCE
46 #define _GNU_SOURCE
47 #endif
49 #include <assert.h> /* assert() */
50 #include <errno.h>
51 #include <pthread.h> /* pthread_mutex_t */
52 #include <semaphore.h> /* sem_t */
53 #include <stdint.h> /* uintptr_t */
54 #include <stdio.h> /* fprintf() */
55 #include <stdlib.h> /* malloc(), free() */
56 #include <unistd.h> /* confstr() */
57 #include "config.h" /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP etc. */
58 #include "drd_basics.h" /* DRD_() */
59 #include "drd_clientreq.h"
60 #include "pub_tool_redir.h" /* VG_WRAP_FUNCTION_ZZ() */
62 #if defined(VGO_solaris)
64 * Solaris usually provides pthread_* functions on top of Solaris threading
65 * and synchronization functions. Usually both need to be intercepted because
66 * pthread_* ones might not call the Solaris ones (see for example sem_wait()).
67 * Such approach is required to correctly report misuse of the POSIX threads
68 * API.
69 * Therefore DRD intercepts and instruments all such functions but due to
70 * DRD_(thread_enter_synchr)() and DRD_(thread_leave_synchr)() guards in
71 * handle_client_request(), only the top-most function is handled.
72 * So the right thing(TM) happens, as expected.
73 * The only exception is when pthread_* function is a weak alias to the Solaris
74 * threading/synchronization function. In such case only one needs to be
75 * intercepted to avoid redirection ambiguity.
77 * Intercepted functions rely on the fact that:
78 * - pthread_mutex_t == mutex_t
79 * - pthread_cond_t == cond_t
80 * - sem_t == sema_t
81 * - pthread_rwlock_t == rwlock_t
83 * It is necessary to intercept also internal libc synchronization functions
84 * for two reasons:
85 * - For read-write locks the unlocking function is shared
86 * - Functions lmutex_lock/lmutex_unlock guard many critical sections in libc
87 * which will be otherwise reported by DRD
89 #include <synch.h>
90 #include <thread.h>
91 #include "pub_tool_vki.h"
94 * Solaris provides higher throughput, parallelism and scalability than other
95 * operating systems, at the cost of more fine-grained locking activity.
96 * This means for example that when a thread is created under Linux, just one
97 * big lock in glibc is used for all thread setup. Solaris libc uses several
98 * fine-grained locks and the creator thread resumes its activities as soon
99 * as possible, leaving for example stack and TLS setup activities to the
100 * created thread.
102 * This situation confuses DRD as it assumes there is some false ordering
103 * in place between creator and created thread; and therefore many types of
104 * race conditions in the application would not be reported. To prevent such
105 * false ordering, command line option --ignore-thread-creation is set to
106 * 'yes' by default on Solaris. All activity (loads, stores, client requests)
107 * is therefore ignored during:
108 * - pthread_create() call in the creator thread [libc.so]
109 * - thread creation phase (stack and TLS setup) in the created thread [libc.so]
111 * As explained in the comments for _ti_bind_guard(), whenever the runtime
112 * linker has to perform any activity (such as resolving a symbol), it protects
113 * its data structures by calling into rt_bind_guard() which in turn invokes
114 * _ti_bind_guard() in libc. Pointers to _ti_bind_guard() and _ti_bind_clear()
115 * are passed from libc to runtime linker in _ld_libc() call during libc_init().
116 * All activity is also ignored during:
117 * - runtime dynamic linker work between rt_bind_guard() and rt_bind_clear()
118 * calls [ld.so]
120 * This also means that DRD does not report race conditions in libc (when
121 * --ignore-thread-creation=yes) and runtime linker itself (unconditionally)
122 * during these ignored sequences.
126 * Original function pointers for _ti_bind_guard() and _ti_bind_clear()
127 * from libc. They are intercepted in function wrapper of _ld_libc().
129 typedef int (*drd_rtld_guard_fn)(int flags);
130 static drd_rtld_guard_fn DRD_(rtld_bind_guard) = NULL;
131 static drd_rtld_guard_fn DRD_(rtld_bind_clear) = NULL;
132 #endif
136 * Notes regarding thread creation:
137 * - sg_init() runs on the context of the created thread and copies the vector
138 * clock of the creator thread. This only works reliably if the creator
139 * thread waits until this copy has been performed.
140 * - DRD_(thread_compute_minimum_vc)() does not take the vector clocks into
141 * account that are involved in thread creation and for which the
142 * corresponding thread has not yet been created. So not waiting until the
143 * created thread has been started would make it possible that segments get
144 * discarded that should not yet be discarded. Or: some data races are not
145 * detected.
149 * Macro for generating a Valgrind interception function.
150 * @param[in] ret_ty Return type of the function to be generated.
151 * @param[in] zf Z-encoded name of the interception function.
152 * @param[in] implf Name of the function that implements the intercept.
153 * @param[in] arg_decl Argument declaration list enclosed in parentheses.
154 * @param[in] argl Argument list enclosed in parentheses.
156 #ifdef VGO_darwin
157 static int never_true;
158 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
159 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
160 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
162 ret_ty pth_func_result = implf argl; \
163 /* Apparently inserting a function call in wrapper functions */ \
164 /* is sufficient to avoid misaligned stack errors. */ \
165 if (never_true) \
166 fflush(stdout); \
167 return pth_func_result; \
169 #elif defined(VGO_solaris)
170 /* On Solaris, libpthread is just a filter library on top of libc.
171 * Threading and synchronization functions in runtime linker are not
172 * intercepted.
174 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
175 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl; \
176 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl \
177 { return implf argl; }
178 #else
179 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
180 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
181 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
182 { return implf argl; }
183 #endif
186 * Macro for generating three Valgrind interception functions: one with the
187 * Z-encoded name zf, one with ZAZa ("@*") appended to the name zf and one
188 * with ZDZa ("$*") appended to the name zf. The second generated interception
189 * function will intercept versioned symbols on Linux, and the third will
190 * intercept versioned symbols on Darwin.
192 #define PTH_FUNCS(ret_ty, zf, implf, argl_decl, argl) \
193 PTH_FUNC(ret_ty, zf, implf, argl_decl, argl); \
194 PTH_FUNC(ret_ty, zf ## ZAZa, implf, argl_decl, argl); \
195 PTH_FUNC(ret_ty, zf ## ZDZa, implf, argl_decl, argl);
198 * Not inlining one of the intercept functions will cause the regression
199 * tests to fail because this would cause an additional stackfram to appear
200 * in the output. The __always_inline macro guarantees that inlining will
201 * happen, even when compiling with optimization disabled.
203 #undef __always_inline /* since already defined in <cdefs.h> */
204 #if __GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 2
205 #define __always_inline __inline__ __attribute__((always_inline))
206 #else
207 #define __always_inline __inline__
208 #endif
210 /* Local data structures. */
212 typedef struct {
213 pthread_mutex_t mutex;
214 pthread_cond_t cond;
215 int counter;
216 } DrdSema;
218 typedef struct
220 void* (*start)(void*);
221 void* arg;
222 int detachstate;
223 DrdSema* wrapper_started;
224 } DrdPosixThreadArgs;
227 /* Local function declarations. */
229 static void DRD_(init)(void) __attribute__((constructor));
230 static void DRD_(check_threading_library)(void);
231 static void DRD_(set_pthread_id)(void);
232 static void DRD_(sema_init)(DrdSema* sema);
233 static void DRD_(sema_destroy)(DrdSema* sema);
234 static void DRD_(sema_down)(DrdSema* sema);
235 static void DRD_(sema_up)(DrdSema* sema);
238 /* Function definitions. */
241 * Shared library initialization function. The function init() is called after
242 * dlopen() has loaded the shared library with DRD client intercepts because
243 * the constructor attribute was specified in the declaration of this function.
244 * Note: do specify the -nostdlib option to gcc when linking this code into a
245 * shared library because doing so would cancel the effect of the constructor
246 * attribute ! Using the gcc option -nodefaultlibs is fine because this last
247 * option preserves the shared library initialization code that calls
248 * constructor and destructor functions.
250 static void DRD_(init)(void)
252 DRD_(check_threading_library)();
253 DRD_(set_pthread_id)();
254 #if defined(VGO_solaris)
255 if ((DRD_(rtld_bind_guard) == NULL) || (DRD_(rtld_bind_clear) == NULL)) {
256 fprintf(stderr,
257 "Bind guard functions for the runtime linker (ld.so.1) were not intercepted.\n"
258 "This means the interface between libc and runtime linker changed and DRD\n"
259 "needs to be ported properly. Giving up.\n");
260 abort();
262 #endif
265 static __always_inline void DRD_(ignore_mutex_ordering)(pthread_mutex_t *mutex)
267 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_IGNORE_MUTEX_ORDERING,
268 mutex, 0, 0, 0, 0);
271 static void DRD_(sema_init)(DrdSema* sema)
273 DRD_IGNORE_VAR(*sema);
274 pthread_mutex_init(&sema->mutex, NULL);
275 DRD_(ignore_mutex_ordering)(&sema->mutex);
276 pthread_cond_init(&sema->cond, NULL);
277 sema->counter = 0;
280 static void DRD_(sema_destroy)(DrdSema* sema)
282 pthread_mutex_destroy(&sema->mutex);
283 pthread_cond_destroy(&sema->cond);
286 static void DRD_(sema_down)(DrdSema* sema)
288 pthread_mutex_lock(&sema->mutex);
289 while (sema->counter == 0)
290 pthread_cond_wait(&sema->cond, &sema->mutex);
291 sema->counter--;
292 pthread_mutex_unlock(&sema->mutex);
295 static void DRD_(sema_up)(DrdSema* sema)
297 pthread_mutex_lock(&sema->mutex);
298 sema->counter++;
299 pthread_cond_signal(&sema->cond);
300 pthread_mutex_unlock(&sema->mutex);
304 * POSIX threads and DRD each have their own mutex type identification.
305 * Convert POSIX threads' mutex type to DRD's mutex type. In the code below
306 * if-statements are used to test the value of 'kind' instead of a switch
307 * statement because some of the PTHREAD_MUTEX_ macro's may have the same
308 * value.
310 static MutexT DRD_(pthread_to_drd_mutex_type)(int kind)
313 * See also PTHREAD_MUTEX_KIND_MASK_NP in glibc source file
314 * <nptl/pthreadP.h>.
316 kind &= PTHREAD_MUTEX_RECURSIVE | PTHREAD_MUTEX_ERRORCHECK |
317 PTHREAD_MUTEX_NORMAL | PTHREAD_MUTEX_DEFAULT;
319 if (kind == PTHREAD_MUTEX_RECURSIVE)
320 return mutex_type_recursive_mutex;
321 else if (kind == PTHREAD_MUTEX_ERRORCHECK)
322 return mutex_type_errorcheck_mutex;
323 else if (kind == PTHREAD_MUTEX_NORMAL)
324 return mutex_type_default_mutex;
325 else if (kind == PTHREAD_MUTEX_DEFAULT)
326 return mutex_type_default_mutex;
327 #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
328 else if (kind == PTHREAD_MUTEX_ADAPTIVE_NP)
329 return mutex_type_default_mutex;
330 #endif
331 else
332 return mutex_type_invalid_mutex;
335 #if defined(VGO_solaris)
337 * Solaris threads and DRD each have their own mutex type identification.
338 * Convert Solaris threads' mutex type to DRD's mutex type.
340 static MutexT DRD_(thread_to_drd_mutex_type)(int type)
342 if (type & LOCK_RECURSIVE) {
343 return mutex_type_recursive_mutex;
344 } else if (type & LOCK_ERRORCHECK) {
345 return mutex_type_errorcheck_mutex;
346 } else {
347 return mutex_type_default_mutex;
350 #endif /* VGO_solaris */
352 #define IS_ALIGNED(p) (((uintptr_t)(p) & (sizeof(*(p)) - 1)) == 0)
355 * Read the mutex type stored in the client memory used for the mutex
356 * implementation.
358 * @note This function depends on the implementation of the POSIX threads
359 * library -- the POSIX standard does not define the name of the member in
360 * which the mutex type is stored.
361 * @note The function mutex_type() has been declared inline in order
362 * to avoid that it shows up in call stacks (drd/tests/...exp* files).
363 * @note glibc stores the mutex type in the lowest two bits, and uses the
364 * higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
365 * PTHREAD_MUTEXATTR_FLAG_PSHARED.
367 static __always_inline MutexT DRD_(mutex_type)(pthread_mutex_t* mutex)
369 #if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
370 /* glibc + LinuxThreads. */
371 if (IS_ALIGNED(&mutex->__m_kind))
373 const int kind = mutex->__m_kind & 3;
374 return DRD_(pthread_to_drd_mutex_type)(kind);
376 #elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
377 /* glibc + NPTL. */
378 if (IS_ALIGNED(&mutex->__data.__kind))
380 const int kind = mutex->__data.__kind & 3;
381 return DRD_(pthread_to_drd_mutex_type)(kind);
383 #elif defined(VGO_solaris)
384 const int type = ((mutex_t *) mutex)->vki_mutex_type;
385 return DRD_(thread_to_drd_mutex_type)(type);
386 #else
388 * Another POSIX threads implementation. The mutex type won't be printed
389 * when enabling --trace-mutex=yes.
391 #endif
392 return mutex_type_unknown;
396 * Tell DRD whether 'tid' is a joinable thread or a detached thread.
398 static void DRD_(set_joinable)(const pthread_t tid, const int joinable)
400 assert(joinable == 0 || joinable == 1);
401 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_JOINABLE,
402 tid, joinable, 0, 0, 0);
405 /** Tell DRD that the calling thread is about to enter pthread_create(). */
406 static __always_inline void DRD_(entering_pthread_create)(void)
408 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__ENTERING_PTHREAD_CREATE,
409 0, 0, 0, 0, 0);
412 /** Tell DRD that the calling thread has left pthread_create(). */
413 static __always_inline void DRD_(left_pthread_create)(void)
415 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LEFT_PTHREAD_CREATE,
416 0, 0, 0, 0, 0);
420 * Entry point for newly created threads. This function is called from the
421 * thread created by pthread_create().
423 static void* DRD_(thread_wrapper)(void* arg)
425 DrdPosixThreadArgs* arg_ptr;
426 DrdPosixThreadArgs arg_copy;
428 arg_ptr = (DrdPosixThreadArgs*)arg;
429 arg_copy = *arg_ptr;
431 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
432 pthread_self(), 0, 0, 0, 0);
434 DRD_(set_joinable)(pthread_self(),
435 arg_copy.detachstate == PTHREAD_CREATE_JOINABLE);
438 * Only set 'wrapper_started' after VG_USERREQ__SET_PTHREADID and
439 * DRD_(set_joinable)() have been invoked to avoid a race with
440 * a pthread_detach() invocation for this thread from another thread.
442 DRD_(sema_up)(arg_copy.wrapper_started);
444 return (arg_copy.start)(arg_copy.arg);
448 * Return 1 if the LinuxThreads implementation of POSIX Threads has been
449 * detected, and 0 otherwise.
451 * @see For more information about the confstr() function, see also
452 * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
454 static int DRD_(detected_linuxthreads)(void)
456 #if defined(linux)
457 #if defined(_CS_GNU_LIBPTHREAD_VERSION)
458 /* Linux with a recent glibc. */
459 HChar buffer[256];
460 unsigned len;
461 len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
462 assert(len <= sizeof(buffer));
463 return len > 0 && buffer[0] == 'l';
464 #else
465 /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
466 return 1;
467 #endif
468 #else
469 /* Another OS than Linux, hence no LinuxThreads. */
470 return 0;
471 #endif
475 * Stop and print an error message in case a non-supported threading
476 * library implementation (LinuxThreads) has been detected.
478 static void DRD_(check_threading_library)(void)
480 if (DRD_(detected_linuxthreads)())
482 if (getenv("LD_ASSUME_KERNEL"))
484 fprintf(stderr,
485 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
486 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
487 "after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
490 else
492 fprintf(stderr,
493 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
494 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
495 "after having upgraded to a newer version of your Linux distribution.\n"
496 "Giving up.\n"
499 abort();
504 * Update DRD's state information about the current thread.
506 static void DRD_(set_pthread_id)(void)
508 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
509 pthread_self(), 0, 0, 0, 0);
513 * Note: as of today there exist three different versions of pthread_create
514 * in Linux:
515 * - pthread_create@GLIBC_2.0
516 * - pthread_create@@GLIBC_2.1
517 * - pthread_create@@GLIBC_2.2.5
518 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
519 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
520 * versions have been implemented. In any glibc version where more than one
521 * pthread_create function has been implemented, older versions call the
522 * newer versions. Or: the pthread_create* wrapper defined below can be
523 * called recursively. Any code in this wrapper should take this in account.
524 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
525 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
526 * See also the implementation of pthread_create@GLIBC_2.0 in
527 * glibc-2.9/nptl/pthread_create.c.
530 static __always_inline
531 int pthread_create_intercept(pthread_t* thread, const pthread_attr_t* attr,
532 void* (*start)(void*), void* arg)
534 int ret;
535 OrigFn fn;
536 DrdSema wrapper_started;
537 DrdPosixThreadArgs thread_args;
539 VALGRIND_GET_ORIG_FN(fn);
541 DRD_(sema_init)(&wrapper_started);
542 thread_args.start = start;
543 thread_args.arg = arg;
544 thread_args.wrapper_started = &wrapper_started;
546 * Find out whether the thread will be started as a joinable thread
547 * or as a detached thread. If no thread attributes have been specified,
548 * this means that the new thread will be started as a joinable thread.
550 thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
551 if (attr)
553 if (pthread_attr_getdetachstate(attr, &thread_args.detachstate) != 0)
554 assert(0);
556 assert(thread_args.detachstate == PTHREAD_CREATE_JOINABLE
557 || thread_args.detachstate == PTHREAD_CREATE_DETACHED);
559 DRD_(entering_pthread_create)();
560 CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), &thread_args);
561 DRD_(left_pthread_create)();
563 if (ret == 0) {
564 /* Wait until the thread wrapper started. */
565 DRD_(sema_down)(&wrapper_started);
568 DRD_(sema_destroy)(&wrapper_started);
570 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT,
571 pthread_self(), 0, 0, 0, 0);
573 return ret;
576 PTH_FUNCS(int, pthreadZucreate, pthread_create_intercept,
577 (pthread_t *thread, const pthread_attr_t *attr,
578 void *(*start) (void *), void *arg),
579 (thread, attr, start, arg));
581 #if defined(VGO_solaris)
582 /* Solaris also provides thr_create() in addition to pthread_create().
583 * Both pthread_create(3C) and thr_create(3C) are based on private
584 * _thrp_create().
586 static __always_inline
587 int thr_create_intercept(void *stk, size_t stksize, void *(*start)(void *),
588 void *arg, long flags, thread_t *new_thread)
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.
605 if (flags & THR_DETACHED)
606 thread_args.detachstate = PTHREAD_CREATE_DETACHED;
607 else
608 thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
610 DRD_(entering_pthread_create)();
611 CALL_FN_W_6W(ret, fn, stk, stksize, DRD_(thread_wrapper), &thread_args,
612 flags, new_thread);
613 DRD_(left_pthread_create)();
615 if (ret == 0) {
616 /* Wait until the thread wrapper started. */
617 DRD_(sema_down)(&wrapper_started);
620 DRD_(sema_destroy)(&wrapper_started);
622 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT,
623 pthread_self(), 0, 0, 0, 0);
625 return ret;
628 PTH_FUNCS(int, thrZucreate, thr_create_intercept,
629 (void *stk, size_t stksize, void *(*start)(void *), void *arg,
630 long flags, thread_t *new_thread),
631 (stk, stksize, start, arg, flags, new_thread));
632 #endif /* VGO_solaris */
634 #if defined(VGO_solaris)
636 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
637 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
638 * and CI_BIND_CLEAR, to provide resilience against function renaming.
640 static __always_inline
641 int DRD_(_ti_bind_guard_intercept)(int flags) {
642 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_GUARD,
643 flags, 0, 0, 0, 0);
644 return DRD_(rtld_bind_guard)(flags);
647 static __always_inline
648 int DRD_(_ti_bind_clear_intercept)(int flags) {
649 int ret = DRD_(rtld_bind_clear)(flags);
650 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_CLEAR,
651 flags, 0, 0, 0, 0);
652 return ret;
656 * Wrapped _ld_libc() from the runtime linker ld.so.1.
658 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr);
659 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr)
661 OrigFn fn;
662 int tag;
664 VALGRIND_GET_ORIG_FN(fn);
666 vki_Lc_interface *funcs = ptr;
667 for (tag = funcs->ci_tag; tag != 0; tag = (++funcs)->ci_tag) {
668 switch (tag) {
669 case VKI_CI_BIND_GUARD:
670 if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_guard_intercept)) {
671 DRD_(rtld_bind_guard) = funcs->vki_ci_un.ci_func;
672 funcs->vki_ci_un.ci_func = DRD_(_ti_bind_guard_intercept);
674 break;
675 case VKI_CI_BIND_CLEAR:
676 if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_clear_intercept)) {
677 DRD_(rtld_bind_clear) = funcs->vki_ci_un.ci_func;
678 funcs->vki_ci_un.ci_func = DRD_(_ti_bind_clear_intercept);
680 break;
684 CALL_FN_v_W(fn, ptr);
686 #endif /* VGO_solaris */
688 static __always_inline
689 int pthread_join_intercept(pthread_t pt_joinee, void **thread_return)
691 int ret;
692 OrigFn fn;
694 VALGRIND_GET_ORIG_FN(fn);
696 * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
697 * implementation triggers a (false positive) race report.
699 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
700 CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
701 if (ret == 0)
703 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN,
704 pt_joinee, 0, 0, 0, 0);
706 ANNOTATE_IGNORE_READS_AND_WRITES_END();
707 return ret;
710 PTH_FUNCS(int, pthreadZujoin, pthread_join_intercept,
711 (pthread_t pt_joinee, void **thread_return),
712 (pt_joinee, thread_return));
714 #if defined(VGO_solaris)
715 /* Solaris also provides thr_join() in addition to pthread_join().
716 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
718 * :TODO: No functionality is currently provided for joinee == 0 and departed.
719 * This would require another client request, of course.
721 static __always_inline
722 int thr_join_intercept(thread_t joinee, thread_t *departed, void **thread_return)
724 int ret;
725 OrigFn fn;
727 VALGRIND_GET_ORIG_FN(fn);
728 CALL_FN_W_WWW(ret, fn, joinee, departed, thread_return);
729 if (ret == 0)
731 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN,
732 joinee, 0, 0, 0, 0);
734 return ret;
737 PTH_FUNCS(int, thrZujoin, thr_join_intercept,
738 (thread_t joinee, thread_t *departed, void **thread_return),
739 (joinee, departed, thread_return));
740 #endif /* VGO_solaris */
742 static __always_inline
743 int pthread_detach_intercept(pthread_t pt_thread)
745 int ret;
746 OrigFn fn;
748 VALGRIND_GET_ORIG_FN(fn);
749 CALL_FN_W_W(ret, fn, pt_thread);
750 DRD_(set_joinable)(pt_thread, 0);
752 return ret;
755 PTH_FUNCS(int, pthreadZudetach, pthread_detach_intercept,
756 (pthread_t thread), (thread));
758 // NOTE: be careful to intercept only pthread_cancel() and not
759 // pthread_cancel_init() on Linux.
761 static __always_inline
762 int pthread_cancel_intercept(pthread_t pt_thread)
764 int ret;
765 OrigFn fn;
766 VALGRIND_GET_ORIG_FN(fn);
767 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_THREAD_CANCEL,
768 pt_thread, 0, 0, 0, 0);
769 CALL_FN_W_W(ret, fn, pt_thread);
770 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_CANCEL,
771 pt_thread, ret==0, 0, 0, 0);
772 return ret;
775 PTH_FUNCS(int, pthreadZucancel, pthread_cancel_intercept,
776 (pthread_t thread), (thread))
778 static __always_inline
779 int pthread_once_intercept(pthread_once_t *once_control,
780 void (*init_routine)(void))
782 int ret;
783 OrigFn fn;
784 VALGRIND_GET_ORIG_FN(fn);
786 * Ignore any data races triggered by the implementation of pthread_once().
787 * Necessary for Darwin. This is not necessary for Linux but doesn't have
788 * any known adverse effects.
790 DRD_IGNORE_VAR(*once_control);
791 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
792 CALL_FN_W_WW(ret, fn, once_control, init_routine);
793 ANNOTATE_IGNORE_READS_AND_WRITES_END();
794 DRD_STOP_IGNORING_VAR(*once_control);
795 return ret;
798 PTH_FUNCS(int, pthreadZuonce, pthread_once_intercept,
799 (pthread_once_t *once_control, void (*init_routine)(void)),
800 (once_control, init_routine));
802 static __always_inline
803 int pthread_mutex_init_intercept(pthread_mutex_t *mutex,
804 const pthread_mutexattr_t* attr)
806 int ret;
807 OrigFn fn;
808 int mt;
809 VALGRIND_GET_ORIG_FN(fn);
810 mt = PTHREAD_MUTEX_DEFAULT;
811 if (attr)
812 pthread_mutexattr_gettype(attr, &mt);
813 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
814 mutex, DRD_(pthread_to_drd_mutex_type)(mt),
815 0, 0, 0);
816 CALL_FN_W_WW(ret, fn, mutex, attr);
817 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
818 mutex, 0, 0, 0, 0);
819 return ret;
822 PTH_FUNCS(int, pthreadZumutexZuinit, pthread_mutex_init_intercept,
823 (pthread_mutex_t *mutex, const pthread_mutexattr_t* attr),
824 (mutex, attr));
826 #if defined(VGO_solaris)
827 static __always_inline
828 int mutex_init_intercept(mutex_t *mutex, int type, void *arg)
830 int ret;
831 OrigFn fn;
832 VALGRIND_GET_ORIG_FN(fn);
834 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
835 mutex, DRD_(thread_to_drd_mutex_type)(type),
836 0, 0, 0);
837 CALL_FN_W_WWW(ret, fn, mutex, type, arg);
838 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
839 mutex, 0, 0, 0, 0);
840 return ret;
843 PTH_FUNCS(int, mutexZuinit, mutex_init_intercept,
844 (mutex_t *mutex, int type, void *arg),
845 (mutex, type, arg));
846 #endif /* VGO_solaris */
848 static __always_inline
849 int pthread_mutex_destroy_intercept(pthread_mutex_t* mutex)
851 int ret;
852 OrigFn fn;
853 VALGRIND_GET_ORIG_FN(fn);
854 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
855 mutex, 0, 0, 0, 0);
856 CALL_FN_W_W(ret, fn, mutex);
857 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
858 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
859 return ret;
862 #if defined(VGO_solaris)
863 /* On Solaris, pthread_mutex_destroy is a weak alias to mutex_destroy. */
864 PTH_FUNCS(int, mutexZudestroy, pthread_mutex_destroy_intercept,
865 (pthread_mutex_t *mutex), (mutex));
866 #else
867 PTH_FUNCS(int, pthreadZumutexZudestroy, pthread_mutex_destroy_intercept,
868 (pthread_mutex_t *mutex), (mutex));
869 #endif /* VGO_solaris */
871 static __always_inline
872 int pthread_mutex_lock_intercept(pthread_mutex_t* mutex)
874 int ret;
875 OrigFn fn;
876 VALGRIND_GET_ORIG_FN(fn);
877 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
878 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
879 CALL_FN_W_W(ret, fn, mutex);
880 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
881 mutex, ret == 0, 0, 0, 0);
882 return ret;
885 #if defined(VGO_solaris)
886 /* On Solaris, pthread_mutex_lock is a weak alias to mutex_lock. */
887 PTH_FUNCS(int, mutexZulock, pthread_mutex_lock_intercept,
888 (pthread_mutex_t *mutex), (mutex));
889 #else
890 PTH_FUNCS(int, pthreadZumutexZulock, pthread_mutex_lock_intercept,
891 (pthread_mutex_t *mutex), (mutex));
892 #endif /* VGO_solaris */
894 #if defined(VGO_solaris)
895 /* Internal to libc. Mutex is usually initialized only implicitly,
896 * by zeroing mutex_t structure.
898 static __always_inline
899 void lmutex_lock_intercept(mutex_t *mutex)
901 OrigFn fn;
902 VALGRIND_GET_ORIG_FN(fn);
903 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
904 mutex,
905 DRD_(mutex_type)((pthread_mutex_t *) mutex),
906 False /* try_lock */, 0, 0);
907 CALL_FN_v_W(fn, mutex);
908 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
909 mutex, True /* took_lock */, 0, 0, 0);
912 PTH_FUNCS(void, lmutexZulock, lmutex_lock_intercept,
913 (mutex_t *mutex), (mutex));
914 #endif /* VGO_solaris */
916 static __always_inline
917 int pthread_mutex_trylock_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__PRE_MUTEX_LOCK,
923 mutex, DRD_(mutex_type)(mutex), 1, 0, 0);
924 CALL_FN_W_W(ret, fn, mutex);
925 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
926 mutex, ret == 0, 0, 0, 0);
927 return ret;
930 #if defined(VGO_solaris)
931 /* On Solaris, pthread_mutex_trylock is a weak alias to mutex_trylock. */
932 PTH_FUNCS(int, mutexZutrylock, pthread_mutex_trylock_intercept,
933 (pthread_mutex_t *mutex), (mutex));
934 #else
935 PTH_FUNCS(int, pthreadZumutexZutrylock, pthread_mutex_trylock_intercept,
936 (pthread_mutex_t *mutex), (mutex));
937 #endif /* VGO_solaris */
939 static __always_inline
940 int pthread_mutex_timedlock_intercept(pthread_mutex_t *mutex,
941 const struct timespec *abs_timeout)
943 int ret;
944 OrigFn fn;
945 VALGRIND_GET_ORIG_FN(fn);
946 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
947 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
948 CALL_FN_W_WW(ret, fn, mutex, abs_timeout);
949 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
950 mutex, ret == 0, 0, 0, 0);
951 return ret;
954 PTH_FUNCS(int, pthreadZumutexZutimedlock, pthread_mutex_timedlock_intercept,
955 (pthread_mutex_t *mutex, const struct timespec *abs_timeout),
956 (mutex, abs_timeout));
957 #if defined(VGO_solaris)
958 PTH_FUNCS(int,
959 pthreadZumutexZureltimedlockZunp, pthread_mutex_timedlock_intercept,
960 (pthread_mutex_t *mutex, const struct timespec *timeout),
961 (mutex, timeout));
962 #endif /* VGO_solaris */
964 static __always_inline
965 int pthread_mutex_unlock_intercept(pthread_mutex_t *mutex)
967 int ret;
968 OrigFn fn;
969 VALGRIND_GET_ORIG_FN(fn);
970 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
971 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
972 CALL_FN_W_W(ret, fn, mutex);
973 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
974 mutex, 0, 0, 0, 0);
975 return ret;
978 #if defined(VGO_solaris)
979 /* On Solaris, pthread_mutex_unlock is a weak alias to mutex_unlock. */
980 PTH_FUNCS(int, mutexZuunlock, pthread_mutex_unlock_intercept,
981 (pthread_mutex_t *mutex), (mutex));
982 #else
983 PTH_FUNCS(int, pthreadZumutexZuunlock, pthread_mutex_unlock_intercept,
984 (pthread_mutex_t *mutex), (mutex));
985 #endif /* VGO_solaris */
987 #if defined(VGO_solaris)
988 /* Internal to libc. */
989 static __always_inline
990 void lmutex_unlock_intercept(mutex_t *mutex)
992 OrigFn fn;
993 VALGRIND_GET_ORIG_FN(fn);
994 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
995 mutex,
996 DRD_(mutex_type)((pthread_mutex_t *) mutex),
997 0, 0, 0);
998 CALL_FN_v_W(fn, mutex);
999 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
1000 mutex, 0, 0, 0, 0);
1003 PTH_FUNCS(void, lmutexZuunlock, lmutex_unlock_intercept,
1004 (mutex_t *mutex), (mutex));
1005 #endif /* VGO_solaris */
1007 static __always_inline
1008 int pthread_cond_init_intercept(pthread_cond_t* cond,
1009 const pthread_condattr_t* attr)
1011 int ret;
1012 OrigFn fn;
1013 VALGRIND_GET_ORIG_FN(fn);
1014 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT,
1015 cond, 0, 0, 0, 0);
1016 CALL_FN_W_WW(ret, fn, cond, attr);
1017 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT,
1018 cond, 0, 0, 0, 0);
1019 return ret;
1022 PTH_FUNCS(int, pthreadZucondZuinit, pthread_cond_init_intercept,
1023 (pthread_cond_t* cond, const pthread_condattr_t* attr),
1024 (cond, attr));
1026 #if defined(VGO_solaris)
1027 static __always_inline
1028 int cond_init_intercept(cond_t *cond, int type, void *arg)
1030 int ret;
1031 OrigFn fn;
1032 VALGRIND_GET_ORIG_FN(fn);
1033 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT,
1034 cond, 0, 0, 0, 0);
1035 CALL_FN_W_WWW(ret, fn, cond, type, arg);
1036 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT,
1037 cond, 0, 0, 0, 0);
1038 return ret;
1041 PTH_FUNCS(int, condZuinit, cond_init_intercept,
1042 (cond_t *cond, int type, void *arg),
1043 (cond, type, arg));
1044 #endif /* VGO_solaris */
1046 static __always_inline
1047 int pthread_cond_destroy_intercept(pthread_cond_t* cond)
1049 int ret;
1050 OrigFn fn;
1051 VALGRIND_GET_ORIG_FN(fn);
1052 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_DESTROY,
1053 cond, 0, 0, 0, 0);
1054 CALL_FN_W_W(ret, fn, cond);
1055 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_DESTROY,
1056 cond, ret==0, 0, 0, 0);
1057 return ret;
1060 #if defined(VGO_solaris)
1061 /* On Solaris, pthread_cond_destroy is a weak alias to cond_destroy. */
1062 PTH_FUNCS(int, condZudestroy, pthread_cond_destroy_intercept,
1063 (pthread_cond_t *cond), (cond));
1064 #else
1065 PTH_FUNCS(int, pthreadZucondZudestroy, pthread_cond_destroy_intercept,
1066 (pthread_cond_t* cond), (cond));
1067 #endif /* VGO_solaris */
1069 static __always_inline
1070 int pthread_cond_wait_intercept(pthread_cond_t *cond, pthread_mutex_t *mutex)
1072 int ret;
1073 OrigFn fn;
1074 VALGRIND_GET_ORIG_FN(fn);
1075 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
1076 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1077 CALL_FN_W_WW(ret, fn, cond, mutex);
1078 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
1079 cond, mutex, 1, 0, 0);
1080 return ret;
1083 PTH_FUNCS(int, pthreadZucondZuwait, pthread_cond_wait_intercept,
1084 (pthread_cond_t *cond, pthread_mutex_t *mutex),
1085 (cond, mutex));
1086 #if defined(VGO_solaris)
1087 PTH_FUNCS(int, condZuwait, pthread_cond_wait_intercept,
1088 (pthread_cond_t *cond, pthread_mutex_t *mutex),
1089 (cond, mutex));
1090 #endif /* VGO_solaris */
1092 static __always_inline
1093 int pthread_cond_timedwait_intercept(pthread_cond_t *cond,
1094 pthread_mutex_t *mutex,
1095 const struct timespec* abstime)
1097 int ret;
1098 OrigFn fn;
1099 VALGRIND_GET_ORIG_FN(fn);
1100 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
1101 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1102 CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
1103 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
1104 cond, mutex, 1, 0, 0);
1105 return ret;
1108 PTH_FUNCS(int, pthreadZucondZutimedwait, pthread_cond_timedwait_intercept,
1109 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1110 const struct timespec* abstime),
1111 (cond, mutex, abstime));
1112 #if defined(VGO_solaris)
1113 PTH_FUNCS(int, condZutimedwait, pthread_cond_timedwait_intercept,
1114 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1115 const struct timespec *timeout),
1116 (cond, mutex, timeout));
1117 PTH_FUNCS(int, condZureltimedwait, pthread_cond_timedwait_intercept,
1118 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1119 const struct timespec *timeout),
1120 (cond, mutex, timeout));
1121 #endif /* VGO_solaris */
1123 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
1124 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
1125 // two. Intercepting all pthread_cond_signal* functions will cause only one
1126 // argument to be passed to pthread_cond_signal_np() and hence will cause this
1127 // last function to crash.
1129 static __always_inline
1130 int pthread_cond_signal_intercept(pthread_cond_t* cond)
1132 int ret;
1133 OrigFn fn;
1134 VALGRIND_GET_ORIG_FN(fn);
1135 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_SIGNAL,
1136 cond, 0, 0, 0, 0);
1137 CALL_FN_W_W(ret, fn, cond);
1138 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_SIGNAL,
1139 cond, 0, 0, 0, 0);
1140 return ret;
1143 #if defined(VGO_solaris)
1144 /* On Solaris, pthread_cond_signal is a weak alias to cond_signal. */
1145 PTH_FUNCS(int, condZusignal, pthread_cond_signal_intercept,
1146 (pthread_cond_t *cond), (cond));
1147 #else
1148 PTH_FUNCS(int, pthreadZucondZusignal, pthread_cond_signal_intercept,
1149 (pthread_cond_t* cond), (cond));
1150 #endif /* VGO_solaris */
1152 static __always_inline
1153 int pthread_cond_broadcast_intercept(pthread_cond_t* cond)
1155 int ret;
1156 OrigFn fn;
1157 VALGRIND_GET_ORIG_FN(fn);
1158 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_BROADCAST,
1159 cond, 0, 0, 0, 0);
1160 CALL_FN_W_W(ret, fn, cond);
1161 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_BROADCAST,
1162 cond, 0, 0, 0, 0);
1163 return ret;
1166 #if defined(VGO_solaris)
1167 /* On Solaris, pthread_cond_broadcast is a weak alias to cond_broadcast. */
1168 PTH_FUNCS(int, condZubroadcast, pthread_cond_broadcast_intercept,
1169 (pthread_cond_t *cond), (cond));
1170 #else
1171 PTH_FUNCS(int, pthreadZucondZubroadcast, pthread_cond_broadcast_intercept,
1172 (pthread_cond_t* cond), (cond));
1173 #endif /* VGO_solaris */
1175 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1176 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1177 static __always_inline
1178 int pthread_spin_init_intercept(pthread_spinlock_t *spinlock, int pshared)
1180 int ret;
1181 OrigFn fn;
1182 VALGRIND_GET_ORIG_FN(fn);
1183 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
1184 spinlock, 0, 0, 0, 0);
1185 CALL_FN_W_WW(ret, fn, spinlock, pshared);
1186 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
1187 spinlock, 0, 0, 0, 0);
1188 return ret;
1191 PTH_FUNCS(int, pthreadZuspinZuinit, pthread_spin_init_intercept,
1192 (pthread_spinlock_t *spinlock, int pshared), (spinlock, pshared));
1194 static __always_inline
1195 int pthread_spin_destroy_intercept(pthread_spinlock_t *spinlock)
1197 int ret;
1198 OrigFn fn;
1199 VALGRIND_GET_ORIG_FN(fn);
1200 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
1201 spinlock, 0, 0, 0, 0);
1202 CALL_FN_W_W(ret, fn, spinlock);
1203 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
1204 spinlock, mutex_type_spinlock, 0, 0, 0);
1205 return ret;
1208 PTH_FUNCS(int, pthreadZuspinZudestroy, pthread_spin_destroy_intercept,
1209 (pthread_spinlock_t *spinlock), (spinlock));
1211 static __always_inline
1212 int pthread_spin_lock_intercept(pthread_spinlock_t *spinlock)
1214 int ret;
1215 OrigFn fn;
1216 VALGRIND_GET_ORIG_FN(fn);
1217 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
1218 spinlock, mutex_type_spinlock, 0, 0, 0);
1219 CALL_FN_W_W(ret, fn, spinlock);
1220 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
1221 spinlock, ret == 0, 0, 0, 0);
1222 return ret;
1225 PTH_FUNCS(int, pthreadZuspinZulock, pthread_spin_lock_intercept,
1226 (pthread_spinlock_t *spinlock), (spinlock));
1228 static __always_inline
1229 int pthread_spin_trylock_intercept(pthread_spinlock_t *spinlock)
1231 int ret;
1232 OrigFn fn;
1233 VALGRIND_GET_ORIG_FN(fn);
1234 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
1235 spinlock, mutex_type_spinlock, 0, 0, 0);
1236 CALL_FN_W_W(ret, fn, spinlock);
1237 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
1238 spinlock, ret == 0, 0, 0, 0);
1239 return ret;
1242 PTH_FUNCS(int, pthreadZuspinZutrylock, pthread_spin_trylock_intercept,
1243 (pthread_spinlock_t *spinlock), (spinlock));
1245 static __always_inline
1246 int pthread_spin_unlock_intercept(pthread_spinlock_t *spinlock)
1248 int ret;
1249 OrigFn fn;
1250 VALGRIND_GET_ORIG_FN(fn);
1251 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
1252 spinlock, mutex_type_spinlock, 0, 0, 0);
1253 CALL_FN_W_W(ret, fn, spinlock);
1254 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
1255 spinlock, 0, 0, 0, 0);
1256 return ret;
1259 PTH_FUNCS(int, pthreadZuspinZuunlock, pthread_spin_unlock_intercept,
1260 (pthread_spinlock_t *spinlock), (spinlock));
1261 #endif // HAVE_PTHREAD_SPIN_LOCK
1264 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1265 static __always_inline
1266 int pthread_barrier_init_intercept(pthread_barrier_t* barrier,
1267 const pthread_barrierattr_t* attr,
1268 unsigned count)
1270 int ret;
1271 OrigFn fn;
1272 VALGRIND_GET_ORIG_FN(fn);
1273 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_INIT,
1274 barrier, pthread_barrier, count, 0, 0);
1275 CALL_FN_W_WWW(ret, fn, barrier, attr, count);
1276 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_INIT,
1277 barrier, pthread_barrier, 0, 0, 0);
1278 return ret;
1281 PTH_FUNCS(int, pthreadZubarrierZuinit, pthread_barrier_init_intercept,
1282 (pthread_barrier_t* barrier, const pthread_barrierattr_t* attr,
1283 unsigned count), (barrier, attr, count));
1285 static __always_inline
1286 int pthread_barrier_destroy_intercept(pthread_barrier_t* barrier)
1288 int ret;
1289 OrigFn fn;
1290 VALGRIND_GET_ORIG_FN(fn);
1291 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_DESTROY,
1292 barrier, pthread_barrier, 0, 0, 0);
1293 CALL_FN_W_W(ret, fn, barrier);
1294 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_DESTROY,
1295 barrier, pthread_barrier, 0, 0, 0);
1296 return ret;
1299 PTH_FUNCS(int, pthreadZubarrierZudestroy, pthread_barrier_destroy_intercept,
1300 (pthread_barrier_t* barrier), (barrier));
1302 static __always_inline
1303 int pthread_barrier_wait_intercept(pthread_barrier_t* barrier)
1305 int ret;
1306 OrigFn fn;
1307 VALGRIND_GET_ORIG_FN(fn);
1308 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_WAIT,
1309 barrier, pthread_barrier, 0, 0, 0);
1310 CALL_FN_W_W(ret, fn, barrier);
1311 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_WAIT,
1312 barrier, pthread_barrier,
1313 ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD,
1314 ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
1315 return ret;
1318 PTH_FUNCS(int, pthreadZubarrierZuwait, pthread_barrier_wait_intercept,
1319 (pthread_barrier_t* barrier), (barrier));
1320 #endif // HAVE_PTHREAD_BARRIER_INIT
1323 static __always_inline
1324 int sem_init_intercept(sem_t *sem, int pshared, unsigned int value)
1326 int ret;
1327 OrigFn fn;
1328 VALGRIND_GET_ORIG_FN(fn);
1329 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT,
1330 sem, pshared, value, 0, 0);
1331 CALL_FN_W_WWW(ret, fn, sem, pshared, value);
1332 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT,
1333 sem, 0, 0, 0, 0);
1334 return ret;
1337 PTH_FUNCS(int, semZuinit, sem_init_intercept,
1338 (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
1340 #if defined(VGO_solaris)
1341 static __always_inline
1342 int sema_init_intercept(sema_t *sem, unsigned int value, int type, void *arg)
1344 int ret;
1345 OrigFn fn;
1346 VALGRIND_GET_ORIG_FN(fn);
1347 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT,
1348 sem, type == USYNC_PROCESS ? 1 : 0,
1349 value, 0, 0);
1350 CALL_FN_W_WWWW(ret, fn, sem, value, type, arg);
1351 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT,
1352 sem, 0, 0, 0, 0);
1353 return ret;
1356 PTH_FUNCS(int, semaZuinit, sema_init_intercept,
1357 (sema_t *sem, unsigned int value, int type, void *arg),
1358 (sem, value, type, arg));
1359 #endif /* VGO_solaris */
1361 static __always_inline
1362 int sem_destroy_intercept(sem_t *sem)
1364 int ret;
1365 OrigFn fn;
1366 VALGRIND_GET_ORIG_FN(fn);
1367 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_DESTROY,
1368 sem, 0, 0, 0, 0);
1369 CALL_FN_W_W(ret, fn, sem);
1370 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_DESTROY,
1371 sem, 0, 0, 0, 0);
1372 return ret;
1375 PTH_FUNCS(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1376 #if defined(VGO_solaris)
1377 PTH_FUNCS(int, semaZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1378 #endif /* VGO_solaris */
1380 static __always_inline
1381 sem_t* sem_open_intercept(const char *name, int oflag, mode_t mode,
1382 unsigned int value)
1384 sem_t *ret;
1385 OrigFn fn;
1386 VALGRIND_GET_ORIG_FN(fn);
1387 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_OPEN,
1388 name, oflag, mode, value, 0);
1389 CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value);
1390 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_OPEN,
1391 ret != SEM_FAILED ? ret : 0,
1392 name, oflag, mode, value);
1393 return ret;
1396 PTH_FUNCS(sem_t *, semZuopen, sem_open_intercept,
1397 (const char *name, int oflag, mode_t mode, unsigned int value),
1398 (name, oflag, mode, value));
1400 static __always_inline int sem_close_intercept(sem_t *sem)
1402 int ret;
1403 OrigFn fn;
1404 VALGRIND_GET_ORIG_FN(fn);
1405 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_CLOSE,
1406 sem, 0, 0, 0, 0);
1407 CALL_FN_W_W(ret, fn, sem);
1408 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_CLOSE,
1409 sem, 0, 0, 0, 0);
1410 return ret;
1413 PTH_FUNCS(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
1415 static __always_inline int sem_wait_intercept(sem_t *sem)
1417 int ret;
1418 OrigFn fn;
1419 VALGRIND_GET_ORIG_FN(fn);
1420 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1421 sem, 0, 0, 0, 0);
1422 CALL_FN_W_W(ret, fn, sem);
1423 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1424 sem, ret == 0, 0, 0, 0);
1425 return ret;
1428 PTH_FUNCS(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1429 #if defined(VGO_solaris)
1430 PTH_FUNCS(int, semaZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1431 #endif /* VGO_solaris */
1433 static __always_inline int sem_trywait_intercept(sem_t *sem)
1435 int ret;
1436 OrigFn fn;
1437 VALGRIND_GET_ORIG_FN(fn);
1438 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1439 sem, 0, 0, 0, 0);
1440 CALL_FN_W_W(ret, fn, sem);
1441 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1442 sem, ret == 0, 0, 0, 0);
1443 return ret;
1446 PTH_FUNCS(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1447 #if defined(VGO_solaris)
1448 PTH_FUNCS(int, semaZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1449 #endif /* VGO_solaris */
1451 static __always_inline
1452 int sem_timedwait_intercept(sem_t *sem, const struct timespec *abs_timeout)
1454 int ret;
1455 OrigFn fn;
1456 VALGRIND_GET_ORIG_FN(fn);
1457 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1458 sem, 0, 0, 0, 0);
1459 CALL_FN_W_WW(ret, fn, sem, abs_timeout);
1460 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1461 sem, ret == 0, 0, 0, 0);
1462 return ret;
1465 PTH_FUNCS(int, semZutimedwait, sem_timedwait_intercept,
1466 (sem_t *sem, const struct timespec *abs_timeout),
1467 (sem, abs_timeout));
1468 #if defined(VGO_solaris)
1469 PTH_FUNCS(int, semaZutimedwait, sem_timedwait_intercept,
1470 (sem_t *sem, const struct timespec *timeout),
1471 (sem, timeout));
1472 PTH_FUNCS(int, semaZureltimedwait, sem_timedwait_intercept,
1473 (sem_t *sem, const struct timespec *timeout),
1474 (sem, timeout));
1475 #endif /* VGO_solaris */
1477 static __always_inline int sem_post_intercept(sem_t *sem)
1479 int ret;
1480 OrigFn fn;
1481 VALGRIND_GET_ORIG_FN(fn);
1482 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_POST,
1483 sem, 0, 0, 0, 0);
1484 CALL_FN_W_W(ret, fn, sem);
1485 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_POST,
1486 sem, ret == 0, 0, 0, 0);
1487 return ret;
1490 PTH_FUNCS(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
1491 #if defined(VGO_solaris)
1492 PTH_FUNCS(int, semaZupost, sem_post_intercept, (sem_t *sem), (sem));
1493 #endif /* VGO_solaris */
1495 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1496 functions have to be conditionally compiled. */
1497 #if defined(HAVE_PTHREAD_RWLOCK_T)
1499 static __always_inline
1500 int pthread_rwlock_init_intercept(pthread_rwlock_t* rwlock,
1501 const pthread_rwlockattr_t* attr)
1503 int ret;
1504 OrigFn fn;
1505 VALGRIND_GET_ORIG_FN(fn);
1506 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT,
1507 rwlock, 0, 0, 0, 0);
1508 CALL_FN_W_WW(ret, fn, rwlock, attr);
1509 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT,
1510 rwlock, 0, 0, 0, 0);
1511 return ret;
1514 PTH_FUNCS(int,
1515 pthreadZurwlockZuinit, pthread_rwlock_init_intercept,
1516 (pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr),
1517 (rwlock, attr));
1519 #if defined(VGO_solaris)
1520 static __always_inline
1521 int rwlock_init_intercept(rwlock_t *rwlock, int type, void *arg)
1523 int ret;
1524 OrigFn fn;
1525 VALGRIND_GET_ORIG_FN(fn);
1526 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT,
1527 rwlock, 0, 0, 0, 0);
1528 CALL_FN_W_WWW(ret, fn, rwlock, type, arg);
1529 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT,
1530 rwlock, 0, 0, 0, 0);
1531 return ret;
1534 PTH_FUNCS(int, rwlockZuinit, rwlock_init_intercept,
1535 (rwlock_t *rwlock, int type, void *arg),
1536 (rwlock, type, arg));
1537 #endif /* VGO_solaris */
1539 static __always_inline
1540 int pthread_rwlock_destroy_intercept(pthread_rwlock_t* rwlock)
1542 int ret;
1543 OrigFn fn;
1544 VALGRIND_GET_ORIG_FN(fn);
1545 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_DESTROY,
1546 rwlock, 0, 0, 0, 0);
1547 CALL_FN_W_W(ret, fn, rwlock);
1548 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_DESTROY,
1549 rwlock, 0, 0, 0, 0);
1550 return ret;
1553 #if defined(VGO_solaris)
1554 /* On Solaris, pthread_rwlock_destroy is a weak alias to rwlock_destroy. */
1555 PTH_FUNCS(int,
1556 rwlockZudestroy, pthread_rwlock_destroy_intercept,
1557 (pthread_rwlock_t *rwlock), (rwlock));
1558 #else
1559 PTH_FUNCS(int,
1560 pthreadZurwlockZudestroy, pthread_rwlock_destroy_intercept,
1561 (pthread_rwlock_t* rwlock), (rwlock));
1562 #endif /* VGO_solaris */
1564 static __always_inline
1565 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t* rwlock)
1567 int ret;
1568 OrigFn fn;
1569 VALGRIND_GET_ORIG_FN(fn);
1570 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1571 rwlock, 0, 0, 0, 0);
1572 CALL_FN_W_W(ret, fn, rwlock);
1573 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1574 rwlock, ret == 0, 0, 0, 0);
1575 return ret;
1578 #if defined(VGO_solaris)
1579 /* On Solaris, pthread_rwlock_rdlock is a weak alias to rw_rdlock. */
1580 PTH_FUNCS(int,
1581 rwZurdlock, pthread_rwlock_rdlock_intercept,
1582 (pthread_rwlock_t *rwlock), (rwlock));
1583 #else
1584 PTH_FUNCS(int,
1585 pthreadZurwlockZurdlock, pthread_rwlock_rdlock_intercept,
1586 (pthread_rwlock_t* rwlock), (rwlock));
1587 #endif /* VGO_solaris */
1589 #if defined(VGO_solaris)
1590 /* Internal to libc. */
1591 static __always_inline
1592 void lrw_rdlock_intercept(rwlock_t *rwlock)
1594 OrigFn fn;
1595 VALGRIND_GET_ORIG_FN(fn);
1596 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1597 rwlock, 0, 0, 0, 0);
1598 CALL_FN_v_W(fn, rwlock);
1599 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1600 rwlock, True /* took_lock */, 0, 0, 0);
1603 PTH_FUNCS(void, lrwZurdlock, lrw_rdlock_intercept,
1604 (rwlock_t *rwlock), (rwlock));
1605 #endif /* VGO_solaris */
1607 static __always_inline
1608 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t* rwlock)
1610 int ret;
1611 OrigFn fn;
1612 VALGRIND_GET_ORIG_FN(fn);
1613 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1614 rwlock, 0, 0, 0, 0);
1615 CALL_FN_W_W(ret, fn, rwlock);
1616 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1617 rwlock, ret == 0, 0, 0, 0);
1618 return ret;
1621 #if defined(VGO_solaris)
1622 /* On Solaris, pthread_rwlock_wrlock is a weak alias to rw_wrlock. */
1623 PTH_FUNCS(int,
1624 rwZuwrlock, pthread_rwlock_wrlock_intercept,
1625 (pthread_rwlock_t *rwlock), (rwlock));
1626 #else
1627 PTH_FUNCS(int,
1628 pthreadZurwlockZuwrlock, pthread_rwlock_wrlock_intercept,
1629 (pthread_rwlock_t* rwlock), (rwlock));
1630 #endif /* VGO_solaris */
1632 #if defined(VGO_solaris)
1633 /* Internal to libc. */
1634 static __always_inline
1635 void lrw_wrlock_intercept(rwlock_t *rwlock)
1637 OrigFn fn;
1638 VALGRIND_GET_ORIG_FN(fn);
1639 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1640 rwlock, 0, 0, 0, 0);
1641 CALL_FN_v_W(fn, rwlock);
1642 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1643 rwlock, True /* took_lock */, 0, 0, 0);
1646 PTH_FUNCS(void, lrwZuwrlock, lrw_wrlock_intercept,
1647 (rwlock_t *rwlock), (rwlock));
1648 #endif /* VGO_solaris */
1650 static __always_inline
1651 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t* rwlock,
1652 const struct timespec *timeout)
1654 int ret;
1655 OrigFn fn;
1656 VALGRIND_GET_ORIG_FN(fn);
1657 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1658 rwlock, 0, 0, 0, 0);
1659 CALL_FN_W_WW(ret, fn, rwlock, timeout);
1660 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1661 rwlock, ret == 0, 0, 0, 0);
1662 return ret;
1665 PTH_FUNCS(int,
1666 pthreadZurwlockZutimedrdlock, pthread_rwlock_timedrdlock_intercept,
1667 (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1668 (rwlock, timeout));
1669 #if defined(VGO_solaris)
1670 PTH_FUNCS(int, pthreadZurwlockZureltimedrdlockZunp,
1671 pthread_rwlock_timedrdlock_intercept,
1672 (pthread_rwlock_t *rwlock, const struct timespec *timeout),
1673 (rwlock, timeout));
1674 #endif /* VGO_solaris */
1676 static __always_inline
1677 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t* rwlock,
1678 const struct timespec *timeout)
1680 int ret;
1681 OrigFn fn;
1682 VALGRIND_GET_ORIG_FN(fn);
1683 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1684 rwlock, 0, 0, 0, 0);
1685 CALL_FN_W_WW(ret, fn, rwlock, timeout);
1686 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1687 rwlock, ret == 0, 0, 0, 0);
1688 return ret;
1691 PTH_FUNCS(int,
1692 pthreadZurwlockZutimedwrlock, pthread_rwlock_timedwrlock_intercept,
1693 (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1694 (rwlock, timeout));
1695 #if defined(VGO_solaris)
1696 PTH_FUNCS(int, pthreadZurwlockZureltimedwrlockZunp,
1697 pthread_rwlock_timedwrlock_intercept,
1698 (pthread_rwlock_t *rwlock, const struct timespec *timeout),
1699 (rwlock, timeout));
1700 #endif /* VGO_solaris */
1702 static __always_inline
1703 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t* rwlock)
1705 int ret;
1706 OrigFn fn;
1707 VALGRIND_GET_ORIG_FN(fn);
1708 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1709 rwlock, 0, 0, 0, 0);
1710 CALL_FN_W_W(ret, fn, rwlock);
1711 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1712 rwlock, ret == 0, 0, 0, 0);
1713 return ret;
1716 #if defined(VGO_solaris)
1717 /* On Solaris, pthread_rwlock_tryrdlock is a weak alias to rw_tryrdlock. */
1718 PTH_FUNCS(int,
1719 rwZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1720 (pthread_rwlock_t *rwlock), (rwlock));
1721 #else
1722 PTH_FUNCS(int,
1723 pthreadZurwlockZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1724 (pthread_rwlock_t* rwlock), (rwlock));
1725 #endif /* VGO_solaris */
1727 static __always_inline
1728 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t* rwlock)
1730 int ret;
1731 OrigFn fn;
1732 VALGRIND_GET_ORIG_FN(fn);
1733 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1734 rwlock, 0, 0, 0, 0);
1735 CALL_FN_W_W(ret, fn, rwlock);
1736 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1737 rwlock, ret == 0, 0, 0, 0);
1738 return ret;
1741 #if defined(VGO_solaris)
1742 /* On Solaris, pthread_rwlock_trywrlock is a weak alias to rw_trywrlock. */
1743 PTH_FUNCS(int,
1744 rwZutrywrlock, pthread_rwlock_trywrlock_intercept,
1745 (pthread_rwlock_t *rwlock), (rwlock));
1746 #else
1747 PTH_FUNCS(int,
1748 pthreadZurwlockZutrywrlock, pthread_rwlock_trywrlock_intercept,
1749 (pthread_rwlock_t* rwlock), (rwlock));
1750 #endif /* VGO_solaris */
1752 static __always_inline
1753 int pthread_rwlock_unlock_intercept(pthread_rwlock_t* rwlock)
1755 int ret;
1756 OrigFn fn;
1757 VALGRIND_GET_ORIG_FN(fn);
1758 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_UNLOCK,
1759 rwlock, 0, 0, 0, 0);
1760 CALL_FN_W_W(ret, fn, rwlock);
1761 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_UNLOCK,
1762 rwlock, ret == 0, 0, 0, 0);
1763 return ret;
1766 #if defined(VGO_solaris)
1767 /* On Solaris, pthread_rwlock_unlock is a weak alias to rw_unlock. */
1768 PTH_FUNCS(int,
1769 rwZuunlock, pthread_rwlock_unlock_intercept,
1770 (pthread_rwlock_t *rwlock), (rwlock));
1771 #else
1772 PTH_FUNCS(int,
1773 pthreadZurwlockZuunlock, pthread_rwlock_unlock_intercept,
1774 (pthread_rwlock_t* rwlock), (rwlock));
1775 #endif /* VGO_solaris */
1777 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */