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