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