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