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