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_DRD_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_DRD_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_DRD_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_DRD_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_DRD_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
;
607 /* The C11 thrd_create() implementation passes -1 as 'attr' argument. */
608 if (attr
&& (uintptr_t)attr
+ 1 != 0)
610 if (pthread_attr_getdetachstate(attr
, &thread_args
.detachstate
) != 0)
613 assert(thread_args
.detachstate
== PTHREAD_CREATE_JOINABLE
614 || thread_args
.detachstate
== PTHREAD_CREATE_DETACHED
);
617 * The DRD_(set_pthread_id)() from DRD_(init)() may encounter that
618 * pthread_self() == 0, e.g. when the main program is not linked with the
619 * pthread library and when a pthread_create() call occurs from within a
620 * shared library. Hence call DRD_(set_pthread_id)() again to ensure that
621 * DRD knows the identity of the current thread. See also B.Z. 356374.
623 DRD_(set_pthread_id
)();
624 DRD_(entering_pthread_create
)();
625 CALL_FN_W_WWWW(ret
, fn
, thread
, attr
, DRD_(thread_wrapper
), &thread_args
);
626 DRD_(left_pthread_create
)();
629 /* Wait until the thread wrapper started. */
630 DRD_(sema_down
)(&wrapper_started
);
633 DRD_(sema_destroy
)(&wrapper_started
);
635 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_START_NEW_SEGMENT
,
636 pthread_self(), 0, 0, 0, 0);
641 PTH_FUNCS(int, pthreadZucreate
, pthread_create_intercept
,
642 (pthread_t
*thread
, const pthread_attr_t
*attr
,
643 void *(*start
) (void *), void *arg
),
644 (thread
, attr
, start
, arg
));
646 #if defined(VGO_solaris)
647 /* Solaris also provides thr_create() in addition to pthread_create().
648 * Both pthread_create(3C) and thr_create(3C) are based on private
651 static __always_inline
652 int thr_create_intercept(void *stk
, size_t stksize
, void *(*start
)(void *),
653 void *arg
, long flags
, thread_t
*new_thread
)
657 DrdSema wrapper_started
;
658 DrdPosixThreadArgs thread_args
;
660 VALGRIND_GET_ORIG_FN(fn
);
662 DRD_(sema_init
)(&wrapper_started
);
663 thread_args
.start
= start
;
664 thread_args
.arg
= arg
;
665 thread_args
.wrapper_started
= &wrapper_started
;
667 * Find out whether the thread will be started as a joinable thread
668 * or as a detached thread.
670 if (flags
& THR_DETACHED
)
671 thread_args
.detachstate
= PTHREAD_CREATE_DETACHED
;
673 thread_args
.detachstate
= PTHREAD_CREATE_JOINABLE
;
675 DRD_(entering_pthread_create
)();
676 CALL_FN_W_6W(ret
, fn
, stk
, stksize
, DRD_(thread_wrapper
), &thread_args
,
678 DRD_(left_pthread_create
)();
681 /* Wait until the thread wrapper started. */
682 DRD_(sema_down
)(&wrapper_started
);
685 DRD_(sema_destroy
)(&wrapper_started
);
687 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_START_NEW_SEGMENT
,
688 pthread_self(), 0, 0, 0, 0);
693 PTH_FUNCS(int, thrZucreate
, thr_create_intercept
,
694 (void *stk
, size_t stksize
, void *(*start
)(void *), void *arg
,
695 long flags
, thread_t
*new_thread
),
696 (stk
, stksize
, start
, arg
, flags
, new_thread
));
697 #endif /* VGO_solaris */
699 #if defined(VGO_solaris)
701 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
702 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
703 * and CI_BIND_CLEAR, to provide resilience against function renaming.
705 static __always_inline
706 int DRD_(_ti_bind_guard_intercept
)(int flags
) {
707 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_RTLD_BIND_GUARD
,
709 return DRD_(rtld_bind_guard
)(flags
);
712 static __always_inline
713 int DRD_(_ti_bind_clear_intercept
)(int flags
) {
714 int ret
= DRD_(rtld_bind_clear
)(flags
);
715 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_RTLD_BIND_CLEAR
,
721 * Wrapped _ld_libc() from the runtime linker ld.so.1.
723 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1
, ZuldZulibc
)(vki_Lc_interface
*ptr
);
724 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1
, ZuldZulibc
)(vki_Lc_interface
*ptr
)
729 VALGRIND_GET_ORIG_FN(fn
);
731 vki_Lc_interface
*funcs
= ptr
;
732 for (tag
= funcs
->ci_tag
; tag
!= 0; tag
= (++funcs
)->ci_tag
) {
734 case VKI_CI_BIND_GUARD
:
735 if (funcs
->vki_ci_un
.ci_func
!= DRD_(_ti_bind_guard_intercept
)) {
736 DRD_(rtld_bind_guard
) = funcs
->vki_ci_un
.ci_func
;
737 funcs
->vki_ci_un
.ci_func
= DRD_(_ti_bind_guard_intercept
);
740 case VKI_CI_BIND_CLEAR
:
741 if (funcs
->vki_ci_un
.ci_func
!= DRD_(_ti_bind_clear_intercept
)) {
742 DRD_(rtld_bind_clear
) = funcs
->vki_ci_un
.ci_func
;
743 funcs
->vki_ci_un
.ci_func
= DRD_(_ti_bind_clear_intercept
);
749 CALL_FN_v_W(fn
, ptr
);
751 #endif /* VGO_solaris */
753 static __always_inline
754 int pthread_join_intercept(pthread_t pt_joinee
, void **thread_return
)
759 VALGRIND_GET_ORIG_FN(fn
);
761 * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
762 * implementation triggers a (false positive) race report.
764 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
765 CALL_FN_W_WW(ret
, fn
, pt_joinee
, thread_return
);
768 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_THREAD_JOIN
,
769 pt_joinee
, 0, 0, 0, 0);
771 ANNOTATE_IGNORE_READS_AND_WRITES_END();
775 PTH_FUNCS(int, pthreadZujoin
, pthread_join_intercept
,
776 (pthread_t pt_joinee
, void **thread_return
),
777 (pt_joinee
, thread_return
));
779 #if defined(VGO_solaris)
780 /* Solaris also provides thr_join() in addition to pthread_join().
781 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
783 * :TODO: No functionality is currently provided for joinee == 0 and departed.
784 * This would require another client request, of course.
786 static __always_inline
787 int thr_join_intercept(thread_t joinee
, thread_t
*departed
, void **thread_return
)
792 VALGRIND_GET_ORIG_FN(fn
);
793 CALL_FN_W_WWW(ret
, fn
, joinee
, departed
, thread_return
);
796 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_THREAD_JOIN
,
802 PTH_FUNCS(int, thrZujoin
, thr_join_intercept
,
803 (thread_t joinee
, thread_t
*departed
, void **thread_return
),
804 (joinee
, departed
, thread_return
));
805 #endif /* VGO_solaris */
807 static __always_inline
808 int pthread_detach_intercept(pthread_t pt_thread
)
813 VALGRIND_GET_ORIG_FN(fn
);
814 CALL_FN_W_W(ret
, fn
, pt_thread
);
815 DRD_(set_joinable
)(pt_thread
, 0);
820 PTH_FUNCS(int, pthreadZudetach
, pthread_detach_intercept
,
821 (pthread_t thread
), (thread
));
823 // NOTE: be careful to intercept only pthread_cancel() and not
824 // pthread_cancel_init() on Linux.
826 static __always_inline
827 int pthread_cancel_intercept(pthread_t pt_thread
)
831 VALGRIND_GET_ORIG_FN(fn
);
832 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_THREAD_CANCEL
,
833 pt_thread
, 0, 0, 0, 0);
834 CALL_FN_W_W(ret
, fn
, pt_thread
);
835 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_THREAD_CANCEL
,
836 pt_thread
, ret
==0, 0, 0, 0);
840 PTH_FUNCS(int, pthreadZucancel
, pthread_cancel_intercept
,
841 (pthread_t thread
), (thread
))
843 static __always_inline
844 int pthread_once_intercept(pthread_once_t
*once_control
,
845 void (*init_routine
)(void))
849 VALGRIND_GET_ORIG_FN(fn
);
851 * Ignore any data races triggered by the implementation of pthread_once().
852 * Necessary for Darwin. This is not necessary for Linux but doesn't have
853 * any known adverse effects.
855 DRD_IGNORE_VAR(*once_control
);
856 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
857 CALL_FN_W_WW(ret
, fn
, once_control
, init_routine
);
858 ANNOTATE_IGNORE_READS_AND_WRITES_END();
859 DRD_STOP_IGNORING_VAR(*once_control
);
863 PTH_FUNCS(int, pthreadZuonce
, pthread_once_intercept
,
864 (pthread_once_t
*once_control
, void (*init_routine
)(void)),
865 (once_control
, init_routine
));
867 static __always_inline
868 int pthread_mutex_init_intercept(pthread_mutex_t
*mutex
,
869 const pthread_mutexattr_t
* attr
)
874 VALGRIND_GET_ORIG_FN(fn
);
875 mt
= PTHREAD_MUTEX_DEFAULT
;
877 pthread_mutexattr_gettype(attr
, &mt
);
878 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_INIT
,
879 mutex
, DRD_(pthread_to_drd_mutex_type
)(mt
),
881 CALL_FN_W_WW(ret
, fn
, mutex
, attr
);
882 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_INIT
,
887 PTH_FUNCS(int, pthreadZumutexZuinit
, pthread_mutex_init_intercept
,
888 (pthread_mutex_t
*mutex
, const pthread_mutexattr_t
* attr
),
891 #if defined(VGO_solaris)
892 static __always_inline
893 int mutex_init_intercept(mutex_t
*mutex
, int type
, void *arg
)
897 VALGRIND_GET_ORIG_FN(fn
);
899 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_INIT
,
900 mutex
, DRD_(thread_to_drd_mutex_type
)(type
),
902 CALL_FN_W_WWW(ret
, fn
, mutex
, type
, arg
);
903 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_INIT
,
908 PTH_FUNCS(int, mutexZuinit
, mutex_init_intercept
,
909 (mutex_t
*mutex
, int type
, void *arg
),
911 #endif /* VGO_solaris */
913 static __always_inline
914 int pthread_mutex_destroy_intercept(pthread_mutex_t
* mutex
)
918 VALGRIND_GET_ORIG_FN(fn
);
919 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_DESTROY
,
921 CALL_FN_W_W(ret
, fn
, mutex
);
922 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_DESTROY
,
923 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
927 #if defined(VGO_solaris)
928 /* On Solaris, pthread_mutex_destroy is a weak alias to mutex_destroy. */
929 PTH_FUNCS(int, mutexZudestroy
, pthread_mutex_destroy_intercept
,
930 (pthread_mutex_t
*mutex
), (mutex
));
932 PTH_FUNCS(int, pthreadZumutexZudestroy
, pthread_mutex_destroy_intercept
,
933 (pthread_mutex_t
*mutex
), (mutex
));
934 #endif /* VGO_solaris */
936 static __always_inline
937 int pthread_mutex_lock_intercept(pthread_mutex_t
* mutex
)
941 VALGRIND_GET_ORIG_FN(fn
);
942 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK
,
943 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
944 CALL_FN_W_W(ret
, fn
, mutex
);
945 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK
,
946 mutex
, ret
== 0, 0, 0, 0);
950 #if defined(VGO_solaris)
951 /* On Solaris, pthread_mutex_lock is a weak alias to mutex_lock. */
952 PTH_FUNCS(int, mutexZulock
, pthread_mutex_lock_intercept
,
953 (pthread_mutex_t
*mutex
), (mutex
));
955 PTH_FUNCS(int, pthreadZumutexZulock
, pthread_mutex_lock_intercept
,
956 (pthread_mutex_t
*mutex
), (mutex
));
957 #endif /* VGO_solaris */
959 #if defined(VGO_solaris)
960 /* Internal to libc. Mutex is usually initialized only implicitly,
961 * by zeroing mutex_t structure.
963 static __always_inline
964 void lmutex_lock_intercept(mutex_t
*mutex
)
967 VALGRIND_GET_ORIG_FN(fn
);
968 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK
,
970 DRD_(mutex_type
)((pthread_mutex_t
*) mutex
),
971 False
/* try_lock */, 0, 0);
972 CALL_FN_v_W(fn
, mutex
);
973 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK
,
974 mutex
, True
/* took_lock */, 0, 0, 0);
977 PTH_FUNCS(void, lmutexZulock
, lmutex_lock_intercept
,
978 (mutex_t
*mutex
), (mutex
));
979 #endif /* VGO_solaris */
981 static __always_inline
982 int pthread_mutex_trylock_intercept(pthread_mutex_t
* mutex
)
986 VALGRIND_GET_ORIG_FN(fn
);
987 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK
,
988 mutex
, DRD_(mutex_type
)(mutex
), 1, 0, 0);
989 CALL_FN_W_W(ret
, fn
, mutex
);
990 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK
,
991 mutex
, ret
== 0, 0, 0, 0);
995 #if defined(VGO_solaris)
996 /* On Solaris, pthread_mutex_trylock is a weak alias to mutex_trylock. */
997 PTH_FUNCS(int, mutexZutrylock
, pthread_mutex_trylock_intercept
,
998 (pthread_mutex_t
*mutex
), (mutex
));
1000 PTH_FUNCS(int, pthreadZumutexZutrylock
, pthread_mutex_trylock_intercept
,
1001 (pthread_mutex_t
*mutex
), (mutex
));
1002 #endif /* VGO_solaris */
1004 static __always_inline
1005 int pthread_mutex_timedlock_intercept(pthread_mutex_t
*mutex
,
1006 const struct timespec
*abs_timeout
)
1010 VALGRIND_GET_ORIG_FN(fn
);
1011 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK
,
1012 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
1013 CALL_FN_W_WW(ret
, fn
, mutex
, abs_timeout
);
1014 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK
,
1015 mutex
, ret
== 0, 0, 0, 0);
1019 PTH_FUNCS(int, pthreadZumutexZutimedlock
, pthread_mutex_timedlock_intercept
,
1020 (pthread_mutex_t
*mutex
, const struct timespec
*abs_timeout
),
1021 (mutex
, abs_timeout
));
1022 #if defined(VGO_solaris)
1024 pthreadZumutexZureltimedlockZunp
, pthread_mutex_timedlock_intercept
,
1025 (pthread_mutex_t
*mutex
, const struct timespec
*timeout
),
1027 #endif /* VGO_solaris */
1029 #if defined(HAVE_CLOCKID_T)
1030 static __always_inline
1031 int pthread_mutex_clocklock_intercept(pthread_mutex_t
*mutex
,
1033 const struct timespec
*abs_timeout
)
1037 VALGRIND_GET_ORIG_FN(fn
);
1038 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK
,
1039 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
1040 CALL_FN_W_WWW(ret
, fn
, mutex
, clockid
, abs_timeout
);
1041 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK
,
1042 mutex
, ret
== 0, 0, 0, 0);
1046 PTH_FUNCS(int, pthreadZumutexZuclocklock
, pthread_mutex_clocklock_intercept
,
1047 (pthread_mutex_t
*mutex
, clockid_t clockid
, const struct timespec
*abs_timeout
),
1048 (mutex
, clockid
, abs_timeout
));
1051 static __always_inline
1052 int pthread_mutex_unlock_intercept(pthread_mutex_t
*mutex
)
1056 VALGRIND_GET_ORIG_FN(fn
);
1057 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_UNLOCK
,
1058 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
1059 CALL_FN_W_W(ret
, fn
, mutex
);
1060 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_UNLOCK
,
1065 #if defined(VGO_solaris)
1066 /* On Solaris, pthread_mutex_unlock is a weak alias to mutex_unlock. */
1067 PTH_FUNCS(int, mutexZuunlock
, pthread_mutex_unlock_intercept
,
1068 (pthread_mutex_t
*mutex
), (mutex
));
1070 PTH_FUNCS(int, pthreadZumutexZuunlock
, pthread_mutex_unlock_intercept
,
1071 (pthread_mutex_t
*mutex
), (mutex
));
1072 #endif /* VGO_solaris */
1074 #if defined(VGO_solaris)
1075 /* Internal to libc. */
1076 static __always_inline
1077 void lmutex_unlock_intercept(mutex_t
*mutex
)
1080 VALGRIND_GET_ORIG_FN(fn
);
1081 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_UNLOCK
,
1083 DRD_(mutex_type
)((pthread_mutex_t
*) mutex
),
1085 CALL_FN_v_W(fn
, mutex
);
1086 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_UNLOCK
,
1090 PTH_FUNCS(void, lmutexZuunlock
, lmutex_unlock_intercept
,
1091 (mutex_t
*mutex
), (mutex
));
1092 #endif /* VGO_solaris */
1094 static __always_inline
1095 int pthread_cond_init_intercept(pthread_cond_t
* cond
,
1096 const pthread_condattr_t
* attr
)
1100 VALGRIND_GET_ORIG_FN(fn
);
1101 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_INIT
,
1103 CALL_FN_W_WW(ret
, fn
, cond
, attr
);
1104 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_INIT
,
1109 PTH_FUNCS(int, pthreadZucondZuinit
, pthread_cond_init_intercept
,
1110 (pthread_cond_t
* cond
, const pthread_condattr_t
* attr
),
1113 #if defined(VGO_solaris)
1114 static __always_inline
1115 int cond_init_intercept(cond_t
*cond
, int type
, void *arg
)
1119 VALGRIND_GET_ORIG_FN(fn
);
1120 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_INIT
,
1122 CALL_FN_W_WWW(ret
, fn
, cond
, type
, arg
);
1123 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_INIT
,
1128 PTH_FUNCS(int, condZuinit
, cond_init_intercept
,
1129 (cond_t
*cond
, int type
, void *arg
),
1131 #endif /* VGO_solaris */
1133 static __always_inline
1134 int pthread_cond_destroy_intercept(pthread_cond_t
* cond
)
1138 VALGRIND_GET_ORIG_FN(fn
);
1139 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_DESTROY
,
1141 CALL_FN_W_W(ret
, fn
, cond
);
1142 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_DESTROY
,
1143 cond
, ret
==0, 0, 0, 0);
1147 #if defined(VGO_solaris)
1148 /* On Solaris, pthread_cond_destroy is a weak alias to cond_destroy. */
1149 PTH_FUNCS(int, condZudestroy
, pthread_cond_destroy_intercept
,
1150 (pthread_cond_t
*cond
), (cond
));
1152 PTH_FUNCS(int, pthreadZucondZudestroy
, pthread_cond_destroy_intercept
,
1153 (pthread_cond_t
* cond
), (cond
));
1154 #endif /* VGO_solaris */
1156 static __always_inline
1157 int pthread_cond_wait_intercept(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
1161 VALGRIND_GET_ORIG_FN(fn
);
1162 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_WAIT
,
1163 cond
, mutex
, DRD_(mutex_type
)(mutex
), 0, 0);
1164 CALL_FN_W_WW(ret
, fn
, cond
, mutex
);
1165 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_WAIT
,
1166 cond
, mutex
, 1, 0, 0);
1170 PTH_FUNCS(int, pthreadZucondZuwait
, pthread_cond_wait_intercept
,
1171 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
),
1173 #if defined(VGO_solaris)
1174 PTH_FUNCS(int, condZuwait
, pthread_cond_wait_intercept
,
1175 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
),
1177 #endif /* VGO_solaris */
1179 static __always_inline
1180 int pthread_cond_timedwait_intercept(pthread_cond_t
*cond
,
1181 pthread_mutex_t
*mutex
,
1182 const struct timespec
* abstime
)
1186 VALGRIND_GET_ORIG_FN(fn
);
1187 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_WAIT
,
1188 cond
, mutex
, DRD_(mutex_type
)(mutex
), 0, 0);
1189 CALL_FN_W_WWW(ret
, fn
, cond
, mutex
, abstime
);
1190 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_WAIT
,
1191 cond
, mutex
, 1, 0, 0);
1195 PTH_FUNCS(int, pthreadZucondZutimedwait
, pthread_cond_timedwait_intercept
,
1196 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1197 const struct timespec
* abstime
),
1198 (cond
, mutex
, abstime
));
1199 #if defined(VGO_solaris)
1200 PTH_FUNCS(int, condZutimedwait
, pthread_cond_timedwait_intercept
,
1201 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1202 const struct timespec
*timeout
),
1203 (cond
, mutex
, timeout
));
1204 PTH_FUNCS(int, condZureltimedwait
, pthread_cond_timedwait_intercept
,
1205 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1206 const struct timespec
*timeout
),
1207 (cond
, mutex
, timeout
));
1208 #endif /* VGO_solaris */
1211 #if defined(HAVE_CLOCKID_T)
1212 static __always_inline
1213 int pthread_cond_clockwait_intercept(pthread_cond_t
*cond
,
1214 pthread_mutex_t
*mutex
,
1216 const struct timespec
* abstime
)
1220 VALGRIND_GET_ORIG_FN(fn
);
1221 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_WAIT
,
1222 cond
, mutex
, DRD_(mutex_type
)(mutex
), 0, 0);
1223 CALL_FN_W_WWWW(ret
, fn
, cond
, mutex
, clockid
, abstime
);
1224 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_WAIT
,
1225 cond
, mutex
, 1, 0, 0);
1229 PTH_FUNCS(int, pthreadZucondZuclockwait
, pthread_cond_clockwait_intercept
,
1230 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1231 clockid_t clockid
, const struct timespec
* abstime
),
1232 (cond
, mutex
, clockid
, abstime
));
1236 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
1237 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
1238 // two. Intercepting all pthread_cond_signal* functions will cause only one
1239 // argument to be passed to pthread_cond_signal_np() and hence will cause this
1240 // last function to crash.
1242 static __always_inline
1243 int pthread_cond_signal_intercept(pthread_cond_t
* cond
)
1247 VALGRIND_GET_ORIG_FN(fn
);
1248 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_SIGNAL
,
1250 CALL_FN_W_W(ret
, fn
, cond
);
1251 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_SIGNAL
,
1256 #if defined(VGO_solaris)
1257 /* On Solaris, pthread_cond_signal is a weak alias to cond_signal. */
1258 PTH_FUNCS(int, condZusignal
, pthread_cond_signal_intercept
,
1259 (pthread_cond_t
*cond
), (cond
));
1261 PTH_FUNCS(int, pthreadZucondZusignal
, pthread_cond_signal_intercept
,
1262 (pthread_cond_t
* cond
), (cond
));
1263 #endif /* VGO_solaris */
1265 static __always_inline
1266 int pthread_cond_broadcast_intercept(pthread_cond_t
* cond
)
1270 VALGRIND_GET_ORIG_FN(fn
);
1271 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_BROADCAST
,
1273 CALL_FN_W_W(ret
, fn
, cond
);
1274 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_BROADCAST
,
1279 #if defined(VGO_solaris)
1280 /* On Solaris, pthread_cond_broadcast is a weak alias to cond_broadcast. */
1281 PTH_FUNCS(int, condZubroadcast
, pthread_cond_broadcast_intercept
,
1282 (pthread_cond_t
*cond
), (cond
));
1284 PTH_FUNCS(int, pthreadZucondZubroadcast
, pthread_cond_broadcast_intercept
,
1285 (pthread_cond_t
* cond
), (cond
));
1286 #endif /* VGO_solaris */
1288 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1289 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1290 static __always_inline
1291 int pthread_spin_init_intercept(pthread_spinlock_t
*spinlock
, int pshared
)
1295 VALGRIND_GET_ORIG_FN(fn
);
1296 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SPIN_INIT_OR_UNLOCK
,
1297 spinlock
, 0, 0, 0, 0);
1298 CALL_FN_W_WW(ret
, fn
, spinlock
, pshared
);
1299 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SPIN_INIT_OR_UNLOCK
,
1300 spinlock
, 0, 0, 0, 0);
1304 PTH_FUNCS(int, pthreadZuspinZuinit
, pthread_spin_init_intercept
,
1305 (pthread_spinlock_t
*spinlock
, int pshared
), (spinlock
, pshared
));
1307 static __always_inline
1308 int pthread_spin_destroy_intercept(pthread_spinlock_t
*spinlock
)
1312 VALGRIND_GET_ORIG_FN(fn
);
1313 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_DESTROY
,
1314 spinlock
, 0, 0, 0, 0);
1315 CALL_FN_W_W(ret
, fn
, spinlock
);
1316 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_DESTROY
,
1317 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1321 PTH_FUNCS(int, pthreadZuspinZudestroy
, pthread_spin_destroy_intercept
,
1322 (pthread_spinlock_t
*spinlock
), (spinlock
));
1324 static __always_inline
1325 int pthread_spin_lock_intercept(pthread_spinlock_t
*spinlock
)
1329 VALGRIND_GET_ORIG_FN(fn
);
1330 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK
,
1331 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1332 CALL_FN_W_W(ret
, fn
, spinlock
);
1333 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK
,
1334 spinlock
, ret
== 0, 0, 0, 0);
1338 PTH_FUNCS(int, pthreadZuspinZulock
, pthread_spin_lock_intercept
,
1339 (pthread_spinlock_t
*spinlock
), (spinlock
));
1341 static __always_inline
1342 int pthread_spin_trylock_intercept(pthread_spinlock_t
*spinlock
)
1346 VALGRIND_GET_ORIG_FN(fn
);
1347 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK
,
1348 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1349 CALL_FN_W_W(ret
, fn
, spinlock
);
1350 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK
,
1351 spinlock
, ret
== 0, 0, 0, 0);
1355 PTH_FUNCS(int, pthreadZuspinZutrylock
, pthread_spin_trylock_intercept
,
1356 (pthread_spinlock_t
*spinlock
), (spinlock
));
1358 static __always_inline
1359 int pthread_spin_unlock_intercept(pthread_spinlock_t
*spinlock
)
1363 VALGRIND_GET_ORIG_FN(fn
);
1364 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SPIN_INIT_OR_UNLOCK
,
1365 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1366 CALL_FN_W_W(ret
, fn
, spinlock
);
1367 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SPIN_INIT_OR_UNLOCK
,
1368 spinlock
, 0, 0, 0, 0);
1372 PTH_FUNCS(int, pthreadZuspinZuunlock
, pthread_spin_unlock_intercept
,
1373 (pthread_spinlock_t
*spinlock
), (spinlock
));
1374 #endif // HAVE_PTHREAD_SPIN_LOCK
1377 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1378 static __always_inline
1379 int pthread_barrier_init_intercept(pthread_barrier_t
* barrier
,
1380 const pthread_barrierattr_t
* attr
,
1385 VALGRIND_GET_ORIG_FN(fn
);
1386 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_BARRIER_INIT
,
1387 barrier
, pthread_barrier
, count
, 0, 0);
1388 CALL_FN_W_WWW(ret
, fn
, barrier
, attr
, count
);
1389 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_BARRIER_INIT
,
1390 barrier
, pthread_barrier
, 0, 0, 0);
1394 PTH_FUNCS(int, pthreadZubarrierZuinit
, pthread_barrier_init_intercept
,
1395 (pthread_barrier_t
* barrier
, const pthread_barrierattr_t
* attr
,
1396 unsigned count
), (barrier
, attr
, count
));
1398 static __always_inline
1399 int pthread_barrier_destroy_intercept(pthread_barrier_t
* barrier
)
1403 VALGRIND_GET_ORIG_FN(fn
);
1404 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_BARRIER_DESTROY
,
1405 barrier
, pthread_barrier
, 0, 0, 0);
1406 CALL_FN_W_W(ret
, fn
, barrier
);
1407 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_BARRIER_DESTROY
,
1408 barrier
, pthread_barrier
, 0, 0, 0);
1412 PTH_FUNCS(int, pthreadZubarrierZudestroy
, pthread_barrier_destroy_intercept
,
1413 (pthread_barrier_t
* barrier
), (barrier
));
1415 static __always_inline
1416 int pthread_barrier_wait_intercept(pthread_barrier_t
* barrier
)
1420 VALGRIND_GET_ORIG_FN(fn
);
1421 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_BARRIER_WAIT
,
1422 barrier
, pthread_barrier
, 0, 0, 0);
1423 CALL_FN_W_W(ret
, fn
, barrier
);
1424 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_BARRIER_WAIT
,
1425 barrier
, pthread_barrier
,
1426 ret
== 0 || ret
== PTHREAD_BARRIER_SERIAL_THREAD
,
1427 ret
== PTHREAD_BARRIER_SERIAL_THREAD
, 0);
1431 PTH_FUNCS(int, pthreadZubarrierZuwait
, pthread_barrier_wait_intercept
,
1432 (pthread_barrier_t
* barrier
), (barrier
));
1433 #endif // HAVE_PTHREAD_BARRIER_INIT
1436 static __always_inline
1437 int sem_init_intercept(sem_t
*sem
, int pshared
, unsigned int value
)
1441 VALGRIND_GET_ORIG_FN(fn
);
1442 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_INIT
,
1443 sem
, pshared
, value
, 0, 0);
1444 CALL_FN_W_WWW(ret
, fn
, sem
, pshared
, value
);
1445 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_INIT
,
1450 #if defined(VGO_freebsd)
1451 LIBC_FUNC(int, semZuinit
, sem_init_intercept
,
1452 (sem_t
*sem
, int pshared
, unsigned int value
), (sem
, pshared
, value
));
1454 PTH_FUNCS(int, semZuinit
, sem_init_intercept
,
1455 (sem_t
*sem
, int pshared
, unsigned int value
), (sem
, pshared
, value
));
1458 #if defined(VGO_solaris)
1459 static __always_inline
1460 int sema_init_intercept(sema_t
*sem
, unsigned int value
, int type
, void *arg
)
1464 VALGRIND_GET_ORIG_FN(fn
);
1465 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_INIT
,
1466 sem
, type
== USYNC_PROCESS
? 1 : 0,
1468 CALL_FN_W_WWWW(ret
, fn
, sem
, value
, type
, arg
);
1469 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_INIT
,
1474 PTH_FUNCS(int, semaZuinit
, sema_init_intercept
,
1475 (sema_t
*sem
, unsigned int value
, int type
, void *arg
),
1476 (sem
, value
, type
, arg
));
1477 #endif /* VGO_solaris */
1479 static __always_inline
1480 int sem_destroy_intercept(sem_t
*sem
)
1484 VALGRIND_GET_ORIG_FN(fn
);
1485 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_DESTROY
,
1487 CALL_FN_W_W(ret
, fn
, sem
);
1488 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_DESTROY
,
1493 #if defined(VGO_freebsd)
1494 LIBC_FUNC(int, semZudestroy
, sem_destroy_intercept
, (sem_t
*sem
), (sem
));
1496 PTH_FUNCS(int, semZudestroy
, sem_destroy_intercept
, (sem_t
*sem
), (sem
));
1499 #if defined(VGO_solaris)
1500 PTH_FUNCS(int, semaZudestroy
, sem_destroy_intercept
, (sem_t
*sem
), (sem
));
1501 #endif /* VGO_solaris */
1503 static __always_inline
1504 sem_t
* sem_open_intercept(const char *name
, int oflag
, mode_t mode
,
1509 VALGRIND_GET_ORIG_FN(fn
);
1510 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_OPEN
,
1511 name
, oflag
, mode
, value
, 0);
1512 CALL_FN_W_WWWW(ret
, fn
, name
, oflag
, mode
, value
);
1513 // To do: figure out why gcc 9.2.1 miscompiles this function if the printf()
1514 // call below is left out.
1516 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_OPEN
,
1517 ret
!= SEM_FAILED
? ret
: 0,
1518 name
, oflag
, mode
, value
);
1522 #if defined(VGO_freebsd)
1523 LIBC_FUNC(sem_t
*, semZuopen
, sem_open_intercept
,
1524 (const char *name
, int oflag
, mode_t mode
, unsigned int value
),
1525 (name
, oflag
, mode
, value
));
1527 PTH_FUNCS(sem_t
*, semZuopen
, sem_open_intercept
,
1528 (const char *name
, int oflag
, mode_t mode
, unsigned int value
),
1529 (name
, oflag
, mode
, value
));
1532 static __always_inline
int sem_close_intercept(sem_t
*sem
)
1536 VALGRIND_GET_ORIG_FN(fn
);
1537 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_CLOSE
,
1539 CALL_FN_W_W(ret
, fn
, sem
);
1540 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_CLOSE
,
1545 #if defined(VGO_freebsd)
1546 LIBC_FUNC(int, semZuclose
, sem_close_intercept
, (sem_t
*sem
), (sem
));
1548 PTH_FUNCS(int, semZuclose
, sem_close_intercept
, (sem_t
*sem
), (sem
));
1551 static __always_inline
int sem_wait_intercept(sem_t
*sem
)
1555 VALGRIND_GET_ORIG_FN(fn
);
1556 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT
,
1558 CALL_FN_W_W(ret
, fn
, sem
);
1559 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT
,
1560 sem
, ret
== 0, 0, 0, 0);
1564 #if defined(VGO_freebsd)
1565 LIBC_FUNC(int, semZuwait
, sem_wait_intercept
, (sem_t
*sem
), (sem
));
1567 PTH_FUNCS(int, semZuwait
, sem_wait_intercept
, (sem_t
*sem
), (sem
));
1570 #if defined(VGO_solaris)
1571 PTH_FUNCS(int, semaZuwait
, sem_wait_intercept
, (sem_t
*sem
), (sem
));
1572 #endif /* VGO_solaris */
1574 static __always_inline
int sem_trywait_intercept(sem_t
*sem
)
1578 VALGRIND_GET_ORIG_FN(fn
);
1579 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT
,
1581 CALL_FN_W_W(ret
, fn
, sem
);
1582 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT
,
1583 sem
, ret
== 0, 0, 0, 0);
1587 #if defined(VGO_freebsd)
1588 LIBC_FUNC(int, semZutrywait
, sem_trywait_intercept
, (sem_t
*sem
), (sem
));
1590 PTH_FUNCS(int, semZutrywait
, sem_trywait_intercept
, (sem_t
*sem
), (sem
));
1592 #if defined(VGO_solaris)
1593 PTH_FUNCS(int, semaZutrywait
, sem_trywait_intercept
, (sem_t
*sem
), (sem
));
1594 #endif /* VGO_solaris */
1596 static __always_inline
1597 int sem_timedwait_intercept(sem_t
*sem
, const struct timespec
*abs_timeout
)
1601 VALGRIND_GET_ORIG_FN(fn
);
1602 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT
,
1604 CALL_FN_W_WW(ret
, fn
, sem
, abs_timeout
);
1605 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT
,
1606 sem
, ret
== 0, 0, 0, 0);
1610 #if defined(VGO_freebsd)
1611 LIBC_FUNC(int, semZutimedwait
, sem_timedwait_intercept
,
1612 (sem_t
*sem
, const struct timespec
*abs_timeout
),
1613 (sem
, abs_timeout
));
1615 PTH_FUNCS(int, semZutimedwait
, sem_timedwait_intercept
,
1616 (sem_t
*sem
, const struct timespec
*abs_timeout
),
1617 (sem
, abs_timeout
));
1619 #if defined(VGO_solaris)
1620 PTH_FUNCS(int, semaZutimedwait
, sem_timedwait_intercept
,
1621 (sem_t
*sem
, const struct timespec
*timeout
),
1623 PTH_FUNCS(int, semaZureltimedwait
, sem_timedwait_intercept
,
1624 (sem_t
*sem
, const struct timespec
*timeout
),
1626 #endif /* VGO_solaris */
1628 static __always_inline
int sem_post_intercept(sem_t
*sem
)
1632 VALGRIND_GET_ORIG_FN(fn
);
1633 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_POST
,
1635 CALL_FN_W_W(ret
, fn
, sem
);
1636 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_POST
,
1637 sem
, ret
== 0, 0, 0, 0);
1641 #if defined(VGO_freebsd)
1642 LIBC_FUNC(int, semZupost
, sem_post_intercept
, (sem_t
*sem
), (sem
));
1644 PTH_FUNCS(int, semZupost
, sem_post_intercept
, (sem_t
*sem
), (sem
));
1646 #if defined(VGO_solaris)
1647 PTH_FUNCS(int, semaZupost
, sem_post_intercept
, (sem_t
*sem
), (sem
));
1648 #endif /* VGO_solaris */
1650 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1651 functions have to be conditionally compiled. */
1652 #if defined(HAVE_PTHREAD_RWLOCK_T)
1654 static __always_inline
1655 int pthread_rwlock_init_intercept(pthread_rwlock_t
* rwlock
,
1656 const pthread_rwlockattr_t
* attr
)
1660 VALGRIND_GET_ORIG_FN(fn
);
1661 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_INIT
,
1662 rwlock
, 0, 0, 0, 0);
1663 CALL_FN_W_WW(ret
, fn
, rwlock
, attr
);
1664 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_INIT
,
1665 rwlock
, 0, 0, 0, 0);
1670 pthreadZurwlockZuinit
, pthread_rwlock_init_intercept
,
1671 (pthread_rwlock_t
* rwlock
, const pthread_rwlockattr_t
* attr
),
1674 #if defined(VGO_solaris)
1675 static __always_inline
1676 int rwlock_init_intercept(rwlock_t
*rwlock
, int type
, void *arg
)
1680 VALGRIND_GET_ORIG_FN(fn
);
1681 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_INIT
,
1682 rwlock
, 0, 0, 0, 0);
1683 CALL_FN_W_WWW(ret
, fn
, rwlock
, type
, arg
);
1684 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_INIT
,
1685 rwlock
, 0, 0, 0, 0);
1689 PTH_FUNCS(int, rwlockZuinit
, rwlock_init_intercept
,
1690 (rwlock_t
*rwlock
, int type
, void *arg
),
1691 (rwlock
, type
, arg
));
1692 #endif /* VGO_solaris */
1694 static __always_inline
1695 int pthread_rwlock_destroy_intercept(pthread_rwlock_t
* rwlock
)
1699 VALGRIND_GET_ORIG_FN(fn
);
1700 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_DESTROY
,
1701 rwlock
, 0, 0, 0, 0);
1702 CALL_FN_W_W(ret
, fn
, rwlock
);
1703 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_DESTROY
,
1704 rwlock
, 0, 0, 0, 0);
1708 #if defined(VGO_solaris)
1709 /* On Solaris, pthread_rwlock_destroy is a weak alias to rwlock_destroy. */
1711 rwlockZudestroy
, pthread_rwlock_destroy_intercept
,
1712 (pthread_rwlock_t
*rwlock
), (rwlock
));
1715 pthreadZurwlockZudestroy
, pthread_rwlock_destroy_intercept
,
1716 (pthread_rwlock_t
* rwlock
), (rwlock
));
1717 #endif /* VGO_solaris */
1719 static __always_inline
1720 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t
* rwlock
)
1724 VALGRIND_GET_ORIG_FN(fn
);
1725 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK
,
1726 rwlock
, 0, 0, 0, 0);
1727 CALL_FN_W_W(ret
, fn
, rwlock
);
1728 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK
,
1729 rwlock
, ret
== 0, 0, 0, 0);
1733 #if defined(VGO_solaris)
1734 /* On Solaris, pthread_rwlock_rdlock is a weak alias to rw_rdlock. */
1736 rwZurdlock
, pthread_rwlock_rdlock_intercept
,
1737 (pthread_rwlock_t
*rwlock
), (rwlock
));
1740 pthreadZurwlockZurdlock
, pthread_rwlock_rdlock_intercept
,
1741 (pthread_rwlock_t
* rwlock
), (rwlock
));
1742 #endif /* VGO_solaris */
1744 #if defined(VGO_solaris)
1745 /* Internal to libc. */
1746 static __always_inline
1747 void lrw_rdlock_intercept(rwlock_t
*rwlock
)
1750 VALGRIND_GET_ORIG_FN(fn
);
1751 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK
,
1752 rwlock
, 0, 0, 0, 0);
1753 CALL_FN_v_W(fn
, rwlock
);
1754 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK
,
1755 rwlock
, True
/* took_lock */, 0, 0, 0);
1758 PTH_FUNCS(void, lrwZurdlock
, lrw_rdlock_intercept
,
1759 (rwlock_t
*rwlock
), (rwlock
));
1760 #endif /* VGO_solaris */
1762 static __always_inline
1763 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t
* rwlock
)
1767 VALGRIND_GET_ORIG_FN(fn
);
1768 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK
,
1769 rwlock
, 0, 0, 0, 0);
1770 CALL_FN_W_W(ret
, fn
, rwlock
);
1771 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK
,
1772 rwlock
, ret
== 0, 0, 0, 0);
1776 #if defined(VGO_solaris)
1777 /* On Solaris, pthread_rwlock_wrlock is a weak alias to rw_wrlock. */
1779 rwZuwrlock
, pthread_rwlock_wrlock_intercept
,
1780 (pthread_rwlock_t
*rwlock
), (rwlock
));
1783 pthreadZurwlockZuwrlock
, pthread_rwlock_wrlock_intercept
,
1784 (pthread_rwlock_t
* rwlock
), (rwlock
));
1785 #endif /* VGO_solaris */
1787 #if defined(VGO_solaris)
1788 /* Internal to libc. */
1789 static __always_inline
1790 void lrw_wrlock_intercept(rwlock_t
*rwlock
)
1793 VALGRIND_GET_ORIG_FN(fn
);
1794 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK
,
1795 rwlock
, 0, 0, 0, 0);
1796 CALL_FN_v_W(fn
, rwlock
);
1797 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK
,
1798 rwlock
, True
/* took_lock */, 0, 0, 0);
1801 PTH_FUNCS(void, lrwZuwrlock
, lrw_wrlock_intercept
,
1802 (rwlock_t
*rwlock
), (rwlock
));
1803 #endif /* VGO_solaris */
1805 static __always_inline
1806 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t
* rwlock
,
1807 const struct timespec
*timeout
)
1811 VALGRIND_GET_ORIG_FN(fn
);
1812 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK
,
1813 rwlock
, 0, 0, 0, 0);
1814 CALL_FN_W_WW(ret
, fn
, rwlock
, timeout
);
1815 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK
,
1816 rwlock
, ret
== 0, 0, 0, 0);
1821 pthreadZurwlockZutimedrdlock
, pthread_rwlock_timedrdlock_intercept
,
1822 (pthread_rwlock_t
* rwlock
, const struct timespec
*timeout
),
1824 #if defined(VGO_solaris)
1825 PTH_FUNCS(int, pthreadZurwlockZureltimedrdlockZunp
,
1826 pthread_rwlock_timedrdlock_intercept
,
1827 (pthread_rwlock_t
*rwlock
, const struct timespec
*timeout
),
1829 #endif /* VGO_solaris */
1832 #if defined(HAVE_CLOCKID_T)
1833 static __always_inline
1834 int pthread_rwlock_clockrdlock_intercept(pthread_rwlock_t
* rwlock
,
1836 const struct timespec
*timeout
)
1840 VALGRIND_GET_ORIG_FN(fn
);
1841 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK
,
1842 rwlock
, 0, 0, 0, 0);
1843 CALL_FN_W_WWW(ret
, fn
, rwlock
, clockid
, timeout
);
1844 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK
,
1845 rwlock
, ret
== 0, 0, 0, 0);
1850 pthreadZurwlockZuclockrdlock
, pthread_rwlock_clockrdlock_intercept
,
1851 (pthread_rwlock_t
* rwlock
, clockid_t clockid
, const struct timespec
*timeout
),
1852 (rwlock
, clockid
, timeout
));
1855 static __always_inline
1856 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t
* rwlock
,
1857 const struct timespec
*timeout
)
1861 VALGRIND_GET_ORIG_FN(fn
);
1862 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK
,
1863 rwlock
, 0, 0, 0, 0);
1864 CALL_FN_W_WW(ret
, fn
, rwlock
, timeout
);
1865 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK
,
1866 rwlock
, ret
== 0, 0, 0, 0);
1871 pthreadZurwlockZutimedwrlock
, pthread_rwlock_timedwrlock_intercept
,
1872 (pthread_rwlock_t
* rwlock
, const struct timespec
*timeout
),
1874 #if defined(VGO_solaris)
1875 PTH_FUNCS(int, pthreadZurwlockZureltimedwrlockZunp
,
1876 pthread_rwlock_timedwrlock_intercept
,
1877 (pthread_rwlock_t
*rwlock
, const struct timespec
*timeout
),
1879 #endif /* VGO_solaris */
1882 #if defined(HAVE_CLOCKID_T)
1883 static __always_inline
1884 int pthread_rwlock_clockwrlock_intercept(pthread_rwlock_t
* rwlock
,
1886 const struct timespec
*timeout
)
1890 VALGRIND_GET_ORIG_FN(fn
);
1891 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK
,
1892 rwlock
, 0, 0, 0, 0);
1893 CALL_FN_W_WWW(ret
, fn
, rwlock
, clockid
, timeout
);
1894 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK
,
1895 rwlock
, ret
== 0, 0, 0, 0);
1900 pthreadZurwlockZuclockwrlock
, pthread_rwlock_clockwrlock_intercept
,
1901 (pthread_rwlock_t
* rwlock
, clockid_t clockid
, const struct timespec
*timeout
),
1902 (rwlock
, clockid
, timeout
));
1906 static __always_inline
1907 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t
* rwlock
)
1911 VALGRIND_GET_ORIG_FN(fn
);
1912 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK
,
1913 rwlock
, 0, 0, 0, 0);
1914 CALL_FN_W_W(ret
, fn
, rwlock
);
1915 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK
,
1916 rwlock
, ret
== 0, 0, 0, 0);
1920 #if defined(VGO_solaris)
1921 /* On Solaris, pthread_rwlock_tryrdlock is a weak alias to rw_tryrdlock. */
1923 rwZutryrdlock
, pthread_rwlock_tryrdlock_intercept
,
1924 (pthread_rwlock_t
*rwlock
), (rwlock
));
1927 pthreadZurwlockZutryrdlock
, pthread_rwlock_tryrdlock_intercept
,
1928 (pthread_rwlock_t
* rwlock
), (rwlock
));
1929 #endif /* VGO_solaris */
1931 static __always_inline
1932 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t
* rwlock
)
1936 VALGRIND_GET_ORIG_FN(fn
);
1937 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK
,
1938 rwlock
, 0, 0, 0, 0);
1939 CALL_FN_W_W(ret
, fn
, rwlock
);
1940 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK
,
1941 rwlock
, ret
== 0, 0, 0, 0);
1945 #if defined(VGO_solaris)
1946 /* On Solaris, pthread_rwlock_trywrlock is a weak alias to rw_trywrlock. */
1948 rwZutrywrlock
, pthread_rwlock_trywrlock_intercept
,
1949 (pthread_rwlock_t
*rwlock
), (rwlock
));
1952 pthreadZurwlockZutrywrlock
, pthread_rwlock_trywrlock_intercept
,
1953 (pthread_rwlock_t
* rwlock
), (rwlock
));
1954 #endif /* VGO_solaris */
1956 static __always_inline
1957 int pthread_rwlock_unlock_intercept(pthread_rwlock_t
* rwlock
)
1961 VALGRIND_GET_ORIG_FN(fn
);
1962 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_UNLOCK
,
1963 rwlock
, 0, 0, 0, 0);
1964 CALL_FN_W_W(ret
, fn
, rwlock
);
1965 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_UNLOCK
,
1966 rwlock
, ret
== 0, 0, 0, 0);
1970 #if defined(VGO_solaris)
1971 /* On Solaris, pthread_rwlock_unlock is a weak alias to rw_unlock. */
1973 rwZuunlock
, pthread_rwlock_unlock_intercept
,
1974 (pthread_rwlock_t
*rwlock
), (rwlock
));
1977 pthreadZurwlockZuunlock
, pthread_rwlock_unlock_intercept
,
1978 (pthread_rwlock_t
* rwlock
), (rwlock
));
1979 #endif /* VGO_solaris */
1981 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */