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