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