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_solaris)
62 * Solaris usually provides pthread_* functions on top of Solaris threading
63 * and synchronization functions. Usually both need to be intercepted because
64 * pthread_* ones might not call the Solaris ones (see for example sem_wait()).
65 * Such approach is required to correctly report misuse of the POSIX threads
67 * Therefore DRD intercepts and instruments all such functions but due to
68 * DRD_(thread_enter_synchr)() and DRD_(thread_leave_synchr)() guards in
69 * handle_client_request(), only the top-most function is handled.
70 * So the right thing(TM) happens, as expected.
71 * The only exception is when pthread_* function is a weak alias to the Solaris
72 * threading/synchronization function. In such case only one needs to be
73 * intercepted to avoid redirection ambiguity.
75 * Intercepted functions rely on the fact that:
76 * - pthread_mutex_t == mutex_t
77 * - pthread_cond_t == cond_t
79 * - pthread_rwlock_t == rwlock_t
81 * It is necessary to intercept also internal libc synchronization functions
83 * - For read-write locks the unlocking function is shared
84 * - Functions lmutex_lock/lmutex_unlock guard many critical sections in libc
85 * which will be otherwise reported by DRD
89 #include "pub_tool_vki.h"
92 * Solaris provides higher throughput, parallelism and scalability than other
93 * operating systems, at the cost of more fine-grained locking activity.
94 * This means for example that when a thread is created under Linux, just one
95 * big lock in glibc is used for all thread setup. Solaris libc uses several
96 * fine-grained locks and the creator thread resumes its activities as soon
97 * as possible, leaving for example stack and TLS setup activities to the
100 * This situation confuses DRD as it assumes there is some false ordering
101 * in place between creator and created thread; and therefore many types of
102 * race conditions in the application would not be reported. To prevent such
103 * false ordering, command line option --ignore-thread-creation is set to
104 * 'yes' by default on Solaris. All activity (loads, stores, client requests)
105 * is therefore ignored during:
106 * - pthread_create() call in the creator thread [libc.so]
107 * - thread creation phase (stack and TLS setup) in the created thread [libc.so]
109 * As explained in the comments for _ti_bind_guard(), whenever the runtime
110 * linker has to perform any activity (such as resolving a symbol), it protects
111 * its data structures by calling into rt_bind_guard() which in turn invokes
112 * _ti_bind_guard() in libc. Pointers to _ti_bind_guard() and _ti_bind_clear()
113 * are passed from libc to runtime linker in _ld_libc() call during libc_init().
114 * All activity is also ignored during:
115 * - runtime dynamic linker work between rt_bind_guard() and rt_bind_clear()
118 * This also means that DRD does not report race conditions in libc (when
119 * --ignore-thread-creation=yes) and runtime linker itself (unconditionally)
120 * during these ignored sequences.
124 * Original function pointers for _ti_bind_guard() and _ti_bind_clear()
125 * from libc. They are intercepted in function wrapper of _ld_libc().
127 typedef int (*drd_rtld_guard_fn
)(int flags
);
128 static drd_rtld_guard_fn
DRD_(rtld_bind_guard
) = NULL
;
129 static drd_rtld_guard_fn
DRD_(rtld_bind_clear
) = NULL
;
134 * Notes regarding thread creation:
135 * - sg_init() runs on the context of the created thread and copies the vector
136 * clock of the creator thread. This only works reliably if the creator
137 * thread waits until this copy has been performed.
138 * - DRD_(thread_compute_minimum_vc)() does not take the vector clocks into
139 * account that are involved in thread creation and for which the
140 * corresponding thread has not yet been created. So not waiting until the
141 * created thread has been started would make it possible that segments get
142 * discarded that should not yet be discarded. Or: some data races are not
147 * Macro for generating a Valgrind interception function.
148 * @param[in] ret_ty Return type of the function to be generated.
149 * @param[in] zf Z-encoded name of the interception function.
150 * @param[in] implf Name of the function that implements the intercept.
151 * @param[in] arg_decl Argument declaration list enclosed in parentheses.
152 * @param[in] argl Argument list enclosed in parentheses.
155 static int never_true
;
156 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
157 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
158 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
160 ret_ty pth_func_result = implf argl; \
161 /* Apparently inserting a function call in wrapper functions */ \
162 /* is sufficient to avoid misaligned stack errors. */ \
165 return pth_func_result; \
167 #elif defined(VGO_solaris)
168 /* On Solaris, libpthread is just a filter library on top of libc.
169 * Threading and synchronization functions in runtime linker are not
172 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
173 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl; \
174 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl \
175 { return implf argl; }
178 * On Linux, intercept both the libc and the libpthread functions. At
179 * least glibc 2.32.9000 (Fedora 34) has an implementation of all pthread
180 * functions in both libc and libpthread. Older glibc versions only have an
181 * implementation of the pthread functions in libpthread.
183 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
184 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl; \
185 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl \
186 { return implf argl; } \
187 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
188 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
189 { return implf argl; }
193 * Macro for generating three Valgrind interception functions: one with the
194 * Z-encoded name zf, one with ZAZa ("@*") appended to the name zf and one
195 * with ZDZa ("$*") appended to the name zf. The second generated interception
196 * function will intercept versioned symbols on Linux, and the third will
197 * intercept versioned symbols on Darwin.
199 #define PTH_FUNCS(ret_ty, zf, implf, argl_decl, argl) \
200 PTH_FUNC(ret_ty, zf, implf, argl_decl, argl); \
201 PTH_FUNC(ret_ty, zf ## ZAZa, implf, argl_decl, argl); \
202 PTH_FUNC(ret_ty, zf ## ZDZa, implf, argl_decl, argl);
205 * Not inlining one of the intercept functions will cause the regression
206 * tests to fail because this would cause an additional stackfram to appear
207 * in the output. The __always_inline macro guarantees that inlining will
208 * happen, even when compiling with optimization disabled.
210 #undef __always_inline /* since already defined in <cdefs.h> */
211 #if __GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 2
212 #define __always_inline __inline__ __attribute__((always_inline))
214 #define __always_inline __inline__
217 /* Local data structures. */
220 pthread_mutex_t mutex
;
227 void* (*start
)(void*);
230 DrdSema
* wrapper_started
;
231 } DrdPosixThreadArgs
;
234 /* Local function declarations. */
236 static void DRD_(init
)(void) __attribute__((constructor
));
237 static void DRD_(check_threading_library
)(void);
238 static void DRD_(set_pthread_id
)(void);
239 static void DRD_(sema_init
)(DrdSema
* sema
);
240 static void DRD_(sema_destroy
)(DrdSema
* sema
);
241 static void DRD_(sema_down
)(DrdSema
* sema
);
242 static void DRD_(sema_up
)(DrdSema
* sema
);
245 /* Function definitions. */
248 * Shared library initialization function. The function init() is called after
249 * dlopen() has loaded the shared library with DRD client intercepts because
250 * the constructor attribute was specified in the declaration of this function.
251 * Note: do specify the -nostdlib option to gcc when linking this code into a
252 * shared library because doing so would cancel the effect of the constructor
253 * attribute ! Using the gcc option -nodefaultlibs is fine because this last
254 * option preserves the shared library initialization code that calls
255 * constructor and destructor functions.
257 static void DRD_(init
)(void)
259 DRD_(check_threading_library
)();
260 DRD_(set_pthread_id
)();
261 #if defined(VGO_solaris)
262 if ((DRD_(rtld_bind_guard
) == NULL
) || (DRD_(rtld_bind_clear
) == NULL
)) {
264 "Bind guard functions for the runtime linker (ld.so.1) were not intercepted.\n"
265 "This means the interface between libc and runtime linker changed and DRD\n"
266 "needs to be ported properly. Giving up.\n");
272 static __always_inline
void DRD_(ignore_mutex_ordering
)(pthread_mutex_t
*mutex
)
274 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_IGNORE_MUTEX_ORDERING
,
278 static void DRD_(sema_init
)(DrdSema
* sema
)
280 DRD_IGNORE_VAR(*sema
);
281 pthread_mutex_init(&sema
->mutex
, NULL
);
282 DRD_(ignore_mutex_ordering
)(&sema
->mutex
);
283 pthread_cond_init(&sema
->cond
, NULL
);
287 static void DRD_(sema_destroy
)(DrdSema
* sema
)
289 pthread_mutex_destroy(&sema
->mutex
);
290 pthread_cond_destroy(&sema
->cond
);
293 static void DRD_(sema_down
)(DrdSema
* sema
)
295 pthread_mutex_lock(&sema
->mutex
);
296 while (sema
->counter
== 0)
297 pthread_cond_wait(&sema
->cond
, &sema
->mutex
);
299 pthread_mutex_unlock(&sema
->mutex
);
302 static void DRD_(sema_up
)(DrdSema
* sema
)
304 pthread_mutex_lock(&sema
->mutex
);
306 pthread_cond_signal(&sema
->cond
);
307 pthread_mutex_unlock(&sema
->mutex
);
311 * POSIX threads and DRD each have their own mutex type identification.
312 * Convert POSIX threads' mutex type to DRD's mutex type. In the code below
313 * if-statements are used to test the value of 'kind' instead of a switch
314 * statement because some of the PTHREAD_MUTEX_ macro's may have the same
317 static MutexT
DRD_(pthread_to_drd_mutex_type
)(int kind
)
320 * See also PTHREAD_MUTEX_KIND_MASK_NP in glibc source file
323 kind
&= PTHREAD_MUTEX_RECURSIVE
| PTHREAD_MUTEX_ERRORCHECK
|
324 PTHREAD_MUTEX_NORMAL
| PTHREAD_MUTEX_DEFAULT
;
326 if (kind
== PTHREAD_MUTEX_RECURSIVE
)
327 return mutex_type_recursive_mutex
;
328 else if (kind
== PTHREAD_MUTEX_ERRORCHECK
)
329 return mutex_type_errorcheck_mutex
;
330 else if (kind
== PTHREAD_MUTEX_NORMAL
)
331 return mutex_type_default_mutex
;
332 else if (kind
== PTHREAD_MUTEX_DEFAULT
)
333 return mutex_type_default_mutex
;
334 #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
335 else if (kind
== PTHREAD_MUTEX_ADAPTIVE_NP
)
336 return mutex_type_default_mutex
;
339 return mutex_type_invalid_mutex
;
342 #if defined(VGO_solaris)
344 * Solaris threads and DRD each have their own mutex type identification.
345 * Convert Solaris threads' mutex type to DRD's mutex type.
347 static MutexT
DRD_(thread_to_drd_mutex_type
)(int type
)
349 if (type
& LOCK_RECURSIVE
) {
350 return mutex_type_recursive_mutex
;
351 } else if (type
& LOCK_ERRORCHECK
) {
352 return mutex_type_errorcheck_mutex
;
354 return mutex_type_default_mutex
;
357 #endif /* VGO_solaris */
359 #define IS_ALIGNED(p) (((uintptr_t)(p) & (sizeof(*(p)) - 1)) == 0)
362 * Read the mutex type stored in the client memory used for the mutex
365 * @note This function depends on the implementation of the POSIX threads
366 * library -- the POSIX standard does not define the name of the member in
367 * which the mutex type is stored.
368 * @note The function mutex_type() has been declared inline in order
369 * to avoid that it shows up in call stacks (drd/tests/...exp* files).
370 * @note glibc stores the mutex type in the lowest two bits, and uses the
371 * higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
372 * PTHREAD_MUTEXATTR_FLAG_PSHARED.
374 static __always_inline MutexT
DRD_(mutex_type
)(pthread_mutex_t
* mutex
)
376 MutexT mutex_type
= mutex_type_unknown
;
378 ANNOTATE_IGNORE_READS_BEGIN();
379 #if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
380 /* glibc + LinuxThreads. */
381 if (IS_ALIGNED(&mutex
->__m_kind
))
383 const int kind
= mutex
->__m_kind
& 3;
384 mutex_type
= DRD_(pthread_to_drd_mutex_type
)(kind
);
386 #elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
388 if (IS_ALIGNED(&mutex
->__data
.__kind
))
390 const int kind
= mutex
->__data
.__kind
& 3;
391 mutex_type
= DRD_(pthread_to_drd_mutex_type
)(kind
);
393 #elif defined(VGO_solaris)
395 const int type
= ((mutex_t
*) mutex
)->vki_mutex_type
;
396 mutex_type
= DRD_(thread_to_drd_mutex_type
)(type
);
400 * Another POSIX threads implementation. The mutex type won't be printed
401 * when enabling --trace-mutex=yes.
404 ANNOTATE_IGNORE_READS_END();
410 * Tell DRD whether 'tid' is a joinable thread or a detached thread.
412 static void DRD_(set_joinable
)(const pthread_t tid
, const int joinable
)
414 assert(joinable
== 0 || joinable
== 1);
415 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_JOINABLE
,
416 tid
, joinable
, 0, 0, 0);
419 /** Tell DRD that the calling thread is about to enter pthread_create(). */
420 static __always_inline
void DRD_(entering_pthread_create
)(void)
422 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__ENTERING_PTHREAD_CREATE
,
426 /** Tell DRD that the calling thread has left pthread_create(). */
427 static __always_inline
void DRD_(left_pthread_create
)(void)
429 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LEFT_PTHREAD_CREATE
,
434 * Entry point for newly created threads. This function is called from the
435 * thread created by pthread_create().
437 static void* DRD_(thread_wrapper
)(void* arg
)
439 DrdPosixThreadArgs
* arg_ptr
;
440 DrdPosixThreadArgs arg_copy
;
442 arg_ptr
= (DrdPosixThreadArgs
*)arg
;
445 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID
,
446 pthread_self(), 0, 0, 0, 0);
448 DRD_(set_joinable
)(pthread_self(),
449 arg_copy
.detachstate
== PTHREAD_CREATE_JOINABLE
);
452 * Only set 'wrapper_started' after VG_USERREQ__SET_PTHREADID and
453 * DRD_(set_joinable)() have been invoked to avoid a race with
454 * a pthread_detach() invocation for this thread from another thread.
456 DRD_(sema_up
)(arg_copy
.wrapper_started
);
458 return (arg_copy
.start
)(arg_copy
.arg
);
462 * Return 1 if the LinuxThreads implementation of POSIX Threads has been
463 * detected, and 0 otherwise.
465 * @see For more information about the confstr() function, see also
466 * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
468 static int DRD_(detected_linuxthreads
)(void)
471 #if defined(_CS_GNU_LIBPTHREAD_VERSION)
472 /* Linux with a recent glibc. */
475 len
= confstr(_CS_GNU_LIBPTHREAD_VERSION
, buffer
, sizeof(buffer
));
476 assert(len
<= sizeof(buffer
));
477 return len
> 0 && buffer
[0] == 'l';
479 /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
483 /* Another OS than Linux, hence no LinuxThreads. */
489 * Stop and print an error message in case a non-supported threading
490 * library implementation (LinuxThreads) has been detected.
492 static void DRD_(check_threading_library
)(void)
494 if (DRD_(detected_linuxthreads
)())
496 if (getenv("LD_ASSUME_KERNEL"))
499 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
500 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
501 "after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
507 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
508 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
509 "after having upgraded to a newer version of your Linux distribution.\n"
518 * Update DRD's state information about the current thread.
520 static void DRD_(set_pthread_id
)(void)
522 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID
,
523 pthread_self(), 0, 0, 0, 0);
527 * Note: as of today there exist three different versions of pthread_create
529 * - pthread_create@GLIBC_2.0
530 * - pthread_create@@GLIBC_2.1
531 * - pthread_create@@GLIBC_2.2.5
532 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
533 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
534 * versions have been implemented. In any glibc version where more than one
535 * pthread_create function has been implemented, older versions call the
536 * newer versions. Or: the pthread_create* wrapper defined below can be
537 * called recursively. Any code in this wrapper should take this in account.
538 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
539 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
540 * See also the implementation of pthread_create@GLIBC_2.0 in
541 * glibc-2.9/nptl/pthread_create.c.
544 static __always_inline
545 int pthread_create_intercept(pthread_t
* thread
, const pthread_attr_t
* attr
,
546 void* (*start
)(void*), void* arg
)
550 DrdSema wrapper_started
;
551 DrdPosixThreadArgs thread_args
;
553 VALGRIND_GET_ORIG_FN(fn
);
555 DRD_(sema_init
)(&wrapper_started
);
556 thread_args
.start
= start
;
557 thread_args
.arg
= arg
;
558 thread_args
.wrapper_started
= &wrapper_started
;
560 * Find out whether the thread will be started as a joinable thread
561 * or as a detached thread. If no thread attributes have been specified,
562 * this means that the new thread will be started as a joinable thread.
564 thread_args
.detachstate
= PTHREAD_CREATE_JOINABLE
;
567 if (pthread_attr_getdetachstate(attr
, &thread_args
.detachstate
) != 0)
570 assert(thread_args
.detachstate
== PTHREAD_CREATE_JOINABLE
571 || thread_args
.detachstate
== PTHREAD_CREATE_DETACHED
);
574 * The DRD_(set_pthread_id)() from DRD_(init)() may encounter that
575 * pthread_self() == 0, e.g. when the main program is not linked with the
576 * pthread library and when a pthread_create() call occurs from within a
577 * shared library. Hence call DRD_(set_pthread_id)() again to ensure that
578 * DRD knows the identity of the current thread. See also B.Z. 356374.
580 DRD_(set_pthread_id
)();
581 DRD_(entering_pthread_create
)();
582 CALL_FN_W_WWWW(ret
, fn
, thread
, attr
, DRD_(thread_wrapper
), &thread_args
);
583 DRD_(left_pthread_create
)();
586 /* Wait until the thread wrapper started. */
587 DRD_(sema_down
)(&wrapper_started
);
590 DRD_(sema_destroy
)(&wrapper_started
);
592 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT
,
593 pthread_self(), 0, 0, 0, 0);
598 PTH_FUNCS(int, pthreadZucreate
, pthread_create_intercept
,
599 (pthread_t
*thread
, const pthread_attr_t
*attr
,
600 void *(*start
) (void *), void *arg
),
601 (thread
, attr
, start
, arg
));
603 #if defined(VGO_solaris)
604 /* Solaris also provides thr_create() in addition to pthread_create().
605 * Both pthread_create(3C) and thr_create(3C) are based on private
608 static __always_inline
609 int thr_create_intercept(void *stk
, size_t stksize
, void *(*start
)(void *),
610 void *arg
, long flags
, thread_t
*new_thread
)
614 DrdSema wrapper_started
;
615 DrdPosixThreadArgs thread_args
;
617 VALGRIND_GET_ORIG_FN(fn
);
619 DRD_(sema_init
)(&wrapper_started
);
620 thread_args
.start
= start
;
621 thread_args
.arg
= arg
;
622 thread_args
.wrapper_started
= &wrapper_started
;
624 * Find out whether the thread will be started as a joinable thread
625 * or as a detached thread.
627 if (flags
& THR_DETACHED
)
628 thread_args
.detachstate
= PTHREAD_CREATE_DETACHED
;
630 thread_args
.detachstate
= PTHREAD_CREATE_JOINABLE
;
632 DRD_(entering_pthread_create
)();
633 CALL_FN_W_6W(ret
, fn
, stk
, stksize
, DRD_(thread_wrapper
), &thread_args
,
635 DRD_(left_pthread_create
)();
638 /* Wait until the thread wrapper started. */
639 DRD_(sema_down
)(&wrapper_started
);
642 DRD_(sema_destroy
)(&wrapper_started
);
644 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT
,
645 pthread_self(), 0, 0, 0, 0);
650 PTH_FUNCS(int, thrZucreate
, thr_create_intercept
,
651 (void *stk
, size_t stksize
, void *(*start
)(void *), void *arg
,
652 long flags
, thread_t
*new_thread
),
653 (stk
, stksize
, start
, arg
, flags
, new_thread
));
654 #endif /* VGO_solaris */
656 #if defined(VGO_solaris)
658 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
659 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
660 * and CI_BIND_CLEAR, to provide resilience against function renaming.
662 static __always_inline
663 int DRD_(_ti_bind_guard_intercept
)(int flags
) {
664 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_GUARD
,
666 return DRD_(rtld_bind_guard
)(flags
);
669 static __always_inline
670 int DRD_(_ti_bind_clear_intercept
)(int flags
) {
671 int ret
= DRD_(rtld_bind_clear
)(flags
);
672 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_CLEAR
,
678 * Wrapped _ld_libc() from the runtime linker ld.so.1.
680 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1
, ZuldZulibc
)(vki_Lc_interface
*ptr
);
681 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1
, ZuldZulibc
)(vki_Lc_interface
*ptr
)
686 VALGRIND_GET_ORIG_FN(fn
);
688 vki_Lc_interface
*funcs
= ptr
;
689 for (tag
= funcs
->ci_tag
; tag
!= 0; tag
= (++funcs
)->ci_tag
) {
691 case VKI_CI_BIND_GUARD
:
692 if (funcs
->vki_ci_un
.ci_func
!= DRD_(_ti_bind_guard_intercept
)) {
693 DRD_(rtld_bind_guard
) = funcs
->vki_ci_un
.ci_func
;
694 funcs
->vki_ci_un
.ci_func
= DRD_(_ti_bind_guard_intercept
);
697 case VKI_CI_BIND_CLEAR
:
698 if (funcs
->vki_ci_un
.ci_func
!= DRD_(_ti_bind_clear_intercept
)) {
699 DRD_(rtld_bind_clear
) = funcs
->vki_ci_un
.ci_func
;
700 funcs
->vki_ci_un
.ci_func
= DRD_(_ti_bind_clear_intercept
);
706 CALL_FN_v_W(fn
, ptr
);
708 #endif /* VGO_solaris */
710 static __always_inline
711 int pthread_join_intercept(pthread_t pt_joinee
, void **thread_return
)
716 VALGRIND_GET_ORIG_FN(fn
);
718 * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
719 * implementation triggers a (false positive) race report.
721 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
722 CALL_FN_W_WW(ret
, fn
, pt_joinee
, thread_return
);
725 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN
,
726 pt_joinee
, 0, 0, 0, 0);
728 ANNOTATE_IGNORE_READS_AND_WRITES_END();
732 PTH_FUNCS(int, pthreadZujoin
, pthread_join_intercept
,
733 (pthread_t pt_joinee
, void **thread_return
),
734 (pt_joinee
, thread_return
));
736 #if defined(VGO_solaris)
737 /* Solaris also provides thr_join() in addition to pthread_join().
738 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
740 * :TODO: No functionality is currently provided for joinee == 0 and departed.
741 * This would require another client request, of course.
743 static __always_inline
744 int thr_join_intercept(thread_t joinee
, thread_t
*departed
, void **thread_return
)
749 VALGRIND_GET_ORIG_FN(fn
);
750 CALL_FN_W_WWW(ret
, fn
, joinee
, departed
, thread_return
);
753 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN
,
759 PTH_FUNCS(int, thrZujoin
, thr_join_intercept
,
760 (thread_t joinee
, thread_t
*departed
, void **thread_return
),
761 (joinee
, departed
, thread_return
));
762 #endif /* VGO_solaris */
764 static __always_inline
765 int pthread_detach_intercept(pthread_t pt_thread
)
770 VALGRIND_GET_ORIG_FN(fn
);
771 CALL_FN_W_W(ret
, fn
, pt_thread
);
772 DRD_(set_joinable
)(pt_thread
, 0);
777 PTH_FUNCS(int, pthreadZudetach
, pthread_detach_intercept
,
778 (pthread_t thread
), (thread
));
780 // NOTE: be careful to intercept only pthread_cancel() and not
781 // pthread_cancel_init() on Linux.
783 static __always_inline
784 int pthread_cancel_intercept(pthread_t pt_thread
)
788 VALGRIND_GET_ORIG_FN(fn
);
789 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_THREAD_CANCEL
,
790 pt_thread
, 0, 0, 0, 0);
791 CALL_FN_W_W(ret
, fn
, pt_thread
);
792 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_CANCEL
,
793 pt_thread
, ret
==0, 0, 0, 0);
797 PTH_FUNCS(int, pthreadZucancel
, pthread_cancel_intercept
,
798 (pthread_t thread
), (thread
))
800 static __always_inline
801 int pthread_once_intercept(pthread_once_t
*once_control
,
802 void (*init_routine
)(void))
806 VALGRIND_GET_ORIG_FN(fn
);
808 * Ignore any data races triggered by the implementation of pthread_once().
809 * Necessary for Darwin. This is not necessary for Linux but doesn't have
810 * any known adverse effects.
812 DRD_IGNORE_VAR(*once_control
);
813 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
814 CALL_FN_W_WW(ret
, fn
, once_control
, init_routine
);
815 ANNOTATE_IGNORE_READS_AND_WRITES_END();
816 DRD_STOP_IGNORING_VAR(*once_control
);
820 PTH_FUNCS(int, pthreadZuonce
, pthread_once_intercept
,
821 (pthread_once_t
*once_control
, void (*init_routine
)(void)),
822 (once_control
, init_routine
));
824 static __always_inline
825 int pthread_mutex_init_intercept(pthread_mutex_t
*mutex
,
826 const pthread_mutexattr_t
* attr
)
831 VALGRIND_GET_ORIG_FN(fn
);
832 mt
= PTHREAD_MUTEX_DEFAULT
;
834 pthread_mutexattr_gettype(attr
, &mt
);
835 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT
,
836 mutex
, DRD_(pthread_to_drd_mutex_type
)(mt
),
838 CALL_FN_W_WW(ret
, fn
, mutex
, attr
);
839 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT
,
844 PTH_FUNCS(int, pthreadZumutexZuinit
, pthread_mutex_init_intercept
,
845 (pthread_mutex_t
*mutex
, const pthread_mutexattr_t
* attr
),
848 #if defined(VGO_solaris)
849 static __always_inline
850 int mutex_init_intercept(mutex_t
*mutex
, int type
, void *arg
)
854 VALGRIND_GET_ORIG_FN(fn
);
856 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT
,
857 mutex
, DRD_(thread_to_drd_mutex_type
)(type
),
859 CALL_FN_W_WWW(ret
, fn
, mutex
, type
, arg
);
860 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT
,
865 PTH_FUNCS(int, mutexZuinit
, mutex_init_intercept
,
866 (mutex_t
*mutex
, int type
, void *arg
),
868 #endif /* VGO_solaris */
870 static __always_inline
871 int pthread_mutex_destroy_intercept(pthread_mutex_t
* mutex
)
875 VALGRIND_GET_ORIG_FN(fn
);
876 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY
,
878 CALL_FN_W_W(ret
, fn
, mutex
);
879 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY
,
880 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
884 #if defined(VGO_solaris)
885 /* On Solaris, pthread_mutex_destroy is a weak alias to mutex_destroy. */
886 PTH_FUNCS(int, mutexZudestroy
, pthread_mutex_destroy_intercept
,
887 (pthread_mutex_t
*mutex
), (mutex
));
889 PTH_FUNCS(int, pthreadZumutexZudestroy
, pthread_mutex_destroy_intercept
,
890 (pthread_mutex_t
*mutex
), (mutex
));
891 #endif /* VGO_solaris */
893 static __always_inline
894 int pthread_mutex_lock_intercept(pthread_mutex_t
* mutex
)
898 VALGRIND_GET_ORIG_FN(fn
);
899 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
900 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
901 CALL_FN_W_W(ret
, fn
, mutex
);
902 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
903 mutex
, ret
== 0, 0, 0, 0);
907 #if defined(VGO_solaris)
908 /* On Solaris, pthread_mutex_lock is a weak alias to mutex_lock. */
909 PTH_FUNCS(int, mutexZulock
, pthread_mutex_lock_intercept
,
910 (pthread_mutex_t
*mutex
), (mutex
));
912 PTH_FUNCS(int, pthreadZumutexZulock
, pthread_mutex_lock_intercept
,
913 (pthread_mutex_t
*mutex
), (mutex
));
914 #endif /* VGO_solaris */
916 #if defined(VGO_solaris)
917 /* Internal to libc. Mutex is usually initialized only implicitly,
918 * by zeroing mutex_t structure.
920 static __always_inline
921 void lmutex_lock_intercept(mutex_t
*mutex
)
924 VALGRIND_GET_ORIG_FN(fn
);
925 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
927 DRD_(mutex_type
)((pthread_mutex_t
*) mutex
),
928 False
/* try_lock */, 0, 0);
929 CALL_FN_v_W(fn
, mutex
);
930 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
931 mutex
, True
/* took_lock */, 0, 0, 0);
934 PTH_FUNCS(void, lmutexZulock
, lmutex_lock_intercept
,
935 (mutex_t
*mutex
), (mutex
));
936 #endif /* VGO_solaris */
938 static __always_inline
939 int pthread_mutex_trylock_intercept(pthread_mutex_t
* mutex
)
943 VALGRIND_GET_ORIG_FN(fn
);
944 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
945 mutex
, DRD_(mutex_type
)(mutex
), 1, 0, 0);
946 CALL_FN_W_W(ret
, fn
, mutex
);
947 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
948 mutex
, ret
== 0, 0, 0, 0);
952 #if defined(VGO_solaris)
953 /* On Solaris, pthread_mutex_trylock is a weak alias to mutex_trylock. */
954 PTH_FUNCS(int, mutexZutrylock
, pthread_mutex_trylock_intercept
,
955 (pthread_mutex_t
*mutex
), (mutex
));
957 PTH_FUNCS(int, pthreadZumutexZutrylock
, pthread_mutex_trylock_intercept
,
958 (pthread_mutex_t
*mutex
), (mutex
));
959 #endif /* VGO_solaris */
961 static __always_inline
962 int pthread_mutex_timedlock_intercept(pthread_mutex_t
*mutex
,
963 const struct timespec
*abs_timeout
)
967 VALGRIND_GET_ORIG_FN(fn
);
968 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
969 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
970 CALL_FN_W_WW(ret
, fn
, mutex
, abs_timeout
);
971 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
972 mutex
, ret
== 0, 0, 0, 0);
976 PTH_FUNCS(int, pthreadZumutexZutimedlock
, pthread_mutex_timedlock_intercept
,
977 (pthread_mutex_t
*mutex
, const struct timespec
*abs_timeout
),
978 (mutex
, abs_timeout
));
979 #if defined(VGO_solaris)
981 pthreadZumutexZureltimedlockZunp
, pthread_mutex_timedlock_intercept
,
982 (pthread_mutex_t
*mutex
, const struct timespec
*timeout
),
984 #endif /* VGO_solaris */
986 static __always_inline
987 int pthread_mutex_unlock_intercept(pthread_mutex_t
*mutex
)
991 VALGRIND_GET_ORIG_FN(fn
);
992 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK
,
993 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
994 CALL_FN_W_W(ret
, fn
, mutex
);
995 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK
,
1000 #if defined(VGO_solaris)
1001 /* On Solaris, pthread_mutex_unlock is a weak alias to mutex_unlock. */
1002 PTH_FUNCS(int, mutexZuunlock
, pthread_mutex_unlock_intercept
,
1003 (pthread_mutex_t
*mutex
), (mutex
));
1005 PTH_FUNCS(int, pthreadZumutexZuunlock
, pthread_mutex_unlock_intercept
,
1006 (pthread_mutex_t
*mutex
), (mutex
));
1007 #endif /* VGO_solaris */
1009 #if defined(VGO_solaris)
1010 /* Internal to libc. */
1011 static __always_inline
1012 void lmutex_unlock_intercept(mutex_t
*mutex
)
1015 VALGRIND_GET_ORIG_FN(fn
);
1016 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK
,
1018 DRD_(mutex_type
)((pthread_mutex_t
*) mutex
),
1020 CALL_FN_v_W(fn
, mutex
);
1021 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK
,
1025 PTH_FUNCS(void, lmutexZuunlock
, lmutex_unlock_intercept
,
1026 (mutex_t
*mutex
), (mutex
));
1027 #endif /* VGO_solaris */
1029 static __always_inline
1030 int pthread_cond_init_intercept(pthread_cond_t
* cond
,
1031 const pthread_condattr_t
* attr
)
1035 VALGRIND_GET_ORIG_FN(fn
);
1036 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT
,
1038 CALL_FN_W_WW(ret
, fn
, cond
, attr
);
1039 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT
,
1044 PTH_FUNCS(int, pthreadZucondZuinit
, pthread_cond_init_intercept
,
1045 (pthread_cond_t
* cond
, const pthread_condattr_t
* attr
),
1048 #if defined(VGO_solaris)
1049 static __always_inline
1050 int cond_init_intercept(cond_t
*cond
, int type
, void *arg
)
1054 VALGRIND_GET_ORIG_FN(fn
);
1055 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT
,
1057 CALL_FN_W_WWW(ret
, fn
, cond
, type
, arg
);
1058 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT
,
1063 PTH_FUNCS(int, condZuinit
, cond_init_intercept
,
1064 (cond_t
*cond
, int type
, void *arg
),
1066 #endif /* VGO_solaris */
1068 static __always_inline
1069 int pthread_cond_destroy_intercept(pthread_cond_t
* cond
)
1073 VALGRIND_GET_ORIG_FN(fn
);
1074 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_DESTROY
,
1076 CALL_FN_W_W(ret
, fn
, cond
);
1077 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_DESTROY
,
1078 cond
, ret
==0, 0, 0, 0);
1082 #if defined(VGO_solaris)
1083 /* On Solaris, pthread_cond_destroy is a weak alias to cond_destroy. */
1084 PTH_FUNCS(int, condZudestroy
, pthread_cond_destroy_intercept
,
1085 (pthread_cond_t
*cond
), (cond
));
1087 PTH_FUNCS(int, pthreadZucondZudestroy
, pthread_cond_destroy_intercept
,
1088 (pthread_cond_t
* cond
), (cond
));
1089 #endif /* VGO_solaris */
1091 static __always_inline
1092 int pthread_cond_wait_intercept(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
1096 VALGRIND_GET_ORIG_FN(fn
);
1097 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT
,
1098 cond
, mutex
, DRD_(mutex_type
)(mutex
), 0, 0);
1099 CALL_FN_W_WW(ret
, fn
, cond
, mutex
);
1100 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT
,
1101 cond
, mutex
, 1, 0, 0);
1105 PTH_FUNCS(int, pthreadZucondZuwait
, pthread_cond_wait_intercept
,
1106 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
),
1108 #if defined(VGO_solaris)
1109 PTH_FUNCS(int, condZuwait
, pthread_cond_wait_intercept
,
1110 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
),
1112 #endif /* VGO_solaris */
1114 static __always_inline
1115 int pthread_cond_timedwait_intercept(pthread_cond_t
*cond
,
1116 pthread_mutex_t
*mutex
,
1117 const struct timespec
* abstime
)
1121 VALGRIND_GET_ORIG_FN(fn
);
1122 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT
,
1123 cond
, mutex
, DRD_(mutex_type
)(mutex
), 0, 0);
1124 CALL_FN_W_WWW(ret
, fn
, cond
, mutex
, abstime
);
1125 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT
,
1126 cond
, mutex
, 1, 0, 0);
1130 PTH_FUNCS(int, pthreadZucondZutimedwait
, pthread_cond_timedwait_intercept
,
1131 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1132 const struct timespec
* abstime
),
1133 (cond
, mutex
, abstime
));
1134 #if defined(VGO_solaris)
1135 PTH_FUNCS(int, condZutimedwait
, pthread_cond_timedwait_intercept
,
1136 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1137 const struct timespec
*timeout
),
1138 (cond
, mutex
, timeout
));
1139 PTH_FUNCS(int, condZureltimedwait
, pthread_cond_timedwait_intercept
,
1140 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1141 const struct timespec
*timeout
),
1142 (cond
, mutex
, timeout
));
1143 #endif /* VGO_solaris */
1145 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
1146 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
1147 // two. Intercepting all pthread_cond_signal* functions will cause only one
1148 // argument to be passed to pthread_cond_signal_np() and hence will cause this
1149 // last function to crash.
1151 static __always_inline
1152 int pthread_cond_signal_intercept(pthread_cond_t
* cond
)
1156 VALGRIND_GET_ORIG_FN(fn
);
1157 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_SIGNAL
,
1159 CALL_FN_W_W(ret
, fn
, cond
);
1160 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_SIGNAL
,
1165 #if defined(VGO_solaris)
1166 /* On Solaris, pthread_cond_signal is a weak alias to cond_signal. */
1167 PTH_FUNCS(int, condZusignal
, pthread_cond_signal_intercept
,
1168 (pthread_cond_t
*cond
), (cond
));
1170 PTH_FUNCS(int, pthreadZucondZusignal
, pthread_cond_signal_intercept
,
1171 (pthread_cond_t
* cond
), (cond
));
1172 #endif /* VGO_solaris */
1174 static __always_inline
1175 int pthread_cond_broadcast_intercept(pthread_cond_t
* cond
)
1179 VALGRIND_GET_ORIG_FN(fn
);
1180 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_BROADCAST
,
1182 CALL_FN_W_W(ret
, fn
, cond
);
1183 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_BROADCAST
,
1188 #if defined(VGO_solaris)
1189 /* On Solaris, pthread_cond_broadcast is a weak alias to cond_broadcast. */
1190 PTH_FUNCS(int, condZubroadcast
, pthread_cond_broadcast_intercept
,
1191 (pthread_cond_t
*cond
), (cond
));
1193 PTH_FUNCS(int, pthreadZucondZubroadcast
, pthread_cond_broadcast_intercept
,
1194 (pthread_cond_t
* cond
), (cond
));
1195 #endif /* VGO_solaris */
1197 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1198 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1199 static __always_inline
1200 int pthread_spin_init_intercept(pthread_spinlock_t
*spinlock
, int pshared
)
1204 VALGRIND_GET_ORIG_FN(fn
);
1205 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK
,
1206 spinlock
, 0, 0, 0, 0);
1207 CALL_FN_W_WW(ret
, fn
, spinlock
, pshared
);
1208 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK
,
1209 spinlock
, 0, 0, 0, 0);
1213 PTH_FUNCS(int, pthreadZuspinZuinit
, pthread_spin_init_intercept
,
1214 (pthread_spinlock_t
*spinlock
, int pshared
), (spinlock
, pshared
));
1216 static __always_inline
1217 int pthread_spin_destroy_intercept(pthread_spinlock_t
*spinlock
)
1221 VALGRIND_GET_ORIG_FN(fn
);
1222 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY
,
1223 spinlock
, 0, 0, 0, 0);
1224 CALL_FN_W_W(ret
, fn
, spinlock
);
1225 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY
,
1226 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1230 PTH_FUNCS(int, pthreadZuspinZudestroy
, pthread_spin_destroy_intercept
,
1231 (pthread_spinlock_t
*spinlock
), (spinlock
));
1233 static __always_inline
1234 int pthread_spin_lock_intercept(pthread_spinlock_t
*spinlock
)
1238 VALGRIND_GET_ORIG_FN(fn
);
1239 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
1240 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1241 CALL_FN_W_W(ret
, fn
, spinlock
);
1242 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
1243 spinlock
, ret
== 0, 0, 0, 0);
1247 PTH_FUNCS(int, pthreadZuspinZulock
, pthread_spin_lock_intercept
,
1248 (pthread_spinlock_t
*spinlock
), (spinlock
));
1250 static __always_inline
1251 int pthread_spin_trylock_intercept(pthread_spinlock_t
*spinlock
)
1255 VALGRIND_GET_ORIG_FN(fn
);
1256 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
1257 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1258 CALL_FN_W_W(ret
, fn
, spinlock
);
1259 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
1260 spinlock
, ret
== 0, 0, 0, 0);
1264 PTH_FUNCS(int, pthreadZuspinZutrylock
, pthread_spin_trylock_intercept
,
1265 (pthread_spinlock_t
*spinlock
), (spinlock
));
1267 static __always_inline
1268 int pthread_spin_unlock_intercept(pthread_spinlock_t
*spinlock
)
1272 VALGRIND_GET_ORIG_FN(fn
);
1273 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK
,
1274 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1275 CALL_FN_W_W(ret
, fn
, spinlock
);
1276 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK
,
1277 spinlock
, 0, 0, 0, 0);
1281 PTH_FUNCS(int, pthreadZuspinZuunlock
, pthread_spin_unlock_intercept
,
1282 (pthread_spinlock_t
*spinlock
), (spinlock
));
1283 #endif // HAVE_PTHREAD_SPIN_LOCK
1286 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1287 static __always_inline
1288 int pthread_barrier_init_intercept(pthread_barrier_t
* barrier
,
1289 const pthread_barrierattr_t
* attr
,
1294 VALGRIND_GET_ORIG_FN(fn
);
1295 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_INIT
,
1296 barrier
, pthread_barrier
, count
, 0, 0);
1297 CALL_FN_W_WWW(ret
, fn
, barrier
, attr
, count
);
1298 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_INIT
,
1299 barrier
, pthread_barrier
, 0, 0, 0);
1303 PTH_FUNCS(int, pthreadZubarrierZuinit
, pthread_barrier_init_intercept
,
1304 (pthread_barrier_t
* barrier
, const pthread_barrierattr_t
* attr
,
1305 unsigned count
), (barrier
, attr
, count
));
1307 static __always_inline
1308 int pthread_barrier_destroy_intercept(pthread_barrier_t
* barrier
)
1312 VALGRIND_GET_ORIG_FN(fn
);
1313 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_DESTROY
,
1314 barrier
, pthread_barrier
, 0, 0, 0);
1315 CALL_FN_W_W(ret
, fn
, barrier
);
1316 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_DESTROY
,
1317 barrier
, pthread_barrier
, 0, 0, 0);
1321 PTH_FUNCS(int, pthreadZubarrierZudestroy
, pthread_barrier_destroy_intercept
,
1322 (pthread_barrier_t
* barrier
), (barrier
));
1324 static __always_inline
1325 int pthread_barrier_wait_intercept(pthread_barrier_t
* barrier
)
1329 VALGRIND_GET_ORIG_FN(fn
);
1330 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_WAIT
,
1331 barrier
, pthread_barrier
, 0, 0, 0);
1332 CALL_FN_W_W(ret
, fn
, barrier
);
1333 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_WAIT
,
1334 barrier
, pthread_barrier
,
1335 ret
== 0 || ret
== PTHREAD_BARRIER_SERIAL_THREAD
,
1336 ret
== PTHREAD_BARRIER_SERIAL_THREAD
, 0);
1340 PTH_FUNCS(int, pthreadZubarrierZuwait
, pthread_barrier_wait_intercept
,
1341 (pthread_barrier_t
* barrier
), (barrier
));
1342 #endif // HAVE_PTHREAD_BARRIER_INIT
1345 static __always_inline
1346 int sem_init_intercept(sem_t
*sem
, int pshared
, unsigned int value
)
1350 VALGRIND_GET_ORIG_FN(fn
);
1351 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT
,
1352 sem
, pshared
, value
, 0, 0);
1353 CALL_FN_W_WWW(ret
, fn
, sem
, pshared
, value
);
1354 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT
,
1359 PTH_FUNCS(int, semZuinit
, sem_init_intercept
,
1360 (sem_t
*sem
, int pshared
, unsigned int value
), (sem
, pshared
, value
));
1362 #if defined(VGO_solaris)
1363 static __always_inline
1364 int sema_init_intercept(sema_t
*sem
, unsigned int value
, int type
, void *arg
)
1368 VALGRIND_GET_ORIG_FN(fn
);
1369 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT
,
1370 sem
, type
== USYNC_PROCESS
? 1 : 0,
1372 CALL_FN_W_WWWW(ret
, fn
, sem
, value
, type
, arg
);
1373 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT
,
1378 PTH_FUNCS(int, semaZuinit
, sema_init_intercept
,
1379 (sema_t
*sem
, unsigned int value
, int type
, void *arg
),
1380 (sem
, value
, type
, arg
));
1381 #endif /* VGO_solaris */
1383 static __always_inline
1384 int sem_destroy_intercept(sem_t
*sem
)
1388 VALGRIND_GET_ORIG_FN(fn
);
1389 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_DESTROY
,
1391 CALL_FN_W_W(ret
, fn
, sem
);
1392 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_DESTROY
,
1397 PTH_FUNCS(int, semZudestroy
, sem_destroy_intercept
, (sem_t
*sem
), (sem
));
1398 #if defined(VGO_solaris)
1399 PTH_FUNCS(int, semaZudestroy
, sem_destroy_intercept
, (sem_t
*sem
), (sem
));
1400 #endif /* VGO_solaris */
1402 static __always_inline
1403 sem_t
* sem_open_intercept(const char *name
, int oflag
, mode_t mode
,
1408 VALGRIND_GET_ORIG_FN(fn
);
1409 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_OPEN
,
1410 name
, oflag
, mode
, value
, 0);
1411 CALL_FN_W_WWWW(ret
, fn
, name
, oflag
, mode
, value
);
1412 // To do: figure out why gcc 9.2.1 miscompiles this function if the printf()
1413 // call below is left out.
1415 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_OPEN
,
1416 ret
!= SEM_FAILED
? ret
: 0,
1417 name
, oflag
, mode
, value
);
1421 PTH_FUNCS(sem_t
*, semZuopen
, sem_open_intercept
,
1422 (const char *name
, int oflag
, mode_t mode
, unsigned int value
),
1423 (name
, oflag
, mode
, value
));
1425 static __always_inline
int sem_close_intercept(sem_t
*sem
)
1429 VALGRIND_GET_ORIG_FN(fn
);
1430 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_CLOSE
,
1432 CALL_FN_W_W(ret
, fn
, sem
);
1433 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_CLOSE
,
1438 PTH_FUNCS(int, semZuclose
, sem_close_intercept
, (sem_t
*sem
), (sem
));
1440 static __always_inline
int sem_wait_intercept(sem_t
*sem
)
1444 VALGRIND_GET_ORIG_FN(fn
);
1445 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT
,
1447 CALL_FN_W_W(ret
, fn
, sem
);
1448 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT
,
1449 sem
, ret
== 0, 0, 0, 0);
1453 PTH_FUNCS(int, semZuwait
, sem_wait_intercept
, (sem_t
*sem
), (sem
));
1454 #if defined(VGO_solaris)
1455 PTH_FUNCS(int, semaZuwait
, sem_wait_intercept
, (sem_t
*sem
), (sem
));
1456 #endif /* VGO_solaris */
1458 static __always_inline
int sem_trywait_intercept(sem_t
*sem
)
1462 VALGRIND_GET_ORIG_FN(fn
);
1463 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT
,
1465 CALL_FN_W_W(ret
, fn
, sem
);
1466 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT
,
1467 sem
, ret
== 0, 0, 0, 0);
1471 PTH_FUNCS(int, semZutrywait
, sem_trywait_intercept
, (sem_t
*sem
), (sem
));
1472 #if defined(VGO_solaris)
1473 PTH_FUNCS(int, semaZutrywait
, sem_trywait_intercept
, (sem_t
*sem
), (sem
));
1474 #endif /* VGO_solaris */
1476 static __always_inline
1477 int sem_timedwait_intercept(sem_t
*sem
, const struct timespec
*abs_timeout
)
1481 VALGRIND_GET_ORIG_FN(fn
);
1482 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT
,
1484 CALL_FN_W_WW(ret
, fn
, sem
, abs_timeout
);
1485 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT
,
1486 sem
, ret
== 0, 0, 0, 0);
1490 PTH_FUNCS(int, semZutimedwait
, sem_timedwait_intercept
,
1491 (sem_t
*sem
, const struct timespec
*abs_timeout
),
1492 (sem
, abs_timeout
));
1493 #if defined(VGO_solaris)
1494 PTH_FUNCS(int, semaZutimedwait
, sem_timedwait_intercept
,
1495 (sem_t
*sem
, const struct timespec
*timeout
),
1497 PTH_FUNCS(int, semaZureltimedwait
, sem_timedwait_intercept
,
1498 (sem_t
*sem
, const struct timespec
*timeout
),
1500 #endif /* VGO_solaris */
1502 static __always_inline
int sem_post_intercept(sem_t
*sem
)
1506 VALGRIND_GET_ORIG_FN(fn
);
1507 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_POST
,
1509 CALL_FN_W_W(ret
, fn
, sem
);
1510 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_POST
,
1511 sem
, ret
== 0, 0, 0, 0);
1515 PTH_FUNCS(int, semZupost
, sem_post_intercept
, (sem_t
*sem
), (sem
));
1516 #if defined(VGO_solaris)
1517 PTH_FUNCS(int, semaZupost
, sem_post_intercept
, (sem_t
*sem
), (sem
));
1518 #endif /* VGO_solaris */
1520 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1521 functions have to be conditionally compiled. */
1522 #if defined(HAVE_PTHREAD_RWLOCK_T)
1524 static __always_inline
1525 int pthread_rwlock_init_intercept(pthread_rwlock_t
* rwlock
,
1526 const pthread_rwlockattr_t
* attr
)
1530 VALGRIND_GET_ORIG_FN(fn
);
1531 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT
,
1532 rwlock
, 0, 0, 0, 0);
1533 CALL_FN_W_WW(ret
, fn
, rwlock
, attr
);
1534 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT
,
1535 rwlock
, 0, 0, 0, 0);
1540 pthreadZurwlockZuinit
, pthread_rwlock_init_intercept
,
1541 (pthread_rwlock_t
* rwlock
, const pthread_rwlockattr_t
* attr
),
1544 #if defined(VGO_solaris)
1545 static __always_inline
1546 int rwlock_init_intercept(rwlock_t
*rwlock
, int type
, void *arg
)
1550 VALGRIND_GET_ORIG_FN(fn
);
1551 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT
,
1552 rwlock
, 0, 0, 0, 0);
1553 CALL_FN_W_WWW(ret
, fn
, rwlock
, type
, arg
);
1554 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT
,
1555 rwlock
, 0, 0, 0, 0);
1559 PTH_FUNCS(int, rwlockZuinit
, rwlock_init_intercept
,
1560 (rwlock_t
*rwlock
, int type
, void *arg
),
1561 (rwlock
, type
, arg
));
1562 #endif /* VGO_solaris */
1564 static __always_inline
1565 int pthread_rwlock_destroy_intercept(pthread_rwlock_t
* rwlock
)
1569 VALGRIND_GET_ORIG_FN(fn
);
1570 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_DESTROY
,
1571 rwlock
, 0, 0, 0, 0);
1572 CALL_FN_W_W(ret
, fn
, rwlock
);
1573 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_DESTROY
,
1574 rwlock
, 0, 0, 0, 0);
1578 #if defined(VGO_solaris)
1579 /* On Solaris, pthread_rwlock_destroy is a weak alias to rwlock_destroy. */
1581 rwlockZudestroy
, pthread_rwlock_destroy_intercept
,
1582 (pthread_rwlock_t
*rwlock
), (rwlock
));
1585 pthreadZurwlockZudestroy
, pthread_rwlock_destroy_intercept
,
1586 (pthread_rwlock_t
* rwlock
), (rwlock
));
1587 #endif /* VGO_solaris */
1589 static __always_inline
1590 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t
* rwlock
)
1594 VALGRIND_GET_ORIG_FN(fn
);
1595 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK
,
1596 rwlock
, 0, 0, 0, 0);
1597 CALL_FN_W_W(ret
, fn
, rwlock
);
1598 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK
,
1599 rwlock
, ret
== 0, 0, 0, 0);
1603 #if defined(VGO_solaris)
1604 /* On Solaris, pthread_rwlock_rdlock is a weak alias to rw_rdlock. */
1606 rwZurdlock
, pthread_rwlock_rdlock_intercept
,
1607 (pthread_rwlock_t
*rwlock
), (rwlock
));
1610 pthreadZurwlockZurdlock
, pthread_rwlock_rdlock_intercept
,
1611 (pthread_rwlock_t
* rwlock
), (rwlock
));
1612 #endif /* VGO_solaris */
1614 #if defined(VGO_solaris)
1615 /* Internal to libc. */
1616 static __always_inline
1617 void lrw_rdlock_intercept(rwlock_t
*rwlock
)
1620 VALGRIND_GET_ORIG_FN(fn
);
1621 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK
,
1622 rwlock
, 0, 0, 0, 0);
1623 CALL_FN_v_W(fn
, rwlock
);
1624 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK
,
1625 rwlock
, True
/* took_lock */, 0, 0, 0);
1628 PTH_FUNCS(void, lrwZurdlock
, lrw_rdlock_intercept
,
1629 (rwlock_t
*rwlock
), (rwlock
));
1630 #endif /* VGO_solaris */
1632 static __always_inline
1633 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t
* rwlock
)
1637 VALGRIND_GET_ORIG_FN(fn
);
1638 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK
,
1639 rwlock
, 0, 0, 0, 0);
1640 CALL_FN_W_W(ret
, fn
, rwlock
);
1641 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK
,
1642 rwlock
, ret
== 0, 0, 0, 0);
1646 #if defined(VGO_solaris)
1647 /* On Solaris, pthread_rwlock_wrlock is a weak alias to rw_wrlock. */
1649 rwZuwrlock
, pthread_rwlock_wrlock_intercept
,
1650 (pthread_rwlock_t
*rwlock
), (rwlock
));
1653 pthreadZurwlockZuwrlock
, pthread_rwlock_wrlock_intercept
,
1654 (pthread_rwlock_t
* rwlock
), (rwlock
));
1655 #endif /* VGO_solaris */
1657 #if defined(VGO_solaris)
1658 /* Internal to libc. */
1659 static __always_inline
1660 void lrw_wrlock_intercept(rwlock_t
*rwlock
)
1663 VALGRIND_GET_ORIG_FN(fn
);
1664 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK
,
1665 rwlock
, 0, 0, 0, 0);
1666 CALL_FN_v_W(fn
, rwlock
);
1667 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK
,
1668 rwlock
, True
/* took_lock */, 0, 0, 0);
1671 PTH_FUNCS(void, lrwZuwrlock
, lrw_wrlock_intercept
,
1672 (rwlock_t
*rwlock
), (rwlock
));
1673 #endif /* VGO_solaris */
1675 static __always_inline
1676 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t
* rwlock
,
1677 const struct timespec
*timeout
)
1681 VALGRIND_GET_ORIG_FN(fn
);
1682 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK
,
1683 rwlock
, 0, 0, 0, 0);
1684 CALL_FN_W_WW(ret
, fn
, rwlock
, timeout
);
1685 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK
,
1686 rwlock
, ret
== 0, 0, 0, 0);
1691 pthreadZurwlockZutimedrdlock
, pthread_rwlock_timedrdlock_intercept
,
1692 (pthread_rwlock_t
* rwlock
, const struct timespec
*timeout
),
1694 #if defined(VGO_solaris)
1695 PTH_FUNCS(int, pthreadZurwlockZureltimedrdlockZunp
,
1696 pthread_rwlock_timedrdlock_intercept
,
1697 (pthread_rwlock_t
*rwlock
, const struct timespec
*timeout
),
1699 #endif /* VGO_solaris */
1701 static __always_inline
1702 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t
* rwlock
,
1703 const struct timespec
*timeout
)
1707 VALGRIND_GET_ORIG_FN(fn
);
1708 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK
,
1709 rwlock
, 0, 0, 0, 0);
1710 CALL_FN_W_WW(ret
, fn
, rwlock
, timeout
);
1711 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK
,
1712 rwlock
, ret
== 0, 0, 0, 0);
1717 pthreadZurwlockZutimedwrlock
, pthread_rwlock_timedwrlock_intercept
,
1718 (pthread_rwlock_t
* rwlock
, const struct timespec
*timeout
),
1720 #if defined(VGO_solaris)
1721 PTH_FUNCS(int, pthreadZurwlockZureltimedwrlockZunp
,
1722 pthread_rwlock_timedwrlock_intercept
,
1723 (pthread_rwlock_t
*rwlock
, const struct timespec
*timeout
),
1725 #endif /* VGO_solaris */
1727 static __always_inline
1728 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t
* rwlock
)
1732 VALGRIND_GET_ORIG_FN(fn
);
1733 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK
,
1734 rwlock
, 0, 0, 0, 0);
1735 CALL_FN_W_W(ret
, fn
, rwlock
);
1736 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK
,
1737 rwlock
, ret
== 0, 0, 0, 0);
1741 #if defined(VGO_solaris)
1742 /* On Solaris, pthread_rwlock_tryrdlock is a weak alias to rw_tryrdlock. */
1744 rwZutryrdlock
, pthread_rwlock_tryrdlock_intercept
,
1745 (pthread_rwlock_t
*rwlock
), (rwlock
));
1748 pthreadZurwlockZutryrdlock
, pthread_rwlock_tryrdlock_intercept
,
1749 (pthread_rwlock_t
* rwlock
), (rwlock
));
1750 #endif /* VGO_solaris */
1752 static __always_inline
1753 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t
* rwlock
)
1757 VALGRIND_GET_ORIG_FN(fn
);
1758 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK
,
1759 rwlock
, 0, 0, 0, 0);
1760 CALL_FN_W_W(ret
, fn
, rwlock
);
1761 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK
,
1762 rwlock
, ret
== 0, 0, 0, 0);
1766 #if defined(VGO_solaris)
1767 /* On Solaris, pthread_rwlock_trywrlock is a weak alias to rw_trywrlock. */
1769 rwZutrywrlock
, pthread_rwlock_trywrlock_intercept
,
1770 (pthread_rwlock_t
*rwlock
), (rwlock
));
1773 pthreadZurwlockZutrywrlock
, pthread_rwlock_trywrlock_intercept
,
1774 (pthread_rwlock_t
* rwlock
), (rwlock
));
1775 #endif /* VGO_solaris */
1777 static __always_inline
1778 int pthread_rwlock_unlock_intercept(pthread_rwlock_t
* rwlock
)
1782 VALGRIND_GET_ORIG_FN(fn
);
1783 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_UNLOCK
,
1784 rwlock
, 0, 0, 0, 0);
1785 CALL_FN_W_W(ret
, fn
, rwlock
);
1786 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_UNLOCK
,
1787 rwlock
, ret
== 0, 0, 0, 0);
1791 #if defined(VGO_solaris)
1792 /* On Solaris, pthread_rwlock_unlock is a weak alias to rw_unlock. */
1794 rwZuunlock
, pthread_rwlock_unlock_intercept
,
1795 (pthread_rwlock_t
*rwlock
), (rwlock
));
1798 pthreadZurwlockZuunlock
, pthread_rwlock_unlock_intercept
,
1799 (pthread_rwlock_t
* rwlock
), (rwlock
));
1800 #endif /* VGO_solaris */
1802 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */