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-2015 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 #include "drd_basics.h"     /* DRD_() */
     59 #include "drd_clientreq.h"
     60 #include "pub_tool_redir.h" /* VG_WRAP_FUNCTION_ZZ() */
     61 
     62 #if defined(VGO_solaris)
     63 /*
     64  * Solaris usually provides pthread_* functions on top of Solaris threading
     65  * and synchronization functions. Usually both need to be intercepted because
     66  * pthread_* ones might not call the Solaris ones (see for example sem_wait()).
     67  * Such approach is required to correctly report misuse of the POSIX threads
     68  * API.
     69  * Therefore DRD intercepts and instruments all such functions but due to
     70  * DRD_(thread_enter_synchr)() and DRD_(thread_leave_synchr)() guards in
     71  * handle_client_request(), only the top-most function is handled.
     72  * So the right thing(TM) happens, as expected.
     73  * The only exception is when pthread_* function is a weak alias to the Solaris
     74  * threading/synchronization function. In such case only one needs to be
     75  * intercepted to avoid redirection ambiguity.
     76  *
     77  * Intercepted functions rely on the fact that:
     78  *  - pthread_mutex_t  == mutex_t
     79  *  - pthread_cond_t   == cond_t
     80  *  - sem_t            == sema_t
     81  *  - pthread_rwlock_t == rwlock_t
     82  *
     83  * It is necessary to intercept also internal libc synchronization functions
     84  * for two reasons:
     85  *  - For read-write locks the unlocking function is shared
     86  *  - Functions lmutex_lock/lmutex_unlock guard many critical sections in libc
     87  *    which will be otherwise reported by DRD
     88  */
     89 #include <synch.h>
     90 #include <thread.h>
     91 #include "pub_tool_vki.h"
     92 
     93 /*
     94  * Solaris provides higher throughput, parallelism and scalability than other
     95  * operating systems, at the cost of more fine-grained locking activity.
     96  * This means for example that when a thread is created under Linux, just one
     97  * big lock in glibc is used for all thread setup. Solaris libc uses several
     98  * fine-grained locks and the creator thread resumes its activities as soon
     99  * as possible, leaving for example stack and TLS setup activities to the
    100  * created thread.
    101  *
    102  * This situation confuses DRD as it assumes there is some false ordering
    103  * in place between creator and created thread; and therefore many types of
    104  * race conditions in the application would not be reported. To prevent such
    105  * false ordering, command line option --ignore-thread-creation is set to
    106  * 'yes' by default on Solaris. All activity (loads, stores, client requests)
    107  * is therefore ignored during:
    108  * - pthread_create() call in the creator thread [libc.so]
    109  * - thread creation phase (stack and TLS setup) in the created thread [libc.so]
    110  *
    111  * As explained in the comments for _ti_bind_guard(), whenever the runtime
    112  * linker has to perform any activity (such as resolving a symbol), it protects
    113  * its data structures by calling into rt_bind_guard() which in turn invokes
    114  * _ti_bind_guard() in libc. Pointers to _ti_bind_guard() and _ti_bind_clear()
    115  * are passed from libc to runtime linker in _ld_libc() call during libc_init().
    116  * All activity is also ignored during:
    117  * - runtime dynamic linker work between rt_bind_guard() and rt_bind_clear()
    118  *   calls [ld.so]
    119  *
    120  * This also means that DRD does not report race conditions in libc (when
    121  * --ignore-thread-creation=yes) and runtime linker itself (unconditionally)
    122  * during these ignored sequences.
    123  */
    124 
    125 /*
    126  * Original function pointers for _ti_bind_guard() and _ti_bind_clear()
    127  * from libc. They are intercepted in function wrapper of _ld_libc().
    128  */
    129 typedef int (*drd_rtld_guard_fn)(int flags);
    130 static drd_rtld_guard_fn DRD_(rtld_bind_guard) = NULL;
    131 static drd_rtld_guard_fn DRD_(rtld_bind_clear) = NULL;
    132 #endif
    133 
    134 
    135 /*
    136  * Notes regarding thread creation:
    137  * - sg_init() runs on the context of the created thread and copies the vector
    138  *   clock of the creator thread. This only works reliably if the creator
    139  *   thread waits until this copy has been performed.
    140  * - DRD_(thread_compute_minimum_vc)() does not take the vector clocks into
    141  *   account that are involved in thread creation and for which the
    142  *   corresponding thread has not yet been created. So not waiting until the
    143  *   created thread has been started would make it possible that segments get
    144  *   discarded that should not yet be discarded. Or: some data races are not
    145  *   detected.
    146  */
    147 
    148 /**
    149  * Macro for generating a Valgrind interception function.
    150  * @param[in] ret_ty Return type of the function to be generated.
    151  * @param[in] zf Z-encoded name of the interception function.
    152  * @param[in] implf Name of the function that implements the intercept.
    153  * @param[in] arg_decl Argument declaration list enclosed in parentheses.
    154  * @param[in] argl Argument list enclosed in parentheses.
    155  */
    156 #ifdef VGO_darwin
    157 static int never_true;
    158 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl)                    \
    159    ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl;     \
    160    ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl      \
    161    {									\
    162       ret_ty pth_func_result = implf argl;				\
    163       /* Apparently inserting a function call in wrapper functions */   \
    164       /* is sufficient to avoid misaligned stack errors.           */	\
    165       if (never_true)							\
    166 	 fflush(stdout);						\
    167       return pth_func_result;						\
    168    }
    169 #elif defined(VGO_solaris)
    170 /* On Solaris, libpthread is just a filter library on top of libc.
    171  * Threading and synchronization functions in runtime linker are not
    172  * intercepted.
    173  */
    174 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl)                    \
    175    ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl;           \
    176    ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl            \
    177    { return implf argl; }
    178 #else
    179 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl)                    \
    180    ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl;     \
    181    ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl      \
    182    { return implf argl; }
    183 #endif
    184 
    185 /**
    186  * Macro for generating three Valgrind interception functions: one with the
    187  * Z-encoded name zf, one with ZAZa ("@*") appended to the name zf and one
    188  * with ZDZa ("$*") appended to the name zf. The second generated interception
    189  * function will intercept versioned symbols on Linux, and the third will
    190  * intercept versioned symbols on Darwin.
    191  */
    192 #define PTH_FUNCS(ret_ty, zf, implf, argl_decl, argl)           \
    193    PTH_FUNC(ret_ty, zf, implf, argl_decl, argl);                \
    194    PTH_FUNC(ret_ty, zf ## ZAZa, implf, argl_decl, argl);        \
    195    PTH_FUNC(ret_ty, zf ## ZDZa, implf, argl_decl, argl);
    196 
    197 /*
    198  * Not inlining one of the intercept functions will cause the regression
    199  * tests to fail because this would cause an additional stackfram to appear
    200  * in the output. The __always_inline macro guarantees that inlining will
    201  * happen, even when compiling with optimization disabled.
    202  */
    203 #undef __always_inline /* since already defined in <cdefs.h> */
    204 #if __GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 2
    205 #define __always_inline __inline__ __attribute__((always_inline))
    206 #else
    207 #define __always_inline __inline__
    208 #endif
    209 
    210 /* Local data structures. */
    211 
    212 typedef struct {
    213    pthread_mutex_t mutex;
    214    pthread_cond_t cond;
    215    int counter;
    216 } DrdSema;
    217 
    218 typedef struct
    219 {
    220    void* (*start)(void*);
    221    void* arg;
    222    int   detachstate;
    223    DrdSema* wrapper_started;
    224 } DrdPosixThreadArgs;
    225 
    226 
    227 /* Local function declarations. */
    228 
    229 static void DRD_(init)(void) __attribute__((constructor));
    230 static void DRD_(check_threading_library)(void);
    231 static void DRD_(set_main_thread_state)(void);
    232 static void DRD_(sema_init)(DrdSema* sema);
    233 static void DRD_(sema_destroy)(DrdSema* sema);
    234 static void DRD_(sema_down)(DrdSema* sema);
    235 static void DRD_(sema_up)(DrdSema* sema);
    236 
    237 
    238 /* Function definitions. */
    239 
    240 /**
    241  * Shared library initialization function. The function init() is called after
    242  * dlopen() has loaded the shared library with DRD client intercepts because
    243  * the constructor attribute was specified in the declaration of this function.
    244  * Note: do specify the -nostdlib option to gcc when linking this code into a
    245  * shared library because doing so would cancel the effect of the constructor
    246  * attribute ! Using the gcc option -nodefaultlibs is fine because this last
    247  * option preserves the shared library initialization code that calls
    248  * constructor and destructor functions.
    249  */
    250 static void DRD_(init)(void)
    251 {
    252    DRD_(check_threading_library)();
    253    DRD_(set_main_thread_state)();
    254 #if defined(VGO_solaris)
    255    if ((DRD_(rtld_bind_guard) == NULL) || (DRD_(rtld_bind_clear) == NULL)) {
    256       fprintf(stderr,
    257 "Bind guard functions for the runtime linker (ld.so.1) were not intercepted.\n"
    258 "This means the interface between libc and runtime linker changed and DRD\n"
    259 "needs to be ported properly. Giving up.\n");
    260       abort();
    261    }
    262 #endif
    263 }
    264 
    265 static __always_inline void DRD_(ignore_mutex_ordering)(pthread_mutex_t *mutex)
    266 {
    267    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_IGNORE_MUTEX_ORDERING,
    268                                    mutex, 0, 0, 0, 0);
    269 }
    270 
    271 static void DRD_(sema_init)(DrdSema* sema)
    272 {
    273    DRD_IGNORE_VAR(*sema);
    274    pthread_mutex_init(&sema->mutex, NULL);
    275    DRD_(ignore_mutex_ordering)(&sema->mutex);
    276    pthread_cond_init(&sema->cond, NULL);
    277    sema->counter = 0;
    278 }
    279 
    280 static void DRD_(sema_destroy)(DrdSema* sema)
    281 {
    282    pthread_mutex_destroy(&sema->mutex);
    283    pthread_cond_destroy(&sema->cond);
    284 }
    285 
    286 static void DRD_(sema_down)(DrdSema* sema)
    287 {
    288    pthread_mutex_lock(&sema->mutex);
    289    while (sema->counter == 0)
    290       pthread_cond_wait(&sema->cond, &sema->mutex);
    291    sema->counter--;
    292    pthread_mutex_unlock(&sema->mutex);
    293 }
    294 
    295 static void DRD_(sema_up)(DrdSema* sema)
    296 {
    297    pthread_mutex_lock(&sema->mutex);
    298    sema->counter++;
    299    pthread_cond_signal(&sema->cond);
    300    pthread_mutex_unlock(&sema->mutex);
    301 }
    302 
    303 /**
    304  * POSIX threads and DRD each have their own mutex type identification.
    305  * Convert POSIX threads' mutex type to DRD's mutex type. In the code below
    306  * if-statements are used to test the value of 'kind' instead of a switch
    307  * statement because some of the PTHREAD_MUTEX_ macro's may have the same
    308  * value.
    309  */
    310 static MutexT DRD_(pthread_to_drd_mutex_type)(int kind)
    311 {
    312    /*
    313     * See also PTHREAD_MUTEX_KIND_MASK_NP in glibc source file
    314     * <nptl/pthreadP.h>.
    315     */
    316    kind &= PTHREAD_MUTEX_RECURSIVE | PTHREAD_MUTEX_ERRORCHECK |
    317       PTHREAD_MUTEX_NORMAL | PTHREAD_MUTEX_DEFAULT;
    318 
    319    if (kind == PTHREAD_MUTEX_RECURSIVE)
    320       return mutex_type_recursive_mutex;
    321    else if (kind == PTHREAD_MUTEX_ERRORCHECK)
    322       return mutex_type_errorcheck_mutex;
    323    else if (kind == PTHREAD_MUTEX_NORMAL)
    324       return mutex_type_default_mutex;
    325    else if (kind == PTHREAD_MUTEX_DEFAULT)
    326       return mutex_type_default_mutex;
    327 #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
    328    else if (kind == PTHREAD_MUTEX_ADAPTIVE_NP)
    329       return mutex_type_default_mutex;
    330 #endif
    331    else
    332       return mutex_type_invalid_mutex;
    333 }
    334 
    335 #if defined(VGO_solaris)
    336 /**
    337  * Solaris threads and DRD each have their own mutex type identification.
    338  * Convert Solaris threads' mutex type to DRD's mutex type.
    339  */
    340 static MutexT DRD_(thread_to_drd_mutex_type)(int type)
    341 {
    342    if (type & LOCK_RECURSIVE) {
    343       return mutex_type_recursive_mutex;
    344    } else if (type & LOCK_ERRORCHECK) {
    345       return mutex_type_errorcheck_mutex;
    346    } else {
    347       return mutex_type_default_mutex;
    348    }
    349 }
    350 #endif /* VGO_solaris */
    351 
    352 #define IS_ALIGNED(p) (((uintptr_t)(p) & (sizeof(*(p)) - 1)) == 0)
    353 
    354 /**
    355  * Read the mutex type stored in the client memory used for the mutex
    356  * implementation.
    357  *
    358  * @note This function depends on the implementation of the POSIX threads
    359  *   library -- the POSIX standard does not define the name of the member in
    360  *   which the mutex type is stored.
    361  * @note The function mutex_type() has been declared inline in order
    362  *   to avoid that it shows up in call stacks (drd/tests/...exp* files).
    363  * @note glibc stores the mutex type in the lowest two bits, and uses the
    364  *   higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
    365  *   PTHREAD_MUTEXATTR_FLAG_PSHARED.
    366  */
    367 static __always_inline MutexT DRD_(mutex_type)(pthread_mutex_t* mutex)
    368 {
    369 #if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
    370    /* glibc + LinuxThreads. */
    371    if (IS_ALIGNED(&mutex->__m_kind))
    372    {
    373       const int kind = mutex->__m_kind & 3;
    374       return DRD_(pthread_to_drd_mutex_type)(kind);
    375    }
    376 #elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
    377    /* glibc + NPTL. */
    378    if (IS_ALIGNED(&mutex->__data.__kind))
    379    {
    380       const int kind = mutex->__data.__kind & 3;
    381       return DRD_(pthread_to_drd_mutex_type)(kind);
    382    }
    383 #elif defined(VGO_solaris)
    384       const int type = ((mutex_t *) mutex)->vki_mutex_type;
    385       return DRD_(thread_to_drd_mutex_type)(type);
    386 #else
    387    /*
    388     * Another POSIX threads implementation. The mutex type won't be printed
    389     * when enabling --trace-mutex=yes.
    390     */
    391 #endif
    392    return mutex_type_unknown;
    393 }
    394 
    395 /**
    396  * Tell DRD whether 'tid' is a joinable thread or a detached thread.
    397  */
    398 static void DRD_(set_joinable)(const pthread_t tid, const int joinable)
    399 {
    400    assert(joinable == 0 || joinable == 1);
    401    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_JOINABLE,
    402                                    tid, joinable, 0, 0, 0);
    403 }
    404 
    405 /** Tell DRD that the calling thread is about to enter pthread_create(). */
    406 static __always_inline void DRD_(entering_pthread_create)(void)
    407 {
    408    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__ENTERING_PTHREAD_CREATE,
    409                                    0, 0, 0, 0, 0);
    410 }
    411 
    412 /** Tell DRD that the calling thread has left pthread_create(). */
    413 static __always_inline void DRD_(left_pthread_create)(void)
    414 {
    415    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LEFT_PTHREAD_CREATE,
    416                                    0, 0, 0, 0, 0);
    417 }
    418 
    419 /**
    420  * Entry point for newly created threads. This function is called from the
    421  * thread created by pthread_create().
    422  */
    423 static void* DRD_(thread_wrapper)(void* arg)
    424 {
    425    DrdPosixThreadArgs* arg_ptr;
    426    DrdPosixThreadArgs arg_copy;
    427 
    428    arg_ptr = (DrdPosixThreadArgs*)arg;
    429    arg_copy = *arg_ptr;
    430 
    431    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
    432                                    pthread_self(), 0, 0, 0, 0);
    433 
    434    DRD_(set_joinable)(pthread_self(),
    435                       arg_copy.detachstate == PTHREAD_CREATE_JOINABLE);
    436 
    437    /*
    438     * Only set 'wrapper_started' after VG_USERREQ__SET_PTHREADID and
    439     * DRD_(set_joinable)() have been invoked to avoid a race with
    440     * a pthread_detach() invocation for this thread from another thread.
    441     */
    442    DRD_(sema_up)(arg_copy.wrapper_started);
    443 
    444    return (arg_copy.start)(arg_copy.arg);
    445 }
    446 
    447 /**
    448  * Return 1 if the LinuxThreads implementation of POSIX Threads has been
    449  * detected, and 0 otherwise.
    450  *
    451  * @see For more information about the confstr() function, see also
    452  * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
    453  */
    454 static int DRD_(detected_linuxthreads)(void)
    455 {
    456 #if defined(linux)
    457 #if defined(_CS_GNU_LIBPTHREAD_VERSION)
    458    /* Linux with a recent glibc. */
    459    HChar buffer[256];
    460    unsigned len;
    461    len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
    462    assert(len <= sizeof(buffer));
    463    return len > 0 && buffer[0] == 'l';
    464 #else
    465    /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
    466    return 1;
    467 #endif
    468 #else
    469    /* Another OS than Linux, hence no LinuxThreads. */
    470    return 0;
    471 #endif
    472 }
    473 
    474 /**
    475  * Stop and print an error message in case a non-supported threading
    476  * library implementation (LinuxThreads) has been detected.
    477  */
    478 static void DRD_(check_threading_library)(void)
    479 {
    480    if (DRD_(detected_linuxthreads)())
    481    {
    482       if (getenv("LD_ASSUME_KERNEL"))
    483       {
    484          fprintf(stderr,
    485 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
    486 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
    487 "after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
    488 );
    489       }
    490       else
    491       {
    492          fprintf(stderr,
    493 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
    494 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
    495 "after having upgraded to a newer version of your Linux distribution.\n"
    496 "Giving up.\n"
    497 );
    498       }
    499       abort();
    500    }
    501 }
    502 
    503 /**
    504  * The main thread is the only thread not created by pthread_create().
    505  * Update DRD's state information about the main thread.
    506  */
    507 static void DRD_(set_main_thread_state)(void)
    508 {
    509    // Make sure that DRD knows about the main thread's POSIX thread ID.
    510    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
    511                                    pthread_self(), 0, 0, 0, 0);
    512 }
    513 
    514 /*
    515  * Note: as of today there exist three different versions of pthread_create
    516  * in Linux:
    517  * - pthread_create (at) GLIBC_2.0
    518  * - pthread_create@@GLIBC_2.1
    519  * - pthread_create@@GLIBC_2.2.5
    520  * As an example, in libpthread-2.3.4 both pthread_create (at) GLIBC_2.0 and
    521  * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
    522  * versions have been implemented. In any glibc version where more than one
    523  * pthread_create function has been implemented, older versions call the
    524  * newer versions. Or: the pthread_create* wrapper defined below can be
    525  * called recursively. Any code in this wrapper should take this in account.
    526  * As an example, it is not safe to invoke the DRD_STOP_RECORDING
    527  * / DRD_START_RECORDING client requests from the pthread_create wrapper.
    528  * See also the implementation of pthread_create (at) GLIBC_2.0 in
    529  * glibc-2.9/nptl/pthread_create.c.
    530  */
    531 
    532 static __always_inline
    533 int pthread_create_intercept(pthread_t* thread, const pthread_attr_t* attr,
    534                              void* (*start)(void*), void* arg)
    535 {
    536    int    ret;
    537    OrigFn fn;
    538    DrdSema wrapper_started;
    539    DrdPosixThreadArgs thread_args;
    540 
    541    VALGRIND_GET_ORIG_FN(fn);
    542 
    543    DRD_(sema_init)(&wrapper_started);
    544    thread_args.start           = start;
    545    thread_args.arg             = arg;
    546    thread_args.wrapper_started = &wrapper_started;
    547    /*
    548     * Find out whether the thread will be started as a joinable thread
    549     * or as a detached thread. If no thread attributes have been specified,
    550     * this means that the new thread will be started as a joinable thread.
    551     */
    552    thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
    553    if (attr)
    554    {
    555       if (pthread_attr_getdetachstate(attr, &thread_args.detachstate) != 0)
    556          assert(0);
    557    }
    558    assert(thread_args.detachstate == PTHREAD_CREATE_JOINABLE
    559           || thread_args.detachstate == PTHREAD_CREATE_DETACHED);
    560 
    561    DRD_(entering_pthread_create)();
    562    CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), &thread_args);
    563    DRD_(left_pthread_create)();
    564 
    565    if (ret == 0) {
    566       /* Wait until the thread wrapper started. */
    567       DRD_(sema_down)(&wrapper_started);
    568    }
    569 
    570    DRD_(sema_destroy)(&wrapper_started);
    571 
    572    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT,
    573                                    pthread_self(), 0, 0, 0, 0);
    574 
    575    return ret;
    576 }
    577 
    578 PTH_FUNCS(int, pthreadZucreate, pthread_create_intercept,
    579           (pthread_t *thread, const pthread_attr_t *attr,
    580            void *(*start) (void *), void *arg),
    581           (thread, attr, start, arg));
    582 
    583 #if defined(VGO_solaris)
    584 /* Solaris also provides thr_create() in addition to pthread_create().
    585  * Both pthread_create(3C) and thr_create(3C) are based on private
    586  * _thrp_create().
    587  */
    588 static __always_inline
    589 int thr_create_intercept(void *stk, size_t stksize, void *(*start)(void *),
    590                          void *arg, long flags, thread_t *new_thread)
    591 {
    592    int                ret;
    593    OrigFn             fn;
    594    DrdSema            wrapper_started;
    595    DrdPosixThreadArgs thread_args;
    596 
    597    VALGRIND_GET_ORIG_FN(fn);
    598 
    599    DRD_(sema_init)(&wrapper_started);
    600    thread_args.start           = start;
    601    thread_args.arg             = arg;
    602    thread_args.wrapper_started = &wrapper_started;
    603    /*
    604     * Find out whether the thread will be started as a joinable thread
    605     * or as a detached thread.
    606     */
    607    if (flags & THR_DETACHED)
    608       thread_args.detachstate = PTHREAD_CREATE_DETACHED;
    609    else
    610       thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
    611 
    612    DRD_(entering_pthread_create)();
    613    CALL_FN_W_6W(ret, fn, stk, stksize, DRD_(thread_wrapper), &thread_args,
    614                 flags, new_thread);
    615    DRD_(left_pthread_create)();
    616 
    617    if (ret == 0) {
    618       /* Wait until the thread wrapper started. */
    619       DRD_(sema_down)(&wrapper_started);
    620    }
    621 
    622    DRD_(sema_destroy)(&wrapper_started);
    623 
    624    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT,
    625                                    pthread_self(), 0, 0, 0, 0);
    626 
    627    return ret;
    628 }
    629 
    630 PTH_FUNCS(int, thrZucreate, thr_create_intercept,
    631           (void *stk, size_t stksize, void *(*start)(void *), void *arg,
    632            long flags, thread_t *new_thread),
    633           (stk, stksize, start, arg, flags, new_thread));
    634 #endif /* VGO_solaris */
    635 
    636 #if defined(VGO_solaris)
    637 /*
    638  * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
    639  * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
    640  * and CI_BIND_CLEAR, to provide resilience against function renaming.
    641  */
    642 static __always_inline
    643 int DRD_(_ti_bind_guard_intercept)(int flags) {
    644    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_GUARD,
    645                                    flags, 0, 0, 0, 0);
    646    return DRD_(rtld_bind_guard)(flags);
    647 }
    648 
    649 static __always_inline
    650 int DRD_(_ti_bind_clear_intercept)(int flags) {
    651    int ret = DRD_(rtld_bind_clear)(flags);
    652    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_CLEAR,
    653                                    flags, 0, 0, 0, 0);
    654    return ret;
    655 }
    656 
    657 /*
    658  * Wrapped _ld_libc() from the runtime linker ld.so.1.
    659  */
    660 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr);
    661 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr)
    662 {
    663    OrigFn fn;
    664    int    tag;
    665 
    666    VALGRIND_GET_ORIG_FN(fn);
    667 
    668    vki_Lc_interface *funcs = ptr;
    669    for (tag = funcs->ci_tag; tag != 0; tag = (++funcs)->ci_tag) {
    670       switch (tag) {
    671       case VKI_CI_BIND_GUARD:
    672          if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_guard_intercept)) {
    673             DRD_(rtld_bind_guard) = funcs->vki_ci_un.ci_func;
    674             funcs->vki_ci_un.ci_func = DRD_(_ti_bind_guard_intercept);
    675          }
    676          break;
    677       case VKI_CI_BIND_CLEAR:
    678          if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_clear_intercept)) {
    679             DRD_(rtld_bind_clear) = funcs->vki_ci_un.ci_func;
    680             funcs->vki_ci_un.ci_func = DRD_(_ti_bind_clear_intercept);
    681          }
    682          break;
    683       }
    684    }
    685 
    686    CALL_FN_v_W(fn, ptr);
    687 }
    688 #endif /* VGO_solaris */
    689 
    690 static __always_inline
    691 int pthread_join_intercept(pthread_t pt_joinee, void **thread_return)
    692 {
    693    int      ret;
    694    OrigFn   fn;
    695 
    696    VALGRIND_GET_ORIG_FN(fn);
    697    /*
    698     * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
    699     * implementation triggers a (false positive) race report.
    700     */
    701    ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
    702    CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
    703    if (ret == 0)
    704    {
    705       VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN,
    706                                       pt_joinee, 0, 0, 0, 0);
    707    }
    708    ANNOTATE_IGNORE_READS_AND_WRITES_END();
    709    return ret;
    710 }
    711 
    712 PTH_FUNCS(int, pthreadZujoin, pthread_join_intercept,
    713           (pthread_t pt_joinee, void **thread_return),
    714           (pt_joinee, thread_return));
    715 
    716 #if defined(VGO_solaris)
    717 /* Solaris also provides thr_join() in addition to pthread_join().
    718  * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
    719  *
    720  * :TODO: No functionality is currently provided for joinee == 0 and departed.
    721  *        This would require another client request, of course.
    722  */
    723 static __always_inline
    724 int thr_join_intercept(thread_t joinee, thread_t *departed, void **thread_return)
    725 {
    726    int      ret;
    727    OrigFn   fn;
    728 
    729    VALGRIND_GET_ORIG_FN(fn);
    730    CALL_FN_W_WWW(ret, fn, joinee, departed, thread_return);
    731    if (ret == 0)
    732    {
    733       VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN,
    734                                       joinee, 0, 0, 0, 0);
    735    }
    736    return ret;
    737 }
    738 
    739 PTH_FUNCS(int, thrZujoin, thr_join_intercept,
    740           (thread_t joinee, thread_t *departed, void **thread_return),
    741           (joinee, departed, thread_return));
    742 #endif /* VGO_solaris */
    743 
    744 static __always_inline
    745 int pthread_detach_intercept(pthread_t pt_thread)
    746 {
    747    int ret;
    748    OrigFn fn;
    749 
    750    VALGRIND_GET_ORIG_FN(fn);
    751    CALL_FN_W_W(ret, fn, pt_thread);
    752    DRD_(set_joinable)(pt_thread, 0);
    753 
    754    return ret;
    755 }
    756 
    757 PTH_FUNCS(int, pthreadZudetach, pthread_detach_intercept,
    758           (pthread_t thread), (thread));
    759 
    760 // NOTE: be careful to intercept only pthread_cancel() and not
    761 // pthread_cancel_init() on Linux.
    762 
    763 static __always_inline
    764 int pthread_cancel_intercept(pthread_t pt_thread)
    765 {
    766    int ret;
    767    OrigFn fn;
    768    VALGRIND_GET_ORIG_FN(fn);
    769    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_THREAD_CANCEL,
    770                                    pt_thread, 0, 0, 0, 0);
    771    CALL_FN_W_W(ret, fn, pt_thread);
    772    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_CANCEL,
    773                                    pt_thread, ret==0, 0, 0, 0);
    774    return ret;
    775 }
    776 
    777 PTH_FUNCS(int, pthreadZucancel, pthread_cancel_intercept,
    778           (pthread_t thread), (thread))
    779 
    780 static __always_inline
    781 int pthread_once_intercept(pthread_once_t *once_control,
    782                            void (*init_routine)(void))
    783 {
    784    int ret;
    785    OrigFn fn;
    786    VALGRIND_GET_ORIG_FN(fn);
    787    /*
    788     * Ignore any data races triggered by the implementation of pthread_once().
    789     * Necessary for Darwin. This is not necessary for Linux but doesn't have
    790     * any known adverse effects.
    791     */
    792    DRD_IGNORE_VAR(*once_control);
    793    ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
    794    CALL_FN_W_WW(ret, fn, once_control, init_routine);
    795    ANNOTATE_IGNORE_READS_AND_WRITES_END();
    796    DRD_STOP_IGNORING_VAR(*once_control);
    797    return ret;
    798 }
    799 
    800 PTH_FUNCS(int, pthreadZuonce, pthread_once_intercept,
    801           (pthread_once_t *once_control, void (*init_routine)(void)),
    802           (once_control, init_routine));
    803 
    804 static __always_inline
    805 int pthread_mutex_init_intercept(pthread_mutex_t *mutex,
    806                                  const pthread_mutexattr_t* attr)
    807 {
    808    int ret;
    809    OrigFn fn;
    810    int mt;
    811    VALGRIND_GET_ORIG_FN(fn);
    812    mt = PTHREAD_MUTEX_DEFAULT;
    813    if (attr)
    814       pthread_mutexattr_gettype(attr, &mt);
    815    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
    816                                    mutex, DRD_(pthread_to_drd_mutex_type)(mt),
    817                                    0, 0, 0);
    818    CALL_FN_W_WW(ret, fn, mutex, attr);
    819    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
    820                                    mutex, 0, 0, 0, 0);
    821    return ret;
    822 }
    823 
    824 PTH_FUNCS(int, pthreadZumutexZuinit, pthread_mutex_init_intercept,
    825           (pthread_mutex_t *mutex, const pthread_mutexattr_t* attr),
    826           (mutex, attr));
    827 
    828 #if defined(VGO_solaris)
    829 static __always_inline
    830 int mutex_init_intercept(mutex_t *mutex, int type, void *arg)
    831 {
    832    int ret;
    833    OrigFn fn;
    834    VALGRIND_GET_ORIG_FN(fn);
    835 
    836    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
    837                                    mutex, DRD_(thread_to_drd_mutex_type)(type),
    838                                    0, 0, 0);
    839    CALL_FN_W_WWW(ret, fn, mutex, type, arg);
    840    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
    841                                    mutex, 0, 0, 0, 0);
    842    return ret;
    843 }
    844 
    845 PTH_FUNCS(int, mutexZuinit, mutex_init_intercept,
    846           (mutex_t *mutex, int type, void *arg),
    847           (mutex, type, arg));
    848 #endif /* VGO_solaris */
    849 
    850 static __always_inline
    851 int pthread_mutex_destroy_intercept(pthread_mutex_t* mutex)
    852 {
    853    int ret;
    854    OrigFn fn;
    855    VALGRIND_GET_ORIG_FN(fn);
    856    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
    857                                    mutex, 0, 0, 0, 0);
    858    CALL_FN_W_W(ret, fn, mutex);
    859    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
    860                                    mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
    861    return ret;
    862 }
    863 
    864 #if defined(VGO_solaris)
    865 /* On Solaris, pthread_mutex_destroy is a weak alias to mutex_destroy. */
    866 PTH_FUNCS(int, mutexZudestroy, pthread_mutex_destroy_intercept,
    867           (pthread_mutex_t *mutex), (mutex));
    868 #else
    869 PTH_FUNCS(int, pthreadZumutexZudestroy, pthread_mutex_destroy_intercept,
    870           (pthread_mutex_t *mutex), (mutex));
    871 #endif /* VGO_solaris */
    872 
    873 static __always_inline
    874 int pthread_mutex_lock_intercept(pthread_mutex_t* mutex)
    875 {
    876    int   ret;
    877    OrigFn fn;
    878    VALGRIND_GET_ORIG_FN(fn);
    879    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
    880                                    mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
    881    CALL_FN_W_W(ret, fn, mutex);
    882    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
    883                                    mutex, ret == 0, 0, 0, 0);
    884    return ret;
    885 }
    886 
    887 #if defined(VGO_solaris)
    888 /* On Solaris, pthread_mutex_lock is a weak alias to mutex_lock. */
    889 PTH_FUNCS(int, mutexZulock, pthread_mutex_lock_intercept,
    890           (pthread_mutex_t *mutex), (mutex));
    891 #else
    892 PTH_FUNCS(int, pthreadZumutexZulock, pthread_mutex_lock_intercept,
    893           (pthread_mutex_t *mutex), (mutex));
    894 #endif /* VGO_solaris */
    895 
    896 #if defined(VGO_solaris)
    897 /* Internal to libc. Mutex is usually initialized only implicitly,
    898  * by zeroing mutex_t structure.
    899  */
    900 static __always_inline
    901 void lmutex_lock_intercept(mutex_t *mutex)
    902 {
    903    OrigFn fn;
    904    VALGRIND_GET_ORIG_FN(fn);
    905    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
    906                                    mutex,
    907                                    DRD_(mutex_type)((pthread_mutex_t *) mutex),
    908                                    False /* try_lock */, 0, 0);
    909    CALL_FN_v_W(fn, mutex);
    910    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
    911                                    mutex, True /* took_lock */, 0, 0, 0);
    912 }
    913 
    914 PTH_FUNCS(void, lmutexZulock, lmutex_lock_intercept,
    915           (mutex_t *mutex), (mutex));
    916 #endif /* VGO_solaris */
    917 
    918 static __always_inline
    919 int pthread_mutex_trylock_intercept(pthread_mutex_t* mutex)
    920 {
    921    int   ret;
    922    OrigFn fn;
    923    VALGRIND_GET_ORIG_FN(fn);
    924    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
    925                                    mutex, DRD_(mutex_type)(mutex), 1, 0, 0);
    926    CALL_FN_W_W(ret, fn, mutex);
    927    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
    928                                    mutex, ret == 0, 0, 0, 0);
    929    return ret;
    930 }
    931 
    932 #if defined(VGO_solaris)
    933 /* On Solaris, pthread_mutex_trylock is a weak alias to mutex_trylock. */
    934 PTH_FUNCS(int, mutexZutrylock, pthread_mutex_trylock_intercept,
    935           (pthread_mutex_t *mutex), (mutex));
    936 #else
    937 PTH_FUNCS(int, pthreadZumutexZutrylock, pthread_mutex_trylock_intercept,
    938           (pthread_mutex_t *mutex), (mutex));
    939 #endif /* VGO_solaris */
    940 
    941 static __always_inline
    942 int pthread_mutex_timedlock_intercept(pthread_mutex_t *mutex,
    943                                       const struct timespec *abs_timeout)
    944 {
    945    int   ret;
    946    OrigFn fn;
    947    VALGRIND_GET_ORIG_FN(fn);
    948    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
    949                                    mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
    950    CALL_FN_W_WW(ret, fn, mutex, abs_timeout);
    951    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
    952                                    mutex, ret == 0, 0, 0, 0);
    953    return ret;
    954 }
    955 
    956 PTH_FUNCS(int, pthreadZumutexZutimedlock, pthread_mutex_timedlock_intercept,
    957           (pthread_mutex_t *mutex, const struct timespec *abs_timeout),
    958           (mutex, abs_timeout));
    959 #if defined(VGO_solaris)
    960 PTH_FUNCS(int,
    961           pthreadZumutexZureltimedlockZunp, pthread_mutex_timedlock_intercept,
    962           (pthread_mutex_t *mutex, const struct timespec *timeout),
    963           (mutex, timeout));
    964 #endif /* VGO_solaris */
    965 
    966 static __always_inline
    967 int pthread_mutex_unlock_intercept(pthread_mutex_t *mutex)
    968 {
    969    int ret;
    970    OrigFn fn;
    971    VALGRIND_GET_ORIG_FN(fn);
    972    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
    973                                    mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
    974    CALL_FN_W_W(ret, fn, mutex);
    975    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
    976                                    mutex, 0, 0, 0, 0);
    977    return ret;
    978 }
    979 
    980 #if defined(VGO_solaris)
    981 /* On Solaris, pthread_mutex_unlock is a weak alias to mutex_unlock. */
    982 PTH_FUNCS(int, mutexZuunlock, pthread_mutex_unlock_intercept,
    983           (pthread_mutex_t *mutex), (mutex));
    984 #else
    985 PTH_FUNCS(int, pthreadZumutexZuunlock, pthread_mutex_unlock_intercept,
    986           (pthread_mutex_t *mutex), (mutex));
    987 #endif /* VGO_solaris */
    988 
    989 #if defined(VGO_solaris)
    990 /* Internal to libc. */
    991 static __always_inline
    992 void lmutex_unlock_intercept(mutex_t *mutex)
    993 {
    994    OrigFn fn;
    995    VALGRIND_GET_ORIG_FN(fn);
    996    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
    997                                    mutex,
    998                                    DRD_(mutex_type)((pthread_mutex_t *) mutex),
    999                                    0, 0, 0);
   1000    CALL_FN_v_W(fn, mutex);
   1001    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
   1002                                    mutex, 0, 0, 0, 0);
   1003 }
   1004 
   1005 PTH_FUNCS(void, lmutexZuunlock, lmutex_unlock_intercept,
   1006           (mutex_t *mutex), (mutex));
   1007 #endif /* VGO_solaris */
   1008 
   1009 static __always_inline
   1010 int pthread_cond_init_intercept(pthread_cond_t* cond,
   1011                                 const pthread_condattr_t* attr)
   1012 {
   1013    int ret;
   1014    OrigFn fn;
   1015    VALGRIND_GET_ORIG_FN(fn);
   1016    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT,
   1017                                    cond, 0, 0, 0, 0);
   1018    CALL_FN_W_WW(ret, fn, cond, attr);
   1019    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT,
   1020                                    cond, 0, 0, 0, 0);
   1021    return ret;
   1022 }
   1023 
   1024 PTH_FUNCS(int, pthreadZucondZuinit, pthread_cond_init_intercept,
   1025           (pthread_cond_t* cond, const pthread_condattr_t* attr),
   1026           (cond, attr));
   1027 
   1028 #if defined(VGO_solaris)
   1029 static __always_inline
   1030 int cond_init_intercept(cond_t *cond, int type, void *arg)
   1031 {
   1032    int ret;
   1033    OrigFn fn;
   1034    VALGRIND_GET_ORIG_FN(fn);
   1035    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT,
   1036                                    cond, 0, 0, 0, 0);
   1037    CALL_FN_W_WWW(ret, fn, cond, type, arg);
   1038    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT,
   1039                                    cond, 0, 0, 0, 0);
   1040    return ret;
   1041 }
   1042 
   1043 PTH_FUNCS(int, condZuinit, cond_init_intercept,
   1044           (cond_t *cond, int type, void *arg),
   1045           (cond, type, arg));
   1046 #endif /* VGO_solaris */
   1047 
   1048 static __always_inline
   1049 int pthread_cond_destroy_intercept(pthread_cond_t* cond)
   1050 {
   1051    int ret;
   1052    OrigFn fn;
   1053    VALGRIND_GET_ORIG_FN(fn);
   1054    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_DESTROY,
   1055                                    cond, 0, 0, 0, 0);
   1056    CALL_FN_W_W(ret, fn, cond);
   1057    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_DESTROY,
   1058                                    cond, ret==0, 0, 0, 0);
   1059    return ret;
   1060 }
   1061 
   1062 #if defined(VGO_solaris)
   1063 /* On Solaris, pthread_cond_destroy is a weak alias to cond_destroy. */
   1064 PTH_FUNCS(int, condZudestroy, pthread_cond_destroy_intercept,
   1065           (pthread_cond_t *cond), (cond));
   1066 #else
   1067 PTH_FUNCS(int, pthreadZucondZudestroy, pthread_cond_destroy_intercept,
   1068           (pthread_cond_t* cond), (cond));
   1069 #endif /* VGO_solaris */
   1070 
   1071 static __always_inline
   1072 int pthread_cond_wait_intercept(pthread_cond_t *cond, pthread_mutex_t *mutex)
   1073 {
   1074    int   ret;
   1075    OrigFn fn;
   1076    VALGRIND_GET_ORIG_FN(fn);
   1077    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
   1078                                    cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
   1079    CALL_FN_W_WW(ret, fn, cond, mutex);
   1080    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
   1081                                    cond, mutex, 1, 0, 0);
   1082    return ret;
   1083 }
   1084 
   1085 PTH_FUNCS(int, pthreadZucondZuwait, pthread_cond_wait_intercept,
   1086           (pthread_cond_t *cond, pthread_mutex_t *mutex),
   1087           (cond, mutex));
   1088 #if defined(VGO_solaris)
   1089 PTH_FUNCS(int, condZuwait, pthread_cond_wait_intercept,
   1090           (pthread_cond_t *cond, pthread_mutex_t *mutex),
   1091           (cond, mutex));
   1092 #endif /* VGO_solaris */
   1093 
   1094 static __always_inline
   1095 int pthread_cond_timedwait_intercept(pthread_cond_t *cond,
   1096                                      pthread_mutex_t *mutex,
   1097                                      const struct timespec* abstime)
   1098 {
   1099    int   ret;
   1100    OrigFn fn;
   1101    VALGRIND_GET_ORIG_FN(fn);
   1102    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
   1103                                    cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
   1104    CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
   1105    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
   1106                                    cond, mutex, 1, 0, 0);
   1107    return ret;
   1108 }
   1109 
   1110 PTH_FUNCS(int, pthreadZucondZutimedwait, pthread_cond_timedwait_intercept,
   1111           (pthread_cond_t *cond, pthread_mutex_t *mutex,
   1112            const struct timespec* abstime),
   1113           (cond, mutex, abstime));
   1114 #if defined(VGO_solaris)
   1115 PTH_FUNCS(int, condZutimedwait, pthread_cond_timedwait_intercept,
   1116           (pthread_cond_t *cond, pthread_mutex_t *mutex,
   1117            const struct timespec *timeout),
   1118           (cond, mutex, timeout));
   1119 PTH_FUNCS(int, condZureltimedwait, pthread_cond_timedwait_intercept,
   1120           (pthread_cond_t *cond, pthread_mutex_t *mutex,
   1121            const struct timespec *timeout),
   1122           (cond, mutex, timeout));
   1123 #endif /* VGO_solaris */
   1124 
   1125 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
   1126 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
   1127 // two. Intercepting all pthread_cond_signal* functions will cause only one
   1128 // argument to be passed to pthread_cond_signal_np() and hence will cause this
   1129 // last function to crash.
   1130 
   1131 static __always_inline
   1132 int pthread_cond_signal_intercept(pthread_cond_t* cond)
   1133 {
   1134    int   ret;
   1135    OrigFn fn;
   1136    VALGRIND_GET_ORIG_FN(fn);
   1137    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_SIGNAL,
   1138                                    cond, 0, 0, 0, 0);
   1139    CALL_FN_W_W(ret, fn, cond);
   1140    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_SIGNAL,
   1141                                    cond, 0, 0, 0, 0);
   1142    return ret;
   1143 }
   1144 
   1145 #if defined(VGO_solaris)
   1146 /* On Solaris, pthread_cond_signal is a weak alias to cond_signal. */
   1147 PTH_FUNCS(int, condZusignal, pthread_cond_signal_intercept,
   1148           (pthread_cond_t *cond), (cond));
   1149 #else
   1150 PTH_FUNCS(int, pthreadZucondZusignal, pthread_cond_signal_intercept,
   1151           (pthread_cond_t* cond), (cond));
   1152 #endif /* VGO_solaris */
   1153 
   1154 static __always_inline
   1155 int pthread_cond_broadcast_intercept(pthread_cond_t* cond)
   1156 {
   1157    int   ret;
   1158    OrigFn fn;
   1159    VALGRIND_GET_ORIG_FN(fn);
   1160    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_BROADCAST,
   1161                                    cond, 0, 0, 0, 0);
   1162    CALL_FN_W_W(ret, fn, cond);
   1163    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_BROADCAST,
   1164                                    cond, 0, 0, 0, 0);
   1165    return ret;
   1166 }
   1167 
   1168 #if defined(VGO_solaris)
   1169 /* On Solaris, pthread_cond_broadcast is a weak alias to cond_broadcast. */
   1170 PTH_FUNCS(int, condZubroadcast, pthread_cond_broadcast_intercept,
   1171           (pthread_cond_t *cond), (cond));
   1172 #else
   1173 PTH_FUNCS(int, pthreadZucondZubroadcast, pthread_cond_broadcast_intercept,
   1174           (pthread_cond_t* cond), (cond));
   1175 #endif /* VGO_solaris */
   1176 
   1177 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
   1178     && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
   1179 static __always_inline
   1180 int pthread_spin_init_intercept(pthread_spinlock_t *spinlock, int pshared)
   1181 {
   1182    int ret;
   1183    OrigFn fn;
   1184    VALGRIND_GET_ORIG_FN(fn);
   1185    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
   1186                                    spinlock, 0, 0, 0, 0);
   1187    CALL_FN_W_WW(ret, fn, spinlock, pshared);
   1188    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
   1189                                    spinlock, 0, 0, 0, 0);
   1190    return ret;
   1191 }
   1192 
   1193 PTH_FUNCS(int, pthreadZuspinZuinit, pthread_spin_init_intercept,
   1194           (pthread_spinlock_t *spinlock, int pshared), (spinlock, pshared));
   1195 
   1196 static __always_inline
   1197 int pthread_spin_destroy_intercept(pthread_spinlock_t *spinlock)
   1198 {
   1199    int ret;
   1200    OrigFn fn;
   1201    VALGRIND_GET_ORIG_FN(fn);
   1202    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
   1203                                    spinlock, 0, 0, 0, 0);
   1204    CALL_FN_W_W(ret, fn, spinlock);
   1205    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
   1206                                    spinlock, mutex_type_spinlock, 0, 0, 0);
   1207    return ret;
   1208 }
   1209 
   1210 PTH_FUNCS(int, pthreadZuspinZudestroy, pthread_spin_destroy_intercept,
   1211           (pthread_spinlock_t *spinlock), (spinlock));
   1212 
   1213 static __always_inline
   1214 int pthread_spin_lock_intercept(pthread_spinlock_t *spinlock)
   1215 {
   1216    int   ret;
   1217    OrigFn fn;
   1218    VALGRIND_GET_ORIG_FN(fn);
   1219    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
   1220                                    spinlock, mutex_type_spinlock, 0, 0, 0);
   1221    CALL_FN_W_W(ret, fn, spinlock);
   1222    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
   1223                                    spinlock, ret == 0, 0, 0, 0);
   1224    return ret;
   1225 }
   1226 
   1227 PTH_FUNCS(int, pthreadZuspinZulock, pthread_spin_lock_intercept,
   1228           (pthread_spinlock_t *spinlock), (spinlock));
   1229 
   1230 static __always_inline
   1231 int pthread_spin_trylock_intercept(pthread_spinlock_t *spinlock)
   1232 {
   1233    int   ret;
   1234    OrigFn fn;
   1235    VALGRIND_GET_ORIG_FN(fn);
   1236    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
   1237                                    spinlock, mutex_type_spinlock, 0, 0, 0);
   1238    CALL_FN_W_W(ret, fn, spinlock);
   1239    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
   1240                                    spinlock, ret == 0, 0, 0, 0);
   1241    return ret;
   1242 }
   1243 
   1244 PTH_FUNCS(int, pthreadZuspinZutrylock, pthread_spin_trylock_intercept,
   1245           (pthread_spinlock_t *spinlock), (spinlock));
   1246 
   1247 static __always_inline
   1248 int pthread_spin_unlock_intercept(pthread_spinlock_t *spinlock)
   1249 {
   1250    int   ret;
   1251    OrigFn fn;
   1252    VALGRIND_GET_ORIG_FN(fn);
   1253    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
   1254                                    spinlock, mutex_type_spinlock, 0, 0, 0);
   1255    CALL_FN_W_W(ret, fn, spinlock);
   1256    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
   1257                                    spinlock, 0, 0, 0, 0);
   1258    return ret;
   1259 }
   1260 
   1261 PTH_FUNCS(int, pthreadZuspinZuunlock, pthread_spin_unlock_intercept,
   1262           (pthread_spinlock_t *spinlock), (spinlock));
   1263 #endif   // HAVE_PTHREAD_SPIN_LOCK
   1264 
   1265 
   1266 #if defined(HAVE_PTHREAD_BARRIER_INIT)
   1267 static __always_inline
   1268 int pthread_barrier_init_intercept(pthread_barrier_t* barrier,
   1269                                    const pthread_barrierattr_t* attr,
   1270                                    unsigned count)
   1271 {
   1272    int   ret;
   1273    OrigFn fn;
   1274    VALGRIND_GET_ORIG_FN(fn);
   1275    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_INIT,
   1276                                    barrier, pthread_barrier, count, 0, 0);
   1277    CALL_FN_W_WWW(ret, fn, barrier, attr, count);
   1278    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_INIT,
   1279                                    barrier, pthread_barrier, 0, 0, 0);
   1280    return ret;
   1281 }
   1282 
   1283 PTH_FUNCS(int, pthreadZubarrierZuinit, pthread_barrier_init_intercept,
   1284           (pthread_barrier_t* barrier, const pthread_barrierattr_t* attr,
   1285            unsigned count), (barrier, attr, count));
   1286 
   1287 static __always_inline
   1288 int pthread_barrier_destroy_intercept(pthread_barrier_t* barrier)
   1289 {
   1290    int   ret;
   1291    OrigFn fn;
   1292    VALGRIND_GET_ORIG_FN(fn);
   1293    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_DESTROY,
   1294                                    barrier, pthread_barrier, 0, 0, 0);
   1295    CALL_FN_W_W(ret, fn, barrier);
   1296    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_DESTROY,
   1297                                    barrier, pthread_barrier, 0, 0, 0);
   1298    return ret;
   1299 }
   1300 
   1301 PTH_FUNCS(int, pthreadZubarrierZudestroy, pthread_barrier_destroy_intercept,
   1302           (pthread_barrier_t* barrier), (barrier));
   1303 
   1304 static __always_inline
   1305 int pthread_barrier_wait_intercept(pthread_barrier_t* barrier)
   1306 {
   1307    int   ret;
   1308    OrigFn fn;
   1309    VALGRIND_GET_ORIG_FN(fn);
   1310    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_WAIT,
   1311                                    barrier, pthread_barrier, 0, 0, 0);
   1312    CALL_FN_W_W(ret, fn, barrier);
   1313    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_WAIT,
   1314                               barrier, pthread_barrier,
   1315                               ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD,
   1316                               ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
   1317    return ret;
   1318 }
   1319 
   1320 PTH_FUNCS(int, pthreadZubarrierZuwait, pthread_barrier_wait_intercept,
   1321           (pthread_barrier_t* barrier), (barrier));
   1322 #endif   // HAVE_PTHREAD_BARRIER_INIT
   1323 
   1324 
   1325 static __always_inline
   1326 int sem_init_intercept(sem_t *sem, int pshared, unsigned int value)
   1327 {
   1328    int   ret;
   1329    OrigFn fn;
   1330    VALGRIND_GET_ORIG_FN(fn);
   1331    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT,
   1332                                    sem, pshared, value, 0, 0);
   1333    CALL_FN_W_WWW(ret, fn, sem, pshared, value);
   1334    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT,
   1335                                    sem, 0, 0, 0, 0);
   1336    return ret;
   1337 }
   1338 
   1339 PTH_FUNCS(int, semZuinit, sem_init_intercept,
   1340           (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
   1341 
   1342 #if defined(VGO_solaris)
   1343 static __always_inline
   1344 int sema_init_intercept(sema_t *sem, unsigned int value, int type, void *arg)
   1345 {
   1346    int   ret;
   1347    OrigFn fn;
   1348    VALGRIND_GET_ORIG_FN(fn);
   1349    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT,
   1350                                    sem, type == USYNC_PROCESS ? 1 : 0,
   1351                                    value, 0, 0);
   1352    CALL_FN_W_WWWW(ret, fn, sem, value, type, arg);
   1353    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT,
   1354                                    sem, 0, 0, 0, 0);
   1355    return ret;
   1356 }
   1357 
   1358 PTH_FUNCS(int, semaZuinit, sema_init_intercept,
   1359           (sema_t *sem, unsigned int value, int type, void *arg),
   1360           (sem, value, type, arg));
   1361 #endif /* VGO_solaris */
   1362 
   1363 static __always_inline
   1364 int sem_destroy_intercept(sem_t *sem)
   1365 {
   1366    int   ret;
   1367    OrigFn fn;
   1368    VALGRIND_GET_ORIG_FN(fn);
   1369    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_DESTROY,
   1370                                    sem, 0, 0, 0, 0);
   1371    CALL_FN_W_W(ret, fn, sem);
   1372    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_DESTROY,
   1373                                    sem, 0, 0, 0, 0);
   1374    return ret;
   1375 }
   1376 
   1377 PTH_FUNCS(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
   1378 #if defined(VGO_solaris)
   1379 PTH_FUNCS(int, semaZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
   1380 #endif /* VGO_solaris */
   1381 
   1382 static __always_inline
   1383 sem_t* sem_open_intercept(const char *name, int oflag, mode_t mode,
   1384                           unsigned int value)
   1385 {
   1386    sem_t *ret;
   1387    OrigFn fn;
   1388    VALGRIND_GET_ORIG_FN(fn);
   1389    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_OPEN,
   1390                                    name, oflag, mode, value, 0);
   1391    CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value);
   1392    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_OPEN,
   1393                                    ret != SEM_FAILED ? ret : 0,
   1394                                    name, oflag, mode, value);
   1395    return ret;
   1396 }
   1397 
   1398 PTH_FUNCS(sem_t *, semZuopen, sem_open_intercept,
   1399           (const char *name, int oflag, mode_t mode, unsigned int value),
   1400           (name, oflag, mode, value));
   1401 
   1402 static __always_inline int sem_close_intercept(sem_t *sem)
   1403 {
   1404    int   ret;
   1405    OrigFn fn;
   1406    VALGRIND_GET_ORIG_FN(fn);
   1407    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_CLOSE,
   1408                                    sem, 0, 0, 0, 0);
   1409    CALL_FN_W_W(ret, fn, sem);
   1410    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_CLOSE,
   1411                                    sem, 0, 0, 0, 0);
   1412    return ret;
   1413 }
   1414 
   1415 PTH_FUNCS(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
   1416 
   1417 static __always_inline int sem_wait_intercept(sem_t *sem)
   1418 {
   1419    int   ret;
   1420    OrigFn fn;
   1421    VALGRIND_GET_ORIG_FN(fn);
   1422    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
   1423                                    sem, 0, 0, 0, 0);
   1424    CALL_FN_W_W(ret, fn, sem);
   1425    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
   1426                                    sem, ret == 0, 0, 0, 0);
   1427    return ret;
   1428 }
   1429 
   1430 PTH_FUNCS(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
   1431 #if defined(VGO_solaris)
   1432 PTH_FUNCS(int, semaZuwait, sem_wait_intercept, (sem_t *sem), (sem));
   1433 #endif /* VGO_solaris */
   1434 
   1435 static __always_inline int sem_trywait_intercept(sem_t *sem)
   1436 {
   1437    int   ret;
   1438    OrigFn fn;
   1439    VALGRIND_GET_ORIG_FN(fn);
   1440    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
   1441                                    sem, 0, 0, 0, 0);
   1442    CALL_FN_W_W(ret, fn, sem);
   1443    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
   1444                                    sem, ret == 0, 0, 0, 0);
   1445    return ret;
   1446 }
   1447 
   1448 PTH_FUNCS(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
   1449 #if defined(VGO_solaris)
   1450 PTH_FUNCS(int, semaZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
   1451 #endif /* VGO_solaris */
   1452 
   1453 static __always_inline
   1454 int sem_timedwait_intercept(sem_t *sem, const struct timespec *abs_timeout)
   1455 {
   1456    int   ret;
   1457    OrigFn fn;
   1458    VALGRIND_GET_ORIG_FN(fn);
   1459    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
   1460                                    sem, 0, 0, 0, 0);
   1461    CALL_FN_W_WW(ret, fn, sem, abs_timeout);
   1462    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
   1463                                    sem, ret == 0, 0, 0, 0);
   1464    return ret;
   1465 }
   1466 
   1467 PTH_FUNCS(int, semZutimedwait, sem_timedwait_intercept,
   1468           (sem_t *sem, const struct timespec *abs_timeout),
   1469           (sem, abs_timeout));
   1470 #if defined(VGO_solaris)
   1471 PTH_FUNCS(int, semaZutimedwait, sem_timedwait_intercept,
   1472           (sem_t *sem, const struct timespec *timeout),
   1473           (sem, timeout));
   1474 PTH_FUNCS(int, semaZureltimedwait, sem_timedwait_intercept,
   1475           (sem_t *sem, const struct timespec *timeout),
   1476           (sem, timeout));
   1477 #endif /* VGO_solaris */
   1478 
   1479 static __always_inline int sem_post_intercept(sem_t *sem)
   1480 {
   1481    int   ret;
   1482    OrigFn fn;
   1483    VALGRIND_GET_ORIG_FN(fn);
   1484    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_POST,
   1485                                    sem, 0, 0, 0, 0);
   1486    CALL_FN_W_W(ret, fn, sem);
   1487    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_POST,
   1488                                    sem, ret == 0, 0, 0, 0);
   1489    return ret;
   1490 }
   1491 
   1492 PTH_FUNCS(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
   1493 #if defined(VGO_solaris)
   1494 PTH_FUNCS(int, semaZupost, sem_post_intercept, (sem_t *sem), (sem));
   1495 #endif /* VGO_solaris */
   1496 
   1497 /* Android's pthread.h doesn't say anything about rwlocks, hence these
   1498    functions have to be conditionally compiled. */
   1499 #if defined(HAVE_PTHREAD_RWLOCK_T)
   1500 
   1501 static __always_inline
   1502 int pthread_rwlock_init_intercept(pthread_rwlock_t* rwlock,
   1503                                   const pthread_rwlockattr_t* attr)
   1504 {
   1505    int   ret;
   1506    OrigFn fn;
   1507    VALGRIND_GET_ORIG_FN(fn);
   1508    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT,
   1509                                    rwlock, 0, 0, 0, 0);
   1510    CALL_FN_W_WW(ret, fn, rwlock, attr);
   1511    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT,
   1512                                    rwlock, 0, 0, 0, 0);
   1513    return ret;
   1514 }
   1515 
   1516 PTH_FUNCS(int,
   1517           pthreadZurwlockZuinit, pthread_rwlock_init_intercept,
   1518           (pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr),
   1519           (rwlock, attr));
   1520 
   1521 #if defined(VGO_solaris)
   1522 static __always_inline
   1523 int rwlock_init_intercept(rwlock_t *rwlock, int type, void *arg)
   1524 {
   1525    int   ret;
   1526    OrigFn fn;
   1527    VALGRIND_GET_ORIG_FN(fn);
   1528    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT,
   1529                                    rwlock, 0, 0, 0, 0);
   1530    CALL_FN_W_WWW(ret, fn, rwlock, type, arg);
   1531    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT,
   1532                                    rwlock, 0, 0, 0, 0);
   1533    return ret;
   1534 }
   1535 
   1536 PTH_FUNCS(int, rwlockZuinit, rwlock_init_intercept,
   1537           (rwlock_t *rwlock, int type, void *arg),
   1538           (rwlock, type, arg));
   1539 #endif /* VGO_solaris */
   1540 
   1541 static __always_inline
   1542 int pthread_rwlock_destroy_intercept(pthread_rwlock_t* rwlock)
   1543 {
   1544    int   ret;
   1545    OrigFn fn;
   1546    VALGRIND_GET_ORIG_FN(fn);
   1547    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_DESTROY,
   1548                                    rwlock, 0, 0, 0, 0);
   1549    CALL_FN_W_W(ret, fn, rwlock);
   1550    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_DESTROY,
   1551                                    rwlock, 0, 0, 0, 0);
   1552    return ret;
   1553 }
   1554 
   1555 #if defined(VGO_solaris)
   1556 /* On Solaris, pthread_rwlock_destroy is a weak alias to rwlock_destroy. */
   1557 PTH_FUNCS(int,
   1558           rwlockZudestroy, pthread_rwlock_destroy_intercept,
   1559           (pthread_rwlock_t *rwlock), (rwlock));
   1560 #else
   1561 PTH_FUNCS(int,
   1562           pthreadZurwlockZudestroy, pthread_rwlock_destroy_intercept,
   1563           (pthread_rwlock_t* rwlock), (rwlock));
   1564 #endif /* VGO_solaris */
   1565 
   1566 static __always_inline
   1567 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t* rwlock)
   1568 {
   1569    int   ret;
   1570    OrigFn fn;
   1571    VALGRIND_GET_ORIG_FN(fn);
   1572    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
   1573                                    rwlock, 0, 0, 0, 0);
   1574    CALL_FN_W_W(ret, fn, rwlock);
   1575    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
   1576                                    rwlock, ret == 0, 0, 0, 0);
   1577    return ret;
   1578 }
   1579 
   1580 #if defined(VGO_solaris)
   1581 /* On Solaris, pthread_rwlock_rdlock is a weak alias to rw_rdlock. */
   1582 PTH_FUNCS(int,
   1583           rwZurdlock, pthread_rwlock_rdlock_intercept,
   1584           (pthread_rwlock_t *rwlock), (rwlock));
   1585 #else
   1586 PTH_FUNCS(int,
   1587           pthreadZurwlockZurdlock, pthread_rwlock_rdlock_intercept,
   1588           (pthread_rwlock_t* rwlock), (rwlock));
   1589 #endif /* VGO_solaris */
   1590 
   1591 #if defined(VGO_solaris)
   1592 /* Internal to libc. */
   1593 static __always_inline
   1594 void lrw_rdlock_intercept(rwlock_t *rwlock)
   1595 {
   1596    OrigFn fn;
   1597    VALGRIND_GET_ORIG_FN(fn);
   1598    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
   1599                                    rwlock, 0, 0, 0, 0);
   1600    CALL_FN_v_W(fn, rwlock);
   1601    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
   1602                                    rwlock, True /* took_lock */, 0, 0, 0);
   1603 }
   1604 
   1605 PTH_FUNCS(void, lrwZurdlock, lrw_rdlock_intercept,
   1606           (rwlock_t *rwlock), (rwlock));
   1607 #endif /* VGO_solaris */
   1608 
   1609 static __always_inline
   1610 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t* rwlock)
   1611 {
   1612    int   ret;
   1613    OrigFn fn;
   1614    VALGRIND_GET_ORIG_FN(fn);
   1615    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
   1616                                    rwlock, 0, 0, 0, 0);
   1617    CALL_FN_W_W(ret, fn, rwlock);
   1618    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
   1619                                    rwlock, ret == 0, 0, 0, 0);
   1620    return ret;
   1621 }
   1622 
   1623 #if defined(VGO_solaris)
   1624 /* On Solaris, pthread_rwlock_wrlock is a weak alias to rw_wrlock. */
   1625 PTH_FUNCS(int,
   1626           rwZuwrlock, pthread_rwlock_wrlock_intercept,
   1627           (pthread_rwlock_t *rwlock), (rwlock));
   1628 #else
   1629 PTH_FUNCS(int,
   1630           pthreadZurwlockZuwrlock, pthread_rwlock_wrlock_intercept,
   1631           (pthread_rwlock_t* rwlock), (rwlock));
   1632 #endif /* VGO_solaris */
   1633 
   1634 #if defined(VGO_solaris)
   1635 /* Internal to libc. */
   1636 static __always_inline
   1637 void lrw_wrlock_intercept(rwlock_t *rwlock)
   1638 {
   1639    OrigFn fn;
   1640    VALGRIND_GET_ORIG_FN(fn);
   1641    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
   1642                                    rwlock, 0, 0, 0, 0);
   1643    CALL_FN_v_W(fn, rwlock);
   1644    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
   1645                                    rwlock, True /* took_lock */, 0, 0, 0);
   1646 }
   1647 
   1648 PTH_FUNCS(void, lrwZuwrlock, lrw_wrlock_intercept,
   1649           (rwlock_t *rwlock), (rwlock));
   1650 #endif /* VGO_solaris */
   1651 
   1652 static __always_inline
   1653 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t* rwlock,
   1654                                          const struct timespec *timeout)
   1655 {
   1656    int   ret;
   1657    OrigFn fn;
   1658    VALGRIND_GET_ORIG_FN(fn);
   1659    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
   1660                                    rwlock, 0, 0, 0, 0);
   1661    CALL_FN_W_WW(ret, fn, rwlock, timeout);
   1662    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
   1663                                    rwlock, ret == 0, 0, 0, 0);
   1664    return ret;
   1665 }
   1666 
   1667 PTH_FUNCS(int,
   1668           pthreadZurwlockZutimedrdlock, pthread_rwlock_timedrdlock_intercept,
   1669           (pthread_rwlock_t* rwlock, const struct timespec *timeout),
   1670           (rwlock, timeout));
   1671 #if defined(VGO_solaris)
   1672 PTH_FUNCS(int, pthreadZurwlockZureltimedrdlockZunp,
   1673           pthread_rwlock_timedrdlock_intercept,
   1674           (pthread_rwlock_t *rwlock, const struct timespec *timeout),
   1675           (rwlock, timeout));
   1676 #endif /* VGO_solaris */
   1677 
   1678 static __always_inline
   1679 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t* rwlock,
   1680                                          const struct timespec *timeout)
   1681 {
   1682    int   ret;
   1683    OrigFn fn;
   1684    VALGRIND_GET_ORIG_FN(fn);
   1685    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
   1686                                    rwlock, 0, 0, 0, 0);
   1687    CALL_FN_W_WW(ret, fn, rwlock, timeout);
   1688    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
   1689                                    rwlock, ret == 0, 0, 0, 0);
   1690    return ret;
   1691 }
   1692 
   1693 PTH_FUNCS(int,
   1694           pthreadZurwlockZutimedwrlock, pthread_rwlock_timedwrlock_intercept,
   1695           (pthread_rwlock_t* rwlock, const struct timespec *timeout),
   1696           (rwlock, timeout));
   1697 #if defined(VGO_solaris)
   1698 PTH_FUNCS(int, pthreadZurwlockZureltimedwrlockZunp,
   1699           pthread_rwlock_timedwrlock_intercept,
   1700           (pthread_rwlock_t *rwlock, const struct timespec *timeout),
   1701           (rwlock, timeout));
   1702 #endif /* VGO_solaris */
   1703 
   1704 static __always_inline
   1705 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t* rwlock)
   1706 {
   1707    int   ret;
   1708    OrigFn fn;
   1709    VALGRIND_GET_ORIG_FN(fn);
   1710    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
   1711                                    rwlock, 0, 0, 0, 0);
   1712    CALL_FN_W_W(ret, fn, rwlock);
   1713    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
   1714                                    rwlock, ret == 0, 0, 0, 0);
   1715    return ret;
   1716 }
   1717 
   1718 #if defined(VGO_solaris)
   1719 /* On Solaris, pthread_rwlock_tryrdlock is a weak alias to rw_tryrdlock. */
   1720 PTH_FUNCS(int,
   1721           rwZutryrdlock, pthread_rwlock_tryrdlock_intercept,
   1722           (pthread_rwlock_t *rwlock), (rwlock));
   1723 #else
   1724 PTH_FUNCS(int,
   1725           pthreadZurwlockZutryrdlock, pthread_rwlock_tryrdlock_intercept,
   1726           (pthread_rwlock_t* rwlock), (rwlock));
   1727 #endif /* VGO_solaris */
   1728 
   1729 static __always_inline
   1730 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t* rwlock)
   1731 {
   1732    int   ret;
   1733    OrigFn fn;
   1734    VALGRIND_GET_ORIG_FN(fn);
   1735    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
   1736                                    rwlock, 0, 0, 0, 0);
   1737    CALL_FN_W_W(ret, fn, rwlock);
   1738    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
   1739                                    rwlock, ret == 0, 0, 0, 0);
   1740    return ret;
   1741 }
   1742 
   1743 #if defined(VGO_solaris)
   1744 /* On Solaris, pthread_rwlock_trywrlock is a weak alias to rw_trywrlock. */
   1745 PTH_FUNCS(int,
   1746           rwZutrywrlock, pthread_rwlock_trywrlock_intercept,
   1747           (pthread_rwlock_t *rwlock), (rwlock));
   1748 #else
   1749 PTH_FUNCS(int,
   1750           pthreadZurwlockZutrywrlock, pthread_rwlock_trywrlock_intercept,
   1751           (pthread_rwlock_t* rwlock), (rwlock));
   1752 #endif /* VGO_solaris */
   1753 
   1754 static __always_inline
   1755 int pthread_rwlock_unlock_intercept(pthread_rwlock_t* rwlock)
   1756 {
   1757    int   ret;
   1758    OrigFn fn;
   1759    VALGRIND_GET_ORIG_FN(fn);
   1760    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_UNLOCK,
   1761                                    rwlock, 0, 0, 0, 0);
   1762    CALL_FN_W_W(ret, fn, rwlock);
   1763    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_UNLOCK,
   1764                                    rwlock, ret == 0, 0, 0, 0);
   1765    return ret;
   1766 }
   1767 
   1768 #if defined(VGO_solaris)
   1769 /* On Solaris, pthread_rwlock_unlock is a weak alias to rw_unlock. */
   1770 PTH_FUNCS(int,
   1771           rwZuunlock, pthread_rwlock_unlock_intercept,
   1772           (pthread_rwlock_t *rwlock), (rwlock));
   1773 #else
   1774 PTH_FUNCS(int,
   1775           pthreadZurwlockZuunlock, pthread_rwlock_unlock_intercept,
   1776           (pthread_rwlock_t* rwlock), (rwlock));
   1777 #endif /* VGO_solaris */
   1778 
   1779 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
   1780