2 /*--------------------------------------------------------------------*/
3 /*--- pthread intercepts for thread checking. ---*/
4 /*--- hg_intercepts.c ---*/
5 /*--------------------------------------------------------------------*/
8 This file is part of Helgrind, a Valgrind tool for detecting errors
11 Copyright (C) 2007-2013 OpenWorks LLP
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.
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.
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
29 The GNU General Public License is contained in the file COPYING.
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.
37 /* RUNS ON SIMULATED CPU
38 Interceptors for pthread_* functions, so that tc_main can see
39 significant thread events.
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
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.
55 #include "pub_tool_basics.h"
56 #include "pub_tool_redir.h"
57 #include "pub_tool_clreq.h"
61 #define TRACE_PTH_FNS 0
62 #define TRACE_QT4_FNS 0
65 /*----------------------------------------------------------------*/
67 /*----------------------------------------------------------------*/
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)
73 // Do a client request. These are macros rather than a functions so
74 // as to avoid having an extra frame in stack traces.
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.
81 // nuke the previous definitions
87 #define DO_CREQ_v_W(_creqF, _ty1F,_arg1F) \
90 assert(sizeof(_ty1F) == sizeof(Word)); \
91 _arg1 = (Word)(_arg1F); \
92 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
96 #define DO_CREQ_v_WW(_creqF, _ty1F,_arg1F, _ty2F,_arg2F) \
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); \
107 #define DO_CREQ_W_WW(_resF, _creqF, _ty1F,_arg1F, \
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, \
117 _arg1,_arg2,0,0,0); \
121 #define DO_CREQ_v_WWW(_creqF, _ty1F,_arg1F, \
122 _ty2F,_arg2F, _ty3F, _arg3F) \
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); \
136 #define DO_PthAPIerror(_fnnameF, _errF) \
138 char* _fnname = (char*)(_fnnameF); \
139 long _err = (long)(int)(_errF); \
140 const char* _errstr = lame_strerror(_err); \
141 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTH_API_ERROR, \
143 long,_err, char*,_errstr); \
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
157 /* A standalone memcmp. */
158 __attribute__((noinline
))
159 static int my_memcmp ( const void* ptr1
, const void* ptr2
, size_t size
)
161 unsigned char* uchar_ptr1
= (unsigned char*) ptr1
;
162 unsigned char* uchar_ptr2
= (unsigned char*) ptr2
;
164 for (i
= 0; i
< size
; ++i
) {
165 if (uchar_ptr1
[i
] != uchar_ptr2
[i
])
166 return (uchar_ptr1
[i
] < uchar_ptr2
[i
]) ? -1 : 1;
171 /* A lame version of strerror which doesn't use the real libc
172 strerror_r, since using the latter just generates endless more
173 threading errors (glibc goes off and does tons of crap w.r.t.
175 static const HChar
* lame_strerror ( long err
)
178 case EPERM
: return "EPERM: Operation not permitted";
179 case ENOENT
: return "ENOENT: No such file or directory";
180 case ESRCH
: return "ESRCH: No such process";
181 case EINTR
: return "EINTR: Interrupted system call";
182 case EBADF
: return "EBADF: Bad file number";
183 case EAGAIN
: return "EAGAIN: Try again";
184 case ENOMEM
: return "ENOMEM: Out of memory";
185 case EACCES
: return "EACCES: Permission denied";
186 case EFAULT
: return "EFAULT: Bad address";
187 case EEXIST
: return "EEXIST: File exists";
188 case EINVAL
: return "EINVAL: Invalid argument";
189 case EMFILE
: return "EMFILE: Too many open files";
190 case ENOSYS
: return "ENOSYS: Function not implemented";
191 case EOVERFLOW
: return "EOVERFLOW: Value too large "
192 "for defined data type";
193 case EBUSY
: return "EBUSY: Device or resource busy";
194 case ETIMEDOUT
: return "ETIMEDOUT: Connection timed out";
195 case EDEADLK
: return "EDEADLK: Resource deadlock would occur";
196 case EOPNOTSUPP
: return "EOPNOTSUPP: Operation not supported on "
197 "transport endpoint"; /* honest, guv */
198 default: return "tc_intercepts.c: lame_strerror(): "
199 "unhandled case -- please fix me!";
204 /*----------------------------------------------------------------*/
205 /*--- pthread_create, pthread_join, pthread_exit ---*/
206 /*----------------------------------------------------------------*/
208 static void* mythread_wrapper ( void* xargsV
)
210 volatile Word
* xargs
= (volatile Word
*) xargsV
;
211 void*(*fn
)(void*) = (void*(*)(void*))xargs
[0];
212 void* arg
= (void*)xargs
[1];
213 pthread_t me
= pthread_self();
214 /* Tell the tool what my pthread_t is. */
215 DO_CREQ_v_W(_VG_USERREQ__HG_SET_MY_PTHREAD_T
, pthread_t
,me
);
216 /* allow the parent to proceed. We can't let it proceed until
217 we're ready because (1) we need to make sure it doesn't exit and
218 hence deallocate xargs[] while we still need it, and (2) we
219 don't want either parent nor child to proceed until the tool has
220 been notified of the child's pthread_t.
222 Note that parent and child access args[] without a lock,
223 effectively using args[2] as a spinlock in order to get the
224 parent to wait until the child passes this point. The parent
225 disables checking on xargs[] before creating the child and
226 re-enables it once the child goes past this point, so the user
227 never sees the race. The previous approach (suppressing the
228 resulting error) was flawed, because it could leave shadow
229 memory for args[] in a state in which subsequent use of it by
230 the parent would report further races. */
232 /* Now we can no longer safely use xargs[]. */
233 return (void*) fn( (void*)arg
);
236 //-----------------------------------------------------------
237 // glibc: pthread_create@GLIBC_2.0
238 // glibc: pthread_create@@GLIBC_2.1
239 // glibc: pthread_create@@GLIBC_2.2.5
240 // darwin: pthread_create
241 // darwin: pthread_create_suspended_np (trapped)
243 /* ensure this has its own frame, so as to make it more distinguishable
245 __attribute__((noinline
))
246 static int pthread_create_WRK(pthread_t
*thread
, const pthread_attr_t
*attr
,
247 void *(*start
) (void *), void *arg
)
251 volatile Word xargs
[3];
253 VALGRIND_GET_ORIG_FN(fn
);
255 fprintf(stderr
, "<< pthread_create wrapper"); fflush(stderr
);
257 xargs
[0] = (Word
)start
;
258 xargs
[1] = (Word
)arg
;
259 xargs
[2] = 1; /* serves as a spinlock -- sigh */
260 /* Disable checking on the spinlock and the two words used to
261 convey args to the child. Basically we need to make it appear
262 as if the child never accessed this area, since merely
263 suppressing the resulting races does not address the issue that
264 that piece of the parent's stack winds up in the "wrong" state
265 and therefore may give rise to mysterious races when the parent
266 comes to re-use this piece of stack in some other frame. */
267 VALGRIND_HG_DISABLE_CHECKING(&xargs
, sizeof(xargs
));
269 CALL_FN_W_WWWW(ret
, fn
, thread
,attr
,mythread_wrapper
,&xargs
[0]);
272 /* we have to wait for the child to notify the tool of its
273 pthread_t before continuing */
274 while (xargs
[2] != 0) {
275 /* Do nothing. We need to spin until the child writes to
276 xargs[2]. However, that can lead to starvation in the
277 child and very long delays (eg, tc19_shadowmem on
278 ppc64-linux Fedora Core 6). So yield the cpu if we can,
279 to let the child run at the earliest available
284 DO_PthAPIerror( "pthread_create", ret
);
287 /* Reenable checking on the area previously used to communicate
289 VALGRIND_HG_ENABLE_CHECKING(&xargs
, sizeof(xargs
));
292 fprintf(stderr
, " :: pth_create -> %d >>\n", ret
);
296 #if defined(VGO_linux)
297 PTH_FUNC(int, pthreadZucreateZAZa
, // pthread_create@*
298 pthread_t
*thread
, const pthread_attr_t
*attr
,
299 void *(*start
) (void *), void *arg
) {
300 return pthread_create_WRK(thread
, attr
, start
, arg
);
302 #elif defined(VGO_darwin)
303 PTH_FUNC(int, pthreadZucreate
, // pthread_create
304 pthread_t
*thread
, const pthread_attr_t
*attr
,
305 void *(*start
) (void *), void *arg
) {
306 return pthread_create_WRK(thread
, attr
, start
, arg
);
308 PTH_FUNC(int, pthreadZucreateZuZa
, // pthread_create_*
309 pthread_t
*thread
, const pthread_attr_t
*attr
,
310 void *(*start
) (void *), void *arg
) {
311 // trap anything else
315 # error "Unsupported OS"
319 //-----------------------------------------------------------
320 // glibc: pthread_join
321 // darwin: pthread_join
322 // darwin: pthread_join$NOCANCEL$UNIX2003
323 // darwin pthread_join$UNIX2003
324 __attribute__((noinline
))
325 static int pthread_join_WRK(pthread_t thread
, void** value_pointer
)
329 VALGRIND_GET_ORIG_FN(fn
);
331 fprintf(stderr
, "<< pthread_join wrapper"); fflush(stderr
);
334 CALL_FN_W_WW(ret
, fn
, thread
,value_pointer
);
336 /* At least with NPTL as the thread library, this is safe because
337 it is guaranteed (by NPTL) that the joiner will completely gone
338 before pthread_join (the original) returns. See email below.*/
339 if (ret
== 0 /*success*/) {
340 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST
, pthread_t
,thread
);
342 DO_PthAPIerror( "pthread_join", ret
);
346 fprintf(stderr
, " :: pth_join -> %d >>\n", ret
);
350 #if defined(VGO_linux)
351 PTH_FUNC(int, pthreadZujoin
, // pthread_join
352 pthread_t thread
, void** value_pointer
) {
353 return pthread_join_WRK(thread
, value_pointer
);
355 #elif defined(VGO_darwin)
356 PTH_FUNC(int, pthreadZujoinZa
, // pthread_join*
357 pthread_t thread
, void** value_pointer
) {
358 return pthread_join_WRK(thread
, value_pointer
);
361 # error "Unsupported OS"
365 /* Behaviour of pthread_join on NPTL:
368 I have a question re the NPTL pthread_join implementation.
370 Suppose I am the thread 'stayer'.
372 If I call pthread_join(quitter), is it guaranteed that the
373 thread 'quitter' has really exited before pthread_join returns?
375 IOW, is it guaranteed that 'quitter' will not execute any further
376 instructions after pthread_join returns?
378 I believe this is true based on the following analysis of
379 glibc-2.5 sources. However am not 100% sure and would appreciate
382 'quitter' will be running start_thread() in nptl/pthread_create.c
384 The last action of start_thread() is to exit via
385 __exit_thread_inline(0), which simply does sys_exit
386 (nptl/pthread_create.c:403)
388 'stayer' meanwhile is waiting for lll_wait_tid (pd->tid)
389 (call at nptl/pthread_join.c:89)
391 As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
392 lll_wait_tid will not return until kernel notifies via futex
393 wakeup that 'quitter' has terminated.
395 Hence pthread_join cannot return until 'quitter' really has
396 completely disappeared.
399 > As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
400 > lll_wait_tid will not return until kernel notifies via futex
401 > wakeup that 'quitter' has terminated.
402 That's the key. The kernel resets the TID field after the thread is
403 done. No way the joiner can return before the thread is gone.
407 /*----------------------------------------------------------------*/
408 /*--- pthread_mutex_t functions ---*/
409 /*----------------------------------------------------------------*/
411 /* Handled: pthread_mutex_init pthread_mutex_destroy
413 pthread_mutex_trylock pthread_mutex_timedlock
417 //-----------------------------------------------------------
418 // glibc: pthread_mutex_init
419 // darwin: pthread_mutex_init
420 PTH_FUNC(int, pthreadZumutexZuinit
, // pthread_mutex_init
421 pthread_mutex_t
*mutex
,
422 pthread_mutexattr_t
* attr
)
427 VALGRIND_GET_ORIG_FN(fn
);
429 fprintf(stderr
, "<< pthread_mxinit %p", mutex
); fflush(stderr
);
435 zzz
= pthread_mutexattr_gettype(attr
, &ty
);
436 if (zzz
== 0 && ty
== PTHREAD_MUTEX_RECURSIVE
)
440 CALL_FN_W_WW(ret
, fn
, mutex
,attr
);
442 if (ret
== 0 /*success*/) {
443 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST
,
444 pthread_mutex_t
*,mutex
, long,mbRec
);
446 DO_PthAPIerror( "pthread_mutex_init", ret
);
450 fprintf(stderr
, " :: mxinit -> %d >>\n", ret
);
456 //-----------------------------------------------------------
457 // glibc: pthread_mutex_destroy
458 // darwin: pthread_mutex_destroy
459 PTH_FUNC(int, pthreadZumutexZudestroy
, // pthread_mutex_destroy
460 pthread_mutex_t
*mutex
)
463 unsigned long mutex_is_init
;
466 VALGRIND_GET_ORIG_FN(fn
);
468 fprintf(stderr
, "<< pthread_mxdestroy %p", mutex
); fflush(stderr
);
472 static const pthread_mutex_t mutex_init
= PTHREAD_MUTEX_INITIALIZER
;
473 mutex_is_init
= my_memcmp(mutex
, &mutex_init
, sizeof(*mutex
)) == 0;
478 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE
,
479 pthread_mutex_t
*, mutex
, unsigned long, mutex_is_init
);
481 CALL_FN_W_W(ret
, fn
, mutex
);
484 DO_PthAPIerror( "pthread_mutex_destroy", ret
);
488 fprintf(stderr
, " :: mxdestroy -> %d >>\n", ret
);
494 //-----------------------------------------------------------
495 // glibc: pthread_mutex_lock
496 // darwin: pthread_mutex_lock
497 PTH_FUNC(int, pthreadZumutexZulock
, // pthread_mutex_lock
498 pthread_mutex_t
*mutex
)
502 VALGRIND_GET_ORIG_FN(fn
);
504 fprintf(stderr
, "<< pthread_mxlock %p", mutex
); fflush(stderr
);
507 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
508 pthread_mutex_t
*,mutex
, long,0/*!isTryLock*/);
510 CALL_FN_W_W(ret
, fn
, mutex
);
512 /* There's a hole here: libpthread now knows the lock is locked,
513 but the tool doesn't, so some other thread could run and detect
514 that the lock has been acquired by someone (this thread). Does
515 this matter? Not sure, but I don't think so. */
517 if (ret
== 0 /*success*/) {
518 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
519 pthread_mutex_t
*,mutex
);
521 DO_PthAPIerror( "pthread_mutex_lock", ret
);
525 fprintf(stderr
, " :: mxlock -> %d >>\n", ret
);
531 //-----------------------------------------------------------
532 // glibc: pthread_mutex_trylock
533 // darwin: pthread_mutex_trylock
535 // pthread_mutex_trylock. The handling needed here is very similar
536 // to that for pthread_mutex_lock, except that we need to tell
537 // the pre-lock creq that this is a trylock-style operation, and
538 // therefore not to complain if the lock is nonrecursive and
539 // already locked by this thread -- because then it'll just fail
540 // immediately with EBUSY.
541 PTH_FUNC(int, pthreadZumutexZutrylock
, // pthread_mutex_trylock
542 pthread_mutex_t
*mutex
)
546 VALGRIND_GET_ORIG_FN(fn
);
548 fprintf(stderr
, "<< pthread_mxtrylock %p", mutex
); fflush(stderr
);
551 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
552 pthread_mutex_t
*,mutex
, long,1/*isTryLock*/);
554 CALL_FN_W_W(ret
, fn
, mutex
);
556 /* There's a hole here: libpthread now knows the lock is locked,
557 but the tool doesn't, so some other thread could run and detect
558 that the lock has been acquired by someone (this thread). Does
559 this matter? Not sure, but I don't think so. */
561 if (ret
== 0 /*success*/) {
562 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
563 pthread_mutex_t
*,mutex
);
566 DO_PthAPIerror( "pthread_mutex_trylock", ret
);
570 fprintf(stderr
, " :: mxtrylock -> %d >>\n", ret
);
576 //-----------------------------------------------------------
577 // glibc: pthread_mutex_timedlock
578 // darwin: (doesn't appear to exist)
580 // pthread_mutex_timedlock. Identical logic to pthread_mutex_trylock.
581 PTH_FUNC(int, pthreadZumutexZutimedlock
, // pthread_mutex_timedlock
582 pthread_mutex_t
*mutex
,
587 VALGRIND_GET_ORIG_FN(fn
);
589 fprintf(stderr
, "<< pthread_mxtimedlock %p %p", mutex
, timeout
);
593 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
594 pthread_mutex_t
*,mutex
, long,1/*isTryLock-ish*/);
596 CALL_FN_W_WW(ret
, fn
, mutex
,timeout
);
598 /* There's a hole here: libpthread now knows the lock is locked,
599 but the tool doesn't, so some other thread could run and detect
600 that the lock has been acquired by someone (this thread). Does
601 this matter? Not sure, but I don't think so. */
603 if (ret
== 0 /*success*/) {
604 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
605 pthread_mutex_t
*,mutex
);
607 if (ret
!= ETIMEDOUT
)
608 DO_PthAPIerror( "pthread_mutex_timedlock", ret
);
612 fprintf(stderr
, " :: mxtimedlock -> %d >>\n", ret
);
618 //-----------------------------------------------------------
619 // glibc: pthread_mutex_unlock
620 // darwin: pthread_mutex_unlock
621 PTH_FUNC(int, pthreadZumutexZuunlock
, // pthread_mutex_unlock
622 pthread_mutex_t
*mutex
)
626 VALGRIND_GET_ORIG_FN(fn
);
629 fprintf(stderr
, "<< pthread_mxunlk %p", mutex
); fflush(stderr
);
632 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE
,
633 pthread_mutex_t
*,mutex
);
635 CALL_FN_W_W(ret
, fn
, mutex
);
637 if (ret
== 0 /*success*/) {
638 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST
,
639 pthread_mutex_t
*,mutex
);
641 DO_PthAPIerror( "pthread_mutex_unlock", ret
);
645 fprintf(stderr
, " mxunlk -> %d >>\n", ret
);
651 /*----------------------------------------------------------------*/
652 /*--- pthread_cond_t functions ---*/
653 /*----------------------------------------------------------------*/
655 /* Handled: pthread_cond_wait pthread_cond_timedwait
656 pthread_cond_signal pthread_cond_broadcast
661 //-----------------------------------------------------------
662 // glibc: pthread_cond_wait@GLIBC_2.2.5
663 // glibc: pthread_cond_wait@@GLIBC_2.3.2
664 // darwin: pthread_cond_wait
665 // darwin: pthread_cond_wait$NOCANCEL$UNIX2003
666 // darwin: pthread_cond_wait$UNIX2003
668 __attribute__((noinline
))
669 static int pthread_cond_wait_WRK(pthread_cond_t
* cond
,
670 pthread_mutex_t
* mutex
)
674 unsigned long mutex_is_valid
;
676 VALGRIND_GET_ORIG_FN(fn
);
679 fprintf(stderr
, "<< pthread_cond_wait %p %p", cond
, mutex
);
683 /* Tell the tool a cond-wait is about to happen, so it can check
684 for bogus argument values. In return it tells us whether it
685 thinks the mutex is valid or not. */
686 DO_CREQ_W_WW(mutex_is_valid
,
687 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE
,
688 pthread_cond_t
*,cond
, pthread_mutex_t
*,mutex
);
689 assert(mutex_is_valid
== 1 || mutex_is_valid
== 0);
691 /* Tell the tool we're about to drop the mutex. This reflects the
692 fact that in a cond_wait, we show up holding the mutex, and the
693 call atomically drops the mutex and waits for the cv to be
695 if (mutex_is_valid
) {
696 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE
,
697 pthread_mutex_t
*,mutex
);
700 CALL_FN_W_WW(ret
, fn
, cond
,mutex
);
702 /* these conditionals look stupid, but compare w/ same logic for
703 pthread_cond_timedwait below */
704 if (ret
== 0 && mutex_is_valid
) {
705 /* and now we have the mutex again */
706 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
707 pthread_mutex_t
*,mutex
);
710 if (ret
== 0 && mutex_is_valid
) {
711 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST
,
712 pthread_cond_t
*,cond
, pthread_mutex_t
*,mutex
, long,0);
716 DO_PthAPIerror( "pthread_cond_wait", ret
);
720 fprintf(stderr
, " cowait -> %d >>\n", ret
);
725 #if defined(VGO_linux)
726 PTH_FUNC(int, pthreadZucondZuwaitZAZa
, // pthread_cond_wait@*
727 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
) {
728 return pthread_cond_wait_WRK(cond
, mutex
);
730 #elif defined(VGO_darwin)
731 PTH_FUNC(int, pthreadZucondZuwaitZa
, // pthread_cond_wait*
732 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
) {
733 return pthread_cond_wait_WRK(cond
, mutex
);
736 # error "Unsupported OS"
740 //-----------------------------------------------------------
741 // glibc: pthread_cond_timedwait@@GLIBC_2.3.2
742 // glibc: pthread_cond_timedwait@GLIBC_2.2.5
743 // glibc: pthread_cond_timedwait@GLIBC_2.0
744 // darwin: pthread_cond_timedwait
745 // darwin: pthread_cond_timedwait$NOCANCEL$UNIX2003
746 // darwin: pthread_cond_timedwait$UNIX2003
747 // darwin: pthread_cond_timedwait_relative_np (trapped)
749 __attribute__((noinline
))
750 static int pthread_cond_timedwait_WRK(pthread_cond_t
* cond
,
751 pthread_mutex_t
* mutex
,
752 struct timespec
* abstime
)
756 unsigned long mutex_is_valid
;
757 Bool abstime_is_valid
;
758 VALGRIND_GET_ORIG_FN(fn
);
761 fprintf(stderr
, "<< pthread_cond_timedwait %p %p %p",
762 cond
, mutex
, abstime
);
766 /* Tell the tool a cond-wait is about to happen, so it can check
767 for bogus argument values. In return it tells us whether it
768 thinks the mutex is valid or not. */
769 DO_CREQ_W_WW(mutex_is_valid
,
770 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE
,
771 pthread_cond_t
*,cond
, pthread_mutex_t
*,mutex
);
772 assert(mutex_is_valid
== 1 || mutex_is_valid
== 0);
774 abstime_is_valid
= abstime
->tv_nsec
>= 0 && abstime
->tv_nsec
< 1000000000;
776 /* Tell the tool we're about to drop the mutex. This reflects the
777 fact that in a cond_wait, we show up holding the mutex, and the
778 call atomically drops the mutex and waits for the cv to be
780 if (mutex_is_valid
&& abstime_is_valid
) {
781 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE
,
782 pthread_mutex_t
*,mutex
);
785 CALL_FN_W_WWW(ret
, fn
, cond
,mutex
,abstime
);
787 if (!abstime_is_valid
&& ret
!= EINVAL
) {
788 DO_PthAPIerror("Bug in libpthread: pthread_cond_timedwait "
789 "invalid abstime did not cause"
793 if ((ret
== 0 || ret
== ETIMEDOUT
) && mutex_is_valid
) {
794 /* and now we have the mutex again */
795 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
796 pthread_mutex_t
*,mutex
);
799 if ((ret
== 0 || ret
== ETIMEDOUT
) && mutex_is_valid
) {
800 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST
,
801 pthread_cond_t
*,cond
, pthread_mutex_t
*,mutex
,
802 long,ret
== ETIMEDOUT
);
805 if (ret
!= 0 && ret
!= ETIMEDOUT
) {
806 DO_PthAPIerror( "pthread_cond_timedwait", ret
);
810 fprintf(stderr
, " cotimedwait -> %d >>\n", ret
);
815 #if defined(VGO_linux)
816 PTH_FUNC(int, pthreadZucondZutimedwaitZAZa
, // pthread_cond_timedwait@*
817 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
,
818 struct timespec
* abstime
) {
819 return pthread_cond_timedwait_WRK(cond
, mutex
, abstime
);
821 #elif defined(VGO_darwin)
822 PTH_FUNC(int, pthreadZucondZutimedwait
, // pthread_cond_timedwait
823 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
,
824 struct timespec
* abstime
) {
825 return pthread_cond_timedwait_WRK(cond
, mutex
, abstime
);
827 PTH_FUNC(int, pthreadZucondZutimedwaitZDZa
, // pthread_cond_timedwait$*
828 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
,
829 struct timespec
* abstime
) {
830 return pthread_cond_timedwait_WRK(cond
, mutex
, abstime
);
832 PTH_FUNC(int, pthreadZucondZutimedwaitZuZa
, // pthread_cond_timedwait_*
833 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
,
834 struct timespec
* abstime
) {
838 # error "Unsupported OS"
842 //-----------------------------------------------------------
843 // glibc: pthread_cond_signal@GLIBC_2.0
844 // glibc: pthread_cond_signal@GLIBC_2.2.5
845 // glibc: pthread_cond_signal@@GLIBC_2.3.2
846 // darwin: pthread_cond_signal
847 // darwin: pthread_cond_signal_thread_np (don't intercept this)
849 __attribute__((noinline
))
850 static int pthread_cond_signal_WRK(pthread_cond_t
* cond
)
854 VALGRIND_GET_ORIG_FN(fn
);
857 fprintf(stderr
, "<< pthread_cond_signal %p", cond
);
861 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE
,
862 pthread_cond_t
*,cond
);
864 CALL_FN_W_W(ret
, fn
, cond
);
867 DO_PthAPIerror( "pthread_cond_signal", ret
);
871 fprintf(stderr
, " cosig -> %d >>\n", ret
);
876 #if defined(VGO_linux)
877 PTH_FUNC(int, pthreadZucondZusignalZAZa
, // pthread_cond_signal@*
878 pthread_cond_t
* cond
) {
879 return pthread_cond_signal_WRK(cond
);
881 #elif defined(VGO_darwin)
882 PTH_FUNC(int, pthreadZucondZusignal
, // pthread_cond_signal
883 pthread_cond_t
* cond
) {
884 return pthread_cond_signal_WRK(cond
);
887 # error "Unsupported OS"
891 //-----------------------------------------------------------
892 // glibc: pthread_cond_broadcast@GLIBC_2.0
893 // glibc: pthread_cond_broadcast@GLIBC_2.2.5
894 // glibc: pthread_cond_broadcast@@GLIBC_2.3.2
895 // darwin: pthread_cond_broadcast
897 // Note, this is pretty much identical, from a dependency-graph
898 // point of view, with cond_signal, so the code is duplicated.
899 // Maybe it should be commoned up.
901 __attribute__((noinline
))
902 static int pthread_cond_broadcast_WRK(pthread_cond_t
* cond
)
906 VALGRIND_GET_ORIG_FN(fn
);
909 fprintf(stderr
, "<< pthread_cond_broadcast %p", cond
);
913 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE
,
914 pthread_cond_t
*,cond
);
916 CALL_FN_W_W(ret
, fn
, cond
);
919 DO_PthAPIerror( "pthread_cond_broadcast", ret
);
923 fprintf(stderr
, " cobro -> %d >>\n", ret
);
928 #if defined(VGO_linux)
929 PTH_FUNC(int, pthreadZucondZubroadcastZAZa
, // pthread_cond_broadcast@*
930 pthread_cond_t
* cond
) {
931 return pthread_cond_broadcast_WRK(cond
);
933 #elif defined(VGO_darwin)
934 PTH_FUNC(int, pthreadZucondZubroadcast
, // pthread_cond_broadcast
935 pthread_cond_t
* cond
) {
936 return pthread_cond_broadcast_WRK(cond
);
939 # error "Unsupported OS"
942 // glibc: pthread_cond_init@GLIBC_2.0
943 // glibc: pthread_cond_init@GLIBC_2.2.5
944 // glibc: pthread_cond_init@@GLIBC_2.3.2
945 // darwin: pthread_cond_init
946 // Easy way out: Handling of attr could have been messier.
947 // It turns out that pthread_cond_init under linux ignores
948 // all information in cond_attr, so do we.
950 __attribute__((noinline
))
951 static int pthread_cond_init_WRK(pthread_cond_t
* cond
, pthread_condattr_t
*cond_attr
)
955 VALGRIND_GET_ORIG_FN(fn
);
958 fprintf(stderr
, "<< pthread_cond_init %p", cond
);
962 CALL_FN_W_WW(ret
, fn
, cond
, cond_attr
);
965 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST
,
966 pthread_cond_t
*,cond
, pthread_condattr_t
*, cond_attr
);
968 DO_PthAPIerror( "pthread_cond_init", ret
);
972 fprintf(stderr
, " coinit -> %d >>\n", ret
);
977 #if defined(VGO_linux)
978 PTH_FUNC(int, pthreadZucondZuinitZAZa
, // pthread_cond_init@*
979 pthread_cond_t
* cond
, pthread_condattr_t
* cond_attr
) {
980 return pthread_cond_init_WRK(cond
, cond_attr
);
982 #elif defined(VGO_darwin)
983 PTH_FUNC(int, pthreadZucondZuinit
, // pthread_cond_init
984 pthread_cond_t
* cond
, pthread_condattr_t
* cond_attr
) {
985 return pthread_cond_init_WRK(cond
, cond_attr
);
988 # error "Unsupported OS"
992 //-----------------------------------------------------------
993 // glibc: pthread_cond_destroy@@GLIBC_2.3.2
994 // glibc: pthread_cond_destroy@GLIBC_2.2.5
995 // glibc: pthread_cond_destroy@GLIBC_2.0
996 // darwin: pthread_cond_destroy
998 __attribute__((noinline
))
999 static int pthread_cond_destroy_WRK(pthread_cond_t
* cond
)
1002 unsigned long cond_is_init
;
1005 VALGRIND_GET_ORIG_FN(fn
);
1007 if (TRACE_PTH_FNS
) {
1008 fprintf(stderr
, "<< pthread_cond_destroy %p", cond
);
1013 const pthread_cond_t cond_init
= PTHREAD_COND_INITIALIZER
;
1014 cond_is_init
= my_memcmp(cond
, &cond_init
, sizeof(*cond
)) == 0;
1019 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_DESTROY_PRE
,
1020 pthread_cond_t
*, cond
, unsigned long, cond_is_init
);
1022 CALL_FN_W_W(ret
, fn
, cond
);
1025 DO_PthAPIerror( "pthread_cond_destroy", ret
);
1028 if (TRACE_PTH_FNS
) {
1029 fprintf(stderr
, " codestr -> %d >>\n", ret
);
1034 #if defined(VGO_linux)
1035 PTH_FUNC(int, pthreadZucondZudestroyZAZa
, // pthread_cond_destroy@*
1036 pthread_cond_t
* cond
) {
1037 return pthread_cond_destroy_WRK(cond
);
1039 #elif defined(VGO_darwin)
1040 PTH_FUNC(int, pthreadZucondZudestroy
, // pthread_cond_destroy
1041 pthread_cond_t
* cond
) {
1042 return pthread_cond_destroy_WRK(cond
);
1045 # error "Unsupported OS"
1049 /*----------------------------------------------------------------*/
1050 /*--- pthread_barrier_t functions ---*/
1051 /*----------------------------------------------------------------*/
1053 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1055 /* Handled: pthread_barrier_init
1056 pthread_barrier_wait
1057 pthread_barrier_destroy
1059 Unhandled: pthread_barrierattr_destroy
1060 pthread_barrierattr_getpshared
1061 pthread_barrierattr_init
1062 pthread_barrierattr_setpshared
1063 -- are these important?
1066 //-----------------------------------------------------------
1067 // glibc: pthread_barrier_init
1068 // darwin: (doesn't appear to exist)
1069 PTH_FUNC(int, pthreadZubarrierZuinit
, // pthread_barrier_init
1070 pthread_barrier_t
* bar
,
1071 pthread_barrierattr_t
* attr
, unsigned long count
)
1075 VALGRIND_GET_ORIG_FN(fn
);
1077 if (TRACE_PTH_FNS
) {
1078 fprintf(stderr
, "<< pthread_barrier_init %p %p %lu",
1083 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE
,
1084 pthread_barrier_t
*, bar
,
1085 unsigned long, count
,
1086 unsigned long, 0/*!resizable*/);
1088 CALL_FN_W_WWW(ret
, fn
, bar
,attr
,count
);
1091 DO_PthAPIerror( "pthread_barrier_init", ret
);
1094 if (TRACE_PTH_FNS
) {
1095 fprintf(stderr
, " pthread_barrier_init -> %d >>\n", ret
);
1102 //-----------------------------------------------------------
1103 // glibc: pthread_barrier_wait
1104 // darwin: (doesn't appear to exist)
1105 PTH_FUNC(int, pthreadZubarrierZuwait
, // pthread_barrier_wait
1106 pthread_barrier_t
* bar
)
1110 VALGRIND_GET_ORIG_FN(fn
);
1112 if (TRACE_PTH_FNS
) {
1113 fprintf(stderr
, "<< pthread_barrier_wait %p", bar
);
1117 /* That this works correctly, and doesn't screw up when a thread
1118 leaving the barrier races round to the front and re-enters while
1119 other threads are still leaving it, is quite subtle. See
1120 comments in the handler for PTHREAD_BARRIER_WAIT_PRE in
1122 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE
,
1123 pthread_barrier_t
*,bar
);
1125 CALL_FN_W_W(ret
, fn
, bar
);
1127 if (ret
!= 0 && ret
!= PTHREAD_BARRIER_SERIAL_THREAD
) {
1128 DO_PthAPIerror( "pthread_barrier_wait", ret
);
1131 if (TRACE_PTH_FNS
) {
1132 fprintf(stderr
, " pthread_barrier_wait -> %d >>\n", ret
);
1139 //-----------------------------------------------------------
1140 // glibc: pthread_barrier_destroy
1141 // darwin: (doesn't appear to exist)
1142 PTH_FUNC(int, pthreadZubarrierZudestroy
, // pthread_barrier_destroy
1143 pthread_barrier_t
* bar
)
1147 VALGRIND_GET_ORIG_FN(fn
);
1149 if (TRACE_PTH_FNS
) {
1150 fprintf(stderr
, "<< pthread_barrier_destroy %p", bar
);
1154 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE
,
1155 pthread_barrier_t
*,bar
);
1157 CALL_FN_W_W(ret
, fn
, bar
);
1160 DO_PthAPIerror( "pthread_barrier_destroy", ret
);
1163 if (TRACE_PTH_FNS
) {
1164 fprintf(stderr
, " pthread_barrier_destroy -> %d >>\n", ret
);
1170 #endif // defined(HAVE_PTHREAD_BARRIER_INIT)
1173 /*----------------------------------------------------------------*/
1174 /*--- pthread_spinlock_t functions ---*/
1175 /*----------------------------------------------------------------*/
1177 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1178 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1180 /* Handled: pthread_spin_init pthread_spin_destroy
1181 pthread_spin_lock pthread_spin_trylock
1187 /* This is a nasty kludge, in that glibc "knows" that initialising a
1188 spin lock unlocks it, and pthread_spin_{init,unlock} are names for
1189 the same function. Hence we have to have a wrapper which does both
1190 things, without knowing which the user intended to happen. */
1192 //-----------------------------------------------------------
1193 // glibc: pthread_spin_init
1194 // glibc: pthread_spin_unlock
1195 // darwin: (doesn't appear to exist)
1196 __attribute__((noinline
))
1197 static int pthread_spin_init_or_unlock_WRK(pthread_spinlock_t
* lock
,
1201 VALGRIND_GET_ORIG_FN(fn
);
1202 if (TRACE_PTH_FNS
) {
1203 fprintf(stderr
, "<< pthread_spin_iORu %p", lock
); fflush(stderr
);
1206 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE
,
1207 pthread_spinlock_t
*, lock
);
1209 CALL_FN_W_WW(ret
, fn
, lock
,pshared
);
1211 if (ret
== 0 /*success*/) {
1212 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST
,
1213 pthread_spinlock_t
*,lock
);
1215 DO_PthAPIerror( "pthread_spinlock_{init,unlock}", ret
);
1218 if (TRACE_PTH_FNS
) {
1219 fprintf(stderr
, " :: spiniORu -> %d >>\n", ret
);
1223 #if defined(VGO_linux)
1224 PTH_FUNC(int, pthreadZuspinZuinit
, // pthread_spin_init
1225 pthread_spinlock_t
* lock
, int pshared
) {
1226 return pthread_spin_init_or_unlock_WRK(lock
, pshared
);
1228 PTH_FUNC(int, pthreadZuspinZuunlock
, // pthread_spin_unlock
1229 pthread_spinlock_t
* lock
) {
1230 /* this is never actually called */
1231 return pthread_spin_init_or_unlock_WRK(lock
, 0/*pshared*/);
1233 #elif defined(VGO_darwin)
1235 # error "Unsupported OS"
1239 //-----------------------------------------------------------
1240 // glibc: pthread_spin_destroy
1241 // darwin: (doesn't appear to exist)
1242 #if defined(VGO_linux)
1244 PTH_FUNC(int, pthreadZuspinZudestroy
, // pthread_spin_destroy
1245 pthread_spinlock_t
* lock
)
1249 VALGRIND_GET_ORIG_FN(fn
);
1250 if (TRACE_PTH_FNS
) {
1251 fprintf(stderr
, "<< pthread_spin_destroy %p", lock
);
1255 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_DESTROY_PRE
,
1256 pthread_spinlock_t
*,lock
);
1258 CALL_FN_W_W(ret
, fn
, lock
);
1261 DO_PthAPIerror( "pthread_spin_destroy", ret
);
1264 if (TRACE_PTH_FNS
) {
1265 fprintf(stderr
, " :: spindestroy -> %d >>\n", ret
);
1270 #elif defined(VGO_darwin)
1272 # error "Unsupported OS"
1276 //-----------------------------------------------------------
1277 // glibc: pthread_spin_lock
1278 // darwin: (doesn't appear to exist)
1279 #if defined(VGO_linux)
1281 PTH_FUNC(int, pthreadZuspinZulock
, // pthread_spin_lock
1282 pthread_spinlock_t
* lock
)
1286 VALGRIND_GET_ORIG_FN(fn
);
1287 if (TRACE_PTH_FNS
) {
1288 fprintf(stderr
, "<< pthread_spinlock %p", lock
);
1292 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE
,
1293 pthread_spinlock_t
*,lock
, long,0/*!isTryLock*/);
1295 CALL_FN_W_W(ret
, fn
, lock
);
1297 /* There's a hole here: libpthread now knows the lock is locked,
1298 but the tool doesn't, so some other thread could run and detect
1299 that the lock has been acquired by someone (this thread). Does
1300 this matter? Not sure, but I don't think so. */
1302 if (ret
== 0 /*success*/) {
1303 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST
,
1304 pthread_spinlock_t
*,lock
);
1306 DO_PthAPIerror( "pthread_spin_lock", ret
);
1309 if (TRACE_PTH_FNS
) {
1310 fprintf(stderr
, " :: spinlock -> %d >>\n", ret
);
1315 #elif defined(VGO_darwin)
1317 # error "Unsupported OS"
1321 //-----------------------------------------------------------
1322 // glibc: pthread_spin_trylock
1323 // darwin: (doesn't appear to exist)
1324 #if defined(VGO_linux)
1326 PTH_FUNC(int, pthreadZuspinZutrylock
, // pthread_spin_trylock
1327 pthread_spinlock_t
* lock
)
1331 VALGRIND_GET_ORIG_FN(fn
);
1332 if (TRACE_PTH_FNS
) {
1333 fprintf(stderr
, "<< pthread_spin_trylock %p", lock
);
1337 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE
,
1338 pthread_spinlock_t
*,lock
, long,1/*isTryLock*/);
1340 CALL_FN_W_W(ret
, fn
, lock
);
1342 /* There's a hole here: libpthread now knows the lock is locked,
1343 but the tool doesn't, so some other thread could run and detect
1344 that the lock has been acquired by someone (this thread). Does
1345 this matter? Not sure, but I don't think so. */
1347 if (ret
== 0 /*success*/) {
1348 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST
,
1349 pthread_spinlock_t
*,lock
);
1352 DO_PthAPIerror( "pthread_spin_trylock", ret
);
1355 if (TRACE_PTH_FNS
) {
1356 fprintf(stderr
, " :: spin_trylock -> %d >>\n", ret
);
1361 #elif defined(VGO_darwin)
1363 # error "Unsupported OS"
1366 #endif // defined(HAVE_PTHREAD_SPIN_LOCK)
1369 /*----------------------------------------------------------------*/
1370 /*--- pthread_rwlock_t functions ---*/
1371 /*----------------------------------------------------------------*/
1373 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1374 functions have to be conditionally compiled. */
1375 #if defined(HAVE_PTHREAD_RWLOCK_T)
1377 /* Handled: pthread_rwlock_init pthread_rwlock_destroy
1378 pthread_rwlock_rdlock
1379 pthread_rwlock_wrlock
1380 pthread_rwlock_unlock
1382 Unhandled: pthread_rwlock_timedrdlock
1383 pthread_rwlock_tryrdlock
1385 pthread_rwlock_timedwrlock
1386 pthread_rwlock_trywrlock
1389 //-----------------------------------------------------------
1390 // glibc: pthread_rwlock_init
1391 // darwin: pthread_rwlock_init
1392 // darwin: pthread_rwlock_init$UNIX2003
1393 __attribute__((noinline
))
1394 static int pthread_rwlock_init_WRK(pthread_rwlock_t
*rwl
,
1395 pthread_rwlockattr_t
* attr
)
1399 VALGRIND_GET_ORIG_FN(fn
);
1400 if (TRACE_PTH_FNS
) {
1401 fprintf(stderr
, "<< pthread_rwl_init %p", rwl
); fflush(stderr
);
1404 CALL_FN_W_WW(ret
, fn
, rwl
,attr
);
1406 if (ret
== 0 /*success*/) {
1407 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST
,
1408 pthread_rwlock_t
*,rwl
);
1410 DO_PthAPIerror( "pthread_rwlock_init", ret
);
1413 if (TRACE_PTH_FNS
) {
1414 fprintf(stderr
, " :: rwl_init -> %d >>\n", ret
);
1418 #if defined(VGO_linux)
1419 PTH_FUNC(int, pthreadZurwlockZuinit
, // pthread_rwlock_init
1420 pthread_rwlock_t
*rwl
,
1421 pthread_rwlockattr_t
* attr
) {
1422 return pthread_rwlock_init_WRK(rwl
, attr
);
1424 #elif defined(VGO_darwin)
1425 PTH_FUNC(int, pthreadZurwlockZuinitZa
, // pthread_rwlock_init*
1426 pthread_rwlock_t
*rwl
,
1427 pthread_rwlockattr_t
* attr
) {
1428 return pthread_rwlock_init_WRK(rwl
, attr
);
1431 # error "Unsupported OS"
1435 //-----------------------------------------------------------
1436 // glibc: pthread_rwlock_destroy
1437 // darwin: pthread_rwlock_destroy
1438 // darwin: pthread_rwlock_destroy$UNIX2003
1440 __attribute__((noinline
))
1441 static int pthread_rwlock_destroy_WRK(pthread_rwlock_t
* rwl
)
1445 VALGRIND_GET_ORIG_FN(fn
);
1446 if (TRACE_PTH_FNS
) {
1447 fprintf(stderr
, "<< pthread_rwl_destroy %p", rwl
); fflush(stderr
);
1450 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE
,
1451 pthread_rwlock_t
*,rwl
);
1453 CALL_FN_W_W(ret
, fn
, rwl
);
1456 DO_PthAPIerror( "pthread_rwlock_destroy", ret
);
1459 if (TRACE_PTH_FNS
) {
1460 fprintf(stderr
, " :: rwl_destroy -> %d >>\n", ret
);
1464 #if defined(VGO_linux)
1465 PTH_FUNC(int, pthreadZurwlockZudestroy
, // pthread_rwlock_destroy
1466 pthread_rwlock_t
*rwl
) {
1467 return pthread_rwlock_destroy_WRK(rwl
);
1469 #elif defined(VGO_darwin)
1470 PTH_FUNC(int, pthreadZurwlockZudestroyZa
, // pthread_rwlock_destroy*
1471 pthread_rwlock_t
*rwl
) {
1472 return pthread_rwlock_destroy_WRK(rwl
);
1475 # error "Unsupported OS"
1479 //-----------------------------------------------------------
1480 // glibc: pthread_rwlock_wrlock
1481 // darwin: pthread_rwlock_wrlock
1482 // darwin: pthread_rwlock_wrlock$UNIX2003
1484 __attribute__((noinline
))
1485 static int pthread_rwlock_wrlock_WRK(pthread_rwlock_t
* rwlock
)
1489 VALGRIND_GET_ORIG_FN(fn
);
1490 if (TRACE_PTH_FNS
) {
1491 fprintf(stderr
, "<< pthread_rwl_wlk %p", rwlock
); fflush(stderr
);
1494 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
1495 pthread_rwlock_t
*,rwlock
,
1496 long,1/*isW*/, long,0/*!isTryLock*/);
1498 CALL_FN_W_W(ret
, fn
, rwlock
);
1500 if (ret
== 0 /*success*/) {
1501 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
1502 pthread_rwlock_t
*,rwlock
, long,1/*isW*/);
1504 DO_PthAPIerror( "pthread_rwlock_wrlock", ret
);
1507 if (TRACE_PTH_FNS
) {
1508 fprintf(stderr
, " :: rwl_wlk -> %d >>\n", ret
);
1512 #if defined(VGO_linux)
1513 PTH_FUNC(int, pthreadZurwlockZuwrlock
, // pthread_rwlock_wrlock
1514 pthread_rwlock_t
* rwlock
) {
1515 return pthread_rwlock_wrlock_WRK(rwlock
);
1517 #elif defined(VGO_darwin)
1518 PTH_FUNC(int, pthreadZurwlockZuwrlockZa
, // pthread_rwlock_wrlock*
1519 pthread_rwlock_t
* rwlock
) {
1520 return pthread_rwlock_wrlock_WRK(rwlock
);
1523 # error "Unsupported OS"
1527 //-----------------------------------------------------------
1528 // glibc: pthread_rwlock_rdlock
1529 // darwin: pthread_rwlock_rdlock
1530 // darwin: pthread_rwlock_rdlock$UNIX2003
1532 __attribute__((noinline
))
1533 static int pthread_rwlock_rdlock_WRK(pthread_rwlock_t
* rwlock
)
1537 VALGRIND_GET_ORIG_FN(fn
);
1538 if (TRACE_PTH_FNS
) {
1539 fprintf(stderr
, "<< pthread_rwl_rlk %p", rwlock
); fflush(stderr
);
1542 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
1543 pthread_rwlock_t
*,rwlock
,
1544 long,0/*!isW*/, long,0/*!isTryLock*/);
1546 CALL_FN_W_W(ret
, fn
, rwlock
);
1548 if (ret
== 0 /*success*/) {
1549 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
1550 pthread_rwlock_t
*,rwlock
, long,0/*!isW*/);
1552 DO_PthAPIerror( "pthread_rwlock_rdlock", ret
);
1555 if (TRACE_PTH_FNS
) {
1556 fprintf(stderr
, " :: rwl_rlk -> %d >>\n", ret
);
1560 #if defined(VGO_linux)
1561 PTH_FUNC(int, pthreadZurwlockZurdlock
, // pthread_rwlock_rdlock
1562 pthread_rwlock_t
* rwlock
) {
1563 return pthread_rwlock_rdlock_WRK(rwlock
);
1565 #elif defined(VGO_darwin)
1566 PTH_FUNC(int, pthreadZurwlockZurdlockZa
, // pthread_rwlock_rdlock*
1567 pthread_rwlock_t
* rwlock
) {
1568 return pthread_rwlock_rdlock_WRK(rwlock
);
1571 # error "Unsupported OS"
1575 //-----------------------------------------------------------
1576 // glibc: pthread_rwlock_trywrlock
1577 // darwin: pthread_rwlock_trywrlock
1578 // darwin: pthread_rwlock_trywrlock$UNIX2003
1580 __attribute__((noinline
))
1581 static int pthread_rwlock_trywrlock_WRK(pthread_rwlock_t
* rwlock
)
1585 VALGRIND_GET_ORIG_FN(fn
);
1586 if (TRACE_PTH_FNS
) {
1587 fprintf(stderr
, "<< pthread_rwl_trywlk %p", rwlock
); fflush(stderr
);
1590 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
1591 pthread_rwlock_t
*,rwlock
,
1592 long,1/*isW*/, long,1/*isTryLock*/);
1594 CALL_FN_W_W(ret
, fn
, rwlock
);
1596 /* There's a hole here: libpthread now knows the lock is locked,
1597 but the tool doesn't, so some other thread could run and detect
1598 that the lock has been acquired by someone (this thread). Does
1599 this matter? Not sure, but I don't think so. */
1601 if (ret
== 0 /*success*/) {
1602 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
1603 pthread_rwlock_t
*,rwlock
, long,1/*isW*/);
1606 DO_PthAPIerror( "pthread_rwlock_trywrlock", ret
);
1609 if (TRACE_PTH_FNS
) {
1610 fprintf(stderr
, " :: rwl_trywlk -> %d >>\n", ret
);
1614 #if defined(VGO_linux)
1615 PTH_FUNC(int, pthreadZurwlockZutrywrlock
, // pthread_rwlock_trywrlock
1616 pthread_rwlock_t
* rwlock
) {
1617 return pthread_rwlock_trywrlock_WRK(rwlock
);
1619 #elif defined(VGO_darwin)
1620 PTH_FUNC(int, pthreadZurwlockZutrywrlockZa
, // pthread_rwlock_trywrlock*
1621 pthread_rwlock_t
* rwlock
) {
1622 return pthread_rwlock_trywrlock_WRK(rwlock
);
1625 # error "Unsupported OS"
1629 //-----------------------------------------------------------
1630 // glibc: pthread_rwlock_tryrdlock
1631 // darwin: pthread_rwlock_trywrlock
1632 // darwin: pthread_rwlock_trywrlock$UNIX2003
1634 __attribute__((noinline
))
1635 static int pthread_rwlock_tryrdlock_WRK(pthread_rwlock_t
* rwlock
)
1639 VALGRIND_GET_ORIG_FN(fn
);
1640 if (TRACE_PTH_FNS
) {
1641 fprintf(stderr
, "<< pthread_rwl_tryrlk %p", rwlock
); fflush(stderr
);
1644 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
1645 pthread_rwlock_t
*,rwlock
,
1646 long,0/*!isW*/, long,1/*isTryLock*/);
1648 CALL_FN_W_W(ret
, fn
, rwlock
);
1650 /* There's a hole here: libpthread now knows the lock is locked,
1651 but the tool doesn't, so some other thread could run and detect
1652 that the lock has been acquired by someone (this thread). Does
1653 this matter? Not sure, but I don't think so. */
1655 if (ret
== 0 /*success*/) {
1656 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
1657 pthread_rwlock_t
*,rwlock
, long,0/*!isW*/);
1660 DO_PthAPIerror( "pthread_rwlock_tryrdlock", ret
);
1663 if (TRACE_PTH_FNS
) {
1664 fprintf(stderr
, " :: rwl_tryrlk -> %d >>\n", ret
);
1668 #if defined(VGO_linux)
1669 PTH_FUNC(int, pthreadZurwlockZutryrdlock
, // pthread_rwlock_tryrdlock
1670 pthread_rwlock_t
* rwlock
) {
1671 return pthread_rwlock_tryrdlock_WRK(rwlock
);
1673 #elif defined(VGO_darwin)
1674 PTH_FUNC(int, pthreadZurwlockZutryrdlockZa
, // pthread_rwlock_tryrdlock*
1675 pthread_rwlock_t
* rwlock
) {
1676 return pthread_rwlock_tryrdlock_WRK(rwlock
);
1679 # error "Unsupported OS"
1683 //-----------------------------------------------------------
1684 // glibc: pthread_rwlock_unlock
1685 // darwin: pthread_rwlock_unlock
1686 // darwin: pthread_rwlock_unlock$UNIX2003
1687 __attribute__((noinline
))
1688 static int pthread_rwlock_unlock_WRK(pthread_rwlock_t
* rwlock
)
1692 VALGRIND_GET_ORIG_FN(fn
);
1693 if (TRACE_PTH_FNS
) {
1694 fprintf(stderr
, "<< pthread_rwl_unlk %p", rwlock
); fflush(stderr
);
1697 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE
,
1698 pthread_rwlock_t
*,rwlock
);
1700 CALL_FN_W_W(ret
, fn
, rwlock
);
1702 if (ret
== 0 /*success*/) {
1703 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST
,
1704 pthread_rwlock_t
*,rwlock
);
1706 DO_PthAPIerror( "pthread_rwlock_unlock", ret
);
1709 if (TRACE_PTH_FNS
) {
1710 fprintf(stderr
, " :: rwl_unlk -> %d >>\n", ret
);
1714 #if defined(VGO_linux)
1715 PTH_FUNC(int, pthreadZurwlockZuunlock
, // pthread_rwlock_unlock
1716 pthread_rwlock_t
* rwlock
) {
1717 return pthread_rwlock_unlock_WRK(rwlock
);
1719 #elif defined(VGO_darwin)
1720 PTH_FUNC(int, pthreadZurwlockZuunlockZa
, // pthread_rwlock_unlock*
1721 pthread_rwlock_t
* rwlock
) {
1722 return pthread_rwlock_unlock_WRK(rwlock
);
1725 # error "Unsupported OS"
1728 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
1731 /*----------------------------------------------------------------*/
1732 /*--- POSIX semaphores ---*/
1733 /*----------------------------------------------------------------*/
1735 #include <semaphore.h>
1736 #include <fcntl.h> /* O_CREAT */
1738 #define TRACE_SEM_FNS 0
1741 int sem_init(sem_t *sem, int pshared, unsigned value);
1742 int sem_destroy(sem_t *sem);
1743 int sem_wait(sem_t *sem);
1744 int sem_post(sem_t *sem);
1745 sem_t* sem_open(const char *name, int oflag,
1746 ... [mode_t mode, unsigned value]);
1747 [complete with its idiotic semantics]
1748 int sem_close(sem_t* sem);
1751 int sem_trywait(sem_t *sem);
1752 int sem_timedwait(sem_t *restrict sem,
1753 const struct timespec *restrict abs_timeout);
1756 //-----------------------------------------------------------
1757 // glibc: sem_init@@GLIBC_2.2.5
1758 // glibc: sem_init@@GLIBC_2.1
1759 // glibc: sem_init@GLIBC_2.0
1762 __attribute__((noinline
))
1763 static int sem_init_WRK(sem_t
* sem
, int pshared
, unsigned long value
)
1767 VALGRIND_GET_ORIG_FN(fn
);
1769 if (TRACE_SEM_FNS
) {
1770 fprintf(stderr
, "<< sem_init(%p,%d,%lu) ", sem
,pshared
,value
);
1774 CALL_FN_W_WWW(ret
, fn
, sem
,pshared
,value
);
1777 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST
,
1778 sem_t
*, sem
, unsigned long, value
);
1780 DO_PthAPIerror( "sem_init", errno
);
1783 if (TRACE_SEM_FNS
) {
1784 fprintf(stderr
, " sem_init -> %d >>\n", ret
);
1790 #if defined(VGO_linux)
1791 PTH_FUNC(int, semZuinitZAZa
, // sem_init@*
1792 sem_t
* sem
, int pshared
, unsigned long value
) {
1793 return sem_init_WRK(sem
, pshared
, value
);
1795 #elif defined(VGO_darwin)
1796 PTH_FUNC(int, semZuinit
, // sem_init
1797 sem_t
* sem
, int pshared
, unsigned long value
) {
1798 return sem_init_WRK(sem
, pshared
, value
);
1801 # error "Unsupported OS"
1805 //-----------------------------------------------------------
1806 // glibc: sem_destroy@GLIBC_2.0
1807 // glibc: sem_destroy@@GLIBC_2.1
1808 // glibc: sem_destroy@@GLIBC_2.2.5
1809 // darwin: sem_destroy
1810 __attribute__((noinline
))
1811 static int sem_destroy_WRK(sem_t
* sem
)
1815 VALGRIND_GET_ORIG_FN(fn
);
1817 if (TRACE_SEM_FNS
) {
1818 fprintf(stderr
, "<< sem_destroy(%p) ", sem
);
1822 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE
, sem_t
*, sem
);
1824 CALL_FN_W_W(ret
, fn
, sem
);
1827 DO_PthAPIerror( "sem_destroy", errno
);
1830 if (TRACE_SEM_FNS
) {
1831 fprintf(stderr
, " sem_destroy -> %d >>\n", ret
);
1837 #if defined(VGO_linux)
1838 PTH_FUNC(int, semZudestroyZAZa
, // sem_destroy*
1840 return sem_destroy_WRK(sem
);
1842 #elif defined(VGO_darwin)
1843 PTH_FUNC(int, semZudestroy
, // sem_destroy
1845 return sem_destroy_WRK(sem
);
1848 # error "Unsupported OS"
1852 //-----------------------------------------------------------
1854 // glibc: sem_wait@GLIBC_2.0
1855 // glibc: sem_wait@@GLIBC_2.1
1857 // darwin: sem_wait$NOCANCEL$UNIX2003
1858 // darwin: sem_wait$UNIX2003
1860 /* wait: decrement semaphore - acquire lockage */
1861 __attribute__((noinline
))
1862 static int sem_wait_WRK(sem_t
* sem
)
1866 VALGRIND_GET_ORIG_FN(fn
);
1868 if (TRACE_SEM_FNS
) {
1869 fprintf(stderr
, "<< sem_wait(%p) ", sem
);
1873 CALL_FN_W_W(ret
, fn
, sem
);
1876 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST
, sem_t
*,sem
);
1878 DO_PthAPIerror( "sem_wait", errno
);
1881 if (TRACE_SEM_FNS
) {
1882 fprintf(stderr
, " sem_wait -> %d >>\n", ret
);
1888 #if defined(VGO_linux)
1889 PTH_FUNC(int, semZuwait
, sem_t
* sem
) { /* sem_wait */
1890 return sem_wait_WRK(sem
);
1892 PTH_FUNC(int, semZuwaitZAZa
, sem_t
* sem
) { /* sem_wait@* */
1893 return sem_wait_WRK(sem
);
1895 #elif defined(VGO_darwin)
1896 PTH_FUNC(int, semZuwait
, sem_t
* sem
) { /* sem_wait */
1897 return sem_wait_WRK(sem
);
1899 PTH_FUNC(int, semZuwaitZDZa
, sem_t
* sem
) { /* sem_wait$* */
1900 return sem_wait_WRK(sem
);
1903 # error "Unsupported OS"
1907 //-----------------------------------------------------------
1909 // glibc: sem_post@GLIBC_2.0
1910 // glibc: sem_post@@GLIBC_2.1
1913 /* post: increment semaphore - release lockage */
1914 __attribute__((noinline
))
1915 static int sem_post_WRK(sem_t
* sem
)
1920 VALGRIND_GET_ORIG_FN(fn
);
1922 if (TRACE_SEM_FNS
) {
1923 fprintf(stderr
, "<< sem_post(%p) ", sem
);
1927 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_PRE
, sem_t
*,sem
);
1929 CALL_FN_W_W(ret
, fn
, sem
);
1932 DO_PthAPIerror( "sem_post", errno
);
1935 if (TRACE_SEM_FNS
) {
1936 fprintf(stderr
, " sem_post -> %d >>\n", ret
);
1942 #if defined(VGO_linux)
1943 PTH_FUNC(int, semZupost
, sem_t
* sem
) { /* sem_post */
1944 return sem_post_WRK(sem
);
1946 PTH_FUNC(int, semZupostZAZa
, sem_t
* sem
) { /* sem_post@* */
1947 return sem_post_WRK(sem
);
1949 #elif defined(VGO_darwin)
1950 PTH_FUNC(int, semZupost
, sem_t
* sem
) { /* sem_post */
1951 return sem_post_WRK(sem
);
1954 # error "Unsupported OS"
1958 //-----------------------------------------------------------
1962 PTH_FUNC(sem_t
*, semZuopen
,
1963 const char* name
, long oflag
,
1964 long mode
, unsigned long value
)
1966 /* A copy of sem_init_WRK (more or less). Is this correct? */
1969 VALGRIND_GET_ORIG_FN(fn
);
1971 if (TRACE_SEM_FNS
) {
1972 fprintf(stderr
, "<< sem_open(\"%s\",%ld,%lx,%lu) ",
1973 name
,oflag
,mode
,value
);
1977 CALL_FN_W_WWWW(ret
, fn
, name
,oflag
,mode
,value
);
1979 if (ret
!= SEM_FAILED
&& (oflag
& O_CREAT
)) {
1980 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST
,
1981 sem_t
*, ret
, unsigned long, value
);
1983 if (ret
== SEM_FAILED
) {
1984 DO_PthAPIerror( "sem_open", errno
);
1987 if (TRACE_SEM_FNS
) {
1988 fprintf(stderr
, " sem_open -> %p >>\n", ret
);
1996 //-----------------------------------------------------------
1998 // darwin: sem_close
1999 PTH_FUNC(int, sem_close
, sem_t
* sem
)
2003 VALGRIND_GET_ORIG_FN(fn
);
2005 if (TRACE_SEM_FNS
) {
2006 fprintf(stderr
, "<< sem_close(%p) ", sem
);
2010 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE
, sem_t
*, sem
);
2012 CALL_FN_W_W(ret
, fn
, sem
);
2015 DO_PthAPIerror( "sem_close", errno
);
2018 if (TRACE_SEM_FNS
) {
2019 fprintf(stderr
, " close -> %d >>\n", ret
);
2027 /*----------------------------------------------------------------*/
2028 /*--- Qt 4 threading functions (w/ GNU name mangling) ---*/
2029 /*----------------------------------------------------------------*/
2035 QMutex::tryLock(int)
2037 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC1ENS_13RecursionModeE
2038 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC2ENS_13RecursionModeE
2039 QMutex::~QMutex() _ZN6QMutexD1Ev
2040 QMutex::~QMutex() _ZN6QMutexD2Ev
2043 QReadWriteLock::lockForRead()
2044 QReadWriteLock::lockForWrite()
2045 QReadWriteLock::unlock()
2046 QReadWriteLock::tryLockForRead(int)
2047 QReadWriteLock::tryLockForRead()
2048 QReadWriteLock::tryLockForWrite(int)
2049 QReadWriteLock::tryLockForWrite()
2051 QWaitCondition::wait(QMutex*, unsigned long)
2052 QWaitCondition::wakeAll()
2053 QWaitCondition::wakeOne()
2057 /* More comments, 19 Nov 08, based on assessment of qt-4.5.0TP1,
2060 It's apparently only necessary to intercept QMutex, since that is
2061 not implemented using pthread_mutex_t; instead Qt4 has its own
2062 implementation based on atomics (to check the non-contended case)
2063 and pthread_cond_wait (to wait in the contended case).
2065 QReadWriteLock is built on top of QMutex, counters, and a wait
2066 queue. So we don't need to handle it specially once QMutex
2067 handling is correct -- presumably the dependencies through QMutex
2068 are sufficient to avoid any false race reports. On the other hand,
2069 it is an open question whether too many dependencies are observed
2070 -- in which case we may miss races (false negatives). I suspect
2071 this is likely to be the case, unfortunately.
2073 QWaitCondition is built on pthread_cond_t, pthread_mutex_t, QMutex
2074 and QReadWriteLock. Same compositional-correctness justificiation
2075 and limitations as fro QReadWriteLock.
2077 Ditto QSemaphore (from cursory examination).
2079 Does it matter that only QMutex is handled directly? Open
2080 question. From testing with drd/tests/qt4_* and with KDE4 apps, it
2081 appears that no false errors are reported; however it is not clear
2082 if this is causing false negatives.
2084 Another problem with Qt4 is thread exiting. Threads are created
2085 with pthread_create (fine); but they detach and simply exit when
2086 done. There is no use of pthread_join, and the provided
2087 wait-for-a-thread-to-exit mechanism (QThread::wait, I believe)
2088 relies on a system of mutexes and flags. I suspect this also
2089 causes too many dependencies to appear. Consequently H sometimes
2090 fails to detect races at exit in some very short-lived racy
2091 programs, because it appears that a thread can exit _and_ have an
2092 observed dependency edge back to the main thread (presumably)
2093 before the main thread reaps the child (that is, calls
2096 This theory is supported by the observation that if all threads are
2097 made to wait at a pthread_barrier_t immediately before they exit,
2098 then H's detection of races in such programs becomes reliable;
2099 without the barrier, it is varies from run to run, depending
2100 (according to investigation) on whether aforementioned
2101 exit-before-reaping behaviour happens or not.
2103 Finally, why is it necessary to intercept the QMutex constructors
2104 and destructors? The constructors are intercepted only as a matter
2105 of convenience, so H can print accurate "first observed at"
2106 clauses. However, it is actually necessary to intercept the
2107 destructors (as it is with pthread_mutex_destroy) in order that
2108 locks get removed from LAOG when they are destroyed.
2111 // soname is libQtCore.so.4 ; match against libQtCore.so*
2112 #define QT4_FUNC(ret_ty, f, args...) \
2113 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args); \
2114 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args)
2116 // soname is libQt5Core.so.4 ; match against libQt5Core.so*
2117 #define QT5_FUNC(ret_ty, f, args...) \
2118 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args); \
2119 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args)
2121 //-----------------------------------------------------------
2123 __attribute__((noinline
))
2124 static void QMutex_lock_WRK(void* self
)
2127 VALGRIND_GET_ORIG_FN(fn
);
2128 if (TRACE_QT4_FNS
) {
2129 fprintf(stderr
, "<< QMutex::lock %p", self
); fflush(stderr
);
2132 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
2133 void*,self
, long,0/*!isTryLock*/);
2135 CALL_FN_v_W(fn
, self
);
2137 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
2140 if (TRACE_QT4_FNS
) {
2141 fprintf(stderr
, " :: Q::lock done >>\n");
2145 QT4_FUNC(void, _ZN6QMutex4lockEv
, void* self
) {
2146 QMutex_lock_WRK(self
);
2148 QT5_FUNC(void, _ZN6QMutex4lockEv
, void* self
) {
2149 QMutex_lock_WRK(self
);
2152 //-----------------------------------------------------------
2154 __attribute__((noinline
))
2155 static void QMutex_unlock_WRK(void* self
)
2158 VALGRIND_GET_ORIG_FN(fn
);
2160 if (TRACE_QT4_FNS
) {
2161 fprintf(stderr
, "<< QMutex::unlock %p", self
); fflush(stderr
);
2164 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE
,
2167 CALL_FN_v_W(fn
, self
);
2169 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST
,
2172 if (TRACE_QT4_FNS
) {
2173 fprintf(stderr
, " Q::unlock done >>\n");
2177 QT4_FUNC(void, _ZN6QMutex6unlockEv
, void* self
) {
2178 QMutex_unlock_WRK(self
);
2180 QT5_FUNC(void, _ZN6QMutex6unlockEv
, void* self
) {
2181 QMutex_unlock_WRK(self
);
2184 //-----------------------------------------------------------
2185 // bool QMutex::tryLock()
2186 // using 'long' to mimic C++ 'bool'
2187 __attribute__((noinline
))
2188 static long QMutex_tryLock_WRK(void* self
)
2192 VALGRIND_GET_ORIG_FN(fn
);
2193 if (TRACE_QT4_FNS
) {
2194 fprintf(stderr
, "<< QMutex::tryLock %p", self
); fflush(stderr
);
2197 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
2198 void*,self
, long,1/*isTryLock*/);
2200 CALL_FN_W_W(ret
, fn
, self
);
2202 // assumes that only the low 8 bits of the 'bool' are significant
2204 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
2208 if (TRACE_QT4_FNS
) {
2209 fprintf(stderr
, " :: Q::tryLock -> %lu >>\n", ret
);
2215 QT4_FUNC(long, _ZN6QMutex7tryLockEv
, void* self
) {
2216 return QMutex_tryLock_WRK(self
);
2218 QT5_FUNC(long, _ZN6QMutex7tryLockEv
, void* self
) {
2219 return QMutex_tryLock_WRK(self
);
2222 //-----------------------------------------------------------
2223 // bool QMutex::tryLock(int)
2224 // using 'long' to mimic C++ 'bool'
2225 __attribute__((noinline
))
2226 static long QMutex_tryLock_int_WRK(void* self
, long arg2
)
2230 VALGRIND_GET_ORIG_FN(fn
);
2231 if (TRACE_QT4_FNS
) {
2232 fprintf(stderr
, "<< QMutex::tryLock(int) %p %d", self
, (int)arg2
);
2236 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
2237 void*,self
, long,1/*isTryLock*/);
2239 CALL_FN_W_WW(ret
, fn
, self
,arg2
);
2241 // assumes that only the low 8 bits of the 'bool' are significant
2243 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
2247 if (TRACE_QT4_FNS
) {
2248 fprintf(stderr
, " :: Q::tryLock(int) -> %lu >>\n", ret
);
2254 QT4_FUNC(long, _ZN6QMutex7tryLockEi
, void* self
, long arg2
) {
2255 return QMutex_tryLock_int_WRK(self
, arg2
);
2257 QT5_FUNC(long, _ZN6QMutex7tryLockEi
, void* self
, long arg2
) {
2258 return QMutex_tryLock_int_WRK(self
, arg2
);
2261 //-----------------------------------------------------------
2262 // It's not really very clear what the args are here. But from
2263 // a bit of dataflow analysis of the generated machine code of
2264 // the original function, it appears this takes two args, and
2265 // returns nothing. Nevertheless preserve return value just in
2266 // case. A bit of debug printing indicates that the first arg
2267 // is that of the mutex and the second is either zero or one,
2268 // probably being the recursion mode, therefore.
2269 // QMutex::QMutex(QMutex::RecursionMode) ("C1ENS" variant)
2270 __attribute__((noinline
))
2271 static void* QMutex_constructor_WRK(void* mutex
, long recmode
)
2275 VALGRIND_GET_ORIG_FN(fn
);
2276 CALL_FN_W_WW(ret
, fn
, mutex
, recmode
);
2277 // fprintf(stderr, "QMutex constructor 1: %p <- %p %p\n", ret, arg1, arg2);
2278 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST
,
2279 void*,mutex
, long,1/*mbRec*/);
2283 QT4_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE
, void* self
, long recmode
) {
2284 return QMutex_constructor_WRK(self
, recmode
);
2286 QT5_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE
, void* self
, long recmode
) {
2287 return QMutex_constructor_WRK(self
, recmode
);
2290 //-----------------------------------------------------------
2291 // QMutex::~QMutex() ("D1Ev" variant)
2292 __attribute__((noinline
))
2293 static void* QMutex_destructor_WRK(void* mutex
)
2297 VALGRIND_GET_ORIG_FN(fn
);
2298 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE
,
2300 CALL_FN_W_W(ret
, fn
, mutex
);
2304 QT4_FUNC(void*, _ZN6QMutexD1Ev
, void* self
) {
2305 return QMutex_destructor_WRK(self
);
2307 QT5_FUNC(void*, _ZN6QMutexD1Ev
, void* self
) {
2308 return QMutex_destructor_WRK(self
);
2311 //-----------------------------------------------------------
2312 // QMutex::QMutex(QMutex::RecursionMode) ("C2ENS" variant)
2313 QT4_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE
,
2319 /* Android's gcc behaves like it doesn't know that assert(0)
2320 never returns. Hence: */
2324 QT5_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE
, void* self
, long recmode
)
2331 //-----------------------------------------------------------
2332 // QMutex::~QMutex() ("D2Ev" variant)
2333 QT4_FUNC(void*, _ZN6QMutexD2Ev
, void* mutex
)
2336 /* Android's gcc behaves like it doesn't know that assert(0)
2337 never returns. Hence: */
2341 QT5_FUNC(void*, _ZN6QMutexD2Ev
, void* self
)
2348 // QReadWriteLock is not intercepted directly. See comments
2351 //// QReadWriteLock::lockForRead()
2352 //// _ZN14QReadWriteLock11lockForReadEv == QReadWriteLock::lockForRead()
2353 //QT4_FUNC(void, ZuZZN14QReadWriteLock11lockForReadEv,
2354 // // _ZN14QReadWriteLock11lockForReadEv
2358 // VALGRIND_GET_ORIG_FN(fn);
2359 // if (TRACE_QT4_FNS) {
2360 // fprintf(stderr, "<< QReadWriteLock::lockForRead %p", self);
2364 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2366 // long,0/*!isW*/, long,0/*!isTryLock*/);
2368 // CALL_FN_v_W(fn, self);
2370 // DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2371 // void*,self, long,0/*!isW*/);
2373 // if (TRACE_QT4_FNS) {
2374 // fprintf(stderr, " :: Q::lockForRead :: done >>\n");
2378 //// QReadWriteLock::lockForWrite()
2379 //// _ZN14QReadWriteLock12lockForWriteEv == QReadWriteLock::lockForWrite()
2380 //QT4_FUNC(void, ZuZZN14QReadWriteLock12lockForWriteEv,
2381 // // _ZN14QReadWriteLock12lockForWriteEv
2385 // VALGRIND_GET_ORIG_FN(fn);
2386 // if (TRACE_QT4_FNS) {
2387 // fprintf(stderr, "<< QReadWriteLock::lockForWrite %p", self);
2391 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2393 // long,1/*isW*/, long,0/*!isTryLock*/);
2395 // CALL_FN_v_W(fn, self);
2397 // DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2398 // void*,self, long,1/*isW*/);
2400 // if (TRACE_QT4_FNS) {
2401 // fprintf(stderr, " :: Q::lockForWrite :: done >>\n");
2405 //// QReadWriteLock::unlock()
2406 //// _ZN14QReadWriteLock6unlockEv == QReadWriteLock::unlock()
2407 //QT4_FUNC(void, ZuZZN14QReadWriteLock6unlockEv,
2408 // // _ZN14QReadWriteLock6unlockEv
2412 // VALGRIND_GET_ORIG_FN(fn);
2413 // if (TRACE_QT4_FNS) {
2414 // fprintf(stderr, "<< QReadWriteLock::unlock %p", self);
2418 // DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
2421 // CALL_FN_v_W(fn, self);
2423 // DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
2426 // if (TRACE_QT4_FNS) {
2427 // fprintf(stderr, " :: Q::unlock :: done >>\n");
2432 /*----------------------------------------------------------------*/
2433 /*--- Replacements for basic string functions, that don't ---*/
2434 /*--- overrun the input arrays. ---*/
2435 /*----------------------------------------------------------------*/
2437 #include "../shared/vg_replace_strmem.c"
2439 /*--------------------------------------------------------------------*/
2440 /*--- end hg_intercepts.c ---*/
2441 /*--------------------------------------------------------------------*/