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