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