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