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