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-2017 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_pthread_id)(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_pthread_id)();
    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  * Update DRD's state information about the current thread.
    505  */
    506 static void DRD_(set_pthread_id)(void)
    507 {
    508    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
    509                                    pthread_self(), 0, 0, 0, 0);
    510 }
    511 
    512 /*
    513  * Note: as of today there exist three different versions of pthread_create
    514  * in Linux:
    515  * - pthread_create (at) GLIBC_2.0
    516  * - pthread_create@@GLIBC_2.1
    517  * - pthread_create@@GLIBC_2.2.5
    518  * As an example, in libpthread-2.3.4 both pthread_create (at) GLIBC_2.0 and
    519  * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
    520  * versions have been implemented. In any glibc version where more than one
    521  * pthread_create function has been implemented, older versions call the
    522  * newer versions. Or: the pthread_create* wrapper defined below can be
    523  * called recursively. Any code in this wrapper should take this in account.
    524  * As an example, it is not safe to invoke the DRD_STOP_RECORDING
    525  * / DRD_START_RECORDING client requests from the pthread_create wrapper.
    526  * See also the implementation of pthread_create (at) GLIBC_2.0 in
    527  * glibc-2.9/nptl/pthread_create.c.
    528  */
    529 
    530 static __always_inline
    531 int pthread_create_intercept(pthread_t* thread, const pthread_attr_t* attr,
    532                              void* (*start)(void*), void* arg)
    533 {
    534    int    ret;
    535    OrigFn fn;
    536    DrdSema wrapper_started;
    537    DrdPosixThreadArgs thread_args;
    538 
    539    VALGRIND_GET_ORIG_FN(fn);
    540 
    541    DRD_(sema_init)(&wrapper_started);
    542    thread_args.start           = start;
    543    thread_args.arg             = arg;
    544    thread_args.wrapper_started = &wrapper_started;
    545    /*
    546     * Find out whether the thread will be started as a joinable thread
    547     * or as a detached thread. If no thread attributes have been specified,
    548     * this means that the new thread will be started as a joinable thread.
    549     */
    550    thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
    551    if (attr)
    552    {
    553       if (pthread_attr_getdetachstate(attr, &thread_args.detachstate) != 0)
    554          assert(0);
    555    }
    556    assert(thread_args.detachstate == PTHREAD_CREATE_JOINABLE
    557           || thread_args.detachstate == PTHREAD_CREATE_DETACHED);
    558 
    559    /*
    560     * The DRD_(set_pthread_id)() from DRD_(init)() may encounter that
    561     * pthread_self() == 0, e.g. when the main program is not linked with the
    562     * pthread library and when a pthread_create() call occurs from within a
    563     * shared library. Hence call DRD_(set_pthread_id)() again to ensure that
    564     * DRD knows the identity of the current thread. See also B.Z. 356374.
    565     */
    566    DRD_(set_pthread_id)();
    567    DRD_(entering_pthread_create)();
    568    CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), &thread_args);
    569    DRD_(left_pthread_create)();
    570 
    571    if (ret == 0) {
    572       /* Wait until the thread wrapper started. */
    573       DRD_(sema_down)(&wrapper_started);
    574    }
    575 
    576    DRD_(sema_destroy)(&wrapper_started);
    577 
    578    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT,
    579                                    pthread_self(), 0, 0, 0, 0);
    580 
    581    return ret;
    582 }
    583 
    584 PTH_FUNCS(int, pthreadZucreate, pthread_create_intercept,
    585           (pthread_t *thread, const pthread_attr_t *attr,
    586            void *(*start) (void *), void *arg),
    587           (thread, attr, start, arg));
    588 
    589 #if defined(VGO_solaris)
    590 /* Solaris also provides thr_create() in addition to pthread_create().
    591  * Both pthread_create(3C) and thr_create(3C) are based on private
    592  * _thrp_create().
    593  */
    594 static __always_inline
    595 int thr_create_intercept(void *stk, size_t stksize, void *(*start)(void *),
    596                          void *arg, long flags, thread_t *new_thread)
    597 {
    598    int                ret;
    599    OrigFn             fn;
    600    DrdSema            wrapper_started;
    601    DrdPosixThreadArgs thread_args;
    602 
    603    VALGRIND_GET_ORIG_FN(fn);
    604 
    605    DRD_(sema_init)(&wrapper_started);
    606    thread_args.start           = start;
    607    thread_args.arg             = arg;
    608    thread_args.wrapper_started = &wrapper_started;
    609    /*
    610     * Find out whether the thread will be started as a joinable thread
    611     * or as a detached thread.
    612     */
    613    if (flags & THR_DETACHED)
    614       thread_args.detachstate = PTHREAD_CREATE_DETACHED;
    615    else
    616       thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
    617 
    618    DRD_(entering_pthread_create)();
    619    CALL_FN_W_6W(ret, fn, stk, stksize, DRD_(thread_wrapper), &thread_args,
    620                 flags, new_thread);
    621    DRD_(left_pthread_create)();
    622 
    623    if (ret == 0) {
    624       /* Wait until the thread wrapper started. */
    625       DRD_(sema_down)(&wrapper_started);
    626    }
    627 
    628    DRD_(sema_destroy)(&wrapper_started);
    629 
    630    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT,
    631                                    pthread_self(), 0, 0, 0, 0);
    632 
    633    return ret;
    634 }
    635 
    636 PTH_FUNCS(int, thrZucreate, thr_create_intercept,
    637           (void *stk, size_t stksize, void *(*start)(void *), void *arg,
    638            long flags, thread_t *new_thread),
    639           (stk, stksize, start, arg, flags, new_thread));
    640 #endif /* VGO_solaris */
    641 
    642 #if defined(VGO_solaris)
    643 /*
    644  * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
    645  * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
    646  * and CI_BIND_CLEAR, to provide resilience against function renaming.
    647  */
    648 static __always_inline
    649 int DRD_(_ti_bind_guard_intercept)(int flags) {
    650    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_GUARD,
    651                                    flags, 0, 0, 0, 0);
    652    return DRD_(rtld_bind_guard)(flags);
    653 }
    654 
    655 static __always_inline
    656 int DRD_(_ti_bind_clear_intercept)(int flags) {
    657    int ret = DRD_(rtld_bind_clear)(flags);
    658    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_CLEAR,
    659                                    flags, 0, 0, 0, 0);
    660    return ret;
    661 }
    662 
    663 /*
    664  * Wrapped _ld_libc() from the runtime linker ld.so.1.
    665  */
    666 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr);
    667 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr)
    668 {
    669    OrigFn fn;
    670    int    tag;
    671 
    672    VALGRIND_GET_ORIG_FN(fn);
    673 
    674    vki_Lc_interface *funcs = ptr;
    675    for (tag = funcs->ci_tag; tag != 0; tag = (++funcs)->ci_tag) {
    676       switch (tag) {
    677       case VKI_CI_BIND_GUARD:
    678          if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_guard_intercept)) {
    679             DRD_(rtld_bind_guard) = funcs->vki_ci_un.ci_func;
    680             funcs->vki_ci_un.ci_func = DRD_(_ti_bind_guard_intercept);
    681          }
    682          break;
    683       case VKI_CI_BIND_CLEAR:
    684          if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_clear_intercept)) {
    685             DRD_(rtld_bind_clear) = funcs->vki_ci_un.ci_func;
    686             funcs->vki_ci_un.ci_func = DRD_(_ti_bind_clear_intercept);
    687          }
    688          break;
    689       }
    690    }
    691 
    692    CALL_FN_v_W(fn, ptr);
    693 }
    694 #endif /* VGO_solaris */
    695 
    696 static __always_inline
    697 int pthread_join_intercept(pthread_t pt_joinee, void **thread_return)
    698 {
    699    int      ret;
    700    OrigFn   fn;
    701 
    702    VALGRIND_GET_ORIG_FN(fn);
    703    /*
    704     * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
    705     * implementation triggers a (false positive) race report.
    706     */
    707    ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
    708    CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
    709    if (ret == 0)
    710    {
    711       VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN,
    712                                       pt_joinee, 0, 0, 0, 0);
    713    }
    714    ANNOTATE_IGNORE_READS_AND_WRITES_END();
    715    return ret;
    716 }
    717 
    718 PTH_FUNCS(int, pthreadZujoin, pthread_join_intercept,
    719           (pthread_t pt_joinee, void **thread_return),
    720           (pt_joinee, thread_return));
    721 
    722 #if defined(VGO_solaris)
    723 /* Solaris also provides thr_join() in addition to pthread_join().
    724  * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
    725  *
    726  * :TODO: No functionality is currently provided for joinee == 0 and departed.
    727  *        This would require another client request, of course.
    728  */
    729 static __always_inline
    730 int thr_join_intercept(thread_t joinee, thread_t *departed, void **thread_return)
    731 {
    732    int      ret;
    733    OrigFn   fn;
    734 
    735    VALGRIND_GET_ORIG_FN(fn);
    736    CALL_FN_W_WWW(ret, fn, joinee, departed, thread_return);
    737    if (ret == 0)
    738    {
    739       VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN,
    740                                       joinee, 0, 0, 0, 0);
    741    }
    742    return ret;
    743 }
    744 
    745 PTH_FUNCS(int, thrZujoin, thr_join_intercept,
    746           (thread_t joinee, thread_t *departed, void **thread_return),
    747           (joinee, departed, thread_return));
    748 #endif /* VGO_solaris */
    749 
    750 static __always_inline
    751 int pthread_detach_intercept(pthread_t pt_thread)
    752 {
    753    int ret;
    754    OrigFn fn;
    755 
    756    VALGRIND_GET_ORIG_FN(fn);
    757    CALL_FN_W_W(ret, fn, pt_thread);
    758    DRD_(set_joinable)(pt_thread, 0);
    759 
    760    return ret;
    761 }
    762 
    763 PTH_FUNCS(int, pthreadZudetach, pthread_detach_intercept,
    764           (pthread_t thread), (thread));
    765 
    766 // NOTE: be careful to intercept only pthread_cancel() and not
    767 // pthread_cancel_init() on Linux.
    768 
    769 static __always_inline
    770 int pthread_cancel_intercept(pthread_t pt_thread)
    771 {
    772    int ret;
    773    OrigFn fn;
    774    VALGRIND_GET_ORIG_FN(fn);
    775    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_THREAD_CANCEL,
    776                                    pt_thread, 0, 0, 0, 0);
    777    CALL_FN_W_W(ret, fn, pt_thread);
    778    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_CANCEL,
    779                                    pt_thread, ret==0, 0, 0, 0);
    780    return ret;
    781 }
    782 
    783 PTH_FUNCS(int, pthreadZucancel, pthread_cancel_intercept,
    784           (pthread_t thread), (thread))
    785 
    786 static __always_inline
    787 int pthread_once_intercept(pthread_once_t *once_control,
    788                            void (*init_routine)(void))
    789 {
    790    int ret;
    791    OrigFn fn;
    792    VALGRIND_GET_ORIG_FN(fn);
    793    /*
    794     * Ignore any data races triggered by the implementation of pthread_once().
    795     * Necessary for Darwin. This is not necessary for Linux but doesn't have
    796     * any known adverse effects.
    797     */
    798    DRD_IGNORE_VAR(*once_control);
    799    ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
    800    CALL_FN_W_WW(ret, fn, once_control, init_routine);
    801    ANNOTATE_IGNORE_READS_AND_WRITES_END();
    802    DRD_STOP_IGNORING_VAR(*once_control);
    803    return ret;
    804 }
    805 
    806 PTH_FUNCS(int, pthreadZuonce, pthread_once_intercept,
    807           (pthread_once_t *once_control, void (*init_routine)(void)),
    808           (once_control, init_routine));
    809 
    810 static __always_inline
    811 int pthread_mutex_init_intercept(pthread_mutex_t *mutex,
    812                                  const pthread_mutexattr_t* attr)
    813 {
    814    int ret;
    815    OrigFn fn;
    816    int mt;
    817    VALGRIND_GET_ORIG_FN(fn);
    818    mt = PTHREAD_MUTEX_DEFAULT;
    819    if (attr)
    820       pthread_mutexattr_gettype(attr, &mt);
    821    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
    822                                    mutex, DRD_(pthread_to_drd_mutex_type)(mt),
    823                                    0, 0, 0);
    824    CALL_FN_W_WW(ret, fn, mutex, attr);
    825    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
    826                                    mutex, 0, 0, 0, 0);
    827    return ret;
    828 }
    829 
    830 PTH_FUNCS(int, pthreadZumutexZuinit, pthread_mutex_init_intercept,
    831           (pthread_mutex_t *mutex, const pthread_mutexattr_t* attr),
    832           (mutex, attr));
    833 
    834 #if defined(VGO_solaris)
    835 static __always_inline
    836 int mutex_init_intercept(mutex_t *mutex, int type, void *arg)
    837 {
    838    int ret;
    839    OrigFn fn;
    840    VALGRIND_GET_ORIG_FN(fn);
    841 
    842    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
    843                                    mutex, DRD_(thread_to_drd_mutex_type)(type),
    844                                    0, 0, 0);
    845    CALL_FN_W_WWW(ret, fn, mutex, type, arg);
    846    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
    847                                    mutex, 0, 0, 0, 0);
    848    return ret;
    849 }
    850 
    851 PTH_FUNCS(int, mutexZuinit, mutex_init_intercept,
    852           (mutex_t *mutex, int type, void *arg),
    853           (mutex, type, arg));
    854 #endif /* VGO_solaris */
    855 
    856 static __always_inline
    857 int pthread_mutex_destroy_intercept(pthread_mutex_t* mutex)
    858 {
    859    int ret;
    860    OrigFn fn;
    861    VALGRIND_GET_ORIG_FN(fn);
    862    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
    863                                    mutex, 0, 0, 0, 0);
    864    CALL_FN_W_W(ret, fn, mutex);
    865    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
    866                                    mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
    867    return ret;
    868 }
    869 
    870 #if defined(VGO_solaris)
    871 /* On Solaris, pthread_mutex_destroy is a weak alias to mutex_destroy. */
    872 PTH_FUNCS(int, mutexZudestroy, pthread_mutex_destroy_intercept,
    873           (pthread_mutex_t *mutex), (mutex));
    874 #else
    875 PTH_FUNCS(int, pthreadZumutexZudestroy, pthread_mutex_destroy_intercept,
    876           (pthread_mutex_t *mutex), (mutex));
    877 #endif /* VGO_solaris */
    878 
    879 static __always_inline
    880 int pthread_mutex_lock_intercept(pthread_mutex_t* mutex)
    881 {
    882    int   ret;
    883    OrigFn fn;
    884    VALGRIND_GET_ORIG_FN(fn);
    885    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
    886                                    mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
    887    CALL_FN_W_W(ret, fn, mutex);
    888    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
    889                                    mutex, ret == 0, 0, 0, 0);
    890    return ret;
    891 }
    892 
    893 #if defined(VGO_solaris)
    894 /* On Solaris, pthread_mutex_lock is a weak alias to mutex_lock. */
    895 PTH_FUNCS(int, mutexZulock, pthread_mutex_lock_intercept,
    896           (pthread_mutex_t *mutex), (mutex));
    897 #else
    898 PTH_FUNCS(int, pthreadZumutexZulock, pthread_mutex_lock_intercept,
    899           (pthread_mutex_t *mutex), (mutex));
    900 #endif /* VGO_solaris */
    901 
    902 #if defined(VGO_solaris)
    903 /* Internal to libc. Mutex is usually initialized only implicitly,
    904  * by zeroing mutex_t structure.
    905  */
    906 static __always_inline
    907 void lmutex_lock_intercept(mutex_t *mutex)
    908 {
    909    OrigFn fn;
    910    VALGRIND_GET_ORIG_FN(fn);
    911    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
    912                                    mutex,
    913                                    DRD_(mutex_type)((pthread_mutex_t *) mutex),
    914                                    False /* try_lock */, 0, 0);
    915    CALL_FN_v_W(fn, mutex);
    916    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
    917                                    mutex, True /* took_lock */, 0, 0, 0);
    918 }
    919 
    920 PTH_FUNCS(void, lmutexZulock, lmutex_lock_intercept,
    921           (mutex_t *mutex), (mutex));
    922 #endif /* VGO_solaris */
    923 
    924 static __always_inline
    925 int pthread_mutex_trylock_intercept(pthread_mutex_t* mutex)
    926 {
    927    int   ret;
    928    OrigFn fn;
    929    VALGRIND_GET_ORIG_FN(fn);
    930    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
    931                                    mutex, DRD_(mutex_type)(mutex), 1, 0, 0);
    932    CALL_FN_W_W(ret, fn, mutex);
    933    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
    934                                    mutex, ret == 0, 0, 0, 0);
    935    return ret;
    936 }
    937 
    938 #if defined(VGO_solaris)
    939 /* On Solaris, pthread_mutex_trylock is a weak alias to mutex_trylock. */
    940 PTH_FUNCS(int, mutexZutrylock, pthread_mutex_trylock_intercept,
    941           (pthread_mutex_t *mutex), (mutex));
    942 #else
    943 PTH_FUNCS(int, pthreadZumutexZutrylock, pthread_mutex_trylock_intercept,
    944           (pthread_mutex_t *mutex), (mutex));
    945 #endif /* VGO_solaris */
    946 
    947 static __always_inline
    948 int pthread_mutex_timedlock_intercept(pthread_mutex_t *mutex,
    949                                       const struct timespec *abs_timeout)
    950 {
    951    int   ret;
    952    OrigFn fn;
    953    VALGRIND_GET_ORIG_FN(fn);
    954    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
    955                                    mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
    956    CALL_FN_W_WW(ret, fn, mutex, abs_timeout);
    957    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
    958                                    mutex, ret == 0, 0, 0, 0);
    959    return ret;
    960 }
    961 
    962 PTH_FUNCS(int, pthreadZumutexZutimedlock, pthread_mutex_timedlock_intercept,
    963           (pthread_mutex_t *mutex, const struct timespec *abs_timeout),
    964           (mutex, abs_timeout));
    965 #if defined(VGO_solaris)
    966 PTH_FUNCS(int,
    967           pthreadZumutexZureltimedlockZunp, pthread_mutex_timedlock_intercept,
    968           (pthread_mutex_t *mutex, const struct timespec *timeout),
    969           (mutex, timeout));
    970 #endif /* VGO_solaris */
    971 
    972 static __always_inline
    973 int pthread_mutex_unlock_intercept(pthread_mutex_t *mutex)
    974 {
    975    int ret;
    976    OrigFn fn;
    977    VALGRIND_GET_ORIG_FN(fn);
    978    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
    979                                    mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
    980    CALL_FN_W_W(ret, fn, mutex);
    981    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
    982                                    mutex, 0, 0, 0, 0);
    983    return ret;
    984 }
    985 
    986 #if defined(VGO_solaris)
    987 /* On Solaris, pthread_mutex_unlock is a weak alias to mutex_unlock. */
    988 PTH_FUNCS(int, mutexZuunlock, pthread_mutex_unlock_intercept,
    989           (pthread_mutex_t *mutex), (mutex));
    990 #else
    991 PTH_FUNCS(int, pthreadZumutexZuunlock, pthread_mutex_unlock_intercept,
    992           (pthread_mutex_t *mutex), (mutex));
    993 #endif /* VGO_solaris */
    994 
    995 #if defined(VGO_solaris)
    996 /* Internal to libc. */
    997 static __always_inline
    998 void lmutex_unlock_intercept(mutex_t *mutex)
    999 {
   1000    OrigFn fn;
   1001    VALGRIND_GET_ORIG_FN(fn);
   1002    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
   1003                                    mutex,
   1004                                    DRD_(mutex_type)((pthread_mutex_t *) mutex),
   1005                                    0, 0, 0);
   1006    CALL_FN_v_W(fn, mutex);
   1007    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
   1008                                    mutex, 0, 0, 0, 0);
   1009 }
   1010 
   1011 PTH_FUNCS(void, lmutexZuunlock, lmutex_unlock_intercept,
   1012           (mutex_t *mutex), (mutex));
   1013 #endif /* VGO_solaris */
   1014 
   1015 static __always_inline
   1016 int pthread_cond_init_intercept(pthread_cond_t* cond,
   1017                                 const pthread_condattr_t* attr)
   1018 {
   1019    int ret;
   1020    OrigFn fn;
   1021    VALGRIND_GET_ORIG_FN(fn);
   1022    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT,
   1023                                    cond, 0, 0, 0, 0);
   1024    CALL_FN_W_WW(ret, fn, cond, attr);
   1025    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT,
   1026                                    cond, 0, 0, 0, 0);
   1027    return ret;
   1028 }
   1029 
   1030 PTH_FUNCS(int, pthreadZucondZuinit, pthread_cond_init_intercept,
   1031           (pthread_cond_t* cond, const pthread_condattr_t* attr),
   1032           (cond, attr));
   1033 
   1034 #if defined(VGO_solaris)
   1035 static __always_inline
   1036 int cond_init_intercept(cond_t *cond, int type, void *arg)
   1037 {
   1038    int ret;
   1039    OrigFn fn;
   1040    VALGRIND_GET_ORIG_FN(fn);
   1041    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT,
   1042                                    cond, 0, 0, 0, 0);
   1043    CALL_FN_W_WWW(ret, fn, cond, type, arg);
   1044    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT,
   1045                                    cond, 0, 0, 0, 0);
   1046    return ret;
   1047 }
   1048 
   1049 PTH_FUNCS(int, condZuinit, cond_init_intercept,
   1050           (cond_t *cond, int type, void *arg),
   1051           (cond, type, arg));
   1052 #endif /* VGO_solaris */
   1053 
   1054 static __always_inline
   1055 int pthread_cond_destroy_intercept(pthread_cond_t* cond)
   1056 {
   1057    int ret;
   1058    OrigFn fn;
   1059    VALGRIND_GET_ORIG_FN(fn);
   1060    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_DESTROY,
   1061                                    cond, 0, 0, 0, 0);
   1062    CALL_FN_W_W(ret, fn, cond);
   1063    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_DESTROY,
   1064                                    cond, ret==0, 0, 0, 0);
   1065    return ret;
   1066 }
   1067 
   1068 #if defined(VGO_solaris)
   1069 /* On Solaris, pthread_cond_destroy is a weak alias to cond_destroy. */
   1070 PTH_FUNCS(int, condZudestroy, pthread_cond_destroy_intercept,
   1071           (pthread_cond_t *cond), (cond));
   1072 #else
   1073 PTH_FUNCS(int, pthreadZucondZudestroy, pthread_cond_destroy_intercept,
   1074           (pthread_cond_t* cond), (cond));
   1075 #endif /* VGO_solaris */
   1076 
   1077 static __always_inline
   1078 int pthread_cond_wait_intercept(pthread_cond_t *cond, pthread_mutex_t *mutex)
   1079 {
   1080    int   ret;
   1081    OrigFn fn;
   1082    VALGRIND_GET_ORIG_FN(fn);
   1083    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
   1084                                    cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
   1085    CALL_FN_W_WW(ret, fn, cond, mutex);
   1086    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
   1087                                    cond, mutex, 1, 0, 0);
   1088    return ret;
   1089 }
   1090 
   1091 PTH_FUNCS(int, pthreadZucondZuwait, pthread_cond_wait_intercept,
   1092           (pthread_cond_t *cond, pthread_mutex_t *mutex),
   1093           (cond, mutex));
   1094 #if defined(VGO_solaris)
   1095 PTH_FUNCS(int, condZuwait, pthread_cond_wait_intercept,
   1096           (pthread_cond_t *cond, pthread_mutex_t *mutex),
   1097           (cond, mutex));
   1098 #endif /* VGO_solaris */
   1099 
   1100 static __always_inline
   1101 int pthread_cond_timedwait_intercept(pthread_cond_t *cond,
   1102                                      pthread_mutex_t *mutex,
   1103                                      const struct timespec* abstime)
   1104 {
   1105    int   ret;
   1106    OrigFn fn;
   1107    VALGRIND_GET_ORIG_FN(fn);
   1108    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
   1109                                    cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
   1110    CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
   1111    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
   1112                                    cond, mutex, 1, 0, 0);
   1113    return ret;
   1114 }
   1115 
   1116 PTH_FUNCS(int, pthreadZucondZutimedwait, pthread_cond_timedwait_intercept,
   1117           (pthread_cond_t *cond, pthread_mutex_t *mutex,
   1118            const struct timespec* abstime),
   1119           (cond, mutex, abstime));
   1120 #if defined(VGO_solaris)
   1121 PTH_FUNCS(int, condZutimedwait, pthread_cond_timedwait_intercept,
   1122           (pthread_cond_t *cond, pthread_mutex_t *mutex,
   1123            const struct timespec *timeout),
   1124           (cond, mutex, timeout));
   1125 PTH_FUNCS(int, condZureltimedwait, pthread_cond_timedwait_intercept,
   1126           (pthread_cond_t *cond, pthread_mutex_t *mutex,
   1127            const struct timespec *timeout),
   1128           (cond, mutex, timeout));
   1129 #endif /* VGO_solaris */
   1130 
   1131 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
   1132 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
   1133 // two. Intercepting all pthread_cond_signal* functions will cause only one
   1134 // argument to be passed to pthread_cond_signal_np() and hence will cause this
   1135 // last function to crash.
   1136 
   1137 static __always_inline
   1138 int pthread_cond_signal_intercept(pthread_cond_t* cond)
   1139 {
   1140    int   ret;
   1141    OrigFn fn;
   1142    VALGRIND_GET_ORIG_FN(fn);
   1143    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_SIGNAL,
   1144                                    cond, 0, 0, 0, 0);
   1145    CALL_FN_W_W(ret, fn, cond);
   1146    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_SIGNAL,
   1147                                    cond, 0, 0, 0, 0);
   1148    return ret;
   1149 }
   1150 
   1151 #if defined(VGO_solaris)
   1152 /* On Solaris, pthread_cond_signal is a weak alias to cond_signal. */
   1153 PTH_FUNCS(int, condZusignal, pthread_cond_signal_intercept,
   1154           (pthread_cond_t *cond), (cond));
   1155 #else
   1156 PTH_FUNCS(int, pthreadZucondZusignal, pthread_cond_signal_intercept,
   1157           (pthread_cond_t* cond), (cond));
   1158 #endif /* VGO_solaris */
   1159 
   1160 static __always_inline
   1161 int pthread_cond_broadcast_intercept(pthread_cond_t* cond)
   1162 {
   1163    int   ret;
   1164    OrigFn fn;
   1165    VALGRIND_GET_ORIG_FN(fn);
   1166    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_BROADCAST,
   1167                                    cond, 0, 0, 0, 0);
   1168    CALL_FN_W_W(ret, fn, cond);
   1169    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_BROADCAST,
   1170                                    cond, 0, 0, 0, 0);
   1171    return ret;
   1172 }
   1173 
   1174 #if defined(VGO_solaris)
   1175 /* On Solaris, pthread_cond_broadcast is a weak alias to cond_broadcast. */
   1176 PTH_FUNCS(int, condZubroadcast, pthread_cond_broadcast_intercept,
   1177           (pthread_cond_t *cond), (cond));
   1178 #else
   1179 PTH_FUNCS(int, pthreadZucondZubroadcast, pthread_cond_broadcast_intercept,
   1180           (pthread_cond_t* cond), (cond));
   1181 #endif /* VGO_solaris */
   1182 
   1183 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
   1184     && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
   1185 static __always_inline
   1186 int pthread_spin_init_intercept(pthread_spinlock_t *spinlock, int pshared)
   1187 {
   1188    int ret;
   1189    OrigFn fn;
   1190    VALGRIND_GET_ORIG_FN(fn);
   1191    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
   1192                                    spinlock, 0, 0, 0, 0);
   1193    CALL_FN_W_WW(ret, fn, spinlock, pshared);
   1194    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
   1195                                    spinlock, 0, 0, 0, 0);
   1196    return ret;
   1197 }
   1198 
   1199 PTH_FUNCS(int, pthreadZuspinZuinit, pthread_spin_init_intercept,
   1200           (pthread_spinlock_t *spinlock, int pshared), (spinlock, pshared));
   1201 
   1202 static __always_inline
   1203 int pthread_spin_destroy_intercept(pthread_spinlock_t *spinlock)
   1204 {
   1205    int ret;
   1206    OrigFn fn;
   1207    VALGRIND_GET_ORIG_FN(fn);
   1208    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
   1209                                    spinlock, 0, 0, 0, 0);
   1210    CALL_FN_W_W(ret, fn, spinlock);
   1211    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
   1212                                    spinlock, mutex_type_spinlock, 0, 0, 0);
   1213    return ret;
   1214 }
   1215 
   1216 PTH_FUNCS(int, pthreadZuspinZudestroy, pthread_spin_destroy_intercept,
   1217           (pthread_spinlock_t *spinlock), (spinlock));
   1218 
   1219 static __always_inline
   1220 int pthread_spin_lock_intercept(pthread_spinlock_t *spinlock)
   1221 {
   1222    int   ret;
   1223    OrigFn fn;
   1224    VALGRIND_GET_ORIG_FN(fn);
   1225    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
   1226                                    spinlock, mutex_type_spinlock, 0, 0, 0);
   1227    CALL_FN_W_W(ret, fn, spinlock);
   1228    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
   1229                                    spinlock, ret == 0, 0, 0, 0);
   1230    return ret;
   1231 }
   1232 
   1233 PTH_FUNCS(int, pthreadZuspinZulock, pthread_spin_lock_intercept,
   1234           (pthread_spinlock_t *spinlock), (spinlock));
   1235 
   1236 static __always_inline
   1237 int pthread_spin_trylock_intercept(pthread_spinlock_t *spinlock)
   1238 {
   1239    int   ret;
   1240    OrigFn fn;
   1241    VALGRIND_GET_ORIG_FN(fn);
   1242    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
   1243                                    spinlock, mutex_type_spinlock, 0, 0, 0);
   1244    CALL_FN_W_W(ret, fn, spinlock);
   1245    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
   1246                                    spinlock, ret == 0, 0, 0, 0);
   1247    return ret;
   1248 }
   1249 
   1250 PTH_FUNCS(int, pthreadZuspinZutrylock, pthread_spin_trylock_intercept,
   1251           (pthread_spinlock_t *spinlock), (spinlock));
   1252 
   1253 static __always_inline
   1254 int pthread_spin_unlock_intercept(pthread_spinlock_t *spinlock)
   1255 {
   1256    int   ret;
   1257    OrigFn fn;
   1258    VALGRIND_GET_ORIG_FN(fn);
   1259    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
   1260                                    spinlock, mutex_type_spinlock, 0, 0, 0);
   1261    CALL_FN_W_W(ret, fn, spinlock);
   1262    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
   1263                                    spinlock, 0, 0, 0, 0);
   1264    return ret;
   1265 }
   1266 
   1267 PTH_FUNCS(int, pthreadZuspinZuunlock, pthread_spin_unlock_intercept,
   1268           (pthread_spinlock_t *spinlock), (spinlock));
   1269 #endif   // HAVE_PTHREAD_SPIN_LOCK
   1270 
   1271 
   1272 #if defined(HAVE_PTHREAD_BARRIER_INIT)
   1273 static __always_inline
   1274 int pthread_barrier_init_intercept(pthread_barrier_t* barrier,
   1275                                    const pthread_barrierattr_t* attr,
   1276                                    unsigned count)
   1277 {
   1278    int   ret;
   1279    OrigFn fn;
   1280    VALGRIND_GET_ORIG_FN(fn);
   1281    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_INIT,
   1282                                    barrier, pthread_barrier, count, 0, 0);
   1283    CALL_FN_W_WWW(ret, fn, barrier, attr, count);
   1284    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_INIT,
   1285                                    barrier, pthread_barrier, 0, 0, 0);
   1286    return ret;
   1287 }
   1288 
   1289 PTH_FUNCS(int, pthreadZubarrierZuinit, pthread_barrier_init_intercept,
   1290           (pthread_barrier_t* barrier, const pthread_barrierattr_t* attr,
   1291            unsigned count), (barrier, attr, count));
   1292 
   1293 static __always_inline
   1294 int pthread_barrier_destroy_intercept(pthread_barrier_t* barrier)
   1295 {
   1296    int   ret;
   1297    OrigFn fn;
   1298    VALGRIND_GET_ORIG_FN(fn);
   1299    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_DESTROY,
   1300                                    barrier, pthread_barrier, 0, 0, 0);
   1301    CALL_FN_W_W(ret, fn, barrier);
   1302    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_DESTROY,
   1303                                    barrier, pthread_barrier, 0, 0, 0);
   1304    return ret;
   1305 }
   1306 
   1307 PTH_FUNCS(int, pthreadZubarrierZudestroy, pthread_barrier_destroy_intercept,
   1308           (pthread_barrier_t* barrier), (barrier));
   1309 
   1310 static __always_inline
   1311 int pthread_barrier_wait_intercept(pthread_barrier_t* barrier)
   1312 {
   1313    int   ret;
   1314    OrigFn fn;
   1315    VALGRIND_GET_ORIG_FN(fn);
   1316    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_WAIT,
   1317                                    barrier, pthread_barrier, 0, 0, 0);
   1318    CALL_FN_W_W(ret, fn, barrier);
   1319    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_WAIT,
   1320                               barrier, pthread_barrier,
   1321                               ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD,
   1322                               ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
   1323    return ret;
   1324 }
   1325 
   1326 PTH_FUNCS(int, pthreadZubarrierZuwait, pthread_barrier_wait_intercept,
   1327           (pthread_barrier_t* barrier), (barrier));
   1328 #endif   // HAVE_PTHREAD_BARRIER_INIT
   1329 
   1330 
   1331 static __always_inline
   1332 int sem_init_intercept(sem_t *sem, int pshared, unsigned int value)
   1333 {
   1334    int   ret;
   1335    OrigFn fn;
   1336    VALGRIND_GET_ORIG_FN(fn);
   1337    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT,
   1338                                    sem, pshared, value, 0, 0);
   1339    CALL_FN_W_WWW(ret, fn, sem, pshared, value);
   1340    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT,
   1341                                    sem, 0, 0, 0, 0);
   1342    return ret;
   1343 }
   1344 
   1345 PTH_FUNCS(int, semZuinit, sem_init_intercept,
   1346           (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
   1347 
   1348 #if defined(VGO_solaris)
   1349 static __always_inline
   1350 int sema_init_intercept(sema_t *sem, unsigned int value, int type, void *arg)
   1351 {
   1352    int   ret;
   1353    OrigFn fn;
   1354    VALGRIND_GET_ORIG_FN(fn);
   1355    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT,
   1356                                    sem, type == USYNC_PROCESS ? 1 : 0,
   1357                                    value, 0, 0);
   1358    CALL_FN_W_WWWW(ret, fn, sem, value, type, arg);
   1359    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT,
   1360                                    sem, 0, 0, 0, 0);
   1361    return ret;
   1362 }
   1363 
   1364 PTH_FUNCS(int, semaZuinit, sema_init_intercept,
   1365           (sema_t *sem, unsigned int value, int type, void *arg),
   1366           (sem, value, type, arg));
   1367 #endif /* VGO_solaris */
   1368 
   1369 static __always_inline
   1370 int sem_destroy_intercept(sem_t *sem)
   1371 {
   1372    int   ret;
   1373    OrigFn fn;
   1374    VALGRIND_GET_ORIG_FN(fn);
   1375    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_DESTROY,
   1376                                    sem, 0, 0, 0, 0);
   1377    CALL_FN_W_W(ret, fn, sem);
   1378    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_DESTROY,
   1379                                    sem, 0, 0, 0, 0);
   1380    return ret;
   1381 }
   1382 
   1383 PTH_FUNCS(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
   1384 #if defined(VGO_solaris)
   1385 PTH_FUNCS(int, semaZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
   1386 #endif /* VGO_solaris */
   1387 
   1388 static __always_inline
   1389 sem_t* sem_open_intercept(const char *name, int oflag, mode_t mode,
   1390                           unsigned int value)
   1391 {
   1392    sem_t *ret;
   1393    OrigFn fn;
   1394    VALGRIND_GET_ORIG_FN(fn);
   1395    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_OPEN,
   1396                                    name, oflag, mode, value, 0);
   1397    CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value);
   1398    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_OPEN,
   1399                                    ret != SEM_FAILED ? ret : 0,
   1400                                    name, oflag, mode, value);
   1401    return ret;
   1402 }
   1403 
   1404 PTH_FUNCS(sem_t *, semZuopen, sem_open_intercept,
   1405           (const char *name, int oflag, mode_t mode, unsigned int value),
   1406           (name, oflag, mode, value));
   1407 
   1408 static __always_inline int sem_close_intercept(sem_t *sem)
   1409 {
   1410    int   ret;
   1411    OrigFn fn;
   1412    VALGRIND_GET_ORIG_FN(fn);
   1413    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_CLOSE,
   1414                                    sem, 0, 0, 0, 0);
   1415    CALL_FN_W_W(ret, fn, sem);
   1416    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_CLOSE,
   1417                                    sem, 0, 0, 0, 0);
   1418    return ret;
   1419 }
   1420 
   1421 PTH_FUNCS(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
   1422 
   1423 static __always_inline int sem_wait_intercept(sem_t *sem)
   1424 {
   1425    int   ret;
   1426    OrigFn fn;
   1427    VALGRIND_GET_ORIG_FN(fn);
   1428    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
   1429                                    sem, 0, 0, 0, 0);
   1430    CALL_FN_W_W(ret, fn, sem);
   1431    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
   1432                                    sem, ret == 0, 0, 0, 0);
   1433    return ret;
   1434 }
   1435 
   1436 PTH_FUNCS(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
   1437 #if defined(VGO_solaris)
   1438 PTH_FUNCS(int, semaZuwait, sem_wait_intercept, (sem_t *sem), (sem));
   1439 #endif /* VGO_solaris */
   1440 
   1441 static __always_inline int sem_trywait_intercept(sem_t *sem)
   1442 {
   1443    int   ret;
   1444    OrigFn fn;
   1445    VALGRIND_GET_ORIG_FN(fn);
   1446    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
   1447                                    sem, 0, 0, 0, 0);
   1448    CALL_FN_W_W(ret, fn, sem);
   1449    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
   1450                                    sem, ret == 0, 0, 0, 0);
   1451    return ret;
   1452 }
   1453 
   1454 PTH_FUNCS(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
   1455 #if defined(VGO_solaris)
   1456 PTH_FUNCS(int, semaZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
   1457 #endif /* VGO_solaris */
   1458 
   1459 static __always_inline
   1460 int sem_timedwait_intercept(sem_t *sem, const struct timespec *abs_timeout)
   1461 {
   1462    int   ret;
   1463    OrigFn fn;
   1464    VALGRIND_GET_ORIG_FN(fn);
   1465    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
   1466                                    sem, 0, 0, 0, 0);
   1467    CALL_FN_W_WW(ret, fn, sem, abs_timeout);
   1468    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
   1469                                    sem, ret == 0, 0, 0, 0);
   1470    return ret;
   1471 }
   1472 
   1473 PTH_FUNCS(int, semZutimedwait, sem_timedwait_intercept,
   1474           (sem_t *sem, const struct timespec *abs_timeout),
   1475           (sem, abs_timeout));
   1476 #if defined(VGO_solaris)
   1477 PTH_FUNCS(int, semaZutimedwait, sem_timedwait_intercept,
   1478           (sem_t *sem, const struct timespec *timeout),
   1479           (sem, timeout));
   1480 PTH_FUNCS(int, semaZureltimedwait, sem_timedwait_intercept,
   1481           (sem_t *sem, const struct timespec *timeout),
   1482           (sem, timeout));
   1483 #endif /* VGO_solaris */
   1484 
   1485 static __always_inline int sem_post_intercept(sem_t *sem)
   1486 {
   1487    int   ret;
   1488    OrigFn fn;
   1489    VALGRIND_GET_ORIG_FN(fn);
   1490    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_POST,
   1491                                    sem, 0, 0, 0, 0);
   1492    CALL_FN_W_W(ret, fn, sem);
   1493    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_POST,
   1494                                    sem, ret == 0, 0, 0, 0);
   1495    return ret;
   1496 }
   1497 
   1498 PTH_FUNCS(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
   1499 #if defined(VGO_solaris)
   1500 PTH_FUNCS(int, semaZupost, sem_post_intercept, (sem_t *sem), (sem));
   1501 #endif /* VGO_solaris */
   1502 
   1503 /* Android's pthread.h doesn't say anything about rwlocks, hence these
   1504    functions have to be conditionally compiled. */
   1505 #if defined(HAVE_PTHREAD_RWLOCK_T)
   1506 
   1507 static __always_inline
   1508 int pthread_rwlock_init_intercept(pthread_rwlock_t* rwlock,
   1509                                   const pthread_rwlockattr_t* attr)
   1510 {
   1511    int   ret;
   1512    OrigFn fn;
   1513    VALGRIND_GET_ORIG_FN(fn);
   1514    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT,
   1515                                    rwlock, 0, 0, 0, 0);
   1516    CALL_FN_W_WW(ret, fn, rwlock, attr);
   1517    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT,
   1518                                    rwlock, 0, 0, 0, 0);
   1519    return ret;
   1520 }
   1521 
   1522 PTH_FUNCS(int,
   1523           pthreadZurwlockZuinit, pthread_rwlock_init_intercept,
   1524           (pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr),
   1525           (rwlock, attr));
   1526 
   1527 #if defined(VGO_solaris)
   1528 static __always_inline
   1529 int rwlock_init_intercept(rwlock_t *rwlock, int type, void *arg)
   1530 {
   1531    int   ret;
   1532    OrigFn fn;
   1533    VALGRIND_GET_ORIG_FN(fn);
   1534    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT,
   1535                                    rwlock, 0, 0, 0, 0);
   1536    CALL_FN_W_WWW(ret, fn, rwlock, type, arg);
   1537    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT,
   1538                                    rwlock, 0, 0, 0, 0);
   1539    return ret;
   1540 }
   1541 
   1542 PTH_FUNCS(int, rwlockZuinit, rwlock_init_intercept,
   1543           (rwlock_t *rwlock, int type, void *arg),
   1544           (rwlock, type, arg));
   1545 #endif /* VGO_solaris */
   1546 
   1547 static __always_inline
   1548 int pthread_rwlock_destroy_intercept(pthread_rwlock_t* rwlock)
   1549 {
   1550    int   ret;
   1551    OrigFn fn;
   1552    VALGRIND_GET_ORIG_FN(fn);
   1553    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_DESTROY,
   1554                                    rwlock, 0, 0, 0, 0);
   1555    CALL_FN_W_W(ret, fn, rwlock);
   1556    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_DESTROY,
   1557                                    rwlock, 0, 0, 0, 0);
   1558    return ret;
   1559 }
   1560 
   1561 #if defined(VGO_solaris)
   1562 /* On Solaris, pthread_rwlock_destroy is a weak alias to rwlock_destroy. */
   1563 PTH_FUNCS(int,
   1564           rwlockZudestroy, pthread_rwlock_destroy_intercept,
   1565           (pthread_rwlock_t *rwlock), (rwlock));
   1566 #else
   1567 PTH_FUNCS(int,
   1568           pthreadZurwlockZudestroy, pthread_rwlock_destroy_intercept,
   1569           (pthread_rwlock_t* rwlock), (rwlock));
   1570 #endif /* VGO_solaris */
   1571 
   1572 static __always_inline
   1573 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t* rwlock)
   1574 {
   1575    int   ret;
   1576    OrigFn fn;
   1577    VALGRIND_GET_ORIG_FN(fn);
   1578    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
   1579                                    rwlock, 0, 0, 0, 0);
   1580    CALL_FN_W_W(ret, fn, rwlock);
   1581    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
   1582                                    rwlock, ret == 0, 0, 0, 0);
   1583    return ret;
   1584 }
   1585 
   1586 #if defined(VGO_solaris)
   1587 /* On Solaris, pthread_rwlock_rdlock is a weak alias to rw_rdlock. */
   1588 PTH_FUNCS(int,
   1589           rwZurdlock, pthread_rwlock_rdlock_intercept,
   1590           (pthread_rwlock_t *rwlock), (rwlock));
   1591 #else
   1592 PTH_FUNCS(int,
   1593           pthreadZurwlockZurdlock, pthread_rwlock_rdlock_intercept,
   1594           (pthread_rwlock_t* rwlock), (rwlock));
   1595 #endif /* VGO_solaris */
   1596 
   1597 #if defined(VGO_solaris)
   1598 /* Internal to libc. */
   1599 static __always_inline
   1600 void lrw_rdlock_intercept(rwlock_t *rwlock)
   1601 {
   1602    OrigFn fn;
   1603    VALGRIND_GET_ORIG_FN(fn);
   1604    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
   1605                                    rwlock, 0, 0, 0, 0);
   1606    CALL_FN_v_W(fn, rwlock);
   1607    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
   1608                                    rwlock, True /* took_lock */, 0, 0, 0);
   1609 }
   1610 
   1611 PTH_FUNCS(void, lrwZurdlock, lrw_rdlock_intercept,
   1612           (rwlock_t *rwlock), (rwlock));
   1613 #endif /* VGO_solaris */
   1614 
   1615 static __always_inline
   1616 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t* rwlock)
   1617 {
   1618    int   ret;
   1619    OrigFn fn;
   1620    VALGRIND_GET_ORIG_FN(fn);
   1621    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
   1622                                    rwlock, 0, 0, 0, 0);
   1623    CALL_FN_W_W(ret, fn, rwlock);
   1624    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
   1625                                    rwlock, ret == 0, 0, 0, 0);
   1626    return ret;
   1627 }
   1628 
   1629 #if defined(VGO_solaris)
   1630 /* On Solaris, pthread_rwlock_wrlock is a weak alias to rw_wrlock. */
   1631 PTH_FUNCS(int,
   1632           rwZuwrlock, pthread_rwlock_wrlock_intercept,
   1633           (pthread_rwlock_t *rwlock), (rwlock));
   1634 #else
   1635 PTH_FUNCS(int,
   1636           pthreadZurwlockZuwrlock, pthread_rwlock_wrlock_intercept,
   1637           (pthread_rwlock_t* rwlock), (rwlock));
   1638 #endif /* VGO_solaris */
   1639 
   1640 #if defined(VGO_solaris)
   1641 /* Internal to libc. */
   1642 static __always_inline
   1643 void lrw_wrlock_intercept(rwlock_t *rwlock)
   1644 {
   1645    OrigFn fn;
   1646    VALGRIND_GET_ORIG_FN(fn);
   1647    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
   1648                                    rwlock, 0, 0, 0, 0);
   1649    CALL_FN_v_W(fn, rwlock);
   1650    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
   1651                                    rwlock, True /* took_lock */, 0, 0, 0);
   1652 }
   1653 
   1654 PTH_FUNCS(void, lrwZuwrlock, lrw_wrlock_intercept,
   1655           (rwlock_t *rwlock), (rwlock));
   1656 #endif /* VGO_solaris */
   1657 
   1658 static __always_inline
   1659 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t* rwlock,
   1660                                          const struct timespec *timeout)
   1661 {
   1662    int   ret;
   1663    OrigFn fn;
   1664    VALGRIND_GET_ORIG_FN(fn);
   1665    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
   1666                                    rwlock, 0, 0, 0, 0);
   1667    CALL_FN_W_WW(ret, fn, rwlock, timeout);
   1668    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
   1669                                    rwlock, ret == 0, 0, 0, 0);
   1670    return ret;
   1671 }
   1672 
   1673 PTH_FUNCS(int,
   1674           pthreadZurwlockZutimedrdlock, pthread_rwlock_timedrdlock_intercept,
   1675           (pthread_rwlock_t* rwlock, const struct timespec *timeout),
   1676           (rwlock, timeout));
   1677 #if defined(VGO_solaris)
   1678 PTH_FUNCS(int, pthreadZurwlockZureltimedrdlockZunp,
   1679           pthread_rwlock_timedrdlock_intercept,
   1680           (pthread_rwlock_t *rwlock, const struct timespec *timeout),
   1681           (rwlock, timeout));
   1682 #endif /* VGO_solaris */
   1683 
   1684 static __always_inline
   1685 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t* rwlock,
   1686                                          const struct timespec *timeout)
   1687 {
   1688    int   ret;
   1689    OrigFn fn;
   1690    VALGRIND_GET_ORIG_FN(fn);
   1691    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
   1692                                    rwlock, 0, 0, 0, 0);
   1693    CALL_FN_W_WW(ret, fn, rwlock, timeout);
   1694    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
   1695                                    rwlock, ret == 0, 0, 0, 0);
   1696    return ret;
   1697 }
   1698 
   1699 PTH_FUNCS(int,
   1700           pthreadZurwlockZutimedwrlock, pthread_rwlock_timedwrlock_intercept,
   1701           (pthread_rwlock_t* rwlock, const struct timespec *timeout),
   1702           (rwlock, timeout));
   1703 #if defined(VGO_solaris)
   1704 PTH_FUNCS(int, pthreadZurwlockZureltimedwrlockZunp,
   1705           pthread_rwlock_timedwrlock_intercept,
   1706           (pthread_rwlock_t *rwlock, const struct timespec *timeout),
   1707           (rwlock, timeout));
   1708 #endif /* VGO_solaris */
   1709 
   1710 static __always_inline
   1711 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t* rwlock)
   1712 {
   1713    int   ret;
   1714    OrigFn fn;
   1715    VALGRIND_GET_ORIG_FN(fn);
   1716    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
   1717                                    rwlock, 0, 0, 0, 0);
   1718    CALL_FN_W_W(ret, fn, rwlock);
   1719    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
   1720                                    rwlock, ret == 0, 0, 0, 0);
   1721    return ret;
   1722 }
   1723 
   1724 #if defined(VGO_solaris)
   1725 /* On Solaris, pthread_rwlock_tryrdlock is a weak alias to rw_tryrdlock. */
   1726 PTH_FUNCS(int,
   1727           rwZutryrdlock, pthread_rwlock_tryrdlock_intercept,
   1728           (pthread_rwlock_t *rwlock), (rwlock));
   1729 #else
   1730 PTH_FUNCS(int,
   1731           pthreadZurwlockZutryrdlock, pthread_rwlock_tryrdlock_intercept,
   1732           (pthread_rwlock_t* rwlock), (rwlock));
   1733 #endif /* VGO_solaris */
   1734 
   1735 static __always_inline
   1736 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t* rwlock)
   1737 {
   1738    int   ret;
   1739    OrigFn fn;
   1740    VALGRIND_GET_ORIG_FN(fn);
   1741    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
   1742                                    rwlock, 0, 0, 0, 0);
   1743    CALL_FN_W_W(ret, fn, rwlock);
   1744    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
   1745                                    rwlock, ret == 0, 0, 0, 0);
   1746    return ret;
   1747 }
   1748 
   1749 #if defined(VGO_solaris)
   1750 /* On Solaris, pthread_rwlock_trywrlock is a weak alias to rw_trywrlock. */
   1751 PTH_FUNCS(int,
   1752           rwZutrywrlock, pthread_rwlock_trywrlock_intercept,
   1753           (pthread_rwlock_t *rwlock), (rwlock));
   1754 #else
   1755 PTH_FUNCS(int,
   1756           pthreadZurwlockZutrywrlock, pthread_rwlock_trywrlock_intercept,
   1757           (pthread_rwlock_t* rwlock), (rwlock));
   1758 #endif /* VGO_solaris */
   1759 
   1760 static __always_inline
   1761 int pthread_rwlock_unlock_intercept(pthread_rwlock_t* rwlock)
   1762 {
   1763    int   ret;
   1764    OrigFn fn;
   1765    VALGRIND_GET_ORIG_FN(fn);
   1766    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_UNLOCK,
   1767                                    rwlock, 0, 0, 0, 0);
   1768    CALL_FN_W_W(ret, fn, rwlock);
   1769    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_UNLOCK,
   1770                                    rwlock, ret == 0, 0, 0, 0);
   1771    return ret;
   1772 }
   1773 
   1774 #if defined(VGO_solaris)
   1775 /* On Solaris, pthread_rwlock_unlock is a weak alias to rw_unlock. */
   1776 PTH_FUNCS(int,
   1777           rwZuunlock, pthread_rwlock_unlock_intercept,
   1778           (pthread_rwlock_t *rwlock), (rwlock));
   1779 #else
   1780 PTH_FUNCS(int,
   1781           pthreadZurwlockZuunlock, pthread_rwlock_unlock_intercept,
   1782           (pthread_rwlock_t* rwlock), (rwlock));
   1783 #endif /* VGO_solaris */
   1784 
   1785 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
   1786