drd: Update copyright notices
[valgrind.git] / drd / drd_pthread_intercepts.c
blob62c466f508ad3a4365ccd431cab9289eff452267
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 #ifdef VGO_darwin
155 static int never_true;
156 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
157 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
158 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
160 ret_ty pth_func_result = implf argl; \
161 /* Apparently inserting a function call in wrapper functions */ \
162 /* is sufficient to avoid misaligned stack errors. */ \
163 if (never_true) \
164 fflush(stdout); \
165 return pth_func_result; \
167 #elif defined(VGO_solaris)
168 /* On Solaris, libpthread is just a filter library on top of libc.
169 * Threading and synchronization functions in runtime linker are not
170 * intercepted.
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 #else
178 * On Linux, intercept both the libc and the libpthread functions. At
179 * least glibc 2.32.9000 (Fedora 34) has an implementation of all pthread
180 * functions in both libc and libpthread. Older glibc versions only have an
181 * implementation of the pthread functions in libpthread.
183 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
184 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl; \
185 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl \
186 { return implf 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 pthread_cond_t cond;
222 int counter;
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_pthread_id)(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_pthread_id)();
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 pthread_cond_init(&sema->cond, NULL);
284 sema->counter = 0;
287 static void DRD_(sema_destroy)(DrdSema* sema)
289 pthread_mutex_destroy(&sema->mutex);
290 pthread_cond_destroy(&sema->cond);
293 static void DRD_(sema_down)(DrdSema* sema)
295 pthread_mutex_lock(&sema->mutex);
296 while (sema->counter == 0)
297 pthread_cond_wait(&sema->cond, &sema->mutex);
298 sema->counter--;
299 pthread_mutex_unlock(&sema->mutex);
302 static void DRD_(sema_up)(DrdSema* sema)
304 pthread_mutex_lock(&sema->mutex);
305 sema->counter++;
306 pthread_cond_signal(&sema->cond);
307 pthread_mutex_unlock(&sema->mutex);
311 * POSIX threads and DRD each have their own mutex type identification.
312 * Convert POSIX threads' mutex type to DRD's mutex type. In the code below
313 * if-statements are used to test the value of 'kind' instead of a switch
314 * statement because some of the PTHREAD_MUTEX_ macro's may have the same
315 * value.
317 static MutexT DRD_(pthread_to_drd_mutex_type)(int kind)
320 * See also PTHREAD_MUTEX_KIND_MASK_NP in glibc source file
321 * <nptl/pthreadP.h>.
323 kind &= PTHREAD_MUTEX_RECURSIVE | PTHREAD_MUTEX_ERRORCHECK |
324 PTHREAD_MUTEX_NORMAL | PTHREAD_MUTEX_DEFAULT;
326 if (kind == PTHREAD_MUTEX_RECURSIVE)
327 return mutex_type_recursive_mutex;
328 else if (kind == PTHREAD_MUTEX_ERRORCHECK)
329 return mutex_type_errorcheck_mutex;
330 else if (kind == PTHREAD_MUTEX_NORMAL)
331 return mutex_type_default_mutex;
332 else if (kind == PTHREAD_MUTEX_DEFAULT)
333 return mutex_type_default_mutex;
334 #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
335 else if (kind == PTHREAD_MUTEX_ADAPTIVE_NP)
336 return mutex_type_default_mutex;
337 #endif
338 else
339 return mutex_type_invalid_mutex;
342 #if defined(VGO_solaris)
344 * Solaris threads and DRD each have their own mutex type identification.
345 * Convert Solaris threads' mutex type to DRD's mutex type.
347 static MutexT DRD_(thread_to_drd_mutex_type)(int type)
349 if (type & LOCK_RECURSIVE) {
350 return mutex_type_recursive_mutex;
351 } else if (type & LOCK_ERRORCHECK) {
352 return mutex_type_errorcheck_mutex;
353 } else {
354 return mutex_type_default_mutex;
357 #endif /* VGO_solaris */
359 #define IS_ALIGNED(p) (((uintptr_t)(p) & (sizeof(*(p)) - 1)) == 0)
362 * Read the mutex type stored in the client memory used for the mutex
363 * implementation.
365 * @note This function depends on the implementation of the POSIX threads
366 * library -- the POSIX standard does not define the name of the member in
367 * which the mutex type is stored.
368 * @note The function mutex_type() has been declared inline in order
369 * to avoid that it shows up in call stacks (drd/tests/...exp* files).
370 * @note glibc stores the mutex type in the lowest two bits, and uses the
371 * higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
372 * PTHREAD_MUTEXATTR_FLAG_PSHARED.
374 static __always_inline MutexT DRD_(mutex_type)(pthread_mutex_t* mutex)
376 MutexT mutex_type = mutex_type_unknown;
378 ANNOTATE_IGNORE_READS_BEGIN();
379 #if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
380 /* glibc + LinuxThreads. */
381 if (IS_ALIGNED(&mutex->__m_kind))
383 const int kind = mutex->__m_kind & 3;
384 mutex_type = DRD_(pthread_to_drd_mutex_type)(kind);
386 #elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
387 /* glibc + NPTL. */
388 if (IS_ALIGNED(&mutex->__data.__kind))
390 const int kind = mutex->__data.__kind & 3;
391 mutex_type = DRD_(pthread_to_drd_mutex_type)(kind);
393 #elif defined(VGO_solaris)
395 const int type = ((mutex_t *) mutex)->vki_mutex_type;
396 mutex_type = DRD_(thread_to_drd_mutex_type)(type);
398 #else
400 * Another POSIX threads implementation. The mutex type won't be printed
401 * when enabling --trace-mutex=yes.
403 #endif
404 ANNOTATE_IGNORE_READS_END();
406 return mutex_type;
410 * Tell DRD whether 'tid' is a joinable thread or a detached thread.
412 static void DRD_(set_joinable)(const pthread_t tid, const int joinable)
414 assert(joinable == 0 || joinable == 1);
415 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_JOINABLE,
416 tid, joinable, 0, 0, 0);
419 /** Tell DRD that the calling thread is about to enter pthread_create(). */
420 static __always_inline void DRD_(entering_pthread_create)(void)
422 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__ENTERING_PTHREAD_CREATE,
423 0, 0, 0, 0, 0);
426 /** Tell DRD that the calling thread has left pthread_create(). */
427 static __always_inline void DRD_(left_pthread_create)(void)
429 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LEFT_PTHREAD_CREATE,
430 0, 0, 0, 0, 0);
434 * Entry point for newly created threads. This function is called from the
435 * thread created by pthread_create().
437 static void* DRD_(thread_wrapper)(void* arg)
439 DrdPosixThreadArgs* arg_ptr;
440 DrdPosixThreadArgs arg_copy;
442 arg_ptr = (DrdPosixThreadArgs*)arg;
443 arg_copy = *arg_ptr;
445 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
446 pthread_self(), 0, 0, 0, 0);
448 DRD_(set_joinable)(pthread_self(),
449 arg_copy.detachstate == PTHREAD_CREATE_JOINABLE);
452 * Only set 'wrapper_started' after VG_USERREQ__SET_PTHREADID and
453 * DRD_(set_joinable)() have been invoked to avoid a race with
454 * a pthread_detach() invocation for this thread from another thread.
456 DRD_(sema_up)(arg_copy.wrapper_started);
458 return (arg_copy.start)(arg_copy.arg);
462 * Return 1 if the LinuxThreads implementation of POSIX Threads has been
463 * detected, and 0 otherwise.
465 * @see For more information about the confstr() function, see also
466 * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
468 static int DRD_(detected_linuxthreads)(void)
470 #if defined(linux)
471 #if defined(_CS_GNU_LIBPTHREAD_VERSION)
472 /* Linux with a recent glibc. */
473 HChar buffer[256];
474 unsigned len;
475 len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
476 assert(len <= sizeof(buffer));
477 return len > 0 && buffer[0] == 'l';
478 #else
479 /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
480 return 1;
481 #endif
482 #else
483 /* Another OS than Linux, hence no LinuxThreads. */
484 return 0;
485 #endif
489 * Stop and print an error message in case a non-supported threading
490 * library implementation (LinuxThreads) has been detected.
492 static void DRD_(check_threading_library)(void)
494 if (DRD_(detected_linuxthreads)())
496 if (getenv("LD_ASSUME_KERNEL"))
498 fprintf(stderr,
499 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
500 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
501 "after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
504 else
506 fprintf(stderr,
507 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
508 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
509 "after having upgraded to a newer version of your Linux distribution.\n"
510 "Giving up.\n"
513 abort();
518 * Update DRD's state information about the current thread.
520 static void DRD_(set_pthread_id)(void)
522 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
523 pthread_self(), 0, 0, 0, 0);
527 * Note: as of today there exist three different versions of pthread_create
528 * in Linux:
529 * - pthread_create@GLIBC_2.0
530 * - pthread_create@@GLIBC_2.1
531 * - pthread_create@@GLIBC_2.2.5
532 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
533 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
534 * versions have been implemented. In any glibc version where more than one
535 * pthread_create function has been implemented, older versions call the
536 * newer versions. Or: the pthread_create* wrapper defined below can be
537 * called recursively. Any code in this wrapper should take this in account.
538 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
539 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
540 * See also the implementation of pthread_create@GLIBC_2.0 in
541 * glibc-2.9/nptl/pthread_create.c.
544 static __always_inline
545 int pthread_create_intercept(pthread_t* thread, const pthread_attr_t* attr,
546 void* (*start)(void*), void* arg)
548 int ret;
549 OrigFn fn;
550 DrdSema wrapper_started;
551 DrdPosixThreadArgs thread_args;
553 VALGRIND_GET_ORIG_FN(fn);
555 DRD_(sema_init)(&wrapper_started);
556 thread_args.start = start;
557 thread_args.arg = arg;
558 thread_args.wrapper_started = &wrapper_started;
560 * Find out whether the thread will be started as a joinable thread
561 * or as a detached thread. If no thread attributes have been specified,
562 * this means that the new thread will be started as a joinable thread.
564 thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
565 if (attr)
567 if (pthread_attr_getdetachstate(attr, &thread_args.detachstate) != 0)
568 assert(0);
570 assert(thread_args.detachstate == PTHREAD_CREATE_JOINABLE
571 || thread_args.detachstate == PTHREAD_CREATE_DETACHED);
574 * The DRD_(set_pthread_id)() from DRD_(init)() may encounter that
575 * pthread_self() == 0, e.g. when the main program is not linked with the
576 * pthread library and when a pthread_create() call occurs from within a
577 * shared library. Hence call DRD_(set_pthread_id)() again to ensure that
578 * DRD knows the identity of the current thread. See also B.Z. 356374.
580 DRD_(set_pthread_id)();
581 DRD_(entering_pthread_create)();
582 CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), &thread_args);
583 DRD_(left_pthread_create)();
585 if (ret == 0) {
586 /* Wait until the thread wrapper started. */
587 DRD_(sema_down)(&wrapper_started);
590 DRD_(sema_destroy)(&wrapper_started);
592 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT,
593 pthread_self(), 0, 0, 0, 0);
595 return ret;
598 PTH_FUNCS(int, pthreadZucreate, pthread_create_intercept,
599 (pthread_t *thread, const pthread_attr_t *attr,
600 void *(*start) (void *), void *arg),
601 (thread, attr, start, arg));
603 #if defined(VGO_solaris)
604 /* Solaris also provides thr_create() in addition to pthread_create().
605 * Both pthread_create(3C) and thr_create(3C) are based on private
606 * _thrp_create().
608 static __always_inline
609 int thr_create_intercept(void *stk, size_t stksize, void *(*start)(void *),
610 void *arg, long flags, thread_t *new_thread)
612 int ret;
613 OrigFn fn;
614 DrdSema wrapper_started;
615 DrdPosixThreadArgs thread_args;
617 VALGRIND_GET_ORIG_FN(fn);
619 DRD_(sema_init)(&wrapper_started);
620 thread_args.start = start;
621 thread_args.arg = arg;
622 thread_args.wrapper_started = &wrapper_started;
624 * Find out whether the thread will be started as a joinable thread
625 * or as a detached thread.
627 if (flags & THR_DETACHED)
628 thread_args.detachstate = PTHREAD_CREATE_DETACHED;
629 else
630 thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
632 DRD_(entering_pthread_create)();
633 CALL_FN_W_6W(ret, fn, stk, stksize, DRD_(thread_wrapper), &thread_args,
634 flags, new_thread);
635 DRD_(left_pthread_create)();
637 if (ret == 0) {
638 /* Wait until the thread wrapper started. */
639 DRD_(sema_down)(&wrapper_started);
642 DRD_(sema_destroy)(&wrapper_started);
644 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT,
645 pthread_self(), 0, 0, 0, 0);
647 return ret;
650 PTH_FUNCS(int, thrZucreate, thr_create_intercept,
651 (void *stk, size_t stksize, void *(*start)(void *), void *arg,
652 long flags, thread_t *new_thread),
653 (stk, stksize, start, arg, flags, new_thread));
654 #endif /* VGO_solaris */
656 #if defined(VGO_solaris)
658 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
659 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
660 * and CI_BIND_CLEAR, to provide resilience against function renaming.
662 static __always_inline
663 int DRD_(_ti_bind_guard_intercept)(int flags) {
664 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_GUARD,
665 flags, 0, 0, 0, 0);
666 return DRD_(rtld_bind_guard)(flags);
669 static __always_inline
670 int DRD_(_ti_bind_clear_intercept)(int flags) {
671 int ret = DRD_(rtld_bind_clear)(flags);
672 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_CLEAR,
673 flags, 0, 0, 0, 0);
674 return ret;
678 * Wrapped _ld_libc() from the runtime linker ld.so.1.
680 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr);
681 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr)
683 OrigFn fn;
684 int tag;
686 VALGRIND_GET_ORIG_FN(fn);
688 vki_Lc_interface *funcs = ptr;
689 for (tag = funcs->ci_tag; tag != 0; tag = (++funcs)->ci_tag) {
690 switch (tag) {
691 case VKI_CI_BIND_GUARD:
692 if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_guard_intercept)) {
693 DRD_(rtld_bind_guard) = funcs->vki_ci_un.ci_func;
694 funcs->vki_ci_un.ci_func = DRD_(_ti_bind_guard_intercept);
696 break;
697 case VKI_CI_BIND_CLEAR:
698 if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_clear_intercept)) {
699 DRD_(rtld_bind_clear) = funcs->vki_ci_un.ci_func;
700 funcs->vki_ci_un.ci_func = DRD_(_ti_bind_clear_intercept);
702 break;
706 CALL_FN_v_W(fn, ptr);
708 #endif /* VGO_solaris */
710 static __always_inline
711 int pthread_join_intercept(pthread_t pt_joinee, void **thread_return)
713 int ret;
714 OrigFn fn;
716 VALGRIND_GET_ORIG_FN(fn);
718 * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
719 * implementation triggers a (false positive) race report.
721 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
722 CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
723 if (ret == 0)
725 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN,
726 pt_joinee, 0, 0, 0, 0);
728 ANNOTATE_IGNORE_READS_AND_WRITES_END();
729 return ret;
732 PTH_FUNCS(int, pthreadZujoin, pthread_join_intercept,
733 (pthread_t pt_joinee, void **thread_return),
734 (pt_joinee, thread_return));
736 #if defined(VGO_solaris)
737 /* Solaris also provides thr_join() in addition to pthread_join().
738 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
740 * :TODO: No functionality is currently provided for joinee == 0 and departed.
741 * This would require another client request, of course.
743 static __always_inline
744 int thr_join_intercept(thread_t joinee, thread_t *departed, void **thread_return)
746 int ret;
747 OrigFn fn;
749 VALGRIND_GET_ORIG_FN(fn);
750 CALL_FN_W_WWW(ret, fn, joinee, departed, thread_return);
751 if (ret == 0)
753 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN,
754 joinee, 0, 0, 0, 0);
756 return ret;
759 PTH_FUNCS(int, thrZujoin, thr_join_intercept,
760 (thread_t joinee, thread_t *departed, void **thread_return),
761 (joinee, departed, thread_return));
762 #endif /* VGO_solaris */
764 static __always_inline
765 int pthread_detach_intercept(pthread_t pt_thread)
767 int ret;
768 OrigFn fn;
770 VALGRIND_GET_ORIG_FN(fn);
771 CALL_FN_W_W(ret, fn, pt_thread);
772 DRD_(set_joinable)(pt_thread, 0);
774 return ret;
777 PTH_FUNCS(int, pthreadZudetach, pthread_detach_intercept,
778 (pthread_t thread), (thread));
780 // NOTE: be careful to intercept only pthread_cancel() and not
781 // pthread_cancel_init() on Linux.
783 static __always_inline
784 int pthread_cancel_intercept(pthread_t pt_thread)
786 int ret;
787 OrigFn fn;
788 VALGRIND_GET_ORIG_FN(fn);
789 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_THREAD_CANCEL,
790 pt_thread, 0, 0, 0, 0);
791 CALL_FN_W_W(ret, fn, pt_thread);
792 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_CANCEL,
793 pt_thread, ret==0, 0, 0, 0);
794 return ret;
797 PTH_FUNCS(int, pthreadZucancel, pthread_cancel_intercept,
798 (pthread_t thread), (thread))
800 static __always_inline
801 int pthread_once_intercept(pthread_once_t *once_control,
802 void (*init_routine)(void))
804 int ret;
805 OrigFn fn;
806 VALGRIND_GET_ORIG_FN(fn);
808 * Ignore any data races triggered by the implementation of pthread_once().
809 * Necessary for Darwin. This is not necessary for Linux but doesn't have
810 * any known adverse effects.
812 DRD_IGNORE_VAR(*once_control);
813 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
814 CALL_FN_W_WW(ret, fn, once_control, init_routine);
815 ANNOTATE_IGNORE_READS_AND_WRITES_END();
816 DRD_STOP_IGNORING_VAR(*once_control);
817 return ret;
820 PTH_FUNCS(int, pthreadZuonce, pthread_once_intercept,
821 (pthread_once_t *once_control, void (*init_routine)(void)),
822 (once_control, init_routine));
824 static __always_inline
825 int pthread_mutex_init_intercept(pthread_mutex_t *mutex,
826 const pthread_mutexattr_t* attr)
828 int ret;
829 OrigFn fn;
830 int mt;
831 VALGRIND_GET_ORIG_FN(fn);
832 mt = PTHREAD_MUTEX_DEFAULT;
833 if (attr)
834 pthread_mutexattr_gettype(attr, &mt);
835 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
836 mutex, DRD_(pthread_to_drd_mutex_type)(mt),
837 0, 0, 0);
838 CALL_FN_W_WW(ret, fn, mutex, attr);
839 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
840 mutex, 0, 0, 0, 0);
841 return ret;
844 PTH_FUNCS(int, pthreadZumutexZuinit, pthread_mutex_init_intercept,
845 (pthread_mutex_t *mutex, const pthread_mutexattr_t* attr),
846 (mutex, attr));
848 #if defined(VGO_solaris)
849 static __always_inline
850 int mutex_init_intercept(mutex_t *mutex, int type, void *arg)
852 int ret;
853 OrigFn fn;
854 VALGRIND_GET_ORIG_FN(fn);
856 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
857 mutex, DRD_(thread_to_drd_mutex_type)(type),
858 0, 0, 0);
859 CALL_FN_W_WWW(ret, fn, mutex, type, arg);
860 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
861 mutex, 0, 0, 0, 0);
862 return ret;
865 PTH_FUNCS(int, mutexZuinit, mutex_init_intercept,
866 (mutex_t *mutex, int type, void *arg),
867 (mutex, type, arg));
868 #endif /* VGO_solaris */
870 static __always_inline
871 int pthread_mutex_destroy_intercept(pthread_mutex_t* mutex)
873 int ret;
874 OrigFn fn;
875 VALGRIND_GET_ORIG_FN(fn);
876 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
877 mutex, 0, 0, 0, 0);
878 CALL_FN_W_W(ret, fn, mutex);
879 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
880 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
881 return ret;
884 #if defined(VGO_solaris)
885 /* On Solaris, pthread_mutex_destroy is a weak alias to mutex_destroy. */
886 PTH_FUNCS(int, mutexZudestroy, pthread_mutex_destroy_intercept,
887 (pthread_mutex_t *mutex), (mutex));
888 #else
889 PTH_FUNCS(int, pthreadZumutexZudestroy, pthread_mutex_destroy_intercept,
890 (pthread_mutex_t *mutex), (mutex));
891 #endif /* VGO_solaris */
893 static __always_inline
894 int pthread_mutex_lock_intercept(pthread_mutex_t* mutex)
896 int ret;
897 OrigFn fn;
898 VALGRIND_GET_ORIG_FN(fn);
899 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
900 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
901 CALL_FN_W_W(ret, fn, mutex);
902 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
903 mutex, ret == 0, 0, 0, 0);
904 return ret;
907 #if defined(VGO_solaris)
908 /* On Solaris, pthread_mutex_lock is a weak alias to mutex_lock. */
909 PTH_FUNCS(int, mutexZulock, pthread_mutex_lock_intercept,
910 (pthread_mutex_t *mutex), (mutex));
911 #else
912 PTH_FUNCS(int, pthreadZumutexZulock, pthread_mutex_lock_intercept,
913 (pthread_mutex_t *mutex), (mutex));
914 #endif /* VGO_solaris */
916 #if defined(VGO_solaris)
917 /* Internal to libc. Mutex is usually initialized only implicitly,
918 * by zeroing mutex_t structure.
920 static __always_inline
921 void lmutex_lock_intercept(mutex_t *mutex)
923 OrigFn fn;
924 VALGRIND_GET_ORIG_FN(fn);
925 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
926 mutex,
927 DRD_(mutex_type)((pthread_mutex_t *) mutex),
928 False /* try_lock */, 0, 0);
929 CALL_FN_v_W(fn, mutex);
930 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
931 mutex, True /* took_lock */, 0, 0, 0);
934 PTH_FUNCS(void, lmutexZulock, lmutex_lock_intercept,
935 (mutex_t *mutex), (mutex));
936 #endif /* VGO_solaris */
938 static __always_inline
939 int pthread_mutex_trylock_intercept(pthread_mutex_t* mutex)
941 int ret;
942 OrigFn fn;
943 VALGRIND_GET_ORIG_FN(fn);
944 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
945 mutex, DRD_(mutex_type)(mutex), 1, 0, 0);
946 CALL_FN_W_W(ret, fn, mutex);
947 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
948 mutex, ret == 0, 0, 0, 0);
949 return ret;
952 #if defined(VGO_solaris)
953 /* On Solaris, pthread_mutex_trylock is a weak alias to mutex_trylock. */
954 PTH_FUNCS(int, mutexZutrylock, pthread_mutex_trylock_intercept,
955 (pthread_mutex_t *mutex), (mutex));
956 #else
957 PTH_FUNCS(int, pthreadZumutexZutrylock, pthread_mutex_trylock_intercept,
958 (pthread_mutex_t *mutex), (mutex));
959 #endif /* VGO_solaris */
961 static __always_inline
962 int pthread_mutex_timedlock_intercept(pthread_mutex_t *mutex,
963 const struct timespec *abs_timeout)
965 int ret;
966 OrigFn fn;
967 VALGRIND_GET_ORIG_FN(fn);
968 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
969 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
970 CALL_FN_W_WW(ret, fn, mutex, abs_timeout);
971 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
972 mutex, ret == 0, 0, 0, 0);
973 return ret;
976 PTH_FUNCS(int, pthreadZumutexZutimedlock, pthread_mutex_timedlock_intercept,
977 (pthread_mutex_t *mutex, const struct timespec *abs_timeout),
978 (mutex, abs_timeout));
979 #if defined(VGO_solaris)
980 PTH_FUNCS(int,
981 pthreadZumutexZureltimedlockZunp, pthread_mutex_timedlock_intercept,
982 (pthread_mutex_t *mutex, const struct timespec *timeout),
983 (mutex, timeout));
984 #endif /* VGO_solaris */
986 static __always_inline
987 int pthread_mutex_unlock_intercept(pthread_mutex_t *mutex)
989 int ret;
990 OrigFn fn;
991 VALGRIND_GET_ORIG_FN(fn);
992 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
993 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
994 CALL_FN_W_W(ret, fn, mutex);
995 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
996 mutex, 0, 0, 0, 0);
997 return ret;
1000 #if defined(VGO_solaris)
1001 /* On Solaris, pthread_mutex_unlock is a weak alias to mutex_unlock. */
1002 PTH_FUNCS(int, mutexZuunlock, pthread_mutex_unlock_intercept,
1003 (pthread_mutex_t *mutex), (mutex));
1004 #else
1005 PTH_FUNCS(int, pthreadZumutexZuunlock, pthread_mutex_unlock_intercept,
1006 (pthread_mutex_t *mutex), (mutex));
1007 #endif /* VGO_solaris */
1009 #if defined(VGO_solaris)
1010 /* Internal to libc. */
1011 static __always_inline
1012 void lmutex_unlock_intercept(mutex_t *mutex)
1014 OrigFn fn;
1015 VALGRIND_GET_ORIG_FN(fn);
1016 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
1017 mutex,
1018 DRD_(mutex_type)((pthread_mutex_t *) mutex),
1019 0, 0, 0);
1020 CALL_FN_v_W(fn, mutex);
1021 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
1022 mutex, 0, 0, 0, 0);
1025 PTH_FUNCS(void, lmutexZuunlock, lmutex_unlock_intercept,
1026 (mutex_t *mutex), (mutex));
1027 #endif /* VGO_solaris */
1029 static __always_inline
1030 int pthread_cond_init_intercept(pthread_cond_t* cond,
1031 const pthread_condattr_t* attr)
1033 int ret;
1034 OrigFn fn;
1035 VALGRIND_GET_ORIG_FN(fn);
1036 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT,
1037 cond, 0, 0, 0, 0);
1038 CALL_FN_W_WW(ret, fn, cond, attr);
1039 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT,
1040 cond, 0, 0, 0, 0);
1041 return ret;
1044 PTH_FUNCS(int, pthreadZucondZuinit, pthread_cond_init_intercept,
1045 (pthread_cond_t* cond, const pthread_condattr_t* attr),
1046 (cond, attr));
1048 #if defined(VGO_solaris)
1049 static __always_inline
1050 int cond_init_intercept(cond_t *cond, int type, void *arg)
1052 int ret;
1053 OrigFn fn;
1054 VALGRIND_GET_ORIG_FN(fn);
1055 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT,
1056 cond, 0, 0, 0, 0);
1057 CALL_FN_W_WWW(ret, fn, cond, type, arg);
1058 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT,
1059 cond, 0, 0, 0, 0);
1060 return ret;
1063 PTH_FUNCS(int, condZuinit, cond_init_intercept,
1064 (cond_t *cond, int type, void *arg),
1065 (cond, type, arg));
1066 #endif /* VGO_solaris */
1068 static __always_inline
1069 int pthread_cond_destroy_intercept(pthread_cond_t* cond)
1071 int ret;
1072 OrigFn fn;
1073 VALGRIND_GET_ORIG_FN(fn);
1074 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_DESTROY,
1075 cond, 0, 0, 0, 0);
1076 CALL_FN_W_W(ret, fn, cond);
1077 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_DESTROY,
1078 cond, ret==0, 0, 0, 0);
1079 return ret;
1082 #if defined(VGO_solaris)
1083 /* On Solaris, pthread_cond_destroy is a weak alias to cond_destroy. */
1084 PTH_FUNCS(int, condZudestroy, pthread_cond_destroy_intercept,
1085 (pthread_cond_t *cond), (cond));
1086 #else
1087 PTH_FUNCS(int, pthreadZucondZudestroy, pthread_cond_destroy_intercept,
1088 (pthread_cond_t* cond), (cond));
1089 #endif /* VGO_solaris */
1091 static __always_inline
1092 int pthread_cond_wait_intercept(pthread_cond_t *cond, pthread_mutex_t *mutex)
1094 int ret;
1095 OrigFn fn;
1096 VALGRIND_GET_ORIG_FN(fn);
1097 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
1098 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1099 CALL_FN_W_WW(ret, fn, cond, mutex);
1100 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
1101 cond, mutex, 1, 0, 0);
1102 return ret;
1105 PTH_FUNCS(int, pthreadZucondZuwait, pthread_cond_wait_intercept,
1106 (pthread_cond_t *cond, pthread_mutex_t *mutex),
1107 (cond, mutex));
1108 #if defined(VGO_solaris)
1109 PTH_FUNCS(int, condZuwait, pthread_cond_wait_intercept,
1110 (pthread_cond_t *cond, pthread_mutex_t *mutex),
1111 (cond, mutex));
1112 #endif /* VGO_solaris */
1114 static __always_inline
1115 int pthread_cond_timedwait_intercept(pthread_cond_t *cond,
1116 pthread_mutex_t *mutex,
1117 const struct timespec* abstime)
1119 int ret;
1120 OrigFn fn;
1121 VALGRIND_GET_ORIG_FN(fn);
1122 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
1123 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1124 CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
1125 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
1126 cond, mutex, 1, 0, 0);
1127 return ret;
1130 PTH_FUNCS(int, pthreadZucondZutimedwait, pthread_cond_timedwait_intercept,
1131 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1132 const struct timespec* abstime),
1133 (cond, mutex, abstime));
1134 #if defined(VGO_solaris)
1135 PTH_FUNCS(int, condZutimedwait, pthread_cond_timedwait_intercept,
1136 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1137 const struct timespec *timeout),
1138 (cond, mutex, timeout));
1139 PTH_FUNCS(int, condZureltimedwait, pthread_cond_timedwait_intercept,
1140 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1141 const struct timespec *timeout),
1142 (cond, mutex, timeout));
1143 #endif /* VGO_solaris */
1145 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
1146 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
1147 // two. Intercepting all pthread_cond_signal* functions will cause only one
1148 // argument to be passed to pthread_cond_signal_np() and hence will cause this
1149 // last function to crash.
1151 static __always_inline
1152 int pthread_cond_signal_intercept(pthread_cond_t* cond)
1154 int ret;
1155 OrigFn fn;
1156 VALGRIND_GET_ORIG_FN(fn);
1157 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_SIGNAL,
1158 cond, 0, 0, 0, 0);
1159 CALL_FN_W_W(ret, fn, cond);
1160 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_SIGNAL,
1161 cond, 0, 0, 0, 0);
1162 return ret;
1165 #if defined(VGO_solaris)
1166 /* On Solaris, pthread_cond_signal is a weak alias to cond_signal. */
1167 PTH_FUNCS(int, condZusignal, pthread_cond_signal_intercept,
1168 (pthread_cond_t *cond), (cond));
1169 #else
1170 PTH_FUNCS(int, pthreadZucondZusignal, pthread_cond_signal_intercept,
1171 (pthread_cond_t* cond), (cond));
1172 #endif /* VGO_solaris */
1174 static __always_inline
1175 int pthread_cond_broadcast_intercept(pthread_cond_t* cond)
1177 int ret;
1178 OrigFn fn;
1179 VALGRIND_GET_ORIG_FN(fn);
1180 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_BROADCAST,
1181 cond, 0, 0, 0, 0);
1182 CALL_FN_W_W(ret, fn, cond);
1183 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_BROADCAST,
1184 cond, 0, 0, 0, 0);
1185 return ret;
1188 #if defined(VGO_solaris)
1189 /* On Solaris, pthread_cond_broadcast is a weak alias to cond_broadcast. */
1190 PTH_FUNCS(int, condZubroadcast, pthread_cond_broadcast_intercept,
1191 (pthread_cond_t *cond), (cond));
1192 #else
1193 PTH_FUNCS(int, pthreadZucondZubroadcast, pthread_cond_broadcast_intercept,
1194 (pthread_cond_t* cond), (cond));
1195 #endif /* VGO_solaris */
1197 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1198 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1199 static __always_inline
1200 int pthread_spin_init_intercept(pthread_spinlock_t *spinlock, int pshared)
1202 int ret;
1203 OrigFn fn;
1204 VALGRIND_GET_ORIG_FN(fn);
1205 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
1206 spinlock, 0, 0, 0, 0);
1207 CALL_FN_W_WW(ret, fn, spinlock, pshared);
1208 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
1209 spinlock, 0, 0, 0, 0);
1210 return ret;
1213 PTH_FUNCS(int, pthreadZuspinZuinit, pthread_spin_init_intercept,
1214 (pthread_spinlock_t *spinlock, int pshared), (spinlock, pshared));
1216 static __always_inline
1217 int pthread_spin_destroy_intercept(pthread_spinlock_t *spinlock)
1219 int ret;
1220 OrigFn fn;
1221 VALGRIND_GET_ORIG_FN(fn);
1222 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
1223 spinlock, 0, 0, 0, 0);
1224 CALL_FN_W_W(ret, fn, spinlock);
1225 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
1226 spinlock, mutex_type_spinlock, 0, 0, 0);
1227 return ret;
1230 PTH_FUNCS(int, pthreadZuspinZudestroy, pthread_spin_destroy_intercept,
1231 (pthread_spinlock_t *spinlock), (spinlock));
1233 static __always_inline
1234 int pthread_spin_lock_intercept(pthread_spinlock_t *spinlock)
1236 int ret;
1237 OrigFn fn;
1238 VALGRIND_GET_ORIG_FN(fn);
1239 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
1240 spinlock, mutex_type_spinlock, 0, 0, 0);
1241 CALL_FN_W_W(ret, fn, spinlock);
1242 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
1243 spinlock, ret == 0, 0, 0, 0);
1244 return ret;
1247 PTH_FUNCS(int, pthreadZuspinZulock, pthread_spin_lock_intercept,
1248 (pthread_spinlock_t *spinlock), (spinlock));
1250 static __always_inline
1251 int pthread_spin_trylock_intercept(pthread_spinlock_t *spinlock)
1253 int ret;
1254 OrigFn fn;
1255 VALGRIND_GET_ORIG_FN(fn);
1256 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
1257 spinlock, mutex_type_spinlock, 0, 0, 0);
1258 CALL_FN_W_W(ret, fn, spinlock);
1259 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
1260 spinlock, ret == 0, 0, 0, 0);
1261 return ret;
1264 PTH_FUNCS(int, pthreadZuspinZutrylock, pthread_spin_trylock_intercept,
1265 (pthread_spinlock_t *spinlock), (spinlock));
1267 static __always_inline
1268 int pthread_spin_unlock_intercept(pthread_spinlock_t *spinlock)
1270 int ret;
1271 OrigFn fn;
1272 VALGRIND_GET_ORIG_FN(fn);
1273 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
1274 spinlock, mutex_type_spinlock, 0, 0, 0);
1275 CALL_FN_W_W(ret, fn, spinlock);
1276 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
1277 spinlock, 0, 0, 0, 0);
1278 return ret;
1281 PTH_FUNCS(int, pthreadZuspinZuunlock, pthread_spin_unlock_intercept,
1282 (pthread_spinlock_t *spinlock), (spinlock));
1283 #endif // HAVE_PTHREAD_SPIN_LOCK
1286 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1287 static __always_inline
1288 int pthread_barrier_init_intercept(pthread_barrier_t* barrier,
1289 const pthread_barrierattr_t* attr,
1290 unsigned count)
1292 int ret;
1293 OrigFn fn;
1294 VALGRIND_GET_ORIG_FN(fn);
1295 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_INIT,
1296 barrier, pthread_barrier, count, 0, 0);
1297 CALL_FN_W_WWW(ret, fn, barrier, attr, count);
1298 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_INIT,
1299 barrier, pthread_barrier, 0, 0, 0);
1300 return ret;
1303 PTH_FUNCS(int, pthreadZubarrierZuinit, pthread_barrier_init_intercept,
1304 (pthread_barrier_t* barrier, const pthread_barrierattr_t* attr,
1305 unsigned count), (barrier, attr, count));
1307 static __always_inline
1308 int pthread_barrier_destroy_intercept(pthread_barrier_t* barrier)
1310 int ret;
1311 OrigFn fn;
1312 VALGRIND_GET_ORIG_FN(fn);
1313 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_DESTROY,
1314 barrier, pthread_barrier, 0, 0, 0);
1315 CALL_FN_W_W(ret, fn, barrier);
1316 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_DESTROY,
1317 barrier, pthread_barrier, 0, 0, 0);
1318 return ret;
1321 PTH_FUNCS(int, pthreadZubarrierZudestroy, pthread_barrier_destroy_intercept,
1322 (pthread_barrier_t* barrier), (barrier));
1324 static __always_inline
1325 int pthread_barrier_wait_intercept(pthread_barrier_t* barrier)
1327 int ret;
1328 OrigFn fn;
1329 VALGRIND_GET_ORIG_FN(fn);
1330 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_WAIT,
1331 barrier, pthread_barrier, 0, 0, 0);
1332 CALL_FN_W_W(ret, fn, barrier);
1333 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_WAIT,
1334 barrier, pthread_barrier,
1335 ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD,
1336 ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
1337 return ret;
1340 PTH_FUNCS(int, pthreadZubarrierZuwait, pthread_barrier_wait_intercept,
1341 (pthread_barrier_t* barrier), (barrier));
1342 #endif // HAVE_PTHREAD_BARRIER_INIT
1345 static __always_inline
1346 int sem_init_intercept(sem_t *sem, int pshared, unsigned int value)
1348 int ret;
1349 OrigFn fn;
1350 VALGRIND_GET_ORIG_FN(fn);
1351 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT,
1352 sem, pshared, value, 0, 0);
1353 CALL_FN_W_WWW(ret, fn, sem, pshared, value);
1354 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT,
1355 sem, 0, 0, 0, 0);
1356 return ret;
1359 PTH_FUNCS(int, semZuinit, sem_init_intercept,
1360 (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
1362 #if defined(VGO_solaris)
1363 static __always_inline
1364 int sema_init_intercept(sema_t *sem, unsigned int value, int type, void *arg)
1366 int ret;
1367 OrigFn fn;
1368 VALGRIND_GET_ORIG_FN(fn);
1369 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT,
1370 sem, type == USYNC_PROCESS ? 1 : 0,
1371 value, 0, 0);
1372 CALL_FN_W_WWWW(ret, fn, sem, value, type, arg);
1373 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT,
1374 sem, 0, 0, 0, 0);
1375 return ret;
1378 PTH_FUNCS(int, semaZuinit, sema_init_intercept,
1379 (sema_t *sem, unsigned int value, int type, void *arg),
1380 (sem, value, type, arg));
1381 #endif /* VGO_solaris */
1383 static __always_inline
1384 int sem_destroy_intercept(sem_t *sem)
1386 int ret;
1387 OrigFn fn;
1388 VALGRIND_GET_ORIG_FN(fn);
1389 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_DESTROY,
1390 sem, 0, 0, 0, 0);
1391 CALL_FN_W_W(ret, fn, sem);
1392 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_DESTROY,
1393 sem, 0, 0, 0, 0);
1394 return ret;
1397 PTH_FUNCS(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1398 #if defined(VGO_solaris)
1399 PTH_FUNCS(int, semaZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1400 #endif /* VGO_solaris */
1402 static __always_inline
1403 sem_t* sem_open_intercept(const char *name, int oflag, mode_t mode,
1404 unsigned int value)
1406 sem_t *ret;
1407 OrigFn fn;
1408 VALGRIND_GET_ORIG_FN(fn);
1409 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_OPEN,
1410 name, oflag, mode, value, 0);
1411 CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value);
1412 // To do: figure out why gcc 9.2.1 miscompiles this function if the printf()
1413 // call below is left out.
1414 printf("");
1415 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_OPEN,
1416 ret != SEM_FAILED ? ret : 0,
1417 name, oflag, mode, value);
1418 return ret;
1421 PTH_FUNCS(sem_t *, semZuopen, sem_open_intercept,
1422 (const char *name, int oflag, mode_t mode, unsigned int value),
1423 (name, oflag, mode, value));
1425 static __always_inline int sem_close_intercept(sem_t *sem)
1427 int ret;
1428 OrigFn fn;
1429 VALGRIND_GET_ORIG_FN(fn);
1430 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_CLOSE,
1431 sem, 0, 0, 0, 0);
1432 CALL_FN_W_W(ret, fn, sem);
1433 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_CLOSE,
1434 sem, 0, 0, 0, 0);
1435 return ret;
1438 PTH_FUNCS(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
1440 static __always_inline int sem_wait_intercept(sem_t *sem)
1442 int ret;
1443 OrigFn fn;
1444 VALGRIND_GET_ORIG_FN(fn);
1445 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1446 sem, 0, 0, 0, 0);
1447 CALL_FN_W_W(ret, fn, sem);
1448 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1449 sem, ret == 0, 0, 0, 0);
1450 return ret;
1453 PTH_FUNCS(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1454 #if defined(VGO_solaris)
1455 PTH_FUNCS(int, semaZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1456 #endif /* VGO_solaris */
1458 static __always_inline int sem_trywait_intercept(sem_t *sem)
1460 int ret;
1461 OrigFn fn;
1462 VALGRIND_GET_ORIG_FN(fn);
1463 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1464 sem, 0, 0, 0, 0);
1465 CALL_FN_W_W(ret, fn, sem);
1466 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1467 sem, ret == 0, 0, 0, 0);
1468 return ret;
1471 PTH_FUNCS(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1472 #if defined(VGO_solaris)
1473 PTH_FUNCS(int, semaZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1474 #endif /* VGO_solaris */
1476 static __always_inline
1477 int sem_timedwait_intercept(sem_t *sem, const struct timespec *abs_timeout)
1479 int ret;
1480 OrigFn fn;
1481 VALGRIND_GET_ORIG_FN(fn);
1482 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1483 sem, 0, 0, 0, 0);
1484 CALL_FN_W_WW(ret, fn, sem, abs_timeout);
1485 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1486 sem, ret == 0, 0, 0, 0);
1487 return ret;
1490 PTH_FUNCS(int, semZutimedwait, sem_timedwait_intercept,
1491 (sem_t *sem, const struct timespec *abs_timeout),
1492 (sem, abs_timeout));
1493 #if defined(VGO_solaris)
1494 PTH_FUNCS(int, semaZutimedwait, sem_timedwait_intercept,
1495 (sem_t *sem, const struct timespec *timeout),
1496 (sem, timeout));
1497 PTH_FUNCS(int, semaZureltimedwait, sem_timedwait_intercept,
1498 (sem_t *sem, const struct timespec *timeout),
1499 (sem, timeout));
1500 #endif /* VGO_solaris */
1502 static __always_inline int sem_post_intercept(sem_t *sem)
1504 int ret;
1505 OrigFn fn;
1506 VALGRIND_GET_ORIG_FN(fn);
1507 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_POST,
1508 sem, 0, 0, 0, 0);
1509 CALL_FN_W_W(ret, fn, sem);
1510 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_POST,
1511 sem, ret == 0, 0, 0, 0);
1512 return ret;
1515 PTH_FUNCS(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
1516 #if defined(VGO_solaris)
1517 PTH_FUNCS(int, semaZupost, sem_post_intercept, (sem_t *sem), (sem));
1518 #endif /* VGO_solaris */
1520 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1521 functions have to be conditionally compiled. */
1522 #if defined(HAVE_PTHREAD_RWLOCK_T)
1524 static __always_inline
1525 int pthread_rwlock_init_intercept(pthread_rwlock_t* rwlock,
1526 const pthread_rwlockattr_t* attr)
1528 int ret;
1529 OrigFn fn;
1530 VALGRIND_GET_ORIG_FN(fn);
1531 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT,
1532 rwlock, 0, 0, 0, 0);
1533 CALL_FN_W_WW(ret, fn, rwlock, attr);
1534 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT,
1535 rwlock, 0, 0, 0, 0);
1536 return ret;
1539 PTH_FUNCS(int,
1540 pthreadZurwlockZuinit, pthread_rwlock_init_intercept,
1541 (pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr),
1542 (rwlock, attr));
1544 #if defined(VGO_solaris)
1545 static __always_inline
1546 int rwlock_init_intercept(rwlock_t *rwlock, int type, void *arg)
1548 int ret;
1549 OrigFn fn;
1550 VALGRIND_GET_ORIG_FN(fn);
1551 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT,
1552 rwlock, 0, 0, 0, 0);
1553 CALL_FN_W_WWW(ret, fn, rwlock, type, arg);
1554 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT,
1555 rwlock, 0, 0, 0, 0);
1556 return ret;
1559 PTH_FUNCS(int, rwlockZuinit, rwlock_init_intercept,
1560 (rwlock_t *rwlock, int type, void *arg),
1561 (rwlock, type, arg));
1562 #endif /* VGO_solaris */
1564 static __always_inline
1565 int pthread_rwlock_destroy_intercept(pthread_rwlock_t* rwlock)
1567 int ret;
1568 OrigFn fn;
1569 VALGRIND_GET_ORIG_FN(fn);
1570 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_DESTROY,
1571 rwlock, 0, 0, 0, 0);
1572 CALL_FN_W_W(ret, fn, rwlock);
1573 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_DESTROY,
1574 rwlock, 0, 0, 0, 0);
1575 return ret;
1578 #if defined(VGO_solaris)
1579 /* On Solaris, pthread_rwlock_destroy is a weak alias to rwlock_destroy. */
1580 PTH_FUNCS(int,
1581 rwlockZudestroy, pthread_rwlock_destroy_intercept,
1582 (pthread_rwlock_t *rwlock), (rwlock));
1583 #else
1584 PTH_FUNCS(int,
1585 pthreadZurwlockZudestroy, pthread_rwlock_destroy_intercept,
1586 (pthread_rwlock_t* rwlock), (rwlock));
1587 #endif /* VGO_solaris */
1589 static __always_inline
1590 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t* rwlock)
1592 int ret;
1593 OrigFn fn;
1594 VALGRIND_GET_ORIG_FN(fn);
1595 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1596 rwlock, 0, 0, 0, 0);
1597 CALL_FN_W_W(ret, fn, rwlock);
1598 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1599 rwlock, ret == 0, 0, 0, 0);
1600 return ret;
1603 #if defined(VGO_solaris)
1604 /* On Solaris, pthread_rwlock_rdlock is a weak alias to rw_rdlock. */
1605 PTH_FUNCS(int,
1606 rwZurdlock, pthread_rwlock_rdlock_intercept,
1607 (pthread_rwlock_t *rwlock), (rwlock));
1608 #else
1609 PTH_FUNCS(int,
1610 pthreadZurwlockZurdlock, pthread_rwlock_rdlock_intercept,
1611 (pthread_rwlock_t* rwlock), (rwlock));
1612 #endif /* VGO_solaris */
1614 #if defined(VGO_solaris)
1615 /* Internal to libc. */
1616 static __always_inline
1617 void lrw_rdlock_intercept(rwlock_t *rwlock)
1619 OrigFn fn;
1620 VALGRIND_GET_ORIG_FN(fn);
1621 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1622 rwlock, 0, 0, 0, 0);
1623 CALL_FN_v_W(fn, rwlock);
1624 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1625 rwlock, True /* took_lock */, 0, 0, 0);
1628 PTH_FUNCS(void, lrwZurdlock, lrw_rdlock_intercept,
1629 (rwlock_t *rwlock), (rwlock));
1630 #endif /* VGO_solaris */
1632 static __always_inline
1633 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t* rwlock)
1635 int ret;
1636 OrigFn fn;
1637 VALGRIND_GET_ORIG_FN(fn);
1638 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1639 rwlock, 0, 0, 0, 0);
1640 CALL_FN_W_W(ret, fn, rwlock);
1641 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1642 rwlock, ret == 0, 0, 0, 0);
1643 return ret;
1646 #if defined(VGO_solaris)
1647 /* On Solaris, pthread_rwlock_wrlock is a weak alias to rw_wrlock. */
1648 PTH_FUNCS(int,
1649 rwZuwrlock, pthread_rwlock_wrlock_intercept,
1650 (pthread_rwlock_t *rwlock), (rwlock));
1651 #else
1652 PTH_FUNCS(int,
1653 pthreadZurwlockZuwrlock, pthread_rwlock_wrlock_intercept,
1654 (pthread_rwlock_t* rwlock), (rwlock));
1655 #endif /* VGO_solaris */
1657 #if defined(VGO_solaris)
1658 /* Internal to libc. */
1659 static __always_inline
1660 void lrw_wrlock_intercept(rwlock_t *rwlock)
1662 OrigFn fn;
1663 VALGRIND_GET_ORIG_FN(fn);
1664 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1665 rwlock, 0, 0, 0, 0);
1666 CALL_FN_v_W(fn, rwlock);
1667 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1668 rwlock, True /* took_lock */, 0, 0, 0);
1671 PTH_FUNCS(void, lrwZuwrlock, lrw_wrlock_intercept,
1672 (rwlock_t *rwlock), (rwlock));
1673 #endif /* VGO_solaris */
1675 static __always_inline
1676 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t* rwlock,
1677 const struct timespec *timeout)
1679 int ret;
1680 OrigFn fn;
1681 VALGRIND_GET_ORIG_FN(fn);
1682 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1683 rwlock, 0, 0, 0, 0);
1684 CALL_FN_W_WW(ret, fn, rwlock, timeout);
1685 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1686 rwlock, ret == 0, 0, 0, 0);
1687 return ret;
1690 PTH_FUNCS(int,
1691 pthreadZurwlockZutimedrdlock, pthread_rwlock_timedrdlock_intercept,
1692 (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1693 (rwlock, timeout));
1694 #if defined(VGO_solaris)
1695 PTH_FUNCS(int, pthreadZurwlockZureltimedrdlockZunp,
1696 pthread_rwlock_timedrdlock_intercept,
1697 (pthread_rwlock_t *rwlock, const struct timespec *timeout),
1698 (rwlock, timeout));
1699 #endif /* VGO_solaris */
1701 static __always_inline
1702 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t* rwlock,
1703 const struct timespec *timeout)
1705 int ret;
1706 OrigFn fn;
1707 VALGRIND_GET_ORIG_FN(fn);
1708 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1709 rwlock, 0, 0, 0, 0);
1710 CALL_FN_W_WW(ret, fn, rwlock, timeout);
1711 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1712 rwlock, ret == 0, 0, 0, 0);
1713 return ret;
1716 PTH_FUNCS(int,
1717 pthreadZurwlockZutimedwrlock, pthread_rwlock_timedwrlock_intercept,
1718 (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1719 (rwlock, timeout));
1720 #if defined(VGO_solaris)
1721 PTH_FUNCS(int, pthreadZurwlockZureltimedwrlockZunp,
1722 pthread_rwlock_timedwrlock_intercept,
1723 (pthread_rwlock_t *rwlock, const struct timespec *timeout),
1724 (rwlock, timeout));
1725 #endif /* VGO_solaris */
1727 static __always_inline
1728 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t* rwlock)
1730 int ret;
1731 OrigFn fn;
1732 VALGRIND_GET_ORIG_FN(fn);
1733 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1734 rwlock, 0, 0, 0, 0);
1735 CALL_FN_W_W(ret, fn, rwlock);
1736 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1737 rwlock, ret == 0, 0, 0, 0);
1738 return ret;
1741 #if defined(VGO_solaris)
1742 /* On Solaris, pthread_rwlock_tryrdlock is a weak alias to rw_tryrdlock. */
1743 PTH_FUNCS(int,
1744 rwZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1745 (pthread_rwlock_t *rwlock), (rwlock));
1746 #else
1747 PTH_FUNCS(int,
1748 pthreadZurwlockZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1749 (pthread_rwlock_t* rwlock), (rwlock));
1750 #endif /* VGO_solaris */
1752 static __always_inline
1753 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t* rwlock)
1755 int ret;
1756 OrigFn fn;
1757 VALGRIND_GET_ORIG_FN(fn);
1758 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1759 rwlock, 0, 0, 0, 0);
1760 CALL_FN_W_W(ret, fn, rwlock);
1761 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1762 rwlock, ret == 0, 0, 0, 0);
1763 return ret;
1766 #if defined(VGO_solaris)
1767 /* On Solaris, pthread_rwlock_trywrlock is a weak alias to rw_trywrlock. */
1768 PTH_FUNCS(int,
1769 rwZutrywrlock, pthread_rwlock_trywrlock_intercept,
1770 (pthread_rwlock_t *rwlock), (rwlock));
1771 #else
1772 PTH_FUNCS(int,
1773 pthreadZurwlockZutrywrlock, pthread_rwlock_trywrlock_intercept,
1774 (pthread_rwlock_t* rwlock), (rwlock));
1775 #endif /* VGO_solaris */
1777 static __always_inline
1778 int pthread_rwlock_unlock_intercept(pthread_rwlock_t* rwlock)
1780 int ret;
1781 OrigFn fn;
1782 VALGRIND_GET_ORIG_FN(fn);
1783 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_UNLOCK,
1784 rwlock, 0, 0, 0, 0);
1785 CALL_FN_W_W(ret, fn, rwlock);
1786 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_UNLOCK,
1787 rwlock, ret == 0, 0, 0, 0);
1788 return ret;
1791 #if defined(VGO_solaris)
1792 /* On Solaris, pthread_rwlock_unlock is a weak alias to rw_unlock. */
1793 PTH_FUNCS(int,
1794 rwZuunlock, pthread_rwlock_unlock_intercept,
1795 (pthread_rwlock_t *rwlock), (rwlock));
1796 #else
1797 PTH_FUNCS(int,
1798 pthreadZurwlockZuunlock, pthread_rwlock_unlock_intercept,
1799 (pthread_rwlock_t* rwlock), (rwlock));
1800 #endif /* VGO_solaris */
1802 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */