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-2017 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, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
25 The GNU General Public License is contained in the file COPYING.
28 /* ---------------------------------------------------------------------
29 ALL THE CODE IN THIS FILE RUNS ON THE SIMULATED CPU.
31 These functions are not called directly - they're the targets of code
32 redirection or load notifications (see pub_core_redir.h for info).
33 They're named weirdly so that the intercept code can find them when the
34 shared object is initially loaded.
36 Note that this filename has the "drd_" prefix because it can appear
37 in stack traces, and the "drd_" makes it a little clearer that it
38 originates from Valgrind.
39 ------------------------------------------------------------------ */
42 * Define _GNU_SOURCE to make sure that pthread_spinlock_t is available when
43 * compiling with older glibc versions (2.3 or before).
49 #include <assert.h> /* assert() */
51 #include <pthread.h> /* pthread_mutex_t */
52 #include <semaphore.h> /* sem_t */
53 #include <stdint.h> /* uintptr_t */
54 #include <stdio.h> /* fprintf() */
55 #include <stdlib.h> /* malloc(), free() */
56 #include <unistd.h> /* confstr() */
57 #include "config.h" /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP etc. */
58 #include "drd_basics.h" /* DRD_() */
59 #include "drd_clientreq.h"
60 #include "pub_tool_redir.h" /* VG_WRAP_FUNCTION_ZZ() */
62 #if defined(VGO_solaris)
64 * Solaris usually provides pthread_* functions on top of Solaris threading
65 * and synchronization functions. Usually both need to be intercepted because
66 * pthread_* ones might not call the Solaris ones (see for example sem_wait()).
67 * Such approach is required to correctly report misuse of the POSIX threads
69 * Therefore DRD intercepts and instruments all such functions but due to
70 * DRD_(thread_enter_synchr)() and DRD_(thread_leave_synchr)() guards in
71 * handle_client_request(), only the top-most function is handled.
72 * So the right thing(TM) happens, as expected.
73 * The only exception is when pthread_* function is a weak alias to the Solaris
74 * threading/synchronization function. In such case only one needs to be
75 * intercepted to avoid redirection ambiguity.
77 * Intercepted functions rely on the fact that:
78 * - pthread_mutex_t == mutex_t
79 * - pthread_cond_t == cond_t
81 * - pthread_rwlock_t == rwlock_t
83 * It is necessary to intercept also internal libc synchronization functions
85 * - For read-write locks the unlocking function is shared
86 * - Functions lmutex_lock/lmutex_unlock guard many critical sections in libc
87 * which will be otherwise reported by DRD
91 #include "pub_tool_vki.h"
94 * Solaris provides higher throughput, parallelism and scalability than other
95 * operating systems, at the cost of more fine-grained locking activity.
96 * This means for example that when a thread is created under Linux, just one
97 * big lock in glibc is used for all thread setup. Solaris libc uses several
98 * fine-grained locks and the creator thread resumes its activities as soon
99 * as possible, leaving for example stack and TLS setup activities to the
102 * This situation confuses DRD as it assumes there is some false ordering
103 * in place between creator and created thread; and therefore many types of
104 * race conditions in the application would not be reported. To prevent such
105 * false ordering, command line option --ignore-thread-creation is set to
106 * 'yes' by default on Solaris. All activity (loads, stores, client requests)
107 * is therefore ignored during:
108 * - pthread_create() call in the creator thread [libc.so]
109 * - thread creation phase (stack and TLS setup) in the created thread [libc.so]
111 * As explained in the comments for _ti_bind_guard(), whenever the runtime
112 * linker has to perform any activity (such as resolving a symbol), it protects
113 * its data structures by calling into rt_bind_guard() which in turn invokes
114 * _ti_bind_guard() in libc. Pointers to _ti_bind_guard() and _ti_bind_clear()
115 * are passed from libc to runtime linker in _ld_libc() call during libc_init().
116 * All activity is also ignored during:
117 * - runtime dynamic linker work between rt_bind_guard() and rt_bind_clear()
120 * This also means that DRD does not report race conditions in libc (when
121 * --ignore-thread-creation=yes) and runtime linker itself (unconditionally)
122 * during these ignored sequences.
126 * Original function pointers for _ti_bind_guard() and _ti_bind_clear()
127 * from libc. They are intercepted in function wrapper of _ld_libc().
129 typedef int (*drd_rtld_guard_fn
)(int flags
);
130 static drd_rtld_guard_fn
DRD_(rtld_bind_guard
) = NULL
;
131 static drd_rtld_guard_fn
DRD_(rtld_bind_clear
) = NULL
;
136 * Notes regarding thread creation:
137 * - sg_init() runs on the context of the created thread and copies the vector
138 * clock of the creator thread. This only works reliably if the creator
139 * thread waits until this copy has been performed.
140 * - DRD_(thread_compute_minimum_vc)() does not take the vector clocks into
141 * account that are involved in thread creation and for which the
142 * corresponding thread has not yet been created. So not waiting until the
143 * created thread has been started would make it possible that segments get
144 * discarded that should not yet be discarded. Or: some data races are not
149 * Macro for generating a Valgrind interception function.
150 * @param[in] ret_ty Return type of the function to be generated.
151 * @param[in] zf Z-encoded name of the interception function.
152 * @param[in] implf Name of the function that implements the intercept.
153 * @param[in] arg_decl Argument declaration list enclosed in parentheses.
154 * @param[in] argl Argument list enclosed in parentheses.
157 static int never_true
;
158 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
159 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
160 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
162 ret_ty pth_func_result = implf argl; \
163 /* Apparently inserting a function call in wrapper functions */ \
164 /* is sufficient to avoid misaligned stack errors. */ \
167 return pth_func_result; \
169 #elif defined(VGO_solaris)
170 /* On Solaris, libpthread is just a filter library on top of libc.
171 * Threading and synchronization functions in runtime linker are not
174 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
175 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl; \
176 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl \
177 { return implf argl; }
179 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
180 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
181 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
182 { return implf argl; }
186 * Macro for generating three Valgrind interception functions: one with the
187 * Z-encoded name zf, one with ZAZa ("@*") appended to the name zf and one
188 * with ZDZa ("$*") appended to the name zf. The second generated interception
189 * function will intercept versioned symbols on Linux, and the third will
190 * intercept versioned symbols on Darwin.
192 #define PTH_FUNCS(ret_ty, zf, implf, argl_decl, argl) \
193 PTH_FUNC(ret_ty, zf, implf, argl_decl, argl); \
194 PTH_FUNC(ret_ty, zf ## ZAZa, implf, argl_decl, argl); \
195 PTH_FUNC(ret_ty, zf ## ZDZa, implf, argl_decl, argl);
198 * Not inlining one of the intercept functions will cause the regression
199 * tests to fail because this would cause an additional stackfram to appear
200 * in the output. The __always_inline macro guarantees that inlining will
201 * happen, even when compiling with optimization disabled.
203 #undef __always_inline /* since already defined in <cdefs.h> */
204 #if __GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 2
205 #define __always_inline __inline__ __attribute__((always_inline))
207 #define __always_inline __inline__
210 /* Local data structures. */
213 pthread_mutex_t mutex
;
220 void* (*start
)(void*);
223 DrdSema
* wrapper_started
;
224 } DrdPosixThreadArgs
;
227 /* Local function declarations. */
229 static void DRD_(init
)(void) __attribute__((constructor
));
230 static void DRD_(check_threading_library
)(void);
231 static void DRD_(set_pthread_id
)(void);
232 static void DRD_(sema_init
)(DrdSema
* sema
);
233 static void DRD_(sema_destroy
)(DrdSema
* sema
);
234 static void DRD_(sema_down
)(DrdSema
* sema
);
235 static void DRD_(sema_up
)(DrdSema
* sema
);
238 /* Function definitions. */
241 * Shared library initialization function. The function init() is called after
242 * dlopen() has loaded the shared library with DRD client intercepts because
243 * the constructor attribute was specified in the declaration of this function.
244 * Note: do specify the -nostdlib option to gcc when linking this code into a
245 * shared library because doing so would cancel the effect of the constructor
246 * attribute ! Using the gcc option -nodefaultlibs is fine because this last
247 * option preserves the shared library initialization code that calls
248 * constructor and destructor functions.
250 static void DRD_(init
)(void)
252 DRD_(check_threading_library
)();
253 DRD_(set_pthread_id
)();
254 #if defined(VGO_solaris)
255 if ((DRD_(rtld_bind_guard
) == NULL
) || (DRD_(rtld_bind_clear
) == NULL
)) {
257 "Bind guard functions for the runtime linker (ld.so.1) were not intercepted.\n"
258 "This means the interface between libc and runtime linker changed and DRD\n"
259 "needs to be ported properly. Giving up.\n");
265 static __always_inline
void DRD_(ignore_mutex_ordering
)(pthread_mutex_t
*mutex
)
267 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_IGNORE_MUTEX_ORDERING
,
271 static void DRD_(sema_init
)(DrdSema
* sema
)
273 DRD_IGNORE_VAR(*sema
);
274 pthread_mutex_init(&sema
->mutex
, NULL
);
275 DRD_(ignore_mutex_ordering
)(&sema
->mutex
);
276 pthread_cond_init(&sema
->cond
, NULL
);
280 static void DRD_(sema_destroy
)(DrdSema
* sema
)
282 pthread_mutex_destroy(&sema
->mutex
);
283 pthread_cond_destroy(&sema
->cond
);
286 static void DRD_(sema_down
)(DrdSema
* sema
)
288 pthread_mutex_lock(&sema
->mutex
);
289 while (sema
->counter
== 0)
290 pthread_cond_wait(&sema
->cond
, &sema
->mutex
);
292 pthread_mutex_unlock(&sema
->mutex
);
295 static void DRD_(sema_up
)(DrdSema
* sema
)
297 pthread_mutex_lock(&sema
->mutex
);
299 pthread_cond_signal(&sema
->cond
);
300 pthread_mutex_unlock(&sema
->mutex
);
304 * POSIX threads and DRD each have their own mutex type identification.
305 * Convert POSIX threads' mutex type to DRD's mutex type. In the code below
306 * if-statements are used to test the value of 'kind' instead of a switch
307 * statement because some of the PTHREAD_MUTEX_ macro's may have the same
310 static MutexT
DRD_(pthread_to_drd_mutex_type
)(int kind
)
313 * See also PTHREAD_MUTEX_KIND_MASK_NP in glibc source file
316 kind
&= PTHREAD_MUTEX_RECURSIVE
| PTHREAD_MUTEX_ERRORCHECK
|
317 PTHREAD_MUTEX_NORMAL
| PTHREAD_MUTEX_DEFAULT
;
319 if (kind
== PTHREAD_MUTEX_RECURSIVE
)
320 return mutex_type_recursive_mutex
;
321 else if (kind
== PTHREAD_MUTEX_ERRORCHECK
)
322 return mutex_type_errorcheck_mutex
;
323 else if (kind
== PTHREAD_MUTEX_NORMAL
)
324 return mutex_type_default_mutex
;
325 else if (kind
== PTHREAD_MUTEX_DEFAULT
)
326 return mutex_type_default_mutex
;
327 #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
328 else if (kind
== PTHREAD_MUTEX_ADAPTIVE_NP
)
329 return mutex_type_default_mutex
;
332 return mutex_type_invalid_mutex
;
335 #if defined(VGO_solaris)
337 * Solaris threads and DRD each have their own mutex type identification.
338 * Convert Solaris threads' mutex type to DRD's mutex type.
340 static MutexT
DRD_(thread_to_drd_mutex_type
)(int type
)
342 if (type
& LOCK_RECURSIVE
) {
343 return mutex_type_recursive_mutex
;
344 } else if (type
& LOCK_ERRORCHECK
) {
345 return mutex_type_errorcheck_mutex
;
347 return mutex_type_default_mutex
;
350 #endif /* VGO_solaris */
352 #define IS_ALIGNED(p) (((uintptr_t)(p) & (sizeof(*(p)) - 1)) == 0)
355 * Read the mutex type stored in the client memory used for the mutex
358 * @note This function depends on the implementation of the POSIX threads
359 * library -- the POSIX standard does not define the name of the member in
360 * which the mutex type is stored.
361 * @note The function mutex_type() has been declared inline in order
362 * to avoid that it shows up in call stacks (drd/tests/...exp* files).
363 * @note glibc stores the mutex type in the lowest two bits, and uses the
364 * higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
365 * PTHREAD_MUTEXATTR_FLAG_PSHARED.
367 static __always_inline MutexT
DRD_(mutex_type
)(pthread_mutex_t
* mutex
)
369 #if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
370 /* glibc + LinuxThreads. */
371 if (IS_ALIGNED(&mutex
->__m_kind
))
373 const int kind
= mutex
->__m_kind
& 3;
374 return DRD_(pthread_to_drd_mutex_type
)(kind
);
376 #elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
378 if (IS_ALIGNED(&mutex
->__data
.__kind
))
380 const int kind
= mutex
->__data
.__kind
& 3;
381 return DRD_(pthread_to_drd_mutex_type
)(kind
);
383 #elif defined(VGO_solaris)
384 const int type
= ((mutex_t
*) mutex
)->vki_mutex_type
;
385 return DRD_(thread_to_drd_mutex_type
)(type
);
388 * Another POSIX threads implementation. The mutex type won't be printed
389 * when enabling --trace-mutex=yes.
392 return mutex_type_unknown
;
396 * Tell DRD whether 'tid' is a joinable thread or a detached thread.
398 static void DRD_(set_joinable
)(const pthread_t tid
, const int joinable
)
400 assert(joinable
== 0 || joinable
== 1);
401 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_JOINABLE
,
402 tid
, joinable
, 0, 0, 0);
405 /** Tell DRD that the calling thread is about to enter pthread_create(). */
406 static __always_inline
void DRD_(entering_pthread_create
)(void)
408 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__ENTERING_PTHREAD_CREATE
,
412 /** Tell DRD that the calling thread has left pthread_create(). */
413 static __always_inline
void DRD_(left_pthread_create
)(void)
415 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LEFT_PTHREAD_CREATE
,
420 * Entry point for newly created threads. This function is called from the
421 * thread created by pthread_create().
423 static void* DRD_(thread_wrapper
)(void* arg
)
425 DrdPosixThreadArgs
* arg_ptr
;
426 DrdPosixThreadArgs arg_copy
;
428 arg_ptr
= (DrdPosixThreadArgs
*)arg
;
431 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID
,
432 pthread_self(), 0, 0, 0, 0);
434 DRD_(set_joinable
)(pthread_self(),
435 arg_copy
.detachstate
== PTHREAD_CREATE_JOINABLE
);
438 * Only set 'wrapper_started' after VG_USERREQ__SET_PTHREADID and
439 * DRD_(set_joinable)() have been invoked to avoid a race with
440 * a pthread_detach() invocation for this thread from another thread.
442 DRD_(sema_up
)(arg_copy
.wrapper_started
);
444 return (arg_copy
.start
)(arg_copy
.arg
);
448 * Return 1 if the LinuxThreads implementation of POSIX Threads has been
449 * detected, and 0 otherwise.
451 * @see For more information about the confstr() function, see also
452 * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
454 static int DRD_(detected_linuxthreads
)(void)
457 #if defined(_CS_GNU_LIBPTHREAD_VERSION)
458 /* Linux with a recent glibc. */
461 len
= confstr(_CS_GNU_LIBPTHREAD_VERSION
, buffer
, sizeof(buffer
));
462 assert(len
<= sizeof(buffer
));
463 return len
> 0 && buffer
[0] == 'l';
465 /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
469 /* Another OS than Linux, hence no LinuxThreads. */
475 * Stop and print an error message in case a non-supported threading
476 * library implementation (LinuxThreads) has been detected.
478 static void DRD_(check_threading_library
)(void)
480 if (DRD_(detected_linuxthreads
)())
482 if (getenv("LD_ASSUME_KERNEL"))
485 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
486 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
487 "after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
493 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
494 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
495 "after having upgraded to a newer version of your Linux distribution.\n"
504 * Update DRD's state information about the current thread.
506 static void DRD_(set_pthread_id
)(void)
508 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID
,
509 pthread_self(), 0, 0, 0, 0);
513 * Note: as of today there exist three different versions of pthread_create
515 * - pthread_create@GLIBC_2.0
516 * - pthread_create@@GLIBC_2.1
517 * - pthread_create@@GLIBC_2.2.5
518 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
519 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
520 * versions have been implemented. In any glibc version where more than one
521 * pthread_create function has been implemented, older versions call the
522 * newer versions. Or: the pthread_create* wrapper defined below can be
523 * called recursively. Any code in this wrapper should take this in account.
524 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
525 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
526 * See also the implementation of pthread_create@GLIBC_2.0 in
527 * glibc-2.9/nptl/pthread_create.c.
530 static __always_inline
531 int pthread_create_intercept(pthread_t
* thread
, const pthread_attr_t
* attr
,
532 void* (*start
)(void*), void* arg
)
536 DrdSema wrapper_started
;
537 DrdPosixThreadArgs thread_args
;
539 VALGRIND_GET_ORIG_FN(fn
);
541 DRD_(sema_init
)(&wrapper_started
);
542 thread_args
.start
= start
;
543 thread_args
.arg
= arg
;
544 thread_args
.wrapper_started
= &wrapper_started
;
546 * Find out whether the thread will be started as a joinable thread
547 * or as a detached thread. If no thread attributes have been specified,
548 * this means that the new thread will be started as a joinable thread.
550 thread_args
.detachstate
= PTHREAD_CREATE_JOINABLE
;
553 if (pthread_attr_getdetachstate(attr
, &thread_args
.detachstate
) != 0)
556 assert(thread_args
.detachstate
== PTHREAD_CREATE_JOINABLE
557 || thread_args
.detachstate
== PTHREAD_CREATE_DETACHED
);
560 * The DRD_(set_pthread_id)() from DRD_(init)() may encounter that
561 * pthread_self() == 0, e.g. when the main program is not linked with the
562 * pthread library and when a pthread_create() call occurs from within a
563 * shared library. Hence call DRD_(set_pthread_id)() again to ensure that
564 * DRD knows the identity of the current thread. See also B.Z. 356374.
566 DRD_(set_pthread_id
)();
567 DRD_(entering_pthread_create
)();
568 CALL_FN_W_WWWW(ret
, fn
, thread
, attr
, DRD_(thread_wrapper
), &thread_args
);
569 DRD_(left_pthread_create
)();
572 /* Wait until the thread wrapper started. */
573 DRD_(sema_down
)(&wrapper_started
);
576 DRD_(sema_destroy
)(&wrapper_started
);
578 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT
,
579 pthread_self(), 0, 0, 0, 0);
584 PTH_FUNCS(int, pthreadZucreate
, pthread_create_intercept
,
585 (pthread_t
*thread
, const pthread_attr_t
*attr
,
586 void *(*start
) (void *), void *arg
),
587 (thread
, attr
, start
, arg
));
589 #if defined(VGO_solaris)
590 /* Solaris also provides thr_create() in addition to pthread_create().
591 * Both pthread_create(3C) and thr_create(3C) are based on private
594 static __always_inline
595 int thr_create_intercept(void *stk
, size_t stksize
, void *(*start
)(void *),
596 void *arg
, long flags
, thread_t
*new_thread
)
600 DrdSema wrapper_started
;
601 DrdPosixThreadArgs thread_args
;
603 VALGRIND_GET_ORIG_FN(fn
);
605 DRD_(sema_init
)(&wrapper_started
);
606 thread_args
.start
= start
;
607 thread_args
.arg
= arg
;
608 thread_args
.wrapper_started
= &wrapper_started
;
610 * Find out whether the thread will be started as a joinable thread
611 * or as a detached thread.
613 if (flags
& THR_DETACHED
)
614 thread_args
.detachstate
= PTHREAD_CREATE_DETACHED
;
616 thread_args
.detachstate
= PTHREAD_CREATE_JOINABLE
;
618 DRD_(entering_pthread_create
)();
619 CALL_FN_W_6W(ret
, fn
, stk
, stksize
, DRD_(thread_wrapper
), &thread_args
,
621 DRD_(left_pthread_create
)();
624 /* Wait until the thread wrapper started. */
625 DRD_(sema_down
)(&wrapper_started
);
628 DRD_(sema_destroy
)(&wrapper_started
);
630 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT
,
631 pthread_self(), 0, 0, 0, 0);
636 PTH_FUNCS(int, thrZucreate
, thr_create_intercept
,
637 (void *stk
, size_t stksize
, void *(*start
)(void *), void *arg
,
638 long flags
, thread_t
*new_thread
),
639 (stk
, stksize
, start
, arg
, flags
, new_thread
));
640 #endif /* VGO_solaris */
642 #if defined(VGO_solaris)
644 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
645 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
646 * and CI_BIND_CLEAR, to provide resilience against function renaming.
648 static __always_inline
649 int DRD_(_ti_bind_guard_intercept
)(int flags
) {
650 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_GUARD
,
652 return DRD_(rtld_bind_guard
)(flags
);
655 static __always_inline
656 int DRD_(_ti_bind_clear_intercept
)(int flags
) {
657 int ret
= DRD_(rtld_bind_clear
)(flags
);
658 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_CLEAR
,
664 * Wrapped _ld_libc() from the runtime linker ld.so.1.
666 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1
, ZuldZulibc
)(vki_Lc_interface
*ptr
);
667 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1
, ZuldZulibc
)(vki_Lc_interface
*ptr
)
672 VALGRIND_GET_ORIG_FN(fn
);
674 vki_Lc_interface
*funcs
= ptr
;
675 for (tag
= funcs
->ci_tag
; tag
!= 0; tag
= (++funcs
)->ci_tag
) {
677 case VKI_CI_BIND_GUARD
:
678 if (funcs
->vki_ci_un
.ci_func
!= DRD_(_ti_bind_guard_intercept
)) {
679 DRD_(rtld_bind_guard
) = funcs
->vki_ci_un
.ci_func
;
680 funcs
->vki_ci_un
.ci_func
= DRD_(_ti_bind_guard_intercept
);
683 case VKI_CI_BIND_CLEAR
:
684 if (funcs
->vki_ci_un
.ci_func
!= DRD_(_ti_bind_clear_intercept
)) {
685 DRD_(rtld_bind_clear
) = funcs
->vki_ci_un
.ci_func
;
686 funcs
->vki_ci_un
.ci_func
= DRD_(_ti_bind_clear_intercept
);
692 CALL_FN_v_W(fn
, ptr
);
694 #endif /* VGO_solaris */
696 static __always_inline
697 int pthread_join_intercept(pthread_t pt_joinee
, void **thread_return
)
702 VALGRIND_GET_ORIG_FN(fn
);
704 * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
705 * implementation triggers a (false positive) race report.
707 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
708 CALL_FN_W_WW(ret
, fn
, pt_joinee
, thread_return
);
711 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN
,
712 pt_joinee
, 0, 0, 0, 0);
714 ANNOTATE_IGNORE_READS_AND_WRITES_END();
718 PTH_FUNCS(int, pthreadZujoin
, pthread_join_intercept
,
719 (pthread_t pt_joinee
, void **thread_return
),
720 (pt_joinee
, thread_return
));
722 #if defined(VGO_solaris)
723 /* Solaris also provides thr_join() in addition to pthread_join().
724 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
726 * :TODO: No functionality is currently provided for joinee == 0 and departed.
727 * This would require another client request, of course.
729 static __always_inline
730 int thr_join_intercept(thread_t joinee
, thread_t
*departed
, void **thread_return
)
735 VALGRIND_GET_ORIG_FN(fn
);
736 CALL_FN_W_WWW(ret
, fn
, joinee
, departed
, thread_return
);
739 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN
,
745 PTH_FUNCS(int, thrZujoin
, thr_join_intercept
,
746 (thread_t joinee
, thread_t
*departed
, void **thread_return
),
747 (joinee
, departed
, thread_return
));
748 #endif /* VGO_solaris */
750 static __always_inline
751 int pthread_detach_intercept(pthread_t pt_thread
)
756 VALGRIND_GET_ORIG_FN(fn
);
757 CALL_FN_W_W(ret
, fn
, pt_thread
);
758 DRD_(set_joinable
)(pt_thread
, 0);
763 PTH_FUNCS(int, pthreadZudetach
, pthread_detach_intercept
,
764 (pthread_t thread
), (thread
));
766 // NOTE: be careful to intercept only pthread_cancel() and not
767 // pthread_cancel_init() on Linux.
769 static __always_inline
770 int pthread_cancel_intercept(pthread_t pt_thread
)
774 VALGRIND_GET_ORIG_FN(fn
);
775 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_THREAD_CANCEL
,
776 pt_thread
, 0, 0, 0, 0);
777 CALL_FN_W_W(ret
, fn
, pt_thread
);
778 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_CANCEL
,
779 pt_thread
, ret
==0, 0, 0, 0);
783 PTH_FUNCS(int, pthreadZucancel
, pthread_cancel_intercept
,
784 (pthread_t thread
), (thread
))
786 static __always_inline
787 int pthread_once_intercept(pthread_once_t
*once_control
,
788 void (*init_routine
)(void))
792 VALGRIND_GET_ORIG_FN(fn
);
794 * Ignore any data races triggered by the implementation of pthread_once().
795 * Necessary for Darwin. This is not necessary for Linux but doesn't have
796 * any known adverse effects.
798 DRD_IGNORE_VAR(*once_control
);
799 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
800 CALL_FN_W_WW(ret
, fn
, once_control
, init_routine
);
801 ANNOTATE_IGNORE_READS_AND_WRITES_END();
802 DRD_STOP_IGNORING_VAR(*once_control
);
806 PTH_FUNCS(int, pthreadZuonce
, pthread_once_intercept
,
807 (pthread_once_t
*once_control
, void (*init_routine
)(void)),
808 (once_control
, init_routine
));
810 static __always_inline
811 int pthread_mutex_init_intercept(pthread_mutex_t
*mutex
,
812 const pthread_mutexattr_t
* attr
)
817 VALGRIND_GET_ORIG_FN(fn
);
818 mt
= PTHREAD_MUTEX_DEFAULT
;
820 pthread_mutexattr_gettype(attr
, &mt
);
821 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT
,
822 mutex
, DRD_(pthread_to_drd_mutex_type
)(mt
),
824 CALL_FN_W_WW(ret
, fn
, mutex
, attr
);
825 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT
,
830 PTH_FUNCS(int, pthreadZumutexZuinit
, pthread_mutex_init_intercept
,
831 (pthread_mutex_t
*mutex
, const pthread_mutexattr_t
* attr
),
834 #if defined(VGO_solaris)
835 static __always_inline
836 int mutex_init_intercept(mutex_t
*mutex
, int type
, void *arg
)
840 VALGRIND_GET_ORIG_FN(fn
);
842 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT
,
843 mutex
, DRD_(thread_to_drd_mutex_type
)(type
),
845 CALL_FN_W_WWW(ret
, fn
, mutex
, type
, arg
);
846 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT
,
851 PTH_FUNCS(int, mutexZuinit
, mutex_init_intercept
,
852 (mutex_t
*mutex
, int type
, void *arg
),
854 #endif /* VGO_solaris */
856 static __always_inline
857 int pthread_mutex_destroy_intercept(pthread_mutex_t
* mutex
)
861 VALGRIND_GET_ORIG_FN(fn
);
862 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY
,
864 CALL_FN_W_W(ret
, fn
, mutex
);
865 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY
,
866 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
870 #if defined(VGO_solaris)
871 /* On Solaris, pthread_mutex_destroy is a weak alias to mutex_destroy. */
872 PTH_FUNCS(int, mutexZudestroy
, pthread_mutex_destroy_intercept
,
873 (pthread_mutex_t
*mutex
), (mutex
));
875 PTH_FUNCS(int, pthreadZumutexZudestroy
, pthread_mutex_destroy_intercept
,
876 (pthread_mutex_t
*mutex
), (mutex
));
877 #endif /* VGO_solaris */
879 static __always_inline
880 int pthread_mutex_lock_intercept(pthread_mutex_t
* mutex
)
884 VALGRIND_GET_ORIG_FN(fn
);
885 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
886 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
887 CALL_FN_W_W(ret
, fn
, mutex
);
888 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
889 mutex
, ret
== 0, 0, 0, 0);
893 #if defined(VGO_solaris)
894 /* On Solaris, pthread_mutex_lock is a weak alias to mutex_lock. */
895 PTH_FUNCS(int, mutexZulock
, pthread_mutex_lock_intercept
,
896 (pthread_mutex_t
*mutex
), (mutex
));
898 PTH_FUNCS(int, pthreadZumutexZulock
, pthread_mutex_lock_intercept
,
899 (pthread_mutex_t
*mutex
), (mutex
));
900 #endif /* VGO_solaris */
902 #if defined(VGO_solaris)
903 /* Internal to libc. Mutex is usually initialized only implicitly,
904 * by zeroing mutex_t structure.
906 static __always_inline
907 void lmutex_lock_intercept(mutex_t
*mutex
)
910 VALGRIND_GET_ORIG_FN(fn
);
911 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
913 DRD_(mutex_type
)((pthread_mutex_t
*) mutex
),
914 False
/* try_lock */, 0, 0);
915 CALL_FN_v_W(fn
, mutex
);
916 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
917 mutex
, True
/* took_lock */, 0, 0, 0);
920 PTH_FUNCS(void, lmutexZulock
, lmutex_lock_intercept
,
921 (mutex_t
*mutex
), (mutex
));
922 #endif /* VGO_solaris */
924 static __always_inline
925 int pthread_mutex_trylock_intercept(pthread_mutex_t
* mutex
)
929 VALGRIND_GET_ORIG_FN(fn
);
930 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
931 mutex
, DRD_(mutex_type
)(mutex
), 1, 0, 0);
932 CALL_FN_W_W(ret
, fn
, mutex
);
933 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
934 mutex
, ret
== 0, 0, 0, 0);
938 #if defined(VGO_solaris)
939 /* On Solaris, pthread_mutex_trylock is a weak alias to mutex_trylock. */
940 PTH_FUNCS(int, mutexZutrylock
, pthread_mutex_trylock_intercept
,
941 (pthread_mutex_t
*mutex
), (mutex
));
943 PTH_FUNCS(int, pthreadZumutexZutrylock
, pthread_mutex_trylock_intercept
,
944 (pthread_mutex_t
*mutex
), (mutex
));
945 #endif /* VGO_solaris */
947 static __always_inline
948 int pthread_mutex_timedlock_intercept(pthread_mutex_t
*mutex
,
949 const struct timespec
*abs_timeout
)
953 VALGRIND_GET_ORIG_FN(fn
);
954 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
955 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
956 CALL_FN_W_WW(ret
, fn
, mutex
, abs_timeout
);
957 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
958 mutex
, ret
== 0, 0, 0, 0);
962 PTH_FUNCS(int, pthreadZumutexZutimedlock
, pthread_mutex_timedlock_intercept
,
963 (pthread_mutex_t
*mutex
, const struct timespec
*abs_timeout
),
964 (mutex
, abs_timeout
));
965 #if defined(VGO_solaris)
967 pthreadZumutexZureltimedlockZunp
, pthread_mutex_timedlock_intercept
,
968 (pthread_mutex_t
*mutex
, const struct timespec
*timeout
),
970 #endif /* VGO_solaris */
972 static __always_inline
973 int pthread_mutex_unlock_intercept(pthread_mutex_t
*mutex
)
977 VALGRIND_GET_ORIG_FN(fn
);
978 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK
,
979 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
980 CALL_FN_W_W(ret
, fn
, mutex
);
981 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK
,
986 #if defined(VGO_solaris)
987 /* On Solaris, pthread_mutex_unlock is a weak alias to mutex_unlock. */
988 PTH_FUNCS(int, mutexZuunlock
, pthread_mutex_unlock_intercept
,
989 (pthread_mutex_t
*mutex
), (mutex
));
991 PTH_FUNCS(int, pthreadZumutexZuunlock
, pthread_mutex_unlock_intercept
,
992 (pthread_mutex_t
*mutex
), (mutex
));
993 #endif /* VGO_solaris */
995 #if defined(VGO_solaris)
996 /* Internal to libc. */
997 static __always_inline
998 void lmutex_unlock_intercept(mutex_t
*mutex
)
1001 VALGRIND_GET_ORIG_FN(fn
);
1002 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK
,
1004 DRD_(mutex_type
)((pthread_mutex_t
*) mutex
),
1006 CALL_FN_v_W(fn
, mutex
);
1007 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK
,
1011 PTH_FUNCS(void, lmutexZuunlock
, lmutex_unlock_intercept
,
1012 (mutex_t
*mutex
), (mutex
));
1013 #endif /* VGO_solaris */
1015 static __always_inline
1016 int pthread_cond_init_intercept(pthread_cond_t
* cond
,
1017 const pthread_condattr_t
* attr
)
1021 VALGRIND_GET_ORIG_FN(fn
);
1022 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT
,
1024 CALL_FN_W_WW(ret
, fn
, cond
, attr
);
1025 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT
,
1030 PTH_FUNCS(int, pthreadZucondZuinit
, pthread_cond_init_intercept
,
1031 (pthread_cond_t
* cond
, const pthread_condattr_t
* attr
),
1034 #if defined(VGO_solaris)
1035 static __always_inline
1036 int cond_init_intercept(cond_t
*cond
, int type
, void *arg
)
1040 VALGRIND_GET_ORIG_FN(fn
);
1041 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT
,
1043 CALL_FN_W_WWW(ret
, fn
, cond
, type
, arg
);
1044 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT
,
1049 PTH_FUNCS(int, condZuinit
, cond_init_intercept
,
1050 (cond_t
*cond
, int type
, void *arg
),
1052 #endif /* VGO_solaris */
1054 static __always_inline
1055 int pthread_cond_destroy_intercept(pthread_cond_t
* cond
)
1059 VALGRIND_GET_ORIG_FN(fn
);
1060 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_DESTROY
,
1062 CALL_FN_W_W(ret
, fn
, cond
);
1063 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_DESTROY
,
1064 cond
, ret
==0, 0, 0, 0);
1068 #if defined(VGO_solaris)
1069 /* On Solaris, pthread_cond_destroy is a weak alias to cond_destroy. */
1070 PTH_FUNCS(int, condZudestroy
, pthread_cond_destroy_intercept
,
1071 (pthread_cond_t
*cond
), (cond
));
1073 PTH_FUNCS(int, pthreadZucondZudestroy
, pthread_cond_destroy_intercept
,
1074 (pthread_cond_t
* cond
), (cond
));
1075 #endif /* VGO_solaris */
1077 static __always_inline
1078 int pthread_cond_wait_intercept(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
1082 VALGRIND_GET_ORIG_FN(fn
);
1083 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT
,
1084 cond
, mutex
, DRD_(mutex_type
)(mutex
), 0, 0);
1085 CALL_FN_W_WW(ret
, fn
, cond
, mutex
);
1086 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT
,
1087 cond
, mutex
, 1, 0, 0);
1091 PTH_FUNCS(int, pthreadZucondZuwait
, pthread_cond_wait_intercept
,
1092 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
),
1094 #if defined(VGO_solaris)
1095 PTH_FUNCS(int, condZuwait
, pthread_cond_wait_intercept
,
1096 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
),
1098 #endif /* VGO_solaris */
1100 static __always_inline
1101 int pthread_cond_timedwait_intercept(pthread_cond_t
*cond
,
1102 pthread_mutex_t
*mutex
,
1103 const struct timespec
* abstime
)
1107 VALGRIND_GET_ORIG_FN(fn
);
1108 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT
,
1109 cond
, mutex
, DRD_(mutex_type
)(mutex
), 0, 0);
1110 CALL_FN_W_WWW(ret
, fn
, cond
, mutex
, abstime
);
1111 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT
,
1112 cond
, mutex
, 1, 0, 0);
1116 PTH_FUNCS(int, pthreadZucondZutimedwait
, pthread_cond_timedwait_intercept
,
1117 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1118 const struct timespec
* abstime
),
1119 (cond
, mutex
, abstime
));
1120 #if defined(VGO_solaris)
1121 PTH_FUNCS(int, condZutimedwait
, pthread_cond_timedwait_intercept
,
1122 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1123 const struct timespec
*timeout
),
1124 (cond
, mutex
, timeout
));
1125 PTH_FUNCS(int, condZureltimedwait
, pthread_cond_timedwait_intercept
,
1126 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1127 const struct timespec
*timeout
),
1128 (cond
, mutex
, timeout
));
1129 #endif /* VGO_solaris */
1131 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
1132 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
1133 // two. Intercepting all pthread_cond_signal* functions will cause only one
1134 // argument to be passed to pthread_cond_signal_np() and hence will cause this
1135 // last function to crash.
1137 static __always_inline
1138 int pthread_cond_signal_intercept(pthread_cond_t
* cond
)
1142 VALGRIND_GET_ORIG_FN(fn
);
1143 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_SIGNAL
,
1145 CALL_FN_W_W(ret
, fn
, cond
);
1146 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_SIGNAL
,
1151 #if defined(VGO_solaris)
1152 /* On Solaris, pthread_cond_signal is a weak alias to cond_signal. */
1153 PTH_FUNCS(int, condZusignal
, pthread_cond_signal_intercept
,
1154 (pthread_cond_t
*cond
), (cond
));
1156 PTH_FUNCS(int, pthreadZucondZusignal
, pthread_cond_signal_intercept
,
1157 (pthread_cond_t
* cond
), (cond
));
1158 #endif /* VGO_solaris */
1160 static __always_inline
1161 int pthread_cond_broadcast_intercept(pthread_cond_t
* cond
)
1165 VALGRIND_GET_ORIG_FN(fn
);
1166 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_BROADCAST
,
1168 CALL_FN_W_W(ret
, fn
, cond
);
1169 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_BROADCAST
,
1174 #if defined(VGO_solaris)
1175 /* On Solaris, pthread_cond_broadcast is a weak alias to cond_broadcast. */
1176 PTH_FUNCS(int, condZubroadcast
, pthread_cond_broadcast_intercept
,
1177 (pthread_cond_t
*cond
), (cond
));
1179 PTH_FUNCS(int, pthreadZucondZubroadcast
, pthread_cond_broadcast_intercept
,
1180 (pthread_cond_t
* cond
), (cond
));
1181 #endif /* VGO_solaris */
1183 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1184 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1185 static __always_inline
1186 int pthread_spin_init_intercept(pthread_spinlock_t
*spinlock
, int pshared
)
1190 VALGRIND_GET_ORIG_FN(fn
);
1191 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK
,
1192 spinlock
, 0, 0, 0, 0);
1193 CALL_FN_W_WW(ret
, fn
, spinlock
, pshared
);
1194 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK
,
1195 spinlock
, 0, 0, 0, 0);
1199 PTH_FUNCS(int, pthreadZuspinZuinit
, pthread_spin_init_intercept
,
1200 (pthread_spinlock_t
*spinlock
, int pshared
), (spinlock
, pshared
));
1202 static __always_inline
1203 int pthread_spin_destroy_intercept(pthread_spinlock_t
*spinlock
)
1207 VALGRIND_GET_ORIG_FN(fn
);
1208 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY
,
1209 spinlock
, 0, 0, 0, 0);
1210 CALL_FN_W_W(ret
, fn
, spinlock
);
1211 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY
,
1212 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1216 PTH_FUNCS(int, pthreadZuspinZudestroy
, pthread_spin_destroy_intercept
,
1217 (pthread_spinlock_t
*spinlock
), (spinlock
));
1219 static __always_inline
1220 int pthread_spin_lock_intercept(pthread_spinlock_t
*spinlock
)
1224 VALGRIND_GET_ORIG_FN(fn
);
1225 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
1226 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1227 CALL_FN_W_W(ret
, fn
, spinlock
);
1228 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
1229 spinlock
, ret
== 0, 0, 0, 0);
1233 PTH_FUNCS(int, pthreadZuspinZulock
, pthread_spin_lock_intercept
,
1234 (pthread_spinlock_t
*spinlock
), (spinlock
));
1236 static __always_inline
1237 int pthread_spin_trylock_intercept(pthread_spinlock_t
*spinlock
)
1241 VALGRIND_GET_ORIG_FN(fn
);
1242 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
1243 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1244 CALL_FN_W_W(ret
, fn
, spinlock
);
1245 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
1246 spinlock
, ret
== 0, 0, 0, 0);
1250 PTH_FUNCS(int, pthreadZuspinZutrylock
, pthread_spin_trylock_intercept
,
1251 (pthread_spinlock_t
*spinlock
), (spinlock
));
1253 static __always_inline
1254 int pthread_spin_unlock_intercept(pthread_spinlock_t
*spinlock
)
1258 VALGRIND_GET_ORIG_FN(fn
);
1259 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK
,
1260 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1261 CALL_FN_W_W(ret
, fn
, spinlock
);
1262 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK
,
1263 spinlock
, 0, 0, 0, 0);
1267 PTH_FUNCS(int, pthreadZuspinZuunlock
, pthread_spin_unlock_intercept
,
1268 (pthread_spinlock_t
*spinlock
), (spinlock
));
1269 #endif // HAVE_PTHREAD_SPIN_LOCK
1272 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1273 static __always_inline
1274 int pthread_barrier_init_intercept(pthread_barrier_t
* barrier
,
1275 const pthread_barrierattr_t
* attr
,
1280 VALGRIND_GET_ORIG_FN(fn
);
1281 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_INIT
,
1282 barrier
, pthread_barrier
, count
, 0, 0);
1283 CALL_FN_W_WWW(ret
, fn
, barrier
, attr
, count
);
1284 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_INIT
,
1285 barrier
, pthread_barrier
, 0, 0, 0);
1289 PTH_FUNCS(int, pthreadZubarrierZuinit
, pthread_barrier_init_intercept
,
1290 (pthread_barrier_t
* barrier
, const pthread_barrierattr_t
* attr
,
1291 unsigned count
), (barrier
, attr
, count
));
1293 static __always_inline
1294 int pthread_barrier_destroy_intercept(pthread_barrier_t
* barrier
)
1298 VALGRIND_GET_ORIG_FN(fn
);
1299 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_DESTROY
,
1300 barrier
, pthread_barrier
, 0, 0, 0);
1301 CALL_FN_W_W(ret
, fn
, barrier
);
1302 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_DESTROY
,
1303 barrier
, pthread_barrier
, 0, 0, 0);
1307 PTH_FUNCS(int, pthreadZubarrierZudestroy
, pthread_barrier_destroy_intercept
,
1308 (pthread_barrier_t
* barrier
), (barrier
));
1310 static __always_inline
1311 int pthread_barrier_wait_intercept(pthread_barrier_t
* barrier
)
1315 VALGRIND_GET_ORIG_FN(fn
);
1316 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_WAIT
,
1317 barrier
, pthread_barrier
, 0, 0, 0);
1318 CALL_FN_W_W(ret
, fn
, barrier
);
1319 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_WAIT
,
1320 barrier
, pthread_barrier
,
1321 ret
== 0 || ret
== PTHREAD_BARRIER_SERIAL_THREAD
,
1322 ret
== PTHREAD_BARRIER_SERIAL_THREAD
, 0);
1326 PTH_FUNCS(int, pthreadZubarrierZuwait
, pthread_barrier_wait_intercept
,
1327 (pthread_barrier_t
* barrier
), (barrier
));
1328 #endif // HAVE_PTHREAD_BARRIER_INIT
1331 static __always_inline
1332 int sem_init_intercept(sem_t
*sem
, int pshared
, unsigned int value
)
1336 VALGRIND_GET_ORIG_FN(fn
);
1337 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT
,
1338 sem
, pshared
, value
, 0, 0);
1339 CALL_FN_W_WWW(ret
, fn
, sem
, pshared
, value
);
1340 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT
,
1345 PTH_FUNCS(int, semZuinit
, sem_init_intercept
,
1346 (sem_t
*sem
, int pshared
, unsigned int value
), (sem
, pshared
, value
));
1348 #if defined(VGO_solaris)
1349 static __always_inline
1350 int sema_init_intercept(sema_t
*sem
, unsigned int value
, int type
, void *arg
)
1354 VALGRIND_GET_ORIG_FN(fn
);
1355 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT
,
1356 sem
, type
== USYNC_PROCESS
? 1 : 0,
1358 CALL_FN_W_WWWW(ret
, fn
, sem
, value
, type
, arg
);
1359 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT
,
1364 PTH_FUNCS(int, semaZuinit
, sema_init_intercept
,
1365 (sema_t
*sem
, unsigned int value
, int type
, void *arg
),
1366 (sem
, value
, type
, arg
));
1367 #endif /* VGO_solaris */
1369 static __always_inline
1370 int sem_destroy_intercept(sem_t
*sem
)
1374 VALGRIND_GET_ORIG_FN(fn
);
1375 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_DESTROY
,
1377 CALL_FN_W_W(ret
, fn
, sem
);
1378 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_DESTROY
,
1383 PTH_FUNCS(int, semZudestroy
, sem_destroy_intercept
, (sem_t
*sem
), (sem
));
1384 #if defined(VGO_solaris)
1385 PTH_FUNCS(int, semaZudestroy
, sem_destroy_intercept
, (sem_t
*sem
), (sem
));
1386 #endif /* VGO_solaris */
1388 static __always_inline
1389 sem_t
* sem_open_intercept(const char *name
, int oflag
, mode_t mode
,
1394 VALGRIND_GET_ORIG_FN(fn
);
1395 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_OPEN
,
1396 name
, oflag
, mode
, value
, 0);
1397 CALL_FN_W_WWWW(ret
, fn
, name
, oflag
, mode
, value
);
1398 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_OPEN
,
1399 ret
!= SEM_FAILED
? ret
: 0,
1400 name
, oflag
, mode
, value
);
1404 PTH_FUNCS(sem_t
*, semZuopen
, sem_open_intercept
,
1405 (const char *name
, int oflag
, mode_t mode
, unsigned int value
),
1406 (name
, oflag
, mode
, value
));
1408 static __always_inline
int sem_close_intercept(sem_t
*sem
)
1412 VALGRIND_GET_ORIG_FN(fn
);
1413 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_CLOSE
,
1415 CALL_FN_W_W(ret
, fn
, sem
);
1416 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_CLOSE
,
1421 PTH_FUNCS(int, semZuclose
, sem_close_intercept
, (sem_t
*sem
), (sem
));
1423 static __always_inline
int sem_wait_intercept(sem_t
*sem
)
1427 VALGRIND_GET_ORIG_FN(fn
);
1428 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT
,
1430 CALL_FN_W_W(ret
, fn
, sem
);
1431 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT
,
1432 sem
, ret
== 0, 0, 0, 0);
1436 PTH_FUNCS(int, semZuwait
, sem_wait_intercept
, (sem_t
*sem
), (sem
));
1437 #if defined(VGO_solaris)
1438 PTH_FUNCS(int, semaZuwait
, sem_wait_intercept
, (sem_t
*sem
), (sem
));
1439 #endif /* VGO_solaris */
1441 static __always_inline
int sem_trywait_intercept(sem_t
*sem
)
1445 VALGRIND_GET_ORIG_FN(fn
);
1446 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT
,
1448 CALL_FN_W_W(ret
, fn
, sem
);
1449 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT
,
1450 sem
, ret
== 0, 0, 0, 0);
1454 PTH_FUNCS(int, semZutrywait
, sem_trywait_intercept
, (sem_t
*sem
), (sem
));
1455 #if defined(VGO_solaris)
1456 PTH_FUNCS(int, semaZutrywait
, sem_trywait_intercept
, (sem_t
*sem
), (sem
));
1457 #endif /* VGO_solaris */
1459 static __always_inline
1460 int sem_timedwait_intercept(sem_t
*sem
, const struct timespec
*abs_timeout
)
1464 VALGRIND_GET_ORIG_FN(fn
);
1465 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT
,
1467 CALL_FN_W_WW(ret
, fn
, sem
, abs_timeout
);
1468 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT
,
1469 sem
, ret
== 0, 0, 0, 0);
1473 PTH_FUNCS(int, semZutimedwait
, sem_timedwait_intercept
,
1474 (sem_t
*sem
, const struct timespec
*abs_timeout
),
1475 (sem
, abs_timeout
));
1476 #if defined(VGO_solaris)
1477 PTH_FUNCS(int, semaZutimedwait
, sem_timedwait_intercept
,
1478 (sem_t
*sem
, const struct timespec
*timeout
),
1480 PTH_FUNCS(int, semaZureltimedwait
, sem_timedwait_intercept
,
1481 (sem_t
*sem
, const struct timespec
*timeout
),
1483 #endif /* VGO_solaris */
1485 static __always_inline
int sem_post_intercept(sem_t
*sem
)
1489 VALGRIND_GET_ORIG_FN(fn
);
1490 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_POST
,
1492 CALL_FN_W_W(ret
, fn
, sem
);
1493 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_POST
,
1494 sem
, ret
== 0, 0, 0, 0);
1498 PTH_FUNCS(int, semZupost
, sem_post_intercept
, (sem_t
*sem
), (sem
));
1499 #if defined(VGO_solaris)
1500 PTH_FUNCS(int, semaZupost
, sem_post_intercept
, (sem_t
*sem
), (sem
));
1501 #endif /* VGO_solaris */
1503 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1504 functions have to be conditionally compiled. */
1505 #if defined(HAVE_PTHREAD_RWLOCK_T)
1507 static __always_inline
1508 int pthread_rwlock_init_intercept(pthread_rwlock_t
* rwlock
,
1509 const pthread_rwlockattr_t
* attr
)
1513 VALGRIND_GET_ORIG_FN(fn
);
1514 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT
,
1515 rwlock
, 0, 0, 0, 0);
1516 CALL_FN_W_WW(ret
, fn
, rwlock
, attr
);
1517 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT
,
1518 rwlock
, 0, 0, 0, 0);
1523 pthreadZurwlockZuinit
, pthread_rwlock_init_intercept
,
1524 (pthread_rwlock_t
* rwlock
, const pthread_rwlockattr_t
* attr
),
1527 #if defined(VGO_solaris)
1528 static __always_inline
1529 int rwlock_init_intercept(rwlock_t
*rwlock
, int type
, void *arg
)
1533 VALGRIND_GET_ORIG_FN(fn
);
1534 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT
,
1535 rwlock
, 0, 0, 0, 0);
1536 CALL_FN_W_WWW(ret
, fn
, rwlock
, type
, arg
);
1537 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT
,
1538 rwlock
, 0, 0, 0, 0);
1542 PTH_FUNCS(int, rwlockZuinit
, rwlock_init_intercept
,
1543 (rwlock_t
*rwlock
, int type
, void *arg
),
1544 (rwlock
, type
, arg
));
1545 #endif /* VGO_solaris */
1547 static __always_inline
1548 int pthread_rwlock_destroy_intercept(pthread_rwlock_t
* rwlock
)
1552 VALGRIND_GET_ORIG_FN(fn
);
1553 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_DESTROY
,
1554 rwlock
, 0, 0, 0, 0);
1555 CALL_FN_W_W(ret
, fn
, rwlock
);
1556 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_DESTROY
,
1557 rwlock
, 0, 0, 0, 0);
1561 #if defined(VGO_solaris)
1562 /* On Solaris, pthread_rwlock_destroy is a weak alias to rwlock_destroy. */
1564 rwlockZudestroy
, pthread_rwlock_destroy_intercept
,
1565 (pthread_rwlock_t
*rwlock
), (rwlock
));
1568 pthreadZurwlockZudestroy
, pthread_rwlock_destroy_intercept
,
1569 (pthread_rwlock_t
* rwlock
), (rwlock
));
1570 #endif /* VGO_solaris */
1572 static __always_inline
1573 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t
* rwlock
)
1577 VALGRIND_GET_ORIG_FN(fn
);
1578 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK
,
1579 rwlock
, 0, 0, 0, 0);
1580 CALL_FN_W_W(ret
, fn
, rwlock
);
1581 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK
,
1582 rwlock
, ret
== 0, 0, 0, 0);
1586 #if defined(VGO_solaris)
1587 /* On Solaris, pthread_rwlock_rdlock is a weak alias to rw_rdlock. */
1589 rwZurdlock
, pthread_rwlock_rdlock_intercept
,
1590 (pthread_rwlock_t
*rwlock
), (rwlock
));
1593 pthreadZurwlockZurdlock
, pthread_rwlock_rdlock_intercept
,
1594 (pthread_rwlock_t
* rwlock
), (rwlock
));
1595 #endif /* VGO_solaris */
1597 #if defined(VGO_solaris)
1598 /* Internal to libc. */
1599 static __always_inline
1600 void lrw_rdlock_intercept(rwlock_t
*rwlock
)
1603 VALGRIND_GET_ORIG_FN(fn
);
1604 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK
,
1605 rwlock
, 0, 0, 0, 0);
1606 CALL_FN_v_W(fn
, rwlock
);
1607 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK
,
1608 rwlock
, True
/* took_lock */, 0, 0, 0);
1611 PTH_FUNCS(void, lrwZurdlock
, lrw_rdlock_intercept
,
1612 (rwlock_t
*rwlock
), (rwlock
));
1613 #endif /* VGO_solaris */
1615 static __always_inline
1616 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t
* rwlock
)
1620 VALGRIND_GET_ORIG_FN(fn
);
1621 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK
,
1622 rwlock
, 0, 0, 0, 0);
1623 CALL_FN_W_W(ret
, fn
, rwlock
);
1624 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK
,
1625 rwlock
, ret
== 0, 0, 0, 0);
1629 #if defined(VGO_solaris)
1630 /* On Solaris, pthread_rwlock_wrlock is a weak alias to rw_wrlock. */
1632 rwZuwrlock
, pthread_rwlock_wrlock_intercept
,
1633 (pthread_rwlock_t
*rwlock
), (rwlock
));
1636 pthreadZurwlockZuwrlock
, pthread_rwlock_wrlock_intercept
,
1637 (pthread_rwlock_t
* rwlock
), (rwlock
));
1638 #endif /* VGO_solaris */
1640 #if defined(VGO_solaris)
1641 /* Internal to libc. */
1642 static __always_inline
1643 void lrw_wrlock_intercept(rwlock_t
*rwlock
)
1646 VALGRIND_GET_ORIG_FN(fn
);
1647 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK
,
1648 rwlock
, 0, 0, 0, 0);
1649 CALL_FN_v_W(fn
, rwlock
);
1650 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK
,
1651 rwlock
, True
/* took_lock */, 0, 0, 0);
1654 PTH_FUNCS(void, lrwZuwrlock
, lrw_wrlock_intercept
,
1655 (rwlock_t
*rwlock
), (rwlock
));
1656 #endif /* VGO_solaris */
1658 static __always_inline
1659 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t
* rwlock
,
1660 const struct timespec
*timeout
)
1664 VALGRIND_GET_ORIG_FN(fn
);
1665 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK
,
1666 rwlock
, 0, 0, 0, 0);
1667 CALL_FN_W_WW(ret
, fn
, rwlock
, timeout
);
1668 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK
,
1669 rwlock
, ret
== 0, 0, 0, 0);
1674 pthreadZurwlockZutimedrdlock
, pthread_rwlock_timedrdlock_intercept
,
1675 (pthread_rwlock_t
* rwlock
, const struct timespec
*timeout
),
1677 #if defined(VGO_solaris)
1678 PTH_FUNCS(int, pthreadZurwlockZureltimedrdlockZunp
,
1679 pthread_rwlock_timedrdlock_intercept
,
1680 (pthread_rwlock_t
*rwlock
, const struct timespec
*timeout
),
1682 #endif /* VGO_solaris */
1684 static __always_inline
1685 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t
* rwlock
,
1686 const struct timespec
*timeout
)
1690 VALGRIND_GET_ORIG_FN(fn
);
1691 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK
,
1692 rwlock
, 0, 0, 0, 0);
1693 CALL_FN_W_WW(ret
, fn
, rwlock
, timeout
);
1694 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK
,
1695 rwlock
, ret
== 0, 0, 0, 0);
1700 pthreadZurwlockZutimedwrlock
, pthread_rwlock_timedwrlock_intercept
,
1701 (pthread_rwlock_t
* rwlock
, const struct timespec
*timeout
),
1703 #if defined(VGO_solaris)
1704 PTH_FUNCS(int, pthreadZurwlockZureltimedwrlockZunp
,
1705 pthread_rwlock_timedwrlock_intercept
,
1706 (pthread_rwlock_t
*rwlock
, const struct timespec
*timeout
),
1708 #endif /* VGO_solaris */
1710 static __always_inline
1711 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t
* rwlock
)
1715 VALGRIND_GET_ORIG_FN(fn
);
1716 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK
,
1717 rwlock
, 0, 0, 0, 0);
1718 CALL_FN_W_W(ret
, fn
, rwlock
);
1719 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK
,
1720 rwlock
, ret
== 0, 0, 0, 0);
1724 #if defined(VGO_solaris)
1725 /* On Solaris, pthread_rwlock_tryrdlock is a weak alias to rw_tryrdlock. */
1727 rwZutryrdlock
, pthread_rwlock_tryrdlock_intercept
,
1728 (pthread_rwlock_t
*rwlock
), (rwlock
));
1731 pthreadZurwlockZutryrdlock
, pthread_rwlock_tryrdlock_intercept
,
1732 (pthread_rwlock_t
* rwlock
), (rwlock
));
1733 #endif /* VGO_solaris */
1735 static __always_inline
1736 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t
* rwlock
)
1740 VALGRIND_GET_ORIG_FN(fn
);
1741 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK
,
1742 rwlock
, 0, 0, 0, 0);
1743 CALL_FN_W_W(ret
, fn
, rwlock
);
1744 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK
,
1745 rwlock
, ret
== 0, 0, 0, 0);
1749 #if defined(VGO_solaris)
1750 /* On Solaris, pthread_rwlock_trywrlock is a weak alias to rw_trywrlock. */
1752 rwZutrywrlock
, pthread_rwlock_trywrlock_intercept
,
1753 (pthread_rwlock_t
*rwlock
), (rwlock
));
1756 pthreadZurwlockZutrywrlock
, pthread_rwlock_trywrlock_intercept
,
1757 (pthread_rwlock_t
* rwlock
), (rwlock
));
1758 #endif /* VGO_solaris */
1760 static __always_inline
1761 int pthread_rwlock_unlock_intercept(pthread_rwlock_t
* rwlock
)
1765 VALGRIND_GET_ORIG_FN(fn
);
1766 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_UNLOCK
,
1767 rwlock
, 0, 0, 0, 0);
1768 CALL_FN_W_W(ret
, fn
, rwlock
);
1769 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_UNLOCK
,
1770 rwlock
, ret
== 0, 0, 0, 0);
1774 #if defined(VGO_solaris)
1775 /* On Solaris, pthread_rwlock_unlock is a weak alias to rw_unlock. */
1777 rwZuunlock
, pthread_rwlock_unlock_intercept
,
1778 (pthread_rwlock_t
*rwlock
), (rwlock
));
1781 pthreadZurwlockZuunlock
, pthread_rwlock_unlock_intercept
,
1782 (pthread_rwlock_t
* rwlock
), (rwlock
));
1783 #endif /* VGO_solaris */
1785 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */