drd/tests/swapcontext: Improve the portability of this test further
[valgrind.git] / drd / drd_pthread_intercepts.c
blob28c0de78bc83ad1949ba2412e5c2d25ef1271979
1 /*--------------------------------------------------------------------*/
2 /*--- Client-space code for DRD. drd_pthread_intercepts.c ---*/
3 /*--------------------------------------------------------------------*/
5 /*
6 This file is part of DRD, a thread error detector.
8 Copyright (C) 2006-2020 Bart Van Assche <bvanassche@acm.org>.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2 of the
13 License, or (at your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, see <http://www.gnu.org/licenses/>.
23 The GNU General Public License is contained in the file COPYING.
26 /* ---------------------------------------------------------------------
27 ALL THE CODE IN THIS FILE RUNS ON THE SIMULATED CPU.
29 These functions are not called directly - they're the targets of code
30 redirection or load notifications (see pub_core_redir.h for info).
31 They're named weirdly so that the intercept code can find them when the
32 shared object is initially loaded.
34 Note that this filename has the "drd_" prefix because it can appear
35 in stack traces, and the "drd_" makes it a little clearer that it
36 originates from Valgrind.
37 ------------------------------------------------------------------ */
40 * Define _GNU_SOURCE to make sure that pthread_spinlock_t is available when
41 * compiling with older glibc versions (2.3 or before).
43 #ifndef _GNU_SOURCE
44 #define _GNU_SOURCE
45 #endif
47 #include <assert.h> /* assert() */
48 #include <errno.h>
49 #include <pthread.h> /* pthread_mutex_t */
50 #include <semaphore.h> /* sem_t */
51 #include <stdint.h> /* uintptr_t */
52 #include <stdio.h> /* fprintf() */
53 #include <stdlib.h> /* malloc(), free() */
54 #include <unistd.h> /* confstr() */
55 #include "config.h" /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP etc. */
56 #include "drd_basics.h" /* DRD_() */
57 #include "drd_clientreq.h"
58 #include "pub_tool_redir.h" /* VG_WRAP_FUNCTION_ZZ() */
60 #if defined(VGO_solaris)
62 * Solaris usually provides pthread_* functions on top of Solaris threading
63 * and synchronization functions. Usually both need to be intercepted because
64 * pthread_* ones might not call the Solaris ones (see for example sem_wait()).
65 * Such approach is required to correctly report misuse of the POSIX threads
66 * API.
67 * Therefore DRD intercepts and instruments all such functions but due to
68 * DRD_(thread_enter_synchr)() and DRD_(thread_leave_synchr)() guards in
69 * handle_client_request(), only the top-most function is handled.
70 * So the right thing(TM) happens, as expected.
71 * The only exception is when pthread_* function is a weak alias to the Solaris
72 * threading/synchronization function. In such case only one needs to be
73 * intercepted to avoid redirection ambiguity.
75 * Intercepted functions rely on the fact that:
76 * - pthread_mutex_t == mutex_t
77 * - pthread_cond_t == cond_t
78 * - sem_t == sema_t
79 * - pthread_rwlock_t == rwlock_t
81 * It is necessary to intercept also internal libc synchronization functions
82 * for two reasons:
83 * - For read-write locks the unlocking function is shared
84 * - Functions lmutex_lock/lmutex_unlock guard many critical sections in libc
85 * which will be otherwise reported by DRD
87 #include <synch.h>
88 #include <thread.h>
89 #include "pub_tool_vki.h"
92 * Solaris provides higher throughput, parallelism and scalability than other
93 * operating systems, at the cost of more fine-grained locking activity.
94 * This means for example that when a thread is created under Linux, just one
95 * big lock in glibc is used for all thread setup. Solaris libc uses several
96 * fine-grained locks and the creator thread resumes its activities as soon
97 * as possible, leaving for example stack and TLS setup activities to the
98 * created thread.
100 * This situation confuses DRD as it assumes there is some false ordering
101 * in place between creator and created thread; and therefore many types of
102 * race conditions in the application would not be reported. To prevent such
103 * false ordering, command line option --ignore-thread-creation is set to
104 * 'yes' by default on Solaris. All activity (loads, stores, client requests)
105 * is therefore ignored during:
106 * - pthread_create() call in the creator thread [libc.so]
107 * - thread creation phase (stack and TLS setup) in the created thread [libc.so]
109 * As explained in the comments for _ti_bind_guard(), whenever the runtime
110 * linker has to perform any activity (such as resolving a symbol), it protects
111 * its data structures by calling into rt_bind_guard() which in turn invokes
112 * _ti_bind_guard() in libc. Pointers to _ti_bind_guard() and _ti_bind_clear()
113 * are passed from libc to runtime linker in _ld_libc() call during libc_init().
114 * All activity is also ignored during:
115 * - runtime dynamic linker work between rt_bind_guard() and rt_bind_clear()
116 * calls [ld.so]
118 * This also means that DRD does not report race conditions in libc (when
119 * --ignore-thread-creation=yes) and runtime linker itself (unconditionally)
120 * during these ignored sequences.
124 * Original function pointers for _ti_bind_guard() and _ti_bind_clear()
125 * from libc. They are intercepted in function wrapper of _ld_libc().
127 typedef int (*drd_rtld_guard_fn)(int flags);
128 static drd_rtld_guard_fn DRD_(rtld_bind_guard) = NULL;
129 static drd_rtld_guard_fn DRD_(rtld_bind_clear) = NULL;
130 #endif
134 * Notes regarding thread creation:
135 * - sg_init() runs on the context of the created thread and copies the vector
136 * clock of the creator thread. This only works reliably if the creator
137 * thread waits until this copy has been performed.
138 * - DRD_(thread_compute_minimum_vc)() does not take the vector clocks into
139 * account that are involved in thread creation and for which the
140 * corresponding thread has not yet been created. So not waiting until the
141 * created thread has been started would make it possible that segments get
142 * discarded that should not yet be discarded. Or: some data races are not
143 * detected.
147 * Macro for generating a Valgrind interception function.
148 * @param[in] ret_ty Return type of the function to be generated.
149 * @param[in] zf Z-encoded name of the interception function.
150 * @param[in] implf Name of the function that implements the intercept.
151 * @param[in] arg_decl Argument declaration list enclosed in parentheses.
152 * @param[in] argl Argument list enclosed in parentheses.
154 #if defined(VGO_darwin)
156 * Note here VGO_darwin is used rather than VG_WRAP_THREAD_FUNCTION_LIBPTHREAD_ONLY
157 * because of the special-case code adding a function call
159 static int never_true;
160 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
161 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
162 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
164 ret_ty pth_func_result = implf argl; \
165 /* Apparently inserting a function call in wrapper functions */ \
166 /* is sufficient to avoid misaligned stack errors. */ \
167 if (never_true) \
168 fflush(stdout); \
169 return pth_func_result; \
171 #elif defined(VG_WRAP_THREAD_FUNCTION_LIBC_ONLY)
172 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
173 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl; \
174 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl \
175 { return implf argl; }
176 #elif defined(VG_WRAP_THREAD_FUNCTION_LIBC_AND_LIBPTHREAD)
177 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
178 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl; \
179 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl \
180 { return implf argl; } \
181 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
182 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
183 { return implf argl; }
184 #else
185 # error "Unknown platform/thread wrapping"
186 #endif
189 * Macro for generating three Valgrind interception functions: one with the
190 * Z-encoded name zf, one with ZAZa ("@*") appended to the name zf and one
191 * with ZDZa ("$*") appended to the name zf. The second generated interception
192 * function will intercept versioned symbols on Linux, and the third will
193 * intercept versioned symbols on Darwin.
195 #define PTH_FUNCS(ret_ty, zf, implf, argl_decl, argl) \
196 PTH_FUNC(ret_ty, zf, implf, argl_decl, argl); \
197 PTH_FUNC(ret_ty, zf ## ZAZa, implf, argl_decl, argl); \
198 PTH_FUNC(ret_ty, zf ## ZDZa, implf, argl_decl, argl);
201 * Not inlining one of the intercept functions will cause the regression
202 * tests to fail because this would cause an additional stackfram to appear
203 * in the output. The __always_inline macro guarantees that inlining will
204 * happen, even when compiling with optimization disabled.
206 #undef __always_inline /* since already defined in <cdefs.h> */
207 #if __GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 2
208 #define __always_inline __inline__ __attribute__((always_inline))
209 #else
210 #define __always_inline __inline__
211 #endif
213 /* Local data structures. */
215 typedef struct {
216 pthread_mutex_t mutex;
217 pthread_cond_t cond;
218 int counter;
219 } DrdSema;
221 typedef struct
223 void* (*start)(void*);
224 void* arg;
225 int detachstate;
226 DrdSema* wrapper_started;
227 } DrdPosixThreadArgs;
230 /* Local function declarations. */
232 static void DRD_(init)(void) __attribute__((constructor));
233 static void DRD_(check_threading_library)(void);
234 static void DRD_(set_pthread_id)(void);
235 static void DRD_(sema_init)(DrdSema* sema);
236 static void DRD_(sema_destroy)(DrdSema* sema);
237 static void DRD_(sema_down)(DrdSema* sema);
238 static void DRD_(sema_up)(DrdSema* sema);
241 /* Function definitions. */
244 * Shared library initialization function. The function init() is called after
245 * dlopen() has loaded the shared library with DRD client intercepts because
246 * the constructor attribute was specified in the declaration of this function.
247 * Note: do specify the -nostdlib option to gcc when linking this code into a
248 * shared library because doing so would cancel the effect of the constructor
249 * attribute ! Using the gcc option -nodefaultlibs is fine because this last
250 * option preserves the shared library initialization code that calls
251 * constructor and destructor functions.
253 static void DRD_(init)(void)
255 DRD_(check_threading_library)();
256 DRD_(set_pthread_id)();
257 #if defined(VGO_solaris)
258 if ((DRD_(rtld_bind_guard) == NULL) || (DRD_(rtld_bind_clear) == NULL)) {
259 fprintf(stderr,
260 "Bind guard functions for the runtime linker (ld.so.1) were not intercepted.\n"
261 "This means the interface between libc and runtime linker changed and DRD\n"
262 "needs to be ported properly. Giving up.\n");
263 abort();
265 #endif
268 static __always_inline void DRD_(ignore_mutex_ordering)(pthread_mutex_t *mutex)
270 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_IGNORE_MUTEX_ORDERING,
271 mutex, 0, 0, 0, 0);
274 static void DRD_(sema_init)(DrdSema* sema)
276 DRD_IGNORE_VAR(*sema);
277 pthread_mutex_init(&sema->mutex, NULL);
278 DRD_(ignore_mutex_ordering)(&sema->mutex);
279 pthread_cond_init(&sema->cond, NULL);
280 sema->counter = 0;
283 static void DRD_(sema_destroy)(DrdSema* sema)
285 pthread_mutex_destroy(&sema->mutex);
286 pthread_cond_destroy(&sema->cond);
289 static void DRD_(sema_down)(DrdSema* sema)
291 pthread_mutex_lock(&sema->mutex);
292 while (sema->counter == 0)
293 pthread_cond_wait(&sema->cond, &sema->mutex);
294 sema->counter--;
295 pthread_mutex_unlock(&sema->mutex);
298 static void DRD_(sema_up)(DrdSema* sema)
300 pthread_mutex_lock(&sema->mutex);
301 sema->counter++;
302 pthread_cond_signal(&sema->cond);
303 pthread_mutex_unlock(&sema->mutex);
307 * POSIX threads and DRD each have their own mutex type identification.
308 * Convert POSIX threads' mutex type to DRD's mutex type. In the code below
309 * if-statements are used to test the value of 'kind' instead of a switch
310 * statement because some of the PTHREAD_MUTEX_ macro's may have the same
311 * value.
313 static MutexT DRD_(pthread_to_drd_mutex_type)(int kind)
316 * See also PTHREAD_MUTEX_KIND_MASK_NP in glibc source file
317 * <nptl/pthreadP.h>.
319 kind &= PTHREAD_MUTEX_RECURSIVE | PTHREAD_MUTEX_ERRORCHECK |
320 PTHREAD_MUTEX_NORMAL | PTHREAD_MUTEX_DEFAULT;
322 if (kind == PTHREAD_MUTEX_RECURSIVE)
323 return mutex_type_recursive_mutex;
324 else if (kind == PTHREAD_MUTEX_ERRORCHECK)
325 return mutex_type_errorcheck_mutex;
326 else if (kind == PTHREAD_MUTEX_NORMAL)
327 return mutex_type_default_mutex;
328 else if (kind == PTHREAD_MUTEX_DEFAULT)
329 return mutex_type_default_mutex;
330 #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
331 else if (kind == PTHREAD_MUTEX_ADAPTIVE_NP)
332 return mutex_type_default_mutex;
333 #endif
334 else
335 return mutex_type_invalid_mutex;
338 #if defined(VGO_solaris)
340 * Solaris threads and DRD each have their own mutex type identification.
341 * Convert Solaris threads' mutex type to DRD's mutex type.
343 static MutexT DRD_(thread_to_drd_mutex_type)(int type)
345 if (type & LOCK_RECURSIVE) {
346 return mutex_type_recursive_mutex;
347 } else if (type & LOCK_ERRORCHECK) {
348 return mutex_type_errorcheck_mutex;
349 } else {
350 return mutex_type_default_mutex;
353 #endif /* VGO_solaris */
355 #define IS_ALIGNED(p) (((uintptr_t)(p) & (sizeof(*(p)) - 1)) == 0)
358 * Read the mutex type stored in the client memory used for the mutex
359 * implementation.
361 * @note This function depends on the implementation of the POSIX threads
362 * library -- the POSIX standard does not define the name of the member in
363 * which the mutex type is stored.
364 * @note The function mutex_type() has been declared inline in order
365 * to avoid that it shows up in call stacks (drd/tests/...exp* files).
366 * @note glibc stores the mutex type in the lowest two bits, and uses the
367 * higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
368 * PTHREAD_MUTEXATTR_FLAG_PSHARED.
370 static __always_inline MutexT DRD_(mutex_type)(pthread_mutex_t* mutex)
372 MutexT mutex_type = mutex_type_unknown;
374 ANNOTATE_IGNORE_READS_BEGIN();
375 #if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
376 /* glibc + LinuxThreads. */
377 if (IS_ALIGNED(&mutex->__m_kind))
379 const int kind = mutex->__m_kind & 3;
380 mutex_type = DRD_(pthread_to_drd_mutex_type)(kind);
382 #elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
383 /* glibc + NPTL. */
384 if (IS_ALIGNED(&mutex->__data.__kind))
386 const int kind = mutex->__data.__kind & 3;
387 mutex_type = DRD_(pthread_to_drd_mutex_type)(kind);
389 #elif defined(VGO_solaris)
391 const int type = ((mutex_t *) mutex)->vki_mutex_type;
392 mutex_type = DRD_(thread_to_drd_mutex_type)(type);
394 #else
396 * Another POSIX threads implementation. The mutex type won't be printed
397 * when enabling --trace-mutex=yes.
399 #endif
400 ANNOTATE_IGNORE_READS_END();
402 return mutex_type;
406 * Tell DRD whether 'tid' is a joinable thread or a detached thread.
408 static void DRD_(set_joinable)(const pthread_t tid, const int joinable)
410 assert(joinable == 0 || joinable == 1);
411 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_JOINABLE,
412 tid, joinable, 0, 0, 0);
415 /** Tell DRD that the calling thread is about to enter pthread_create(). */
416 static __always_inline void DRD_(entering_pthread_create)(void)
418 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__ENTERING_PTHREAD_CREATE,
419 0, 0, 0, 0, 0);
422 /** Tell DRD that the calling thread has left pthread_create(). */
423 static __always_inline void DRD_(left_pthread_create)(void)
425 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LEFT_PTHREAD_CREATE,
426 0, 0, 0, 0, 0);
430 * Entry point for newly created threads. This function is called from the
431 * thread created by pthread_create().
433 static void* DRD_(thread_wrapper)(void* arg)
435 DrdPosixThreadArgs* arg_ptr;
436 DrdPosixThreadArgs arg_copy;
438 arg_ptr = (DrdPosixThreadArgs*)arg;
439 arg_copy = *arg_ptr;
441 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
442 pthread_self(), 0, 0, 0, 0);
444 DRD_(set_joinable)(pthread_self(),
445 arg_copy.detachstate == PTHREAD_CREATE_JOINABLE);
448 * Only set 'wrapper_started' after VG_USERREQ__SET_PTHREADID and
449 * DRD_(set_joinable)() have been invoked to avoid a race with
450 * a pthread_detach() invocation for this thread from another thread.
452 DRD_(sema_up)(arg_copy.wrapper_started);
454 return (arg_copy.start)(arg_copy.arg);
458 * Return 1 if the LinuxThreads implementation of POSIX Threads has been
459 * detected, and 0 otherwise.
461 * @see For more information about the confstr() function, see also
462 * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
464 static int DRD_(detected_linuxthreads)(void)
466 #if defined(linux)
467 #if defined(_CS_GNU_LIBPTHREAD_VERSION)
468 /* Linux with a recent glibc. */
469 HChar buffer[256];
470 unsigned len;
471 len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
472 assert(len <= sizeof(buffer));
473 return len > 0 && buffer[0] == 'l';
474 #else
475 /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
476 return 1;
477 #endif
478 #else
479 /* Another OS than Linux, hence no LinuxThreads. */
480 return 0;
481 #endif
485 * Stop and print an error message in case a non-supported threading
486 * library implementation (LinuxThreads) has been detected.
488 static void DRD_(check_threading_library)(void)
490 if (DRD_(detected_linuxthreads)())
492 if (getenv("LD_ASSUME_KERNEL"))
494 fprintf(stderr,
495 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
496 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
497 "after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
500 else
502 fprintf(stderr,
503 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
504 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
505 "after having upgraded to a newer version of your Linux distribution.\n"
506 "Giving up.\n"
509 abort();
514 * Update DRD's state information about the current thread.
516 static void DRD_(set_pthread_id)(void)
518 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
519 pthread_self(), 0, 0, 0, 0);
523 * Note: as of today there exist three different versions of pthread_create
524 * in Linux:
525 * - pthread_create@GLIBC_2.0
526 * - pthread_create@@GLIBC_2.1
527 * - pthread_create@@GLIBC_2.2.5
528 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
529 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
530 * versions have been implemented. In any glibc version where more than one
531 * pthread_create function has been implemented, older versions call the
532 * newer versions. Or: the pthread_create* wrapper defined below can be
533 * called recursively. Any code in this wrapper should take this in account.
534 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
535 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
536 * See also the implementation of pthread_create@GLIBC_2.0 in
537 * glibc-2.9/nptl/pthread_create.c.
540 static __always_inline
541 int pthread_create_intercept(pthread_t* thread, const pthread_attr_t* attr,
542 void* (*start)(void*), void* arg)
544 int ret;
545 OrigFn fn;
546 DrdSema wrapper_started;
547 DrdPosixThreadArgs thread_args;
549 VALGRIND_GET_ORIG_FN(fn);
551 DRD_(sema_init)(&wrapper_started);
552 thread_args.start = start;
553 thread_args.arg = arg;
554 thread_args.wrapper_started = &wrapper_started;
556 * Find out whether the thread will be started as a joinable thread
557 * or as a detached thread. If no thread attributes have been specified,
558 * this means that the new thread will be started as a joinable thread.
560 thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
561 if (attr)
563 if (pthread_attr_getdetachstate(attr, &thread_args.detachstate) != 0)
564 assert(0);
566 assert(thread_args.detachstate == PTHREAD_CREATE_JOINABLE
567 || thread_args.detachstate == PTHREAD_CREATE_DETACHED);
570 * The DRD_(set_pthread_id)() from DRD_(init)() may encounter that
571 * pthread_self() == 0, e.g. when the main program is not linked with the
572 * pthread library and when a pthread_create() call occurs from within a
573 * shared library. Hence call DRD_(set_pthread_id)() again to ensure that
574 * DRD knows the identity of the current thread. See also B.Z. 356374.
576 DRD_(set_pthread_id)();
577 DRD_(entering_pthread_create)();
578 CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), &thread_args);
579 DRD_(left_pthread_create)();
581 if (ret == 0) {
582 /* Wait until the thread wrapper started. */
583 DRD_(sema_down)(&wrapper_started);
586 DRD_(sema_destroy)(&wrapper_started);
588 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT,
589 pthread_self(), 0, 0, 0, 0);
591 return ret;
594 PTH_FUNCS(int, pthreadZucreate, pthread_create_intercept,
595 (pthread_t *thread, const pthread_attr_t *attr,
596 void *(*start) (void *), void *arg),
597 (thread, attr, start, arg));
599 #if defined(VGO_solaris)
600 /* Solaris also provides thr_create() in addition to pthread_create().
601 * Both pthread_create(3C) and thr_create(3C) are based on private
602 * _thrp_create().
604 static __always_inline
605 int thr_create_intercept(void *stk, size_t stksize, void *(*start)(void *),
606 void *arg, long flags, thread_t *new_thread)
608 int ret;
609 OrigFn fn;
610 DrdSema wrapper_started;
611 DrdPosixThreadArgs thread_args;
613 VALGRIND_GET_ORIG_FN(fn);
615 DRD_(sema_init)(&wrapper_started);
616 thread_args.start = start;
617 thread_args.arg = arg;
618 thread_args.wrapper_started = &wrapper_started;
620 * Find out whether the thread will be started as a joinable thread
621 * or as a detached thread.
623 if (flags & THR_DETACHED)
624 thread_args.detachstate = PTHREAD_CREATE_DETACHED;
625 else
626 thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
628 DRD_(entering_pthread_create)();
629 CALL_FN_W_6W(ret, fn, stk, stksize, DRD_(thread_wrapper), &thread_args,
630 flags, new_thread);
631 DRD_(left_pthread_create)();
633 if (ret == 0) {
634 /* Wait until the thread wrapper started. */
635 DRD_(sema_down)(&wrapper_started);
638 DRD_(sema_destroy)(&wrapper_started);
640 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT,
641 pthread_self(), 0, 0, 0, 0);
643 return ret;
646 PTH_FUNCS(int, thrZucreate, thr_create_intercept,
647 (void *stk, size_t stksize, void *(*start)(void *), void *arg,
648 long flags, thread_t *new_thread),
649 (stk, stksize, start, arg, flags, new_thread));
650 #endif /* VGO_solaris */
652 #if defined(VGO_solaris)
654 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
655 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
656 * and CI_BIND_CLEAR, to provide resilience against function renaming.
658 static __always_inline
659 int DRD_(_ti_bind_guard_intercept)(int flags) {
660 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_GUARD,
661 flags, 0, 0, 0, 0);
662 return DRD_(rtld_bind_guard)(flags);
665 static __always_inline
666 int DRD_(_ti_bind_clear_intercept)(int flags) {
667 int ret = DRD_(rtld_bind_clear)(flags);
668 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_CLEAR,
669 flags, 0, 0, 0, 0);
670 return ret;
674 * Wrapped _ld_libc() from the runtime linker ld.so.1.
676 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr);
677 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr)
679 OrigFn fn;
680 int tag;
682 VALGRIND_GET_ORIG_FN(fn);
684 vki_Lc_interface *funcs = ptr;
685 for (tag = funcs->ci_tag; tag != 0; tag = (++funcs)->ci_tag) {
686 switch (tag) {
687 case VKI_CI_BIND_GUARD:
688 if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_guard_intercept)) {
689 DRD_(rtld_bind_guard) = funcs->vki_ci_un.ci_func;
690 funcs->vki_ci_un.ci_func = DRD_(_ti_bind_guard_intercept);
692 break;
693 case VKI_CI_BIND_CLEAR:
694 if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_clear_intercept)) {
695 DRD_(rtld_bind_clear) = funcs->vki_ci_un.ci_func;
696 funcs->vki_ci_un.ci_func = DRD_(_ti_bind_clear_intercept);
698 break;
702 CALL_FN_v_W(fn, ptr);
704 #endif /* VGO_solaris */
706 static __always_inline
707 int pthread_join_intercept(pthread_t pt_joinee, void **thread_return)
709 int ret;
710 OrigFn fn;
712 VALGRIND_GET_ORIG_FN(fn);
714 * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
715 * implementation triggers a (false positive) race report.
717 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
718 CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
719 if (ret == 0)
721 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN,
722 pt_joinee, 0, 0, 0, 0);
724 ANNOTATE_IGNORE_READS_AND_WRITES_END();
725 return ret;
728 PTH_FUNCS(int, pthreadZujoin, pthread_join_intercept,
729 (pthread_t pt_joinee, void **thread_return),
730 (pt_joinee, thread_return));
732 #if defined(VGO_solaris)
733 /* Solaris also provides thr_join() in addition to pthread_join().
734 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
736 * :TODO: No functionality is currently provided for joinee == 0 and departed.
737 * This would require another client request, of course.
739 static __always_inline
740 int thr_join_intercept(thread_t joinee, thread_t *departed, void **thread_return)
742 int ret;
743 OrigFn fn;
745 VALGRIND_GET_ORIG_FN(fn);
746 CALL_FN_W_WWW(ret, fn, joinee, departed, thread_return);
747 if (ret == 0)
749 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN,
750 joinee, 0, 0, 0, 0);
752 return ret;
755 PTH_FUNCS(int, thrZujoin, thr_join_intercept,
756 (thread_t joinee, thread_t *departed, void **thread_return),
757 (joinee, departed, thread_return));
758 #endif /* VGO_solaris */
760 static __always_inline
761 int pthread_detach_intercept(pthread_t pt_thread)
763 int ret;
764 OrigFn fn;
766 VALGRIND_GET_ORIG_FN(fn);
767 CALL_FN_W_W(ret, fn, pt_thread);
768 DRD_(set_joinable)(pt_thread, 0);
770 return ret;
773 PTH_FUNCS(int, pthreadZudetach, pthread_detach_intercept,
774 (pthread_t thread), (thread));
776 // NOTE: be careful to intercept only pthread_cancel() and not
777 // pthread_cancel_init() on Linux.
779 static __always_inline
780 int pthread_cancel_intercept(pthread_t pt_thread)
782 int ret;
783 OrigFn fn;
784 VALGRIND_GET_ORIG_FN(fn);
785 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_THREAD_CANCEL,
786 pt_thread, 0, 0, 0, 0);
787 CALL_FN_W_W(ret, fn, pt_thread);
788 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_CANCEL,
789 pt_thread, ret==0, 0, 0, 0);
790 return ret;
793 PTH_FUNCS(int, pthreadZucancel, pthread_cancel_intercept,
794 (pthread_t thread), (thread))
796 static __always_inline
797 int pthread_once_intercept(pthread_once_t *once_control,
798 void (*init_routine)(void))
800 int ret;
801 OrigFn fn;
802 VALGRIND_GET_ORIG_FN(fn);
804 * Ignore any data races triggered by the implementation of pthread_once().
805 * Necessary for Darwin. This is not necessary for Linux but doesn't have
806 * any known adverse effects.
808 DRD_IGNORE_VAR(*once_control);
809 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
810 CALL_FN_W_WW(ret, fn, once_control, init_routine);
811 ANNOTATE_IGNORE_READS_AND_WRITES_END();
812 DRD_STOP_IGNORING_VAR(*once_control);
813 return ret;
816 PTH_FUNCS(int, pthreadZuonce, pthread_once_intercept,
817 (pthread_once_t *once_control, void (*init_routine)(void)),
818 (once_control, init_routine));
820 static __always_inline
821 int pthread_mutex_init_intercept(pthread_mutex_t *mutex,
822 const pthread_mutexattr_t* attr)
824 int ret;
825 OrigFn fn;
826 int mt;
827 VALGRIND_GET_ORIG_FN(fn);
828 mt = PTHREAD_MUTEX_DEFAULT;
829 if (attr)
830 pthread_mutexattr_gettype(attr, &mt);
831 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
832 mutex, DRD_(pthread_to_drd_mutex_type)(mt),
833 0, 0, 0);
834 CALL_FN_W_WW(ret, fn, mutex, attr);
835 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
836 mutex, 0, 0, 0, 0);
837 return ret;
840 PTH_FUNCS(int, pthreadZumutexZuinit, pthread_mutex_init_intercept,
841 (pthread_mutex_t *mutex, const pthread_mutexattr_t* attr),
842 (mutex, attr));
844 #if defined(VGO_solaris)
845 static __always_inline
846 int mutex_init_intercept(mutex_t *mutex, int type, void *arg)
848 int ret;
849 OrigFn fn;
850 VALGRIND_GET_ORIG_FN(fn);
852 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
853 mutex, DRD_(thread_to_drd_mutex_type)(type),
854 0, 0, 0);
855 CALL_FN_W_WWW(ret, fn, mutex, type, arg);
856 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
857 mutex, 0, 0, 0, 0);
858 return ret;
861 PTH_FUNCS(int, mutexZuinit, mutex_init_intercept,
862 (mutex_t *mutex, int type, void *arg),
863 (mutex, type, arg));
864 #endif /* VGO_solaris */
866 static __always_inline
867 int pthread_mutex_destroy_intercept(pthread_mutex_t* mutex)
869 int ret;
870 OrigFn fn;
871 VALGRIND_GET_ORIG_FN(fn);
872 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
873 mutex, 0, 0, 0, 0);
874 CALL_FN_W_W(ret, fn, mutex);
875 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
876 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
877 return ret;
880 #if defined(VGO_solaris)
881 /* On Solaris, pthread_mutex_destroy is a weak alias to mutex_destroy. */
882 PTH_FUNCS(int, mutexZudestroy, pthread_mutex_destroy_intercept,
883 (pthread_mutex_t *mutex), (mutex));
884 #else
885 PTH_FUNCS(int, pthreadZumutexZudestroy, pthread_mutex_destroy_intercept,
886 (pthread_mutex_t *mutex), (mutex));
887 #endif /* VGO_solaris */
889 static __always_inline
890 int pthread_mutex_lock_intercept(pthread_mutex_t* mutex)
892 int ret;
893 OrigFn fn;
894 VALGRIND_GET_ORIG_FN(fn);
895 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
896 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
897 CALL_FN_W_W(ret, fn, mutex);
898 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
899 mutex, ret == 0, 0, 0, 0);
900 return ret;
903 #if defined(VGO_solaris)
904 /* On Solaris, pthread_mutex_lock is a weak alias to mutex_lock. */
905 PTH_FUNCS(int, mutexZulock, pthread_mutex_lock_intercept,
906 (pthread_mutex_t *mutex), (mutex));
907 #else
908 PTH_FUNCS(int, pthreadZumutexZulock, pthread_mutex_lock_intercept,
909 (pthread_mutex_t *mutex), (mutex));
910 #endif /* VGO_solaris */
912 #if defined(VGO_solaris)
913 /* Internal to libc. Mutex is usually initialized only implicitly,
914 * by zeroing mutex_t structure.
916 static __always_inline
917 void lmutex_lock_intercept(mutex_t *mutex)
919 OrigFn fn;
920 VALGRIND_GET_ORIG_FN(fn);
921 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
922 mutex,
923 DRD_(mutex_type)((pthread_mutex_t *) mutex),
924 False /* try_lock */, 0, 0);
925 CALL_FN_v_W(fn, mutex);
926 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
927 mutex, True /* took_lock */, 0, 0, 0);
930 PTH_FUNCS(void, lmutexZulock, lmutex_lock_intercept,
931 (mutex_t *mutex), (mutex));
932 #endif /* VGO_solaris */
934 static __always_inline
935 int pthread_mutex_trylock_intercept(pthread_mutex_t* mutex)
937 int ret;
938 OrigFn fn;
939 VALGRIND_GET_ORIG_FN(fn);
940 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
941 mutex, DRD_(mutex_type)(mutex), 1, 0, 0);
942 CALL_FN_W_W(ret, fn, mutex);
943 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
944 mutex, ret == 0, 0, 0, 0);
945 return ret;
948 #if defined(VGO_solaris)
949 /* On Solaris, pthread_mutex_trylock is a weak alias to mutex_trylock. */
950 PTH_FUNCS(int, mutexZutrylock, pthread_mutex_trylock_intercept,
951 (pthread_mutex_t *mutex), (mutex));
952 #else
953 PTH_FUNCS(int, pthreadZumutexZutrylock, pthread_mutex_trylock_intercept,
954 (pthread_mutex_t *mutex), (mutex));
955 #endif /* VGO_solaris */
957 static __always_inline
958 int pthread_mutex_timedlock_intercept(pthread_mutex_t *mutex,
959 const struct timespec *abs_timeout)
961 int ret;
962 OrigFn fn;
963 VALGRIND_GET_ORIG_FN(fn);
964 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
965 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
966 CALL_FN_W_WW(ret, fn, mutex, abs_timeout);
967 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
968 mutex, ret == 0, 0, 0, 0);
969 return ret;
972 PTH_FUNCS(int, pthreadZumutexZutimedlock, pthread_mutex_timedlock_intercept,
973 (pthread_mutex_t *mutex, const struct timespec *abs_timeout),
974 (mutex, abs_timeout));
975 #if defined(VGO_solaris)
976 PTH_FUNCS(int,
977 pthreadZumutexZureltimedlockZunp, pthread_mutex_timedlock_intercept,
978 (pthread_mutex_t *mutex, const struct timespec *timeout),
979 (mutex, timeout));
980 #endif /* VGO_solaris */
982 static __always_inline
983 int pthread_mutex_unlock_intercept(pthread_mutex_t *mutex)
985 int ret;
986 OrigFn fn;
987 VALGRIND_GET_ORIG_FN(fn);
988 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
989 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
990 CALL_FN_W_W(ret, fn, mutex);
991 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
992 mutex, 0, 0, 0, 0);
993 return ret;
996 #if defined(VGO_solaris)
997 /* On Solaris, pthread_mutex_unlock is a weak alias to mutex_unlock. */
998 PTH_FUNCS(int, mutexZuunlock, pthread_mutex_unlock_intercept,
999 (pthread_mutex_t *mutex), (mutex));
1000 #else
1001 PTH_FUNCS(int, pthreadZumutexZuunlock, pthread_mutex_unlock_intercept,
1002 (pthread_mutex_t *mutex), (mutex));
1003 #endif /* VGO_solaris */
1005 #if defined(VGO_solaris)
1006 /* Internal to libc. */
1007 static __always_inline
1008 void lmutex_unlock_intercept(mutex_t *mutex)
1010 OrigFn fn;
1011 VALGRIND_GET_ORIG_FN(fn);
1012 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
1013 mutex,
1014 DRD_(mutex_type)((pthread_mutex_t *) mutex),
1015 0, 0, 0);
1016 CALL_FN_v_W(fn, mutex);
1017 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
1018 mutex, 0, 0, 0, 0);
1021 PTH_FUNCS(void, lmutexZuunlock, lmutex_unlock_intercept,
1022 (mutex_t *mutex), (mutex));
1023 #endif /* VGO_solaris */
1025 static __always_inline
1026 int pthread_cond_init_intercept(pthread_cond_t* cond,
1027 const pthread_condattr_t* attr)
1029 int ret;
1030 OrigFn fn;
1031 VALGRIND_GET_ORIG_FN(fn);
1032 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT,
1033 cond, 0, 0, 0, 0);
1034 CALL_FN_W_WW(ret, fn, cond, attr);
1035 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT,
1036 cond, 0, 0, 0, 0);
1037 return ret;
1040 PTH_FUNCS(int, pthreadZucondZuinit, pthread_cond_init_intercept,
1041 (pthread_cond_t* cond, const pthread_condattr_t* attr),
1042 (cond, attr));
1044 #if defined(VGO_solaris)
1045 static __always_inline
1046 int cond_init_intercept(cond_t *cond, int type, void *arg)
1048 int ret;
1049 OrigFn fn;
1050 VALGRIND_GET_ORIG_FN(fn);
1051 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT,
1052 cond, 0, 0, 0, 0);
1053 CALL_FN_W_WWW(ret, fn, cond, type, arg);
1054 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT,
1055 cond, 0, 0, 0, 0);
1056 return ret;
1059 PTH_FUNCS(int, condZuinit, cond_init_intercept,
1060 (cond_t *cond, int type, void *arg),
1061 (cond, type, arg));
1062 #endif /* VGO_solaris */
1064 static __always_inline
1065 int pthread_cond_destroy_intercept(pthread_cond_t* cond)
1067 int ret;
1068 OrigFn fn;
1069 VALGRIND_GET_ORIG_FN(fn);
1070 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_DESTROY,
1071 cond, 0, 0, 0, 0);
1072 CALL_FN_W_W(ret, fn, cond);
1073 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_DESTROY,
1074 cond, ret==0, 0, 0, 0);
1075 return ret;
1078 #if defined(VGO_solaris)
1079 /* On Solaris, pthread_cond_destroy is a weak alias to cond_destroy. */
1080 PTH_FUNCS(int, condZudestroy, pthread_cond_destroy_intercept,
1081 (pthread_cond_t *cond), (cond));
1082 #else
1083 PTH_FUNCS(int, pthreadZucondZudestroy, pthread_cond_destroy_intercept,
1084 (pthread_cond_t* cond), (cond));
1085 #endif /* VGO_solaris */
1087 static __always_inline
1088 int pthread_cond_wait_intercept(pthread_cond_t *cond, pthread_mutex_t *mutex)
1090 int ret;
1091 OrigFn fn;
1092 VALGRIND_GET_ORIG_FN(fn);
1093 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
1094 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1095 CALL_FN_W_WW(ret, fn, cond, mutex);
1096 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
1097 cond, mutex, 1, 0, 0);
1098 return ret;
1101 PTH_FUNCS(int, pthreadZucondZuwait, pthread_cond_wait_intercept,
1102 (pthread_cond_t *cond, pthread_mutex_t *mutex),
1103 (cond, mutex));
1104 #if defined(VGO_solaris)
1105 PTH_FUNCS(int, condZuwait, pthread_cond_wait_intercept,
1106 (pthread_cond_t *cond, pthread_mutex_t *mutex),
1107 (cond, mutex));
1108 #endif /* VGO_solaris */
1110 static __always_inline
1111 int pthread_cond_timedwait_intercept(pthread_cond_t *cond,
1112 pthread_mutex_t *mutex,
1113 const struct timespec* abstime)
1115 int ret;
1116 OrigFn fn;
1117 VALGRIND_GET_ORIG_FN(fn);
1118 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
1119 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1120 CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
1121 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
1122 cond, mutex, 1, 0, 0);
1123 return ret;
1126 PTH_FUNCS(int, pthreadZucondZutimedwait, pthread_cond_timedwait_intercept,
1127 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1128 const struct timespec* abstime),
1129 (cond, mutex, abstime));
1130 #if defined(VGO_solaris)
1131 PTH_FUNCS(int, condZutimedwait, pthread_cond_timedwait_intercept,
1132 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1133 const struct timespec *timeout),
1134 (cond, mutex, timeout));
1135 PTH_FUNCS(int, condZureltimedwait, pthread_cond_timedwait_intercept,
1136 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1137 const struct timespec *timeout),
1138 (cond, mutex, timeout));
1139 #endif /* VGO_solaris */
1141 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
1142 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
1143 // two. Intercepting all pthread_cond_signal* functions will cause only one
1144 // argument to be passed to pthread_cond_signal_np() and hence will cause this
1145 // last function to crash.
1147 static __always_inline
1148 int pthread_cond_signal_intercept(pthread_cond_t* cond)
1150 int ret;
1151 OrigFn fn;
1152 VALGRIND_GET_ORIG_FN(fn);
1153 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_SIGNAL,
1154 cond, 0, 0, 0, 0);
1155 CALL_FN_W_W(ret, fn, cond);
1156 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_SIGNAL,
1157 cond, 0, 0, 0, 0);
1158 return ret;
1161 #if defined(VGO_solaris)
1162 /* On Solaris, pthread_cond_signal is a weak alias to cond_signal. */
1163 PTH_FUNCS(int, condZusignal, pthread_cond_signal_intercept,
1164 (pthread_cond_t *cond), (cond));
1165 #else
1166 PTH_FUNCS(int, pthreadZucondZusignal, pthread_cond_signal_intercept,
1167 (pthread_cond_t* cond), (cond));
1168 #endif /* VGO_solaris */
1170 static __always_inline
1171 int pthread_cond_broadcast_intercept(pthread_cond_t* cond)
1173 int ret;
1174 OrigFn fn;
1175 VALGRIND_GET_ORIG_FN(fn);
1176 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_BROADCAST,
1177 cond, 0, 0, 0, 0);
1178 CALL_FN_W_W(ret, fn, cond);
1179 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_BROADCAST,
1180 cond, 0, 0, 0, 0);
1181 return ret;
1184 #if defined(VGO_solaris)
1185 /* On Solaris, pthread_cond_broadcast is a weak alias to cond_broadcast. */
1186 PTH_FUNCS(int, condZubroadcast, pthread_cond_broadcast_intercept,
1187 (pthread_cond_t *cond), (cond));
1188 #else
1189 PTH_FUNCS(int, pthreadZucondZubroadcast, pthread_cond_broadcast_intercept,
1190 (pthread_cond_t* cond), (cond));
1191 #endif /* VGO_solaris */
1193 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1194 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1195 static __always_inline
1196 int pthread_spin_init_intercept(pthread_spinlock_t *spinlock, int pshared)
1198 int ret;
1199 OrigFn fn;
1200 VALGRIND_GET_ORIG_FN(fn);
1201 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
1202 spinlock, 0, 0, 0, 0);
1203 CALL_FN_W_WW(ret, fn, spinlock, pshared);
1204 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
1205 spinlock, 0, 0, 0, 0);
1206 return ret;
1209 PTH_FUNCS(int, pthreadZuspinZuinit, pthread_spin_init_intercept,
1210 (pthread_spinlock_t *spinlock, int pshared), (spinlock, pshared));
1212 static __always_inline
1213 int pthread_spin_destroy_intercept(pthread_spinlock_t *spinlock)
1215 int ret;
1216 OrigFn fn;
1217 VALGRIND_GET_ORIG_FN(fn);
1218 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
1219 spinlock, 0, 0, 0, 0);
1220 CALL_FN_W_W(ret, fn, spinlock);
1221 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
1222 spinlock, mutex_type_spinlock, 0, 0, 0);
1223 return ret;
1226 PTH_FUNCS(int, pthreadZuspinZudestroy, pthread_spin_destroy_intercept,
1227 (pthread_spinlock_t *spinlock), (spinlock));
1229 static __always_inline
1230 int pthread_spin_lock_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_LOCK,
1236 spinlock, mutex_type_spinlock, 0, 0, 0);
1237 CALL_FN_W_W(ret, fn, spinlock);
1238 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
1239 spinlock, ret == 0, 0, 0, 0);
1240 return ret;
1243 PTH_FUNCS(int, pthreadZuspinZulock, pthread_spin_lock_intercept,
1244 (pthread_spinlock_t *spinlock), (spinlock));
1246 static __always_inline
1247 int pthread_spin_trylock_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, pthreadZuspinZutrylock, pthread_spin_trylock_intercept,
1261 (pthread_spinlock_t *spinlock), (spinlock));
1263 static __always_inline
1264 int pthread_spin_unlock_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_SPIN_INIT_OR_UNLOCK,
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_SPIN_INIT_OR_UNLOCK,
1273 spinlock, 0, 0, 0, 0);
1274 return ret;
1277 PTH_FUNCS(int, pthreadZuspinZuunlock, pthread_spin_unlock_intercept,
1278 (pthread_spinlock_t *spinlock), (spinlock));
1279 #endif // HAVE_PTHREAD_SPIN_LOCK
1282 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1283 static __always_inline
1284 int pthread_barrier_init_intercept(pthread_barrier_t* barrier,
1285 const pthread_barrierattr_t* attr,
1286 unsigned count)
1288 int ret;
1289 OrigFn fn;
1290 VALGRIND_GET_ORIG_FN(fn);
1291 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_INIT,
1292 barrier, pthread_barrier, count, 0, 0);
1293 CALL_FN_W_WWW(ret, fn, barrier, attr, count);
1294 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_INIT,
1295 barrier, pthread_barrier, 0, 0, 0);
1296 return ret;
1299 PTH_FUNCS(int, pthreadZubarrierZuinit, pthread_barrier_init_intercept,
1300 (pthread_barrier_t* barrier, const pthread_barrierattr_t* attr,
1301 unsigned count), (barrier, attr, count));
1303 static __always_inline
1304 int pthread_barrier_destroy_intercept(pthread_barrier_t* barrier)
1306 int ret;
1307 OrigFn fn;
1308 VALGRIND_GET_ORIG_FN(fn);
1309 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_DESTROY,
1310 barrier, pthread_barrier, 0, 0, 0);
1311 CALL_FN_W_W(ret, fn, barrier);
1312 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_DESTROY,
1313 barrier, pthread_barrier, 0, 0, 0);
1314 return ret;
1317 PTH_FUNCS(int, pthreadZubarrierZudestroy, pthread_barrier_destroy_intercept,
1318 (pthread_barrier_t* barrier), (barrier));
1320 static __always_inline
1321 int pthread_barrier_wait_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_WAIT,
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_WAIT,
1330 barrier, pthread_barrier,
1331 ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD,
1332 ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
1333 return ret;
1336 PTH_FUNCS(int, pthreadZubarrierZuwait, pthread_barrier_wait_intercept,
1337 (pthread_barrier_t* barrier), (barrier));
1338 #endif // HAVE_PTHREAD_BARRIER_INIT
1341 static __always_inline
1342 int sem_init_intercept(sem_t *sem, int pshared, unsigned int value)
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, pshared, value, 0, 0);
1349 CALL_FN_W_WWW(ret, fn, sem, pshared, value);
1350 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT,
1351 sem, 0, 0, 0, 0);
1352 return ret;
1355 PTH_FUNCS(int, semZuinit, sem_init_intercept,
1356 (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
1358 #if defined(VGO_solaris)
1359 static __always_inline
1360 int sema_init_intercept(sema_t *sem, unsigned int value, int type, void *arg)
1362 int ret;
1363 OrigFn fn;
1364 VALGRIND_GET_ORIG_FN(fn);
1365 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT,
1366 sem, type == USYNC_PROCESS ? 1 : 0,
1367 value, 0, 0);
1368 CALL_FN_W_WWWW(ret, fn, sem, value, type, arg);
1369 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT,
1370 sem, 0, 0, 0, 0);
1371 return ret;
1374 PTH_FUNCS(int, semaZuinit, sema_init_intercept,
1375 (sema_t *sem, unsigned int value, int type, void *arg),
1376 (sem, value, type, arg));
1377 #endif /* VGO_solaris */
1379 static __always_inline
1380 int sem_destroy_intercept(sem_t *sem)
1382 int ret;
1383 OrigFn fn;
1384 VALGRIND_GET_ORIG_FN(fn);
1385 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_DESTROY,
1386 sem, 0, 0, 0, 0);
1387 CALL_FN_W_W(ret, fn, sem);
1388 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_DESTROY,
1389 sem, 0, 0, 0, 0);
1390 return ret;
1393 PTH_FUNCS(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1394 #if defined(VGO_solaris)
1395 PTH_FUNCS(int, semaZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1396 #endif /* VGO_solaris */
1398 static __always_inline
1399 sem_t* sem_open_intercept(const char *name, int oflag, mode_t mode,
1400 unsigned int value)
1402 sem_t *ret;
1403 OrigFn fn;
1404 VALGRIND_GET_ORIG_FN(fn);
1405 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_OPEN,
1406 name, oflag, mode, value, 0);
1407 CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value);
1408 // To do: figure out why gcc 9.2.1 miscompiles this function if the printf()
1409 // call below is left out.
1410 printf("");
1411 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_OPEN,
1412 ret != SEM_FAILED ? ret : 0,
1413 name, oflag, mode, value);
1414 return ret;
1417 PTH_FUNCS(sem_t *, semZuopen, sem_open_intercept,
1418 (const char *name, int oflag, mode_t mode, unsigned int value),
1419 (name, oflag, mode, value));
1421 static __always_inline int sem_close_intercept(sem_t *sem)
1423 int ret;
1424 OrigFn fn;
1425 VALGRIND_GET_ORIG_FN(fn);
1426 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_CLOSE,
1427 sem, 0, 0, 0, 0);
1428 CALL_FN_W_W(ret, fn, sem);
1429 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_CLOSE,
1430 sem, 0, 0, 0, 0);
1431 return ret;
1434 PTH_FUNCS(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
1436 static __always_inline int sem_wait_intercept(sem_t *sem)
1438 int ret;
1439 OrigFn fn;
1440 VALGRIND_GET_ORIG_FN(fn);
1441 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1442 sem, 0, 0, 0, 0);
1443 CALL_FN_W_W(ret, fn, sem);
1444 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1445 sem, ret == 0, 0, 0, 0);
1446 return ret;
1449 PTH_FUNCS(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1450 #if defined(VGO_solaris)
1451 PTH_FUNCS(int, semaZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1452 #endif /* VGO_solaris */
1454 static __always_inline int sem_trywait_intercept(sem_t *sem)
1456 int ret;
1457 OrigFn fn;
1458 VALGRIND_GET_ORIG_FN(fn);
1459 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1460 sem, 0, 0, 0, 0);
1461 CALL_FN_W_W(ret, fn, sem);
1462 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1463 sem, ret == 0, 0, 0, 0);
1464 return ret;
1467 PTH_FUNCS(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1468 #if defined(VGO_solaris)
1469 PTH_FUNCS(int, semaZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1470 #endif /* VGO_solaris */
1472 static __always_inline
1473 int sem_timedwait_intercept(sem_t *sem, const struct timespec *abs_timeout)
1475 int ret;
1476 OrigFn fn;
1477 VALGRIND_GET_ORIG_FN(fn);
1478 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1479 sem, 0, 0, 0, 0);
1480 CALL_FN_W_WW(ret, fn, sem, abs_timeout);
1481 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1482 sem, ret == 0, 0, 0, 0);
1483 return ret;
1486 PTH_FUNCS(int, semZutimedwait, sem_timedwait_intercept,
1487 (sem_t *sem, const struct timespec *abs_timeout),
1488 (sem, abs_timeout));
1489 #if defined(VGO_solaris)
1490 PTH_FUNCS(int, semaZutimedwait, sem_timedwait_intercept,
1491 (sem_t *sem, const struct timespec *timeout),
1492 (sem, timeout));
1493 PTH_FUNCS(int, semaZureltimedwait, sem_timedwait_intercept,
1494 (sem_t *sem, const struct timespec *timeout),
1495 (sem, timeout));
1496 #endif /* VGO_solaris */
1498 static __always_inline int sem_post_intercept(sem_t *sem)
1500 int ret;
1501 OrigFn fn;
1502 VALGRIND_GET_ORIG_FN(fn);
1503 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_POST,
1504 sem, 0, 0, 0, 0);
1505 CALL_FN_W_W(ret, fn, sem);
1506 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_POST,
1507 sem, ret == 0, 0, 0, 0);
1508 return ret;
1511 PTH_FUNCS(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
1512 #if defined(VGO_solaris)
1513 PTH_FUNCS(int, semaZupost, sem_post_intercept, (sem_t *sem), (sem));
1514 #endif /* VGO_solaris */
1516 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1517 functions have to be conditionally compiled. */
1518 #if defined(HAVE_PTHREAD_RWLOCK_T)
1520 static __always_inline
1521 int pthread_rwlock_init_intercept(pthread_rwlock_t* rwlock,
1522 const pthread_rwlockattr_t* attr)
1524 int ret;
1525 OrigFn fn;
1526 VALGRIND_GET_ORIG_FN(fn);
1527 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT,
1528 rwlock, 0, 0, 0, 0);
1529 CALL_FN_W_WW(ret, fn, rwlock, attr);
1530 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT,
1531 rwlock, 0, 0, 0, 0);
1532 return ret;
1535 PTH_FUNCS(int,
1536 pthreadZurwlockZuinit, pthread_rwlock_init_intercept,
1537 (pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr),
1538 (rwlock, attr));
1540 #if defined(VGO_solaris)
1541 static __always_inline
1542 int rwlock_init_intercept(rwlock_t *rwlock, int type, void *arg)
1544 int ret;
1545 OrigFn fn;
1546 VALGRIND_GET_ORIG_FN(fn);
1547 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT,
1548 rwlock, 0, 0, 0, 0);
1549 CALL_FN_W_WWW(ret, fn, rwlock, type, arg);
1550 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT,
1551 rwlock, 0, 0, 0, 0);
1552 return ret;
1555 PTH_FUNCS(int, rwlockZuinit, rwlock_init_intercept,
1556 (rwlock_t *rwlock, int type, void *arg),
1557 (rwlock, type, arg));
1558 #endif /* VGO_solaris */
1560 static __always_inline
1561 int pthread_rwlock_destroy_intercept(pthread_rwlock_t* rwlock)
1563 int ret;
1564 OrigFn fn;
1565 VALGRIND_GET_ORIG_FN(fn);
1566 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_DESTROY,
1567 rwlock, 0, 0, 0, 0);
1568 CALL_FN_W_W(ret, fn, rwlock);
1569 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_DESTROY,
1570 rwlock, 0, 0, 0, 0);
1571 return ret;
1574 #if defined(VGO_solaris)
1575 /* On Solaris, pthread_rwlock_destroy is a weak alias to rwlock_destroy. */
1576 PTH_FUNCS(int,
1577 rwlockZudestroy, pthread_rwlock_destroy_intercept,
1578 (pthread_rwlock_t *rwlock), (rwlock));
1579 #else
1580 PTH_FUNCS(int,
1581 pthreadZurwlockZudestroy, pthread_rwlock_destroy_intercept,
1582 (pthread_rwlock_t* rwlock), (rwlock));
1583 #endif /* VGO_solaris */
1585 static __always_inline
1586 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t* rwlock)
1588 int ret;
1589 OrigFn fn;
1590 VALGRIND_GET_ORIG_FN(fn);
1591 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1592 rwlock, 0, 0, 0, 0);
1593 CALL_FN_W_W(ret, fn, rwlock);
1594 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1595 rwlock, ret == 0, 0, 0, 0);
1596 return ret;
1599 #if defined(VGO_solaris)
1600 /* On Solaris, pthread_rwlock_rdlock is a weak alias to rw_rdlock. */
1601 PTH_FUNCS(int,
1602 rwZurdlock, pthread_rwlock_rdlock_intercept,
1603 (pthread_rwlock_t *rwlock), (rwlock));
1604 #else
1605 PTH_FUNCS(int,
1606 pthreadZurwlockZurdlock, pthread_rwlock_rdlock_intercept,
1607 (pthread_rwlock_t* rwlock), (rwlock));
1608 #endif /* VGO_solaris */
1610 #if defined(VGO_solaris)
1611 /* Internal to libc. */
1612 static __always_inline
1613 void lrw_rdlock_intercept(rwlock_t *rwlock)
1615 OrigFn fn;
1616 VALGRIND_GET_ORIG_FN(fn);
1617 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1618 rwlock, 0, 0, 0, 0);
1619 CALL_FN_v_W(fn, rwlock);
1620 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1621 rwlock, True /* took_lock */, 0, 0, 0);
1624 PTH_FUNCS(void, lrwZurdlock, lrw_rdlock_intercept,
1625 (rwlock_t *rwlock), (rwlock));
1626 #endif /* VGO_solaris */
1628 static __always_inline
1629 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t* rwlock)
1631 int ret;
1632 OrigFn fn;
1633 VALGRIND_GET_ORIG_FN(fn);
1634 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1635 rwlock, 0, 0, 0, 0);
1636 CALL_FN_W_W(ret, fn, rwlock);
1637 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1638 rwlock, ret == 0, 0, 0, 0);
1639 return ret;
1642 #if defined(VGO_solaris)
1643 /* On Solaris, pthread_rwlock_wrlock is a weak alias to rw_wrlock. */
1644 PTH_FUNCS(int,
1645 rwZuwrlock, pthread_rwlock_wrlock_intercept,
1646 (pthread_rwlock_t *rwlock), (rwlock));
1647 #else
1648 PTH_FUNCS(int,
1649 pthreadZurwlockZuwrlock, pthread_rwlock_wrlock_intercept,
1650 (pthread_rwlock_t* rwlock), (rwlock));
1651 #endif /* VGO_solaris */
1653 #if defined(VGO_solaris)
1654 /* Internal to libc. */
1655 static __always_inline
1656 void lrw_wrlock_intercept(rwlock_t *rwlock)
1658 OrigFn fn;
1659 VALGRIND_GET_ORIG_FN(fn);
1660 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1661 rwlock, 0, 0, 0, 0);
1662 CALL_FN_v_W(fn, rwlock);
1663 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1664 rwlock, True /* took_lock */, 0, 0, 0);
1667 PTH_FUNCS(void, lrwZuwrlock, lrw_wrlock_intercept,
1668 (rwlock_t *rwlock), (rwlock));
1669 #endif /* VGO_solaris */
1671 static __always_inline
1672 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t* rwlock,
1673 const struct timespec *timeout)
1675 int ret;
1676 OrigFn fn;
1677 VALGRIND_GET_ORIG_FN(fn);
1678 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1679 rwlock, 0, 0, 0, 0);
1680 CALL_FN_W_WW(ret, fn, rwlock, timeout);
1681 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1682 rwlock, ret == 0, 0, 0, 0);
1683 return ret;
1686 PTH_FUNCS(int,
1687 pthreadZurwlockZutimedrdlock, pthread_rwlock_timedrdlock_intercept,
1688 (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1689 (rwlock, timeout));
1690 #if defined(VGO_solaris)
1691 PTH_FUNCS(int, pthreadZurwlockZureltimedrdlockZunp,
1692 pthread_rwlock_timedrdlock_intercept,
1693 (pthread_rwlock_t *rwlock, const struct timespec *timeout),
1694 (rwlock, timeout));
1695 #endif /* VGO_solaris */
1697 static __always_inline
1698 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t* rwlock,
1699 const struct timespec *timeout)
1701 int ret;
1702 OrigFn fn;
1703 VALGRIND_GET_ORIG_FN(fn);
1704 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1705 rwlock, 0, 0, 0, 0);
1706 CALL_FN_W_WW(ret, fn, rwlock, timeout);
1707 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1708 rwlock, ret == 0, 0, 0, 0);
1709 return ret;
1712 PTH_FUNCS(int,
1713 pthreadZurwlockZutimedwrlock, pthread_rwlock_timedwrlock_intercept,
1714 (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1715 (rwlock, timeout));
1716 #if defined(VGO_solaris)
1717 PTH_FUNCS(int, pthreadZurwlockZureltimedwrlockZunp,
1718 pthread_rwlock_timedwrlock_intercept,
1719 (pthread_rwlock_t *rwlock, const struct timespec *timeout),
1720 (rwlock, timeout));
1721 #endif /* VGO_solaris */
1723 static __always_inline
1724 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t* rwlock)
1726 int ret;
1727 OrigFn fn;
1728 VALGRIND_GET_ORIG_FN(fn);
1729 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1730 rwlock, 0, 0, 0, 0);
1731 CALL_FN_W_W(ret, fn, rwlock);
1732 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1733 rwlock, ret == 0, 0, 0, 0);
1734 return ret;
1737 #if defined(VGO_solaris)
1738 /* On Solaris, pthread_rwlock_tryrdlock is a weak alias to rw_tryrdlock. */
1739 PTH_FUNCS(int,
1740 rwZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1741 (pthread_rwlock_t *rwlock), (rwlock));
1742 #else
1743 PTH_FUNCS(int,
1744 pthreadZurwlockZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1745 (pthread_rwlock_t* rwlock), (rwlock));
1746 #endif /* VGO_solaris */
1748 static __always_inline
1749 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t* rwlock)
1751 int ret;
1752 OrigFn fn;
1753 VALGRIND_GET_ORIG_FN(fn);
1754 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1755 rwlock, 0, 0, 0, 0);
1756 CALL_FN_W_W(ret, fn, rwlock);
1757 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1758 rwlock, ret == 0, 0, 0, 0);
1759 return ret;
1762 #if defined(VGO_solaris)
1763 /* On Solaris, pthread_rwlock_trywrlock is a weak alias to rw_trywrlock. */
1764 PTH_FUNCS(int,
1765 rwZutrywrlock, pthread_rwlock_trywrlock_intercept,
1766 (pthread_rwlock_t *rwlock), (rwlock));
1767 #else
1768 PTH_FUNCS(int,
1769 pthreadZurwlockZutrywrlock, pthread_rwlock_trywrlock_intercept,
1770 (pthread_rwlock_t* rwlock), (rwlock));
1771 #endif /* VGO_solaris */
1773 static __always_inline
1774 int pthread_rwlock_unlock_intercept(pthread_rwlock_t* rwlock)
1776 int ret;
1777 OrigFn fn;
1778 VALGRIND_GET_ORIG_FN(fn);
1779 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_UNLOCK,
1780 rwlock, 0, 0, 0, 0);
1781 CALL_FN_W_W(ret, fn, rwlock);
1782 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_UNLOCK,
1783 rwlock, ret == 0, 0, 0, 0);
1784 return ret;
1787 #if defined(VGO_solaris)
1788 /* On Solaris, pthread_rwlock_unlock is a weak alias to rw_unlock. */
1789 PTH_FUNCS(int,
1790 rwZuunlock, pthread_rwlock_unlock_intercept,
1791 (pthread_rwlock_t *rwlock), (rwlock));
1792 #else
1793 PTH_FUNCS(int,
1794 pthreadZurwlockZuunlock, pthread_rwlock_unlock_intercept,
1795 (pthread_rwlock_t* rwlock), (rwlock));
1796 #endif /* VGO_solaris */
1798 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */