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-2017 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 //   procedure Master_Hook
    677 //     (Dependent    : Task_Id;
    678 //      Parent       : Task_Id;
    679 //      Master_Level : Integer);
    680 // where    type Task_Id is access all Ada_Task_Control_Block;
    681 // System.Tasking.Debug.Master_Hook is called by a task Dependent to
    682 // indicate that its master is identified by master+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 void I_WRAP_SONAME_FNNAME_ZU
    688    (Za,
    689     system__tasking__debug__master_hook)
    690      (void *dependent, void *master, int master_level)
    691 {
    692    OrigFn fn;
    693    VALGRIND_GET_ORIG_FN(fn);
    694    if (TRACE_GNAT_FNS) {
    695      fprintf(stderr, "<< GNAT master_hook wrapper "
    696              "dependent %p master %p master_level %d\n",
    697              dependent, master, master_level); fflush(stderr);
    698    }
    699 
    700    // We call the wrapped function, even if it is a null body.
    701    CALL_FN_v_WWW(fn, dependent, master, master_level);
    702 
    703    DO_CREQ_v_WWW(_VG_USERREQ__HG_GNAT_MASTER_HOOK,
    704                  void*,dependent, void*,master,
    705                  Word, (Word)master_level);
    706 
    707    if (TRACE_GNAT_FNS) {
    708       fprintf(stderr, " :: GNAT master_hook >>\n");
    709    }
    710 }
    711 
    712 // System.Tasking.Debug.Master_Completed_Hook is called by a task to
    713 // indicate that it has completed a master.
    714 //  procedure Master_Completed_Hook
    715 //     (Self_ID      : Task_Id;
    716 //      Master_Level : Integer);
    717 // where    type Task_Id is access all Ada_Task_Control_Block;
    718 // This indicates that all its Dependent tasks (that identified themselves
    719 // with the Master_Hook call) are terminated. Helgrind can consider
    720 // at this point that the equivalent of a 'pthread_join' has been done
    721 // between self_id and all dependent tasks at master_level.
    722 void I_WRAP_SONAME_FNNAME_ZU
    723    (Za,
    724     system__tasking__debug__master_completed_hook)
    725      (void *self_id, int master_level);
    726 void I_WRAP_SONAME_FNNAME_ZU
    727    (Za,
    728     system__tasking__debug__master_completed_hook)
    729      (void *self_id, int master_level)
    730 {
    731    OrigFn fn;
    732    VALGRIND_GET_ORIG_FN(fn);
    733    if (TRACE_GNAT_FNS) {
    734      fprintf(stderr, "<< GNAT master_completed_hook wrapper "
    735              "self_id %p master_level %d\n",
    736              self_id, master_level); fflush(stderr);
    737    }
    738 
    739    // We call the wrapped function, even if it is a null body.
    740    CALL_FN_v_WW(fn, self_id, master_level);
    741 
    742    DO_CREQ_v_WW(_VG_USERREQ__HG_GNAT_MASTER_COMPLETED_HOOK,
    743                  void*,self_id, Word,(Word)master_level);
    744 
    745    if (TRACE_GNAT_FNS) {
    746       fprintf(stderr, " :: GNAT master_completed_hook >>\n");
    747    }
    748 }
    749 
    750 /*----------------------------------------------------------------*/
    751 /*--- pthread_mutex_t functions                                ---*/
    752 /*----------------------------------------------------------------*/
    753 
    754 /* Handled:   pthread_mutex_init pthread_mutex_destroy
    755               pthread_mutex_lock
    756               pthread_mutex_trylock pthread_mutex_timedlock
    757               pthread_mutex_unlock
    758 */
    759 
    760 //-----------------------------------------------------------
    761 #if !defined(VGO_solaris)
    762 // glibc:  pthread_mutex_init
    763 // darwin: pthread_mutex_init
    764 PTH_FUNC(int, pthreadZumutexZuinit, // pthread_mutex_init
    765               pthread_mutex_t *mutex,
    766               pthread_mutexattr_t* attr)
    767 {
    768    int    ret;
    769    long   mbRec;
    770    OrigFn fn;
    771    VALGRIND_GET_ORIG_FN(fn);
    772    if (TRACE_PTH_FNS) {
    773       fprintf(stderr, "<< pthread_mxinit %p", mutex); fflush(stderr);
    774    }
    775 
    776    mbRec = 0;
    777    if (attr) {
    778       int ty, zzz;
    779       zzz = pthread_mutexattr_gettype(attr, &ty);
    780       if (zzz == 0 && ty == PTHREAD_MUTEX_RECURSIVE)
    781          mbRec = 1;
    782    }
    783 
    784    CALL_FN_W_WW(ret, fn, mutex,attr);
    785 
    786    if (ret == 0 /*success*/) {
    787       DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
    788                    pthread_mutex_t*,mutex, long,mbRec);
    789    } else {
    790       DO_PthAPIerror( "pthread_mutex_init", ret );
    791    }
    792 
    793    if (TRACE_PTH_FNS) {
    794       fprintf(stderr, " :: mxinit -> %d >>\n", ret);
    795    }
    796    return ret;
    797 }
    798 
    799 #else /* VGO_solaris */
    800 
    801 // Solaris: mutex_init (pthread_mutex_init calls here)
    802 PTH_FUNC(int, mutexZuinit, // mutex_init
    803               mutex_t *mutex, int type, void *arg)
    804 {
    805    int    ret;
    806    long   mbRec;
    807    OrigFn fn;
    808    VALGRIND_GET_ORIG_FN(fn);
    809    if (TRACE_PTH_FNS) {
    810       fprintf(stderr, "<< mxinit %p", mutex); fflush(stderr);
    811    }
    812 
    813    mbRec = ((type & LOCK_RECURSIVE) != 0) ? 1 : 0;
    814 
    815    CALL_FN_W_WWW(ret, fn, mutex, type, arg);
    816 
    817    if (ret == 0 /*success*/) {
    818       DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
    819                    mutex_t *, mutex, long, mbRec);
    820    } else {
    821       DO_PthAPIerror("mutex_init", ret);
    822    }
    823 
    824    if (TRACE_PTH_FNS) {
    825       fprintf(stderr, " :: mxinit -> %d >>\n", ret);
    826    }
    827    return ret;
    828 }
    829 #endif /* VGO_solaris */
    830 
    831 
    832 //-----------------------------------------------------------
    833 // glibc:   pthread_mutex_destroy
    834 // darwin:  pthread_mutex_destroy
    835 // Solaris: mutex_destroy (pthread_mutex_destroy is a weak alias)
    836 __attribute__((noinline))
    837 static int mutex_destroy_WRK(pthread_mutex_t *mutex)
    838 {
    839    int    ret;
    840    unsigned long mutex_is_init;
    841    OrigFn fn;
    842 
    843    VALGRIND_GET_ORIG_FN(fn);
    844    if (TRACE_PTH_FNS) {
    845       fprintf(stderr, "<< pthread_mxdestroy %p", mutex); fflush(stderr);
    846    }
    847 
    848    if (mutex != NULL) {
    849       static const pthread_mutex_t mutex_init = PTHREAD_MUTEX_INITIALIZER;
    850       mutex_is_init = my_memcmp(mutex, &mutex_init, sizeof(*mutex)) == 0;
    851    } else {
    852       mutex_is_init = 0;
    853    }
    854 
    855    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
    856                 pthread_mutex_t*, mutex, unsigned long, mutex_is_init);
    857 
    858    CALL_FN_W_W(ret, fn, mutex);
    859 
    860    if (ret != 0) {
    861       DO_PthAPIerror( "pthread_mutex_destroy", ret );
    862    }
    863 
    864    if (TRACE_PTH_FNS) {
    865       fprintf(stderr, " :: mxdestroy -> %d >>\n", ret);
    866    }
    867    return ret;
    868 }
    869 
    870 #if defined(VGO_linux) || defined(VGO_darwin)
    871    PTH_FUNC(int, pthreadZumutexZudestroy, // pthread_mutex_destroy
    872             pthread_mutex_t *mutex) {
    873       return mutex_destroy_WRK(mutex);
    874    }
    875 #elif defined(VGO_solaris)
    876    PTH_FUNC(int, mutexZudestroy, // mutex_destroy
    877             pthread_mutex_t *mutex) {
    878       return mutex_destroy_WRK(mutex);
    879    }
    880 #else
    881 #  error "Unsupported OS"
    882 #endif
    883 
    884 
    885 //-----------------------------------------------------------
    886 // glibc:   pthread_mutex_lock
    887 // darwin:  pthread_mutex_lock
    888 // Solaris: mutex_lock (pthread_mutex_lock is a weak alias)
    889 __attribute__((noinline))
    890 static int mutex_lock_WRK(pthread_mutex_t *mutex)
    891 {
    892    int    ret;
    893    OrigFn fn;
    894    VALGRIND_GET_ORIG_FN(fn);
    895    if (TRACE_PTH_FNS) {
    896       fprintf(stderr, "<< pthread_mxlock %p", mutex); fflush(stderr);
    897    }
    898 
    899    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
    900                 pthread_mutex_t*,mutex, long,0/*!isTryLock*/);
    901 
    902    CALL_FN_W_W(ret, fn, mutex);
    903 
    904    /* There's a hole here: libpthread now knows the lock is locked,
    905       but the tool doesn't, so some other thread could run and detect
    906       that the lock has been acquired by someone (this thread).  Does
    907       this matter?  Not sure, but I don't think so. */
    908 
    909    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
    910                 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
    911 
    912    if (ret != 0) {
    913       DO_PthAPIerror( "pthread_mutex_lock", ret );
    914    }
    915 
    916    if (TRACE_PTH_FNS) {
    917       fprintf(stderr, " :: mxlock -> %d >>\n", ret);
    918    }
    919    return ret;
    920 }
    921 
    922 #if defined(VGO_linux) || defined(VGO_darwin)
    923    PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock
    924             pthread_mutex_t *mutex) {
    925       return mutex_lock_WRK(mutex);
    926    }
    927 #elif defined(VGO_solaris)
    928    PTH_FUNC(int, mutexZulock, // mutex_lock
    929             pthread_mutex_t *mutex) {
    930       return mutex_lock_WRK(mutex);
    931    }
    932 #else
    933 #  error "Unsupported OS"
    934 #endif
    935 
    936 #if defined(VGO_solaris)
    937 /* Internal to libc. Mutex is usually initialized only implicitly,
    938  * by zeroing mutex_t structure.
    939  */
    940 __attribute__((noinline))
    941 PTH_FUNC(void, lmutexZulock, // lmutex_lock
    942                mutex_t *mutex)
    943 {
    944    OrigFn fn;
    945    VALGRIND_GET_ORIG_FN(fn);
    946    if (TRACE_PTH_FNS) {
    947       fprintf(stderr, "<< lmxlock %p", mutex); fflush(stderr);
    948    }
    949 
    950    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
    951                 mutex_t *, mutex, long, 0 /*!isTryLock*/);
    952    CALL_FN_v_W(fn, mutex);
    953    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
    954                 mutex_t *, mutex, long, True);
    955 
    956    if (TRACE_PTH_FNS) {
    957       fprintf(stderr, " :: lmxlock >>\n");
    958    }
    959 }
    960 #endif /* VGO_solaris */
    961 
    962 
    963 //-----------------------------------------------------------
    964 // glibc:   pthread_mutex_trylock
    965 // darwin:  pthread_mutex_trylock
    966 // Solaris: mutex_trylock (pthread_mutex_trylock is a weak alias)
    967 //
    968 // pthread_mutex_trylock.  The handling needed here is very similar
    969 // to that for pthread_mutex_lock, except that we need to tell
    970 // the pre-lock creq that this is a trylock-style operation, and
    971 // therefore not to complain if the lock is nonrecursive and
    972 // already locked by this thread -- because then it'll just fail
    973 // immediately with EBUSY.
    974 __attribute__((noinline))
    975 static int mutex_trylock_WRK(pthread_mutex_t *mutex)
    976 {
    977    int    ret;
    978    OrigFn fn;
    979    VALGRIND_GET_ORIG_FN(fn);
    980    if (TRACE_PTH_FNS) {
    981       fprintf(stderr, "<< pthread_mxtrylock %p", mutex); fflush(stderr);
    982    }
    983 
    984    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
    985                 pthread_mutex_t*,mutex, long,1/*isTryLock*/);
    986 
    987    CALL_FN_W_W(ret, fn, mutex);
    988 
    989    /* There's a hole here: libpthread now knows the lock is locked,
    990       but the tool doesn't, so some other thread could run and detect
    991       that the lock has been acquired by someone (this thread).  Does
    992       this matter?  Not sure, but I don't think so. */
    993 
    994    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
    995                pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
    996 
    997    if (ret != 0) {
    998       if (ret != EBUSY)
    999          DO_PthAPIerror( "pthread_mutex_trylock", ret );
   1000    }
   1001 
   1002    if (TRACE_PTH_FNS) {
   1003       fprintf(stderr, " :: mxtrylock -> %d >>\n", ret);
   1004    }
   1005    return ret;
   1006 }
   1007 
   1008 #if defined(VGO_linux) || defined(VGO_darwin)
   1009    PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock
   1010             pthread_mutex_t *mutex) {
   1011       return mutex_trylock_WRK(mutex);
   1012    }
   1013 #elif defined(VGO_solaris)
   1014    PTH_FUNC(int, mutexZutrylock, // mutex_trylock
   1015             pthread_mutex_t *mutex) {
   1016       return mutex_trylock_WRK(mutex);
   1017    }
   1018 #else
   1019 #  error "Unsupported OS"
   1020 #endif
   1021 
   1022 
   1023 //-----------------------------------------------------------
   1024 // glibc:   pthread_mutex_timedlock
   1025 // darwin:  (doesn't appear to exist)
   1026 // Solaris: pthread_mutex_timedlock
   1027 //
   1028 // pthread_mutex_timedlock.  Identical logic to pthread_mutex_trylock.
   1029 __attribute__((noinline))
   1030 static int mutex_timedlock_WRK(pthread_mutex_t *mutex,
   1031                                void *timeout)
   1032 {
   1033    int    ret;
   1034    OrigFn fn;
   1035    VALGRIND_GET_ORIG_FN(fn);
   1036    if (TRACE_PTH_FNS) {
   1037       fprintf(stderr, "<< pthread_mxtimedlock %p %p", mutex, timeout);
   1038       fflush(stderr);
   1039    }
   1040 
   1041    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
   1042                 pthread_mutex_t*,mutex, long,1/*isTryLock-ish*/);
   1043 
   1044    CALL_FN_W_WW(ret, fn, mutex,timeout);
   1045 
   1046    /* There's a hole here: libpthread now knows the lock is locked,
   1047       but the tool doesn't, so some other thread could run and detect
   1048       that the lock has been acquired by someone (this thread).  Does
   1049       this matter?  Not sure, but I don't think so. */
   1050 
   1051    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
   1052                 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
   1053 
   1054    if (ret != 0) {
   1055       if (ret != ETIMEDOUT)
   1056          DO_PthAPIerror( "pthread_mutex_timedlock", ret );
   1057    }
   1058 
   1059    if (TRACE_PTH_FNS) {
   1060       fprintf(stderr, " :: mxtimedlock -> %d >>\n", ret);
   1061    }
   1062    return ret;
   1063 }
   1064 
   1065 PTH_FUNC(int, pthreadZumutexZutimedlock, // pthread_mutex_timedlock
   1066          pthread_mutex_t *mutex,
   1067          void *timeout) {
   1068    return mutex_timedlock_WRK(mutex, timeout);
   1069 }
   1070 #if defined(VGO_solaris)
   1071 PTH_FUNC(int, pthreadZumutexZureltimedlock, // pthread_mutex_reltimedlock
   1072          pthread_mutex_t *mutex,
   1073          void *timeout) {
   1074    return mutex_timedlock_WRK(mutex, timeout);
   1075 }
   1076 #endif
   1077 
   1078 
   1079 //-----------------------------------------------------------
   1080 // glibc:   pthread_mutex_unlock
   1081 // darwin:  pthread_mutex_unlock
   1082 // Solaris: mutex_unlock (pthread_mutex_unlock is a weak alias)
   1083 __attribute__((noinline))
   1084 static int mutex_unlock_WRK(pthread_mutex_t *mutex)
   1085 {
   1086    int    ret;
   1087    OrigFn fn;
   1088    VALGRIND_GET_ORIG_FN(fn);
   1089 
   1090    if (TRACE_PTH_FNS) {
   1091       fprintf(stderr, "<< pthread_mxunlk %p", mutex); fflush(stderr);
   1092    }
   1093 
   1094    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
   1095                pthread_mutex_t*,mutex);
   1096 
   1097    CALL_FN_W_W(ret, fn, mutex);
   1098 
   1099    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
   1100                pthread_mutex_t*,mutex);
   1101 
   1102    if (ret != 0) {
   1103       DO_PthAPIerror( "pthread_mutex_unlock", ret );
   1104    }
   1105 
   1106    if (TRACE_PTH_FNS) {
   1107       fprintf(stderr, " mxunlk -> %d >>\n", ret);
   1108    }
   1109    return ret;
   1110 }
   1111 
   1112 #if defined(VGO_linux) || defined(VGO_darwin)
   1113    PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock
   1114             pthread_mutex_t *mutex) {
   1115       return mutex_unlock_WRK(mutex);
   1116    }
   1117 #elif defined(VGO_solaris)
   1118    PTH_FUNC(int, mutexZuunlock, // mutex_unlock
   1119             pthread_mutex_t *mutex) {
   1120       return mutex_unlock_WRK(mutex);
   1121    }
   1122 #else
   1123 #  error "Unsupported OS"
   1124 #endif
   1125 
   1126 
   1127 #if defined(VGO_solaris)
   1128 /* Internal to libc. */
   1129 __attribute__((noinline))
   1130 PTH_FUNC(void, lmutexZuunlock, // lmutex_unlock
   1131                mutex_t *mutex)
   1132 {
   1133    OrigFn fn;
   1134    VALGRIND_GET_ORIG_FN(fn);
   1135 
   1136    if (TRACE_PTH_FNS) {
   1137       fprintf(stderr, "<< lmxunlk %p", mutex); fflush(stderr);
   1138    }
   1139 
   1140    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
   1141                mutex_t *, mutex);
   1142    CALL_FN_v_W(fn, mutex);
   1143    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
   1144                mutex_t*, mutex);
   1145 
   1146    if (TRACE_PTH_FNS) {
   1147       fprintf(stderr, " lmxunlk >>\n");
   1148    }
   1149 }
   1150 #endif /* VGO_solaris */
   1151 
   1152 
   1153 /*----------------------------------------------------------------*/
   1154 /*--- pthread_cond_t functions                                 ---*/
   1155 /*----------------------------------------------------------------*/
   1156 
   1157 /* Handled:   pthread_cond_wait pthread_cond_timedwait
   1158               pthread_cond_signal pthread_cond_broadcast
   1159               pthread_cond_init
   1160               pthread_cond_destroy
   1161 */
   1162 
   1163 //-----------------------------------------------------------
   1164 // glibc:   pthread_cond_wait (at) GLIBC_2.2.5
   1165 // glibc:   pthread_cond_wait@@GLIBC_2.3.2
   1166 // darwin:  pthread_cond_wait
   1167 // darwin:  pthread_cond_wait$NOCANCEL$UNIX2003
   1168 // darwin:  pthread_cond_wait$UNIX2003
   1169 // Solaris: cond_wait (pthread_cond_wait is built atop of cond_wait)
   1170 //
   1171 __attribute__((noinline))
   1172 static int pthread_cond_wait_WRK(pthread_cond_t* cond,
   1173                                  pthread_mutex_t* mutex)
   1174 {
   1175    int ret;
   1176    OrigFn fn;
   1177    unsigned long mutex_is_valid;
   1178 
   1179    VALGRIND_GET_ORIG_FN(fn);
   1180 
   1181    if (TRACE_PTH_FNS) {
   1182       fprintf(stderr, "<< pthread_cond_wait %p %p", cond, mutex);
   1183       fflush(stderr);
   1184    }
   1185 
   1186    /* Tell the tool a cond-wait is about to happen, so it can check
   1187       for bogus argument values.  In return it tells us whether it
   1188       thinks the mutex is valid or not. */
   1189    DO_CREQ_W_WW(mutex_is_valid,
   1190                 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
   1191                 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
   1192    assert(mutex_is_valid == 1 || mutex_is_valid == 0);
   1193 
   1194    /* Tell the tool we're about to drop the mutex.  This reflects the
   1195       fact that in a cond_wait, we show up holding the mutex, and the
   1196       call atomically drops the mutex and waits for the cv to be
   1197       signalled. */
   1198    if (mutex_is_valid) {
   1199       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
   1200                   pthread_mutex_t*,mutex);
   1201    }
   1202 
   1203    CALL_FN_W_WW(ret, fn, cond,mutex);
   1204 
   1205    /* this conditional look stupid, but compare w/ same logic for
   1206       pthread_cond_timedwait below */
   1207    if (mutex_is_valid) {
   1208       /* and now we have the mutex again if (ret == 0) */
   1209       DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
   1210                    pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
   1211    }
   1212 
   1213    DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
   1214                   pthread_cond_t*,cond, pthread_mutex_t*,mutex, long,0,
   1215                   long, (ret == 0 && mutex_is_valid) ? True : False);
   1216 
   1217    if (ret != 0) {
   1218       DO_PthAPIerror( "pthread_cond_wait", ret );
   1219    }
   1220 
   1221    if (TRACE_PTH_FNS) {
   1222       fprintf(stderr, " cowait -> %d >>\n", ret);
   1223    }
   1224 
   1225    return ret;
   1226 }
   1227 #if defined(VGO_linux)
   1228    PTH_FUNC(int, pthreadZucondZuwaitZAZa, // pthread_cond_wait@*
   1229                  pthread_cond_t* cond, pthread_mutex_t* mutex) {
   1230       return pthread_cond_wait_WRK(cond, mutex);
   1231    }
   1232 #elif defined(VGO_darwin)
   1233    PTH_FUNC(int, pthreadZucondZuwaitZa, // pthread_cond_wait*
   1234                  pthread_cond_t* cond, pthread_mutex_t* mutex) {
   1235       return pthread_cond_wait_WRK(cond, mutex);
   1236    }
   1237 #elif defined(VGO_solaris)
   1238    PTH_FUNC(int, condZuwait, // cond_wait
   1239                  pthread_cond_t *cond, pthread_mutex_t *mutex) {
   1240       return pthread_cond_wait_WRK(cond, mutex);
   1241    }
   1242 #else
   1243 #  error "Unsupported OS"
   1244 #endif
   1245 
   1246 
   1247 //-----------------------------------------------------------
   1248 // glibc:   pthread_cond_timedwait@@GLIBC_2.3.2
   1249 // glibc:   pthread_cond_timedwait (at) GLIBC_2.2.5
   1250 // glibc:   pthread_cond_timedwait (at) GLIBC_2.0
   1251 // darwin:  pthread_cond_timedwait
   1252 // darwin:  pthread_cond_timedwait$NOCANCEL$UNIX2003
   1253 // darwin:  pthread_cond_timedwait$UNIX2003
   1254 // darwin:  pthread_cond_timedwait_relative_np (trapped)
   1255 // Solaris: cond_timedwait (pthread_cond_timedwait is built on cond_timedwait)
   1256 // Solaris: cond_reltimedwait (pthread_cond_reltimedwait_np is built on this)
   1257 //
   1258 __attribute__((noinline))
   1259 static int pthread_cond_timedwait_WRK(pthread_cond_t* cond,
   1260                                       pthread_mutex_t* mutex,
   1261                                       struct timespec* abstime,
   1262                                       int timeout_error)
   1263 {
   1264    int ret;
   1265    OrigFn fn;
   1266    unsigned long mutex_is_valid;
   1267    Bool abstime_is_valid;
   1268    VALGRIND_GET_ORIG_FN(fn);
   1269 
   1270    if (TRACE_PTH_FNS) {
   1271       fprintf(stderr, "<< pthread_cond_timedwait %p %p %p",
   1272                       cond, mutex, abstime);
   1273       fflush(stderr);
   1274    }
   1275 
   1276    /* Tell the tool a cond-wait is about to happen, so it can check
   1277       for bogus argument values.  In return it tells us whether it
   1278       thinks the mutex is valid or not. */
   1279    DO_CREQ_W_WW(mutex_is_valid,
   1280                 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
   1281                 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
   1282    assert(mutex_is_valid == 1 || mutex_is_valid == 0);
   1283 
   1284    abstime_is_valid = abstime->tv_nsec >= 0 && abstime->tv_nsec < 1000000000;
   1285 
   1286    /* Tell the tool we're about to drop the mutex.  This reflects the
   1287       fact that in a cond_wait, we show up holding the mutex, and the
   1288       call atomically drops the mutex and waits for the cv to be
   1289       signalled. */
   1290    if (mutex_is_valid && abstime_is_valid) {
   1291       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
   1292                   pthread_mutex_t*,mutex);
   1293    }
   1294 
   1295    CALL_FN_W_WWW(ret, fn, cond,mutex,abstime);
   1296 
   1297    if (mutex_is_valid && !abstime_is_valid && ret != EINVAL) {
   1298       DO_PthAPIerror("Bug in libpthread: pthread_cond_timedwait "
   1299                      "invalid abstime did not cause"
   1300                      " EINVAL", ret);
   1301    }
   1302 
   1303    if (mutex_is_valid && abstime_is_valid) {
   1304       /* and now we have the mutex again if (ret == 0 || ret == timeout) */
   1305       DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
   1306                    pthread_mutex_t *, mutex,
   1307                    long, (ret == 0 || ret == timeout_error) ? True : False);
   1308    }
   1309 
   1310    DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
   1311                   pthread_cond_t*,cond, pthread_mutex_t*,mutex,
   1312                   long,ret == timeout_error,
   1313                   long, (ret == 0 || ret == timeout_error) && mutex_is_valid
   1314                         ? True : False);
   1315 
   1316    if (ret != 0 && ret != timeout_error) {
   1317       DO_PthAPIerror( "pthread_cond_timedwait", ret );
   1318    }
   1319 
   1320    if (TRACE_PTH_FNS) {
   1321       fprintf(stderr, " cotimedwait -> %d >>\n", ret);
   1322    }
   1323 
   1324    return ret;
   1325 }
   1326 #if defined(VGO_linux)
   1327    PTH_FUNC(int, pthreadZucondZutimedwaitZAZa, // pthread_cond_timedwait@*
   1328                  pthread_cond_t* cond, pthread_mutex_t* mutex,
   1329                  struct timespec* abstime) {
   1330       return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
   1331    }
   1332 #elif defined(VGO_darwin)
   1333    PTH_FUNC(int, pthreadZucondZutimedwait, // pthread_cond_timedwait
   1334                  pthread_cond_t* cond, pthread_mutex_t* mutex,
   1335                  struct timespec* abstime) {
   1336       return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
   1337    }
   1338    PTH_FUNC(int, pthreadZucondZutimedwaitZDZa, // pthread_cond_timedwait$*
   1339                  pthread_cond_t* cond, pthread_mutex_t* mutex,
   1340                  struct timespec* abstime) {
   1341       return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
   1342    }
   1343    PTH_FUNC(int, pthreadZucondZutimedwaitZuZa, // pthread_cond_timedwait_*
   1344                  pthread_cond_t* cond, pthread_mutex_t* mutex,
   1345                  struct timespec* abstime) {
   1346       assert(0);
   1347    }
   1348 #elif defined(VGO_solaris)
   1349    PTH_FUNC(int, condZutimedwait, // cond_timedwait
   1350                  pthread_cond_t *cond, pthread_mutex_t *mutex,
   1351                  struct timespec *abstime) {
   1352       return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIME);
   1353    }
   1354    PTH_FUNC(int, condZureltimedwait, // cond_reltimedwait
   1355                  pthread_cond_t *cond, pthread_mutex_t *mutex,
   1356                  struct timespec *reltime) {
   1357       return pthread_cond_timedwait_WRK(cond, mutex, reltime, ETIME);
   1358    }
   1359 #else
   1360 #  error "Unsupported OS"
   1361 #endif
   1362 
   1363 
   1364 //-----------------------------------------------------------
   1365 // glibc:   pthread_cond_signal (at) GLIBC_2.0
   1366 // glibc:   pthread_cond_signal (at) GLIBC_2.2.5
   1367 // glibc:   pthread_cond_signal@@GLIBC_2.3.2
   1368 // darwin:  pthread_cond_signal
   1369 // darwin:  pthread_cond_signal_thread_np (don't intercept this)
   1370 // Solaris: cond_signal (pthread_cond_signal is a weak alias)
   1371 //
   1372 __attribute__((noinline))
   1373 static int pthread_cond_signal_WRK(pthread_cond_t* cond)
   1374 {
   1375    int ret;
   1376    OrigFn fn;
   1377    VALGRIND_GET_ORIG_FN(fn);
   1378 
   1379    if (TRACE_PTH_FNS) {
   1380       fprintf(stderr, "<< pthread_cond_signal %p", cond);
   1381       fflush(stderr);
   1382    }
   1383 
   1384    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE,
   1385                pthread_cond_t*,cond);
   1386 
   1387    CALL_FN_W_W(ret, fn, cond);
   1388 
   1389    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_POST,
   1390                pthread_cond_t*,cond);
   1391 
   1392    if (ret != 0) {
   1393       DO_PthAPIerror( "pthread_cond_signal", ret );
   1394    }
   1395 
   1396    if (TRACE_PTH_FNS) {
   1397       fprintf(stderr, " cosig -> %d >>\n", ret);
   1398    }
   1399 
   1400    return ret;
   1401 }
   1402 #if defined(VGO_linux)
   1403    PTH_FUNC(int, pthreadZucondZusignalZAZa, // pthread_cond_signal@*
   1404                  pthread_cond_t* cond) {
   1405       return pthread_cond_signal_WRK(cond);
   1406    }
   1407 #elif defined(VGO_darwin)
   1408    PTH_FUNC(int, pthreadZucondZusignal, // pthread_cond_signal
   1409                  pthread_cond_t* cond) {
   1410       return pthread_cond_signal_WRK(cond);
   1411    }
   1412 #elif defined(VGO_solaris)
   1413    PTH_FUNC(int, condZusignal, // cond_signal
   1414                  pthread_cond_t *cond) {
   1415       return pthread_cond_signal_WRK(cond);
   1416    }
   1417 #else
   1418 #  error "Unsupported OS"
   1419 #endif
   1420 
   1421 
   1422 //-----------------------------------------------------------
   1423 // glibc:   pthread_cond_broadcast (at) GLIBC_2.0
   1424 // glibc:   pthread_cond_broadcast (at) GLIBC_2.2.5
   1425 // glibc:   pthread_cond_broadcast@@GLIBC_2.3.2
   1426 // darwin:  pthread_cond_broadcast
   1427 // Solaris: cond_broadcast (pthread_cond_broadcast is a weak alias)
   1428 //
   1429 // Note, this is pretty much identical, from a dependency-graph
   1430 // point of view, with cond_signal, so the code is duplicated.
   1431 // Maybe it should be commoned up.
   1432 //
   1433 __attribute__((noinline))
   1434 static int pthread_cond_broadcast_WRK(pthread_cond_t* cond)
   1435 {
   1436    int ret;
   1437    OrigFn fn;
   1438    VALGRIND_GET_ORIG_FN(fn);
   1439 
   1440    if (TRACE_PTH_FNS) {
   1441       fprintf(stderr, "<< pthread_cond_broadcast %p", cond);
   1442       fflush(stderr);
   1443    }
   1444 
   1445    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE,
   1446                pthread_cond_t*,cond);
   1447 
   1448    CALL_FN_W_W(ret, fn, cond);
   1449 
   1450    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_POST,
   1451                pthread_cond_t*,cond);
   1452 
   1453    if (ret != 0) {
   1454       DO_PthAPIerror( "pthread_cond_broadcast", ret );
   1455    }
   1456 
   1457    if (TRACE_PTH_FNS) {
   1458       fprintf(stderr, " cobro -> %d >>\n", ret);
   1459    }
   1460 
   1461    return ret;
   1462 }
   1463 #if defined(VGO_linux)
   1464    PTH_FUNC(int, pthreadZucondZubroadcastZAZa, // pthread_cond_broadcast@*
   1465                  pthread_cond_t* cond) {
   1466       return pthread_cond_broadcast_WRK(cond);
   1467    }
   1468 #elif defined(VGO_darwin)
   1469    PTH_FUNC(int, pthreadZucondZubroadcast, // pthread_cond_broadcast
   1470                  pthread_cond_t* cond) {
   1471       return pthread_cond_broadcast_WRK(cond);
   1472    }
   1473 #elif defined(VGO_solaris)
   1474    PTH_FUNC(int, condZubroadcast, // cond_broadcast
   1475                  pthread_cond_t *cond) {
   1476       return pthread_cond_broadcast_WRK(cond);
   1477    }
   1478 #else
   1479 #   error "Unsupported OS"
   1480 #endif
   1481 
   1482 // glibc:   pthread_cond_init (at) GLIBC_2.0
   1483 // glibc:   pthread_cond_init (at) GLIBC_2.2.5
   1484 // glibc:   pthread_cond_init@@GLIBC_2.3.2
   1485 // darwin:  pthread_cond_init
   1486 // Solaris: cond_init (pthread_cond_init is built atop on this function)
   1487 // Easy way out: Handling of attr could have been messier.
   1488 // It turns out that pthread_cond_init under linux ignores
   1489 // all information in cond_attr, so do we.
   1490 // FIXME: MacOS X?
   1491 #if !defined(VGO_solaris)
   1492 __attribute__((noinline))
   1493 static int pthread_cond_init_WRK(pthread_cond_t* cond, pthread_condattr_t *cond_attr)
   1494 {
   1495    int ret;
   1496    OrigFn fn;
   1497    VALGRIND_GET_ORIG_FN(fn);
   1498 
   1499    if (TRACE_PTH_FNS) {
   1500       fprintf(stderr, "<< pthread_cond_init %p", cond);
   1501       fflush(stderr);
   1502    }
   1503 
   1504    CALL_FN_W_WW(ret, fn, cond, cond_attr);
   1505 
   1506    if (ret == 0) {
   1507       DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST,
   1508                    pthread_cond_t*,cond, pthread_condattr_t*, cond_attr);
   1509    } else {
   1510       DO_PthAPIerror( "pthread_cond_init", ret );
   1511    }
   1512 
   1513    if (TRACE_PTH_FNS) {
   1514       fprintf(stderr, " coinit -> %d >>\n", ret);
   1515    }
   1516 
   1517    return ret;
   1518 }
   1519 #if defined(VGO_linux)
   1520    PTH_FUNC(int, pthreadZucondZuinitZAZa, // pthread_cond_init@*
   1521 	    pthread_cond_t* cond, pthread_condattr_t* cond_attr) {
   1522      return pthread_cond_init_WRK(cond, cond_attr);
   1523    }
   1524 #elif defined(VGO_darwin)
   1525    PTH_FUNC(int, pthreadZucondZuinit, // pthread_cond_init
   1526 	    pthread_cond_t* cond, pthread_condattr_t * cond_attr) {
   1527      return pthread_cond_init_WRK(cond, cond_attr);
   1528    }
   1529 #else
   1530 #  error "Unsupported OS"
   1531 #endif
   1532 
   1533 #else /* VGO_solaris */
   1534 __attribute__((noinline))
   1535 PTH_FUNC(int, condZuinit, // cond_init
   1536               cond_t *cond, int type, void *arg)
   1537 {
   1538    int ret;
   1539    OrigFn fn;
   1540    VALGRIND_GET_ORIG_FN(fn);
   1541 
   1542    if (TRACE_PTH_FNS) {
   1543       fprintf(stderr, "<< cond_init %p", cond); fflush(stderr);
   1544    }
   1545 
   1546    CALL_FN_W_WWW(ret, fn, cond, type, arg);
   1547 
   1548    if (ret == 0) {
   1549       /* Luckily evh__HG_PTHREAD_COND_INIT_POST() ignores cond_attr.
   1550          See also comment for pthread_cond_init_WRK(). */
   1551       DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST,
   1552                    cond_t *, cond, void *, NULL);
   1553    } else {
   1554       DO_PthAPIerror("cond_init", ret);
   1555    }
   1556 
   1557    if (TRACE_PTH_FNS) {
   1558       fprintf(stderr, " cond_init -> %d >>\n", ret);
   1559    }
   1560 
   1561    return ret;
   1562 }
   1563 #endif /* VGO_solaris */
   1564 
   1565 
   1566 //-----------------------------------------------------------
   1567 // glibc:   pthread_cond_destroy@@GLIBC_2.3.2
   1568 // glibc:   pthread_cond_destroy (at) GLIBC_2.2.5
   1569 // glibc:   pthread_cond_destroy (at) GLIBC_2.0
   1570 // darwin:  pthread_cond_destroy
   1571 // Solaris: cond_destroy (pthread_cond_destroy is a weak alias)
   1572 //
   1573 __attribute__((noinline))
   1574 static int pthread_cond_destroy_WRK(pthread_cond_t* cond)
   1575 {
   1576    int ret;
   1577    unsigned long cond_is_init;
   1578    OrigFn fn;
   1579 
   1580    VALGRIND_GET_ORIG_FN(fn);
   1581 
   1582    if (TRACE_PTH_FNS) {
   1583       fprintf(stderr, "<< pthread_cond_destroy %p", cond);
   1584       fflush(stderr);
   1585    }
   1586 
   1587    if (cond != NULL) {
   1588       const pthread_cond_t cond_init = PTHREAD_COND_INITIALIZER;
   1589       cond_is_init = my_memcmp(cond, &cond_init, sizeof(*cond)) == 0;
   1590    } else {
   1591      cond_is_init = 0;
   1592    }
   1593 
   1594    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_DESTROY_PRE,
   1595                 pthread_cond_t*, cond, unsigned long, cond_is_init);
   1596 
   1597    CALL_FN_W_W(ret, fn, cond);
   1598 
   1599    if (ret != 0) {
   1600       DO_PthAPIerror( "pthread_cond_destroy", ret );
   1601    }
   1602 
   1603    if (TRACE_PTH_FNS) {
   1604       fprintf(stderr, " codestr -> %d >>\n", ret);
   1605    }
   1606 
   1607    return ret;
   1608 }
   1609 #if defined(VGO_linux)
   1610    PTH_FUNC(int, pthreadZucondZudestroyZAZa, // pthread_cond_destroy@*
   1611                  pthread_cond_t* cond) {
   1612       return pthread_cond_destroy_WRK(cond);
   1613    }
   1614 #elif defined(VGO_darwin)
   1615    PTH_FUNC(int, pthreadZucondZudestroy, // pthread_cond_destroy
   1616                  pthread_cond_t* cond) {
   1617       return pthread_cond_destroy_WRK(cond);
   1618    }
   1619 #elif defined(VGO_solaris)
   1620    PTH_FUNC(int, condZudestroy, // cond_destroy
   1621                  pthread_cond_t *cond) {
   1622       return pthread_cond_destroy_WRK(cond);
   1623    }
   1624 #else
   1625 #  error "Unsupported OS"
   1626 #endif
   1627 
   1628 
   1629 /*----------------------------------------------------------------*/
   1630 /*--- pthread_barrier_t functions                              ---*/
   1631 /*----------------------------------------------------------------*/
   1632 
   1633 #if defined(HAVE_PTHREAD_BARRIER_INIT)
   1634 
   1635 /* Handled:   pthread_barrier_init
   1636               pthread_barrier_wait
   1637               pthread_barrier_destroy
   1638 
   1639    Unhandled: pthread_barrierattr_destroy
   1640               pthread_barrierattr_getpshared
   1641               pthread_barrierattr_init
   1642               pthread_barrierattr_setpshared
   1643               -- are these important?
   1644 */
   1645 
   1646 //-----------------------------------------------------------
   1647 // glibc:   pthread_barrier_init
   1648 // darwin:  (doesn't appear to exist)
   1649 // Solaris: pthread_barrier_init
   1650 PTH_FUNC(int, pthreadZubarrierZuinit, // pthread_barrier_init
   1651          pthread_barrier_t* bar,
   1652          pthread_barrierattr_t* attr, unsigned long count)
   1653 {
   1654    int ret;
   1655    OrigFn fn;
   1656    VALGRIND_GET_ORIG_FN(fn);
   1657 
   1658    if (TRACE_PTH_FNS) {
   1659       fprintf(stderr, "<< pthread_barrier_init %p %p %lu",
   1660                       bar, attr, count);
   1661       fflush(stderr);
   1662    }
   1663 
   1664    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE,
   1665                  pthread_barrier_t*, bar,
   1666                  unsigned long, count,
   1667                  unsigned long, 0/*!resizable*/);
   1668 
   1669    CALL_FN_W_WWW(ret, fn, bar,attr,count);
   1670 
   1671    if (ret != 0) {
   1672       DO_PthAPIerror( "pthread_barrier_init", ret );
   1673    }
   1674 
   1675    if (TRACE_PTH_FNS) {
   1676       fprintf(stderr, "  pthread_barrier_init -> %d >>\n", ret);
   1677    }
   1678 
   1679    return ret;
   1680 }
   1681 
   1682 
   1683 //-----------------------------------------------------------
   1684 // glibc:   pthread_barrier_wait
   1685 // darwin:  (doesn't appear to exist)
   1686 // Solaris: pthread_barrier_wait
   1687 PTH_FUNC(int, pthreadZubarrierZuwait, // pthread_barrier_wait
   1688               pthread_barrier_t* bar)
   1689 {
   1690    int ret;
   1691    OrigFn fn;
   1692    VALGRIND_GET_ORIG_FN(fn);
   1693 
   1694    if (TRACE_PTH_FNS) {
   1695       fprintf(stderr, "<< pthread_barrier_wait %p", bar);
   1696       fflush(stderr);
   1697    }
   1698 
   1699    /* That this works correctly, and doesn't screw up when a thread
   1700       leaving the barrier races round to the front and re-enters while
   1701       other threads are still leaving it, is quite subtle.  See
   1702       comments in the handler for PTHREAD_BARRIER_WAIT_PRE in
   1703       hg_main.c. */
   1704    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE,
   1705                pthread_barrier_t*,bar);
   1706 
   1707    CALL_FN_W_W(ret, fn, bar);
   1708 
   1709    if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) {
   1710       DO_PthAPIerror( "pthread_barrier_wait", ret );
   1711    }
   1712 
   1713    if (TRACE_PTH_FNS) {
   1714       fprintf(stderr, "  pthread_barrier_wait -> %d >>\n", ret);
   1715    }
   1716 
   1717    return ret;
   1718 }
   1719 
   1720 
   1721 //-----------------------------------------------------------
   1722 // glibc:   pthread_barrier_destroy
   1723 // darwin:  (doesn't appear to exist)
   1724 // Solaris: pthread_barrier_destroy
   1725 PTH_FUNC(int, pthreadZubarrierZudestroy, // pthread_barrier_destroy
   1726          pthread_barrier_t* bar)
   1727 {
   1728    int ret;
   1729    OrigFn fn;
   1730    VALGRIND_GET_ORIG_FN(fn);
   1731 
   1732    if (TRACE_PTH_FNS) {
   1733       fprintf(stderr, "<< pthread_barrier_destroy %p", bar);
   1734       fflush(stderr);
   1735    }
   1736 
   1737    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE,
   1738                pthread_barrier_t*,bar);
   1739 
   1740    CALL_FN_W_W(ret, fn, bar);
   1741 
   1742    if (ret != 0) {
   1743       DO_PthAPIerror( "pthread_barrier_destroy", ret );
   1744    }
   1745 
   1746    if (TRACE_PTH_FNS) {
   1747       fprintf(stderr, "  pthread_barrier_destroy -> %d >>\n", ret);
   1748    }
   1749 
   1750    return ret;
   1751 }
   1752 
   1753 #endif   // defined(HAVE_PTHREAD_BARRIER_INIT)
   1754 
   1755 
   1756 /*----------------------------------------------------------------*/
   1757 /*--- pthread_spinlock_t functions                             ---*/
   1758 /*----------------------------------------------------------------*/
   1759 
   1760 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
   1761     && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
   1762 
   1763 /* Handled:   pthread_spin_init pthread_spin_destroy
   1764               pthread_spin_lock pthread_spin_trylock
   1765               pthread_spin_unlock
   1766 
   1767    Unhandled:
   1768 */
   1769 
   1770 /* This is a nasty kludge, in that glibc "knows" that initialising a
   1771    spin lock unlocks it, and pthread_spin_{init,unlock} are names for
   1772    the same function.  Hence we have to have a wrapper which does both
   1773    things, without knowing which the user intended to happen.
   1774    Solaris has distinct functions for init/unlock but client requests
   1775    are immutable in helgrind.h so follow the glibc lead. */
   1776 
   1777 //-----------------------------------------------------------
   1778 // glibc:   pthread_spin_init
   1779 // glibc:   pthread_spin_unlock
   1780 // darwin:  (doesn't appear to exist)
   1781 // Solaris: pthread_spin_init
   1782 // Solaris: pthread_spin_unlock
   1783 __attribute__((noinline))
   1784 static int pthread_spin_init_or_unlock_WRK(pthread_spinlock_t* lock,
   1785                                            int pshared) {
   1786    int    ret;
   1787    OrigFn fn;
   1788    VALGRIND_GET_ORIG_FN(fn);
   1789    if (TRACE_PTH_FNS) {
   1790       fprintf(stderr, "<< pthread_spin_iORu %p", lock); fflush(stderr);
   1791    }
   1792 
   1793    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE,
   1794                pthread_spinlock_t*, lock);
   1795 
   1796    CALL_FN_W_WW(ret, fn, lock,pshared);
   1797 
   1798    if (ret == 0 /*success*/) {
   1799       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST,
   1800                   pthread_spinlock_t*,lock);
   1801    } else {
   1802       DO_PthAPIerror( "pthread_spinlock_{init,unlock}", ret );
   1803    }
   1804 
   1805    if (TRACE_PTH_FNS) {
   1806       fprintf(stderr, " :: spiniORu -> %d >>\n", ret);
   1807    }
   1808    return ret;
   1809 }
   1810 #if defined(VGO_linux)
   1811    PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
   1812             pthread_spinlock_t* lock, int pshared) {
   1813       return pthread_spin_init_or_unlock_WRK(lock, pshared);
   1814    }
   1815    PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
   1816             pthread_spinlock_t* lock) {
   1817       /* this is never actually called */
   1818       return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/);
   1819    }
   1820 #elif defined(VGO_darwin)
   1821 #elif defined(VGO_solaris)
   1822    PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
   1823             pthread_spinlock_t *lock, int pshared) {
   1824       return pthread_spin_init_or_unlock_WRK(lock, pshared);
   1825    }
   1826    PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
   1827             pthread_spinlock_t *lock) {
   1828       return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/);
   1829    }
   1830 #else
   1831 #  error "Unsupported OS"
   1832 #endif
   1833 
   1834 
   1835 //-----------------------------------------------------------
   1836 // glibc:   pthread_spin_destroy
   1837 // darwin:  (doesn't appear to exist)
   1838 // Solaris: pthread_spin_destroy
   1839 __attribute__((noinline))
   1840 static int pthread_spin_destroy_WRK(pthread_spinlock_t *lock)
   1841 {
   1842    int    ret;
   1843    OrigFn fn;
   1844    VALGRIND_GET_ORIG_FN(fn);
   1845    if (TRACE_PTH_FNS) {
   1846       fprintf(stderr, "<< pthread_spin_destroy %p", lock);
   1847       fflush(stderr);
   1848    }
   1849 
   1850    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_DESTROY_PRE,
   1851                pthread_spinlock_t*,lock);
   1852 
   1853    CALL_FN_W_W(ret, fn, lock);
   1854 
   1855    if (ret != 0) {
   1856       DO_PthAPIerror( "pthread_spin_destroy", ret );
   1857    }
   1858 
   1859    if (TRACE_PTH_FNS) {
   1860       fprintf(stderr, " :: spindestroy -> %d >>\n", ret);
   1861    }
   1862    return ret;
   1863 }
   1864 #if defined(VGO_linux)
   1865    PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy
   1866             pthread_spinlock_t *lock) {
   1867       return pthread_spin_destroy_WRK(lock);
   1868    }
   1869 #elif defined(VGO_darwin)
   1870 #elif defined(VGO_solaris)
   1871    PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy
   1872             pthread_spinlock_t *lock) {
   1873       return pthread_spin_destroy_WRK(lock);
   1874    }
   1875 #else
   1876 #  error "Unsupported OS"
   1877 #endif
   1878 
   1879 
   1880 //-----------------------------------------------------------
   1881 // glibc:   pthread_spin_lock
   1882 // darwin:  (doesn't appear to exist)
   1883 // Solaris: pthread_spin_lock
   1884 __attribute__((noinline))
   1885 static int pthread_spin_lock_WRK(pthread_spinlock_t *lock)
   1886 {
   1887    int    ret;
   1888    OrigFn fn;
   1889    VALGRIND_GET_ORIG_FN(fn);
   1890    if (TRACE_PTH_FNS) {
   1891       fprintf(stderr, "<< pthread_spinlock %p", lock);
   1892       fflush(stderr);
   1893    }
   1894 
   1895    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE,
   1896                 pthread_spinlock_t*,lock, long,0/*!isTryLock*/);
   1897 
   1898    CALL_FN_W_W(ret, fn, lock);
   1899 
   1900    /* There's a hole here: libpthread now knows the lock is locked,
   1901       but the tool doesn't, so some other thread could run and detect
   1902       that the lock has been acquired by someone (this thread).  Does
   1903       this matter?  Not sure, but I don't think so. */
   1904 
   1905    if (ret == 0 /*success*/) {
   1906       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST,
   1907                   pthread_spinlock_t*,lock);
   1908    } else {
   1909       DO_PthAPIerror( "pthread_spin_lock", ret );
   1910    }
   1911 
   1912    if (TRACE_PTH_FNS) {
   1913       fprintf(stderr, " :: spinlock -> %d >>\n", ret);
   1914    }
   1915    return ret;
   1916 }
   1917 #if defined(VGO_linux)
   1918    PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
   1919                  pthread_spinlock_t *lock) {
   1920       return pthread_spin_lock_WRK(lock);
   1921    }
   1922 #elif defined(VGO_darwin)
   1923 #elif defined(VGO_solaris)
   1924    PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
   1925                  pthread_spinlock_t *lock) {
   1926       return pthread_spin_lock_WRK(lock);
   1927    }
   1928 #else
   1929 #  error "Unsupported OS"
   1930 #endif
   1931 
   1932 
   1933 //-----------------------------------------------------------
   1934 // glibc:   pthread_spin_trylock
   1935 // darwin:  (doesn't appear to exist)
   1936 // Solaris: pthread_spin_trylock
   1937 __attribute__((noinline))
   1938 static int pthread_spin_trylock_WRK(pthread_spinlock_t *lock)
   1939 {
   1940    int    ret;
   1941    OrigFn fn;
   1942    VALGRIND_GET_ORIG_FN(fn);
   1943    if (TRACE_PTH_FNS) {
   1944       fprintf(stderr, "<< pthread_spin_trylock %p", lock);
   1945       fflush(stderr);
   1946    }
   1947 
   1948    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE,
   1949                 pthread_spinlock_t*,lock, long,1/*isTryLock*/);
   1950 
   1951    CALL_FN_W_W(ret, fn, lock);
   1952 
   1953    /* There's a hole here: libpthread now knows the lock is locked,
   1954       but the tool doesn't, so some other thread could run and detect
   1955       that the lock has been acquired by someone (this thread).  Does
   1956       this matter?  Not sure, but I don't think so. */
   1957 
   1958    if (ret == 0 /*success*/) {
   1959       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST,
   1960                   pthread_spinlock_t*,lock);
   1961    } else {
   1962       if (ret != EBUSY)
   1963          DO_PthAPIerror( "pthread_spin_trylock", ret );
   1964    }
   1965 
   1966    if (TRACE_PTH_FNS) {
   1967       fprintf(stderr, " :: spin_trylock -> %d >>\n", ret);
   1968    }
   1969    return ret;
   1970 }
   1971 #if defined(VGO_linux)
   1972    PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
   1973                  pthread_spinlock_t *lock) {
   1974       return pthread_spin_trylock_WRK(lock);
   1975    }
   1976 #elif defined(VGO_darwin)
   1977 #elif defined(VGO_solaris)
   1978    PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
   1979                  pthread_spinlock_t *lock) {
   1980       return pthread_spin_trylock_WRK(lock);
   1981    }
   1982 #else
   1983 #  error "Unsupported OS"
   1984 #endif
   1985 
   1986 #endif // defined(HAVE_PTHREAD_SPIN_LOCK)
   1987 
   1988 
   1989 /*----------------------------------------------------------------*/
   1990 /*--- pthread_rwlock_t functions                               ---*/
   1991 /*----------------------------------------------------------------*/
   1992 
   1993 /* Android's pthread.h doesn't say anything about rwlocks, hence these
   1994    functions have to be conditionally compiled. */
   1995 #if defined(HAVE_PTHREAD_RWLOCK_T)
   1996 
   1997 /* Handled:   pthread_rwlock_init pthread_rwlock_destroy
   1998               pthread_rwlock_rdlock
   1999               pthread_rwlock_wrlock
   2000               pthread_rwlock_unlock
   2001               pthread_rwlock_tryrdlock
   2002               pthread_rwlock_trywrlock
   2003 
   2004    Unhandled: pthread_rwlock_timedrdlock
   2005               pthread_rwlock_timedwrlock
   2006 */
   2007 
   2008 //-----------------------------------------------------------
   2009 // glibc:   pthread_rwlock_init
   2010 // darwin:  pthread_rwlock_init
   2011 // darwin:  pthread_rwlock_init$UNIX2003
   2012 // Solaris: rwlock_init (pthread_rwlock_init is built atop of rwlock_init)
   2013 __attribute__((noinline))
   2014 static int pthread_rwlock_init_WRK(pthread_rwlock_t *rwl,
   2015                                    pthread_rwlockattr_t* attr)
   2016 {
   2017    int    ret;
   2018    OrigFn fn;
   2019    VALGRIND_GET_ORIG_FN(fn);
   2020    if (TRACE_PTH_FNS) {
   2021       fprintf(stderr, "<< pthread_rwl_init %p", rwl); fflush(stderr);
   2022    }
   2023 
   2024    CALL_FN_W_WW(ret, fn, rwl,attr);
   2025 
   2026    if (ret == 0 /*success*/) {
   2027       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
   2028                   pthread_rwlock_t*,rwl);
   2029    } else {
   2030       DO_PthAPIerror( "pthread_rwlock_init", ret );
   2031    }
   2032 
   2033    if (TRACE_PTH_FNS) {
   2034       fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
   2035    }
   2036    return ret;
   2037 }
   2038 #if defined(VGO_linux)
   2039    PTH_FUNC(int, pthreadZurwlockZuinit, // pthread_rwlock_init
   2040                  pthread_rwlock_t *rwl,
   2041                  pthread_rwlockattr_t* attr) {
   2042       return pthread_rwlock_init_WRK(rwl, attr);
   2043    }
   2044 #elif defined(VGO_darwin)
   2045    PTH_FUNC(int, pthreadZurwlockZuinitZa, // pthread_rwlock_init*
   2046                  pthread_rwlock_t *rwl,
   2047                  pthread_rwlockattr_t* attr) {
   2048       return pthread_rwlock_init_WRK(rwl, attr);
   2049    }
   2050 #elif defined(VGO_solaris)
   2051 static int pthread_rwlock_init_WRK(pthread_rwlock_t *rwl,
   2052                                    pthread_rwlockattr_t* attr)
   2053                                    __attribute__((unused));
   2054 #else
   2055 #  error "Unsupported OS"
   2056 #endif
   2057 
   2058 #if defined(VGO_solaris)
   2059 PTH_FUNC(int, rwlockZuinit, // rwlock_init
   2060               rwlock_t *rwlock,
   2061               int type,
   2062               void *arg)
   2063 {
   2064    int    ret;
   2065    OrigFn fn;
   2066    VALGRIND_GET_ORIG_FN(fn);
   2067    if (TRACE_PTH_FNS) {
   2068       fprintf(stderr, "<< rwl_init %p", rwlock); fflush(stderr);
   2069    }
   2070 
   2071    CALL_FN_W_WWW(ret, fn, rwlock, type, arg);
   2072 
   2073    if (ret == 0 /*success*/) {
   2074       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
   2075                   rwlock_t *, rwlock);
   2076    } else {
   2077       DO_PthAPIerror("rwlock_init", ret);
   2078    }
   2079 
   2080    if (TRACE_PTH_FNS) {
   2081       fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
   2082    }
   2083    return ret;
   2084 }
   2085 #endif /* VGO_solaris */
   2086 
   2087 
   2088 //-----------------------------------------------------------
   2089 // glibc:   pthread_rwlock_destroy
   2090 // darwin:  pthread_rwlock_destroy
   2091 // darwin:  pthread_rwlock_destroy$UNIX2003
   2092 // Solaris: rwlock_destroy (pthread_rwlock_destroy is a weak alias)
   2093 //
   2094 __attribute__((noinline))
   2095 static int pthread_rwlock_destroy_WRK(pthread_rwlock_t* rwl)
   2096 {
   2097    int    ret;
   2098    OrigFn fn;
   2099    VALGRIND_GET_ORIG_FN(fn);
   2100    if (TRACE_PTH_FNS) {
   2101       fprintf(stderr, "<< pthread_rwl_destroy %p", rwl); fflush(stderr);
   2102    }
   2103 
   2104    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE,
   2105                pthread_rwlock_t*,rwl);
   2106 
   2107    CALL_FN_W_W(ret, fn, rwl);
   2108 
   2109    if (ret != 0) {
   2110       DO_PthAPIerror( "pthread_rwlock_destroy", ret );
   2111    }
   2112 
   2113    if (TRACE_PTH_FNS) {
   2114       fprintf(stderr, " :: rwl_destroy -> %d >>\n", ret);
   2115    }
   2116    return ret;
   2117 }
   2118 #if defined(VGO_linux)
   2119    PTH_FUNC(int, pthreadZurwlockZudestroy, // pthread_rwlock_destroy
   2120                  pthread_rwlock_t *rwl) {
   2121       return pthread_rwlock_destroy_WRK(rwl);
   2122    }
   2123 #elif defined(VGO_darwin)
   2124    PTH_FUNC(int, pthreadZurwlockZudestroyZa, // pthread_rwlock_destroy*
   2125                  pthread_rwlock_t *rwl) {
   2126       return pthread_rwlock_destroy_WRK(rwl);
   2127    }
   2128 #elif defined(VGO_solaris)
   2129    PTH_FUNC(int, rwlockZudestroy, // rwlock_destroy
   2130                  pthread_rwlock_t *rwl) {
   2131       return pthread_rwlock_destroy_WRK(rwl);
   2132    }
   2133 #else
   2134 #  error "Unsupported OS"
   2135 #endif
   2136 
   2137 
   2138 //-----------------------------------------------------------
   2139 // glibc:   pthread_rwlock_wrlock
   2140 // darwin:  pthread_rwlock_wrlock
   2141 // darwin:  pthread_rwlock_wrlock$UNIX2003
   2142 // Solaris: rw_wrlock (pthread_rwlock_wrlock is a weak alias)
   2143 //
   2144 __attribute__((noinline))
   2145 static int pthread_rwlock_wrlock_WRK(pthread_rwlock_t* rwlock)
   2146 {
   2147    int    ret;
   2148    OrigFn fn;
   2149    VALGRIND_GET_ORIG_FN(fn);
   2150    if (TRACE_PTH_FNS) {
   2151       fprintf(stderr, "<< pthread_rwl_wlk %p", rwlock); fflush(stderr);
   2152    }
   2153 
   2154    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
   2155                  pthread_rwlock_t*,rwlock,
   2156                  long,1/*isW*/, long,0/*!isTryLock*/);
   2157 
   2158    CALL_FN_W_W(ret, fn, rwlock);
   2159 
   2160    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
   2161                  pthread_rwlock_t*,rwlock, long,1/*isW*/,
   2162                  long, (ret == 0) ? True : False);
   2163    if (ret != 0) {
   2164       DO_PthAPIerror( "pthread_rwlock_wrlock", ret );
   2165    }
   2166 
   2167    if (TRACE_PTH_FNS) {
   2168       fprintf(stderr, " :: rwl_wlk -> %d >>\n", ret);
   2169    }
   2170    return ret;
   2171 }
   2172 #if defined(VGO_linux)
   2173    PTH_FUNC(int, pthreadZurwlockZuwrlock, // pthread_rwlock_wrlock
   2174                  pthread_rwlock_t* rwlock) {
   2175       return pthread_rwlock_wrlock_WRK(rwlock);
   2176    }
   2177 #elif defined(VGO_darwin)
   2178    PTH_FUNC(int, pthreadZurwlockZuwrlockZa, // pthread_rwlock_wrlock*
   2179                  pthread_rwlock_t* rwlock) {
   2180       return pthread_rwlock_wrlock_WRK(rwlock);
   2181    }
   2182 #elif defined(VGO_solaris)
   2183    PTH_FUNC(int, rwZuwrlock, // rw_wrlock
   2184                  pthread_rwlock_t *rwlock) {
   2185       return pthread_rwlock_wrlock_WRK(rwlock);
   2186    }
   2187 #else
   2188 #  error "Unsupported OS"
   2189 #endif
   2190 
   2191 #if defined(VGO_solaris)
   2192 /* Internal to libc. */
   2193 PTH_FUNC(void, lrwZuwrlock, // lrw_wrlock
   2194                rwlock_t *rwlock)
   2195 {
   2196    OrigFn fn;
   2197    VALGRIND_GET_ORIG_FN(fn);
   2198    if (TRACE_PTH_FNS) {
   2199       fprintf(stderr, "<< lrw_wlk %p", rwlock); fflush(stderr);
   2200    }
   2201 
   2202    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
   2203                  pthread_rwlock_t *, rwlock,
   2204                  long, 1/*isW*/, long, 0/*!isTryLock*/);
   2205 
   2206    CALL_FN_v_W(fn, rwlock);
   2207 
   2208    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
   2209                  pthread_rwlock_t *, rwlock, long, 1/*isW*/, long, True);
   2210 
   2211    if (TRACE_PTH_FNS) {
   2212       fprintf(stderr, " :: lrw_wlk >>\n");
   2213    }
   2214 }
   2215 #endif /* VGO_solaris */
   2216 
   2217 
   2218 //-----------------------------------------------------------
   2219 // glibc:   pthread_rwlock_rdlock
   2220 // darwin:  pthread_rwlock_rdlock
   2221 // darwin:  pthread_rwlock_rdlock$UNIX2003
   2222 // Solaris: rw_rdlock (pthread_rwlock_rdlock is a weak alias)
   2223 //
   2224 __attribute__((noinline))
   2225 static int pthread_rwlock_rdlock_WRK(pthread_rwlock_t* rwlock)
   2226 {
   2227    int    ret;
   2228    OrigFn fn;
   2229    VALGRIND_GET_ORIG_FN(fn);
   2230    if (TRACE_PTH_FNS) {
   2231       fprintf(stderr, "<< pthread_rwl_rlk %p", rwlock); fflush(stderr);
   2232    }
   2233 
   2234    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
   2235                  pthread_rwlock_t*,rwlock,
   2236                  long,0/*!isW*/, long,0/*!isTryLock*/);
   2237 
   2238    CALL_FN_W_W(ret, fn, rwlock);
   2239 
   2240    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
   2241                  pthread_rwlock_t*,rwlock, long,0/*!isW*/,
   2242                  long, (ret == 0) ? True : False);
   2243    if (ret != 0) {
   2244       DO_PthAPIerror( "pthread_rwlock_rdlock", ret );
   2245    }
   2246 
   2247    if (TRACE_PTH_FNS) {
   2248       fprintf(stderr, " :: rwl_rlk -> %d >>\n", ret);
   2249    }
   2250    return ret;
   2251 }
   2252 #if defined(VGO_linux)
   2253    PTH_FUNC(int, pthreadZurwlockZurdlock, // pthread_rwlock_rdlock
   2254                  pthread_rwlock_t* rwlock) {
   2255       return pthread_rwlock_rdlock_WRK(rwlock);
   2256    }
   2257 #elif defined(VGO_darwin)
   2258    PTH_FUNC(int, pthreadZurwlockZurdlockZa, // pthread_rwlock_rdlock*
   2259                  pthread_rwlock_t* rwlock) {
   2260       return pthread_rwlock_rdlock_WRK(rwlock);
   2261    }
   2262 #elif defined(VGO_solaris)
   2263    PTH_FUNC(int, rwZurdlock, // rw_rdlock
   2264                  pthread_rwlock_t *rwlock) {
   2265       return pthread_rwlock_rdlock_WRK(rwlock);
   2266    }
   2267 #else
   2268 #  error "Unsupported OS"
   2269 #endif
   2270 
   2271 #if defined(VGO_solaris)
   2272 /* Internal to libc. */
   2273 PTH_FUNC(void, lrwZurdlock, // lrw_rdlock
   2274                rwlock_t *rwlock)
   2275 {
   2276    OrigFn fn;
   2277    VALGRIND_GET_ORIG_FN(fn);
   2278    if (TRACE_PTH_FNS) {
   2279       fprintf(stderr, "<< lrw_rlk %p", rwlock); fflush(stderr);
   2280    }
   2281 
   2282    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
   2283                  pthread_rwlock_t *, rwlock,
   2284                  long, 0/*!isW*/, long, 0/*!isTryLock*/);
   2285 
   2286    CALL_FN_v_W(fn, rwlock);
   2287 
   2288    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
   2289                  pthread_rwlock_t *, rwlock, long, 0/*!isW*/, long, True);
   2290 
   2291    if (TRACE_PTH_FNS) {
   2292       fprintf(stderr, " :: lrw_rlk ->>\n");
   2293    }
   2294 }
   2295 #endif /* VGO_solaris */
   2296 
   2297 
   2298 //-----------------------------------------------------------
   2299 // glibc:   pthread_rwlock_trywrlock
   2300 // darwin:  pthread_rwlock_trywrlock
   2301 // darwin:  pthread_rwlock_trywrlock$UNIX2003
   2302 // Solaris: rw_trywrlock (pthread_rwlock_trywrlock is a weak alias)
   2303 //
   2304 __attribute__((noinline))
   2305 static int pthread_rwlock_trywrlock_WRK(pthread_rwlock_t* rwlock)
   2306 {
   2307    int    ret;
   2308    OrigFn fn;
   2309    VALGRIND_GET_ORIG_FN(fn);
   2310    if (TRACE_PTH_FNS) {
   2311       fprintf(stderr, "<< pthread_rwl_trywlk %p", rwlock); fflush(stderr);
   2312    }
   2313 
   2314    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
   2315                  pthread_rwlock_t*,rwlock,
   2316                  long,1/*isW*/, long,1/*isTryLock*/);
   2317 
   2318    CALL_FN_W_W(ret, fn, rwlock);
   2319 
   2320    /* There's a hole here: libpthread now knows the lock is locked,
   2321       but the tool doesn't, so some other thread could run and detect
   2322       that the lock has been acquired by someone (this thread).  Does
   2323       this matter?  Not sure, but I don't think so. */
   2324 
   2325    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
   2326                  pthread_rwlock_t*,rwlock, long,1/*isW*/,
   2327                  long, (ret == 0) ? True : False);
   2328    if (ret != 0) {
   2329       if (ret != EBUSY)
   2330          DO_PthAPIerror( "pthread_rwlock_trywrlock", ret );
   2331    }
   2332 
   2333    if (TRACE_PTH_FNS) {
   2334       fprintf(stderr, " :: rwl_trywlk -> %d >>\n", ret);
   2335    }
   2336    return ret;
   2337 }
   2338 #if defined(VGO_linux)
   2339    PTH_FUNC(int, pthreadZurwlockZutrywrlock, // pthread_rwlock_trywrlock
   2340                  pthread_rwlock_t* rwlock) {
   2341       return pthread_rwlock_trywrlock_WRK(rwlock);
   2342    }
   2343 #elif defined(VGO_darwin)
   2344    PTH_FUNC(int, pthreadZurwlockZutrywrlockZa, // pthread_rwlock_trywrlock*
   2345                  pthread_rwlock_t* rwlock) {
   2346       return pthread_rwlock_trywrlock_WRK(rwlock);
   2347    }
   2348 #elif defined(VGO_solaris)
   2349    PTH_FUNC(int, rwZutrywrlock, // rw_trywrlock
   2350                  pthread_rwlock_t *rwlock) {
   2351       return pthread_rwlock_trywrlock_WRK(rwlock);
   2352    }
   2353 #else
   2354 #  error "Unsupported OS"
   2355 #endif
   2356 
   2357 
   2358 //-----------------------------------------------------------
   2359 // glibc:   pthread_rwlock_tryrdlock
   2360 // darwin:  pthread_rwlock_tryrdlock
   2361 // darwin:  pthread_rwlock_tryrdlock$UNIX2003
   2362 // Solaris: rw_tryrdlock (pthread_rwlock_tryrdlock is a weak alias)
   2363 //
   2364 __attribute__((noinline))
   2365 static int pthread_rwlock_tryrdlock_WRK(pthread_rwlock_t* rwlock)
   2366 {
   2367    int    ret;
   2368    OrigFn fn;
   2369    VALGRIND_GET_ORIG_FN(fn);
   2370    if (TRACE_PTH_FNS) {
   2371       fprintf(stderr, "<< pthread_rwl_tryrlk %p", rwlock); fflush(stderr);
   2372    }
   2373 
   2374    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
   2375                  pthread_rwlock_t*,rwlock,
   2376                  long,0/*!isW*/, long,1/*isTryLock*/);
   2377 
   2378    CALL_FN_W_W(ret, fn, rwlock);
   2379 
   2380    /* There's a hole here: libpthread now knows the lock is locked,
   2381       but the tool doesn't, so some other thread could run and detect
   2382       that the lock has been acquired by someone (this thread).  Does
   2383       this matter?  Not sure, but I don't think so. */
   2384 
   2385    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
   2386                 pthread_rwlock_t*,rwlock, long,0/*!isW*/,
   2387                 long, (ret == 0) ? True : False);
   2388 
   2389    if (ret != 0) {
   2390       if (ret != EBUSY)
   2391          DO_PthAPIerror( "pthread_rwlock_tryrdlock", ret );
   2392    }
   2393 
   2394    if (TRACE_PTH_FNS) {
   2395       fprintf(stderr, " :: rwl_tryrlk -> %d >>\n", ret);
   2396    }
   2397    return ret;
   2398 }
   2399 #if defined(VGO_linux)
   2400    PTH_FUNC(int, pthreadZurwlockZutryrdlock, // pthread_rwlock_tryrdlock
   2401                  pthread_rwlock_t* rwlock) {
   2402       return pthread_rwlock_tryrdlock_WRK(rwlock);
   2403    }
   2404 #elif defined(VGO_darwin)
   2405    PTH_FUNC(int, pthreadZurwlockZutryrdlockZa, // pthread_rwlock_tryrdlock*
   2406                  pthread_rwlock_t* rwlock) {
   2407       return pthread_rwlock_tryrdlock_WRK(rwlock);
   2408    }
   2409 #elif defined(VGO_solaris)
   2410    PTH_FUNC(int, rwZutryrdlock, // rw_tryrdlock
   2411                  pthread_rwlock_t *rwlock) {
   2412       return pthread_rwlock_tryrdlock_WRK(rwlock);
   2413    }
   2414 #else
   2415 #  error "Unsupported OS"
   2416 #endif
   2417 
   2418 
   2419 //-----------------------------------------------------------
   2420 // glibc:   Unhandled
   2421 // darwin:  Unhandled
   2422 // Solaris: pthread_rwlock_timedrdlock
   2423 // Solaris: pthread_rwlock_reltimedrdlock_np
   2424 //
   2425 __attribute__((noinline)) __attribute__((unused))
   2426 static int pthread_rwlock_timedrdlock_WRK(pthread_rwlock_t *rwlock,
   2427                                           const struct timespec *timeout)
   2428 {
   2429    int    ret;
   2430    OrigFn fn;
   2431    VALGRIND_GET_ORIG_FN(fn);
   2432    if (TRACE_PTH_FNS) {
   2433       fprintf(stderr, "<< pthread_rwl_timedrdl %p", rwlock); fflush(stderr);
   2434    }
   2435 
   2436    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
   2437                  pthread_rwlock_t *, rwlock,
   2438                  long, 0/*isW*/, long, 0/*isTryLock*/);
   2439 
   2440    CALL_FN_W_WW(ret, fn, rwlock, timeout);
   2441 
   2442    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
   2443                  pthread_rwlock_t *, rwlock, long, 0/*isW*/,
   2444                  long, (ret == 0) ? True : False);
   2445    if (ret != 0) {
   2446       DO_PthAPIerror("pthread_rwlock_timedrdlock", ret);
   2447    }
   2448 
   2449    if (TRACE_PTH_FNS) {
   2450       fprintf(stderr, " :: rwl_timedrdl -> %d >>\n", ret);
   2451    }
   2452    return ret;
   2453 }
   2454 #if defined(VGO_linux)
   2455 #elif defined(VGO_darwin)
   2456 #elif defined(VGO_solaris)
   2457    PTH_FUNC(int, pthreadZurwlockZutimedrdlock, // pthread_rwlock_timedrdlock
   2458                  pthread_rwlock_t *rwlock,
   2459                  const struct timespec *timeout) {
   2460       return pthread_rwlock_timedrdlock_WRK(rwlock, timeout);
   2461    }
   2462    PTH_FUNC(int, pthreadZurwlockZureltimedrdlockZunp, // pthread_rwlock_timedrdlock_np
   2463                  pthread_rwlock_t *rwlock,
   2464                  const struct timespec *timeout) {
   2465       return pthread_rwlock_timedrdlock_WRK(rwlock, timeout);
   2466    }
   2467 #else
   2468 #  error "Unsupported OS"
   2469 #endif
   2470 
   2471 
   2472 //-----------------------------------------------------------
   2473 // glibc:   Unhandled
   2474 // darwin:  Unhandled
   2475 // Solaris: pthread_rwlock_timedwrlock
   2476 // Solaris: pthread_rwlock_reltimedwrlock_np
   2477 //
   2478 __attribute__((noinline)) __attribute__((unused))
   2479 static int pthread_rwlock_timedwrlock_WRK(pthread_rwlock_t *rwlock,
   2480                                           const struct timespec *timeout)
   2481 {
   2482    int    ret;
   2483    OrigFn fn;
   2484    VALGRIND_GET_ORIG_FN(fn);
   2485    if (TRACE_PTH_FNS) {
   2486       fprintf(stderr, "<< pthread_rwl_timedwrl %p", rwlock); fflush(stderr);
   2487    }
   2488 
   2489    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
   2490                  pthread_rwlock_t *, rwlock,
   2491                  long, 1/*isW*/, long, 0/*isTryLock*/);
   2492 
   2493    CALL_FN_W_WW(ret, fn, rwlock, timeout);
   2494 
   2495    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
   2496                  pthread_rwlock_t *, rwlock, long, 1/*isW*/,
   2497                  long, (ret == 0) ? True : False);
   2498    if (ret != 0) {
   2499       DO_PthAPIerror("pthread_rwlock_timedwrlock", ret);
   2500    }
   2501 
   2502    if (TRACE_PTH_FNS) {
   2503       fprintf(stderr, " :: rwl_timedwrl -> %d >>\n", ret);
   2504    }
   2505    return ret;
   2506 }
   2507 #if defined(VGO_linux)
   2508 #elif defined(VGO_darwin)
   2509 #elif defined(VGO_solaris)
   2510    PTH_FUNC(int, pthreadZurwlockZutimedwrlock, // pthread_rwlock_timedwrlock
   2511                  pthread_rwlock_t *rwlock,
   2512                  const struct timespec *timeout) {
   2513       return pthread_rwlock_timedwrlock_WRK(rwlock, timeout);
   2514    }
   2515    PTH_FUNC(int, pthreadZurwlockZureltimedwrlockZunp, // pthread_rwlock_timedwrlock_np
   2516                  pthread_rwlock_t *rwlock,
   2517                  const struct timespec *timeout) {
   2518       return pthread_rwlock_timedwrlock_WRK(rwlock, timeout);
   2519    }
   2520 #else
   2521 #  error "Unsupported OS"
   2522 #endif
   2523 
   2524 
   2525 //-----------------------------------------------------------
   2526 // glibc:   pthread_rwlock_unlock
   2527 // darwin:  pthread_rwlock_unlock
   2528 // darwin:  pthread_rwlock_unlock$UNIX2003
   2529 // Solaris: rw_unlock (pthread_rwlock_unlock is a weak alias)
   2530 __attribute__((noinline))
   2531 static int pthread_rwlock_unlock_WRK(pthread_rwlock_t* rwlock)
   2532 {
   2533    int    ret;
   2534    OrigFn fn;
   2535    VALGRIND_GET_ORIG_FN(fn);
   2536    if (TRACE_PTH_FNS) {
   2537       fprintf(stderr, "<< pthread_rwl_unlk %p", rwlock); fflush(stderr);
   2538    }
   2539 
   2540    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
   2541                pthread_rwlock_t*,rwlock);
   2542 
   2543    CALL_FN_W_W(ret, fn, rwlock);
   2544 
   2545    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
   2546                pthread_rwlock_t*,rwlock);
   2547    if (ret != 0) {
   2548       DO_PthAPIerror( "pthread_rwlock_unlock", ret );
   2549    }
   2550 
   2551    if (TRACE_PTH_FNS) {
   2552       fprintf(stderr, " :: rwl_unlk -> %d >>\n", ret);
   2553    }
   2554    return ret;
   2555 }
   2556 #if defined(VGO_linux)
   2557    PTH_FUNC(int, pthreadZurwlockZuunlock, // pthread_rwlock_unlock
   2558                  pthread_rwlock_t* rwlock) {
   2559       return pthread_rwlock_unlock_WRK(rwlock);
   2560    }
   2561 #elif defined(VGO_darwin)
   2562    PTH_FUNC(int, pthreadZurwlockZuunlockZa, // pthread_rwlock_unlock*
   2563                  pthread_rwlock_t* rwlock) {
   2564       return pthread_rwlock_unlock_WRK(rwlock);
   2565    }
   2566 #elif defined(VGO_solaris)
   2567    PTH_FUNC(int, rwZuunlock, // rw_unlock
   2568                  pthread_rwlock_t *rwlock) {
   2569       return pthread_rwlock_unlock_WRK(rwlock);
   2570    }
   2571 #else
   2572 #  error "Unsupported OS"
   2573 #endif
   2574 
   2575 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
   2576 
   2577 
   2578 /*----------------------------------------------------------------*/
   2579 /*--- POSIX semaphores                                         ---*/
   2580 /*----------------------------------------------------------------*/
   2581 
   2582 #include <semaphore.h>
   2583 #include <fcntl.h>       /* O_CREAT */
   2584 
   2585 #define TRACE_SEM_FNS 0
   2586 
   2587 /* Handled:
   2588      int sem_init(sem_t *sem, int pshared, unsigned value);
   2589      int sem_destroy(sem_t *sem);
   2590      int sem_wait(sem_t *sem);
   2591      int sem_post(sem_t *sem);
   2592      sem_t* sem_open(const char *name, int oflag,
   2593                      ... [mode_t mode, unsigned value]);
   2594         [complete with its idiotic semantics]
   2595      int sem_close(sem_t* sem);
   2596 
   2597    Unhandled:
   2598      int sem_trywait(sem_t *sem);
   2599      int sem_timedwait(sem_t *restrict sem,
   2600                        const struct timespec *restrict abs_timeout);
   2601 */
   2602 
   2603 //-----------------------------------------------------------
   2604 // glibc:   sem_init@@GLIBC_2.2.5
   2605 // glibc:   sem_init@@GLIBC_2.1
   2606 // glibc:   sem_init (at) GLIBC_2.0
   2607 // darwin:  sem_init
   2608 // Solaris: sema_init (sem_init is built on top of sem_init)
   2609 //
   2610 #if !defined(VGO_solaris)
   2611 __attribute__((noinline))
   2612 static int sem_init_WRK(sem_t* sem, int pshared, unsigned long value)
   2613 {
   2614    OrigFn fn;
   2615    int    ret;
   2616    VALGRIND_GET_ORIG_FN(fn);
   2617 
   2618    if (TRACE_SEM_FNS) {
   2619       fprintf(stderr, "<< sem_init(%p,%d,%lu) ", sem,pshared,value);
   2620       fflush(stderr);
   2621    }
   2622 
   2623    CALL_FN_W_WWW(ret, fn, sem,pshared,value);
   2624 
   2625    if (ret == 0) {
   2626       DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
   2627                    sem_t*, sem, unsigned long, value);
   2628    } else {
   2629       DO_PthAPIerror( "sem_init", errno );
   2630    }
   2631 
   2632    if (TRACE_SEM_FNS) {
   2633       fprintf(stderr, " sem_init -> %d >>\n", ret);
   2634       fflush(stderr);
   2635    }
   2636 
   2637    return ret;
   2638 }
   2639 #if defined(VGO_linux)
   2640    PTH_FUNC(int, semZuinitZAZa, // sem_init@*
   2641                  sem_t* sem, int pshared, unsigned long value) {
   2642       return sem_init_WRK(sem, pshared, value);
   2643    }
   2644 #elif defined(VGO_darwin)
   2645    PTH_FUNC(int, semZuinit, // sem_init
   2646                  sem_t* sem, int pshared, unsigned long value) {
   2647       return sem_init_WRK(sem, pshared, value);
   2648    }
   2649 #else
   2650 #  error "Unsupported OS"
   2651 #endif
   2652 
   2653 #else /* VGO_solaris */
   2654 PTH_FUNC(int, semaZuinit, // sema_init
   2655               sema_t *sem,
   2656               unsigned int value,
   2657               int type,
   2658               void *arg)
   2659 {
   2660    OrigFn fn;
   2661    int    ret;
   2662    VALGRIND_GET_ORIG_FN(fn);
   2663 
   2664    if (TRACE_SEM_FNS) {
   2665       fprintf(stderr, "<< sema_init(%p, %d, %u) ", sem, type, value);
   2666       fflush(stderr);
   2667    }
   2668 
   2669    CALL_FN_W_WWWW(ret, fn, sem, value, type, arg);
   2670 
   2671    if (ret == 0) {
   2672       DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
   2673                    sema_t *, sem, Word, value);
   2674    } else {
   2675       DO_PthAPIerror("sema_init", ret);
   2676    }
   2677 
   2678    if (TRACE_SEM_FNS) {
   2679       fprintf(stderr, " sema_init -> %d >>\n", ret);
   2680       fflush(stderr);
   2681    }
   2682 
   2683    return ret;
   2684 }
   2685 #endif /* VGO_solaris */
   2686 
   2687 
   2688 //-----------------------------------------------------------
   2689 // glibc:   sem_destroy (at) GLIBC_2.0
   2690 // glibc:   sem_destroy@@GLIBC_2.1
   2691 // glibc:   sem_destroy@@GLIBC_2.2.5
   2692 // darwin:  sem_destroy
   2693 // Solaris: sema_destroy (sem_destroy is built on top of sema_destroy)
   2694 __attribute__((noinline))
   2695 static int sem_destroy_WRK(sem_t* sem)
   2696 {
   2697    OrigFn fn;
   2698    int    ret;
   2699    VALGRIND_GET_ORIG_FN(fn);
   2700 
   2701    if (TRACE_SEM_FNS) {
   2702       fprintf(stderr, "<< sem_destroy(%p) ", sem);
   2703       fflush(stderr);
   2704    }
   2705 
   2706    DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
   2707 
   2708    CALL_FN_W_W(ret, fn, sem);
   2709 
   2710    if (ret != 0) {
   2711       DO_PthAPIerror( "sem_destroy", SEM_ERROR );
   2712    }
   2713 
   2714    if (TRACE_SEM_FNS) {
   2715       fprintf(stderr, " sem_destroy -> %d >>\n", ret);
   2716       fflush(stderr);
   2717    }
   2718 
   2719    return ret;
   2720 }
   2721 #if defined(VGO_linux)
   2722    PTH_FUNC(int, semZudestroyZAZa,  // sem_destroy*
   2723                  sem_t* sem) {
   2724       return sem_destroy_WRK(sem);
   2725    }
   2726 #elif defined(VGO_darwin)
   2727    PTH_FUNC(int, semZudestroy,  // sem_destroy
   2728                  sem_t* sem) {
   2729       return sem_destroy_WRK(sem);
   2730    }
   2731 #elif defined(VGO_solaris)
   2732    PTH_FUNC(int, semaZudestroy,  // sema_destroy
   2733                  sem_t *sem) {
   2734       return sem_destroy_WRK(sem);
   2735    }
   2736 #else
   2737 #  error "Unsupported OS"
   2738 #endif
   2739 
   2740 
   2741 //-----------------------------------------------------------
   2742 // glibc:   sem_wait
   2743 // glibc:   sem_wait (at) GLIBC_2.0
   2744 // glibc:   sem_wait@@GLIBC_2.1
   2745 // darwin:  sem_wait
   2746 // darwin:  sem_wait$NOCANCEL$UNIX2003
   2747 // darwin:  sem_wait$UNIX2003
   2748 // Solaris: sema_wait (sem_wait is built on top of sema_wait)
   2749 //
   2750 /* wait: decrement semaphore - acquire lockage */
   2751 __attribute__((noinline))
   2752 static int sem_wait_WRK(sem_t* sem)
   2753 {
   2754    OrigFn fn;
   2755    int    ret;
   2756    VALGRIND_GET_ORIG_FN(fn);
   2757 
   2758    if (TRACE_SEM_FNS) {
   2759       fprintf(stderr, "<< sem_wait(%p) ", sem);
   2760       fflush(stderr);
   2761    }
   2762 
   2763    DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_PRE, sem_t*,sem);
   2764 
   2765    CALL_FN_W_W(ret, fn, sem);
   2766 
   2767    DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST, sem_t*,sem,
   2768                 long, (ret == 0) ? True : False);
   2769 
   2770    if (ret != 0) {
   2771       DO_PthAPIerror( "sem_wait", SEM_ERROR );
   2772    }
   2773 
   2774    if (TRACE_SEM_FNS) {
   2775       fprintf(stderr, " sem_wait -> %d >>\n", ret);
   2776       fflush(stderr);
   2777    }
   2778 
   2779    return ret;
   2780 }
   2781 #if defined(VGO_linux)
   2782    PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
   2783       return sem_wait_WRK(sem);
   2784    }
   2785    PTH_FUNC(int, semZuwaitZAZa, sem_t* sem) { /* sem_wait@* */
   2786       return sem_wait_WRK(sem);
   2787    }
   2788 #elif defined(VGO_darwin)
   2789    PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
   2790       return sem_wait_WRK(sem);
   2791    }
   2792    PTH_FUNC(int, semZuwaitZDZa, sem_t* sem) { /* sem_wait$* */
   2793       return sem_wait_WRK(sem);
   2794    }
   2795 #elif defined(VGO_solaris)
   2796    PTH_FUNC(int, semaZuwait, sem_t *sem) { /* sema_wait */
   2797       return sem_wait_WRK(sem);
   2798    }
   2799 #else
   2800 #  error "Unsupported OS"
   2801 #endif
   2802 
   2803 
   2804 //-----------------------------------------------------------
   2805 // glibc:   sem_post
   2806 // glibc:   sem_post (at) GLIBC_2.0
   2807 // glibc:   sem_post@@GLIBC_2.1
   2808 // darwin:  sem_post
   2809 // Solaris: sema_post (sem_post is built on top of sema_post)
   2810 //
   2811 /* post: increment semaphore - release lockage */
   2812 __attribute__((noinline))
   2813 static int sem_post_WRK(sem_t* sem)
   2814 {
   2815    OrigFn fn;
   2816    int    ret;
   2817 
   2818    VALGRIND_GET_ORIG_FN(fn);
   2819 
   2820    if (TRACE_SEM_FNS) {
   2821       fprintf(stderr, "<< sem_post(%p) ", sem);
   2822       fflush(stderr);
   2823    }
   2824 
   2825    DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_PRE, sem_t*,sem);
   2826 
   2827    CALL_FN_W_W(ret, fn, sem);
   2828 
   2829    DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_POST, sem_t*,sem);
   2830 
   2831    if (ret != 0) {
   2832       DO_PthAPIerror( "sem_post", SEM_ERROR );
   2833    }
   2834 
   2835    if (TRACE_SEM_FNS) {
   2836       fprintf(stderr, " sem_post -> %d >>\n", ret);
   2837       fflush(stderr);
   2838    }
   2839 
   2840    return ret;
   2841 }
   2842 #if defined(VGO_linux)
   2843    PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
   2844       return sem_post_WRK(sem);
   2845    }
   2846    PTH_FUNC(int, semZupostZAZa, sem_t* sem) { /* sem_post@* */
   2847       return sem_post_WRK(sem);
   2848    }
   2849 #elif defined(VGO_darwin)
   2850    PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
   2851       return sem_post_WRK(sem);
   2852    }
   2853 #elif defined(VGO_solaris)
   2854    PTH_FUNC(int, semaZupost, sem_t *sem) { /* sema_post */
   2855       return sem_post_WRK(sem);
   2856    }
   2857 #else
   2858 #  error "Unsupported OS"
   2859 #endif
   2860 
   2861 
   2862 //-----------------------------------------------------------
   2863 // glibc:   sem_open
   2864 // darwin:  sem_open
   2865 // Solaris: sem_open
   2866 //
   2867 PTH_FUNC(sem_t*, semZuopen,
   2868                  const char* name, long oflag,
   2869                  long mode, unsigned long value)
   2870 {
   2871    /* A copy of sem_init_WRK (more or less).  Is this correct? */
   2872    OrigFn fn;
   2873    sem_t* ret;
   2874    VALGRIND_GET_ORIG_FN(fn);
   2875 
   2876    if (TRACE_SEM_FNS) {
   2877       fprintf(stderr, "<< sem_open(\"%s\",%ld,%lx,%lu) ",
   2878                       name,oflag,mode,value);
   2879       fflush(stderr);
   2880    }
   2881 
   2882    CALL_FN_W_WWWW(ret, fn, name,oflag,mode,value);
   2883 
   2884    if (ret != SEM_FAILED && (oflag & O_CREAT)) {
   2885       DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
   2886                    sem_t*, ret, unsigned long, value);
   2887    }
   2888    if (ret == SEM_FAILED) {
   2889       DO_PthAPIerror( "sem_open", errno );
   2890    }
   2891 
   2892    if (TRACE_SEM_FNS) {
   2893       fprintf(stderr, " sem_open -> %p >>\n", ret);
   2894       fflush(stderr);
   2895    }
   2896 
   2897    return ret;
   2898 }
   2899 
   2900 
   2901 //-----------------------------------------------------------
   2902 // glibc:   sem_close
   2903 // darwin:  sem_close
   2904 // Solaris: sem_close
   2905 PTH_FUNC(int, sem_close, sem_t* sem)
   2906 {
   2907    OrigFn fn;
   2908    int    ret;
   2909    VALGRIND_GET_ORIG_FN(fn);
   2910 
   2911    if (TRACE_SEM_FNS) {
   2912       fprintf(stderr, "<< sem_close(%p) ", sem);
   2913       fflush(stderr);
   2914    }
   2915 
   2916    DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
   2917 
   2918    CALL_FN_W_W(ret, fn, sem);
   2919 
   2920    if (ret != 0) {
   2921       DO_PthAPIerror( "sem_close", errno );
   2922    }
   2923 
   2924    if (TRACE_SEM_FNS) {
   2925       fprintf(stderr, " close -> %d >>\n", ret);
   2926       fflush(stderr);
   2927    }
   2928 
   2929    return ret;
   2930 }
   2931 
   2932 
   2933 /*----------------------------------------------------------------*/
   2934 /*--- Qt 4 threading functions (w/ GNU name mangling)          ---*/
   2935 /*----------------------------------------------------------------*/
   2936 
   2937 /* Handled:
   2938       QMutex::lock()
   2939       QMutex::unlock()
   2940       QMutex::tryLock()
   2941       QMutex::tryLock(int)
   2942 
   2943       QMutex::QMutex(QMutex::RecursionMode)  _ZN6QMutexC1ENS_13RecursionModeE
   2944       QMutex::QMutex(QMutex::RecursionMode)  _ZN6QMutexC2ENS_13RecursionModeE
   2945       QMutex::~QMutex()                      _ZN6QMutexD1Ev
   2946       QMutex::~QMutex()                      _ZN6QMutexD2Ev
   2947 
   2948    Unhandled:
   2949       QReadWriteLock::lockForRead()
   2950       QReadWriteLock::lockForWrite()
   2951       QReadWriteLock::unlock()
   2952       QReadWriteLock::tryLockForRead(int)
   2953       QReadWriteLock::tryLockForRead()
   2954       QReadWriteLock::tryLockForWrite(int)
   2955       QReadWriteLock::tryLockForWrite()
   2956 
   2957       QWaitCondition::wait(QMutex*, unsigned long)
   2958       QWaitCondition::wakeAll()
   2959       QWaitCondition::wakeOne()
   2960 
   2961       QSemaphore::*
   2962 */
   2963 /* More comments, 19 Nov 08, based on assessment of qt-4.5.0TP1,
   2964    at least on Unix:
   2965 
   2966    It's apparently only necessary to intercept QMutex, since that is
   2967    not implemented using pthread_mutex_t; instead Qt4 has its own
   2968    implementation based on atomics (to check the non-contended case)
   2969    and pthread_cond_wait (to wait in the contended case).
   2970 
   2971    QReadWriteLock is built on top of QMutex, counters, and a wait
   2972    queue.  So we don't need to handle it specially once QMutex
   2973    handling is correct -- presumably the dependencies through QMutex
   2974    are sufficient to avoid any false race reports.  On the other hand,
   2975    it is an open question whether too many dependencies are observed
   2976    -- in which case we may miss races (false negatives).  I suspect
   2977    this is likely to be the case, unfortunately.
   2978 
   2979    QWaitCondition is built on pthread_cond_t, pthread_mutex_t, QMutex
   2980    and QReadWriteLock.  Same compositional-correctness justificiation
   2981    and limitations as fro QReadWriteLock.
   2982 
   2983    Ditto QSemaphore (from cursory examination).
   2984 
   2985    Does it matter that only QMutex is handled directly?  Open
   2986    question.  From testing with drd/tests/qt4_* and with KDE4 apps, it
   2987    appears that no false errors are reported; however it is not clear
   2988    if this is causing false negatives.
   2989 
   2990    Another problem with Qt4 is thread exiting.  Threads are created
   2991    with pthread_create (fine); but they detach and simply exit when
   2992    done.  There is no use of pthread_join, and the provided
   2993    wait-for-a-thread-to-exit mechanism (QThread::wait, I believe)
   2994    relies on a system of mutexes and flags.  I suspect this also
   2995    causes too many dependencies to appear.  Consequently H sometimes
   2996    fails to detect races at exit in some very short-lived racy
   2997    programs, because it appears that a thread can exit _and_ have an
   2998    observed dependency edge back to the main thread (presumably)
   2999    before the main thread reaps the child (that is, calls
   3000    QThread::wait).
   3001 
   3002    This theory is supported by the observation that if all threads are
   3003    made to wait at a pthread_barrier_t immediately before they exit,
   3004    then H's detection of races in such programs becomes reliable;
   3005    without the barrier, it is varies from run to run, depending
   3006    (according to investigation) on whether aforementioned
   3007    exit-before-reaping behaviour happens or not.
   3008 
   3009    Finally, why is it necessary to intercept the QMutex constructors
   3010    and destructors?  The constructors are intercepted only as a matter
   3011    of convenience, so H can print accurate "first observed at"
   3012    clauses.  However, it is actually necessary to intercept the
   3013    destructors (as it is with pthread_mutex_destroy) in order that
   3014    locks get removed from LAOG when they are destroyed.
   3015 */
   3016 
   3017 // soname is libQtCore.so.4 ; match against libQtCore.so*
   3018 #define QT4_FUNC(ret_ty, f, args...) \
   3019    ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args); \
   3020    ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args)
   3021 
   3022 // soname is libQt5Core.so.4 ; match against libQt5Core.so*
   3023 #define QT5_FUNC(ret_ty, f, args...) \
   3024    ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args); \
   3025    ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args)
   3026 
   3027 //-----------------------------------------------------------
   3028 // QMutex::lock()
   3029 __attribute__((noinline))
   3030 static void QMutex_lock_WRK(void* self)
   3031 {
   3032    OrigFn fn;
   3033    VALGRIND_GET_ORIG_FN(fn);
   3034    if (TRACE_QT4_FNS) {
   3035       fprintf(stderr, "<< QMutex::lock %p", self); fflush(stderr);
   3036    }
   3037 
   3038    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
   3039                 void*,self, long,0/*!isTryLock*/);
   3040 
   3041    CALL_FN_v_W(fn, self);
   3042 
   3043    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
   3044                 void *, self, long, True);
   3045 
   3046    if (TRACE_QT4_FNS) {
   3047       fprintf(stderr, " :: Q::lock done >>\n");
   3048    }
   3049 }
   3050 
   3051 QT4_FUNC(void, _ZN6QMutex4lockEv, void* self) {
   3052     QMutex_lock_WRK(self);
   3053 }
   3054 QT5_FUNC(void, _ZN6QMutex4lockEv, void* self) {
   3055     QMutex_lock_WRK(self);
   3056 }
   3057 
   3058 //-----------------------------------------------------------
   3059 // QMutex::unlock()
   3060 __attribute__((noinline))
   3061 static void QMutex_unlock_WRK(void* self)
   3062 {
   3063    OrigFn fn;
   3064    VALGRIND_GET_ORIG_FN(fn);
   3065 
   3066    if (TRACE_QT4_FNS) {
   3067       fprintf(stderr, "<< QMutex::unlock %p", self); fflush(stderr);
   3068    }
   3069 
   3070    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
   3071                void*, self);
   3072 
   3073    CALL_FN_v_W(fn, self);
   3074 
   3075    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
   3076                void*, self);
   3077 
   3078    if (TRACE_QT4_FNS) {
   3079       fprintf(stderr, " Q::unlock done >>\n");
   3080    }
   3081 }
   3082 
   3083 QT4_FUNC(void, _ZN6QMutex6unlockEv, void* self) {
   3084     QMutex_unlock_WRK(self);
   3085 }
   3086 QT5_FUNC(void, _ZN6QMutex6unlockEv, void* self) {
   3087     QMutex_unlock_WRK(self);
   3088 }
   3089 
   3090 //-----------------------------------------------------------
   3091 // bool QMutex::tryLock()
   3092 // using 'long' to mimic C++ 'bool'
   3093 __attribute__((noinline))
   3094 static long QMutex_tryLock_WRK(void* self)
   3095 {
   3096    OrigFn fn;
   3097    long   ret;
   3098    VALGRIND_GET_ORIG_FN(fn);
   3099    if (TRACE_QT4_FNS) {
   3100       fprintf(stderr, "<< QMutex::tryLock %p", self); fflush(stderr);
   3101    }
   3102 
   3103    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
   3104                 void*,self, long,1/*isTryLock*/);
   3105 
   3106    CALL_FN_W_W(ret, fn, self);
   3107 
   3108    // assumes that only the low 8 bits of the 'bool' are significant
   3109    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
   3110                 void *, self, long, (ret & 0xFF) ? True : False);
   3111 
   3112    if (TRACE_QT4_FNS) {
   3113       fprintf(stderr, " :: Q::tryLock -> %lu >>\n", ret);
   3114    }
   3115 
   3116    return ret;
   3117 }
   3118 
   3119 QT4_FUNC(long, _ZN6QMutex7tryLockEv, void* self) {
   3120     return QMutex_tryLock_WRK(self);
   3121 }
   3122 QT5_FUNC(long, _ZN6QMutex7tryLockEv, void* self) {
   3123     return QMutex_tryLock_WRK(self);
   3124 }
   3125 
   3126 //-----------------------------------------------------------
   3127 // bool QMutex::tryLock(int)
   3128 // using 'long' to mimic C++ 'bool'
   3129 __attribute__((noinline))
   3130 static long QMutex_tryLock_int_WRK(void* self, long arg2)
   3131 {
   3132    OrigFn fn;
   3133    long   ret;
   3134    VALGRIND_GET_ORIG_FN(fn);
   3135    if (TRACE_QT4_FNS) {
   3136       fprintf(stderr, "<< QMutex::tryLock(int) %p %d", self, (int)arg2);
   3137       fflush(stderr);
   3138    }
   3139 
   3140    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
   3141                 void*,self, long,1/*isTryLock*/);
   3142 
   3143    CALL_FN_W_WW(ret, fn, self,arg2);
   3144 
   3145    // assumes that only the low 8 bits of the 'bool' are significant
   3146    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
   3147                void *, self, long, (ret & 0xFF) ? True : False);
   3148 
   3149    if (TRACE_QT4_FNS) {
   3150       fprintf(stderr, " :: Q::tryLock(int) -> %lu >>\n", ret);
   3151    }
   3152 
   3153    return ret;
   3154 }
   3155 
   3156 QT4_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2) {
   3157     return QMutex_tryLock_int_WRK(self, arg2);
   3158 }
   3159 QT5_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2) {
   3160     return QMutex_tryLock_int_WRK(self, arg2);
   3161 }
   3162 
   3163 //-----------------------------------------------------------
   3164 // It's not really very clear what the args are here.  But from
   3165 // a bit of dataflow analysis of the generated machine code of
   3166 // the original function, it appears this takes two args, and
   3167 // returns nothing.  Nevertheless preserve return value just in
   3168 // case.  A bit of debug printing indicates that the first arg
   3169 // is that of the mutex and the second is either zero or one,
   3170 // probably being the recursion mode, therefore.
   3171 // QMutex::QMutex(QMutex::RecursionMode)  ("C1ENS" variant)
   3172 __attribute__((noinline))
   3173 static void* QMutex_constructor_WRK(void* mutex, long recmode)
   3174 {
   3175    OrigFn fn;
   3176    long   ret;
   3177    VALGRIND_GET_ORIG_FN(fn);
   3178    CALL_FN_W_WW(ret, fn, mutex, recmode);
   3179    //   fprintf(stderr, "QMutex constructor 1: %p <- %p %p\n", ret, arg1, arg2);
   3180    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
   3181                 void*,mutex, long,1/*mbRec*/);
   3182    return (void*)ret;
   3183 }
   3184 
   3185 QT4_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE, void* self, long recmode) {
   3186     return QMutex_constructor_WRK(self, recmode);
   3187 }
   3188 QT5_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE, void* self, long recmode) {
   3189     return QMutex_constructor_WRK(self, recmode);
   3190 }
   3191 
   3192 //-----------------------------------------------------------
   3193 // QMutex::~QMutex()  ("D1Ev" variant)
   3194 __attribute__((noinline))
   3195 static void* QMutex_destructor_WRK(void* mutex)
   3196 {
   3197    OrigFn fn;
   3198    long   ret;
   3199    VALGRIND_GET_ORIG_FN(fn);
   3200    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
   3201                void*,mutex);
   3202    CALL_FN_W_W(ret, fn, mutex);
   3203    return (void*)ret;
   3204 }
   3205 
   3206 QT4_FUNC(void*, _ZN6QMutexD1Ev, void* self) {
   3207     return QMutex_destructor_WRK(self);
   3208 }
   3209 QT5_FUNC(void*, _ZN6QMutexD1Ev, void* self) {
   3210     return QMutex_destructor_WRK(self);
   3211 }
   3212 
   3213 //-----------------------------------------------------------
   3214 // QMutex::QMutex(QMutex::RecursionMode)  ("C2ENS" variant)
   3215 QT4_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE,
   3216          void* mutex,
   3217          long  recmode)
   3218 {
   3219    assert(0);
   3220    /*NOTREACHED*/
   3221    /* Android's gcc behaves like it doesn't know that assert(0)
   3222       never returns.  Hence: */
   3223    return NULL;
   3224 }
   3225 
   3226 QT5_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE, void* self, long recmode)
   3227 {
   3228    assert(0);
   3229    /*NOTREACHED*/
   3230    return NULL;
   3231 }
   3232 
   3233 //-----------------------------------------------------------
   3234 // QMutex::~QMutex()  ("D2Ev" variant)
   3235 QT4_FUNC(void*, _ZN6QMutexD2Ev, void* mutex)
   3236 {
   3237    assert(0);
   3238    /* Android's gcc behaves like it doesn't know that assert(0)
   3239       never returns.  Hence: */
   3240    return NULL;
   3241 }
   3242 
   3243 QT5_FUNC(void*, _ZN6QMutexD2Ev, void* self)
   3244 {
   3245    assert(0);
   3246    /*NOTREACHED*/
   3247    return NULL;
   3248 }
   3249 
   3250 // QReadWriteLock is not intercepted directly.  See comments
   3251 // above.
   3252 
   3253 //// QReadWriteLock::lockForRead()
   3254 //// _ZN14QReadWriteLock11lockForReadEv == QReadWriteLock::lockForRead()
   3255 //QT4_FUNC(void, ZuZZN14QReadWriteLock11lockForReadEv,
   3256 //               // _ZN14QReadWriteLock11lockForReadEv
   3257 //               void* self)
   3258 //{
   3259 //   OrigFn fn;
   3260 //   VALGRIND_GET_ORIG_FN(fn);
   3261 //   if (TRACE_QT4_FNS) {
   3262 //      fprintf(stderr, "<< QReadWriteLock::lockForRead %p", self);
   3263 //      fflush(stderr);
   3264 //   }
   3265 //
   3266 //   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
   3267 //                 void*,self,
   3268 //                 long,0/*!isW*/, long,0/*!isTryLock*/);
   3269 //
   3270 //   CALL_FN_v_W(fn, self);
   3271 //
   3272 //   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
   3273 //                 void*,self, long,0/*!isW*/, long, True);
   3274 //
   3275 //   if (TRACE_QT4_FNS) {
   3276 //      fprintf(stderr, " :: Q::lockForRead :: done >>\n");
   3277 //   }
   3278 //}
   3279 //
   3280 //// QReadWriteLock::lockForWrite()
   3281 //// _ZN14QReadWriteLock12lockForWriteEv == QReadWriteLock::lockForWrite()
   3282 //QT4_FUNC(void, ZuZZN14QReadWriteLock12lockForWriteEv,
   3283 //               // _ZN14QReadWriteLock12lockForWriteEv
   3284 //               void* self)
   3285 //{
   3286 //   OrigFn fn;
   3287 //   VALGRIND_GET_ORIG_FN(fn);
   3288 //   if (TRACE_QT4_FNS) {
   3289 //      fprintf(stderr, "<< QReadWriteLock::lockForWrite %p", self);
   3290 //      fflush(stderr);
   3291 //   }
   3292 //
   3293 //   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
   3294 //                 void*,self,
   3295 //                 long,1/*isW*/, long,0/*!isTryLock*/);
   3296 //
   3297 //   CALL_FN_v_W(fn, self);
   3298 //
   3299 //   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
   3300 //                 void*,self, long,1/*isW*/, long, True);
   3301 //
   3302 //   if (TRACE_QT4_FNS) {
   3303 //      fprintf(stderr, " :: Q::lockForWrite :: done >>\n");
   3304 //   }
   3305 //}
   3306 //
   3307 //// QReadWriteLock::unlock()
   3308 //// _ZN14QReadWriteLock6unlockEv == QReadWriteLock::unlock()
   3309 //QT4_FUNC(void, ZuZZN14QReadWriteLock6unlockEv,
   3310 //               // _ZN14QReadWriteLock6unlockEv
   3311 //               void* self)
   3312 //{
   3313 //   OrigFn fn;
   3314 //   VALGRIND_GET_ORIG_FN(fn);
   3315 //   if (TRACE_QT4_FNS) {
   3316 //      fprintf(stderr, "<< QReadWriteLock::unlock %p", self);
   3317 //      fflush(stderr);
   3318 //   }
   3319 //
   3320 //   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
   3321 //               void*,self);
   3322 //
   3323 //   CALL_FN_v_W(fn, self);
   3324 //
   3325 //   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
   3326 //               void*,self);
   3327 //
   3328 //   if (TRACE_QT4_FNS) {
   3329 //      fprintf(stderr, " :: Q::unlock :: done >>\n");
   3330 //   }
   3331 //}
   3332 
   3333 
   3334 /*----------------------------------------------------------------*/
   3335 /*--- Replacements for basic string functions, that don't      ---*/
   3336 /*--- overrun the input arrays.                                ---*/
   3337 /*----------------------------------------------------------------*/
   3338 
   3339 #include "../shared/vg_replace_strmem.c"
   3340 
   3341 /*--------------------------------------------------------------------*/
   3342 /*--- end                                          hg_intercepts.c ---*/
   3343 /*--------------------------------------------------------------------*/
   3344