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