]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/valgrind/src/valgrind-3.6.0-svn/drd/drd_pthread_intercepts.c
bead0e9859c61ce0e4b623d64210a0ddf22de37e
[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
346 /*
347  * Note: as of today there exist three different versions of pthread_create
348  * in Linux:
349  * - pthread_create@GLIBC_2.0
350  * - pthread_create@@GLIBC_2.1
351  * - pthread_create@@GLIBC_2.2.5
352  * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
353  * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
354  * versions have been implemented. In any glibc version where more than one
355  * pthread_create function has been implemented, older versions call the
356  * newer versions. Or: the pthread_create* wrapper defined below can be
357  * called recursively. Any code in this wrapper should take this in account.
358  * As an example, it is not safe to invoke the DRD_STOP_RECORDING
359  * / DRD_START_RECORDING client requests from the pthread_create wrapper.
360  * See also the implementation of pthread_create@GLIBC_2.0 in
361  * glibc-2.9/nptl/pthread_create.c.
362  */
363
364 static __always_inline
365 int pthread_create_intercept(pthread_t* thread, const pthread_attr_t* attr,
366                              void* (*start)(void*), void* arg)
367 {
368    int    res;
369    int    ret;
370    OrigFn fn;
371 #if defined(ALLOCATE_THREAD_ARGS_ON_THE_STACK)
372    DrdPosixThreadArgs thread_args;
373 #endif
374    DrdPosixThreadArgs* thread_args_p;
375
376    VALGRIND_GET_ORIG_FN(fn);
377
378 #if defined(ALLOCATE_THREAD_ARGS_ON_THE_STACK)
379    thread_args_p = &thread_args;
380 #else
381    thread_args_p = malloc(sizeof(*thread_args_p));
382 #endif
383    assert(thread_args_p);
384
385    thread_args_p->start           = start;
386    thread_args_p->arg             = arg;
387 #if defined(WAIT_UNTIL_CREATED_THREAD_STARTED)
388    DRD_IGNORE_VAR(thread_args_p->wrapper_started);
389    thread_args_p->wrapper_started = 0;
390 #endif
391    /*
392     * Find out whether the thread will be started as a joinable thread
393     * or as a detached thread. If no thread attributes have been specified,
394     * this means that the new thread will be started as a joinable thread.
395     */
396    thread_args_p->detachstate = PTHREAD_CREATE_JOINABLE;
397    if (attr)
398    {
399       if (pthread_attr_getdetachstate(attr, &thread_args_p->detachstate) != 0)
400       {
401          assert(0);
402       }
403    }
404    assert(thread_args_p->detachstate == PTHREAD_CREATE_JOINABLE
405           || thread_args_p->detachstate == PTHREAD_CREATE_DETACHED);
406
407
408    DRD_(entering_pthread_create)();
409    CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), thread_args_p);
410    DRD_(left_pthread_create)();
411
412 #if defined(WAIT_UNTIL_CREATED_THREAD_STARTED)
413    if (ret == 0)
414    {
415       /*
416        * Wait until the thread wrapper started.
417        * @todo Find out why some regression tests fail if thread arguments are
418        *   passed via dynamically allocated memory and if the loop below is
419        *   removed.
420        */
421       while (! thread_args_p->wrapper_started)
422       {
423          sched_yield();
424       }
425    }
426
427 #if defined(ALLOCATE_THREAD_ARGS_DYNAMICALLY)
428    free(thread_args_p);
429 #endif
430
431 #endif
432
433    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__DRD_START_NEW_SEGMENT,
434                               pthread_self(), 0, 0, 0, 0);
435
436    return ret;
437 }
438
439 PTH_FUNCS(int, pthreadZucreate, pthread_create_intercept,
440           (pthread_t *thread, const pthread_attr_t *attr,
441            void *(*start) (void *), void *arg),
442           (thread, attr, start, arg));
443
444 static __always_inline
445 int pthread_join_intercept(pthread_t pt_joinee, void **thread_return)
446 {
447    int      ret;
448    int      res;
449    OrigFn   fn;
450
451    VALGRIND_GET_ORIG_FN(fn);
452    CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
453    if (ret == 0)
454    {
455       VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_THREAD_JOIN,
456                                  pt_joinee, 0, 0, 0, 0);
457    }
458    return ret;
459 }
460
461 PTH_FUNCS(int, pthreadZujoin, pthread_join_intercept,
462           (pthread_t pt_joinee, void **thread_return),
463           (pt_joinee, thread_return));
464
465 static __always_inline
466 int pthread_detach_intercept(pthread_t pt_thread)
467 {
468    int ret;
469    OrigFn fn;
470    VALGRIND_GET_ORIG_FN(fn);
471    {
472       CALL_FN_W_W(ret, fn, pt_thread);
473       if (ret == 0)
474       {
475          DRD_(set_joinable)(pt_thread, 0);
476       }
477    }
478    return ret;
479 }
480
481 PTH_FUNCS(int, pthreadZudetach, pthread_detach_intercept,
482           (pthread_t thread), (thread));
483
484 // NOTE: be careful to intercept only pthread_cancel() and not
485 // pthread_cancel_init() on Linux.
486
487 static __always_inline
488 int pthread_cancel_intercept(pthread_t pt_thread)
489 {
490    int res;
491    int ret;
492    OrigFn fn;
493    VALGRIND_GET_ORIG_FN(fn);
494    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_THREAD_CANCEL,
495                               pt_thread, 0, 0, 0, 0);
496    CALL_FN_W_W(ret, fn, pt_thread);
497    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_THREAD_CANCEL,
498                               pt_thread, ret==0, 0, 0, 0);
499    return ret;
500 }
501
502 PTH_FUNCS(int, pthreadZucancel, pthread_cancel_intercept,
503           (pthread_t thread), (thread))
504
505 static __always_inline
506 int pthread_once_intercept(pthread_once_t *once_control,
507                            void (*init_routine)(void))
508 {
509    int ret;
510    OrigFn fn;
511    VALGRIND_GET_ORIG_FN(fn);
512    /*
513     * Ignore any data races triggered by the implementation of pthread_once().
514     * Necessary for Darwin. This is not necessary for Linux but doesn't have
515     * any known adverse effects.
516     */
517    DRD_IGNORE_VAR(*once_control);
518    CALL_FN_W_WW(ret, fn, once_control, init_routine);
519    DRD_STOP_IGNORING_VAR(*once_control);
520    return ret;
521 }
522
523 PTH_FUNCS(int, pthreadZuonce, pthread_once_intercept,
524           (pthread_once_t *once_control, void (*init_routine)(void)),
525           (once_control, init_routine));
526
527 static __always_inline
528 int pthread_mutex_init_intercept(pthread_mutex_t *mutex,
529                                  const pthread_mutexattr_t* attr)
530 {
531    int ret;
532    int res;
533    OrigFn fn;
534    int mt;
535    VALGRIND_GET_ORIG_FN(fn);
536    mt = PTHREAD_MUTEX_DEFAULT;
537    if (attr)
538       pthread_mutexattr_gettype(attr, &mt);
539    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_MUTEX_INIT,
540                               mutex, DRD_(pthread_to_drd_mutex_type)(mt),
541                               0, 0, 0);
542    CALL_FN_W_WW(ret, fn, mutex, attr);
543    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_INIT,
544                               mutex, 0, 0, 0, 0);
545    return ret;
546 }
547
548 PTH_FUNCS(int, pthreadZumutexZuinit, pthread_mutex_init_intercept,
549           (pthread_mutex_t *mutex, const pthread_mutexattr_t* attr),
550           (mutex, attr));
551
552 static __always_inline
553 int pthread_mutex_destroy_intercept(pthread_mutex_t* mutex)
554 {
555    int ret;
556    int res;
557    OrigFn fn;
558    VALGRIND_GET_ORIG_FN(fn);
559    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_MUTEX_DESTROY,
560                               mutex, 0, 0, 0, 0);
561    CALL_FN_W_W(ret, fn, mutex);
562    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_DESTROY,
563                               mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
564    return ret;
565 }
566
567 PTH_FUNCS(int, pthreadZumutexZudestroy, pthread_mutex_destroy_intercept,
568           (pthread_mutex_t *mutex), (mutex));
569
570 static __always_inline
571 int pthread_mutex_lock_intercept(pthread_mutex_t* mutex)
572 {
573    int   ret;
574    int   res;
575    OrigFn fn;
576    VALGRIND_GET_ORIG_FN(fn);
577    VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
578                               mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
579    CALL_FN_W_W(ret, fn, mutex);
580    VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__POST_MUTEX_LOCK,
581                               mutex, ret == 0, 0, 0, 0);
582    return ret;
583 }
584
585 PTH_FUNCS(int, pthreadZumutexZulock, pthread_mutex_lock_intercept,
586           (pthread_mutex_t *mutex), (mutex));
587
588 static __always_inline
589 int pthread_mutex_trylock_intercept(pthread_mutex_t* mutex)
590 {
591    int   ret;
592    int   res;
593    OrigFn fn;
594    VALGRIND_GET_ORIG_FN(fn);
595    VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
596                               mutex, DRD_(mutex_type)(mutex), 1, 0, 0);
597    CALL_FN_W_W(ret, fn, mutex);
598    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_LOCK,
599                               mutex, ret == 0, 0, 0, 0);
600    return ret;
601 }
602
603 PTH_FUNCS(int, pthreadZumutexZutrylock, pthread_mutex_trylock_intercept,
604           (pthread_mutex_t *mutex), (mutex));
605
606 static __always_inline
607 int pthread_mutex_timedlock_intercept(pthread_mutex_t *mutex,
608                                       const struct timespec *abs_timeout)
609 {
610    int   ret;
611    int   res;
612    OrigFn fn;
613    VALGRIND_GET_ORIG_FN(fn);
614    VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
615                               mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
616    CALL_FN_W_WW(ret, fn, mutex, abs_timeout);
617    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_LOCK,
618                               mutex, ret == 0, 0, 0, 0);
619    return ret;
620 }
621
622 PTH_FUNCS(int, pthreadZumutexZutimedlock, pthread_mutex_timedlock_intercept,
623           (pthread_mutex_t *mutex, const struct timespec *abs_timeout),
624           (mutex, abs_timeout));
625
626 static __always_inline
627 int pthread_mutex_unlock_intercept(pthread_mutex_t *mutex)
628 {
629    int ret;
630    int   res;
631    OrigFn fn;
632    VALGRIND_GET_ORIG_FN(fn);
633    VALGRIND_DO_CLIENT_REQUEST(res, -1,
634                               VG_USERREQ__PRE_MUTEX_UNLOCK,
635                               mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
636    CALL_FN_W_W(ret, fn, mutex);
637    VALGRIND_DO_CLIENT_REQUEST(res, -1,
638                               VG_USERREQ__POST_MUTEX_UNLOCK,
639                               mutex, 0, 0, 0, 0);
640    return ret;
641 }
642
643 PTH_FUNCS(int, pthreadZumutexZuunlock, pthread_mutex_unlock_intercept,
644           (pthread_mutex_t *mutex), (mutex));
645
646 static __always_inline
647 int pthread_cond_init_intercept(pthread_cond_t* cond,
648                                 const pthread_condattr_t* attr)
649 {
650    int ret;
651    int res;
652    OrigFn fn;
653    VALGRIND_GET_ORIG_FN(fn);
654    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_INIT,
655                               cond, 0, 0, 0, 0);
656    CALL_FN_W_WW(ret, fn, cond, attr);
657    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_INIT,
658                               cond, 0, 0, 0, 0);
659    return ret;
660 }
661
662 PTH_FUNCS(int, pthreadZucondZuinit, pthread_cond_init_intercept,
663           (pthread_cond_t* cond, const pthread_condattr_t* attr),
664           (cond, attr));
665
666 static __always_inline
667 int pthread_cond_destroy_intercept(pthread_cond_t* cond)
668 {
669    int ret;
670    int res;
671    OrigFn fn;
672    VALGRIND_GET_ORIG_FN(fn);
673    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_DESTROY,
674                               cond, 0, 0, 0, 0);
675    CALL_FN_W_W(ret, fn, cond);
676    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_DESTROY,
677                               cond, 0, 0, 0, 0);
678    return ret;
679 }
680
681 PTH_FUNCS(int, pthreadZucondZudestroy, pthread_cond_destroy_intercept,
682           (pthread_cond_t* cond), (cond));
683
684 static __always_inline
685 int pthread_cond_wait_intercept(pthread_cond_t *cond, pthread_mutex_t *mutex)
686 {
687    int   ret;
688    int   res;
689    OrigFn fn;
690    VALGRIND_GET_ORIG_FN(fn);
691    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_WAIT,
692                               cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
693    CALL_FN_W_WW(ret, fn, cond, mutex);
694    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_WAIT,
695                               cond, mutex, 1, 0, 0);
696    return ret;
697 }
698
699 PTH_FUNCS(int, pthreadZucondZuwait, pthread_cond_wait_intercept,
700           (pthread_cond_t *cond, pthread_mutex_t *mutex),
701           (cond, mutex));
702
703 static __always_inline
704 int pthread_cond_timedwait_intercept(pthread_cond_t *cond,
705                                      pthread_mutex_t *mutex,
706                                      const struct timespec* abstime)
707 {
708    int   ret;
709    int   res;
710    OrigFn fn;
711    VALGRIND_GET_ORIG_FN(fn);
712    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_WAIT,
713                               cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
714    CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
715    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_WAIT,
716                               cond, mutex, 1, 0, 0);
717    return ret;
718 }
719
720 PTH_FUNCS(int, pthreadZucondZutimedwait, pthread_cond_timedwait_intercept,
721           (pthread_cond_t *cond, pthread_mutex_t *mutex,
722            const struct timespec* abstime),
723           (cond, mutex, abstime));
724
725 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
726 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
727 // two. Intercepting all pthread_cond_signal* functions will cause only one
728 // argument to be passed to pthread_cond_signal_np() and hence will cause this
729 // last function to crash.
730
731 static __always_inline
732 int pthread_cond_signal_intercept(pthread_cond_t* cond)
733 {
734    int   ret;
735    int   res;
736    OrigFn fn;
737    VALGRIND_GET_ORIG_FN(fn);
738    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_SIGNAL,
739                               cond, 0, 0, 0, 0);
740    CALL_FN_W_W(ret, fn, cond);
741    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_SIGNAL,
742                               cond, 0, 0, 0, 0);
743    return ret;
744 }
745
746 PTH_FUNCS(int, pthreadZucondZusignal, pthread_cond_signal_intercept,
747           (pthread_cond_t* cond), (cond));
748
749 static __always_inline
750 int pthread_cond_broadcast_intercept(pthread_cond_t* cond)
751 {
752    int   ret;
753    int   res;
754    OrigFn fn;
755    VALGRIND_GET_ORIG_FN(fn);
756    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_BROADCAST,
757                               cond, 0, 0, 0, 0);
758    CALL_FN_W_W(ret, fn, cond);
759    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_BROADCAST,
760                               cond, 0, 0, 0, 0);
761    return ret;
762 }
763
764 PTH_FUNCS(int, pthreadZucondZubroadcast, pthread_cond_broadcast_intercept,
765           (pthread_cond_t* cond), (cond));
766
767 #if defined(HAVE_PTHREAD_SPIN_LOCK)
768 static __always_inline
769 int pthread_spin_init_intercept(pthread_spinlock_t *spinlock, int pshared)
770 {
771    int ret;
772    int res;
773    OrigFn fn;
774    VALGRIND_GET_ORIG_FN(fn);
775    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
776                               spinlock, 0, 0, 0, 0);
777    CALL_FN_W_WW(ret, fn, spinlock, pshared);
778    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
779                               spinlock, 0, 0, 0, 0);
780    return ret;
781 }
782
783 PTH_FUNCS(int, pthreadZuspinZuinit, pthread_spin_init_intercept,
784           (pthread_spinlock_t *spinlock, int pshared), (spinlock, pshared));
785
786 static __always_inline
787 int pthread_spin_destroy_intercept(pthread_spinlock_t *spinlock)
788 {
789    int ret;
790    int res;
791    OrigFn fn;
792    VALGRIND_GET_ORIG_FN(fn);
793    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_MUTEX_DESTROY,
794                               spinlock, 0, 0, 0, 0);
795    CALL_FN_W_W(ret, fn, spinlock);
796    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_DESTROY,
797                               spinlock, mutex_type_spinlock, 0, 0, 0);
798    return ret;
799 }
800
801 PTH_FUNCS(int, pthreadZuspinZudestroy, pthread_spin_destroy_intercept,
802           (pthread_spinlock_t *spinlock), (spinlock));
803
804 static __always_inline
805 int pthread_spin_lock_intercept(pthread_spinlock_t *spinlock)
806 {
807    int   ret;
808    int   res;
809    OrigFn fn;
810    VALGRIND_GET_ORIG_FN(fn);
811    VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
812                               spinlock, mutex_type_spinlock, 0, 0, 0);
813    CALL_FN_W_W(ret, fn, spinlock);
814    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_LOCK,
815                               spinlock, ret == 0, 0, 0, 0);
816    return ret;
817 }
818
819 PTH_FUNCS(int, pthreadZuspinZulock, pthread_spin_lock_intercept,
820           (pthread_spinlock_t *spinlock), (spinlock));
821
822 static __always_inline
823 int pthread_spin_trylock_intercept(pthread_spinlock_t *spinlock)
824 {
825    int   ret;
826    int   res;
827    OrigFn fn;
828    VALGRIND_GET_ORIG_FN(fn);
829    VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
830                               spinlock, mutex_type_spinlock, 0, 0, 0);
831    CALL_FN_W_W(ret, fn, spinlock);
832    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_LOCK,
833                               spinlock, ret == 0, 0, 0, 0);
834    return ret;
835 }
836
837 PTH_FUNCS(int, pthreadZuspinZutrylock, pthread_spin_trylock_intercept,
838           (pthread_spinlock_t *spinlock), (spinlock));
839
840 static __always_inline
841 int pthread_spin_unlock_intercept(pthread_spinlock_t *spinlock)
842 {
843    int   ret;
844    int   res;
845    OrigFn fn;
846    VALGRIND_GET_ORIG_FN(fn);
847    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
848                               spinlock, mutex_type_spinlock, 0, 0, 0);
849    CALL_FN_W_W(ret, fn, spinlock);
850    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
851                               spinlock, 0, 0, 0, 0);
852    return ret;
853 }
854
855 PTH_FUNCS(int, pthreadZuspinZuunlock, pthread_spin_unlock_intercept,
856           (pthread_spinlock_t *spinlock), (spinlock));
857 #endif   // HAVE_PTHREAD_SPIN_LOCK
858
859
860 #if defined(HAVE_PTHREAD_BARRIER_INIT)
861 static __always_inline
862 int pthread_barrier_init_intercept(pthread_barrier_t* barrier,
863                                    const pthread_barrierattr_t* attr,
864                                    unsigned count)
865 {
866    int   ret;
867    int   res;
868    OrigFn fn;
869    VALGRIND_GET_ORIG_FN(fn);
870    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_BARRIER_INIT,
871                               barrier, pthread_barrier, count, 0, 0);
872    CALL_FN_W_WWW(ret, fn, barrier, attr, count);
873    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_BARRIER_INIT,
874                               barrier, pthread_barrier, 0, 0, 0);
875    return ret;
876 }
877
878 PTH_FUNCS(int, pthreadZubarrierZuinit, pthread_barrier_init_intercept,
879           (pthread_barrier_t* barrier, const pthread_barrierattr_t* attr,
880            unsigned count), (barrier, attr, count));
881
882 static __always_inline
883 int pthread_barrier_destroy_intercept(pthread_barrier_t* barrier)
884 {
885    int   ret;
886    int   res;
887    OrigFn fn;
888    VALGRIND_GET_ORIG_FN(fn);
889    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_BARRIER_DESTROY,
890                               barrier, pthread_barrier, 0, 0, 0);
891    CALL_FN_W_W(ret, fn, barrier);
892    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_BARRIER_DESTROY,
893                               barrier, pthread_barrier, 0, 0, 0);
894    return ret;
895 }
896
897 PTH_FUNCS(int, pthreadZubarrierZudestroy, pthread_barrier_destroy_intercept,
898           (pthread_barrier_t* barrier), (barrier));
899
900 static __always_inline
901 int pthread_barrier_wait_intercept(pthread_barrier_t* barrier)
902 {
903    int   ret;
904    int   res;
905    OrigFn fn;
906    VALGRIND_GET_ORIG_FN(fn);
907    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_BARRIER_WAIT,
908                               barrier, pthread_barrier, 0, 0, 0);
909    CALL_FN_W_W(ret, fn, barrier);
910    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_BARRIER_WAIT,
911                               barrier, pthread_barrier,
912                               ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD,
913                               ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
914    return ret;
915 }
916
917 PTH_FUNCS(int, pthreadZubarrierZuwait, pthread_barrier_wait_intercept,
918           (pthread_barrier_t* barrier), (barrier));
919 #endif   // HAVE_PTHREAD_BARRIER_INIT
920
921
922 static __always_inline
923 int sem_init_intercept(sem_t *sem, int pshared, unsigned int value)
924 {
925    int   ret;
926    int   res;
927    OrigFn fn;
928    VALGRIND_GET_ORIG_FN(fn);
929    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_INIT,
930                               sem, pshared, value, 0, 0);
931    CALL_FN_W_WWW(ret, fn, sem, pshared, value);
932    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_INIT,
933                               sem, 0, 0, 0, 0);
934    return ret;
935 }
936
937 PTH_FUNCS(int, semZuinit, sem_init_intercept,
938           (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
939
940 static __always_inline
941 int sem_destroy_intercept(sem_t *sem)
942 {
943    int   ret;
944    int   res;
945    OrigFn fn;
946    VALGRIND_GET_ORIG_FN(fn);
947    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_DESTROY,
948                               sem, 0, 0, 0, 0);
949    CALL_FN_W_W(ret, fn, sem);
950    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_DESTROY,
951                               sem, 0, 0, 0, 0);
952    return ret;
953 }
954
955 PTH_FUNCS(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
956
957 static __always_inline
958 sem_t* sem_open_intercept(const char *name, int oflag, mode_t mode,
959                           unsigned int value)
960 {
961    sem_t *ret;
962    int    res;
963    OrigFn fn;
964    VALGRIND_GET_ORIG_FN(fn);
965    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_OPEN,
966                               name, oflag, mode, value, 0);
967    CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value);
968    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_OPEN,
969                               ret != SEM_FAILED ? ret : 0,
970                               name, oflag, mode, value);
971    return ret;
972 }
973
974 PTH_FUNCS(sem_t *, semZuopen, sem_open_intercept,
975           (const char *name, int oflag, mode_t mode, unsigned int value),
976           (name, oflag, mode, value));
977
978 static __always_inline int sem_close_intercept(sem_t *sem)
979 {
980    int   ret;
981    int   res;
982    OrigFn fn;
983    VALGRIND_GET_ORIG_FN(fn);
984    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_CLOSE,
985                               sem, 0, 0, 0, 0);
986    CALL_FN_W_W(ret, fn, sem);
987    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_CLOSE,
988                               sem, 0, 0, 0, 0);
989    return ret;
990 }
991
992 PTH_FUNCS(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
993
994 static __always_inline int sem_wait_intercept(sem_t *sem)
995 {
996    int   ret;
997    int   res;
998    OrigFn fn;
999    VALGRIND_GET_ORIG_FN(fn);
1000    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_WAIT,
1001                               sem, 0, 0, 0, 0);
1002    CALL_FN_W_W(ret, fn, sem);
1003    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
1004                               sem, ret == 0, 0, 0, 0);
1005    return ret;
1006 }
1007
1008 PTH_FUNCS(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1009
1010 static __always_inline int sem_trywait_intercept(sem_t *sem)
1011 {
1012    int   ret;
1013    int   res;
1014    OrigFn fn;
1015    VALGRIND_GET_ORIG_FN(fn);
1016    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_WAIT,
1017                               sem, 0, 0, 0, 0);
1018    CALL_FN_W_W(ret, fn, sem);
1019    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
1020                               sem, ret == 0, 0, 0, 0);
1021    return ret;
1022 }
1023
1024 PTH_FUNCS(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1025
1026 static __always_inline
1027 int sem_timedwait_intercept(sem_t *sem, const struct timespec *abs_timeout)
1028 {
1029    int   ret;
1030    int   res;
1031    OrigFn fn;
1032    VALGRIND_GET_ORIG_FN(fn);
1033    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_WAIT,
1034                               sem, 0, 0, 0, 0);
1035    CALL_FN_W_WW(ret, fn, sem, abs_timeout);
1036    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
1037                               sem, ret == 0, 0, 0, 0);
1038    return ret;
1039 }
1040
1041 PTH_FUNCS(int, semZutimedwait, sem_timedwait_intercept,
1042           (sem_t *sem, const struct timespec *abs_timeout),
1043           (sem, abs_timeout));
1044
1045 static __always_inline int sem_post_intercept(sem_t *sem)
1046 {
1047    int   ret;
1048    int   res;
1049    OrigFn fn;
1050    VALGRIND_GET_ORIG_FN(fn);
1051    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_POST,
1052                               sem, 0, 0, 0, 0);
1053    CALL_FN_W_W(ret, fn, sem);
1054    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_POST,
1055                               sem, ret == 0, 0, 0, 0);
1056    return ret;
1057 }
1058
1059 PTH_FUNCS(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
1060
1061 static __always_inline
1062 int pthread_rwlock_init_intercept(pthread_rwlock_t* rwlock,
1063                                   const pthread_rwlockattr_t* attr)
1064 {
1065    int   ret;
1066    int   res;
1067    OrigFn fn;
1068    VALGRIND_GET_ORIG_FN(fn);
1069    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_INIT,
1070                               rwlock, 0, 0, 0, 0);
1071    CALL_FN_W_WW(ret, fn, rwlock, attr);
1072    return ret;
1073 }
1074
1075 PTH_FUNCS(int,
1076           pthreadZurwlockZuinit, pthread_rwlock_init_intercept,
1077           (pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr),
1078           (rwlock, attr));
1079
1080 static __always_inline
1081 int pthread_rwlock_destroy_intercept(pthread_rwlock_t* rwlock)
1082 {
1083    int   ret;
1084    int   res;
1085    OrigFn fn;
1086    VALGRIND_GET_ORIG_FN(fn);
1087    CALL_FN_W_W(ret, fn, rwlock);
1088    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_DESTROY,
1089                               rwlock, 0, 0, 0, 0);
1090    return ret;
1091 }
1092
1093 PTH_FUNCS(int,
1094           pthreadZurwlockZudestroy, pthread_rwlock_destroy_intercept,
1095           (pthread_rwlock_t* rwlock), (rwlock));
1096
1097 static __always_inline
1098 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t* rwlock)
1099 {
1100    int   ret;
1101    int   res;
1102    OrigFn fn;
1103    VALGRIND_GET_ORIG_FN(fn);
1104    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_RDLOCK,
1105                               rwlock, 0, 0, 0, 0);
1106    CALL_FN_W_W(ret, fn, rwlock);
1107    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_RDLOCK,
1108                               rwlock, ret == 0, 0, 0, 0);
1109    return ret;
1110 }
1111
1112 PTH_FUNCS(int,
1113           pthreadZurwlockZurdlock, pthread_rwlock_rdlock_intercept,
1114           (pthread_rwlock_t* rwlock), (rwlock));
1115
1116 static __always_inline
1117 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t* rwlock)
1118 {
1119    int   ret;
1120    int   res;
1121    OrigFn fn;
1122    VALGRIND_GET_ORIG_FN(fn);
1123    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_WRLOCK,
1124                               rwlock, 0, 0, 0, 0);
1125    CALL_FN_W_W(ret, fn, rwlock);
1126    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_WRLOCK,
1127                               rwlock, ret == 0, 0, 0, 0);
1128    return ret;
1129 }
1130
1131 PTH_FUNCS(int,
1132           pthreadZurwlockZuwrlock, pthread_rwlock_wrlock_intercept,
1133           (pthread_rwlock_t* rwlock), (rwlock));
1134
1135 static __always_inline
1136 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t* rwlock)
1137 {
1138    int   ret;
1139    int   res;
1140    OrigFn fn;
1141    VALGRIND_GET_ORIG_FN(fn);
1142    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_RDLOCK,
1143                               rwlock, 0, 0, 0, 0);
1144    CALL_FN_W_W(ret, fn, rwlock);
1145    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_RDLOCK,
1146                               rwlock, ret == 0, 0, 0, 0);
1147    return ret;
1148 }
1149
1150 PTH_FUNCS(int,
1151           pthreadZurwlockZutimedrdlock, pthread_rwlock_timedrdlock_intercept,
1152           (pthread_rwlock_t* rwlock), (rwlock));
1153
1154 static __always_inline
1155 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t* rwlock)
1156 {
1157    int   ret;
1158    int   res;
1159    OrigFn fn;
1160    VALGRIND_GET_ORIG_FN(fn);
1161    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_WRLOCK,
1162                               rwlock, 0, 0, 0, 0);
1163    CALL_FN_W_W(ret, fn, rwlock);
1164    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_WRLOCK,
1165                               rwlock, ret == 0, 0, 0, 0);
1166    return ret;
1167 }
1168
1169 PTH_FUNCS(int,
1170           pthreadZurwlockZutimedwrlock, pthread_rwlock_timedwrlock_intercept,
1171           (pthread_rwlock_t* rwlock), (rwlock));
1172
1173 static __always_inline
1174 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t* rwlock)
1175 {
1176    int   ret;
1177    int   res;
1178    OrigFn fn;
1179    VALGRIND_GET_ORIG_FN(fn);
1180    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_RDLOCK,
1181                               rwlock, 0, 0, 0, 0);
1182    CALL_FN_W_W(ret, fn, rwlock);
1183    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_RDLOCK,
1184                               rwlock, ret == 0, 0, 0, 0);
1185    return ret;
1186 }
1187
1188 PTH_FUNCS(int,
1189           pthreadZurwlockZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1190           (pthread_rwlock_t* rwlock), (rwlock));
1191
1192 static __always_inline
1193 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t* rwlock)
1194 {
1195    int   ret;
1196    int   res;
1197    OrigFn fn;
1198    VALGRIND_GET_ORIG_FN(fn);
1199    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_WRLOCK,
1200                               rwlock, 0, 0, 0, 0);
1201    CALL_FN_W_W(ret, fn, rwlock);
1202    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_WRLOCK,
1203                               rwlock, ret == 0, 0, 0, 0);
1204    return ret;
1205 }
1206
1207 PTH_FUNCS(int,
1208           pthreadZurwlockZutrywrlock, pthread_rwlock_trywrlock_intercept,
1209           (pthread_rwlock_t* rwlock), (rwlock));
1210
1211 static __always_inline
1212 int pthread_rwlock_unlock_intercept(pthread_rwlock_t* rwlock)
1213 {
1214    int   ret;
1215    int   res;
1216    OrigFn fn;
1217    VALGRIND_GET_ORIG_FN(fn);
1218    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_UNLOCK,
1219                               rwlock, 0, 0, 0, 0);
1220    CALL_FN_W_W(ret, fn, rwlock);
1221    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_UNLOCK,
1222                               rwlock, ret == 0, 0, 0, 0);
1223    return ret;
1224 }
1225
1226 PTH_FUNCS(int,
1227           pthreadZurwlockZuunlock, pthread_rwlock_unlock_intercept,
1228           (pthread_rwlock_t* rwlock), (rwlock));