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