1 /*--------------------------------------------------------------------*/
2 /*--- Client-space code for DRD. drd_pthread_intercepts.c ---*/
3 /*--------------------------------------------------------------------*/
6 This file is part of DRD, a thread error detector.
8 Copyright (C) 2006-2020 Bart Van Assche <bvanassche@acm.org>.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2 of the
13 License, or (at your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, see <http://www.gnu.org/licenses/>.
23 The GNU General Public License is contained in the file COPYING.
26 /* ---------------------------------------------------------------------
27 ALL THE CODE IN THIS FILE RUNS ON THE SIMULATED CPU.
29 These functions are not called directly - they're the targets of code
30 redirection or load notifications (see pub_core_redir.h for info).
31 They're named weirdly so that the intercept code can find them when the
32 shared object is initially loaded.
34 Note that this filename has the "drd_" prefix because it can appear
35 in stack traces, and the "drd_" makes it a little clearer that it
36 originates from Valgrind.
37 ------------------------------------------------------------------ */
40 * Define _GNU_SOURCE to make sure that pthread_spinlock_t is available when
41 * compiling with older glibc versions (2.3 or before).
47 #include <assert.h> /* assert() */
49 #include <pthread.h> /* pthread_mutex_t */
50 #include <semaphore.h> /* sem_t */
51 #include <stdint.h> /* uintptr_t */
52 #include <stdio.h> /* fprintf() */
53 #include <stdlib.h> /* malloc(), free() */
54 #include <unistd.h> /* confstr() */
55 #include "config.h" /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP etc. */
56 #include "drd_basics.h" /* DRD_() */
57 #include "drd_clientreq.h"
58 #include "pub_tool_redir.h" /* VG_WRAP_FUNCTION_ZZ() */
60 #if defined(VGO_solaris)
62 * Solaris usually provides pthread_* functions on top of Solaris threading
63 * and synchronization functions. Usually both need to be intercepted because
64 * pthread_* ones might not call the Solaris ones (see for example sem_wait()).
65 * Such approach is required to correctly report misuse of the POSIX threads
67 * Therefore DRD intercepts and instruments all such functions but due to
68 * DRD_(thread_enter_synchr)() and DRD_(thread_leave_synchr)() guards in
69 * handle_client_request(), only the top-most function is handled.
70 * So the right thing(TM) happens, as expected.
71 * The only exception is when pthread_* function is a weak alias to the Solaris
72 * threading/synchronization function. In such case only one needs to be
73 * intercepted to avoid redirection ambiguity.
75 * Intercepted functions rely on the fact that:
76 * - pthread_mutex_t == mutex_t
77 * - pthread_cond_t == cond_t
79 * - pthread_rwlock_t == rwlock_t
81 * It is necessary to intercept also internal libc synchronization functions
83 * - For read-write locks the unlocking function is shared
84 * - Functions lmutex_lock/lmutex_unlock guard many critical sections in libc
85 * which will be otherwise reported by DRD
89 #include "pub_tool_vki.h"
92 * Solaris provides higher throughput, parallelism and scalability than other
93 * operating systems, at the cost of more fine-grained locking activity.
94 * This means for example that when a thread is created under Linux, just one
95 * big lock in glibc is used for all thread setup. Solaris libc uses several
96 * fine-grained locks and the creator thread resumes its activities as soon
97 * as possible, leaving for example stack and TLS setup activities to the
100 * This situation confuses DRD as it assumes there is some false ordering
101 * in place between creator and created thread; and therefore many types of
102 * race conditions in the application would not be reported. To prevent such
103 * false ordering, command line option --ignore-thread-creation is set to
104 * 'yes' by default on Solaris. All activity (loads, stores, client requests)
105 * is therefore ignored during:
106 * - pthread_create() call in the creator thread [libc.so]
107 * - thread creation phase (stack and TLS setup) in the created thread [libc.so]
109 * As explained in the comments for _ti_bind_guard(), whenever the runtime
110 * linker has to perform any activity (such as resolving a symbol), it protects
111 * its data structures by calling into rt_bind_guard() which in turn invokes
112 * _ti_bind_guard() in libc. Pointers to _ti_bind_guard() and _ti_bind_clear()
113 * are passed from libc to runtime linker in _ld_libc() call during libc_init().
114 * All activity is also ignored during:
115 * - runtime dynamic linker work between rt_bind_guard() and rt_bind_clear()
118 * This also means that DRD does not report race conditions in libc (when
119 * --ignore-thread-creation=yes) and runtime linker itself (unconditionally)
120 * during these ignored sequences.
124 * Original function pointers for _ti_bind_guard() and _ti_bind_clear()
125 * from libc. They are intercepted in function wrapper of _ld_libc().
127 typedef int (*drd_rtld_guard_fn
)(int flags
);
128 static drd_rtld_guard_fn
DRD_(rtld_bind_guard
) = NULL
;
129 static drd_rtld_guard_fn
DRD_(rtld_bind_clear
) = NULL
;
134 * Notes regarding thread creation:
135 * - sg_init() runs on the context of the created thread and copies the vector
136 * clock of the creator thread. This only works reliably if the creator
137 * thread waits until this copy has been performed.
138 * - DRD_(thread_compute_minimum_vc)() does not take the vector clocks into
139 * account that are involved in thread creation and for which the
140 * corresponding thread has not yet been created. So not waiting until the
141 * created thread has been started would make it possible that segments get
142 * discarded that should not yet be discarded. Or: some data races are not
147 * Macro for generating a Valgrind interception function.
148 * @param[in] ret_ty Return type of the function to be generated.
149 * @param[in] zf Z-encoded name of the interception function.
150 * @param[in] implf Name of the function that implements the intercept.
151 * @param[in] arg_decl Argument declaration list enclosed in parentheses.
152 * @param[in] argl Argument list enclosed in parentheses.
154 #if defined(VGO_darwin)
156 * Note here VGO_darwin is used rather than VG_WRAP_THREAD_FUNCTION_LIBPTHREAD_ONLY
157 * because of the special-case code adding a function call
159 static int never_true
;
160 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
161 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
162 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
164 ret_ty pth_func_result = implf argl; \
165 /* Apparently inserting a function call in wrapper functions */ \
166 /* is sufficient to avoid misaligned stack errors. */ \
169 return pth_func_result; \
171 #elif defined(VG_WRAP_THREAD_FUNCTION_LIBC_ONLY)
172 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
173 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl; \
174 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl \
175 { return implf argl; }
176 #elif defined(VG_WRAP_THREAD_FUNCTION_LIBC_AND_LIBPTHREAD)
177 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
178 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl; \
179 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl \
180 { return implf argl; } \
181 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
182 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
183 { return implf argl; }
185 # error "Unknown platform/thread wrapping"
189 * Macro for generating three Valgrind interception functions: one with the
190 * Z-encoded name zf, one with ZAZa ("@*") appended to the name zf and one
191 * with ZDZa ("$*") appended to the name zf. The second generated interception
192 * function will intercept versioned symbols on Linux, and the third will
193 * intercept versioned symbols on Darwin.
195 #define PTH_FUNCS(ret_ty, zf, implf, argl_decl, argl) \
196 PTH_FUNC(ret_ty, zf, implf, argl_decl, argl); \
197 PTH_FUNC(ret_ty, zf ## ZAZa, implf, argl_decl, argl); \
198 PTH_FUNC(ret_ty, zf ## ZDZa, implf, argl_decl, argl);
201 * Not inlining one of the intercept functions will cause the regression
202 * tests to fail because this would cause an additional stackfram to appear
203 * in the output. The __always_inline macro guarantees that inlining will
204 * happen, even when compiling with optimization disabled.
206 #undef __always_inline /* since already defined in <cdefs.h> */
207 #if __GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 2
208 #define __always_inline __inline__ __attribute__((always_inline))
210 #define __always_inline __inline__
213 /* Local data structures. */
216 pthread_mutex_t mutex
;
223 void* (*start
)(void*);
226 DrdSema
* wrapper_started
;
227 } DrdPosixThreadArgs
;
230 /* Local function declarations. */
232 static void DRD_(init
)(void) __attribute__((constructor
));
233 static void DRD_(check_threading_library
)(void);
234 static void DRD_(set_pthread_id
)(void);
235 static void DRD_(sema_init
)(DrdSema
* sema
);
236 static void DRD_(sema_destroy
)(DrdSema
* sema
);
237 static void DRD_(sema_down
)(DrdSema
* sema
);
238 static void DRD_(sema_up
)(DrdSema
* sema
);
241 /* Function definitions. */
244 * Shared library initialization function. The function init() is called after
245 * dlopen() has loaded the shared library with DRD client intercepts because
246 * the constructor attribute was specified in the declaration of this function.
247 * Note: do specify the -nostdlib option to gcc when linking this code into a
248 * shared library because doing so would cancel the effect of the constructor
249 * attribute ! Using the gcc option -nodefaultlibs is fine because this last
250 * option preserves the shared library initialization code that calls
251 * constructor and destructor functions.
253 static void DRD_(init
)(void)
255 DRD_(check_threading_library
)();
256 DRD_(set_pthread_id
)();
257 #if defined(VGO_solaris)
258 if ((DRD_(rtld_bind_guard
) == NULL
) || (DRD_(rtld_bind_clear
) == NULL
)) {
260 "Bind guard functions for the runtime linker (ld.so.1) were not intercepted.\n"
261 "This means the interface between libc and runtime linker changed and DRD\n"
262 "needs to be ported properly. Giving up.\n");
268 static __always_inline
void DRD_(ignore_mutex_ordering
)(pthread_mutex_t
*mutex
)
270 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_IGNORE_MUTEX_ORDERING
,
274 static void DRD_(sema_init
)(DrdSema
* sema
)
276 DRD_IGNORE_VAR(*sema
);
277 pthread_mutex_init(&sema
->mutex
, NULL
);
278 DRD_(ignore_mutex_ordering
)(&sema
->mutex
);
279 pthread_cond_init(&sema
->cond
, NULL
);
283 static void DRD_(sema_destroy
)(DrdSema
* sema
)
285 pthread_mutex_destroy(&sema
->mutex
);
286 pthread_cond_destroy(&sema
->cond
);
289 static void DRD_(sema_down
)(DrdSema
* sema
)
291 pthread_mutex_lock(&sema
->mutex
);
292 while (sema
->counter
== 0)
293 pthread_cond_wait(&sema
->cond
, &sema
->mutex
);
295 pthread_mutex_unlock(&sema
->mutex
);
298 static void DRD_(sema_up
)(DrdSema
* sema
)
300 pthread_mutex_lock(&sema
->mutex
);
302 pthread_cond_signal(&sema
->cond
);
303 pthread_mutex_unlock(&sema
->mutex
);
307 * POSIX threads and DRD each have their own mutex type identification.
308 * Convert POSIX threads' mutex type to DRD's mutex type. In the code below
309 * if-statements are used to test the value of 'kind' instead of a switch
310 * statement because some of the PTHREAD_MUTEX_ macro's may have the same
313 static MutexT
DRD_(pthread_to_drd_mutex_type
)(int kind
)
316 * See also PTHREAD_MUTEX_KIND_MASK_NP in glibc source file
319 kind
&= PTHREAD_MUTEX_RECURSIVE
| PTHREAD_MUTEX_ERRORCHECK
|
320 PTHREAD_MUTEX_NORMAL
| PTHREAD_MUTEX_DEFAULT
;
322 if (kind
== PTHREAD_MUTEX_RECURSIVE
)
323 return mutex_type_recursive_mutex
;
324 else if (kind
== PTHREAD_MUTEX_ERRORCHECK
)
325 return mutex_type_errorcheck_mutex
;
326 else if (kind
== PTHREAD_MUTEX_NORMAL
)
327 return mutex_type_default_mutex
;
328 else if (kind
== PTHREAD_MUTEX_DEFAULT
)
329 return mutex_type_default_mutex
;
330 #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
331 else if (kind
== PTHREAD_MUTEX_ADAPTIVE_NP
)
332 return mutex_type_default_mutex
;
335 return mutex_type_invalid_mutex
;
338 #if defined(VGO_solaris)
340 * Solaris threads and DRD each have their own mutex type identification.
341 * Convert Solaris threads' mutex type to DRD's mutex type.
343 static MutexT
DRD_(thread_to_drd_mutex_type
)(int type
)
345 if (type
& LOCK_RECURSIVE
) {
346 return mutex_type_recursive_mutex
;
347 } else if (type
& LOCK_ERRORCHECK
) {
348 return mutex_type_errorcheck_mutex
;
350 return mutex_type_default_mutex
;
353 #endif /* VGO_solaris */
355 #define IS_ALIGNED(p) (((uintptr_t)(p) & (sizeof(*(p)) - 1)) == 0)
358 * Read the mutex type stored in the client memory used for the mutex
361 * @note This function depends on the implementation of the POSIX threads
362 * library -- the POSIX standard does not define the name of the member in
363 * which the mutex type is stored.
364 * @note The function mutex_type() has been declared inline in order
365 * to avoid that it shows up in call stacks (drd/tests/...exp* files).
366 * @note glibc stores the mutex type in the lowest two bits, and uses the
367 * higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
368 * PTHREAD_MUTEXATTR_FLAG_PSHARED.
370 static __always_inline MutexT
DRD_(mutex_type
)(pthread_mutex_t
* mutex
)
372 MutexT mutex_type
= mutex_type_unknown
;
374 ANNOTATE_IGNORE_READS_BEGIN();
375 #if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
376 /* glibc + LinuxThreads. */
377 if (IS_ALIGNED(&mutex
->__m_kind
))
379 const int kind
= mutex
->__m_kind
& 3;
380 mutex_type
= DRD_(pthread_to_drd_mutex_type
)(kind
);
382 #elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
384 if (IS_ALIGNED(&mutex
->__data
.__kind
))
386 const int kind
= mutex
->__data
.__kind
& 3;
387 mutex_type
= DRD_(pthread_to_drd_mutex_type
)(kind
);
389 #elif defined(VGO_solaris)
391 const int type
= ((mutex_t
*) mutex
)->vki_mutex_type
;
392 mutex_type
= DRD_(thread_to_drd_mutex_type
)(type
);
396 * Another POSIX threads implementation. The mutex type won't be printed
397 * when enabling --trace-mutex=yes.
400 ANNOTATE_IGNORE_READS_END();
406 * Tell DRD whether 'tid' is a joinable thread or a detached thread.
408 static void DRD_(set_joinable
)(const pthread_t tid
, const int joinable
)
410 assert(joinable
== 0 || joinable
== 1);
411 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_JOINABLE
,
412 tid
, joinable
, 0, 0, 0);
415 /** Tell DRD that the calling thread is about to enter pthread_create(). */
416 static __always_inline
void DRD_(entering_pthread_create
)(void)
418 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__ENTERING_PTHREAD_CREATE
,
422 /** Tell DRD that the calling thread has left pthread_create(). */
423 static __always_inline
void DRD_(left_pthread_create
)(void)
425 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LEFT_PTHREAD_CREATE
,
430 * Entry point for newly created threads. This function is called from the
431 * thread created by pthread_create().
433 static void* DRD_(thread_wrapper
)(void* arg
)
435 DrdPosixThreadArgs
* arg_ptr
;
436 DrdPosixThreadArgs arg_copy
;
438 arg_ptr
= (DrdPosixThreadArgs
*)arg
;
441 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID
,
442 pthread_self(), 0, 0, 0, 0);
444 DRD_(set_joinable
)(pthread_self(),
445 arg_copy
.detachstate
== PTHREAD_CREATE_JOINABLE
);
448 * Only set 'wrapper_started' after VG_USERREQ__SET_PTHREADID and
449 * DRD_(set_joinable)() have been invoked to avoid a race with
450 * a pthread_detach() invocation for this thread from another thread.
452 DRD_(sema_up
)(arg_copy
.wrapper_started
);
454 return (arg_copy
.start
)(arg_copy
.arg
);
458 * Return 1 if the LinuxThreads implementation of POSIX Threads has been
459 * detected, and 0 otherwise.
461 * @see For more information about the confstr() function, see also
462 * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
464 static int DRD_(detected_linuxthreads
)(void)
467 #if defined(_CS_GNU_LIBPTHREAD_VERSION)
468 /* Linux with a recent glibc. */
471 len
= confstr(_CS_GNU_LIBPTHREAD_VERSION
, buffer
, sizeof(buffer
));
472 assert(len
<= sizeof(buffer
));
473 return len
> 0 && buffer
[0] == 'l';
475 /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
479 /* Another OS than Linux, hence no LinuxThreads. */
485 * Stop and print an error message in case a non-supported threading
486 * library implementation (LinuxThreads) has been detected.
488 static void DRD_(check_threading_library
)(void)
490 if (DRD_(detected_linuxthreads
)())
492 if (getenv("LD_ASSUME_KERNEL"))
495 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
496 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
497 "after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
503 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
504 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
505 "after having upgraded to a newer version of your Linux distribution.\n"
514 * Update DRD's state information about the current thread.
516 static void DRD_(set_pthread_id
)(void)
518 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID
,
519 pthread_self(), 0, 0, 0, 0);
523 * Note: as of today there exist three different versions of pthread_create
525 * - pthread_create@GLIBC_2.0
526 * - pthread_create@@GLIBC_2.1
527 * - pthread_create@@GLIBC_2.2.5
528 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
529 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
530 * versions have been implemented. In any glibc version where more than one
531 * pthread_create function has been implemented, older versions call the
532 * newer versions. Or: the pthread_create* wrapper defined below can be
533 * called recursively. Any code in this wrapper should take this in account.
534 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
535 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
536 * See also the implementation of pthread_create@GLIBC_2.0 in
537 * glibc-2.9/nptl/pthread_create.c.
540 static __always_inline
541 int pthread_create_intercept(pthread_t
* thread
, const pthread_attr_t
* attr
,
542 void* (*start
)(void*), void* arg
)
546 DrdSema wrapper_started
;
547 DrdPosixThreadArgs thread_args
;
549 VALGRIND_GET_ORIG_FN(fn
);
551 DRD_(sema_init
)(&wrapper_started
);
552 thread_args
.start
= start
;
553 thread_args
.arg
= arg
;
554 thread_args
.wrapper_started
= &wrapper_started
;
556 * Find out whether the thread will be started as a joinable thread
557 * or as a detached thread. If no thread attributes have been specified,
558 * this means that the new thread will be started as a joinable thread.
560 thread_args
.detachstate
= PTHREAD_CREATE_JOINABLE
;
563 if (pthread_attr_getdetachstate(attr
, &thread_args
.detachstate
) != 0)
566 assert(thread_args
.detachstate
== PTHREAD_CREATE_JOINABLE
567 || thread_args
.detachstate
== PTHREAD_CREATE_DETACHED
);
570 * The DRD_(set_pthread_id)() from DRD_(init)() may encounter that
571 * pthread_self() == 0, e.g. when the main program is not linked with the
572 * pthread library and when a pthread_create() call occurs from within a
573 * shared library. Hence call DRD_(set_pthread_id)() again to ensure that
574 * DRD knows the identity of the current thread. See also B.Z. 356374.
576 DRD_(set_pthread_id
)();
577 DRD_(entering_pthread_create
)();
578 CALL_FN_W_WWWW(ret
, fn
, thread
, attr
, DRD_(thread_wrapper
), &thread_args
);
579 DRD_(left_pthread_create
)();
582 /* Wait until the thread wrapper started. */
583 DRD_(sema_down
)(&wrapper_started
);
586 DRD_(sema_destroy
)(&wrapper_started
);
588 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT
,
589 pthread_self(), 0, 0, 0, 0);
594 PTH_FUNCS(int, pthreadZucreate
, pthread_create_intercept
,
595 (pthread_t
*thread
, const pthread_attr_t
*attr
,
596 void *(*start
) (void *), void *arg
),
597 (thread
, attr
, start
, arg
));
599 #if defined(VGO_solaris)
600 /* Solaris also provides thr_create() in addition to pthread_create().
601 * Both pthread_create(3C) and thr_create(3C) are based on private
604 static __always_inline
605 int thr_create_intercept(void *stk
, size_t stksize
, void *(*start
)(void *),
606 void *arg
, long flags
, thread_t
*new_thread
)
610 DrdSema wrapper_started
;
611 DrdPosixThreadArgs thread_args
;
613 VALGRIND_GET_ORIG_FN(fn
);
615 DRD_(sema_init
)(&wrapper_started
);
616 thread_args
.start
= start
;
617 thread_args
.arg
= arg
;
618 thread_args
.wrapper_started
= &wrapper_started
;
620 * Find out whether the thread will be started as a joinable thread
621 * or as a detached thread.
623 if (flags
& THR_DETACHED
)
624 thread_args
.detachstate
= PTHREAD_CREATE_DETACHED
;
626 thread_args
.detachstate
= PTHREAD_CREATE_JOINABLE
;
628 DRD_(entering_pthread_create
)();
629 CALL_FN_W_6W(ret
, fn
, stk
, stksize
, DRD_(thread_wrapper
), &thread_args
,
631 DRD_(left_pthread_create
)();
634 /* Wait until the thread wrapper started. */
635 DRD_(sema_down
)(&wrapper_started
);
638 DRD_(sema_destroy
)(&wrapper_started
);
640 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT
,
641 pthread_self(), 0, 0, 0, 0);
646 PTH_FUNCS(int, thrZucreate
, thr_create_intercept
,
647 (void *stk
, size_t stksize
, void *(*start
)(void *), void *arg
,
648 long flags
, thread_t
*new_thread
),
649 (stk
, stksize
, start
, arg
, flags
, new_thread
));
650 #endif /* VGO_solaris */
652 #if defined(VGO_solaris)
654 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
655 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
656 * and CI_BIND_CLEAR, to provide resilience against function renaming.
658 static __always_inline
659 int DRD_(_ti_bind_guard_intercept
)(int flags
) {
660 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_GUARD
,
662 return DRD_(rtld_bind_guard
)(flags
);
665 static __always_inline
666 int DRD_(_ti_bind_clear_intercept
)(int flags
) {
667 int ret
= DRD_(rtld_bind_clear
)(flags
);
668 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_CLEAR
,
674 * Wrapped _ld_libc() from the runtime linker ld.so.1.
676 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1
, ZuldZulibc
)(vki_Lc_interface
*ptr
);
677 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1
, ZuldZulibc
)(vki_Lc_interface
*ptr
)
682 VALGRIND_GET_ORIG_FN(fn
);
684 vki_Lc_interface
*funcs
= ptr
;
685 for (tag
= funcs
->ci_tag
; tag
!= 0; tag
= (++funcs
)->ci_tag
) {
687 case VKI_CI_BIND_GUARD
:
688 if (funcs
->vki_ci_un
.ci_func
!= DRD_(_ti_bind_guard_intercept
)) {
689 DRD_(rtld_bind_guard
) = funcs
->vki_ci_un
.ci_func
;
690 funcs
->vki_ci_un
.ci_func
= DRD_(_ti_bind_guard_intercept
);
693 case VKI_CI_BIND_CLEAR
:
694 if (funcs
->vki_ci_un
.ci_func
!= DRD_(_ti_bind_clear_intercept
)) {
695 DRD_(rtld_bind_clear
) = funcs
->vki_ci_un
.ci_func
;
696 funcs
->vki_ci_un
.ci_func
= DRD_(_ti_bind_clear_intercept
);
702 CALL_FN_v_W(fn
, ptr
);
704 #endif /* VGO_solaris */
706 static __always_inline
707 int pthread_join_intercept(pthread_t pt_joinee
, void **thread_return
)
712 VALGRIND_GET_ORIG_FN(fn
);
714 * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
715 * implementation triggers a (false positive) race report.
717 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
718 CALL_FN_W_WW(ret
, fn
, pt_joinee
, thread_return
);
721 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN
,
722 pt_joinee
, 0, 0, 0, 0);
724 ANNOTATE_IGNORE_READS_AND_WRITES_END();
728 PTH_FUNCS(int, pthreadZujoin
, pthread_join_intercept
,
729 (pthread_t pt_joinee
, void **thread_return
),
730 (pt_joinee
, thread_return
));
732 #if defined(VGO_solaris)
733 /* Solaris also provides thr_join() in addition to pthread_join().
734 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
736 * :TODO: No functionality is currently provided for joinee == 0 and departed.
737 * This would require another client request, of course.
739 static __always_inline
740 int thr_join_intercept(thread_t joinee
, thread_t
*departed
, void **thread_return
)
745 VALGRIND_GET_ORIG_FN(fn
);
746 CALL_FN_W_WWW(ret
, fn
, joinee
, departed
, thread_return
);
749 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN
,
755 PTH_FUNCS(int, thrZujoin
, thr_join_intercept
,
756 (thread_t joinee
, thread_t
*departed
, void **thread_return
),
757 (joinee
, departed
, thread_return
));
758 #endif /* VGO_solaris */
760 static __always_inline
761 int pthread_detach_intercept(pthread_t pt_thread
)
766 VALGRIND_GET_ORIG_FN(fn
);
767 CALL_FN_W_W(ret
, fn
, pt_thread
);
768 DRD_(set_joinable
)(pt_thread
, 0);
773 PTH_FUNCS(int, pthreadZudetach
, pthread_detach_intercept
,
774 (pthread_t thread
), (thread
));
776 // NOTE: be careful to intercept only pthread_cancel() and not
777 // pthread_cancel_init() on Linux.
779 static __always_inline
780 int pthread_cancel_intercept(pthread_t pt_thread
)
784 VALGRIND_GET_ORIG_FN(fn
);
785 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_THREAD_CANCEL
,
786 pt_thread
, 0, 0, 0, 0);
787 CALL_FN_W_W(ret
, fn
, pt_thread
);
788 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_CANCEL
,
789 pt_thread
, ret
==0, 0, 0, 0);
793 PTH_FUNCS(int, pthreadZucancel
, pthread_cancel_intercept
,
794 (pthread_t thread
), (thread
))
796 static __always_inline
797 int pthread_once_intercept(pthread_once_t
*once_control
,
798 void (*init_routine
)(void))
802 VALGRIND_GET_ORIG_FN(fn
);
804 * Ignore any data races triggered by the implementation of pthread_once().
805 * Necessary for Darwin. This is not necessary for Linux but doesn't have
806 * any known adverse effects.
808 DRD_IGNORE_VAR(*once_control
);
809 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
810 CALL_FN_W_WW(ret
, fn
, once_control
, init_routine
);
811 ANNOTATE_IGNORE_READS_AND_WRITES_END();
812 DRD_STOP_IGNORING_VAR(*once_control
);
816 PTH_FUNCS(int, pthreadZuonce
, pthread_once_intercept
,
817 (pthread_once_t
*once_control
, void (*init_routine
)(void)),
818 (once_control
, init_routine
));
820 static __always_inline
821 int pthread_mutex_init_intercept(pthread_mutex_t
*mutex
,
822 const pthread_mutexattr_t
* attr
)
827 VALGRIND_GET_ORIG_FN(fn
);
828 mt
= PTHREAD_MUTEX_DEFAULT
;
830 pthread_mutexattr_gettype(attr
, &mt
);
831 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT
,
832 mutex
, DRD_(pthread_to_drd_mutex_type
)(mt
),
834 CALL_FN_W_WW(ret
, fn
, mutex
, attr
);
835 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT
,
840 PTH_FUNCS(int, pthreadZumutexZuinit
, pthread_mutex_init_intercept
,
841 (pthread_mutex_t
*mutex
, const pthread_mutexattr_t
* attr
),
844 #if defined(VGO_solaris)
845 static __always_inline
846 int mutex_init_intercept(mutex_t
*mutex
, int type
, void *arg
)
850 VALGRIND_GET_ORIG_FN(fn
);
852 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT
,
853 mutex
, DRD_(thread_to_drd_mutex_type
)(type
),
855 CALL_FN_W_WWW(ret
, fn
, mutex
, type
, arg
);
856 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT
,
861 PTH_FUNCS(int, mutexZuinit
, mutex_init_intercept
,
862 (mutex_t
*mutex
, int type
, void *arg
),
864 #endif /* VGO_solaris */
866 static __always_inline
867 int pthread_mutex_destroy_intercept(pthread_mutex_t
* mutex
)
871 VALGRIND_GET_ORIG_FN(fn
);
872 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY
,
874 CALL_FN_W_W(ret
, fn
, mutex
);
875 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY
,
876 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
880 #if defined(VGO_solaris)
881 /* On Solaris, pthread_mutex_destroy is a weak alias to mutex_destroy. */
882 PTH_FUNCS(int, mutexZudestroy
, pthread_mutex_destroy_intercept
,
883 (pthread_mutex_t
*mutex
), (mutex
));
885 PTH_FUNCS(int, pthreadZumutexZudestroy
, pthread_mutex_destroy_intercept
,
886 (pthread_mutex_t
*mutex
), (mutex
));
887 #endif /* VGO_solaris */
889 static __always_inline
890 int pthread_mutex_lock_intercept(pthread_mutex_t
* mutex
)
894 VALGRIND_GET_ORIG_FN(fn
);
895 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
896 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
897 CALL_FN_W_W(ret
, fn
, mutex
);
898 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
899 mutex
, ret
== 0, 0, 0, 0);
903 #if defined(VGO_solaris)
904 /* On Solaris, pthread_mutex_lock is a weak alias to mutex_lock. */
905 PTH_FUNCS(int, mutexZulock
, pthread_mutex_lock_intercept
,
906 (pthread_mutex_t
*mutex
), (mutex
));
908 PTH_FUNCS(int, pthreadZumutexZulock
, pthread_mutex_lock_intercept
,
909 (pthread_mutex_t
*mutex
), (mutex
));
910 #endif /* VGO_solaris */
912 #if defined(VGO_solaris)
913 /* Internal to libc. Mutex is usually initialized only implicitly,
914 * by zeroing mutex_t structure.
916 static __always_inline
917 void lmutex_lock_intercept(mutex_t
*mutex
)
920 VALGRIND_GET_ORIG_FN(fn
);
921 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
923 DRD_(mutex_type
)((pthread_mutex_t
*) mutex
),
924 False
/* try_lock */, 0, 0);
925 CALL_FN_v_W(fn
, mutex
);
926 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
927 mutex
, True
/* took_lock */, 0, 0, 0);
930 PTH_FUNCS(void, lmutexZulock
, lmutex_lock_intercept
,
931 (mutex_t
*mutex
), (mutex
));
932 #endif /* VGO_solaris */
934 static __always_inline
935 int pthread_mutex_trylock_intercept(pthread_mutex_t
* mutex
)
939 VALGRIND_GET_ORIG_FN(fn
);
940 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
941 mutex
, DRD_(mutex_type
)(mutex
), 1, 0, 0);
942 CALL_FN_W_W(ret
, fn
, mutex
);
943 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
944 mutex
, ret
== 0, 0, 0, 0);
948 #if defined(VGO_solaris)
949 /* On Solaris, pthread_mutex_trylock is a weak alias to mutex_trylock. */
950 PTH_FUNCS(int, mutexZutrylock
, pthread_mutex_trylock_intercept
,
951 (pthread_mutex_t
*mutex
), (mutex
));
953 PTH_FUNCS(int, pthreadZumutexZutrylock
, pthread_mutex_trylock_intercept
,
954 (pthread_mutex_t
*mutex
), (mutex
));
955 #endif /* VGO_solaris */
957 static __always_inline
958 int pthread_mutex_timedlock_intercept(pthread_mutex_t
*mutex
,
959 const struct timespec
*abs_timeout
)
963 VALGRIND_GET_ORIG_FN(fn
);
964 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
965 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
966 CALL_FN_W_WW(ret
, fn
, mutex
, abs_timeout
);
967 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
968 mutex
, ret
== 0, 0, 0, 0);
972 PTH_FUNCS(int, pthreadZumutexZutimedlock
, pthread_mutex_timedlock_intercept
,
973 (pthread_mutex_t
*mutex
, const struct timespec
*abs_timeout
),
974 (mutex
, abs_timeout
));
975 #if defined(VGO_solaris)
977 pthreadZumutexZureltimedlockZunp
, pthread_mutex_timedlock_intercept
,
978 (pthread_mutex_t
*mutex
, const struct timespec
*timeout
),
980 #endif /* VGO_solaris */
982 static __always_inline
983 int pthread_mutex_unlock_intercept(pthread_mutex_t
*mutex
)
987 VALGRIND_GET_ORIG_FN(fn
);
988 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK
,
989 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
990 CALL_FN_W_W(ret
, fn
, mutex
);
991 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK
,
996 #if defined(VGO_solaris)
997 /* On Solaris, pthread_mutex_unlock is a weak alias to mutex_unlock. */
998 PTH_FUNCS(int, mutexZuunlock
, pthread_mutex_unlock_intercept
,
999 (pthread_mutex_t
*mutex
), (mutex
));
1001 PTH_FUNCS(int, pthreadZumutexZuunlock
, pthread_mutex_unlock_intercept
,
1002 (pthread_mutex_t
*mutex
), (mutex
));
1003 #endif /* VGO_solaris */
1005 #if defined(VGO_solaris)
1006 /* Internal to libc. */
1007 static __always_inline
1008 void lmutex_unlock_intercept(mutex_t
*mutex
)
1011 VALGRIND_GET_ORIG_FN(fn
);
1012 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK
,
1014 DRD_(mutex_type
)((pthread_mutex_t
*) mutex
),
1016 CALL_FN_v_W(fn
, mutex
);
1017 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK
,
1021 PTH_FUNCS(void, lmutexZuunlock
, lmutex_unlock_intercept
,
1022 (mutex_t
*mutex
), (mutex
));
1023 #endif /* VGO_solaris */
1025 static __always_inline
1026 int pthread_cond_init_intercept(pthread_cond_t
* cond
,
1027 const pthread_condattr_t
* attr
)
1031 VALGRIND_GET_ORIG_FN(fn
);
1032 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT
,
1034 CALL_FN_W_WW(ret
, fn
, cond
, attr
);
1035 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT
,
1040 PTH_FUNCS(int, pthreadZucondZuinit
, pthread_cond_init_intercept
,
1041 (pthread_cond_t
* cond
, const pthread_condattr_t
* attr
),
1044 #if defined(VGO_solaris)
1045 static __always_inline
1046 int cond_init_intercept(cond_t
*cond
, int type
, void *arg
)
1050 VALGRIND_GET_ORIG_FN(fn
);
1051 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT
,
1053 CALL_FN_W_WWW(ret
, fn
, cond
, type
, arg
);
1054 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT
,
1059 PTH_FUNCS(int, condZuinit
, cond_init_intercept
,
1060 (cond_t
*cond
, int type
, void *arg
),
1062 #endif /* VGO_solaris */
1064 static __always_inline
1065 int pthread_cond_destroy_intercept(pthread_cond_t
* cond
)
1069 VALGRIND_GET_ORIG_FN(fn
);
1070 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_DESTROY
,
1072 CALL_FN_W_W(ret
, fn
, cond
);
1073 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_DESTROY
,
1074 cond
, ret
==0, 0, 0, 0);
1078 #if defined(VGO_solaris)
1079 /* On Solaris, pthread_cond_destroy is a weak alias to cond_destroy. */
1080 PTH_FUNCS(int, condZudestroy
, pthread_cond_destroy_intercept
,
1081 (pthread_cond_t
*cond
), (cond
));
1083 PTH_FUNCS(int, pthreadZucondZudestroy
, pthread_cond_destroy_intercept
,
1084 (pthread_cond_t
* cond
), (cond
));
1085 #endif /* VGO_solaris */
1087 static __always_inline
1088 int pthread_cond_wait_intercept(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
1092 VALGRIND_GET_ORIG_FN(fn
);
1093 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT
,
1094 cond
, mutex
, DRD_(mutex_type
)(mutex
), 0, 0);
1095 CALL_FN_W_WW(ret
, fn
, cond
, mutex
);
1096 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT
,
1097 cond
, mutex
, 1, 0, 0);
1101 PTH_FUNCS(int, pthreadZucondZuwait
, pthread_cond_wait_intercept
,
1102 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
),
1104 #if defined(VGO_solaris)
1105 PTH_FUNCS(int, condZuwait
, pthread_cond_wait_intercept
,
1106 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
),
1108 #endif /* VGO_solaris */
1110 static __always_inline
1111 int pthread_cond_timedwait_intercept(pthread_cond_t
*cond
,
1112 pthread_mutex_t
*mutex
,
1113 const struct timespec
* abstime
)
1117 VALGRIND_GET_ORIG_FN(fn
);
1118 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT
,
1119 cond
, mutex
, DRD_(mutex_type
)(mutex
), 0, 0);
1120 CALL_FN_W_WWW(ret
, fn
, cond
, mutex
, abstime
);
1121 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT
,
1122 cond
, mutex
, 1, 0, 0);
1126 PTH_FUNCS(int, pthreadZucondZutimedwait
, pthread_cond_timedwait_intercept
,
1127 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1128 const struct timespec
* abstime
),
1129 (cond
, mutex
, abstime
));
1130 #if defined(VGO_solaris)
1131 PTH_FUNCS(int, condZutimedwait
, pthread_cond_timedwait_intercept
,
1132 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1133 const struct timespec
*timeout
),
1134 (cond
, mutex
, timeout
));
1135 PTH_FUNCS(int, condZureltimedwait
, pthread_cond_timedwait_intercept
,
1136 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1137 const struct timespec
*timeout
),
1138 (cond
, mutex
, timeout
));
1139 #endif /* VGO_solaris */
1141 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
1142 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
1143 // two. Intercepting all pthread_cond_signal* functions will cause only one
1144 // argument to be passed to pthread_cond_signal_np() and hence will cause this
1145 // last function to crash.
1147 static __always_inline
1148 int pthread_cond_signal_intercept(pthread_cond_t
* cond
)
1152 VALGRIND_GET_ORIG_FN(fn
);
1153 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_SIGNAL
,
1155 CALL_FN_W_W(ret
, fn
, cond
);
1156 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_SIGNAL
,
1161 #if defined(VGO_solaris)
1162 /* On Solaris, pthread_cond_signal is a weak alias to cond_signal. */
1163 PTH_FUNCS(int, condZusignal
, pthread_cond_signal_intercept
,
1164 (pthread_cond_t
*cond
), (cond
));
1166 PTH_FUNCS(int, pthreadZucondZusignal
, pthread_cond_signal_intercept
,
1167 (pthread_cond_t
* cond
), (cond
));
1168 #endif /* VGO_solaris */
1170 static __always_inline
1171 int pthread_cond_broadcast_intercept(pthread_cond_t
* cond
)
1175 VALGRIND_GET_ORIG_FN(fn
);
1176 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_BROADCAST
,
1178 CALL_FN_W_W(ret
, fn
, cond
);
1179 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_BROADCAST
,
1184 #if defined(VGO_solaris)
1185 /* On Solaris, pthread_cond_broadcast is a weak alias to cond_broadcast. */
1186 PTH_FUNCS(int, condZubroadcast
, pthread_cond_broadcast_intercept
,
1187 (pthread_cond_t
*cond
), (cond
));
1189 PTH_FUNCS(int, pthreadZucondZubroadcast
, pthread_cond_broadcast_intercept
,
1190 (pthread_cond_t
* cond
), (cond
));
1191 #endif /* VGO_solaris */
1193 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1194 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1195 static __always_inline
1196 int pthread_spin_init_intercept(pthread_spinlock_t
*spinlock
, int pshared
)
1200 VALGRIND_GET_ORIG_FN(fn
);
1201 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK
,
1202 spinlock
, 0, 0, 0, 0);
1203 CALL_FN_W_WW(ret
, fn
, spinlock
, pshared
);
1204 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK
,
1205 spinlock
, 0, 0, 0, 0);
1209 PTH_FUNCS(int, pthreadZuspinZuinit
, pthread_spin_init_intercept
,
1210 (pthread_spinlock_t
*spinlock
, int pshared
), (spinlock
, pshared
));
1212 static __always_inline
1213 int pthread_spin_destroy_intercept(pthread_spinlock_t
*spinlock
)
1217 VALGRIND_GET_ORIG_FN(fn
);
1218 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY
,
1219 spinlock
, 0, 0, 0, 0);
1220 CALL_FN_W_W(ret
, fn
, spinlock
);
1221 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY
,
1222 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1226 PTH_FUNCS(int, pthreadZuspinZudestroy
, pthread_spin_destroy_intercept
,
1227 (pthread_spinlock_t
*spinlock
), (spinlock
));
1229 static __always_inline
1230 int pthread_spin_lock_intercept(pthread_spinlock_t
*spinlock
)
1234 VALGRIND_GET_ORIG_FN(fn
);
1235 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK
,
1236 spinlock
, mutex_type_spinlock
, 0, 0, 0);
1237 CALL_FN_W_W(ret
, fn
, spinlock
);
1238 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK
,
1239 spinlock
, ret
== 0, 0, 0, 0);
1243 PTH_FUNCS(int, pthreadZuspinZulock
, pthread_spin_lock_intercept
,
1244 (pthread_spinlock_t
*spinlock
), (spinlock
));
1246 static __always_inline
1247 int pthread_spin_trylock_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, pthreadZuspinZutrylock
, pthread_spin_trylock_intercept
,
1261 (pthread_spinlock_t
*spinlock
), (spinlock
));
1263 static __always_inline
1264 int pthread_spin_unlock_intercept(pthread_spinlock_t
*spinlock
)
1268 VALGRIND_GET_ORIG_FN(fn
);
1269 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK
,
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_SPIN_INIT_OR_UNLOCK
,
1273 spinlock
, 0, 0, 0, 0);
1277 PTH_FUNCS(int, pthreadZuspinZuunlock
, pthread_spin_unlock_intercept
,
1278 (pthread_spinlock_t
*spinlock
), (spinlock
));
1279 #endif // HAVE_PTHREAD_SPIN_LOCK
1282 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1283 static __always_inline
1284 int pthread_barrier_init_intercept(pthread_barrier_t
* barrier
,
1285 const pthread_barrierattr_t
* attr
,
1290 VALGRIND_GET_ORIG_FN(fn
);
1291 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_INIT
,
1292 barrier
, pthread_barrier
, count
, 0, 0);
1293 CALL_FN_W_WWW(ret
, fn
, barrier
, attr
, count
);
1294 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_INIT
,
1295 barrier
, pthread_barrier
, 0, 0, 0);
1299 PTH_FUNCS(int, pthreadZubarrierZuinit
, pthread_barrier_init_intercept
,
1300 (pthread_barrier_t
* barrier
, const pthread_barrierattr_t
* attr
,
1301 unsigned count
), (barrier
, attr
, count
));
1303 static __always_inline
1304 int pthread_barrier_destroy_intercept(pthread_barrier_t
* barrier
)
1308 VALGRIND_GET_ORIG_FN(fn
);
1309 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_DESTROY
,
1310 barrier
, pthread_barrier
, 0, 0, 0);
1311 CALL_FN_W_W(ret
, fn
, barrier
);
1312 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_DESTROY
,
1313 barrier
, pthread_barrier
, 0, 0, 0);
1317 PTH_FUNCS(int, pthreadZubarrierZudestroy
, pthread_barrier_destroy_intercept
,
1318 (pthread_barrier_t
* barrier
), (barrier
));
1320 static __always_inline
1321 int pthread_barrier_wait_intercept(pthread_barrier_t
* barrier
)
1325 VALGRIND_GET_ORIG_FN(fn
);
1326 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_WAIT
,
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_WAIT
,
1330 barrier
, pthread_barrier
,
1331 ret
== 0 || ret
== PTHREAD_BARRIER_SERIAL_THREAD
,
1332 ret
== PTHREAD_BARRIER_SERIAL_THREAD
, 0);
1336 PTH_FUNCS(int, pthreadZubarrierZuwait
, pthread_barrier_wait_intercept
,
1337 (pthread_barrier_t
* barrier
), (barrier
));
1338 #endif // HAVE_PTHREAD_BARRIER_INIT
1341 static __always_inline
1342 int sem_init_intercept(sem_t
*sem
, int pshared
, unsigned int value
)
1346 VALGRIND_GET_ORIG_FN(fn
);
1347 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT
,
1348 sem
, pshared
, value
, 0, 0);
1349 CALL_FN_W_WWW(ret
, fn
, sem
, pshared
, value
);
1350 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT
,
1355 PTH_FUNCS(int, semZuinit
, sem_init_intercept
,
1356 (sem_t
*sem
, int pshared
, unsigned int value
), (sem
, pshared
, value
));
1358 #if defined(VGO_solaris)
1359 static __always_inline
1360 int sema_init_intercept(sema_t
*sem
, unsigned int value
, int type
, void *arg
)
1364 VALGRIND_GET_ORIG_FN(fn
);
1365 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT
,
1366 sem
, type
== USYNC_PROCESS
? 1 : 0,
1368 CALL_FN_W_WWWW(ret
, fn
, sem
, value
, type
, arg
);
1369 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT
,
1374 PTH_FUNCS(int, semaZuinit
, sema_init_intercept
,
1375 (sema_t
*sem
, unsigned int value
, int type
, void *arg
),
1376 (sem
, value
, type
, arg
));
1377 #endif /* VGO_solaris */
1379 static __always_inline
1380 int sem_destroy_intercept(sem_t
*sem
)
1384 VALGRIND_GET_ORIG_FN(fn
);
1385 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_DESTROY
,
1387 CALL_FN_W_W(ret
, fn
, sem
);
1388 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_DESTROY
,
1393 PTH_FUNCS(int, semZudestroy
, sem_destroy_intercept
, (sem_t
*sem
), (sem
));
1394 #if defined(VGO_solaris)
1395 PTH_FUNCS(int, semaZudestroy
, sem_destroy_intercept
, (sem_t
*sem
), (sem
));
1396 #endif /* VGO_solaris */
1398 static __always_inline
1399 sem_t
* sem_open_intercept(const char *name
, int oflag
, mode_t mode
,
1404 VALGRIND_GET_ORIG_FN(fn
);
1405 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_OPEN
,
1406 name
, oflag
, mode
, value
, 0);
1407 CALL_FN_W_WWWW(ret
, fn
, name
, oflag
, mode
, value
);
1408 // To do: figure out why gcc 9.2.1 miscompiles this function if the printf()
1409 // call below is left out.
1411 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_OPEN
,
1412 ret
!= SEM_FAILED
? ret
: 0,
1413 name
, oflag
, mode
, value
);
1417 PTH_FUNCS(sem_t
*, semZuopen
, sem_open_intercept
,
1418 (const char *name
, int oflag
, mode_t mode
, unsigned int value
),
1419 (name
, oflag
, mode
, value
));
1421 static __always_inline
int sem_close_intercept(sem_t
*sem
)
1425 VALGRIND_GET_ORIG_FN(fn
);
1426 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_CLOSE
,
1428 CALL_FN_W_W(ret
, fn
, sem
);
1429 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_CLOSE
,
1434 PTH_FUNCS(int, semZuclose
, sem_close_intercept
, (sem_t
*sem
), (sem
));
1436 static __always_inline
int sem_wait_intercept(sem_t
*sem
)
1440 VALGRIND_GET_ORIG_FN(fn
);
1441 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT
,
1443 CALL_FN_W_W(ret
, fn
, sem
);
1444 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT
,
1445 sem
, ret
== 0, 0, 0, 0);
1449 PTH_FUNCS(int, semZuwait
, sem_wait_intercept
, (sem_t
*sem
), (sem
));
1450 #if defined(VGO_solaris)
1451 PTH_FUNCS(int, semaZuwait
, sem_wait_intercept
, (sem_t
*sem
), (sem
));
1452 #endif /* VGO_solaris */
1454 static __always_inline
int sem_trywait_intercept(sem_t
*sem
)
1458 VALGRIND_GET_ORIG_FN(fn
);
1459 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT
,
1461 CALL_FN_W_W(ret
, fn
, sem
);
1462 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT
,
1463 sem
, ret
== 0, 0, 0, 0);
1467 PTH_FUNCS(int, semZutrywait
, sem_trywait_intercept
, (sem_t
*sem
), (sem
));
1468 #if defined(VGO_solaris)
1469 PTH_FUNCS(int, semaZutrywait
, sem_trywait_intercept
, (sem_t
*sem
), (sem
));
1470 #endif /* VGO_solaris */
1472 static __always_inline
1473 int sem_timedwait_intercept(sem_t
*sem
, const struct timespec
*abs_timeout
)
1477 VALGRIND_GET_ORIG_FN(fn
);
1478 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT
,
1480 CALL_FN_W_WW(ret
, fn
, sem
, abs_timeout
);
1481 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT
,
1482 sem
, ret
== 0, 0, 0, 0);
1486 PTH_FUNCS(int, semZutimedwait
, sem_timedwait_intercept
,
1487 (sem_t
*sem
, const struct timespec
*abs_timeout
),
1488 (sem
, abs_timeout
));
1489 #if defined(VGO_solaris)
1490 PTH_FUNCS(int, semaZutimedwait
, sem_timedwait_intercept
,
1491 (sem_t
*sem
, const struct timespec
*timeout
),
1493 PTH_FUNCS(int, semaZureltimedwait
, sem_timedwait_intercept
,
1494 (sem_t
*sem
, const struct timespec
*timeout
),
1496 #endif /* VGO_solaris */
1498 static __always_inline
int sem_post_intercept(sem_t
*sem
)
1502 VALGRIND_GET_ORIG_FN(fn
);
1503 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_POST
,
1505 CALL_FN_W_W(ret
, fn
, sem
);
1506 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_POST
,
1507 sem
, ret
== 0, 0, 0, 0);
1511 PTH_FUNCS(int, semZupost
, sem_post_intercept
, (sem_t
*sem
), (sem
));
1512 #if defined(VGO_solaris)
1513 PTH_FUNCS(int, semaZupost
, sem_post_intercept
, (sem_t
*sem
), (sem
));
1514 #endif /* VGO_solaris */
1516 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1517 functions have to be conditionally compiled. */
1518 #if defined(HAVE_PTHREAD_RWLOCK_T)
1520 static __always_inline
1521 int pthread_rwlock_init_intercept(pthread_rwlock_t
* rwlock
,
1522 const pthread_rwlockattr_t
* attr
)
1526 VALGRIND_GET_ORIG_FN(fn
);
1527 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT
,
1528 rwlock
, 0, 0, 0, 0);
1529 CALL_FN_W_WW(ret
, fn
, rwlock
, attr
);
1530 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT
,
1531 rwlock
, 0, 0, 0, 0);
1536 pthreadZurwlockZuinit
, pthread_rwlock_init_intercept
,
1537 (pthread_rwlock_t
* rwlock
, const pthread_rwlockattr_t
* attr
),
1540 #if defined(VGO_solaris)
1541 static __always_inline
1542 int rwlock_init_intercept(rwlock_t
*rwlock
, int type
, void *arg
)
1546 VALGRIND_GET_ORIG_FN(fn
);
1547 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT
,
1548 rwlock
, 0, 0, 0, 0);
1549 CALL_FN_W_WWW(ret
, fn
, rwlock
, type
, arg
);
1550 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT
,
1551 rwlock
, 0, 0, 0, 0);
1555 PTH_FUNCS(int, rwlockZuinit
, rwlock_init_intercept
,
1556 (rwlock_t
*rwlock
, int type
, void *arg
),
1557 (rwlock
, type
, arg
));
1558 #endif /* VGO_solaris */
1560 static __always_inline
1561 int pthread_rwlock_destroy_intercept(pthread_rwlock_t
* rwlock
)
1565 VALGRIND_GET_ORIG_FN(fn
);
1566 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_DESTROY
,
1567 rwlock
, 0, 0, 0, 0);
1568 CALL_FN_W_W(ret
, fn
, rwlock
);
1569 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_DESTROY
,
1570 rwlock
, 0, 0, 0, 0);
1574 #if defined(VGO_solaris)
1575 /* On Solaris, pthread_rwlock_destroy is a weak alias to rwlock_destroy. */
1577 rwlockZudestroy
, pthread_rwlock_destroy_intercept
,
1578 (pthread_rwlock_t
*rwlock
), (rwlock
));
1581 pthreadZurwlockZudestroy
, pthread_rwlock_destroy_intercept
,
1582 (pthread_rwlock_t
* rwlock
), (rwlock
));
1583 #endif /* VGO_solaris */
1585 static __always_inline
1586 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t
* rwlock
)
1590 VALGRIND_GET_ORIG_FN(fn
);
1591 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK
,
1592 rwlock
, 0, 0, 0, 0);
1593 CALL_FN_W_W(ret
, fn
, rwlock
);
1594 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK
,
1595 rwlock
, ret
== 0, 0, 0, 0);
1599 #if defined(VGO_solaris)
1600 /* On Solaris, pthread_rwlock_rdlock is a weak alias to rw_rdlock. */
1602 rwZurdlock
, pthread_rwlock_rdlock_intercept
,
1603 (pthread_rwlock_t
*rwlock
), (rwlock
));
1606 pthreadZurwlockZurdlock
, pthread_rwlock_rdlock_intercept
,
1607 (pthread_rwlock_t
* rwlock
), (rwlock
));
1608 #endif /* VGO_solaris */
1610 #if defined(VGO_solaris)
1611 /* Internal to libc. */
1612 static __always_inline
1613 void lrw_rdlock_intercept(rwlock_t
*rwlock
)
1616 VALGRIND_GET_ORIG_FN(fn
);
1617 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK
,
1618 rwlock
, 0, 0, 0, 0);
1619 CALL_FN_v_W(fn
, rwlock
);
1620 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK
,
1621 rwlock
, True
/* took_lock */, 0, 0, 0);
1624 PTH_FUNCS(void, lrwZurdlock
, lrw_rdlock_intercept
,
1625 (rwlock_t
*rwlock
), (rwlock
));
1626 #endif /* VGO_solaris */
1628 static __always_inline
1629 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t
* rwlock
)
1633 VALGRIND_GET_ORIG_FN(fn
);
1634 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK
,
1635 rwlock
, 0, 0, 0, 0);
1636 CALL_FN_W_W(ret
, fn
, rwlock
);
1637 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK
,
1638 rwlock
, ret
== 0, 0, 0, 0);
1642 #if defined(VGO_solaris)
1643 /* On Solaris, pthread_rwlock_wrlock is a weak alias to rw_wrlock. */
1645 rwZuwrlock
, pthread_rwlock_wrlock_intercept
,
1646 (pthread_rwlock_t
*rwlock
), (rwlock
));
1649 pthreadZurwlockZuwrlock
, pthread_rwlock_wrlock_intercept
,
1650 (pthread_rwlock_t
* rwlock
), (rwlock
));
1651 #endif /* VGO_solaris */
1653 #if defined(VGO_solaris)
1654 /* Internal to libc. */
1655 static __always_inline
1656 void lrw_wrlock_intercept(rwlock_t
*rwlock
)
1659 VALGRIND_GET_ORIG_FN(fn
);
1660 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK
,
1661 rwlock
, 0, 0, 0, 0);
1662 CALL_FN_v_W(fn
, rwlock
);
1663 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK
,
1664 rwlock
, True
/* took_lock */, 0, 0, 0);
1667 PTH_FUNCS(void, lrwZuwrlock
, lrw_wrlock_intercept
,
1668 (rwlock_t
*rwlock
), (rwlock
));
1669 #endif /* VGO_solaris */
1671 static __always_inline
1672 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t
* rwlock
,
1673 const struct timespec
*timeout
)
1677 VALGRIND_GET_ORIG_FN(fn
);
1678 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK
,
1679 rwlock
, 0, 0, 0, 0);
1680 CALL_FN_W_WW(ret
, fn
, rwlock
, timeout
);
1681 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK
,
1682 rwlock
, ret
== 0, 0, 0, 0);
1687 pthreadZurwlockZutimedrdlock
, pthread_rwlock_timedrdlock_intercept
,
1688 (pthread_rwlock_t
* rwlock
, const struct timespec
*timeout
),
1690 #if defined(VGO_solaris)
1691 PTH_FUNCS(int, pthreadZurwlockZureltimedrdlockZunp
,
1692 pthread_rwlock_timedrdlock_intercept
,
1693 (pthread_rwlock_t
*rwlock
, const struct timespec
*timeout
),
1695 #endif /* VGO_solaris */
1697 static __always_inline
1698 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t
* rwlock
,
1699 const struct timespec
*timeout
)
1703 VALGRIND_GET_ORIG_FN(fn
);
1704 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK
,
1705 rwlock
, 0, 0, 0, 0);
1706 CALL_FN_W_WW(ret
, fn
, rwlock
, timeout
);
1707 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK
,
1708 rwlock
, ret
== 0, 0, 0, 0);
1713 pthreadZurwlockZutimedwrlock
, pthread_rwlock_timedwrlock_intercept
,
1714 (pthread_rwlock_t
* rwlock
, const struct timespec
*timeout
),
1716 #if defined(VGO_solaris)
1717 PTH_FUNCS(int, pthreadZurwlockZureltimedwrlockZunp
,
1718 pthread_rwlock_timedwrlock_intercept
,
1719 (pthread_rwlock_t
*rwlock
, const struct timespec
*timeout
),
1721 #endif /* VGO_solaris */
1723 static __always_inline
1724 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t
* rwlock
)
1728 VALGRIND_GET_ORIG_FN(fn
);
1729 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK
,
1730 rwlock
, 0, 0, 0, 0);
1731 CALL_FN_W_W(ret
, fn
, rwlock
);
1732 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK
,
1733 rwlock
, ret
== 0, 0, 0, 0);
1737 #if defined(VGO_solaris)
1738 /* On Solaris, pthread_rwlock_tryrdlock is a weak alias to rw_tryrdlock. */
1740 rwZutryrdlock
, pthread_rwlock_tryrdlock_intercept
,
1741 (pthread_rwlock_t
*rwlock
), (rwlock
));
1744 pthreadZurwlockZutryrdlock
, pthread_rwlock_tryrdlock_intercept
,
1745 (pthread_rwlock_t
* rwlock
), (rwlock
));
1746 #endif /* VGO_solaris */
1748 static __always_inline
1749 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t
* rwlock
)
1753 VALGRIND_GET_ORIG_FN(fn
);
1754 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK
,
1755 rwlock
, 0, 0, 0, 0);
1756 CALL_FN_W_W(ret
, fn
, rwlock
);
1757 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK
,
1758 rwlock
, ret
== 0, 0, 0, 0);
1762 #if defined(VGO_solaris)
1763 /* On Solaris, pthread_rwlock_trywrlock is a weak alias to rw_trywrlock. */
1765 rwZutrywrlock
, pthread_rwlock_trywrlock_intercept
,
1766 (pthread_rwlock_t
*rwlock
), (rwlock
));
1769 pthreadZurwlockZutrywrlock
, pthread_rwlock_trywrlock_intercept
,
1770 (pthread_rwlock_t
* rwlock
), (rwlock
));
1771 #endif /* VGO_solaris */
1773 static __always_inline
1774 int pthread_rwlock_unlock_intercept(pthread_rwlock_t
* rwlock
)
1778 VALGRIND_GET_ORIG_FN(fn
);
1779 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_UNLOCK
,
1780 rwlock
, 0, 0, 0, 0);
1781 CALL_FN_W_W(ret
, fn
, rwlock
);
1782 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_UNLOCK
,
1783 rwlock
, ret
== 0, 0, 0, 0);
1787 #if defined(VGO_solaris)
1788 /* On Solaris, pthread_rwlock_unlock is a weak alias to rw_unlock. */
1790 rwZuunlock
, pthread_rwlock_unlock_intercept
,
1791 (pthread_rwlock_t
*rwlock
), (rwlock
));
1794 pthreadZurwlockZuunlock
, pthread_rwlock_unlock_intercept
,
1795 (pthread_rwlock_t
* rwlock
), (rwlock
));
1796 #endif /* VGO_solaris */
1798 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */