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