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