1/*--------------------------------------------------------------------*/
2/*--- Client-space code for DRD.          drd_pthread_intercepts.c ---*/
3/*--------------------------------------------------------------------*/
4
5/*
6  This file is part of DRD, a thread error detector.
7
8  Copyright (C) 2006-2013 Bart Van Assche <bvanassche@acm.org>.
9
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.
14
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.
19
20  You should have received a copy of the GNU General Public License
21  along with this program; if not, write to the Free Software
22  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
23  02111-1307, USA.
24
25  The GNU General Public License is contained in the file COPYING.
26*/
27
28/* ---------------------------------------------------------------------
29   ALL THE CODE IN THIS FILE RUNS ON THE SIMULATED CPU.
30
31   These functions are not called directly - they're the targets of code
32   redirection or load notifications (see pub_core_redir.h for info).
33   They're named weirdly so that the intercept code can find them when the
34   shared object is initially loaded.
35
36   Note that this filename has the "drd_" prefix because it can appear
37   in stack traces, and the "drd_" makes it a little clearer that it
38   originates from Valgrind.
39   ------------------------------------------------------------------ */
40
41/*
42 * Define _GNU_SOURCE to make sure that pthread_spinlock_t is available when
43 * compiling with older glibc versions (2.3 or before).
44 */
45#ifndef _GNU_SOURCE
46#define _GNU_SOURCE
47#endif
48
49#include <assert.h>         /* assert() */
50#include <errno.h>
51#include <pthread.h>        /* pthread_mutex_t */
52#include <semaphore.h>      /* sem_t */
53#include <stdint.h>         /* uintptr_t */
54#include <stdio.h>          /* fprintf() */
55#include <stdlib.h>         /* malloc(), free() */
56#include <unistd.h>         /* confstr() */
57#include "config.h"         /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP etc. */
58#ifdef HAVE_USABLE_LINUX_FUTEX_H
59#include <asm/unistd.h>     /* __NR_futex */
60#include <linux/futex.h>    /* FUTEX_WAIT */
61#ifndef FUTEX_PRIVATE_FLAG
62#define FUTEX_PRIVATE_FLAG 0
63#endif
64#endif
65#include "drd_basics.h"     /* DRD_() */
66#include "drd_clientreq.h"
67#include "pub_tool_redir.h" /* VG_WRAP_FUNCTION_ZZ() */
68
69
70/*
71 * Notes regarding thread creation:
72 * - sg_init() runs on the context of the created thread and copies the vector
73 *   clock of the creator thread. This only works reliably if the creator
74 *   thread waits until this copy has been performed.
75 * - DRD_(thread_compute_minimum_vc)() does not take the vector clocks into
76 *   account that are involved in thread creation and for which the
77 *   corresponding thread has not yet been created. So not waiting until the
78 *   created thread has been started would make it possible that segments get
79 *   discarded that should not yet be discarded. Or: some data races are not
80 *   detected.
81 */
82
83/**
84 * Macro for generating a Valgrind interception function.
85 * @param[in] ret_ty Return type of the function to be generated.
86 * @param[in] zf Z-encoded name of the interception function.
87 * @param[in] implf Name of the function that implements the intercept.
88 * @param[in] arg_decl Argument declaration list enclosed in parentheses.
89 * @param[in] argl Argument list enclosed in parentheses.
90 */
91#ifdef VGO_darwin
92static int never_true;
93#define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl)                    \
94   ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl;     \
95   ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl      \
96   {									\
97      ret_ty pth_func_result = implf argl;				\
98      /* Apparently inserting a function call in wrapper functions */   \
99      /* is sufficient to avoid misaligned stack errors.           */	\
100      if (never_true)							\
101	 fflush(stdout);						\
102      return pth_func_result;						\
103   }
104#else
105#define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl)                    \
106   ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl;     \
107   ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl      \
108   { return implf argl; }
109#endif
110
111/**
112 * Macro for generating three Valgrind interception functions: one with the
113 * Z-encoded name zf, one with ZAZa ("@*") appended to the name zf and one
114 * with ZDZa ("$*") appended to the name zf. The second generated interception
115 * function will intercept versioned symbols on Linux, and the third will
116 * intercept versioned symbols on Darwin.
117 */
118#define PTH_FUNCS(ret_ty, zf, implf, argl_decl, argl)           \
119   PTH_FUNC(ret_ty, zf, implf, argl_decl, argl);                \
120   PTH_FUNC(ret_ty, zf ## ZAZa, implf, argl_decl, argl);        \
121   PTH_FUNC(ret_ty, zf ## ZDZa, implf, argl_decl, argl);
122
123/*
124 * Not inlining one of the intercept functions will cause the regression
125 * tests to fail because this would cause an additional stackfram to appear
126 * in the output. The __always_inline macro guarantees that inlining will
127 * happen, even when compiling with optimization disabled.
128 */
129#undef __always_inline /* since already defined in <cdefs.h> */
130#if __GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 2
131#define __always_inline __inline__ __attribute__((always_inline))
132#else
133#define __always_inline __inline__
134#endif
135
136/* Local data structures. */
137
138typedef struct {
139   pthread_mutex_t mutex;
140   int counter;
141   int waiters;
142} DrdSema;
143
144typedef struct
145{
146   void* (*start)(void*);
147   void* arg;
148   int   detachstate;
149   DrdSema* wrapper_started;
150} DrdPosixThreadArgs;
151
152
153/* Local function declarations. */
154
155static void DRD_(init)(void) __attribute__((constructor));
156static void DRD_(check_threading_library)(void);
157static void DRD_(set_main_thread_state)(void);
158static void DRD_(sema_init)(DrdSema* sema);
159static void DRD_(sema_destroy)(DrdSema* sema);
160static void DRD_(sema_down)(DrdSema* sema);
161static void DRD_(sema_up)(DrdSema* sema);
162
163
164/* Function definitions. */
165
166/**
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.
175 */
176static void DRD_(init)(void)
177{
178   DRD_(check_threading_library)();
179   DRD_(set_main_thread_state)();
180}
181
182static __always_inline void DRD_(ignore_mutex_ordering)(pthread_mutex_t *mutex)
183{
184   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_IGNORE_MUTEX_ORDERING,
185                                   mutex, 0, 0, 0, 0);
186}
187
188static void DRD_(sema_init)(DrdSema* sema)
189{
190   DRD_IGNORE_VAR(*sema);
191   pthread_mutex_init(&sema->mutex, NULL);
192   DRD_(ignore_mutex_ordering)(&sema->mutex);
193   sema->counter = 0;
194   sema->waiters = 0;
195}
196
197static void DRD_(sema_destroy)(DrdSema* sema)
198{
199   pthread_mutex_destroy(&sema->mutex);
200}
201
202static void DRD_(sema_down)(DrdSema* sema)
203{
204   int res = ENOSYS;
205
206   pthread_mutex_lock(&sema->mutex);
207   if (sema->counter == 0) {
208      sema->waiters++;
209      while (sema->counter == 0) {
210         pthread_mutex_unlock(&sema->mutex);
211#ifdef HAVE_USABLE_LINUX_FUTEX_H
212         if (syscall(__NR_futex, (UWord)&sema->counter,
213                     FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0) == 0)
214            res = 0;
215         else
216            res = errno;
217#endif
218         /*
219          * Invoke sched_yield() on non-Linux systems, if the futex syscall has
220          * not been invoked or if this code has been built on a Linux system
221          * where __NR_futex is defined and is run on a Linux system that does
222          * not support the futex syscall.
223          */
224         if (res != 0 && res != EWOULDBLOCK)
225            sched_yield();
226         pthread_mutex_lock(&sema->mutex);
227      }
228      sema->waiters--;
229   }
230   sema->counter--;
231   pthread_mutex_unlock(&sema->mutex);
232}
233
234static void DRD_(sema_up)(DrdSema* sema)
235{
236   pthread_mutex_lock(&sema->mutex);
237   sema->counter++;
238#ifdef HAVE_USABLE_LINUX_FUTEX_H
239   if (sema->waiters > 0)
240      syscall(__NR_futex, (UWord)&sema->counter,
241              FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1);
242#endif
243   pthread_mutex_unlock(&sema->mutex);
244}
245
246/**
247 * POSIX threads and DRD each have their own mutex type identification.
248 * Convert POSIX threads' mutex type to DRD's mutex type. In the code below
249 * if-statements are used to test the value of 'kind' instead of a switch
250 * statement because some of the PTHREAD_MUTEX_ macro's may have the same
251 * value.
252 */
253static MutexT DRD_(pthread_to_drd_mutex_type)(int kind)
254{
255   /*
256    * See also PTHREAD_MUTEX_KIND_MASK_NP in glibc source file
257    * <nptl/pthreadP.h>.
258    */
259   kind &= PTHREAD_MUTEX_RECURSIVE | PTHREAD_MUTEX_ERRORCHECK |
260      PTHREAD_MUTEX_NORMAL | PTHREAD_MUTEX_DEFAULT;
261
262   if (kind == PTHREAD_MUTEX_RECURSIVE)
263      return mutex_type_recursive_mutex;
264   else if (kind == PTHREAD_MUTEX_ERRORCHECK)
265      return mutex_type_errorcheck_mutex;
266   else if (kind == PTHREAD_MUTEX_NORMAL)
267      return mutex_type_default_mutex;
268   else if (kind == PTHREAD_MUTEX_DEFAULT)
269      return mutex_type_default_mutex;
270#if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
271   else if (kind == PTHREAD_MUTEX_ADAPTIVE_NP)
272      return mutex_type_default_mutex;
273#endif
274   else
275      return mutex_type_invalid_mutex;
276}
277
278#define IS_ALIGNED(p) (((uintptr_t)(p) & (sizeof(*(p)) - 1)) == 0)
279
280/**
281 * Read the mutex type stored in the client memory used for the mutex
282 * implementation.
283 *
284 * @note This function depends on the implementation of the POSIX threads
285 *   library -- the POSIX standard does not define the name of the member in
286 *   which the mutex type is stored.
287 * @note The function mutex_type() has been declared inline in order
288 *   to avoid that it shows up in call stacks (drd/tests/...exp* files).
289 * @note glibc stores the mutex type in the lowest two bits, and uses the
290 *   higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
291 *   PTHREAD_MUTEXATTR_FLAG_PSHARED.
292 */
293static __always_inline MutexT DRD_(mutex_type)(pthread_mutex_t* mutex)
294{
295#if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
296   /* glibc + LinuxThreads. */
297   if (IS_ALIGNED(&mutex->__m_kind))
298   {
299      const int kind = mutex->__m_kind & 3;
300      return DRD_(pthread_to_drd_mutex_type)(kind);
301   }
302#elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
303   /* glibc + NPTL. */
304   if (IS_ALIGNED(&mutex->__data.__kind))
305   {
306      const int kind = mutex->__data.__kind & 3;
307      return DRD_(pthread_to_drd_mutex_type)(kind);
308   }
309#else
310   /*
311    * Another POSIX threads implementation. The mutex type won't be printed
312    * when enabling --trace-mutex=yes.
313    */
314#endif
315   return mutex_type_unknown;
316}
317
318/**
319 * Tell DRD whether 'tid' is a joinable thread or a detached thread.
320 */
321static void DRD_(set_joinable)(const pthread_t tid, const int joinable)
322{
323   assert(joinable == 0 || joinable == 1);
324   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_JOINABLE,
325                                   tid, joinable, 0, 0, 0);
326}
327
328/** Tell DRD that the calling thread is about to enter pthread_create(). */
329static __always_inline void DRD_(entering_pthread_create)(void)
330{
331   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__ENTERING_PTHREAD_CREATE,
332                                   0, 0, 0, 0, 0);
333}
334
335/** Tell DRD that the calling thread has left pthread_create(). */
336static __always_inline void DRD_(left_pthread_create)(void)
337{
338   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LEFT_PTHREAD_CREATE,
339                                   0, 0, 0, 0, 0);
340}
341
342/**
343 * Entry point for newly created threads. This function is called from the
344 * thread created by pthread_create().
345 */
346static void* DRD_(thread_wrapper)(void* arg)
347{
348   DrdPosixThreadArgs* arg_ptr;
349   DrdPosixThreadArgs arg_copy;
350
351   arg_ptr = (DrdPosixThreadArgs*)arg;
352   arg_copy = *arg_ptr;
353
354   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
355                                   pthread_self(), 0, 0, 0, 0);
356
357   DRD_(set_joinable)(pthread_self(),
358                      arg_copy.detachstate == PTHREAD_CREATE_JOINABLE);
359
360   /*
361    * Only set 'wrapper_started' after VG_USERREQ__SET_PTHREADID and
362    * DRD_(set_joinable)() have been invoked to avoid a race with
363    * a pthread_detach() invocation for this thread from another thread.
364    */
365   DRD_(sema_up)(arg_copy.wrapper_started);
366
367   return (arg_copy.start)(arg_copy.arg);
368}
369
370/**
371 * Return 1 if the LinuxThreads implementation of POSIX Threads has been
372 * detected, and 0 otherwise.
373 *
374 * @see For more information about the confstr() function, see also
375 * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
376 */
377static int DRD_(detected_linuxthreads)(void)
378{
379#if defined(linux)
380#if defined(_CS_GNU_LIBPTHREAD_VERSION)
381   /* Linux with a recent glibc. */
382   HChar buffer[256];
383   unsigned len;
384   len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
385   assert(len <= sizeof(buffer));
386   return len > 0 && buffer[0] == 'l';
387#else
388   /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
389   return 1;
390#endif
391#else
392   /* Another OS than Linux, hence no LinuxThreads. */
393   return 0;
394#endif
395}
396
397/**
398 * Stop and print an error message in case a non-supported threading
399 * library implementation (LinuxThreads) has been detected.
400 */
401static void DRD_(check_threading_library)(void)
402{
403   if (DRD_(detected_linuxthreads)())
404   {
405      if (getenv("LD_ASSUME_KERNEL"))
406      {
407         fprintf(stderr,
408"Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
409"the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
410"after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
411);
412      }
413      else
414      {
415         fprintf(stderr,
416"Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
417"the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
418"after having upgraded to a newer version of your Linux distribution.\n"
419"Giving up.\n"
420);
421      }
422      abort();
423   }
424}
425
426/**
427 * The main thread is the only thread not created by pthread_create().
428 * Update DRD's state information about the main thread.
429 */
430static void DRD_(set_main_thread_state)(void)
431{
432   // Make sure that DRD knows about the main thread's POSIX thread ID.
433   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
434                                   pthread_self(), 0, 0, 0, 0);
435}
436
437/*
438 * Note: as of today there exist three different versions of pthread_create
439 * in Linux:
440 * - pthread_create@GLIBC_2.0
441 * - pthread_create@@GLIBC_2.1
442 * - pthread_create@@GLIBC_2.2.5
443 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
444 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
445 * versions have been implemented. In any glibc version where more than one
446 * pthread_create function has been implemented, older versions call the
447 * newer versions. Or: the pthread_create* wrapper defined below can be
448 * called recursively. Any code in this wrapper should take this in account.
449 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
450 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
451 * See also the implementation of pthread_create@GLIBC_2.0 in
452 * glibc-2.9/nptl/pthread_create.c.
453 */
454
455static __always_inline
456int pthread_create_intercept(pthread_t* thread, const pthread_attr_t* attr,
457                             void* (*start)(void*), void* arg)
458{
459   int    ret;
460   OrigFn fn;
461   DrdSema wrapper_started;
462   DrdPosixThreadArgs thread_args;
463
464   VALGRIND_GET_ORIG_FN(fn);
465
466   DRD_(sema_init)(&wrapper_started);
467   thread_args.start           = start;
468   thread_args.arg             = arg;
469   thread_args.wrapper_started = &wrapper_started;
470   /*
471    * Find out whether the thread will be started as a joinable thread
472    * or as a detached thread. If no thread attributes have been specified,
473    * this means that the new thread will be started as a joinable thread.
474    */
475   thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
476   if (attr)
477   {
478      if (pthread_attr_getdetachstate(attr, &thread_args.detachstate) != 0)
479         assert(0);
480   }
481   assert(thread_args.detachstate == PTHREAD_CREATE_JOINABLE
482          || thread_args.detachstate == PTHREAD_CREATE_DETACHED);
483
484   DRD_(entering_pthread_create)();
485   CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), &thread_args);
486   DRD_(left_pthread_create)();
487
488   if (ret == 0) {
489      /* Wait until the thread wrapper started. */
490      DRD_(sema_down)(&wrapper_started);
491   }
492
493   DRD_(sema_destroy)(&wrapper_started);
494
495   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT,
496                                   pthread_self(), 0, 0, 0, 0);
497
498   return ret;
499}
500
501PTH_FUNCS(int, pthreadZucreate, pthread_create_intercept,
502          (pthread_t *thread, const pthread_attr_t *attr,
503           void *(*start) (void *), void *arg),
504          (thread, attr, start, arg));
505
506static __always_inline
507int pthread_join_intercept(pthread_t pt_joinee, void **thread_return)
508{
509   int      ret;
510   OrigFn   fn;
511
512   VALGRIND_GET_ORIG_FN(fn);
513   /*
514    * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
515    * implementation triggers a (false positive) race report.
516    */
517   ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
518   CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
519   if (ret == 0)
520   {
521      VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN,
522                                      pt_joinee, 0, 0, 0, 0);
523   }
524   ANNOTATE_IGNORE_READS_AND_WRITES_END();
525   return ret;
526}
527
528PTH_FUNCS(int, pthreadZujoin, pthread_join_intercept,
529          (pthread_t pt_joinee, void **thread_return),
530          (pt_joinee, thread_return));
531
532static __always_inline
533int pthread_detach_intercept(pthread_t pt_thread)
534{
535   int ret;
536   OrigFn fn;
537
538   VALGRIND_GET_ORIG_FN(fn);
539   CALL_FN_W_W(ret, fn, pt_thread);
540   DRD_(set_joinable)(pt_thread, 0);
541
542   return ret;
543}
544
545PTH_FUNCS(int, pthreadZudetach, pthread_detach_intercept,
546          (pthread_t thread), (thread));
547
548// NOTE: be careful to intercept only pthread_cancel() and not
549// pthread_cancel_init() on Linux.
550
551static __always_inline
552int pthread_cancel_intercept(pthread_t pt_thread)
553{
554   int ret;
555   OrigFn fn;
556   VALGRIND_GET_ORIG_FN(fn);
557   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_THREAD_CANCEL,
558                                   pt_thread, 0, 0, 0, 0);
559   CALL_FN_W_W(ret, fn, pt_thread);
560   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_CANCEL,
561                                   pt_thread, ret==0, 0, 0, 0);
562   return ret;
563}
564
565PTH_FUNCS(int, pthreadZucancel, pthread_cancel_intercept,
566          (pthread_t thread), (thread))
567
568static __always_inline
569int pthread_once_intercept(pthread_once_t *once_control,
570                           void (*init_routine)(void))
571{
572   int ret;
573   OrigFn fn;
574   VALGRIND_GET_ORIG_FN(fn);
575   /*
576    * Ignore any data races triggered by the implementation of pthread_once().
577    * Necessary for Darwin. This is not necessary for Linux but doesn't have
578    * any known adverse effects.
579    */
580   DRD_IGNORE_VAR(*once_control);
581   ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
582   CALL_FN_W_WW(ret, fn, once_control, init_routine);
583   ANNOTATE_IGNORE_READS_AND_WRITES_END();
584   DRD_STOP_IGNORING_VAR(*once_control);
585   return ret;
586}
587
588PTH_FUNCS(int, pthreadZuonce, pthread_once_intercept,
589          (pthread_once_t *once_control, void (*init_routine)(void)),
590          (once_control, init_routine));
591
592static __always_inline
593int pthread_mutex_init_intercept(pthread_mutex_t *mutex,
594                                 const pthread_mutexattr_t* attr)
595{
596   int ret;
597   OrigFn fn;
598   int mt;
599   VALGRIND_GET_ORIG_FN(fn);
600   mt = PTHREAD_MUTEX_DEFAULT;
601   if (attr)
602      pthread_mutexattr_gettype(attr, &mt);
603   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
604                                   mutex, DRD_(pthread_to_drd_mutex_type)(mt),
605                                   0, 0, 0);
606   CALL_FN_W_WW(ret, fn, mutex, attr);
607   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
608                                   mutex, 0, 0, 0, 0);
609   return ret;
610}
611
612PTH_FUNCS(int, pthreadZumutexZuinit, pthread_mutex_init_intercept,
613          (pthread_mutex_t *mutex, const pthread_mutexattr_t* attr),
614          (mutex, attr));
615
616static __always_inline
617int pthread_mutex_destroy_intercept(pthread_mutex_t* mutex)
618{
619   int ret;
620   OrigFn fn;
621   VALGRIND_GET_ORIG_FN(fn);
622   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
623                                   mutex, 0, 0, 0, 0);
624   CALL_FN_W_W(ret, fn, mutex);
625   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
626                                   mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
627   return ret;
628}
629
630PTH_FUNCS(int, pthreadZumutexZudestroy, pthread_mutex_destroy_intercept,
631          (pthread_mutex_t *mutex), (mutex));
632
633static __always_inline
634int pthread_mutex_lock_intercept(pthread_mutex_t* mutex)
635{
636   int   ret;
637   OrigFn fn;
638   VALGRIND_GET_ORIG_FN(fn);
639   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
640                                   mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
641   CALL_FN_W_W(ret, fn, mutex);
642   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
643                                   mutex, ret == 0, 0, 0, 0);
644   return ret;
645}
646
647PTH_FUNCS(int, pthreadZumutexZulock, pthread_mutex_lock_intercept,
648          (pthread_mutex_t *mutex), (mutex));
649
650static __always_inline
651int pthread_mutex_trylock_intercept(pthread_mutex_t* mutex)
652{
653   int   ret;
654   OrigFn fn;
655   VALGRIND_GET_ORIG_FN(fn);
656   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
657                                   mutex, DRD_(mutex_type)(mutex), 1, 0, 0);
658   CALL_FN_W_W(ret, fn, mutex);
659   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
660                                   mutex, ret == 0, 0, 0, 0);
661   return ret;
662}
663
664PTH_FUNCS(int, pthreadZumutexZutrylock, pthread_mutex_trylock_intercept,
665          (pthread_mutex_t *mutex), (mutex));
666
667static __always_inline
668int pthread_mutex_timedlock_intercept(pthread_mutex_t *mutex,
669                                      const struct timespec *abs_timeout)
670{
671   int   ret;
672   OrigFn fn;
673   VALGRIND_GET_ORIG_FN(fn);
674   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
675                                   mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
676   CALL_FN_W_WW(ret, fn, mutex, abs_timeout);
677   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
678                                   mutex, ret == 0, 0, 0, 0);
679   return ret;
680}
681
682PTH_FUNCS(int, pthreadZumutexZutimedlock, pthread_mutex_timedlock_intercept,
683          (pthread_mutex_t *mutex, const struct timespec *abs_timeout),
684          (mutex, abs_timeout));
685
686static __always_inline
687int pthread_mutex_unlock_intercept(pthread_mutex_t *mutex)
688{
689   int ret;
690   OrigFn fn;
691   VALGRIND_GET_ORIG_FN(fn);
692   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
693                                   mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
694   CALL_FN_W_W(ret, fn, mutex);
695   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
696                                   mutex, 0, 0, 0, 0);
697   return ret;
698}
699
700PTH_FUNCS(int, pthreadZumutexZuunlock, pthread_mutex_unlock_intercept,
701          (pthread_mutex_t *mutex), (mutex));
702
703static __always_inline
704int pthread_cond_init_intercept(pthread_cond_t* cond,
705                                const pthread_condattr_t* attr)
706{
707   int ret;
708   OrigFn fn;
709   VALGRIND_GET_ORIG_FN(fn);
710   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT,
711                                   cond, 0, 0, 0, 0);
712   CALL_FN_W_WW(ret, fn, cond, attr);
713   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT,
714                                   cond, 0, 0, 0, 0);
715   return ret;
716}
717
718PTH_FUNCS(int, pthreadZucondZuinit, pthread_cond_init_intercept,
719          (pthread_cond_t* cond, const pthread_condattr_t* attr),
720          (cond, attr));
721
722static __always_inline
723int pthread_cond_destroy_intercept(pthread_cond_t* cond)
724{
725   int ret;
726   OrigFn fn;
727   VALGRIND_GET_ORIG_FN(fn);
728   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_DESTROY,
729                                   cond, 0, 0, 0, 0);
730   CALL_FN_W_W(ret, fn, cond);
731   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_DESTROY,
732                                   cond, ret==0, 0, 0, 0);
733   return ret;
734}
735
736PTH_FUNCS(int, pthreadZucondZudestroy, pthread_cond_destroy_intercept,
737          (pthread_cond_t* cond), (cond));
738
739static __always_inline
740int pthread_cond_wait_intercept(pthread_cond_t *cond, pthread_mutex_t *mutex)
741{
742   int   ret;
743   OrigFn fn;
744   VALGRIND_GET_ORIG_FN(fn);
745   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
746                                   cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
747   CALL_FN_W_WW(ret, fn, cond, mutex);
748   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
749                                   cond, mutex, 1, 0, 0);
750   return ret;
751}
752
753PTH_FUNCS(int, pthreadZucondZuwait, pthread_cond_wait_intercept,
754          (pthread_cond_t *cond, pthread_mutex_t *mutex),
755          (cond, mutex));
756
757static __always_inline
758int pthread_cond_timedwait_intercept(pthread_cond_t *cond,
759                                     pthread_mutex_t *mutex,
760                                     const struct timespec* abstime)
761{
762   int   ret;
763   OrigFn fn;
764   VALGRIND_GET_ORIG_FN(fn);
765   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
766                                   cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
767   CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
768   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
769                                   cond, mutex, 1, 0, 0);
770   return ret;
771}
772
773PTH_FUNCS(int, pthreadZucondZutimedwait, pthread_cond_timedwait_intercept,
774          (pthread_cond_t *cond, pthread_mutex_t *mutex,
775           const struct timespec* abstime),
776          (cond, mutex, abstime));
777
778// NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
779// pthread_cond_signal_thread_np(). The former accepts one argument; the latter
780// two. Intercepting all pthread_cond_signal* functions will cause only one
781// argument to be passed to pthread_cond_signal_np() and hence will cause this
782// last function to crash.
783
784static __always_inline
785int pthread_cond_signal_intercept(pthread_cond_t* cond)
786{
787   int   ret;
788   OrigFn fn;
789   VALGRIND_GET_ORIG_FN(fn);
790   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_SIGNAL,
791                                   cond, 0, 0, 0, 0);
792   CALL_FN_W_W(ret, fn, cond);
793   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_SIGNAL,
794                                   cond, 0, 0, 0, 0);
795   return ret;
796}
797
798PTH_FUNCS(int, pthreadZucondZusignal, pthread_cond_signal_intercept,
799          (pthread_cond_t* cond), (cond));
800
801static __always_inline
802int pthread_cond_broadcast_intercept(pthread_cond_t* cond)
803{
804   int   ret;
805   OrigFn fn;
806   VALGRIND_GET_ORIG_FN(fn);
807   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_BROADCAST,
808                                   cond, 0, 0, 0, 0);
809   CALL_FN_W_W(ret, fn, cond);
810   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_BROADCAST,
811                                   cond, 0, 0, 0, 0);
812   return ret;
813}
814
815PTH_FUNCS(int, pthreadZucondZubroadcast, pthread_cond_broadcast_intercept,
816          (pthread_cond_t* cond), (cond));
817
818#if defined(HAVE_PTHREAD_SPIN_LOCK) \
819    && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
820static __always_inline
821int pthread_spin_init_intercept(pthread_spinlock_t *spinlock, int pshared)
822{
823   int ret;
824   OrigFn fn;
825   VALGRIND_GET_ORIG_FN(fn);
826   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
827                                   spinlock, 0, 0, 0, 0);
828   CALL_FN_W_WW(ret, fn, spinlock, pshared);
829   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
830                                   spinlock, 0, 0, 0, 0);
831   return ret;
832}
833
834PTH_FUNCS(int, pthreadZuspinZuinit, pthread_spin_init_intercept,
835          (pthread_spinlock_t *spinlock, int pshared), (spinlock, pshared));
836
837static __always_inline
838int pthread_spin_destroy_intercept(pthread_spinlock_t *spinlock)
839{
840   int ret;
841   OrigFn fn;
842   VALGRIND_GET_ORIG_FN(fn);
843   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
844                                   spinlock, 0, 0, 0, 0);
845   CALL_FN_W_W(ret, fn, spinlock);
846   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
847                                   spinlock, mutex_type_spinlock, 0, 0, 0);
848   return ret;
849}
850
851PTH_FUNCS(int, pthreadZuspinZudestroy, pthread_spin_destroy_intercept,
852          (pthread_spinlock_t *spinlock), (spinlock));
853
854static __always_inline
855int pthread_spin_lock_intercept(pthread_spinlock_t *spinlock)
856{
857   int   ret;
858   OrigFn fn;
859   VALGRIND_GET_ORIG_FN(fn);
860   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
861                                   spinlock, mutex_type_spinlock, 0, 0, 0);
862   CALL_FN_W_W(ret, fn, spinlock);
863   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
864                                   spinlock, ret == 0, 0, 0, 0);
865   return ret;
866}
867
868PTH_FUNCS(int, pthreadZuspinZulock, pthread_spin_lock_intercept,
869          (pthread_spinlock_t *spinlock), (spinlock));
870
871static __always_inline
872int pthread_spin_trylock_intercept(pthread_spinlock_t *spinlock)
873{
874   int   ret;
875   OrigFn fn;
876   VALGRIND_GET_ORIG_FN(fn);
877   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
878                                   spinlock, mutex_type_spinlock, 0, 0, 0);
879   CALL_FN_W_W(ret, fn, spinlock);
880   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
881                                   spinlock, ret == 0, 0, 0, 0);
882   return ret;
883}
884
885PTH_FUNCS(int, pthreadZuspinZutrylock, pthread_spin_trylock_intercept,
886          (pthread_spinlock_t *spinlock), (spinlock));
887
888static __always_inline
889int pthread_spin_unlock_intercept(pthread_spinlock_t *spinlock)
890{
891   int   ret;
892   OrigFn fn;
893   VALGRIND_GET_ORIG_FN(fn);
894   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
895                                   spinlock, mutex_type_spinlock, 0, 0, 0);
896   CALL_FN_W_W(ret, fn, spinlock);
897   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
898                                   spinlock, 0, 0, 0, 0);
899   return ret;
900}
901
902PTH_FUNCS(int, pthreadZuspinZuunlock, pthread_spin_unlock_intercept,
903          (pthread_spinlock_t *spinlock), (spinlock));
904#endif   // HAVE_PTHREAD_SPIN_LOCK
905
906
907#if defined(HAVE_PTHREAD_BARRIER_INIT)
908static __always_inline
909int pthread_barrier_init_intercept(pthread_barrier_t* barrier,
910                                   const pthread_barrierattr_t* attr,
911                                   unsigned count)
912{
913   int   ret;
914   OrigFn fn;
915   VALGRIND_GET_ORIG_FN(fn);
916   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_INIT,
917                                   barrier, pthread_barrier, count, 0, 0);
918   CALL_FN_W_WWW(ret, fn, barrier, attr, count);
919   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_INIT,
920                                   barrier, pthread_barrier, 0, 0, 0);
921   return ret;
922}
923
924PTH_FUNCS(int, pthreadZubarrierZuinit, pthread_barrier_init_intercept,
925          (pthread_barrier_t* barrier, const pthread_barrierattr_t* attr,
926           unsigned count), (barrier, attr, count));
927
928static __always_inline
929int pthread_barrier_destroy_intercept(pthread_barrier_t* barrier)
930{
931   int   ret;
932   OrigFn fn;
933   VALGRIND_GET_ORIG_FN(fn);
934   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_DESTROY,
935                                   barrier, pthread_barrier, 0, 0, 0);
936   CALL_FN_W_W(ret, fn, barrier);
937   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_DESTROY,
938                                   barrier, pthread_barrier, 0, 0, 0);
939   return ret;
940}
941
942PTH_FUNCS(int, pthreadZubarrierZudestroy, pthread_barrier_destroy_intercept,
943          (pthread_barrier_t* barrier), (barrier));
944
945static __always_inline
946int pthread_barrier_wait_intercept(pthread_barrier_t* barrier)
947{
948   int   ret;
949   OrigFn fn;
950   VALGRIND_GET_ORIG_FN(fn);
951   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_WAIT,
952                                   barrier, pthread_barrier, 0, 0, 0);
953   CALL_FN_W_W(ret, fn, barrier);
954   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_WAIT,
955                              barrier, pthread_barrier,
956                              ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD,
957                              ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
958   return ret;
959}
960
961PTH_FUNCS(int, pthreadZubarrierZuwait, pthread_barrier_wait_intercept,
962          (pthread_barrier_t* barrier), (barrier));
963#endif   // HAVE_PTHREAD_BARRIER_INIT
964
965
966static __always_inline
967int sem_init_intercept(sem_t *sem, int pshared, unsigned int value)
968{
969   int   ret;
970   OrigFn fn;
971   VALGRIND_GET_ORIG_FN(fn);
972   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT,
973                                   sem, pshared, value, 0, 0);
974   CALL_FN_W_WWW(ret, fn, sem, pshared, value);
975   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT,
976                                   sem, 0, 0, 0, 0);
977   return ret;
978}
979
980PTH_FUNCS(int, semZuinit, sem_init_intercept,
981          (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
982
983static __always_inline
984int sem_destroy_intercept(sem_t *sem)
985{
986   int   ret;
987   OrigFn fn;
988   VALGRIND_GET_ORIG_FN(fn);
989   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_DESTROY,
990                                   sem, 0, 0, 0, 0);
991   CALL_FN_W_W(ret, fn, sem);
992   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_DESTROY,
993                                   sem, 0, 0, 0, 0);
994   return ret;
995}
996
997PTH_FUNCS(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
998
999static __always_inline
1000sem_t* sem_open_intercept(const char *name, int oflag, mode_t mode,
1001                          unsigned int value)
1002{
1003   sem_t *ret;
1004   OrigFn fn;
1005   VALGRIND_GET_ORIG_FN(fn);
1006   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_OPEN,
1007                                   name, oflag, mode, value, 0);
1008   CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value);
1009   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_OPEN,
1010                                   ret != SEM_FAILED ? ret : 0,
1011                                   name, oflag, mode, value);
1012   return ret;
1013}
1014
1015PTH_FUNCS(sem_t *, semZuopen, sem_open_intercept,
1016          (const char *name, int oflag, mode_t mode, unsigned int value),
1017          (name, oflag, mode, value));
1018
1019static __always_inline int sem_close_intercept(sem_t *sem)
1020{
1021   int   ret;
1022   OrigFn fn;
1023   VALGRIND_GET_ORIG_FN(fn);
1024   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_CLOSE,
1025                                   sem, 0, 0, 0, 0);
1026   CALL_FN_W_W(ret, fn, sem);
1027   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_CLOSE,
1028                                   sem, 0, 0, 0, 0);
1029   return ret;
1030}
1031
1032PTH_FUNCS(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
1033
1034static __always_inline int sem_wait_intercept(sem_t *sem)
1035{
1036   int   ret;
1037   OrigFn fn;
1038   VALGRIND_GET_ORIG_FN(fn);
1039   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1040                                   sem, 0, 0, 0, 0);
1041   CALL_FN_W_W(ret, fn, sem);
1042   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1043                                   sem, ret == 0, 0, 0, 0);
1044   return ret;
1045}
1046
1047PTH_FUNCS(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1048
1049static __always_inline int sem_trywait_intercept(sem_t *sem)
1050{
1051   int   ret;
1052   OrigFn fn;
1053   VALGRIND_GET_ORIG_FN(fn);
1054   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1055                                   sem, 0, 0, 0, 0);
1056   CALL_FN_W_W(ret, fn, sem);
1057   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1058                                   sem, ret == 0, 0, 0, 0);
1059   return ret;
1060}
1061
1062PTH_FUNCS(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1063
1064static __always_inline
1065int sem_timedwait_intercept(sem_t *sem, const struct timespec *abs_timeout)
1066{
1067   int   ret;
1068   OrigFn fn;
1069   VALGRIND_GET_ORIG_FN(fn);
1070   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1071                                   sem, 0, 0, 0, 0);
1072   CALL_FN_W_WW(ret, fn, sem, abs_timeout);
1073   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1074                                   sem, ret == 0, 0, 0, 0);
1075   return ret;
1076}
1077
1078PTH_FUNCS(int, semZutimedwait, sem_timedwait_intercept,
1079          (sem_t *sem, const struct timespec *abs_timeout),
1080          (sem, abs_timeout));
1081
1082static __always_inline int sem_post_intercept(sem_t *sem)
1083{
1084   int   ret;
1085   OrigFn fn;
1086   VALGRIND_GET_ORIG_FN(fn);
1087   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_POST,
1088                                   sem, 0, 0, 0, 0);
1089   CALL_FN_W_W(ret, fn, sem);
1090   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_POST,
1091                                   sem, ret == 0, 0, 0, 0);
1092   return ret;
1093}
1094
1095PTH_FUNCS(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
1096
1097/* Android's pthread.h doesn't say anything about rwlocks, hence these
1098   functions have to be conditionally compiled. */
1099#if defined(HAVE_PTHREAD_RWLOCK_T)
1100
1101static __always_inline
1102int pthread_rwlock_init_intercept(pthread_rwlock_t* rwlock,
1103                                  const pthread_rwlockattr_t* attr)
1104{
1105   int   ret;
1106   OrigFn fn;
1107   VALGRIND_GET_ORIG_FN(fn);
1108   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT,
1109                                   rwlock, 0, 0, 0, 0);
1110   CALL_FN_W_WW(ret, fn, rwlock, attr);
1111   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT,
1112                                   rwlock, 0, 0, 0, 0);
1113   return ret;
1114}
1115
1116PTH_FUNCS(int,
1117          pthreadZurwlockZuinit, pthread_rwlock_init_intercept,
1118          (pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr),
1119          (rwlock, attr));
1120
1121static __always_inline
1122int pthread_rwlock_destroy_intercept(pthread_rwlock_t* rwlock)
1123{
1124   int   ret;
1125   OrigFn fn;
1126   VALGRIND_GET_ORIG_FN(fn);
1127   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_DESTROY,
1128                                   rwlock, 0, 0, 0, 0);
1129   CALL_FN_W_W(ret, fn, rwlock);
1130   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_DESTROY,
1131                                   rwlock, 0, 0, 0, 0);
1132   return ret;
1133}
1134
1135PTH_FUNCS(int,
1136          pthreadZurwlockZudestroy, pthread_rwlock_destroy_intercept,
1137          (pthread_rwlock_t* rwlock), (rwlock));
1138
1139static __always_inline
1140int pthread_rwlock_rdlock_intercept(pthread_rwlock_t* rwlock)
1141{
1142   int   ret;
1143   OrigFn fn;
1144   VALGRIND_GET_ORIG_FN(fn);
1145   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1146                                   rwlock, 0, 0, 0, 0);
1147   CALL_FN_W_W(ret, fn, rwlock);
1148   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1149                                   rwlock, ret == 0, 0, 0, 0);
1150   return ret;
1151}
1152
1153PTH_FUNCS(int,
1154          pthreadZurwlockZurdlock, pthread_rwlock_rdlock_intercept,
1155          (pthread_rwlock_t* rwlock), (rwlock));
1156
1157static __always_inline
1158int pthread_rwlock_wrlock_intercept(pthread_rwlock_t* rwlock)
1159{
1160   int   ret;
1161   OrigFn fn;
1162   VALGRIND_GET_ORIG_FN(fn);
1163   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1164                                   rwlock, 0, 0, 0, 0);
1165   CALL_FN_W_W(ret, fn, rwlock);
1166   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1167                                   rwlock, ret == 0, 0, 0, 0);
1168   return ret;
1169}
1170
1171PTH_FUNCS(int,
1172          pthreadZurwlockZuwrlock, pthread_rwlock_wrlock_intercept,
1173          (pthread_rwlock_t* rwlock), (rwlock));
1174
1175static __always_inline
1176int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t* rwlock,
1177                                         const struct timespec *timeout)
1178{
1179   int   ret;
1180   OrigFn fn;
1181   VALGRIND_GET_ORIG_FN(fn);
1182   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1183                                   rwlock, 0, 0, 0, 0);
1184   CALL_FN_W_WW(ret, fn, rwlock, timeout);
1185   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1186                                   rwlock, ret == 0, 0, 0, 0);
1187   return ret;
1188}
1189
1190PTH_FUNCS(int,
1191          pthreadZurwlockZutimedrdlock, pthread_rwlock_timedrdlock_intercept,
1192          (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1193          (rwlock, timeout));
1194
1195static __always_inline
1196int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t* rwlock,
1197                                         const struct timespec *timeout)
1198{
1199   int   ret;
1200   OrigFn fn;
1201   VALGRIND_GET_ORIG_FN(fn);
1202   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1203                                   rwlock, 0, 0, 0, 0);
1204   CALL_FN_W_WW(ret, fn, rwlock, timeout);
1205   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1206                                   rwlock, ret == 0, 0, 0, 0);
1207   return ret;
1208}
1209
1210PTH_FUNCS(int,
1211          pthreadZurwlockZutimedwrlock, pthread_rwlock_timedwrlock_intercept,
1212          (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1213          (rwlock, timeout));
1214
1215static __always_inline
1216int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t* rwlock)
1217{
1218   int   ret;
1219   OrigFn fn;
1220   VALGRIND_GET_ORIG_FN(fn);
1221   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1222                                   rwlock, 0, 0, 0, 0);
1223   CALL_FN_W_W(ret, fn, rwlock);
1224   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1225                                   rwlock, ret == 0, 0, 0, 0);
1226   return ret;
1227}
1228
1229PTH_FUNCS(int,
1230          pthreadZurwlockZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1231          (pthread_rwlock_t* rwlock), (rwlock));
1232
1233static __always_inline
1234int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t* rwlock)
1235{
1236   int   ret;
1237   OrigFn fn;
1238   VALGRIND_GET_ORIG_FN(fn);
1239   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1240                                   rwlock, 0, 0, 0, 0);
1241   CALL_FN_W_W(ret, fn, rwlock);
1242   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1243                                   rwlock, ret == 0, 0, 0, 0);
1244   return ret;
1245}
1246
1247PTH_FUNCS(int,
1248          pthreadZurwlockZutrywrlock, pthread_rwlock_trywrlock_intercept,
1249          (pthread_rwlock_t* rwlock), (rwlock));
1250
1251static __always_inline
1252int pthread_rwlock_unlock_intercept(pthread_rwlock_t* rwlock)
1253{
1254   int   ret;
1255   OrigFn fn;
1256   VALGRIND_GET_ORIG_FN(fn);
1257   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_UNLOCK,
1258                                   rwlock, 0, 0, 0, 0);
1259   CALL_FN_W_W(ret, fn, rwlock);
1260   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_UNLOCK,
1261                                   rwlock, ret == 0, 0, 0, 0);
1262   return ret;
1263}
1264
1265PTH_FUNCS(int,
1266          pthreadZurwlockZuunlock, pthread_rwlock_unlock_intercept,
1267          (pthread_rwlock_t* rwlock), (rwlock));
1268
1269#endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
1270