1 /* -*- mode: C; c-basic-offset: 3; indent-tabs-mode: nil; -*- */
3 /*--------------------------------------------------------------------*/
4 /*--- Client-space code for DRD. drd_pthread_intercepts.c ---*/
5 /*--------------------------------------------------------------------*/
8 This file is part of DRD, a thread error detector.
10 Copyright (C) 2006-2011 Bart Van Assche <bvanassche@acm.org>.
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation; either version 2 of the
15 License, or (at your option) any later version.
17 This program is distributed in the hope that it will be useful, but
18 WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 The GNU General Public License is contained in the file COPYING.
30 /* ---------------------------------------------------------------------
31 ALL THE CODE IN THIS FILE RUNS ON THE SIMULATED CPU.
33 These functions are not called directly - they're the targets of code
34 redirection or load notifications (see pub_core_redir.h for info).
35 They're named weirdly so that the intercept code can find them when the
36 shared object is initially loaded.
38 Note that this filename has the "drd_" prefix because it can appear
39 in stack traces, and the "drd_" makes it a little clearer that it
40 originates from Valgrind.
41 ------------------------------------------------------------------ */
44 * Define _GNU_SOURCE to make sure that pthread_spinlock_t is available when
45 * compiling with older glibc versions (2.3 or before).
51 #include <assert.h> /* assert() */
53 #include <pthread.h> /* pthread_mutex_t */
54 #include <semaphore.h> /* sem_t */
55 #include <stdint.h> /* uintptr_t */
56 #include <stdio.h> /* fprintf() */
57 #include <stdlib.h> /* malloc(), free() */
58 #include <unistd.h> /* confstr() */
59 #include "config.h" /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP etc. */
60 #ifdef HAVE_USABLE_LINUX_FUTEX_H
61 #include <asm/unistd.h> /* __NR_futex */
62 #include <linux/futex.h> /* FUTEX_WAIT */
63 #ifndef FUTEX_PRIVATE_FLAG
64 #define FUTEX_PRIVATE_FLAG 0
67 #include "drd_basics.h" /* DRD_() */
68 #include "drd_clientreq.h"
69 #include "pub_tool_redir.h" /* VG_WRAP_FUNCTION_ZZ() */
73 * Notes regarding thread creation:
74 * - sg_init() runs on the context of the created thread and copies the vector
75 * clock of the creator thread. This only works reliably if the creator
76 * thread waits until this copy has been performed.
77 * - DRD_(thread_compute_minimum_vc)() does not take the vector clocks into
78 * account that are involved in thread creation and for which the
79 * corresponding thread has not yet been created. So not waiting until the
80 * created thread has been started would make it possible that segments get
81 * discarded that should not yet be discarded. Or: some data races are not
86 * Macro for generating a Valgrind interception function.
87 * @param[in] ret_ty Return type of the function to be generated.
88 * @param[in] zf Z-encoded name of the interception function.
89 * @param[in] implf Name of the function that implements the intercept.
90 * @param[in] arg_decl Argument declaration list enclosed in parentheses.
91 * @param[in] argl Argument list enclosed in parentheses.
94 static int never_true
;
95 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
96 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
97 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
99 ret_ty pth_func_result = implf argl; \
100 /* Apparently inserting a function call in wrapper functions */ \
101 /* is sufficient to avoid misaligned stack errors. */ \
104 return pth_func_result; \
107 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
108 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
109 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
110 { return implf argl; }
114 * Macro for generating three Valgrind interception functions: one with the
115 * Z-encoded name zf, one with ZAZa ("@*") appended to the name zf and one
116 * with ZDZa ("$*") appended to the name zf. The second generated interception
117 * function will intercept versioned symbols on Linux, and the third will
118 * intercept versioned symbols on Darwin.
120 #define PTH_FUNCS(ret_ty, zf, implf, argl_decl, argl) \
121 PTH_FUNC(ret_ty, zf, implf, argl_decl, argl); \
122 PTH_FUNC(ret_ty, zf ## ZAZa, implf, argl_decl, argl); \
123 PTH_FUNC(ret_ty, zf ## ZDZa, implf, argl_decl, argl);
126 * Not inlining one of the intercept functions will cause the regression
127 * tests to fail because this would cause an additional stackfram to appear
128 * in the output. The __always_inline macro guarantees that inlining will
129 * happen, even when compiling with optimization disabled.
131 #undef __always_inline /* since already defined in <cdefs.h> */
132 #if __GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 2
133 #define __always_inline __inline__ __attribute__((always_inline))
135 #define __always_inline __inline__
138 /* Local data structures. */
141 volatile int counter
;
146 void* (*start
)(void*);
149 DrdSema wrapper_started
;
150 } DrdPosixThreadArgs
;
153 /* Local function declarations. */
155 static void DRD_(init
)(void) __attribute__((constructor
));
156 static void DRD_(check_threading_library
)(void);
157 static void DRD_(set_main_thread_state
)(void);
158 static void DRD_(sema_init
)(DrdSema
* sema
);
159 static void DRD_(sema_destroy
)(DrdSema
* sema
);
160 static void DRD_(sema_down
)(DrdSema
* sema
);
161 static void DRD_(sema_up
)(DrdSema
* sema
);
164 /* Function definitions. */
167 * Shared library initialization function. The function init() is called after
168 * dlopen() has loaded the shared library with DRD client intercepts because
169 * the constructor attribute was specified in the declaration of this function.
170 * Note: do specify the -nostdlib option to gcc when linking this code into a
171 * shared library because doing so would cancel the effect of the constructor
172 * attribute ! Using the gcc option -nodefaultlibs is fine because this last
173 * option preserves the shared library initialization code that calls
174 * constructor and destructor functions.
176 static void DRD_(init
)(void)
178 DRD_(check_threading_library
)();
179 DRD_(set_main_thread_state
)();
182 static void DRD_(sema_init
)(DrdSema
* sema
)
184 DRD_IGNORE_VAR(sema
->counter
);
188 static void DRD_(sema_destroy
)(DrdSema
* sema
)
192 static void DRD_(sema_down
)(DrdSema
* sema
)
196 while (sema
->counter
== 0) {
197 #ifdef HAVE_USABLE_LINUX_FUTEX_H
198 if (syscall(__NR_futex
, (UWord
)&sema
->counter
,
199 FUTEX_WAIT
| FUTEX_PRIVATE_FLAG
, 0) == 0)
205 * Invoke sched_yield() on non-Linux systems, if the futex syscall has
206 * not been invoked or if this code has been built on a Linux system
207 * where __NR_futex is defined and is run on a Linux system that does
208 * not support the futex syscall.
210 if (res
!= 0 && res
!= EWOULDBLOCK
)
216 static void DRD_(sema_up
)(DrdSema
* sema
)
219 #ifdef HAVE_USABLE_LINUX_FUTEX_H
220 syscall(__NR_futex
, (UWord
)&sema
->counter
,
221 FUTEX_WAKE
| FUTEX_PRIVATE_FLAG
, 1);
226 * POSIX threads and DRD each have their own mutex type identification.
227 * Convert POSIX threads' mutex type to DRD's mutex type. In the code below
228 * if-statements are used to test the value of 'kind' instead of a switch
229 * statement because some of the PTHREAD_MUTEX_ macro's may have the same
232 static MutexT
DRD_(pthread_to_drd_mutex_type
)(const int kind
)
234 if (kind
== PTHREAD_MUTEX_RECURSIVE
)
235 return mutex_type_recursive_mutex
;
236 else if (kind
== PTHREAD_MUTEX_ERRORCHECK
)
237 return mutex_type_errorcheck_mutex
;
238 else if (kind
== PTHREAD_MUTEX_NORMAL
)
239 return mutex_type_default_mutex
;
240 else if (kind
== PTHREAD_MUTEX_DEFAULT
)
241 return mutex_type_default_mutex
;
242 #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
243 else if (kind
== PTHREAD_MUTEX_ADAPTIVE_NP
)
244 return mutex_type_default_mutex
;
248 return mutex_type_invalid_mutex
;
252 #define IS_ALIGNED(p) (((uintptr_t)(p) & (sizeof(*(p)) - 1)) == 0)
255 * Read the mutex type stored in the client memory used for the mutex
258 * @note This function depends on the implementation of the POSIX threads
259 * library -- the POSIX standard does not define the name of the member in
260 * which the mutex type is stored.
261 * @note The function mutex_type() has been declared inline in order
262 * to avoid that it shows up in call stacks (drd/tests/...exp* files).
263 * @note glibc stores the mutex type in the lowest two bits, and uses the
264 * higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
265 * PTHREAD_MUTEXATTR_FLAG_PSHARED.
267 static __always_inline MutexT
DRD_(mutex_type
)(pthread_mutex_t
* mutex
)
269 #if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
270 /* glibc + LinuxThreads. */
271 if (IS_ALIGNED(&mutex
->__m_kind
))
273 const int kind
= mutex
->__m_kind
& 3;
274 return DRD_(pthread_to_drd_mutex_type
)(kind
);
276 #elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
278 if (IS_ALIGNED(&mutex
->__data
.__kind
))
280 const int kind
= mutex
->__data
.__kind
& 3;
281 return DRD_(pthread_to_drd_mutex_type
)(kind
);
285 * Another POSIX threads implementation. The mutex type won't be printed
286 * when enabling --trace-mutex=yes.
289 return mutex_type_unknown
;
293 * Tell DRD whether 'tid' is a joinable thread or a detached thread.
295 static void DRD_(set_joinable
)(const pthread_t tid
, const int joinable
)
297 assert(joinable
== 0 || joinable
== 1);
298 VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__SET_JOINABLE
,
299 tid
, joinable
, 0, 0, 0);
302 /** Tell DRD that the calling thread is about to enter pthread_create(). */
303 static __always_inline
void DRD_(entering_pthread_create
)(void)
305 VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__ENTERING_PTHREAD_CREATE
,
309 /** Tell DRD that the calling thread has left pthread_create(). */
310 static __always_inline
void DRD_(left_pthread_create
)(void)
312 VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__LEFT_PTHREAD_CREATE
,
317 * Entry point for newly created threads. This function is called from the
318 * thread created by pthread_create().
320 static void* DRD_(thread_wrapper
)(void* arg
)
322 DrdPosixThreadArgs
* arg_ptr
;
323 DrdPosixThreadArgs arg_copy
;
325 arg_ptr
= (DrdPosixThreadArgs
*)arg
;
328 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__SET_PTHREADID
,
329 pthread_self(), 0, 0, 0, 0);
331 DRD_(set_joinable
)(pthread_self(),
332 arg_copy
.detachstate
== PTHREAD_CREATE_JOINABLE
);
335 * Only set 'wrapper_started' after VG_USERREQ__SET_PTHREADID and
336 * DRD_(set_joinable)() have been invoked to avoid a race with
337 * a pthread_detach() invocation for this thread from another thread.
339 DRD_(sema_up
)(&arg_ptr
->wrapper_started
);
341 return (arg_copy
.start
)(arg_copy
.arg
);
345 * Return 1 if the LinuxThreads implementation of POSIX Threads has been
346 * detected, and 0 otherwise.
348 * @see For more information about the confstr() function, see also
349 * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
351 static int DRD_(detected_linuxthreads
)(void)
354 #if defined(_CS_GNU_LIBPTHREAD_VERSION)
355 /* Linux with a recent glibc. */
358 len
= confstr(_CS_GNU_LIBPTHREAD_VERSION
, buffer
, sizeof(buffer
));
359 assert(len
<= sizeof(buffer
));
360 return len
> 0 && buffer
[0] == 'l';
362 /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
366 /* Another OS than Linux, hence no LinuxThreads. */
372 * Stop and print an error message in case a non-supported threading
373 * library implementation (LinuxThreads) has been detected.
375 static void DRD_(check_threading_library
)(void)
377 if (DRD_(detected_linuxthreads
)())
379 if (getenv("LD_ASSUME_KERNEL"))
382 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
383 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
384 "after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
390 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
391 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
392 "after having upgraded to a newer version of your Linux distribution.\n"
401 * The main thread is the only thread not created by pthread_create().
402 * Update DRD's state information about the main thread.
404 static void DRD_(set_main_thread_state
)(void)
406 // Make sure that DRD knows about the main thread's POSIX thread ID.
407 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__SET_PTHREADID
,
408 pthread_self(), 0, 0, 0, 0);
412 * Note: as of today there exist three different versions of pthread_create
414 * - pthread_create@GLIBC_2.0
415 * - pthread_create@@GLIBC_2.1
416 * - pthread_create@@GLIBC_2.2.5
417 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
418 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
419 * versions have been implemented. In any glibc version where more than one
420 * pthread_create function has been implemented, older versions call the
421 * newer versions. Or: the pthread_create* wrapper defined below can be
422 * called recursively. Any code in this wrapper should take this in account.
423 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
424 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
425 * See also the implementation of pthread_create@GLIBC_2.0 in
426 * glibc-2.9/nptl/pthread_create.c.
429 static __always_inline
430 int pthread_create_intercept(pthread_t
* thread
, const pthread_attr_t
* attr
,
431 void* (*start
)(void*), void* arg
)
435 DrdPosixThreadArgs thread_args
;
437 VALGRIND_GET_ORIG_FN(fn
);
439 thread_args
.start
= start
;
440 thread_args
.arg
= arg
;
441 DRD_(sema_init
)(&thread_args
.wrapper_started
);
443 * Find out whether the thread will be started as a joinable thread
444 * or as a detached thread. If no thread attributes have been specified,
445 * this means that the new thread will be started as a joinable thread.
447 thread_args
.detachstate
= PTHREAD_CREATE_JOINABLE
;
450 if (pthread_attr_getdetachstate(attr
, &thread_args
.detachstate
) != 0)
453 assert(thread_args
.detachstate
== PTHREAD_CREATE_JOINABLE
454 || thread_args
.detachstate
== PTHREAD_CREATE_DETACHED
);
456 DRD_(entering_pthread_create
)();
457 CALL_FN_W_WWWW(ret
, fn
, thread
, attr
, DRD_(thread_wrapper
), &thread_args
);
458 DRD_(left_pthread_create
)();
462 /* Wait until the thread wrapper started. */
463 DRD_(sema_down
)(&thread_args
.wrapper_started
);
466 DRD_(sema_destroy
)(&thread_args
.wrapper_started
);
468 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__DRD_START_NEW_SEGMENT
,
469 pthread_self(), 0, 0, 0, 0);
474 PTH_FUNCS(int, pthreadZucreate
, pthread_create_intercept
,
475 (pthread_t
*thread
, const pthread_attr_t
*attr
,
476 void *(*start
) (void *), void *arg
),
477 (thread
, attr
, start
, arg
));
479 static __always_inline
480 int pthread_join_intercept(pthread_t pt_joinee
, void **thread_return
)
485 VALGRIND_GET_ORIG_FN(fn
);
487 * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
488 * implementation triggers a (false positive) race report.
490 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
491 CALL_FN_W_WW(ret
, fn
, pt_joinee
, thread_return
);
494 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_THREAD_JOIN
,
495 pt_joinee
, 0, 0, 0, 0);
497 ANNOTATE_IGNORE_READS_AND_WRITES_END();
501 PTH_FUNCS(int, pthreadZujoin
, pthread_join_intercept
,
502 (pthread_t pt_joinee
, void **thread_return
),
503 (pt_joinee
, thread_return
));
505 static __always_inline
506 int pthread_detach_intercept(pthread_t pt_thread
)
511 VALGRIND_GET_ORIG_FN(fn
);
512 CALL_FN_W_W(ret
, fn
, pt_thread
);
513 DRD_(set_joinable
)(pt_thread
, 0);
518 PTH_FUNCS(int, pthreadZudetach
, pthread_detach_intercept
,
519 (pthread_t thread
), (thread
));
521 // NOTE: be careful to intercept only pthread_cancel() and not
522 // pthread_cancel_init() on Linux.
524 static __always_inline
525 int pthread_cancel_intercept(pthread_t pt_thread
)
529 VALGRIND_GET_ORIG_FN(fn
);
530 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_THREAD_CANCEL
,
531 pt_thread
, 0, 0, 0, 0);
532 CALL_FN_W_W(ret
, fn
, pt_thread
);
533 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_THREAD_CANCEL
,
534 pt_thread
, ret
==0, 0, 0, 0);
538 PTH_FUNCS(int, pthreadZucancel
, pthread_cancel_intercept
,
539 (pthread_t thread
), (thread
))
541 static __always_inline
542 int pthread_once_intercept(pthread_once_t
*once_control
,
543 void (*init_routine
)(void))
547 VALGRIND_GET_ORIG_FN(fn
);
549 * Ignore any data races triggered by the implementation of pthread_once().
550 * Necessary for Darwin. This is not necessary for Linux but doesn't have
551 * any known adverse effects.
553 DRD_IGNORE_VAR(*once_control
);
554 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
555 CALL_FN_W_WW(ret
, fn
, once_control
, init_routine
);
556 ANNOTATE_IGNORE_READS_AND_WRITES_END();
557 DRD_STOP_IGNORING_VAR(*once_control
);
561 PTH_FUNCS(int, pthreadZuonce
, pthread_once_intercept
,
562 (pthread_once_t
*once_control
, void (*init_routine
)(void)),
563 (once_control
, init_routine
));
565 static __always_inline
566 int pthread_mutex_init_intercept(pthread_mutex_t
*mutex
,
567 const pthread_mutexattr_t
* attr
)
572 VALGRIND_GET_ORIG_FN(fn
);
573 mt
= PTHREAD_MUTEX_DEFAULT
;
575 pthread_mutexattr_gettype(attr
, &mt
);
576 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_MUTEX_INIT
,
577 mutex
, DRD_(pthread_to_drd_mutex_type
)(mt
),
579 CALL_FN_W_WW(ret
, fn
, mutex
, attr
);
580 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_MUTEX_INIT
,
585 PTH_FUNCS(int, pthreadZumutexZuinit
, pthread_mutex_init_intercept
,
586 (pthread_mutex_t
*mutex
, const pthread_mutexattr_t
* attr
),
589 static __always_inline
590 int pthread_mutex_destroy_intercept(pthread_mutex_t
* mutex
)
594 VALGRIND_GET_ORIG_FN(fn
);
595 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_MUTEX_DESTROY
,
597 CALL_FN_W_W(ret
, fn
, mutex
);
598 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_MUTEX_DESTROY
,
599 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
603 PTH_FUNCS(int, pthreadZumutexZudestroy
, pthread_mutex_destroy_intercept
,
604 (pthread_mutex_t
*mutex
), (mutex
));
606 static __always_inline
607 int pthread_mutex_lock_intercept(pthread_mutex_t
* mutex
)
611 VALGRIND_GET_ORIG_FN(fn
);
612 VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRE_MUTEX_LOCK
,
613 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
614 CALL_FN_W_W(ret
, fn
, mutex
);
615 VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__POST_MUTEX_LOCK
,
616 mutex
, ret
== 0, 0, 0, 0);
620 PTH_FUNCS(int, pthreadZumutexZulock
, pthread_mutex_lock_intercept
,
621 (pthread_mutex_t
*mutex
), (mutex
));
623 static __always_inline
624 int pthread_mutex_trylock_intercept(pthread_mutex_t
* mutex
)
628 VALGRIND_GET_ORIG_FN(fn
);
629 VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRE_MUTEX_LOCK
,
630 mutex
, DRD_(mutex_type
)(mutex
), 1, 0, 0);
631 CALL_FN_W_W(ret
, fn
, mutex
);
632 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_MUTEX_LOCK
,
633 mutex
, ret
== 0, 0, 0, 0);
637 PTH_FUNCS(int, pthreadZumutexZutrylock
, pthread_mutex_trylock_intercept
,
638 (pthread_mutex_t
*mutex
), (mutex
));
640 static __always_inline
641 int pthread_mutex_timedlock_intercept(pthread_mutex_t
*mutex
,
642 const struct timespec
*abs_timeout
)
646 VALGRIND_GET_ORIG_FN(fn
);
647 VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRE_MUTEX_LOCK
,
648 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
649 CALL_FN_W_WW(ret
, fn
, mutex
, abs_timeout
);
650 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_MUTEX_LOCK
,
651 mutex
, ret
== 0, 0, 0, 0);
655 PTH_FUNCS(int, pthreadZumutexZutimedlock
, pthread_mutex_timedlock_intercept
,
656 (pthread_mutex_t
*mutex
, const struct timespec
*abs_timeout
),
657 (mutex
, abs_timeout
));
659 static __always_inline
660 int pthread_mutex_unlock_intercept(pthread_mutex_t
*mutex
)
664 VALGRIND_GET_ORIG_FN(fn
);
665 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_MUTEX_UNLOCK
,
666 mutex
, DRD_(mutex_type
)(mutex
), 0, 0, 0);
667 CALL_FN_W_W(ret
, fn
, mutex
);
668 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_MUTEX_UNLOCK
,
673 PTH_FUNCS(int, pthreadZumutexZuunlock
, pthread_mutex_unlock_intercept
,
674 (pthread_mutex_t
*mutex
), (mutex
));
676 static __always_inline
677 int pthread_cond_init_intercept(pthread_cond_t
* cond
,
678 const pthread_condattr_t
* attr
)
682 VALGRIND_GET_ORIG_FN(fn
);
683 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_COND_INIT
,
685 CALL_FN_W_WW(ret
, fn
, cond
, attr
);
686 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_COND_INIT
,
691 PTH_FUNCS(int, pthreadZucondZuinit
, pthread_cond_init_intercept
,
692 (pthread_cond_t
* cond
, const pthread_condattr_t
* attr
),
695 static __always_inline
696 int pthread_cond_destroy_intercept(pthread_cond_t
* cond
)
700 VALGRIND_GET_ORIG_FN(fn
);
701 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_COND_DESTROY
,
703 CALL_FN_W_W(ret
, fn
, cond
);
704 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_COND_DESTROY
,
709 PTH_FUNCS(int, pthreadZucondZudestroy
, pthread_cond_destroy_intercept
,
710 (pthread_cond_t
* cond
), (cond
));
712 static __always_inline
713 int pthread_cond_wait_intercept(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
717 VALGRIND_GET_ORIG_FN(fn
);
718 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_COND_WAIT
,
719 cond
, mutex
, DRD_(mutex_type
)(mutex
), 0, 0);
720 CALL_FN_W_WW(ret
, fn
, cond
, mutex
);
721 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_COND_WAIT
,
722 cond
, mutex
, 1, 0, 0);
726 PTH_FUNCS(int, pthreadZucondZuwait
, pthread_cond_wait_intercept
,
727 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
),
730 static __always_inline
731 int pthread_cond_timedwait_intercept(pthread_cond_t
*cond
,
732 pthread_mutex_t
*mutex
,
733 const struct timespec
* abstime
)
737 VALGRIND_GET_ORIG_FN(fn
);
738 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_COND_WAIT
,
739 cond
, mutex
, DRD_(mutex_type
)(mutex
), 0, 0);
740 CALL_FN_W_WWW(ret
, fn
, cond
, mutex
, abstime
);
741 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_COND_WAIT
,
742 cond
, mutex
, 1, 0, 0);
746 PTH_FUNCS(int, pthreadZucondZutimedwait
, pthread_cond_timedwait_intercept
,
747 (pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
748 const struct timespec
* abstime
),
749 (cond
, mutex
, abstime
));
751 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
752 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
753 // two. Intercepting all pthread_cond_signal* functions will cause only one
754 // argument to be passed to pthread_cond_signal_np() and hence will cause this
755 // last function to crash.
757 static __always_inline
758 int pthread_cond_signal_intercept(pthread_cond_t
* cond
)
762 VALGRIND_GET_ORIG_FN(fn
);
763 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_COND_SIGNAL
,
765 CALL_FN_W_W(ret
, fn
, cond
);
766 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_COND_SIGNAL
,
771 PTH_FUNCS(int, pthreadZucondZusignal
, pthread_cond_signal_intercept
,
772 (pthread_cond_t
* cond
), (cond
));
774 static __always_inline
775 int pthread_cond_broadcast_intercept(pthread_cond_t
* cond
)
779 VALGRIND_GET_ORIG_FN(fn
);
780 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_COND_BROADCAST
,
782 CALL_FN_W_W(ret
, fn
, cond
);
783 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_COND_BROADCAST
,
788 PTH_FUNCS(int, pthreadZucondZubroadcast
, pthread_cond_broadcast_intercept
,
789 (pthread_cond_t
* cond
), (cond
));
791 #if defined(HAVE_PTHREAD_SPIN_LOCK)
792 static __always_inline
793 int pthread_spin_init_intercept(pthread_spinlock_t
*spinlock
, int pshared
)
797 VALGRIND_GET_ORIG_FN(fn
);
798 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK
,
799 spinlock
, 0, 0, 0, 0);
800 CALL_FN_W_WW(ret
, fn
, spinlock
, pshared
);
801 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK
,
802 spinlock
, 0, 0, 0, 0);
806 PTH_FUNCS(int, pthreadZuspinZuinit
, pthread_spin_init_intercept
,
807 (pthread_spinlock_t
*spinlock
, int pshared
), (spinlock
, pshared
));
809 static __always_inline
810 int pthread_spin_destroy_intercept(pthread_spinlock_t
*spinlock
)
814 VALGRIND_GET_ORIG_FN(fn
);
815 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_MUTEX_DESTROY
,
816 spinlock
, 0, 0, 0, 0);
817 CALL_FN_W_W(ret
, fn
, spinlock
);
818 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_MUTEX_DESTROY
,
819 spinlock
, mutex_type_spinlock
, 0, 0, 0);
823 PTH_FUNCS(int, pthreadZuspinZudestroy
, pthread_spin_destroy_intercept
,
824 (pthread_spinlock_t
*spinlock
), (spinlock
));
826 static __always_inline
827 int pthread_spin_lock_intercept(pthread_spinlock_t
*spinlock
)
831 VALGRIND_GET_ORIG_FN(fn
);
832 VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRE_MUTEX_LOCK
,
833 spinlock
, mutex_type_spinlock
, 0, 0, 0);
834 CALL_FN_W_W(ret
, fn
, spinlock
);
835 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_MUTEX_LOCK
,
836 spinlock
, ret
== 0, 0, 0, 0);
840 PTH_FUNCS(int, pthreadZuspinZulock
, pthread_spin_lock_intercept
,
841 (pthread_spinlock_t
*spinlock
), (spinlock
));
843 static __always_inline
844 int pthread_spin_trylock_intercept(pthread_spinlock_t
*spinlock
)
848 VALGRIND_GET_ORIG_FN(fn
);
849 VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRE_MUTEX_LOCK
,
850 spinlock
, mutex_type_spinlock
, 0, 0, 0);
851 CALL_FN_W_W(ret
, fn
, spinlock
);
852 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_MUTEX_LOCK
,
853 spinlock
, ret
== 0, 0, 0, 0);
857 PTH_FUNCS(int, pthreadZuspinZutrylock
, pthread_spin_trylock_intercept
,
858 (pthread_spinlock_t
*spinlock
), (spinlock
));
860 static __always_inline
861 int pthread_spin_unlock_intercept(pthread_spinlock_t
*spinlock
)
865 VALGRIND_GET_ORIG_FN(fn
);
866 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK
,
867 spinlock
, mutex_type_spinlock
, 0, 0, 0);
868 CALL_FN_W_W(ret
, fn
, spinlock
);
869 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK
,
870 spinlock
, 0, 0, 0, 0);
874 PTH_FUNCS(int, pthreadZuspinZuunlock
, pthread_spin_unlock_intercept
,
875 (pthread_spinlock_t
*spinlock
), (spinlock
));
876 #endif // HAVE_PTHREAD_SPIN_LOCK
879 #if defined(HAVE_PTHREAD_BARRIER_INIT)
880 static __always_inline
881 int pthread_barrier_init_intercept(pthread_barrier_t
* barrier
,
882 const pthread_barrierattr_t
* attr
,
887 VALGRIND_GET_ORIG_FN(fn
);
888 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_BARRIER_INIT
,
889 barrier
, pthread_barrier
, count
, 0, 0);
890 CALL_FN_W_WWW(ret
, fn
, barrier
, attr
, count
);
891 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_BARRIER_INIT
,
892 barrier
, pthread_barrier
, 0, 0, 0);
896 PTH_FUNCS(int, pthreadZubarrierZuinit
, pthread_barrier_init_intercept
,
897 (pthread_barrier_t
* barrier
, const pthread_barrierattr_t
* attr
,
898 unsigned count
), (barrier
, attr
, count
));
900 static __always_inline
901 int pthread_barrier_destroy_intercept(pthread_barrier_t
* barrier
)
905 VALGRIND_GET_ORIG_FN(fn
);
906 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_BARRIER_DESTROY
,
907 barrier
, pthread_barrier
, 0, 0, 0);
908 CALL_FN_W_W(ret
, fn
, barrier
);
909 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_BARRIER_DESTROY
,
910 barrier
, pthread_barrier
, 0, 0, 0);
914 PTH_FUNCS(int, pthreadZubarrierZudestroy
, pthread_barrier_destroy_intercept
,
915 (pthread_barrier_t
* barrier
), (barrier
));
917 static __always_inline
918 int pthread_barrier_wait_intercept(pthread_barrier_t
* barrier
)
922 VALGRIND_GET_ORIG_FN(fn
);
923 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_BARRIER_WAIT
,
924 barrier
, pthread_barrier
, 0, 0, 0);
925 CALL_FN_W_W(ret
, fn
, barrier
);
926 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_BARRIER_WAIT
,
927 barrier
, pthread_barrier
,
928 ret
== 0 || ret
== PTHREAD_BARRIER_SERIAL_THREAD
,
929 ret
== PTHREAD_BARRIER_SERIAL_THREAD
, 0);
933 PTH_FUNCS(int, pthreadZubarrierZuwait
, pthread_barrier_wait_intercept
,
934 (pthread_barrier_t
* barrier
), (barrier
));
935 #endif // HAVE_PTHREAD_BARRIER_INIT
938 static __always_inline
939 int sem_init_intercept(sem_t
*sem
, int pshared
, unsigned int value
)
943 VALGRIND_GET_ORIG_FN(fn
);
944 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_SEM_INIT
,
945 sem
, pshared
, value
, 0, 0);
946 CALL_FN_W_WWW(ret
, fn
, sem
, pshared
, value
);
947 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_SEM_INIT
,
952 PTH_FUNCS(int, semZuinit
, sem_init_intercept
,
953 (sem_t
*sem
, int pshared
, unsigned int value
), (sem
, pshared
, value
));
955 static __always_inline
956 int sem_destroy_intercept(sem_t
*sem
)
960 VALGRIND_GET_ORIG_FN(fn
);
961 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_SEM_DESTROY
,
963 CALL_FN_W_W(ret
, fn
, sem
);
964 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_SEM_DESTROY
,
969 PTH_FUNCS(int, semZudestroy
, sem_destroy_intercept
, (sem_t
*sem
), (sem
));
971 static __always_inline
972 sem_t
* sem_open_intercept(const char *name
, int oflag
, mode_t mode
,
977 VALGRIND_GET_ORIG_FN(fn
);
978 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_SEM_OPEN
,
979 name
, oflag
, mode
, value
, 0);
980 CALL_FN_W_WWWW(ret
, fn
, name
, oflag
, mode
, value
);
981 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_SEM_OPEN
,
982 ret
!= SEM_FAILED
? ret
: 0,
983 name
, oflag
, mode
, value
);
987 PTH_FUNCS(sem_t
*, semZuopen
, sem_open_intercept
,
988 (const char *name
, int oflag
, mode_t mode
, unsigned int value
),
989 (name
, oflag
, mode
, value
));
991 static __always_inline
int sem_close_intercept(sem_t
*sem
)
995 VALGRIND_GET_ORIG_FN(fn
);
996 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_SEM_CLOSE
,
998 CALL_FN_W_W(ret
, fn
, sem
);
999 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_SEM_CLOSE
,
1004 PTH_FUNCS(int, semZuclose
, sem_close_intercept
, (sem_t
*sem
), (sem
));
1006 static __always_inline
int sem_wait_intercept(sem_t
*sem
)
1010 VALGRIND_GET_ORIG_FN(fn
);
1011 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_SEM_WAIT
,
1013 CALL_FN_W_W(ret
, fn
, sem
);
1014 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_SEM_WAIT
,
1015 sem
, ret
== 0, 0, 0, 0);
1019 PTH_FUNCS(int, semZuwait
, sem_wait_intercept
, (sem_t
*sem
), (sem
));
1021 static __always_inline
int sem_trywait_intercept(sem_t
*sem
)
1025 VALGRIND_GET_ORIG_FN(fn
);
1026 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_SEM_WAIT
,
1028 CALL_FN_W_W(ret
, fn
, sem
);
1029 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_SEM_WAIT
,
1030 sem
, ret
== 0, 0, 0, 0);
1034 PTH_FUNCS(int, semZutrywait
, sem_trywait_intercept
, (sem_t
*sem
), (sem
));
1036 static __always_inline
1037 int sem_timedwait_intercept(sem_t
*sem
, const struct timespec
*abs_timeout
)
1041 VALGRIND_GET_ORIG_FN(fn
);
1042 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_SEM_WAIT
,
1044 CALL_FN_W_WW(ret
, fn
, sem
, abs_timeout
);
1045 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_SEM_WAIT
,
1046 sem
, ret
== 0, 0, 0, 0);
1050 PTH_FUNCS(int, semZutimedwait
, sem_timedwait_intercept
,
1051 (sem_t
*sem
, const struct timespec
*abs_timeout
),
1052 (sem
, abs_timeout
));
1054 static __always_inline
int sem_post_intercept(sem_t
*sem
)
1058 VALGRIND_GET_ORIG_FN(fn
);
1059 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_SEM_POST
,
1061 CALL_FN_W_W(ret
, fn
, sem
);
1062 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_SEM_POST
,
1063 sem
, ret
== 0, 0, 0, 0);
1067 PTH_FUNCS(int, semZupost
, sem_post_intercept
, (sem_t
*sem
), (sem
));
1069 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1070 functions have to be conditionally compiled. */
1071 #if defined(HAVE_PTHREAD_RWLOCK_T)
1073 static __always_inline
1074 int pthread_rwlock_init_intercept(pthread_rwlock_t
* rwlock
,
1075 const pthread_rwlockattr_t
* attr
)
1079 VALGRIND_GET_ORIG_FN(fn
);
1080 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_RWLOCK_INIT
,
1081 rwlock
, 0, 0, 0, 0);
1082 CALL_FN_W_WW(ret
, fn
, rwlock
, attr
);
1087 pthreadZurwlockZuinit
, pthread_rwlock_init_intercept
,
1088 (pthread_rwlock_t
* rwlock
, const pthread_rwlockattr_t
* attr
),
1091 static __always_inline
1092 int pthread_rwlock_destroy_intercept(pthread_rwlock_t
* rwlock
)
1096 VALGRIND_GET_ORIG_FN(fn
);
1097 CALL_FN_W_W(ret
, fn
, rwlock
);
1098 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_RWLOCK_DESTROY
,
1099 rwlock
, 0, 0, 0, 0);
1104 pthreadZurwlockZudestroy
, pthread_rwlock_destroy_intercept
,
1105 (pthread_rwlock_t
* rwlock
), (rwlock
));
1107 static __always_inline
1108 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t
* rwlock
)
1112 VALGRIND_GET_ORIG_FN(fn
);
1113 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_RWLOCK_RDLOCK
,
1114 rwlock
, 0, 0, 0, 0);
1115 CALL_FN_W_W(ret
, fn
, rwlock
);
1116 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_RWLOCK_RDLOCK
,
1117 rwlock
, ret
== 0, 0, 0, 0);
1122 pthreadZurwlockZurdlock
, pthread_rwlock_rdlock_intercept
,
1123 (pthread_rwlock_t
* rwlock
), (rwlock
));
1125 static __always_inline
1126 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t
* rwlock
)
1130 VALGRIND_GET_ORIG_FN(fn
);
1131 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_RWLOCK_WRLOCK
,
1132 rwlock
, 0, 0, 0, 0);
1133 CALL_FN_W_W(ret
, fn
, rwlock
);
1134 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_RWLOCK_WRLOCK
,
1135 rwlock
, ret
== 0, 0, 0, 0);
1140 pthreadZurwlockZuwrlock
, pthread_rwlock_wrlock_intercept
,
1141 (pthread_rwlock_t
* rwlock
), (rwlock
));
1143 static __always_inline
1144 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t
* rwlock
)
1148 VALGRIND_GET_ORIG_FN(fn
);
1149 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_RWLOCK_RDLOCK
,
1150 rwlock
, 0, 0, 0, 0);
1151 CALL_FN_W_W(ret
, fn
, rwlock
);
1152 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_RWLOCK_RDLOCK
,
1153 rwlock
, ret
== 0, 0, 0, 0);
1158 pthreadZurwlockZutimedrdlock
, pthread_rwlock_timedrdlock_intercept
,
1159 (pthread_rwlock_t
* rwlock
), (rwlock
));
1161 static __always_inline
1162 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t
* rwlock
)
1166 VALGRIND_GET_ORIG_FN(fn
);
1167 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_RWLOCK_WRLOCK
,
1168 rwlock
, 0, 0, 0, 0);
1169 CALL_FN_W_W(ret
, fn
, rwlock
);
1170 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_RWLOCK_WRLOCK
,
1171 rwlock
, ret
== 0, 0, 0, 0);
1176 pthreadZurwlockZutimedwrlock
, pthread_rwlock_timedwrlock_intercept
,
1177 (pthread_rwlock_t
* rwlock
), (rwlock
));
1179 static __always_inline
1180 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t
* rwlock
)
1184 VALGRIND_GET_ORIG_FN(fn
);
1185 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_RWLOCK_RDLOCK
,
1186 rwlock
, 0, 0, 0, 0);
1187 CALL_FN_W_W(ret
, fn
, rwlock
);
1188 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_RWLOCK_RDLOCK
,
1189 rwlock
, ret
== 0, 0, 0, 0);
1194 pthreadZurwlockZutryrdlock
, pthread_rwlock_tryrdlock_intercept
,
1195 (pthread_rwlock_t
* rwlock
), (rwlock
));
1197 static __always_inline
1198 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t
* rwlock
)
1202 VALGRIND_GET_ORIG_FN(fn
);
1203 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_RWLOCK_WRLOCK
,
1204 rwlock
, 0, 0, 0, 0);
1205 CALL_FN_W_W(ret
, fn
, rwlock
);
1206 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_RWLOCK_WRLOCK
,
1207 rwlock
, ret
== 0, 0, 0, 0);
1212 pthreadZurwlockZutrywrlock
, pthread_rwlock_trywrlock_intercept
,
1213 (pthread_rwlock_t
* rwlock
), (rwlock
));
1215 static __always_inline
1216 int pthread_rwlock_unlock_intercept(pthread_rwlock_t
* rwlock
)
1220 VALGRIND_GET_ORIG_FN(fn
);
1221 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_RWLOCK_UNLOCK
,
1222 rwlock
, 0, 0, 0, 0);
1223 CALL_FN_W_W(ret
, fn
, rwlock
);
1224 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_RWLOCK_UNLOCK
,
1225 rwlock
, ret
== 0, 0, 0, 0);
1230 pthreadZurwlockZuunlock
, pthread_rwlock_unlock_intercept
,
1231 (pthread_rwlock_t
* rwlock
), (rwlock
));
1233 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */