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-2017 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
62#if defined(VGO_solaris)
63/* See porting comments in drd/drd_pthread_intercepts.c
64   However when a POSIX threads API function (for example pthread_cond_init)
65   is built upon the Solaris one (cond_init), intercept only the bottom one.
66   Helgrind does not contain generic synchronization nesting like DRD
67   and double intercept confuses it. */
68#include <synch.h>
69#include <thread.h>
70#endif /* VGO_solaris */
71
72
73#define TRACE_PTH_FNS 0
74#define TRACE_QT4_FNS 0
75#define TRACE_GNAT_FNS 0
76
77
78/*----------------------------------------------------------------*/
79/*---                                                          ---*/
80/*----------------------------------------------------------------*/
81
82#if defined(VGO_solaris)
83/* On Solaris, libpthread is just a filter library on top of libc.
84 * Threading and synchronization functions in runtime linker are not
85 * intercepted.
86 */
87#define PTH_FUNC(ret_ty, f, args...) \
88   ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)(args); \
89   ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)(args)
90
91/* pthread_t is typedef'd to 'unsigned int' but in DO_CREQ_* macros
92   sizeof(Word) is expected. */
93#define CREQ_PTHREAD_T Word
94#define SEM_ERROR ret
95#else
96#define PTH_FUNC(ret_ty, f, args...) \
97   ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args); \
98   ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args)
99#define CREQ_PTHREAD_T pthread_t
100#define SEM_ERROR errno
101#endif /* VGO_solaris */
102
103// Do a client request.  These are macros rather than a functions so
104// as to avoid having an extra frame in stack traces.
105
106// NB: these duplicate definitions in helgrind.h.  But here, we
107// can have better typing (Word etc) and assertions, whereas
108// in helgrind.h we can't.  Obviously it's important the two
109// sets of definitions are kept in sync.
110
111// nuke the previous definitions
112#undef DO_CREQ_v_W
113#undef DO_CREQ_v_WW
114#undef DO_CREQ_W_WW
115#undef DO_CREQ_v_WWW
116
117#define DO_CREQ_v_W(_creqF, _ty1F,_arg1F)                \
118   do {                                                  \
119      Word _arg1;                                        \
120      assert(sizeof(_ty1F) == sizeof(Word));             \
121      _arg1 = (Word)(_arg1F);                            \
122      VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF),          \
123                                 _arg1, 0,0,0,0);        \
124   } while (0)
125
126#define DO_CREQ_v_WW(_creqF, _ty1F,_arg1F, _ty2F,_arg2F) \
127   do {                                                  \
128      Word _arg1, _arg2;                                 \
129      assert(sizeof(_ty1F) == sizeof(Word));             \
130      assert(sizeof(_ty2F) == sizeof(Word));             \
131      _arg1 = (Word)(_arg1F);                            \
132      _arg2 = (Word)(_arg2F);                            \
133      VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF),          \
134                                 _arg1,_arg2,0,0,0);     \
135   } while (0)
136
137#define DO_CREQ_W_WW(_resF, _creqF, _ty1F,_arg1F,        \
138                     _ty2F,_arg2F)                       \
139   do {                                                  \
140      Word _res, _arg1, _arg2;                           \
141      assert(sizeof(_ty1F) == sizeof(Word));             \
142      assert(sizeof(_ty2F) == sizeof(Word));             \
143      _arg1 = (Word)(_arg1F);                            \
144      _arg2 = (Word)(_arg2F);                            \
145      _res = VALGRIND_DO_CLIENT_REQUEST_EXPR(2,          \
146                                 (_creqF),               \
147                                 _arg1,_arg2,0,0,0);     \
148      _resF = _res;                                      \
149   } while (0)
150
151#define DO_CREQ_v_WWW(_creqF, _ty1F,_arg1F,              \
152                      _ty2F,_arg2F, _ty3F, _arg3F)       \
153   do {                                                  \
154      Word _arg1, _arg2, _arg3;                          \
155      assert(sizeof(_ty1F) == sizeof(Word));             \
156      assert(sizeof(_ty2F) == sizeof(Word));             \
157      assert(sizeof(_ty3F) == sizeof(Word));             \
158      _arg1 = (Word)(_arg1F);                            \
159      _arg2 = (Word)(_arg2F);                            \
160      _arg3 = (Word)(_arg3F);                            \
161      VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF),          \
162                                 _arg1,_arg2,_arg3,0,0); \
163   } while (0)
164
165#define DO_CREQ_v_WWWW(_creqF, _ty1F,_arg1F,             \
166                       _ty2F, _arg2F, _ty3F, _arg3F,     \
167                       _ty4F, _arg4F)                    \
168   do {                                                  \
169      Word _arg1, _arg2, _arg3, _arg4;                   \
170      assert(sizeof(_ty1F) == sizeof(Word));             \
171      assert(sizeof(_ty2F) == sizeof(Word));             \
172      assert(sizeof(_ty3F) == sizeof(Word));             \
173      assert(sizeof(_ty4F) == sizeof(Word));             \
174      _arg1 = (Word)(_arg1F);                            \
175      _arg2 = (Word)(_arg2F);                            \
176      _arg3 = (Word)(_arg3F);                            \
177      _arg4 = (Word)(_arg4F);                            \
178      VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF),          \
179                             _arg1,_arg2,_arg3,_arg4,0); \
180   } while (0)
181
182#define DO_PthAPIerror(_fnnameF, _errF)                  \
183   do {                                                  \
184      const char* _fnname = (_fnnameF);                  \
185      long  _err    = (long)(int)(_errF);                \
186      const char* _errstr = lame_strerror(_err);         \
187      DO_CREQ_v_WWW(_VG_USERREQ__HG_PTH_API_ERROR,       \
188                    char*,_fnname,                       \
189                    long,_err, char*,_errstr);           \
190   } while (0)
191
192
193/* Needed for older glibcs (2.3 and older, at least) who don't
194   otherwise "know" about pthread_rwlock_anything or about
195   PTHREAD_MUTEX_RECURSIVE (amongst things). */
196#define _GNU_SOURCE 1
197
198#include <stdio.h>
199#include <assert.h>
200#include <errno.h>
201#include <pthread.h>
202
203/* A standalone memcmp. */
204__attribute__((noinline))
205static int my_memcmp ( const void* ptr1, const void* ptr2, size_t size)
206{
207   const unsigned char* uchar_ptr1 = (const unsigned char*) ptr1;
208   const unsigned char* uchar_ptr2 = (const unsigned char*) ptr2;
209   size_t i;
210   for (i = 0; i < size; ++i) {
211      if (uchar_ptr1[i] != uchar_ptr2[i])
212         return (uchar_ptr1[i] < uchar_ptr2[i]) ? -1 : 1;
213   }
214   return 0;
215}
216
217/* A lame version of strerror which doesn't use the real libc
218   strerror_r, since using the latter just generates endless more
219   threading errors (glibc goes off and does tons of crap w.r.t.
220   locales etc) */
221static const HChar* lame_strerror ( long err )
222{
223   switch (err) {
224      case EPERM:       return "EPERM: Operation not permitted";
225      case ENOENT:      return "ENOENT: No such file or directory";
226      case ESRCH:       return "ESRCH: No such process";
227      case EINTR:       return "EINTR: Interrupted system call";
228      case EBADF:       return "EBADF: Bad file number";
229      case EAGAIN:      return "EAGAIN: Try again";
230      case ENOMEM:      return "ENOMEM: Out of memory";
231      case EACCES:      return "EACCES: Permission denied";
232      case EFAULT:      return "EFAULT: Bad address";
233      case EEXIST:      return "EEXIST: File exists";
234      case EINVAL:      return "EINVAL: Invalid argument";
235      case EMFILE:      return "EMFILE: Too many open files";
236      case ENOSYS:      return "ENOSYS: Function not implemented";
237      case EOVERFLOW:   return "EOVERFLOW: Value too large "
238                               "for defined data type";
239      case EBUSY:       return "EBUSY: Device or resource busy";
240      case ETIMEDOUT:   return "ETIMEDOUT: Connection timed out";
241      case EDEADLK:     return "EDEADLK: Resource deadlock would occur";
242      case EOPNOTSUPP:  return "EOPNOTSUPP: Operation not supported on "
243                               "transport endpoint"; /* honest, guv */
244      case ETIME:       return "ETIME: Timer expired";
245      default:          return "hg_intercepts.c: lame_strerror(): "
246                               "unhandled case -- please fix me!";
247   }
248}
249
250#if defined(VGO_solaris)
251/*
252 * Solaris provides higher throughput, parallelism and scalability than other
253 * operating systems, at the cost of more fine-grained locking activity.
254 * This means for example that when a thread is created under Linux, just one
255 * big lock in glibc is used for all thread setup. Solaris libc uses several
256 * fine-grained locks and the creator thread resumes its activities as soon
257 * as possible, leaving for example stack and TLS setup activities to the
258 * created thread.
259 *
260 * This situation confuses Helgrind as it assumes there is some false ordering
261 * in place between creator and created thread; and therefore many types of
262 * race conditions in the application would not be reported. To prevent such
263 * false ordering, command line option --ignore-thread-creation is set to
264 * 'yes' by default on Solaris. All activity (loads, stores, client requests)
265 * is therefore ignored during:
266 * - pthread_create() call in the creator thread [libc.so]
267 * - thread creation phase (stack and TLS setup) in the created thread [libc.so]
268 *
269 * As explained in the comments for _ti_bind_guard(), whenever the runtime
270 * linker has to perform any activity (such as resolving a symbol), it protects
271 * its data structures by calling into rt_bind_guard() which in turn invokes
272 * _ti_bind_guard() in libc. Pointers to _ti_bind_guard() and _ti_bind_clear()
273 * are passed from libc to runtime linker in _ld_libc() call during libc_init().
274 * All activity is also ignored during:
275 * - runtime dynamic linker work between rt_bind_guard() and rt_bind_clear()
276 *   calls [ld.so]
277 *
278 * This also means that Helgrind does not report race conditions in libc (when
279 * --ignore-thread-creation=yes) and runtime linker itself (unconditionally)
280 * during these ignored sequences.
281 */
282
283#include "pub_tool_libcassert.h"
284#include "pub_tool_vki.h"
285
286/*
287 * Original function pointers for _ti_bind_guard() and _ti_bind_clear()
288 * from libc. They are intercepted in function wrapper of _ld_libc().
289 */
290typedef int (*hg_rtld_guard_fn)(int flags);
291static hg_rtld_guard_fn hg_rtld_bind_guard = NULL;
292static hg_rtld_guard_fn hg_rtld_bind_clear = NULL;
293
294static void hg_init(void) __attribute__((constructor));
295static void hg_init(void)
296{
297   if ((hg_rtld_bind_guard == NULL) || (hg_rtld_bind_clear == NULL)) {
298      fprintf(stderr,
299"Bind guard functions for the runtime linker (ld.so.1) were not intercepted.\n"
300"This means the interface between libc and runtime linker changed\n"
301"and Helgrind needs to be ported properly. Giving up.\n");
302      tl_assert(0);
303   }
304}
305
306/*
307 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
308 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
309 * and CI_BIND_CLEAR, to provide resilience against function renaming.
310 */
311static int _ti_bind_guard_intercept_WRK(int flags)
312{
313   VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_RTLD_BIND_GUARD,
314                                   flags, 0, 0, 0, 0);
315   return hg_rtld_bind_guard(flags);
316}
317
318static int _ti_bind_clear_intercept_WRK(int flags)
319{
320   int ret = hg_rtld_bind_clear(flags);
321   VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_RTLD_BIND_CLEAR,
322                                   flags, 0, 0, 0, 0);
323   return ret;
324}
325
326/*
327 * Wrapped _ld_libc() from the runtime linker ld.so.1.
328 */
329void I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr);
330void I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr)
331{
332   OrigFn fn;
333   int    tag;
334
335   VALGRIND_GET_ORIG_FN(fn);
336
337   vki_Lc_interface *funcs = ptr;
338   for (tag = funcs->ci_tag; tag != 0; tag = (++funcs)->ci_tag) {
339      switch (tag) {
340      case VKI_CI_BIND_GUARD:
341         if (funcs->vki_ci_un.ci_func != _ti_bind_guard_intercept_WRK) {
342            hg_rtld_bind_guard = funcs->vki_ci_un.ci_func;
343            funcs->vki_ci_un.ci_func = _ti_bind_guard_intercept_WRK;
344         }
345         break;
346      case VKI_CI_BIND_CLEAR:
347         if (funcs->vki_ci_un.ci_func != _ti_bind_clear_intercept_WRK) {
348            hg_rtld_bind_clear = funcs->vki_ci_un.ci_func;
349            funcs->vki_ci_un.ci_func = _ti_bind_clear_intercept_WRK;
350         }
351         break;
352      }
353   }
354
355   CALL_FN_v_W(fn, ptr);
356}
357#endif /* VGO_solaris */
358
359
360/*----------------------------------------------------------------*/
361/*--- pthread_create, pthread_join, pthread_exit               ---*/
362/*----------------------------------------------------------------*/
363
364static void* mythread_wrapper ( void* xargsV )
365{
366   volatile Word* xargs = (volatile Word*) xargsV;
367   void*(*fn)(void*) = (void*(*)(void*))xargs[0];
368   void* arg         = (void*)xargs[1];
369   pthread_t me = pthread_self();
370   /* Tell the tool what my pthread_t is. */
371   DO_CREQ_v_W(_VG_USERREQ__HG_SET_MY_PTHREAD_T, CREQ_PTHREAD_T, me);
372   /* allow the parent to proceed.  We can't let it proceed until
373      we're ready because (1) we need to make sure it doesn't exit and
374      hence deallocate xargs[] while we still need it, and (2) we
375      don't want either parent nor child to proceed until the tool has
376      been notified of the child's pthread_t.
377
378      Note that parent and child access args[] without a lock,
379      effectively using args[2] as a spinlock in order to get the
380      parent to wait until the child passes this point.  The parent
381      disables checking on xargs[] before creating the child and
382      re-enables it once the child goes past this point, so the user
383      never sees the race.  The previous approach (suppressing the
384      resulting error) was flawed, because it could leave shadow
385      memory for args[] in a state in which subsequent use of it by
386      the parent would report further races. */
387   xargs[2] = 0;
388   /* Now we can no longer safely use xargs[]. */
389   return (void*) fn( (void*)arg );
390}
391
392//-----------------------------------------------------------
393// glibc:  pthread_create@GLIBC_2.0
394// glibc:  pthread_create@@GLIBC_2.1
395// glibc:  pthread_create@@GLIBC_2.2.5
396// darwin: pthread_create
397// darwin: pthread_create_suspended_np (trapped)
398//
399/* ensure this has its own frame, so as to make it more distinguishable
400   in suppressions */
401__attribute__((noinline))
402static int pthread_create_WRK(pthread_t *thread, const pthread_attr_t *attr,
403                              void *(*start) (void *), void *arg)
404{
405   int    ret;
406   OrigFn fn;
407   volatile Word xargs[3];
408
409   VALGRIND_GET_ORIG_FN(fn);
410   if (TRACE_PTH_FNS) {
411      fprintf(stderr, "<< pthread_create wrapper"); fflush(stderr);
412   }
413   xargs[0] = (Word)start;
414   xargs[1] = (Word)arg;
415   xargs[2] = 1; /* serves as a spinlock -- sigh */
416   /* Disable checking on the spinlock and the two words used to
417      convey args to the child.  Basically we need to make it appear
418      as if the child never accessed this area, since merely
419      suppressing the resulting races does not address the issue that
420      that piece of the parent's stack winds up in the "wrong" state
421      and therefore may give rise to mysterious races when the parent
422      comes to re-use this piece of stack in some other frame. */
423   VALGRIND_HG_DISABLE_CHECKING(&xargs, sizeof(xargs));
424
425   VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_BEGIN,
426                                   0, 0, 0, 0, 0);
427   CALL_FN_W_WWWW(ret, fn, thread,attr,mythread_wrapper,&xargs[0]);
428   VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_END,
429                                   0, 0, 0, 0, 0);
430
431   if (ret == 0) {
432      /* we have to wait for the child to notify the tool of its
433         pthread_t before continuing */
434      while (xargs[2] != 0) {
435         /* Do nothing.  We need to spin until the child writes to
436            xargs[2].  However, that can lead to starvation in the
437            child and very long delays (eg, tc19_shadowmem on
438            ppc64-linux Fedora Core 6).  So yield the cpu if we can,
439            to let the child run at the earliest available
440            opportunity. */
441         sched_yield();
442      }
443   } else {
444      DO_PthAPIerror( "pthread_create", ret );
445   }
446
447   /* Reenable checking on the area previously used to communicate
448      with the child. */
449   VALGRIND_HG_ENABLE_CHECKING(&xargs, sizeof(xargs));
450
451   if (TRACE_PTH_FNS) {
452      fprintf(stderr, " :: pth_create -> %d >>\n", ret);
453   }
454   return ret;
455}
456#if defined(VGO_linux)
457   PTH_FUNC(int, pthreadZucreateZAZa, // pthread_create@*
458                 pthread_t *thread, const pthread_attr_t *attr,
459                 void *(*start) (void *), void *arg) {
460      return pthread_create_WRK(thread, attr, start, arg);
461   }
462#elif defined(VGO_darwin)
463   PTH_FUNC(int, pthreadZucreate, // pthread_create
464                 pthread_t *thread, const pthread_attr_t *attr,
465                 void *(*start) (void *), void *arg) {
466      return pthread_create_WRK(thread, attr, start, arg);
467   }
468   PTH_FUNC(int, pthreadZucreateZuZa, // pthread_create_*
469                 pthread_t *thread, const pthread_attr_t *attr,
470                 void *(*start) (void *), void *arg) {
471      // trap anything else
472      assert(0);
473   }
474#elif defined(VGO_solaris)
475   PTH_FUNC(int, pthreadZucreate, // pthread_create
476                 pthread_t *thread, const pthread_attr_t *attr,
477                 void *(*start) (void *), void *arg) {
478      return pthread_create_WRK(thread, attr, start, arg);
479   }
480#else
481#  error "Unsupported OS"
482#endif
483
484#if defined(VGO_solaris)
485/* Solaris also provides thr_create() in addition to pthread_create().
486 * Both pthread_create(3C) and thr_create(3C) are based on private
487 * _thrp_create().
488 */
489__attribute__((noinline))
490static int thr_create_WRK(void *stk, size_t stksize, void *(*start)(void *),
491                          void *arg, long flags, thread_t *new_thread)
492{
493   int    ret;
494   OrigFn fn;
495   volatile Word xargs[3];
496
497   VALGRIND_GET_ORIG_FN(fn);
498   if (TRACE_PTH_FNS) {
499      fprintf(stderr, "<< thr_create wrapper"); fflush(stderr);
500   }
501   xargs[0] = (Word)start;
502   xargs[1] = (Word)arg;
503   xargs[2] = 1; /* serves as a spinlock -- sigh */
504   /* See comments in pthread_create_WRK() */
505   VALGRIND_HG_DISABLE_CHECKING(&xargs, sizeof(xargs));
506
507   VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_BEGIN,
508                                   0, 0, 0, 0, 0);
509   CALL_FN_W_6W(ret, fn, stk, stksize, mythread_wrapper, start, flags,
510                new_thread);
511   VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_END,
512                                   0, 0, 0, 0, 0);
513
514   if (ret == 0) {
515      while (xargs[2] != 0) {
516         /* See comments in pthread_create_WRK(). */
517         sched_yield();
518      }
519   } else {
520      DO_PthAPIerror("thr_create", ret);
521   }
522
523   VALGRIND_HG_ENABLE_CHECKING(&xargs, sizeof(xargs));
524
525   if (TRACE_PTH_FNS) {
526      fprintf(stderr, " :: thr_create -> %d >>\n", ret);
527   }
528   return ret;
529}
530   PTH_FUNC(int, thrZucreate, // thr_create
531                 void *stk, size_t stksize, void *(*start)(void *),
532                 void *arg, long flags, thread_t *new_thread) {
533      return thr_create_WRK(stk, stksize, start, arg, flags, new_thread);
534   }
535#endif /* VGO_solaris */
536
537
538//-----------------------------------------------------------
539// glibc:  pthread_join
540// darwin: pthread_join
541// darwin: pthread_join$NOCANCEL$UNIX2003
542// darwin  pthread_join$UNIX2003
543__attribute__((noinline))
544static int pthread_join_WRK(pthread_t thread, void** value_pointer)
545{
546   int ret;
547   OrigFn fn;
548   VALGRIND_GET_ORIG_FN(fn);
549   if (TRACE_PTH_FNS) {
550      fprintf(stderr, "<< pthread_join wrapper"); fflush(stderr);
551   }
552
553   CALL_FN_W_WW(ret, fn, thread,value_pointer);
554
555   /* At least with NPTL as the thread library, this is safe because
556      it is guaranteed (by NPTL) that the joiner will completely gone
557      before pthread_join (the original) returns.  See email below.*/
558   if (ret == 0 /*success*/) {
559      DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST, CREQ_PTHREAD_T, thread);
560   } else {
561      DO_PthAPIerror( "pthread_join", ret );
562   }
563
564   if (TRACE_PTH_FNS) {
565      fprintf(stderr, " :: pth_join -> %d >>\n", ret);
566   }
567   return ret;
568}
569#if defined(VGO_linux)
570   PTH_FUNC(int, pthreadZujoin, // pthread_join
571            pthread_t thread, void** value_pointer) {
572      return pthread_join_WRK(thread, value_pointer);
573   }
574#elif defined(VGO_darwin)
575   PTH_FUNC(int, pthreadZujoinZa, // pthread_join*
576            pthread_t thread, void** value_pointer) {
577      return pthread_join_WRK(thread, value_pointer);
578   }
579#elif defined(VGO_solaris)
580   PTH_FUNC(int, pthreadZujoin, // pthread_join
581            pthread_t thread, void** value_pointer) {
582      return pthread_join_WRK(thread, value_pointer);
583   }
584#else
585#  error "Unsupported OS"
586#endif
587
588
589/* Behaviour of pthread_join on NPTL:
590
591Me:
592I have a question re the NPTL pthread_join implementation.
593
594  Suppose I am the thread 'stayer'.
595
596  If I call pthread_join(quitter), is it guaranteed that the
597  thread 'quitter' has really exited before pthread_join returns?
598
599  IOW, is it guaranteed that 'quitter' will not execute any further
600  instructions after pthread_join returns?
601
602I believe this is true based on the following analysis of
603glibc-2.5 sources.  However am not 100% sure and would appreciate
604confirmation.
605
606  'quitter' will be running start_thread() in nptl/pthread_create.c
607
608  The last action of start_thread() is to exit via
609  __exit_thread_inline(0), which simply does sys_exit
610  (nptl/pthread_create.c:403)
611
612  'stayer' meanwhile is waiting for lll_wait_tid (pd->tid)
613  (call at nptl/pthread_join.c:89)
614
615  As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
616  lll_wait_tid will not return until kernel notifies via futex
617  wakeup that 'quitter' has terminated.
618
619  Hence pthread_join cannot return until 'quitter' really has
620  completely disappeared.
621
622Drepper:
623>   As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
624>   lll_wait_tid will not return until kernel notifies via futex
625>   wakeup that 'quitter' has terminated.
626That's the key.  The kernel resets the TID field after the thread is
627done.  No way the joiner can return before the thread is gone.
628*/
629
630#if defined(VGO_solaris)
631/* Solaris also provides thr_join() in addition to pthread_join().
632 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
633 *
634 * :TODO: No functionality is currently provided for joinee == 0 and departed.
635 *        This would require another client request, of course.
636 */
637__attribute__((noinline))
638static int thr_join_WRK(thread_t joinee, thread_t *departed, void **thread_return)
639{
640   int ret;
641   OrigFn fn;
642   VALGRIND_GET_ORIG_FN(fn);
643   if (TRACE_PTH_FNS) {
644      fprintf(stderr, "<< thr_join wrapper"); fflush(stderr);
645   }
646
647   CALL_FN_W_WWW(ret, fn, joinee, departed, thread_return);
648
649   if (ret == 0 /*success*/) {
650      DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST, CREQ_PTHREAD_T, joinee);
651   } else {
652      DO_PthAPIerror("thr_join", ret);
653   }
654
655   if (TRACE_PTH_FNS) {
656      fprintf(stderr, " :: thr_join -> %d >>\n", ret);
657   }
658   return ret;
659}
660   PTH_FUNC(int, thrZujoin, // thr_join
661            thread_t joinee, thread_t *departed, void **thread_return) {
662      return thr_join_WRK(joinee, departed, thread_return);
663   }
664#endif /* VGO_solaris */
665
666
667//-----------------------------------------------------------
668// Ada gcc gnat runtime:
669// The gnat gcc Ada runtime does not use pthread_join. Instead, it uses
670// a combination of other pthread primitives to ensure a child thread
671// is gone. This combination is somewhat functionally equivalent to a
672// pthread_join.
673// We wrap two hook procedures called by the gnat gcc Ada runtime
674// that allows helgrind to understand the semantic of Ada task dependencies
675// and termination.
676//   procedure Master_Hook
677//     (Dependent    : Task_Id;
678//      Parent       : Task_Id;
679//      Master_Level : Integer);
680// where    type Task_Id is access all Ada_Task_Control_Block;
681// System.Tasking.Debug.Master_Hook is called by a task Dependent to
682// indicate that its master is identified by master+master_level.
683void I_WRAP_SONAME_FNNAME_ZU
684   (Za,
685    system__tasking__debug__master_hook)
686     (void *dependent, void *master, int master_level);
687void I_WRAP_SONAME_FNNAME_ZU
688   (Za,
689    system__tasking__debug__master_hook)
690     (void *dependent, void *master, int master_level)
691{
692   OrigFn fn;
693   VALGRIND_GET_ORIG_FN(fn);
694   if (TRACE_GNAT_FNS) {
695     fprintf(stderr, "<< GNAT master_hook wrapper "
696             "dependent %p master %p master_level %d\n",
697             dependent, master, master_level); fflush(stderr);
698   }
699
700   // We call the wrapped function, even if it is a null body.
701   CALL_FN_v_WWW(fn, dependent, master, master_level);
702
703   DO_CREQ_v_WWW(_VG_USERREQ__HG_GNAT_MASTER_HOOK,
704                 void*,dependent, void*,master,
705                 Word, (Word)master_level);
706
707   if (TRACE_GNAT_FNS) {
708      fprintf(stderr, " :: GNAT master_hook >>\n");
709   }
710}
711
712// System.Tasking.Debug.Master_Completed_Hook is called by a task to
713// indicate that it has completed a master.
714//  procedure Master_Completed_Hook
715//     (Self_ID      : Task_Id;
716//      Master_Level : Integer);
717// where    type Task_Id is access all Ada_Task_Control_Block;
718// This indicates that all its Dependent tasks (that identified themselves
719// with the Master_Hook call) are terminated. Helgrind can consider
720// at this point that the equivalent of a 'pthread_join' has been done
721// between self_id and all dependent tasks at master_level.
722void I_WRAP_SONAME_FNNAME_ZU
723   (Za,
724    system__tasking__debug__master_completed_hook)
725     (void *self_id, int master_level);
726void I_WRAP_SONAME_FNNAME_ZU
727   (Za,
728    system__tasking__debug__master_completed_hook)
729     (void *self_id, int master_level)
730{
731   OrigFn fn;
732   VALGRIND_GET_ORIG_FN(fn);
733   if (TRACE_GNAT_FNS) {
734     fprintf(stderr, "<< GNAT master_completed_hook wrapper "
735             "self_id %p master_level %d\n",
736             self_id, master_level); fflush(stderr);
737   }
738
739   // We call the wrapped function, even if it is a null body.
740   CALL_FN_v_WW(fn, self_id, master_level);
741
742   DO_CREQ_v_WW(_VG_USERREQ__HG_GNAT_MASTER_COMPLETED_HOOK,
743                 void*,self_id, Word,(Word)master_level);
744
745   if (TRACE_GNAT_FNS) {
746      fprintf(stderr, " :: GNAT master_completed_hook >>\n");
747   }
748}
749
750/*----------------------------------------------------------------*/
751/*--- pthread_mutex_t functions                                ---*/
752/*----------------------------------------------------------------*/
753
754/* Handled:   pthread_mutex_init pthread_mutex_destroy
755              pthread_mutex_lock
756              pthread_mutex_trylock pthread_mutex_timedlock
757              pthread_mutex_unlock
758*/
759
760//-----------------------------------------------------------
761#if !defined(VGO_solaris)
762// glibc:  pthread_mutex_init
763// darwin: pthread_mutex_init
764PTH_FUNC(int, pthreadZumutexZuinit, // pthread_mutex_init
765              pthread_mutex_t *mutex,
766              pthread_mutexattr_t* attr)
767{
768   int    ret;
769   long   mbRec;
770   OrigFn fn;
771   VALGRIND_GET_ORIG_FN(fn);
772   if (TRACE_PTH_FNS) {
773      fprintf(stderr, "<< pthread_mxinit %p", mutex); fflush(stderr);
774   }
775
776   mbRec = 0;
777   if (attr) {
778      int ty, zzz;
779      zzz = pthread_mutexattr_gettype(attr, &ty);
780      if (zzz == 0 && ty == PTHREAD_MUTEX_RECURSIVE)
781         mbRec = 1;
782   }
783
784   CALL_FN_W_WW(ret, fn, mutex,attr);
785
786   if (ret == 0 /*success*/) {
787      DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
788                   pthread_mutex_t*,mutex, long,mbRec);
789   } else {
790      DO_PthAPIerror( "pthread_mutex_init", ret );
791   }
792
793   if (TRACE_PTH_FNS) {
794      fprintf(stderr, " :: mxinit -> %d >>\n", ret);
795   }
796   return ret;
797}
798
799#else /* VGO_solaris */
800
801// Solaris: mutex_init (pthread_mutex_init calls here)
802PTH_FUNC(int, mutexZuinit, // mutex_init
803              mutex_t *mutex, int type, void *arg)
804{
805   int    ret;
806   long   mbRec;
807   OrigFn fn;
808   VALGRIND_GET_ORIG_FN(fn);
809   if (TRACE_PTH_FNS) {
810      fprintf(stderr, "<< mxinit %p", mutex); fflush(stderr);
811   }
812
813   mbRec = ((type & LOCK_RECURSIVE) != 0) ? 1 : 0;
814
815   CALL_FN_W_WWW(ret, fn, mutex, type, arg);
816
817   if (ret == 0 /*success*/) {
818      DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
819                   mutex_t *, mutex, long, mbRec);
820   } else {
821      DO_PthAPIerror("mutex_init", ret);
822   }
823
824   if (TRACE_PTH_FNS) {
825      fprintf(stderr, " :: mxinit -> %d >>\n", ret);
826   }
827   return ret;
828}
829#endif /* VGO_solaris */
830
831
832//-----------------------------------------------------------
833// glibc:   pthread_mutex_destroy
834// darwin:  pthread_mutex_destroy
835// Solaris: mutex_destroy (pthread_mutex_destroy is a weak alias)
836__attribute__((noinline))
837static int mutex_destroy_WRK(pthread_mutex_t *mutex)
838{
839   int    ret;
840   unsigned long mutex_is_init;
841   OrigFn fn;
842
843   VALGRIND_GET_ORIG_FN(fn);
844   if (TRACE_PTH_FNS) {
845      fprintf(stderr, "<< pthread_mxdestroy %p", mutex); fflush(stderr);
846   }
847
848   if (mutex != NULL) {
849      static const pthread_mutex_t mutex_init = PTHREAD_MUTEX_INITIALIZER;
850      mutex_is_init = my_memcmp(mutex, &mutex_init, sizeof(*mutex)) == 0;
851   } else {
852      mutex_is_init = 0;
853   }
854
855   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
856                pthread_mutex_t*, mutex, unsigned long, mutex_is_init);
857
858   CALL_FN_W_W(ret, fn, mutex);
859
860   if (ret != 0) {
861      DO_PthAPIerror( "pthread_mutex_destroy", ret );
862   }
863
864   if (TRACE_PTH_FNS) {
865      fprintf(stderr, " :: mxdestroy -> %d >>\n", ret);
866   }
867   return ret;
868}
869
870#if defined(VGO_linux) || defined(VGO_darwin)
871   PTH_FUNC(int, pthreadZumutexZudestroy, // pthread_mutex_destroy
872            pthread_mutex_t *mutex) {
873      return mutex_destroy_WRK(mutex);
874   }
875#elif defined(VGO_solaris)
876   PTH_FUNC(int, mutexZudestroy, // mutex_destroy
877            pthread_mutex_t *mutex) {
878      return mutex_destroy_WRK(mutex);
879   }
880#else
881#  error "Unsupported OS"
882#endif
883
884
885//-----------------------------------------------------------
886// glibc:   pthread_mutex_lock
887// darwin:  pthread_mutex_lock
888// Solaris: mutex_lock (pthread_mutex_lock is a weak alias)
889__attribute__((noinline))
890static int mutex_lock_WRK(pthread_mutex_t *mutex)
891{
892   int    ret;
893   OrigFn fn;
894   VALGRIND_GET_ORIG_FN(fn);
895   if (TRACE_PTH_FNS) {
896      fprintf(stderr, "<< pthread_mxlock %p", mutex); fflush(stderr);
897   }
898
899   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
900                pthread_mutex_t*,mutex, long,0/*!isTryLock*/);
901
902   CALL_FN_W_W(ret, fn, mutex);
903
904   /* There's a hole here: libpthread now knows the lock is locked,
905      but the tool doesn't, so some other thread could run and detect
906      that the lock has been acquired by someone (this thread).  Does
907      this matter?  Not sure, but I don't think so. */
908
909   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
910                pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
911
912   if (ret != 0) {
913      DO_PthAPIerror( "pthread_mutex_lock", ret );
914   }
915
916   if (TRACE_PTH_FNS) {
917      fprintf(stderr, " :: mxlock -> %d >>\n", ret);
918   }
919   return ret;
920}
921
922#if defined(VGO_linux) || defined(VGO_darwin)
923   PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock
924            pthread_mutex_t *mutex) {
925      return mutex_lock_WRK(mutex);
926   }
927#elif defined(VGO_solaris)
928   PTH_FUNC(int, mutexZulock, // mutex_lock
929            pthread_mutex_t *mutex) {
930      return mutex_lock_WRK(mutex);
931   }
932#else
933#  error "Unsupported OS"
934#endif
935
936#if defined(VGO_solaris)
937/* Internal to libc. Mutex is usually initialized only implicitly,
938 * by zeroing mutex_t structure.
939 */
940__attribute__((noinline))
941PTH_FUNC(void, lmutexZulock, // lmutex_lock
942               mutex_t *mutex)
943{
944   OrigFn fn;
945   VALGRIND_GET_ORIG_FN(fn);
946   if (TRACE_PTH_FNS) {
947      fprintf(stderr, "<< lmxlock %p", mutex); fflush(stderr);
948   }
949
950   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
951                mutex_t *, mutex, long, 0 /*!isTryLock*/);
952   CALL_FN_v_W(fn, mutex);
953   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
954                mutex_t *, mutex, long, True);
955
956   if (TRACE_PTH_FNS) {
957      fprintf(stderr, " :: lmxlock >>\n");
958   }
959}
960#endif /* VGO_solaris */
961
962
963//-----------------------------------------------------------
964// glibc:   pthread_mutex_trylock
965// darwin:  pthread_mutex_trylock
966// Solaris: mutex_trylock (pthread_mutex_trylock is a weak alias)
967//
968// pthread_mutex_trylock.  The handling needed here is very similar
969// to that for pthread_mutex_lock, except that we need to tell
970// the pre-lock creq that this is a trylock-style operation, and
971// therefore not to complain if the lock is nonrecursive and
972// already locked by this thread -- because then it'll just fail
973// immediately with EBUSY.
974__attribute__((noinline))
975static int mutex_trylock_WRK(pthread_mutex_t *mutex)
976{
977   int    ret;
978   OrigFn fn;
979   VALGRIND_GET_ORIG_FN(fn);
980   if (TRACE_PTH_FNS) {
981      fprintf(stderr, "<< pthread_mxtrylock %p", mutex); fflush(stderr);
982   }
983
984   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
985                pthread_mutex_t*,mutex, long,1/*isTryLock*/);
986
987   CALL_FN_W_W(ret, fn, mutex);
988
989   /* There's a hole here: libpthread now knows the lock is locked,
990      but the tool doesn't, so some other thread could run and detect
991      that the lock has been acquired by someone (this thread).  Does
992      this matter?  Not sure, but I don't think so. */
993
994   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
995               pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
996
997   if (ret != 0) {
998      if (ret != EBUSY)
999         DO_PthAPIerror( "pthread_mutex_trylock", ret );
1000   }
1001
1002   if (TRACE_PTH_FNS) {
1003      fprintf(stderr, " :: mxtrylock -> %d >>\n", ret);
1004   }
1005   return ret;
1006}
1007
1008#if defined(VGO_linux) || defined(VGO_darwin)
1009   PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock
1010            pthread_mutex_t *mutex) {
1011      return mutex_trylock_WRK(mutex);
1012   }
1013#elif defined(VGO_solaris)
1014   PTH_FUNC(int, mutexZutrylock, // mutex_trylock
1015            pthread_mutex_t *mutex) {
1016      return mutex_trylock_WRK(mutex);
1017   }
1018#else
1019#  error "Unsupported OS"
1020#endif
1021
1022
1023//-----------------------------------------------------------
1024// glibc:   pthread_mutex_timedlock
1025// darwin:  (doesn't appear to exist)
1026// Solaris: pthread_mutex_timedlock
1027//
1028// pthread_mutex_timedlock.  Identical logic to pthread_mutex_trylock.
1029__attribute__((noinline))
1030static int mutex_timedlock_WRK(pthread_mutex_t *mutex,
1031                               void *timeout)
1032{
1033   int    ret;
1034   OrigFn fn;
1035   VALGRIND_GET_ORIG_FN(fn);
1036   if (TRACE_PTH_FNS) {
1037      fprintf(stderr, "<< pthread_mxtimedlock %p %p", mutex, timeout);
1038      fflush(stderr);
1039   }
1040
1041   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
1042                pthread_mutex_t*,mutex, long,1/*isTryLock-ish*/);
1043
1044   CALL_FN_W_WW(ret, fn, mutex,timeout);
1045
1046   /* There's a hole here: libpthread now knows the lock is locked,
1047      but the tool doesn't, so some other thread could run and detect
1048      that the lock has been acquired by someone (this thread).  Does
1049      this matter?  Not sure, but I don't think so. */
1050
1051   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1052                pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
1053
1054   if (ret != 0) {
1055      if (ret != ETIMEDOUT)
1056         DO_PthAPIerror( "pthread_mutex_timedlock", ret );
1057   }
1058
1059   if (TRACE_PTH_FNS) {
1060      fprintf(stderr, " :: mxtimedlock -> %d >>\n", ret);
1061   }
1062   return ret;
1063}
1064
1065PTH_FUNC(int, pthreadZumutexZutimedlock, // pthread_mutex_timedlock
1066         pthread_mutex_t *mutex,
1067         void *timeout) {
1068   return mutex_timedlock_WRK(mutex, timeout);
1069}
1070#if defined(VGO_solaris)
1071PTH_FUNC(int, pthreadZumutexZureltimedlock, // pthread_mutex_reltimedlock
1072         pthread_mutex_t *mutex,
1073         void *timeout) {
1074   return mutex_timedlock_WRK(mutex, timeout);
1075}
1076#endif
1077
1078
1079//-----------------------------------------------------------
1080// glibc:   pthread_mutex_unlock
1081// darwin:  pthread_mutex_unlock
1082// Solaris: mutex_unlock (pthread_mutex_unlock is a weak alias)
1083__attribute__((noinline))
1084static int mutex_unlock_WRK(pthread_mutex_t *mutex)
1085{
1086   int    ret;
1087   OrigFn fn;
1088   VALGRIND_GET_ORIG_FN(fn);
1089
1090   if (TRACE_PTH_FNS) {
1091      fprintf(stderr, "<< pthread_mxunlk %p", mutex); fflush(stderr);
1092   }
1093
1094   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1095               pthread_mutex_t*,mutex);
1096
1097   CALL_FN_W_W(ret, fn, mutex);
1098
1099   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
1100               pthread_mutex_t*,mutex);
1101
1102   if (ret != 0) {
1103      DO_PthAPIerror( "pthread_mutex_unlock", ret );
1104   }
1105
1106   if (TRACE_PTH_FNS) {
1107      fprintf(stderr, " mxunlk -> %d >>\n", ret);
1108   }
1109   return ret;
1110}
1111
1112#if defined(VGO_linux) || defined(VGO_darwin)
1113   PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock
1114            pthread_mutex_t *mutex) {
1115      return mutex_unlock_WRK(mutex);
1116   }
1117#elif defined(VGO_solaris)
1118   PTH_FUNC(int, mutexZuunlock, // mutex_unlock
1119            pthread_mutex_t *mutex) {
1120      return mutex_unlock_WRK(mutex);
1121   }
1122#else
1123#  error "Unsupported OS"
1124#endif
1125
1126
1127#if defined(VGO_solaris)
1128/* Internal to libc. */
1129__attribute__((noinline))
1130PTH_FUNC(void, lmutexZuunlock, // lmutex_unlock
1131               mutex_t *mutex)
1132{
1133   OrigFn fn;
1134   VALGRIND_GET_ORIG_FN(fn);
1135
1136   if (TRACE_PTH_FNS) {
1137      fprintf(stderr, "<< lmxunlk %p", mutex); fflush(stderr);
1138   }
1139
1140   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1141               mutex_t *, mutex);
1142   CALL_FN_v_W(fn, mutex);
1143   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
1144               mutex_t*, mutex);
1145
1146   if (TRACE_PTH_FNS) {
1147      fprintf(stderr, " lmxunlk >>\n");
1148   }
1149}
1150#endif /* VGO_solaris */
1151
1152
1153/*----------------------------------------------------------------*/
1154/*--- pthread_cond_t functions                                 ---*/
1155/*----------------------------------------------------------------*/
1156
1157/* Handled:   pthread_cond_wait pthread_cond_timedwait
1158              pthread_cond_signal pthread_cond_broadcast
1159              pthread_cond_init
1160              pthread_cond_destroy
1161*/
1162
1163//-----------------------------------------------------------
1164// glibc:   pthread_cond_wait@GLIBC_2.2.5
1165// glibc:   pthread_cond_wait@@GLIBC_2.3.2
1166// darwin:  pthread_cond_wait
1167// darwin:  pthread_cond_wait$NOCANCEL$UNIX2003
1168// darwin:  pthread_cond_wait$UNIX2003
1169// Solaris: cond_wait (pthread_cond_wait is built atop of cond_wait)
1170//
1171__attribute__((noinline))
1172static int pthread_cond_wait_WRK(pthread_cond_t* cond,
1173                                 pthread_mutex_t* mutex)
1174{
1175   int ret;
1176   OrigFn fn;
1177   unsigned long mutex_is_valid;
1178
1179   VALGRIND_GET_ORIG_FN(fn);
1180
1181   if (TRACE_PTH_FNS) {
1182      fprintf(stderr, "<< pthread_cond_wait %p %p", cond, mutex);
1183      fflush(stderr);
1184   }
1185
1186   /* Tell the tool a cond-wait is about to happen, so it can check
1187      for bogus argument values.  In return it tells us whether it
1188      thinks the mutex is valid or not. */
1189   DO_CREQ_W_WW(mutex_is_valid,
1190                _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
1191                pthread_cond_t*,cond, pthread_mutex_t*,mutex);
1192   assert(mutex_is_valid == 1 || mutex_is_valid == 0);
1193
1194   /* Tell the tool we're about to drop the mutex.  This reflects the
1195      fact that in a cond_wait, we show up holding the mutex, and the
1196      call atomically drops the mutex and waits for the cv to be
1197      signalled. */
1198   if (mutex_is_valid) {
1199      DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1200                  pthread_mutex_t*,mutex);
1201   }
1202
1203   CALL_FN_W_WW(ret, fn, cond,mutex);
1204
1205   /* this conditional look stupid, but compare w/ same logic for
1206      pthread_cond_timedwait below */
1207   if (mutex_is_valid) {
1208      /* and now we have the mutex again if (ret == 0) */
1209      DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1210                   pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
1211   }
1212
1213   DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
1214                  pthread_cond_t*,cond, pthread_mutex_t*,mutex, long,0,
1215                  long, (ret == 0 && mutex_is_valid) ? True : False);
1216
1217   if (ret != 0) {
1218      DO_PthAPIerror( "pthread_cond_wait", ret );
1219   }
1220
1221   if (TRACE_PTH_FNS) {
1222      fprintf(stderr, " cowait -> %d >>\n", ret);
1223   }
1224
1225   return ret;
1226}
1227#if defined(VGO_linux)
1228   PTH_FUNC(int, pthreadZucondZuwaitZAZa, // pthread_cond_wait@*
1229                 pthread_cond_t* cond, pthread_mutex_t* mutex) {
1230      return pthread_cond_wait_WRK(cond, mutex);
1231   }
1232#elif defined(VGO_darwin)
1233   PTH_FUNC(int, pthreadZucondZuwaitZa, // pthread_cond_wait*
1234                 pthread_cond_t* cond, pthread_mutex_t* mutex) {
1235      return pthread_cond_wait_WRK(cond, mutex);
1236   }
1237#elif defined(VGO_solaris)
1238   PTH_FUNC(int, condZuwait, // cond_wait
1239                 pthread_cond_t *cond, pthread_mutex_t *mutex) {
1240      return pthread_cond_wait_WRK(cond, mutex);
1241   }
1242#else
1243#  error "Unsupported OS"
1244#endif
1245
1246
1247//-----------------------------------------------------------
1248// glibc:   pthread_cond_timedwait@@GLIBC_2.3.2
1249// glibc:   pthread_cond_timedwait@GLIBC_2.2.5
1250// glibc:   pthread_cond_timedwait@GLIBC_2.0
1251// darwin:  pthread_cond_timedwait
1252// darwin:  pthread_cond_timedwait$NOCANCEL$UNIX2003
1253// darwin:  pthread_cond_timedwait$UNIX2003
1254// darwin:  pthread_cond_timedwait_relative_np (trapped)
1255// Solaris: cond_timedwait (pthread_cond_timedwait is built on cond_timedwait)
1256// Solaris: cond_reltimedwait (pthread_cond_reltimedwait_np is built on this)
1257//
1258__attribute__((noinline))
1259static int pthread_cond_timedwait_WRK(pthread_cond_t* cond,
1260                                      pthread_mutex_t* mutex,
1261                                      struct timespec* abstime,
1262                                      int timeout_error)
1263{
1264   int ret;
1265   OrigFn fn;
1266   unsigned long mutex_is_valid;
1267   Bool abstime_is_valid;
1268   VALGRIND_GET_ORIG_FN(fn);
1269
1270   if (TRACE_PTH_FNS) {
1271      fprintf(stderr, "<< pthread_cond_timedwait %p %p %p",
1272                      cond, mutex, abstime);
1273      fflush(stderr);
1274   }
1275
1276   /* Tell the tool a cond-wait is about to happen, so it can check
1277      for bogus argument values.  In return it tells us whether it
1278      thinks the mutex is valid or not. */
1279   DO_CREQ_W_WW(mutex_is_valid,
1280                _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
1281                pthread_cond_t*,cond, pthread_mutex_t*,mutex);
1282   assert(mutex_is_valid == 1 || mutex_is_valid == 0);
1283
1284   abstime_is_valid = abstime->tv_nsec >= 0 && abstime->tv_nsec < 1000000000;
1285
1286   /* Tell the tool we're about to drop the mutex.  This reflects the
1287      fact that in a cond_wait, we show up holding the mutex, and the
1288      call atomically drops the mutex and waits for the cv to be
1289      signalled. */
1290   if (mutex_is_valid && abstime_is_valid) {
1291      DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1292                  pthread_mutex_t*,mutex);
1293   }
1294
1295   CALL_FN_W_WWW(ret, fn, cond,mutex,abstime);
1296
1297   if (mutex_is_valid && !abstime_is_valid && ret != EINVAL) {
1298      DO_PthAPIerror("Bug in libpthread: pthread_cond_timedwait "
1299                     "invalid abstime did not cause"
1300                     " EINVAL", ret);
1301   }
1302
1303   if (mutex_is_valid && abstime_is_valid) {
1304      /* and now we have the mutex again if (ret == 0 || ret == timeout) */
1305      DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1306                   pthread_mutex_t *, mutex,
1307                   long, (ret == 0 || ret == timeout_error) ? True : False);
1308   }
1309
1310   DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
1311                  pthread_cond_t*,cond, pthread_mutex_t*,mutex,
1312                  long,ret == timeout_error,
1313                  long, (ret == 0 || ret == timeout_error) && mutex_is_valid
1314                        ? True : False);
1315
1316   if (ret != 0 && ret != timeout_error) {
1317      DO_PthAPIerror( "pthread_cond_timedwait", ret );
1318   }
1319
1320   if (TRACE_PTH_FNS) {
1321      fprintf(stderr, " cotimedwait -> %d >>\n", ret);
1322   }
1323
1324   return ret;
1325}
1326#if defined(VGO_linux)
1327   PTH_FUNC(int, pthreadZucondZutimedwaitZAZa, // pthread_cond_timedwait@*
1328                 pthread_cond_t* cond, pthread_mutex_t* mutex,
1329                 struct timespec* abstime) {
1330      return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
1331   }
1332#elif defined(VGO_darwin)
1333   PTH_FUNC(int, pthreadZucondZutimedwait, // pthread_cond_timedwait
1334                 pthread_cond_t* cond, pthread_mutex_t* mutex,
1335                 struct timespec* abstime) {
1336      return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
1337   }
1338   PTH_FUNC(int, pthreadZucondZutimedwaitZDZa, // pthread_cond_timedwait$*
1339                 pthread_cond_t* cond, pthread_mutex_t* mutex,
1340                 struct timespec* abstime) {
1341      return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
1342   }
1343   PTH_FUNC(int, pthreadZucondZutimedwaitZuZa, // pthread_cond_timedwait_*
1344                 pthread_cond_t* cond, pthread_mutex_t* mutex,
1345                 struct timespec* abstime) {
1346      assert(0);
1347   }
1348#elif defined(VGO_solaris)
1349   PTH_FUNC(int, condZutimedwait, // cond_timedwait
1350                 pthread_cond_t *cond, pthread_mutex_t *mutex,
1351                 struct timespec *abstime) {
1352      return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIME);
1353   }
1354   PTH_FUNC(int, condZureltimedwait, // cond_reltimedwait
1355                 pthread_cond_t *cond, pthread_mutex_t *mutex,
1356                 struct timespec *reltime) {
1357      return pthread_cond_timedwait_WRK(cond, mutex, reltime, ETIME);
1358   }
1359#else
1360#  error "Unsupported OS"
1361#endif
1362
1363
1364//-----------------------------------------------------------
1365// glibc:   pthread_cond_signal@GLIBC_2.0
1366// glibc:   pthread_cond_signal@GLIBC_2.2.5
1367// glibc:   pthread_cond_signal@@GLIBC_2.3.2
1368// darwin:  pthread_cond_signal
1369// darwin:  pthread_cond_signal_thread_np (don't intercept this)
1370// Solaris: cond_signal (pthread_cond_signal is a weak alias)
1371//
1372__attribute__((noinline))
1373static int pthread_cond_signal_WRK(pthread_cond_t* cond)
1374{
1375   int ret;
1376   OrigFn fn;
1377   VALGRIND_GET_ORIG_FN(fn);
1378
1379   if (TRACE_PTH_FNS) {
1380      fprintf(stderr, "<< pthread_cond_signal %p", cond);
1381      fflush(stderr);
1382   }
1383
1384   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE,
1385               pthread_cond_t*,cond);
1386
1387   CALL_FN_W_W(ret, fn, cond);
1388
1389   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_POST,
1390               pthread_cond_t*,cond);
1391
1392   if (ret != 0) {
1393      DO_PthAPIerror( "pthread_cond_signal", ret );
1394   }
1395
1396   if (TRACE_PTH_FNS) {
1397      fprintf(stderr, " cosig -> %d >>\n", ret);
1398   }
1399
1400   return ret;
1401}
1402#if defined(VGO_linux)
1403   PTH_FUNC(int, pthreadZucondZusignalZAZa, // pthread_cond_signal@*
1404                 pthread_cond_t* cond) {
1405      return pthread_cond_signal_WRK(cond);
1406   }
1407#elif defined(VGO_darwin)
1408   PTH_FUNC(int, pthreadZucondZusignal, // pthread_cond_signal
1409                 pthread_cond_t* cond) {
1410      return pthread_cond_signal_WRK(cond);
1411   }
1412#elif defined(VGO_solaris)
1413   PTH_FUNC(int, condZusignal, // cond_signal
1414                 pthread_cond_t *cond) {
1415      return pthread_cond_signal_WRK(cond);
1416   }
1417#else
1418#  error "Unsupported OS"
1419#endif
1420
1421
1422//-----------------------------------------------------------
1423// glibc:   pthread_cond_broadcast@GLIBC_2.0
1424// glibc:   pthread_cond_broadcast@GLIBC_2.2.5
1425// glibc:   pthread_cond_broadcast@@GLIBC_2.3.2
1426// darwin:  pthread_cond_broadcast
1427// Solaris: cond_broadcast (pthread_cond_broadcast is a weak alias)
1428//
1429// Note, this is pretty much identical, from a dependency-graph
1430// point of view, with cond_signal, so the code is duplicated.
1431// Maybe it should be commoned up.
1432//
1433__attribute__((noinline))
1434static int pthread_cond_broadcast_WRK(pthread_cond_t* cond)
1435{
1436   int ret;
1437   OrigFn fn;
1438   VALGRIND_GET_ORIG_FN(fn);
1439
1440   if (TRACE_PTH_FNS) {
1441      fprintf(stderr, "<< pthread_cond_broadcast %p", cond);
1442      fflush(stderr);
1443   }
1444
1445   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE,
1446               pthread_cond_t*,cond);
1447
1448   CALL_FN_W_W(ret, fn, cond);
1449
1450   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_POST,
1451               pthread_cond_t*,cond);
1452
1453   if (ret != 0) {
1454      DO_PthAPIerror( "pthread_cond_broadcast", ret );
1455   }
1456
1457   if (TRACE_PTH_FNS) {
1458      fprintf(stderr, " cobro -> %d >>\n", ret);
1459   }
1460
1461   return ret;
1462}
1463#if defined(VGO_linux)
1464   PTH_FUNC(int, pthreadZucondZubroadcastZAZa, // pthread_cond_broadcast@*
1465                 pthread_cond_t* cond) {
1466      return pthread_cond_broadcast_WRK(cond);
1467   }
1468#elif defined(VGO_darwin)
1469   PTH_FUNC(int, pthreadZucondZubroadcast, // pthread_cond_broadcast
1470                 pthread_cond_t* cond) {
1471      return pthread_cond_broadcast_WRK(cond);
1472   }
1473#elif defined(VGO_solaris)
1474   PTH_FUNC(int, condZubroadcast, // cond_broadcast
1475                 pthread_cond_t *cond) {
1476      return pthread_cond_broadcast_WRK(cond);
1477   }
1478#else
1479#   error "Unsupported OS"
1480#endif
1481
1482// glibc:   pthread_cond_init@GLIBC_2.0
1483// glibc:   pthread_cond_init@GLIBC_2.2.5
1484// glibc:   pthread_cond_init@@GLIBC_2.3.2
1485// darwin:  pthread_cond_init
1486// Solaris: cond_init (pthread_cond_init is built atop on this function)
1487// Easy way out: Handling of attr could have been messier.
1488// It turns out that pthread_cond_init under linux ignores
1489// all information in cond_attr, so do we.
1490// FIXME: MacOS X?
1491#if !defined(VGO_solaris)
1492__attribute__((noinline))
1493static int pthread_cond_init_WRK(pthread_cond_t* cond, pthread_condattr_t *cond_attr)
1494{
1495   int ret;
1496   OrigFn fn;
1497   VALGRIND_GET_ORIG_FN(fn);
1498
1499   if (TRACE_PTH_FNS) {
1500      fprintf(stderr, "<< pthread_cond_init %p", cond);
1501      fflush(stderr);
1502   }
1503
1504   CALL_FN_W_WW(ret, fn, cond, cond_attr);
1505
1506   if (ret == 0) {
1507      DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST,
1508                   pthread_cond_t*,cond, pthread_condattr_t*, cond_attr);
1509   } else {
1510      DO_PthAPIerror( "pthread_cond_init", ret );
1511   }
1512
1513   if (TRACE_PTH_FNS) {
1514      fprintf(stderr, " coinit -> %d >>\n", ret);
1515   }
1516
1517   return ret;
1518}
1519#if defined(VGO_linux)
1520   PTH_FUNC(int, pthreadZucondZuinitZAZa, // pthread_cond_init@*
1521	    pthread_cond_t* cond, pthread_condattr_t* cond_attr) {
1522     return pthread_cond_init_WRK(cond, cond_attr);
1523   }
1524#elif defined(VGO_darwin)
1525   PTH_FUNC(int, pthreadZucondZuinit, // pthread_cond_init
1526	    pthread_cond_t* cond, pthread_condattr_t * cond_attr) {
1527     return pthread_cond_init_WRK(cond, cond_attr);
1528   }
1529#else
1530#  error "Unsupported OS"
1531#endif
1532
1533#else /* VGO_solaris */
1534__attribute__((noinline))
1535PTH_FUNC(int, condZuinit, // cond_init
1536              cond_t *cond, int type, void *arg)
1537{
1538   int ret;
1539   OrigFn fn;
1540   VALGRIND_GET_ORIG_FN(fn);
1541
1542   if (TRACE_PTH_FNS) {
1543      fprintf(stderr, "<< cond_init %p", cond); fflush(stderr);
1544   }
1545
1546   CALL_FN_W_WWW(ret, fn, cond, type, arg);
1547
1548   if (ret == 0) {
1549      /* Luckily evh__HG_PTHREAD_COND_INIT_POST() ignores cond_attr.
1550         See also comment for pthread_cond_init_WRK(). */
1551      DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST,
1552                   cond_t *, cond, void *, NULL);
1553   } else {
1554      DO_PthAPIerror("cond_init", ret);
1555   }
1556
1557   if (TRACE_PTH_FNS) {
1558      fprintf(stderr, " cond_init -> %d >>\n", ret);
1559   }
1560
1561   return ret;
1562}
1563#endif /* VGO_solaris */
1564
1565
1566//-----------------------------------------------------------
1567// glibc:   pthread_cond_destroy@@GLIBC_2.3.2
1568// glibc:   pthread_cond_destroy@GLIBC_2.2.5
1569// glibc:   pthread_cond_destroy@GLIBC_2.0
1570// darwin:  pthread_cond_destroy
1571// Solaris: cond_destroy (pthread_cond_destroy is a weak alias)
1572//
1573__attribute__((noinline))
1574static int pthread_cond_destroy_WRK(pthread_cond_t* cond)
1575{
1576   int ret;
1577   unsigned long cond_is_init;
1578   OrigFn fn;
1579
1580   VALGRIND_GET_ORIG_FN(fn);
1581
1582   if (TRACE_PTH_FNS) {
1583      fprintf(stderr, "<< pthread_cond_destroy %p", cond);
1584      fflush(stderr);
1585   }
1586
1587   if (cond != NULL) {
1588      const pthread_cond_t cond_init = PTHREAD_COND_INITIALIZER;
1589      cond_is_init = my_memcmp(cond, &cond_init, sizeof(*cond)) == 0;
1590   } else {
1591     cond_is_init = 0;
1592   }
1593
1594   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_DESTROY_PRE,
1595                pthread_cond_t*, cond, unsigned long, cond_is_init);
1596
1597   CALL_FN_W_W(ret, fn, cond);
1598
1599   if (ret != 0) {
1600      DO_PthAPIerror( "pthread_cond_destroy", ret );
1601   }
1602
1603   if (TRACE_PTH_FNS) {
1604      fprintf(stderr, " codestr -> %d >>\n", ret);
1605   }
1606
1607   return ret;
1608}
1609#if defined(VGO_linux)
1610   PTH_FUNC(int, pthreadZucondZudestroyZAZa, // pthread_cond_destroy@*
1611                 pthread_cond_t* cond) {
1612      return pthread_cond_destroy_WRK(cond);
1613   }
1614#elif defined(VGO_darwin)
1615   PTH_FUNC(int, pthreadZucondZudestroy, // pthread_cond_destroy
1616                 pthread_cond_t* cond) {
1617      return pthread_cond_destroy_WRK(cond);
1618   }
1619#elif defined(VGO_solaris)
1620   PTH_FUNC(int, condZudestroy, // cond_destroy
1621                 pthread_cond_t *cond) {
1622      return pthread_cond_destroy_WRK(cond);
1623   }
1624#else
1625#  error "Unsupported OS"
1626#endif
1627
1628
1629/*----------------------------------------------------------------*/
1630/*--- pthread_barrier_t functions                              ---*/
1631/*----------------------------------------------------------------*/
1632
1633#if defined(HAVE_PTHREAD_BARRIER_INIT)
1634
1635/* Handled:   pthread_barrier_init
1636              pthread_barrier_wait
1637              pthread_barrier_destroy
1638
1639   Unhandled: pthread_barrierattr_destroy
1640              pthread_barrierattr_getpshared
1641              pthread_barrierattr_init
1642              pthread_barrierattr_setpshared
1643              -- are these important?
1644*/
1645
1646//-----------------------------------------------------------
1647// glibc:   pthread_barrier_init
1648// darwin:  (doesn't appear to exist)
1649// Solaris: pthread_barrier_init
1650PTH_FUNC(int, pthreadZubarrierZuinit, // pthread_barrier_init
1651         pthread_barrier_t* bar,
1652         pthread_barrierattr_t* attr, unsigned long count)
1653{
1654   int ret;
1655   OrigFn fn;
1656   VALGRIND_GET_ORIG_FN(fn);
1657
1658   if (TRACE_PTH_FNS) {
1659      fprintf(stderr, "<< pthread_barrier_init %p %p %lu",
1660                      bar, attr, count);
1661      fflush(stderr);
1662   }
1663
1664   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE,
1665                 pthread_barrier_t*, bar,
1666                 unsigned long, count,
1667                 unsigned long, 0/*!resizable*/);
1668
1669   CALL_FN_W_WWW(ret, fn, bar,attr,count);
1670
1671   if (ret != 0) {
1672      DO_PthAPIerror( "pthread_barrier_init", ret );
1673   }
1674
1675   if (TRACE_PTH_FNS) {
1676      fprintf(stderr, "  pthread_barrier_init -> %d >>\n", ret);
1677   }
1678
1679   return ret;
1680}
1681
1682
1683//-----------------------------------------------------------
1684// glibc:   pthread_barrier_wait
1685// darwin:  (doesn't appear to exist)
1686// Solaris: pthread_barrier_wait
1687PTH_FUNC(int, pthreadZubarrierZuwait, // pthread_barrier_wait
1688              pthread_barrier_t* bar)
1689{
1690   int ret;
1691   OrigFn fn;
1692   VALGRIND_GET_ORIG_FN(fn);
1693
1694   if (TRACE_PTH_FNS) {
1695      fprintf(stderr, "<< pthread_barrier_wait %p", bar);
1696      fflush(stderr);
1697   }
1698
1699   /* That this works correctly, and doesn't screw up when a thread
1700      leaving the barrier races round to the front and re-enters while
1701      other threads are still leaving it, is quite subtle.  See
1702      comments in the handler for PTHREAD_BARRIER_WAIT_PRE in
1703      hg_main.c. */
1704   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE,
1705               pthread_barrier_t*,bar);
1706
1707   CALL_FN_W_W(ret, fn, bar);
1708
1709   if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) {
1710      DO_PthAPIerror( "pthread_barrier_wait", ret );
1711   }
1712
1713   if (TRACE_PTH_FNS) {
1714      fprintf(stderr, "  pthread_barrier_wait -> %d >>\n", ret);
1715   }
1716
1717   return ret;
1718}
1719
1720
1721//-----------------------------------------------------------
1722// glibc:   pthread_barrier_destroy
1723// darwin:  (doesn't appear to exist)
1724// Solaris: pthread_barrier_destroy
1725PTH_FUNC(int, pthreadZubarrierZudestroy, // pthread_barrier_destroy
1726         pthread_barrier_t* bar)
1727{
1728   int ret;
1729   OrigFn fn;
1730   VALGRIND_GET_ORIG_FN(fn);
1731
1732   if (TRACE_PTH_FNS) {
1733      fprintf(stderr, "<< pthread_barrier_destroy %p", bar);
1734      fflush(stderr);
1735   }
1736
1737   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE,
1738               pthread_barrier_t*,bar);
1739
1740   CALL_FN_W_W(ret, fn, bar);
1741
1742   if (ret != 0) {
1743      DO_PthAPIerror( "pthread_barrier_destroy", ret );
1744   }
1745
1746   if (TRACE_PTH_FNS) {
1747      fprintf(stderr, "  pthread_barrier_destroy -> %d >>\n", ret);
1748   }
1749
1750   return ret;
1751}
1752
1753#endif   // defined(HAVE_PTHREAD_BARRIER_INIT)
1754
1755
1756/*----------------------------------------------------------------*/
1757/*--- pthread_spinlock_t functions                             ---*/
1758/*----------------------------------------------------------------*/
1759
1760#if defined(HAVE_PTHREAD_SPIN_LOCK) \
1761    && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1762
1763/* Handled:   pthread_spin_init pthread_spin_destroy
1764              pthread_spin_lock pthread_spin_trylock
1765              pthread_spin_unlock
1766
1767   Unhandled:
1768*/
1769
1770/* This is a nasty kludge, in that glibc "knows" that initialising a
1771   spin lock unlocks it, and pthread_spin_{init,unlock} are names for
1772   the same function.  Hence we have to have a wrapper which does both
1773   things, without knowing which the user intended to happen.
1774   Solaris has distinct functions for init/unlock but client requests
1775   are immutable in helgrind.h so follow the glibc lead. */
1776
1777//-----------------------------------------------------------
1778// glibc:   pthread_spin_init
1779// glibc:   pthread_spin_unlock
1780// darwin:  (doesn't appear to exist)
1781// Solaris: pthread_spin_init
1782// Solaris: pthread_spin_unlock
1783__attribute__((noinline))
1784static int pthread_spin_init_or_unlock_WRK(pthread_spinlock_t* lock,
1785                                           int pshared) {
1786   int    ret;
1787   OrigFn fn;
1788   VALGRIND_GET_ORIG_FN(fn);
1789   if (TRACE_PTH_FNS) {
1790      fprintf(stderr, "<< pthread_spin_iORu %p", lock); fflush(stderr);
1791   }
1792
1793   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE,
1794               pthread_spinlock_t*, lock);
1795
1796   CALL_FN_W_WW(ret, fn, lock,pshared);
1797
1798   if (ret == 0 /*success*/) {
1799      DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST,
1800                  pthread_spinlock_t*,lock);
1801   } else {
1802      DO_PthAPIerror( "pthread_spinlock_{init,unlock}", ret );
1803   }
1804
1805   if (TRACE_PTH_FNS) {
1806      fprintf(stderr, " :: spiniORu -> %d >>\n", ret);
1807   }
1808   return ret;
1809}
1810#if defined(VGO_linux)
1811   PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
1812            pthread_spinlock_t* lock, int pshared) {
1813      return pthread_spin_init_or_unlock_WRK(lock, pshared);
1814   }
1815   PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
1816            pthread_spinlock_t* lock) {
1817      /* this is never actually called */
1818      return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/);
1819   }
1820#elif defined(VGO_darwin)
1821#elif defined(VGO_solaris)
1822   PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
1823            pthread_spinlock_t *lock, int pshared) {
1824      return pthread_spin_init_or_unlock_WRK(lock, pshared);
1825   }
1826   PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
1827            pthread_spinlock_t *lock) {
1828      return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/);
1829   }
1830#else
1831#  error "Unsupported OS"
1832#endif
1833
1834
1835//-----------------------------------------------------------
1836// glibc:   pthread_spin_destroy
1837// darwin:  (doesn't appear to exist)
1838// Solaris: pthread_spin_destroy
1839__attribute__((noinline))
1840static int pthread_spin_destroy_WRK(pthread_spinlock_t *lock)
1841{
1842   int    ret;
1843   OrigFn fn;
1844   VALGRIND_GET_ORIG_FN(fn);
1845   if (TRACE_PTH_FNS) {
1846      fprintf(stderr, "<< pthread_spin_destroy %p", lock);
1847      fflush(stderr);
1848   }
1849
1850   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_DESTROY_PRE,
1851               pthread_spinlock_t*,lock);
1852
1853   CALL_FN_W_W(ret, fn, lock);
1854
1855   if (ret != 0) {
1856      DO_PthAPIerror( "pthread_spin_destroy", ret );
1857   }
1858
1859   if (TRACE_PTH_FNS) {
1860      fprintf(stderr, " :: spindestroy -> %d >>\n", ret);
1861   }
1862   return ret;
1863}
1864#if defined(VGO_linux)
1865   PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy
1866            pthread_spinlock_t *lock) {
1867      return pthread_spin_destroy_WRK(lock);
1868   }
1869#elif defined(VGO_darwin)
1870#elif defined(VGO_solaris)
1871   PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy
1872            pthread_spinlock_t *lock) {
1873      return pthread_spin_destroy_WRK(lock);
1874   }
1875#else
1876#  error "Unsupported OS"
1877#endif
1878
1879
1880//-----------------------------------------------------------
1881// glibc:   pthread_spin_lock
1882// darwin:  (doesn't appear to exist)
1883// Solaris: pthread_spin_lock
1884__attribute__((noinline))
1885static int pthread_spin_lock_WRK(pthread_spinlock_t *lock)
1886{
1887   int    ret;
1888   OrigFn fn;
1889   VALGRIND_GET_ORIG_FN(fn);
1890   if (TRACE_PTH_FNS) {
1891      fprintf(stderr, "<< pthread_spinlock %p", lock);
1892      fflush(stderr);
1893   }
1894
1895   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE,
1896                pthread_spinlock_t*,lock, long,0/*!isTryLock*/);
1897
1898   CALL_FN_W_W(ret, fn, lock);
1899
1900   /* There's a hole here: libpthread now knows the lock is locked,
1901      but the tool doesn't, so some other thread could run and detect
1902      that the lock has been acquired by someone (this thread).  Does
1903      this matter?  Not sure, but I don't think so. */
1904
1905   if (ret == 0 /*success*/) {
1906      DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST,
1907                  pthread_spinlock_t*,lock);
1908   } else {
1909      DO_PthAPIerror( "pthread_spin_lock", ret );
1910   }
1911
1912   if (TRACE_PTH_FNS) {
1913      fprintf(stderr, " :: spinlock -> %d >>\n", ret);
1914   }
1915   return ret;
1916}
1917#if defined(VGO_linux)
1918   PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
1919                 pthread_spinlock_t *lock) {
1920      return pthread_spin_lock_WRK(lock);
1921   }
1922#elif defined(VGO_darwin)
1923#elif defined(VGO_solaris)
1924   PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
1925                 pthread_spinlock_t *lock) {
1926      return pthread_spin_lock_WRK(lock);
1927   }
1928#else
1929#  error "Unsupported OS"
1930#endif
1931
1932
1933//-----------------------------------------------------------
1934// glibc:   pthread_spin_trylock
1935// darwin:  (doesn't appear to exist)
1936// Solaris: pthread_spin_trylock
1937__attribute__((noinline))
1938static int pthread_spin_trylock_WRK(pthread_spinlock_t *lock)
1939{
1940   int    ret;
1941   OrigFn fn;
1942   VALGRIND_GET_ORIG_FN(fn);
1943   if (TRACE_PTH_FNS) {
1944      fprintf(stderr, "<< pthread_spin_trylock %p", lock);
1945      fflush(stderr);
1946   }
1947
1948   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE,
1949                pthread_spinlock_t*,lock, long,1/*isTryLock*/);
1950
1951   CALL_FN_W_W(ret, fn, lock);
1952
1953   /* There's a hole here: libpthread now knows the lock is locked,
1954      but the tool doesn't, so some other thread could run and detect
1955      that the lock has been acquired by someone (this thread).  Does
1956      this matter?  Not sure, but I don't think so. */
1957
1958   if (ret == 0 /*success*/) {
1959      DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST,
1960                  pthread_spinlock_t*,lock);
1961   } else {
1962      if (ret != EBUSY)
1963         DO_PthAPIerror( "pthread_spin_trylock", ret );
1964   }
1965
1966   if (TRACE_PTH_FNS) {
1967      fprintf(stderr, " :: spin_trylock -> %d >>\n", ret);
1968   }
1969   return ret;
1970}
1971#if defined(VGO_linux)
1972   PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
1973                 pthread_spinlock_t *lock) {
1974      return pthread_spin_trylock_WRK(lock);
1975   }
1976#elif defined(VGO_darwin)
1977#elif defined(VGO_solaris)
1978   PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
1979                 pthread_spinlock_t *lock) {
1980      return pthread_spin_trylock_WRK(lock);
1981   }
1982#else
1983#  error "Unsupported OS"
1984#endif
1985
1986#endif // defined(HAVE_PTHREAD_SPIN_LOCK)
1987
1988
1989/*----------------------------------------------------------------*/
1990/*--- pthread_rwlock_t functions                               ---*/
1991/*----------------------------------------------------------------*/
1992
1993/* Android's pthread.h doesn't say anything about rwlocks, hence these
1994   functions have to be conditionally compiled. */
1995#if defined(HAVE_PTHREAD_RWLOCK_T)
1996
1997/* Handled:   pthread_rwlock_init pthread_rwlock_destroy
1998              pthread_rwlock_rdlock
1999              pthread_rwlock_wrlock
2000              pthread_rwlock_unlock
2001              pthread_rwlock_tryrdlock
2002              pthread_rwlock_trywrlock
2003
2004   Unhandled: pthread_rwlock_timedrdlock
2005              pthread_rwlock_timedwrlock
2006*/
2007
2008//-----------------------------------------------------------
2009// glibc:   pthread_rwlock_init
2010// darwin:  pthread_rwlock_init
2011// darwin:  pthread_rwlock_init$UNIX2003
2012// Solaris: rwlock_init (pthread_rwlock_init is built atop of rwlock_init)
2013__attribute__((noinline))
2014static int pthread_rwlock_init_WRK(pthread_rwlock_t *rwl,
2015                                   pthread_rwlockattr_t* attr)
2016{
2017   int    ret;
2018   OrigFn fn;
2019   VALGRIND_GET_ORIG_FN(fn);
2020   if (TRACE_PTH_FNS) {
2021      fprintf(stderr, "<< pthread_rwl_init %p", rwl); fflush(stderr);
2022   }
2023
2024   CALL_FN_W_WW(ret, fn, rwl,attr);
2025
2026   if (ret == 0 /*success*/) {
2027      DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
2028                  pthread_rwlock_t*,rwl);
2029   } else {
2030      DO_PthAPIerror( "pthread_rwlock_init", ret );
2031   }
2032
2033   if (TRACE_PTH_FNS) {
2034      fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
2035   }
2036   return ret;
2037}
2038#if defined(VGO_linux)
2039   PTH_FUNC(int, pthreadZurwlockZuinit, // pthread_rwlock_init
2040                 pthread_rwlock_t *rwl,
2041                 pthread_rwlockattr_t* attr) {
2042      return pthread_rwlock_init_WRK(rwl, attr);
2043   }
2044#elif defined(VGO_darwin)
2045   PTH_FUNC(int, pthreadZurwlockZuinitZa, // pthread_rwlock_init*
2046                 pthread_rwlock_t *rwl,
2047                 pthread_rwlockattr_t* attr) {
2048      return pthread_rwlock_init_WRK(rwl, attr);
2049   }
2050#elif defined(VGO_solaris)
2051static int pthread_rwlock_init_WRK(pthread_rwlock_t *rwl,
2052                                   pthread_rwlockattr_t* attr)
2053                                   __attribute__((unused));
2054#else
2055#  error "Unsupported OS"
2056#endif
2057
2058#if defined(VGO_solaris)
2059PTH_FUNC(int, rwlockZuinit, // rwlock_init
2060              rwlock_t *rwlock,
2061              int type,
2062              void *arg)
2063{
2064   int    ret;
2065   OrigFn fn;
2066   VALGRIND_GET_ORIG_FN(fn);
2067   if (TRACE_PTH_FNS) {
2068      fprintf(stderr, "<< rwl_init %p", rwlock); fflush(stderr);
2069   }
2070
2071   CALL_FN_W_WWW(ret, fn, rwlock, type, arg);
2072
2073   if (ret == 0 /*success*/) {
2074      DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
2075                  rwlock_t *, rwlock);
2076   } else {
2077      DO_PthAPIerror("rwlock_init", ret);
2078   }
2079
2080   if (TRACE_PTH_FNS) {
2081      fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
2082   }
2083   return ret;
2084}
2085#endif /* VGO_solaris */
2086
2087
2088//-----------------------------------------------------------
2089// glibc:   pthread_rwlock_destroy
2090// darwin:  pthread_rwlock_destroy
2091// darwin:  pthread_rwlock_destroy$UNIX2003
2092// Solaris: rwlock_destroy (pthread_rwlock_destroy is a weak alias)
2093//
2094__attribute__((noinline))
2095static int pthread_rwlock_destroy_WRK(pthread_rwlock_t* rwl)
2096{
2097   int    ret;
2098   OrigFn fn;
2099   VALGRIND_GET_ORIG_FN(fn);
2100   if (TRACE_PTH_FNS) {
2101      fprintf(stderr, "<< pthread_rwl_destroy %p", rwl); fflush(stderr);
2102   }
2103
2104   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE,
2105               pthread_rwlock_t*,rwl);
2106
2107   CALL_FN_W_W(ret, fn, rwl);
2108
2109   if (ret != 0) {
2110      DO_PthAPIerror( "pthread_rwlock_destroy", ret );
2111   }
2112
2113   if (TRACE_PTH_FNS) {
2114      fprintf(stderr, " :: rwl_destroy -> %d >>\n", ret);
2115   }
2116   return ret;
2117}
2118#if defined(VGO_linux)
2119   PTH_FUNC(int, pthreadZurwlockZudestroy, // pthread_rwlock_destroy
2120                 pthread_rwlock_t *rwl) {
2121      return pthread_rwlock_destroy_WRK(rwl);
2122   }
2123#elif defined(VGO_darwin)
2124   PTH_FUNC(int, pthreadZurwlockZudestroyZa, // pthread_rwlock_destroy*
2125                 pthread_rwlock_t *rwl) {
2126      return pthread_rwlock_destroy_WRK(rwl);
2127   }
2128#elif defined(VGO_solaris)
2129   PTH_FUNC(int, rwlockZudestroy, // rwlock_destroy
2130                 pthread_rwlock_t *rwl) {
2131      return pthread_rwlock_destroy_WRK(rwl);
2132   }
2133#else
2134#  error "Unsupported OS"
2135#endif
2136
2137
2138//-----------------------------------------------------------
2139// glibc:   pthread_rwlock_wrlock
2140// darwin:  pthread_rwlock_wrlock
2141// darwin:  pthread_rwlock_wrlock$UNIX2003
2142// Solaris: rw_wrlock (pthread_rwlock_wrlock is a weak alias)
2143//
2144__attribute__((noinline))
2145static int pthread_rwlock_wrlock_WRK(pthread_rwlock_t* rwlock)
2146{
2147   int    ret;
2148   OrigFn fn;
2149   VALGRIND_GET_ORIG_FN(fn);
2150   if (TRACE_PTH_FNS) {
2151      fprintf(stderr, "<< pthread_rwl_wlk %p", rwlock); fflush(stderr);
2152   }
2153
2154   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2155                 pthread_rwlock_t*,rwlock,
2156                 long,1/*isW*/, long,0/*!isTryLock*/);
2157
2158   CALL_FN_W_W(ret, fn, rwlock);
2159
2160   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2161                 pthread_rwlock_t*,rwlock, long,1/*isW*/,
2162                 long, (ret == 0) ? True : False);
2163   if (ret != 0) {
2164      DO_PthAPIerror( "pthread_rwlock_wrlock", ret );
2165   }
2166
2167   if (TRACE_PTH_FNS) {
2168      fprintf(stderr, " :: rwl_wlk -> %d >>\n", ret);
2169   }
2170   return ret;
2171}
2172#if defined(VGO_linux)
2173   PTH_FUNC(int, pthreadZurwlockZuwrlock, // pthread_rwlock_wrlock
2174                 pthread_rwlock_t* rwlock) {
2175      return pthread_rwlock_wrlock_WRK(rwlock);
2176   }
2177#elif defined(VGO_darwin)
2178   PTH_FUNC(int, pthreadZurwlockZuwrlockZa, // pthread_rwlock_wrlock*
2179                 pthread_rwlock_t* rwlock) {
2180      return pthread_rwlock_wrlock_WRK(rwlock);
2181   }
2182#elif defined(VGO_solaris)
2183   PTH_FUNC(int, rwZuwrlock, // rw_wrlock
2184                 pthread_rwlock_t *rwlock) {
2185      return pthread_rwlock_wrlock_WRK(rwlock);
2186   }
2187#else
2188#  error "Unsupported OS"
2189#endif
2190
2191#if defined(VGO_solaris)
2192/* Internal to libc. */
2193PTH_FUNC(void, lrwZuwrlock, // lrw_wrlock
2194               rwlock_t *rwlock)
2195{
2196   OrigFn fn;
2197   VALGRIND_GET_ORIG_FN(fn);
2198   if (TRACE_PTH_FNS) {
2199      fprintf(stderr, "<< lrw_wlk %p", rwlock); fflush(stderr);
2200   }
2201
2202   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2203                 pthread_rwlock_t *, rwlock,
2204                 long, 1/*isW*/, long, 0/*!isTryLock*/);
2205
2206   CALL_FN_v_W(fn, rwlock);
2207
2208   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2209                 pthread_rwlock_t *, rwlock, long, 1/*isW*/, long, True);
2210
2211   if (TRACE_PTH_FNS) {
2212      fprintf(stderr, " :: lrw_wlk >>\n");
2213   }
2214}
2215#endif /* VGO_solaris */
2216
2217
2218//-----------------------------------------------------------
2219// glibc:   pthread_rwlock_rdlock
2220// darwin:  pthread_rwlock_rdlock
2221// darwin:  pthread_rwlock_rdlock$UNIX2003
2222// Solaris: rw_rdlock (pthread_rwlock_rdlock is a weak alias)
2223//
2224__attribute__((noinline))
2225static int pthread_rwlock_rdlock_WRK(pthread_rwlock_t* rwlock)
2226{
2227   int    ret;
2228   OrigFn fn;
2229   VALGRIND_GET_ORIG_FN(fn);
2230   if (TRACE_PTH_FNS) {
2231      fprintf(stderr, "<< pthread_rwl_rlk %p", rwlock); fflush(stderr);
2232   }
2233
2234   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2235                 pthread_rwlock_t*,rwlock,
2236                 long,0/*!isW*/, long,0/*!isTryLock*/);
2237
2238   CALL_FN_W_W(ret, fn, rwlock);
2239
2240   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2241                 pthread_rwlock_t*,rwlock, long,0/*!isW*/,
2242                 long, (ret == 0) ? True : False);
2243   if (ret != 0) {
2244      DO_PthAPIerror( "pthread_rwlock_rdlock", ret );
2245   }
2246
2247   if (TRACE_PTH_FNS) {
2248      fprintf(stderr, " :: rwl_rlk -> %d >>\n", ret);
2249   }
2250   return ret;
2251}
2252#if defined(VGO_linux)
2253   PTH_FUNC(int, pthreadZurwlockZurdlock, // pthread_rwlock_rdlock
2254                 pthread_rwlock_t* rwlock) {
2255      return pthread_rwlock_rdlock_WRK(rwlock);
2256   }
2257#elif defined(VGO_darwin)
2258   PTH_FUNC(int, pthreadZurwlockZurdlockZa, // pthread_rwlock_rdlock*
2259                 pthread_rwlock_t* rwlock) {
2260      return pthread_rwlock_rdlock_WRK(rwlock);
2261   }
2262#elif defined(VGO_solaris)
2263   PTH_FUNC(int, rwZurdlock, // rw_rdlock
2264                 pthread_rwlock_t *rwlock) {
2265      return pthread_rwlock_rdlock_WRK(rwlock);
2266   }
2267#else
2268#  error "Unsupported OS"
2269#endif
2270
2271#if defined(VGO_solaris)
2272/* Internal to libc. */
2273PTH_FUNC(void, lrwZurdlock, // lrw_rdlock
2274               rwlock_t *rwlock)
2275{
2276   OrigFn fn;
2277   VALGRIND_GET_ORIG_FN(fn);
2278   if (TRACE_PTH_FNS) {
2279      fprintf(stderr, "<< lrw_rlk %p", rwlock); fflush(stderr);
2280   }
2281
2282   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2283                 pthread_rwlock_t *, rwlock,
2284                 long, 0/*!isW*/, long, 0/*!isTryLock*/);
2285
2286   CALL_FN_v_W(fn, rwlock);
2287
2288   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2289                 pthread_rwlock_t *, rwlock, long, 0/*!isW*/, long, True);
2290
2291   if (TRACE_PTH_FNS) {
2292      fprintf(stderr, " :: lrw_rlk ->>\n");
2293   }
2294}
2295#endif /* VGO_solaris */
2296
2297
2298//-----------------------------------------------------------
2299// glibc:   pthread_rwlock_trywrlock
2300// darwin:  pthread_rwlock_trywrlock
2301// darwin:  pthread_rwlock_trywrlock$UNIX2003
2302// Solaris: rw_trywrlock (pthread_rwlock_trywrlock is a weak alias)
2303//
2304__attribute__((noinline))
2305static int pthread_rwlock_trywrlock_WRK(pthread_rwlock_t* rwlock)
2306{
2307   int    ret;
2308   OrigFn fn;
2309   VALGRIND_GET_ORIG_FN(fn);
2310   if (TRACE_PTH_FNS) {
2311      fprintf(stderr, "<< pthread_rwl_trywlk %p", rwlock); fflush(stderr);
2312   }
2313
2314   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2315                 pthread_rwlock_t*,rwlock,
2316                 long,1/*isW*/, long,1/*isTryLock*/);
2317
2318   CALL_FN_W_W(ret, fn, rwlock);
2319
2320   /* There's a hole here: libpthread now knows the lock is locked,
2321      but the tool doesn't, so some other thread could run and detect
2322      that the lock has been acquired by someone (this thread).  Does
2323      this matter?  Not sure, but I don't think so. */
2324
2325   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2326                 pthread_rwlock_t*,rwlock, long,1/*isW*/,
2327                 long, (ret == 0) ? True : False);
2328   if (ret != 0) {
2329      if (ret != EBUSY)
2330         DO_PthAPIerror( "pthread_rwlock_trywrlock", ret );
2331   }
2332
2333   if (TRACE_PTH_FNS) {
2334      fprintf(stderr, " :: rwl_trywlk -> %d >>\n", ret);
2335   }
2336   return ret;
2337}
2338#if defined(VGO_linux)
2339   PTH_FUNC(int, pthreadZurwlockZutrywrlock, // pthread_rwlock_trywrlock
2340                 pthread_rwlock_t* rwlock) {
2341      return pthread_rwlock_trywrlock_WRK(rwlock);
2342   }
2343#elif defined(VGO_darwin)
2344   PTH_FUNC(int, pthreadZurwlockZutrywrlockZa, // pthread_rwlock_trywrlock*
2345                 pthread_rwlock_t* rwlock) {
2346      return pthread_rwlock_trywrlock_WRK(rwlock);
2347   }
2348#elif defined(VGO_solaris)
2349   PTH_FUNC(int, rwZutrywrlock, // rw_trywrlock
2350                 pthread_rwlock_t *rwlock) {
2351      return pthread_rwlock_trywrlock_WRK(rwlock);
2352   }
2353#else
2354#  error "Unsupported OS"
2355#endif
2356
2357
2358//-----------------------------------------------------------
2359// glibc:   pthread_rwlock_tryrdlock
2360// darwin:  pthread_rwlock_tryrdlock
2361// darwin:  pthread_rwlock_tryrdlock$UNIX2003
2362// Solaris: rw_tryrdlock (pthread_rwlock_tryrdlock is a weak alias)
2363//
2364__attribute__((noinline))
2365static int pthread_rwlock_tryrdlock_WRK(pthread_rwlock_t* rwlock)
2366{
2367   int    ret;
2368   OrigFn fn;
2369   VALGRIND_GET_ORIG_FN(fn);
2370   if (TRACE_PTH_FNS) {
2371      fprintf(stderr, "<< pthread_rwl_tryrlk %p", rwlock); fflush(stderr);
2372   }
2373
2374   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2375                 pthread_rwlock_t*,rwlock,
2376                 long,0/*!isW*/, long,1/*isTryLock*/);
2377
2378   CALL_FN_W_W(ret, fn, rwlock);
2379
2380   /* There's a hole here: libpthread now knows the lock is locked,
2381      but the tool doesn't, so some other thread could run and detect
2382      that the lock has been acquired by someone (this thread).  Does
2383      this matter?  Not sure, but I don't think so. */
2384
2385   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2386                pthread_rwlock_t*,rwlock, long,0/*!isW*/,
2387                long, (ret == 0) ? True : False);
2388
2389   if (ret != 0) {
2390      if (ret != EBUSY)
2391         DO_PthAPIerror( "pthread_rwlock_tryrdlock", ret );
2392   }
2393
2394   if (TRACE_PTH_FNS) {
2395      fprintf(stderr, " :: rwl_tryrlk -> %d >>\n", ret);
2396   }
2397   return ret;
2398}
2399#if defined(VGO_linux)
2400   PTH_FUNC(int, pthreadZurwlockZutryrdlock, // pthread_rwlock_tryrdlock
2401                 pthread_rwlock_t* rwlock) {
2402      return pthread_rwlock_tryrdlock_WRK(rwlock);
2403   }
2404#elif defined(VGO_darwin)
2405   PTH_FUNC(int, pthreadZurwlockZutryrdlockZa, // pthread_rwlock_tryrdlock*
2406                 pthread_rwlock_t* rwlock) {
2407      return pthread_rwlock_tryrdlock_WRK(rwlock);
2408   }
2409#elif defined(VGO_solaris)
2410   PTH_FUNC(int, rwZutryrdlock, // rw_tryrdlock
2411                 pthread_rwlock_t *rwlock) {
2412      return pthread_rwlock_tryrdlock_WRK(rwlock);
2413   }
2414#else
2415#  error "Unsupported OS"
2416#endif
2417
2418
2419//-----------------------------------------------------------
2420// glibc:   Unhandled
2421// darwin:  Unhandled
2422// Solaris: pthread_rwlock_timedrdlock
2423// Solaris: pthread_rwlock_reltimedrdlock_np
2424//
2425__attribute__((noinline)) __attribute__((unused))
2426static int pthread_rwlock_timedrdlock_WRK(pthread_rwlock_t *rwlock,
2427                                          const struct timespec *timeout)
2428{
2429   int    ret;
2430   OrigFn fn;
2431   VALGRIND_GET_ORIG_FN(fn);
2432   if (TRACE_PTH_FNS) {
2433      fprintf(stderr, "<< pthread_rwl_timedrdl %p", rwlock); fflush(stderr);
2434   }
2435
2436   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2437                 pthread_rwlock_t *, rwlock,
2438                 long, 0/*isW*/, long, 0/*isTryLock*/);
2439
2440   CALL_FN_W_WW(ret, fn, rwlock, timeout);
2441
2442   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2443                 pthread_rwlock_t *, rwlock, long, 0/*isW*/,
2444                 long, (ret == 0) ? True : False);
2445   if (ret != 0) {
2446      DO_PthAPIerror("pthread_rwlock_timedrdlock", ret);
2447   }
2448
2449   if (TRACE_PTH_FNS) {
2450      fprintf(stderr, " :: rwl_timedrdl -> %d >>\n", ret);
2451   }
2452   return ret;
2453}
2454#if defined(VGO_linux)
2455#elif defined(VGO_darwin)
2456#elif defined(VGO_solaris)
2457   PTH_FUNC(int, pthreadZurwlockZutimedrdlock, // pthread_rwlock_timedrdlock
2458                 pthread_rwlock_t *rwlock,
2459                 const struct timespec *timeout) {
2460      return pthread_rwlock_timedrdlock_WRK(rwlock, timeout);
2461   }
2462   PTH_FUNC(int, pthreadZurwlockZureltimedrdlockZunp, // pthread_rwlock_timedrdlock_np
2463                 pthread_rwlock_t *rwlock,
2464                 const struct timespec *timeout) {
2465      return pthread_rwlock_timedrdlock_WRK(rwlock, timeout);
2466   }
2467#else
2468#  error "Unsupported OS"
2469#endif
2470
2471
2472//-----------------------------------------------------------
2473// glibc:   Unhandled
2474// darwin:  Unhandled
2475// Solaris: pthread_rwlock_timedwrlock
2476// Solaris: pthread_rwlock_reltimedwrlock_np
2477//
2478__attribute__((noinline)) __attribute__((unused))
2479static int pthread_rwlock_timedwrlock_WRK(pthread_rwlock_t *rwlock,
2480                                          const struct timespec *timeout)
2481{
2482   int    ret;
2483   OrigFn fn;
2484   VALGRIND_GET_ORIG_FN(fn);
2485   if (TRACE_PTH_FNS) {
2486      fprintf(stderr, "<< pthread_rwl_timedwrl %p", rwlock); fflush(stderr);
2487   }
2488
2489   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2490                 pthread_rwlock_t *, rwlock,
2491                 long, 1/*isW*/, long, 0/*isTryLock*/);
2492
2493   CALL_FN_W_WW(ret, fn, rwlock, timeout);
2494
2495   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2496                 pthread_rwlock_t *, rwlock, long, 1/*isW*/,
2497                 long, (ret == 0) ? True : False);
2498   if (ret != 0) {
2499      DO_PthAPIerror("pthread_rwlock_timedwrlock", ret);
2500   }
2501
2502   if (TRACE_PTH_FNS) {
2503      fprintf(stderr, " :: rwl_timedwrl -> %d >>\n", ret);
2504   }
2505   return ret;
2506}
2507#if defined(VGO_linux)
2508#elif defined(VGO_darwin)
2509#elif defined(VGO_solaris)
2510   PTH_FUNC(int, pthreadZurwlockZutimedwrlock, // pthread_rwlock_timedwrlock
2511                 pthread_rwlock_t *rwlock,
2512                 const struct timespec *timeout) {
2513      return pthread_rwlock_timedwrlock_WRK(rwlock, timeout);
2514   }
2515   PTH_FUNC(int, pthreadZurwlockZureltimedwrlockZunp, // pthread_rwlock_timedwrlock_np
2516                 pthread_rwlock_t *rwlock,
2517                 const struct timespec *timeout) {
2518      return pthread_rwlock_timedwrlock_WRK(rwlock, timeout);
2519   }
2520#else
2521#  error "Unsupported OS"
2522#endif
2523
2524
2525//-----------------------------------------------------------
2526// glibc:   pthread_rwlock_unlock
2527// darwin:  pthread_rwlock_unlock
2528// darwin:  pthread_rwlock_unlock$UNIX2003
2529// Solaris: rw_unlock (pthread_rwlock_unlock is a weak alias)
2530__attribute__((noinline))
2531static int pthread_rwlock_unlock_WRK(pthread_rwlock_t* rwlock)
2532{
2533   int    ret;
2534   OrigFn fn;
2535   VALGRIND_GET_ORIG_FN(fn);
2536   if (TRACE_PTH_FNS) {
2537      fprintf(stderr, "<< pthread_rwl_unlk %p", rwlock); fflush(stderr);
2538   }
2539
2540   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
2541               pthread_rwlock_t*,rwlock);
2542
2543   CALL_FN_W_W(ret, fn, rwlock);
2544
2545   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
2546               pthread_rwlock_t*,rwlock);
2547   if (ret != 0) {
2548      DO_PthAPIerror( "pthread_rwlock_unlock", ret );
2549   }
2550
2551   if (TRACE_PTH_FNS) {
2552      fprintf(stderr, " :: rwl_unlk -> %d >>\n", ret);
2553   }
2554   return ret;
2555}
2556#if defined(VGO_linux)
2557   PTH_FUNC(int, pthreadZurwlockZuunlock, // pthread_rwlock_unlock
2558                 pthread_rwlock_t* rwlock) {
2559      return pthread_rwlock_unlock_WRK(rwlock);
2560   }
2561#elif defined(VGO_darwin)
2562   PTH_FUNC(int, pthreadZurwlockZuunlockZa, // pthread_rwlock_unlock*
2563                 pthread_rwlock_t* rwlock) {
2564      return pthread_rwlock_unlock_WRK(rwlock);
2565   }
2566#elif defined(VGO_solaris)
2567   PTH_FUNC(int, rwZuunlock, // rw_unlock
2568                 pthread_rwlock_t *rwlock) {
2569      return pthread_rwlock_unlock_WRK(rwlock);
2570   }
2571#else
2572#  error "Unsupported OS"
2573#endif
2574
2575#endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
2576
2577
2578/*----------------------------------------------------------------*/
2579/*--- POSIX semaphores                                         ---*/
2580/*----------------------------------------------------------------*/
2581
2582#include <semaphore.h>
2583#include <fcntl.h>       /* O_CREAT */
2584
2585#define TRACE_SEM_FNS 0
2586
2587/* Handled:
2588     int sem_init(sem_t *sem, int pshared, unsigned value);
2589     int sem_destroy(sem_t *sem);
2590     int sem_wait(sem_t *sem);
2591     int sem_post(sem_t *sem);
2592     sem_t* sem_open(const char *name, int oflag,
2593                     ... [mode_t mode, unsigned value]);
2594        [complete with its idiotic semantics]
2595     int sem_close(sem_t* sem);
2596
2597   Unhandled:
2598     int sem_trywait(sem_t *sem);
2599     int sem_timedwait(sem_t *restrict sem,
2600                       const struct timespec *restrict abs_timeout);
2601*/
2602
2603//-----------------------------------------------------------
2604// glibc:   sem_init@@GLIBC_2.2.5
2605// glibc:   sem_init@@GLIBC_2.1
2606// glibc:   sem_init@GLIBC_2.0
2607// darwin:  sem_init
2608// Solaris: sema_init (sem_init is built on top of sem_init)
2609//
2610#if !defined(VGO_solaris)
2611__attribute__((noinline))
2612static int sem_init_WRK(sem_t* sem, int pshared, unsigned long value)
2613{
2614   OrigFn fn;
2615   int    ret;
2616   VALGRIND_GET_ORIG_FN(fn);
2617
2618   if (TRACE_SEM_FNS) {
2619      fprintf(stderr, "<< sem_init(%p,%d,%lu) ", sem,pshared,value);
2620      fflush(stderr);
2621   }
2622
2623   CALL_FN_W_WWW(ret, fn, sem,pshared,value);
2624
2625   if (ret == 0) {
2626      DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
2627                   sem_t*, sem, unsigned long, value);
2628   } else {
2629      DO_PthAPIerror( "sem_init", errno );
2630   }
2631
2632   if (TRACE_SEM_FNS) {
2633      fprintf(stderr, " sem_init -> %d >>\n", ret);
2634      fflush(stderr);
2635   }
2636
2637   return ret;
2638}
2639#if defined(VGO_linux)
2640   PTH_FUNC(int, semZuinitZAZa, // sem_init@*
2641                 sem_t* sem, int pshared, unsigned long value) {
2642      return sem_init_WRK(sem, pshared, value);
2643   }
2644#elif defined(VGO_darwin)
2645   PTH_FUNC(int, semZuinit, // sem_init
2646                 sem_t* sem, int pshared, unsigned long value) {
2647      return sem_init_WRK(sem, pshared, value);
2648   }
2649#else
2650#  error "Unsupported OS"
2651#endif
2652
2653#else /* VGO_solaris */
2654PTH_FUNC(int, semaZuinit, // sema_init
2655              sema_t *sem,
2656              unsigned int value,
2657              int type,
2658              void *arg)
2659{
2660   OrigFn fn;
2661   int    ret;
2662   VALGRIND_GET_ORIG_FN(fn);
2663
2664   if (TRACE_SEM_FNS) {
2665      fprintf(stderr, "<< sema_init(%p, %d, %u) ", sem, type, value);
2666      fflush(stderr);
2667   }
2668
2669   CALL_FN_W_WWWW(ret, fn, sem, value, type, arg);
2670
2671   if (ret == 0) {
2672      DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
2673                   sema_t *, sem, Word, value);
2674   } else {
2675      DO_PthAPIerror("sema_init", ret);
2676   }
2677
2678   if (TRACE_SEM_FNS) {
2679      fprintf(stderr, " sema_init -> %d >>\n", ret);
2680      fflush(stderr);
2681   }
2682
2683   return ret;
2684}
2685#endif /* VGO_solaris */
2686
2687
2688//-----------------------------------------------------------
2689// glibc:   sem_destroy@GLIBC_2.0
2690// glibc:   sem_destroy@@GLIBC_2.1
2691// glibc:   sem_destroy@@GLIBC_2.2.5
2692// darwin:  sem_destroy
2693// Solaris: sema_destroy (sem_destroy is built on top of sema_destroy)
2694__attribute__((noinline))
2695static int sem_destroy_WRK(sem_t* sem)
2696{
2697   OrigFn fn;
2698   int    ret;
2699   VALGRIND_GET_ORIG_FN(fn);
2700
2701   if (TRACE_SEM_FNS) {
2702      fprintf(stderr, "<< sem_destroy(%p) ", sem);
2703      fflush(stderr);
2704   }
2705
2706   DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
2707
2708   CALL_FN_W_W(ret, fn, sem);
2709
2710   if (ret != 0) {
2711      DO_PthAPIerror( "sem_destroy", SEM_ERROR );
2712   }
2713
2714   if (TRACE_SEM_FNS) {
2715      fprintf(stderr, " sem_destroy -> %d >>\n", ret);
2716      fflush(stderr);
2717   }
2718
2719   return ret;
2720}
2721#if defined(VGO_linux)
2722   PTH_FUNC(int, semZudestroyZAZa,  // sem_destroy*
2723                 sem_t* sem) {
2724      return sem_destroy_WRK(sem);
2725   }
2726#elif defined(VGO_darwin)
2727   PTH_FUNC(int, semZudestroy,  // sem_destroy
2728                 sem_t* sem) {
2729      return sem_destroy_WRK(sem);
2730   }
2731#elif defined(VGO_solaris)
2732   PTH_FUNC(int, semaZudestroy,  // sema_destroy
2733                 sem_t *sem) {
2734      return sem_destroy_WRK(sem);
2735   }
2736#else
2737#  error "Unsupported OS"
2738#endif
2739
2740
2741//-----------------------------------------------------------
2742// glibc:   sem_wait
2743// glibc:   sem_wait@GLIBC_2.0
2744// glibc:   sem_wait@@GLIBC_2.1
2745// darwin:  sem_wait
2746// darwin:  sem_wait$NOCANCEL$UNIX2003
2747// darwin:  sem_wait$UNIX2003
2748// Solaris: sema_wait (sem_wait is built on top of sema_wait)
2749//
2750/* wait: decrement semaphore - acquire lockage */
2751__attribute__((noinline))
2752static int sem_wait_WRK(sem_t* sem)
2753{
2754   OrigFn fn;
2755   int    ret;
2756   VALGRIND_GET_ORIG_FN(fn);
2757
2758   if (TRACE_SEM_FNS) {
2759      fprintf(stderr, "<< sem_wait(%p) ", sem);
2760      fflush(stderr);
2761   }
2762
2763   DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_PRE, sem_t*,sem);
2764
2765   CALL_FN_W_W(ret, fn, sem);
2766
2767   DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST, sem_t*,sem,
2768                long, (ret == 0) ? True : False);
2769
2770   if (ret != 0) {
2771      DO_PthAPIerror( "sem_wait", SEM_ERROR );
2772   }
2773
2774   if (TRACE_SEM_FNS) {
2775      fprintf(stderr, " sem_wait -> %d >>\n", ret);
2776      fflush(stderr);
2777   }
2778
2779   return ret;
2780}
2781#if defined(VGO_linux)
2782   PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
2783      return sem_wait_WRK(sem);
2784   }
2785   PTH_FUNC(int, semZuwaitZAZa, sem_t* sem) { /* sem_wait@* */
2786      return sem_wait_WRK(sem);
2787   }
2788#elif defined(VGO_darwin)
2789   PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
2790      return sem_wait_WRK(sem);
2791   }
2792   PTH_FUNC(int, semZuwaitZDZa, sem_t* sem) { /* sem_wait$* */
2793      return sem_wait_WRK(sem);
2794   }
2795#elif defined(VGO_solaris)
2796   PTH_FUNC(int, semaZuwait, sem_t *sem) { /* sema_wait */
2797      return sem_wait_WRK(sem);
2798   }
2799#else
2800#  error "Unsupported OS"
2801#endif
2802
2803
2804//-----------------------------------------------------------
2805// glibc:   sem_post
2806// glibc:   sem_post@GLIBC_2.0
2807// glibc:   sem_post@@GLIBC_2.1
2808// darwin:  sem_post
2809// Solaris: sema_post (sem_post is built on top of sema_post)
2810//
2811/* post: increment semaphore - release lockage */
2812__attribute__((noinline))
2813static int sem_post_WRK(sem_t* sem)
2814{
2815   OrigFn fn;
2816   int    ret;
2817
2818   VALGRIND_GET_ORIG_FN(fn);
2819
2820   if (TRACE_SEM_FNS) {
2821      fprintf(stderr, "<< sem_post(%p) ", sem);
2822      fflush(stderr);
2823   }
2824
2825   DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_PRE, sem_t*,sem);
2826
2827   CALL_FN_W_W(ret, fn, sem);
2828
2829   DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_POST, sem_t*,sem);
2830
2831   if (ret != 0) {
2832      DO_PthAPIerror( "sem_post", SEM_ERROR );
2833   }
2834
2835   if (TRACE_SEM_FNS) {
2836      fprintf(stderr, " sem_post -> %d >>\n", ret);
2837      fflush(stderr);
2838   }
2839
2840   return ret;
2841}
2842#if defined(VGO_linux)
2843   PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
2844      return sem_post_WRK(sem);
2845   }
2846   PTH_FUNC(int, semZupostZAZa, sem_t* sem) { /* sem_post@* */
2847      return sem_post_WRK(sem);
2848   }
2849#elif defined(VGO_darwin)
2850   PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
2851      return sem_post_WRK(sem);
2852   }
2853#elif defined(VGO_solaris)
2854   PTH_FUNC(int, semaZupost, sem_t *sem) { /* sema_post */
2855      return sem_post_WRK(sem);
2856   }
2857#else
2858#  error "Unsupported OS"
2859#endif
2860
2861
2862//-----------------------------------------------------------
2863// glibc:   sem_open
2864// darwin:  sem_open
2865// Solaris: sem_open
2866//
2867PTH_FUNC(sem_t*, semZuopen,
2868                 const char* name, long oflag,
2869                 long mode, unsigned long value)
2870{
2871   /* A copy of sem_init_WRK (more or less).  Is this correct? */
2872   OrigFn fn;
2873   sem_t* ret;
2874   VALGRIND_GET_ORIG_FN(fn);
2875
2876   if (TRACE_SEM_FNS) {
2877      fprintf(stderr, "<< sem_open(\"%s\",%ld,%lx,%lu) ",
2878                      name,oflag,mode,value);
2879      fflush(stderr);
2880   }
2881
2882   CALL_FN_W_WWWW(ret, fn, name,oflag,mode,value);
2883
2884   if (ret != SEM_FAILED && (oflag & O_CREAT)) {
2885      DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
2886                   sem_t*, ret, unsigned long, value);
2887   }
2888   if (ret == SEM_FAILED) {
2889      DO_PthAPIerror( "sem_open", errno );
2890   }
2891
2892   if (TRACE_SEM_FNS) {
2893      fprintf(stderr, " sem_open -> %p >>\n", ret);
2894      fflush(stderr);
2895   }
2896
2897   return ret;
2898}
2899
2900
2901//-----------------------------------------------------------
2902// glibc:   sem_close
2903// darwin:  sem_close
2904// Solaris: sem_close
2905PTH_FUNC(int, sem_close, sem_t* sem)
2906{
2907   OrigFn fn;
2908   int    ret;
2909   VALGRIND_GET_ORIG_FN(fn);
2910
2911   if (TRACE_SEM_FNS) {
2912      fprintf(stderr, "<< sem_close(%p) ", sem);
2913      fflush(stderr);
2914   }
2915
2916   DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
2917
2918   CALL_FN_W_W(ret, fn, sem);
2919
2920   if (ret != 0) {
2921      DO_PthAPIerror( "sem_close", errno );
2922   }
2923
2924   if (TRACE_SEM_FNS) {
2925      fprintf(stderr, " close -> %d >>\n", ret);
2926      fflush(stderr);
2927   }
2928
2929   return ret;
2930}
2931
2932
2933/*----------------------------------------------------------------*/
2934/*--- Qt 4 threading functions (w/ GNU name mangling)          ---*/
2935/*----------------------------------------------------------------*/
2936
2937/* Handled:
2938      QMutex::lock()
2939      QMutex::unlock()
2940      QMutex::tryLock()
2941      QMutex::tryLock(int)
2942
2943      QMutex::QMutex(QMutex::RecursionMode)  _ZN6QMutexC1ENS_13RecursionModeE
2944      QMutex::QMutex(QMutex::RecursionMode)  _ZN6QMutexC2ENS_13RecursionModeE
2945      QMutex::~QMutex()                      _ZN6QMutexD1Ev
2946      QMutex::~QMutex()                      _ZN6QMutexD2Ev
2947
2948   Unhandled:
2949      QReadWriteLock::lockForRead()
2950      QReadWriteLock::lockForWrite()
2951      QReadWriteLock::unlock()
2952      QReadWriteLock::tryLockForRead(int)
2953      QReadWriteLock::tryLockForRead()
2954      QReadWriteLock::tryLockForWrite(int)
2955      QReadWriteLock::tryLockForWrite()
2956
2957      QWaitCondition::wait(QMutex*, unsigned long)
2958      QWaitCondition::wakeAll()
2959      QWaitCondition::wakeOne()
2960
2961      QSemaphore::*
2962*/
2963/* More comments, 19 Nov 08, based on assessment of qt-4.5.0TP1,
2964   at least on Unix:
2965
2966   It's apparently only necessary to intercept QMutex, since that is
2967   not implemented using pthread_mutex_t; instead Qt4 has its own
2968   implementation based on atomics (to check the non-contended case)
2969   and pthread_cond_wait (to wait in the contended case).
2970
2971   QReadWriteLock is built on top of QMutex, counters, and a wait
2972   queue.  So we don't need to handle it specially once QMutex
2973   handling is correct -- presumably the dependencies through QMutex
2974   are sufficient to avoid any false race reports.  On the other hand,
2975   it is an open question whether too many dependencies are observed
2976   -- in which case we may miss races (false negatives).  I suspect
2977   this is likely to be the case, unfortunately.
2978
2979   QWaitCondition is built on pthread_cond_t, pthread_mutex_t, QMutex
2980   and QReadWriteLock.  Same compositional-correctness justificiation
2981   and limitations as fro QReadWriteLock.
2982
2983   Ditto QSemaphore (from cursory examination).
2984
2985   Does it matter that only QMutex is handled directly?  Open
2986   question.  From testing with drd/tests/qt4_* and with KDE4 apps, it
2987   appears that no false errors are reported; however it is not clear
2988   if this is causing false negatives.
2989
2990   Another problem with Qt4 is thread exiting.  Threads are created
2991   with pthread_create (fine); but they detach and simply exit when
2992   done.  There is no use of pthread_join, and the provided
2993   wait-for-a-thread-to-exit mechanism (QThread::wait, I believe)
2994   relies on a system of mutexes and flags.  I suspect this also
2995   causes too many dependencies to appear.  Consequently H sometimes
2996   fails to detect races at exit in some very short-lived racy
2997   programs, because it appears that a thread can exit _and_ have an
2998   observed dependency edge back to the main thread (presumably)
2999   before the main thread reaps the child (that is, calls
3000   QThread::wait).
3001
3002   This theory is supported by the observation that if all threads are
3003   made to wait at a pthread_barrier_t immediately before they exit,
3004   then H's detection of races in such programs becomes reliable;
3005   without the barrier, it is varies from run to run, depending
3006   (according to investigation) on whether aforementioned
3007   exit-before-reaping behaviour happens or not.
3008
3009   Finally, why is it necessary to intercept the QMutex constructors
3010   and destructors?  The constructors are intercepted only as a matter
3011   of convenience, so H can print accurate "first observed at"
3012   clauses.  However, it is actually necessary to intercept the
3013   destructors (as it is with pthread_mutex_destroy) in order that
3014   locks get removed from LAOG when they are destroyed.
3015*/
3016
3017// soname is libQtCore.so.4 ; match against libQtCore.so*
3018#define QT4_FUNC(ret_ty, f, args...) \
3019   ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args); \
3020   ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args)
3021
3022// soname is libQt5Core.so.4 ; match against libQt5Core.so*
3023#define QT5_FUNC(ret_ty, f, args...) \
3024   ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args); \
3025   ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args)
3026
3027//-----------------------------------------------------------
3028// QMutex::lock()
3029__attribute__((noinline))
3030static void QMutex_lock_WRK(void* self)
3031{
3032   OrigFn fn;
3033   VALGRIND_GET_ORIG_FN(fn);
3034   if (TRACE_QT4_FNS) {
3035      fprintf(stderr, "<< QMutex::lock %p", self); fflush(stderr);
3036   }
3037
3038   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
3039                void*,self, long,0/*!isTryLock*/);
3040
3041   CALL_FN_v_W(fn, self);
3042
3043   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
3044                void *, self, long, True);
3045
3046   if (TRACE_QT4_FNS) {
3047      fprintf(stderr, " :: Q::lock done >>\n");
3048   }
3049}
3050
3051QT4_FUNC(void, _ZN6QMutex4lockEv, void* self) {
3052    QMutex_lock_WRK(self);
3053}
3054QT5_FUNC(void, _ZN6QMutex4lockEv, void* self) {
3055    QMutex_lock_WRK(self);
3056}
3057
3058//-----------------------------------------------------------
3059// QMutex::unlock()
3060__attribute__((noinline))
3061static void QMutex_unlock_WRK(void* self)
3062{
3063   OrigFn fn;
3064   VALGRIND_GET_ORIG_FN(fn);
3065
3066   if (TRACE_QT4_FNS) {
3067      fprintf(stderr, "<< QMutex::unlock %p", self); fflush(stderr);
3068   }
3069
3070   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
3071               void*, self);
3072
3073   CALL_FN_v_W(fn, self);
3074
3075   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
3076               void*, self);
3077
3078   if (TRACE_QT4_FNS) {
3079      fprintf(stderr, " Q::unlock done >>\n");
3080   }
3081}
3082
3083QT4_FUNC(void, _ZN6QMutex6unlockEv, void* self) {
3084    QMutex_unlock_WRK(self);
3085}
3086QT5_FUNC(void, _ZN6QMutex6unlockEv, void* self) {
3087    QMutex_unlock_WRK(self);
3088}
3089
3090//-----------------------------------------------------------
3091// bool QMutex::tryLock()
3092// using 'long' to mimic C++ 'bool'
3093__attribute__((noinline))
3094static long QMutex_tryLock_WRK(void* self)
3095{
3096   OrigFn fn;
3097   long   ret;
3098   VALGRIND_GET_ORIG_FN(fn);
3099   if (TRACE_QT4_FNS) {
3100      fprintf(stderr, "<< QMutex::tryLock %p", self); fflush(stderr);
3101   }
3102
3103   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
3104                void*,self, long,1/*isTryLock*/);
3105
3106   CALL_FN_W_W(ret, fn, self);
3107
3108   // assumes that only the low 8 bits of the 'bool' are significant
3109   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
3110                void *, self, long, (ret & 0xFF) ? True : False);
3111
3112   if (TRACE_QT4_FNS) {
3113      fprintf(stderr, " :: Q::tryLock -> %lu >>\n", ret);
3114   }
3115
3116   return ret;
3117}
3118
3119QT4_FUNC(long, _ZN6QMutex7tryLockEv, void* self) {
3120    return QMutex_tryLock_WRK(self);
3121}
3122QT5_FUNC(long, _ZN6QMutex7tryLockEv, void* self) {
3123    return QMutex_tryLock_WRK(self);
3124}
3125
3126//-----------------------------------------------------------
3127// bool QMutex::tryLock(int)
3128// using 'long' to mimic C++ 'bool'
3129__attribute__((noinline))
3130static long QMutex_tryLock_int_WRK(void* self, long arg2)
3131{
3132   OrigFn fn;
3133   long   ret;
3134   VALGRIND_GET_ORIG_FN(fn);
3135   if (TRACE_QT4_FNS) {
3136      fprintf(stderr, "<< QMutex::tryLock(int) %p %d", self, (int)arg2);
3137      fflush(stderr);
3138   }
3139
3140   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
3141                void*,self, long,1/*isTryLock*/);
3142
3143   CALL_FN_W_WW(ret, fn, self,arg2);
3144
3145   // assumes that only the low 8 bits of the 'bool' are significant
3146   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
3147               void *, self, long, (ret & 0xFF) ? True : False);
3148
3149   if (TRACE_QT4_FNS) {
3150      fprintf(stderr, " :: Q::tryLock(int) -> %lu >>\n", ret);
3151   }
3152
3153   return ret;
3154}
3155
3156QT4_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2) {
3157    return QMutex_tryLock_int_WRK(self, arg2);
3158}
3159QT5_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2) {
3160    return QMutex_tryLock_int_WRK(self, arg2);
3161}
3162
3163//-----------------------------------------------------------
3164// It's not really very clear what the args are here.  But from
3165// a bit of dataflow analysis of the generated machine code of
3166// the original function, it appears this takes two args, and
3167// returns nothing.  Nevertheless preserve return value just in
3168// case.  A bit of debug printing indicates that the first arg
3169// is that of the mutex and the second is either zero or one,
3170// probably being the recursion mode, therefore.
3171// QMutex::QMutex(QMutex::RecursionMode)  ("C1ENS" variant)
3172__attribute__((noinline))
3173static void* QMutex_constructor_WRK(void* mutex, long recmode)
3174{
3175   OrigFn fn;
3176   long   ret;
3177   VALGRIND_GET_ORIG_FN(fn);
3178   CALL_FN_W_WW(ret, fn, mutex, recmode);
3179   //   fprintf(stderr, "QMutex constructor 1: %p <- %p %p\n", ret, arg1, arg2);
3180   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
3181                void*,mutex, long,1/*mbRec*/);
3182   return (void*)ret;
3183}
3184
3185QT4_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE, void* self, long recmode) {
3186    return QMutex_constructor_WRK(self, recmode);
3187}
3188QT5_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE, void* self, long recmode) {
3189    return QMutex_constructor_WRK(self, recmode);
3190}
3191
3192//-----------------------------------------------------------
3193// QMutex::~QMutex()  ("D1Ev" variant)
3194__attribute__((noinline))
3195static void* QMutex_destructor_WRK(void* mutex)
3196{
3197   OrigFn fn;
3198   long   ret;
3199   VALGRIND_GET_ORIG_FN(fn);
3200   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
3201               void*,mutex);
3202   CALL_FN_W_W(ret, fn, mutex);
3203   return (void*)ret;
3204}
3205
3206QT4_FUNC(void*, _ZN6QMutexD1Ev, void* self) {
3207    return QMutex_destructor_WRK(self);
3208}
3209QT5_FUNC(void*, _ZN6QMutexD1Ev, void* self) {
3210    return QMutex_destructor_WRK(self);
3211}
3212
3213//-----------------------------------------------------------
3214// QMutex::QMutex(QMutex::RecursionMode)  ("C2ENS" variant)
3215QT4_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE,
3216         void* mutex,
3217         long  recmode)
3218{
3219   assert(0);
3220   /*NOTREACHED*/
3221   /* Android's gcc behaves like it doesn't know that assert(0)
3222      never returns.  Hence: */
3223   return NULL;
3224}
3225
3226QT5_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE, void* self, long recmode)
3227{
3228   assert(0);
3229   /*NOTREACHED*/
3230   return NULL;
3231}
3232
3233//-----------------------------------------------------------
3234// QMutex::~QMutex()  ("D2Ev" variant)
3235QT4_FUNC(void*, _ZN6QMutexD2Ev, void* mutex)
3236{
3237   assert(0);
3238   /* Android's gcc behaves like it doesn't know that assert(0)
3239      never returns.  Hence: */
3240   return NULL;
3241}
3242
3243QT5_FUNC(void*, _ZN6QMutexD2Ev, void* self)
3244{
3245   assert(0);
3246   /*NOTREACHED*/
3247   return NULL;
3248}
3249
3250// QReadWriteLock is not intercepted directly.  See comments
3251// above.
3252
3253//// QReadWriteLock::lockForRead()
3254//// _ZN14QReadWriteLock11lockForReadEv == QReadWriteLock::lockForRead()
3255//QT4_FUNC(void, ZuZZN14QReadWriteLock11lockForReadEv,
3256//               // _ZN14QReadWriteLock11lockForReadEv
3257//               void* self)
3258//{
3259//   OrigFn fn;
3260//   VALGRIND_GET_ORIG_FN(fn);
3261//   if (TRACE_QT4_FNS) {
3262//      fprintf(stderr, "<< QReadWriteLock::lockForRead %p", self);
3263//      fflush(stderr);
3264//   }
3265//
3266//   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
3267//                 void*,self,
3268//                 long,0/*!isW*/, long,0/*!isTryLock*/);
3269//
3270//   CALL_FN_v_W(fn, self);
3271//
3272//   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
3273//                 void*,self, long,0/*!isW*/, long, True);
3274//
3275//   if (TRACE_QT4_FNS) {
3276//      fprintf(stderr, " :: Q::lockForRead :: done >>\n");
3277//   }
3278//}
3279//
3280//// QReadWriteLock::lockForWrite()
3281//// _ZN14QReadWriteLock12lockForWriteEv == QReadWriteLock::lockForWrite()
3282//QT4_FUNC(void, ZuZZN14QReadWriteLock12lockForWriteEv,
3283//               // _ZN14QReadWriteLock12lockForWriteEv
3284//               void* self)
3285//{
3286//   OrigFn fn;
3287//   VALGRIND_GET_ORIG_FN(fn);
3288//   if (TRACE_QT4_FNS) {
3289//      fprintf(stderr, "<< QReadWriteLock::lockForWrite %p", self);
3290//      fflush(stderr);
3291//   }
3292//
3293//   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
3294//                 void*,self,
3295//                 long,1/*isW*/, long,0/*!isTryLock*/);
3296//
3297//   CALL_FN_v_W(fn, self);
3298//
3299//   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
3300//                 void*,self, long,1/*isW*/, long, True);
3301//
3302//   if (TRACE_QT4_FNS) {
3303//      fprintf(stderr, " :: Q::lockForWrite :: done >>\n");
3304//   }
3305//}
3306//
3307//// QReadWriteLock::unlock()
3308//// _ZN14QReadWriteLock6unlockEv == QReadWriteLock::unlock()
3309//QT4_FUNC(void, ZuZZN14QReadWriteLock6unlockEv,
3310//               // _ZN14QReadWriteLock6unlockEv
3311//               void* self)
3312//{
3313//   OrigFn fn;
3314//   VALGRIND_GET_ORIG_FN(fn);
3315//   if (TRACE_QT4_FNS) {
3316//      fprintf(stderr, "<< QReadWriteLock::unlock %p", self);
3317//      fflush(stderr);
3318//   }
3319//
3320//   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
3321//               void*,self);
3322//
3323//   CALL_FN_v_W(fn, self);
3324//
3325//   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
3326//               void*,self);
3327//
3328//   if (TRACE_QT4_FNS) {
3329//      fprintf(stderr, " :: Q::unlock :: done >>\n");
3330//   }
3331//}
3332
3333
3334/*----------------------------------------------------------------*/
3335/*--- Replacements for basic string functions, that don't      ---*/
3336/*--- overrun the input arrays.                                ---*/
3337/*----------------------------------------------------------------*/
3338
3339#include "../shared/vg_replace_strmem.c"
3340
3341/*--------------------------------------------------------------------*/
3342/*--- end                                          hg_intercepts.c ---*/
3343/*--------------------------------------------------------------------*/
3344