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