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