tests/vg_regtest: Always evaluate prerequisite expressions with sh
[valgrind.git] / drd / drd_pthread_intercepts.c
blobea14fa45cb625a73420bc6dd50accf32ffe33bbc
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-2013 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 #ifdef HAVE_USABLE_LINUX_FUTEX_H
59 #include <asm/unistd.h> /* __NR_futex */
60 #include <linux/futex.h> /* FUTEX_WAIT */
61 #ifndef FUTEX_PRIVATE_FLAG
62 #define FUTEX_PRIVATE_FLAG 0
63 #endif
64 #endif
65 #include "drd_basics.h" /* DRD_() */
66 #include "drd_clientreq.h"
67 #include "pub_tool_redir.h" /* VG_WRAP_FUNCTION_ZZ() */
69 #if defined(VGO_solaris)
71 * Solaris usually provides pthread_* functions on top of Solaris threading
72 * and synchronization functions. Usually both need to be intercepted because
73 * pthread_* ones might not call the Solaris ones (see for example sem_wait()).
74 * Such approach is required to correctly report misuse of the POSIX threads
75 * API.
76 * Therefore DRD intercepts and instruments all such functions but due to
77 * DRD_(thread_enter_synchr)() and DRD_(thread_leave_synchr)() guards in
78 * handle_client_request(), only the top-most function is handled.
79 * So the right thing(TM) happens, as expected.
80 * The only exception is when pthread_* function is a weak alias to the Solaris
81 * threading/synchronization function. In such case only one needs to be
82 * intercepted to avoid redirection ambiguity.
84 * Intercepted functions rely on the fact that:
85 * - pthread_mutex_t == mutex_t
86 * - pthread_cond_t == cond_t
87 * - sem_t == sema_t
88 * - pthread_rwlock_t == rwlock_t
90 * It is necessary to intercept also internal libc synchronization functions
91 * for two reasons:
92 * - For read-write locks the unlocking function is shared
93 * - Functions lmutex_lock/lmutex_unlock guard many critical sections in libc
94 * which will be otherwise reported by DRD
96 #include <synch.h>
97 #include <thread.h>
98 #include "pub_tool_vki.h"
101 * Solaris provides higher throughput, parallelism and scalability than other
102 * operating systems, at the cost of more fine-grained locking activity.
103 * This means for example that when a thread is created under Linux, just one
104 * big lock in glibc is used for all thread setup. Solaris libc uses several
105 * fine-grained locks and the creator thread resumes its activities as soon
106 * as possible, leaving for example stack and TLS setup activities to the
107 * created thread.
109 * This situation confuses DRD as it assumes there is some false ordering
110 * in place between creator and created thread; and therefore many types of
111 * race conditions in the application would not be reported. To prevent such
112 * false ordering, command line option --ignore-thread-creation is set to
113 * 'yes' by default on Solaris. All activity (loads, stores, client requests)
114 * is therefore ignored during:
115 * - pthread_create() call in the creator thread [libc.so]
116 * - thread creation phase (stack and TLS setup) in the created thread [libc.so]
118 * As explained in the comments for _ti_bind_guard(), whenever the runtime
119 * linker has to perform any activity (such as resolving a symbol), it protects
120 * its data structures by calling into rt_bind_guard() which in turn invokes
121 * _ti_bind_guard() in libc. Pointers to _ti_bind_guard() and _ti_bind_clear()
122 * are passed from libc to runtime linker in _ld_libc() call during libc_init().
123 * All activity is also ignored during:
124 * - runtime dynamic linker work between rt_bind_guard() and rt_bind_clear()
125 * calls [ld.so]
127 * This also means that DRD does not report race conditions in libc (when
128 * --ignore-thread-creation=yes) and runtime linker itself (unconditionally)
129 * during these ignored sequences.
133 * Original function pointers for _ti_bind_guard() and _ti_bind_clear()
134 * from libc. They are intercepted in function wrapper of _ld_libc().
136 typedef int (*drd_rtld_guard_fn)(int flags);
137 static drd_rtld_guard_fn DRD_(rtld_bind_guard) = NULL;
138 static drd_rtld_guard_fn DRD_(rtld_bind_clear) = NULL;
139 #endif
143 * Notes regarding thread creation:
144 * - sg_init() runs on the context of the created thread and copies the vector
145 * clock of the creator thread. This only works reliably if the creator
146 * thread waits until this copy has been performed.
147 * - DRD_(thread_compute_minimum_vc)() does not take the vector clocks into
148 * account that are involved in thread creation and for which the
149 * corresponding thread has not yet been created. So not waiting until the
150 * created thread has been started would make it possible that segments get
151 * discarded that should not yet be discarded. Or: some data races are not
152 * detected.
156 * Macro for generating a Valgrind interception function.
157 * @param[in] ret_ty Return type of the function to be generated.
158 * @param[in] zf Z-encoded name of the interception function.
159 * @param[in] implf Name of the function that implements the intercept.
160 * @param[in] arg_decl Argument declaration list enclosed in parentheses.
161 * @param[in] argl Argument list enclosed in parentheses.
163 #ifdef VGO_darwin
164 static int never_true;
165 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
166 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
167 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
169 ret_ty pth_func_result = implf argl; \
170 /* Apparently inserting a function call in wrapper functions */ \
171 /* is sufficient to avoid misaligned stack errors. */ \
172 if (never_true) \
173 fflush(stdout); \
174 return pth_func_result; \
176 #elif defined(VGO_solaris)
177 /* On Solaris, libpthread is just a filter library on top of libc.
178 * Threading and synchronization functions in runtime linker are not
179 * intercepted.
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 #else
186 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
187 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
188 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
189 { return implf argl; }
190 #endif
193 * Macro for generating three Valgrind interception functions: one with the
194 * Z-encoded name zf, one with ZAZa ("@*") appended to the name zf and one
195 * with ZDZa ("$*") appended to the name zf. The second generated interception
196 * function will intercept versioned symbols on Linux, and the third will
197 * intercept versioned symbols on Darwin.
199 #define PTH_FUNCS(ret_ty, zf, implf, argl_decl, argl) \
200 PTH_FUNC(ret_ty, zf, implf, argl_decl, argl); \
201 PTH_FUNC(ret_ty, zf ## ZAZa, implf, argl_decl, argl); \
202 PTH_FUNC(ret_ty, zf ## ZDZa, implf, argl_decl, argl);
205 * Not inlining one of the intercept functions will cause the regression
206 * tests to fail because this would cause an additional stackfram to appear
207 * in the output. The __always_inline macro guarantees that inlining will
208 * happen, even when compiling with optimization disabled.
210 #undef __always_inline /* since already defined in <cdefs.h> */
211 #if __GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 2
212 #define __always_inline __inline__ __attribute__((always_inline))
213 #else
214 #define __always_inline __inline__
215 #endif
217 /* Local data structures. */
219 typedef struct {
220 pthread_mutex_t mutex;
221 int counter;
222 int waiters;
223 } DrdSema;
225 typedef struct
227 void* (*start)(void*);
228 void* arg;
229 int detachstate;
230 DrdSema* wrapper_started;
231 } DrdPosixThreadArgs;
234 /* Local function declarations. */
236 static void DRD_(init)(void) __attribute__((constructor));
237 static void DRD_(check_threading_library)(void);
238 static void DRD_(set_main_thread_state)(void);
239 static void DRD_(sema_init)(DrdSema* sema);
240 static void DRD_(sema_destroy)(DrdSema* sema);
241 static void DRD_(sema_down)(DrdSema* sema);
242 static void DRD_(sema_up)(DrdSema* sema);
245 /* Function definitions. */
248 * Shared library initialization function. The function init() is called after
249 * dlopen() has loaded the shared library with DRD client intercepts because
250 * the constructor attribute was specified in the declaration of this function.
251 * Note: do specify the -nostdlib option to gcc when linking this code into a
252 * shared library because doing so would cancel the effect of the constructor
253 * attribute ! Using the gcc option -nodefaultlibs is fine because this last
254 * option preserves the shared library initialization code that calls
255 * constructor and destructor functions.
257 static void DRD_(init)(void)
259 DRD_(check_threading_library)();
260 DRD_(set_main_thread_state)();
261 #if defined(VGO_solaris)
262 if ((DRD_(rtld_bind_guard) == NULL) || (DRD_(rtld_bind_clear) == NULL)) {
263 fprintf(stderr,
264 "Bind guard functions for the runtime linker (ld.so.1) were not intercepted.\n"
265 "This means the interface between libc and runtime linker changed and DRD\n"
266 "needs to be ported properly. Giving up.\n");
267 abort();
269 #endif
272 static __always_inline void DRD_(ignore_mutex_ordering)(pthread_mutex_t *mutex)
274 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_IGNORE_MUTEX_ORDERING,
275 mutex, 0, 0, 0, 0);
278 static void DRD_(sema_init)(DrdSema* sema)
280 DRD_IGNORE_VAR(*sema);
281 pthread_mutex_init(&sema->mutex, NULL);
282 DRD_(ignore_mutex_ordering)(&sema->mutex);
283 sema->counter = 0;
284 sema->waiters = 0;
287 static void DRD_(sema_destroy)(DrdSema* sema)
289 pthread_mutex_destroy(&sema->mutex);
292 static void DRD_(sema_down)(DrdSema* sema)
294 int res = ENOSYS;
296 pthread_mutex_lock(&sema->mutex);
297 if (sema->counter == 0) {
298 sema->waiters++;
299 while (sema->counter == 0) {
300 pthread_mutex_unlock(&sema->mutex);
301 #ifdef HAVE_USABLE_LINUX_FUTEX_H
302 if (syscall(__NR_futex, (UWord)&sema->counter,
303 FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0) == 0)
304 res = 0;
305 else
306 res = errno;
307 #endif
309 * Invoke sched_yield() on non-Linux systems, if the futex syscall has
310 * not been invoked or if this code has been built on a Linux system
311 * where __NR_futex is defined and is run on a Linux system that does
312 * not support the futex syscall.
314 if (res != 0 && res != EWOULDBLOCK)
315 sched_yield();
316 pthread_mutex_lock(&sema->mutex);
318 sema->waiters--;
320 sema->counter--;
321 pthread_mutex_unlock(&sema->mutex);
324 static void DRD_(sema_up)(DrdSema* sema)
326 pthread_mutex_lock(&sema->mutex);
327 sema->counter++;
328 #ifdef HAVE_USABLE_LINUX_FUTEX_H
329 if (sema->waiters > 0)
330 syscall(__NR_futex, (UWord)&sema->counter,
331 FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1);
332 #endif
333 pthread_mutex_unlock(&sema->mutex);
337 * POSIX threads and DRD each have their own mutex type identification.
338 * Convert POSIX threads' mutex type to DRD's mutex type. In the code below
339 * if-statements are used to test the value of 'kind' instead of a switch
340 * statement because some of the PTHREAD_MUTEX_ macro's may have the same
341 * value.
343 static MutexT DRD_(pthread_to_drd_mutex_type)(int kind)
346 * See also PTHREAD_MUTEX_KIND_MASK_NP in glibc source file
347 * <nptl/pthreadP.h>.
349 kind &= PTHREAD_MUTEX_RECURSIVE | PTHREAD_MUTEX_ERRORCHECK |
350 PTHREAD_MUTEX_NORMAL | PTHREAD_MUTEX_DEFAULT;
352 if (kind == PTHREAD_MUTEX_RECURSIVE)
353 return mutex_type_recursive_mutex;
354 else if (kind == PTHREAD_MUTEX_ERRORCHECK)
355 return mutex_type_errorcheck_mutex;
356 else if (kind == PTHREAD_MUTEX_NORMAL)
357 return mutex_type_default_mutex;
358 else if (kind == PTHREAD_MUTEX_DEFAULT)
359 return mutex_type_default_mutex;
360 #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
361 else if (kind == PTHREAD_MUTEX_ADAPTIVE_NP)
362 return mutex_type_default_mutex;
363 #endif
364 else
365 return mutex_type_invalid_mutex;
368 #if defined(VGO_solaris)
370 * Solaris threads and DRD each have their own mutex type identification.
371 * Convert Solaris threads' mutex type to DRD's mutex type.
373 static MutexT DRD_(thread_to_drd_mutex_type)(int type)
375 if (type & LOCK_RECURSIVE) {
376 return mutex_type_recursive_mutex;
377 } else if (type & LOCK_ERRORCHECK) {
378 return mutex_type_errorcheck_mutex;
379 } else {
380 return mutex_type_default_mutex;
383 #endif /* VGO_solaris */
385 #define IS_ALIGNED(p) (((uintptr_t)(p) & (sizeof(*(p)) - 1)) == 0)
388 * Read the mutex type stored in the client memory used for the mutex
389 * implementation.
391 * @note This function depends on the implementation of the POSIX threads
392 * library -- the POSIX standard does not define the name of the member in
393 * which the mutex type is stored.
394 * @note The function mutex_type() has been declared inline in order
395 * to avoid that it shows up in call stacks (drd/tests/...exp* files).
396 * @note glibc stores the mutex type in the lowest two bits, and uses the
397 * higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
398 * PTHREAD_MUTEXATTR_FLAG_PSHARED.
400 static __always_inline MutexT DRD_(mutex_type)(pthread_mutex_t* mutex)
402 #if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
403 /* glibc + LinuxThreads. */
404 if (IS_ALIGNED(&mutex->__m_kind))
406 const int kind = mutex->__m_kind & 3;
407 return DRD_(pthread_to_drd_mutex_type)(kind);
409 #elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
410 /* glibc + NPTL. */
411 if (IS_ALIGNED(&mutex->__data.__kind))
413 const int kind = mutex->__data.__kind & 3;
414 return DRD_(pthread_to_drd_mutex_type)(kind);
416 #elif defined(VGO_solaris)
417 const int type = ((mutex_t *) mutex)->vki_mutex_type;
418 return DRD_(thread_to_drd_mutex_type)(type);
419 #else
421 * Another POSIX threads implementation. The mutex type won't be printed
422 * when enabling --trace-mutex=yes.
424 #endif
425 return mutex_type_unknown;
429 * Tell DRD whether 'tid' is a joinable thread or a detached thread.
431 static void DRD_(set_joinable)(const pthread_t tid, const int joinable)
433 assert(joinable == 0 || joinable == 1);
434 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_JOINABLE,
435 tid, joinable, 0, 0, 0);
438 /** Tell DRD that the calling thread is about to enter pthread_create(). */
439 static __always_inline void DRD_(entering_pthread_create)(void)
441 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__ENTERING_PTHREAD_CREATE,
442 0, 0, 0, 0, 0);
445 /** Tell DRD that the calling thread has left pthread_create(). */
446 static __always_inline void DRD_(left_pthread_create)(void)
448 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LEFT_PTHREAD_CREATE,
449 0, 0, 0, 0, 0);
453 * Entry point for newly created threads. This function is called from the
454 * thread created by pthread_create().
456 static void* DRD_(thread_wrapper)(void* arg)
458 DrdPosixThreadArgs* arg_ptr;
459 DrdPosixThreadArgs arg_copy;
461 arg_ptr = (DrdPosixThreadArgs*)arg;
462 arg_copy = *arg_ptr;
464 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
465 pthread_self(), 0, 0, 0, 0);
467 DRD_(set_joinable)(pthread_self(),
468 arg_copy.detachstate == PTHREAD_CREATE_JOINABLE);
471 * Only set 'wrapper_started' after VG_USERREQ__SET_PTHREADID and
472 * DRD_(set_joinable)() have been invoked to avoid a race with
473 * a pthread_detach() invocation for this thread from another thread.
475 DRD_(sema_up)(arg_copy.wrapper_started);
477 return (arg_copy.start)(arg_copy.arg);
481 * Return 1 if the LinuxThreads implementation of POSIX Threads has been
482 * detected, and 0 otherwise.
484 * @see For more information about the confstr() function, see also
485 * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
487 static int DRD_(detected_linuxthreads)(void)
489 #if defined(linux)
490 #if defined(_CS_GNU_LIBPTHREAD_VERSION)
491 /* Linux with a recent glibc. */
492 HChar buffer[256];
493 unsigned len;
494 len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
495 assert(len <= sizeof(buffer));
496 return len > 0 && buffer[0] == 'l';
497 #else
498 /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
499 return 1;
500 #endif
501 #else
502 /* Another OS than Linux, hence no LinuxThreads. */
503 return 0;
504 #endif
508 * Stop and print an error message in case a non-supported threading
509 * library implementation (LinuxThreads) has been detected.
511 static void DRD_(check_threading_library)(void)
513 if (DRD_(detected_linuxthreads)())
515 if (getenv("LD_ASSUME_KERNEL"))
517 fprintf(stderr,
518 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
519 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
520 "after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
523 else
525 fprintf(stderr,
526 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
527 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
528 "after having upgraded to a newer version of your Linux distribution.\n"
529 "Giving up.\n"
532 abort();
537 * The main thread is the only thread not created by pthread_create().
538 * Update DRD's state information about the main thread.
540 static void DRD_(set_main_thread_state)(void)
542 // Make sure that DRD knows about the main thread's POSIX thread ID.
543 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
544 pthread_self(), 0, 0, 0, 0);
548 * Note: as of today there exist three different versions of pthread_create
549 * in Linux:
550 * - pthread_create@GLIBC_2.0
551 * - pthread_create@@GLIBC_2.1
552 * - pthread_create@@GLIBC_2.2.5
553 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
554 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
555 * versions have been implemented. In any glibc version where more than one
556 * pthread_create function has been implemented, older versions call the
557 * newer versions. Or: the pthread_create* wrapper defined below can be
558 * called recursively. Any code in this wrapper should take this in account.
559 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
560 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
561 * See also the implementation of pthread_create@GLIBC_2.0 in
562 * glibc-2.9/nptl/pthread_create.c.
565 static __always_inline
566 int pthread_create_intercept(pthread_t* thread, const pthread_attr_t* attr,
567 void* (*start)(void*), void* arg)
569 int ret;
570 OrigFn fn;
571 DrdSema wrapper_started;
572 DrdPosixThreadArgs thread_args;
574 VALGRIND_GET_ORIG_FN(fn);
576 DRD_(sema_init)(&wrapper_started);
577 thread_args.start = start;
578 thread_args.arg = arg;
579 thread_args.wrapper_started = &wrapper_started;
581 * Find out whether the thread will be started as a joinable thread
582 * or as a detached thread. If no thread attributes have been specified,
583 * this means that the new thread will be started as a joinable thread.
585 thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
586 if (attr)
588 if (pthread_attr_getdetachstate(attr, &thread_args.detachstate) != 0)
589 assert(0);
591 assert(thread_args.detachstate == PTHREAD_CREATE_JOINABLE
592 || thread_args.detachstate == PTHREAD_CREATE_DETACHED);
594 DRD_(entering_pthread_create)();
595 CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), &thread_args);
596 DRD_(left_pthread_create)();
598 if (ret == 0) {
599 /* Wait until the thread wrapper started. */
600 DRD_(sema_down)(&wrapper_started);
603 DRD_(sema_destroy)(&wrapper_started);
605 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT,
606 pthread_self(), 0, 0, 0, 0);
608 return ret;
611 PTH_FUNCS(int, pthreadZucreate, pthread_create_intercept,
612 (pthread_t *thread, const pthread_attr_t *attr,
613 void *(*start) (void *), void *arg),
614 (thread, attr, start, arg));
616 #if defined(VGO_solaris)
617 /* Solaris also provides thr_create() in addition to pthread_create().
618 * Both pthread_create(3C) and thr_create(3C) are based on private
619 * _thrp_create().
621 static __always_inline
622 int thr_create_intercept(void *stk, size_t stksize, void *(*start)(void *),
623 void *arg, long flags, thread_t *new_thread)
625 int ret;
626 OrigFn fn;
627 DrdSema wrapper_started;
628 DrdPosixThreadArgs thread_args;
630 VALGRIND_GET_ORIG_FN(fn);
632 DRD_(sema_init)(&wrapper_started);
633 thread_args.start = start;
634 thread_args.arg = arg;
635 thread_args.wrapper_started = &wrapper_started;
637 * Find out whether the thread will be started as a joinable thread
638 * or as a detached thread.
640 if (flags & THR_DETACHED)
641 thread_args.detachstate = PTHREAD_CREATE_DETACHED;
642 else
643 thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
645 DRD_(entering_pthread_create)();
646 CALL_FN_W_6W(ret, fn, stk, stksize, DRD_(thread_wrapper), &thread_args,
647 flags, new_thread);
648 DRD_(left_pthread_create)();
650 if (ret == 0) {
651 /* Wait until the thread wrapper started. */
652 DRD_(sema_down)(&wrapper_started);
655 DRD_(sema_destroy)(&wrapper_started);
657 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT,
658 pthread_self(), 0, 0, 0, 0);
660 return ret;
663 PTH_FUNCS(int, thrZucreate, thr_create_intercept,
664 (void *stk, size_t stksize, void *(*start)(void *), void *arg,
665 long flags, thread_t *new_thread),
666 (stk, stksize, start, arg, flags, new_thread));
667 #endif /* VGO_solaris */
669 #if defined(VGO_solaris)
671 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
672 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
673 * and CI_BIND_CLEAR, to provide resilience against function renaming.
675 static __always_inline
676 int DRD_(_ti_bind_guard_intercept)(int flags) {
677 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_GUARD,
678 flags, 0, 0, 0, 0);
679 return DRD_(rtld_bind_guard)(flags);
682 static __always_inline
683 int DRD_(_ti_bind_clear_intercept)(int flags) {
684 int ret = DRD_(rtld_bind_clear)(flags);
685 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_CLEAR,
686 flags, 0, 0, 0, 0);
687 return ret;
691 * Wrapped _ld_libc() from the runtime linker ld.so.1.
693 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr);
694 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr)
696 OrigFn fn;
697 int tag;
699 VALGRIND_GET_ORIG_FN(fn);
701 vki_Lc_interface *funcs = ptr;
702 for (tag = funcs->ci_tag; tag != 0; tag = (++funcs)->ci_tag) {
703 switch (tag) {
704 case VKI_CI_BIND_GUARD:
705 if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_guard_intercept)) {
706 DRD_(rtld_bind_guard) = funcs->vki_ci_un.ci_func;
707 funcs->vki_ci_un.ci_func = DRD_(_ti_bind_guard_intercept);
709 break;
710 case VKI_CI_BIND_CLEAR:
711 if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_clear_intercept)) {
712 DRD_(rtld_bind_clear) = funcs->vki_ci_un.ci_func;
713 funcs->vki_ci_un.ci_func = DRD_(_ti_bind_clear_intercept);
715 break;
719 CALL_FN_v_W(fn, ptr);
721 #endif /* VGO_solaris */
723 static __always_inline
724 int pthread_join_intercept(pthread_t pt_joinee, void **thread_return)
726 int ret;
727 OrigFn fn;
729 VALGRIND_GET_ORIG_FN(fn);
731 * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
732 * implementation triggers a (false positive) race report.
734 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
735 CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
736 if (ret == 0)
738 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN,
739 pt_joinee, 0, 0, 0, 0);
741 ANNOTATE_IGNORE_READS_AND_WRITES_END();
742 return ret;
745 PTH_FUNCS(int, pthreadZujoin, pthread_join_intercept,
746 (pthread_t pt_joinee, void **thread_return),
747 (pt_joinee, thread_return));
749 #if defined(VGO_solaris)
750 /* Solaris also provides thr_join() in addition to pthread_join().
751 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
753 * :TODO: No functionality is currently provided for joinee == 0 and departed.
754 * This would require another client request, of course.
756 static __always_inline
757 int thr_join_intercept(thread_t joinee, thread_t *departed, void **thread_return)
759 int ret;
760 OrigFn fn;
762 VALGRIND_GET_ORIG_FN(fn);
763 CALL_FN_W_WWW(ret, fn, joinee, departed, thread_return);
764 if (ret == 0)
766 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN,
767 joinee, 0, 0, 0, 0);
769 return ret;
772 PTH_FUNCS(int, thrZujoin, thr_join_intercept,
773 (thread_t joinee, thread_t *departed, void **thread_return),
774 (joinee, departed, thread_return));
775 #endif /* VGO_solaris */
777 static __always_inline
778 int pthread_detach_intercept(pthread_t pt_thread)
780 int ret;
781 OrigFn fn;
783 VALGRIND_GET_ORIG_FN(fn);
784 CALL_FN_W_W(ret, fn, pt_thread);
785 DRD_(set_joinable)(pt_thread, 0);
787 return ret;
790 PTH_FUNCS(int, pthreadZudetach, pthread_detach_intercept,
791 (pthread_t thread), (thread));
793 // NOTE: be careful to intercept only pthread_cancel() and not
794 // pthread_cancel_init() on Linux.
796 static __always_inline
797 int pthread_cancel_intercept(pthread_t pt_thread)
799 int ret;
800 OrigFn fn;
801 VALGRIND_GET_ORIG_FN(fn);
802 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_THREAD_CANCEL,
803 pt_thread, 0, 0, 0, 0);
804 CALL_FN_W_W(ret, fn, pt_thread);
805 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_CANCEL,
806 pt_thread, ret==0, 0, 0, 0);
807 return ret;
810 PTH_FUNCS(int, pthreadZucancel, pthread_cancel_intercept,
811 (pthread_t thread), (thread))
813 static __always_inline
814 int pthread_once_intercept(pthread_once_t *once_control,
815 void (*init_routine)(void))
817 int ret;
818 OrigFn fn;
819 VALGRIND_GET_ORIG_FN(fn);
821 * Ignore any data races triggered by the implementation of pthread_once().
822 * Necessary for Darwin. This is not necessary for Linux but doesn't have
823 * any known adverse effects.
825 DRD_IGNORE_VAR(*once_control);
826 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
827 CALL_FN_W_WW(ret, fn, once_control, init_routine);
828 ANNOTATE_IGNORE_READS_AND_WRITES_END();
829 DRD_STOP_IGNORING_VAR(*once_control);
830 return ret;
833 PTH_FUNCS(int, pthreadZuonce, pthread_once_intercept,
834 (pthread_once_t *once_control, void (*init_routine)(void)),
835 (once_control, init_routine));
837 static __always_inline
838 int pthread_mutex_init_intercept(pthread_mutex_t *mutex,
839 const pthread_mutexattr_t* attr)
841 int ret;
842 OrigFn fn;
843 int mt;
844 VALGRIND_GET_ORIG_FN(fn);
845 mt = PTHREAD_MUTEX_DEFAULT;
846 if (attr)
847 pthread_mutexattr_gettype(attr, &mt);
848 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
849 mutex, DRD_(pthread_to_drd_mutex_type)(mt),
850 0, 0, 0);
851 CALL_FN_W_WW(ret, fn, mutex, attr);
852 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
853 mutex, 0, 0, 0, 0);
854 return ret;
857 PTH_FUNCS(int, pthreadZumutexZuinit, pthread_mutex_init_intercept,
858 (pthread_mutex_t *mutex, const pthread_mutexattr_t* attr),
859 (mutex, attr));
861 #if defined(VGO_solaris)
862 static __always_inline
863 int mutex_init_intercept(mutex_t *mutex, int type, void *arg)
865 int ret;
866 OrigFn fn;
867 VALGRIND_GET_ORIG_FN(fn);
869 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
870 mutex, DRD_(thread_to_drd_mutex_type)(type),
871 0, 0, 0);
872 CALL_FN_W_WWW(ret, fn, mutex, type, arg);
873 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
874 mutex, 0, 0, 0, 0);
875 return ret;
878 PTH_FUNCS(int, mutexZuinit, mutex_init_intercept,
879 (mutex_t *mutex, int type, void *arg),
880 (mutex, type, arg));
881 #endif /* VGO_solaris */
883 static __always_inline
884 int pthread_mutex_destroy_intercept(pthread_mutex_t* mutex)
886 int ret;
887 OrigFn fn;
888 VALGRIND_GET_ORIG_FN(fn);
889 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
890 mutex, 0, 0, 0, 0);
891 CALL_FN_W_W(ret, fn, mutex);
892 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
893 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
894 return ret;
897 #if defined(VGO_solaris)
898 /* On Solaris, pthread_mutex_destroy is a weak alias to mutex_destroy. */
899 PTH_FUNCS(int, mutexZudestroy, pthread_mutex_destroy_intercept,
900 (pthread_mutex_t *mutex), (mutex));
901 #else
902 PTH_FUNCS(int, pthreadZumutexZudestroy, pthread_mutex_destroy_intercept,
903 (pthread_mutex_t *mutex), (mutex));
904 #endif /* VGO_solaris */
906 static __always_inline
907 int pthread_mutex_lock_intercept(pthread_mutex_t* mutex)
909 int ret;
910 OrigFn fn;
911 VALGRIND_GET_ORIG_FN(fn);
912 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
913 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
914 CALL_FN_W_W(ret, fn, mutex);
915 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
916 mutex, ret == 0, 0, 0, 0);
917 return ret;
920 #if defined(VGO_solaris)
921 /* On Solaris, pthread_mutex_lock is a weak alias to mutex_lock. */
922 PTH_FUNCS(int, mutexZulock, pthread_mutex_lock_intercept,
923 (pthread_mutex_t *mutex), (mutex));
924 #else
925 PTH_FUNCS(int, pthreadZumutexZulock, pthread_mutex_lock_intercept,
926 (pthread_mutex_t *mutex), (mutex));
927 #endif /* VGO_solaris */
929 #if defined(VGO_solaris)
930 /* Internal to libc. Mutex is usually initialized only implicitly,
931 * by zeroing mutex_t structure.
933 static __always_inline
934 void lmutex_lock_intercept(mutex_t *mutex)
936 OrigFn fn;
937 VALGRIND_GET_ORIG_FN(fn);
938 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
939 mutex,
940 DRD_(mutex_type)((pthread_mutex_t *) mutex),
941 False /* try_lock */, 0, 0);
942 CALL_FN_v_W(fn, mutex);
943 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
944 mutex, True /* took_lock */, 0, 0, 0);
947 PTH_FUNCS(void, lmutexZulock, lmutex_lock_intercept,
948 (mutex_t *mutex), (mutex));
949 #endif /* VGO_solaris */
951 static __always_inline
952 int pthread_mutex_trylock_intercept(pthread_mutex_t* mutex)
954 int ret;
955 OrigFn fn;
956 VALGRIND_GET_ORIG_FN(fn);
957 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
958 mutex, DRD_(mutex_type)(mutex), 1, 0, 0);
959 CALL_FN_W_W(ret, fn, mutex);
960 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
961 mutex, ret == 0, 0, 0, 0);
962 return ret;
965 #if defined(VGO_solaris)
966 /* On Solaris, pthread_mutex_trylock is a weak alias to mutex_trylock. */
967 PTH_FUNCS(int, mutexZutrylock, pthread_mutex_trylock_intercept,
968 (pthread_mutex_t *mutex), (mutex));
969 #else
970 PTH_FUNCS(int, pthreadZumutexZutrylock, pthread_mutex_trylock_intercept,
971 (pthread_mutex_t *mutex), (mutex));
972 #endif /* VGO_solaris */
974 static __always_inline
975 int pthread_mutex_timedlock_intercept(pthread_mutex_t *mutex,
976 const struct timespec *abs_timeout)
978 int ret;
979 OrigFn fn;
980 VALGRIND_GET_ORIG_FN(fn);
981 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
982 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
983 CALL_FN_W_WW(ret, fn, mutex, abs_timeout);
984 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
985 mutex, ret == 0, 0, 0, 0);
986 return ret;
989 PTH_FUNCS(int, pthreadZumutexZutimedlock, pthread_mutex_timedlock_intercept,
990 (pthread_mutex_t *mutex, const struct timespec *abs_timeout),
991 (mutex, abs_timeout));
992 #if defined(VGO_solaris)
993 PTH_FUNCS(int,
994 pthreadZumutexZureltimedlockZunp, pthread_mutex_timedlock_intercept,
995 (pthread_mutex_t *mutex, const struct timespec *timeout),
996 (mutex, timeout));
997 #endif /* VGO_solaris */
999 static __always_inline
1000 int pthread_mutex_unlock_intercept(pthread_mutex_t *mutex)
1002 int ret;
1003 OrigFn fn;
1004 VALGRIND_GET_ORIG_FN(fn);
1005 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
1006 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
1007 CALL_FN_W_W(ret, fn, mutex);
1008 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
1009 mutex, 0, 0, 0, 0);
1010 return ret;
1013 #if defined(VGO_solaris)
1014 /* On Solaris, pthread_mutex_unlock is a weak alias to mutex_unlock. */
1015 PTH_FUNCS(int, mutexZuunlock, pthread_mutex_unlock_intercept,
1016 (pthread_mutex_t *mutex), (mutex));
1017 #else
1018 PTH_FUNCS(int, pthreadZumutexZuunlock, pthread_mutex_unlock_intercept,
1019 (pthread_mutex_t *mutex), (mutex));
1020 #endif /* VGO_solaris */
1022 #if defined(VGO_solaris)
1023 /* Internal to libc. */
1024 static __always_inline
1025 void lmutex_unlock_intercept(mutex_t *mutex)
1027 OrigFn fn;
1028 VALGRIND_GET_ORIG_FN(fn);
1029 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
1030 mutex,
1031 DRD_(mutex_type)((pthread_mutex_t *) mutex),
1032 0, 0, 0);
1033 CALL_FN_v_W(fn, mutex);
1034 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
1035 mutex, 0, 0, 0, 0);
1038 PTH_FUNCS(void, lmutexZuunlock, lmutex_unlock_intercept,
1039 (mutex_t *mutex), (mutex));
1040 #endif /* VGO_solaris */
1042 static __always_inline
1043 int pthread_cond_init_intercept(pthread_cond_t* cond,
1044 const pthread_condattr_t* attr)
1046 int ret;
1047 OrigFn fn;
1048 VALGRIND_GET_ORIG_FN(fn);
1049 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT,
1050 cond, 0, 0, 0, 0);
1051 CALL_FN_W_WW(ret, fn, cond, attr);
1052 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT,
1053 cond, 0, 0, 0, 0);
1054 return ret;
1057 PTH_FUNCS(int, pthreadZucondZuinit, pthread_cond_init_intercept,
1058 (pthread_cond_t* cond, const pthread_condattr_t* attr),
1059 (cond, attr));
1061 #if defined(VGO_solaris)
1062 static __always_inline
1063 int cond_init_intercept(cond_t *cond, int type, void *arg)
1065 int ret;
1066 OrigFn fn;
1067 VALGRIND_GET_ORIG_FN(fn);
1068 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT,
1069 cond, 0, 0, 0, 0);
1070 CALL_FN_W_WWW(ret, fn, cond, type, arg);
1071 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT,
1072 cond, 0, 0, 0, 0);
1073 return ret;
1076 PTH_FUNCS(int, condZuinit, cond_init_intercept,
1077 (cond_t *cond, int type, void *arg),
1078 (cond, type, arg));
1079 #endif /* VGO_solaris */
1081 static __always_inline
1082 int pthread_cond_destroy_intercept(pthread_cond_t* cond)
1084 int ret;
1085 OrigFn fn;
1086 VALGRIND_GET_ORIG_FN(fn);
1087 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_DESTROY,
1088 cond, 0, 0, 0, 0);
1089 CALL_FN_W_W(ret, fn, cond);
1090 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_DESTROY,
1091 cond, ret==0, 0, 0, 0);
1092 return ret;
1095 #if defined(VGO_solaris)
1096 /* On Solaris, pthread_cond_destroy is a weak alias to cond_destroy. */
1097 PTH_FUNCS(int, condZudestroy, pthread_cond_destroy_intercept,
1098 (pthread_cond_t *cond), (cond));
1099 #else
1100 PTH_FUNCS(int, pthreadZucondZudestroy, pthread_cond_destroy_intercept,
1101 (pthread_cond_t* cond), (cond));
1102 #endif /* VGO_solaris */
1104 static __always_inline
1105 int pthread_cond_wait_intercept(pthread_cond_t *cond, pthread_mutex_t *mutex)
1107 int ret;
1108 OrigFn fn;
1109 VALGRIND_GET_ORIG_FN(fn);
1110 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
1111 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1112 CALL_FN_W_WW(ret, fn, cond, mutex);
1113 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
1114 cond, mutex, 1, 0, 0);
1115 return ret;
1118 PTH_FUNCS(int, pthreadZucondZuwait, pthread_cond_wait_intercept,
1119 (pthread_cond_t *cond, pthread_mutex_t *mutex),
1120 (cond, mutex));
1121 #if defined(VGO_solaris)
1122 PTH_FUNCS(int, condZuwait, pthread_cond_wait_intercept,
1123 (pthread_cond_t *cond, pthread_mutex_t *mutex),
1124 (cond, mutex));
1125 #endif /* VGO_solaris */
1127 static __always_inline
1128 int pthread_cond_timedwait_intercept(pthread_cond_t *cond,
1129 pthread_mutex_t *mutex,
1130 const struct timespec* abstime)
1132 int ret;
1133 OrigFn fn;
1134 VALGRIND_GET_ORIG_FN(fn);
1135 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
1136 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1137 CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
1138 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
1139 cond, mutex, 1, 0, 0);
1140 return ret;
1143 PTH_FUNCS(int, pthreadZucondZutimedwait, pthread_cond_timedwait_intercept,
1144 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1145 const struct timespec* abstime),
1146 (cond, mutex, abstime));
1147 #if defined(VGO_solaris)
1148 PTH_FUNCS(int, condZutimedwait, pthread_cond_timedwait_intercept,
1149 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1150 const struct timespec *timeout),
1151 (cond, mutex, timeout));
1152 PTH_FUNCS(int, condZureltimedwait, pthread_cond_timedwait_intercept,
1153 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1154 const struct timespec *timeout),
1155 (cond, mutex, timeout));
1156 #endif /* VGO_solaris */
1158 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
1159 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
1160 // two. Intercepting all pthread_cond_signal* functions will cause only one
1161 // argument to be passed to pthread_cond_signal_np() and hence will cause this
1162 // last function to crash.
1164 static __always_inline
1165 int pthread_cond_signal_intercept(pthread_cond_t* cond)
1167 int ret;
1168 OrigFn fn;
1169 VALGRIND_GET_ORIG_FN(fn);
1170 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_SIGNAL,
1171 cond, 0, 0, 0, 0);
1172 CALL_FN_W_W(ret, fn, cond);
1173 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_SIGNAL,
1174 cond, 0, 0, 0, 0);
1175 return ret;
1178 #if defined(VGO_solaris)
1179 /* On Solaris, pthread_cond_signal is a weak alias to cond_signal. */
1180 PTH_FUNCS(int, condZusignal, pthread_cond_signal_intercept,
1181 (pthread_cond_t *cond), (cond));
1182 #else
1183 PTH_FUNCS(int, pthreadZucondZusignal, pthread_cond_signal_intercept,
1184 (pthread_cond_t* cond), (cond));
1185 #endif /* VGO_solaris */
1187 static __always_inline
1188 int pthread_cond_broadcast_intercept(pthread_cond_t* cond)
1190 int ret;
1191 OrigFn fn;
1192 VALGRIND_GET_ORIG_FN(fn);
1193 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_BROADCAST,
1194 cond, 0, 0, 0, 0);
1195 CALL_FN_W_W(ret, fn, cond);
1196 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_BROADCAST,
1197 cond, 0, 0, 0, 0);
1198 return ret;
1201 #if defined(VGO_solaris)
1202 /* On Solaris, pthread_cond_broadcast is a weak alias to cond_broadcast. */
1203 PTH_FUNCS(int, condZubroadcast, pthread_cond_broadcast_intercept,
1204 (pthread_cond_t *cond), (cond));
1205 #else
1206 PTH_FUNCS(int, pthreadZucondZubroadcast, pthread_cond_broadcast_intercept,
1207 (pthread_cond_t* cond), (cond));
1208 #endif /* VGO_solaris */
1210 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1211 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1212 static __always_inline
1213 int pthread_spin_init_intercept(pthread_spinlock_t *spinlock, int pshared)
1215 int ret;
1216 OrigFn fn;
1217 VALGRIND_GET_ORIG_FN(fn);
1218 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
1219 spinlock, 0, 0, 0, 0);
1220 CALL_FN_W_WW(ret, fn, spinlock, pshared);
1221 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
1222 spinlock, 0, 0, 0, 0);
1223 return ret;
1226 PTH_FUNCS(int, pthreadZuspinZuinit, pthread_spin_init_intercept,
1227 (pthread_spinlock_t *spinlock, int pshared), (spinlock, pshared));
1229 static __always_inline
1230 int pthread_spin_destroy_intercept(pthread_spinlock_t *spinlock)
1232 int ret;
1233 OrigFn fn;
1234 VALGRIND_GET_ORIG_FN(fn);
1235 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
1236 spinlock, 0, 0, 0, 0);
1237 CALL_FN_W_W(ret, fn, spinlock);
1238 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
1239 spinlock, mutex_type_spinlock, 0, 0, 0);
1240 return ret;
1243 PTH_FUNCS(int, pthreadZuspinZudestroy, pthread_spin_destroy_intercept,
1244 (pthread_spinlock_t *spinlock), (spinlock));
1246 static __always_inline
1247 int pthread_spin_lock_intercept(pthread_spinlock_t *spinlock)
1249 int ret;
1250 OrigFn fn;
1251 VALGRIND_GET_ORIG_FN(fn);
1252 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
1253 spinlock, mutex_type_spinlock, 0, 0, 0);
1254 CALL_FN_W_W(ret, fn, spinlock);
1255 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
1256 spinlock, ret == 0, 0, 0, 0);
1257 return ret;
1260 PTH_FUNCS(int, pthreadZuspinZulock, pthread_spin_lock_intercept,
1261 (pthread_spinlock_t *spinlock), (spinlock));
1263 static __always_inline
1264 int pthread_spin_trylock_intercept(pthread_spinlock_t *spinlock)
1266 int ret;
1267 OrigFn fn;
1268 VALGRIND_GET_ORIG_FN(fn);
1269 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
1270 spinlock, mutex_type_spinlock, 0, 0, 0);
1271 CALL_FN_W_W(ret, fn, spinlock);
1272 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
1273 spinlock, ret == 0, 0, 0, 0);
1274 return ret;
1277 PTH_FUNCS(int, pthreadZuspinZutrylock, pthread_spin_trylock_intercept,
1278 (pthread_spinlock_t *spinlock), (spinlock));
1280 static __always_inline
1281 int pthread_spin_unlock_intercept(pthread_spinlock_t *spinlock)
1283 int ret;
1284 OrigFn fn;
1285 VALGRIND_GET_ORIG_FN(fn);
1286 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
1287 spinlock, mutex_type_spinlock, 0, 0, 0);
1288 CALL_FN_W_W(ret, fn, spinlock);
1289 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
1290 spinlock, 0, 0, 0, 0);
1291 return ret;
1294 PTH_FUNCS(int, pthreadZuspinZuunlock, pthread_spin_unlock_intercept,
1295 (pthread_spinlock_t *spinlock), (spinlock));
1296 #endif // HAVE_PTHREAD_SPIN_LOCK
1299 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1300 static __always_inline
1301 int pthread_barrier_init_intercept(pthread_barrier_t* barrier,
1302 const pthread_barrierattr_t* attr,
1303 unsigned count)
1305 int ret;
1306 OrigFn fn;
1307 VALGRIND_GET_ORIG_FN(fn);
1308 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_INIT,
1309 barrier, pthread_barrier, count, 0, 0);
1310 CALL_FN_W_WWW(ret, fn, barrier, attr, count);
1311 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_INIT,
1312 barrier, pthread_barrier, 0, 0, 0);
1313 return ret;
1316 PTH_FUNCS(int, pthreadZubarrierZuinit, pthread_barrier_init_intercept,
1317 (pthread_barrier_t* barrier, const pthread_barrierattr_t* attr,
1318 unsigned count), (barrier, attr, count));
1320 static __always_inline
1321 int pthread_barrier_destroy_intercept(pthread_barrier_t* barrier)
1323 int ret;
1324 OrigFn fn;
1325 VALGRIND_GET_ORIG_FN(fn);
1326 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_DESTROY,
1327 barrier, pthread_barrier, 0, 0, 0);
1328 CALL_FN_W_W(ret, fn, barrier);
1329 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_DESTROY,
1330 barrier, pthread_barrier, 0, 0, 0);
1331 return ret;
1334 PTH_FUNCS(int, pthreadZubarrierZudestroy, pthread_barrier_destroy_intercept,
1335 (pthread_barrier_t* barrier), (barrier));
1337 static __always_inline
1338 int pthread_barrier_wait_intercept(pthread_barrier_t* barrier)
1340 int ret;
1341 OrigFn fn;
1342 VALGRIND_GET_ORIG_FN(fn);
1343 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_WAIT,
1344 barrier, pthread_barrier, 0, 0, 0);
1345 CALL_FN_W_W(ret, fn, barrier);
1346 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_WAIT,
1347 barrier, pthread_barrier,
1348 ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD,
1349 ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
1350 return ret;
1353 PTH_FUNCS(int, pthreadZubarrierZuwait, pthread_barrier_wait_intercept,
1354 (pthread_barrier_t* barrier), (barrier));
1355 #endif // HAVE_PTHREAD_BARRIER_INIT
1358 static __always_inline
1359 int sem_init_intercept(sem_t *sem, int pshared, unsigned int value)
1361 int ret;
1362 OrigFn fn;
1363 VALGRIND_GET_ORIG_FN(fn);
1364 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT,
1365 sem, pshared, value, 0, 0);
1366 CALL_FN_W_WWW(ret, fn, sem, pshared, value);
1367 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT,
1368 sem, 0, 0, 0, 0);
1369 return ret;
1372 PTH_FUNCS(int, semZuinit, sem_init_intercept,
1373 (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
1375 #if defined(VGO_solaris)
1376 static __always_inline
1377 int sema_init_intercept(sema_t *sem, unsigned int value, int type, void *arg)
1379 int ret;
1380 OrigFn fn;
1381 VALGRIND_GET_ORIG_FN(fn);
1382 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT,
1383 sem, type == USYNC_PROCESS ? 1 : 0,
1384 value, 0, 0);
1385 CALL_FN_W_WWWW(ret, fn, sem, value, type, arg);
1386 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT,
1387 sem, 0, 0, 0, 0);
1388 return ret;
1391 PTH_FUNCS(int, semaZuinit, sema_init_intercept,
1392 (sema_t *sem, unsigned int value, int type, void *arg),
1393 (sem, value, type, arg));
1394 #endif /* VGO_solaris */
1396 static __always_inline
1397 int sem_destroy_intercept(sem_t *sem)
1399 int ret;
1400 OrigFn fn;
1401 VALGRIND_GET_ORIG_FN(fn);
1402 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_DESTROY,
1403 sem, 0, 0, 0, 0);
1404 CALL_FN_W_W(ret, fn, sem);
1405 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_DESTROY,
1406 sem, 0, 0, 0, 0);
1407 return ret;
1410 PTH_FUNCS(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1411 #if defined(VGO_solaris)
1412 PTH_FUNCS(int, semaZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1413 #endif /* VGO_solaris */
1415 static __always_inline
1416 sem_t* sem_open_intercept(const char *name, int oflag, mode_t mode,
1417 unsigned int value)
1419 sem_t *ret;
1420 OrigFn fn;
1421 VALGRIND_GET_ORIG_FN(fn);
1422 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_OPEN,
1423 name, oflag, mode, value, 0);
1424 CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value);
1425 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_OPEN,
1426 ret != SEM_FAILED ? ret : 0,
1427 name, oflag, mode, value);
1428 return ret;
1431 PTH_FUNCS(sem_t *, semZuopen, sem_open_intercept,
1432 (const char *name, int oflag, mode_t mode, unsigned int value),
1433 (name, oflag, mode, value));
1435 static __always_inline int sem_close_intercept(sem_t *sem)
1437 int ret;
1438 OrigFn fn;
1439 VALGRIND_GET_ORIG_FN(fn);
1440 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_CLOSE,
1441 sem, 0, 0, 0, 0);
1442 CALL_FN_W_W(ret, fn, sem);
1443 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_CLOSE,
1444 sem, 0, 0, 0, 0);
1445 return ret;
1448 PTH_FUNCS(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
1450 static __always_inline int sem_wait_intercept(sem_t *sem)
1452 int ret;
1453 OrigFn fn;
1454 VALGRIND_GET_ORIG_FN(fn);
1455 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1456 sem, 0, 0, 0, 0);
1457 CALL_FN_W_W(ret, fn, sem);
1458 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1459 sem, ret == 0, 0, 0, 0);
1460 return ret;
1463 PTH_FUNCS(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1464 #if defined(VGO_solaris)
1465 PTH_FUNCS(int, semaZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1466 #endif /* VGO_solaris */
1468 static __always_inline int sem_trywait_intercept(sem_t *sem)
1470 int ret;
1471 OrigFn fn;
1472 VALGRIND_GET_ORIG_FN(fn);
1473 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1474 sem, 0, 0, 0, 0);
1475 CALL_FN_W_W(ret, fn, sem);
1476 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1477 sem, ret == 0, 0, 0, 0);
1478 return ret;
1481 PTH_FUNCS(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1482 #if defined(VGO_solaris)
1483 PTH_FUNCS(int, semaZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1484 #endif /* VGO_solaris */
1486 static __always_inline
1487 int sem_timedwait_intercept(sem_t *sem, const struct timespec *abs_timeout)
1489 int ret;
1490 OrigFn fn;
1491 VALGRIND_GET_ORIG_FN(fn);
1492 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1493 sem, 0, 0, 0, 0);
1494 CALL_FN_W_WW(ret, fn, sem, abs_timeout);
1495 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1496 sem, ret == 0, 0, 0, 0);
1497 return ret;
1500 PTH_FUNCS(int, semZutimedwait, sem_timedwait_intercept,
1501 (sem_t *sem, const struct timespec *abs_timeout),
1502 (sem, abs_timeout));
1503 #if defined(VGO_solaris)
1504 PTH_FUNCS(int, semaZutimedwait, sem_timedwait_intercept,
1505 (sem_t *sem, const struct timespec *timeout),
1506 (sem, timeout));
1507 PTH_FUNCS(int, semaZureltimedwait, sem_timedwait_intercept,
1508 (sem_t *sem, const struct timespec *timeout),
1509 (sem, timeout));
1510 #endif /* VGO_solaris */
1512 static __always_inline int sem_post_intercept(sem_t *sem)
1514 int ret;
1515 OrigFn fn;
1516 VALGRIND_GET_ORIG_FN(fn);
1517 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_POST,
1518 sem, 0, 0, 0, 0);
1519 CALL_FN_W_W(ret, fn, sem);
1520 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_POST,
1521 sem, ret == 0, 0, 0, 0);
1522 return ret;
1525 PTH_FUNCS(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
1526 #if defined(VGO_solaris)
1527 PTH_FUNCS(int, semaZupost, sem_post_intercept, (sem_t *sem), (sem));
1528 #endif /* VGO_solaris */
1530 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1531 functions have to be conditionally compiled. */
1532 #if defined(HAVE_PTHREAD_RWLOCK_T)
1534 static __always_inline
1535 int pthread_rwlock_init_intercept(pthread_rwlock_t* rwlock,
1536 const pthread_rwlockattr_t* attr)
1538 int ret;
1539 OrigFn fn;
1540 VALGRIND_GET_ORIG_FN(fn);
1541 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT,
1542 rwlock, 0, 0, 0, 0);
1543 CALL_FN_W_WW(ret, fn, rwlock, attr);
1544 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT,
1545 rwlock, 0, 0, 0, 0);
1546 return ret;
1549 PTH_FUNCS(int,
1550 pthreadZurwlockZuinit, pthread_rwlock_init_intercept,
1551 (pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr),
1552 (rwlock, attr));
1554 #if defined(VGO_solaris)
1555 static __always_inline
1556 int rwlock_init_intercept(rwlock_t *rwlock, int type, void *arg)
1558 int ret;
1559 OrigFn fn;
1560 VALGRIND_GET_ORIG_FN(fn);
1561 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT,
1562 rwlock, 0, 0, 0, 0);
1563 CALL_FN_W_WWW(ret, fn, rwlock, type, arg);
1564 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT,
1565 rwlock, 0, 0, 0, 0);
1566 return ret;
1569 PTH_FUNCS(int, rwlockZuinit, rwlock_init_intercept,
1570 (rwlock_t *rwlock, int type, void *arg),
1571 (rwlock, type, arg));
1572 #endif /* VGO_solaris */
1574 static __always_inline
1575 int pthread_rwlock_destroy_intercept(pthread_rwlock_t* rwlock)
1577 int ret;
1578 OrigFn fn;
1579 VALGRIND_GET_ORIG_FN(fn);
1580 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_DESTROY,
1581 rwlock, 0, 0, 0, 0);
1582 CALL_FN_W_W(ret, fn, rwlock);
1583 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_DESTROY,
1584 rwlock, 0, 0, 0, 0);
1585 return ret;
1588 #if defined(VGO_solaris)
1589 /* On Solaris, pthread_rwlock_destroy is a weak alias to rwlock_destroy. */
1590 PTH_FUNCS(int,
1591 rwlockZudestroy, pthread_rwlock_destroy_intercept,
1592 (pthread_rwlock_t *rwlock), (rwlock));
1593 #else
1594 PTH_FUNCS(int,
1595 pthreadZurwlockZudestroy, pthread_rwlock_destroy_intercept,
1596 (pthread_rwlock_t* rwlock), (rwlock));
1597 #endif /* VGO_solaris */
1599 static __always_inline
1600 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t* rwlock)
1602 int ret;
1603 OrigFn fn;
1604 VALGRIND_GET_ORIG_FN(fn);
1605 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1606 rwlock, 0, 0, 0, 0);
1607 CALL_FN_W_W(ret, fn, rwlock);
1608 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1609 rwlock, ret == 0, 0, 0, 0);
1610 return ret;
1613 #if defined(VGO_solaris)
1614 /* On Solaris, pthread_rwlock_rdlock is a weak alias to rw_rdlock. */
1615 PTH_FUNCS(int,
1616 rwZurdlock, pthread_rwlock_rdlock_intercept,
1617 (pthread_rwlock_t *rwlock), (rwlock));
1618 #else
1619 PTH_FUNCS(int,
1620 pthreadZurwlockZurdlock, pthread_rwlock_rdlock_intercept,
1621 (pthread_rwlock_t* rwlock), (rwlock));
1622 #endif /* VGO_solaris */
1624 #if defined(VGO_solaris)
1625 /* Internal to libc. */
1626 static __always_inline
1627 void lrw_rdlock_intercept(rwlock_t *rwlock)
1629 OrigFn fn;
1630 VALGRIND_GET_ORIG_FN(fn);
1631 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1632 rwlock, 0, 0, 0, 0);
1633 CALL_FN_v_W(fn, rwlock);
1634 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1635 rwlock, True /* took_lock */, 0, 0, 0);
1638 PTH_FUNCS(void, lrwZurdlock, lrw_rdlock_intercept,
1639 (rwlock_t *rwlock), (rwlock));
1640 #endif /* VGO_solaris */
1642 static __always_inline
1643 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t* rwlock)
1645 int ret;
1646 OrigFn fn;
1647 VALGRIND_GET_ORIG_FN(fn);
1648 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1649 rwlock, 0, 0, 0, 0);
1650 CALL_FN_W_W(ret, fn, rwlock);
1651 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1652 rwlock, ret == 0, 0, 0, 0);
1653 return ret;
1656 #if defined(VGO_solaris)
1657 /* On Solaris, pthread_rwlock_wrlock is a weak alias to rw_wrlock. */
1658 PTH_FUNCS(int,
1659 rwZuwrlock, pthread_rwlock_wrlock_intercept,
1660 (pthread_rwlock_t *rwlock), (rwlock));
1661 #else
1662 PTH_FUNCS(int,
1663 pthreadZurwlockZuwrlock, pthread_rwlock_wrlock_intercept,
1664 (pthread_rwlock_t* rwlock), (rwlock));
1665 #endif /* VGO_solaris */
1667 #if defined(VGO_solaris)
1668 /* Internal to libc. */
1669 static __always_inline
1670 void lrw_wrlock_intercept(rwlock_t *rwlock)
1672 OrigFn fn;
1673 VALGRIND_GET_ORIG_FN(fn);
1674 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1675 rwlock, 0, 0, 0, 0);
1676 CALL_FN_v_W(fn, rwlock);
1677 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1678 rwlock, True /* took_lock */, 0, 0, 0);
1681 PTH_FUNCS(void, lrwZuwrlock, lrw_wrlock_intercept,
1682 (rwlock_t *rwlock), (rwlock));
1683 #endif /* VGO_solaris */
1685 static __always_inline
1686 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t* rwlock,
1687 const struct timespec *timeout)
1689 int ret;
1690 OrigFn fn;
1691 VALGRIND_GET_ORIG_FN(fn);
1692 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1693 rwlock, 0, 0, 0, 0);
1694 CALL_FN_W_WW(ret, fn, rwlock, timeout);
1695 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1696 rwlock, ret == 0, 0, 0, 0);
1697 return ret;
1700 PTH_FUNCS(int,
1701 pthreadZurwlockZutimedrdlock, pthread_rwlock_timedrdlock_intercept,
1702 (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1703 (rwlock, timeout));
1704 #if defined(VGO_solaris)
1705 PTH_FUNCS(int, pthreadZurwlockZureltimedrdlockZunp,
1706 pthread_rwlock_timedrdlock_intercept,
1707 (pthread_rwlock_t *rwlock, const struct timespec *timeout),
1708 (rwlock, timeout));
1709 #endif /* VGO_solaris */
1711 static __always_inline
1712 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t* rwlock,
1713 const struct timespec *timeout)
1715 int ret;
1716 OrigFn fn;
1717 VALGRIND_GET_ORIG_FN(fn);
1718 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1719 rwlock, 0, 0, 0, 0);
1720 CALL_FN_W_WW(ret, fn, rwlock, timeout);
1721 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1722 rwlock, ret == 0, 0, 0, 0);
1723 return ret;
1726 PTH_FUNCS(int,
1727 pthreadZurwlockZutimedwrlock, pthread_rwlock_timedwrlock_intercept,
1728 (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1729 (rwlock, timeout));
1730 #if defined(VGO_solaris)
1731 PTH_FUNCS(int, pthreadZurwlockZureltimedwrlockZunp,
1732 pthread_rwlock_timedwrlock_intercept,
1733 (pthread_rwlock_t *rwlock, const struct timespec *timeout),
1734 (rwlock, timeout));
1735 #endif /* VGO_solaris */
1737 static __always_inline
1738 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t* rwlock)
1740 int ret;
1741 OrigFn fn;
1742 VALGRIND_GET_ORIG_FN(fn);
1743 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1744 rwlock, 0, 0, 0, 0);
1745 CALL_FN_W_W(ret, fn, rwlock);
1746 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1747 rwlock, ret == 0, 0, 0, 0);
1748 return ret;
1751 #if defined(VGO_solaris)
1752 /* On Solaris, pthread_rwlock_tryrdlock is a weak alias to rw_tryrdlock. */
1753 PTH_FUNCS(int,
1754 rwZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1755 (pthread_rwlock_t *rwlock), (rwlock));
1756 #else
1757 PTH_FUNCS(int,
1758 pthreadZurwlockZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1759 (pthread_rwlock_t* rwlock), (rwlock));
1760 #endif /* VGO_solaris */
1762 static __always_inline
1763 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t* rwlock)
1765 int ret;
1766 OrigFn fn;
1767 VALGRIND_GET_ORIG_FN(fn);
1768 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1769 rwlock, 0, 0, 0, 0);
1770 CALL_FN_W_W(ret, fn, rwlock);
1771 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1772 rwlock, ret == 0, 0, 0, 0);
1773 return ret;
1776 #if defined(VGO_solaris)
1777 /* On Solaris, pthread_rwlock_trywrlock is a weak alias to rw_trywrlock. */
1778 PTH_FUNCS(int,
1779 rwZutrywrlock, pthread_rwlock_trywrlock_intercept,
1780 (pthread_rwlock_t *rwlock), (rwlock));
1781 #else
1782 PTH_FUNCS(int,
1783 pthreadZurwlockZutrywrlock, pthread_rwlock_trywrlock_intercept,
1784 (pthread_rwlock_t* rwlock), (rwlock));
1785 #endif /* VGO_solaris */
1787 static __always_inline
1788 int pthread_rwlock_unlock_intercept(pthread_rwlock_t* rwlock)
1790 int ret;
1791 OrigFn fn;
1792 VALGRIND_GET_ORIG_FN(fn);
1793 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_UNLOCK,
1794 rwlock, 0, 0, 0, 0);
1795 CALL_FN_W_W(ret, fn, rwlock);
1796 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_UNLOCK,
1797 rwlock, ret == 0, 0, 0, 0);
1798 return ret;
1801 #if defined(VGO_solaris)
1802 /* On Solaris, pthread_rwlock_unlock is a weak alias to rw_unlock. */
1803 PTH_FUNCS(int,
1804 rwZuunlock, pthread_rwlock_unlock_intercept,
1805 (pthread_rwlock_t *rwlock), (rwlock));
1806 #else
1807 PTH_FUNCS(int,
1808 pthreadZurwlockZuunlock, pthread_rwlock_unlock_intercept,
1809 (pthread_rwlock_t* rwlock), (rwlock));
1810 #endif /* VGO_solaris */
1812 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */