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
;
365 else if (kind
== PTHREAD_MUTEX_ERRORCHECK
)
366 return mutex_type_errorcheck_mutex
;
367 else if (kind
== PTHREAD_MUTEX_NORMAL
)
368 return mutex_type_default_mutex
;
369 else if (kind
== PTHREAD_MUTEX_DEFAULT
)
370 // @todo PJF what about Solaris?
371 #if defined(VGO_freebsd)
372 return mutex_type_errorcheck_mutex
;
374 return mutex_type_default_mutex
;
376 #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
377 else if (kind
== PTHREAD_MUTEX_ADAPTIVE_NP
)
378 return mutex_type_default_mutex
;
381 return mutex_type_invalid_mutex
;
384 #if defined(VGO_solaris)
386 * Solaris threads and DRD each have their own mutex type identification.
387 * Convert Solaris threads' mutex type to DRD's mutex type.
389 static MutexT
DRD_(thread_to_drd_mutex_type
)(int type
)
391 if (type
& LOCK_RECURSIVE
) {
392 return mutex_type_recursive_mutex
;
393 } else if (type
& LOCK_ERRORCHECK
) {
394 return mutex_type_errorcheck_mutex
;
396 return mutex_type_default_mutex
;
399 #endif /* VGO_solaris */
401 #define IS_ALIGNED(p) (((uintptr_t)(p) & (sizeof(*(p)) - 1)) == 0)
404 * Read the mutex type stored in the client memory used for the mutex
407 * @note This function depends on the implementation of the POSIX threads
408 * library -- the POSIX standard does not define the name of the member in
409 * which the mutex type is stored.
410 * @note The function mutex_type() has been declared inline in order
411 * to avoid that it shows up in call stacks (drd/tests/...exp* files).
412 * @note glibc stores the mutex type in the lowest two bits, and uses the
413 * higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
414 * PTHREAD_MUTEXATTR_FLAG_PSHARED.
416 static __always_inline MutexT
DRD_(mutex_type
)(pthread_mutex_t
* mutex
)
418 MutexT mutex_type
= mutex_type_unknown
;
420 ANNOTATE_IGNORE_READS_BEGIN();
421 #if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
422 /* glibc + LinuxThreads. */
423 if (IS_ALIGNED(&mutex
->__m_kind
))
425 const int kind
= mutex
->__m_kind
& 3;
426 mutex_type
= DRD_(pthread_to_drd_mutex_type
)(kind
);
428 #elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
430 if (IS_ALIGNED(&mutex
->__data
.__kind
))
432 const int kind
= mutex
->__data
.__kind
& 3;
433 mutex_type
= DRD_(pthread_to_drd_mutex_type
)(kind
);
435 #elif defined(VGO_solaris)
437 const int type
= ((mutex_t
*) mutex
)->vki_mutex_type
;
438 mutex_type
= DRD_(thread_to_drd_mutex_type
)(type
);
442 * Another POSIX threads implementation. The mutex type won't be printed
443 * when enabling --trace-mutex=yes.
446 ANNOTATE_IGNORE_READS_END();
452 * Tell DRD whether 'tid' is a joinable thread or a detached thread.
454 static void DRD_(set_joinable
)(const pthread_t tid
, const int joinable
)
456 assert(joinable
== 0 || joinable
== 1);
457 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_JOINABLE
,
458 tid
, joinable
, 0, 0, 0);
461 /** Tell DRD that the calling thread is about to enter pthread_create(). */
462 static __always_inline
void DRD_(entering_pthread_create
)(void)
464 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__ENTERING_PTHREAD_CREATE
,
468 /** Tell DRD that the calling thread has left pthread_create(). */
469 static __always_inline
void DRD_(left_pthread_create
)(void)
471 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LEFT_PTHREAD_CREATE
,
476 * Entry point for newly created threads. This function is called from the
477 * thread created by pthread_create().
479 static void* DRD_(thread_wrapper
)(void* arg
)
481 DrdPosixThreadArgs
* arg_ptr
;
482 DrdPosixThreadArgs arg_copy
;
484 arg_ptr
= (DrdPosixThreadArgs
*)arg
;
487 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID
,
488 pthread_self(), 0, 0, 0, 0);
490 DRD_(set_joinable
)(pthread_self(),
491 arg_copy
.detachstate
== PTHREAD_CREATE_JOINABLE
);
494 * Only set 'wrapper_started' after VG_USERREQ__SET_PTHREADID and
495 * DRD_(set_joinable)() have been invoked to avoid a race with
496 * a pthread_detach() invocation for this thread from another thread.
498 DRD_(sema_up
)(arg_copy
.wrapper_started
);
500 return (arg_copy
.start
)(arg_copy
.arg
);
504 * Return 1 if the LinuxThreads implementation of POSIX Threads has been
505 * detected, and 0 otherwise.
507 * @see For more information about the confstr() function, see also
508 * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
510 static int DRD_(detected_linuxthreads
)(void)
513 #if defined(_CS_GNU_LIBPTHREAD_VERSION)
514 /* Linux with a recent glibc. */
517 len
= confstr(_CS_GNU_LIBPTHREAD_VERSION
, buffer
, sizeof(buffer
));
518 assert(len
<= sizeof(buffer
));
519 return len
> 0 && buffer
[0] == 'l';
521 /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
525 /* Another OS than Linux, hence no LinuxThreads. */
531 * Stop and print an error message in case a non-supported threading
532 * library implementation (LinuxThreads) has been detected.
534 static void DRD_(check_threading_library
)(void)
536 if (DRD_(detected_linuxthreads
)())
538 if (getenv("LD_ASSUME_KERNEL"))
541 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
542 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
543 "after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
549 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
550 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
551 "after having upgraded to a newer version of your Linux distribution.\n"
560 * Update DRD's state information about the current thread.
562 static void DRD_(set_pthread_id
)(void)
564 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID
,
565 pthread_self(), 0, 0, 0, 0);
569 * Note: as of today there exist three different versions of pthread_create
571 * - pthread_create@GLIBC_2.0
572 * - pthread_create@@GLIBC_2.1
573 * - pthread_create@@GLIBC_2.2.5
574 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
575 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
576 * versions have been implemented. In any glibc version where more than one
577 * pthread_create function has been implemented, older versions call the
578 * newer versions. Or: the pthread_create* wrapper defined below can be
579 * called recursively. Any code in this wrapper should take this in account.
580 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
581 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
582 * See also the implementation of pthread_create@GLIBC_2.0 in
583 * glibc-2.9/nptl/pthread_create.c.
586 static __always_inline
587 int pthread_create_intercept(pthread_t
* thread
, const pthread_attr_t
* attr
,
588 void* (*start
)(void*), void* arg
)
592 DrdSema wrapper_started
;
593 DrdPosixThreadArgs thread_args
;
595 VALGRIND_GET_ORIG_FN(fn
);
597 DRD_(sema_init
)(&wrapper_started
);
598 thread_args
.start
= start
;
599 thread_args
.arg
= arg
;
600 thread_args
.wrapper_started
= &wrapper_started
;
602 * Find out whether the thread will be started as a joinable thread
603 * or as a detached thread. If no thread attributes have been specified,
604 * this means that the new thread will be started as a joinable thread.
606 thread_args
.detachstate
= PTHREAD_CREATE_JOINABLE
;
609 if (pthread_attr_getdetachstate(attr
, &thread_args
.detachstate
) != 0)
612 assert(thread_args
.detachstate
== PTHREAD_CREATE_JOINABLE
613 || thread_args
.detachstate
== PTHREAD_CREATE_DETACHED
);
616 * The DRD_(set_pthread_id)() from DRD_(init)() may encounter that
617 * pthread_self() == 0, e.g. when the main program is not linked with the
618 * pthread library and when a pthread_create() call occurs from within a
619 * shared library. Hence call DRD_(set_pthread_id)() again to ensure that
620 * DRD knows the identity of the current thread. See also B.Z. 356374.
622 DRD_(set_pthread_id
)();
623 DRD_(entering_pthread_create
)();
624 CALL_FN_W_WWWW(ret
, fn
, thread
, attr
, DRD_(thread_wrapper
), &thread_args
);
625 DRD_(left_pthread_create
)();
628 /* Wait until the thread wrapper started. */
629 DRD_(sema_down
)(&wrapper_started
);
632 DRD_(sema_destroy
)(&wrapper_started
);
634 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT
,
635 pthread_self(), 0, 0, 0, 0);
640 PTH_FUNCS(int, pthreadZucreate
, pthread_create_intercept
,
641 (pthread_t
*thread
, const pthread_attr_t
*attr
,
642 void *(*start
) (void *), void *arg
),
643 (thread
, attr
, start
, arg
));
645 #if defined(VGO_solaris)
646 /* Solaris also provides thr_create() in addition to pthread_create().
647 * Both pthread_create(3C) and thr_create(3C) are based on private
650 static __always_inline
651 int thr_create_intercept(void *stk
, size_t stksize
, void *(*start
)(void *),
652 void *arg
, long flags
, thread_t
*new_thread
)
656 DrdSema wrapper_started
;
657 DrdPosixThreadArgs thread_args
;
659 VALGRIND_GET_ORIG_FN(fn
);
661 DRD_(sema_init
)(&wrapper_started
);
662 thread_args
.start
= start
;
663 thread_args
.arg
= arg
;
664 thread_args
.wrapper_started
= &wrapper_started
;
666 * Find out whether the thread will be started as a joinable thread
667 * or as a detached thread.
669 if (flags
& THR_DETACHED
)
670 thread_args
.detachstate
= PTHREAD_CREATE_DETACHED
;
672 thread_args
.detachstate
= PTHREAD_CREATE_JOINABLE
;
674 DRD_(entering_pthread_create
)();
675 CALL_FN_W_6W(ret
, fn
, stk
, stksize
, DRD_(thread_wrapper
), &thread_args
,
677 DRD_(left_pthread_create
)();
680 /* Wait until the thread wrapper started. */
681 DRD_(sema_down
)(&wrapper_started
);
684 DRD_(sema_destroy
)(&wrapper_started
);
686 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT
,
687 pthread_self(), 0, 0, 0, 0);
692 PTH_FUNCS(int, thrZucreate
, thr_create_intercept
,
693 (void *stk
, size_t stksize
, void *(*start
)(void *), void *arg
,
694 long flags
, thread_t
*new_thread
),
695 (stk
, stksize
, start
, arg
, flags
, new_thread
));
696 #endif /* VGO_solaris */
698 #if defined(VGO_solaris)
700 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
701 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
702 * and CI_BIND_CLEAR, to provide resilience against function renaming.
704 static __always_inline
705 int DRD_(_ti_bind_guard_intercept
)(int flags
) {
706 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_GUARD
,
708 return DRD_(rtld_bind_guard
)(flags
);
711 static __always_inline
712 int DRD_(_ti_bind_clear_intercept
)(int flags
) {
713 int ret
= DRD_(rtld_bind_clear
)(flags
);
714 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_CLEAR
,
720 * Wrapped _ld_libc() from the runtime linker ld.so.1.
722 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1
, ZuldZulibc
)(vki_Lc_interface
*ptr
);
723 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1
, ZuldZulibc
)(vki_Lc_interface
*ptr
)
728 VALGRIND_GET_ORIG_FN(fn
);
730 vki_Lc_interface
*funcs
= ptr
;
731 for (tag
= funcs
->ci_tag
; tag
!= 0; tag
= (++funcs
)->ci_tag
) {
733 case VKI_CI_BIND_GUARD
:
734 if (funcs
->vki_ci_un
.ci_func
!= DRD_(_ti_bind_guard_intercept
)) {
735 DRD_(rtld_bind_guard
) = funcs
->vki_ci_un
.ci_func
;
736 funcs
->vki_ci_un
.ci_func
= DRD_(_ti_bind_guard_intercept
);
739 case VKI_CI_BIND_CLEAR
:
740 if (funcs
->vki_ci_un
.ci_func
!= DRD_(_ti_bind_clear_intercept
)) {
741 DRD_(rtld_bind_clear
) = funcs
->vki_ci_un
.ci_func
;
742 funcs
->vki_ci_un
.ci_func
= DRD_(_ti_bind_clear_intercept
);
748 CALL_FN_v_W(fn
, ptr
);
750 #endif /* VGO_solaris */
752 static __always_inline
753 int pthread_join_intercept(pthread_t pt_joinee
, void **thread_return
)
758 VALGRIND_GET_ORIG_FN(fn
);
760 * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
761 * implementation triggers a (false positive) race report.
763 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
764 CALL_FN_W_WW(ret
, fn
, pt_joinee
, thread_return
);
767 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN
,
768 pt_joinee
, 0, 0, 0, 0);
770 ANNOTATE_IGNORE_READS_AND_WRITES_END();
774 PTH_FUNCS(int, pthreadZujoin
, pthread_join_intercept
,
775 (pthread_t pt_joinee
, void **thread_return
),
776 (pt_joinee
, thread_return
));
778 #if defined(VGO_solaris)
779 /* Solaris also provides thr_join() in addition to pthread_join().
780 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
782 * :TODO: No functionality is currently provided for joinee == 0 and departed.
783 * This would require another client request, of course.
785 static __always_inline
786 int thr_join_intercept(thread_t joinee
, thread_t
*departed
, void **thread_return
)
791 VALGRIND_GET_ORIG_FN(fn
);
792 CALL_FN_W_WWW(ret
, fn
, joinee
, departed
, thread_return
);
795 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN
,
801 PTH_FUNCS(int, thrZujoin
, thr_join_intercept
,
802 (thread_t joinee
, thread_t
*departed
, void **thread_return
),
803 (joinee
, departed
, thread_return
));
804 #endif /* VGO_solaris */
806 static __always_inline
807 int pthread_detach_intercept(pthread_t pt_thread
)
812 VALGRIND_GET_ORIG_FN(fn
);
813 CALL_FN_W_W(ret
, fn
, pt_thread
);
814 DRD_(set_joinable
)(pt_thread
, 0);
819 PTH_FUNCS(int, pthreadZudetach
, pthread_detach_intercept
,
820 (pthread_t thread
), (thread
));
822 // NOTE: be careful to intercept only pthread_cancel() and not
823 // pthread_cancel_init() on Linux.
825 static __always_inline
826 int pthread_cancel_intercept(pthread_t pt_thread
)
830 VALGRIND_GET_ORIG_FN(fn
);
831 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_THREAD_CANCEL
,
832 pt_thread
, 0, 0, 0, 0);
833 CALL_FN_W_W(ret
, fn
, pt_thread
);
834 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_CANCEL
,
835 pt_thread
, ret
==0, 0, 0, 0);
839 PTH_FUNCS(int, pthreadZucancel
, pthread_cancel_intercept
,
840 (pthread_t thread
), (thread
))
842 static __always_inline
843 int pthread_once_intercept(pthread_once_t
*once_control
,
844 void (*init_routine
)(void))
848 VALGRIND_GET_ORIG_FN(fn
);
850 * Ignore any data races triggered by the implementation of pthread_once().
851 * Necessary for Darwin. This is not necessary for Linux but doesn't have
852 * any known adverse effects.
854 DRD_IGNORE_VAR(*once_control
);
855 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
856 CALL_FN_W_WW(ret
, fn
, once_control
, init_routine
);
857 ANNOTATE_IGNORE_READS_AND_WRITES_END();
858 DRD_STOP_IGNORING_VAR(*once_control
);
862 PTH_FUNCS(int, pthreadZuonce
, pthread_once_intercept
,
863 (pthread_once_t
*once_control
, void (*init_routine
)(void)),
864 (once_control
, init_routine
));
866 static __always_inline
867 int pthread_mutex_init_intercept(pthread_mutex_t
*mutex
,
868 const pthread_mutexattr_t
* attr
)
873 VALGRIND_GET_ORIG_FN(fn
);
874 mt
= PTHREAD_MUTEX_DEFAULT
;
876 pthread_mutexattr_gettype(attr
, &mt
);
877 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT
,
878 mutex
, DRD_(pthread_to_drd_mutex_type
)(mt
),
880 CALL_FN_W_WW(ret
, fn
, mutex
, attr
);
881 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT
,
886 PTH_FUNCS(int, pthreadZumutexZuinit
, pthread_mutex_init_intercept
,
887 (pthread_mutex_t
*mutex
, const pthread_mutexattr_t
* attr
),
890 #if defined(VGO_solaris)
891 static __always_inline
892 int mutex_init_intercept(mutex_t
*mutex
, int type
, void *arg
)
896 VALGRIND_GET_ORIG_FN(fn
);
898 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT
,
899 mutex
, DRD_(thread_to_drd_mutex_type
)(type
),
901 CALL_FN_W_WWW(ret
, fn
, mutex
, type
, arg
);
902 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT
,
907 PTH_FUNCS(int, mutexZuinit
, mutex_init_intercept
,
908 (mutex_t
*mutex
, int type
, void *arg
),
910 #endif /* VGO_solaris */
912 static __always_inline
913 int pthread_mutex_destroy_intercept(pthread_mutex_t
* mutex
)
917 VALGRIND_GET_ORIG_FN(fn
);
918 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY
,
920 CALL_FN_W_W(ret
, fn
, mutex
);
921 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY
,
922 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
926 #if defined(VGO_solaris)
927 /* On Solaris, pthread_mutex_destroy is a weak alias to mutex_destroy. */
928 PTH_FUNCS(int, mutexZudestroy
, pthread_mutex_destroy_intercept
,
929 (pthread_mutex_t
*mutex
), (mutex
));
931 PTH_FUNCS(int, pthreadZumutexZudestroy
, pthread_mutex_destroy_intercept
,
932 (pthread_mutex_t
*mutex
), (mutex
));
933 #endif /* VGO_solaris */
935 static __always_inline
936 int pthread_mutex_lock_intercept(pthread_mutex_t
* mutex
)
940 VALGRIND_GET_ORIG_FN(fn
);
941 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
942 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
943 CALL_FN_W_W(ret
, fn
, mutex
);
944 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
945 mutex
, ret
== 0, 0, 0, 0);
949 #if defined(VGO_solaris)
950 /* On Solaris, pthread_mutex_lock is a weak alias to mutex_lock. */
951 PTH_FUNCS(int, mutexZulock
, pthread_mutex_lock_intercept
,
952 (pthread_mutex_t
*mutex
), (mutex
));
954 PTH_FUNCS(int, pthreadZumutexZulock
, pthread_mutex_lock_intercept
,
955 (pthread_mutex_t
*mutex
), (mutex
));
956 #endif /* VGO_solaris */
958 #if defined(VGO_solaris)
959 /* Internal to libc. Mutex is usually initialized only implicitly,
960 * by zeroing mutex_t structure.
962 static __always_inline
963 void lmutex_lock_intercept(mutex_t
*mutex
)
966 VALGRIND_GET_ORIG_FN(fn
);
967 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
969 DRD_(mutex_type
)((pthread_mutex_t
*) mutex
),
970 False
/* try_lock */, 0, 0);
971 CALL_FN_v_W(fn
, mutex
);
972 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
973 mutex
, True
/* took_lock */, 0, 0, 0);
976 PTH_FUNCS(void, lmutexZulock
, lmutex_lock_intercept
,
977 (mutex_t
*mutex
), (mutex
));
978 #endif /* VGO_solaris */
980 static __always_inline
981 int pthread_mutex_trylock_intercept(pthread_mutex_t
* mutex
)
985 VALGRIND_GET_ORIG_FN(fn
);
986 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
987 mutex
, DRD_(mutex_type
)(mutex
), 1, 0, 0);
988 CALL_FN_W_W(ret
, fn
, mutex
);
989 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
990 mutex
, ret
== 0, 0, 0, 0);
994 #if defined(VGO_solaris)
995 /* On Solaris, pthread_mutex_trylock is a weak alias to mutex_trylock. */
996 PTH_FUNCS(int, mutexZutrylock
, pthread_mutex_trylock_intercept
,
997 (pthread_mutex_t
*mutex
), (mutex
));
999 PTH_FUNCS(int, pthreadZumutexZutrylock
, pthread_mutex_trylock_intercept
,
1000 (pthread_mutex_t
*mutex
), (mutex
));
1001 #endif /* VGO_solaris */
1003 static __always_inline
1004 int pthread_mutex_timedlock_intercept(pthread_mutex_t
*mutex
,
1005 const struct timespec
*abs_timeout
)
1009 VALGRIND_GET_ORIG_FN(fn
);
1010 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
1011 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
1012 CALL_FN_W_WW(ret
, fn
, mutex
, abs_timeout
);
1013 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
1014 mutex
, ret
== 0, 0, 0, 0);
1018 PTH_FUNCS(int, pthreadZumutexZutimedlock
, pthread_mutex_timedlock_intercept
,
1019 (pthread_mutex_t
*mutex
, const struct timespec
*abs_timeout
),
1020 (mutex
, abs_timeout
));
1021 #if defined(VGO_solaris)
1023 pthreadZumutexZureltimedlockZunp
, pthread_mutex_timedlock_intercept
,
1024 (pthread_mutex_t
*mutex
, const struct timespec
*timeout
),
1026 #endif /* VGO_solaris */
1028 #if defined(HAVE_CLOCKID_T)
1029 static __always_inline
1030 int pthread_mutex_clocklock_intercept(pthread_mutex_t
*mutex
,
1032 const struct timespec
*abs_timeout
)
1036 VALGRIND_GET_ORIG_FN(fn
);
1037 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
1038 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
1039 CALL_FN_W_WWW(ret
, fn
, mutex
, clockid
, abs_timeout
);
1040 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
1041 mutex
, ret
== 0, 0, 0, 0);
1045 PTH_FUNCS(int, pthreadZumutexZuclocklock
, pthread_mutex_clocklock_intercept
,
1046 (pthread_mutex_t
*mutex
, clockid_t clockid
, const struct timespec
*abs_timeout
),
1047 (mutex
, clockid
, abs_timeout
));
1050 static __always_inline
1051 int pthread_mutex_unlock_intercept(pthread_mutex_t
*mutex
)
1055 VALGRIND_GET_ORIG_FN(fn
);
1056 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK
,
1057 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
1058 CALL_FN_W_W(ret
, fn
, mutex
);
1059 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK
,
1064 #if defined(VGO_solaris)
1065 /* On Solaris, pthread_mutex_unlock is a weak alias to mutex_unlock. */
1066 PTH_FUNCS(int, mutexZuunlock
, pthread_mutex_unlock_intercept
,
1067 (pthread_mutex_t
*mutex
), (mutex
));
1069 PTH_FUNCS(int, pthreadZumutexZuunlock
, pthread_mutex_unlock_intercept
,
1070 (pthread_mutex_t
*mutex
), (mutex
));
1071 #endif /* VGO_solaris */
1073 #if defined(VGO_solaris)
1074 /* Internal to libc. */
1075 static __always_inline
1076 void lmutex_unlock_intercept(mutex_t
*mutex
)
1079 VALGRIND_GET_ORIG_FN(fn
);
1080 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK
,
1082 DRD_(mutex_type
)((pthread_mutex_t
*) mutex
),
1084 CALL_FN_v_W(fn
, mutex
);
1085 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK
,
1089 PTH_FUNCS(void, lmutexZuunlock
, lmutex_unlock_intercept
,
1090 (mutex_t
*mutex
), (mutex
));
1091 #endif /* VGO_solaris */
1093 static __always_inline
1094 int pthread_cond_init_intercept(pthread_cond_t
* cond
,
1095 const pthread_condattr_t
* attr
)
1099 VALGRIND_GET_ORIG_FN(fn
);
1100 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT
,
1102 CALL_FN_W_WW(ret
, fn
, cond
, attr
);
1103 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT
,
1108 PTH_FUNCS(int, pthreadZucondZuinit
, pthread_cond_init_intercept
,
1109 (pthread_cond_t
* cond
, const pthread_condattr_t
* attr
),
1112 #if defined(VGO_solaris)
1113 static __always_inline
1114 int cond_init_intercept(cond_t
*cond
, int type
, void *arg
)
1118 VALGRIND_GET_ORIG_FN(fn
);
1119 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT
,
1121 CALL_FN_W_WWW(ret
, fn
, cond
, type
, arg
);
1122 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT
,
1127 PTH_FUNCS(int, condZuinit
, cond_init_intercept
,
1128 (cond_t
*cond
, int type
, void *arg
),
1130 #endif /* VGO_solaris */
1132 static __always_inline
1133 int pthread_cond_destroy_intercept(pthread_cond_t
* cond
)
1137 VALGRIND_GET_ORIG_FN(fn
);
1138 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_DESTROY
,
1140 CALL_FN_W_W(ret
, fn
, cond
);
1141 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_DESTROY
,
1142 cond
, ret
==0, 0, 0, 0);
1146 #if defined(VGO_solaris)
1147 /* On Solaris, pthread_cond_destroy is a weak alias to cond_destroy. */
1148 PTH_FUNCS(int, condZudestroy
, pthread_cond_destroy_intercept
,
1149 (pthread_cond_t
*cond
), (cond
));
1151 PTH_FUNCS(int, pthreadZucondZudestroy
, pthread_cond_destroy_intercept
,
1152 (pthread_cond_t
* cond
), (cond
));
1153 #endif /* VGO_solaris */
1155 static __always_inline
1156 int pthread_cond_wait_intercept(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
1160 VALGRIND_GET_ORIG_FN(fn
);
1161 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT
,
1162 cond
, mutex
, DRD_(mutex_type
)(mutex
), 0, 0);
1163 CALL_FN_W_WW(ret
, fn
, cond
, mutex
);
1164 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT
,
1165 cond
, mutex
, 1, 0, 0);
1169 PTH_FUNCS(int, pthreadZucondZuwait
, pthread_cond_wait_intercept
,
1170 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
),
1172 #if defined(VGO_solaris)
1173 PTH_FUNCS(int, condZuwait
, pthread_cond_wait_intercept
,
1174 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
),
1176 #endif /* VGO_solaris */
1178 static __always_inline
1179 int pthread_cond_timedwait_intercept(pthread_cond_t
*cond
,
1180 pthread_mutex_t
*mutex
,
1181 const struct timespec
* abstime
)
1185 VALGRIND_GET_ORIG_FN(fn
);
1186 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT
,
1187 cond
, mutex
, DRD_(mutex_type
)(mutex
), 0, 0);
1188 CALL_FN_W_WWW(ret
, fn
, cond
, mutex
, abstime
);
1189 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT
,
1190 cond
, mutex
, 1, 0, 0);
1194 PTH_FUNCS(int, pthreadZucondZutimedwait
, pthread_cond_timedwait_intercept
,
1195 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1196 const struct timespec
* abstime
),
1197 (cond
, mutex
, abstime
));
1198 #if defined(VGO_solaris)
1199 PTH_FUNCS(int, condZutimedwait
, pthread_cond_timedwait_intercept
,
1200 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1201 const struct timespec
*timeout
),
1202 (cond
, mutex
, timeout
));
1203 PTH_FUNCS(int, condZureltimedwait
, pthread_cond_timedwait_intercept
,
1204 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1205 const struct timespec
*timeout
),
1206 (cond
, mutex
, timeout
));
1207 #endif /* VGO_solaris */
1210 #if defined(HAVE_CLOCKID_T)
1211 static __always_inline
1212 int pthread_cond_clockwait_intercept(pthread_cond_t
*cond
,
1213 pthread_mutex_t
*mutex
,
1215 const struct timespec
* abstime
)
1219 VALGRIND_GET_ORIG_FN(fn
);
1220 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT
,
1221 cond
, mutex
, DRD_(mutex_type
)(mutex
), 0, 0);
1222 CALL_FN_W_WWWW(ret
, fn
, cond
, mutex
, clockid
, abstime
);
1223 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT
,
1224 cond
, mutex
, 1, 0, 0);
1228 PTH_FUNCS(int, pthreadZucondZuclockwait
, pthread_cond_clockwait_intercept
,
1229 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1230 clockid_t clockid
, const struct timespec
* abstime
),
1231 (cond
, mutex
, clockid
, abstime
));
1235 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
1236 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
1237 // two. Intercepting all pthread_cond_signal* functions will cause only one
1238 // argument to be passed to pthread_cond_signal_np() and hence will cause this
1239 // last function to crash.
1241 static __always_inline
1242 int pthread_cond_signal_intercept(pthread_cond_t
* cond
)
1246 VALGRIND_GET_ORIG_FN(fn
);
1247 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_SIGNAL
,
1249 CALL_FN_W_W(ret
, fn
, cond
);
1250 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_SIGNAL
,
1255 #if defined(VGO_solaris)
1256 /* On Solaris, pthread_cond_signal is a weak alias to cond_signal. */
1257 PTH_FUNCS(int, condZusignal
, pthread_cond_signal_intercept
,
1258 (pthread_cond_t
*cond
), (cond
));
1260 PTH_FUNCS(int, pthreadZucondZusignal
, pthread_cond_signal_intercept
,
1261 (pthread_cond_t
* cond
), (cond
));
1262 #endif /* VGO_solaris */
1264 static __always_inline
1265 int pthread_cond_broadcast_intercept(pthread_cond_t
* cond
)
1269 VALGRIND_GET_ORIG_FN(fn
);
1270 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_BROADCAST
,
1272 CALL_FN_W_W(ret
, fn
, cond
);
1273 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_BROADCAST
,
1278 #if defined(VGO_solaris)
1279 /* On Solaris, pthread_cond_broadcast is a weak alias to cond_broadcast. */
1280 PTH_FUNCS(int, condZubroadcast
, pthread_cond_broadcast_intercept
,
1281 (pthread_cond_t
*cond
), (cond
));
1283 PTH_FUNCS(int, pthreadZucondZubroadcast
, pthread_cond_broadcast_intercept
,
1284 (pthread_cond_t
* cond
), (cond
));
1285 #endif /* VGO_solaris */
1287 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1288 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1289 static __always_inline
1290 int pthread_spin_init_intercept(pthread_spinlock_t
*spinlock
, int pshared
)
1294 VALGRIND_GET_ORIG_FN(fn
);
1295 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK
,
1296 spinlock
, 0, 0, 0, 0);
1297 CALL_FN_W_WW(ret
, fn
, spinlock
, pshared
);
1298 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK
,
1299 spinlock
, 0, 0, 0, 0);
1303 PTH_FUNCS(int, pthreadZuspinZuinit
, pthread_spin_init_intercept
,
1304 (pthread_spinlock_t
*spinlock
, int pshared
), (spinlock
, pshared
));
1306 static __always_inline
1307 int pthread_spin_destroy_intercept(pthread_spinlock_t
*spinlock
)
1311 VALGRIND_GET_ORIG_FN(fn
);
1312 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY
,
1313 spinlock
, 0, 0, 0, 0);
1314 CALL_FN_W_W(ret
, fn
, spinlock
);
1315 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY
,
1316 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1320 PTH_FUNCS(int, pthreadZuspinZudestroy
, pthread_spin_destroy_intercept
,
1321 (pthread_spinlock_t
*spinlock
), (spinlock
));
1323 static __always_inline
1324 int pthread_spin_lock_intercept(pthread_spinlock_t
*spinlock
)
1328 VALGRIND_GET_ORIG_FN(fn
);
1329 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
1330 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1331 CALL_FN_W_W(ret
, fn
, spinlock
);
1332 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
1333 spinlock
, ret
== 0, 0, 0, 0);
1337 PTH_FUNCS(int, pthreadZuspinZulock
, pthread_spin_lock_intercept
,
1338 (pthread_spinlock_t
*spinlock
), (spinlock
));
1340 static __always_inline
1341 int pthread_spin_trylock_intercept(pthread_spinlock_t
*spinlock
)
1345 VALGRIND_GET_ORIG_FN(fn
);
1346 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
1347 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1348 CALL_FN_W_W(ret
, fn
, spinlock
);
1349 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
1350 spinlock
, ret
== 0, 0, 0, 0);
1354 PTH_FUNCS(int, pthreadZuspinZutrylock
, pthread_spin_trylock_intercept
,
1355 (pthread_spinlock_t
*spinlock
), (spinlock
));
1357 static __always_inline
1358 int pthread_spin_unlock_intercept(pthread_spinlock_t
*spinlock
)
1362 VALGRIND_GET_ORIG_FN(fn
);
1363 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK
,
1364 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1365 CALL_FN_W_W(ret
, fn
, spinlock
);
1366 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK
,
1367 spinlock
, 0, 0, 0, 0);
1371 PTH_FUNCS(int, pthreadZuspinZuunlock
, pthread_spin_unlock_intercept
,
1372 (pthread_spinlock_t
*spinlock
), (spinlock
));
1373 #endif // HAVE_PTHREAD_SPIN_LOCK
1376 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1377 static __always_inline
1378 int pthread_barrier_init_intercept(pthread_barrier_t
* barrier
,
1379 const pthread_barrierattr_t
* attr
,
1384 VALGRIND_GET_ORIG_FN(fn
);
1385 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_INIT
,
1386 barrier
, pthread_barrier
, count
, 0, 0);
1387 CALL_FN_W_WWW(ret
, fn
, barrier
, attr
, count
);
1388 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_INIT
,
1389 barrier
, pthread_barrier
, 0, 0, 0);
1393 PTH_FUNCS(int, pthreadZubarrierZuinit
, pthread_barrier_init_intercept
,
1394 (pthread_barrier_t
* barrier
, const pthread_barrierattr_t
* attr
,
1395 unsigned count
), (barrier
, attr
, count
));
1397 static __always_inline
1398 int pthread_barrier_destroy_intercept(pthread_barrier_t
* barrier
)
1402 VALGRIND_GET_ORIG_FN(fn
);
1403 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_DESTROY
,
1404 barrier
, pthread_barrier
, 0, 0, 0);
1405 CALL_FN_W_W(ret
, fn
, barrier
);
1406 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_DESTROY
,
1407 barrier
, pthread_barrier
, 0, 0, 0);
1411 PTH_FUNCS(int, pthreadZubarrierZudestroy
, pthread_barrier_destroy_intercept
,
1412 (pthread_barrier_t
* barrier
), (barrier
));
1414 static __always_inline
1415 int pthread_barrier_wait_intercept(pthread_barrier_t
* barrier
)
1419 VALGRIND_GET_ORIG_FN(fn
);
1420 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_WAIT
,
1421 barrier
, pthread_barrier
, 0, 0, 0);
1422 CALL_FN_W_W(ret
, fn
, barrier
);
1423 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_WAIT
,
1424 barrier
, pthread_barrier
,
1425 ret
== 0 || ret
== PTHREAD_BARRIER_SERIAL_THREAD
,
1426 ret
== PTHREAD_BARRIER_SERIAL_THREAD
, 0);
1430 PTH_FUNCS(int, pthreadZubarrierZuwait
, pthread_barrier_wait_intercept
,
1431 (pthread_barrier_t
* barrier
), (barrier
));
1432 #endif // HAVE_PTHREAD_BARRIER_INIT
1435 static __always_inline
1436 int sem_init_intercept(sem_t
*sem
, int pshared
, unsigned int value
)
1440 VALGRIND_GET_ORIG_FN(fn
);
1441 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT
,
1442 sem
, pshared
, value
, 0, 0);
1443 CALL_FN_W_WWW(ret
, fn
, sem
, pshared
, value
);
1444 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT
,
1449 #if defined(VGO_freebsd)
1450 LIBC_FUNC(int, semZuinit
, sem_init_intercept
,
1451 (sem_t
*sem
, int pshared
, unsigned int value
), (sem
, pshared
, value
));
1453 PTH_FUNCS(int, semZuinit
, sem_init_intercept
,
1454 (sem_t
*sem
, int pshared
, unsigned int value
), (sem
, pshared
, value
));
1457 #if defined(VGO_solaris)
1458 static __always_inline
1459 int sema_init_intercept(sema_t
*sem
, unsigned int value
, int type
, void *arg
)
1463 VALGRIND_GET_ORIG_FN(fn
);
1464 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT
,
1465 sem
, type
== USYNC_PROCESS
? 1 : 0,
1467 CALL_FN_W_WWWW(ret
, fn
, sem
, value
, type
, arg
);
1468 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT
,
1473 PTH_FUNCS(int, semaZuinit
, sema_init_intercept
,
1474 (sema_t
*sem
, unsigned int value
, int type
, void *arg
),
1475 (sem
, value
, type
, arg
));
1476 #endif /* VGO_solaris */
1478 static __always_inline
1479 int sem_destroy_intercept(sem_t
*sem
)
1483 VALGRIND_GET_ORIG_FN(fn
);
1484 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_DESTROY
,
1486 CALL_FN_W_W(ret
, fn
, sem
);
1487 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_DESTROY
,
1492 #if defined(VGO_freebsd)
1493 LIBC_FUNC(int, semZudestroy
, sem_destroy_intercept
, (sem_t
*sem
), (sem
));
1495 PTH_FUNCS(int, semZudestroy
, sem_destroy_intercept
, (sem_t
*sem
), (sem
));
1498 #if defined(VGO_solaris)
1499 PTH_FUNCS(int, semaZudestroy
, sem_destroy_intercept
, (sem_t
*sem
), (sem
));
1500 #endif /* VGO_solaris */
1502 static __always_inline
1503 sem_t
* sem_open_intercept(const char *name
, int oflag
, mode_t mode
,
1508 VALGRIND_GET_ORIG_FN(fn
);
1509 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_OPEN
,
1510 name
, oflag
, mode
, value
, 0);
1511 CALL_FN_W_WWWW(ret
, fn
, name
, oflag
, mode
, value
);
1512 // To do: figure out why gcc 9.2.1 miscompiles this function if the printf()
1513 // call below is left out.
1515 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_OPEN
,
1516 ret
!= SEM_FAILED
? ret
: 0,
1517 name
, oflag
, mode
, value
);
1521 #if defined(VGO_freebsd)
1522 LIBC_FUNC(sem_t
*, semZuopen
, sem_open_intercept
,
1523 (const char *name
, int oflag
, mode_t mode
, unsigned int value
),
1524 (name
, oflag
, mode
, value
));
1526 PTH_FUNCS(sem_t
*, semZuopen
, sem_open_intercept
,
1527 (const char *name
, int oflag
, mode_t mode
, unsigned int value
),
1528 (name
, oflag
, mode
, value
));
1531 static __always_inline
int sem_close_intercept(sem_t
*sem
)
1535 VALGRIND_GET_ORIG_FN(fn
);
1536 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_CLOSE
,
1538 CALL_FN_W_W(ret
, fn
, sem
);
1539 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_CLOSE
,
1544 #if defined(VGO_freebsd)
1545 LIBC_FUNC(int, semZuclose
, sem_close_intercept
, (sem_t
*sem
), (sem
));
1547 PTH_FUNCS(int, semZuclose
, sem_close_intercept
, (sem_t
*sem
), (sem
));
1550 static __always_inline
int sem_wait_intercept(sem_t
*sem
)
1554 VALGRIND_GET_ORIG_FN(fn
);
1555 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT
,
1557 CALL_FN_W_W(ret
, fn
, sem
);
1558 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT
,
1559 sem
, ret
== 0, 0, 0, 0);
1563 #if defined(VGO_freebsd)
1564 LIBC_FUNC(int, semZuwait
, sem_wait_intercept
, (sem_t
*sem
), (sem
));
1566 PTH_FUNCS(int, semZuwait
, sem_wait_intercept
, (sem_t
*sem
), (sem
));
1569 #if defined(VGO_solaris)
1570 PTH_FUNCS(int, semaZuwait
, sem_wait_intercept
, (sem_t
*sem
), (sem
));
1571 #endif /* VGO_solaris */
1573 static __always_inline
int sem_trywait_intercept(sem_t
*sem
)
1577 VALGRIND_GET_ORIG_FN(fn
);
1578 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT
,
1580 CALL_FN_W_W(ret
, fn
, sem
);
1581 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT
,
1582 sem
, ret
== 0, 0, 0, 0);
1586 #if defined(VGO_freebsd)
1587 LIBC_FUNC(int, semZutrywait
, sem_trywait_intercept
, (sem_t
*sem
), (sem
));
1589 PTH_FUNCS(int, semZutrywait
, sem_trywait_intercept
, (sem_t
*sem
), (sem
));
1591 #if defined(VGO_solaris)
1592 PTH_FUNCS(int, semaZutrywait
, sem_trywait_intercept
, (sem_t
*sem
), (sem
));
1593 #endif /* VGO_solaris */
1595 static __always_inline
1596 int sem_timedwait_intercept(sem_t
*sem
, const struct timespec
*abs_timeout
)
1600 VALGRIND_GET_ORIG_FN(fn
);
1601 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT
,
1603 CALL_FN_W_WW(ret
, fn
, sem
, abs_timeout
);
1604 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT
,
1605 sem
, ret
== 0, 0, 0, 0);
1609 #if defined(VGO_freebsd)
1610 LIBC_FUNC(int, semZutimedwait
, sem_timedwait_intercept
,
1611 (sem_t
*sem
, const struct timespec
*abs_timeout
),
1612 (sem
, abs_timeout
));
1614 PTH_FUNCS(int, semZutimedwait
, sem_timedwait_intercept
,
1615 (sem_t
*sem
, const struct timespec
*abs_timeout
),
1616 (sem
, abs_timeout
));
1618 #if defined(VGO_solaris)
1619 PTH_FUNCS(int, semaZutimedwait
, sem_timedwait_intercept
,
1620 (sem_t
*sem
, const struct timespec
*timeout
),
1622 PTH_FUNCS(int, semaZureltimedwait
, sem_timedwait_intercept
,
1623 (sem_t
*sem
, const struct timespec
*timeout
),
1625 #endif /* VGO_solaris */
1627 static __always_inline
int sem_post_intercept(sem_t
*sem
)
1631 VALGRIND_GET_ORIG_FN(fn
);
1632 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_POST
,
1634 CALL_FN_W_W(ret
, fn
, sem
);
1635 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_POST
,
1636 sem
, ret
== 0, 0, 0, 0);
1640 #if defined(VGO_freebsd)
1641 LIBC_FUNC(int, semZupost
, sem_post_intercept
, (sem_t
*sem
), (sem
));
1643 PTH_FUNCS(int, semZupost
, sem_post_intercept
, (sem_t
*sem
), (sem
));
1645 #if defined(VGO_solaris)
1646 PTH_FUNCS(int, semaZupost
, sem_post_intercept
, (sem_t
*sem
), (sem
));
1647 #endif /* VGO_solaris */
1649 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1650 functions have to be conditionally compiled. */
1651 #if defined(HAVE_PTHREAD_RWLOCK_T)
1653 static __always_inline
1654 int pthread_rwlock_init_intercept(pthread_rwlock_t
* rwlock
,
1655 const pthread_rwlockattr_t
* attr
)
1659 VALGRIND_GET_ORIG_FN(fn
);
1660 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT
,
1661 rwlock
, 0, 0, 0, 0);
1662 CALL_FN_W_WW(ret
, fn
, rwlock
, attr
);
1663 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT
,
1664 rwlock
, 0, 0, 0, 0);
1669 pthreadZurwlockZuinit
, pthread_rwlock_init_intercept
,
1670 (pthread_rwlock_t
* rwlock
, const pthread_rwlockattr_t
* attr
),
1673 #if defined(VGO_solaris)
1674 static __always_inline
1675 int rwlock_init_intercept(rwlock_t
*rwlock
, int type
, void *arg
)
1679 VALGRIND_GET_ORIG_FN(fn
);
1680 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT
,
1681 rwlock
, 0, 0, 0, 0);
1682 CALL_FN_W_WWW(ret
, fn
, rwlock
, type
, arg
);
1683 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT
,
1684 rwlock
, 0, 0, 0, 0);
1688 PTH_FUNCS(int, rwlockZuinit
, rwlock_init_intercept
,
1689 (rwlock_t
*rwlock
, int type
, void *arg
),
1690 (rwlock
, type
, arg
));
1691 #endif /* VGO_solaris */
1693 static __always_inline
1694 int pthread_rwlock_destroy_intercept(pthread_rwlock_t
* rwlock
)
1698 VALGRIND_GET_ORIG_FN(fn
);
1699 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_DESTROY
,
1700 rwlock
, 0, 0, 0, 0);
1701 CALL_FN_W_W(ret
, fn
, rwlock
);
1702 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_DESTROY
,
1703 rwlock
, 0, 0, 0, 0);
1707 #if defined(VGO_solaris)
1708 /* On Solaris, pthread_rwlock_destroy is a weak alias to rwlock_destroy. */
1710 rwlockZudestroy
, pthread_rwlock_destroy_intercept
,
1711 (pthread_rwlock_t
*rwlock
), (rwlock
));
1714 pthreadZurwlockZudestroy
, pthread_rwlock_destroy_intercept
,
1715 (pthread_rwlock_t
* rwlock
), (rwlock
));
1716 #endif /* VGO_solaris */
1718 static __always_inline
1719 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t
* rwlock
)
1723 VALGRIND_GET_ORIG_FN(fn
);
1724 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK
,
1725 rwlock
, 0, 0, 0, 0);
1726 CALL_FN_W_W(ret
, fn
, rwlock
);
1727 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK
,
1728 rwlock
, ret
== 0, 0, 0, 0);
1732 #if defined(VGO_solaris)
1733 /* On Solaris, pthread_rwlock_rdlock is a weak alias to rw_rdlock. */
1735 rwZurdlock
, pthread_rwlock_rdlock_intercept
,
1736 (pthread_rwlock_t
*rwlock
), (rwlock
));
1739 pthreadZurwlockZurdlock
, pthread_rwlock_rdlock_intercept
,
1740 (pthread_rwlock_t
* rwlock
), (rwlock
));
1741 #endif /* VGO_solaris */
1743 #if defined(VGO_solaris)
1744 /* Internal to libc. */
1745 static __always_inline
1746 void lrw_rdlock_intercept(rwlock_t
*rwlock
)
1749 VALGRIND_GET_ORIG_FN(fn
);
1750 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK
,
1751 rwlock
, 0, 0, 0, 0);
1752 CALL_FN_v_W(fn
, rwlock
);
1753 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK
,
1754 rwlock
, True
/* took_lock */, 0, 0, 0);
1757 PTH_FUNCS(void, lrwZurdlock
, lrw_rdlock_intercept
,
1758 (rwlock_t
*rwlock
), (rwlock
));
1759 #endif /* VGO_solaris */
1761 static __always_inline
1762 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t
* rwlock
)
1766 VALGRIND_GET_ORIG_FN(fn
);
1767 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK
,
1768 rwlock
, 0, 0, 0, 0);
1769 CALL_FN_W_W(ret
, fn
, rwlock
);
1770 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK
,
1771 rwlock
, ret
== 0, 0, 0, 0);
1775 #if defined(VGO_solaris)
1776 /* On Solaris, pthread_rwlock_wrlock is a weak alias to rw_wrlock. */
1778 rwZuwrlock
, pthread_rwlock_wrlock_intercept
,
1779 (pthread_rwlock_t
*rwlock
), (rwlock
));
1782 pthreadZurwlockZuwrlock
, pthread_rwlock_wrlock_intercept
,
1783 (pthread_rwlock_t
* rwlock
), (rwlock
));
1784 #endif /* VGO_solaris */
1786 #if defined(VGO_solaris)
1787 /* Internal to libc. */
1788 static __always_inline
1789 void lrw_wrlock_intercept(rwlock_t
*rwlock
)
1792 VALGRIND_GET_ORIG_FN(fn
);
1793 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK
,
1794 rwlock
, 0, 0, 0, 0);
1795 CALL_FN_v_W(fn
, rwlock
);
1796 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK
,
1797 rwlock
, True
/* took_lock */, 0, 0, 0);
1800 PTH_FUNCS(void, lrwZuwrlock
, lrw_wrlock_intercept
,
1801 (rwlock_t
*rwlock
), (rwlock
));
1802 #endif /* VGO_solaris */
1804 static __always_inline
1805 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t
* rwlock
,
1806 const struct timespec
*timeout
)
1810 VALGRIND_GET_ORIG_FN(fn
);
1811 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK
,
1812 rwlock
, 0, 0, 0, 0);
1813 CALL_FN_W_WW(ret
, fn
, rwlock
, timeout
);
1814 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK
,
1815 rwlock
, ret
== 0, 0, 0, 0);
1820 pthreadZurwlockZutimedrdlock
, pthread_rwlock_timedrdlock_intercept
,
1821 (pthread_rwlock_t
* rwlock
, const struct timespec
*timeout
),
1823 #if defined(VGO_solaris)
1824 PTH_FUNCS(int, pthreadZurwlockZureltimedrdlockZunp
,
1825 pthread_rwlock_timedrdlock_intercept
,
1826 (pthread_rwlock_t
*rwlock
, const struct timespec
*timeout
),
1828 #endif /* VGO_solaris */
1831 #if defined(HAVE_CLOCKID_T)
1832 static __always_inline
1833 int pthread_rwlock_clockrdlock_intercept(pthread_rwlock_t
* rwlock
,
1835 const struct timespec
*timeout
)
1839 VALGRIND_GET_ORIG_FN(fn
);
1840 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK
,
1841 rwlock
, 0, 0, 0, 0);
1842 CALL_FN_W_WWW(ret
, fn
, rwlock
, clockid
, timeout
);
1843 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK
,
1844 rwlock
, ret
== 0, 0, 0, 0);
1849 pthreadZurwlockZuclockrdlock
, pthread_rwlock_clockrdlock_intercept
,
1850 (pthread_rwlock_t
* rwlock
, clockid_t clockid
, const struct timespec
*timeout
),
1851 (rwlock
, clockid
, timeout
));
1854 static __always_inline
1855 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t
* rwlock
,
1856 const struct timespec
*timeout
)
1860 VALGRIND_GET_ORIG_FN(fn
);
1861 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK
,
1862 rwlock
, 0, 0, 0, 0);
1863 CALL_FN_W_WW(ret
, fn
, rwlock
, timeout
);
1864 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK
,
1865 rwlock
, ret
== 0, 0, 0, 0);
1870 pthreadZurwlockZutimedwrlock
, pthread_rwlock_timedwrlock_intercept
,
1871 (pthread_rwlock_t
* rwlock
, const struct timespec
*timeout
),
1873 #if defined(VGO_solaris)
1874 PTH_FUNCS(int, pthreadZurwlockZureltimedwrlockZunp
,
1875 pthread_rwlock_timedwrlock_intercept
,
1876 (pthread_rwlock_t
*rwlock
, const struct timespec
*timeout
),
1878 #endif /* VGO_solaris */
1881 #if defined(HAVE_CLOCKID_T)
1882 static __always_inline
1883 int pthread_rwlock_clockwrlock_intercept(pthread_rwlock_t
* rwlock
,
1885 const struct timespec
*timeout
)
1889 VALGRIND_GET_ORIG_FN(fn
);
1890 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK
,
1891 rwlock
, 0, 0, 0, 0);
1892 CALL_FN_W_WWW(ret
, fn
, rwlock
, clockid
, timeout
);
1893 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK
,
1894 rwlock
, ret
== 0, 0, 0, 0);
1899 pthreadZurwlockZuclockwrlock
, pthread_rwlock_clockwrlock_intercept
,
1900 (pthread_rwlock_t
* rwlock
, clockid_t clockid
, const struct timespec
*timeout
),
1901 (rwlock
, clockid
, timeout
));
1905 static __always_inline
1906 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t
* rwlock
)
1910 VALGRIND_GET_ORIG_FN(fn
);
1911 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK
,
1912 rwlock
, 0, 0, 0, 0);
1913 CALL_FN_W_W(ret
, fn
, rwlock
);
1914 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK
,
1915 rwlock
, ret
== 0, 0, 0, 0);
1919 #if defined(VGO_solaris)
1920 /* On Solaris, pthread_rwlock_tryrdlock is a weak alias to rw_tryrdlock. */
1922 rwZutryrdlock
, pthread_rwlock_tryrdlock_intercept
,
1923 (pthread_rwlock_t
*rwlock
), (rwlock
));
1926 pthreadZurwlockZutryrdlock
, pthread_rwlock_tryrdlock_intercept
,
1927 (pthread_rwlock_t
* rwlock
), (rwlock
));
1928 #endif /* VGO_solaris */
1930 static __always_inline
1931 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t
* rwlock
)
1935 VALGRIND_GET_ORIG_FN(fn
);
1936 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK
,
1937 rwlock
, 0, 0, 0, 0);
1938 CALL_FN_W_W(ret
, fn
, rwlock
);
1939 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK
,
1940 rwlock
, ret
== 0, 0, 0, 0);
1944 #if defined(VGO_solaris)
1945 /* On Solaris, pthread_rwlock_trywrlock is a weak alias to rw_trywrlock. */
1947 rwZutrywrlock
, pthread_rwlock_trywrlock_intercept
,
1948 (pthread_rwlock_t
*rwlock
), (rwlock
));
1951 pthreadZurwlockZutrywrlock
, pthread_rwlock_trywrlock_intercept
,
1952 (pthread_rwlock_t
* rwlock
), (rwlock
));
1953 #endif /* VGO_solaris */
1955 static __always_inline
1956 int pthread_rwlock_unlock_intercept(pthread_rwlock_t
* rwlock
)
1960 VALGRIND_GET_ORIG_FN(fn
);
1961 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_UNLOCK
,
1962 rwlock
, 0, 0, 0, 0);
1963 CALL_FN_W_W(ret
, fn
, rwlock
);
1964 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_UNLOCK
,
1965 rwlock
, ret
== 0, 0, 0, 0);
1969 #if defined(VGO_solaris)
1970 /* On Solaris, pthread_rwlock_unlock is a weak alias to rw_unlock. */
1972 rwZuunlock
, pthread_rwlock_unlock_intercept
,
1973 (pthread_rwlock_t
*rwlock
), (rwlock
));
1976 pthreadZurwlockZuunlock
, pthread_rwlock_unlock_intercept
,
1977 (pthread_rwlock_t
* rwlock
), (rwlock
));
1978 #endif /* VGO_solaris */
1980 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */