helgrind/tests/cond_timedwait_invalid: Update expected output because of r12213
[valgrind.git] / drd / drd_pthread_intercepts.c
blob4dc631c6932f3212cb6d754961a1f4a9a2872bae
1 /* -*- mode: C; c-basic-offset: 3; indent-tabs-mode: nil; -*- */
3 /*--------------------------------------------------------------------*/
4 /*--- Client-space code for DRD. drd_pthread_intercepts.c ---*/
5 /*--------------------------------------------------------------------*/
7 /*
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
25 02111-1307, USA.
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).
47 #ifndef _GNU_SOURCE
48 #define _GNU_SOURCE
49 #endif
51 #include <assert.h> /* assert() */
52 #include <errno.h>
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
65 #endif
66 #endif
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
82 * detected.
85 /**
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.
93 #ifdef VGO_darwin
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 \
98 { \
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. */ \
102 if (never_true) \
103 fflush(stdout); \
104 return pth_func_result; \
106 #else
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; }
111 #endif
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))
134 #else
135 #define __always_inline __inline__
136 #endif
138 /* Local data structures. */
140 typedef struct {
141 volatile int counter;
142 } DrdSema;
144 typedef struct
146 void* (*start)(void*);
147 void* arg;
148 int detachstate;
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);
185 sema->counter = 0;
188 static void DRD_(sema_destroy)(DrdSema* sema)
192 static void DRD_(sema_down)(DrdSema* sema)
194 int res = ENOSYS;
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)
200 res = 0;
201 else
202 res = errno;
203 #endif
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)
211 sched_yield();
213 sema->counter--;
216 static void DRD_(sema_up)(DrdSema* sema)
218 sema->counter++;
219 #ifdef HAVE_USABLE_LINUX_FUTEX_H
220 syscall(__NR_futex, (UWord)&sema->counter,
221 FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1);
222 #endif
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
230 * value.
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;
245 #endif
246 else
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
256 * implementation.
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)
277 /* glibc + NPTL. */
278 if (IS_ALIGNED(&mutex->__data.__kind))
280 const int kind = mutex->__data.__kind & 3;
281 return DRD_(pthread_to_drd_mutex_type)(kind);
283 #else
285 * Another POSIX threads implementation. The mutex type won't be printed
286 * when enabling --trace-mutex=yes.
288 #endif
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,
306 0, 0, 0, 0, 0);
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,
313 0, 0, 0, 0, 0);
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;
326 arg_copy = *arg_ptr;
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)
353 #if defined(linux)
354 #if defined(_CS_GNU_LIBPTHREAD_VERSION)
355 /* Linux with a recent glibc. */
356 char buffer[256];
357 unsigned len;
358 len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
359 assert(len <= sizeof(buffer));
360 return len > 0 && buffer[0] == 'l';
361 #else
362 /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
363 return 1;
364 #endif
365 #else
366 /* Another OS than Linux, hence no LinuxThreads. */
367 return 0;
368 #endif
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"))
381 fprintf(stderr,
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"
387 else
389 fprintf(stderr,
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"
393 "Giving up.\n"
396 abort();
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
413 * in Linux:
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)
433 int ret;
434 OrigFn fn;
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;
448 if (attr)
450 if (pthread_attr_getdetachstate(attr, &thread_args.detachstate) != 0)
451 assert(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)();
460 if (ret == 0)
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);
471 return ret;
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)
482 int ret;
483 OrigFn fn;
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);
492 if (ret == 0)
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();
498 return ret;
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)
508 int ret;
509 OrigFn fn;
511 VALGRIND_GET_ORIG_FN(fn);
512 CALL_FN_W_W(ret, fn, pt_thread);
513 DRD_(set_joinable)(pt_thread, 0);
515 return ret;
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)
527 int ret;
528 OrigFn fn;
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);
535 return ret;
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))
545 int ret;
546 OrigFn fn;
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);
558 return ret;
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)
569 int ret;
570 OrigFn fn;
571 int mt;
572 VALGRIND_GET_ORIG_FN(fn);
573 mt = PTHREAD_MUTEX_DEFAULT;
574 if (attr)
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),
578 0, 0, 0);
579 CALL_FN_W_WW(ret, fn, mutex, attr);
580 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_MUTEX_INIT,
581 mutex, 0, 0, 0, 0);
582 return ret;
585 PTH_FUNCS(int, pthreadZumutexZuinit, pthread_mutex_init_intercept,
586 (pthread_mutex_t *mutex, const pthread_mutexattr_t* attr),
587 (mutex, attr));
589 static __always_inline
590 int pthread_mutex_destroy_intercept(pthread_mutex_t* mutex)
592 int ret;
593 OrigFn fn;
594 VALGRIND_GET_ORIG_FN(fn);
595 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_MUTEX_DESTROY,
596 mutex, 0, 0, 0, 0);
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);
600 return ret;
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)
609 int ret;
610 OrigFn fn;
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);
617 return ret;
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)
626 int ret;
627 OrigFn fn;
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);
634 return ret;
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)
644 int ret;
645 OrigFn fn;
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);
652 return ret;
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)
662 int ret;
663 OrigFn fn;
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,
669 mutex, 0, 0, 0, 0);
670 return ret;
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)
680 int ret;
681 OrigFn fn;
682 VALGRIND_GET_ORIG_FN(fn);
683 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_COND_INIT,
684 cond, 0, 0, 0, 0);
685 CALL_FN_W_WW(ret, fn, cond, attr);
686 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_COND_INIT,
687 cond, 0, 0, 0, 0);
688 return ret;
691 PTH_FUNCS(int, pthreadZucondZuinit, pthread_cond_init_intercept,
692 (pthread_cond_t* cond, const pthread_condattr_t* attr),
693 (cond, attr));
695 static __always_inline
696 int pthread_cond_destroy_intercept(pthread_cond_t* cond)
698 int ret;
699 OrigFn fn;
700 VALGRIND_GET_ORIG_FN(fn);
701 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_COND_DESTROY,
702 cond, 0, 0, 0, 0);
703 CALL_FN_W_W(ret, fn, cond);
704 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_COND_DESTROY,
705 cond, 0, 0, 0, 0);
706 return ret;
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)
715 int ret;
716 OrigFn fn;
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);
723 return ret;
726 PTH_FUNCS(int, pthreadZucondZuwait, pthread_cond_wait_intercept,
727 (pthread_cond_t *cond, pthread_mutex_t *mutex),
728 (cond, 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)
735 int ret;
736 OrigFn fn;
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);
743 return ret;
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)
760 int ret;
761 OrigFn fn;
762 VALGRIND_GET_ORIG_FN(fn);
763 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_COND_SIGNAL,
764 cond, 0, 0, 0, 0);
765 CALL_FN_W_W(ret, fn, cond);
766 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_COND_SIGNAL,
767 cond, 0, 0, 0, 0);
768 return ret;
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)
777 int ret;
778 OrigFn fn;
779 VALGRIND_GET_ORIG_FN(fn);
780 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_COND_BROADCAST,
781 cond, 0, 0, 0, 0);
782 CALL_FN_W_W(ret, fn, cond);
783 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_COND_BROADCAST,
784 cond, 0, 0, 0, 0);
785 return ret;
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)
795 int ret;
796 OrigFn fn;
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);
803 return ret;
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)
812 int ret;
813 OrigFn fn;
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);
820 return ret;
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)
829 int ret;
830 OrigFn fn;
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);
837 return ret;
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)
846 int ret;
847 OrigFn fn;
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);
854 return ret;
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)
863 int ret;
864 OrigFn fn;
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);
871 return ret;
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,
883 unsigned count)
885 int ret;
886 OrigFn fn;
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);
893 return ret;
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)
903 int ret;
904 OrigFn fn;
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);
911 return ret;
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)
920 int ret;
921 OrigFn fn;
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);
930 return ret;
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)
941 int ret;
942 OrigFn fn;
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,
948 sem, 0, 0, 0, 0);
949 return ret;
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)
958 int ret;
959 OrigFn fn;
960 VALGRIND_GET_ORIG_FN(fn);
961 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_SEM_DESTROY,
962 sem, 0, 0, 0, 0);
963 CALL_FN_W_W(ret, fn, sem);
964 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_SEM_DESTROY,
965 sem, 0, 0, 0, 0);
966 return ret;
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,
973 unsigned int value)
975 sem_t *ret;
976 OrigFn fn;
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);
984 return ret;
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)
993 int ret;
994 OrigFn fn;
995 VALGRIND_GET_ORIG_FN(fn);
996 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_SEM_CLOSE,
997 sem, 0, 0, 0, 0);
998 CALL_FN_W_W(ret, fn, sem);
999 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__POST_SEM_CLOSE,
1000 sem, 0, 0, 0, 0);
1001 return ret;
1004 PTH_FUNCS(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
1006 static __always_inline int sem_wait_intercept(sem_t *sem)
1008 int ret;
1009 OrigFn fn;
1010 VALGRIND_GET_ORIG_FN(fn);
1011 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_SEM_WAIT,
1012 sem, 0, 0, 0, 0);
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);
1016 return ret;
1019 PTH_FUNCS(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1021 static __always_inline int sem_trywait_intercept(sem_t *sem)
1023 int ret;
1024 OrigFn fn;
1025 VALGRIND_GET_ORIG_FN(fn);
1026 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_SEM_WAIT,
1027 sem, 0, 0, 0, 0);
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);
1031 return ret;
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)
1039 int ret;
1040 OrigFn fn;
1041 VALGRIND_GET_ORIG_FN(fn);
1042 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_SEM_WAIT,
1043 sem, 0, 0, 0, 0);
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);
1047 return ret;
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)
1056 int ret;
1057 OrigFn fn;
1058 VALGRIND_GET_ORIG_FN(fn);
1059 VALGRIND_DO_CLIENT_REQUEST_EXPR(-1, VG_USERREQ__PRE_SEM_POST,
1060 sem, 0, 0, 0, 0);
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);
1064 return ret;
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)
1077 int ret;
1078 OrigFn fn;
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);
1083 return ret;
1086 PTH_FUNCS(int,
1087 pthreadZurwlockZuinit, pthread_rwlock_init_intercept,
1088 (pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr),
1089 (rwlock, attr));
1091 static __always_inline
1092 int pthread_rwlock_destroy_intercept(pthread_rwlock_t* rwlock)
1094 int ret;
1095 OrigFn fn;
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);
1100 return ret;
1103 PTH_FUNCS(int,
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)
1110 int ret;
1111 OrigFn fn;
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);
1118 return ret;
1121 PTH_FUNCS(int,
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)
1128 int ret;
1129 OrigFn fn;
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);
1136 return ret;
1139 PTH_FUNCS(int,
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)
1146 int ret;
1147 OrigFn fn;
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);
1154 return ret;
1157 PTH_FUNCS(int,
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)
1164 int ret;
1165 OrigFn fn;
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);
1172 return ret;
1175 PTH_FUNCS(int,
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)
1182 int ret;
1183 OrigFn fn;
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);
1190 return ret;
1193 PTH_FUNCS(int,
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)
1200 int ret;
1201 OrigFn fn;
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);
1208 return ret;
1211 PTH_FUNCS(int,
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)
1218 int ret;
1219 OrigFn fn;
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);
1226 return ret;
1229 PTH_FUNCS(int,
1230 pthreadZurwlockZuunlock, pthread_rwlock_unlock_intercept,
1231 (pthread_rwlock_t* rwlock), (rwlock));
1233 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */