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 dlclose(dlopen("/lib/libthr.so.3", RTLD_NOW
|RTLD_GLOBAL
|RTLD_NODELETE
));
292 DRD_(check_threading_library
)();
293 DRD_(set_pthread_id
)();
294 #if defined(VGO_solaris)
295 if ((DRD_(rtld_bind_guard
) == NULL
) || (DRD_(rtld_bind_clear
) == NULL
)) {
297 "Bind guard functions for the runtime linker (ld.so.1) were not intercepted.\n"
298 "This means the interface between libc and runtime linker changed and DRD\n"
299 "needs to be ported properly. Giving up.\n");
305 static __always_inline
void DRD_(ignore_mutex_ordering
)(pthread_mutex_t
*mutex
)
307 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_IGNORE_MUTEX_ORDERING
,
311 static void DRD_(sema_init
)(DrdSema
* sema
)
313 DRD_IGNORE_VAR(*sema
);
314 pthread_mutex_init(&sema
->mutex
, NULL
);
315 DRD_(ignore_mutex_ordering
)(&sema
->mutex
);
316 pthread_cond_init(&sema
->cond
, NULL
);
320 static void DRD_(sema_destroy
)(DrdSema
* sema
)
322 pthread_mutex_destroy(&sema
->mutex
);
323 pthread_cond_destroy(&sema
->cond
);
326 static void DRD_(sema_down
)(DrdSema
* sema
)
328 pthread_mutex_lock(&sema
->mutex
);
329 while (sema
->counter
== 0)
330 pthread_cond_wait(&sema
->cond
, &sema
->mutex
);
332 pthread_mutex_unlock(&sema
->mutex
);
335 static void DRD_(sema_up
)(DrdSema
* sema
)
337 pthread_mutex_lock(&sema
->mutex
);
339 pthread_cond_signal(&sema
->cond
);
340 pthread_mutex_unlock(&sema
->mutex
);
344 * POSIX threads and DRD each have their own mutex type identification.
345 * Convert POSIX threads' mutex type to DRD's mutex type. In the code below
346 * if-statements are used to test the value of 'kind' instead of a switch
347 * statement because some of the PTHREAD_MUTEX_ macro's may have the same
350 static MutexT
DRD_(pthread_to_drd_mutex_type
)(int kind
)
353 * Static checkers don't like this as there are repeated branch
354 * but because there is variation between different platforms
355 * it's messy to make something without repetition.
357 * See also PTHREAD_MUTEX_KIND_MASK_NP in glibc source file
360 kind
&= PTHREAD_MUTEX_RECURSIVE
| PTHREAD_MUTEX_ERRORCHECK
|
361 PTHREAD_MUTEX_NORMAL
| PTHREAD_MUTEX_DEFAULT
;
363 if (kind
== PTHREAD_MUTEX_RECURSIVE
) {
364 return mutex_type_recursive_mutex
;
366 if (kind
== PTHREAD_MUTEX_ERRORCHECK
) {
367 return mutex_type_errorcheck_mutex
;
369 if (kind
== PTHREAD_MUTEX_NORMAL
) {
370 return mutex_type_default_mutex
;
372 if (kind
== PTHREAD_MUTEX_DEFAULT
) {
373 // On FreeBSD PTHREAD_MUTEX_DEFAULT is the same as PTHREAD_MUTEX_ERRORCHECK
374 // so this code is unreachable, but that's not true for all platforms
375 // so just ignore the warning
376 // coverity[DEADCODE:FALSE]
377 return mutex_type_default_mutex
;
379 #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
380 if (kind
== PTHREAD_MUTEX_ADAPTIVE_NP
) {
381 return mutex_type_default_mutex
;
384 return mutex_type_invalid_mutex
;
387 #if defined(VGO_solaris)
389 * Solaris threads and DRD each have their own mutex type identification.
390 * Convert Solaris threads' mutex type to DRD's mutex type.
392 static MutexT
DRD_(thread_to_drd_mutex_type
)(int type
)
394 if (type
& LOCK_RECURSIVE
) {
395 return mutex_type_recursive_mutex
;
396 } else if (type
& LOCK_ERRORCHECK
) {
397 return mutex_type_errorcheck_mutex
;
399 return mutex_type_default_mutex
;
402 #endif /* VGO_solaris */
404 #define IS_ALIGNED(p) (((uintptr_t)(p) & (sizeof(*(p)) - 1)) == 0)
407 * Read the mutex type stored in the client memory used for the mutex
410 * @note This function depends on the implementation of the POSIX threads
411 * library -- the POSIX standard does not define the name of the member in
412 * which the mutex type is stored.
413 * @note The function mutex_type() has been declared inline in order
414 * to avoid that it shows up in call stacks (drd/tests/...exp* files).
415 * @note glibc stores the mutex type in the lowest two bits, and uses the
416 * higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
417 * PTHREAD_MUTEXATTR_FLAG_PSHARED.
419 static __always_inline MutexT
DRD_(mutex_type
)(pthread_mutex_t
* mutex
)
421 MutexT mutex_type
= mutex_type_unknown
;
423 ANNOTATE_IGNORE_READS_BEGIN();
424 #if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
425 /* glibc + LinuxThreads. */
426 if (IS_ALIGNED(&mutex
->__m_kind
))
428 const int kind
= mutex
->__m_kind
& 3;
429 mutex_type
= DRD_(pthread_to_drd_mutex_type
)(kind
);
431 #elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
433 if (IS_ALIGNED(&mutex
->__data
.__kind
))
435 const int kind
= mutex
->__data
.__kind
& 3;
436 mutex_type
= DRD_(pthread_to_drd_mutex_type
)(kind
);
438 #elif defined(VGO_solaris)
440 const int type
= ((mutex_t
*) mutex
)->vki_mutex_type
;
441 mutex_type
= DRD_(thread_to_drd_mutex_type
)(type
);
445 * Another POSIX threads implementation. The mutex type won't be printed
446 * when enabling --trace-mutex=yes.
449 ANNOTATE_IGNORE_READS_END();
455 * Tell DRD whether 'tid' is a joinable thread or a detached thread.
457 static void DRD_(set_joinable
)(const pthread_t tid
, const int joinable
)
459 assert(joinable
== 0 || joinable
== 1);
460 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_SET_JOINABLE
,
461 tid
, joinable
, 0, 0, 0);
464 /** Tell DRD that the calling thread is about to enter pthread_create(). */
465 static __always_inline
void DRD_(entering_pthread_create
)(void)
467 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_ENTERING_PTHREAD_CREATE
,
471 /** Tell DRD that the calling thread has left pthread_create(). */
472 static __always_inline
void DRD_(left_pthread_create
)(void)
474 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_LEFT_PTHREAD_CREATE
,
479 * Entry point for newly created threads. This function is called from the
480 * thread created by pthread_create().
482 static void* DRD_(thread_wrapper
)(void* arg
)
484 DrdPosixThreadArgs
* arg_ptr
;
485 DrdPosixThreadArgs arg_copy
;
487 arg_ptr
= (DrdPosixThreadArgs
*)arg
;
490 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_SET_PTHREADID
,
491 pthread_self(), 0, 0, 0, 0);
493 DRD_(set_joinable
)(pthread_self(),
494 arg_copy
.detachstate
== PTHREAD_CREATE_JOINABLE
);
497 * Only set 'wrapper_started' after VG_USERREQ__SET_PTHREADID and
498 * DRD_(set_joinable)() have been invoked to avoid a race with
499 * a pthread_detach() invocation for this thread from another thread.
501 DRD_(sema_up
)(arg_copy
.wrapper_started
);
503 return (arg_copy
.start
)(arg_copy
.arg
);
507 * Return 1 if the LinuxThreads implementation of POSIX Threads has been
508 * detected, and 0 otherwise.
510 * @see For more information about the confstr() function, see also
511 * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
513 static int DRD_(detected_linuxthreads
)(void)
516 #if defined(_CS_GNU_LIBPTHREAD_VERSION)
517 /* Linux with a recent glibc. */
520 len
= confstr(_CS_GNU_LIBPTHREAD_VERSION
, buffer
, sizeof(buffer
));
521 assert(len
<= sizeof(buffer
));
522 return len
> 0 && buffer
[0] == 'l';
524 /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
528 /* Another OS than Linux, hence no LinuxThreads. */
534 * Stop and print an error message in case a non-supported threading
535 * library implementation (LinuxThreads) has been detected.
537 static void DRD_(check_threading_library
)(void)
539 if (DRD_(detected_linuxthreads
)())
541 if (getenv("LD_ASSUME_KERNEL"))
544 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
545 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
546 "after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
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 upgraded to a newer version of your Linux distribution.\n"
563 * Update DRD's state information about the current thread.
565 static void DRD_(set_pthread_id
)(void)
567 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_SET_PTHREADID
,
568 pthread_self(), 0, 0, 0, 0);
572 * Note: as of today there exist three different versions of pthread_create
574 * - pthread_create@GLIBC_2.0
575 * - pthread_create@@GLIBC_2.1
576 * - pthread_create@@GLIBC_2.2.5
577 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
578 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
579 * versions have been implemented. In any glibc version where more than one
580 * pthread_create function has been implemented, older versions call the
581 * newer versions. Or: the pthread_create* wrapper defined below can be
582 * called recursively. Any code in this wrapper should take this in account.
583 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
584 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
585 * See also the implementation of pthread_create@GLIBC_2.0 in
586 * glibc-2.9/nptl/pthread_create.c.
589 static __always_inline
590 int pthread_create_intercept(pthread_t
* thread
, const pthread_attr_t
* attr
,
591 void* (*start
)(void*), void* arg
)
595 DrdSema wrapper_started
;
596 DrdPosixThreadArgs thread_args
;
598 VALGRIND_GET_ORIG_FN(fn
);
600 DRD_(sema_init
)(&wrapper_started
);
601 thread_args
.start
= start
;
602 thread_args
.arg
= arg
;
603 thread_args
.wrapper_started
= &wrapper_started
;
605 * Find out whether the thread will be started as a joinable thread
606 * or as a detached thread. If no thread attributes have been specified,
607 * this means that the new thread will be started as a joinable thread.
609 thread_args
.detachstate
= PTHREAD_CREATE_JOINABLE
;
610 /* The C11 thrd_create() implementation passes -1 as 'attr' argument. */
611 if (attr
&& (uintptr_t)attr
+ 1 != 0)
613 if (pthread_attr_getdetachstate(attr
, &thread_args
.detachstate
) != 0)
616 assert(thread_args
.detachstate
== PTHREAD_CREATE_JOINABLE
617 || thread_args
.detachstate
== PTHREAD_CREATE_DETACHED
);
620 * The DRD_(set_pthread_id)() from DRD_(init)() may encounter that
621 * pthread_self() == 0, e.g. when the main program is not linked with the
622 * pthread library and when a pthread_create() call occurs from within a
623 * shared library. Hence call DRD_(set_pthread_id)() again to ensure that
624 * DRD knows the identity of the current thread. See also B.Z. 356374.
626 DRD_(set_pthread_id
)();
627 DRD_(entering_pthread_create
)();
628 CALL_FN_W_WWWW(ret
, fn
, thread
, attr
, DRD_(thread_wrapper
), &thread_args
);
629 DRD_(left_pthread_create
)();
632 /* Wait until the thread wrapper started. */
633 DRD_(sema_down
)(&wrapper_started
);
636 DRD_(sema_destroy
)(&wrapper_started
);
638 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_START_NEW_SEGMENT
,
639 pthread_self(), 0, 0, 0, 0);
644 PTH_FUNCS(int, pthreadZucreate
, pthread_create_intercept
,
645 (pthread_t
*thread
, const pthread_attr_t
*attr
,
646 void *(*start
) (void *), void *arg
),
647 (thread
, attr
, start
, arg
));
649 #if defined(VGO_solaris)
650 /* Solaris also provides thr_create() in addition to pthread_create().
651 * Both pthread_create(3C) and thr_create(3C) are based on private
654 static __always_inline
655 int thr_create_intercept(void *stk
, size_t stksize
, void *(*start
)(void *),
656 void *arg
, long flags
, thread_t
*new_thread
)
660 DrdSema wrapper_started
;
661 DrdPosixThreadArgs thread_args
;
663 VALGRIND_GET_ORIG_FN(fn
);
665 DRD_(sema_init
)(&wrapper_started
);
666 thread_args
.start
= start
;
667 thread_args
.arg
= arg
;
668 thread_args
.wrapper_started
= &wrapper_started
;
670 * Find out whether the thread will be started as a joinable thread
671 * or as a detached thread.
673 if (flags
& THR_DETACHED
)
674 thread_args
.detachstate
= PTHREAD_CREATE_DETACHED
;
676 thread_args
.detachstate
= PTHREAD_CREATE_JOINABLE
;
678 DRD_(entering_pthread_create
)();
679 CALL_FN_W_6W(ret
, fn
, stk
, stksize
, DRD_(thread_wrapper
), &thread_args
,
681 DRD_(left_pthread_create
)();
684 /* Wait until the thread wrapper started. */
685 DRD_(sema_down
)(&wrapper_started
);
688 DRD_(sema_destroy
)(&wrapper_started
);
690 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_START_NEW_SEGMENT
,
691 pthread_self(), 0, 0, 0, 0);
696 PTH_FUNCS(int, thrZucreate
, thr_create_intercept
,
697 (void *stk
, size_t stksize
, void *(*start
)(void *), void *arg
,
698 long flags
, thread_t
*new_thread
),
699 (stk
, stksize
, start
, arg
, flags
, new_thread
));
700 #endif /* VGO_solaris */
702 #if defined(VGO_solaris)
704 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
705 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
706 * and CI_BIND_CLEAR, to provide resilience against function renaming.
708 static __always_inline
709 int DRD_(_ti_bind_guard_intercept
)(int flags
) {
710 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_RTLD_BIND_GUARD
,
712 return DRD_(rtld_bind_guard
)(flags
);
715 static __always_inline
716 int DRD_(_ti_bind_clear_intercept
)(int flags
) {
717 int ret
= DRD_(rtld_bind_clear
)(flags
);
718 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_RTLD_BIND_CLEAR
,
724 * Wrapped _ld_libc() from the runtime linker ld.so.1.
726 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1
, ZuldZulibc
)(vki_Lc_interface
*ptr
);
727 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1
, ZuldZulibc
)(vki_Lc_interface
*ptr
)
732 VALGRIND_GET_ORIG_FN(fn
);
734 vki_Lc_interface
*funcs
= ptr
;
735 for (tag
= funcs
->ci_tag
; tag
!= 0; tag
= (++funcs
)->ci_tag
) {
737 case VKI_CI_BIND_GUARD
:
738 if (funcs
->vki_ci_un
.ci_func
!= DRD_(_ti_bind_guard_intercept
)) {
739 DRD_(rtld_bind_guard
) = funcs
->vki_ci_un
.ci_func
;
740 funcs
->vki_ci_un
.ci_func
= DRD_(_ti_bind_guard_intercept
);
743 case VKI_CI_BIND_CLEAR
:
744 if (funcs
->vki_ci_un
.ci_func
!= DRD_(_ti_bind_clear_intercept
)) {
745 DRD_(rtld_bind_clear
) = funcs
->vki_ci_un
.ci_func
;
746 funcs
->vki_ci_un
.ci_func
= DRD_(_ti_bind_clear_intercept
);
752 CALL_FN_v_W(fn
, ptr
);
754 #endif /* VGO_solaris */
756 static __always_inline
757 int pthread_join_intercept(pthread_t pt_joinee
, void **thread_return
)
762 VALGRIND_GET_ORIG_FN(fn
);
764 * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
765 * implementation triggers a (false positive) race report.
767 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
768 CALL_FN_W_WW(ret
, fn
, pt_joinee
, thread_return
);
771 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_THREAD_JOIN
,
772 pt_joinee
, 0, 0, 0, 0);
774 ANNOTATE_IGNORE_READS_AND_WRITES_END();
778 PTH_FUNCS(int, pthreadZujoin
, pthread_join_intercept
,
779 (pthread_t pt_joinee
, void **thread_return
),
780 (pt_joinee
, thread_return
));
782 #if defined(VGO_solaris)
783 /* Solaris also provides thr_join() in addition to pthread_join().
784 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
786 * :TODO: No functionality is currently provided for joinee == 0 and departed.
787 * This would require another client request, of course.
789 static __always_inline
790 int thr_join_intercept(thread_t joinee
, thread_t
*departed
, void **thread_return
)
795 VALGRIND_GET_ORIG_FN(fn
);
796 CALL_FN_W_WWW(ret
, fn
, joinee
, departed
, thread_return
);
799 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_THREAD_JOIN
,
805 PTH_FUNCS(int, thrZujoin
, thr_join_intercept
,
806 (thread_t joinee
, thread_t
*departed
, void **thread_return
),
807 (joinee
, departed
, thread_return
));
808 #endif /* VGO_solaris */
810 static __always_inline
811 int pthread_detach_intercept(pthread_t pt_thread
)
816 VALGRIND_GET_ORIG_FN(fn
);
817 CALL_FN_W_W(ret
, fn
, pt_thread
);
818 DRD_(set_joinable
)(pt_thread
, 0);
823 PTH_FUNCS(int, pthreadZudetach
, pthread_detach_intercept
,
824 (pthread_t thread
), (thread
));
826 // NOTE: be careful to intercept only pthread_cancel() and not
827 // pthread_cancel_init() on Linux.
829 static __always_inline
830 int pthread_cancel_intercept(pthread_t pt_thread
)
834 VALGRIND_GET_ORIG_FN(fn
);
835 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_THREAD_CANCEL
,
836 pt_thread
, 0, 0, 0, 0);
837 CALL_FN_W_W(ret
, fn
, pt_thread
);
838 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_THREAD_CANCEL
,
839 pt_thread
, ret
==0, 0, 0, 0);
843 PTH_FUNCS(int, pthreadZucancel
, pthread_cancel_intercept
,
844 (pthread_t thread
), (thread
))
846 static __always_inline
847 int pthread_once_intercept(pthread_once_t
*once_control
,
848 void (*init_routine
)(void))
852 VALGRIND_GET_ORIG_FN(fn
);
854 * Ignore any data races triggered by the implementation of pthread_once().
855 * Necessary for Darwin. This is not necessary for Linux but doesn't have
856 * any known adverse effects.
858 DRD_IGNORE_VAR(*once_control
);
859 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
860 CALL_FN_W_WW(ret
, fn
, once_control
, init_routine
);
861 ANNOTATE_IGNORE_READS_AND_WRITES_END();
862 DRD_STOP_IGNORING_VAR(*once_control
);
866 PTH_FUNCS(int, pthreadZuonce
, pthread_once_intercept
,
867 (pthread_once_t
*once_control
, void (*init_routine
)(void)),
868 (once_control
, init_routine
));
870 static __always_inline
871 int pthread_mutex_init_intercept(pthread_mutex_t
*mutex
,
872 const pthread_mutexattr_t
* attr
)
877 VALGRIND_GET_ORIG_FN(fn
);
878 mt
= PTHREAD_MUTEX_DEFAULT
;
880 pthread_mutexattr_gettype(attr
, &mt
);
881 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_INIT
,
882 mutex
, DRD_(pthread_to_drd_mutex_type
)(mt
),
884 CALL_FN_W_WW(ret
, fn
, mutex
, attr
);
885 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_INIT
,
890 PTH_FUNCS(int, pthreadZumutexZuinit
, pthread_mutex_init_intercept
,
891 (pthread_mutex_t
*mutex
, const pthread_mutexattr_t
* attr
),
894 #if defined(VGO_solaris)
895 static __always_inline
896 int mutex_init_intercept(mutex_t
*mutex
, int type
, void *arg
)
900 VALGRIND_GET_ORIG_FN(fn
);
902 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_INIT
,
903 mutex
, DRD_(thread_to_drd_mutex_type
)(type
),
905 CALL_FN_W_WWW(ret
, fn
, mutex
, type
, arg
);
906 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_INIT
,
911 PTH_FUNCS(int, mutexZuinit
, mutex_init_intercept
,
912 (mutex_t
*mutex
, int type
, void *arg
),
914 #endif /* VGO_solaris */
916 static __always_inline
917 int pthread_mutex_destroy_intercept(pthread_mutex_t
* mutex
)
921 VALGRIND_GET_ORIG_FN(fn
);
922 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_DESTROY
,
924 CALL_FN_W_W(ret
, fn
, mutex
);
925 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_DESTROY
,
926 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
930 #if defined(VGO_solaris)
931 /* On Solaris, pthread_mutex_destroy is a weak alias to mutex_destroy. */
932 PTH_FUNCS(int, mutexZudestroy
, pthread_mutex_destroy_intercept
,
933 (pthread_mutex_t
*mutex
), (mutex
));
935 PTH_FUNCS(int, pthreadZumutexZudestroy
, pthread_mutex_destroy_intercept
,
936 (pthread_mutex_t
*mutex
), (mutex
));
937 #endif /* VGO_solaris */
939 static __always_inline
940 int pthread_mutex_lock_intercept(pthread_mutex_t
* mutex
)
944 VALGRIND_GET_ORIG_FN(fn
);
945 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK
,
946 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
947 CALL_FN_W_W(ret
, fn
, mutex
);
948 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK
,
949 mutex
, ret
== 0, 0, 0, 0);
953 #if defined(VGO_solaris)
954 /* On Solaris, pthread_mutex_lock is a weak alias to mutex_lock. */
955 PTH_FUNCS(int, mutexZulock
, pthread_mutex_lock_intercept
,
956 (pthread_mutex_t
*mutex
), (mutex
));
958 PTH_FUNCS(int, pthreadZumutexZulock
, pthread_mutex_lock_intercept
,
959 (pthread_mutex_t
*mutex
), (mutex
));
960 #endif /* VGO_solaris */
962 #if defined(VGO_solaris)
963 /* Internal to libc. Mutex is usually initialized only implicitly,
964 * by zeroing mutex_t structure.
966 static __always_inline
967 void lmutex_lock_intercept(mutex_t
*mutex
)
970 VALGRIND_GET_ORIG_FN(fn
);
971 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK
,
973 DRD_(mutex_type
)((pthread_mutex_t
*) mutex
),
974 False
/* try_lock */, 0, 0);
975 CALL_FN_v_W(fn
, mutex
);
976 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK
,
977 mutex
, True
/* took_lock */, 0, 0, 0);
980 PTH_FUNCS(void, lmutexZulock
, lmutex_lock_intercept
,
981 (mutex_t
*mutex
), (mutex
));
982 #endif /* VGO_solaris */
984 static __always_inline
985 int pthread_mutex_trylock_intercept(pthread_mutex_t
* mutex
)
989 VALGRIND_GET_ORIG_FN(fn
);
990 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK
,
991 mutex
, DRD_(mutex_type
)(mutex
), 1, 0, 0);
992 CALL_FN_W_W(ret
, fn
, mutex
);
993 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK
,
994 mutex
, ret
== 0, 0, 0, 0);
998 #if defined(VGO_solaris)
999 /* On Solaris, pthread_mutex_trylock is a weak alias to mutex_trylock. */
1000 PTH_FUNCS(int, mutexZutrylock
, pthread_mutex_trylock_intercept
,
1001 (pthread_mutex_t
*mutex
), (mutex
));
1003 PTH_FUNCS(int, pthreadZumutexZutrylock
, pthread_mutex_trylock_intercept
,
1004 (pthread_mutex_t
*mutex
), (mutex
));
1005 #endif /* VGO_solaris */
1007 static __always_inline
1008 int pthread_mutex_timedlock_intercept(pthread_mutex_t
*mutex
,
1009 const struct timespec
*abs_timeout
)
1013 VALGRIND_GET_ORIG_FN(fn
);
1014 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK
,
1015 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
1016 CALL_FN_W_WW(ret
, fn
, mutex
, abs_timeout
);
1017 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK
,
1018 mutex
, ret
== 0, 0, 0, 0);
1022 PTH_FUNCS(int, pthreadZumutexZutimedlock
, pthread_mutex_timedlock_intercept
,
1023 (pthread_mutex_t
*mutex
, const struct timespec
*abs_timeout
),
1024 (mutex
, abs_timeout
));
1025 #if defined(VGO_solaris)
1027 pthreadZumutexZureltimedlockZunp
, pthread_mutex_timedlock_intercept
,
1028 (pthread_mutex_t
*mutex
, const struct timespec
*timeout
),
1030 #endif /* VGO_solaris */
1032 #if defined(HAVE_CLOCKID_T)
1033 static __always_inline
1034 int pthread_mutex_clocklock_intercept(pthread_mutex_t
*mutex
,
1036 const struct timespec
*abs_timeout
)
1040 VALGRIND_GET_ORIG_FN(fn
);
1041 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK
,
1042 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
1043 CALL_FN_W_WWW(ret
, fn
, mutex
, clockid
, abs_timeout
);
1044 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK
,
1045 mutex
, ret
== 0, 0, 0, 0);
1049 PTH_FUNCS(int, pthreadZumutexZuclocklock
, pthread_mutex_clocklock_intercept
,
1050 (pthread_mutex_t
*mutex
, clockid_t clockid
, const struct timespec
*abs_timeout
),
1051 (mutex
, clockid
, abs_timeout
));
1054 static __always_inline
1055 int pthread_mutex_unlock_intercept(pthread_mutex_t
*mutex
)
1059 VALGRIND_GET_ORIG_FN(fn
);
1060 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_UNLOCK
,
1061 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
1062 CALL_FN_W_W(ret
, fn
, mutex
);
1063 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_UNLOCK
,
1068 #if defined(VGO_solaris)
1069 /* On Solaris, pthread_mutex_unlock is a weak alias to mutex_unlock. */
1070 PTH_FUNCS(int, mutexZuunlock
, pthread_mutex_unlock_intercept
,
1071 (pthread_mutex_t
*mutex
), (mutex
));
1073 PTH_FUNCS(int, pthreadZumutexZuunlock
, pthread_mutex_unlock_intercept
,
1074 (pthread_mutex_t
*mutex
), (mutex
));
1075 #endif /* VGO_solaris */
1077 #if defined(VGO_solaris)
1078 /* Internal to libc. */
1079 static __always_inline
1080 void lmutex_unlock_intercept(mutex_t
*mutex
)
1083 VALGRIND_GET_ORIG_FN(fn
);
1084 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_UNLOCK
,
1086 DRD_(mutex_type
)((pthread_mutex_t
*) mutex
),
1088 CALL_FN_v_W(fn
, mutex
);
1089 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_UNLOCK
,
1093 PTH_FUNCS(void, lmutexZuunlock
, lmutex_unlock_intercept
,
1094 (mutex_t
*mutex
), (mutex
));
1095 #endif /* VGO_solaris */
1097 static __always_inline
1098 int pthread_cond_init_intercept(pthread_cond_t
* cond
,
1099 const pthread_condattr_t
* attr
)
1103 VALGRIND_GET_ORIG_FN(fn
);
1104 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_INIT
,
1106 CALL_FN_W_WW(ret
, fn
, cond
, attr
);
1107 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_INIT
,
1112 PTH_FUNCS(int, pthreadZucondZuinit
, pthread_cond_init_intercept
,
1113 (pthread_cond_t
* cond
, const pthread_condattr_t
* attr
),
1116 #if defined(VGO_solaris)
1117 static __always_inline
1118 int cond_init_intercept(cond_t
*cond
, int type
, void *arg
)
1122 VALGRIND_GET_ORIG_FN(fn
);
1123 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_INIT
,
1125 CALL_FN_W_WWW(ret
, fn
, cond
, type
, arg
);
1126 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_INIT
,
1131 PTH_FUNCS(int, condZuinit
, cond_init_intercept
,
1132 (cond_t
*cond
, int type
, void *arg
),
1134 #endif /* VGO_solaris */
1136 static __always_inline
1137 int pthread_cond_destroy_intercept(pthread_cond_t
* cond
)
1141 VALGRIND_GET_ORIG_FN(fn
);
1142 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_DESTROY
,
1144 CALL_FN_W_W(ret
, fn
, cond
);
1145 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_DESTROY
,
1146 cond
, ret
==0, 0, 0, 0);
1150 #if defined(VGO_solaris)
1151 /* On Solaris, pthread_cond_destroy is a weak alias to cond_destroy. */
1152 PTH_FUNCS(int, condZudestroy
, pthread_cond_destroy_intercept
,
1153 (pthread_cond_t
*cond
), (cond
));
1155 PTH_FUNCS(int, pthreadZucondZudestroy
, pthread_cond_destroy_intercept
,
1156 (pthread_cond_t
* cond
), (cond
));
1157 #endif /* VGO_solaris */
1159 static __always_inline
1160 int pthread_cond_wait_intercept(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
1164 VALGRIND_GET_ORIG_FN(fn
);
1165 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_WAIT
,
1166 cond
, mutex
, DRD_(mutex_type
)(mutex
), 0, 0);
1167 CALL_FN_W_WW(ret
, fn
, cond
, mutex
);
1168 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_WAIT
,
1169 cond
, mutex
, 1, 0, 0);
1173 PTH_FUNCS(int, pthreadZucondZuwait
, pthread_cond_wait_intercept
,
1174 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
),
1176 #if defined(VGO_solaris)
1177 PTH_FUNCS(int, condZuwait
, pthread_cond_wait_intercept
,
1178 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
),
1180 #endif /* VGO_solaris */
1182 static __always_inline
1183 int pthread_cond_timedwait_intercept(pthread_cond_t
*cond
,
1184 pthread_mutex_t
*mutex
,
1185 const struct timespec
* abstime
)
1189 VALGRIND_GET_ORIG_FN(fn
);
1190 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_WAIT
,
1191 cond
, mutex
, DRD_(mutex_type
)(mutex
), 0, 0);
1192 CALL_FN_W_WWW(ret
, fn
, cond
, mutex
, abstime
);
1193 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_WAIT
,
1194 cond
, mutex
, 1, 0, 0);
1198 PTH_FUNCS(int, pthreadZucondZutimedwait
, pthread_cond_timedwait_intercept
,
1199 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1200 const struct timespec
* abstime
),
1201 (cond
, mutex
, abstime
));
1202 #if defined(VGO_solaris)
1203 PTH_FUNCS(int, condZutimedwait
, pthread_cond_timedwait_intercept
,
1204 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1205 const struct timespec
*timeout
),
1206 (cond
, mutex
, timeout
));
1207 PTH_FUNCS(int, condZureltimedwait
, pthread_cond_timedwait_intercept
,
1208 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1209 const struct timespec
*timeout
),
1210 (cond
, mutex
, timeout
));
1211 #endif /* VGO_solaris */
1214 #if defined(HAVE_CLOCKID_T)
1215 static __always_inline
1216 int pthread_cond_clockwait_intercept(pthread_cond_t
*cond
,
1217 pthread_mutex_t
*mutex
,
1219 const struct timespec
* abstime
)
1223 VALGRIND_GET_ORIG_FN(fn
);
1224 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_WAIT
,
1225 cond
, mutex
, DRD_(mutex_type
)(mutex
), 0, 0);
1226 CALL_FN_W_WWWW(ret
, fn
, cond
, mutex
, clockid
, abstime
);
1227 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_WAIT
,
1228 cond
, mutex
, 1, 0, 0);
1232 PTH_FUNCS(int, pthreadZucondZuclockwait
, pthread_cond_clockwait_intercept
,
1233 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1234 clockid_t clockid
, const struct timespec
* abstime
),
1235 (cond
, mutex
, clockid
, abstime
));
1239 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
1240 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
1241 // two. Intercepting all pthread_cond_signal* functions will cause only one
1242 // argument to be passed to pthread_cond_signal_np() and hence will cause this
1243 // last function to crash.
1245 static __always_inline
1246 int pthread_cond_signal_intercept(pthread_cond_t
* cond
)
1250 VALGRIND_GET_ORIG_FN(fn
);
1251 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_SIGNAL
,
1253 CALL_FN_W_W(ret
, fn
, cond
);
1254 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_SIGNAL
,
1259 #if defined(VGO_solaris)
1260 /* On Solaris, pthread_cond_signal is a weak alias to cond_signal. */
1261 PTH_FUNCS(int, condZusignal
, pthread_cond_signal_intercept
,
1262 (pthread_cond_t
*cond
), (cond
));
1264 PTH_FUNCS(int, pthreadZucondZusignal
, pthread_cond_signal_intercept
,
1265 (pthread_cond_t
* cond
), (cond
));
1266 #endif /* VGO_solaris */
1268 static __always_inline
1269 int pthread_cond_broadcast_intercept(pthread_cond_t
* cond
)
1273 VALGRIND_GET_ORIG_FN(fn
);
1274 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_BROADCAST
,
1276 CALL_FN_W_W(ret
, fn
, cond
);
1277 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_BROADCAST
,
1282 #if defined(VGO_solaris)
1283 /* On Solaris, pthread_cond_broadcast is a weak alias to cond_broadcast. */
1284 PTH_FUNCS(int, condZubroadcast
, pthread_cond_broadcast_intercept
,
1285 (pthread_cond_t
*cond
), (cond
));
1287 PTH_FUNCS(int, pthreadZucondZubroadcast
, pthread_cond_broadcast_intercept
,
1288 (pthread_cond_t
* cond
), (cond
));
1289 #endif /* VGO_solaris */
1291 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1292 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1293 static __always_inline
1294 int pthread_spin_init_intercept(pthread_spinlock_t
*spinlock
, int pshared
)
1298 VALGRIND_GET_ORIG_FN(fn
);
1299 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SPIN_INIT_OR_UNLOCK
,
1300 spinlock
, 0, 0, 0, 0);
1301 CALL_FN_W_WW(ret
, fn
, spinlock
, pshared
);
1302 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SPIN_INIT_OR_UNLOCK
,
1303 spinlock
, 0, 0, 0, 0);
1307 PTH_FUNCS(int, pthreadZuspinZuinit
, pthread_spin_init_intercept
,
1308 (pthread_spinlock_t
*spinlock
, int pshared
), (spinlock
, pshared
));
1310 static __always_inline
1311 int pthread_spin_destroy_intercept(pthread_spinlock_t
*spinlock
)
1315 VALGRIND_GET_ORIG_FN(fn
);
1316 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_DESTROY
,
1317 spinlock
, 0, 0, 0, 0);
1318 CALL_FN_W_W(ret
, fn
, spinlock
);
1319 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_DESTROY
,
1320 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1324 PTH_FUNCS(int, pthreadZuspinZudestroy
, pthread_spin_destroy_intercept
,
1325 (pthread_spinlock_t
*spinlock
), (spinlock
));
1327 static __always_inline
1328 int pthread_spin_lock_intercept(pthread_spinlock_t
*spinlock
)
1332 VALGRIND_GET_ORIG_FN(fn
);
1333 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK
,
1334 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1335 CALL_FN_W_W(ret
, fn
, spinlock
);
1336 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK
,
1337 spinlock
, ret
== 0, 0, 0, 0);
1341 PTH_FUNCS(int, pthreadZuspinZulock
, pthread_spin_lock_intercept
,
1342 (pthread_spinlock_t
*spinlock
), (spinlock
));
1344 static __always_inline
1345 int pthread_spin_trylock_intercept(pthread_spinlock_t
*spinlock
)
1349 VALGRIND_GET_ORIG_FN(fn
);
1350 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK
,
1351 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1352 CALL_FN_W_W(ret
, fn
, spinlock
);
1353 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK
,
1354 spinlock
, ret
== 0, 0, 0, 0);
1358 PTH_FUNCS(int, pthreadZuspinZutrylock
, pthread_spin_trylock_intercept
,
1359 (pthread_spinlock_t
*spinlock
), (spinlock
));
1361 static __always_inline
1362 int pthread_spin_unlock_intercept(pthread_spinlock_t
*spinlock
)
1366 VALGRIND_GET_ORIG_FN(fn
);
1367 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SPIN_INIT_OR_UNLOCK
,
1368 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1369 CALL_FN_W_W(ret
, fn
, spinlock
);
1370 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SPIN_INIT_OR_UNLOCK
,
1371 spinlock
, 0, 0, 0, 0);
1375 PTH_FUNCS(int, pthreadZuspinZuunlock
, pthread_spin_unlock_intercept
,
1376 (pthread_spinlock_t
*spinlock
), (spinlock
));
1377 #endif // HAVE_PTHREAD_SPIN_LOCK
1380 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1381 static __always_inline
1382 int pthread_barrier_init_intercept(pthread_barrier_t
* barrier
,
1383 const pthread_barrierattr_t
* attr
,
1388 VALGRIND_GET_ORIG_FN(fn
);
1389 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_BARRIER_INIT
,
1390 barrier
, pthread_barrier
, count
, 0, 0);
1391 CALL_FN_W_WWW(ret
, fn
, barrier
, attr
, count
);
1392 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_BARRIER_INIT
,
1393 barrier
, pthread_barrier
, 0, 0, 0);
1397 PTH_FUNCS(int, pthreadZubarrierZuinit
, pthread_barrier_init_intercept
,
1398 (pthread_barrier_t
* barrier
, const pthread_barrierattr_t
* attr
,
1399 unsigned count
), (barrier
, attr
, count
));
1401 static __always_inline
1402 int pthread_barrier_destroy_intercept(pthread_barrier_t
* barrier
)
1406 VALGRIND_GET_ORIG_FN(fn
);
1407 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_BARRIER_DESTROY
,
1408 barrier
, pthread_barrier
, 0, 0, 0);
1409 CALL_FN_W_W(ret
, fn
, barrier
);
1410 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_BARRIER_DESTROY
,
1411 barrier
, pthread_barrier
, 0, 0, 0);
1415 PTH_FUNCS(int, pthreadZubarrierZudestroy
, pthread_barrier_destroy_intercept
,
1416 (pthread_barrier_t
* barrier
), (barrier
));
1418 static __always_inline
1419 int pthread_barrier_wait_intercept(pthread_barrier_t
* barrier
)
1423 VALGRIND_GET_ORIG_FN(fn
);
1424 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_BARRIER_WAIT
,
1425 barrier
, pthread_barrier
, 0, 0, 0);
1426 CALL_FN_W_W(ret
, fn
, barrier
);
1427 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_BARRIER_WAIT
,
1428 barrier
, pthread_barrier
,
1429 ret
== 0 || ret
== PTHREAD_BARRIER_SERIAL_THREAD
,
1430 ret
== PTHREAD_BARRIER_SERIAL_THREAD
, 0);
1434 PTH_FUNCS(int, pthreadZubarrierZuwait
, pthread_barrier_wait_intercept
,
1435 (pthread_barrier_t
* barrier
), (barrier
));
1436 #endif // HAVE_PTHREAD_BARRIER_INIT
1439 static __always_inline
1440 int sem_init_intercept(sem_t
*sem
, int pshared
, unsigned int value
)
1444 VALGRIND_GET_ORIG_FN(fn
);
1445 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_INIT
,
1446 sem
, pshared
, value
, 0, 0);
1447 CALL_FN_W_WWW(ret
, fn
, sem
, pshared
, value
);
1448 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_INIT
,
1453 #if defined(VGO_freebsd)
1454 LIBC_FUNC(int, semZuinit
, sem_init_intercept
,
1455 (sem_t
*sem
, int pshared
, unsigned int value
), (sem
, pshared
, value
));
1457 PTH_FUNCS(int, semZuinit
, sem_init_intercept
,
1458 (sem_t
*sem
, int pshared
, unsigned int value
), (sem
, pshared
, value
));
1461 #if defined(VGO_solaris)
1462 static __always_inline
1463 int sema_init_intercept(sema_t
*sem
, unsigned int value
, int type
, void *arg
)
1467 VALGRIND_GET_ORIG_FN(fn
);
1468 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_INIT
,
1469 sem
, type
== USYNC_PROCESS
? 1 : 0,
1471 CALL_FN_W_WWWW(ret
, fn
, sem
, value
, type
, arg
);
1472 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_INIT
,
1477 PTH_FUNCS(int, semaZuinit
, sema_init_intercept
,
1478 (sema_t
*sem
, unsigned int value
, int type
, void *arg
),
1479 (sem
, value
, type
, arg
));
1480 #endif /* VGO_solaris */
1482 static __always_inline
1483 int sem_destroy_intercept(sem_t
*sem
)
1487 VALGRIND_GET_ORIG_FN(fn
);
1488 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_DESTROY
,
1490 CALL_FN_W_W(ret
, fn
, sem
);
1491 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_DESTROY
,
1496 #if defined(VGO_freebsd)
1497 LIBC_FUNC(int, semZudestroy
, sem_destroy_intercept
, (sem_t
*sem
), (sem
));
1499 PTH_FUNCS(int, semZudestroy
, sem_destroy_intercept
, (sem_t
*sem
), (sem
));
1502 #if defined(VGO_solaris)
1503 PTH_FUNCS(int, semaZudestroy
, sem_destroy_intercept
, (sem_t
*sem
), (sem
));
1504 #endif /* VGO_solaris */
1506 static __always_inline
1507 sem_t
* sem_open_intercept(const char *name
, int oflag
, mode_t mode
,
1512 VALGRIND_GET_ORIG_FN(fn
);
1513 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_OPEN
,
1514 name
, oflag
, mode
, value
, 0);
1515 CALL_FN_W_WWWW(ret
, fn
, name
, oflag
, mode
, value
);
1516 // To do: figure out why gcc 9.2.1 miscompiles this function if the printf()
1517 // call below is left out.
1519 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_OPEN
,
1520 ret
!= SEM_FAILED
? ret
: 0,
1521 name
, oflag
, mode
, value
);
1525 #if defined(VGO_freebsd)
1526 LIBC_FUNC(sem_t
*, semZuopen
, sem_open_intercept
,
1527 (const char *name
, int oflag
, mode_t mode
, unsigned int value
),
1528 (name
, oflag
, mode
, value
));
1530 PTH_FUNCS(sem_t
*, semZuopen
, sem_open_intercept
,
1531 (const char *name
, int oflag
, mode_t mode
, unsigned int value
),
1532 (name
, oflag
, mode
, value
));
1535 static __always_inline
int sem_close_intercept(sem_t
*sem
)
1539 VALGRIND_GET_ORIG_FN(fn
);
1540 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_CLOSE
,
1542 CALL_FN_W_W(ret
, fn
, sem
);
1543 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_CLOSE
,
1548 #if defined(VGO_freebsd)
1549 LIBC_FUNC(int, semZuclose
, sem_close_intercept
, (sem_t
*sem
), (sem
));
1551 PTH_FUNCS(int, semZuclose
, sem_close_intercept
, (sem_t
*sem
), (sem
));
1554 static __always_inline
int sem_wait_intercept(sem_t
*sem
)
1558 VALGRIND_GET_ORIG_FN(fn
);
1559 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT
,
1561 CALL_FN_W_W(ret
, fn
, sem
);
1562 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT
,
1563 sem
, ret
== 0, 0, 0, 0);
1567 #if defined(VGO_freebsd)
1568 LIBC_FUNC(int, semZuwait
, sem_wait_intercept
, (sem_t
*sem
), (sem
));
1570 PTH_FUNCS(int, semZuwait
, sem_wait_intercept
, (sem_t
*sem
), (sem
));
1573 #if defined(VGO_solaris)
1574 PTH_FUNCS(int, semaZuwait
, sem_wait_intercept
, (sem_t
*sem
), (sem
));
1575 #endif /* VGO_solaris */
1577 static __always_inline
int sem_trywait_intercept(sem_t
*sem
)
1581 VALGRIND_GET_ORIG_FN(fn
);
1582 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT
,
1584 CALL_FN_W_W(ret
, fn
, sem
);
1585 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT
,
1586 sem
, ret
== 0, 0, 0, 0);
1590 #if defined(VGO_freebsd)
1591 LIBC_FUNC(int, semZutrywait
, sem_trywait_intercept
, (sem_t
*sem
), (sem
));
1593 PTH_FUNCS(int, semZutrywait
, sem_trywait_intercept
, (sem_t
*sem
), (sem
));
1595 #if defined(VGO_solaris)
1596 PTH_FUNCS(int, semaZutrywait
, sem_trywait_intercept
, (sem_t
*sem
), (sem
));
1597 #endif /* VGO_solaris */
1599 static __always_inline
1600 int sem_timedwait_intercept(sem_t
*sem
, const struct timespec
*abs_timeout
)
1604 VALGRIND_GET_ORIG_FN(fn
);
1605 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT
,
1607 CALL_FN_W_WW(ret
, fn
, sem
, abs_timeout
);
1608 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT
,
1609 sem
, ret
== 0, 0, 0, 0);
1613 #if defined(VGO_freebsd)
1614 LIBC_FUNC(int, semZutimedwait
, sem_timedwait_intercept
,
1615 (sem_t
*sem
, const struct timespec
*abs_timeout
),
1616 (sem
, abs_timeout
));
1618 PTH_FUNCS(int, semZutimedwait
, sem_timedwait_intercept
,
1619 (sem_t
*sem
, const struct timespec
*abs_timeout
),
1620 (sem
, abs_timeout
));
1622 #if defined(VGO_solaris)
1623 PTH_FUNCS(int, semaZutimedwait
, sem_timedwait_intercept
,
1624 (sem_t
*sem
, const struct timespec
*timeout
),
1626 PTH_FUNCS(int, semaZureltimedwait
, sem_timedwait_intercept
,
1627 (sem_t
*sem
, const struct timespec
*timeout
),
1629 #endif /* VGO_solaris */
1631 static __always_inline
int sem_post_intercept(sem_t
*sem
)
1635 VALGRIND_GET_ORIG_FN(fn
);
1636 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_POST
,
1638 CALL_FN_W_W(ret
, fn
, sem
);
1639 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_POST
,
1640 sem
, ret
== 0, 0, 0, 0);
1644 #if defined(VGO_freebsd)
1645 LIBC_FUNC(int, semZupost
, sem_post_intercept
, (sem_t
*sem
), (sem
));
1647 PTH_FUNCS(int, semZupost
, sem_post_intercept
, (sem_t
*sem
), (sem
));
1649 #if defined(VGO_solaris)
1650 PTH_FUNCS(int, semaZupost
, sem_post_intercept
, (sem_t
*sem
), (sem
));
1651 #endif /* VGO_solaris */
1653 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1654 functions have to be conditionally compiled. */
1655 #if defined(HAVE_PTHREAD_RWLOCK_T)
1657 static __always_inline
1658 int pthread_rwlock_init_intercept(pthread_rwlock_t
* rwlock
,
1659 const pthread_rwlockattr_t
* attr
)
1663 VALGRIND_GET_ORIG_FN(fn
);
1664 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_INIT
,
1665 rwlock
, 0, 0, 0, 0);
1666 CALL_FN_W_WW(ret
, fn
, rwlock
, attr
);
1667 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_INIT
,
1668 rwlock
, 0, 0, 0, 0);
1673 pthreadZurwlockZuinit
, pthread_rwlock_init_intercept
,
1674 (pthread_rwlock_t
* rwlock
, const pthread_rwlockattr_t
* attr
),
1677 #if defined(VGO_solaris)
1678 static __always_inline
1679 int rwlock_init_intercept(rwlock_t
*rwlock
, int type
, void *arg
)
1683 VALGRIND_GET_ORIG_FN(fn
);
1684 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_INIT
,
1685 rwlock
, 0, 0, 0, 0);
1686 CALL_FN_W_WWW(ret
, fn
, rwlock
, type
, arg
);
1687 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_INIT
,
1688 rwlock
, 0, 0, 0, 0);
1692 PTH_FUNCS(int, rwlockZuinit
, rwlock_init_intercept
,
1693 (rwlock_t
*rwlock
, int type
, void *arg
),
1694 (rwlock
, type
, arg
));
1695 #endif /* VGO_solaris */
1697 static __always_inline
1698 int pthread_rwlock_destroy_intercept(pthread_rwlock_t
* rwlock
)
1702 VALGRIND_GET_ORIG_FN(fn
);
1703 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_DESTROY
,
1704 rwlock
, 0, 0, 0, 0);
1705 CALL_FN_W_W(ret
, fn
, rwlock
);
1706 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_DESTROY
,
1707 rwlock
, 0, 0, 0, 0);
1711 #if defined(VGO_solaris)
1712 /* On Solaris, pthread_rwlock_destroy is a weak alias to rwlock_destroy. */
1714 rwlockZudestroy
, pthread_rwlock_destroy_intercept
,
1715 (pthread_rwlock_t
*rwlock
), (rwlock
));
1718 pthreadZurwlockZudestroy
, pthread_rwlock_destroy_intercept
,
1719 (pthread_rwlock_t
* rwlock
), (rwlock
));
1720 #endif /* VGO_solaris */
1722 static __always_inline
1723 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t
* rwlock
)
1727 VALGRIND_GET_ORIG_FN(fn
);
1728 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK
,
1729 rwlock
, 0, 0, 0, 0);
1730 CALL_FN_W_W(ret
, fn
, rwlock
);
1731 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK
,
1732 rwlock
, ret
== 0, 0, 0, 0);
1736 #if defined(VGO_solaris)
1737 /* On Solaris, pthread_rwlock_rdlock is a weak alias to rw_rdlock. */
1739 rwZurdlock
, pthread_rwlock_rdlock_intercept
,
1740 (pthread_rwlock_t
*rwlock
), (rwlock
));
1743 pthreadZurwlockZurdlock
, pthread_rwlock_rdlock_intercept
,
1744 (pthread_rwlock_t
* rwlock
), (rwlock
));
1745 #endif /* VGO_solaris */
1747 #if defined(VGO_solaris)
1748 /* Internal to libc. */
1749 static __always_inline
1750 void lrw_rdlock_intercept(rwlock_t
*rwlock
)
1753 VALGRIND_GET_ORIG_FN(fn
);
1754 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK
,
1755 rwlock
, 0, 0, 0, 0);
1756 CALL_FN_v_W(fn
, rwlock
);
1757 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK
,
1758 rwlock
, True
/* took_lock */, 0, 0, 0);
1761 PTH_FUNCS(void, lrwZurdlock
, lrw_rdlock_intercept
,
1762 (rwlock_t
*rwlock
), (rwlock
));
1763 #endif /* VGO_solaris */
1765 static __always_inline
1766 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t
* rwlock
)
1770 VALGRIND_GET_ORIG_FN(fn
);
1771 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK
,
1772 rwlock
, 0, 0, 0, 0);
1773 CALL_FN_W_W(ret
, fn
, rwlock
);
1774 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK
,
1775 rwlock
, ret
== 0, 0, 0, 0);
1779 #if defined(VGO_solaris)
1780 /* On Solaris, pthread_rwlock_wrlock is a weak alias to rw_wrlock. */
1782 rwZuwrlock
, pthread_rwlock_wrlock_intercept
,
1783 (pthread_rwlock_t
*rwlock
), (rwlock
));
1786 pthreadZurwlockZuwrlock
, pthread_rwlock_wrlock_intercept
,
1787 (pthread_rwlock_t
* rwlock
), (rwlock
));
1788 #endif /* VGO_solaris */
1790 #if defined(VGO_solaris)
1791 /* Internal to libc. */
1792 static __always_inline
1793 void lrw_wrlock_intercept(rwlock_t
*rwlock
)
1796 VALGRIND_GET_ORIG_FN(fn
);
1797 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK
,
1798 rwlock
, 0, 0, 0, 0);
1799 CALL_FN_v_W(fn
, rwlock
);
1800 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK
,
1801 rwlock
, True
/* took_lock */, 0, 0, 0);
1804 PTH_FUNCS(void, lrwZuwrlock
, lrw_wrlock_intercept
,
1805 (rwlock_t
*rwlock
), (rwlock
));
1806 #endif /* VGO_solaris */
1808 static __always_inline
1809 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t
* rwlock
,
1810 const struct timespec
*timeout
)
1814 VALGRIND_GET_ORIG_FN(fn
);
1815 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK
,
1816 rwlock
, 0, 0, 0, 0);
1817 CALL_FN_W_WW(ret
, fn
, rwlock
, timeout
);
1818 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK
,
1819 rwlock
, ret
== 0, 0, 0, 0);
1824 pthreadZurwlockZutimedrdlock
, pthread_rwlock_timedrdlock_intercept
,
1825 (pthread_rwlock_t
* rwlock
, const struct timespec
*timeout
),
1827 #if defined(VGO_solaris)
1828 PTH_FUNCS(int, pthreadZurwlockZureltimedrdlockZunp
,
1829 pthread_rwlock_timedrdlock_intercept
,
1830 (pthread_rwlock_t
*rwlock
, const struct timespec
*timeout
),
1832 #endif /* VGO_solaris */
1835 #if defined(HAVE_CLOCKID_T)
1836 static __always_inline
1837 int pthread_rwlock_clockrdlock_intercept(pthread_rwlock_t
* rwlock
,
1839 const struct timespec
*timeout
)
1843 VALGRIND_GET_ORIG_FN(fn
);
1844 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK
,
1845 rwlock
, 0, 0, 0, 0);
1846 CALL_FN_W_WWW(ret
, fn
, rwlock
, clockid
, timeout
);
1847 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK
,
1848 rwlock
, ret
== 0, 0, 0, 0);
1853 pthreadZurwlockZuclockrdlock
, pthread_rwlock_clockrdlock_intercept
,
1854 (pthread_rwlock_t
* rwlock
, clockid_t clockid
, const struct timespec
*timeout
),
1855 (rwlock
, clockid
, timeout
));
1858 static __always_inline
1859 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t
* rwlock
,
1860 const struct timespec
*timeout
)
1864 VALGRIND_GET_ORIG_FN(fn
);
1865 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK
,
1866 rwlock
, 0, 0, 0, 0);
1867 CALL_FN_W_WW(ret
, fn
, rwlock
, timeout
);
1868 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK
,
1869 rwlock
, ret
== 0, 0, 0, 0);
1874 pthreadZurwlockZutimedwrlock
, pthread_rwlock_timedwrlock_intercept
,
1875 (pthread_rwlock_t
* rwlock
, const struct timespec
*timeout
),
1877 #if defined(VGO_solaris)
1878 PTH_FUNCS(int, pthreadZurwlockZureltimedwrlockZunp
,
1879 pthread_rwlock_timedwrlock_intercept
,
1880 (pthread_rwlock_t
*rwlock
, const struct timespec
*timeout
),
1882 #endif /* VGO_solaris */
1885 #if defined(HAVE_CLOCKID_T)
1886 static __always_inline
1887 int pthread_rwlock_clockwrlock_intercept(pthread_rwlock_t
* rwlock
,
1889 const struct timespec
*timeout
)
1893 VALGRIND_GET_ORIG_FN(fn
);
1894 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK
,
1895 rwlock
, 0, 0, 0, 0);
1896 CALL_FN_W_WWW(ret
, fn
, rwlock
, clockid
, timeout
);
1897 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK
,
1898 rwlock
, ret
== 0, 0, 0, 0);
1903 pthreadZurwlockZuclockwrlock
, pthread_rwlock_clockwrlock_intercept
,
1904 (pthread_rwlock_t
* rwlock
, clockid_t clockid
, const struct timespec
*timeout
),
1905 (rwlock
, clockid
, timeout
));
1909 static __always_inline
1910 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t
* rwlock
)
1914 VALGRIND_GET_ORIG_FN(fn
);
1915 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK
,
1916 rwlock
, 0, 0, 0, 0);
1917 CALL_FN_W_W(ret
, fn
, rwlock
);
1918 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK
,
1919 rwlock
, ret
== 0, 0, 0, 0);
1923 #if defined(VGO_solaris)
1924 /* On Solaris, pthread_rwlock_tryrdlock is a weak alias to rw_tryrdlock. */
1926 rwZutryrdlock
, pthread_rwlock_tryrdlock_intercept
,
1927 (pthread_rwlock_t
*rwlock
), (rwlock
));
1930 pthreadZurwlockZutryrdlock
, pthread_rwlock_tryrdlock_intercept
,
1931 (pthread_rwlock_t
* rwlock
), (rwlock
));
1932 #endif /* VGO_solaris */
1934 static __always_inline
1935 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t
* rwlock
)
1939 VALGRIND_GET_ORIG_FN(fn
);
1940 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK
,
1941 rwlock
, 0, 0, 0, 0);
1942 CALL_FN_W_W(ret
, fn
, rwlock
);
1943 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK
,
1944 rwlock
, ret
== 0, 0, 0, 0);
1948 #if defined(VGO_solaris)
1949 /* On Solaris, pthread_rwlock_trywrlock is a weak alias to rw_trywrlock. */
1951 rwZutrywrlock
, pthread_rwlock_trywrlock_intercept
,
1952 (pthread_rwlock_t
*rwlock
), (rwlock
));
1955 pthreadZurwlockZutrywrlock
, pthread_rwlock_trywrlock_intercept
,
1956 (pthread_rwlock_t
* rwlock
), (rwlock
));
1957 #endif /* VGO_solaris */
1959 static __always_inline
1960 int pthread_rwlock_unlock_intercept(pthread_rwlock_t
* rwlock
)
1964 VALGRIND_GET_ORIG_FN(fn
);
1965 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_UNLOCK
,
1966 rwlock
, 0, 0, 0, 0);
1967 CALL_FN_W_W(ret
, fn
, rwlock
);
1968 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_UNLOCK
,
1969 rwlock
, ret
== 0, 0, 0, 0);
1973 #if defined(VGO_solaris)
1974 /* On Solaris, pthread_rwlock_unlock is a weak alias to rw_unlock. */
1976 rwZuunlock
, pthread_rwlock_unlock_intercept
,
1977 (pthread_rwlock_t
*rwlock
), (rwlock
));
1980 pthreadZurwlockZuunlock
, pthread_rwlock_unlock_intercept
,
1981 (pthread_rwlock_t
* rwlock
), (rwlock
));
1982 #endif /* VGO_solaris */
1984 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */