Home | History | Annotate | Download | only in helgrind
      1 
      2 /*--------------------------------------------------------------------*/
      3 /*--- pthread intercepts for thread checking.                      ---*/
      4 /*---                                              hg_intercepts.c ---*/
      5 /*--------------------------------------------------------------------*/
      6 
      7 /*
      8    This file is part of Helgrind, a Valgrind tool for detecting errors
      9    in threaded programs.
     10 
     11    Copyright (C) 2007-2015 OpenWorks LLP
     12       info (at) open-works.co.uk
     13 
     14    This program is free software; you can redistribute it and/or
     15    modify it under the terms of the GNU General Public License as
     16    published by the Free Software Foundation; either version 2 of the
     17    License, or (at your option) any later version.
     18 
     19    This program is distributed in the hope that it will be useful, but
     20    WITHOUT ANY WARRANTY; without even the implied warranty of
     21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     22    General Public License for more details.
     23 
     24    You should have received a copy of the GNU General Public License
     25    along with this program; if not, write to the Free Software
     26    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
     27    02111-1307, USA.
     28 
     29    The GNU General Public License is contained in the file COPYING.
     30 
     31    Neither the names of the U.S. Department of Energy nor the
     32    University of California nor the names of its contributors may be
     33    used to endorse or promote products derived from this software
     34    without prior written permission.
     35 */
     36 
     37 /* RUNS ON SIMULATED CPU
     38    Interceptors for pthread_* functions, so that tc_main can see
     39    significant thread events.
     40 
     41    Important: when adding a function wrapper to this file, remember to
     42    add a test case to tc20_verifywrap.c.  A common cause of failure is
     43    for wrappers to not engage on different distros, and
     44    tc20_verifywrap essentially checks that each wrapper is really
     45    doing something.
     46 */
     47 
     48 // DDD: for Darwin, need to have non-"@*"-suffixed versions for all pthread
     49 // functions that currently have them.
     50 // Note also, in the comments and code below, all Darwin symbols start
     51 // with a leading underscore, which is not shown either in the comments
     52 // nor in the redirect specs.
     53 
     54 
     55 #include "pub_tool_basics.h"
     56 #include "pub_tool_redir.h"
     57 #include "pub_tool_clreq.h"
     58 #include "helgrind.h"
     59 #include "config.h"
     60 
     61 
     62 #if defined(VGO_solaris)
     63 /* See porting comments in drd/drd_pthread_intercepts.c
     64    However when a POSIX threads API function (for example pthread_cond_init)
     65    is built upon the Solaris one (cond_init), intercept only the bottom one.
     66    Helgrind does not contain generic synchronization nesting like DRD
     67    and double intercept confuses it. */
     68 #include <synch.h>
     69 #include <thread.h>
     70 #endif /* VGO_solaris */
     71 
     72 
     73 #define TRACE_PTH_FNS 0
     74 #define TRACE_QT4_FNS 0
     75 #define TRACE_GNAT_FNS 0
     76 
     77 
     78 /*----------------------------------------------------------------*/
     79 /*---                                                          ---*/
     80 /*----------------------------------------------------------------*/
     81 
     82 #if defined(VGO_solaris)
     83 /* On Solaris, libpthread is just a filter library on top of libc.
     84  * Threading and synchronization functions in runtime linker are not
     85  * intercepted.
     86  */
     87 #define PTH_FUNC(ret_ty, f, args...) \
     88    ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)(args); \
     89    ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)(args)
     90 
     91 /* pthread_t is typedef'd to 'unsigned int' but in DO_CREQ_* macros
     92    sizeof(Word) is expected. */
     93 #define CREQ_PTHREAD_T Word
     94 #define SEM_ERROR ret
     95 #else
     96 #define PTH_FUNC(ret_ty, f, args...) \
     97    ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args); \
     98    ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args)
     99 #define CREQ_PTHREAD_T pthread_t
    100 #define SEM_ERROR errno
    101 #endif /* VGO_solaris */
    102 
    103 // Do a client request.  These are macros rather than a functions so
    104 // as to avoid having an extra frame in stack traces.
    105 
    106 // NB: these duplicate definitions in helgrind.h.  But here, we
    107 // can have better typing (Word etc) and assertions, whereas
    108 // in helgrind.h we can't.  Obviously it's important the two
    109 // sets of definitions are kept in sync.
    110 
    111 // nuke the previous definitions
    112 #undef DO_CREQ_v_W
    113 #undef DO_CREQ_v_WW
    114 #undef DO_CREQ_W_WW
    115 #undef DO_CREQ_v_WWW
    116 
    117 #define DO_CREQ_v_W(_creqF, _ty1F,_arg1F)                \
    118    do {                                                  \
    119       Word _arg1;                                        \
    120       assert(sizeof(_ty1F) == sizeof(Word));             \
    121       _arg1 = (Word)(_arg1F);                            \
    122       VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF),          \
    123                                  _arg1, 0,0,0,0);        \
    124    } while (0)
    125 
    126 #define DO_CREQ_v_WW(_creqF, _ty1F,_arg1F, _ty2F,_arg2F) \
    127    do {                                                  \
    128       Word _arg1, _arg2;                                 \
    129       assert(sizeof(_ty1F) == sizeof(Word));             \
    130       assert(sizeof(_ty2F) == sizeof(Word));             \
    131       _arg1 = (Word)(_arg1F);                            \
    132       _arg2 = (Word)(_arg2F);                            \
    133       VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF),          \
    134                                  _arg1,_arg2,0,0,0);     \
    135    } while (0)
    136 
    137 #define DO_CREQ_W_WW(_resF, _creqF, _ty1F,_arg1F,        \
    138                      _ty2F,_arg2F)                       \
    139    do {                                                  \
    140       Word _res, _arg1, _arg2;                           \
    141       assert(sizeof(_ty1F) == sizeof(Word));             \
    142       assert(sizeof(_ty2F) == sizeof(Word));             \
    143       _arg1 = (Word)(_arg1F);                            \
    144       _arg2 = (Word)(_arg2F);                            \
    145       _res = VALGRIND_DO_CLIENT_REQUEST_EXPR(2,          \
    146                                  (_creqF),               \
    147                                  _arg1,_arg2,0,0,0);     \
    148       _resF = _res;                                      \
    149    } while (0)
    150 
    151 #define DO_CREQ_v_WWW(_creqF, _ty1F,_arg1F,              \
    152                       _ty2F,_arg2F, _ty3F, _arg3F)       \
    153    do {                                                  \
    154       Word _arg1, _arg2, _arg3;                          \
    155       assert(sizeof(_ty1F) == sizeof(Word));             \
    156       assert(sizeof(_ty2F) == sizeof(Word));             \
    157       assert(sizeof(_ty3F) == sizeof(Word));             \
    158       _arg1 = (Word)(_arg1F);                            \
    159       _arg2 = (Word)(_arg2F);                            \
    160       _arg3 = (Word)(_arg3F);                            \
    161       VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF),          \
    162                                  _arg1,_arg2,_arg3,0,0); \
    163    } while (0)
    164 
    165 #define DO_CREQ_v_WWWW(_creqF, _ty1F,_arg1F,             \
    166                        _ty2F, _arg2F, _ty3F, _arg3F,     \
    167                        _ty4F, _arg4F)                    \
    168    do {                                                  \
    169       Word _arg1, _arg2, _arg3, _arg4;                   \
    170       assert(sizeof(_ty1F) == sizeof(Word));             \
    171       assert(sizeof(_ty2F) == sizeof(Word));             \
    172       assert(sizeof(_ty3F) == sizeof(Word));             \
    173       assert(sizeof(_ty4F) == sizeof(Word));             \
    174       _arg1 = (Word)(_arg1F);                            \
    175       _arg2 = (Word)(_arg2F);                            \
    176       _arg3 = (Word)(_arg3F);                            \
    177       _arg4 = (Word)(_arg4F);                            \
    178       VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF),          \
    179                              _arg1,_arg2,_arg3,_arg4,0); \
    180    } while (0)
    181 
    182 #define DO_PthAPIerror(_fnnameF, _errF)                  \
    183    do {                                                  \
    184       const char* _fnname = (_fnnameF);                  \
    185       long  _err    = (long)(int)(_errF);                \
    186       const char* _errstr = lame_strerror(_err);         \
    187       DO_CREQ_v_WWW(_VG_USERREQ__HG_PTH_API_ERROR,       \
    188                     char*,_fnname,                       \
    189                     long,_err, char*,_errstr);           \
    190    } while (0)
    191 
    192 
    193 /* Needed for older glibcs (2.3 and older, at least) who don't
    194    otherwise "know" about pthread_rwlock_anything or about
    195    PTHREAD_MUTEX_RECURSIVE (amongst things). */
    196 #define _GNU_SOURCE 1
    197 
    198 #include <stdio.h>
    199 #include <assert.h>
    200 #include <errno.h>
    201 #include <pthread.h>
    202 
    203 /* A standalone memcmp. */
    204 __attribute__((noinline))
    205 static int my_memcmp ( const void* ptr1, const void* ptr2, size_t size)
    206 {
    207    const unsigned char* uchar_ptr1 = (const unsigned char*) ptr1;
    208    const unsigned char* uchar_ptr2 = (const unsigned char*) ptr2;
    209    size_t i;
    210    for (i = 0; i < size; ++i) {
    211       if (uchar_ptr1[i] != uchar_ptr2[i])
    212          return (uchar_ptr1[i] < uchar_ptr2[i]) ? -1 : 1;
    213    }
    214    return 0;
    215 }
    216 
    217 /* A lame version of strerror which doesn't use the real libc
    218    strerror_r, since using the latter just generates endless more
    219    threading errors (glibc goes off and does tons of crap w.r.t.
    220    locales etc) */
    221 static const HChar* lame_strerror ( long err )
    222 {
    223    switch (err) {
    224       case EPERM:       return "EPERM: Operation not permitted";
    225       case ENOENT:      return "ENOENT: No such file or directory";
    226       case ESRCH:       return "ESRCH: No such process";
    227       case EINTR:       return "EINTR: Interrupted system call";
    228       case EBADF:       return "EBADF: Bad file number";
    229       case EAGAIN:      return "EAGAIN: Try again";
    230       case ENOMEM:      return "ENOMEM: Out of memory";
    231       case EACCES:      return "EACCES: Permission denied";
    232       case EFAULT:      return "EFAULT: Bad address";
    233       case EEXIST:      return "EEXIST: File exists";
    234       case EINVAL:      return "EINVAL: Invalid argument";
    235       case EMFILE:      return "EMFILE: Too many open files";
    236       case ENOSYS:      return "ENOSYS: Function not implemented";
    237       case EOVERFLOW:   return "EOVERFLOW: Value too large "
    238                                "for defined data type";
    239       case EBUSY:       return "EBUSY: Device or resource busy";
    240       case ETIMEDOUT:   return "ETIMEDOUT: Connection timed out";
    241       case EDEADLK:     return "EDEADLK: Resource deadlock would occur";
    242       case EOPNOTSUPP:  return "EOPNOTSUPP: Operation not supported on "
    243                                "transport endpoint"; /* honest, guv */
    244       case ETIME:       return "ETIME: Timer expired";
    245       default:          return "hg_intercepts.c: lame_strerror(): "
    246                                "unhandled case -- please fix me!";
    247    }
    248 }
    249 
    250 #if defined(VGO_solaris)
    251 /*
    252  * Solaris provides higher throughput, parallelism and scalability than other
    253  * operating systems, at the cost of more fine-grained locking activity.
    254  * This means for example that when a thread is created under Linux, just one
    255  * big lock in glibc is used for all thread setup. Solaris libc uses several
    256  * fine-grained locks and the creator thread resumes its activities as soon
    257  * as possible, leaving for example stack and TLS setup activities to the
    258  * created thread.
    259  *
    260  * This situation confuses Helgrind as it assumes there is some false ordering
    261  * in place between creator and created thread; and therefore many types of
    262  * race conditions in the application would not be reported. To prevent such
    263  * false ordering, command line option --ignore-thread-creation is set to
    264  * 'yes' by default on Solaris. All activity (loads, stores, client requests)
    265  * is therefore ignored during:
    266  * - pthread_create() call in the creator thread [libc.so]
    267  * - thread creation phase (stack and TLS setup) in the created thread [libc.so]
    268  *
    269  * As explained in the comments for _ti_bind_guard(), whenever the runtime
    270  * linker has to perform any activity (such as resolving a symbol), it protects
    271  * its data structures by calling into rt_bind_guard() which in turn invokes
    272  * _ti_bind_guard() in libc. Pointers to _ti_bind_guard() and _ti_bind_clear()
    273  * are passed from libc to runtime linker in _ld_libc() call during libc_init().
    274  * All activity is also ignored during:
    275  * - runtime dynamic linker work between rt_bind_guard() and rt_bind_clear()
    276  *   calls [ld.so]
    277  *
    278  * This also means that Helgrind does not report race conditions in libc (when
    279  * --ignore-thread-creation=yes) and runtime linker itself (unconditionally)
    280  * during these ignored sequences.
    281  */
    282 
    283 #include "pub_tool_libcassert.h"
    284 #include "pub_tool_vki.h"
    285 
    286 /*
    287  * Original function pointers for _ti_bind_guard() and _ti_bind_clear()
    288  * from libc. They are intercepted in function wrapper of _ld_libc().
    289  */
    290 typedef int (*hg_rtld_guard_fn)(int flags);
    291 static hg_rtld_guard_fn hg_rtld_bind_guard = NULL;
    292 static hg_rtld_guard_fn hg_rtld_bind_clear = NULL;
    293 
    294 static void hg_init(void) __attribute__((constructor));
    295 static void hg_init(void)
    296 {
    297    if ((hg_rtld_bind_guard == NULL) || (hg_rtld_bind_clear == NULL)) {
    298       fprintf(stderr,
    299 "Bind guard functions for the runtime linker (ld.so.1) were not intercepted.\n"
    300 "This means the interface between libc and runtime linker changed\n"
    301 "and Helgrind needs to be ported properly. Giving up.\n");
    302       tl_assert(0);
    303    }
    304 }
    305 
    306 /*
    307  * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
    308  * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
    309  * and CI_BIND_CLEAR, to provide resilience against function renaming.
    310  */
    311 static int _ti_bind_guard_intercept_WRK(int flags)
    312 {
    313    VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_RTLD_BIND_GUARD,
    314                                    flags, 0, 0, 0, 0);
    315    return hg_rtld_bind_guard(flags);
    316 }
    317 
    318 static int _ti_bind_clear_intercept_WRK(int flags)
    319 {
    320    int ret = hg_rtld_bind_clear(flags);
    321    VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_RTLD_BIND_CLEAR,
    322                                    flags, 0, 0, 0, 0);
    323    return ret;
    324 }
    325 
    326 /*
    327  * Wrapped _ld_libc() from the runtime linker ld.so.1.
    328  */
    329 void I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr);
    330 void I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr)
    331 {
    332    OrigFn fn;
    333    int    tag;
    334 
    335    VALGRIND_GET_ORIG_FN(fn);
    336 
    337    vki_Lc_interface *funcs = ptr;
    338    for (tag = funcs->ci_tag; tag != 0; tag = (++funcs)->ci_tag) {
    339       switch (tag) {
    340       case VKI_CI_BIND_GUARD:
    341          if (funcs->vki_ci_un.ci_func != _ti_bind_guard_intercept_WRK) {
    342             hg_rtld_bind_guard = funcs->vki_ci_un.ci_func;
    343             funcs->vki_ci_un.ci_func = _ti_bind_guard_intercept_WRK;
    344          }
    345          break;
    346       case VKI_CI_BIND_CLEAR:
    347          if (funcs->vki_ci_un.ci_func != _ti_bind_clear_intercept_WRK) {
    348             hg_rtld_bind_clear = funcs->vki_ci_un.ci_func;
    349             funcs->vki_ci_un.ci_func = _ti_bind_clear_intercept_WRK;
    350          }
    351          break;
    352       }
    353    }
    354 
    355    CALL_FN_v_W(fn, ptr);
    356 }
    357 #endif /* VGO_solaris */
    358 
    359 
    360 /*----------------------------------------------------------------*/
    361 /*--- pthread_create, pthread_join, pthread_exit               ---*/
    362 /*----------------------------------------------------------------*/
    363 
    364 static void* mythread_wrapper ( void* xargsV )
    365 {
    366    volatile Word* xargs = (volatile Word*) xargsV;
    367    void*(*fn)(void*) = (void*(*)(void*))xargs[0];
    368    void* arg         = (void*)xargs[1];
    369    pthread_t me = pthread_self();
    370    /* Tell the tool what my pthread_t is. */
    371    DO_CREQ_v_W(_VG_USERREQ__HG_SET_MY_PTHREAD_T, CREQ_PTHREAD_T, me);
    372    /* allow the parent to proceed.  We can't let it proceed until
    373       we're ready because (1) we need to make sure it doesn't exit and
    374       hence deallocate xargs[] while we still need it, and (2) we
    375       don't want either parent nor child to proceed until the tool has
    376       been notified of the child's pthread_t.
    377 
    378       Note that parent and child access args[] without a lock,
    379       effectively using args[2] as a spinlock in order to get the
    380       parent to wait until the child passes this point.  The parent
    381       disables checking on xargs[] before creating the child and
    382       re-enables it once the child goes past this point, so the user
    383       never sees the race.  The previous approach (suppressing the
    384       resulting error) was flawed, because it could leave shadow
    385       memory for args[] in a state in which subsequent use of it by
    386       the parent would report further races. */
    387    xargs[2] = 0;
    388    /* Now we can no longer safely use xargs[]. */
    389    return (void*) fn( (void*)arg );
    390 }
    391 
    392 //-----------------------------------------------------------
    393 // glibc:  pthread_create (at) GLIBC_2.0
    394 // glibc:  pthread_create@@GLIBC_2.1
    395 // glibc:  pthread_create@@GLIBC_2.2.5
    396 // darwin: pthread_create
    397 // darwin: pthread_create_suspended_np (trapped)
    398 //
    399 /* ensure this has its own frame, so as to make it more distinguishable
    400    in suppressions */
    401 __attribute__((noinline))
    402 static int pthread_create_WRK(pthread_t *thread, const pthread_attr_t *attr,
    403                               void *(*start) (void *), void *arg)
    404 {
    405    int    ret;
    406    OrigFn fn;
    407    volatile Word xargs[3];
    408 
    409    VALGRIND_GET_ORIG_FN(fn);
    410    if (TRACE_PTH_FNS) {
    411       fprintf(stderr, "<< pthread_create wrapper"); fflush(stderr);
    412    }
    413    xargs[0] = (Word)start;
    414    xargs[1] = (Word)arg;
    415    xargs[2] = 1; /* serves as a spinlock -- sigh */
    416    /* Disable checking on the spinlock and the two words used to
    417       convey args to the child.  Basically we need to make it appear
    418       as if the child never accessed this area, since merely
    419       suppressing the resulting races does not address the issue that
    420       that piece of the parent's stack winds up in the "wrong" state
    421       and therefore may give rise to mysterious races when the parent
    422       comes to re-use this piece of stack in some other frame. */
    423    VALGRIND_HG_DISABLE_CHECKING(&xargs, sizeof(xargs));
    424 
    425    VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_BEGIN,
    426                                    0, 0, 0, 0, 0);
    427    CALL_FN_W_WWWW(ret, fn, thread,attr,mythread_wrapper,&xargs[0]);
    428    VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_END,
    429                                    0, 0, 0, 0, 0);
    430 
    431    if (ret == 0) {
    432       /* we have to wait for the child to notify the tool of its
    433          pthread_t before continuing */
    434       while (xargs[2] != 0) {
    435          /* Do nothing.  We need to spin until the child writes to
    436             xargs[2].  However, that can lead to starvation in the
    437             child and very long delays (eg, tc19_shadowmem on
    438             ppc64-linux Fedora Core 6).  So yield the cpu if we can,
    439             to let the child run at the earliest available
    440             opportunity. */
    441          sched_yield();
    442       }
    443    } else {
    444       DO_PthAPIerror( "pthread_create", ret );
    445    }
    446 
    447    /* Reenable checking on the area previously used to communicate
    448       with the child. */
    449    VALGRIND_HG_ENABLE_CHECKING(&xargs, sizeof(xargs));
    450 
    451    if (TRACE_PTH_FNS) {
    452       fprintf(stderr, " :: pth_create -> %d >>\n", ret);
    453    }
    454    return ret;
    455 }
    456 #if defined(VGO_linux)
    457    PTH_FUNC(int, pthreadZucreateZAZa, // pthread_create@*
    458                  pthread_t *thread, const pthread_attr_t *attr,
    459                  void *(*start) (void *), void *arg) {
    460       return pthread_create_WRK(thread, attr, start, arg);
    461    }
    462 #elif defined(VGO_darwin)
    463    PTH_FUNC(int, pthreadZucreate, // pthread_create
    464                  pthread_t *thread, const pthread_attr_t *attr,
    465                  void *(*start) (void *), void *arg) {
    466       return pthread_create_WRK(thread, attr, start, arg);
    467    }
    468    PTH_FUNC(int, pthreadZucreateZuZa, // pthread_create_*
    469                  pthread_t *thread, const pthread_attr_t *attr,
    470                  void *(*start) (void *), void *arg) {
    471       // trap anything else
    472       assert(0);
    473    }
    474 #elif defined(VGO_solaris)
    475    PTH_FUNC(int, pthreadZucreate, // pthread_create
    476                  pthread_t *thread, const pthread_attr_t *attr,
    477                  void *(*start) (void *), void *arg) {
    478       return pthread_create_WRK(thread, attr, start, arg);
    479    }
    480 #else
    481 #  error "Unsupported OS"
    482 #endif
    483 
    484 #if defined(VGO_solaris)
    485 /* Solaris also provides thr_create() in addition to pthread_create().
    486  * Both pthread_create(3C) and thr_create(3C) are based on private
    487  * _thrp_create().
    488  */
    489 __attribute__((noinline))
    490 static int thr_create_WRK(void *stk, size_t stksize, void *(*start)(void *),
    491                           void *arg, long flags, thread_t *new_thread)
    492 {
    493    int    ret;
    494    OrigFn fn;
    495    volatile Word xargs[3];
    496 
    497    VALGRIND_GET_ORIG_FN(fn);
    498    if (TRACE_PTH_FNS) {
    499       fprintf(stderr, "<< thr_create wrapper"); fflush(stderr);
    500    }
    501    xargs[0] = (Word)start;
    502    xargs[1] = (Word)arg;
    503    xargs[2] = 1; /* serves as a spinlock -- sigh */
    504    /* See comments in pthread_create_WRK() */
    505    VALGRIND_HG_DISABLE_CHECKING(&xargs, sizeof(xargs));
    506 
    507    VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_BEGIN,
    508                                    0, 0, 0, 0, 0);
    509    CALL_FN_W_6W(ret, fn, stk, stksize, mythread_wrapper, start, flags,
    510                 new_thread);
    511    VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_END,
    512                                    0, 0, 0, 0, 0);
    513 
    514    if (ret == 0) {
    515       while (xargs[2] != 0) {
    516          /* See comments in pthread_create_WRK(). */
    517          sched_yield();
    518       }
    519    } else {
    520       DO_PthAPIerror("thr_create", ret);
    521    }
    522 
    523    VALGRIND_HG_ENABLE_CHECKING(&xargs, sizeof(xargs));
    524 
    525    if (TRACE_PTH_FNS) {
    526       fprintf(stderr, " :: thr_create -> %d >>\n", ret);
    527    }
    528    return ret;
    529 }
    530    PTH_FUNC(int, thrZucreate, // thr_create
    531                  void *stk, size_t stksize, void *(*start)(void *),
    532                  void *arg, long flags, thread_t *new_thread) {
    533       return thr_create_WRK(stk, stksize, start, arg, flags, new_thread);
    534    }
    535 #endif /* VGO_solaris */
    536 
    537 
    538 //-----------------------------------------------------------
    539 // glibc:  pthread_join
    540 // darwin: pthread_join
    541 // darwin: pthread_join$NOCANCEL$UNIX2003
    542 // darwin  pthread_join$UNIX2003
    543 __attribute__((noinline))
    544 static int pthread_join_WRK(pthread_t thread, void** value_pointer)
    545 {
    546    int ret;
    547    OrigFn fn;
    548    VALGRIND_GET_ORIG_FN(fn);
    549    if (TRACE_PTH_FNS) {
    550       fprintf(stderr, "<< pthread_join wrapper"); fflush(stderr);
    551    }
    552 
    553    CALL_FN_W_WW(ret, fn, thread,value_pointer);
    554 
    555    /* At least with NPTL as the thread library, this is safe because
    556       it is guaranteed (by NPTL) that the joiner will completely gone
    557       before pthread_join (the original) returns.  See email below.*/
    558    if (ret == 0 /*success*/) {
    559       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST, CREQ_PTHREAD_T, thread);
    560    } else {
    561       DO_PthAPIerror( "pthread_join", ret );
    562    }
    563 
    564    if (TRACE_PTH_FNS) {
    565       fprintf(stderr, " :: pth_join -> %d >>\n", ret);
    566    }
    567    return ret;
    568 }
    569 #if defined(VGO_linux)
    570    PTH_FUNC(int, pthreadZujoin, // pthread_join
    571             pthread_t thread, void** value_pointer) {
    572       return pthread_join_WRK(thread, value_pointer);
    573    }
    574 #elif defined(VGO_darwin)
    575    PTH_FUNC(int, pthreadZujoinZa, // pthread_join*
    576             pthread_t thread, void** value_pointer) {
    577       return pthread_join_WRK(thread, value_pointer);
    578    }
    579 #elif defined(VGO_solaris)
    580    PTH_FUNC(int, pthreadZujoin, // pthread_join
    581             pthread_t thread, void** value_pointer) {
    582       return pthread_join_WRK(thread, value_pointer);
    583    }
    584 #else
    585 #  error "Unsupported OS"
    586 #endif
    587 
    588 
    589 /* Behaviour of pthread_join on NPTL:
    590 
    591 Me:
    592 I have a question re the NPTL pthread_join implementation.
    593 
    594   Suppose I am the thread 'stayer'.
    595 
    596   If I call pthread_join(quitter), is it guaranteed that the
    597   thread 'quitter' has really exited before pthread_join returns?
    598 
    599   IOW, is it guaranteed that 'quitter' will not execute any further
    600   instructions after pthread_join returns?
    601 
    602 I believe this is true based on the following analysis of
    603 glibc-2.5 sources.  However am not 100% sure and would appreciate
    604 confirmation.
    605 
    606   'quitter' will be running start_thread() in nptl/pthread_create.c
    607 
    608   The last action of start_thread() is to exit via
    609   __exit_thread_inline(0), which simply does sys_exit
    610   (nptl/pthread_create.c:403)
    611 
    612   'stayer' meanwhile is waiting for lll_wait_tid (pd->tid)
    613   (call at nptl/pthread_join.c:89)
    614 
    615   As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
    616   lll_wait_tid will not return until kernel notifies via futex
    617   wakeup that 'quitter' has terminated.
    618 
    619   Hence pthread_join cannot return until 'quitter' really has
    620   completely disappeared.
    621 
    622 Drepper:
    623 >   As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
    624 >   lll_wait_tid will not return until kernel notifies via futex
    625 >   wakeup that 'quitter' has terminated.
    626 That's the key.  The kernel resets the TID field after the thread is
    627 done.  No way the joiner can return before the thread is gone.
    628 */
    629 
    630 #if defined(VGO_solaris)
    631 /* Solaris also provides thr_join() in addition to pthread_join().
    632  * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
    633  *
    634  * :TODO: No functionality is currently provided for joinee == 0 and departed.
    635  *        This would require another client request, of course.
    636  */
    637 __attribute__((noinline))
    638 static int thr_join_WRK(thread_t joinee, thread_t *departed, void **thread_return)
    639 {
    640    int ret;
    641    OrigFn fn;
    642    VALGRIND_GET_ORIG_FN(fn);
    643    if (TRACE_PTH_FNS) {
    644       fprintf(stderr, "<< thr_join wrapper"); fflush(stderr);
    645    }
    646 
    647    CALL_FN_W_WWW(ret, fn, joinee, departed, thread_return);
    648 
    649    if (ret == 0 /*success*/) {
    650       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST, CREQ_PTHREAD_T, joinee);
    651    } else {
    652       DO_PthAPIerror("thr_join", ret);
    653    }
    654 
    655    if (TRACE_PTH_FNS) {
    656       fprintf(stderr, " :: thr_join -> %d >>\n", ret);
    657    }
    658    return ret;
    659 }
    660    PTH_FUNC(int, thrZujoin, // thr_join
    661             thread_t joinee, thread_t *departed, void **thread_return) {
    662       return thr_join_WRK(joinee, departed, thread_return);
    663    }
    664 #endif /* VGO_solaris */
    665 
    666 
    667 //-----------------------------------------------------------
    668 // Ada gcc gnat runtime:
    669 // The gnat gcc Ada runtime does not use pthread_join. Instead, it uses
    670 // a combination of other pthread primitives to ensure a child thread
    671 // is gone. This combination is somewhat functionally equivalent to a
    672 // pthread_join.
    673 // We wrap two hook procedures called by the gnat gcc Ada runtime
    674 // that allows helgrind to understand the semantic of Ada task dependencies
    675 // and termination.
    676 
    677 // System.Tasking.Debug.Master_Hook is called by a task Dependent to
    678 // indicate that its master is identified by master+master_level.
    679 void I_WRAP_SONAME_FNNAME_ZU
    680    (Za,
    681     system__tasking__debug__master_hook)
    682      (void *dependent, void *master, int master_level);
    683 void I_WRAP_SONAME_FNNAME_ZU
    684    (Za,
    685     system__tasking__debug__master_hook)
    686      (void *dependent, void *master, int master_level)
    687 {
    688    OrigFn fn;
    689    VALGRIND_GET_ORIG_FN(fn);
    690    if (TRACE_GNAT_FNS) {
    691      fprintf(stderr, "<< GNAT master_hook wrapper "
    692              "dependent %p master %p master_level %d\n",
    693              dependent, master, master_level); fflush(stderr);
    694    }
    695 
    696    // We call the wrapped function, even if it is a null body.
    697    CALL_FN_v_WWW(fn, dependent, master, master_level);
    698 
    699    DO_CREQ_v_WWW(_VG_USERREQ__HG_GNAT_MASTER_HOOK,
    700                  void*,dependent, void*,master,
    701                  Word, (Word)master_level);
    702 
    703    if (TRACE_GNAT_FNS) {
    704       fprintf(stderr, " :: GNAT master_hook >>\n");
    705    }
    706 }
    707 
    708 // System.Tasking.Debug.Master_Completed_Hook is called by a task to
    709 // indicate that it has completed a master.
    710 // This indicates that all its Dependent tasks (that identified themselves
    711 // with the Master_Hook call) are terminated. Helgrind can consider
    712 // at this point that the equivalent of a 'pthread_join' has been done
    713 // between self_id and all dependent tasks at master_level.
    714 void I_WRAP_SONAME_FNNAME_ZU
    715    (Za,
    716     system__tasking__debug__master_completed_hook)
    717      (void *self_id, int master_level);
    718 void I_WRAP_SONAME_FNNAME_ZU
    719    (Za,
    720     system__tasking__debug__master_completed_hook)
    721      (void *self_id, int master_level)
    722 {
    723    OrigFn fn;
    724    VALGRIND_GET_ORIG_FN(fn);
    725    if (TRACE_GNAT_FNS) {
    726      fprintf(stderr, "<< GNAT master_completed_hook wrapper "
    727              "self_id %p master_level %d\n",
    728              self_id, master_level); fflush(stderr);
    729    }
    730 
    731    // We call the wrapped function, even if it is a null body.
    732    CALL_FN_v_WW(fn, self_id, master_level);
    733 
    734    DO_CREQ_v_WW(_VG_USERREQ__HG_GNAT_MASTER_COMPLETED_HOOK,
    735                  void*,self_id, Word,(Word)master_level);
    736 
    737    if (TRACE_GNAT_FNS) {
    738       fprintf(stderr, " :: GNAT master_completed_hook >>\n");
    739    }
    740 }
    741 
    742 /*----------------------------------------------------------------*/
    743 /*--- pthread_mutex_t functions                                ---*/
    744 /*----------------------------------------------------------------*/
    745 
    746 /* Handled:   pthread_mutex_init pthread_mutex_destroy
    747               pthread_mutex_lock
    748               pthread_mutex_trylock pthread_mutex_timedlock
    749               pthread_mutex_unlock
    750 */
    751 
    752 //-----------------------------------------------------------
    753 #if !defined(VGO_solaris)
    754 // glibc:  pthread_mutex_init
    755 // darwin: pthread_mutex_init
    756 PTH_FUNC(int, pthreadZumutexZuinit, // pthread_mutex_init
    757               pthread_mutex_t *mutex,
    758               pthread_mutexattr_t* attr)
    759 {
    760    int    ret;
    761    long   mbRec;
    762    OrigFn fn;
    763    VALGRIND_GET_ORIG_FN(fn);
    764    if (TRACE_PTH_FNS) {
    765       fprintf(stderr, "<< pthread_mxinit %p", mutex); fflush(stderr);
    766    }
    767 
    768    mbRec = 0;
    769    if (attr) {
    770       int ty, zzz;
    771       zzz = pthread_mutexattr_gettype(attr, &ty);
    772       if (zzz == 0 && ty == PTHREAD_MUTEX_RECURSIVE)
    773          mbRec = 1;
    774    }
    775 
    776    CALL_FN_W_WW(ret, fn, mutex,attr);
    777 
    778    if (ret == 0 /*success*/) {
    779       DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
    780                    pthread_mutex_t*,mutex, long,mbRec);
    781    } else {
    782       DO_PthAPIerror( "pthread_mutex_init", ret );
    783    }
    784 
    785    if (TRACE_PTH_FNS) {
    786       fprintf(stderr, " :: mxinit -> %d >>\n", ret);
    787    }
    788    return ret;
    789 }
    790 
    791 #else /* VGO_solaris */
    792 
    793 // Solaris: mutex_init (pthread_mutex_init calls here)
    794 PTH_FUNC(int, mutexZuinit, // mutex_init
    795               mutex_t *mutex, int type, void *arg)
    796 {
    797    int    ret;
    798    long   mbRec;
    799    OrigFn fn;
    800    VALGRIND_GET_ORIG_FN(fn);
    801    if (TRACE_PTH_FNS) {
    802       fprintf(stderr, "<< mxinit %p", mutex); fflush(stderr);
    803    }
    804 
    805    mbRec = ((type & LOCK_RECURSIVE) != 0) ? 1 : 0;
    806 
    807    CALL_FN_W_WWW(ret, fn, mutex, type, arg);
    808 
    809    if (ret == 0 /*success*/) {
    810       DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
    811                    mutex_t *, mutex, long, mbRec);
    812    } else {
    813       DO_PthAPIerror("mutex_init", ret);
    814    }
    815 
    816    if (TRACE_PTH_FNS) {
    817       fprintf(stderr, " :: mxinit -> %d >>\n", ret);
    818    }
    819    return ret;
    820 }
    821 #endif /* VGO_solaris */
    822 
    823 
    824 //-----------------------------------------------------------
    825 // glibc:   pthread_mutex_destroy
    826 // darwin:  pthread_mutex_destroy
    827 // Solaris: mutex_destroy (pthread_mutex_destroy is a weak alias)
    828 __attribute__((noinline))
    829 static int mutex_destroy_WRK(pthread_mutex_t *mutex)
    830 {
    831    int    ret;
    832    unsigned long mutex_is_init;
    833    OrigFn fn;
    834 
    835    VALGRIND_GET_ORIG_FN(fn);
    836    if (TRACE_PTH_FNS) {
    837       fprintf(stderr, "<< pthread_mxdestroy %p", mutex); fflush(stderr);
    838    }
    839 
    840    if (mutex != NULL) {
    841       static const pthread_mutex_t mutex_init = PTHREAD_MUTEX_INITIALIZER;
    842       mutex_is_init = my_memcmp(mutex, &mutex_init, sizeof(*mutex)) == 0;
    843    } else {
    844       mutex_is_init = 0;
    845    }
    846 
    847    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
    848                 pthread_mutex_t*, mutex, unsigned long, mutex_is_init);
    849 
    850    CALL_FN_W_W(ret, fn, mutex);
    851 
    852    if (ret != 0) {
    853       DO_PthAPIerror( "pthread_mutex_destroy", ret );
    854    }
    855 
    856    if (TRACE_PTH_FNS) {
    857       fprintf(stderr, " :: mxdestroy -> %d >>\n", ret);
    858    }
    859    return ret;
    860 }
    861 
    862 #if defined(VGO_linux) || defined(VGO_darwin)
    863    PTH_FUNC(int, pthreadZumutexZudestroy, // pthread_mutex_destroy
    864             pthread_mutex_t *mutex) {
    865       return mutex_destroy_WRK(mutex);
    866    }
    867 #elif defined(VGO_solaris)
    868    PTH_FUNC(int, mutexZudestroy, // mutex_destroy
    869             pthread_mutex_t *mutex) {
    870       return mutex_destroy_WRK(mutex);
    871    }
    872 #else
    873 #  error "Unsupported OS"
    874 #endif
    875 
    876 
    877 //-----------------------------------------------------------
    878 // glibc:   pthread_mutex_lock
    879 // darwin:  pthread_mutex_lock
    880 // Solaris: mutex_lock (pthread_mutex_lock is a weak alias)
    881 __attribute__((noinline))
    882 static int mutex_lock_WRK(pthread_mutex_t *mutex)
    883 {
    884    int    ret;
    885    OrigFn fn;
    886    VALGRIND_GET_ORIG_FN(fn);
    887    if (TRACE_PTH_FNS) {
    888       fprintf(stderr, "<< pthread_mxlock %p", mutex); fflush(stderr);
    889    }
    890 
    891    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
    892                 pthread_mutex_t*,mutex, long,0/*!isTryLock*/);
    893 
    894    CALL_FN_W_W(ret, fn, mutex);
    895 
    896    /* There's a hole here: libpthread now knows the lock is locked,
    897       but the tool doesn't, so some other thread could run and detect
    898       that the lock has been acquired by someone (this thread).  Does
    899       this matter?  Not sure, but I don't think so. */
    900 
    901    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
    902                 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
    903 
    904    if (ret != 0) {
    905       DO_PthAPIerror( "pthread_mutex_lock", ret );
    906    }
    907 
    908    if (TRACE_PTH_FNS) {
    909       fprintf(stderr, " :: mxlock -> %d >>\n", ret);
    910    }
    911    return ret;
    912 }
    913 
    914 #if defined(VGO_linux) || defined(VGO_darwin)
    915    PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock
    916             pthread_mutex_t *mutex) {
    917       return mutex_lock_WRK(mutex);
    918    }
    919 #elif defined(VGO_solaris)
    920    PTH_FUNC(int, mutexZulock, // mutex_lock
    921             pthread_mutex_t *mutex) {
    922       return mutex_lock_WRK(mutex);
    923    }
    924 #else
    925 #  error "Unsupported OS"
    926 #endif
    927 
    928 #if defined(VGO_solaris)
    929 /* Internal to libc. Mutex is usually initialized only implicitly,
    930  * by zeroing mutex_t structure.
    931  */
    932 __attribute__((noinline))
    933 PTH_FUNC(void, lmutexZulock, // lmutex_lock
    934                mutex_t *mutex)
    935 {
    936    OrigFn fn;
    937    VALGRIND_GET_ORIG_FN(fn);
    938    if (TRACE_PTH_FNS) {
    939       fprintf(stderr, "<< lmxlock %p", mutex); fflush(stderr);
    940    }
    941 
    942    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
    943                 mutex_t *, mutex, long, 0 /*!isTryLock*/);
    944    CALL_FN_v_W(fn, mutex);
    945    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
    946                 mutex_t *, mutex, long, True);
    947 
    948    if (TRACE_PTH_FNS) {
    949       fprintf(stderr, " :: lmxlock >>\n");
    950    }
    951 }
    952 #endif /* VGO_solaris */
    953 
    954 
    955 //-----------------------------------------------------------
    956 // glibc:   pthread_mutex_trylock
    957 // darwin:  pthread_mutex_trylock
    958 // Solaris: mutex_trylock (pthread_mutex_trylock is a weak alias)
    959 //
    960 // pthread_mutex_trylock.  The handling needed here is very similar
    961 // to that for pthread_mutex_lock, except that we need to tell
    962 // the pre-lock creq that this is a trylock-style operation, and
    963 // therefore not to complain if the lock is nonrecursive and
    964 // already locked by this thread -- because then it'll just fail
    965 // immediately with EBUSY.
    966 __attribute__((noinline))
    967 static int mutex_trylock_WRK(pthread_mutex_t *mutex)
    968 {
    969    int    ret;
    970    OrigFn fn;
    971    VALGRIND_GET_ORIG_FN(fn);
    972    if (TRACE_PTH_FNS) {
    973       fprintf(stderr, "<< pthread_mxtrylock %p", mutex); fflush(stderr);
    974    }
    975 
    976    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
    977                 pthread_mutex_t*,mutex, long,1/*isTryLock*/);
    978 
    979    CALL_FN_W_W(ret, fn, mutex);
    980 
    981    /* There's a hole here: libpthread now knows the lock is locked,
    982       but the tool doesn't, so some other thread could run and detect
    983       that the lock has been acquired by someone (this thread).  Does
    984       this matter?  Not sure, but I don't think so. */
    985 
    986    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
    987                pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
    988 
    989    if (ret != 0) {
    990       if (ret != EBUSY)
    991          DO_PthAPIerror( "pthread_mutex_trylock", ret );
    992    }
    993 
    994    if (TRACE_PTH_FNS) {
    995       fprintf(stderr, " :: mxtrylock -> %d >>\n", ret);
    996    }
    997    return ret;
    998 }
    999 
   1000 #if defined(VGO_linux) || defined(VGO_darwin)
   1001    PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock
   1002             pthread_mutex_t *mutex) {
   1003       return mutex_trylock_WRK(mutex);
   1004    }
   1005 #elif defined(VGO_solaris)
   1006    PTH_FUNC(int, mutexZutrylock, // mutex_trylock
   1007             pthread_mutex_t *mutex) {
   1008       return mutex_trylock_WRK(mutex);
   1009    }
   1010 #else
   1011 #  error "Unsupported OS"
   1012 #endif
   1013 
   1014 
   1015 //-----------------------------------------------------------
   1016 // glibc:   pthread_mutex_timedlock
   1017 // darwin:  (doesn't appear to exist)
   1018 // Solaris: pthread_mutex_timedlock
   1019 //
   1020 // pthread_mutex_timedlock.  Identical logic to pthread_mutex_trylock.
   1021 __attribute__((noinline))
   1022 static int mutex_timedlock_WRK(pthread_mutex_t *mutex,
   1023                                void *timeout)
   1024 {
   1025    int    ret;
   1026    OrigFn fn;
   1027    VALGRIND_GET_ORIG_FN(fn);
   1028    if (TRACE_PTH_FNS) {
   1029       fprintf(stderr, "<< pthread_mxtimedlock %p %p", mutex, timeout);
   1030       fflush(stderr);
   1031    }
   1032 
   1033    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
   1034                 pthread_mutex_t*,mutex, long,1/*isTryLock-ish*/);
   1035 
   1036    CALL_FN_W_WW(ret, fn, mutex,timeout);
   1037 
   1038    /* There's a hole here: libpthread now knows the lock is locked,
   1039       but the tool doesn't, so some other thread could run and detect
   1040       that the lock has been acquired by someone (this thread).  Does
   1041       this matter?  Not sure, but I don't think so. */
   1042 
   1043    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
   1044                 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
   1045 
   1046    if (ret != 0) {
   1047       if (ret != ETIMEDOUT)
   1048          DO_PthAPIerror( "pthread_mutex_timedlock", ret );
   1049    }
   1050 
   1051    if (TRACE_PTH_FNS) {
   1052       fprintf(stderr, " :: mxtimedlock -> %d >>\n", ret);
   1053    }
   1054    return ret;
   1055 }
   1056 
   1057 PTH_FUNC(int, pthreadZumutexZutimedlock, // pthread_mutex_timedlock
   1058          pthread_mutex_t *mutex,
   1059          void *timeout) {
   1060    return mutex_timedlock_WRK(mutex, timeout);
   1061 }
   1062 #if defined(VGO_solaris)
   1063 PTH_FUNC(int, pthreadZumutexZureltimedlock, // pthread_mutex_reltimedlock
   1064          pthread_mutex_t *mutex,
   1065          void *timeout) {
   1066    return mutex_timedlock_WRK(mutex, timeout);
   1067 }
   1068 #endif
   1069 
   1070 
   1071 //-----------------------------------------------------------
   1072 // glibc:   pthread_mutex_unlock
   1073 // darwin:  pthread_mutex_unlock
   1074 // Solaris: mutex_unlock (pthread_mutex_unlock is a weak alias)
   1075 __attribute__((noinline))
   1076 static int mutex_unlock_WRK(pthread_mutex_t *mutex)
   1077 {
   1078    int    ret;
   1079    OrigFn fn;
   1080    VALGRIND_GET_ORIG_FN(fn);
   1081 
   1082    if (TRACE_PTH_FNS) {
   1083       fprintf(stderr, "<< pthread_mxunlk %p", mutex); fflush(stderr);
   1084    }
   1085 
   1086    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
   1087                pthread_mutex_t*,mutex);
   1088 
   1089    CALL_FN_W_W(ret, fn, mutex);
   1090 
   1091    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
   1092                pthread_mutex_t*,mutex);
   1093 
   1094    if (ret != 0) {
   1095       DO_PthAPIerror( "pthread_mutex_unlock", ret );
   1096    }
   1097 
   1098    if (TRACE_PTH_FNS) {
   1099       fprintf(stderr, " mxunlk -> %d >>\n", ret);
   1100    }
   1101    return ret;
   1102 }
   1103 
   1104 #if defined(VGO_linux) || defined(VGO_darwin)
   1105    PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock
   1106             pthread_mutex_t *mutex) {
   1107       return mutex_unlock_WRK(mutex);
   1108    }
   1109 #elif defined(VGO_solaris)
   1110    PTH_FUNC(int, mutexZuunlock, // mutex_unlock
   1111             pthread_mutex_t *mutex) {
   1112       return mutex_unlock_WRK(mutex);
   1113    }
   1114 #else
   1115 #  error "Unsupported OS"
   1116 #endif
   1117 
   1118 
   1119 #if defined(VGO_solaris)
   1120 /* Internal to libc. */
   1121 __attribute__((noinline))
   1122 PTH_FUNC(void, lmutexZuunlock, // lmutex_unlock
   1123                mutex_t *mutex)
   1124 {
   1125    OrigFn fn;
   1126    VALGRIND_GET_ORIG_FN(fn);
   1127 
   1128    if (TRACE_PTH_FNS) {
   1129       fprintf(stderr, "<< lmxunlk %p", mutex); fflush(stderr);
   1130    }
   1131 
   1132    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
   1133                mutex_t *, mutex);
   1134    CALL_FN_v_W(fn, mutex);
   1135    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
   1136                mutex_t*, mutex);
   1137 
   1138    if (TRACE_PTH_FNS) {
   1139       fprintf(stderr, " lmxunlk >>\n");
   1140    }
   1141 }
   1142 #endif /* VGO_solaris */
   1143 
   1144 
   1145 /*----------------------------------------------------------------*/
   1146 /*--- pthread_cond_t functions                                 ---*/
   1147 /*----------------------------------------------------------------*/
   1148 
   1149 /* Handled:   pthread_cond_wait pthread_cond_timedwait
   1150               pthread_cond_signal pthread_cond_broadcast
   1151               pthread_cond_init
   1152               pthread_cond_destroy
   1153 */
   1154 
   1155 //-----------------------------------------------------------
   1156 // glibc:   pthread_cond_wait (at) GLIBC_2.2.5
   1157 // glibc:   pthread_cond_wait@@GLIBC_2.3.2
   1158 // darwin:  pthread_cond_wait
   1159 // darwin:  pthread_cond_wait$NOCANCEL$UNIX2003
   1160 // darwin:  pthread_cond_wait$UNIX2003
   1161 // Solaris: cond_wait (pthread_cond_wait is built atop of cond_wait)
   1162 //
   1163 __attribute__((noinline))
   1164 static int pthread_cond_wait_WRK(pthread_cond_t* cond,
   1165                                  pthread_mutex_t* mutex)
   1166 {
   1167    int ret;
   1168    OrigFn fn;
   1169    unsigned long mutex_is_valid;
   1170 
   1171    VALGRIND_GET_ORIG_FN(fn);
   1172 
   1173    if (TRACE_PTH_FNS) {
   1174       fprintf(stderr, "<< pthread_cond_wait %p %p", cond, mutex);
   1175       fflush(stderr);
   1176    }
   1177 
   1178    /* Tell the tool a cond-wait is about to happen, so it can check
   1179       for bogus argument values.  In return it tells us whether it
   1180       thinks the mutex is valid or not. */
   1181    DO_CREQ_W_WW(mutex_is_valid,
   1182                 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
   1183                 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
   1184    assert(mutex_is_valid == 1 || mutex_is_valid == 0);
   1185 
   1186    /* Tell the tool we're about to drop the mutex.  This reflects the
   1187       fact that in a cond_wait, we show up holding the mutex, and the
   1188       call atomically drops the mutex and waits for the cv to be
   1189       signalled. */
   1190    if (mutex_is_valid) {
   1191       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
   1192                   pthread_mutex_t*,mutex);
   1193    }
   1194 
   1195    CALL_FN_W_WW(ret, fn, cond,mutex);
   1196 
   1197    /* this conditional look stupid, but compare w/ same logic for
   1198       pthread_cond_timedwait below */
   1199    if (mutex_is_valid) {
   1200       /* and now we have the mutex again if (ret == 0) */
   1201       DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
   1202                    pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
   1203    }
   1204 
   1205    DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
   1206                   pthread_cond_t*,cond, pthread_mutex_t*,mutex, long,0,
   1207                   long, (ret == 0 && mutex_is_valid) ? True : False);
   1208 
   1209    if (ret != 0) {
   1210       DO_PthAPIerror( "pthread_cond_wait", ret );
   1211    }
   1212 
   1213    if (TRACE_PTH_FNS) {
   1214       fprintf(stderr, " cowait -> %d >>\n", ret);
   1215    }
   1216 
   1217    return ret;
   1218 }
   1219 #if defined(VGO_linux)
   1220    PTH_FUNC(int, pthreadZucondZuwaitZAZa, // pthread_cond_wait@*
   1221                  pthread_cond_t* cond, pthread_mutex_t* mutex) {
   1222       return pthread_cond_wait_WRK(cond, mutex);
   1223    }
   1224 #elif defined(VGO_darwin)
   1225    PTH_FUNC(int, pthreadZucondZuwaitZa, // pthread_cond_wait*
   1226                  pthread_cond_t* cond, pthread_mutex_t* mutex) {
   1227       return pthread_cond_wait_WRK(cond, mutex);
   1228    }
   1229 #elif defined(VGO_solaris)
   1230    PTH_FUNC(int, condZuwait, // cond_wait
   1231                  pthread_cond_t *cond, pthread_mutex_t *mutex) {
   1232       return pthread_cond_wait_WRK(cond, mutex);
   1233    }
   1234 #else
   1235 #  error "Unsupported OS"
   1236 #endif
   1237 
   1238 
   1239 //-----------------------------------------------------------
   1240 // glibc:   pthread_cond_timedwait@@GLIBC_2.3.2
   1241 // glibc:   pthread_cond_timedwait (at) GLIBC_2.2.5
   1242 // glibc:   pthread_cond_timedwait (at) GLIBC_2.0
   1243 // darwin:  pthread_cond_timedwait
   1244 // darwin:  pthread_cond_timedwait$NOCANCEL$UNIX2003
   1245 // darwin:  pthread_cond_timedwait$UNIX2003
   1246 // darwin:  pthread_cond_timedwait_relative_np (trapped)
   1247 // Solaris: cond_timedwait (pthread_cond_timedwait is built on cond_timedwait)
   1248 // Solaris: cond_reltimedwait (pthread_cond_reltimedwait_np is built on this)
   1249 //
   1250 __attribute__((noinline))
   1251 static int pthread_cond_timedwait_WRK(pthread_cond_t* cond,
   1252                                       pthread_mutex_t* mutex,
   1253                                       struct timespec* abstime,
   1254                                       int timeout_error)
   1255 {
   1256    int ret;
   1257    OrigFn fn;
   1258    unsigned long mutex_is_valid;
   1259    Bool abstime_is_valid;
   1260    VALGRIND_GET_ORIG_FN(fn);
   1261 
   1262    if (TRACE_PTH_FNS) {
   1263       fprintf(stderr, "<< pthread_cond_timedwait %p %p %p",
   1264                       cond, mutex, abstime);
   1265       fflush(stderr);
   1266    }
   1267 
   1268    /* Tell the tool a cond-wait is about to happen, so it can check
   1269       for bogus argument values.  In return it tells us whether it
   1270       thinks the mutex is valid or not. */
   1271    DO_CREQ_W_WW(mutex_is_valid,
   1272                 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
   1273                 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
   1274    assert(mutex_is_valid == 1 || mutex_is_valid == 0);
   1275 
   1276    abstime_is_valid = abstime->tv_nsec >= 0 && abstime->tv_nsec < 1000000000;
   1277 
   1278    /* Tell the tool we're about to drop the mutex.  This reflects the
   1279       fact that in a cond_wait, we show up holding the mutex, and the
   1280       call atomically drops the mutex and waits for the cv to be
   1281       signalled. */
   1282    if (mutex_is_valid && abstime_is_valid) {
   1283       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
   1284                   pthread_mutex_t*,mutex);
   1285    }
   1286 
   1287    CALL_FN_W_WWW(ret, fn, cond,mutex,abstime);
   1288 
   1289    if (mutex_is_valid && !abstime_is_valid && ret != EINVAL) {
   1290       DO_PthAPIerror("Bug in libpthread: pthread_cond_timedwait "
   1291                      "invalid abstime did not cause"
   1292                      " EINVAL", ret);
   1293    }
   1294 
   1295    if (mutex_is_valid && abstime_is_valid) {
   1296       /* and now we have the mutex again if (ret == 0 || ret == timeout) */
   1297       DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
   1298                    pthread_mutex_t *, mutex,
   1299                    long, (ret == 0 || ret == timeout_error) ? True : False);
   1300    }
   1301 
   1302    DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
   1303                   pthread_cond_t*,cond, pthread_mutex_t*,mutex,
   1304                   long,ret == timeout_error,
   1305                   long, (ret == 0 || ret == timeout_error) && mutex_is_valid
   1306                         ? True : False);
   1307 
   1308    if (ret != 0 && ret != timeout_error) {
   1309       DO_PthAPIerror( "pthread_cond_timedwait", ret );
   1310    }
   1311 
   1312    if (TRACE_PTH_FNS) {
   1313       fprintf(stderr, " cotimedwait -> %d >>\n", ret);
   1314    }
   1315 
   1316    return ret;
   1317 }
   1318 #if defined(VGO_linux)
   1319    PTH_FUNC(int, pthreadZucondZutimedwaitZAZa, // pthread_cond_timedwait@*
   1320                  pthread_cond_t* cond, pthread_mutex_t* mutex,
   1321                  struct timespec* abstime) {
   1322       return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
   1323    }
   1324 #elif defined(VGO_darwin)
   1325    PTH_FUNC(int, pthreadZucondZutimedwait, // pthread_cond_timedwait
   1326                  pthread_cond_t* cond, pthread_mutex_t* mutex,
   1327                  struct timespec* abstime) {
   1328       return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
   1329    }
   1330    PTH_FUNC(int, pthreadZucondZutimedwaitZDZa, // pthread_cond_timedwait$*
   1331                  pthread_cond_t* cond, pthread_mutex_t* mutex,
   1332                  struct timespec* abstime) {
   1333       return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
   1334    }
   1335    PTH_FUNC(int, pthreadZucondZutimedwaitZuZa, // pthread_cond_timedwait_*
   1336                  pthread_cond_t* cond, pthread_mutex_t* mutex,
   1337                  struct timespec* abstime) {
   1338       assert(0);
   1339    }
   1340 #elif defined(VGO_solaris)
   1341    PTH_FUNC(int, condZutimedwait, // cond_timedwait
   1342                  pthread_cond_t *cond, pthread_mutex_t *mutex,
   1343                  struct timespec *abstime) {
   1344       return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIME);
   1345    }
   1346    PTH_FUNC(int, condZureltimedwait, // cond_reltimedwait
   1347                  pthread_cond_t *cond, pthread_mutex_t *mutex,
   1348                  struct timespec *reltime) {
   1349       return pthread_cond_timedwait_WRK(cond, mutex, reltime, ETIME);
   1350    }
   1351 #else
   1352 #  error "Unsupported OS"
   1353 #endif
   1354 
   1355 
   1356 //-----------------------------------------------------------
   1357 // glibc:   pthread_cond_signal (at) GLIBC_2.0
   1358 // glibc:   pthread_cond_signal (at) GLIBC_2.2.5
   1359 // glibc:   pthread_cond_signal@@GLIBC_2.3.2
   1360 // darwin:  pthread_cond_signal
   1361 // darwin:  pthread_cond_signal_thread_np (don't intercept this)
   1362 // Solaris: cond_signal (pthread_cond_signal is a weak alias)
   1363 //
   1364 __attribute__((noinline))
   1365 static int pthread_cond_signal_WRK(pthread_cond_t* cond)
   1366 {
   1367    int ret;
   1368    OrigFn fn;
   1369    VALGRIND_GET_ORIG_FN(fn);
   1370 
   1371    if (TRACE_PTH_FNS) {
   1372       fprintf(stderr, "<< pthread_cond_signal %p", cond);
   1373       fflush(stderr);
   1374    }
   1375 
   1376    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE,
   1377                pthread_cond_t*,cond);
   1378 
   1379    CALL_FN_W_W(ret, fn, cond);
   1380 
   1381    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_POST,
   1382                pthread_cond_t*,cond);
   1383 
   1384    if (ret != 0) {
   1385       DO_PthAPIerror( "pthread_cond_signal", ret );
   1386    }
   1387 
   1388    if (TRACE_PTH_FNS) {
   1389       fprintf(stderr, " cosig -> %d >>\n", ret);
   1390    }
   1391 
   1392    return ret;
   1393 }
   1394 #if defined(VGO_linux)
   1395    PTH_FUNC(int, pthreadZucondZusignalZAZa, // pthread_cond_signal@*
   1396                  pthread_cond_t* cond) {
   1397       return pthread_cond_signal_WRK(cond);
   1398    }
   1399 #elif defined(VGO_darwin)
   1400    PTH_FUNC(int, pthreadZucondZusignal, // pthread_cond_signal
   1401                  pthread_cond_t* cond) {
   1402       return pthread_cond_signal_WRK(cond);
   1403    }
   1404 #elif defined(VGO_solaris)
   1405    PTH_FUNC(int, condZusignal, // cond_signal
   1406                  pthread_cond_t *cond) {
   1407       return pthread_cond_signal_WRK(cond);
   1408    }
   1409 #else
   1410 #  error "Unsupported OS"
   1411 #endif
   1412 
   1413 
   1414 //-----------------------------------------------------------
   1415 // glibc:   pthread_cond_broadcast (at) GLIBC_2.0
   1416 // glibc:   pthread_cond_broadcast (at) GLIBC_2.2.5
   1417 // glibc:   pthread_cond_broadcast@@GLIBC_2.3.2
   1418 // darwin:  pthread_cond_broadcast
   1419 // Solaris: cond_broadcast (pthread_cond_broadcast is a weak alias)
   1420 //
   1421 // Note, this is pretty much identical, from a dependency-graph
   1422 // point of view, with cond_signal, so the code is duplicated.
   1423 // Maybe it should be commoned up.
   1424 //
   1425 __attribute__((noinline))
   1426 static int pthread_cond_broadcast_WRK(pthread_cond_t* cond)
   1427 {
   1428    int ret;
   1429    OrigFn fn;
   1430    VALGRIND_GET_ORIG_FN(fn);
   1431 
   1432    if (TRACE_PTH_FNS) {
   1433       fprintf(stderr, "<< pthread_cond_broadcast %p", cond);
   1434       fflush(stderr);
   1435    }
   1436 
   1437    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE,
   1438                pthread_cond_t*,cond);
   1439 
   1440    CALL_FN_W_W(ret, fn, cond);
   1441 
   1442    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_POST,
   1443                pthread_cond_t*,cond);
   1444 
   1445    if (ret != 0) {
   1446       DO_PthAPIerror( "pthread_cond_broadcast", ret );
   1447    }
   1448 
   1449    if (TRACE_PTH_FNS) {
   1450       fprintf(stderr, " cobro -> %d >>\n", ret);
   1451    }
   1452 
   1453    return ret;
   1454 }
   1455 #if defined(VGO_linux)
   1456    PTH_FUNC(int, pthreadZucondZubroadcastZAZa, // pthread_cond_broadcast@*
   1457                  pthread_cond_t* cond) {
   1458       return pthread_cond_broadcast_WRK(cond);
   1459    }
   1460 #elif defined(VGO_darwin)
   1461    PTH_FUNC(int, pthreadZucondZubroadcast, // pthread_cond_broadcast
   1462                  pthread_cond_t* cond) {
   1463       return pthread_cond_broadcast_WRK(cond);
   1464    }
   1465 #elif defined(VGO_solaris)
   1466    PTH_FUNC(int, condZubroadcast, // cond_broadcast
   1467                  pthread_cond_t *cond) {
   1468       return pthread_cond_broadcast_WRK(cond);
   1469    }
   1470 #else
   1471 #   error "Unsupported OS"
   1472 #endif
   1473 
   1474 // glibc:   pthread_cond_init (at) GLIBC_2.0
   1475 // glibc:   pthread_cond_init (at) GLIBC_2.2.5
   1476 // glibc:   pthread_cond_init@@GLIBC_2.3.2
   1477 // darwin:  pthread_cond_init
   1478 // Solaris: cond_init (pthread_cond_init is built atop on this function)
   1479 // Easy way out: Handling of attr could have been messier.
   1480 // It turns out that pthread_cond_init under linux ignores
   1481 // all information in cond_attr, so do we.
   1482 // FIXME: MacOS X?
   1483 #if !defined(VGO_solaris)
   1484 __attribute__((noinline))
   1485 static int pthread_cond_init_WRK(pthread_cond_t* cond, pthread_condattr_t *cond_attr)
   1486 {
   1487    int ret;
   1488    OrigFn fn;
   1489    VALGRIND_GET_ORIG_FN(fn);
   1490 
   1491    if (TRACE_PTH_FNS) {
   1492       fprintf(stderr, "<< pthread_cond_init %p", cond);
   1493       fflush(stderr);
   1494    }
   1495 
   1496    CALL_FN_W_WW(ret, fn, cond, cond_attr);
   1497 
   1498    if (ret == 0) {
   1499       DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST,
   1500                    pthread_cond_t*,cond, pthread_condattr_t*, cond_attr);
   1501    } else {
   1502       DO_PthAPIerror( "pthread_cond_init", ret );
   1503    }
   1504 
   1505    if (TRACE_PTH_FNS) {
   1506       fprintf(stderr, " coinit -> %d >>\n", ret);
   1507    }
   1508 
   1509    return ret;
   1510 }
   1511 #if defined(VGO_linux)
   1512    PTH_FUNC(int, pthreadZucondZuinitZAZa, // pthread_cond_init@*
   1513 	    pthread_cond_t* cond, pthread_condattr_t* cond_attr) {
   1514      return pthread_cond_init_WRK(cond, cond_attr);
   1515    }
   1516 #elif defined(VGO_darwin)
   1517    PTH_FUNC(int, pthreadZucondZuinit, // pthread_cond_init
   1518 	    pthread_cond_t* cond, pthread_condattr_t * cond_attr) {
   1519      return pthread_cond_init_WRK(cond, cond_attr);
   1520    }
   1521 #else
   1522 #  error "Unsupported OS"
   1523 #endif
   1524 
   1525 #else /* VGO_solaris */
   1526 __attribute__((noinline))
   1527 PTH_FUNC(int, condZuinit, // cond_init
   1528               cond_t *cond, int type, void *arg)
   1529 {
   1530    int ret;
   1531    OrigFn fn;
   1532    VALGRIND_GET_ORIG_FN(fn);
   1533 
   1534    if (TRACE_PTH_FNS) {
   1535       fprintf(stderr, "<< cond_init %p", cond); fflush(stderr);
   1536    }
   1537 
   1538    CALL_FN_W_WWW(ret, fn, cond, type, arg);
   1539 
   1540    if (ret == 0) {
   1541       /* Luckily evh__HG_PTHREAD_COND_INIT_POST() ignores cond_attr.
   1542          See also comment for pthread_cond_init_WRK(). */
   1543       DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST,
   1544                    cond_t *, cond, void *, NULL);
   1545    } else {
   1546       DO_PthAPIerror("cond_init", ret);
   1547    }
   1548 
   1549    if (TRACE_PTH_FNS) {
   1550       fprintf(stderr, " cond_init -> %d >>\n", ret);
   1551    }
   1552 
   1553    return ret;
   1554 }
   1555 #endif /* VGO_solaris */
   1556 
   1557 
   1558 //-----------------------------------------------------------
   1559 // glibc:   pthread_cond_destroy@@GLIBC_2.3.2
   1560 // glibc:   pthread_cond_destroy (at) GLIBC_2.2.5
   1561 // glibc:   pthread_cond_destroy (at) GLIBC_2.0
   1562 // darwin:  pthread_cond_destroy
   1563 // Solaris: cond_destroy (pthread_cond_destroy is a weak alias)
   1564 //
   1565 __attribute__((noinline))
   1566 static int pthread_cond_destroy_WRK(pthread_cond_t* cond)
   1567 {
   1568    int ret;
   1569    unsigned long cond_is_init;
   1570    OrigFn fn;
   1571 
   1572    VALGRIND_GET_ORIG_FN(fn);
   1573 
   1574    if (TRACE_PTH_FNS) {
   1575       fprintf(stderr, "<< pthread_cond_destroy %p", cond);
   1576       fflush(stderr);
   1577    }
   1578 
   1579    if (cond != NULL) {
   1580       const pthread_cond_t cond_init = PTHREAD_COND_INITIALIZER;
   1581       cond_is_init = my_memcmp(cond, &cond_init, sizeof(*cond)) == 0;
   1582    } else {
   1583      cond_is_init = 0;
   1584    }
   1585 
   1586    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_DESTROY_PRE,
   1587                 pthread_cond_t*, cond, unsigned long, cond_is_init);
   1588 
   1589    CALL_FN_W_W(ret, fn, cond);
   1590 
   1591    if (ret != 0) {
   1592       DO_PthAPIerror( "pthread_cond_destroy", ret );
   1593    }
   1594 
   1595    if (TRACE_PTH_FNS) {
   1596       fprintf(stderr, " codestr -> %d >>\n", ret);
   1597    }
   1598 
   1599    return ret;
   1600 }
   1601 #if defined(VGO_linux)
   1602    PTH_FUNC(int, pthreadZucondZudestroyZAZa, // pthread_cond_destroy@*
   1603                  pthread_cond_t* cond) {
   1604       return pthread_cond_destroy_WRK(cond);
   1605    }
   1606 #elif defined(VGO_darwin)
   1607    PTH_FUNC(int, pthreadZucondZudestroy, // pthread_cond_destroy
   1608                  pthread_cond_t* cond) {
   1609       return pthread_cond_destroy_WRK(cond);
   1610    }
   1611 #elif defined(VGO_solaris)
   1612    PTH_FUNC(int, condZudestroy, // cond_destroy
   1613                  pthread_cond_t *cond) {
   1614       return pthread_cond_destroy_WRK(cond);
   1615    }
   1616 #else
   1617 #  error "Unsupported OS"
   1618 #endif
   1619 
   1620 
   1621 /*----------------------------------------------------------------*/
   1622 /*--- pthread_barrier_t functions                              ---*/
   1623 /*----------------------------------------------------------------*/
   1624 
   1625 #if defined(HAVE_PTHREAD_BARRIER_INIT)
   1626 
   1627 /* Handled:   pthread_barrier_init
   1628               pthread_barrier_wait
   1629               pthread_barrier_destroy
   1630 
   1631    Unhandled: pthread_barrierattr_destroy
   1632               pthread_barrierattr_getpshared
   1633               pthread_barrierattr_init
   1634               pthread_barrierattr_setpshared
   1635               -- are these important?
   1636 */
   1637 
   1638 //-----------------------------------------------------------
   1639 // glibc:   pthread_barrier_init
   1640 // darwin:  (doesn't appear to exist)
   1641 // Solaris: pthread_barrier_init
   1642 PTH_FUNC(int, pthreadZubarrierZuinit, // pthread_barrier_init
   1643          pthread_barrier_t* bar,
   1644          pthread_barrierattr_t* attr, unsigned long count)
   1645 {
   1646    int ret;
   1647    OrigFn fn;
   1648    VALGRIND_GET_ORIG_FN(fn);
   1649 
   1650    if (TRACE_PTH_FNS) {
   1651       fprintf(stderr, "<< pthread_barrier_init %p %p %lu",
   1652                       bar, attr, count);
   1653       fflush(stderr);
   1654    }
   1655 
   1656    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE,
   1657                  pthread_barrier_t*, bar,
   1658                  unsigned long, count,
   1659                  unsigned long, 0/*!resizable*/);
   1660 
   1661    CALL_FN_W_WWW(ret, fn, bar,attr,count);
   1662 
   1663    if (ret != 0) {
   1664       DO_PthAPIerror( "pthread_barrier_init", ret );
   1665    }
   1666 
   1667    if (TRACE_PTH_FNS) {
   1668       fprintf(stderr, "  pthread_barrier_init -> %d >>\n", ret);
   1669    }
   1670 
   1671    return ret;
   1672 }
   1673 
   1674 
   1675 //-----------------------------------------------------------
   1676 // glibc:   pthread_barrier_wait
   1677 // darwin:  (doesn't appear to exist)
   1678 // Solaris: pthread_barrier_wait
   1679 PTH_FUNC(int, pthreadZubarrierZuwait, // pthread_barrier_wait
   1680               pthread_barrier_t* bar)
   1681 {
   1682    int ret;
   1683    OrigFn fn;
   1684    VALGRIND_GET_ORIG_FN(fn);
   1685 
   1686    if (TRACE_PTH_FNS) {
   1687       fprintf(stderr, "<< pthread_barrier_wait %p", bar);
   1688       fflush(stderr);
   1689    }
   1690 
   1691    /* That this works correctly, and doesn't screw up when a thread
   1692       leaving the barrier races round to the front and re-enters while
   1693       other threads are still leaving it, is quite subtle.  See
   1694       comments in the handler for PTHREAD_BARRIER_WAIT_PRE in
   1695       hg_main.c. */
   1696    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE,
   1697                pthread_barrier_t*,bar);
   1698 
   1699    CALL_FN_W_W(ret, fn, bar);
   1700 
   1701    if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) {
   1702       DO_PthAPIerror( "pthread_barrier_wait", ret );
   1703    }
   1704 
   1705    if (TRACE_PTH_FNS) {
   1706       fprintf(stderr, "  pthread_barrier_wait -> %d >>\n", ret);
   1707    }
   1708 
   1709    return ret;
   1710 }
   1711 
   1712 
   1713 //-----------------------------------------------------------
   1714 // glibc:   pthread_barrier_destroy
   1715 // darwin:  (doesn't appear to exist)
   1716 // Solaris: pthread_barrier_destroy
   1717 PTH_FUNC(int, pthreadZubarrierZudestroy, // pthread_barrier_destroy
   1718          pthread_barrier_t* bar)
   1719 {
   1720    int ret;
   1721    OrigFn fn;
   1722    VALGRIND_GET_ORIG_FN(fn);
   1723 
   1724    if (TRACE_PTH_FNS) {
   1725       fprintf(stderr, "<< pthread_barrier_destroy %p", bar);
   1726       fflush(stderr);
   1727    }
   1728 
   1729    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE,
   1730                pthread_barrier_t*,bar);
   1731 
   1732    CALL_FN_W_W(ret, fn, bar);
   1733 
   1734    if (ret != 0) {
   1735       DO_PthAPIerror( "pthread_barrier_destroy", ret );
   1736    }
   1737 
   1738    if (TRACE_PTH_FNS) {
   1739       fprintf(stderr, "  pthread_barrier_destroy -> %d >>\n", ret);
   1740    }
   1741 
   1742    return ret;
   1743 }
   1744 
   1745 #endif   // defined(HAVE_PTHREAD_BARRIER_INIT)
   1746 
   1747 
   1748 /*----------------------------------------------------------------*/
   1749 /*--- pthread_spinlock_t functions                             ---*/
   1750 /*----------------------------------------------------------------*/
   1751 
   1752 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
   1753     && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
   1754 
   1755 /* Handled:   pthread_spin_init pthread_spin_destroy
   1756               pthread_spin_lock pthread_spin_trylock
   1757               pthread_spin_unlock
   1758 
   1759    Unhandled:
   1760 */
   1761 
   1762 /* This is a nasty kludge, in that glibc "knows" that initialising a
   1763    spin lock unlocks it, and pthread_spin_{init,unlock} are names for
   1764    the same function.  Hence we have to have a wrapper which does both
   1765    things, without knowing which the user intended to happen.
   1766    Solaris has distinct functions for init/unlock but client requests
   1767    are immutable in helgrind.h so follow the glibc lead. */
   1768 
   1769 //-----------------------------------------------------------
   1770 // glibc:   pthread_spin_init
   1771 // glibc:   pthread_spin_unlock
   1772 // darwin:  (doesn't appear to exist)
   1773 // Solaris: pthread_spin_init
   1774 // Solaris: pthread_spin_unlock
   1775 __attribute__((noinline))
   1776 static int pthread_spin_init_or_unlock_WRK(pthread_spinlock_t* lock,
   1777                                            int pshared) {
   1778    int    ret;
   1779    OrigFn fn;
   1780    VALGRIND_GET_ORIG_FN(fn);
   1781    if (TRACE_PTH_FNS) {
   1782       fprintf(stderr, "<< pthread_spin_iORu %p", lock); fflush(stderr);
   1783    }
   1784 
   1785    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE,
   1786                pthread_spinlock_t*, lock);
   1787 
   1788    CALL_FN_W_WW(ret, fn, lock,pshared);
   1789 
   1790    if (ret == 0 /*success*/) {
   1791       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST,
   1792                   pthread_spinlock_t*,lock);
   1793    } else {
   1794       DO_PthAPIerror( "pthread_spinlock_{init,unlock}", ret );
   1795    }
   1796 
   1797    if (TRACE_PTH_FNS) {
   1798       fprintf(stderr, " :: spiniORu -> %d >>\n", ret);
   1799    }
   1800    return ret;
   1801 }
   1802 #if defined(VGO_linux)
   1803    PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
   1804             pthread_spinlock_t* lock, int pshared) {
   1805       return pthread_spin_init_or_unlock_WRK(lock, pshared);
   1806    }
   1807    PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
   1808             pthread_spinlock_t* lock) {
   1809       /* this is never actually called */
   1810       return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/);
   1811    }
   1812 #elif defined(VGO_darwin)
   1813 #elif defined(VGO_solaris)
   1814    PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
   1815             pthread_spinlock_t *lock, int pshared) {
   1816       return pthread_spin_init_or_unlock_WRK(lock, pshared);
   1817    }
   1818    PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
   1819             pthread_spinlock_t *lock) {
   1820       return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/);
   1821    }
   1822 #else
   1823 #  error "Unsupported OS"
   1824 #endif
   1825 
   1826 
   1827 //-----------------------------------------------------------
   1828 // glibc:   pthread_spin_destroy
   1829 // darwin:  (doesn't appear to exist)
   1830 // Solaris: pthread_spin_destroy
   1831 __attribute__((noinline))
   1832 static int pthread_spin_destroy_WRK(pthread_spinlock_t *lock)
   1833 {
   1834    int    ret;
   1835    OrigFn fn;
   1836    VALGRIND_GET_ORIG_FN(fn);
   1837    if (TRACE_PTH_FNS) {
   1838       fprintf(stderr, "<< pthread_spin_destroy %p", lock);
   1839       fflush(stderr);
   1840    }
   1841 
   1842    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_DESTROY_PRE,
   1843                pthread_spinlock_t*,lock);
   1844 
   1845    CALL_FN_W_W(ret, fn, lock);
   1846 
   1847    if (ret != 0) {
   1848       DO_PthAPIerror( "pthread_spin_destroy", ret );
   1849    }
   1850 
   1851    if (TRACE_PTH_FNS) {
   1852       fprintf(stderr, " :: spindestroy -> %d >>\n", ret);
   1853    }
   1854    return ret;
   1855 }
   1856 #if defined(VGO_linux)
   1857    PTH_FUNC(int, pthreadZuspinZusdestroy, // pthread_spin_destroy
   1858             pthread_spinlock_t *lock) {
   1859       return pthread_spin_destroy_WRK(lock);
   1860    }
   1861 #elif defined(VGO_darwin)
   1862 #elif defined(VGO_solaris)
   1863    PTH_FUNC(int, pthreadZuspinZusdestroy, // pthread_spin_destroy
   1864             pthread_spinlock_t *lock) {
   1865       return pthread_spin_destroy_WRK(lock);
   1866    }
   1867 #else
   1868 #  error "Unsupported OS"
   1869 #endif
   1870 
   1871 
   1872 //-----------------------------------------------------------
   1873 // glibc:   pthread_spin_lock
   1874 // darwin:  (doesn't appear to exist)
   1875 // Solaris: pthread_spin_lock
   1876 __attribute__((noinline))
   1877 static int pthread_spin_lock_WRK(pthread_spinlock_t *lock)
   1878 {
   1879    int    ret;
   1880    OrigFn fn;
   1881    VALGRIND_GET_ORIG_FN(fn);
   1882    if (TRACE_PTH_FNS) {
   1883       fprintf(stderr, "<< pthread_spinlock %p", lock);
   1884       fflush(stderr);
   1885    }
   1886 
   1887    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE,
   1888                 pthread_spinlock_t*,lock, long,0/*!isTryLock*/);
   1889 
   1890    CALL_FN_W_W(ret, fn, lock);
   1891 
   1892    /* There's a hole here: libpthread now knows the lock is locked,
   1893       but the tool doesn't, so some other thread could run and detect
   1894       that the lock has been acquired by someone (this thread).  Does
   1895       this matter?  Not sure, but I don't think so. */
   1896 
   1897    if (ret == 0 /*success*/) {
   1898       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST,
   1899                   pthread_spinlock_t*,lock);
   1900    } else {
   1901       DO_PthAPIerror( "pthread_spin_lock", ret );
   1902    }
   1903 
   1904    if (TRACE_PTH_FNS) {
   1905       fprintf(stderr, " :: spinlock -> %d >>\n", ret);
   1906    }
   1907    return ret;
   1908 }
   1909 #if defined(VGO_linux)
   1910    PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
   1911                  pthread_spinlock_t *lock) {
   1912       return pthread_spin_lock_WRK(lock);
   1913    }
   1914 #elif defined(VGO_darwin)
   1915 #elif defined(VGO_solaris)
   1916    PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
   1917                  pthread_spinlock_t *lock) {
   1918       return pthread_spin_lock_WRK(lock);
   1919    }
   1920 #else
   1921 #  error "Unsupported OS"
   1922 #endif
   1923 
   1924 
   1925 //-----------------------------------------------------------
   1926 // glibc:   pthread_spin_trylock
   1927 // darwin:  (doesn't appear to exist)
   1928 // Solaris: pthread_spin_trylock
   1929 __attribute__((noinline))
   1930 static int pthread_spin_trylock_WRK(pthread_spinlock_t *lock)
   1931 {
   1932    int    ret;
   1933    OrigFn fn;
   1934    VALGRIND_GET_ORIG_FN(fn);
   1935    if (TRACE_PTH_FNS) {
   1936       fprintf(stderr, "<< pthread_spin_trylock %p", lock);
   1937       fflush(stderr);
   1938    }
   1939 
   1940    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE,
   1941                 pthread_spinlock_t*,lock, long,1/*isTryLock*/);
   1942 
   1943    CALL_FN_W_W(ret, fn, lock);
   1944 
   1945    /* There's a hole here: libpthread now knows the lock is locked,
   1946       but the tool doesn't, so some other thread could run and detect
   1947       that the lock has been acquired by someone (this thread).  Does
   1948       this matter?  Not sure, but I don't think so. */
   1949 
   1950    if (ret == 0 /*success*/) {
   1951       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST,
   1952                   pthread_spinlock_t*,lock);
   1953    } else {
   1954       if (ret != EBUSY)
   1955          DO_PthAPIerror( "pthread_spin_trylock", ret );
   1956    }
   1957 
   1958    if (TRACE_PTH_FNS) {
   1959       fprintf(stderr, " :: spin_trylock -> %d >>\n", ret);
   1960    }
   1961    return ret;
   1962 }
   1963 #if defined(VGO_linux)
   1964    PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
   1965                  pthread_spinlock_t *lock) {
   1966       return pthread_spin_trylock_WRK(lock);
   1967    }
   1968 #elif defined(VGO_darwin)
   1969 #elif defined(VGO_solaris)
   1970    PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
   1971                  pthread_spinlock_t *lock) {
   1972       return pthread_spin_trylock_WRK(lock);
   1973    }
   1974 #else
   1975 #  error "Unsupported OS"
   1976 #endif
   1977 
   1978 #endif // defined(HAVE_PTHREAD_SPIN_LOCK)
   1979 
   1980 
   1981 /*----------------------------------------------------------------*/
   1982 /*--- pthread_rwlock_t functions                               ---*/
   1983 /*----------------------------------------------------------------*/
   1984 
   1985 /* Android's pthread.h doesn't say anything about rwlocks, hence these
   1986    functions have to be conditionally compiled. */
   1987 #if defined(HAVE_PTHREAD_RWLOCK_T)
   1988 
   1989 /* Handled:   pthread_rwlock_init pthread_rwlock_destroy
   1990               pthread_rwlock_rdlock
   1991               pthread_rwlock_wrlock
   1992               pthread_rwlock_unlock
   1993               pthread_rwlock_tryrdlock
   1994               pthread_rwlock_trywrlock
   1995 
   1996    Unhandled: pthread_rwlock_timedrdlock
   1997               pthread_rwlock_timedwrlock
   1998 */
   1999 
   2000 //-----------------------------------------------------------
   2001 // glibc:   pthread_rwlock_init
   2002 // darwin:  pthread_rwlock_init
   2003 // darwin:  pthread_rwlock_init$UNIX2003
   2004 // Solaris: rwlock_init (pthread_rwlock_init is built atop of rwlock_init)
   2005 __attribute__((noinline))
   2006 static int pthread_rwlock_init_WRK(pthread_rwlock_t *rwl,
   2007                                    pthread_rwlockattr_t* attr)
   2008 {
   2009    int    ret;
   2010    OrigFn fn;
   2011    VALGRIND_GET_ORIG_FN(fn);
   2012    if (TRACE_PTH_FNS) {
   2013       fprintf(stderr, "<< pthread_rwl_init %p", rwl); fflush(stderr);
   2014    }
   2015 
   2016    CALL_FN_W_WW(ret, fn, rwl,attr);
   2017 
   2018    if (ret == 0 /*success*/) {
   2019       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
   2020                   pthread_rwlock_t*,rwl);
   2021    } else {
   2022       DO_PthAPIerror( "pthread_rwlock_init", ret );
   2023    }
   2024 
   2025    if (TRACE_PTH_FNS) {
   2026       fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
   2027    }
   2028    return ret;
   2029 }
   2030 #if defined(VGO_linux)
   2031    PTH_FUNC(int, pthreadZurwlockZuinit, // pthread_rwlock_init
   2032                  pthread_rwlock_t *rwl,
   2033                  pthread_rwlockattr_t* attr) {
   2034       return pthread_rwlock_init_WRK(rwl, attr);
   2035    }
   2036 #elif defined(VGO_darwin)
   2037    PTH_FUNC(int, pthreadZurwlockZuinitZa, // pthread_rwlock_init*
   2038                  pthread_rwlock_t *rwl,
   2039                  pthread_rwlockattr_t* attr) {
   2040       return pthread_rwlock_init_WRK(rwl, attr);
   2041    }
   2042 #elif defined(VGO_solaris)
   2043 static int pthread_rwlock_init_WRK(pthread_rwlock_t *rwl,
   2044                                    pthread_rwlockattr_t* attr)
   2045                                    __attribute__((unused));
   2046 #else
   2047 #  error "Unsupported OS"
   2048 #endif
   2049 
   2050 #if defined(VGO_solaris)
   2051 PTH_FUNC(int, rwlockZuinit, // rwlock_init
   2052               rwlock_t *rwlock,
   2053               int type,
   2054               void *arg)
   2055 {
   2056    int    ret;
   2057    OrigFn fn;
   2058    VALGRIND_GET_ORIG_FN(fn);
   2059    if (TRACE_PTH_FNS) {
   2060       fprintf(stderr, "<< rwl_init %p", rwlock); fflush(stderr);
   2061    }
   2062 
   2063    CALL_FN_W_WWW(ret, fn, rwlock, type, arg);
   2064 
   2065    if (ret == 0 /*success*/) {
   2066       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
   2067                   rwlock_t *, rwlock);
   2068    } else {
   2069       DO_PthAPIerror("rwlock_init", ret);
   2070    }
   2071 
   2072    if (TRACE_PTH_FNS) {
   2073       fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
   2074    }
   2075    return ret;
   2076 }
   2077 #endif /* VGO_solaris */
   2078 
   2079 
   2080 //-----------------------------------------------------------
   2081 // glibc:   pthread_rwlock_destroy
   2082 // darwin:  pthread_rwlock_destroy
   2083 // darwin:  pthread_rwlock_destroy$UNIX2003
   2084 // Solaris: rwlock_destroy (pthread_rwlock_destroy is a weak alias)
   2085 //
   2086 __attribute__((noinline))
   2087 static int pthread_rwlock_destroy_WRK(pthread_rwlock_t* rwl)
   2088 {
   2089    int    ret;
   2090    OrigFn fn;
   2091    VALGRIND_GET_ORIG_FN(fn);
   2092    if (TRACE_PTH_FNS) {
   2093       fprintf(stderr, "<< pthread_rwl_destroy %p", rwl); fflush(stderr);
   2094    }
   2095 
   2096    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE,
   2097                pthread_rwlock_t*,rwl);
   2098 
   2099    CALL_FN_W_W(ret, fn, rwl);
   2100 
   2101    if (ret != 0) {
   2102       DO_PthAPIerror( "pthread_rwlock_destroy", ret );
   2103    }
   2104 
   2105    if (TRACE_PTH_FNS) {
   2106       fprintf(stderr, " :: rwl_destroy -> %d >>\n", ret);
   2107    }
   2108    return ret;
   2109 }
   2110 #if defined(VGO_linux)
   2111    PTH_FUNC(int, pthreadZurwlockZudestroy, // pthread_rwlock_destroy
   2112                  pthread_rwlock_t *rwl) {
   2113       return pthread_rwlock_destroy_WRK(rwl);
   2114    }
   2115 #elif defined(VGO_darwin)
   2116    PTH_FUNC(int, pthreadZurwlockZudestroyZa, // pthread_rwlock_destroy*
   2117                  pthread_rwlock_t *rwl) {
   2118       return pthread_rwlock_destroy_WRK(rwl);
   2119    }
   2120 #elif defined(VGO_solaris)
   2121    PTH_FUNC(int, rwlockZudestroy, // rwlock_destroy
   2122                  pthread_rwlock_t *rwl) {
   2123       return pthread_rwlock_destroy_WRK(rwl);
   2124    }
   2125 #else
   2126 #  error "Unsupported OS"
   2127 #endif
   2128 
   2129 
   2130 //-----------------------------------------------------------
   2131 // glibc:   pthread_rwlock_wrlock
   2132 // darwin:  pthread_rwlock_wrlock
   2133 // darwin:  pthread_rwlock_wrlock$UNIX2003
   2134 // Solaris: rw_wrlock (pthread_rwlock_wrlock is a weak alias)
   2135 //
   2136 __attribute__((noinline))
   2137 static int pthread_rwlock_wrlock_WRK(pthread_rwlock_t* rwlock)
   2138 {
   2139    int    ret;
   2140    OrigFn fn;
   2141    VALGRIND_GET_ORIG_FN(fn);
   2142    if (TRACE_PTH_FNS) {
   2143       fprintf(stderr, "<< pthread_rwl_wlk %p", rwlock); fflush(stderr);
   2144    }
   2145 
   2146    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
   2147                  pthread_rwlock_t*,rwlock,
   2148                  long,1/*isW*/, long,0/*!isTryLock*/);
   2149 
   2150    CALL_FN_W_W(ret, fn, rwlock);
   2151 
   2152    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
   2153                  pthread_rwlock_t*,rwlock, long,1/*isW*/,
   2154                  long, (ret == 0) ? True : False);
   2155    if (ret != 0) {
   2156       DO_PthAPIerror( "pthread_rwlock_wrlock", ret );
   2157    }
   2158 
   2159    if (TRACE_PTH_FNS) {
   2160       fprintf(stderr, " :: rwl_wlk -> %d >>\n", ret);
   2161    }
   2162    return ret;
   2163 }
   2164 #if defined(VGO_linux)
   2165    PTH_FUNC(int, pthreadZurwlockZuwrlock, // pthread_rwlock_wrlock
   2166                  pthread_rwlock_t* rwlock) {
   2167       return pthread_rwlock_wrlock_WRK(rwlock);
   2168    }
   2169 #elif defined(VGO_darwin)
   2170    PTH_FUNC(int, pthreadZurwlockZuwrlockZa, // pthread_rwlock_wrlock*
   2171                  pthread_rwlock_t* rwlock) {
   2172       return pthread_rwlock_wrlock_WRK(rwlock);
   2173    }
   2174 #elif defined(VGO_solaris)
   2175    PTH_FUNC(int, rwZuwrlock, // rw_wrlock
   2176                  pthread_rwlock_t *rwlock) {
   2177       return pthread_rwlock_wrlock_WRK(rwlock);
   2178    }
   2179 #else
   2180 #  error "Unsupported OS"
   2181 #endif
   2182 
   2183 #if defined(VGO_solaris)
   2184 /* Internal to libc. */
   2185 PTH_FUNC(void, lrwZuwrlock, // lrw_wrlock
   2186                rwlock_t *rwlock)
   2187 {
   2188    OrigFn fn;
   2189    VALGRIND_GET_ORIG_FN(fn);
   2190    if (TRACE_PTH_FNS) {
   2191       fprintf(stderr, "<< lrw_wlk %p", rwlock); fflush(stderr);
   2192    }
   2193 
   2194    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
   2195                  pthread_rwlock_t *, rwlock,
   2196                  long, 1/*isW*/, long, 0/*!isTryLock*/);
   2197 
   2198    CALL_FN_v_W(fn, rwlock);
   2199 
   2200    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
   2201                  pthread_rwlock_t *, rwlock, long, 1/*isW*/, long, True);
   2202 
   2203    if (TRACE_PTH_FNS) {
   2204       fprintf(stderr, " :: lrw_wlk >>\n");
   2205    }
   2206 }
   2207 #endif /* VGO_solaris */
   2208 
   2209 
   2210 //-----------------------------------------------------------
   2211 // glibc:   pthread_rwlock_rdlock
   2212 // darwin:  pthread_rwlock_rdlock
   2213 // darwin:  pthread_rwlock_rdlock$UNIX2003
   2214 // Solaris: rw_rdlock (pthread_rwlock_rdlock is a weak alias)
   2215 //
   2216 __attribute__((noinline))
   2217 static int pthread_rwlock_rdlock_WRK(pthread_rwlock_t* rwlock)
   2218 {
   2219    int    ret;
   2220    OrigFn fn;
   2221    VALGRIND_GET_ORIG_FN(fn);
   2222    if (TRACE_PTH_FNS) {
   2223       fprintf(stderr, "<< pthread_rwl_rlk %p", rwlock); fflush(stderr);
   2224    }
   2225 
   2226    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
   2227                  pthread_rwlock_t*,rwlock,
   2228                  long,0/*!isW*/, long,0/*!isTryLock*/);
   2229 
   2230    CALL_FN_W_W(ret, fn, rwlock);
   2231 
   2232    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
   2233                  pthread_rwlock_t*,rwlock, long,0/*!isW*/,
   2234                  long, (ret == 0) ? True : False);
   2235    if (ret != 0) {
   2236       DO_PthAPIerror( "pthread_rwlock_rdlock", ret );
   2237    }
   2238 
   2239    if (TRACE_PTH_FNS) {
   2240       fprintf(stderr, " :: rwl_rlk -> %d >>\n", ret);
   2241    }
   2242    return ret;
   2243 }
   2244 #if defined(VGO_linux)
   2245    PTH_FUNC(int, pthreadZurwlockZurdlock, // pthread_rwlock_rdlock
   2246                  pthread_rwlock_t* rwlock) {
   2247       return pthread_rwlock_rdlock_WRK(rwlock);
   2248    }
   2249 #elif defined(VGO_darwin)
   2250    PTH_FUNC(int, pthreadZurwlockZurdlockZa, // pthread_rwlock_rdlock*
   2251                  pthread_rwlock_t* rwlock) {
   2252       return pthread_rwlock_rdlock_WRK(rwlock);
   2253    }
   2254 #elif defined(VGO_solaris)
   2255    PTH_FUNC(int, rwZurdlock, // rw_rdlock
   2256                  pthread_rwlock_t *rwlock) {
   2257       return pthread_rwlock_rdlock_WRK(rwlock);
   2258    }
   2259 #else
   2260 #  error "Unsupported OS"
   2261 #endif
   2262 
   2263 #if defined(VGO_solaris)
   2264 /* Internal to libc. */
   2265 PTH_FUNC(void, lrwZurdlock, // lrw_rdlock
   2266                rwlock_t *rwlock)
   2267 {
   2268    OrigFn fn;
   2269    VALGRIND_GET_ORIG_FN(fn);
   2270    if (TRACE_PTH_FNS) {
   2271       fprintf(stderr, "<< lrw_rlk %p", rwlock); fflush(stderr);
   2272    }
   2273 
   2274    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
   2275                  pthread_rwlock_t *, rwlock,
   2276                  long, 0/*!isW*/, long, 0/*!isTryLock*/);
   2277 
   2278    CALL_FN_v_W(fn, rwlock);
   2279 
   2280    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
   2281                  pthread_rwlock_t *, rwlock, long, 0/*!isW*/, long, True);
   2282 
   2283    if (TRACE_PTH_FNS) {
   2284       fprintf(stderr, " :: lrw_rlk ->>\n");
   2285    }
   2286 }
   2287 #endif /* VGO_solaris */
   2288 
   2289 
   2290 //-----------------------------------------------------------
   2291 // glibc:   pthread_rwlock_trywrlock
   2292 // darwin:  pthread_rwlock_trywrlock
   2293 // darwin:  pthread_rwlock_trywrlock$UNIX2003
   2294 // Solaris: rw_trywrlock (pthread_rwlock_trywrlock is a weak alias)
   2295 //
   2296 __attribute__((noinline))
   2297 static int pthread_rwlock_trywrlock_WRK(pthread_rwlock_t* rwlock)
   2298 {
   2299    int    ret;
   2300    OrigFn fn;
   2301    VALGRIND_GET_ORIG_FN(fn);
   2302    if (TRACE_PTH_FNS) {
   2303       fprintf(stderr, "<< pthread_rwl_trywlk %p", rwlock); fflush(stderr);
   2304    }
   2305 
   2306    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
   2307                  pthread_rwlock_t*,rwlock,
   2308                  long,1/*isW*/, long,1/*isTryLock*/);
   2309 
   2310    CALL_FN_W_W(ret, fn, rwlock);
   2311 
   2312    /* There's a hole here: libpthread now knows the lock is locked,
   2313       but the tool doesn't, so some other thread could run and detect
   2314       that the lock has been acquired by someone (this thread).  Does
   2315       this matter?  Not sure, but I don't think so. */
   2316 
   2317    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
   2318                  pthread_rwlock_t*,rwlock, long,1/*isW*/,
   2319                  long, (ret == 0) ? True : False);
   2320    if (ret != 0) {
   2321       if (ret != EBUSY)
   2322          DO_PthAPIerror( "pthread_rwlock_trywrlock", ret );
   2323    }
   2324 
   2325    if (TRACE_PTH_FNS) {
   2326       fprintf(stderr, " :: rwl_trywlk -> %d >>\n", ret);
   2327    }
   2328    return ret;
   2329 }
   2330 #if defined(VGO_linux)
   2331    PTH_FUNC(int, pthreadZurwlockZutrywrlock, // pthread_rwlock_trywrlock
   2332                  pthread_rwlock_t* rwlock) {
   2333       return pthread_rwlock_trywrlock_WRK(rwlock);
   2334    }
   2335 #elif defined(VGO_darwin)
   2336    PTH_FUNC(int, pthreadZurwlockZutrywrlockZa, // pthread_rwlock_trywrlock*
   2337                  pthread_rwlock_t* rwlock) {
   2338       return pthread_rwlock_trywrlock_WRK(rwlock);
   2339    }
   2340 #elif defined(VGO_solaris)
   2341    PTH_FUNC(int, rwZutrywrlock, // rw_trywrlock
   2342                  pthread_rwlock_t *rwlock) {
   2343       return pthread_rwlock_trywrlock_WRK(rwlock);
   2344    }
   2345 #else
   2346 #  error "Unsupported OS"
   2347 #endif
   2348 
   2349 
   2350 //-----------------------------------------------------------
   2351 // glibc:   pthread_rwlock_tryrdlock
   2352 // darwin:  pthread_rwlock_tryrdlock
   2353 // darwin:  pthread_rwlock_tryrdlock$UNIX2003
   2354 // Solaris: rw_tryrdlock (pthread_rwlock_tryrdlock is a weak alias)
   2355 //
   2356 __attribute__((noinline))
   2357 static int pthread_rwlock_tryrdlock_WRK(pthread_rwlock_t* rwlock)
   2358 {
   2359    int    ret;
   2360    OrigFn fn;
   2361    VALGRIND_GET_ORIG_FN(fn);
   2362    if (TRACE_PTH_FNS) {
   2363       fprintf(stderr, "<< pthread_rwl_tryrlk %p", rwlock); fflush(stderr);
   2364    }
   2365 
   2366    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
   2367                  pthread_rwlock_t*,rwlock,
   2368                  long,0/*!isW*/, long,1/*isTryLock*/);
   2369 
   2370    CALL_FN_W_W(ret, fn, rwlock);
   2371 
   2372    /* There's a hole here: libpthread now knows the lock is locked,
   2373       but the tool doesn't, so some other thread could run and detect
   2374       that the lock has been acquired by someone (this thread).  Does
   2375       this matter?  Not sure, but I don't think so. */
   2376 
   2377    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
   2378                 pthread_rwlock_t*,rwlock, long,0/*!isW*/,
   2379                 long, (ret == 0) ? True : False);
   2380 
   2381    if (ret != 0) {
   2382       if (ret != EBUSY)
   2383          DO_PthAPIerror( "pthread_rwlock_tryrdlock", ret );
   2384    }
   2385 
   2386    if (TRACE_PTH_FNS) {
   2387       fprintf(stderr, " :: rwl_tryrlk -> %d >>\n", ret);
   2388    }
   2389    return ret;
   2390 }
   2391 #if defined(VGO_linux)
   2392    PTH_FUNC(int, pthreadZurwlockZutryrdlock, // pthread_rwlock_tryrdlock
   2393                  pthread_rwlock_t* rwlock) {
   2394       return pthread_rwlock_tryrdlock_WRK(rwlock);
   2395    }
   2396 #elif defined(VGO_darwin)
   2397    PTH_FUNC(int, pthreadZurwlockZutryrdlockZa, // pthread_rwlock_tryrdlock*
   2398                  pthread_rwlock_t* rwlock) {
   2399       return pthread_rwlock_tryrdlock_WRK(rwlock);
   2400    }
   2401 #elif defined(VGO_solaris)
   2402    PTH_FUNC(int, rwZutryrdlock, // rw_tryrdlock
   2403                  pthread_rwlock_t *rwlock) {
   2404       return pthread_rwlock_tryrdlock_WRK(rwlock);
   2405    }
   2406 #else
   2407 #  error "Unsupported OS"
   2408 #endif
   2409 
   2410 
   2411 //-----------------------------------------------------------
   2412 // glibc:   Unhandled
   2413 // darwin:  Unhandled
   2414 // Solaris: pthread_rwlock_timedrdlock
   2415 // Solaris: pthread_rwlock_reltimedrdlock_np
   2416 //
   2417 __attribute__((noinline)) __attribute__((unused))
   2418 static int pthread_rwlock_timedrdlock_WRK(pthread_rwlock_t *rwlock,
   2419                                           const struct timespec *timeout)
   2420 {
   2421    int    ret;
   2422    OrigFn fn;
   2423    VALGRIND_GET_ORIG_FN(fn);
   2424    if (TRACE_PTH_FNS) {
   2425       fprintf(stderr, "<< pthread_rwl_timedrdl %p", rwlock); fflush(stderr);
   2426    }
   2427 
   2428    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
   2429                  pthread_rwlock_t *, rwlock,
   2430                  long, 0/*isW*/, long, 0/*isTryLock*/);
   2431 
   2432    CALL_FN_W_WW(ret, fn, rwlock, timeout);
   2433 
   2434    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
   2435                  pthread_rwlock_t *, rwlock, long, 0/*isW*/,
   2436                  long, (ret == 0) ? True : False);
   2437    if (ret != 0) {
   2438       DO_PthAPIerror("pthread_rwlock_timedrdlock", ret);
   2439    }
   2440 
   2441    if (TRACE_PTH_FNS) {
   2442       fprintf(stderr, " :: rwl_timedrdl -> %d >>\n", ret);
   2443    }
   2444    return ret;
   2445 }
   2446 #if defined(VGO_linux)
   2447 #elif defined(VGO_darwin)
   2448 #elif defined(VGO_solaris)
   2449    PTH_FUNC(int, pthreadZurwlockZutimedrdlock, // pthread_rwlock_timedrdlock
   2450                  pthread_rwlock_t *rwlock,
   2451                  const struct timespec *timeout) {
   2452       return pthread_rwlock_timedrdlock_WRK(rwlock, timeout);
   2453    }
   2454    PTH_FUNC(int, pthreadZurwlockZureltimedrdlockZunp, // pthread_rwlock_timedrdlock_np
   2455                  pthread_rwlock_t *rwlock,
   2456                  const struct timespec *timeout) {
   2457       return pthread_rwlock_timedrdlock_WRK(rwlock, timeout);
   2458    }
   2459 #else
   2460 #  error "Unsupported OS"
   2461 #endif
   2462 
   2463 
   2464 //-----------------------------------------------------------
   2465 // glibc:   Unhandled
   2466 // darwin:  Unhandled
   2467 // Solaris: pthread_rwlock_timedwrlock
   2468 // Solaris: pthread_rwlock_reltimedwrlock_np
   2469 //
   2470 __attribute__((noinline)) __attribute__((unused))
   2471 static int pthread_rwlock_timedwrlock_WRK(pthread_rwlock_t *rwlock,
   2472                                           const struct timespec *timeout)
   2473 {
   2474    int    ret;
   2475    OrigFn fn;
   2476    VALGRIND_GET_ORIG_FN(fn);
   2477    if (TRACE_PTH_FNS) {
   2478       fprintf(stderr, "<< pthread_rwl_timedwrl %p", rwlock); fflush(stderr);
   2479    }
   2480 
   2481    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
   2482                  pthread_rwlock_t *, rwlock,
   2483                  long, 1/*isW*/, long, 0/*isTryLock*/);
   2484 
   2485    CALL_FN_W_WW(ret, fn, rwlock, timeout);
   2486 
   2487    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
   2488                  pthread_rwlock_t *, rwlock, long, 1/*isW*/,
   2489                  long, (ret == 0) ? True : False);
   2490    if (ret != 0) {
   2491       DO_PthAPIerror("pthread_rwlock_timedwrlock", ret);
   2492    }
   2493 
   2494    if (TRACE_PTH_FNS) {
   2495       fprintf(stderr, " :: rwl_timedwrl -> %d >>\n", ret);
   2496    }
   2497    return ret;
   2498 }
   2499 #if defined(VGO_linux)
   2500 #elif defined(VGO_darwin)
   2501 #elif defined(VGO_solaris)
   2502    PTH_FUNC(int, pthreadZurwlockZutimedwrlock, // pthread_rwlock_timedwrlock
   2503                  pthread_rwlock_t *rwlock,
   2504                  const struct timespec *timeout) {
   2505       return pthread_rwlock_timedwrlock_WRK(rwlock, timeout);
   2506    }
   2507    PTH_FUNC(int, pthreadZurwlockZureltimedwrlockZunp, // pthread_rwlock_timedwrlock_np
   2508                  pthread_rwlock_t *rwlock,
   2509                  const struct timespec *timeout) {
   2510       return pthread_rwlock_timedwrlock_WRK(rwlock, timeout);
   2511    }
   2512 #else
   2513 #  error "Unsupported OS"
   2514 #endif
   2515 
   2516 
   2517 //-----------------------------------------------------------
   2518 // glibc:   pthread_rwlock_unlock
   2519 // darwin:  pthread_rwlock_unlock
   2520 // darwin:  pthread_rwlock_unlock$UNIX2003
   2521 // Solaris: rw_unlock (pthread_rwlock_unlock is a weak alias)
   2522 __attribute__((noinline))
   2523 static int pthread_rwlock_unlock_WRK(pthread_rwlock_t* rwlock)
   2524 {
   2525    int    ret;
   2526    OrigFn fn;
   2527    VALGRIND_GET_ORIG_FN(fn);
   2528    if (TRACE_PTH_FNS) {
   2529       fprintf(stderr, "<< pthread_rwl_unlk %p", rwlock); fflush(stderr);
   2530    }
   2531 
   2532    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
   2533                pthread_rwlock_t*,rwlock);
   2534 
   2535    CALL_FN_W_W(ret, fn, rwlock);
   2536 
   2537    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
   2538                pthread_rwlock_t*,rwlock);
   2539    if (ret != 0) {
   2540       DO_PthAPIerror( "pthread_rwlock_unlock", ret );
   2541    }
   2542 
   2543    if (TRACE_PTH_FNS) {
   2544       fprintf(stderr, " :: rwl_unlk -> %d >>\n", ret);
   2545    }
   2546    return ret;
   2547 }
   2548 #if defined(VGO_linux)
   2549    PTH_FUNC(int, pthreadZurwlockZuunlock, // pthread_rwlock_unlock
   2550                  pthread_rwlock_t* rwlock) {
   2551       return pthread_rwlock_unlock_WRK(rwlock);
   2552    }
   2553 #elif defined(VGO_darwin)
   2554    PTH_FUNC(int, pthreadZurwlockZuunlockZa, // pthread_rwlock_unlock*
   2555                  pthread_rwlock_t* rwlock) {
   2556       return pthread_rwlock_unlock_WRK(rwlock);
   2557    }
   2558 #elif defined(VGO_solaris)
   2559    PTH_FUNC(int, rwZuunlock, // rw_unlock
   2560                  pthread_rwlock_t *rwlock) {
   2561       return pthread_rwlock_unlock_WRK(rwlock);
   2562    }
   2563 #else
   2564 #  error "Unsupported OS"
   2565 #endif
   2566 
   2567 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
   2568 
   2569 
   2570 /*----------------------------------------------------------------*/
   2571 /*--- POSIX semaphores                                         ---*/
   2572 /*----------------------------------------------------------------*/
   2573 
   2574 #include <semaphore.h>
   2575 #include <fcntl.h>       /* O_CREAT */
   2576 
   2577 #define TRACE_SEM_FNS 0
   2578 
   2579 /* Handled:
   2580      int sem_init(sem_t *sem, int pshared, unsigned value);
   2581      int sem_destroy(sem_t *sem);
   2582      int sem_wait(sem_t *sem);
   2583      int sem_post(sem_t *sem);
   2584      sem_t* sem_open(const char *name, int oflag,
   2585                      ... [mode_t mode, unsigned value]);
   2586         [complete with its idiotic semantics]
   2587      int sem_close(sem_t* sem);
   2588 
   2589    Unhandled:
   2590      int sem_trywait(sem_t *sem);
   2591      int sem_timedwait(sem_t *restrict sem,
   2592                        const struct timespec *restrict abs_timeout);
   2593 */
   2594 
   2595 //-----------------------------------------------------------
   2596 // glibc:   sem_init@@GLIBC_2.2.5
   2597 // glibc:   sem_init@@GLIBC_2.1
   2598 // glibc:   sem_init (at) GLIBC_2.0
   2599 // darwin:  sem_init
   2600 // Solaris: sema_init (sem_init is built on top of sem_init)
   2601 //
   2602 #if !defined(VGO_solaris)
   2603 __attribute__((noinline))
   2604 static int sem_init_WRK(sem_t* sem, int pshared, unsigned long value)
   2605 {
   2606    OrigFn fn;
   2607    int    ret;
   2608    VALGRIND_GET_ORIG_FN(fn);
   2609 
   2610    if (TRACE_SEM_FNS) {
   2611       fprintf(stderr, "<< sem_init(%p,%d,%lu) ", sem,pshared,value);
   2612       fflush(stderr);
   2613    }
   2614 
   2615    CALL_FN_W_WWW(ret, fn, sem,pshared,value);
   2616 
   2617    if (ret == 0) {
   2618       DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
   2619                    sem_t*, sem, unsigned long, value);
   2620    } else {
   2621       DO_PthAPIerror( "sem_init", errno );
   2622    }
   2623 
   2624    if (TRACE_SEM_FNS) {
   2625       fprintf(stderr, " sem_init -> %d >>\n", ret);
   2626       fflush(stderr);
   2627    }
   2628 
   2629    return ret;
   2630 }
   2631 #if defined(VGO_linux)
   2632    PTH_FUNC(int, semZuinitZAZa, // sem_init@*
   2633                  sem_t* sem, int pshared, unsigned long value) {
   2634       return sem_init_WRK(sem, pshared, value);
   2635    }
   2636 #elif defined(VGO_darwin)
   2637    PTH_FUNC(int, semZuinit, // sem_init
   2638                  sem_t* sem, int pshared, unsigned long value) {
   2639       return sem_init_WRK(sem, pshared, value);
   2640    }
   2641 #else
   2642 #  error "Unsupported OS"
   2643 #endif
   2644 
   2645 #else /* VGO_solaris */
   2646 PTH_FUNC(int, semaZuinit, // sema_init
   2647               sema_t *sem,
   2648               unsigned int value,
   2649               int type,
   2650               void *arg)
   2651 {
   2652    OrigFn fn;
   2653    int    ret;
   2654    VALGRIND_GET_ORIG_FN(fn);
   2655 
   2656    if (TRACE_SEM_FNS) {
   2657       fprintf(stderr, "<< sema_init(%p, %d, %u) ", sem, type, value);
   2658       fflush(stderr);
   2659    }
   2660 
   2661    CALL_FN_W_WWWW(ret, fn, sem, value, type, arg);
   2662 
   2663    if (ret == 0) {
   2664       DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
   2665                    sema_t *, sem, Word, value);
   2666    } else {
   2667       DO_PthAPIerror("sema_init", ret);
   2668    }
   2669 
   2670    if (TRACE_SEM_FNS) {
   2671       fprintf(stderr, " sema_init -> %d >>\n", ret);
   2672       fflush(stderr);
   2673    }
   2674 
   2675    return ret;
   2676 }
   2677 #endif /* VGO_solaris */
   2678 
   2679 
   2680 //-----------------------------------------------------------
   2681 // glibc:   sem_destroy (at) GLIBC_2.0
   2682 // glibc:   sem_destroy@@GLIBC_2.1
   2683 // glibc:   sem_destroy@@GLIBC_2.2.5
   2684 // darwin:  sem_destroy
   2685 // Solaris: sema_destroy (sem_destroy is built on top of sema_destroy)
   2686 __attribute__((noinline))
   2687 static int sem_destroy_WRK(sem_t* sem)
   2688 {
   2689    OrigFn fn;
   2690    int    ret;
   2691    VALGRIND_GET_ORIG_FN(fn);
   2692 
   2693    if (TRACE_SEM_FNS) {
   2694       fprintf(stderr, "<< sem_destroy(%p) ", sem);
   2695       fflush(stderr);
   2696    }
   2697 
   2698    DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
   2699 
   2700    CALL_FN_W_W(ret, fn, sem);
   2701 
   2702    if (ret != 0) {
   2703       DO_PthAPIerror( "sem_destroy", SEM_ERROR );
   2704    }
   2705 
   2706    if (TRACE_SEM_FNS) {
   2707       fprintf(stderr, " sem_destroy -> %d >>\n", ret);
   2708       fflush(stderr);
   2709    }
   2710 
   2711    return ret;
   2712 }
   2713 #if defined(VGO_linux)
   2714    PTH_FUNC(int, semZudestroyZAZa,  // sem_destroy*
   2715                  sem_t* sem) {
   2716       return sem_destroy_WRK(sem);
   2717    }
   2718 #elif defined(VGO_darwin)
   2719    PTH_FUNC(int, semZudestroy,  // sem_destroy
   2720                  sem_t* sem) {
   2721       return sem_destroy_WRK(sem);
   2722    }
   2723 #elif defined(VGO_solaris)
   2724    PTH_FUNC(int, semaZudestroy,  // sema_destroy
   2725                  sem_t *sem) {
   2726       return sem_destroy_WRK(sem);
   2727    }
   2728 #else
   2729 #  error "Unsupported OS"
   2730 #endif
   2731 
   2732 
   2733 //-----------------------------------------------------------
   2734 // glibc:   sem_wait
   2735 // glibc:   sem_wait (at) GLIBC_2.0
   2736 // glibc:   sem_wait@@GLIBC_2.1
   2737 // darwin:  sem_wait
   2738 // darwin:  sem_wait$NOCANCEL$UNIX2003
   2739 // darwin:  sem_wait$UNIX2003
   2740 // Solaris: sema_wait (sem_wait is built on top of sema_wait)
   2741 //
   2742 /* wait: decrement semaphore - acquire lockage */
   2743 __attribute__((noinline))
   2744 static int sem_wait_WRK(sem_t* sem)
   2745 {
   2746    OrigFn fn;
   2747    int    ret;
   2748    VALGRIND_GET_ORIG_FN(fn);
   2749 
   2750    if (TRACE_SEM_FNS) {
   2751       fprintf(stderr, "<< sem_wait(%p) ", sem);
   2752       fflush(stderr);
   2753    }
   2754 
   2755    DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_PRE, sem_t*,sem);
   2756 
   2757    CALL_FN_W_W(ret, fn, sem);
   2758 
   2759    DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST, sem_t*,sem,
   2760                 long, (ret == 0) ? True : False);
   2761 
   2762    if (ret != 0) {
   2763       DO_PthAPIerror( "sem_wait", SEM_ERROR );
   2764    }
   2765 
   2766    if (TRACE_SEM_FNS) {
   2767       fprintf(stderr, " sem_wait -> %d >>\n", ret);
   2768       fflush(stderr);
   2769    }
   2770 
   2771    return ret;
   2772 }
   2773 #if defined(VGO_linux)
   2774    PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
   2775       return sem_wait_WRK(sem);
   2776    }
   2777    PTH_FUNC(int, semZuwaitZAZa, sem_t* sem) { /* sem_wait@* */
   2778       return sem_wait_WRK(sem);
   2779    }
   2780 #elif defined(VGO_darwin)
   2781    PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
   2782       return sem_wait_WRK(sem);
   2783    }
   2784    PTH_FUNC(int, semZuwaitZDZa, sem_t* sem) { /* sem_wait$* */
   2785       return sem_wait_WRK(sem);
   2786    }
   2787 #elif defined(VGO_solaris)
   2788    PTH_FUNC(int, semaZuwait, sem_t *sem) { /* sema_wait */
   2789       return sem_wait_WRK(sem);
   2790    }
   2791 #else
   2792 #  error "Unsupported OS"
   2793 #endif
   2794 
   2795 
   2796 //-----------------------------------------------------------
   2797 // glibc:   sem_post
   2798 // glibc:   sem_post (at) GLIBC_2.0
   2799 // glibc:   sem_post@@GLIBC_2.1
   2800 // darwin:  sem_post
   2801 // Solaris: sema_post (sem_post is built on top of sema_post)
   2802 //
   2803 /* post: increment semaphore - release lockage */
   2804 __attribute__((noinline))
   2805 static int sem_post_WRK(sem_t* sem)
   2806 {
   2807    OrigFn fn;
   2808    int    ret;
   2809 
   2810    VALGRIND_GET_ORIG_FN(fn);
   2811 
   2812    if (TRACE_SEM_FNS) {
   2813       fprintf(stderr, "<< sem_post(%p) ", sem);
   2814       fflush(stderr);
   2815    }
   2816 
   2817    DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_PRE, sem_t*,sem);
   2818 
   2819    CALL_FN_W_W(ret, fn, sem);
   2820 
   2821    DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_POST, sem_t*,sem);
   2822 
   2823    if (ret != 0) {
   2824       DO_PthAPIerror( "sem_post", SEM_ERROR );
   2825    }
   2826 
   2827    if (TRACE_SEM_FNS) {
   2828       fprintf(stderr, " sem_post -> %d >>\n", ret);
   2829       fflush(stderr);
   2830    }
   2831 
   2832    return ret;
   2833 }
   2834 #if defined(VGO_linux)
   2835    PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
   2836       return sem_post_WRK(sem);
   2837    }
   2838    PTH_FUNC(int, semZupostZAZa, sem_t* sem) { /* sem_post@* */
   2839       return sem_post_WRK(sem);
   2840    }
   2841 #elif defined(VGO_darwin)
   2842    PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
   2843       return sem_post_WRK(sem);
   2844    }
   2845 #elif defined(VGO_solaris)
   2846    PTH_FUNC(int, semaZupost, sem_t *sem) { /* sema_post */
   2847       return sem_post_WRK(sem);
   2848    }
   2849 #else
   2850 #  error "Unsupported OS"
   2851 #endif
   2852 
   2853 
   2854 //-----------------------------------------------------------
   2855 // glibc:   sem_open
   2856 // darwin:  sem_open
   2857 // Solaris: sem_open
   2858 //
   2859 PTH_FUNC(sem_t*, semZuopen,
   2860                  const char* name, long oflag,
   2861                  long mode, unsigned long value)
   2862 {
   2863    /* A copy of sem_init_WRK (more or less).  Is this correct? */
   2864    OrigFn fn;
   2865    sem_t* ret;
   2866    VALGRIND_GET_ORIG_FN(fn);
   2867 
   2868    if (TRACE_SEM_FNS) {
   2869       fprintf(stderr, "<< sem_open(\"%s\",%ld,%lx,%lu) ",
   2870                       name,oflag,mode,value);
   2871       fflush(stderr);
   2872    }
   2873 
   2874    CALL_FN_W_WWWW(ret, fn, name,oflag,mode,value);
   2875 
   2876    if (ret != SEM_FAILED && (oflag & O_CREAT)) {
   2877       DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
   2878                    sem_t*, ret, unsigned long, value);
   2879    }
   2880    if (ret == SEM_FAILED) {
   2881       DO_PthAPIerror( "sem_open", errno );
   2882    }
   2883 
   2884    if (TRACE_SEM_FNS) {
   2885       fprintf(stderr, " sem_open -> %p >>\n", ret);
   2886       fflush(stderr);
   2887    }
   2888 
   2889    return ret;
   2890 }
   2891 
   2892 
   2893 //-----------------------------------------------------------
   2894 // glibc:   sem_close
   2895 // darwin:  sem_close
   2896 // Solaris: sem_close
   2897 PTH_FUNC(int, sem_close, sem_t* sem)
   2898 {
   2899    OrigFn fn;
   2900    int    ret;
   2901    VALGRIND_GET_ORIG_FN(fn);
   2902 
   2903    if (TRACE_SEM_FNS) {
   2904       fprintf(stderr, "<< sem_close(%p) ", sem);
   2905       fflush(stderr);
   2906    }
   2907 
   2908    DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
   2909 
   2910    CALL_FN_W_W(ret, fn, sem);
   2911 
   2912    if (ret != 0) {
   2913       DO_PthAPIerror( "sem_close", errno );
   2914    }
   2915 
   2916    if (TRACE_SEM_FNS) {
   2917       fprintf(stderr, " close -> %d >>\n", ret);
   2918       fflush(stderr);
   2919    }
   2920 
   2921    return ret;
   2922 }
   2923 
   2924 
   2925 /*----------------------------------------------------------------*/
   2926 /*--- Qt 4 threading functions (w/ GNU name mangling)          ---*/
   2927 /*----------------------------------------------------------------*/
   2928 
   2929 /* Handled:
   2930       QMutex::lock()
   2931       QMutex::unlock()
   2932       QMutex::tryLock()
   2933       QMutex::tryLock(int)
   2934 
   2935       QMutex::QMutex(QMutex::RecursionMode)  _ZN6QMutexC1ENS_13RecursionModeE
   2936       QMutex::QMutex(QMutex::RecursionMode)  _ZN6QMutexC2ENS_13RecursionModeE
   2937       QMutex::~QMutex()                      _ZN6QMutexD1Ev
   2938       QMutex::~QMutex()                      _ZN6QMutexD2Ev
   2939 
   2940    Unhandled:
   2941       QReadWriteLock::lockForRead()
   2942       QReadWriteLock::lockForWrite()
   2943       QReadWriteLock::unlock()
   2944       QReadWriteLock::tryLockForRead(int)
   2945       QReadWriteLock::tryLockForRead()
   2946       QReadWriteLock::tryLockForWrite(int)
   2947       QReadWriteLock::tryLockForWrite()
   2948 
   2949       QWaitCondition::wait(QMutex*, unsigned long)
   2950       QWaitCondition::wakeAll()
   2951       QWaitCondition::wakeOne()
   2952 
   2953       QSemaphore::*
   2954 */
   2955 /* More comments, 19 Nov 08, based on assessment of qt-4.5.0TP1,
   2956    at least on Unix:
   2957 
   2958    It's apparently only necessary to intercept QMutex, since that is
   2959    not implemented using pthread_mutex_t; instead Qt4 has its own
   2960    implementation based on atomics (to check the non-contended case)
   2961    and pthread_cond_wait (to wait in the contended case).
   2962 
   2963    QReadWriteLock is built on top of QMutex, counters, and a wait
   2964    queue.  So we don't need to handle it specially once QMutex
   2965    handling is correct -- presumably the dependencies through QMutex
   2966    are sufficient to avoid any false race reports.  On the other hand,
   2967    it is an open question whether too many dependencies are observed
   2968    -- in which case we may miss races (false negatives).  I suspect
   2969    this is likely to be the case, unfortunately.
   2970 
   2971    QWaitCondition is built on pthread_cond_t, pthread_mutex_t, QMutex
   2972    and QReadWriteLock.  Same compositional-correctness justificiation
   2973    and limitations as fro QReadWriteLock.
   2974 
   2975    Ditto QSemaphore (from cursory examination).
   2976 
   2977    Does it matter that only QMutex is handled directly?  Open
   2978    question.  From testing with drd/tests/qt4_* and with KDE4 apps, it
   2979    appears that no false errors are reported; however it is not clear
   2980    if this is causing false negatives.
   2981 
   2982    Another problem with Qt4 is thread exiting.  Threads are created
   2983    with pthread_create (fine); but they detach and simply exit when
   2984    done.  There is no use of pthread_join, and the provided
   2985    wait-for-a-thread-to-exit mechanism (QThread::wait, I believe)
   2986    relies on a system of mutexes and flags.  I suspect this also
   2987    causes too many dependencies to appear.  Consequently H sometimes
   2988    fails to detect races at exit in some very short-lived racy
   2989    programs, because it appears that a thread can exit _and_ have an
   2990    observed dependency edge back to the main thread (presumably)
   2991    before the main thread reaps the child (that is, calls
   2992    QThread::wait).
   2993 
   2994    This theory is supported by the observation that if all threads are
   2995    made to wait at a pthread_barrier_t immediately before they exit,
   2996    then H's detection of races in such programs becomes reliable;
   2997    without the barrier, it is varies from run to run, depending
   2998    (according to investigation) on whether aforementioned
   2999    exit-before-reaping behaviour happens or not.
   3000 
   3001    Finally, why is it necessary to intercept the QMutex constructors
   3002    and destructors?  The constructors are intercepted only as a matter
   3003    of convenience, so H can print accurate "first observed at"
   3004    clauses.  However, it is actually necessary to intercept the
   3005    destructors (as it is with pthread_mutex_destroy) in order that
   3006    locks get removed from LAOG when they are destroyed.
   3007 */
   3008 
   3009 // soname is libQtCore.so.4 ; match against libQtCore.so*
   3010 #define QT4_FUNC(ret_ty, f, args...) \
   3011    ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args); \
   3012    ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args)
   3013 
   3014 // soname is libQt5Core.so.4 ; match against libQt5Core.so*
   3015 #define QT5_FUNC(ret_ty, f, args...) \
   3016    ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args); \
   3017    ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args)
   3018 
   3019 //-----------------------------------------------------------
   3020 // QMutex::lock()
   3021 __attribute__((noinline))
   3022 static void QMutex_lock_WRK(void* self)
   3023 {
   3024    OrigFn fn;
   3025    VALGRIND_GET_ORIG_FN(fn);
   3026    if (TRACE_QT4_FNS) {
   3027       fprintf(stderr, "<< QMutex::lock %p", self); fflush(stderr);
   3028    }
   3029 
   3030    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
   3031                 void*,self, long,0/*!isTryLock*/);
   3032 
   3033    CALL_FN_v_W(fn, self);
   3034 
   3035    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
   3036                 void *, self, long, True);
   3037 
   3038    if (TRACE_QT4_FNS) {
   3039       fprintf(stderr, " :: Q::lock done >>\n");
   3040    }
   3041 }
   3042 
   3043 QT4_FUNC(void, _ZN6QMutex4lockEv, void* self) {
   3044     QMutex_lock_WRK(self);
   3045 }
   3046 QT5_FUNC(void, _ZN6QMutex4lockEv, void* self) {
   3047     QMutex_lock_WRK(self);
   3048 }
   3049 
   3050 //-----------------------------------------------------------
   3051 // QMutex::unlock()
   3052 __attribute__((noinline))
   3053 static void QMutex_unlock_WRK(void* self)
   3054 {
   3055    OrigFn fn;
   3056    VALGRIND_GET_ORIG_FN(fn);
   3057 
   3058    if (TRACE_QT4_FNS) {
   3059       fprintf(stderr, "<< QMutex::unlock %p", self); fflush(stderr);
   3060    }
   3061 
   3062    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
   3063                void*, self);
   3064 
   3065    CALL_FN_v_W(fn, self);
   3066 
   3067    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
   3068                void*, self);
   3069 
   3070    if (TRACE_QT4_FNS) {
   3071       fprintf(stderr, " Q::unlock done >>\n");
   3072    }
   3073 }
   3074 
   3075 QT4_FUNC(void, _ZN6QMutex6unlockEv, void* self) {
   3076     QMutex_unlock_WRK(self);
   3077 }
   3078 QT5_FUNC(void, _ZN6QMutex6unlockEv, void* self) {
   3079     QMutex_unlock_WRK(self);
   3080 }
   3081 
   3082 //-----------------------------------------------------------
   3083 // bool QMutex::tryLock()
   3084 // using 'long' to mimic C++ 'bool'
   3085 __attribute__((noinline))
   3086 static long QMutex_tryLock_WRK(void* self)
   3087 {
   3088    OrigFn fn;
   3089    long   ret;
   3090    VALGRIND_GET_ORIG_FN(fn);
   3091    if (TRACE_QT4_FNS) {
   3092       fprintf(stderr, "<< QMutex::tryLock %p", self); fflush(stderr);
   3093    }
   3094 
   3095    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
   3096                 void*,self, long,1/*isTryLock*/);
   3097 
   3098    CALL_FN_W_W(ret, fn, self);
   3099 
   3100    // assumes that only the low 8 bits of the 'bool' are significant
   3101    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
   3102                 void *, self, long, (ret & 0xFF) ? True : False);
   3103 
   3104    if (TRACE_QT4_FNS) {
   3105       fprintf(stderr, " :: Q::tryLock -> %lu >>\n", ret);
   3106    }
   3107 
   3108    return ret;
   3109 }
   3110 
   3111 QT4_FUNC(long, _ZN6QMutex7tryLockEv, void* self) {
   3112     return QMutex_tryLock_WRK(self);
   3113 }
   3114 QT5_FUNC(long, _ZN6QMutex7tryLockEv, void* self) {
   3115     return QMutex_tryLock_WRK(self);
   3116 }
   3117 
   3118 //-----------------------------------------------------------
   3119 // bool QMutex::tryLock(int)
   3120 // using 'long' to mimic C++ 'bool'
   3121 __attribute__((noinline))
   3122 static long QMutex_tryLock_int_WRK(void* self, long arg2)
   3123 {
   3124    OrigFn fn;
   3125    long   ret;
   3126    VALGRIND_GET_ORIG_FN(fn);
   3127    if (TRACE_QT4_FNS) {
   3128       fprintf(stderr, "<< QMutex::tryLock(int) %p %d", self, (int)arg2);
   3129       fflush(stderr);
   3130    }
   3131 
   3132    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
   3133                 void*,self, long,1/*isTryLock*/);
   3134 
   3135    CALL_FN_W_WW(ret, fn, self,arg2);
   3136 
   3137    // assumes that only the low 8 bits of the 'bool' are significant
   3138    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
   3139                void *, self, long, (ret & 0xFF) ? True : False);
   3140 
   3141    if (TRACE_QT4_FNS) {
   3142       fprintf(stderr, " :: Q::tryLock(int) -> %lu >>\n", ret);
   3143    }
   3144 
   3145    return ret;
   3146 }
   3147 
   3148 QT4_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2) {
   3149     return QMutex_tryLock_int_WRK(self, arg2);
   3150 }
   3151 QT5_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2) {
   3152     return QMutex_tryLock_int_WRK(self, arg2);
   3153 }
   3154 
   3155 //-----------------------------------------------------------
   3156 // It's not really very clear what the args are here.  But from
   3157 // a bit of dataflow analysis of the generated machine code of
   3158 // the original function, it appears this takes two args, and
   3159 // returns nothing.  Nevertheless preserve return value just in
   3160 // case.  A bit of debug printing indicates that the first arg
   3161 // is that of the mutex and the second is either zero or one,
   3162 // probably being the recursion mode, therefore.
   3163 // QMutex::QMutex(QMutex::RecursionMode)  ("C1ENS" variant)
   3164 __attribute__((noinline))
   3165 static void* QMutex_constructor_WRK(void* mutex, long recmode)
   3166 {
   3167    OrigFn fn;
   3168    long   ret;
   3169    VALGRIND_GET_ORIG_FN(fn);
   3170    CALL_FN_W_WW(ret, fn, mutex, recmode);
   3171    //   fprintf(stderr, "QMutex constructor 1: %p <- %p %p\n", ret, arg1, arg2);
   3172    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
   3173                 void*,mutex, long,1/*mbRec*/);
   3174    return (void*)ret;
   3175 }
   3176 
   3177 QT4_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE, void* self, long recmode) {
   3178     return QMutex_constructor_WRK(self, recmode);
   3179 }
   3180 QT5_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE, void* self, long recmode) {
   3181     return QMutex_constructor_WRK(self, recmode);
   3182 }
   3183 
   3184 //-----------------------------------------------------------
   3185 // QMutex::~QMutex()  ("D1Ev" variant)
   3186 __attribute__((noinline))
   3187 static void* QMutex_destructor_WRK(void* mutex)
   3188 {
   3189    OrigFn fn;
   3190    long   ret;
   3191    VALGRIND_GET_ORIG_FN(fn);
   3192    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
   3193                void*,mutex);
   3194    CALL_FN_W_W(ret, fn, mutex);
   3195    return (void*)ret;
   3196 }
   3197 
   3198 QT4_FUNC(void*, _ZN6QMutexD1Ev, void* self) {
   3199     return QMutex_destructor_WRK(self);
   3200 }
   3201 QT5_FUNC(void*, _ZN6QMutexD1Ev, void* self) {
   3202     return QMutex_destructor_WRK(self);
   3203 }
   3204 
   3205 //-----------------------------------------------------------
   3206 // QMutex::QMutex(QMutex::RecursionMode)  ("C2ENS" variant)
   3207 QT4_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE,
   3208          void* mutex,
   3209          long  recmode)
   3210 {
   3211    assert(0);
   3212    /*NOTREACHED*/
   3213    /* Android's gcc behaves like it doesn't know that assert(0)
   3214       never returns.  Hence: */
   3215    return NULL;
   3216 }
   3217 
   3218 QT5_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE, void* self, long recmode)
   3219 {
   3220    assert(0);
   3221    /*NOTREACHED*/
   3222    return NULL;
   3223 }
   3224 
   3225 //-----------------------------------------------------------
   3226 // QMutex::~QMutex()  ("D2Ev" variant)
   3227 QT4_FUNC(void*, _ZN6QMutexD2Ev, void* mutex)
   3228 {
   3229    assert(0);
   3230    /* Android's gcc behaves like it doesn't know that assert(0)
   3231       never returns.  Hence: */
   3232    return NULL;
   3233 }
   3234 
   3235 QT5_FUNC(void*, _ZN6QMutexD2Ev, void* self)
   3236 {
   3237    assert(0);
   3238    /*NOTREACHED*/
   3239    return NULL;
   3240 }
   3241 
   3242 // QReadWriteLock is not intercepted directly.  See comments
   3243 // above.
   3244 
   3245 //// QReadWriteLock::lockForRead()
   3246 //// _ZN14QReadWriteLock11lockForReadEv == QReadWriteLock::lockForRead()
   3247 //QT4_FUNC(void, ZuZZN14QReadWriteLock11lockForReadEv,
   3248 //               // _ZN14QReadWriteLock11lockForReadEv
   3249 //               void* self)
   3250 //{
   3251 //   OrigFn fn;
   3252 //   VALGRIND_GET_ORIG_FN(fn);
   3253 //   if (TRACE_QT4_FNS) {
   3254 //      fprintf(stderr, "<< QReadWriteLock::lockForRead %p", self);
   3255 //      fflush(stderr);
   3256 //   }
   3257 //
   3258 //   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
   3259 //                 void*,self,
   3260 //                 long,0/*!isW*/, long,0/*!isTryLock*/);
   3261 //
   3262 //   CALL_FN_v_W(fn, self);
   3263 //
   3264 //   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
   3265 //                 void*,self, long,0/*!isW*/, long, True);
   3266 //
   3267 //   if (TRACE_QT4_FNS) {
   3268 //      fprintf(stderr, " :: Q::lockForRead :: done >>\n");
   3269 //   }
   3270 //}
   3271 //
   3272 //// QReadWriteLock::lockForWrite()
   3273 //// _ZN14QReadWriteLock12lockForWriteEv == QReadWriteLock::lockForWrite()
   3274 //QT4_FUNC(void, ZuZZN14QReadWriteLock12lockForWriteEv,
   3275 //               // _ZN14QReadWriteLock12lockForWriteEv
   3276 //               void* self)
   3277 //{
   3278 //   OrigFn fn;
   3279 //   VALGRIND_GET_ORIG_FN(fn);
   3280 //   if (TRACE_QT4_FNS) {
   3281 //      fprintf(stderr, "<< QReadWriteLock::lockForWrite %p", self);
   3282 //      fflush(stderr);
   3283 //   }
   3284 //
   3285 //   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
   3286 //                 void*,self,
   3287 //                 long,1/*isW*/, long,0/*!isTryLock*/);
   3288 //
   3289 //   CALL_FN_v_W(fn, self);
   3290 //
   3291 //   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
   3292 //                 void*,self, long,1/*isW*/, long, True);
   3293 //
   3294 //   if (TRACE_QT4_FNS) {
   3295 //      fprintf(stderr, " :: Q::lockForWrite :: done >>\n");
   3296 //   }
   3297 //}
   3298 //
   3299 //// QReadWriteLock::unlock()
   3300 //// _ZN14QReadWriteLock6unlockEv == QReadWriteLock::unlock()
   3301 //QT4_FUNC(void, ZuZZN14QReadWriteLock6unlockEv,
   3302 //               // _ZN14QReadWriteLock6unlockEv
   3303 //               void* self)
   3304 //{
   3305 //   OrigFn fn;
   3306 //   VALGRIND_GET_ORIG_FN(fn);
   3307 //   if (TRACE_QT4_FNS) {
   3308 //      fprintf(stderr, "<< QReadWriteLock::unlock %p", self);
   3309 //      fflush(stderr);
   3310 //   }
   3311 //
   3312 //   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
   3313 //               void*,self);
   3314 //
   3315 //   CALL_FN_v_W(fn, self);
   3316 //
   3317 //   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
   3318 //               void*,self);
   3319 //
   3320 //   if (TRACE_QT4_FNS) {
   3321 //      fprintf(stderr, " :: Q::unlock :: done >>\n");
   3322 //   }
   3323 //}
   3324 
   3325 
   3326 /*----------------------------------------------------------------*/
   3327 /*--- Replacements for basic string functions, that don't      ---*/
   3328 /*--- overrun the input arrays.                                ---*/
   3329 /*----------------------------------------------------------------*/
   3330 
   3331 #include "../shared/vg_replace_strmem.c"
   3332 
   3333 /*--------------------------------------------------------------------*/
   3334 /*--- end                                          hg_intercepts.c ---*/
   3335 /*--------------------------------------------------------------------*/
   3336