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-2013 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 #define TRACE_PTH_FNS 0
     62 #define TRACE_QT4_FNS 0
     63 
     64 
     65 /*----------------------------------------------------------------*/
     66 /*---                                                          ---*/
     67 /*----------------------------------------------------------------*/
     68 
     69 #define PTH_FUNC(ret_ty, f, args...) \
     70    ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args); \
     71    ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args)
     72 
     73 // Do a client request.  These are macros rather than a functions so
     74 // as to avoid having an extra frame in stack traces.
     75 
     76 // NB: these duplicate definitions in helgrind.h.  But here, we
     77 // can have better typing (Word etc) and assertions, whereas
     78 // in helgrind.h we can't.  Obviously it's important the two
     79 // sets of definitions are kept in sync.
     80 
     81 // nuke the previous definitions
     82 #undef DO_CREQ_v_W
     83 #undef DO_CREQ_v_WW
     84 #undef DO_CREQ_W_WW
     85 #undef DO_CREQ_v_WWW
     86 
     87 #define DO_CREQ_v_W(_creqF, _ty1F,_arg1F)                \
     88    do {                                                  \
     89       Word _arg1;                                        \
     90       assert(sizeof(_ty1F) == sizeof(Word));             \
     91       _arg1 = (Word)(_arg1F);                            \
     92       VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF),          \
     93                                  _arg1, 0,0,0,0);        \
     94    } while (0)
     95 
     96 #define DO_CREQ_v_WW(_creqF, _ty1F,_arg1F, _ty2F,_arg2F) \
     97    do {                                                  \
     98       Word _arg1, _arg2;                                 \
     99       assert(sizeof(_ty1F) == sizeof(Word));             \
    100       assert(sizeof(_ty2F) == sizeof(Word));             \
    101       _arg1 = (Word)(_arg1F);                            \
    102       _arg2 = (Word)(_arg2F);                            \
    103       VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF),          \
    104                                  _arg1,_arg2,0,0,0);     \
    105    } while (0)
    106 
    107 #define DO_CREQ_W_WW(_resF, _creqF, _ty1F,_arg1F,        \
    108                      _ty2F,_arg2F)                       \
    109    do {                                                  \
    110       Word _res, _arg1, _arg2;                           \
    111       assert(sizeof(_ty1F) == sizeof(Word));             \
    112       assert(sizeof(_ty2F) == sizeof(Word));             \
    113       _arg1 = (Word)(_arg1F);                            \
    114       _arg2 = (Word)(_arg2F);                            \
    115       _res = VALGRIND_DO_CLIENT_REQUEST_EXPR(2,          \
    116                                  (_creqF),               \
    117                                  _arg1,_arg2,0,0,0);     \
    118       _resF = _res;                                      \
    119    } while (0)
    120 
    121 #define DO_CREQ_v_WWW(_creqF, _ty1F,_arg1F,              \
    122                       _ty2F,_arg2F, _ty3F, _arg3F)       \
    123    do {                                                  \
    124       Word _arg1, _arg2, _arg3;                          \
    125       assert(sizeof(_ty1F) == sizeof(Word));             \
    126       assert(sizeof(_ty2F) == sizeof(Word));             \
    127       assert(sizeof(_ty3F) == sizeof(Word));             \
    128       _arg1 = (Word)(_arg1F);                            \
    129       _arg2 = (Word)(_arg2F);                            \
    130       _arg3 = (Word)(_arg3F);                            \
    131       VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF),          \
    132                                  _arg1,_arg2,_arg3,0,0); \
    133    } while (0)
    134 
    135 
    136 #define DO_PthAPIerror(_fnnameF, _errF)                  \
    137    do {                                                  \
    138       char* _fnname = (char*)(_fnnameF);                 \
    139       long  _err    = (long)(int)(_errF);                \
    140       const char* _errstr = lame_strerror(_err);         \
    141       DO_CREQ_v_WWW(_VG_USERREQ__HG_PTH_API_ERROR,       \
    142                     char*,_fnname,                       \
    143                     long,_err, char*,_errstr);           \
    144    } while (0)
    145 
    146 
    147 /* Needed for older glibcs (2.3 and older, at least) who don't
    148    otherwise "know" about pthread_rwlock_anything or about
    149    PTHREAD_MUTEX_RECURSIVE (amongst things). */
    150 #define _GNU_SOURCE 1
    151 
    152 #include <stdio.h>
    153 #include <assert.h>
    154 #include <errno.h>
    155 #include <pthread.h>
    156 
    157 /* A standalone memcmp. */
    158 __attribute__((noinline))
    159 static int my_memcmp ( const void* ptr1, const void* ptr2, size_t size)
    160 {
    161    unsigned char* uchar_ptr1 = (unsigned char*) ptr1;
    162    unsigned char* uchar_ptr2 = (unsigned char*) ptr2;
    163    size_t i;
    164    for (i = 0; i < size; ++i) {
    165       if (uchar_ptr1[i] != uchar_ptr2[i])
    166          return (uchar_ptr1[i] < uchar_ptr2[i]) ? -1 : 1;
    167    }
    168    return 0;
    169 }
    170 
    171 /* A lame version of strerror which doesn't use the real libc
    172    strerror_r, since using the latter just generates endless more
    173    threading errors (glibc goes off and does tons of crap w.r.t.
    174    locales etc) */
    175 static const HChar* lame_strerror ( long err )
    176 {
    177    switch (err) {
    178       case EPERM:       return "EPERM: Operation not permitted";
    179       case ENOENT:      return "ENOENT: No such file or directory";
    180       case ESRCH:       return "ESRCH: No such process";
    181       case EINTR:       return "EINTR: Interrupted system call";
    182       case EBADF:       return "EBADF: Bad file number";
    183       case EAGAIN:      return "EAGAIN: Try again";
    184       case ENOMEM:      return "ENOMEM: Out of memory";
    185       case EACCES:      return "EACCES: Permission denied";
    186       case EFAULT:      return "EFAULT: Bad address";
    187       case EEXIST:      return "EEXIST: File exists";
    188       case EINVAL:      return "EINVAL: Invalid argument";
    189       case EMFILE:      return "EMFILE: Too many open files";
    190       case ENOSYS:      return "ENOSYS: Function not implemented";
    191       case EOVERFLOW:   return "EOVERFLOW: Value too large "
    192                                "for defined data type";
    193       case EBUSY:       return "EBUSY: Device or resource busy";
    194       case ETIMEDOUT:   return "ETIMEDOUT: Connection timed out";
    195       case EDEADLK:     return "EDEADLK: Resource deadlock would occur";
    196       case EOPNOTSUPP:  return "EOPNOTSUPP: Operation not supported on "
    197                                "transport endpoint"; /* honest, guv */
    198       default:          return "tc_intercepts.c: lame_strerror(): "
    199                                "unhandled case -- please fix me!";
    200    }
    201 }
    202 
    203 
    204 /*----------------------------------------------------------------*/
    205 /*--- pthread_create, pthread_join, pthread_exit               ---*/
    206 /*----------------------------------------------------------------*/
    207 
    208 static void* mythread_wrapper ( void* xargsV )
    209 {
    210    volatile Word* xargs = (volatile Word*) xargsV;
    211    void*(*fn)(void*) = (void*(*)(void*))xargs[0];
    212    void* arg         = (void*)xargs[1];
    213    pthread_t me = pthread_self();
    214    /* Tell the tool what my pthread_t is. */
    215    DO_CREQ_v_W(_VG_USERREQ__HG_SET_MY_PTHREAD_T, pthread_t,me);
    216    /* allow the parent to proceed.  We can't let it proceed until
    217       we're ready because (1) we need to make sure it doesn't exit and
    218       hence deallocate xargs[] while we still need it, and (2) we
    219       don't want either parent nor child to proceed until the tool has
    220       been notified of the child's pthread_t.
    221 
    222       Note that parent and child access args[] without a lock,
    223       effectively using args[2] as a spinlock in order to get the
    224       parent to wait until the child passes this point.  The parent
    225       disables checking on xargs[] before creating the child and
    226       re-enables it once the child goes past this point, so the user
    227       never sees the race.  The previous approach (suppressing the
    228       resulting error) was flawed, because it could leave shadow
    229       memory for args[] in a state in which subsequent use of it by
    230       the parent would report further races. */
    231    xargs[2] = 0;
    232    /* Now we can no longer safely use xargs[]. */
    233    return (void*) fn( (void*)arg );
    234 }
    235 
    236 //-----------------------------------------------------------
    237 // glibc:  pthread_create (at) GLIBC_2.0
    238 // glibc:  pthread_create@@GLIBC_2.1
    239 // glibc:  pthread_create@@GLIBC_2.2.5
    240 // darwin: pthread_create
    241 // darwin: pthread_create_suspended_np (trapped)
    242 //
    243 /* ensure this has its own frame, so as to make it more distinguishable
    244    in suppressions */
    245 __attribute__((noinline))
    246 static int pthread_create_WRK(pthread_t *thread, const pthread_attr_t *attr,
    247                               void *(*start) (void *), void *arg)
    248 {
    249    int    ret;
    250    OrigFn fn;
    251    volatile Word xargs[3];
    252 
    253    VALGRIND_GET_ORIG_FN(fn);
    254    if (TRACE_PTH_FNS) {
    255       fprintf(stderr, "<< pthread_create wrapper"); fflush(stderr);
    256    }
    257    xargs[0] = (Word)start;
    258    xargs[1] = (Word)arg;
    259    xargs[2] = 1; /* serves as a spinlock -- sigh */
    260    /* Disable checking on the spinlock and the two words used to
    261       convey args to the child.  Basically we need to make it appear
    262       as if the child never accessed this area, since merely
    263       suppressing the resulting races does not address the issue that
    264       that piece of the parent's stack winds up in the "wrong" state
    265       and therefore may give rise to mysterious races when the parent
    266       comes to re-use this piece of stack in some other frame. */
    267    VALGRIND_HG_DISABLE_CHECKING(&xargs, sizeof(xargs));
    268 
    269    CALL_FN_W_WWWW(ret, fn, thread,attr,mythread_wrapper,&xargs[0]);
    270 
    271    if (ret == 0) {
    272       /* we have to wait for the child to notify the tool of its
    273          pthread_t before continuing */
    274       while (xargs[2] != 0) {
    275          /* Do nothing.  We need to spin until the child writes to
    276             xargs[2].  However, that can lead to starvation in the
    277             child and very long delays (eg, tc19_shadowmem on
    278             ppc64-linux Fedora Core 6).  So yield the cpu if we can,
    279             to let the child run at the earliest available
    280             opportunity. */
    281          sched_yield();
    282       }
    283    } else {
    284       DO_PthAPIerror( "pthread_create", ret );
    285    }
    286 
    287    /* Reenable checking on the area previously used to communicate
    288       with the child. */
    289    VALGRIND_HG_ENABLE_CHECKING(&xargs, sizeof(xargs));
    290 
    291    if (TRACE_PTH_FNS) {
    292       fprintf(stderr, " :: pth_create -> %d >>\n", ret);
    293    }
    294    return ret;
    295 }
    296 #if defined(VGO_linux)
    297    PTH_FUNC(int, pthreadZucreateZAZa, // pthread_create@*
    298                  pthread_t *thread, const pthread_attr_t *attr,
    299                  void *(*start) (void *), void *arg) {
    300       return pthread_create_WRK(thread, attr, start, arg);
    301    }
    302 #elif defined(VGO_darwin)
    303    PTH_FUNC(int, pthreadZucreate, // pthread_create
    304                  pthread_t *thread, const pthread_attr_t *attr,
    305                  void *(*start) (void *), void *arg) {
    306       return pthread_create_WRK(thread, attr, start, arg);
    307    }
    308    PTH_FUNC(int, pthreadZucreateZuZa, // pthread_create_*
    309                  pthread_t *thread, const pthread_attr_t *attr,
    310                  void *(*start) (void *), void *arg) {
    311       // trap anything else
    312       assert(0);
    313    }
    314 #else
    315 #  error "Unsupported OS"
    316 #endif
    317 
    318 
    319 //-----------------------------------------------------------
    320 // glibc:  pthread_join
    321 // darwin: pthread_join
    322 // darwin: pthread_join$NOCANCEL$UNIX2003
    323 // darwin  pthread_join$UNIX2003
    324 __attribute__((noinline))
    325 static int pthread_join_WRK(pthread_t thread, void** value_pointer)
    326 {
    327    int ret;
    328    OrigFn fn;
    329    VALGRIND_GET_ORIG_FN(fn);
    330    if (TRACE_PTH_FNS) {
    331       fprintf(stderr, "<< pthread_join wrapper"); fflush(stderr);
    332    }
    333 
    334    CALL_FN_W_WW(ret, fn, thread,value_pointer);
    335 
    336    /* At least with NPTL as the thread library, this is safe because
    337       it is guaranteed (by NPTL) that the joiner will completely gone
    338       before pthread_join (the original) returns.  See email below.*/
    339    if (ret == 0 /*success*/) {
    340       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST, pthread_t,thread);
    341    } else {
    342       DO_PthAPIerror( "pthread_join", ret );
    343    }
    344 
    345    if (TRACE_PTH_FNS) {
    346       fprintf(stderr, " :: pth_join -> %d >>\n", ret);
    347    }
    348    return ret;
    349 }
    350 #if defined(VGO_linux)
    351    PTH_FUNC(int, pthreadZujoin, // pthread_join
    352             pthread_t thread, void** value_pointer) {
    353       return pthread_join_WRK(thread, value_pointer);
    354    }
    355 #elif defined(VGO_darwin)
    356    PTH_FUNC(int, pthreadZujoinZa, // pthread_join*
    357             pthread_t thread, void** value_pointer) {
    358       return pthread_join_WRK(thread, value_pointer);
    359    }
    360 #else
    361 #  error "Unsupported OS"
    362 #endif
    363 
    364 
    365 /* Behaviour of pthread_join on NPTL:
    366 
    367 Me:
    368 I have a question re the NPTL pthread_join implementation.
    369 
    370   Suppose I am the thread 'stayer'.
    371 
    372   If I call pthread_join(quitter), is it guaranteed that the
    373   thread 'quitter' has really exited before pthread_join returns?
    374 
    375   IOW, is it guaranteed that 'quitter' will not execute any further
    376   instructions after pthread_join returns?
    377 
    378 I believe this is true based on the following analysis of
    379 glibc-2.5 sources.  However am not 100% sure and would appreciate
    380 confirmation.
    381 
    382   'quitter' will be running start_thread() in nptl/pthread_create.c
    383 
    384   The last action of start_thread() is to exit via
    385   __exit_thread_inline(0), which simply does sys_exit
    386   (nptl/pthread_create.c:403)
    387 
    388   'stayer' meanwhile is waiting for lll_wait_tid (pd->tid)
    389   (call at nptl/pthread_join.c:89)
    390 
    391   As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
    392   lll_wait_tid will not return until kernel notifies via futex
    393   wakeup that 'quitter' has terminated.
    394 
    395   Hence pthread_join cannot return until 'quitter' really has
    396   completely disappeared.
    397 
    398 Drepper:
    399 >   As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
    400 >   lll_wait_tid will not return until kernel notifies via futex
    401 >   wakeup that 'quitter' has terminated.
    402 That's the key.  The kernel resets the TID field after the thread is
    403 done.  No way the joiner can return before the thread is gone.
    404 */
    405 
    406 
    407 /*----------------------------------------------------------------*/
    408 /*--- pthread_mutex_t functions                                ---*/
    409 /*----------------------------------------------------------------*/
    410 
    411 /* Handled:   pthread_mutex_init pthread_mutex_destroy
    412               pthread_mutex_lock
    413               pthread_mutex_trylock pthread_mutex_timedlock
    414               pthread_mutex_unlock
    415 */
    416 
    417 //-----------------------------------------------------------
    418 // glibc:  pthread_mutex_init
    419 // darwin: pthread_mutex_init
    420 PTH_FUNC(int, pthreadZumutexZuinit, // pthread_mutex_init
    421               pthread_mutex_t *mutex,
    422               pthread_mutexattr_t* attr)
    423 {
    424    int    ret;
    425    long   mbRec;
    426    OrigFn fn;
    427    VALGRIND_GET_ORIG_FN(fn);
    428    if (TRACE_PTH_FNS) {
    429       fprintf(stderr, "<< pthread_mxinit %p", mutex); fflush(stderr);
    430    }
    431 
    432    mbRec = 0;
    433    if (attr) {
    434       int ty, zzz;
    435       zzz = pthread_mutexattr_gettype(attr, &ty);
    436       if (zzz == 0 && ty == PTHREAD_MUTEX_RECURSIVE)
    437          mbRec = 1;
    438    }
    439 
    440    CALL_FN_W_WW(ret, fn, mutex,attr);
    441 
    442    if (ret == 0 /*success*/) {
    443       DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
    444                    pthread_mutex_t*,mutex, long,mbRec);
    445    } else {
    446       DO_PthAPIerror( "pthread_mutex_init", ret );
    447    }
    448 
    449    if (TRACE_PTH_FNS) {
    450       fprintf(stderr, " :: mxinit -> %d >>\n", ret);
    451    }
    452    return ret;
    453 }
    454 
    455 
    456 //-----------------------------------------------------------
    457 // glibc:  pthread_mutex_destroy
    458 // darwin: pthread_mutex_destroy
    459 PTH_FUNC(int, pthreadZumutexZudestroy, // pthread_mutex_destroy
    460               pthread_mutex_t *mutex)
    461 {
    462    int    ret;
    463    unsigned long mutex_is_init;
    464    OrigFn fn;
    465 
    466    VALGRIND_GET_ORIG_FN(fn);
    467    if (TRACE_PTH_FNS) {
    468       fprintf(stderr, "<< pthread_mxdestroy %p", mutex); fflush(stderr);
    469    }
    470 
    471    if (mutex != NULL) {
    472       static const pthread_mutex_t mutex_init = PTHREAD_MUTEX_INITIALIZER;
    473       mutex_is_init = my_memcmp(mutex, &mutex_init, sizeof(*mutex)) == 0;
    474    } else {
    475       mutex_is_init = 0;
    476    }
    477 
    478    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
    479                 pthread_mutex_t*, mutex, unsigned long, mutex_is_init);
    480 
    481    CALL_FN_W_W(ret, fn, mutex);
    482 
    483    if (ret != 0) {
    484       DO_PthAPIerror( "pthread_mutex_destroy", ret );
    485    }
    486 
    487    if (TRACE_PTH_FNS) {
    488       fprintf(stderr, " :: mxdestroy -> %d >>\n", ret);
    489    }
    490    return ret;
    491 }
    492 
    493 
    494 //-----------------------------------------------------------
    495 // glibc:  pthread_mutex_lock
    496 // darwin: pthread_mutex_lock
    497 PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock
    498               pthread_mutex_t *mutex)
    499 {
    500    int    ret;
    501    OrigFn fn;
    502    VALGRIND_GET_ORIG_FN(fn);
    503    if (TRACE_PTH_FNS) {
    504       fprintf(stderr, "<< pthread_mxlock %p", mutex); fflush(stderr);
    505    }
    506 
    507    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
    508                 pthread_mutex_t*,mutex, long,0/*!isTryLock*/);
    509 
    510    CALL_FN_W_W(ret, fn, mutex);
    511 
    512    /* There's a hole here: libpthread now knows the lock is locked,
    513       but the tool doesn't, so some other thread could run and detect
    514       that the lock has been acquired by someone (this thread).  Does
    515       this matter?  Not sure, but I don't think so. */
    516 
    517    if (ret == 0 /*success*/) {
    518       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
    519                   pthread_mutex_t*,mutex);
    520    } else {
    521       DO_PthAPIerror( "pthread_mutex_lock", ret );
    522    }
    523 
    524    if (TRACE_PTH_FNS) {
    525       fprintf(stderr, " :: mxlock -> %d >>\n", ret);
    526    }
    527    return ret;
    528 }
    529 
    530 
    531 //-----------------------------------------------------------
    532 // glibc:  pthread_mutex_trylock
    533 // darwin: pthread_mutex_trylock
    534 //
    535 // pthread_mutex_trylock.  The handling needed here is very similar
    536 // to that for pthread_mutex_lock, except that we need to tell
    537 // the pre-lock creq that this is a trylock-style operation, and
    538 // therefore not to complain if the lock is nonrecursive and
    539 // already locked by this thread -- because then it'll just fail
    540 // immediately with EBUSY.
    541 PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock
    542               pthread_mutex_t *mutex)
    543 {
    544    int    ret;
    545    OrigFn fn;
    546    VALGRIND_GET_ORIG_FN(fn);
    547    if (TRACE_PTH_FNS) {
    548       fprintf(stderr, "<< pthread_mxtrylock %p", mutex); fflush(stderr);
    549    }
    550 
    551    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
    552                 pthread_mutex_t*,mutex, long,1/*isTryLock*/);
    553 
    554    CALL_FN_W_W(ret, fn, mutex);
    555 
    556    /* There's a hole here: libpthread now knows the lock is locked,
    557       but the tool doesn't, so some other thread could run and detect
    558       that the lock has been acquired by someone (this thread).  Does
    559       this matter?  Not sure, but I don't think so. */
    560 
    561    if (ret == 0 /*success*/) {
    562       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
    563                   pthread_mutex_t*,mutex);
    564    } else {
    565       if (ret != EBUSY)
    566          DO_PthAPIerror( "pthread_mutex_trylock", ret );
    567    }
    568 
    569    if (TRACE_PTH_FNS) {
    570       fprintf(stderr, " :: mxtrylock -> %d >>\n", ret);
    571    }
    572    return ret;
    573 }
    574 
    575 
    576 //-----------------------------------------------------------
    577 // glibc:  pthread_mutex_timedlock
    578 // darwin: (doesn't appear to exist)
    579 //
    580 // pthread_mutex_timedlock.  Identical logic to pthread_mutex_trylock.
    581 PTH_FUNC(int, pthreadZumutexZutimedlock, // pthread_mutex_timedlock
    582          pthread_mutex_t *mutex,
    583          void* timeout)
    584 {
    585    int    ret;
    586    OrigFn fn;
    587    VALGRIND_GET_ORIG_FN(fn);
    588    if (TRACE_PTH_FNS) {
    589       fprintf(stderr, "<< pthread_mxtimedlock %p %p", mutex, timeout);
    590       fflush(stderr);
    591    }
    592 
    593    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
    594                 pthread_mutex_t*,mutex, long,1/*isTryLock-ish*/);
    595 
    596    CALL_FN_W_WW(ret, fn, mutex,timeout);
    597 
    598    /* There's a hole here: libpthread now knows the lock is locked,
    599       but the tool doesn't, so some other thread could run and detect
    600       that the lock has been acquired by someone (this thread).  Does
    601       this matter?  Not sure, but I don't think so. */
    602 
    603    if (ret == 0 /*success*/) {
    604       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
    605                   pthread_mutex_t*,mutex);
    606    } else {
    607       if (ret != ETIMEDOUT)
    608          DO_PthAPIerror( "pthread_mutex_timedlock", ret );
    609    }
    610 
    611    if (TRACE_PTH_FNS) {
    612       fprintf(stderr, " :: mxtimedlock -> %d >>\n", ret);
    613    }
    614    return ret;
    615 }
    616 
    617 
    618 //-----------------------------------------------------------
    619 // glibc:  pthread_mutex_unlock
    620 // darwin: pthread_mutex_unlock
    621 PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock
    622               pthread_mutex_t *mutex)
    623 {
    624    int    ret;
    625    OrigFn fn;
    626    VALGRIND_GET_ORIG_FN(fn);
    627 
    628    if (TRACE_PTH_FNS) {
    629       fprintf(stderr, "<< pthread_mxunlk %p", mutex); fflush(stderr);
    630    }
    631 
    632    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
    633                pthread_mutex_t*,mutex);
    634 
    635    CALL_FN_W_W(ret, fn, mutex);
    636 
    637    if (ret == 0 /*success*/) {
    638       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
    639                   pthread_mutex_t*,mutex);
    640    } else {
    641       DO_PthAPIerror( "pthread_mutex_unlock", ret );
    642    }
    643 
    644    if (TRACE_PTH_FNS) {
    645       fprintf(stderr, " mxunlk -> %d >>\n", ret);
    646    }
    647    return ret;
    648 }
    649 
    650 
    651 /*----------------------------------------------------------------*/
    652 /*--- pthread_cond_t functions                                 ---*/
    653 /*----------------------------------------------------------------*/
    654 
    655 /* Handled:   pthread_cond_wait pthread_cond_timedwait
    656               pthread_cond_signal pthread_cond_broadcast
    657               pthread_cond_init
    658               pthread_cond_destroy
    659 */
    660 
    661 //-----------------------------------------------------------
    662 // glibc:  pthread_cond_wait (at) GLIBC_2.2.5
    663 // glibc:  pthread_cond_wait@@GLIBC_2.3.2
    664 // darwin: pthread_cond_wait
    665 // darwin: pthread_cond_wait$NOCANCEL$UNIX2003
    666 // darwin: pthread_cond_wait$UNIX2003
    667 //
    668 __attribute__((noinline))
    669 static int pthread_cond_wait_WRK(pthread_cond_t* cond,
    670                                  pthread_mutex_t* mutex)
    671 {
    672    int ret;
    673    OrigFn fn;
    674    unsigned long mutex_is_valid;
    675 
    676    VALGRIND_GET_ORIG_FN(fn);
    677 
    678    if (TRACE_PTH_FNS) {
    679       fprintf(stderr, "<< pthread_cond_wait %p %p", cond, mutex);
    680       fflush(stderr);
    681    }
    682 
    683    /* Tell the tool a cond-wait is about to happen, so it can check
    684       for bogus argument values.  In return it tells us whether it
    685       thinks the mutex is valid or not. */
    686    DO_CREQ_W_WW(mutex_is_valid,
    687                 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
    688                 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
    689    assert(mutex_is_valid == 1 || mutex_is_valid == 0);
    690 
    691    /* Tell the tool we're about to drop the mutex.  This reflects the
    692       fact that in a cond_wait, we show up holding the mutex, and the
    693       call atomically drops the mutex and waits for the cv to be
    694       signalled. */
    695    if (mutex_is_valid) {
    696       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
    697                   pthread_mutex_t*,mutex);
    698    }
    699 
    700    CALL_FN_W_WW(ret, fn, cond,mutex);
    701 
    702    /* these conditionals look stupid, but compare w/ same logic for
    703       pthread_cond_timedwait below */
    704    if (ret == 0 && mutex_is_valid) {
    705       /* and now we have the mutex again */
    706       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
    707                   pthread_mutex_t*,mutex);
    708    }
    709 
    710    if (ret == 0 && mutex_is_valid) {
    711       DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
    712                     pthread_cond_t*,cond, pthread_mutex_t*,mutex, long,0);
    713    }
    714 
    715    if (ret != 0) {
    716       DO_PthAPIerror( "pthread_cond_wait", ret );
    717    }
    718 
    719    if (TRACE_PTH_FNS) {
    720       fprintf(stderr, " cowait -> %d >>\n", ret);
    721    }
    722 
    723    return ret;
    724 }
    725 #if defined(VGO_linux)
    726    PTH_FUNC(int, pthreadZucondZuwaitZAZa, // pthread_cond_wait@*
    727                  pthread_cond_t* cond, pthread_mutex_t* mutex) {
    728       return pthread_cond_wait_WRK(cond, mutex);
    729    }
    730 #elif defined(VGO_darwin)
    731    PTH_FUNC(int, pthreadZucondZuwaitZa, // pthread_cond_wait*
    732                  pthread_cond_t* cond, pthread_mutex_t* mutex) {
    733       return pthread_cond_wait_WRK(cond, mutex);
    734    }
    735 #else
    736 #  error "Unsupported OS"
    737 #endif
    738 
    739 
    740 //-----------------------------------------------------------
    741 // glibc:  pthread_cond_timedwait@@GLIBC_2.3.2
    742 // glibc:  pthread_cond_timedwait (at) GLIBC_2.2.5
    743 // glibc:  pthread_cond_timedwait (at) GLIBC_2.0
    744 // darwin: pthread_cond_timedwait
    745 // darwin: pthread_cond_timedwait$NOCANCEL$UNIX2003
    746 // darwin: pthread_cond_timedwait$UNIX2003
    747 // darwin: pthread_cond_timedwait_relative_np (trapped)
    748 //
    749 __attribute__((noinline))
    750 static int pthread_cond_timedwait_WRK(pthread_cond_t* cond,
    751                                       pthread_mutex_t* mutex,
    752                                       struct timespec* abstime)
    753 {
    754    int ret;
    755    OrigFn fn;
    756    unsigned long mutex_is_valid;
    757    Bool abstime_is_valid;
    758    VALGRIND_GET_ORIG_FN(fn);
    759 
    760    if (TRACE_PTH_FNS) {
    761       fprintf(stderr, "<< pthread_cond_timedwait %p %p %p",
    762                       cond, mutex, abstime);
    763       fflush(stderr);
    764    }
    765 
    766    /* Tell the tool a cond-wait is about to happen, so it can check
    767       for bogus argument values.  In return it tells us whether it
    768       thinks the mutex is valid or not. */
    769    DO_CREQ_W_WW(mutex_is_valid,
    770                 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
    771                 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
    772    assert(mutex_is_valid == 1 || mutex_is_valid == 0);
    773 
    774    abstime_is_valid = abstime->tv_nsec >= 0 && abstime->tv_nsec < 1000000000;
    775 
    776    /* Tell the tool we're about to drop the mutex.  This reflects the
    777       fact that in a cond_wait, we show up holding the mutex, and the
    778       call atomically drops the mutex and waits for the cv to be
    779       signalled. */
    780    if (mutex_is_valid && abstime_is_valid) {
    781       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
    782                   pthread_mutex_t*,mutex);
    783    }
    784 
    785    CALL_FN_W_WWW(ret, fn, cond,mutex,abstime);
    786 
    787    if (!abstime_is_valid && ret != EINVAL) {
    788       DO_PthAPIerror("Bug in libpthread: pthread_cond_timedwait "
    789                      "invalid abstime did not cause"
    790                      " EINVAL", ret);
    791    }
    792 
    793    if ((ret == 0 || ret == ETIMEDOUT) && mutex_is_valid) {
    794       /* and now we have the mutex again */
    795       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
    796                   pthread_mutex_t*,mutex);
    797    }
    798 
    799    if ((ret == 0 || ret == ETIMEDOUT) && mutex_is_valid) {
    800       DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
    801                     pthread_cond_t*,cond, pthread_mutex_t*,mutex,
    802                     long,ret == ETIMEDOUT);
    803    }
    804 
    805    if (ret != 0 && ret != ETIMEDOUT) {
    806       DO_PthAPIerror( "pthread_cond_timedwait", ret );
    807    }
    808 
    809    if (TRACE_PTH_FNS) {
    810       fprintf(stderr, " cotimedwait -> %d >>\n", ret);
    811    }
    812 
    813    return ret;
    814 }
    815 #if defined(VGO_linux)
    816    PTH_FUNC(int, pthreadZucondZutimedwaitZAZa, // pthread_cond_timedwait@*
    817                  pthread_cond_t* cond, pthread_mutex_t* mutex,
    818                  struct timespec* abstime) {
    819       return pthread_cond_timedwait_WRK(cond, mutex, abstime);
    820    }
    821 #elif defined(VGO_darwin)
    822    PTH_FUNC(int, pthreadZucondZutimedwait, // pthread_cond_timedwait
    823                  pthread_cond_t* cond, pthread_mutex_t* mutex,
    824                  struct timespec* abstime) {
    825       return pthread_cond_timedwait_WRK(cond, mutex, abstime);
    826    }
    827    PTH_FUNC(int, pthreadZucondZutimedwaitZDZa, // pthread_cond_timedwait$*
    828                  pthread_cond_t* cond, pthread_mutex_t* mutex,
    829                  struct timespec* abstime) {
    830       return pthread_cond_timedwait_WRK(cond, mutex, abstime);
    831    }
    832    PTH_FUNC(int, pthreadZucondZutimedwaitZuZa, // pthread_cond_timedwait_*
    833                  pthread_cond_t* cond, pthread_mutex_t* mutex,
    834                  struct timespec* abstime) {
    835       assert(0);
    836    }
    837 #else
    838 #  error "Unsupported OS"
    839 #endif
    840 
    841 
    842 //-----------------------------------------------------------
    843 // glibc:  pthread_cond_signal (at) GLIBC_2.0
    844 // glibc:  pthread_cond_signal (at) GLIBC_2.2.5
    845 // glibc:  pthread_cond_signal@@GLIBC_2.3.2
    846 // darwin: pthread_cond_signal
    847 // darwin: pthread_cond_signal_thread_np (don't intercept this)
    848 //
    849 __attribute__((noinline))
    850 static int pthread_cond_signal_WRK(pthread_cond_t* cond)
    851 {
    852    int ret;
    853    OrigFn fn;
    854    VALGRIND_GET_ORIG_FN(fn);
    855 
    856    if (TRACE_PTH_FNS) {
    857       fprintf(stderr, "<< pthread_cond_signal %p", cond);
    858       fflush(stderr);
    859    }
    860 
    861    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE,
    862                pthread_cond_t*,cond);
    863 
    864    CALL_FN_W_W(ret, fn, cond);
    865 
    866    if (ret != 0) {
    867       DO_PthAPIerror( "pthread_cond_signal", ret );
    868    }
    869 
    870    if (TRACE_PTH_FNS) {
    871       fprintf(stderr, " cosig -> %d >>\n", ret);
    872    }
    873 
    874    return ret;
    875 }
    876 #if defined(VGO_linux)
    877    PTH_FUNC(int, pthreadZucondZusignalZAZa, // pthread_cond_signal@*
    878                  pthread_cond_t* cond) {
    879       return pthread_cond_signal_WRK(cond);
    880    }
    881 #elif defined(VGO_darwin)
    882    PTH_FUNC(int, pthreadZucondZusignal, // pthread_cond_signal
    883                  pthread_cond_t* cond) {
    884       return pthread_cond_signal_WRK(cond);
    885    }
    886 #else
    887 #  error "Unsupported OS"
    888 #endif
    889 
    890 
    891 //-----------------------------------------------------------
    892 // glibc:  pthread_cond_broadcast (at) GLIBC_2.0
    893 // glibc:  pthread_cond_broadcast (at) GLIBC_2.2.5
    894 // glibc:  pthread_cond_broadcast@@GLIBC_2.3.2
    895 // darwin: pthread_cond_broadcast
    896 //
    897 // Note, this is pretty much identical, from a dependency-graph
    898 // point of view, with cond_signal, so the code is duplicated.
    899 // Maybe it should be commoned up.
    900 //
    901 __attribute__((noinline))
    902 static int pthread_cond_broadcast_WRK(pthread_cond_t* cond)
    903 {
    904    int ret;
    905    OrigFn fn;
    906    VALGRIND_GET_ORIG_FN(fn);
    907 
    908    if (TRACE_PTH_FNS) {
    909       fprintf(stderr, "<< pthread_cond_broadcast %p", cond);
    910       fflush(stderr);
    911    }
    912 
    913    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE,
    914                pthread_cond_t*,cond);
    915 
    916    CALL_FN_W_W(ret, fn, cond);
    917 
    918    if (ret != 0) {
    919       DO_PthAPIerror( "pthread_cond_broadcast", ret );
    920    }
    921 
    922    if (TRACE_PTH_FNS) {
    923       fprintf(stderr, " cobro -> %d >>\n", ret);
    924    }
    925 
    926    return ret;
    927 }
    928 #if defined(VGO_linux)
    929    PTH_FUNC(int, pthreadZucondZubroadcastZAZa, // pthread_cond_broadcast@*
    930                  pthread_cond_t* cond) {
    931       return pthread_cond_broadcast_WRK(cond);
    932    }
    933 #elif defined(VGO_darwin)
    934    PTH_FUNC(int, pthreadZucondZubroadcast, // pthread_cond_broadcast
    935                  pthread_cond_t* cond) {
    936       return pthread_cond_broadcast_WRK(cond);
    937    }
    938 #else
    939 #   error "Unsupported OS"
    940 #endif
    941 
    942 // glibc:  pthread_cond_init (at) GLIBC_2.0
    943 // glibc:  pthread_cond_init (at) GLIBC_2.2.5
    944 // glibc:  pthread_cond_init@@GLIBC_2.3.2
    945 // darwin: pthread_cond_init
    946 // Easy way out: Handling of attr could have been messier.
    947 // It turns out that pthread_cond_init under linux ignores
    948 // all information in cond_attr, so do we.
    949 // FIXME: MacOS X?
    950 __attribute__((noinline))
    951 static int pthread_cond_init_WRK(pthread_cond_t* cond, pthread_condattr_t *cond_attr)
    952 {
    953    int ret;
    954    OrigFn fn;
    955    VALGRIND_GET_ORIG_FN(fn);
    956 
    957    if (TRACE_PTH_FNS) {
    958       fprintf(stderr, "<< pthread_cond_init %p", cond);
    959       fflush(stderr);
    960    }
    961 
    962    CALL_FN_W_WW(ret, fn, cond, cond_attr);
    963 
    964    if (ret == 0) {
    965       DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST,
    966                    pthread_cond_t*,cond, pthread_condattr_t*, cond_attr);
    967    } else {
    968       DO_PthAPIerror( "pthread_cond_init", ret );
    969    }
    970 
    971    if (TRACE_PTH_FNS) {
    972       fprintf(stderr, " coinit -> %d >>\n", ret);
    973    }
    974 
    975    return ret;
    976 }
    977 #if defined(VGO_linux)
    978    PTH_FUNC(int, pthreadZucondZuinitZAZa, // pthread_cond_init@*
    979 	    pthread_cond_t* cond, pthread_condattr_t* cond_attr) {
    980      return pthread_cond_init_WRK(cond, cond_attr);
    981    }
    982 #elif defined(VGO_darwin)
    983    PTH_FUNC(int, pthreadZucondZuinit, // pthread_cond_init
    984 	    pthread_cond_t* cond, pthread_condattr_t * cond_attr) {
    985      return pthread_cond_init_WRK(cond, cond_attr);
    986    }
    987 #else
    988 #  error "Unsupported OS"
    989 #endif
    990 
    991 
    992 //-----------------------------------------------------------
    993 // glibc:  pthread_cond_destroy@@GLIBC_2.3.2
    994 // glibc:  pthread_cond_destroy (at) GLIBC_2.2.5
    995 // glibc:  pthread_cond_destroy (at) GLIBC_2.0
    996 // darwin: pthread_cond_destroy
    997 //
    998 __attribute__((noinline))
    999 static int pthread_cond_destroy_WRK(pthread_cond_t* cond)
   1000 {
   1001    int ret;
   1002    unsigned long cond_is_init;
   1003    OrigFn fn;
   1004 
   1005    VALGRIND_GET_ORIG_FN(fn);
   1006 
   1007    if (TRACE_PTH_FNS) {
   1008       fprintf(stderr, "<< pthread_cond_destroy %p", cond);
   1009       fflush(stderr);
   1010    }
   1011 
   1012    if (cond != NULL) {
   1013       const pthread_cond_t cond_init = PTHREAD_COND_INITIALIZER;
   1014       cond_is_init = my_memcmp(cond, &cond_init, sizeof(*cond)) == 0;
   1015    } else {
   1016      cond_is_init = 0;
   1017    }
   1018 
   1019    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_DESTROY_PRE,
   1020                 pthread_cond_t*, cond, unsigned long, cond_is_init);
   1021 
   1022    CALL_FN_W_W(ret, fn, cond);
   1023 
   1024    if (ret != 0) {
   1025       DO_PthAPIerror( "pthread_cond_destroy", ret );
   1026    }
   1027 
   1028    if (TRACE_PTH_FNS) {
   1029       fprintf(stderr, " codestr -> %d >>\n", ret);
   1030    }
   1031 
   1032    return ret;
   1033 }
   1034 #if defined(VGO_linux)
   1035    PTH_FUNC(int, pthreadZucondZudestroyZAZa, // pthread_cond_destroy@*
   1036                  pthread_cond_t* cond) {
   1037       return pthread_cond_destroy_WRK(cond);
   1038    }
   1039 #elif defined(VGO_darwin)
   1040    PTH_FUNC(int, pthreadZucondZudestroy, // pthread_cond_destroy
   1041                  pthread_cond_t* cond) {
   1042       return pthread_cond_destroy_WRK(cond);
   1043    }
   1044 #else
   1045 #  error "Unsupported OS"
   1046 #endif
   1047 
   1048 
   1049 /*----------------------------------------------------------------*/
   1050 /*--- pthread_barrier_t functions                              ---*/
   1051 /*----------------------------------------------------------------*/
   1052 
   1053 #if defined(HAVE_PTHREAD_BARRIER_INIT)
   1054 
   1055 /* Handled:   pthread_barrier_init
   1056               pthread_barrier_wait
   1057               pthread_barrier_destroy
   1058 
   1059    Unhandled: pthread_barrierattr_destroy
   1060               pthread_barrierattr_getpshared
   1061               pthread_barrierattr_init
   1062               pthread_barrierattr_setpshared
   1063               -- are these important?
   1064 */
   1065 
   1066 //-----------------------------------------------------------
   1067 // glibc:  pthread_barrier_init
   1068 // darwin: (doesn't appear to exist)
   1069 PTH_FUNC(int, pthreadZubarrierZuinit, // pthread_barrier_init
   1070          pthread_barrier_t* bar,
   1071          pthread_barrierattr_t* attr, unsigned long count)
   1072 {
   1073    int ret;
   1074    OrigFn fn;
   1075    VALGRIND_GET_ORIG_FN(fn);
   1076 
   1077    if (TRACE_PTH_FNS) {
   1078       fprintf(stderr, "<< pthread_barrier_init %p %p %lu",
   1079                       bar, attr, count);
   1080       fflush(stderr);
   1081    }
   1082 
   1083    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE,
   1084                  pthread_barrier_t*, bar,
   1085                  unsigned long, count,
   1086                  unsigned long, 0/*!resizable*/);
   1087 
   1088    CALL_FN_W_WWW(ret, fn, bar,attr,count);
   1089 
   1090    if (ret != 0) {
   1091       DO_PthAPIerror( "pthread_barrier_init", ret );
   1092    }
   1093 
   1094    if (TRACE_PTH_FNS) {
   1095       fprintf(stderr, "  pthread_barrier_init -> %d >>\n", ret);
   1096    }
   1097 
   1098    return ret;
   1099 }
   1100 
   1101 
   1102 //-----------------------------------------------------------
   1103 // glibc:  pthread_barrier_wait
   1104 // darwin: (doesn't appear to exist)
   1105 PTH_FUNC(int, pthreadZubarrierZuwait, // pthread_barrier_wait
   1106               pthread_barrier_t* bar)
   1107 {
   1108    int ret;
   1109    OrigFn fn;
   1110    VALGRIND_GET_ORIG_FN(fn);
   1111 
   1112    if (TRACE_PTH_FNS) {
   1113       fprintf(stderr, "<< pthread_barrier_wait %p", bar);
   1114       fflush(stderr);
   1115    }
   1116 
   1117    /* That this works correctly, and doesn't screw up when a thread
   1118       leaving the barrier races round to the front and re-enters while
   1119       other threads are still leaving it, is quite subtle.  See
   1120       comments in the handler for PTHREAD_BARRIER_WAIT_PRE in
   1121       hg_main.c. */
   1122    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE,
   1123                pthread_barrier_t*,bar);
   1124 
   1125    CALL_FN_W_W(ret, fn, bar);
   1126 
   1127    if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) {
   1128       DO_PthAPIerror( "pthread_barrier_wait", ret );
   1129    }
   1130 
   1131    if (TRACE_PTH_FNS) {
   1132       fprintf(stderr, "  pthread_barrier_wait -> %d >>\n", ret);
   1133    }
   1134 
   1135    return ret;
   1136 }
   1137 
   1138 
   1139 //-----------------------------------------------------------
   1140 // glibc:  pthread_barrier_destroy
   1141 // darwin: (doesn't appear to exist)
   1142 PTH_FUNC(int, pthreadZubarrierZudestroy, // pthread_barrier_destroy
   1143          pthread_barrier_t* bar)
   1144 {
   1145    int ret;
   1146    OrigFn fn;
   1147    VALGRIND_GET_ORIG_FN(fn);
   1148 
   1149    if (TRACE_PTH_FNS) {
   1150       fprintf(stderr, "<< pthread_barrier_destroy %p", bar);
   1151       fflush(stderr);
   1152    }
   1153 
   1154    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE,
   1155                pthread_barrier_t*,bar);
   1156 
   1157    CALL_FN_W_W(ret, fn, bar);
   1158 
   1159    if (ret != 0) {
   1160       DO_PthAPIerror( "pthread_barrier_destroy", ret );
   1161    }
   1162 
   1163    if (TRACE_PTH_FNS) {
   1164       fprintf(stderr, "  pthread_barrier_destroy -> %d >>\n", ret);
   1165    }
   1166 
   1167    return ret;
   1168 }
   1169 
   1170 #endif   // defined(HAVE_PTHREAD_BARRIER_INIT)
   1171 
   1172 
   1173 /*----------------------------------------------------------------*/
   1174 /*--- pthread_spinlock_t functions                             ---*/
   1175 /*----------------------------------------------------------------*/
   1176 
   1177 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
   1178     && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
   1179 
   1180 /* Handled:   pthread_spin_init pthread_spin_destroy
   1181               pthread_spin_lock pthread_spin_trylock
   1182               pthread_spin_unlock
   1183 
   1184    Unhandled:
   1185 */
   1186 
   1187 /* This is a nasty kludge, in that glibc "knows" that initialising a
   1188    spin lock unlocks it, and pthread_spin_{init,unlock} are names for
   1189    the same function.  Hence we have to have a wrapper which does both
   1190    things, without knowing which the user intended to happen. */
   1191 
   1192 //-----------------------------------------------------------
   1193 // glibc:  pthread_spin_init
   1194 // glibc:  pthread_spin_unlock
   1195 // darwin: (doesn't appear to exist)
   1196 __attribute__((noinline))
   1197 static int pthread_spin_init_or_unlock_WRK(pthread_spinlock_t* lock,
   1198                                            int pshared) {
   1199    int    ret;
   1200    OrigFn fn;
   1201    VALGRIND_GET_ORIG_FN(fn);
   1202    if (TRACE_PTH_FNS) {
   1203       fprintf(stderr, "<< pthread_spin_iORu %p", lock); fflush(stderr);
   1204    }
   1205 
   1206    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE,
   1207                pthread_spinlock_t*, lock);
   1208 
   1209    CALL_FN_W_WW(ret, fn, lock,pshared);
   1210 
   1211    if (ret == 0 /*success*/) {
   1212       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST,
   1213                   pthread_spinlock_t*,lock);
   1214    } else {
   1215       DO_PthAPIerror( "pthread_spinlock_{init,unlock}", ret );
   1216    }
   1217 
   1218    if (TRACE_PTH_FNS) {
   1219       fprintf(stderr, " :: spiniORu -> %d >>\n", ret);
   1220    }
   1221    return ret;
   1222 }
   1223 #if defined(VGO_linux)
   1224    PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
   1225             pthread_spinlock_t* lock, int pshared) {
   1226       return pthread_spin_init_or_unlock_WRK(lock, pshared);
   1227    }
   1228    PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
   1229             pthread_spinlock_t* lock) {
   1230       /* this is never actually called */
   1231       return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/);
   1232    }
   1233 #elif defined(VGO_darwin)
   1234 #else
   1235 #  error "Unsupported OS"
   1236 #endif
   1237 
   1238 
   1239 //-----------------------------------------------------------
   1240 // glibc:  pthread_spin_destroy
   1241 // darwin: (doesn't appear to exist)
   1242 #if defined(VGO_linux)
   1243 
   1244 PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy
   1245               pthread_spinlock_t* lock)
   1246 {
   1247    int    ret;
   1248    OrigFn fn;
   1249    VALGRIND_GET_ORIG_FN(fn);
   1250    if (TRACE_PTH_FNS) {
   1251       fprintf(stderr, "<< pthread_spin_destroy %p", lock);
   1252       fflush(stderr);
   1253    }
   1254 
   1255    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_DESTROY_PRE,
   1256                pthread_spinlock_t*,lock);
   1257 
   1258    CALL_FN_W_W(ret, fn, lock);
   1259 
   1260    if (ret != 0) {
   1261       DO_PthAPIerror( "pthread_spin_destroy", ret );
   1262    }
   1263 
   1264    if (TRACE_PTH_FNS) {
   1265       fprintf(stderr, " :: spindestroy -> %d >>\n", ret);
   1266    }
   1267    return ret;
   1268 }
   1269 
   1270 #elif defined(VGO_darwin)
   1271 #else
   1272 #  error "Unsupported OS"
   1273 #endif
   1274 
   1275 
   1276 //-----------------------------------------------------------
   1277 // glibc:  pthread_spin_lock
   1278 // darwin: (doesn't appear to exist)
   1279 #if defined(VGO_linux)
   1280 
   1281 PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
   1282               pthread_spinlock_t* lock)
   1283 {
   1284    int    ret;
   1285    OrigFn fn;
   1286    VALGRIND_GET_ORIG_FN(fn);
   1287    if (TRACE_PTH_FNS) {
   1288       fprintf(stderr, "<< pthread_spinlock %p", lock);
   1289       fflush(stderr);
   1290    }
   1291 
   1292    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE,
   1293                 pthread_spinlock_t*,lock, long,0/*!isTryLock*/);
   1294 
   1295    CALL_FN_W_W(ret, fn, lock);
   1296 
   1297    /* There's a hole here: libpthread now knows the lock is locked,
   1298       but the tool doesn't, so some other thread could run and detect
   1299       that the lock has been acquired by someone (this thread).  Does
   1300       this matter?  Not sure, but I don't think so. */
   1301 
   1302    if (ret == 0 /*success*/) {
   1303       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST,
   1304                   pthread_spinlock_t*,lock);
   1305    } else {
   1306       DO_PthAPIerror( "pthread_spin_lock", ret );
   1307    }
   1308 
   1309    if (TRACE_PTH_FNS) {
   1310       fprintf(stderr, " :: spinlock -> %d >>\n", ret);
   1311    }
   1312    return ret;
   1313 }
   1314 
   1315 #elif defined(VGO_darwin)
   1316 #else
   1317 #  error "Unsupported OS"
   1318 #endif
   1319 
   1320 
   1321 //-----------------------------------------------------------
   1322 // glibc:  pthread_spin_trylock
   1323 // darwin: (doesn't appear to exist)
   1324 #if defined(VGO_linux)
   1325 
   1326 PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
   1327               pthread_spinlock_t* lock)
   1328 {
   1329    int    ret;
   1330    OrigFn fn;
   1331    VALGRIND_GET_ORIG_FN(fn);
   1332    if (TRACE_PTH_FNS) {
   1333       fprintf(stderr, "<< pthread_spin_trylock %p", lock);
   1334       fflush(stderr);
   1335    }
   1336 
   1337    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE,
   1338                 pthread_spinlock_t*,lock, long,1/*isTryLock*/);
   1339 
   1340    CALL_FN_W_W(ret, fn, lock);
   1341 
   1342    /* There's a hole here: libpthread now knows the lock is locked,
   1343       but the tool doesn't, so some other thread could run and detect
   1344       that the lock has been acquired by someone (this thread).  Does
   1345       this matter?  Not sure, but I don't think so. */
   1346 
   1347    if (ret == 0 /*success*/) {
   1348       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST,
   1349                   pthread_spinlock_t*,lock);
   1350    } else {
   1351       if (ret != EBUSY)
   1352          DO_PthAPIerror( "pthread_spin_trylock", ret );
   1353    }
   1354 
   1355    if (TRACE_PTH_FNS) {
   1356       fprintf(stderr, " :: spin_trylock -> %d >>\n", ret);
   1357    }
   1358    return ret;
   1359 }
   1360 
   1361 #elif defined(VGO_darwin)
   1362 #else
   1363 #  error "Unsupported OS"
   1364 #endif
   1365 
   1366 #endif // defined(HAVE_PTHREAD_SPIN_LOCK)
   1367 
   1368 
   1369 /*----------------------------------------------------------------*/
   1370 /*--- pthread_rwlock_t functions                               ---*/
   1371 /*----------------------------------------------------------------*/
   1372 
   1373 /* Android's pthread.h doesn't say anything about rwlocks, hence these
   1374    functions have to be conditionally compiled. */
   1375 #if defined(HAVE_PTHREAD_RWLOCK_T)
   1376 
   1377 /* Handled:   pthread_rwlock_init pthread_rwlock_destroy
   1378               pthread_rwlock_rdlock
   1379               pthread_rwlock_wrlock
   1380               pthread_rwlock_unlock
   1381 
   1382    Unhandled: pthread_rwlock_timedrdlock
   1383               pthread_rwlock_tryrdlock
   1384 
   1385               pthread_rwlock_timedwrlock
   1386               pthread_rwlock_trywrlock
   1387 */
   1388 
   1389 //-----------------------------------------------------------
   1390 // glibc:  pthread_rwlock_init
   1391 // darwin: pthread_rwlock_init
   1392 // darwin: pthread_rwlock_init$UNIX2003
   1393 __attribute__((noinline))
   1394 static int pthread_rwlock_init_WRK(pthread_rwlock_t *rwl,
   1395                                    pthread_rwlockattr_t* attr)
   1396 {
   1397    int    ret;
   1398    OrigFn fn;
   1399    VALGRIND_GET_ORIG_FN(fn);
   1400    if (TRACE_PTH_FNS) {
   1401       fprintf(stderr, "<< pthread_rwl_init %p", rwl); fflush(stderr);
   1402    }
   1403 
   1404    CALL_FN_W_WW(ret, fn, rwl,attr);
   1405 
   1406    if (ret == 0 /*success*/) {
   1407       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
   1408                   pthread_rwlock_t*,rwl);
   1409    } else {
   1410       DO_PthAPIerror( "pthread_rwlock_init", ret );
   1411    }
   1412 
   1413    if (TRACE_PTH_FNS) {
   1414       fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
   1415    }
   1416    return ret;
   1417 }
   1418 #if defined(VGO_linux)
   1419    PTH_FUNC(int, pthreadZurwlockZuinit, // pthread_rwlock_init
   1420                  pthread_rwlock_t *rwl,
   1421                  pthread_rwlockattr_t* attr) {
   1422       return pthread_rwlock_init_WRK(rwl, attr);
   1423    }
   1424 #elif defined(VGO_darwin)
   1425    PTH_FUNC(int, pthreadZurwlockZuinitZa, // pthread_rwlock_init*
   1426                  pthread_rwlock_t *rwl,
   1427                  pthread_rwlockattr_t* attr) {
   1428       return pthread_rwlock_init_WRK(rwl, attr);
   1429    }
   1430 #else
   1431 #  error "Unsupported OS"
   1432 #endif
   1433 
   1434 
   1435 //-----------------------------------------------------------
   1436 // glibc:  pthread_rwlock_destroy
   1437 // darwin: pthread_rwlock_destroy
   1438 // darwin: pthread_rwlock_destroy$UNIX2003
   1439 //
   1440 __attribute__((noinline))
   1441 static int pthread_rwlock_destroy_WRK(pthread_rwlock_t* rwl)
   1442 {
   1443    int    ret;
   1444    OrigFn fn;
   1445    VALGRIND_GET_ORIG_FN(fn);
   1446    if (TRACE_PTH_FNS) {
   1447       fprintf(stderr, "<< pthread_rwl_destroy %p", rwl); fflush(stderr);
   1448    }
   1449 
   1450    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE,
   1451                pthread_rwlock_t*,rwl);
   1452 
   1453    CALL_FN_W_W(ret, fn, rwl);
   1454 
   1455    if (ret != 0) {
   1456       DO_PthAPIerror( "pthread_rwlock_destroy", ret );
   1457    }
   1458 
   1459    if (TRACE_PTH_FNS) {
   1460       fprintf(stderr, " :: rwl_destroy -> %d >>\n", ret);
   1461    }
   1462    return ret;
   1463 }
   1464 #if defined(VGO_linux)
   1465    PTH_FUNC(int, pthreadZurwlockZudestroy, // pthread_rwlock_destroy
   1466                  pthread_rwlock_t *rwl) {
   1467       return pthread_rwlock_destroy_WRK(rwl);
   1468    }
   1469 #elif defined(VGO_darwin)
   1470    PTH_FUNC(int, pthreadZurwlockZudestroyZa, // pthread_rwlock_destroy*
   1471                  pthread_rwlock_t *rwl) {
   1472       return pthread_rwlock_destroy_WRK(rwl);
   1473    }
   1474 #else
   1475 #  error "Unsupported OS"
   1476 #endif
   1477 
   1478 
   1479 //-----------------------------------------------------------
   1480 // glibc:  pthread_rwlock_wrlock
   1481 // darwin: pthread_rwlock_wrlock
   1482 // darwin: pthread_rwlock_wrlock$UNIX2003
   1483 //
   1484 __attribute__((noinline))
   1485 static int pthread_rwlock_wrlock_WRK(pthread_rwlock_t* rwlock)
   1486 {
   1487    int    ret;
   1488    OrigFn fn;
   1489    VALGRIND_GET_ORIG_FN(fn);
   1490    if (TRACE_PTH_FNS) {
   1491       fprintf(stderr, "<< pthread_rwl_wlk %p", rwlock); fflush(stderr);
   1492    }
   1493 
   1494    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
   1495                  pthread_rwlock_t*,rwlock,
   1496                  long,1/*isW*/, long,0/*!isTryLock*/);
   1497 
   1498    CALL_FN_W_W(ret, fn, rwlock);
   1499 
   1500    if (ret == 0 /*success*/) {
   1501       DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
   1502                    pthread_rwlock_t*,rwlock, long,1/*isW*/);
   1503    } else {
   1504       DO_PthAPIerror( "pthread_rwlock_wrlock", ret );
   1505    }
   1506 
   1507    if (TRACE_PTH_FNS) {
   1508       fprintf(stderr, " :: rwl_wlk -> %d >>\n", ret);
   1509    }
   1510    return ret;
   1511 }
   1512 #if defined(VGO_linux)
   1513    PTH_FUNC(int, pthreadZurwlockZuwrlock, // pthread_rwlock_wrlock
   1514                  pthread_rwlock_t* rwlock) {
   1515       return pthread_rwlock_wrlock_WRK(rwlock);
   1516    }
   1517 #elif defined(VGO_darwin)
   1518    PTH_FUNC(int, pthreadZurwlockZuwrlockZa, // pthread_rwlock_wrlock*
   1519                  pthread_rwlock_t* rwlock) {
   1520       return pthread_rwlock_wrlock_WRK(rwlock);
   1521    }
   1522 #else
   1523 #  error "Unsupported OS"
   1524 #endif
   1525 
   1526 
   1527 //-----------------------------------------------------------
   1528 // glibc:  pthread_rwlock_rdlock
   1529 // darwin: pthread_rwlock_rdlock
   1530 // darwin: pthread_rwlock_rdlock$UNIX2003
   1531 //
   1532 __attribute__((noinline))
   1533 static int pthread_rwlock_rdlock_WRK(pthread_rwlock_t* rwlock)
   1534 {
   1535    int    ret;
   1536    OrigFn fn;
   1537    VALGRIND_GET_ORIG_FN(fn);
   1538    if (TRACE_PTH_FNS) {
   1539       fprintf(stderr, "<< pthread_rwl_rlk %p", rwlock); fflush(stderr);
   1540    }
   1541 
   1542    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
   1543                  pthread_rwlock_t*,rwlock,
   1544                  long,0/*!isW*/, long,0/*!isTryLock*/);
   1545 
   1546    CALL_FN_W_W(ret, fn, rwlock);
   1547 
   1548    if (ret == 0 /*success*/) {
   1549       DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
   1550                    pthread_rwlock_t*,rwlock, long,0/*!isW*/);
   1551    } else {
   1552       DO_PthAPIerror( "pthread_rwlock_rdlock", ret );
   1553    }
   1554 
   1555    if (TRACE_PTH_FNS) {
   1556       fprintf(stderr, " :: rwl_rlk -> %d >>\n", ret);
   1557    }
   1558    return ret;
   1559 }
   1560 #if defined(VGO_linux)
   1561    PTH_FUNC(int, pthreadZurwlockZurdlock, // pthread_rwlock_rdlock
   1562                  pthread_rwlock_t* rwlock) {
   1563       return pthread_rwlock_rdlock_WRK(rwlock);
   1564    }
   1565 #elif defined(VGO_darwin)
   1566    PTH_FUNC(int, pthreadZurwlockZurdlockZa, // pthread_rwlock_rdlock*
   1567                  pthread_rwlock_t* rwlock) {
   1568       return pthread_rwlock_rdlock_WRK(rwlock);
   1569    }
   1570 #else
   1571 #  error "Unsupported OS"
   1572 #endif
   1573 
   1574 
   1575 //-----------------------------------------------------------
   1576 // glibc:  pthread_rwlock_trywrlock
   1577 // darwin: pthread_rwlock_trywrlock
   1578 // darwin: pthread_rwlock_trywrlock$UNIX2003
   1579 //
   1580 __attribute__((noinline))
   1581 static int pthread_rwlock_trywrlock_WRK(pthread_rwlock_t* rwlock)
   1582 {
   1583    int    ret;
   1584    OrigFn fn;
   1585    VALGRIND_GET_ORIG_FN(fn);
   1586    if (TRACE_PTH_FNS) {
   1587       fprintf(stderr, "<< pthread_rwl_trywlk %p", rwlock); fflush(stderr);
   1588    }
   1589 
   1590    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
   1591                  pthread_rwlock_t*,rwlock,
   1592                  long,1/*isW*/, long,1/*isTryLock*/);
   1593 
   1594    CALL_FN_W_W(ret, fn, rwlock);
   1595 
   1596    /* There's a hole here: libpthread now knows the lock is locked,
   1597       but the tool doesn't, so some other thread could run and detect
   1598       that the lock has been acquired by someone (this thread).  Does
   1599       this matter?  Not sure, but I don't think so. */
   1600 
   1601    if (ret == 0 /*success*/) {
   1602       DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
   1603                    pthread_rwlock_t*,rwlock, long,1/*isW*/);
   1604    } else {
   1605       if (ret != EBUSY)
   1606          DO_PthAPIerror( "pthread_rwlock_trywrlock", ret );
   1607    }
   1608 
   1609    if (TRACE_PTH_FNS) {
   1610       fprintf(stderr, " :: rwl_trywlk -> %d >>\n", ret);
   1611    }
   1612    return ret;
   1613 }
   1614 #if defined(VGO_linux)
   1615    PTH_FUNC(int, pthreadZurwlockZutrywrlock, // pthread_rwlock_trywrlock
   1616                  pthread_rwlock_t* rwlock) {
   1617       return pthread_rwlock_trywrlock_WRK(rwlock);
   1618    }
   1619 #elif defined(VGO_darwin)
   1620    PTH_FUNC(int, pthreadZurwlockZutrywrlockZa, // pthread_rwlock_trywrlock*
   1621                  pthread_rwlock_t* rwlock) {
   1622       return pthread_rwlock_trywrlock_WRK(rwlock);
   1623    }
   1624 #else
   1625 #  error "Unsupported OS"
   1626 #endif
   1627 
   1628 
   1629 //-----------------------------------------------------------
   1630 // glibc:  pthread_rwlock_tryrdlock
   1631 // darwin: pthread_rwlock_trywrlock
   1632 // darwin: pthread_rwlock_trywrlock$UNIX2003
   1633 //
   1634 __attribute__((noinline))
   1635 static int pthread_rwlock_tryrdlock_WRK(pthread_rwlock_t* rwlock)
   1636 {
   1637    int    ret;
   1638    OrigFn fn;
   1639    VALGRIND_GET_ORIG_FN(fn);
   1640    if (TRACE_PTH_FNS) {
   1641       fprintf(stderr, "<< pthread_rwl_tryrlk %p", rwlock); fflush(stderr);
   1642    }
   1643 
   1644    DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
   1645                  pthread_rwlock_t*,rwlock,
   1646                  long,0/*!isW*/, long,1/*isTryLock*/);
   1647 
   1648    CALL_FN_W_W(ret, fn, rwlock);
   1649 
   1650    /* There's a hole here: libpthread now knows the lock is locked,
   1651       but the tool doesn't, so some other thread could run and detect
   1652       that the lock has been acquired by someone (this thread).  Does
   1653       this matter?  Not sure, but I don't think so. */
   1654 
   1655    if (ret == 0 /*success*/) {
   1656       DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
   1657                    pthread_rwlock_t*,rwlock, long,0/*!isW*/);
   1658    } else {
   1659       if (ret != EBUSY)
   1660          DO_PthAPIerror( "pthread_rwlock_tryrdlock", ret );
   1661    }
   1662 
   1663    if (TRACE_PTH_FNS) {
   1664       fprintf(stderr, " :: rwl_tryrlk -> %d >>\n", ret);
   1665    }
   1666    return ret;
   1667 }
   1668 #if defined(VGO_linux)
   1669    PTH_FUNC(int, pthreadZurwlockZutryrdlock, // pthread_rwlock_tryrdlock
   1670                  pthread_rwlock_t* rwlock) {
   1671       return pthread_rwlock_tryrdlock_WRK(rwlock);
   1672    }
   1673 #elif defined(VGO_darwin)
   1674    PTH_FUNC(int, pthreadZurwlockZutryrdlockZa, // pthread_rwlock_tryrdlock*
   1675                  pthread_rwlock_t* rwlock) {
   1676       return pthread_rwlock_tryrdlock_WRK(rwlock);
   1677    }
   1678 #else
   1679 #  error "Unsupported OS"
   1680 #endif
   1681 
   1682 
   1683 //-----------------------------------------------------------
   1684 // glibc:  pthread_rwlock_unlock
   1685 // darwin: pthread_rwlock_unlock
   1686 // darwin: pthread_rwlock_unlock$UNIX2003
   1687 __attribute__((noinline))
   1688 static int pthread_rwlock_unlock_WRK(pthread_rwlock_t* rwlock)
   1689 {
   1690    int    ret;
   1691    OrigFn fn;
   1692    VALGRIND_GET_ORIG_FN(fn);
   1693    if (TRACE_PTH_FNS) {
   1694       fprintf(stderr, "<< pthread_rwl_unlk %p", rwlock); fflush(stderr);
   1695    }
   1696 
   1697    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
   1698                pthread_rwlock_t*,rwlock);
   1699 
   1700    CALL_FN_W_W(ret, fn, rwlock);
   1701 
   1702    if (ret == 0 /*success*/) {
   1703       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
   1704                   pthread_rwlock_t*,rwlock);
   1705    } else {
   1706       DO_PthAPIerror( "pthread_rwlock_unlock", ret );
   1707    }
   1708 
   1709    if (TRACE_PTH_FNS) {
   1710       fprintf(stderr, " :: rwl_unlk -> %d >>\n", ret);
   1711    }
   1712    return ret;
   1713 }
   1714 #if defined(VGO_linux)
   1715    PTH_FUNC(int, pthreadZurwlockZuunlock, // pthread_rwlock_unlock
   1716                  pthread_rwlock_t* rwlock) {
   1717       return pthread_rwlock_unlock_WRK(rwlock);
   1718    }
   1719 #elif defined(VGO_darwin)
   1720    PTH_FUNC(int, pthreadZurwlockZuunlockZa, // pthread_rwlock_unlock*
   1721                  pthread_rwlock_t* rwlock) {
   1722       return pthread_rwlock_unlock_WRK(rwlock);
   1723    }
   1724 #else
   1725 #  error "Unsupported OS"
   1726 #endif
   1727 
   1728 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
   1729 
   1730 
   1731 /*----------------------------------------------------------------*/
   1732 /*--- POSIX semaphores                                         ---*/
   1733 /*----------------------------------------------------------------*/
   1734 
   1735 #include <semaphore.h>
   1736 #include <fcntl.h>       /* O_CREAT */
   1737 
   1738 #define TRACE_SEM_FNS 0
   1739 
   1740 /* Handled:
   1741      int sem_init(sem_t *sem, int pshared, unsigned value);
   1742      int sem_destroy(sem_t *sem);
   1743      int sem_wait(sem_t *sem);
   1744      int sem_post(sem_t *sem);
   1745      sem_t* sem_open(const char *name, int oflag,
   1746                      ... [mode_t mode, unsigned value]);
   1747         [complete with its idiotic semantics]
   1748      int sem_close(sem_t* sem);
   1749 
   1750    Unhandled:
   1751      int sem_trywait(sem_t *sem);
   1752      int sem_timedwait(sem_t *restrict sem,
   1753                        const struct timespec *restrict abs_timeout);
   1754 */
   1755 
   1756 //-----------------------------------------------------------
   1757 // glibc:  sem_init@@GLIBC_2.2.5
   1758 // glibc:  sem_init@@GLIBC_2.1
   1759 // glibc:  sem_init (at) GLIBC_2.0
   1760 // darwin: sem_init
   1761 //
   1762 __attribute__((noinline))
   1763 static int sem_init_WRK(sem_t* sem, int pshared, unsigned long value)
   1764 {
   1765    OrigFn fn;
   1766    int    ret;
   1767    VALGRIND_GET_ORIG_FN(fn);
   1768 
   1769    if (TRACE_SEM_FNS) {
   1770       fprintf(stderr, "<< sem_init(%p,%d,%lu) ", sem,pshared,value);
   1771       fflush(stderr);
   1772    }
   1773 
   1774    CALL_FN_W_WWW(ret, fn, sem,pshared,value);
   1775 
   1776    if (ret == 0) {
   1777       DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
   1778                    sem_t*, sem, unsigned long, value);
   1779    } else {
   1780       DO_PthAPIerror( "sem_init", errno );
   1781    }
   1782 
   1783    if (TRACE_SEM_FNS) {
   1784       fprintf(stderr, " sem_init -> %d >>\n", ret);
   1785       fflush(stderr);
   1786    }
   1787 
   1788    return ret;
   1789 }
   1790 #if defined(VGO_linux)
   1791    PTH_FUNC(int, semZuinitZAZa, // sem_init@*
   1792                  sem_t* sem, int pshared, unsigned long value) {
   1793       return sem_init_WRK(sem, pshared, value);
   1794    }
   1795 #elif defined(VGO_darwin)
   1796    PTH_FUNC(int, semZuinit, // sem_init
   1797                  sem_t* sem, int pshared, unsigned long value) {
   1798       return sem_init_WRK(sem, pshared, value);
   1799    }
   1800 #else
   1801 #  error "Unsupported OS"
   1802 #endif
   1803 
   1804 
   1805 //-----------------------------------------------------------
   1806 // glibc:  sem_destroy (at) GLIBC_2.0
   1807 // glibc:  sem_destroy@@GLIBC_2.1
   1808 // glibc:  sem_destroy@@GLIBC_2.2.5
   1809 // darwin: sem_destroy
   1810 __attribute__((noinline))
   1811 static int sem_destroy_WRK(sem_t* sem)
   1812 {
   1813    OrigFn fn;
   1814    int    ret;
   1815    VALGRIND_GET_ORIG_FN(fn);
   1816 
   1817    if (TRACE_SEM_FNS) {
   1818       fprintf(stderr, "<< sem_destroy(%p) ", sem);
   1819       fflush(stderr);
   1820    }
   1821 
   1822    DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
   1823 
   1824    CALL_FN_W_W(ret, fn, sem);
   1825 
   1826    if (ret != 0) {
   1827       DO_PthAPIerror( "sem_destroy", errno );
   1828    }
   1829 
   1830    if (TRACE_SEM_FNS) {
   1831       fprintf(stderr, " sem_destroy -> %d >>\n", ret);
   1832       fflush(stderr);
   1833    }
   1834 
   1835    return ret;
   1836 }
   1837 #if defined(VGO_linux)
   1838    PTH_FUNC(int, semZudestroyZAZa,  // sem_destroy*
   1839                  sem_t* sem) {
   1840       return sem_destroy_WRK(sem);
   1841    }
   1842 #elif defined(VGO_darwin)
   1843    PTH_FUNC(int, semZudestroy,  // sem_destroy
   1844                  sem_t* sem) {
   1845       return sem_destroy_WRK(sem);
   1846    }
   1847 #else
   1848 #  error "Unsupported OS"
   1849 #endif
   1850 
   1851 
   1852 //-----------------------------------------------------------
   1853 // glibc:  sem_wait
   1854 // glibc:  sem_wait (at) GLIBC_2.0
   1855 // glibc:  sem_wait@@GLIBC_2.1
   1856 // darwin: sem_wait
   1857 // darwin: sem_wait$NOCANCEL$UNIX2003
   1858 // darwin: sem_wait$UNIX2003
   1859 //
   1860 /* wait: decrement semaphore - acquire lockage */
   1861 __attribute__((noinline))
   1862 static int sem_wait_WRK(sem_t* sem)
   1863 {
   1864    OrigFn fn;
   1865    int    ret;
   1866    VALGRIND_GET_ORIG_FN(fn);
   1867 
   1868    if (TRACE_SEM_FNS) {
   1869       fprintf(stderr, "<< sem_wait(%p) ", sem);
   1870       fflush(stderr);
   1871    }
   1872 
   1873    CALL_FN_W_W(ret, fn, sem);
   1874 
   1875    if (ret == 0) {
   1876       DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST, sem_t*,sem);
   1877    } else {
   1878       DO_PthAPIerror( "sem_wait", errno );
   1879    }
   1880 
   1881    if (TRACE_SEM_FNS) {
   1882       fprintf(stderr, " sem_wait -> %d >>\n", ret);
   1883       fflush(stderr);
   1884    }
   1885 
   1886    return ret;
   1887 }
   1888 #if defined(VGO_linux)
   1889    PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
   1890       return sem_wait_WRK(sem);
   1891    }
   1892    PTH_FUNC(int, semZuwaitZAZa, sem_t* sem) { /* sem_wait@* */
   1893       return sem_wait_WRK(sem);
   1894    }
   1895 #elif defined(VGO_darwin)
   1896    PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
   1897       return sem_wait_WRK(sem);
   1898    }
   1899    PTH_FUNC(int, semZuwaitZDZa, sem_t* sem) { /* sem_wait$* */
   1900       return sem_wait_WRK(sem);
   1901    }
   1902 #else
   1903 #  error "Unsupported OS"
   1904 #endif
   1905 
   1906 
   1907 //-----------------------------------------------------------
   1908 // glibc:  sem_post
   1909 // glibc:  sem_post (at) GLIBC_2.0
   1910 // glibc:  sem_post@@GLIBC_2.1
   1911 // darwin: sem_post
   1912 //
   1913 /* post: increment semaphore - release lockage */
   1914 __attribute__((noinline))
   1915 static int sem_post_WRK(sem_t* sem)
   1916 {
   1917    OrigFn fn;
   1918    int    ret;
   1919 
   1920    VALGRIND_GET_ORIG_FN(fn);
   1921 
   1922    if (TRACE_SEM_FNS) {
   1923       fprintf(stderr, "<< sem_post(%p) ", sem);
   1924       fflush(stderr);
   1925    }
   1926 
   1927    DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_PRE, sem_t*,sem);
   1928 
   1929    CALL_FN_W_W(ret, fn, sem);
   1930 
   1931    if (ret != 0) {
   1932       DO_PthAPIerror( "sem_post", errno );
   1933    }
   1934 
   1935    if (TRACE_SEM_FNS) {
   1936       fprintf(stderr, " sem_post -> %d >>\n", ret);
   1937       fflush(stderr);
   1938    }
   1939 
   1940    return ret;
   1941 }
   1942 #if defined(VGO_linux)
   1943    PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
   1944       return sem_post_WRK(sem);
   1945    }
   1946    PTH_FUNC(int, semZupostZAZa, sem_t* sem) { /* sem_post@* */
   1947       return sem_post_WRK(sem);
   1948    }
   1949 #elif defined(VGO_darwin)
   1950    PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
   1951       return sem_post_WRK(sem);
   1952    }
   1953 #else
   1954 #  error "Unsupported OS"
   1955 #endif
   1956 
   1957 
   1958 //-----------------------------------------------------------
   1959 // glibc:  sem_open
   1960 // darwin: sem_open
   1961 //
   1962 PTH_FUNC(sem_t*, semZuopen,
   1963                  const char* name, long oflag,
   1964                  long mode, unsigned long value)
   1965 {
   1966    /* A copy of sem_init_WRK (more or less).  Is this correct? */
   1967    OrigFn fn;
   1968    sem_t* ret;
   1969    VALGRIND_GET_ORIG_FN(fn);
   1970 
   1971    if (TRACE_SEM_FNS) {
   1972       fprintf(stderr, "<< sem_open(\"%s\",%ld,%lx,%lu) ",
   1973                       name,oflag,mode,value);
   1974       fflush(stderr);
   1975    }
   1976 
   1977    CALL_FN_W_WWWW(ret, fn, name,oflag,mode,value);
   1978 
   1979    if (ret != SEM_FAILED && (oflag & O_CREAT)) {
   1980       DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
   1981                    sem_t*, ret, unsigned long, value);
   1982    }
   1983    if (ret == SEM_FAILED) {
   1984       DO_PthAPIerror( "sem_open", errno );
   1985    }
   1986 
   1987    if (TRACE_SEM_FNS) {
   1988       fprintf(stderr, " sem_open -> %p >>\n", ret);
   1989       fflush(stderr);
   1990    }
   1991 
   1992    return ret;
   1993 }
   1994 
   1995 
   1996 //-----------------------------------------------------------
   1997 // glibc:  sem_close
   1998 // darwin: sem_close
   1999 PTH_FUNC(int, sem_close, sem_t* sem)
   2000 {
   2001    OrigFn fn;
   2002    int    ret;
   2003    VALGRIND_GET_ORIG_FN(fn);
   2004 
   2005    if (TRACE_SEM_FNS) {
   2006       fprintf(stderr, "<< sem_close(%p) ", sem);
   2007       fflush(stderr);
   2008    }
   2009 
   2010    DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
   2011 
   2012    CALL_FN_W_W(ret, fn, sem);
   2013 
   2014    if (ret != 0) {
   2015       DO_PthAPIerror( "sem_close", errno );
   2016    }
   2017 
   2018    if (TRACE_SEM_FNS) {
   2019       fprintf(stderr, " close -> %d >>\n", ret);
   2020       fflush(stderr);
   2021    }
   2022 
   2023    return ret;
   2024 }
   2025 
   2026 
   2027 /*----------------------------------------------------------------*/
   2028 /*--- Qt 4 threading functions (w/ GNU name mangling)          ---*/
   2029 /*----------------------------------------------------------------*/
   2030 
   2031 /* Handled:
   2032       QMutex::lock()
   2033       QMutex::unlock()
   2034       QMutex::tryLock()
   2035       QMutex::tryLock(int)
   2036 
   2037       QMutex::QMutex(QMutex::RecursionMode)  _ZN6QMutexC1ENS_13RecursionModeE
   2038       QMutex::QMutex(QMutex::RecursionMode)  _ZN6QMutexC2ENS_13RecursionModeE
   2039       QMutex::~QMutex()                      _ZN6QMutexD1Ev
   2040       QMutex::~QMutex()                      _ZN6QMutexD2Ev
   2041 
   2042    Unhandled:
   2043       QReadWriteLock::lockForRead()
   2044       QReadWriteLock::lockForWrite()
   2045       QReadWriteLock::unlock()
   2046       QReadWriteLock::tryLockForRead(int)
   2047       QReadWriteLock::tryLockForRead()
   2048       QReadWriteLock::tryLockForWrite(int)
   2049       QReadWriteLock::tryLockForWrite()
   2050 
   2051       QWaitCondition::wait(QMutex*, unsigned long)
   2052       QWaitCondition::wakeAll()
   2053       QWaitCondition::wakeOne()
   2054 
   2055       QSemaphore::*
   2056 */
   2057 /* More comments, 19 Nov 08, based on assessment of qt-4.5.0TP1,
   2058    at least on Unix:
   2059 
   2060    It's apparently only necessary to intercept QMutex, since that is
   2061    not implemented using pthread_mutex_t; instead Qt4 has its own
   2062    implementation based on atomics (to check the non-contended case)
   2063    and pthread_cond_wait (to wait in the contended case).
   2064 
   2065    QReadWriteLock is built on top of QMutex, counters, and a wait
   2066    queue.  So we don't need to handle it specially once QMutex
   2067    handling is correct -- presumably the dependencies through QMutex
   2068    are sufficient to avoid any false race reports.  On the other hand,
   2069    it is an open question whether too many dependencies are observed
   2070    -- in which case we may miss races (false negatives).  I suspect
   2071    this is likely to be the case, unfortunately.
   2072 
   2073    QWaitCondition is built on pthread_cond_t, pthread_mutex_t, QMutex
   2074    and QReadWriteLock.  Same compositional-correctness justificiation
   2075    and limitations as fro QReadWriteLock.
   2076 
   2077    Ditto QSemaphore (from cursory examination).
   2078 
   2079    Does it matter that only QMutex is handled directly?  Open
   2080    question.  From testing with drd/tests/qt4_* and with KDE4 apps, it
   2081    appears that no false errors are reported; however it is not clear
   2082    if this is causing false negatives.
   2083 
   2084    Another problem with Qt4 is thread exiting.  Threads are created
   2085    with pthread_create (fine); but they detach and simply exit when
   2086    done.  There is no use of pthread_join, and the provided
   2087    wait-for-a-thread-to-exit mechanism (QThread::wait, I believe)
   2088    relies on a system of mutexes and flags.  I suspect this also
   2089    causes too many dependencies to appear.  Consequently H sometimes
   2090    fails to detect races at exit in some very short-lived racy
   2091    programs, because it appears that a thread can exit _and_ have an
   2092    observed dependency edge back to the main thread (presumably)
   2093    before the main thread reaps the child (that is, calls
   2094    QThread::wait).
   2095 
   2096    This theory is supported by the observation that if all threads are
   2097    made to wait at a pthread_barrier_t immediately before they exit,
   2098    then H's detection of races in such programs becomes reliable;
   2099    without the barrier, it is varies from run to run, depending
   2100    (according to investigation) on whether aforementioned
   2101    exit-before-reaping behaviour happens or not.
   2102 
   2103    Finally, why is it necessary to intercept the QMutex constructors
   2104    and destructors?  The constructors are intercepted only as a matter
   2105    of convenience, so H can print accurate "first observed at"
   2106    clauses.  However, it is actually necessary to intercept the
   2107    destructors (as it is with pthread_mutex_destroy) in order that
   2108    locks get removed from LAOG when they are destroyed.
   2109 */
   2110 
   2111 // soname is libQtCore.so.4 ; match against libQtCore.so*
   2112 #define QT4_FUNC(ret_ty, f, args...) \
   2113    ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args); \
   2114    ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args)
   2115 
   2116 // soname is libQt5Core.so.4 ; match against libQt5Core.so*
   2117 #define QT5_FUNC(ret_ty, f, args...) \
   2118    ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args); \
   2119    ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args)
   2120 
   2121 //-----------------------------------------------------------
   2122 // QMutex::lock()
   2123 __attribute__((noinline))
   2124 static void QMutex_lock_WRK(void* self)
   2125 {
   2126    OrigFn fn;
   2127    VALGRIND_GET_ORIG_FN(fn);
   2128    if (TRACE_QT4_FNS) {
   2129       fprintf(stderr, "<< QMutex::lock %p", self); fflush(stderr);
   2130    }
   2131 
   2132    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
   2133                 void*,self, long,0/*!isTryLock*/);
   2134 
   2135    CALL_FN_v_W(fn, self);
   2136 
   2137    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
   2138                void*, self);
   2139 
   2140    if (TRACE_QT4_FNS) {
   2141       fprintf(stderr, " :: Q::lock done >>\n");
   2142    }
   2143 }
   2144 
   2145 QT4_FUNC(void, _ZN6QMutex4lockEv, void* self) {
   2146     QMutex_lock_WRK(self);
   2147 }
   2148 QT5_FUNC(void, _ZN6QMutex4lockEv, void* self) {
   2149     QMutex_lock_WRK(self);
   2150 }
   2151 
   2152 //-----------------------------------------------------------
   2153 // QMutex::unlock()
   2154 __attribute__((noinline))
   2155 static void QMutex_unlock_WRK(void* self)
   2156 {
   2157    OrigFn fn;
   2158    VALGRIND_GET_ORIG_FN(fn);
   2159 
   2160    if (TRACE_QT4_FNS) {
   2161       fprintf(stderr, "<< QMutex::unlock %p", self); fflush(stderr);
   2162    }
   2163 
   2164    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
   2165                void*, self);
   2166 
   2167    CALL_FN_v_W(fn, self);
   2168 
   2169    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
   2170                void*, self);
   2171 
   2172    if (TRACE_QT4_FNS) {
   2173       fprintf(stderr, " Q::unlock done >>\n");
   2174    }
   2175 }
   2176 
   2177 QT4_FUNC(void, _ZN6QMutex6unlockEv, void* self) {
   2178     QMutex_unlock_WRK(self);
   2179 }
   2180 QT5_FUNC(void, _ZN6QMutex6unlockEv, void* self) {
   2181     QMutex_unlock_WRK(self);
   2182 }
   2183 
   2184 //-----------------------------------------------------------
   2185 // bool QMutex::tryLock()
   2186 // using 'long' to mimic C++ 'bool'
   2187 __attribute__((noinline))
   2188 static long QMutex_tryLock_WRK(void* self)
   2189 {
   2190    OrigFn fn;
   2191    long   ret;
   2192    VALGRIND_GET_ORIG_FN(fn);
   2193    if (TRACE_QT4_FNS) {
   2194       fprintf(stderr, "<< QMutex::tryLock %p", self); fflush(stderr);
   2195    }
   2196 
   2197    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
   2198                 void*,self, long,1/*isTryLock*/);
   2199 
   2200    CALL_FN_W_W(ret, fn, self);
   2201 
   2202    // assumes that only the low 8 bits of the 'bool' are significant
   2203    if (ret & 0xFF) {
   2204       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
   2205                   void*, self);
   2206    }
   2207 
   2208    if (TRACE_QT4_FNS) {
   2209       fprintf(stderr, " :: Q::tryLock -> %lu >>\n", ret);
   2210    }
   2211 
   2212    return ret;
   2213 }
   2214 
   2215 QT4_FUNC(long, _ZN6QMutex7tryLockEv, void* self) {
   2216     return QMutex_tryLock_WRK(self);
   2217 }
   2218 QT5_FUNC(long, _ZN6QMutex7tryLockEv, void* self) {
   2219     return QMutex_tryLock_WRK(self);
   2220 }
   2221 
   2222 //-----------------------------------------------------------
   2223 // bool QMutex::tryLock(int)
   2224 // using 'long' to mimic C++ 'bool'
   2225 __attribute__((noinline))
   2226 static long QMutex_tryLock_int_WRK(void* self, long arg2)
   2227 {
   2228    OrigFn fn;
   2229    long   ret;
   2230    VALGRIND_GET_ORIG_FN(fn);
   2231    if (TRACE_QT4_FNS) {
   2232       fprintf(stderr, "<< QMutex::tryLock(int) %p %d", self, (int)arg2);
   2233       fflush(stderr);
   2234    }
   2235 
   2236    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
   2237                 void*,self, long,1/*isTryLock*/);
   2238 
   2239    CALL_FN_W_WW(ret, fn, self,arg2);
   2240 
   2241    // assumes that only the low 8 bits of the 'bool' are significant
   2242    if (ret & 0xFF) {
   2243       DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
   2244                   void*, self);
   2245    }
   2246 
   2247    if (TRACE_QT4_FNS) {
   2248       fprintf(stderr, " :: Q::tryLock(int) -> %lu >>\n", ret);
   2249    }
   2250 
   2251    return ret;
   2252 }
   2253 
   2254 QT4_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2) {
   2255     return QMutex_tryLock_int_WRK(self, arg2);
   2256 }
   2257 QT5_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2) {
   2258     return QMutex_tryLock_int_WRK(self, arg2);
   2259 }
   2260 
   2261 //-----------------------------------------------------------
   2262 // It's not really very clear what the args are here.  But from
   2263 // a bit of dataflow analysis of the generated machine code of
   2264 // the original function, it appears this takes two args, and
   2265 // returns nothing.  Nevertheless preserve return value just in
   2266 // case.  A bit of debug printing indicates that the first arg
   2267 // is that of the mutex and the second is either zero or one,
   2268 // probably being the recursion mode, therefore.
   2269 // QMutex::QMutex(QMutex::RecursionMode)  ("C1ENS" variant)
   2270 __attribute__((noinline))
   2271 static void* QMutex_constructor_WRK(void* mutex, long recmode)
   2272 {
   2273    OrigFn fn;
   2274    long   ret;
   2275    VALGRIND_GET_ORIG_FN(fn);
   2276    CALL_FN_W_WW(ret, fn, mutex, recmode);
   2277    //   fprintf(stderr, "QMutex constructor 1: %p <- %p %p\n", ret, arg1, arg2);
   2278    DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
   2279                 void*,mutex, long,1/*mbRec*/);
   2280    return (void*)ret;
   2281 }
   2282 
   2283 QT4_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE, void* self, long recmode) {
   2284     return QMutex_constructor_WRK(self, recmode);
   2285 }
   2286 QT5_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE, void* self, long recmode) {
   2287     return QMutex_constructor_WRK(self, recmode);
   2288 }
   2289 
   2290 //-----------------------------------------------------------
   2291 // QMutex::~QMutex()  ("D1Ev" variant)
   2292 __attribute__((noinline))
   2293 static void* QMutex_destructor_WRK(void* mutex)
   2294 {
   2295    OrigFn fn;
   2296    long   ret;
   2297    VALGRIND_GET_ORIG_FN(fn);
   2298    DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
   2299                void*,mutex);
   2300    CALL_FN_W_W(ret, fn, mutex);
   2301    return (void*)ret;
   2302 }
   2303 
   2304 QT4_FUNC(void*, _ZN6QMutexD1Ev, void* self) {
   2305     return QMutex_destructor_WRK(self);
   2306 }
   2307 QT5_FUNC(void*, _ZN6QMutexD1Ev, void* self) {
   2308     return QMutex_destructor_WRK(self);
   2309 }
   2310 
   2311 //-----------------------------------------------------------
   2312 // QMutex::QMutex(QMutex::RecursionMode)  ("C2ENS" variant)
   2313 QT4_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE,
   2314          void* mutex,
   2315          long  recmode)
   2316 {
   2317    assert(0);
   2318    /*NOTREACHED*/
   2319    /* Android's gcc behaves like it doesn't know that assert(0)
   2320       never returns.  Hence: */
   2321    return NULL;
   2322 }
   2323 
   2324 QT5_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE, void* self, long recmode)
   2325 {
   2326    assert(0);
   2327    /*NOTREACHED*/
   2328    return NULL;
   2329 }
   2330 
   2331 //-----------------------------------------------------------
   2332 // QMutex::~QMutex()  ("D2Ev" variant)
   2333 QT4_FUNC(void*, _ZN6QMutexD2Ev, void* mutex)
   2334 {
   2335    assert(0);
   2336    /* Android's gcc behaves like it doesn't know that assert(0)
   2337       never returns.  Hence: */
   2338    return NULL;
   2339 }
   2340 
   2341 QT5_FUNC(void*, _ZN6QMutexD2Ev, void* self)
   2342 {
   2343    assert(0);
   2344    /*NOTREACHED*/
   2345    return NULL;
   2346 }
   2347 
   2348 // QReadWriteLock is not intercepted directly.  See comments
   2349 // above.
   2350 
   2351 //// QReadWriteLock::lockForRead()
   2352 //// _ZN14QReadWriteLock11lockForReadEv == QReadWriteLock::lockForRead()
   2353 //QT4_FUNC(void, ZuZZN14QReadWriteLock11lockForReadEv,
   2354 //               // _ZN14QReadWriteLock11lockForReadEv
   2355 //               void* self)
   2356 //{
   2357 //   OrigFn fn;
   2358 //   VALGRIND_GET_ORIG_FN(fn);
   2359 //   if (TRACE_QT4_FNS) {
   2360 //      fprintf(stderr, "<< QReadWriteLock::lockForRead %p", self);
   2361 //      fflush(stderr);
   2362 //   }
   2363 //
   2364 //   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
   2365 //                 void*,self,
   2366 //                 long,0/*!isW*/, long,0/*!isTryLock*/);
   2367 //
   2368 //   CALL_FN_v_W(fn, self);
   2369 //
   2370 //   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
   2371 //                void*,self, long,0/*!isW*/);
   2372 //
   2373 //   if (TRACE_QT4_FNS) {
   2374 //      fprintf(stderr, " :: Q::lockForRead :: done >>\n");
   2375 //   }
   2376 //}
   2377 //
   2378 //// QReadWriteLock::lockForWrite()
   2379 //// _ZN14QReadWriteLock12lockForWriteEv == QReadWriteLock::lockForWrite()
   2380 //QT4_FUNC(void, ZuZZN14QReadWriteLock12lockForWriteEv,
   2381 //               // _ZN14QReadWriteLock12lockForWriteEv
   2382 //               void* self)
   2383 //{
   2384 //   OrigFn fn;
   2385 //   VALGRIND_GET_ORIG_FN(fn);
   2386 //   if (TRACE_QT4_FNS) {
   2387 //      fprintf(stderr, "<< QReadWriteLock::lockForWrite %p", self);
   2388 //      fflush(stderr);
   2389 //   }
   2390 //
   2391 //   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
   2392 //                 void*,self,
   2393 //                 long,1/*isW*/, long,0/*!isTryLock*/);
   2394 //
   2395 //   CALL_FN_v_W(fn, self);
   2396 //
   2397 //   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
   2398 //                void*,self, long,1/*isW*/);
   2399 //
   2400 //   if (TRACE_QT4_FNS) {
   2401 //      fprintf(stderr, " :: Q::lockForWrite :: done >>\n");
   2402 //   }
   2403 //}
   2404 //
   2405 //// QReadWriteLock::unlock()
   2406 //// _ZN14QReadWriteLock6unlockEv == QReadWriteLock::unlock()
   2407 //QT4_FUNC(void, ZuZZN14QReadWriteLock6unlockEv,
   2408 //               // _ZN14QReadWriteLock6unlockEv
   2409 //               void* self)
   2410 //{
   2411 //   OrigFn fn;
   2412 //   VALGRIND_GET_ORIG_FN(fn);
   2413 //   if (TRACE_QT4_FNS) {
   2414 //      fprintf(stderr, "<< QReadWriteLock::unlock %p", self);
   2415 //      fflush(stderr);
   2416 //   }
   2417 //
   2418 //   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
   2419 //               void*,self);
   2420 //
   2421 //   CALL_FN_v_W(fn, self);
   2422 //
   2423 //   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
   2424 //               void*,self);
   2425 //
   2426 //   if (TRACE_QT4_FNS) {
   2427 //      fprintf(stderr, " :: Q::unlock :: done >>\n");
   2428 //   }
   2429 //}
   2430 
   2431 
   2432 /*----------------------------------------------------------------*/
   2433 /*--- Replacements for basic string functions, that don't      ---*/
   2434 /*--- overrun the input arrays.                                ---*/
   2435 /*----------------------------------------------------------------*/
   2436 
   2437 #include "../shared/vg_replace_strmem.c"
   2438 
   2439 /*--------------------------------------------------------------------*/
   2440 /*--- end                                          hg_intercepts.c ---*/
   2441 /*--------------------------------------------------------------------*/
   2442