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)
62 #include <osreldate.h>
65 #if defined(VGO_solaris)
67 * Solaris usually provides pthread_* functions on top of Solaris threading
68 * and synchronization functions. Usually both need to be intercepted because
69 * pthread_* ones might not call the Solaris ones (see for example sem_wait()).
70 * Such approach is required to correctly report misuse of the POSIX threads
72 * Therefore DRD intercepts and instruments all such functions but due to
73 * DRD_(thread_enter_synchr)() and DRD_(thread_leave_synchr)() guards in
74 * handle_client_request(), only the top-most function is handled.
75 * So the right thing(TM) happens, as expected.
76 * The only exception is when pthread_* function is a weak alias to the Solaris
77 * threading/synchronization function. In such case only one needs to be
78 * intercepted to avoid redirection ambiguity.
80 * Intercepted functions rely on the fact that:
81 * - pthread_mutex_t == mutex_t
82 * - pthread_cond_t == cond_t
84 * - pthread_rwlock_t == rwlock_t
86 * It is necessary to intercept also internal libc synchronization functions
88 * - For read-write locks the unlocking function is shared
89 * - Functions lmutex_lock/lmutex_unlock guard many critical sections in libc
90 * which will be otherwise reported by DRD
94 #include "pub_tool_vki.h"
97 * Solaris provides higher throughput, parallelism and scalability than other
98 * operating systems, at the cost of more fine-grained locking activity.
99 * This means for example that when a thread is created under Linux, just one
100 * big lock in glibc is used for all thread setup. Solaris libc uses several
101 * fine-grained locks and the creator thread resumes its activities as soon
102 * as possible, leaving for example stack and TLS setup activities to the
105 * This situation confuses DRD as it assumes there is some false ordering
106 * in place between creator and created thread; and therefore many types of
107 * race conditions in the application would not be reported. To prevent such
108 * false ordering, command line option --ignore-thread-creation is set to
109 * 'yes' by default on Solaris. All activity (loads, stores, client requests)
110 * is therefore ignored during:
111 * - pthread_create() call in the creator thread [libc.so]
112 * - thread creation phase (stack and TLS setup) in the created thread [libc.so]
114 * As explained in the comments for _ti_bind_guard(), whenever the runtime
115 * linker has to perform any activity (such as resolving a symbol), it protects
116 * its data structures by calling into rt_bind_guard() which in turn invokes
117 * _ti_bind_guard() in libc. Pointers to _ti_bind_guard() and _ti_bind_clear()
118 * are passed from libc to runtime linker in _ld_libc() call during libc_init().
119 * All activity is also ignored during:
120 * - runtime dynamic linker work between rt_bind_guard() and rt_bind_clear()
123 * This also means that DRD does not report race conditions in libc (when
124 * --ignore-thread-creation=yes) and runtime linker itself (unconditionally)
125 * during these ignored sequences.
129 * Original function pointers for _ti_bind_guard() and _ti_bind_clear()
130 * from libc. They are intercepted in function wrapper of _ld_libc().
132 typedef int (*drd_rtld_guard_fn
)(int flags
);
133 static drd_rtld_guard_fn
DRD_(rtld_bind_guard
) = NULL
;
134 static drd_rtld_guard_fn
DRD_(rtld_bind_clear
) = NULL
;
139 * Notes regarding thread creation:
140 * - sg_init() runs on the context of the created thread and copies the vector
141 * clock of the creator thread. This only works reliably if the creator
142 * thread waits until this copy has been performed.
143 * - DRD_(thread_compute_minimum_vc)() does not take the vector clocks into
144 * account that are involved in thread creation and for which the
145 * corresponding thread has not yet been created. So not waiting until the
146 * created thread has been started would make it possible that segments get
147 * discarded that should not yet be discarded. Or: some data races are not
152 * Macro for generating a Valgrind interception function.
153 * @param[in] ret_ty Return type of the function to be generated.
154 * @param[in] zf Z-encoded name of the interception function.
155 * @param[in] implf Name of the function that implements the intercept.
156 * @param[in] arg_decl Argument declaration list enclosed in parentheses.
157 * @param[in] argl Argument list enclosed in parentheses.
159 #if defined(VGO_darwin)
161 * Note here VGO_darwin is used rather than VG_WRAP_THREAD_FUNCTION_LIBPTHREAD_ONLY
162 * because of the special-case code adding a function call
164 static int never_true
;
165 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
166 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
167 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
169 ret_ty pth_func_result = implf argl; \
170 /* Apparently inserting a function call in wrapper functions */ \
171 /* is sufficient to avoid misaligned stack errors. */ \
174 return pth_func_result; \
176 #elif defined(VG_WRAP_THREAD_FUNCTION_LIBPTHREAD_ONLY)
177 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
178 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
179 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
180 { return implf argl; }
181 #elif defined(VG_WRAP_THREAD_FUNCTION_LIBC_ONLY)
182 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
183 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl; \
184 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl \
185 { return implf argl; }
186 #elif defined(VG_WRAP_THREAD_FUNCTION_LIBC_AND_LIBPTHREAD)
187 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
188 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl; \
189 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl \
190 { return implf argl; } \
191 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
192 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
193 { return implf argl; }
195 # error "Unknown platform/thread wrapping"
198 #if defined(VGO_freebsd)
199 #define LIBC_FUNC(ret_ty, zf, implf, argl_decl, argl) \
200 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl; \
201 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl \
202 { return implf argl; }
206 * Macro for generating three Valgrind interception functions: one with the
207 * Z-encoded name zf, one with ZAZa ("@*") appended to the name zf and one
208 * with ZDZa ("$*") appended to the name zf. The second generated interception
209 * function will intercept versioned symbols on Linux, and the third will
210 * intercept versioned symbols on Darwin.
212 #define PTH_FUNCS(ret_ty, zf, implf, argl_decl, argl) \
213 PTH_FUNC(ret_ty, zf, implf, argl_decl, argl); \
214 PTH_FUNC(ret_ty, zf ## ZAZa, implf, argl_decl, argl); \
215 PTH_FUNC(ret_ty, zf ## ZDZa, implf, argl_decl, argl);
218 * Not inlining one of the intercept functions will cause the regression
219 * tests to fail because this would cause an additional stackfram to appear
220 * in the output. The __always_inline macro guarantees that inlining will
221 * happen, even when compiling with optimization disabled.
223 #undef __always_inline /* since already defined in <cdefs.h> */
224 #if __GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 2
225 #define __always_inline __inline__ __attribute__((always_inline))
227 #define __always_inline __inline__
230 /* Local data structures. */
233 pthread_mutex_t mutex
;
240 void* (*start
)(void*);
243 DrdSema
* wrapper_started
;
244 } DrdPosixThreadArgs
;
247 /* Local function declarations. */
249 static void DRD_(init
)(void) __attribute__((constructor
));
250 static void DRD_(check_threading_library
)(void);
251 static void DRD_(set_pthread_id
)(void);
252 static void DRD_(sema_init
)(DrdSema
* sema
);
253 static void DRD_(sema_destroy
)(DrdSema
* sema
);
254 static void DRD_(sema_down
)(DrdSema
* sema
);
255 static void DRD_(sema_up
)(DrdSema
* sema
);
258 /* Function definitions. */
261 * Shared library initialization function. The function init() is called after
262 * dlopen() has loaded the shared library with DRD client intercepts because
263 * the constructor attribute was specified in the declaration of this function.
264 * Note: do specify the -nostdlib option to gcc when linking this code into a
265 * shared library because doing so would cancel the effect of the constructor
266 * attribute ! Using the gcc option -nodefaultlibs is fine because this last
267 * option preserves the shared library initialization code that calls
268 * constructor and destructor functions.
270 static void DRD_(init
)(void)
272 #if defined(VGO_freebsd)
275 * On FreeBSD, pthead functions are all in libthr.so
276 * However libc.so contains stubs. In this ctor function,
277 * calling DRD_(set_pthread_id)() results in a call to
278 * pthread_self() resolving to the libc.so stub which
279 * returns a junk value for the tid. Subsequent calls
280 * to pthread_create() then also cause calls to
281 * DRD_(set_pthread_id)(), but this time with pthread_self()
282 * resolving to the good libthr.so version (since this is later
283 * and libthr.so has been loaded). That causes an assert
284 * since we expect the tid to either be INVALID_POSIX_THREADID
285 * or the same as the current tid, and the junk value
286 * is neither. So we force loading of libthr.so, which
287 * avoids this junk tid value.
289 #if (__FreeBSD_version >= 1500013)
290 void* libsys
= dlopen("/lib/libsys.so.7", RTLD_NOW
|RTLD_GLOBAL
|RTLD_NODELETE
);
292 dlclose(dlopen("/lib/libthr.so.3", RTLD_NOW
|RTLD_GLOBAL
|RTLD_NODELETE
));
293 #if (__FreeBSD_version >= 1500013)
301 DRD_(check_threading_library
)();
302 DRD_(set_pthread_id
)();
303 #if defined(VGO_solaris)
304 if ((DRD_(rtld_bind_guard
) == NULL
) || (DRD_(rtld_bind_clear
) == NULL
)) {
306 "Bind guard functions for the runtime linker (ld.so.1) were not intercepted.\n"
307 "This means the interface between libc and runtime linker changed and DRD\n"
308 "needs to be ported properly. Giving up.\n");
314 static __always_inline
void DRD_(ignore_mutex_ordering
)(pthread_mutex_t
*mutex
)
316 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_IGNORE_MUTEX_ORDERING
,
320 static void DRD_(sema_init
)(DrdSema
* sema
)
322 DRD_IGNORE_VAR(*sema
);
323 pthread_mutex_init(&sema
->mutex
, NULL
);
324 DRD_(ignore_mutex_ordering
)(&sema
->mutex
);
325 pthread_cond_init(&sema
->cond
, NULL
);
329 static void DRD_(sema_destroy
)(DrdSema
* sema
)
331 pthread_mutex_destroy(&sema
->mutex
);
332 pthread_cond_destroy(&sema
->cond
);
335 static void DRD_(sema_down
)(DrdSema
* sema
)
337 pthread_mutex_lock(&sema
->mutex
);
338 while (sema
->counter
== 0)
339 pthread_cond_wait(&sema
->cond
, &sema
->mutex
);
341 pthread_mutex_unlock(&sema
->mutex
);
344 static void DRD_(sema_up
)(DrdSema
* sema
)
346 pthread_mutex_lock(&sema
->mutex
);
348 pthread_cond_signal(&sema
->cond
);
349 pthread_mutex_unlock(&sema
->mutex
);
353 * POSIX threads and DRD each have their own mutex type identification.
354 * Convert POSIX threads' mutex type to DRD's mutex type. In the code below
355 * if-statements are used to test the value of 'kind' instead of a switch
356 * statement because some of the PTHREAD_MUTEX_ macro's may have the same
359 static MutexT
DRD_(pthread_to_drd_mutex_type
)(int kind
)
362 * Static checkers don't like this as there are repeated branch
363 * but because there is variation between different platforms
364 * it's messy to make something without repetition.
366 * See also PTHREAD_MUTEX_KIND_MASK_NP in glibc source file
369 kind
&= PTHREAD_MUTEX_RECURSIVE
| PTHREAD_MUTEX_ERRORCHECK
|
370 PTHREAD_MUTEX_NORMAL
| PTHREAD_MUTEX_DEFAULT
;
372 if (kind
== PTHREAD_MUTEX_RECURSIVE
) {
373 return mutex_type_recursive_mutex
;
375 if (kind
== PTHREAD_MUTEX_ERRORCHECK
) {
376 return mutex_type_errorcheck_mutex
;
378 if (kind
== PTHREAD_MUTEX_NORMAL
) {
379 return mutex_type_default_mutex
;
381 if (kind
== PTHREAD_MUTEX_DEFAULT
) {
382 // On FreeBSD PTHREAD_MUTEX_DEFAULT is the same as PTHREAD_MUTEX_ERRORCHECK
383 // so this code is unreachable, but that's not true for all platforms
384 // so just ignore the warning
385 // coverity[DEADCODE:FALSE]
386 return mutex_type_default_mutex
;
388 #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
389 if (kind
== PTHREAD_MUTEX_ADAPTIVE_NP
) {
390 return mutex_type_default_mutex
;
393 return mutex_type_invalid_mutex
;
396 #if defined(VGO_solaris)
398 * Solaris threads and DRD each have their own mutex type identification.
399 * Convert Solaris threads' mutex type to DRD's mutex type.
401 static MutexT
DRD_(thread_to_drd_mutex_type
)(int type
)
403 if (type
& LOCK_RECURSIVE
) {
404 return mutex_type_recursive_mutex
;
405 } else if (type
& LOCK_ERRORCHECK
) {
406 return mutex_type_errorcheck_mutex
;
408 return mutex_type_default_mutex
;
411 #endif /* VGO_solaris */
413 #define IS_ALIGNED(p) (((uintptr_t)(p) & (sizeof(*(p)) - 1)) == 0)
416 * Read the mutex type stored in the client memory used for the mutex
419 * @note This function depends on the implementation of the POSIX threads
420 * library -- the POSIX standard does not define the name of the member in
421 * which the mutex type is stored.
422 * @note The function mutex_type() has been declared inline in order
423 * to avoid that it shows up in call stacks (drd/tests/...exp* files).
424 * @note glibc stores the mutex type in the lowest two bits, and uses the
425 * higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
426 * PTHREAD_MUTEXATTR_FLAG_PSHARED.
428 static __always_inline MutexT
DRD_(mutex_type
)(pthread_mutex_t
* mutex
)
430 MutexT mutex_type
= mutex_type_unknown
;
432 ANNOTATE_IGNORE_READS_BEGIN();
433 #if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
434 /* glibc + LinuxThreads. */
435 if (IS_ALIGNED(&mutex
->__m_kind
))
437 const int kind
= mutex
->__m_kind
& 3;
438 mutex_type
= DRD_(pthread_to_drd_mutex_type
)(kind
);
440 #elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
442 if (IS_ALIGNED(&mutex
->__data
.__kind
))
444 const int kind
= mutex
->__data
.__kind
& 3;
445 mutex_type
= DRD_(pthread_to_drd_mutex_type
)(kind
);
447 #elif defined(VGO_solaris)
449 const int type
= ((mutex_t
*) mutex
)->vki_mutex_type
;
450 mutex_type
= DRD_(thread_to_drd_mutex_type
)(type
);
454 * Another POSIX threads implementation. The mutex type won't be printed
455 * when enabling --trace-mutex=yes.
458 ANNOTATE_IGNORE_READS_END();
464 * Tell DRD whether 'tid' is a joinable thread or a detached thread.
466 static void DRD_(set_joinable
)(const pthread_t tid
, const int joinable
)
468 assert(joinable
== 0 || joinable
== 1);
469 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_SET_JOINABLE
,
470 tid
, joinable
, 0, 0, 0);
473 /** Tell DRD that the calling thread is about to enter pthread_create(). */
474 static __always_inline
void DRD_(entering_pthread_create
)(void)
476 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_ENTERING_PTHREAD_CREATE
,
480 /** Tell DRD that the calling thread has left pthread_create(). */
481 static __always_inline
void DRD_(left_pthread_create
)(void)
483 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_LEFT_PTHREAD_CREATE
,
488 * Entry point for newly created threads. This function is called from the
489 * thread created by pthread_create().
491 static void* DRD_(thread_wrapper
)(void* arg
)
493 DrdPosixThreadArgs
* arg_ptr
;
494 DrdPosixThreadArgs arg_copy
;
496 arg_ptr
= (DrdPosixThreadArgs
*)arg
;
499 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_SET_PTHREADID
,
500 pthread_self(), 0, 0, 0, 0);
502 DRD_(set_joinable
)(pthread_self(),
503 arg_copy
.detachstate
== PTHREAD_CREATE_JOINABLE
);
506 * Only set 'wrapper_started' after VG_USERREQ__SET_PTHREADID and
507 * DRD_(set_joinable)() have been invoked to avoid a race with
508 * a pthread_detach() invocation for this thread from another thread.
510 DRD_(sema_up
)(arg_copy
.wrapper_started
);
512 return (arg_copy
.start
)(arg_copy
.arg
);
516 * Return 1 if the LinuxThreads implementation of POSIX Threads has been
517 * detected, and 0 otherwise.
519 * @see For more information about the confstr() function, see also
520 * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
522 static int DRD_(detected_linuxthreads
)(void)
525 #if defined(_CS_GNU_LIBPTHREAD_VERSION)
526 /* Linux with a recent glibc. */
529 len
= confstr(_CS_GNU_LIBPTHREAD_VERSION
, buffer
, sizeof(buffer
));
530 assert(len
<= sizeof(buffer
));
531 return len
> 0 && buffer
[0] == 'l';
533 /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
537 /* Another OS than Linux, hence no LinuxThreads. */
543 * Stop and print an error message in case a non-supported threading
544 * library implementation (LinuxThreads) has been detected.
546 static void DRD_(check_threading_library
)(void)
548 if (DRD_(detected_linuxthreads
)())
550 if (getenv("LD_ASSUME_KERNEL"))
553 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
554 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
555 "after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
561 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
562 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
563 "after having upgraded to a newer version of your Linux distribution.\n"
572 * Update DRD's state information about the current thread.
574 static void DRD_(set_pthread_id
)(void)
576 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_SET_PTHREADID
,
577 pthread_self(), 0, 0, 0, 0);
581 * Note: as of today there exist three different versions of pthread_create
583 * - pthread_create@GLIBC_2.0
584 * - pthread_create@@GLIBC_2.1
585 * - pthread_create@@GLIBC_2.2.5
586 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
587 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
588 * versions have been implemented. In any glibc version where more than one
589 * pthread_create function has been implemented, older versions call the
590 * newer versions. Or: the pthread_create* wrapper defined below can be
591 * called recursively. Any code in this wrapper should take this in account.
592 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
593 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
594 * See also the implementation of pthread_create@GLIBC_2.0 in
595 * glibc-2.9/nptl/pthread_create.c.
598 static __always_inline
599 int pthread_create_intercept(pthread_t
* thread
, const pthread_attr_t
* attr
,
600 void* (*start
)(void*), void* arg
)
604 DrdSema wrapper_started
;
605 DrdPosixThreadArgs thread_args
;
607 VALGRIND_GET_ORIG_FN(fn
);
609 DRD_(sema_init
)(&wrapper_started
);
610 thread_args
.start
= start
;
611 thread_args
.arg
= arg
;
612 thread_args
.wrapper_started
= &wrapper_started
;
614 * Find out whether the thread will be started as a joinable thread
615 * or as a detached thread. If no thread attributes have been specified,
616 * this means that the new thread will be started as a joinable thread.
618 thread_args
.detachstate
= PTHREAD_CREATE_JOINABLE
;
619 /* The C11 thrd_create() implementation passes -1 as 'attr' argument. */
620 if (attr
&& (uintptr_t)attr
+ 1 != 0)
622 if (pthread_attr_getdetachstate(attr
, &thread_args
.detachstate
) != 0)
625 assert(thread_args
.detachstate
== PTHREAD_CREATE_JOINABLE
626 || thread_args
.detachstate
== PTHREAD_CREATE_DETACHED
);
629 * The DRD_(set_pthread_id)() from DRD_(init)() may encounter that
630 * pthread_self() == 0, e.g. when the main program is not linked with the
631 * pthread library and when a pthread_create() call occurs from within a
632 * shared library. Hence call DRD_(set_pthread_id)() again to ensure that
633 * DRD knows the identity of the current thread. See also B.Z. 356374.
635 DRD_(set_pthread_id
)();
636 DRD_(entering_pthread_create
)();
637 CALL_FN_W_WWWW(ret
, fn
, thread
, attr
, DRD_(thread_wrapper
), &thread_args
);
638 DRD_(left_pthread_create
)();
641 /* Wait until the thread wrapper started. */
642 DRD_(sema_down
)(&wrapper_started
);
645 DRD_(sema_destroy
)(&wrapper_started
);
647 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_START_NEW_SEGMENT
,
648 pthread_self(), 0, 0, 0, 0);
653 PTH_FUNCS(int, pthreadZucreate
, pthread_create_intercept
,
654 (pthread_t
*thread
, const pthread_attr_t
*attr
,
655 void *(*start
) (void *), void *arg
),
656 (thread
, attr
, start
, arg
));
658 #if defined(VGO_solaris)
659 /* Solaris also provides thr_create() in addition to pthread_create().
660 * Both pthread_create(3C) and thr_create(3C) are based on private
663 static __always_inline
664 int thr_create_intercept(void *stk
, size_t stksize
, void *(*start
)(void *),
665 void *arg
, long flags
, thread_t
*new_thread
)
669 DrdSema wrapper_started
;
670 DrdPosixThreadArgs thread_args
;
672 VALGRIND_GET_ORIG_FN(fn
);
674 DRD_(sema_init
)(&wrapper_started
);
675 thread_args
.start
= start
;
676 thread_args
.arg
= arg
;
677 thread_args
.wrapper_started
= &wrapper_started
;
679 * Find out whether the thread will be started as a joinable thread
680 * or as a detached thread.
682 if (flags
& THR_DETACHED
)
683 thread_args
.detachstate
= PTHREAD_CREATE_DETACHED
;
685 thread_args
.detachstate
= PTHREAD_CREATE_JOINABLE
;
687 DRD_(entering_pthread_create
)();
688 CALL_FN_W_6W(ret
, fn
, stk
, stksize
, DRD_(thread_wrapper
), &thread_args
,
690 DRD_(left_pthread_create
)();
693 /* Wait until the thread wrapper started. */
694 DRD_(sema_down
)(&wrapper_started
);
697 DRD_(sema_destroy
)(&wrapper_started
);
699 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_START_NEW_SEGMENT
,
700 pthread_self(), 0, 0, 0, 0);
705 PTH_FUNCS(int, thrZucreate
, thr_create_intercept
,
706 (void *stk
, size_t stksize
, void *(*start
)(void *), void *arg
,
707 long flags
, thread_t
*new_thread
),
708 (stk
, stksize
, start
, arg
, flags
, new_thread
));
709 #endif /* VGO_solaris */
711 #if defined(VGO_solaris)
713 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
714 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
715 * and CI_BIND_CLEAR, to provide resilience against function renaming.
717 static __always_inline
718 int DRD_(_ti_bind_guard_intercept
)(int flags
) {
719 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_RTLD_BIND_GUARD
,
721 return DRD_(rtld_bind_guard
)(flags
);
724 static __always_inline
725 int DRD_(_ti_bind_clear_intercept
)(int flags
) {
726 int ret
= DRD_(rtld_bind_clear
)(flags
);
727 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_RTLD_BIND_CLEAR
,
733 * Wrapped _ld_libc() from the runtime linker ld.so.1.
735 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1
, ZuldZulibc
)(vki_Lc_interface
*ptr
);
736 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1
, ZuldZulibc
)(vki_Lc_interface
*ptr
)
741 VALGRIND_GET_ORIG_FN(fn
);
743 vki_Lc_interface
*funcs
= ptr
;
744 for (tag
= funcs
->ci_tag
; tag
!= 0; tag
= (++funcs
)->ci_tag
) {
746 case VKI_CI_BIND_GUARD
:
747 if (funcs
->vki_ci_un
.ci_func
!= DRD_(_ti_bind_guard_intercept
)) {
748 DRD_(rtld_bind_guard
) = funcs
->vki_ci_un
.ci_func
;
749 funcs
->vki_ci_un
.ci_func
= DRD_(_ti_bind_guard_intercept
);
752 case VKI_CI_BIND_CLEAR
:
753 if (funcs
->vki_ci_un
.ci_func
!= DRD_(_ti_bind_clear_intercept
)) {
754 DRD_(rtld_bind_clear
) = funcs
->vki_ci_un
.ci_func
;
755 funcs
->vki_ci_un
.ci_func
= DRD_(_ti_bind_clear_intercept
);
761 CALL_FN_v_W(fn
, ptr
);
763 #endif /* VGO_solaris */
765 static __always_inline
766 int pthread_join_intercept(pthread_t pt_joinee
, void **thread_return
)
771 VALGRIND_GET_ORIG_FN(fn
);
773 * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
774 * implementation triggers a (false positive) race report.
776 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
777 CALL_FN_W_WW(ret
, fn
, pt_joinee
, thread_return
);
780 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_THREAD_JOIN
,
781 pt_joinee
, 0, 0, 0, 0);
783 ANNOTATE_IGNORE_READS_AND_WRITES_END();
787 PTH_FUNCS(int, pthreadZujoin
, pthread_join_intercept
,
788 (pthread_t pt_joinee
, void **thread_return
),
789 (pt_joinee
, thread_return
));
791 #if defined(VGO_solaris)
792 /* Solaris also provides thr_join() in addition to pthread_join().
793 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
795 * :TODO: No functionality is currently provided for joinee == 0 and departed.
796 * This would require another client request, of course.
798 static __always_inline
799 int thr_join_intercept(thread_t joinee
, thread_t
*departed
, void **thread_return
)
804 VALGRIND_GET_ORIG_FN(fn
);
805 CALL_FN_W_WWW(ret
, fn
, joinee
, departed
, thread_return
);
808 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_THREAD_JOIN
,
814 PTH_FUNCS(int, thrZujoin
, thr_join_intercept
,
815 (thread_t joinee
, thread_t
*departed
, void **thread_return
),
816 (joinee
, departed
, thread_return
));
817 #endif /* VGO_solaris */
819 static __always_inline
820 int pthread_detach_intercept(pthread_t pt_thread
)
825 VALGRIND_GET_ORIG_FN(fn
);
826 CALL_FN_W_W(ret
, fn
, pt_thread
);
827 DRD_(set_joinable
)(pt_thread
, 0);
832 PTH_FUNCS(int, pthreadZudetach
, pthread_detach_intercept
,
833 (pthread_t thread
), (thread
));
835 // NOTE: be careful to intercept only pthread_cancel() and not
836 // pthread_cancel_init() on Linux.
838 static __always_inline
839 int pthread_cancel_intercept(pthread_t pt_thread
)
843 VALGRIND_GET_ORIG_FN(fn
);
844 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_THREAD_CANCEL
,
845 pt_thread
, 0, 0, 0, 0);
846 CALL_FN_W_W(ret
, fn
, pt_thread
);
847 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_THREAD_CANCEL
,
848 pt_thread
, ret
==0, 0, 0, 0);
852 PTH_FUNCS(int, pthreadZucancel
, pthread_cancel_intercept
,
853 (pthread_t thread
), (thread
))
855 static __always_inline
856 int pthread_once_intercept(pthread_once_t
*once_control
,
857 void (*init_routine
)(void))
861 VALGRIND_GET_ORIG_FN(fn
);
863 * Ignore any data races triggered by the implementation of pthread_once().
864 * Necessary for Darwin. This is not necessary for Linux but doesn't have
865 * any known adverse effects.
867 DRD_IGNORE_VAR(*once_control
);
868 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
869 CALL_FN_W_WW(ret
, fn
, once_control
, init_routine
);
870 ANNOTATE_IGNORE_READS_AND_WRITES_END();
871 DRD_STOP_IGNORING_VAR(*once_control
);
875 PTH_FUNCS(int, pthreadZuonce
, pthread_once_intercept
,
876 (pthread_once_t
*once_control
, void (*init_routine
)(void)),
877 (once_control
, init_routine
));
879 static __always_inline
880 int pthread_mutex_init_intercept(pthread_mutex_t
*mutex
,
881 const pthread_mutexattr_t
* attr
)
886 VALGRIND_GET_ORIG_FN(fn
);
887 mt
= PTHREAD_MUTEX_DEFAULT
;
889 pthread_mutexattr_gettype(attr
, &mt
);
890 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_INIT
,
891 mutex
, DRD_(pthread_to_drd_mutex_type
)(mt
),
893 CALL_FN_W_WW(ret
, fn
, mutex
, attr
);
894 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_INIT
,
899 PTH_FUNCS(int, pthreadZumutexZuinit
, pthread_mutex_init_intercept
,
900 (pthread_mutex_t
*mutex
, const pthread_mutexattr_t
* attr
),
903 #if defined(VGO_solaris)
904 static __always_inline
905 int mutex_init_intercept(mutex_t
*mutex
, int type
, void *arg
)
909 VALGRIND_GET_ORIG_FN(fn
);
911 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_INIT
,
912 mutex
, DRD_(thread_to_drd_mutex_type
)(type
),
914 CALL_FN_W_WWW(ret
, fn
, mutex
, type
, arg
);
915 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_INIT
,
920 PTH_FUNCS(int, mutexZuinit
, mutex_init_intercept
,
921 (mutex_t
*mutex
, int type
, void *arg
),
923 #endif /* VGO_solaris */
925 static __always_inline
926 int pthread_mutex_destroy_intercept(pthread_mutex_t
* mutex
)
930 VALGRIND_GET_ORIG_FN(fn
);
931 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_DESTROY
,
933 CALL_FN_W_W(ret
, fn
, mutex
);
934 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_DESTROY
,
935 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
939 #if defined(VGO_solaris)
940 /* On Solaris, pthread_mutex_destroy is a weak alias to mutex_destroy. */
941 PTH_FUNCS(int, mutexZudestroy
, pthread_mutex_destroy_intercept
,
942 (pthread_mutex_t
*mutex
), (mutex
));
944 PTH_FUNCS(int, pthreadZumutexZudestroy
, pthread_mutex_destroy_intercept
,
945 (pthread_mutex_t
*mutex
), (mutex
));
946 #endif /* VGO_solaris */
948 static __always_inline
949 int pthread_mutex_lock_intercept(pthread_mutex_t
* mutex
)
953 VALGRIND_GET_ORIG_FN(fn
);
954 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK
,
955 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
956 CALL_FN_W_W(ret
, fn
, mutex
);
957 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK
,
958 mutex
, ret
== 0, 0, 0, 0);
962 #if defined(VGO_solaris)
963 /* On Solaris, pthread_mutex_lock is a weak alias to mutex_lock. */
964 PTH_FUNCS(int, mutexZulock
, pthread_mutex_lock_intercept
,
965 (pthread_mutex_t
*mutex
), (mutex
));
967 PTH_FUNCS(int, pthreadZumutexZulock
, pthread_mutex_lock_intercept
,
968 (pthread_mutex_t
*mutex
), (mutex
));
969 #endif /* VGO_solaris */
971 #if defined(VGO_solaris)
972 /* Internal to libc. Mutex is usually initialized only implicitly,
973 * by zeroing mutex_t structure.
975 static __always_inline
976 void lmutex_lock_intercept(mutex_t
*mutex
)
979 VALGRIND_GET_ORIG_FN(fn
);
980 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK
,
982 DRD_(mutex_type
)((pthread_mutex_t
*) mutex
),
983 False
/* try_lock */, 0, 0);
984 CALL_FN_v_W(fn
, mutex
);
985 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK
,
986 mutex
, True
/* took_lock */, 0, 0, 0);
989 PTH_FUNCS(void, lmutexZulock
, lmutex_lock_intercept
,
990 (mutex_t
*mutex
), (mutex
));
991 #endif /* VGO_solaris */
993 static __always_inline
994 int pthread_mutex_trylock_intercept(pthread_mutex_t
* mutex
)
998 VALGRIND_GET_ORIG_FN(fn
);
999 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK
,
1000 mutex
, DRD_(mutex_type
)(mutex
), 1, 0, 0);
1001 CALL_FN_W_W(ret
, fn
, mutex
);
1002 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK
,
1003 mutex
, ret
== 0, 0, 0, 0);
1007 #if defined(VGO_solaris)
1008 /* On Solaris, pthread_mutex_trylock is a weak alias to mutex_trylock. */
1009 PTH_FUNCS(int, mutexZutrylock
, pthread_mutex_trylock_intercept
,
1010 (pthread_mutex_t
*mutex
), (mutex
));
1012 PTH_FUNCS(int, pthreadZumutexZutrylock
, pthread_mutex_trylock_intercept
,
1013 (pthread_mutex_t
*mutex
), (mutex
));
1014 #endif /* VGO_solaris */
1016 static __always_inline
1017 int pthread_mutex_timedlock_intercept(pthread_mutex_t
*mutex
,
1018 const struct timespec
*abs_timeout
)
1022 VALGRIND_GET_ORIG_FN(fn
);
1023 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK
,
1024 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
1025 CALL_FN_W_WW(ret
, fn
, mutex
, abs_timeout
);
1026 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK
,
1027 mutex
, ret
== 0, 0, 0, 0);
1031 PTH_FUNCS(int, pthreadZumutexZutimedlock
, pthread_mutex_timedlock_intercept
,
1032 (pthread_mutex_t
*mutex
, const struct timespec
*abs_timeout
),
1033 (mutex
, abs_timeout
));
1034 #if defined(VGO_solaris)
1036 pthreadZumutexZureltimedlockZunp
, pthread_mutex_timedlock_intercept
,
1037 (pthread_mutex_t
*mutex
, const struct timespec
*timeout
),
1039 #endif /* VGO_solaris */
1041 #if defined(HAVE_CLOCKID_T)
1042 static __always_inline
1043 int pthread_mutex_clocklock_intercept(pthread_mutex_t
*mutex
,
1045 const struct timespec
*abs_timeout
)
1049 VALGRIND_GET_ORIG_FN(fn
);
1050 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK
,
1051 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
1052 CALL_FN_W_WWW(ret
, fn
, mutex
, clockid
, abs_timeout
);
1053 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK
,
1054 mutex
, ret
== 0, 0, 0, 0);
1058 PTH_FUNCS(int, pthreadZumutexZuclocklock
, pthread_mutex_clocklock_intercept
,
1059 (pthread_mutex_t
*mutex
, clockid_t clockid
, const struct timespec
*abs_timeout
),
1060 (mutex
, clockid
, abs_timeout
));
1063 static __always_inline
1064 int pthread_mutex_unlock_intercept(pthread_mutex_t
*mutex
)
1068 VALGRIND_GET_ORIG_FN(fn
);
1069 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_UNLOCK
,
1070 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
1071 CALL_FN_W_W(ret
, fn
, mutex
);
1072 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_UNLOCK
,
1077 #if defined(VGO_solaris)
1078 /* On Solaris, pthread_mutex_unlock is a weak alias to mutex_unlock. */
1079 PTH_FUNCS(int, mutexZuunlock
, pthread_mutex_unlock_intercept
,
1080 (pthread_mutex_t
*mutex
), (mutex
));
1082 PTH_FUNCS(int, pthreadZumutexZuunlock
, pthread_mutex_unlock_intercept
,
1083 (pthread_mutex_t
*mutex
), (mutex
));
1084 #endif /* VGO_solaris */
1086 #if defined(VGO_solaris)
1087 /* Internal to libc. */
1088 static __always_inline
1089 void lmutex_unlock_intercept(mutex_t
*mutex
)
1092 VALGRIND_GET_ORIG_FN(fn
);
1093 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_UNLOCK
,
1095 DRD_(mutex_type
)((pthread_mutex_t
*) mutex
),
1097 CALL_FN_v_W(fn
, mutex
);
1098 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_UNLOCK
,
1102 PTH_FUNCS(void, lmutexZuunlock
, lmutex_unlock_intercept
,
1103 (mutex_t
*mutex
), (mutex
));
1104 #endif /* VGO_solaris */
1106 static __always_inline
1107 int pthread_cond_init_intercept(pthread_cond_t
* cond
,
1108 const pthread_condattr_t
* attr
)
1112 VALGRIND_GET_ORIG_FN(fn
);
1113 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_INIT
,
1115 CALL_FN_W_WW(ret
, fn
, cond
, attr
);
1116 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_INIT
,
1121 PTH_FUNCS(int, pthreadZucondZuinit
, pthread_cond_init_intercept
,
1122 (pthread_cond_t
* cond
, const pthread_condattr_t
* attr
),
1125 #if defined(VGO_solaris)
1126 static __always_inline
1127 int cond_init_intercept(cond_t
*cond
, int type
, void *arg
)
1131 VALGRIND_GET_ORIG_FN(fn
);
1132 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_INIT
,
1134 CALL_FN_W_WWW(ret
, fn
, cond
, type
, arg
);
1135 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_INIT
,
1140 PTH_FUNCS(int, condZuinit
, cond_init_intercept
,
1141 (cond_t
*cond
, int type
, void *arg
),
1143 #endif /* VGO_solaris */
1145 static __always_inline
1146 int pthread_cond_destroy_intercept(pthread_cond_t
* cond
)
1150 VALGRIND_GET_ORIG_FN(fn
);
1151 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_DESTROY
,
1153 CALL_FN_W_W(ret
, fn
, cond
);
1154 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_DESTROY
,
1155 cond
, ret
==0, 0, 0, 0);
1159 #if defined(VGO_solaris)
1160 /* On Solaris, pthread_cond_destroy is a weak alias to cond_destroy. */
1161 PTH_FUNCS(int, condZudestroy
, pthread_cond_destroy_intercept
,
1162 (pthread_cond_t
*cond
), (cond
));
1164 PTH_FUNCS(int, pthreadZucondZudestroy
, pthread_cond_destroy_intercept
,
1165 (pthread_cond_t
* cond
), (cond
));
1166 #endif /* VGO_solaris */
1168 static __always_inline
1169 int pthread_cond_wait_intercept(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
1173 VALGRIND_GET_ORIG_FN(fn
);
1174 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_WAIT
,
1175 cond
, mutex
, DRD_(mutex_type
)(mutex
), 0, 0);
1176 CALL_FN_W_WW(ret
, fn
, cond
, mutex
);
1177 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_WAIT
,
1178 cond
, mutex
, 1, 0, 0);
1182 PTH_FUNCS(int, pthreadZucondZuwait
, pthread_cond_wait_intercept
,
1183 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
),
1185 #if defined(VGO_solaris)
1186 PTH_FUNCS(int, condZuwait
, pthread_cond_wait_intercept
,
1187 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
),
1189 #endif /* VGO_solaris */
1191 static __always_inline
1192 int pthread_cond_timedwait_intercept(pthread_cond_t
*cond
,
1193 pthread_mutex_t
*mutex
,
1194 const struct timespec
* abstime
)
1198 VALGRIND_GET_ORIG_FN(fn
);
1199 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_WAIT
,
1200 cond
, mutex
, DRD_(mutex_type
)(mutex
), 0, 0);
1201 CALL_FN_W_WWW(ret
, fn
, cond
, mutex
, abstime
);
1202 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_WAIT
,
1203 cond
, mutex
, 1, 0, 0);
1207 PTH_FUNCS(int, pthreadZucondZutimedwait
, pthread_cond_timedwait_intercept
,
1208 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1209 const struct timespec
* abstime
),
1210 (cond
, mutex
, abstime
));
1211 #if defined(VGO_solaris)
1212 PTH_FUNCS(int, condZutimedwait
, pthread_cond_timedwait_intercept
,
1213 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1214 const struct timespec
*timeout
),
1215 (cond
, mutex
, timeout
));
1216 PTH_FUNCS(int, condZureltimedwait
, pthread_cond_timedwait_intercept
,
1217 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1218 const struct timespec
*timeout
),
1219 (cond
, mutex
, timeout
));
1220 #endif /* VGO_solaris */
1223 #if defined(HAVE_CLOCKID_T)
1224 static __always_inline
1225 int pthread_cond_clockwait_intercept(pthread_cond_t
*cond
,
1226 pthread_mutex_t
*mutex
,
1228 const struct timespec
* abstime
)
1232 VALGRIND_GET_ORIG_FN(fn
);
1233 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_WAIT
,
1234 cond
, mutex
, DRD_(mutex_type
)(mutex
), 0, 0);
1235 CALL_FN_W_WWWW(ret
, fn
, cond
, mutex
, clockid
, abstime
);
1236 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_WAIT
,
1237 cond
, mutex
, 1, 0, 0);
1241 PTH_FUNCS(int, pthreadZucondZuclockwait
, pthread_cond_clockwait_intercept
,
1242 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1243 clockid_t clockid
, const struct timespec
* abstime
),
1244 (cond
, mutex
, clockid
, abstime
));
1248 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
1249 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
1250 // two. Intercepting all pthread_cond_signal* functions will cause only one
1251 // argument to be passed to pthread_cond_signal_np() and hence will cause this
1252 // last function to crash.
1254 static __always_inline
1255 int pthread_cond_signal_intercept(pthread_cond_t
* cond
)
1259 VALGRIND_GET_ORIG_FN(fn
);
1260 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_SIGNAL
,
1262 CALL_FN_W_W(ret
, fn
, cond
);
1263 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_SIGNAL
,
1268 #if defined(VGO_solaris)
1269 /* On Solaris, pthread_cond_signal is a weak alias to cond_signal. */
1270 PTH_FUNCS(int, condZusignal
, pthread_cond_signal_intercept
,
1271 (pthread_cond_t
*cond
), (cond
));
1273 PTH_FUNCS(int, pthreadZucondZusignal
, pthread_cond_signal_intercept
,
1274 (pthread_cond_t
* cond
), (cond
));
1275 #endif /* VGO_solaris */
1277 static __always_inline
1278 int pthread_cond_broadcast_intercept(pthread_cond_t
* cond
)
1282 VALGRIND_GET_ORIG_FN(fn
);
1283 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_BROADCAST
,
1285 CALL_FN_W_W(ret
, fn
, cond
);
1286 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_BROADCAST
,
1291 #if defined(VGO_solaris)
1292 /* On Solaris, pthread_cond_broadcast is a weak alias to cond_broadcast. */
1293 PTH_FUNCS(int, condZubroadcast
, pthread_cond_broadcast_intercept
,
1294 (pthread_cond_t
*cond
), (cond
));
1296 PTH_FUNCS(int, pthreadZucondZubroadcast
, pthread_cond_broadcast_intercept
,
1297 (pthread_cond_t
* cond
), (cond
));
1298 #endif /* VGO_solaris */
1300 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1301 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1302 static __always_inline
1303 int pthread_spin_init_intercept(pthread_spinlock_t
*spinlock
, int pshared
)
1307 VALGRIND_GET_ORIG_FN(fn
);
1308 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SPIN_INIT_OR_UNLOCK
,
1309 spinlock
, 0, 0, 0, 0);
1310 CALL_FN_W_WW(ret
, fn
, spinlock
, pshared
);
1311 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SPIN_INIT_OR_UNLOCK
,
1312 spinlock
, 0, 0, 0, 0);
1316 PTH_FUNCS(int, pthreadZuspinZuinit
, pthread_spin_init_intercept
,
1317 (pthread_spinlock_t
*spinlock
, int pshared
), (spinlock
, pshared
));
1319 static __always_inline
1320 int pthread_spin_destroy_intercept(pthread_spinlock_t
*spinlock
)
1324 VALGRIND_GET_ORIG_FN(fn
);
1325 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_DESTROY
,
1326 spinlock
, 0, 0, 0, 0);
1327 CALL_FN_W_W(ret
, fn
, spinlock
);
1328 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_DESTROY
,
1329 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1333 PTH_FUNCS(int, pthreadZuspinZudestroy
, pthread_spin_destroy_intercept
,
1334 (pthread_spinlock_t
*spinlock
), (spinlock
));
1336 static __always_inline
1337 int pthread_spin_lock_intercept(pthread_spinlock_t
*spinlock
)
1341 VALGRIND_GET_ORIG_FN(fn
);
1342 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK
,
1343 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1344 CALL_FN_W_W(ret
, fn
, spinlock
);
1345 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK
,
1346 spinlock
, ret
== 0, 0, 0, 0);
1350 PTH_FUNCS(int, pthreadZuspinZulock
, pthread_spin_lock_intercept
,
1351 (pthread_spinlock_t
*spinlock
), (spinlock
));
1353 static __always_inline
1354 int pthread_spin_trylock_intercept(pthread_spinlock_t
*spinlock
)
1358 VALGRIND_GET_ORIG_FN(fn
);
1359 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK
,
1360 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1361 CALL_FN_W_W(ret
, fn
, spinlock
);
1362 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK
,
1363 spinlock
, ret
== 0, 0, 0, 0);
1367 PTH_FUNCS(int, pthreadZuspinZutrylock
, pthread_spin_trylock_intercept
,
1368 (pthread_spinlock_t
*spinlock
), (spinlock
));
1370 static __always_inline
1371 int pthread_spin_unlock_intercept(pthread_spinlock_t
*spinlock
)
1375 VALGRIND_GET_ORIG_FN(fn
);
1376 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SPIN_INIT_OR_UNLOCK
,
1377 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1378 CALL_FN_W_W(ret
, fn
, spinlock
);
1379 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SPIN_INIT_OR_UNLOCK
,
1380 spinlock
, 0, 0, 0, 0);
1384 PTH_FUNCS(int, pthreadZuspinZuunlock
, pthread_spin_unlock_intercept
,
1385 (pthread_spinlock_t
*spinlock
), (spinlock
));
1386 #endif // HAVE_PTHREAD_SPIN_LOCK
1389 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1390 static __always_inline
1391 int pthread_barrier_init_intercept(pthread_barrier_t
* barrier
,
1392 const pthread_barrierattr_t
* attr
,
1397 VALGRIND_GET_ORIG_FN(fn
);
1398 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_BARRIER_INIT
,
1399 barrier
, pthread_barrier
, count
, 0, 0);
1400 CALL_FN_W_WWW(ret
, fn
, barrier
, attr
, count
);
1401 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_BARRIER_INIT
,
1402 barrier
, pthread_barrier
, 0, 0, 0);
1406 PTH_FUNCS(int, pthreadZubarrierZuinit
, pthread_barrier_init_intercept
,
1407 (pthread_barrier_t
* barrier
, const pthread_barrierattr_t
* attr
,
1408 unsigned count
), (barrier
, attr
, count
));
1410 static __always_inline
1411 int pthread_barrier_destroy_intercept(pthread_barrier_t
* barrier
)
1415 VALGRIND_GET_ORIG_FN(fn
);
1416 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_BARRIER_DESTROY
,
1417 barrier
, pthread_barrier
, 0, 0, 0);
1418 CALL_FN_W_W(ret
, fn
, barrier
);
1419 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_BARRIER_DESTROY
,
1420 barrier
, pthread_barrier
, 0, 0, 0);
1424 PTH_FUNCS(int, pthreadZubarrierZudestroy
, pthread_barrier_destroy_intercept
,
1425 (pthread_barrier_t
* barrier
), (barrier
));
1427 static __always_inline
1428 int pthread_barrier_wait_intercept(pthread_barrier_t
* barrier
)
1432 VALGRIND_GET_ORIG_FN(fn
);
1433 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_BARRIER_WAIT
,
1434 barrier
, pthread_barrier
, 0, 0, 0);
1435 CALL_FN_W_W(ret
, fn
, barrier
);
1436 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_BARRIER_WAIT
,
1437 barrier
, pthread_barrier
,
1438 ret
== 0 || ret
== PTHREAD_BARRIER_SERIAL_THREAD
,
1439 ret
== PTHREAD_BARRIER_SERIAL_THREAD
, 0);
1443 PTH_FUNCS(int, pthreadZubarrierZuwait
, pthread_barrier_wait_intercept
,
1444 (pthread_barrier_t
* barrier
), (barrier
));
1445 #endif // HAVE_PTHREAD_BARRIER_INIT
1448 static __always_inline
1449 int sem_init_intercept(sem_t
*sem
, int pshared
, unsigned int value
)
1453 VALGRIND_GET_ORIG_FN(fn
);
1454 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_INIT
,
1455 sem
, pshared
, value
, 0, 0);
1456 CALL_FN_W_WWW(ret
, fn
, sem
, pshared
, value
);
1457 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_INIT
,
1462 #if defined(VGO_freebsd)
1463 LIBC_FUNC(int, semZuinit
, sem_init_intercept
,
1464 (sem_t
*sem
, int pshared
, unsigned int value
), (sem
, pshared
, value
));
1466 PTH_FUNCS(int, semZuinit
, sem_init_intercept
,
1467 (sem_t
*sem
, int pshared
, unsigned int value
), (sem
, pshared
, value
));
1470 #if defined(VGO_solaris)
1471 static __always_inline
1472 int sema_init_intercept(sema_t
*sem
, unsigned int value
, int type
, void *arg
)
1476 VALGRIND_GET_ORIG_FN(fn
);
1477 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_INIT
,
1478 sem
, type
== USYNC_PROCESS
? 1 : 0,
1480 CALL_FN_W_WWWW(ret
, fn
, sem
, value
, type
, arg
);
1481 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_INIT
,
1486 PTH_FUNCS(int, semaZuinit
, sema_init_intercept
,
1487 (sema_t
*sem
, unsigned int value
, int type
, void *arg
),
1488 (sem
, value
, type
, arg
));
1489 #endif /* VGO_solaris */
1491 static __always_inline
1492 int sem_destroy_intercept(sem_t
*sem
)
1496 VALGRIND_GET_ORIG_FN(fn
);
1497 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_DESTROY
,
1499 CALL_FN_W_W(ret
, fn
, sem
);
1500 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_DESTROY
,
1505 #if defined(VGO_freebsd)
1506 LIBC_FUNC(int, semZudestroy
, sem_destroy_intercept
, (sem_t
*sem
), (sem
));
1508 PTH_FUNCS(int, semZudestroy
, sem_destroy_intercept
, (sem_t
*sem
), (sem
));
1511 #if defined(VGO_solaris)
1512 PTH_FUNCS(int, semaZudestroy
, sem_destroy_intercept
, (sem_t
*sem
), (sem
));
1513 #endif /* VGO_solaris */
1515 static __always_inline
1516 sem_t
* sem_open_intercept(const char *name
, int oflag
, mode_t mode
,
1521 VALGRIND_GET_ORIG_FN(fn
);
1522 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_OPEN
,
1523 name
, oflag
, mode
, value
, 0);
1524 CALL_FN_W_WWWW(ret
, fn
, name
, oflag
, mode
, value
);
1525 // To do: figure out why gcc 9.2.1 miscompiles this function if the printf()
1526 // call below is left out.
1528 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_OPEN
,
1529 ret
!= SEM_FAILED
? ret
: 0,
1530 name
, oflag
, mode
, value
);
1534 #if defined(VGO_freebsd)
1535 LIBC_FUNC(sem_t
*, semZuopen
, sem_open_intercept
,
1536 (const char *name
, int oflag
, mode_t mode
, unsigned int value
),
1537 (name
, oflag
, mode
, value
));
1539 PTH_FUNCS(sem_t
*, semZuopen
, sem_open_intercept
,
1540 (const char *name
, int oflag
, mode_t mode
, unsigned int value
),
1541 (name
, oflag
, mode
, value
));
1544 static __always_inline
int sem_close_intercept(sem_t
*sem
)
1548 VALGRIND_GET_ORIG_FN(fn
);
1549 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_CLOSE
,
1551 CALL_FN_W_W(ret
, fn
, sem
);
1552 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_CLOSE
,
1557 #if defined(VGO_freebsd)
1558 LIBC_FUNC(int, semZuclose
, sem_close_intercept
, (sem_t
*sem
), (sem
));
1560 PTH_FUNCS(int, semZuclose
, sem_close_intercept
, (sem_t
*sem
), (sem
));
1563 static __always_inline
int sem_wait_intercept(sem_t
*sem
)
1567 VALGRIND_GET_ORIG_FN(fn
);
1568 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT
,
1570 CALL_FN_W_W(ret
, fn
, sem
);
1571 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT
,
1572 sem
, ret
== 0, 0, 0, 0);
1576 #if defined(VGO_freebsd)
1577 LIBC_FUNC(int, semZuwait
, sem_wait_intercept
, (sem_t
*sem
), (sem
));
1579 PTH_FUNCS(int, semZuwait
, sem_wait_intercept
, (sem_t
*sem
), (sem
));
1582 #if defined(VGO_solaris)
1583 PTH_FUNCS(int, semaZuwait
, sem_wait_intercept
, (sem_t
*sem
), (sem
));
1584 #endif /* VGO_solaris */
1586 static __always_inline
int sem_trywait_intercept(sem_t
*sem
)
1590 VALGRIND_GET_ORIG_FN(fn
);
1591 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT
,
1593 CALL_FN_W_W(ret
, fn
, sem
);
1594 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT
,
1595 sem
, ret
== 0, 0, 0, 0);
1599 #if defined(VGO_freebsd)
1600 LIBC_FUNC(int, semZutrywait
, sem_trywait_intercept
, (sem_t
*sem
), (sem
));
1602 PTH_FUNCS(int, semZutrywait
, sem_trywait_intercept
, (sem_t
*sem
), (sem
));
1604 #if defined(VGO_solaris)
1605 PTH_FUNCS(int, semaZutrywait
, sem_trywait_intercept
, (sem_t
*sem
), (sem
));
1606 #endif /* VGO_solaris */
1608 static __always_inline
1609 int sem_timedwait_intercept(sem_t
*sem
, const struct timespec
*abs_timeout
)
1613 VALGRIND_GET_ORIG_FN(fn
);
1614 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT
,
1616 CALL_FN_W_WW(ret
, fn
, sem
, abs_timeout
);
1617 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT
,
1618 sem
, ret
== 0, 0, 0, 0);
1622 #if defined(VGO_freebsd)
1623 LIBC_FUNC(int, semZutimedwait
, sem_timedwait_intercept
,
1624 (sem_t
*sem
, const struct timespec
*abs_timeout
),
1625 (sem
, abs_timeout
));
1627 PTH_FUNCS(int, semZutimedwait
, sem_timedwait_intercept
,
1628 (sem_t
*sem
, const struct timespec
*abs_timeout
),
1629 (sem
, abs_timeout
));
1631 #if defined(VGO_solaris)
1632 PTH_FUNCS(int, semaZutimedwait
, sem_timedwait_intercept
,
1633 (sem_t
*sem
, const struct timespec
*timeout
),
1635 PTH_FUNCS(int, semaZureltimedwait
, sem_timedwait_intercept
,
1636 (sem_t
*sem
, const struct timespec
*timeout
),
1638 #endif /* VGO_solaris */
1640 #if defined(VGO_freebsd)
1641 static __always_inline
1642 int sem_clockwait_np_intercept(sem_t
* sem
, clockid_t clock_id
, int flags
,
1643 const struct timespec
* rqtp
, struct timespec
* rmtp
)
1647 VALGRIND_GET_ORIG_FN(fn
);
1648 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT
,
1650 CALL_FN_W_5W(ret
, fn
, sem
, clock_id
, flags
, rqtp
, rmtp
);
1651 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT
,
1652 sem
, ret
== 0, 0, 0, 0);
1656 LIBC_FUNC(int, semZuclockwaitZunp
, sem_clockwait_np_intercept
,
1657 (sem_t
* sem
, clockid_t clock_id
, int flags
,
1658 const struct timespec
* rqtp
, struct timespec
* rmtp
),
1659 (sem
, clock_id
, flags
, rqtp
, rmtp
));
1662 static __always_inline
int sem_post_intercept(sem_t
*sem
)
1666 VALGRIND_GET_ORIG_FN(fn
);
1667 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_POST
,
1669 CALL_FN_W_W(ret
, fn
, sem
);
1670 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_POST
,
1671 sem
, ret
== 0, 0, 0, 0);
1675 #if defined(VGO_freebsd)
1676 LIBC_FUNC(int, semZupost
, sem_post_intercept
, (sem_t
*sem
), (sem
));
1678 PTH_FUNCS(int, semZupost
, sem_post_intercept
, (sem_t
*sem
), (sem
));
1680 #if defined(VGO_solaris)
1681 PTH_FUNCS(int, semaZupost
, sem_post_intercept
, (sem_t
*sem
), (sem
));
1682 #endif /* VGO_solaris */
1684 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1685 functions have to be conditionally compiled. */
1686 #if defined(HAVE_PTHREAD_RWLOCK_T)
1688 static __always_inline
1689 int pthread_rwlock_init_intercept(pthread_rwlock_t
* rwlock
,
1690 const pthread_rwlockattr_t
* attr
)
1694 VALGRIND_GET_ORIG_FN(fn
);
1695 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_INIT
,
1696 rwlock
, 0, 0, 0, 0);
1697 CALL_FN_W_WW(ret
, fn
, rwlock
, attr
);
1698 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_INIT
,
1699 rwlock
, 0, 0, 0, 0);
1704 pthreadZurwlockZuinit
, pthread_rwlock_init_intercept
,
1705 (pthread_rwlock_t
* rwlock
, const pthread_rwlockattr_t
* attr
),
1708 #if defined(VGO_solaris)
1709 static __always_inline
1710 int rwlock_init_intercept(rwlock_t
*rwlock
, int type
, void *arg
)
1714 VALGRIND_GET_ORIG_FN(fn
);
1715 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_INIT
,
1716 rwlock
, 0, 0, 0, 0);
1717 CALL_FN_W_WWW(ret
, fn
, rwlock
, type
, arg
);
1718 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_INIT
,
1719 rwlock
, 0, 0, 0, 0);
1723 PTH_FUNCS(int, rwlockZuinit
, rwlock_init_intercept
,
1724 (rwlock_t
*rwlock
, int type
, void *arg
),
1725 (rwlock
, type
, arg
));
1726 #endif /* VGO_solaris */
1728 static __always_inline
1729 int pthread_rwlock_destroy_intercept(pthread_rwlock_t
* rwlock
)
1733 VALGRIND_GET_ORIG_FN(fn
);
1734 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_DESTROY
,
1735 rwlock
, 0, 0, 0, 0);
1736 CALL_FN_W_W(ret
, fn
, rwlock
);
1737 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_DESTROY
,
1738 rwlock
, 0, 0, 0, 0);
1742 #if defined(VGO_solaris)
1743 /* On Solaris, pthread_rwlock_destroy is a weak alias to rwlock_destroy. */
1745 rwlockZudestroy
, pthread_rwlock_destroy_intercept
,
1746 (pthread_rwlock_t
*rwlock
), (rwlock
));
1749 pthreadZurwlockZudestroy
, pthread_rwlock_destroy_intercept
,
1750 (pthread_rwlock_t
* rwlock
), (rwlock
));
1751 #endif /* VGO_solaris */
1753 static __always_inline
1754 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t
* rwlock
)
1758 VALGRIND_GET_ORIG_FN(fn
);
1759 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK
,
1760 rwlock
, 0, 0, 0, 0);
1761 CALL_FN_W_W(ret
, fn
, rwlock
);
1762 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK
,
1763 rwlock
, ret
== 0, 0, 0, 0);
1767 #if defined(VGO_solaris)
1768 /* On Solaris, pthread_rwlock_rdlock is a weak alias to rw_rdlock. */
1770 rwZurdlock
, pthread_rwlock_rdlock_intercept
,
1771 (pthread_rwlock_t
*rwlock
), (rwlock
));
1774 pthreadZurwlockZurdlock
, pthread_rwlock_rdlock_intercept
,
1775 (pthread_rwlock_t
* rwlock
), (rwlock
));
1776 #endif /* VGO_solaris */
1778 #if defined(VGO_solaris)
1779 /* Internal to libc. */
1780 static __always_inline
1781 void lrw_rdlock_intercept(rwlock_t
*rwlock
)
1784 VALGRIND_GET_ORIG_FN(fn
);
1785 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK
,
1786 rwlock
, 0, 0, 0, 0);
1787 CALL_FN_v_W(fn
, rwlock
);
1788 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK
,
1789 rwlock
, True
/* took_lock */, 0, 0, 0);
1792 PTH_FUNCS(void, lrwZurdlock
, lrw_rdlock_intercept
,
1793 (rwlock_t
*rwlock
), (rwlock
));
1794 #endif /* VGO_solaris */
1796 static __always_inline
1797 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t
* rwlock
)
1801 VALGRIND_GET_ORIG_FN(fn
);
1802 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK
,
1803 rwlock
, 0, 0, 0, 0);
1804 CALL_FN_W_W(ret
, fn
, rwlock
);
1805 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK
,
1806 rwlock
, ret
== 0, 0, 0, 0);
1810 #if defined(VGO_solaris)
1811 /* On Solaris, pthread_rwlock_wrlock is a weak alias to rw_wrlock. */
1813 rwZuwrlock
, pthread_rwlock_wrlock_intercept
,
1814 (pthread_rwlock_t
*rwlock
), (rwlock
));
1817 pthreadZurwlockZuwrlock
, pthread_rwlock_wrlock_intercept
,
1818 (pthread_rwlock_t
* rwlock
), (rwlock
));
1819 #endif /* VGO_solaris */
1821 #if defined(VGO_solaris)
1822 /* Internal to libc. */
1823 static __always_inline
1824 void lrw_wrlock_intercept(rwlock_t
*rwlock
)
1827 VALGRIND_GET_ORIG_FN(fn
);
1828 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK
,
1829 rwlock
, 0, 0, 0, 0);
1830 CALL_FN_v_W(fn
, rwlock
);
1831 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK
,
1832 rwlock
, True
/* took_lock */, 0, 0, 0);
1835 PTH_FUNCS(void, lrwZuwrlock
, lrw_wrlock_intercept
,
1836 (rwlock_t
*rwlock
), (rwlock
));
1837 #endif /* VGO_solaris */
1839 static __always_inline
1840 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t
* rwlock
,
1841 const struct timespec
*timeout
)
1845 VALGRIND_GET_ORIG_FN(fn
);
1846 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK
,
1847 rwlock
, 0, 0, 0, 0);
1848 CALL_FN_W_WW(ret
, fn
, rwlock
, timeout
);
1849 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK
,
1850 rwlock
, ret
== 0, 0, 0, 0);
1855 pthreadZurwlockZutimedrdlock
, pthread_rwlock_timedrdlock_intercept
,
1856 (pthread_rwlock_t
* rwlock
, const struct timespec
*timeout
),
1858 #if defined(VGO_solaris)
1859 PTH_FUNCS(int, pthreadZurwlockZureltimedrdlockZunp
,
1860 pthread_rwlock_timedrdlock_intercept
,
1861 (pthread_rwlock_t
*rwlock
, const struct timespec
*timeout
),
1863 #endif /* VGO_solaris */
1866 #if defined(HAVE_CLOCKID_T)
1867 static __always_inline
1868 int pthread_rwlock_clockrdlock_intercept(pthread_rwlock_t
* rwlock
,
1870 const struct timespec
*timeout
)
1874 VALGRIND_GET_ORIG_FN(fn
);
1875 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK
,
1876 rwlock
, 0, 0, 0, 0);
1877 CALL_FN_W_WWW(ret
, fn
, rwlock
, clockid
, timeout
);
1878 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK
,
1879 rwlock
, ret
== 0, 0, 0, 0);
1884 pthreadZurwlockZuclockrdlock
, pthread_rwlock_clockrdlock_intercept
,
1885 (pthread_rwlock_t
* rwlock
, clockid_t clockid
, const struct timespec
*timeout
),
1886 (rwlock
, clockid
, timeout
));
1889 static __always_inline
1890 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t
* rwlock
,
1891 const struct timespec
*timeout
)
1895 VALGRIND_GET_ORIG_FN(fn
);
1896 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK
,
1897 rwlock
, 0, 0, 0, 0);
1898 CALL_FN_W_WW(ret
, fn
, rwlock
, timeout
);
1899 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK
,
1900 rwlock
, ret
== 0, 0, 0, 0);
1905 pthreadZurwlockZutimedwrlock
, pthread_rwlock_timedwrlock_intercept
,
1906 (pthread_rwlock_t
* rwlock
, const struct timespec
*timeout
),
1908 #if defined(VGO_solaris)
1909 PTH_FUNCS(int, pthreadZurwlockZureltimedwrlockZunp
,
1910 pthread_rwlock_timedwrlock_intercept
,
1911 (pthread_rwlock_t
*rwlock
, const struct timespec
*timeout
),
1913 #endif /* VGO_solaris */
1916 #if defined(HAVE_CLOCKID_T)
1917 static __always_inline
1918 int pthread_rwlock_clockwrlock_intercept(pthread_rwlock_t
* rwlock
,
1920 const struct timespec
*timeout
)
1924 VALGRIND_GET_ORIG_FN(fn
);
1925 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK
,
1926 rwlock
, 0, 0, 0, 0);
1927 CALL_FN_W_WWW(ret
, fn
, rwlock
, clockid
, timeout
);
1928 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK
,
1929 rwlock
, ret
== 0, 0, 0, 0);
1934 pthreadZurwlockZuclockwrlock
, pthread_rwlock_clockwrlock_intercept
,
1935 (pthread_rwlock_t
* rwlock
, clockid_t clockid
, const struct timespec
*timeout
),
1936 (rwlock
, clockid
, timeout
));
1940 static __always_inline
1941 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t
* rwlock
)
1945 VALGRIND_GET_ORIG_FN(fn
);
1946 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK
,
1947 rwlock
, 0, 0, 0, 0);
1948 CALL_FN_W_W(ret
, fn
, rwlock
);
1949 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK
,
1950 rwlock
, ret
== 0, 0, 0, 0);
1954 #if defined(VGO_solaris)
1955 /* On Solaris, pthread_rwlock_tryrdlock is a weak alias to rw_tryrdlock. */
1957 rwZutryrdlock
, pthread_rwlock_tryrdlock_intercept
,
1958 (pthread_rwlock_t
*rwlock
), (rwlock
));
1961 pthreadZurwlockZutryrdlock
, pthread_rwlock_tryrdlock_intercept
,
1962 (pthread_rwlock_t
* rwlock
), (rwlock
));
1963 #endif /* VGO_solaris */
1965 static __always_inline
1966 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t
* rwlock
)
1970 VALGRIND_GET_ORIG_FN(fn
);
1971 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK
,
1972 rwlock
, 0, 0, 0, 0);
1973 CALL_FN_W_W(ret
, fn
, rwlock
);
1974 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK
,
1975 rwlock
, ret
== 0, 0, 0, 0);
1979 #if defined(VGO_solaris)
1980 /* On Solaris, pthread_rwlock_trywrlock is a weak alias to rw_trywrlock. */
1982 rwZutrywrlock
, pthread_rwlock_trywrlock_intercept
,
1983 (pthread_rwlock_t
*rwlock
), (rwlock
));
1986 pthreadZurwlockZutrywrlock
, pthread_rwlock_trywrlock_intercept
,
1987 (pthread_rwlock_t
* rwlock
), (rwlock
));
1988 #endif /* VGO_solaris */
1990 static __always_inline
1991 int pthread_rwlock_unlock_intercept(pthread_rwlock_t
* rwlock
)
1995 VALGRIND_GET_ORIG_FN(fn
);
1996 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_UNLOCK
,
1997 rwlock
, 0, 0, 0, 0);
1998 CALL_FN_W_W(ret
, fn
, rwlock
);
1999 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_UNLOCK
,
2000 rwlock
, ret
== 0, 0, 0, 0);
2004 #if defined(VGO_solaris)
2005 /* On Solaris, pthread_rwlock_unlock is a weak alias to rw_unlock. */
2007 rwZuunlock
, pthread_rwlock_unlock_intercept
,
2008 (pthread_rwlock_t
*rwlock
), (rwlock
));
2011 pthreadZurwlockZuunlock
, pthread_rwlock_unlock_intercept
,
2012 (pthread_rwlock_t
* rwlock
), (rwlock
));
2013 #endif /* VGO_solaris */
2015 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */