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-2013 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 #ifdef HAVE_USABLE_LINUX_FUTEX_H
59 #include <asm/unistd.h> /* __NR_futex */
60 #include <linux/futex.h> /* FUTEX_WAIT */
61 #ifndef FUTEX_PRIVATE_FLAG
62 #define FUTEX_PRIVATE_FLAG 0
65 #include "drd_basics.h" /* DRD_() */
66 #include "drd_clientreq.h"
67 #include "pub_tool_redir.h" /* VG_WRAP_FUNCTION_ZZ() */
69 #if defined(VGO_solaris)
71 * Solaris usually provides pthread_* functions on top of Solaris threading
72 * and synchronization functions. Usually both need to be intercepted because
73 * pthread_* ones might not call the Solaris ones (see for example sem_wait()).
74 * Such approach is required to correctly report misuse of the POSIX threads
76 * Therefore DRD intercepts and instruments all such functions but due to
77 * DRD_(thread_enter_synchr)() and DRD_(thread_leave_synchr)() guards in
78 * handle_client_request(), only the top-most function is handled.
79 * So the right thing(TM) happens, as expected.
80 * The only exception is when pthread_* function is a weak alias to the Solaris
81 * threading/synchronization function. In such case only one needs to be
82 * intercepted to avoid redirection ambiguity.
84 * Intercepted functions rely on the fact that:
85 * - pthread_mutex_t == mutex_t
86 * - pthread_cond_t == cond_t
88 * - pthread_rwlock_t == rwlock_t
90 * It is necessary to intercept also internal libc synchronization functions
92 * - For read-write locks the unlocking function is shared
93 * - Functions lmutex_lock/lmutex_unlock guard many critical sections in libc
94 * which will be otherwise reported by DRD
98 #include "pub_tool_vki.h"
101 * Solaris provides higher throughput, parallelism and scalability than other
102 * operating systems, at the cost of more fine-grained locking activity.
103 * This means for example that when a thread is created under Linux, just one
104 * big lock in glibc is used for all thread setup. Solaris libc uses several
105 * fine-grained locks and the creator thread resumes its activities as soon
106 * as possible, leaving for example stack and TLS setup activities to the
109 * This situation confuses DRD as it assumes there is some false ordering
110 * in place between creator and created thread; and therefore many types of
111 * race conditions in the application would not be reported. To prevent such
112 * false ordering, command line option --ignore-thread-creation is set to
113 * 'yes' by default on Solaris. All activity (loads, stores, client requests)
114 * is therefore ignored during:
115 * - pthread_create() call in the creator thread [libc.so]
116 * - thread creation phase (stack and TLS setup) in the created thread [libc.so]
118 * As explained in the comments for _ti_bind_guard(), whenever the runtime
119 * linker has to perform any activity (such as resolving a symbol), it protects
120 * its data structures by calling into rt_bind_guard() which in turn invokes
121 * _ti_bind_guard() in libc. Pointers to _ti_bind_guard() and _ti_bind_clear()
122 * are passed from libc to runtime linker in _ld_libc() call during libc_init().
123 * All activity is also ignored during:
124 * - runtime dynamic linker work between rt_bind_guard() and rt_bind_clear()
127 * This also means that DRD does not report race conditions in libc (when
128 * --ignore-thread-creation=yes) and runtime linker itself (unconditionally)
129 * during these ignored sequences.
133 * Original function pointers for _ti_bind_guard() and _ti_bind_clear()
134 * from libc. They are intercepted in function wrapper of _ld_libc().
136 typedef int (*drd_rtld_guard_fn
)(int flags
);
137 static drd_rtld_guard_fn
DRD_(rtld_bind_guard
) = NULL
;
138 static drd_rtld_guard_fn
DRD_(rtld_bind_clear
) = NULL
;
143 * Notes regarding thread creation:
144 * - sg_init() runs on the context of the created thread and copies the vector
145 * clock of the creator thread. This only works reliably if the creator
146 * thread waits until this copy has been performed.
147 * - DRD_(thread_compute_minimum_vc)() does not take the vector clocks into
148 * account that are involved in thread creation and for which the
149 * corresponding thread has not yet been created. So not waiting until the
150 * created thread has been started would make it possible that segments get
151 * discarded that should not yet be discarded. Or: some data races are not
156 * Macro for generating a Valgrind interception function.
157 * @param[in] ret_ty Return type of the function to be generated.
158 * @param[in] zf Z-encoded name of the interception function.
159 * @param[in] implf Name of the function that implements the intercept.
160 * @param[in] arg_decl Argument declaration list enclosed in parentheses.
161 * @param[in] argl Argument list enclosed in parentheses.
164 static int never_true
;
165 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
166 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
167 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
169 ret_ty pth_func_result = implf argl; \
170 /* Apparently inserting a function call in wrapper functions */ \
171 /* is sufficient to avoid misaligned stack errors. */ \
174 return pth_func_result; \
176 #elif defined(VGO_solaris)
177 /* On Solaris, libpthread is just a filter library on top of libc.
178 * Threading and synchronization functions in runtime linker are not
181 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
182 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl; \
183 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl \
184 { return implf argl; }
186 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, 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_main_thread_state
)(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_main_thread_state
)();
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
);
287 static void DRD_(sema_destroy
)(DrdSema
* sema
)
289 pthread_mutex_destroy(&sema
->mutex
);
292 static void DRD_(sema_down
)(DrdSema
* sema
)
296 pthread_mutex_lock(&sema
->mutex
);
297 if (sema
->counter
== 0) {
299 while (sema
->counter
== 0) {
300 pthread_mutex_unlock(&sema
->mutex
);
301 #ifdef HAVE_USABLE_LINUX_FUTEX_H
302 if (syscall(__NR_futex
, (UWord
)&sema
->counter
,
303 FUTEX_WAIT
| FUTEX_PRIVATE_FLAG
, 0) == 0)
309 * Invoke sched_yield() on non-Linux systems, if the futex syscall has
310 * not been invoked or if this code has been built on a Linux system
311 * where __NR_futex is defined and is run on a Linux system that does
312 * not support the futex syscall.
314 if (res
!= 0 && res
!= EWOULDBLOCK
)
316 pthread_mutex_lock(&sema
->mutex
);
321 pthread_mutex_unlock(&sema
->mutex
);
324 static void DRD_(sema_up
)(DrdSema
* sema
)
326 pthread_mutex_lock(&sema
->mutex
);
328 #ifdef HAVE_USABLE_LINUX_FUTEX_H
329 if (sema
->waiters
> 0)
330 syscall(__NR_futex
, (UWord
)&sema
->counter
,
331 FUTEX_WAKE
| FUTEX_PRIVATE_FLAG
, 1);
333 pthread_mutex_unlock(&sema
->mutex
);
337 * POSIX threads and DRD each have their own mutex type identification.
338 * Convert POSIX threads' mutex type to DRD's mutex type. In the code below
339 * if-statements are used to test the value of 'kind' instead of a switch
340 * statement because some of the PTHREAD_MUTEX_ macro's may have the same
343 static MutexT
DRD_(pthread_to_drd_mutex_type
)(int kind
)
346 * See also PTHREAD_MUTEX_KIND_MASK_NP in glibc source file
349 kind
&= PTHREAD_MUTEX_RECURSIVE
| PTHREAD_MUTEX_ERRORCHECK
|
350 PTHREAD_MUTEX_NORMAL
| PTHREAD_MUTEX_DEFAULT
;
352 if (kind
== PTHREAD_MUTEX_RECURSIVE
)
353 return mutex_type_recursive_mutex
;
354 else if (kind
== PTHREAD_MUTEX_ERRORCHECK
)
355 return mutex_type_errorcheck_mutex
;
356 else if (kind
== PTHREAD_MUTEX_NORMAL
)
357 return mutex_type_default_mutex
;
358 else if (kind
== PTHREAD_MUTEX_DEFAULT
)
359 return mutex_type_default_mutex
;
360 #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
361 else if (kind
== PTHREAD_MUTEX_ADAPTIVE_NP
)
362 return mutex_type_default_mutex
;
365 return mutex_type_invalid_mutex
;
368 #if defined(VGO_solaris)
370 * Solaris threads and DRD each have their own mutex type identification.
371 * Convert Solaris threads' mutex type to DRD's mutex type.
373 static MutexT
DRD_(thread_to_drd_mutex_type
)(int type
)
375 if (type
& LOCK_RECURSIVE
) {
376 return mutex_type_recursive_mutex
;
377 } else if (type
& LOCK_ERRORCHECK
) {
378 return mutex_type_errorcheck_mutex
;
380 return mutex_type_default_mutex
;
383 #endif /* VGO_solaris */
385 #define IS_ALIGNED(p) (((uintptr_t)(p) & (sizeof(*(p)) - 1)) == 0)
388 * Read the mutex type stored in the client memory used for the mutex
391 * @note This function depends on the implementation of the POSIX threads
392 * library -- the POSIX standard does not define the name of the member in
393 * which the mutex type is stored.
394 * @note The function mutex_type() has been declared inline in order
395 * to avoid that it shows up in call stacks (drd/tests/...exp* files).
396 * @note glibc stores the mutex type in the lowest two bits, and uses the
397 * higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
398 * PTHREAD_MUTEXATTR_FLAG_PSHARED.
400 static __always_inline MutexT
DRD_(mutex_type
)(pthread_mutex_t
* mutex
)
402 #if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
403 /* glibc + LinuxThreads. */
404 if (IS_ALIGNED(&mutex
->__m_kind
))
406 const int kind
= mutex
->__m_kind
& 3;
407 return DRD_(pthread_to_drd_mutex_type
)(kind
);
409 #elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
411 if (IS_ALIGNED(&mutex
->__data
.__kind
))
413 const int kind
= mutex
->__data
.__kind
& 3;
414 return DRD_(pthread_to_drd_mutex_type
)(kind
);
416 #elif defined(VGO_solaris)
417 const int type
= ((mutex_t
*) mutex
)->vki_mutex_type
;
418 return DRD_(thread_to_drd_mutex_type
)(type
);
421 * Another POSIX threads implementation. The mutex type won't be printed
422 * when enabling --trace-mutex=yes.
425 return mutex_type_unknown
;
429 * Tell DRD whether 'tid' is a joinable thread or a detached thread.
431 static void DRD_(set_joinable
)(const pthread_t tid
, const int joinable
)
433 assert(joinable
== 0 || joinable
== 1);
434 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_JOINABLE
,
435 tid
, joinable
, 0, 0, 0);
438 /** Tell DRD that the calling thread is about to enter pthread_create(). */
439 static __always_inline
void DRD_(entering_pthread_create
)(void)
441 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__ENTERING_PTHREAD_CREATE
,
445 /** Tell DRD that the calling thread has left pthread_create(). */
446 static __always_inline
void DRD_(left_pthread_create
)(void)
448 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LEFT_PTHREAD_CREATE
,
453 * Entry point for newly created threads. This function is called from the
454 * thread created by pthread_create().
456 static void* DRD_(thread_wrapper
)(void* arg
)
458 DrdPosixThreadArgs
* arg_ptr
;
459 DrdPosixThreadArgs arg_copy
;
461 arg_ptr
= (DrdPosixThreadArgs
*)arg
;
464 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID
,
465 pthread_self(), 0, 0, 0, 0);
467 DRD_(set_joinable
)(pthread_self(),
468 arg_copy
.detachstate
== PTHREAD_CREATE_JOINABLE
);
471 * Only set 'wrapper_started' after VG_USERREQ__SET_PTHREADID and
472 * DRD_(set_joinable)() have been invoked to avoid a race with
473 * a pthread_detach() invocation for this thread from another thread.
475 DRD_(sema_up
)(arg_copy
.wrapper_started
);
477 return (arg_copy
.start
)(arg_copy
.arg
);
481 * Return 1 if the LinuxThreads implementation of POSIX Threads has been
482 * detected, and 0 otherwise.
484 * @see For more information about the confstr() function, see also
485 * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
487 static int DRD_(detected_linuxthreads
)(void)
490 #if defined(_CS_GNU_LIBPTHREAD_VERSION)
491 /* Linux with a recent glibc. */
494 len
= confstr(_CS_GNU_LIBPTHREAD_VERSION
, buffer
, sizeof(buffer
));
495 assert(len
<= sizeof(buffer
));
496 return len
> 0 && buffer
[0] == 'l';
498 /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
502 /* Another OS than Linux, hence no LinuxThreads. */
508 * Stop and print an error message in case a non-supported threading
509 * library implementation (LinuxThreads) has been detected.
511 static void DRD_(check_threading_library
)(void)
513 if (DRD_(detected_linuxthreads
)())
515 if (getenv("LD_ASSUME_KERNEL"))
518 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
519 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
520 "after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
526 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
527 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
528 "after having upgraded to a newer version of your Linux distribution.\n"
537 * The main thread is the only thread not created by pthread_create().
538 * Update DRD's state information about the main thread.
540 static void DRD_(set_main_thread_state
)(void)
542 // Make sure that DRD knows about the main thread's POSIX thread ID.
543 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID
,
544 pthread_self(), 0, 0, 0, 0);
548 * Note: as of today there exist three different versions of pthread_create
550 * - pthread_create@GLIBC_2.0
551 * - pthread_create@@GLIBC_2.1
552 * - pthread_create@@GLIBC_2.2.5
553 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
554 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
555 * versions have been implemented. In any glibc version where more than one
556 * pthread_create function has been implemented, older versions call the
557 * newer versions. Or: the pthread_create* wrapper defined below can be
558 * called recursively. Any code in this wrapper should take this in account.
559 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
560 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
561 * See also the implementation of pthread_create@GLIBC_2.0 in
562 * glibc-2.9/nptl/pthread_create.c.
565 static __always_inline
566 int pthread_create_intercept(pthread_t
* thread
, const pthread_attr_t
* attr
,
567 void* (*start
)(void*), void* arg
)
571 DrdSema wrapper_started
;
572 DrdPosixThreadArgs thread_args
;
574 VALGRIND_GET_ORIG_FN(fn
);
576 DRD_(sema_init
)(&wrapper_started
);
577 thread_args
.start
= start
;
578 thread_args
.arg
= arg
;
579 thread_args
.wrapper_started
= &wrapper_started
;
581 * Find out whether the thread will be started as a joinable thread
582 * or as a detached thread. If no thread attributes have been specified,
583 * this means that the new thread will be started as a joinable thread.
585 thread_args
.detachstate
= PTHREAD_CREATE_JOINABLE
;
588 if (pthread_attr_getdetachstate(attr
, &thread_args
.detachstate
) != 0)
591 assert(thread_args
.detachstate
== PTHREAD_CREATE_JOINABLE
592 || thread_args
.detachstate
== PTHREAD_CREATE_DETACHED
);
594 DRD_(entering_pthread_create
)();
595 CALL_FN_W_WWWW(ret
, fn
, thread
, attr
, DRD_(thread_wrapper
), &thread_args
);
596 DRD_(left_pthread_create
)();
599 /* Wait until the thread wrapper started. */
600 DRD_(sema_down
)(&wrapper_started
);
603 DRD_(sema_destroy
)(&wrapper_started
);
605 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT
,
606 pthread_self(), 0, 0, 0, 0);
611 PTH_FUNCS(int, pthreadZucreate
, pthread_create_intercept
,
612 (pthread_t
*thread
, const pthread_attr_t
*attr
,
613 void *(*start
) (void *), void *arg
),
614 (thread
, attr
, start
, arg
));
616 #if defined(VGO_solaris)
617 /* Solaris also provides thr_create() in addition to pthread_create().
618 * Both pthread_create(3C) and thr_create(3C) are based on private
621 static __always_inline
622 int thr_create_intercept(void *stk
, size_t stksize
, void *(*start
)(void *),
623 void *arg
, long flags
, thread_t
*new_thread
)
627 DrdSema wrapper_started
;
628 DrdPosixThreadArgs thread_args
;
630 VALGRIND_GET_ORIG_FN(fn
);
632 DRD_(sema_init
)(&wrapper_started
);
633 thread_args
.start
= start
;
634 thread_args
.arg
= arg
;
635 thread_args
.wrapper_started
= &wrapper_started
;
637 * Find out whether the thread will be started as a joinable thread
638 * or as a detached thread.
640 if (flags
& THR_DETACHED
)
641 thread_args
.detachstate
= PTHREAD_CREATE_DETACHED
;
643 thread_args
.detachstate
= PTHREAD_CREATE_JOINABLE
;
645 DRD_(entering_pthread_create
)();
646 CALL_FN_W_6W(ret
, fn
, stk
, stksize
, DRD_(thread_wrapper
), &thread_args
,
648 DRD_(left_pthread_create
)();
651 /* Wait until the thread wrapper started. */
652 DRD_(sema_down
)(&wrapper_started
);
655 DRD_(sema_destroy
)(&wrapper_started
);
657 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT
,
658 pthread_self(), 0, 0, 0, 0);
663 PTH_FUNCS(int, thrZucreate
, thr_create_intercept
,
664 (void *stk
, size_t stksize
, void *(*start
)(void *), void *arg
,
665 long flags
, thread_t
*new_thread
),
666 (stk
, stksize
, start
, arg
, flags
, new_thread
));
667 #endif /* VGO_solaris */
669 #if defined(VGO_solaris)
671 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
672 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
673 * and CI_BIND_CLEAR, to provide resilience against function renaming.
675 static __always_inline
676 int DRD_(_ti_bind_guard_intercept
)(int flags
) {
677 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_GUARD
,
679 return DRD_(rtld_bind_guard
)(flags
);
682 static __always_inline
683 int DRD_(_ti_bind_clear_intercept
)(int flags
) {
684 int ret
= DRD_(rtld_bind_clear
)(flags
);
685 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_CLEAR
,
691 * Wrapped _ld_libc() from the runtime linker ld.so.1.
693 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1
, ZuldZulibc
)(vki_Lc_interface
*ptr
);
694 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1
, ZuldZulibc
)(vki_Lc_interface
*ptr
)
699 VALGRIND_GET_ORIG_FN(fn
);
701 vki_Lc_interface
*funcs
= ptr
;
702 for (tag
= funcs
->ci_tag
; tag
!= 0; tag
= (++funcs
)->ci_tag
) {
704 case VKI_CI_BIND_GUARD
:
705 if (funcs
->vki_ci_un
.ci_func
!= DRD_(_ti_bind_guard_intercept
)) {
706 DRD_(rtld_bind_guard
) = funcs
->vki_ci_un
.ci_func
;
707 funcs
->vki_ci_un
.ci_func
= DRD_(_ti_bind_guard_intercept
);
710 case VKI_CI_BIND_CLEAR
:
711 if (funcs
->vki_ci_un
.ci_func
!= DRD_(_ti_bind_clear_intercept
)) {
712 DRD_(rtld_bind_clear
) = funcs
->vki_ci_un
.ci_func
;
713 funcs
->vki_ci_un
.ci_func
= DRD_(_ti_bind_clear_intercept
);
719 CALL_FN_v_W(fn
, ptr
);
721 #endif /* VGO_solaris */
723 static __always_inline
724 int pthread_join_intercept(pthread_t pt_joinee
, void **thread_return
)
729 VALGRIND_GET_ORIG_FN(fn
);
731 * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
732 * implementation triggers a (false positive) race report.
734 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
735 CALL_FN_W_WW(ret
, fn
, pt_joinee
, thread_return
);
738 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN
,
739 pt_joinee
, 0, 0, 0, 0);
741 ANNOTATE_IGNORE_READS_AND_WRITES_END();
745 PTH_FUNCS(int, pthreadZujoin
, pthread_join_intercept
,
746 (pthread_t pt_joinee
, void **thread_return
),
747 (pt_joinee
, thread_return
));
749 #if defined(VGO_solaris)
750 /* Solaris also provides thr_join() in addition to pthread_join().
751 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
753 * :TODO: No functionality is currently provided for joinee == 0 and departed.
754 * This would require another client request, of course.
756 static __always_inline
757 int thr_join_intercept(thread_t joinee
, thread_t
*departed
, void **thread_return
)
762 VALGRIND_GET_ORIG_FN(fn
);
763 CALL_FN_W_WWW(ret
, fn
, joinee
, departed
, thread_return
);
766 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN
,
772 PTH_FUNCS(int, thrZujoin
, thr_join_intercept
,
773 (thread_t joinee
, thread_t
*departed
, void **thread_return
),
774 (joinee
, departed
, thread_return
));
775 #endif /* VGO_solaris */
777 static __always_inline
778 int pthread_detach_intercept(pthread_t pt_thread
)
783 VALGRIND_GET_ORIG_FN(fn
);
784 CALL_FN_W_W(ret
, fn
, pt_thread
);
785 DRD_(set_joinable
)(pt_thread
, 0);
790 PTH_FUNCS(int, pthreadZudetach
, pthread_detach_intercept
,
791 (pthread_t thread
), (thread
));
793 // NOTE: be careful to intercept only pthread_cancel() and not
794 // pthread_cancel_init() on Linux.
796 static __always_inline
797 int pthread_cancel_intercept(pthread_t pt_thread
)
801 VALGRIND_GET_ORIG_FN(fn
);
802 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_THREAD_CANCEL
,
803 pt_thread
, 0, 0, 0, 0);
804 CALL_FN_W_W(ret
, fn
, pt_thread
);
805 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_CANCEL
,
806 pt_thread
, ret
==0, 0, 0, 0);
810 PTH_FUNCS(int, pthreadZucancel
, pthread_cancel_intercept
,
811 (pthread_t thread
), (thread
))
813 static __always_inline
814 int pthread_once_intercept(pthread_once_t
*once_control
,
815 void (*init_routine
)(void))
819 VALGRIND_GET_ORIG_FN(fn
);
821 * Ignore any data races triggered by the implementation of pthread_once().
822 * Necessary for Darwin. This is not necessary for Linux but doesn't have
823 * any known adverse effects.
825 DRD_IGNORE_VAR(*once_control
);
826 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
827 CALL_FN_W_WW(ret
, fn
, once_control
, init_routine
);
828 ANNOTATE_IGNORE_READS_AND_WRITES_END();
829 DRD_STOP_IGNORING_VAR(*once_control
);
833 PTH_FUNCS(int, pthreadZuonce
, pthread_once_intercept
,
834 (pthread_once_t
*once_control
, void (*init_routine
)(void)),
835 (once_control
, init_routine
));
837 static __always_inline
838 int pthread_mutex_init_intercept(pthread_mutex_t
*mutex
,
839 const pthread_mutexattr_t
* attr
)
844 VALGRIND_GET_ORIG_FN(fn
);
845 mt
= PTHREAD_MUTEX_DEFAULT
;
847 pthread_mutexattr_gettype(attr
, &mt
);
848 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT
,
849 mutex
, DRD_(pthread_to_drd_mutex_type
)(mt
),
851 CALL_FN_W_WW(ret
, fn
, mutex
, attr
);
852 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT
,
857 PTH_FUNCS(int, pthreadZumutexZuinit
, pthread_mutex_init_intercept
,
858 (pthread_mutex_t
*mutex
, const pthread_mutexattr_t
* attr
),
861 #if defined(VGO_solaris)
862 static __always_inline
863 int mutex_init_intercept(mutex_t
*mutex
, int type
, void *arg
)
867 VALGRIND_GET_ORIG_FN(fn
);
869 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT
,
870 mutex
, DRD_(thread_to_drd_mutex_type
)(type
),
872 CALL_FN_W_WWW(ret
, fn
, mutex
, type
, arg
);
873 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT
,
878 PTH_FUNCS(int, mutexZuinit
, mutex_init_intercept
,
879 (mutex_t
*mutex
, int type
, void *arg
),
881 #endif /* VGO_solaris */
883 static __always_inline
884 int pthread_mutex_destroy_intercept(pthread_mutex_t
* mutex
)
888 VALGRIND_GET_ORIG_FN(fn
);
889 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY
,
891 CALL_FN_W_W(ret
, fn
, mutex
);
892 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY
,
893 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
897 #if defined(VGO_solaris)
898 /* On Solaris, pthread_mutex_destroy is a weak alias to mutex_destroy. */
899 PTH_FUNCS(int, mutexZudestroy
, pthread_mutex_destroy_intercept
,
900 (pthread_mutex_t
*mutex
), (mutex
));
902 PTH_FUNCS(int, pthreadZumutexZudestroy
, pthread_mutex_destroy_intercept
,
903 (pthread_mutex_t
*mutex
), (mutex
));
904 #endif /* VGO_solaris */
906 static __always_inline
907 int pthread_mutex_lock_intercept(pthread_mutex_t
* mutex
)
911 VALGRIND_GET_ORIG_FN(fn
);
912 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
913 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
914 CALL_FN_W_W(ret
, fn
, mutex
);
915 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
916 mutex
, ret
== 0, 0, 0, 0);
920 #if defined(VGO_solaris)
921 /* On Solaris, pthread_mutex_lock is a weak alias to mutex_lock. */
922 PTH_FUNCS(int, mutexZulock
, pthread_mutex_lock_intercept
,
923 (pthread_mutex_t
*mutex
), (mutex
));
925 PTH_FUNCS(int, pthreadZumutexZulock
, pthread_mutex_lock_intercept
,
926 (pthread_mutex_t
*mutex
), (mutex
));
927 #endif /* VGO_solaris */
929 #if defined(VGO_solaris)
930 /* Internal to libc. Mutex is usually initialized only implicitly,
931 * by zeroing mutex_t structure.
933 static __always_inline
934 void lmutex_lock_intercept(mutex_t
*mutex
)
937 VALGRIND_GET_ORIG_FN(fn
);
938 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
940 DRD_(mutex_type
)((pthread_mutex_t
*) mutex
),
941 False
/* try_lock */, 0, 0);
942 CALL_FN_v_W(fn
, mutex
);
943 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
944 mutex
, True
/* took_lock */, 0, 0, 0);
947 PTH_FUNCS(void, lmutexZulock
, lmutex_lock_intercept
,
948 (mutex_t
*mutex
), (mutex
));
949 #endif /* VGO_solaris */
951 static __always_inline
952 int pthread_mutex_trylock_intercept(pthread_mutex_t
* mutex
)
956 VALGRIND_GET_ORIG_FN(fn
);
957 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
958 mutex
, DRD_(mutex_type
)(mutex
), 1, 0, 0);
959 CALL_FN_W_W(ret
, fn
, mutex
);
960 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
961 mutex
, ret
== 0, 0, 0, 0);
965 #if defined(VGO_solaris)
966 /* On Solaris, pthread_mutex_trylock is a weak alias to mutex_trylock. */
967 PTH_FUNCS(int, mutexZutrylock
, pthread_mutex_trylock_intercept
,
968 (pthread_mutex_t
*mutex
), (mutex
));
970 PTH_FUNCS(int, pthreadZumutexZutrylock
, pthread_mutex_trylock_intercept
,
971 (pthread_mutex_t
*mutex
), (mutex
));
972 #endif /* VGO_solaris */
974 static __always_inline
975 int pthread_mutex_timedlock_intercept(pthread_mutex_t
*mutex
,
976 const struct timespec
*abs_timeout
)
980 VALGRIND_GET_ORIG_FN(fn
);
981 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
982 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
983 CALL_FN_W_WW(ret
, fn
, mutex
, abs_timeout
);
984 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
985 mutex
, ret
== 0, 0, 0, 0);
989 PTH_FUNCS(int, pthreadZumutexZutimedlock
, pthread_mutex_timedlock_intercept
,
990 (pthread_mutex_t
*mutex
, const struct timespec
*abs_timeout
),
991 (mutex
, abs_timeout
));
992 #if defined(VGO_solaris)
994 pthreadZumutexZureltimedlockZunp
, pthread_mutex_timedlock_intercept
,
995 (pthread_mutex_t
*mutex
, const struct timespec
*timeout
),
997 #endif /* VGO_solaris */
999 static __always_inline
1000 int pthread_mutex_unlock_intercept(pthread_mutex_t
*mutex
)
1004 VALGRIND_GET_ORIG_FN(fn
);
1005 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK
,
1006 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
1007 CALL_FN_W_W(ret
, fn
, mutex
);
1008 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK
,
1013 #if defined(VGO_solaris)
1014 /* On Solaris, pthread_mutex_unlock is a weak alias to mutex_unlock. */
1015 PTH_FUNCS(int, mutexZuunlock
, pthread_mutex_unlock_intercept
,
1016 (pthread_mutex_t
*mutex
), (mutex
));
1018 PTH_FUNCS(int, pthreadZumutexZuunlock
, pthread_mutex_unlock_intercept
,
1019 (pthread_mutex_t
*mutex
), (mutex
));
1020 #endif /* VGO_solaris */
1022 #if defined(VGO_solaris)
1023 /* Internal to libc. */
1024 static __always_inline
1025 void lmutex_unlock_intercept(mutex_t
*mutex
)
1028 VALGRIND_GET_ORIG_FN(fn
);
1029 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK
,
1031 DRD_(mutex_type
)((pthread_mutex_t
*) mutex
),
1033 CALL_FN_v_W(fn
, mutex
);
1034 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK
,
1038 PTH_FUNCS(void, lmutexZuunlock
, lmutex_unlock_intercept
,
1039 (mutex_t
*mutex
), (mutex
));
1040 #endif /* VGO_solaris */
1042 static __always_inline
1043 int pthread_cond_init_intercept(pthread_cond_t
* cond
,
1044 const pthread_condattr_t
* attr
)
1048 VALGRIND_GET_ORIG_FN(fn
);
1049 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT
,
1051 CALL_FN_W_WW(ret
, fn
, cond
, attr
);
1052 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT
,
1057 PTH_FUNCS(int, pthreadZucondZuinit
, pthread_cond_init_intercept
,
1058 (pthread_cond_t
* cond
, const pthread_condattr_t
* attr
),
1061 #if defined(VGO_solaris)
1062 static __always_inline
1063 int cond_init_intercept(cond_t
*cond
, int type
, void *arg
)
1067 VALGRIND_GET_ORIG_FN(fn
);
1068 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT
,
1070 CALL_FN_W_WWW(ret
, fn
, cond
, type
, arg
);
1071 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT
,
1076 PTH_FUNCS(int, condZuinit
, cond_init_intercept
,
1077 (cond_t
*cond
, int type
, void *arg
),
1079 #endif /* VGO_solaris */
1081 static __always_inline
1082 int pthread_cond_destroy_intercept(pthread_cond_t
* cond
)
1086 VALGRIND_GET_ORIG_FN(fn
);
1087 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_DESTROY
,
1089 CALL_FN_W_W(ret
, fn
, cond
);
1090 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_DESTROY
,
1091 cond
, ret
==0, 0, 0, 0);
1095 #if defined(VGO_solaris)
1096 /* On Solaris, pthread_cond_destroy is a weak alias to cond_destroy. */
1097 PTH_FUNCS(int, condZudestroy
, pthread_cond_destroy_intercept
,
1098 (pthread_cond_t
*cond
), (cond
));
1100 PTH_FUNCS(int, pthreadZucondZudestroy
, pthread_cond_destroy_intercept
,
1101 (pthread_cond_t
* cond
), (cond
));
1102 #endif /* VGO_solaris */
1104 static __always_inline
1105 int pthread_cond_wait_intercept(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
1109 VALGRIND_GET_ORIG_FN(fn
);
1110 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT
,
1111 cond
, mutex
, DRD_(mutex_type
)(mutex
), 0, 0);
1112 CALL_FN_W_WW(ret
, fn
, cond
, mutex
);
1113 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT
,
1114 cond
, mutex
, 1, 0, 0);
1118 PTH_FUNCS(int, pthreadZucondZuwait
, pthread_cond_wait_intercept
,
1119 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
),
1121 #if defined(VGO_solaris)
1122 PTH_FUNCS(int, condZuwait
, pthread_cond_wait_intercept
,
1123 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
),
1125 #endif /* VGO_solaris */
1127 static __always_inline
1128 int pthread_cond_timedwait_intercept(pthread_cond_t
*cond
,
1129 pthread_mutex_t
*mutex
,
1130 const struct timespec
* abstime
)
1134 VALGRIND_GET_ORIG_FN(fn
);
1135 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT
,
1136 cond
, mutex
, DRD_(mutex_type
)(mutex
), 0, 0);
1137 CALL_FN_W_WWW(ret
, fn
, cond
, mutex
, abstime
);
1138 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT
,
1139 cond
, mutex
, 1, 0, 0);
1143 PTH_FUNCS(int, pthreadZucondZutimedwait
, pthread_cond_timedwait_intercept
,
1144 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1145 const struct timespec
* abstime
),
1146 (cond
, mutex
, abstime
));
1147 #if defined(VGO_solaris)
1148 PTH_FUNCS(int, condZutimedwait
, pthread_cond_timedwait_intercept
,
1149 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1150 const struct timespec
*timeout
),
1151 (cond
, mutex
, timeout
));
1152 PTH_FUNCS(int, condZureltimedwait
, pthread_cond_timedwait_intercept
,
1153 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1154 const struct timespec
*timeout
),
1155 (cond
, mutex
, timeout
));
1156 #endif /* VGO_solaris */
1158 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
1159 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
1160 // two. Intercepting all pthread_cond_signal* functions will cause only one
1161 // argument to be passed to pthread_cond_signal_np() and hence will cause this
1162 // last function to crash.
1164 static __always_inline
1165 int pthread_cond_signal_intercept(pthread_cond_t
* cond
)
1169 VALGRIND_GET_ORIG_FN(fn
);
1170 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_SIGNAL
,
1172 CALL_FN_W_W(ret
, fn
, cond
);
1173 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_SIGNAL
,
1178 #if defined(VGO_solaris)
1179 /* On Solaris, pthread_cond_signal is a weak alias to cond_signal. */
1180 PTH_FUNCS(int, condZusignal
, pthread_cond_signal_intercept
,
1181 (pthread_cond_t
*cond
), (cond
));
1183 PTH_FUNCS(int, pthreadZucondZusignal
, pthread_cond_signal_intercept
,
1184 (pthread_cond_t
* cond
), (cond
));
1185 #endif /* VGO_solaris */
1187 static __always_inline
1188 int pthread_cond_broadcast_intercept(pthread_cond_t
* cond
)
1192 VALGRIND_GET_ORIG_FN(fn
);
1193 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_BROADCAST
,
1195 CALL_FN_W_W(ret
, fn
, cond
);
1196 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_BROADCAST
,
1201 #if defined(VGO_solaris)
1202 /* On Solaris, pthread_cond_broadcast is a weak alias to cond_broadcast. */
1203 PTH_FUNCS(int, condZubroadcast
, pthread_cond_broadcast_intercept
,
1204 (pthread_cond_t
*cond
), (cond
));
1206 PTH_FUNCS(int, pthreadZucondZubroadcast
, pthread_cond_broadcast_intercept
,
1207 (pthread_cond_t
* cond
), (cond
));
1208 #endif /* VGO_solaris */
1210 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1211 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1212 static __always_inline
1213 int pthread_spin_init_intercept(pthread_spinlock_t
*spinlock
, int pshared
)
1217 VALGRIND_GET_ORIG_FN(fn
);
1218 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK
,
1219 spinlock
, 0, 0, 0, 0);
1220 CALL_FN_W_WW(ret
, fn
, spinlock
, pshared
);
1221 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK
,
1222 spinlock
, 0, 0, 0, 0);
1226 PTH_FUNCS(int, pthreadZuspinZuinit
, pthread_spin_init_intercept
,
1227 (pthread_spinlock_t
*spinlock
, int pshared
), (spinlock
, pshared
));
1229 static __always_inline
1230 int pthread_spin_destroy_intercept(pthread_spinlock_t
*spinlock
)
1234 VALGRIND_GET_ORIG_FN(fn
);
1235 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY
,
1236 spinlock
, 0, 0, 0, 0);
1237 CALL_FN_W_W(ret
, fn
, spinlock
);
1238 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY
,
1239 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1243 PTH_FUNCS(int, pthreadZuspinZudestroy
, pthread_spin_destroy_intercept
,
1244 (pthread_spinlock_t
*spinlock
), (spinlock
));
1246 static __always_inline
1247 int pthread_spin_lock_intercept(pthread_spinlock_t
*spinlock
)
1251 VALGRIND_GET_ORIG_FN(fn
);
1252 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
1253 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1254 CALL_FN_W_W(ret
, fn
, spinlock
);
1255 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
1256 spinlock
, ret
== 0, 0, 0, 0);
1260 PTH_FUNCS(int, pthreadZuspinZulock
, pthread_spin_lock_intercept
,
1261 (pthread_spinlock_t
*spinlock
), (spinlock
));
1263 static __always_inline
1264 int pthread_spin_trylock_intercept(pthread_spinlock_t
*spinlock
)
1268 VALGRIND_GET_ORIG_FN(fn
);
1269 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
1270 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1271 CALL_FN_W_W(ret
, fn
, spinlock
);
1272 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
1273 spinlock
, ret
== 0, 0, 0, 0);
1277 PTH_FUNCS(int, pthreadZuspinZutrylock
, pthread_spin_trylock_intercept
,
1278 (pthread_spinlock_t
*spinlock
), (spinlock
));
1280 static __always_inline
1281 int pthread_spin_unlock_intercept(pthread_spinlock_t
*spinlock
)
1285 VALGRIND_GET_ORIG_FN(fn
);
1286 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK
,
1287 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1288 CALL_FN_W_W(ret
, fn
, spinlock
);
1289 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK
,
1290 spinlock
, 0, 0, 0, 0);
1294 PTH_FUNCS(int, pthreadZuspinZuunlock
, pthread_spin_unlock_intercept
,
1295 (pthread_spinlock_t
*spinlock
), (spinlock
));
1296 #endif // HAVE_PTHREAD_SPIN_LOCK
1299 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1300 static __always_inline
1301 int pthread_barrier_init_intercept(pthread_barrier_t
* barrier
,
1302 const pthread_barrierattr_t
* attr
,
1307 VALGRIND_GET_ORIG_FN(fn
);
1308 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_INIT
,
1309 barrier
, pthread_barrier
, count
, 0, 0);
1310 CALL_FN_W_WWW(ret
, fn
, barrier
, attr
, count
);
1311 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_INIT
,
1312 barrier
, pthread_barrier
, 0, 0, 0);
1316 PTH_FUNCS(int, pthreadZubarrierZuinit
, pthread_barrier_init_intercept
,
1317 (pthread_barrier_t
* barrier
, const pthread_barrierattr_t
* attr
,
1318 unsigned count
), (barrier
, attr
, count
));
1320 static __always_inline
1321 int pthread_barrier_destroy_intercept(pthread_barrier_t
* barrier
)
1325 VALGRIND_GET_ORIG_FN(fn
);
1326 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_DESTROY
,
1327 barrier
, pthread_barrier
, 0, 0, 0);
1328 CALL_FN_W_W(ret
, fn
, barrier
);
1329 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_DESTROY
,
1330 barrier
, pthread_barrier
, 0, 0, 0);
1334 PTH_FUNCS(int, pthreadZubarrierZudestroy
, pthread_barrier_destroy_intercept
,
1335 (pthread_barrier_t
* barrier
), (barrier
));
1337 static __always_inline
1338 int pthread_barrier_wait_intercept(pthread_barrier_t
* barrier
)
1342 VALGRIND_GET_ORIG_FN(fn
);
1343 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_WAIT
,
1344 barrier
, pthread_barrier
, 0, 0, 0);
1345 CALL_FN_W_W(ret
, fn
, barrier
);
1346 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_WAIT
,
1347 barrier
, pthread_barrier
,
1348 ret
== 0 || ret
== PTHREAD_BARRIER_SERIAL_THREAD
,
1349 ret
== PTHREAD_BARRIER_SERIAL_THREAD
, 0);
1353 PTH_FUNCS(int, pthreadZubarrierZuwait
, pthread_barrier_wait_intercept
,
1354 (pthread_barrier_t
* barrier
), (barrier
));
1355 #endif // HAVE_PTHREAD_BARRIER_INIT
1358 static __always_inline
1359 int sem_init_intercept(sem_t
*sem
, int pshared
, unsigned int value
)
1363 VALGRIND_GET_ORIG_FN(fn
);
1364 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT
,
1365 sem
, pshared
, value
, 0, 0);
1366 CALL_FN_W_WWW(ret
, fn
, sem
, pshared
, value
);
1367 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT
,
1372 PTH_FUNCS(int, semZuinit
, sem_init_intercept
,
1373 (sem_t
*sem
, int pshared
, unsigned int value
), (sem
, pshared
, value
));
1375 #if defined(VGO_solaris)
1376 static __always_inline
1377 int sema_init_intercept(sema_t
*sem
, unsigned int value
, int type
, void *arg
)
1381 VALGRIND_GET_ORIG_FN(fn
);
1382 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT
,
1383 sem
, type
== USYNC_PROCESS
? 1 : 0,
1385 CALL_FN_W_WWWW(ret
, fn
, sem
, value
, type
, arg
);
1386 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT
,
1391 PTH_FUNCS(int, semaZuinit
, sema_init_intercept
,
1392 (sema_t
*sem
, unsigned int value
, int type
, void *arg
),
1393 (sem
, value
, type
, arg
));
1394 #endif /* VGO_solaris */
1396 static __always_inline
1397 int sem_destroy_intercept(sem_t
*sem
)
1401 VALGRIND_GET_ORIG_FN(fn
);
1402 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_DESTROY
,
1404 CALL_FN_W_W(ret
, fn
, sem
);
1405 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_DESTROY
,
1410 PTH_FUNCS(int, semZudestroy
, sem_destroy_intercept
, (sem_t
*sem
), (sem
));
1411 #if defined(VGO_solaris)
1412 PTH_FUNCS(int, semaZudestroy
, sem_destroy_intercept
, (sem_t
*sem
), (sem
));
1413 #endif /* VGO_solaris */
1415 static __always_inline
1416 sem_t
* sem_open_intercept(const char *name
, int oflag
, mode_t mode
,
1421 VALGRIND_GET_ORIG_FN(fn
);
1422 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_OPEN
,
1423 name
, oflag
, mode
, value
, 0);
1424 CALL_FN_W_WWWW(ret
, fn
, name
, oflag
, mode
, value
);
1425 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_OPEN
,
1426 ret
!= SEM_FAILED
? ret
: 0,
1427 name
, oflag
, mode
, value
);
1431 PTH_FUNCS(sem_t
*, semZuopen
, sem_open_intercept
,
1432 (const char *name
, int oflag
, mode_t mode
, unsigned int value
),
1433 (name
, oflag
, mode
, value
));
1435 static __always_inline
int sem_close_intercept(sem_t
*sem
)
1439 VALGRIND_GET_ORIG_FN(fn
);
1440 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_CLOSE
,
1442 CALL_FN_W_W(ret
, fn
, sem
);
1443 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_CLOSE
,
1448 PTH_FUNCS(int, semZuclose
, sem_close_intercept
, (sem_t
*sem
), (sem
));
1450 static __always_inline
int sem_wait_intercept(sem_t
*sem
)
1454 VALGRIND_GET_ORIG_FN(fn
);
1455 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT
,
1457 CALL_FN_W_W(ret
, fn
, sem
);
1458 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT
,
1459 sem
, ret
== 0, 0, 0, 0);
1463 PTH_FUNCS(int, semZuwait
, sem_wait_intercept
, (sem_t
*sem
), (sem
));
1464 #if defined(VGO_solaris)
1465 PTH_FUNCS(int, semaZuwait
, sem_wait_intercept
, (sem_t
*sem
), (sem
));
1466 #endif /* VGO_solaris */
1468 static __always_inline
int sem_trywait_intercept(sem_t
*sem
)
1472 VALGRIND_GET_ORIG_FN(fn
);
1473 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT
,
1475 CALL_FN_W_W(ret
, fn
, sem
);
1476 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT
,
1477 sem
, ret
== 0, 0, 0, 0);
1481 PTH_FUNCS(int, semZutrywait
, sem_trywait_intercept
, (sem_t
*sem
), (sem
));
1482 #if defined(VGO_solaris)
1483 PTH_FUNCS(int, semaZutrywait
, sem_trywait_intercept
, (sem_t
*sem
), (sem
));
1484 #endif /* VGO_solaris */
1486 static __always_inline
1487 int sem_timedwait_intercept(sem_t
*sem
, const struct timespec
*abs_timeout
)
1491 VALGRIND_GET_ORIG_FN(fn
);
1492 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT
,
1494 CALL_FN_W_WW(ret
, fn
, sem
, abs_timeout
);
1495 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT
,
1496 sem
, ret
== 0, 0, 0, 0);
1500 PTH_FUNCS(int, semZutimedwait
, sem_timedwait_intercept
,
1501 (sem_t
*sem
, const struct timespec
*abs_timeout
),
1502 (sem
, abs_timeout
));
1503 #if defined(VGO_solaris)
1504 PTH_FUNCS(int, semaZutimedwait
, sem_timedwait_intercept
,
1505 (sem_t
*sem
, const struct timespec
*timeout
),
1507 PTH_FUNCS(int, semaZureltimedwait
, sem_timedwait_intercept
,
1508 (sem_t
*sem
, const struct timespec
*timeout
),
1510 #endif /* VGO_solaris */
1512 static __always_inline
int sem_post_intercept(sem_t
*sem
)
1516 VALGRIND_GET_ORIG_FN(fn
);
1517 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_POST
,
1519 CALL_FN_W_W(ret
, fn
, sem
);
1520 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_POST
,
1521 sem
, ret
== 0, 0, 0, 0);
1525 PTH_FUNCS(int, semZupost
, sem_post_intercept
, (sem_t
*sem
), (sem
));
1526 #if defined(VGO_solaris)
1527 PTH_FUNCS(int, semaZupost
, sem_post_intercept
, (sem_t
*sem
), (sem
));
1528 #endif /* VGO_solaris */
1530 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1531 functions have to be conditionally compiled. */
1532 #if defined(HAVE_PTHREAD_RWLOCK_T)
1534 static __always_inline
1535 int pthread_rwlock_init_intercept(pthread_rwlock_t
* rwlock
,
1536 const pthread_rwlockattr_t
* attr
)
1540 VALGRIND_GET_ORIG_FN(fn
);
1541 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT
,
1542 rwlock
, 0, 0, 0, 0);
1543 CALL_FN_W_WW(ret
, fn
, rwlock
, attr
);
1544 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT
,
1545 rwlock
, 0, 0, 0, 0);
1550 pthreadZurwlockZuinit
, pthread_rwlock_init_intercept
,
1551 (pthread_rwlock_t
* rwlock
, const pthread_rwlockattr_t
* attr
),
1554 #if defined(VGO_solaris)
1555 static __always_inline
1556 int rwlock_init_intercept(rwlock_t
*rwlock
, int type
, void *arg
)
1560 VALGRIND_GET_ORIG_FN(fn
);
1561 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT
,
1562 rwlock
, 0, 0, 0, 0);
1563 CALL_FN_W_WWW(ret
, fn
, rwlock
, type
, arg
);
1564 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT
,
1565 rwlock
, 0, 0, 0, 0);
1569 PTH_FUNCS(int, rwlockZuinit
, rwlock_init_intercept
,
1570 (rwlock_t
*rwlock
, int type
, void *arg
),
1571 (rwlock
, type
, arg
));
1572 #endif /* VGO_solaris */
1574 static __always_inline
1575 int pthread_rwlock_destroy_intercept(pthread_rwlock_t
* rwlock
)
1579 VALGRIND_GET_ORIG_FN(fn
);
1580 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_DESTROY
,
1581 rwlock
, 0, 0, 0, 0);
1582 CALL_FN_W_W(ret
, fn
, rwlock
);
1583 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_DESTROY
,
1584 rwlock
, 0, 0, 0, 0);
1588 #if defined(VGO_solaris)
1589 /* On Solaris, pthread_rwlock_destroy is a weak alias to rwlock_destroy. */
1591 rwlockZudestroy
, pthread_rwlock_destroy_intercept
,
1592 (pthread_rwlock_t
*rwlock
), (rwlock
));
1595 pthreadZurwlockZudestroy
, pthread_rwlock_destroy_intercept
,
1596 (pthread_rwlock_t
* rwlock
), (rwlock
));
1597 #endif /* VGO_solaris */
1599 static __always_inline
1600 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t
* rwlock
)
1604 VALGRIND_GET_ORIG_FN(fn
);
1605 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK
,
1606 rwlock
, 0, 0, 0, 0);
1607 CALL_FN_W_W(ret
, fn
, rwlock
);
1608 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK
,
1609 rwlock
, ret
== 0, 0, 0, 0);
1613 #if defined(VGO_solaris)
1614 /* On Solaris, pthread_rwlock_rdlock is a weak alias to rw_rdlock. */
1616 rwZurdlock
, pthread_rwlock_rdlock_intercept
,
1617 (pthread_rwlock_t
*rwlock
), (rwlock
));
1620 pthreadZurwlockZurdlock
, pthread_rwlock_rdlock_intercept
,
1621 (pthread_rwlock_t
* rwlock
), (rwlock
));
1622 #endif /* VGO_solaris */
1624 #if defined(VGO_solaris)
1625 /* Internal to libc. */
1626 static __always_inline
1627 void lrw_rdlock_intercept(rwlock_t
*rwlock
)
1630 VALGRIND_GET_ORIG_FN(fn
);
1631 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK
,
1632 rwlock
, 0, 0, 0, 0);
1633 CALL_FN_v_W(fn
, rwlock
);
1634 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK
,
1635 rwlock
, True
/* took_lock */, 0, 0, 0);
1638 PTH_FUNCS(void, lrwZurdlock
, lrw_rdlock_intercept
,
1639 (rwlock_t
*rwlock
), (rwlock
));
1640 #endif /* VGO_solaris */
1642 static __always_inline
1643 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t
* rwlock
)
1647 VALGRIND_GET_ORIG_FN(fn
);
1648 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK
,
1649 rwlock
, 0, 0, 0, 0);
1650 CALL_FN_W_W(ret
, fn
, rwlock
);
1651 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK
,
1652 rwlock
, ret
== 0, 0, 0, 0);
1656 #if defined(VGO_solaris)
1657 /* On Solaris, pthread_rwlock_wrlock is a weak alias to rw_wrlock. */
1659 rwZuwrlock
, pthread_rwlock_wrlock_intercept
,
1660 (pthread_rwlock_t
*rwlock
), (rwlock
));
1663 pthreadZurwlockZuwrlock
, pthread_rwlock_wrlock_intercept
,
1664 (pthread_rwlock_t
* rwlock
), (rwlock
));
1665 #endif /* VGO_solaris */
1667 #if defined(VGO_solaris)
1668 /* Internal to libc. */
1669 static __always_inline
1670 void lrw_wrlock_intercept(rwlock_t
*rwlock
)
1673 VALGRIND_GET_ORIG_FN(fn
);
1674 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK
,
1675 rwlock
, 0, 0, 0, 0);
1676 CALL_FN_v_W(fn
, rwlock
);
1677 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK
,
1678 rwlock
, True
/* took_lock */, 0, 0, 0);
1681 PTH_FUNCS(void, lrwZuwrlock
, lrw_wrlock_intercept
,
1682 (rwlock_t
*rwlock
), (rwlock
));
1683 #endif /* VGO_solaris */
1685 static __always_inline
1686 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t
* rwlock
,
1687 const struct timespec
*timeout
)
1691 VALGRIND_GET_ORIG_FN(fn
);
1692 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK
,
1693 rwlock
, 0, 0, 0, 0);
1694 CALL_FN_W_WW(ret
, fn
, rwlock
, timeout
);
1695 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK
,
1696 rwlock
, ret
== 0, 0, 0, 0);
1701 pthreadZurwlockZutimedrdlock
, pthread_rwlock_timedrdlock_intercept
,
1702 (pthread_rwlock_t
* rwlock
, const struct timespec
*timeout
),
1704 #if defined(VGO_solaris)
1705 PTH_FUNCS(int, pthreadZurwlockZureltimedrdlockZunp
,
1706 pthread_rwlock_timedrdlock_intercept
,
1707 (pthread_rwlock_t
*rwlock
, const struct timespec
*timeout
),
1709 #endif /* VGO_solaris */
1711 static __always_inline
1712 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t
* rwlock
,
1713 const struct timespec
*timeout
)
1717 VALGRIND_GET_ORIG_FN(fn
);
1718 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK
,
1719 rwlock
, 0, 0, 0, 0);
1720 CALL_FN_W_WW(ret
, fn
, rwlock
, timeout
);
1721 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK
,
1722 rwlock
, ret
== 0, 0, 0, 0);
1727 pthreadZurwlockZutimedwrlock
, pthread_rwlock_timedwrlock_intercept
,
1728 (pthread_rwlock_t
* rwlock
, const struct timespec
*timeout
),
1730 #if defined(VGO_solaris)
1731 PTH_FUNCS(int, pthreadZurwlockZureltimedwrlockZunp
,
1732 pthread_rwlock_timedwrlock_intercept
,
1733 (pthread_rwlock_t
*rwlock
, const struct timespec
*timeout
),
1735 #endif /* VGO_solaris */
1737 static __always_inline
1738 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t
* rwlock
)
1742 VALGRIND_GET_ORIG_FN(fn
);
1743 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK
,
1744 rwlock
, 0, 0, 0, 0);
1745 CALL_FN_W_W(ret
, fn
, rwlock
);
1746 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK
,
1747 rwlock
, ret
== 0, 0, 0, 0);
1751 #if defined(VGO_solaris)
1752 /* On Solaris, pthread_rwlock_tryrdlock is a weak alias to rw_tryrdlock. */
1754 rwZutryrdlock
, pthread_rwlock_tryrdlock_intercept
,
1755 (pthread_rwlock_t
*rwlock
), (rwlock
));
1758 pthreadZurwlockZutryrdlock
, pthread_rwlock_tryrdlock_intercept
,
1759 (pthread_rwlock_t
* rwlock
), (rwlock
));
1760 #endif /* VGO_solaris */
1762 static __always_inline
1763 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t
* rwlock
)
1767 VALGRIND_GET_ORIG_FN(fn
);
1768 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK
,
1769 rwlock
, 0, 0, 0, 0);
1770 CALL_FN_W_W(ret
, fn
, rwlock
);
1771 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK
,
1772 rwlock
, ret
== 0, 0, 0, 0);
1776 #if defined(VGO_solaris)
1777 /* On Solaris, pthread_rwlock_trywrlock is a weak alias to rw_trywrlock. */
1779 rwZutrywrlock
, pthread_rwlock_trywrlock_intercept
,
1780 (pthread_rwlock_t
*rwlock
), (rwlock
));
1783 pthreadZurwlockZutrywrlock
, pthread_rwlock_trywrlock_intercept
,
1784 (pthread_rwlock_t
* rwlock
), (rwlock
));
1785 #endif /* VGO_solaris */
1787 static __always_inline
1788 int pthread_rwlock_unlock_intercept(pthread_rwlock_t
* rwlock
)
1792 VALGRIND_GET_ORIG_FN(fn
);
1793 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_UNLOCK
,
1794 rwlock
, 0, 0, 0, 0);
1795 CALL_FN_W_W(ret
, fn
, rwlock
);
1796 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_UNLOCK
,
1797 rwlock
, ret
== 0, 0, 0, 0);
1801 #if defined(VGO_solaris)
1802 /* On Solaris, pthread_rwlock_unlock is a weak alias to rw_unlock. */
1804 rwZuunlock
, pthread_rwlock_unlock_intercept
,
1805 (pthread_rwlock_t
*rwlock
), (rwlock
));
1808 pthreadZurwlockZuunlock
, pthread_rwlock_unlock_intercept
,
1809 (pthread_rwlock_t
* rwlock
), (rwlock
));
1810 #endif /* VGO_solaris */
1812 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */