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