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