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