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