1 /*--------------------------------------------------------------------*/
2 /*--- Client-space code for DRD. drd_pthread_intercepts.c ---*/
3 /*--------------------------------------------------------------------*/
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).
47 #include <assert.h> /* assert() */
49 #include <pthread.h> /* pthread_mutex_t */
50 #include <semaphore.h> /* sem_t */
51 #include <stdint.h> /* uintptr_t */
52 #include <stdio.h> /* fprintf() */
53 #include <stdlib.h> /* malloc(), free() */
54 #include <unistd.h> /* confstr() */
55 #include "config.h" /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP etc. */
56 #include "drd_basics.h" /* DRD_() */
57 #include "drd_clientreq.h"
58 #include "pub_tool_redir.h" /* VG_WRAP_FUNCTION_ZZ() */
60 #if defined(VGO_freebsd)
64 #if defined(VGO_solaris)
66 * Solaris usually provides pthread_* functions on top of Solaris threading
67 * and synchronization functions. Usually both need to be intercepted because
68 * pthread_* ones might not call the Solaris ones (see for example sem_wait()).
69 * Such approach is required to correctly report misuse of the POSIX threads
71 * Therefore DRD intercepts and instruments all such functions but due to
72 * DRD_(thread_enter_synchr)() and DRD_(thread_leave_synchr)() guards in
73 * handle_client_request(), only the top-most function is handled.
74 * So the right thing(TM) happens, as expected.
75 * The only exception is when pthread_* function is a weak alias to the Solaris
76 * threading/synchronization function. In such case only one needs to be
77 * intercepted to avoid redirection ambiguity.
79 * Intercepted functions rely on the fact that:
80 * - pthread_mutex_t == mutex_t
81 * - pthread_cond_t == cond_t
83 * - pthread_rwlock_t == rwlock_t
85 * It is necessary to intercept also internal libc synchronization functions
87 * - For read-write locks the unlocking function is shared
88 * - Functions lmutex_lock/lmutex_unlock guard many critical sections in libc
89 * which will be otherwise reported by DRD
93 #include "pub_tool_vki.h"
96 * Solaris provides higher throughput, parallelism and scalability than other
97 * operating systems, at the cost of more fine-grained locking activity.
98 * This means for example that when a thread is created under Linux, just one
99 * big lock in glibc is used for all thread setup. Solaris libc uses several
100 * fine-grained locks and the creator thread resumes its activities as soon
101 * as possible, leaving for example stack and TLS setup activities to the
104 * This situation confuses DRD as it assumes there is some false ordering
105 * in place between creator and created thread; and therefore many types of
106 * race conditions in the application would not be reported. To prevent such
107 * false ordering, command line option --ignore-thread-creation is set to
108 * 'yes' by default on Solaris. All activity (loads, stores, client requests)
109 * is therefore ignored during:
110 * - pthread_create() call in the creator thread [libc.so]
111 * - thread creation phase (stack and TLS setup) in the created thread [libc.so]
113 * As explained in the comments for _ti_bind_guard(), whenever the runtime
114 * linker has to perform any activity (such as resolving a symbol), it protects
115 * its data structures by calling into rt_bind_guard() which in turn invokes
116 * _ti_bind_guard() in libc. Pointers to _ti_bind_guard() and _ti_bind_clear()
117 * are passed from libc to runtime linker in _ld_libc() call during libc_init().
118 * All activity is also ignored during:
119 * - runtime dynamic linker work between rt_bind_guard() and rt_bind_clear()
122 * This also means that DRD does not report race conditions in libc (when
123 * --ignore-thread-creation=yes) and runtime linker itself (unconditionally)
124 * during these ignored sequences.
128 * Original function pointers for _ti_bind_guard() and _ti_bind_clear()
129 * from libc. They are intercepted in function wrapper of _ld_libc().
131 typedef int (*drd_rtld_guard_fn
)(int flags
);
132 static drd_rtld_guard_fn
DRD_(rtld_bind_guard
) = NULL
;
133 static drd_rtld_guard_fn
DRD_(rtld_bind_clear
) = NULL
;
138 * Notes regarding thread creation:
139 * - sg_init() runs on the context of the created thread and copies the vector
140 * clock of the creator thread. This only works reliably if the creator
141 * thread waits until this copy has been performed.
142 * - DRD_(thread_compute_minimum_vc)() does not take the vector clocks into
143 * account that are involved in thread creation and for which the
144 * corresponding thread has not yet been created. So not waiting until the
145 * created thread has been started would make it possible that segments get
146 * discarded that should not yet be discarded. Or: some data races are not
151 * Macro for generating a Valgrind interception function.
152 * @param[in] ret_ty Return type of the function to be generated.
153 * @param[in] zf Z-encoded name of the interception function.
154 * @param[in] implf Name of the function that implements the intercept.
155 * @param[in] arg_decl Argument declaration list enclosed in parentheses.
156 * @param[in] argl Argument list enclosed in parentheses.
158 #if defined(VGO_darwin)
160 * Note here VGO_darwin is used rather than VG_WRAP_THREAD_FUNCTION_LIBPTHREAD_ONLY
161 * because of the special-case code adding a function call
163 static int never_true
;
164 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
165 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
166 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
168 ret_ty pth_func_result = implf argl; \
169 /* Apparently inserting a function call in wrapper functions */ \
170 /* is sufficient to avoid misaligned stack errors. */ \
173 return pth_func_result; \
175 #elif defined(VG_WRAP_THREAD_FUNCTION_LIBPTHREAD_ONLY)
176 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
177 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
178 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
179 { return implf argl; }
180 #elif defined(VG_WRAP_THREAD_FUNCTION_LIBC_ONLY)
181 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
182 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl; \
183 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl \
184 { return implf argl; }
185 #elif defined(VG_WRAP_THREAD_FUNCTION_LIBC_AND_LIBPTHREAD)
186 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
187 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl; \
188 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl \
189 { return implf argl; } \
190 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
191 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
192 { return implf argl; }
194 # error "Unknown platform/thread wrapping"
197 #if defined(VGO_freebsd)
198 #define LIBC_FUNC(ret_ty, zf, implf, argl_decl, argl) \
199 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl; \
200 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl \
201 { return implf argl; }
205 * Macro for generating three Valgrind interception functions: one with the
206 * Z-encoded name zf, one with ZAZa ("@*") appended to the name zf and one
207 * with ZDZa ("$*") appended to the name zf. The second generated interception
208 * function will intercept versioned symbols on Linux, and the third will
209 * intercept versioned symbols on Darwin.
211 #define PTH_FUNCS(ret_ty, zf, implf, argl_decl, argl) \
212 PTH_FUNC(ret_ty, zf, implf, argl_decl, argl); \
213 PTH_FUNC(ret_ty, zf ## ZAZa, implf, argl_decl, argl); \
214 PTH_FUNC(ret_ty, zf ## ZDZa, implf, argl_decl, argl);
217 * Not inlining one of the intercept functions will cause the regression
218 * tests to fail because this would cause an additional stackfram to appear
219 * in the output. The __always_inline macro guarantees that inlining will
220 * happen, even when compiling with optimization disabled.
222 #undef __always_inline /* since already defined in <cdefs.h> */
223 #if __GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 2
224 #define __always_inline __inline__ __attribute__((always_inline))
226 #define __always_inline __inline__
229 /* Local data structures. */
232 pthread_mutex_t mutex
;
239 void* (*start
)(void*);
242 DrdSema
* wrapper_started
;
243 } DrdPosixThreadArgs
;
246 /* Local function declarations. */
248 static void DRD_(init
)(void) __attribute__((constructor
));
249 static void DRD_(check_threading_library
)(void);
250 static void DRD_(set_pthread_id
)(void);
251 static void DRD_(sema_init
)(DrdSema
* sema
);
252 static void DRD_(sema_destroy
)(DrdSema
* sema
);
253 static void DRD_(sema_down
)(DrdSema
* sema
);
254 static void DRD_(sema_up
)(DrdSema
* sema
);
257 /* Function definitions. */
260 * Shared library initialization function. The function init() is called after
261 * dlopen() has loaded the shared library with DRD client intercepts because
262 * the constructor attribute was specified in the declaration of this function.
263 * Note: do specify the -nostdlib option to gcc when linking this code into a
264 * shared library because doing so would cancel the effect of the constructor
265 * attribute ! Using the gcc option -nodefaultlibs is fine because this last
266 * option preserves the shared library initialization code that calls
267 * constructor and destructor functions.
269 static void DRD_(init
)(void)
271 #if defined(VGO_freebsd)
274 * On FreeBSD, pthead functions are all in libthr.so
275 * However libc.so contains stubs. In this ctor function,
276 * calling DRD_(set_pthread_id)() results in a call to
277 * pthread_self() resolving to the libc.so stub which
278 * returns a junk value for the tid. Subsequent calls
279 * to pthread_create() then also cause calls to
280 * DRD_(set_pthread_id)(), but this time with pthread_self()
281 * resolving to the good libthr.so version (since this is later
282 * and libthr.so has been loaded). That causes an assert
283 * since we expect the tid to either be INVALID_POSIX_THREADID
284 * or the same as the current tid, and the junk value
285 * is neither. So we force loading of libthr.so, which
286 * avoids this junk tid value.
288 #if (FREEBSD_VERS >= FREEBSD_15)
289 void* libsys
= dlopen("/lib/libsys.so.7", RTLD_NOW
|RTLD_GLOBAL
|RTLD_NODELETE
);
291 dlclose(dlopen("/lib/libthr.so.3", RTLD_NOW
|RTLD_GLOBAL
|RTLD_NODELETE
));
292 #if (FREEBSD_VERS >= FREEBSD_15)
300 DRD_(check_threading_library
)();
301 DRD_(set_pthread_id
)();
302 #if defined(VGO_solaris)
303 if ((DRD_(rtld_bind_guard
) == NULL
) || (DRD_(rtld_bind_clear
) == NULL
)) {
305 "Bind guard functions for the runtime linker (ld.so.1) were not intercepted.\n"
306 "This means the interface between libc and runtime linker changed and DRD\n"
307 "needs to be ported properly. Giving up.\n");
313 static __always_inline
void DRD_(ignore_mutex_ordering
)(pthread_mutex_t
*mutex
)
315 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_IGNORE_MUTEX_ORDERING
,
319 static void DRD_(sema_init
)(DrdSema
* sema
)
321 DRD_IGNORE_VAR(*sema
);
322 pthread_mutex_init(&sema
->mutex
, NULL
);
323 DRD_(ignore_mutex_ordering
)(&sema
->mutex
);
324 pthread_cond_init(&sema
->cond
, NULL
);
328 static void DRD_(sema_destroy
)(DrdSema
* sema
)
330 pthread_mutex_destroy(&sema
->mutex
);
331 pthread_cond_destroy(&sema
->cond
);
334 static void DRD_(sema_down
)(DrdSema
* sema
)
336 pthread_mutex_lock(&sema
->mutex
);
337 while (sema
->counter
== 0)
338 pthread_cond_wait(&sema
->cond
, &sema
->mutex
);
340 pthread_mutex_unlock(&sema
->mutex
);
343 static void DRD_(sema_up
)(DrdSema
* sema
)
345 pthread_mutex_lock(&sema
->mutex
);
347 pthread_cond_signal(&sema
->cond
);
348 pthread_mutex_unlock(&sema
->mutex
);
352 * POSIX threads and DRD each have their own mutex type identification.
353 * Convert POSIX threads' mutex type to DRD's mutex type. In the code below
354 * if-statements are used to test the value of 'kind' instead of a switch
355 * statement because some of the PTHREAD_MUTEX_ macro's may have the same
358 static MutexT
DRD_(pthread_to_drd_mutex_type
)(int kind
)
361 * Static checkers don't like this as there are repeated branch
362 * but because there is variation between different platforms
363 * it's messy to make something without repetition.
365 * See also PTHREAD_MUTEX_KIND_MASK_NP in glibc source file
368 kind
&= PTHREAD_MUTEX_RECURSIVE
| PTHREAD_MUTEX_ERRORCHECK
|
369 PTHREAD_MUTEX_NORMAL
| PTHREAD_MUTEX_DEFAULT
;
371 if (kind
== PTHREAD_MUTEX_RECURSIVE
) {
372 return mutex_type_recursive_mutex
;
374 if (kind
== PTHREAD_MUTEX_ERRORCHECK
) {
375 return mutex_type_errorcheck_mutex
;
377 if (kind
== PTHREAD_MUTEX_NORMAL
) {
378 return mutex_type_default_mutex
;
380 if (kind
== PTHREAD_MUTEX_DEFAULT
) {
381 // On FreeBSD PTHREAD_MUTEX_DEFAULT is the same as PTHREAD_MUTEX_ERRORCHECK
382 // so this code is unreachable, but that's not true for all platforms
383 // so just ignore the warning
384 // coverity[DEADCODE:FALSE]
385 return mutex_type_default_mutex
;
387 #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
388 if (kind
== PTHREAD_MUTEX_ADAPTIVE_NP
) {
389 return mutex_type_default_mutex
;
392 return mutex_type_invalid_mutex
;
395 #if defined(VGO_solaris)
397 * Solaris threads and DRD each have their own mutex type identification.
398 * Convert Solaris threads' mutex type to DRD's mutex type.
400 static MutexT
DRD_(thread_to_drd_mutex_type
)(int type
)
402 if (type
& LOCK_RECURSIVE
) {
403 return mutex_type_recursive_mutex
;
404 } else if (type
& LOCK_ERRORCHECK
) {
405 return mutex_type_errorcheck_mutex
;
407 return mutex_type_default_mutex
;
410 #endif /* VGO_solaris */
412 #define IS_ALIGNED(p) (((uintptr_t)(p) & (sizeof(*(p)) - 1)) == 0)
415 * Read the mutex type stored in the client memory used for the mutex
418 * @note This function depends on the implementation of the POSIX threads
419 * library -- the POSIX standard does not define the name of the member in
420 * which the mutex type is stored.
421 * @note The function mutex_type() has been declared inline in order
422 * to avoid that it shows up in call stacks (drd/tests/...exp* files).
423 * @note glibc stores the mutex type in the lowest two bits, and uses the
424 * higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
425 * PTHREAD_MUTEXATTR_FLAG_PSHARED.
427 static __always_inline MutexT
DRD_(mutex_type
)(pthread_mutex_t
* mutex
)
429 MutexT mutex_type
= mutex_type_unknown
;
431 ANNOTATE_IGNORE_READS_BEGIN();
432 #if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
433 /* glibc + LinuxThreads. */
434 if (IS_ALIGNED(&mutex
->__m_kind
))
436 const int kind
= mutex
->__m_kind
& 3;
437 mutex_type
= DRD_(pthread_to_drd_mutex_type
)(kind
);
439 #elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
441 if (IS_ALIGNED(&mutex
->__data
.__kind
))
443 const int kind
= mutex
->__data
.__kind
& 3;
444 mutex_type
= DRD_(pthread_to_drd_mutex_type
)(kind
);
446 #elif defined(VGO_solaris)
448 const int type
= ((mutex_t
*) mutex
)->vki_mutex_type
;
449 mutex_type
= DRD_(thread_to_drd_mutex_type
)(type
);
453 * Another POSIX threads implementation. The mutex type won't be printed
454 * when enabling --trace-mutex=yes.
457 ANNOTATE_IGNORE_READS_END();
463 * Tell DRD whether 'tid' is a joinable thread or a detached thread.
465 static void DRD_(set_joinable
)(const pthread_t tid
, const int joinable
)
467 assert(joinable
== 0 || joinable
== 1);
468 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_SET_JOINABLE
,
469 tid
, joinable
, 0, 0, 0);
472 /** Tell DRD that the calling thread is about to enter pthread_create(). */
473 static __always_inline
void DRD_(entering_pthread_create
)(void)
475 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_ENTERING_PTHREAD_CREATE
,
479 /** Tell DRD that the calling thread has left pthread_create(). */
480 static __always_inline
void DRD_(left_pthread_create
)(void)
482 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_LEFT_PTHREAD_CREATE
,
487 * Entry point for newly created threads. This function is called from the
488 * thread created by pthread_create().
490 static void* DRD_(thread_wrapper
)(void* arg
)
492 DrdPosixThreadArgs
* arg_ptr
;
493 DrdPosixThreadArgs arg_copy
;
495 arg_ptr
= (DrdPosixThreadArgs
*)arg
;
498 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_SET_PTHREADID
,
499 pthread_self(), 0, 0, 0, 0);
501 DRD_(set_joinable
)(pthread_self(),
502 arg_copy
.detachstate
== PTHREAD_CREATE_JOINABLE
);
505 * Only set 'wrapper_started' after VG_USERREQ__SET_PTHREADID and
506 * DRD_(set_joinable)() have been invoked to avoid a race with
507 * a pthread_detach() invocation for this thread from another thread.
509 DRD_(sema_up
)(arg_copy
.wrapper_started
);
511 return (arg_copy
.start
)(arg_copy
.arg
);
515 * Return 1 if the LinuxThreads implementation of POSIX Threads has been
516 * detected, and 0 otherwise.
518 * @see For more information about the confstr() function, see also
519 * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
521 static int DRD_(detected_linuxthreads
)(void)
524 #if defined(_CS_GNU_LIBPTHREAD_VERSION)
525 /* Linux with a recent glibc. */
528 len
= confstr(_CS_GNU_LIBPTHREAD_VERSION
, buffer
, sizeof(buffer
));
529 assert(len
<= sizeof(buffer
));
530 return len
> 0 && buffer
[0] == 'l';
532 /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
536 /* Another OS than Linux, hence no LinuxThreads. */
542 * Stop and print an error message in case a non-supported threading
543 * library implementation (LinuxThreads) has been detected.
545 static void DRD_(check_threading_library
)(void)
547 if (DRD_(detected_linuxthreads
)())
549 if (getenv("LD_ASSUME_KERNEL"))
552 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
553 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
554 "after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
560 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
561 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
562 "after having upgraded to a newer version of your Linux distribution.\n"
571 * Update DRD's state information about the current thread.
573 static void DRD_(set_pthread_id
)(void)
575 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_SET_PTHREADID
,
576 pthread_self(), 0, 0, 0, 0);
580 * Note: as of today there exist three different versions of pthread_create
582 * - pthread_create@GLIBC_2.0
583 * - pthread_create@@GLIBC_2.1
584 * - pthread_create@@GLIBC_2.2.5
585 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
586 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
587 * versions have been implemented. In any glibc version where more than one
588 * pthread_create function has been implemented, older versions call the
589 * newer versions. Or: the pthread_create* wrapper defined below can be
590 * called recursively. Any code in this wrapper should take this in account.
591 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
592 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
593 * See also the implementation of pthread_create@GLIBC_2.0 in
594 * glibc-2.9/nptl/pthread_create.c.
597 static __always_inline
598 int pthread_create_intercept(pthread_t
* thread
, const pthread_attr_t
* attr
,
599 void* (*start
)(void*), void* arg
)
603 DrdSema wrapper_started
;
604 DrdPosixThreadArgs thread_args
;
606 VALGRIND_GET_ORIG_FN(fn
);
608 DRD_(sema_init
)(&wrapper_started
);
609 thread_args
.start
= start
;
610 thread_args
.arg
= arg
;
611 thread_args
.wrapper_started
= &wrapper_started
;
613 * Find out whether the thread will be started as a joinable thread
614 * or as a detached thread. If no thread attributes have been specified,
615 * this means that the new thread will be started as a joinable thread.
617 thread_args
.detachstate
= PTHREAD_CREATE_JOINABLE
;
618 /* The C11 thrd_create() implementation passes -1 as 'attr' argument. */
619 if (attr
&& (uintptr_t)attr
+ 1 != 0)
621 if (pthread_attr_getdetachstate(attr
, &thread_args
.detachstate
) != 0)
624 assert(thread_args
.detachstate
== PTHREAD_CREATE_JOINABLE
625 || thread_args
.detachstate
== PTHREAD_CREATE_DETACHED
);
628 * The DRD_(set_pthread_id)() from DRD_(init)() may encounter that
629 * pthread_self() == 0, e.g. when the main program is not linked with the
630 * pthread library and when a pthread_create() call occurs from within a
631 * shared library. Hence call DRD_(set_pthread_id)() again to ensure that
632 * DRD knows the identity of the current thread. See also B.Z. 356374.
634 DRD_(set_pthread_id
)();
635 DRD_(entering_pthread_create
)();
636 CALL_FN_W_WWWW(ret
, fn
, thread
, attr
, DRD_(thread_wrapper
), &thread_args
);
637 DRD_(left_pthread_create
)();
640 /* Wait until the thread wrapper started. */
641 DRD_(sema_down
)(&wrapper_started
);
644 DRD_(sema_destroy
)(&wrapper_started
);
646 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_START_NEW_SEGMENT
,
647 pthread_self(), 0, 0, 0, 0);
652 PTH_FUNCS(int, pthreadZucreate
, pthread_create_intercept
,
653 (pthread_t
*thread
, const pthread_attr_t
*attr
,
654 void *(*start
) (void *), void *arg
),
655 (thread
, attr
, start
, arg
));
657 #if defined(VGO_solaris)
658 /* Solaris also provides thr_create() in addition to pthread_create().
659 * Both pthread_create(3C) and thr_create(3C) are based on private
662 static __always_inline
663 int thr_create_intercept(void *stk
, size_t stksize
, void *(*start
)(void *),
664 void *arg
, long flags
, thread_t
*new_thread
)
668 DrdSema wrapper_started
;
669 DrdPosixThreadArgs thread_args
;
671 VALGRIND_GET_ORIG_FN(fn
);
673 DRD_(sema_init
)(&wrapper_started
);
674 thread_args
.start
= start
;
675 thread_args
.arg
= arg
;
676 thread_args
.wrapper_started
= &wrapper_started
;
678 * Find out whether the thread will be started as a joinable thread
679 * or as a detached thread.
681 if (flags
& THR_DETACHED
)
682 thread_args
.detachstate
= PTHREAD_CREATE_DETACHED
;
684 thread_args
.detachstate
= PTHREAD_CREATE_JOINABLE
;
686 DRD_(entering_pthread_create
)();
687 CALL_FN_W_6W(ret
, fn
, stk
, stksize
, DRD_(thread_wrapper
), &thread_args
,
689 DRD_(left_pthread_create
)();
692 /* Wait until the thread wrapper started. */
693 DRD_(sema_down
)(&wrapper_started
);
696 DRD_(sema_destroy
)(&wrapper_started
);
698 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_START_NEW_SEGMENT
,
699 pthread_self(), 0, 0, 0, 0);
704 PTH_FUNCS(int, thrZucreate
, thr_create_intercept
,
705 (void *stk
, size_t stksize
, void *(*start
)(void *), void *arg
,
706 long flags
, thread_t
*new_thread
),
707 (stk
, stksize
, start
, arg
, flags
, new_thread
));
708 #endif /* VGO_solaris */
710 #if defined(VGO_solaris)
712 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
713 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
714 * and CI_BIND_CLEAR, to provide resilience against function renaming.
716 static __always_inline
717 int DRD_(_ti_bind_guard_intercept
)(int flags
) {
718 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_RTLD_BIND_GUARD
,
720 return DRD_(rtld_bind_guard
)(flags
);
723 static __always_inline
724 int DRD_(_ti_bind_clear_intercept
)(int flags
) {
725 int ret
= DRD_(rtld_bind_clear
)(flags
);
726 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_RTLD_BIND_CLEAR
,
732 * Wrapped _ld_libc() from the runtime linker ld.so.1.
734 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1
, ZuldZulibc
)(vki_Lc_interface
*ptr
);
735 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1
, ZuldZulibc
)(vki_Lc_interface
*ptr
)
740 VALGRIND_GET_ORIG_FN(fn
);
742 vki_Lc_interface
*funcs
= ptr
;
743 for (tag
= funcs
->ci_tag
; tag
!= 0; tag
= (++funcs
)->ci_tag
) {
745 case VKI_CI_BIND_GUARD
:
746 if (funcs
->vki_ci_un
.ci_func
!= DRD_(_ti_bind_guard_intercept
)) {
747 DRD_(rtld_bind_guard
) = funcs
->vki_ci_un
.ci_func
;
748 funcs
->vki_ci_un
.ci_func
= DRD_(_ti_bind_guard_intercept
);
751 case VKI_CI_BIND_CLEAR
:
752 if (funcs
->vki_ci_un
.ci_func
!= DRD_(_ti_bind_clear_intercept
)) {
753 DRD_(rtld_bind_clear
) = funcs
->vki_ci_un
.ci_func
;
754 funcs
->vki_ci_un
.ci_func
= DRD_(_ti_bind_clear_intercept
);
760 CALL_FN_v_W(fn
, ptr
);
762 #endif /* VGO_solaris */
764 static __always_inline
765 int pthread_join_intercept(pthread_t pt_joinee
, void **thread_return
)
770 VALGRIND_GET_ORIG_FN(fn
);
772 * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
773 * implementation triggers a (false positive) race report.
775 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
776 CALL_FN_W_WW(ret
, fn
, pt_joinee
, thread_return
);
779 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_THREAD_JOIN
,
780 pt_joinee
, 0, 0, 0, 0);
782 ANNOTATE_IGNORE_READS_AND_WRITES_END();
786 PTH_FUNCS(int, pthreadZujoin
, pthread_join_intercept
,
787 (pthread_t pt_joinee
, void **thread_return
),
788 (pt_joinee
, thread_return
));
790 #if defined(VGO_solaris)
791 /* Solaris also provides thr_join() in addition to pthread_join().
792 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
794 * :TODO: No functionality is currently provided for joinee == 0 and departed.
795 * This would require another client request, of course.
797 static __always_inline
798 int thr_join_intercept(thread_t joinee
, thread_t
*departed
, void **thread_return
)
803 VALGRIND_GET_ORIG_FN(fn
);
804 CALL_FN_W_WWW(ret
, fn
, joinee
, departed
, thread_return
);
807 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_THREAD_JOIN
,
813 PTH_FUNCS(int, thrZujoin
, thr_join_intercept
,
814 (thread_t joinee
, thread_t
*departed
, void **thread_return
),
815 (joinee
, departed
, thread_return
));
816 #endif /* VGO_solaris */
818 static __always_inline
819 int pthread_detach_intercept(pthread_t pt_thread
)
824 VALGRIND_GET_ORIG_FN(fn
);
825 CALL_FN_W_W(ret
, fn
, pt_thread
);
826 DRD_(set_joinable
)(pt_thread
, 0);
831 PTH_FUNCS(int, pthreadZudetach
, pthread_detach_intercept
,
832 (pthread_t thread
), (thread
));
834 // NOTE: be careful to intercept only pthread_cancel() and not
835 // pthread_cancel_init() on Linux.
837 static __always_inline
838 int pthread_cancel_intercept(pthread_t pt_thread
)
842 VALGRIND_GET_ORIG_FN(fn
);
843 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_THREAD_CANCEL
,
844 pt_thread
, 0, 0, 0, 0);
845 CALL_FN_W_W(ret
, fn
, pt_thread
);
846 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_THREAD_CANCEL
,
847 pt_thread
, ret
==0, 0, 0, 0);
851 PTH_FUNCS(int, pthreadZucancel
, pthread_cancel_intercept
,
852 (pthread_t thread
), (thread
))
854 static __always_inline
855 int pthread_once_intercept(pthread_once_t
*once_control
,
856 void (*init_routine
)(void))
860 VALGRIND_GET_ORIG_FN(fn
);
862 * Ignore any data races triggered by the implementation of pthread_once().
863 * Necessary for Darwin. This is not necessary for Linux but doesn't have
864 * any known adverse effects.
866 DRD_IGNORE_VAR(*once_control
);
867 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
868 CALL_FN_W_WW(ret
, fn
, once_control
, init_routine
);
869 ANNOTATE_IGNORE_READS_AND_WRITES_END();
870 DRD_STOP_IGNORING_VAR(*once_control
);
874 PTH_FUNCS(int, pthreadZuonce
, pthread_once_intercept
,
875 (pthread_once_t
*once_control
, void (*init_routine
)(void)),
876 (once_control
, init_routine
));
878 static __always_inline
879 int pthread_mutex_init_intercept(pthread_mutex_t
*mutex
,
880 const pthread_mutexattr_t
* attr
)
885 VALGRIND_GET_ORIG_FN(fn
);
886 mt
= PTHREAD_MUTEX_DEFAULT
;
888 pthread_mutexattr_gettype(attr
, &mt
);
889 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_INIT
,
890 mutex
, DRD_(pthread_to_drd_mutex_type
)(mt
),
892 CALL_FN_W_WW(ret
, fn
, mutex
, attr
);
893 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_INIT
,
898 PTH_FUNCS(int, pthreadZumutexZuinit
, pthread_mutex_init_intercept
,
899 (pthread_mutex_t
*mutex
, const pthread_mutexattr_t
* attr
),
902 #if defined(VGO_solaris)
903 static __always_inline
904 int mutex_init_intercept(mutex_t
*mutex
, int type
, void *arg
)
908 VALGRIND_GET_ORIG_FN(fn
);
910 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_INIT
,
911 mutex
, DRD_(thread_to_drd_mutex_type
)(type
),
913 CALL_FN_W_WWW(ret
, fn
, mutex
, type
, arg
);
914 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_INIT
,
919 PTH_FUNCS(int, mutexZuinit
, mutex_init_intercept
,
920 (mutex_t
*mutex
, int type
, void *arg
),
922 #endif /* VGO_solaris */
924 static __always_inline
925 int pthread_mutex_destroy_intercept(pthread_mutex_t
* mutex
)
929 VALGRIND_GET_ORIG_FN(fn
);
930 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_DESTROY
,
932 CALL_FN_W_W(ret
, fn
, mutex
);
933 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_DESTROY
,
934 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
938 #if defined(VGO_solaris)
939 /* On Solaris, pthread_mutex_destroy is a weak alias to mutex_destroy. */
940 PTH_FUNCS(int, mutexZudestroy
, pthread_mutex_destroy_intercept
,
941 (pthread_mutex_t
*mutex
), (mutex
));
943 PTH_FUNCS(int, pthreadZumutexZudestroy
, pthread_mutex_destroy_intercept
,
944 (pthread_mutex_t
*mutex
), (mutex
));
945 #endif /* VGO_solaris */
947 static __always_inline
948 int pthread_mutex_lock_intercept(pthread_mutex_t
* mutex
)
952 VALGRIND_GET_ORIG_FN(fn
);
953 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK
,
954 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
955 CALL_FN_W_W(ret
, fn
, mutex
);
956 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK
,
957 mutex
, ret
== 0, 0, 0, 0);
961 #if defined(VGO_solaris)
962 /* On Solaris, pthread_mutex_lock is a weak alias to mutex_lock. */
963 PTH_FUNCS(int, mutexZulock
, pthread_mutex_lock_intercept
,
964 (pthread_mutex_t
*mutex
), (mutex
));
966 PTH_FUNCS(int, pthreadZumutexZulock
, pthread_mutex_lock_intercept
,
967 (pthread_mutex_t
*mutex
), (mutex
));
968 #endif /* VGO_solaris */
970 #if defined(VGO_solaris)
971 /* Internal to libc. Mutex is usually initialized only implicitly,
972 * by zeroing mutex_t structure.
974 static __always_inline
975 void lmutex_lock_intercept(mutex_t
*mutex
)
978 VALGRIND_GET_ORIG_FN(fn
);
979 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK
,
981 DRD_(mutex_type
)((pthread_mutex_t
*) mutex
),
982 False
/* try_lock */, 0, 0);
983 CALL_FN_v_W(fn
, mutex
);
984 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK
,
985 mutex
, True
/* took_lock */, 0, 0, 0);
988 PTH_FUNCS(void, lmutexZulock
, lmutex_lock_intercept
,
989 (mutex_t
*mutex
), (mutex
));
990 #endif /* VGO_solaris */
992 static __always_inline
993 int pthread_mutex_trylock_intercept(pthread_mutex_t
* mutex
)
997 VALGRIND_GET_ORIG_FN(fn
);
998 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK
,
999 mutex
, DRD_(mutex_type
)(mutex
), 1, 0, 0);
1000 CALL_FN_W_W(ret
, fn
, mutex
);
1001 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK
,
1002 mutex
, ret
== 0, 0, 0, 0);
1006 #if defined(VGO_solaris)
1007 /* On Solaris, pthread_mutex_trylock is a weak alias to mutex_trylock. */
1008 PTH_FUNCS(int, mutexZutrylock
, pthread_mutex_trylock_intercept
,
1009 (pthread_mutex_t
*mutex
), (mutex
));
1011 PTH_FUNCS(int, pthreadZumutexZutrylock
, pthread_mutex_trylock_intercept
,
1012 (pthread_mutex_t
*mutex
), (mutex
));
1013 #endif /* VGO_solaris */
1015 static __always_inline
1016 int pthread_mutex_timedlock_intercept(pthread_mutex_t
*mutex
,
1017 const struct timespec
*abs_timeout
)
1021 VALGRIND_GET_ORIG_FN(fn
);
1022 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK
,
1023 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
1024 CALL_FN_W_WW(ret
, fn
, mutex
, abs_timeout
);
1025 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK
,
1026 mutex
, ret
== 0, 0, 0, 0);
1030 PTH_FUNCS(int, pthreadZumutexZutimedlock
, pthread_mutex_timedlock_intercept
,
1031 (pthread_mutex_t
*mutex
, const struct timespec
*abs_timeout
),
1032 (mutex
, abs_timeout
));
1033 #if defined(VGO_solaris)
1035 pthreadZumutexZureltimedlockZunp
, pthread_mutex_timedlock_intercept
,
1036 (pthread_mutex_t
*mutex
, const struct timespec
*timeout
),
1038 #endif /* VGO_solaris */
1040 #if defined(HAVE_CLOCKID_T)
1041 static __always_inline
1042 int pthread_mutex_clocklock_intercept(pthread_mutex_t
*mutex
,
1044 const struct timespec
*abs_timeout
)
1048 VALGRIND_GET_ORIG_FN(fn
);
1049 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK
,
1050 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
1051 CALL_FN_W_WWW(ret
, fn
, mutex
, clockid
, abs_timeout
);
1052 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK
,
1053 mutex
, ret
== 0, 0, 0, 0);
1057 PTH_FUNCS(int, pthreadZumutexZuclocklock
, pthread_mutex_clocklock_intercept
,
1058 (pthread_mutex_t
*mutex
, clockid_t clockid
, const struct timespec
*abs_timeout
),
1059 (mutex
, clockid
, abs_timeout
));
1062 static __always_inline
1063 int pthread_mutex_unlock_intercept(pthread_mutex_t
*mutex
)
1067 VALGRIND_GET_ORIG_FN(fn
);
1068 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_UNLOCK
,
1069 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
1070 CALL_FN_W_W(ret
, fn
, mutex
);
1071 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_UNLOCK
,
1076 #if defined(VGO_solaris)
1077 /* On Solaris, pthread_mutex_unlock is a weak alias to mutex_unlock. */
1078 PTH_FUNCS(int, mutexZuunlock
, pthread_mutex_unlock_intercept
,
1079 (pthread_mutex_t
*mutex
), (mutex
));
1081 PTH_FUNCS(int, pthreadZumutexZuunlock
, pthread_mutex_unlock_intercept
,
1082 (pthread_mutex_t
*mutex
), (mutex
));
1083 #endif /* VGO_solaris */
1085 #if defined(VGO_solaris)
1086 /* Internal to libc. */
1087 static __always_inline
1088 void lmutex_unlock_intercept(mutex_t
*mutex
)
1091 VALGRIND_GET_ORIG_FN(fn
);
1092 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_UNLOCK
,
1094 DRD_(mutex_type
)((pthread_mutex_t
*) mutex
),
1096 CALL_FN_v_W(fn
, mutex
);
1097 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_UNLOCK
,
1101 PTH_FUNCS(void, lmutexZuunlock
, lmutex_unlock_intercept
,
1102 (mutex_t
*mutex
), (mutex
));
1103 #endif /* VGO_solaris */
1105 static __always_inline
1106 int pthread_cond_init_intercept(pthread_cond_t
* cond
,
1107 const pthread_condattr_t
* attr
)
1111 VALGRIND_GET_ORIG_FN(fn
);
1112 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_INIT
,
1114 CALL_FN_W_WW(ret
, fn
, cond
, attr
);
1115 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_INIT
,
1120 PTH_FUNCS(int, pthreadZucondZuinit
, pthread_cond_init_intercept
,
1121 (pthread_cond_t
* cond
, const pthread_condattr_t
* attr
),
1124 #if defined(VGO_solaris)
1125 static __always_inline
1126 int cond_init_intercept(cond_t
*cond
, int type
, void *arg
)
1130 VALGRIND_GET_ORIG_FN(fn
);
1131 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_INIT
,
1133 CALL_FN_W_WWW(ret
, fn
, cond
, type
, arg
);
1134 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_INIT
,
1139 PTH_FUNCS(int, condZuinit
, cond_init_intercept
,
1140 (cond_t
*cond
, int type
, void *arg
),
1142 #endif /* VGO_solaris */
1144 static __always_inline
1145 int pthread_cond_destroy_intercept(pthread_cond_t
* cond
)
1149 VALGRIND_GET_ORIG_FN(fn
);
1150 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_DESTROY
,
1152 CALL_FN_W_W(ret
, fn
, cond
);
1153 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_DESTROY
,
1154 cond
, ret
==0, 0, 0, 0);
1158 #if defined(VGO_solaris)
1159 /* On Solaris, pthread_cond_destroy is a weak alias to cond_destroy. */
1160 PTH_FUNCS(int, condZudestroy
, pthread_cond_destroy_intercept
,
1161 (pthread_cond_t
*cond
), (cond
));
1163 PTH_FUNCS(int, pthreadZucondZudestroy
, pthread_cond_destroy_intercept
,
1164 (pthread_cond_t
* cond
), (cond
));
1165 #endif /* VGO_solaris */
1167 static __always_inline
1168 int pthread_cond_wait_intercept(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
1172 VALGRIND_GET_ORIG_FN(fn
);
1173 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_WAIT
,
1174 cond
, mutex
, DRD_(mutex_type
)(mutex
), 0, 0);
1175 CALL_FN_W_WW(ret
, fn
, cond
, mutex
);
1176 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_WAIT
,
1177 cond
, mutex
, 1, 0, 0);
1181 PTH_FUNCS(int, pthreadZucondZuwait
, pthread_cond_wait_intercept
,
1182 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
),
1184 #if defined(VGO_solaris)
1185 PTH_FUNCS(int, condZuwait
, pthread_cond_wait_intercept
,
1186 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
),
1188 #endif /* VGO_solaris */
1190 static __always_inline
1191 int pthread_cond_timedwait_intercept(pthread_cond_t
*cond
,
1192 pthread_mutex_t
*mutex
,
1193 const struct timespec
* abstime
)
1197 VALGRIND_GET_ORIG_FN(fn
);
1198 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_WAIT
,
1199 cond
, mutex
, DRD_(mutex_type
)(mutex
), 0, 0);
1200 CALL_FN_W_WWW(ret
, fn
, cond
, mutex
, abstime
);
1201 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_WAIT
,
1202 cond
, mutex
, 1, 0, 0);
1206 PTH_FUNCS(int, pthreadZucondZutimedwait
, pthread_cond_timedwait_intercept
,
1207 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1208 const struct timespec
* abstime
),
1209 (cond
, mutex
, abstime
));
1210 #if defined(VGO_solaris)
1211 PTH_FUNCS(int, condZutimedwait
, pthread_cond_timedwait_intercept
,
1212 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1213 const struct timespec
*timeout
),
1214 (cond
, mutex
, timeout
));
1215 PTH_FUNCS(int, condZureltimedwait
, pthread_cond_timedwait_intercept
,
1216 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1217 const struct timespec
*timeout
),
1218 (cond
, mutex
, timeout
));
1219 #endif /* VGO_solaris */
1222 #if defined(HAVE_CLOCKID_T)
1223 static __always_inline
1224 int pthread_cond_clockwait_intercept(pthread_cond_t
*cond
,
1225 pthread_mutex_t
*mutex
,
1227 const struct timespec
* abstime
)
1231 VALGRIND_GET_ORIG_FN(fn
);
1232 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_WAIT
,
1233 cond
, mutex
, DRD_(mutex_type
)(mutex
), 0, 0);
1234 CALL_FN_W_WWWW(ret
, fn
, cond
, mutex
, clockid
, abstime
);
1235 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_WAIT
,
1236 cond
, mutex
, 1, 0, 0);
1240 PTH_FUNCS(int, pthreadZucondZuclockwait
, pthread_cond_clockwait_intercept
,
1241 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1242 clockid_t clockid
, const struct timespec
* abstime
),
1243 (cond
, mutex
, clockid
, abstime
));
1247 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
1248 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
1249 // two. Intercepting all pthread_cond_signal* functions will cause only one
1250 // argument to be passed to pthread_cond_signal_np() and hence will cause this
1251 // last function to crash.
1253 static __always_inline
1254 int pthread_cond_signal_intercept(pthread_cond_t
* cond
)
1258 VALGRIND_GET_ORIG_FN(fn
);
1259 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_SIGNAL
,
1261 CALL_FN_W_W(ret
, fn
, cond
);
1262 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_SIGNAL
,
1267 #if defined(VGO_solaris)
1268 /* On Solaris, pthread_cond_signal is a weak alias to cond_signal. */
1269 PTH_FUNCS(int, condZusignal
, pthread_cond_signal_intercept
,
1270 (pthread_cond_t
*cond
), (cond
));
1272 PTH_FUNCS(int, pthreadZucondZusignal
, pthread_cond_signal_intercept
,
1273 (pthread_cond_t
* cond
), (cond
));
1274 #endif /* VGO_solaris */
1276 static __always_inline
1277 int pthread_cond_broadcast_intercept(pthread_cond_t
* cond
)
1281 VALGRIND_GET_ORIG_FN(fn
);
1282 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_BROADCAST
,
1284 CALL_FN_W_W(ret
, fn
, cond
);
1285 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_BROADCAST
,
1290 #if defined(VGO_solaris)
1291 /* On Solaris, pthread_cond_broadcast is a weak alias to cond_broadcast. */
1292 PTH_FUNCS(int, condZubroadcast
, pthread_cond_broadcast_intercept
,
1293 (pthread_cond_t
*cond
), (cond
));
1295 PTH_FUNCS(int, pthreadZucondZubroadcast
, pthread_cond_broadcast_intercept
,
1296 (pthread_cond_t
* cond
), (cond
));
1297 #endif /* VGO_solaris */
1299 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1300 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1301 static __always_inline
1302 int pthread_spin_init_intercept(pthread_spinlock_t
*spinlock
, int pshared
)
1306 VALGRIND_GET_ORIG_FN(fn
);
1307 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SPIN_INIT_OR_UNLOCK
,
1308 spinlock
, 0, 0, 0, 0);
1309 CALL_FN_W_WW(ret
, fn
, spinlock
, pshared
);
1310 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SPIN_INIT_OR_UNLOCK
,
1311 spinlock
, 0, 0, 0, 0);
1315 PTH_FUNCS(int, pthreadZuspinZuinit
, pthread_spin_init_intercept
,
1316 (pthread_spinlock_t
*spinlock
, int pshared
), (spinlock
, pshared
));
1318 static __always_inline
1319 int pthread_spin_destroy_intercept(pthread_spinlock_t
*spinlock
)
1323 VALGRIND_GET_ORIG_FN(fn
);
1324 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_DESTROY
,
1325 spinlock
, 0, 0, 0, 0);
1326 CALL_FN_W_W(ret
, fn
, spinlock
);
1327 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_DESTROY
,
1328 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1332 PTH_FUNCS(int, pthreadZuspinZudestroy
, pthread_spin_destroy_intercept
,
1333 (pthread_spinlock_t
*spinlock
), (spinlock
));
1335 static __always_inline
1336 int pthread_spin_lock_intercept(pthread_spinlock_t
*spinlock
)
1340 VALGRIND_GET_ORIG_FN(fn
);
1341 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK
,
1342 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1343 CALL_FN_W_W(ret
, fn
, spinlock
);
1344 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK
,
1345 spinlock
, ret
== 0, 0, 0, 0);
1349 PTH_FUNCS(int, pthreadZuspinZulock
, pthread_spin_lock_intercept
,
1350 (pthread_spinlock_t
*spinlock
), (spinlock
));
1352 static __always_inline
1353 int pthread_spin_trylock_intercept(pthread_spinlock_t
*spinlock
)
1357 VALGRIND_GET_ORIG_FN(fn
);
1358 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK
,
1359 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1360 CALL_FN_W_W(ret
, fn
, spinlock
);
1361 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK
,
1362 spinlock
, ret
== 0, 0, 0, 0);
1366 PTH_FUNCS(int, pthreadZuspinZutrylock
, pthread_spin_trylock_intercept
,
1367 (pthread_spinlock_t
*spinlock
), (spinlock
));
1369 static __always_inline
1370 int pthread_spin_unlock_intercept(pthread_spinlock_t
*spinlock
)
1374 VALGRIND_GET_ORIG_FN(fn
);
1375 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SPIN_INIT_OR_UNLOCK
,
1376 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1377 CALL_FN_W_W(ret
, fn
, spinlock
);
1378 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SPIN_INIT_OR_UNLOCK
,
1379 spinlock
, 0, 0, 0, 0);
1383 PTH_FUNCS(int, pthreadZuspinZuunlock
, pthread_spin_unlock_intercept
,
1384 (pthread_spinlock_t
*spinlock
), (spinlock
));
1385 #endif // HAVE_PTHREAD_SPIN_LOCK
1388 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1389 static __always_inline
1390 int pthread_barrier_init_intercept(pthread_barrier_t
* barrier
,
1391 const pthread_barrierattr_t
* attr
,
1396 VALGRIND_GET_ORIG_FN(fn
);
1397 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_BARRIER_INIT
,
1398 barrier
, pthread_barrier
, count
, 0, 0);
1399 CALL_FN_W_WWW(ret
, fn
, barrier
, attr
, count
);
1400 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_BARRIER_INIT
,
1401 barrier
, pthread_barrier
, 0, 0, 0);
1405 PTH_FUNCS(int, pthreadZubarrierZuinit
, pthread_barrier_init_intercept
,
1406 (pthread_barrier_t
* barrier
, const pthread_barrierattr_t
* attr
,
1407 unsigned count
), (barrier
, attr
, count
));
1409 static __always_inline
1410 int pthread_barrier_destroy_intercept(pthread_barrier_t
* barrier
)
1414 VALGRIND_GET_ORIG_FN(fn
);
1415 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_BARRIER_DESTROY
,
1416 barrier
, pthread_barrier
, 0, 0, 0);
1417 CALL_FN_W_W(ret
, fn
, barrier
);
1418 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_BARRIER_DESTROY
,
1419 barrier
, pthread_barrier
, 0, 0, 0);
1423 PTH_FUNCS(int, pthreadZubarrierZudestroy
, pthread_barrier_destroy_intercept
,
1424 (pthread_barrier_t
* barrier
), (barrier
));
1426 static __always_inline
1427 int pthread_barrier_wait_intercept(pthread_barrier_t
* barrier
)
1431 VALGRIND_GET_ORIG_FN(fn
);
1432 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_BARRIER_WAIT
,
1433 barrier
, pthread_barrier
, 0, 0, 0);
1434 CALL_FN_W_W(ret
, fn
, barrier
);
1435 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_BARRIER_WAIT
,
1436 barrier
, pthread_barrier
,
1437 ret
== 0 || ret
== PTHREAD_BARRIER_SERIAL_THREAD
,
1438 ret
== PTHREAD_BARRIER_SERIAL_THREAD
, 0);
1442 PTH_FUNCS(int, pthreadZubarrierZuwait
, pthread_barrier_wait_intercept
,
1443 (pthread_barrier_t
* barrier
), (barrier
));
1444 #endif // HAVE_PTHREAD_BARRIER_INIT
1447 static __always_inline
1448 int sem_init_intercept(sem_t
*sem
, int pshared
, unsigned int value
)
1452 VALGRIND_GET_ORIG_FN(fn
);
1453 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_INIT
,
1454 sem
, pshared
, value
, 0, 0);
1455 CALL_FN_W_WWW(ret
, fn
, sem
, pshared
, value
);
1456 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_INIT
,
1461 #if defined(VGO_freebsd)
1462 LIBC_FUNC(int, semZuinit
, sem_init_intercept
,
1463 (sem_t
*sem
, int pshared
, unsigned int value
), (sem
, pshared
, value
));
1465 PTH_FUNCS(int, semZuinit
, sem_init_intercept
,
1466 (sem_t
*sem
, int pshared
, unsigned int value
), (sem
, pshared
, value
));
1469 #if defined(VGO_solaris)
1470 static __always_inline
1471 int sema_init_intercept(sema_t
*sem
, unsigned int value
, int type
, void *arg
)
1475 VALGRIND_GET_ORIG_FN(fn
);
1476 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_INIT
,
1477 sem
, type
== USYNC_PROCESS
? 1 : 0,
1479 CALL_FN_W_WWWW(ret
, fn
, sem
, value
, type
, arg
);
1480 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_INIT
,
1485 PTH_FUNCS(int, semaZuinit
, sema_init_intercept
,
1486 (sema_t
*sem
, unsigned int value
, int type
, void *arg
),
1487 (sem
, value
, type
, arg
));
1488 #endif /* VGO_solaris */
1490 static __always_inline
1491 int sem_destroy_intercept(sem_t
*sem
)
1495 VALGRIND_GET_ORIG_FN(fn
);
1496 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_DESTROY
,
1498 CALL_FN_W_W(ret
, fn
, sem
);
1499 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_DESTROY
,
1504 #if defined(VGO_freebsd)
1505 LIBC_FUNC(int, semZudestroy
, sem_destroy_intercept
, (sem_t
*sem
), (sem
));
1507 PTH_FUNCS(int, semZudestroy
, sem_destroy_intercept
, (sem_t
*sem
), (sem
));
1510 #if defined(VGO_solaris)
1511 PTH_FUNCS(int, semaZudestroy
, sem_destroy_intercept
, (sem_t
*sem
), (sem
));
1512 #endif /* VGO_solaris */
1514 static __always_inline
1515 sem_t
* sem_open_intercept(const char *name
, int oflag
, mode_t mode
,
1520 VALGRIND_GET_ORIG_FN(fn
);
1521 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_OPEN
,
1522 name
, oflag
, mode
, value
, 0);
1523 CALL_FN_W_WWWW(ret
, fn
, name
, oflag
, mode
, value
);
1524 // To do: figure out why gcc 9.2.1 miscompiles this function if the printf()
1525 // call below is left out.
1527 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_OPEN
,
1528 ret
!= SEM_FAILED
? ret
: 0,
1529 name
, oflag
, mode
, value
);
1533 #if defined(VGO_freebsd)
1534 LIBC_FUNC(sem_t
*, semZuopen
, sem_open_intercept
,
1535 (const char *name
, int oflag
, mode_t mode
, unsigned int value
),
1536 (name
, oflag
, mode
, value
));
1538 PTH_FUNCS(sem_t
*, semZuopen
, sem_open_intercept
,
1539 (const char *name
, int oflag
, mode_t mode
, unsigned int value
),
1540 (name
, oflag
, mode
, value
));
1543 static __always_inline
int sem_close_intercept(sem_t
*sem
)
1547 VALGRIND_GET_ORIG_FN(fn
);
1548 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_CLOSE
,
1550 CALL_FN_W_W(ret
, fn
, sem
);
1551 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_CLOSE
,
1556 #if defined(VGO_freebsd)
1557 LIBC_FUNC(int, semZuclose
, sem_close_intercept
, (sem_t
*sem
), (sem
));
1559 PTH_FUNCS(int, semZuclose
, sem_close_intercept
, (sem_t
*sem
), (sem
));
1562 static __always_inline
int sem_wait_intercept(sem_t
*sem
)
1566 VALGRIND_GET_ORIG_FN(fn
);
1567 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT
,
1569 CALL_FN_W_W(ret
, fn
, sem
);
1570 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT
,
1571 sem
, ret
== 0, 0, 0, 0);
1575 #if defined(VGO_freebsd)
1576 LIBC_FUNC(int, semZuwait
, sem_wait_intercept
, (sem_t
*sem
), (sem
));
1578 PTH_FUNCS(int, semZuwait
, sem_wait_intercept
, (sem_t
*sem
), (sem
));
1581 #if defined(VGO_solaris)
1582 PTH_FUNCS(int, semaZuwait
, sem_wait_intercept
, (sem_t
*sem
), (sem
));
1583 #endif /* VGO_solaris */
1585 static __always_inline
int sem_trywait_intercept(sem_t
*sem
)
1589 VALGRIND_GET_ORIG_FN(fn
);
1590 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT
,
1592 CALL_FN_W_W(ret
, fn
, sem
);
1593 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT
,
1594 sem
, ret
== 0, 0, 0, 0);
1598 #if defined(VGO_freebsd)
1599 LIBC_FUNC(int, semZutrywait
, sem_trywait_intercept
, (sem_t
*sem
), (sem
));
1601 PTH_FUNCS(int, semZutrywait
, sem_trywait_intercept
, (sem_t
*sem
), (sem
));
1603 #if defined(VGO_solaris)
1604 PTH_FUNCS(int, semaZutrywait
, sem_trywait_intercept
, (sem_t
*sem
), (sem
));
1605 #endif /* VGO_solaris */
1607 static __always_inline
1608 int sem_timedwait_intercept(sem_t
*sem
, const struct timespec
*abs_timeout
)
1612 VALGRIND_GET_ORIG_FN(fn
);
1613 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT
,
1615 CALL_FN_W_WW(ret
, fn
, sem
, abs_timeout
);
1616 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT
,
1617 sem
, ret
== 0, 0, 0, 0);
1621 #if defined(VGO_freebsd)
1622 LIBC_FUNC(int, semZutimedwait
, sem_timedwait_intercept
,
1623 (sem_t
*sem
, const struct timespec
*abs_timeout
),
1624 (sem
, abs_timeout
));
1626 PTH_FUNCS(int, semZutimedwait
, sem_timedwait_intercept
,
1627 (sem_t
*sem
, const struct timespec
*abs_timeout
),
1628 (sem
, abs_timeout
));
1630 #if defined(VGO_solaris)
1631 PTH_FUNCS(int, semaZutimedwait
, sem_timedwait_intercept
,
1632 (sem_t
*sem
, const struct timespec
*timeout
),
1634 PTH_FUNCS(int, semaZureltimedwait
, sem_timedwait_intercept
,
1635 (sem_t
*sem
, const struct timespec
*timeout
),
1637 #endif /* VGO_solaris */
1639 #if defined(VGO_freebsd)
1640 static __always_inline
1641 int sem_clockwait_np_intercept(sem_t
* sem
, clockid_t clock_id
, int flags
,
1642 const struct timespec
* rqtp
, struct timespec
* rmtp
)
1646 VALGRIND_GET_ORIG_FN(fn
);
1647 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT
,
1649 CALL_FN_W_5W(ret
, fn
, sem
, clock_id
, flags
, rqtp
, rmtp
);
1650 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT
,
1651 sem
, ret
== 0, 0, 0, 0);
1655 LIBC_FUNC(int, semZuclockwaitZunp
, sem_clockwait_np_intercept
,
1656 (sem_t
* sem
, clockid_t clock_id
, int flags
,
1657 const struct timespec
* rqtp
, struct timespec
* rmtp
),
1658 (sem
, clock_id
, flags
, rqtp
, rmtp
));
1661 static __always_inline
int sem_post_intercept(sem_t
*sem
)
1665 VALGRIND_GET_ORIG_FN(fn
);
1666 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_POST
,
1668 CALL_FN_W_W(ret
, fn
, sem
);
1669 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_POST
,
1670 sem
, ret
== 0, 0, 0, 0);
1674 #if defined(VGO_freebsd)
1675 LIBC_FUNC(int, semZupost
, sem_post_intercept
, (sem_t
*sem
), (sem
));
1677 PTH_FUNCS(int, semZupost
, sem_post_intercept
, (sem_t
*sem
), (sem
));
1679 #if defined(VGO_solaris)
1680 PTH_FUNCS(int, semaZupost
, sem_post_intercept
, (sem_t
*sem
), (sem
));
1681 #endif /* VGO_solaris */
1683 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1684 functions have to be conditionally compiled. */
1685 #if defined(HAVE_PTHREAD_RWLOCK_T)
1687 static __always_inline
1688 int pthread_rwlock_init_intercept(pthread_rwlock_t
* rwlock
,
1689 const pthread_rwlockattr_t
* attr
)
1693 VALGRIND_GET_ORIG_FN(fn
);
1694 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_INIT
,
1695 rwlock
, 0, 0, 0, 0);
1696 CALL_FN_W_WW(ret
, fn
, rwlock
, attr
);
1697 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_INIT
,
1698 rwlock
, 0, 0, 0, 0);
1703 pthreadZurwlockZuinit
, pthread_rwlock_init_intercept
,
1704 (pthread_rwlock_t
* rwlock
, const pthread_rwlockattr_t
* attr
),
1707 #if defined(VGO_solaris)
1708 static __always_inline
1709 int rwlock_init_intercept(rwlock_t
*rwlock
, int type
, void *arg
)
1713 VALGRIND_GET_ORIG_FN(fn
);
1714 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_INIT
,
1715 rwlock
, 0, 0, 0, 0);
1716 CALL_FN_W_WWW(ret
, fn
, rwlock
, type
, arg
);
1717 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_INIT
,
1718 rwlock
, 0, 0, 0, 0);
1722 PTH_FUNCS(int, rwlockZuinit
, rwlock_init_intercept
,
1723 (rwlock_t
*rwlock
, int type
, void *arg
),
1724 (rwlock
, type
, arg
));
1725 #endif /* VGO_solaris */
1727 static __always_inline
1728 int pthread_rwlock_destroy_intercept(pthread_rwlock_t
* rwlock
)
1732 VALGRIND_GET_ORIG_FN(fn
);
1733 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_DESTROY
,
1734 rwlock
, 0, 0, 0, 0);
1735 CALL_FN_W_W(ret
, fn
, rwlock
);
1736 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_DESTROY
,
1737 rwlock
, 0, 0, 0, 0);
1741 #if defined(VGO_solaris)
1742 /* On Solaris, pthread_rwlock_destroy is a weak alias to rwlock_destroy. */
1744 rwlockZudestroy
, pthread_rwlock_destroy_intercept
,
1745 (pthread_rwlock_t
*rwlock
), (rwlock
));
1748 pthreadZurwlockZudestroy
, pthread_rwlock_destroy_intercept
,
1749 (pthread_rwlock_t
* rwlock
), (rwlock
));
1750 #endif /* VGO_solaris */
1752 static __always_inline
1753 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t
* rwlock
)
1757 VALGRIND_GET_ORIG_FN(fn
);
1758 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK
,
1759 rwlock
, 0, 0, 0, 0);
1760 CALL_FN_W_W(ret
, fn
, rwlock
);
1761 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK
,
1762 rwlock
, ret
== 0, 0, 0, 0);
1766 #if defined(VGO_solaris)
1767 /* On Solaris, pthread_rwlock_rdlock is a weak alias to rw_rdlock. */
1769 rwZurdlock
, pthread_rwlock_rdlock_intercept
,
1770 (pthread_rwlock_t
*rwlock
), (rwlock
));
1773 pthreadZurwlockZurdlock
, pthread_rwlock_rdlock_intercept
,
1774 (pthread_rwlock_t
* rwlock
), (rwlock
));
1775 #endif /* VGO_solaris */
1777 #if defined(VGO_solaris)
1778 /* Internal to libc. */
1779 static __always_inline
1780 void lrw_rdlock_intercept(rwlock_t
*rwlock
)
1783 VALGRIND_GET_ORIG_FN(fn
);
1784 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK
,
1785 rwlock
, 0, 0, 0, 0);
1786 CALL_FN_v_W(fn
, rwlock
);
1787 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK
,
1788 rwlock
, True
/* took_lock */, 0, 0, 0);
1791 PTH_FUNCS(void, lrwZurdlock
, lrw_rdlock_intercept
,
1792 (rwlock_t
*rwlock
), (rwlock
));
1793 #endif /* VGO_solaris */
1795 static __always_inline
1796 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t
* rwlock
)
1800 VALGRIND_GET_ORIG_FN(fn
);
1801 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK
,
1802 rwlock
, 0, 0, 0, 0);
1803 CALL_FN_W_W(ret
, fn
, rwlock
);
1804 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK
,
1805 rwlock
, ret
== 0, 0, 0, 0);
1809 #if defined(VGO_solaris)
1810 /* On Solaris, pthread_rwlock_wrlock is a weak alias to rw_wrlock. */
1812 rwZuwrlock
, pthread_rwlock_wrlock_intercept
,
1813 (pthread_rwlock_t
*rwlock
), (rwlock
));
1816 pthreadZurwlockZuwrlock
, pthread_rwlock_wrlock_intercept
,
1817 (pthread_rwlock_t
* rwlock
), (rwlock
));
1818 #endif /* VGO_solaris */
1820 #if defined(VGO_solaris)
1821 /* Internal to libc. */
1822 static __always_inline
1823 void lrw_wrlock_intercept(rwlock_t
*rwlock
)
1826 VALGRIND_GET_ORIG_FN(fn
);
1827 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK
,
1828 rwlock
, 0, 0, 0, 0);
1829 CALL_FN_v_W(fn
, rwlock
);
1830 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK
,
1831 rwlock
, True
/* took_lock */, 0, 0, 0);
1834 PTH_FUNCS(void, lrwZuwrlock
, lrw_wrlock_intercept
,
1835 (rwlock_t
*rwlock
), (rwlock
));
1836 #endif /* VGO_solaris */
1838 static __always_inline
1839 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t
* rwlock
,
1840 const struct timespec
*timeout
)
1844 VALGRIND_GET_ORIG_FN(fn
);
1845 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK
,
1846 rwlock
, 0, 0, 0, 0);
1847 CALL_FN_W_WW(ret
, fn
, rwlock
, timeout
);
1848 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK
,
1849 rwlock
, ret
== 0, 0, 0, 0);
1854 pthreadZurwlockZutimedrdlock
, pthread_rwlock_timedrdlock_intercept
,
1855 (pthread_rwlock_t
* rwlock
, const struct timespec
*timeout
),
1857 #if defined(VGO_solaris)
1858 PTH_FUNCS(int, pthreadZurwlockZureltimedrdlockZunp
,
1859 pthread_rwlock_timedrdlock_intercept
,
1860 (pthread_rwlock_t
*rwlock
, const struct timespec
*timeout
),
1862 #endif /* VGO_solaris */
1865 #if defined(HAVE_CLOCKID_T)
1866 static __always_inline
1867 int pthread_rwlock_clockrdlock_intercept(pthread_rwlock_t
* rwlock
,
1869 const struct timespec
*timeout
)
1873 VALGRIND_GET_ORIG_FN(fn
);
1874 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK
,
1875 rwlock
, 0, 0, 0, 0);
1876 CALL_FN_W_WWW(ret
, fn
, rwlock
, clockid
, timeout
);
1877 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK
,
1878 rwlock
, ret
== 0, 0, 0, 0);
1883 pthreadZurwlockZuclockrdlock
, pthread_rwlock_clockrdlock_intercept
,
1884 (pthread_rwlock_t
* rwlock
, clockid_t clockid
, const struct timespec
*timeout
),
1885 (rwlock
, clockid
, timeout
));
1888 static __always_inline
1889 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t
* rwlock
,
1890 const struct timespec
*timeout
)
1894 VALGRIND_GET_ORIG_FN(fn
);
1895 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK
,
1896 rwlock
, 0, 0, 0, 0);
1897 CALL_FN_W_WW(ret
, fn
, rwlock
, timeout
);
1898 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK
,
1899 rwlock
, ret
== 0, 0, 0, 0);
1904 pthreadZurwlockZutimedwrlock
, pthread_rwlock_timedwrlock_intercept
,
1905 (pthread_rwlock_t
* rwlock
, const struct timespec
*timeout
),
1907 #if defined(VGO_solaris)
1908 PTH_FUNCS(int, pthreadZurwlockZureltimedwrlockZunp
,
1909 pthread_rwlock_timedwrlock_intercept
,
1910 (pthread_rwlock_t
*rwlock
, const struct timespec
*timeout
),
1912 #endif /* VGO_solaris */
1915 #if defined(HAVE_CLOCKID_T)
1916 static __always_inline
1917 int pthread_rwlock_clockwrlock_intercept(pthread_rwlock_t
* rwlock
,
1919 const struct timespec
*timeout
)
1923 VALGRIND_GET_ORIG_FN(fn
);
1924 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK
,
1925 rwlock
, 0, 0, 0, 0);
1926 CALL_FN_W_WWW(ret
, fn
, rwlock
, clockid
, timeout
);
1927 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK
,
1928 rwlock
, ret
== 0, 0, 0, 0);
1933 pthreadZurwlockZuclockwrlock
, pthread_rwlock_clockwrlock_intercept
,
1934 (pthread_rwlock_t
* rwlock
, clockid_t clockid
, const struct timespec
*timeout
),
1935 (rwlock
, clockid
, timeout
));
1939 static __always_inline
1940 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t
* rwlock
)
1944 VALGRIND_GET_ORIG_FN(fn
);
1945 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK
,
1946 rwlock
, 0, 0, 0, 0);
1947 CALL_FN_W_W(ret
, fn
, rwlock
);
1948 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK
,
1949 rwlock
, ret
== 0, 0, 0, 0);
1953 #if defined(VGO_solaris)
1954 /* On Solaris, pthread_rwlock_tryrdlock is a weak alias to rw_tryrdlock. */
1956 rwZutryrdlock
, pthread_rwlock_tryrdlock_intercept
,
1957 (pthread_rwlock_t
*rwlock
), (rwlock
));
1960 pthreadZurwlockZutryrdlock
, pthread_rwlock_tryrdlock_intercept
,
1961 (pthread_rwlock_t
* rwlock
), (rwlock
));
1962 #endif /* VGO_solaris */
1964 static __always_inline
1965 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t
* rwlock
)
1969 VALGRIND_GET_ORIG_FN(fn
);
1970 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK
,
1971 rwlock
, 0, 0, 0, 0);
1972 CALL_FN_W_W(ret
, fn
, rwlock
);
1973 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK
,
1974 rwlock
, ret
== 0, 0, 0, 0);
1978 #if defined(VGO_solaris)
1979 /* On Solaris, pthread_rwlock_trywrlock is a weak alias to rw_trywrlock. */
1981 rwZutrywrlock
, pthread_rwlock_trywrlock_intercept
,
1982 (pthread_rwlock_t
*rwlock
), (rwlock
));
1985 pthreadZurwlockZutrywrlock
, pthread_rwlock_trywrlock_intercept
,
1986 (pthread_rwlock_t
* rwlock
), (rwlock
));
1987 #endif /* VGO_solaris */
1989 static __always_inline
1990 int pthread_rwlock_unlock_intercept(pthread_rwlock_t
* rwlock
)
1994 VALGRIND_GET_ORIG_FN(fn
);
1995 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_UNLOCK
,
1996 rwlock
, 0, 0, 0, 0);
1997 CALL_FN_W_W(ret
, fn
, rwlock
);
1998 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_UNLOCK
,
1999 rwlock
, ret
== 0, 0, 0, 0);
2003 #if defined(VGO_solaris)
2004 /* On Solaris, pthread_rwlock_unlock is a weak alias to rw_unlock. */
2006 rwZuunlock
, pthread_rwlock_unlock_intercept
,
2007 (pthread_rwlock_t
*rwlock
), (rwlock
));
2010 pthreadZurwlockZuunlock
, pthread_rwlock_unlock_intercept
,
2011 (pthread_rwlock_t
* rwlock
), (rwlock
));
2012 #endif /* VGO_solaris */
2014 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */