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