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