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-2017 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"
62 #if defined(VGO_solaris)
63 /* See porting comments in drd/drd_pthread_intercepts.c
64 However when a POSIX threads API function (for example pthread_cond_init)
65 is built upon the Solaris one (cond_init), intercept only the bottom one.
66 Helgrind does not contain generic synchronization nesting like DRD
67 and double intercept confuses it. */
70 #endif /* VGO_solaris */
73 #define TRACE_PTH_FNS 0
74 #define TRACE_QT4_FNS 0
75 #define TRACE_GNAT_FNS 0
78 /*----------------------------------------------------------------*/
80 /*----------------------------------------------------------------*/
82 #if defined(VGO_solaris)
83 /* On Solaris, libpthread is just a filter library on top of libc.
84 * Threading and synchronization functions in runtime linker are not
87 #define PTH_FUNC(ret_ty, f, args...) \
88 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)(args); \
89 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)(args)
91 /* pthread_t is typedef'd to 'unsigned int' but in DO_CREQ_* macros
92 sizeof(Word) is expected. */
93 #define CREQ_PTHREAD_T Word
96 #define PTH_FUNC(ret_ty, f, args...) \
97 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args); \
98 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args)
99 #define CREQ_PTHREAD_T pthread_t
100 #define SEM_ERROR errno
101 #endif /* VGO_solaris */
103 // Do a client request. These are macros rather than a functions so
104 // as to avoid having an extra frame in stack traces.
106 // NB: these duplicate definitions in helgrind.h. But here, we
107 // can have better typing (Word etc) and assertions, whereas
108 // in helgrind.h we can't. Obviously it's important the two
109 // sets of definitions are kept in sync.
111 // nuke the previous definitions
117 #define DO_CREQ_v_W(_creqF, _ty1F,_arg1F) \
120 assert(sizeof(_ty1F) == sizeof(Word)); \
121 _arg1 = (Word)(_arg1F); \
122 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
126 #define DO_CREQ_v_WW(_creqF, _ty1F,_arg1F, _ty2F,_arg2F) \
129 assert(sizeof(_ty1F) == sizeof(Word)); \
130 assert(sizeof(_ty2F) == sizeof(Word)); \
131 _arg1 = (Word)(_arg1F); \
132 _arg2 = (Word)(_arg2F); \
133 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
134 _arg1,_arg2,0,0,0); \
137 #define DO_CREQ_W_WW(_resF, _creqF, _ty1F,_arg1F, \
140 Word _res, _arg1, _arg2; \
141 assert(sizeof(_ty1F) == sizeof(Word)); \
142 assert(sizeof(_ty2F) == sizeof(Word)); \
143 _arg1 = (Word)(_arg1F); \
144 _arg2 = (Word)(_arg2F); \
145 _res = VALGRIND_DO_CLIENT_REQUEST_EXPR(2, \
147 _arg1,_arg2,0,0,0); \
151 #define DO_CREQ_v_WWW(_creqF, _ty1F,_arg1F, \
152 _ty2F,_arg2F, _ty3F, _arg3F) \
154 Word _arg1, _arg2, _arg3; \
155 assert(sizeof(_ty1F) == sizeof(Word)); \
156 assert(sizeof(_ty2F) == sizeof(Word)); \
157 assert(sizeof(_ty3F) == sizeof(Word)); \
158 _arg1 = (Word)(_arg1F); \
159 _arg2 = (Word)(_arg2F); \
160 _arg3 = (Word)(_arg3F); \
161 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
162 _arg1,_arg2,_arg3,0,0); \
165 #define DO_CREQ_v_WWWW(_creqF, _ty1F,_arg1F, \
166 _ty2F, _arg2F, _ty3F, _arg3F, \
169 Word _arg1, _arg2, _arg3, _arg4; \
170 assert(sizeof(_ty1F) == sizeof(Word)); \
171 assert(sizeof(_ty2F) == sizeof(Word)); \
172 assert(sizeof(_ty3F) == sizeof(Word)); \
173 assert(sizeof(_ty4F) == sizeof(Word)); \
174 _arg1 = (Word)(_arg1F); \
175 _arg2 = (Word)(_arg2F); \
176 _arg3 = (Word)(_arg3F); \
177 _arg4 = (Word)(_arg4F); \
178 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
179 _arg1,_arg2,_arg3,_arg4,0); \
182 #define DO_PthAPIerror(_fnnameF, _errF) \
184 const char* _fnname = (_fnnameF); \
185 long _err = (long)(int)(_errF); \
186 const char* _errstr = lame_strerror(_err); \
187 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTH_API_ERROR, \
189 long,_err, char*,_errstr); \
193 /* Needed for older glibcs (2.3 and older, at least) who don't
194 otherwise "know" about pthread_rwlock_anything or about
195 PTHREAD_MUTEX_RECURSIVE (amongst things). */
196 #define _GNU_SOURCE 1
203 /* A standalone memcmp. */
204 __attribute__((noinline
))
205 static int my_memcmp ( const void* ptr1
, const void* ptr2
, size_t size
)
207 const unsigned char* uchar_ptr1
= (const unsigned char*) ptr1
;
208 const unsigned char* uchar_ptr2
= (const unsigned char*) ptr2
;
210 for (i
= 0; i
< size
; ++i
) {
211 if (uchar_ptr1
[i
] != uchar_ptr2
[i
])
212 return (uchar_ptr1
[i
] < uchar_ptr2
[i
]) ? -1 : 1;
217 /* A lame version of strerror which doesn't use the real libc
218 strerror_r, since using the latter just generates endless more
219 threading errors (glibc goes off and does tons of crap w.r.t.
221 static const HChar
* lame_strerror ( long err
)
224 case EPERM
: return "EPERM: Operation not permitted";
225 case ENOENT
: return "ENOENT: No such file or directory";
226 case ESRCH
: return "ESRCH: No such process";
227 case EINTR
: return "EINTR: Interrupted system call";
228 case EBADF
: return "EBADF: Bad file number";
229 case EAGAIN
: return "EAGAIN: Try again";
230 case ENOMEM
: return "ENOMEM: Out of memory";
231 case EACCES
: return "EACCES: Permission denied";
232 case EFAULT
: return "EFAULT: Bad address";
233 case EEXIST
: return "EEXIST: File exists";
234 case EINVAL
: return "EINVAL: Invalid argument";
235 case EMFILE
: return "EMFILE: Too many open files";
236 case ENOSYS
: return "ENOSYS: Function not implemented";
237 case EOVERFLOW
: return "EOVERFLOW: Value too large "
238 "for defined data type";
239 case EBUSY
: return "EBUSY: Device or resource busy";
240 case ETIMEDOUT
: return "ETIMEDOUT: Connection timed out";
241 case EDEADLK
: return "EDEADLK: Resource deadlock would occur";
242 case EOPNOTSUPP
: return "EOPNOTSUPP: Operation not supported on "
243 "transport endpoint"; /* honest, guv */
244 case ETIME
: return "ETIME: Timer expired";
245 default: return "hg_intercepts.c: lame_strerror(): "
246 "unhandled case -- please fix me!";
250 #if defined(VGO_solaris)
252 * Solaris provides higher throughput, parallelism and scalability than other
253 * operating systems, at the cost of more fine-grained locking activity.
254 * This means for example that when a thread is created under Linux, just one
255 * big lock in glibc is used for all thread setup. Solaris libc uses several
256 * fine-grained locks and the creator thread resumes its activities as soon
257 * as possible, leaving for example stack and TLS setup activities to the
260 * This situation confuses Helgrind as it assumes there is some false ordering
261 * in place between creator and created thread; and therefore many types of
262 * race conditions in the application would not be reported. To prevent such
263 * false ordering, command line option --ignore-thread-creation is set to
264 * 'yes' by default on Solaris. All activity (loads, stores, client requests)
265 * is therefore ignored during:
266 * - pthread_create() call in the creator thread [libc.so]
267 * - thread creation phase (stack and TLS setup) in the created thread [libc.so]
269 * As explained in the comments for _ti_bind_guard(), whenever the runtime
270 * linker has to perform any activity (such as resolving a symbol), it protects
271 * its data structures by calling into rt_bind_guard() which in turn invokes
272 * _ti_bind_guard() in libc. Pointers to _ti_bind_guard() and _ti_bind_clear()
273 * are passed from libc to runtime linker in _ld_libc() call during libc_init().
274 * All activity is also ignored during:
275 * - runtime dynamic linker work between rt_bind_guard() and rt_bind_clear()
278 * This also means that Helgrind does not report race conditions in libc (when
279 * --ignore-thread-creation=yes) and runtime linker itself (unconditionally)
280 * during these ignored sequences.
283 #include "pub_tool_libcassert.h"
284 #include "pub_tool_vki.h"
287 * Original function pointers for _ti_bind_guard() and _ti_bind_clear()
288 * from libc. They are intercepted in function wrapper of _ld_libc().
290 typedef int (*hg_rtld_guard_fn
)(int flags
);
291 static hg_rtld_guard_fn hg_rtld_bind_guard
= NULL
;
292 static hg_rtld_guard_fn hg_rtld_bind_clear
= NULL
;
294 static void hg_init(void) __attribute__((constructor
));
295 static void hg_init(void)
297 if ((hg_rtld_bind_guard
== NULL
) || (hg_rtld_bind_clear
== NULL
)) {
299 "Bind guard functions for the runtime linker (ld.so.1) were not intercepted.\n"
300 "This means the interface between libc and runtime linker changed\n"
301 "and Helgrind needs to be ported properly. Giving up.\n");
307 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
308 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
309 * and CI_BIND_CLEAR, to provide resilience against function renaming.
311 static int _ti_bind_guard_intercept_WRK(int flags
)
313 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_RTLD_BIND_GUARD
,
315 return hg_rtld_bind_guard(flags
);
318 static int _ti_bind_clear_intercept_WRK(int flags
)
320 int ret
= hg_rtld_bind_clear(flags
);
321 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_RTLD_BIND_CLEAR
,
327 * Wrapped _ld_libc() from the runtime linker ld.so.1.
329 void I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LD_SO_1
, ZuldZulibc
)(vki_Lc_interface
*ptr
);
330 void I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LD_SO_1
, ZuldZulibc
)(vki_Lc_interface
*ptr
)
335 VALGRIND_GET_ORIG_FN(fn
);
337 vki_Lc_interface
*funcs
= ptr
;
338 for (tag
= funcs
->ci_tag
; tag
!= 0; tag
= (++funcs
)->ci_tag
) {
340 case VKI_CI_BIND_GUARD
:
341 if (funcs
->vki_ci_un
.ci_func
!= _ti_bind_guard_intercept_WRK
) {
342 hg_rtld_bind_guard
= funcs
->vki_ci_un
.ci_func
;
343 funcs
->vki_ci_un
.ci_func
= _ti_bind_guard_intercept_WRK
;
346 case VKI_CI_BIND_CLEAR
:
347 if (funcs
->vki_ci_un
.ci_func
!= _ti_bind_clear_intercept_WRK
) {
348 hg_rtld_bind_clear
= funcs
->vki_ci_un
.ci_func
;
349 funcs
->vki_ci_un
.ci_func
= _ti_bind_clear_intercept_WRK
;
355 CALL_FN_v_W(fn
, ptr
);
357 #endif /* VGO_solaris */
360 /*----------------------------------------------------------------*/
361 /*--- pthread_create, pthread_join, pthread_exit ---*/
362 /*----------------------------------------------------------------*/
364 static void* mythread_wrapper ( void* xargsV
)
366 volatile Word
* xargs
= (volatile Word
*) xargsV
;
367 void*(*fn
)(void*) = (void*(*)(void*))xargs
[0];
368 void* arg
= (void*)xargs
[1];
369 pthread_t me
= pthread_self();
370 /* Tell the tool what my pthread_t is. */
371 DO_CREQ_v_W(_VG_USERREQ__HG_SET_MY_PTHREAD_T
, CREQ_PTHREAD_T
, me
);
372 /* allow the parent to proceed. We can't let it proceed until
373 we're ready because (1) we need to make sure it doesn't exit and
374 hence deallocate xargs[] while we still need it, and (2) we
375 don't want either parent nor child to proceed until the tool has
376 been notified of the child's pthread_t.
378 Note that parent and child access args[] without a lock,
379 effectively using args[2] as a spinlock in order to get the
380 parent to wait until the child passes this point. The parent
381 disables checking on xargs[] before creating the child and
382 re-enables it once the child goes past this point, so the user
383 never sees the race. The previous approach (suppressing the
384 resulting error) was flawed, because it could leave shadow
385 memory for args[] in a state in which subsequent use of it by
386 the parent would report further races. */
388 /* Now we can no longer safely use xargs[]. */
389 return (void*) fn( (void*)arg
);
392 //-----------------------------------------------------------
393 // glibc: pthread_create@GLIBC_2.0
394 // glibc: pthread_create@@GLIBC_2.1
395 // glibc: pthread_create@@GLIBC_2.2.5
396 // darwin: pthread_create
397 // darwin: pthread_create_suspended_np (trapped)
399 /* ensure this has its own frame, so as to make it more distinguishable
401 __attribute__((noinline
))
402 static int pthread_create_WRK(pthread_t
*thread
, const pthread_attr_t
*attr
,
403 void *(*start
) (void *), void *arg
)
407 volatile Word xargs
[3];
409 VALGRIND_GET_ORIG_FN(fn
);
411 fprintf(stderr
, "<< pthread_create wrapper"); fflush(stderr
);
413 xargs
[0] = (Word
)start
;
414 xargs
[1] = (Word
)arg
;
415 xargs
[2] = 1; /* serves as a spinlock -- sigh */
416 /* Disable checking on the spinlock and the two words used to
417 convey args to the child. Basically we need to make it appear
418 as if the child never accessed this area, since merely
419 suppressing the resulting races does not address the issue that
420 that piece of the parent's stack winds up in the "wrong" state
421 and therefore may give rise to mysterious races when the parent
422 comes to re-use this piece of stack in some other frame. */
423 VALGRIND_HG_DISABLE_CHECKING(&xargs
, sizeof(xargs
));
425 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_BEGIN
,
427 CALL_FN_W_WWWW(ret
, fn
, thread
,attr
,mythread_wrapper
,&xargs
[0]);
428 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_END
,
432 /* we have to wait for the child to notify the tool of its
433 pthread_t before continuing */
434 while (xargs
[2] != 0) {
435 /* Do nothing. We need to spin until the child writes to
436 xargs[2]. However, that can lead to starvation in the
437 child and very long delays (eg, tc19_shadowmem on
438 ppc64-linux Fedora Core 6). So yield the cpu if we can,
439 to let the child run at the earliest available
444 DO_PthAPIerror( "pthread_create", ret
);
447 /* Reenable checking on the area previously used to communicate
449 VALGRIND_HG_ENABLE_CHECKING(&xargs
, sizeof(xargs
));
452 fprintf(stderr
, " :: pth_create -> %d >>\n", ret
);
456 #if defined(VGO_linux)
457 PTH_FUNC(int, pthreadZucreateZAZa
, // pthread_create@*
458 pthread_t
*thread
, const pthread_attr_t
*attr
,
459 void *(*start
) (void *), void *arg
) {
460 return pthread_create_WRK(thread
, attr
, start
, arg
);
462 #elif defined(VGO_darwin)
463 PTH_FUNC(int, pthreadZucreate
, // pthread_create
464 pthread_t
*thread
, const pthread_attr_t
*attr
,
465 void *(*start
) (void *), void *arg
) {
466 return pthread_create_WRK(thread
, attr
, start
, arg
);
468 PTH_FUNC(int, pthreadZucreateZuZa
, // pthread_create_*
469 pthread_t
*thread
, const pthread_attr_t
*attr
,
470 void *(*start
) (void *), void *arg
) {
471 // trap anything else
474 #elif defined(VGO_solaris)
475 PTH_FUNC(int, pthreadZucreate
, // pthread_create
476 pthread_t
*thread
, const pthread_attr_t
*attr
,
477 void *(*start
) (void *), void *arg
) {
478 return pthread_create_WRK(thread
, attr
, start
, arg
);
481 # error "Unsupported OS"
484 #if defined(VGO_solaris)
485 /* Solaris also provides thr_create() in addition to pthread_create().
486 * Both pthread_create(3C) and thr_create(3C) are based on private
489 __attribute__((noinline
))
490 static int thr_create_WRK(void *stk
, size_t stksize
, void *(*start
)(void *),
491 void *arg
, long flags
, thread_t
*new_thread
)
495 volatile Word xargs
[3];
497 VALGRIND_GET_ORIG_FN(fn
);
499 fprintf(stderr
, "<< thr_create wrapper"); fflush(stderr
);
501 xargs
[0] = (Word
)start
;
502 xargs
[1] = (Word
)arg
;
503 xargs
[2] = 1; /* serves as a spinlock -- sigh */
504 /* See comments in pthread_create_WRK() */
505 VALGRIND_HG_DISABLE_CHECKING(&xargs
, sizeof(xargs
));
507 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_BEGIN
,
509 CALL_FN_W_6W(ret
, fn
, stk
, stksize
, mythread_wrapper
, start
, flags
,
511 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_END
,
515 while (xargs
[2] != 0) {
516 /* See comments in pthread_create_WRK(). */
520 DO_PthAPIerror("thr_create", ret
);
523 VALGRIND_HG_ENABLE_CHECKING(&xargs
, sizeof(xargs
));
526 fprintf(stderr
, " :: thr_create -> %d >>\n", ret
);
530 PTH_FUNC(int, thrZucreate
, // thr_create
531 void *stk
, size_t stksize
, void *(*start
)(void *),
532 void *arg
, long flags
, thread_t
*new_thread
) {
533 return thr_create_WRK(stk
, stksize
, start
, arg
, flags
, new_thread
);
535 #endif /* VGO_solaris */
538 //-----------------------------------------------------------
539 // glibc: pthread_join
540 // darwin: pthread_join
541 // darwin: pthread_join$NOCANCEL$UNIX2003
542 // darwin pthread_join$UNIX2003
543 __attribute__((noinline
))
544 static int pthread_join_WRK(pthread_t thread
, void** value_pointer
)
548 VALGRIND_GET_ORIG_FN(fn
);
550 fprintf(stderr
, "<< pthread_join wrapper"); fflush(stderr
);
553 CALL_FN_W_WW(ret
, fn
, thread
,value_pointer
);
555 /* At least with NPTL as the thread library, this is safe because
556 it is guaranteed (by NPTL) that the joiner will completely gone
557 before pthread_join (the original) returns. See email below.*/
558 if (ret
== 0 /*success*/) {
559 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST
, CREQ_PTHREAD_T
, thread
);
561 DO_PthAPIerror( "pthread_join", ret
);
565 fprintf(stderr
, " :: pth_join -> %d >>\n", ret
);
569 #if defined(VGO_linux)
570 PTH_FUNC(int, pthreadZujoin
, // pthread_join
571 pthread_t thread
, void** value_pointer
) {
572 return pthread_join_WRK(thread
, value_pointer
);
574 #elif defined(VGO_darwin)
575 PTH_FUNC(int, pthreadZujoinZa
, // pthread_join*
576 pthread_t thread
, void** value_pointer
) {
577 return pthread_join_WRK(thread
, value_pointer
);
579 #elif defined(VGO_solaris)
580 PTH_FUNC(int, pthreadZujoin
, // pthread_join
581 pthread_t thread
, void** value_pointer
) {
582 return pthread_join_WRK(thread
, value_pointer
);
585 # error "Unsupported OS"
589 /* Behaviour of pthread_join on NPTL:
592 I have a question re the NPTL pthread_join implementation.
594 Suppose I am the thread 'stayer'.
596 If I call pthread_join(quitter), is it guaranteed that the
597 thread 'quitter' has really exited before pthread_join returns?
599 IOW, is it guaranteed that 'quitter' will not execute any further
600 instructions after pthread_join returns?
602 I believe this is true based on the following analysis of
603 glibc-2.5 sources. However am not 100% sure and would appreciate
606 'quitter' will be running start_thread() in nptl/pthread_create.c
608 The last action of start_thread() is to exit via
609 __exit_thread_inline(0), which simply does sys_exit
610 (nptl/pthread_create.c:403)
612 'stayer' meanwhile is waiting for lll_wait_tid (pd->tid)
613 (call at nptl/pthread_join.c:89)
615 As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
616 lll_wait_tid will not return until kernel notifies via futex
617 wakeup that 'quitter' has terminated.
619 Hence pthread_join cannot return until 'quitter' really has
620 completely disappeared.
623 > As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
624 > lll_wait_tid will not return until kernel notifies via futex
625 > wakeup that 'quitter' has terminated.
626 That's the key. The kernel resets the TID field after the thread is
627 done. No way the joiner can return before the thread is gone.
630 #if defined(VGO_solaris)
631 /* Solaris also provides thr_join() in addition to pthread_join().
632 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
634 * :TODO: No functionality is currently provided for joinee == 0 and departed.
635 * This would require another client request, of course.
637 __attribute__((noinline
))
638 static int thr_join_WRK(thread_t joinee
, thread_t
*departed
, void **thread_return
)
642 VALGRIND_GET_ORIG_FN(fn
);
644 fprintf(stderr
, "<< thr_join wrapper"); fflush(stderr
);
647 CALL_FN_W_WWW(ret
, fn
, joinee
, departed
, thread_return
);
649 if (ret
== 0 /*success*/) {
650 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST
, CREQ_PTHREAD_T
, joinee
);
652 DO_PthAPIerror("thr_join", ret
);
656 fprintf(stderr
, " :: thr_join -> %d >>\n", ret
);
660 PTH_FUNC(int, thrZujoin
, // thr_join
661 thread_t joinee
, thread_t
*departed
, void **thread_return
) {
662 return thr_join_WRK(joinee
, departed
, thread_return
);
664 #endif /* VGO_solaris */
667 //-----------------------------------------------------------
668 // Ada gcc gnat runtime:
669 // The gnat gcc Ada runtime does not use pthread_join. Instead, it uses
670 // a combination of other pthread primitives to ensure a child thread
671 // is gone. This combination is somewhat functionally equivalent to a
673 // We wrap two hook procedures called by the gnat gcc Ada runtime
674 // that allows helgrind to understand the semantic of Ada task dependencies
676 // procedure Master_Hook
677 // (Dependent : Task_Id;
679 // Master_Level : Integer);
680 // where type Task_Id is access all Ada_Task_Control_Block;
681 // System.Tasking.Debug.Master_Hook is called by a task Dependent to
682 // indicate that its master is identified by master+master_level.
683 void I_WRAP_SONAME_FNNAME_ZU
685 system__tasking__debug__master_hook
)
686 (void *dependent
, void *master
, int master_level
);
687 void I_WRAP_SONAME_FNNAME_ZU
689 system__tasking__debug__master_hook
)
690 (void *dependent
, void *master
, int master_level
)
693 VALGRIND_GET_ORIG_FN(fn
);
694 if (TRACE_GNAT_FNS
) {
695 fprintf(stderr
, "<< GNAT master_hook wrapper "
696 "dependent %p master %p master_level %d\n",
697 dependent
, master
, master_level
); fflush(stderr
);
700 // We call the wrapped function, even if it is a null body.
701 CALL_FN_v_WWW(fn
, dependent
, master
, master_level
);
703 DO_CREQ_v_WWW(_VG_USERREQ__HG_GNAT_MASTER_HOOK
,
704 void*,dependent
, void*,master
,
705 Word
, (Word
)master_level
);
707 if (TRACE_GNAT_FNS
) {
708 fprintf(stderr
, " :: GNAT master_hook >>\n");
712 // System.Tasking.Debug.Master_Completed_Hook is called by a task to
713 // indicate that it has completed a master.
714 // procedure Master_Completed_Hook
715 // (Self_ID : Task_Id;
716 // Master_Level : Integer);
717 // where type Task_Id is access all Ada_Task_Control_Block;
718 // This indicates that all its Dependent tasks (that identified themselves
719 // with the Master_Hook call) are terminated. Helgrind can consider
720 // at this point that the equivalent of a 'pthread_join' has been done
721 // between self_id and all dependent tasks at master_level.
722 void I_WRAP_SONAME_FNNAME_ZU
724 system__tasking__debug__master_completed_hook
)
725 (void *self_id
, int master_level
);
726 void I_WRAP_SONAME_FNNAME_ZU
728 system__tasking__debug__master_completed_hook
)
729 (void *self_id
, int master_level
)
732 VALGRIND_GET_ORIG_FN(fn
);
733 if (TRACE_GNAT_FNS
) {
734 fprintf(stderr
, "<< GNAT master_completed_hook wrapper "
735 "self_id %p master_level %d\n",
736 self_id
, master_level
); fflush(stderr
);
739 // We call the wrapped function, even if it is a null body.
740 CALL_FN_v_WW(fn
, self_id
, master_level
);
742 DO_CREQ_v_WW(_VG_USERREQ__HG_GNAT_MASTER_COMPLETED_HOOK
,
743 void*,self_id
, Word
,(Word
)master_level
);
745 if (TRACE_GNAT_FNS
) {
746 fprintf(stderr
, " :: GNAT master_completed_hook >>\n");
750 /*----------------------------------------------------------------*/
751 /*--- pthread_mutex_t functions ---*/
752 /*----------------------------------------------------------------*/
754 /* Handled: pthread_mutex_init pthread_mutex_destroy
756 pthread_mutex_trylock pthread_mutex_timedlock
760 //-----------------------------------------------------------
761 #if !defined(VGO_solaris)
762 // glibc: pthread_mutex_init
763 // darwin: pthread_mutex_init
764 PTH_FUNC(int, pthreadZumutexZuinit
, // pthread_mutex_init
765 pthread_mutex_t
*mutex
,
766 pthread_mutexattr_t
* attr
)
771 VALGRIND_GET_ORIG_FN(fn
);
773 fprintf(stderr
, "<< pthread_mxinit %p", mutex
); fflush(stderr
);
779 zzz
= pthread_mutexattr_gettype(attr
, &ty
);
780 if (zzz
== 0 && ty
== PTHREAD_MUTEX_RECURSIVE
)
784 CALL_FN_W_WW(ret
, fn
, mutex
,attr
);
786 if (ret
== 0 /*success*/) {
787 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST
,
788 pthread_mutex_t
*,mutex
, long,mbRec
);
790 DO_PthAPIerror( "pthread_mutex_init", ret
);
794 fprintf(stderr
, " :: mxinit -> %d >>\n", ret
);
799 #else /* VGO_solaris */
801 // Solaris: mutex_init (pthread_mutex_init calls here)
802 PTH_FUNC(int, mutexZuinit
, // mutex_init
803 mutex_t
*mutex
, int type
, void *arg
)
808 VALGRIND_GET_ORIG_FN(fn
);
810 fprintf(stderr
, "<< mxinit %p", mutex
); fflush(stderr
);
813 mbRec
= ((type
& LOCK_RECURSIVE
) != 0) ? 1 : 0;
815 CALL_FN_W_WWW(ret
, fn
, mutex
, type
, arg
);
817 if (ret
== 0 /*success*/) {
818 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST
,
819 mutex_t
*, mutex
, long, mbRec
);
821 DO_PthAPIerror("mutex_init", ret
);
825 fprintf(stderr
, " :: mxinit -> %d >>\n", ret
);
829 #endif /* VGO_solaris */
832 //-----------------------------------------------------------
833 // glibc: pthread_mutex_destroy
834 // darwin: pthread_mutex_destroy
835 // Solaris: mutex_destroy (pthread_mutex_destroy is a weak alias)
836 __attribute__((noinline
))
837 static int mutex_destroy_WRK(pthread_mutex_t
*mutex
)
840 unsigned long mutex_is_init
;
843 VALGRIND_GET_ORIG_FN(fn
);
845 fprintf(stderr
, "<< pthread_mxdestroy %p", mutex
); fflush(stderr
);
849 static const pthread_mutex_t mutex_init
= PTHREAD_MUTEX_INITIALIZER
;
850 mutex_is_init
= my_memcmp(mutex
, &mutex_init
, sizeof(*mutex
)) == 0;
855 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE
,
856 pthread_mutex_t
*, mutex
, unsigned long, mutex_is_init
);
858 CALL_FN_W_W(ret
, fn
, mutex
);
861 DO_PthAPIerror( "pthread_mutex_destroy", ret
);
865 fprintf(stderr
, " :: mxdestroy -> %d >>\n", ret
);
870 #if defined(VGO_linux) || defined(VGO_darwin)
871 PTH_FUNC(int, pthreadZumutexZudestroy
, // pthread_mutex_destroy
872 pthread_mutex_t
*mutex
) {
873 return mutex_destroy_WRK(mutex
);
875 #elif defined(VGO_solaris)
876 PTH_FUNC(int, mutexZudestroy
, // mutex_destroy
877 pthread_mutex_t
*mutex
) {
878 return mutex_destroy_WRK(mutex
);
881 # error "Unsupported OS"
885 //-----------------------------------------------------------
886 // glibc: pthread_mutex_lock
887 // darwin: pthread_mutex_lock
888 // Solaris: mutex_lock (pthread_mutex_lock is a weak alias)
889 __attribute__((noinline
))
890 static int mutex_lock_WRK(pthread_mutex_t
*mutex
)
894 VALGRIND_GET_ORIG_FN(fn
);
896 fprintf(stderr
, "<< pthread_mxlock %p", mutex
); fflush(stderr
);
899 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
900 pthread_mutex_t
*,mutex
, long,0/*!isTryLock*/);
902 CALL_FN_W_W(ret
, fn
, mutex
);
904 /* There's a hole here: libpthread now knows the lock is locked,
905 but the tool doesn't, so some other thread could run and detect
906 that the lock has been acquired by someone (this thread). Does
907 this matter? Not sure, but I don't think so. */
909 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
910 pthread_mutex_t
*, mutex
, long, (ret
== 0) ? True
: False
);
913 DO_PthAPIerror( "pthread_mutex_lock", ret
);
917 fprintf(stderr
, " :: mxlock -> %d >>\n", ret
);
922 #if defined(VGO_linux) || defined(VGO_darwin)
923 PTH_FUNC(int, pthreadZumutexZulock
, // pthread_mutex_lock
924 pthread_mutex_t
*mutex
) {
925 return mutex_lock_WRK(mutex
);
927 #elif defined(VGO_solaris)
928 PTH_FUNC(int, mutexZulock
, // mutex_lock
929 pthread_mutex_t
*mutex
) {
930 return mutex_lock_WRK(mutex
);
933 # error "Unsupported OS"
936 #if defined(VGO_solaris)
937 /* Internal to libc. Mutex is usually initialized only implicitly,
938 * by zeroing mutex_t structure.
940 __attribute__((noinline
))
941 PTH_FUNC(void, lmutexZulock
, // lmutex_lock
945 VALGRIND_GET_ORIG_FN(fn
);
947 fprintf(stderr
, "<< lmxlock %p", mutex
); fflush(stderr
);
950 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
951 mutex_t
*, mutex
, long, 0 /*!isTryLock*/);
952 CALL_FN_v_W(fn
, mutex
);
953 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
954 mutex_t
*, mutex
, long, True
);
957 fprintf(stderr
, " :: lmxlock >>\n");
960 #endif /* VGO_solaris */
963 //-----------------------------------------------------------
964 // glibc: pthread_mutex_trylock
965 // darwin: pthread_mutex_trylock
966 // Solaris: mutex_trylock (pthread_mutex_trylock is a weak alias)
968 // pthread_mutex_trylock. The handling needed here is very similar
969 // to that for pthread_mutex_lock, except that we need to tell
970 // the pre-lock creq that this is a trylock-style operation, and
971 // therefore not to complain if the lock is nonrecursive and
972 // already locked by this thread -- because then it'll just fail
973 // immediately with EBUSY.
974 __attribute__((noinline
))
975 static int mutex_trylock_WRK(pthread_mutex_t
*mutex
)
979 VALGRIND_GET_ORIG_FN(fn
);
981 fprintf(stderr
, "<< pthread_mxtrylock %p", mutex
); fflush(stderr
);
984 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
985 pthread_mutex_t
*,mutex
, long,1/*isTryLock*/);
987 CALL_FN_W_W(ret
, fn
, mutex
);
989 /* There's a hole here: libpthread now knows the lock is locked,
990 but the tool doesn't, so some other thread could run and detect
991 that the lock has been acquired by someone (this thread). Does
992 this matter? Not sure, but I don't think so. */
994 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
995 pthread_mutex_t
*, mutex
, long, (ret
== 0) ? True
: False
);
999 DO_PthAPIerror( "pthread_mutex_trylock", ret
);
1002 if (TRACE_PTH_FNS
) {
1003 fprintf(stderr
, " :: mxtrylock -> %d >>\n", ret
);
1008 #if defined(VGO_linux) || defined(VGO_darwin)
1009 PTH_FUNC(int, pthreadZumutexZutrylock
, // pthread_mutex_trylock
1010 pthread_mutex_t
*mutex
) {
1011 return mutex_trylock_WRK(mutex
);
1013 #elif defined(VGO_solaris)
1014 PTH_FUNC(int, mutexZutrylock
, // mutex_trylock
1015 pthread_mutex_t
*mutex
) {
1016 return mutex_trylock_WRK(mutex
);
1019 # error "Unsupported OS"
1023 //-----------------------------------------------------------
1024 // glibc: pthread_mutex_timedlock
1025 // darwin: (doesn't appear to exist)
1026 // Solaris: pthread_mutex_timedlock
1028 // pthread_mutex_timedlock. Identical logic to pthread_mutex_trylock.
1029 __attribute__((noinline
))
1030 static int mutex_timedlock_WRK(pthread_mutex_t
*mutex
,
1035 VALGRIND_GET_ORIG_FN(fn
);
1036 if (TRACE_PTH_FNS
) {
1037 fprintf(stderr
, "<< pthread_mxtimedlock %p %p", mutex
, timeout
);
1041 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
1042 pthread_mutex_t
*,mutex
, long,1/*isTryLock-ish*/);
1044 CALL_FN_W_WW(ret
, fn
, mutex
,timeout
);
1046 /* There's a hole here: libpthread now knows the lock is locked,
1047 but the tool doesn't, so some other thread could run and detect
1048 that the lock has been acquired by someone (this thread). Does
1049 this matter? Not sure, but I don't think so. */
1051 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
1052 pthread_mutex_t
*, mutex
, long, (ret
== 0) ? True
: False
);
1055 if (ret
!= ETIMEDOUT
)
1056 DO_PthAPIerror( "pthread_mutex_timedlock", ret
);
1059 if (TRACE_PTH_FNS
) {
1060 fprintf(stderr
, " :: mxtimedlock -> %d >>\n", ret
);
1065 PTH_FUNC(int, pthreadZumutexZutimedlock
, // pthread_mutex_timedlock
1066 pthread_mutex_t
*mutex
,
1068 return mutex_timedlock_WRK(mutex
, timeout
);
1070 #if defined(VGO_solaris)
1071 PTH_FUNC(int, pthreadZumutexZureltimedlock
, // pthread_mutex_reltimedlock
1072 pthread_mutex_t
*mutex
,
1074 return mutex_timedlock_WRK(mutex
, timeout
);
1079 //-----------------------------------------------------------
1080 // glibc: pthread_mutex_unlock
1081 // darwin: pthread_mutex_unlock
1082 // Solaris: mutex_unlock (pthread_mutex_unlock is a weak alias)
1083 __attribute__((noinline
))
1084 static int mutex_unlock_WRK(pthread_mutex_t
*mutex
)
1088 VALGRIND_GET_ORIG_FN(fn
);
1090 if (TRACE_PTH_FNS
) {
1091 fprintf(stderr
, "<< pthread_mxunlk %p", mutex
); fflush(stderr
);
1094 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE
,
1095 pthread_mutex_t
*,mutex
);
1097 CALL_FN_W_W(ret
, fn
, mutex
);
1099 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST
,
1100 pthread_mutex_t
*,mutex
);
1103 DO_PthAPIerror( "pthread_mutex_unlock", ret
);
1106 if (TRACE_PTH_FNS
) {
1107 fprintf(stderr
, " mxunlk -> %d >>\n", ret
);
1112 #if defined(VGO_linux) || defined(VGO_darwin)
1113 PTH_FUNC(int, pthreadZumutexZuunlock
, // pthread_mutex_unlock
1114 pthread_mutex_t
*mutex
) {
1115 return mutex_unlock_WRK(mutex
);
1117 #elif defined(VGO_solaris)
1118 PTH_FUNC(int, mutexZuunlock
, // mutex_unlock
1119 pthread_mutex_t
*mutex
) {
1120 return mutex_unlock_WRK(mutex
);
1123 # error "Unsupported OS"
1127 #if defined(VGO_solaris)
1128 /* Internal to libc. */
1129 __attribute__((noinline
))
1130 PTH_FUNC(void, lmutexZuunlock
, // lmutex_unlock
1134 VALGRIND_GET_ORIG_FN(fn
);
1136 if (TRACE_PTH_FNS
) {
1137 fprintf(stderr
, "<< lmxunlk %p", mutex
); fflush(stderr
);
1140 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE
,
1142 CALL_FN_v_W(fn
, mutex
);
1143 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST
,
1146 if (TRACE_PTH_FNS
) {
1147 fprintf(stderr
, " lmxunlk >>\n");
1150 #endif /* VGO_solaris */
1153 /*----------------------------------------------------------------*/
1154 /*--- pthread_cond_t functions ---*/
1155 /*----------------------------------------------------------------*/
1157 /* Handled: pthread_cond_wait pthread_cond_timedwait
1158 pthread_cond_signal pthread_cond_broadcast
1160 pthread_cond_destroy
1163 //-----------------------------------------------------------
1164 // glibc: pthread_cond_wait@GLIBC_2.2.5
1165 // glibc: pthread_cond_wait@@GLIBC_2.3.2
1166 // darwin: pthread_cond_wait
1167 // darwin: pthread_cond_wait$NOCANCEL$UNIX2003
1168 // darwin: pthread_cond_wait$UNIX2003
1169 // Solaris: cond_wait (pthread_cond_wait is built atop of cond_wait)
1171 __attribute__((noinline
))
1172 static int pthread_cond_wait_WRK(pthread_cond_t
* cond
,
1173 pthread_mutex_t
* mutex
)
1177 unsigned long mutex_is_valid
;
1179 VALGRIND_GET_ORIG_FN(fn
);
1181 if (TRACE_PTH_FNS
) {
1182 fprintf(stderr
, "<< pthread_cond_wait %p %p", cond
, mutex
);
1186 /* Tell the tool a cond-wait is about to happen, so it can check
1187 for bogus argument values. In return it tells us whether it
1188 thinks the mutex is valid or not. */
1189 DO_CREQ_W_WW(mutex_is_valid
,
1190 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE
,
1191 pthread_cond_t
*,cond
, pthread_mutex_t
*,mutex
);
1192 assert(mutex_is_valid
== 1 || mutex_is_valid
== 0);
1194 /* Tell the tool we're about to drop the mutex. This reflects the
1195 fact that in a cond_wait, we show up holding the mutex, and the
1196 call atomically drops the mutex and waits for the cv to be
1198 if (mutex_is_valid
) {
1199 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE
,
1200 pthread_mutex_t
*,mutex
);
1203 CALL_FN_W_WW(ret
, fn
, cond
,mutex
);
1205 /* this conditional look stupid, but compare w/ same logic for
1206 pthread_cond_timedwait below */
1207 if (mutex_is_valid
) {
1208 /* and now we have the mutex again if (ret == 0) */
1209 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
1210 pthread_mutex_t
*, mutex
, long, (ret
== 0) ? True
: False
);
1213 DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST
,
1214 pthread_cond_t
*,cond
, pthread_mutex_t
*,mutex
, long,0,
1215 long, (ret
== 0 && mutex_is_valid
) ? True
: False
);
1218 DO_PthAPIerror( "pthread_cond_wait", ret
);
1221 if (TRACE_PTH_FNS
) {
1222 fprintf(stderr
, " cowait -> %d >>\n", ret
);
1227 #if defined(VGO_linux)
1228 PTH_FUNC(int, pthreadZucondZuwaitZAZa
, // pthread_cond_wait@*
1229 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
) {
1230 return pthread_cond_wait_WRK(cond
, mutex
);
1232 #elif defined(VGO_darwin)
1233 PTH_FUNC(int, pthreadZucondZuwaitZa
, // pthread_cond_wait*
1234 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
) {
1235 return pthread_cond_wait_WRK(cond
, mutex
);
1237 #elif defined(VGO_solaris)
1238 PTH_FUNC(int, condZuwait
, // cond_wait
1239 pthread_cond_t
*cond
, pthread_mutex_t
*mutex
) {
1240 return pthread_cond_wait_WRK(cond
, mutex
);
1243 # error "Unsupported OS"
1247 //-----------------------------------------------------------
1248 // glibc: pthread_cond_timedwait@@GLIBC_2.3.2
1249 // glibc: pthread_cond_timedwait@GLIBC_2.2.5
1250 // glibc: pthread_cond_timedwait@GLIBC_2.0
1251 // darwin: pthread_cond_timedwait
1252 // darwin: pthread_cond_timedwait$NOCANCEL$UNIX2003
1253 // darwin: pthread_cond_timedwait$UNIX2003
1254 // darwin: pthread_cond_timedwait_relative_np (trapped)
1255 // Solaris: cond_timedwait (pthread_cond_timedwait is built on cond_timedwait)
1256 // Solaris: cond_reltimedwait (pthread_cond_reltimedwait_np is built on this)
1258 __attribute__((noinline
))
1259 static int pthread_cond_timedwait_WRK(pthread_cond_t
* cond
,
1260 pthread_mutex_t
* mutex
,
1261 struct timespec
* abstime
,
1266 unsigned long mutex_is_valid
;
1267 Bool abstime_is_valid
;
1268 VALGRIND_GET_ORIG_FN(fn
);
1270 if (TRACE_PTH_FNS
) {
1271 fprintf(stderr
, "<< pthread_cond_timedwait %p %p %p",
1272 cond
, mutex
, abstime
);
1276 /* Tell the tool a cond-wait is about to happen, so it can check
1277 for bogus argument values. In return it tells us whether it
1278 thinks the mutex is valid or not. */
1279 DO_CREQ_W_WW(mutex_is_valid
,
1280 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE
,
1281 pthread_cond_t
*,cond
, pthread_mutex_t
*,mutex
);
1282 assert(mutex_is_valid
== 1 || mutex_is_valid
== 0);
1284 abstime_is_valid
= abstime
->tv_nsec
>= 0 && abstime
->tv_nsec
< 1000000000;
1286 /* Tell the tool we're about to drop the mutex. This reflects the
1287 fact that in a cond_wait, we show up holding the mutex, and the
1288 call atomically drops the mutex and waits for the cv to be
1290 if (mutex_is_valid
&& abstime_is_valid
) {
1291 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE
,
1292 pthread_mutex_t
*,mutex
);
1295 CALL_FN_W_WWW(ret
, fn
, cond
,mutex
,abstime
);
1297 if (mutex_is_valid
&& !abstime_is_valid
&& ret
!= EINVAL
) {
1298 DO_PthAPIerror("Bug in libpthread: pthread_cond_timedwait "
1299 "invalid abstime did not cause"
1303 if (mutex_is_valid
&& abstime_is_valid
) {
1304 /* and now we have the mutex again if (ret == 0 || ret == timeout) */
1305 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
1306 pthread_mutex_t
*, mutex
,
1307 long, (ret
== 0 || ret
== timeout_error
) ? True
: False
);
1310 DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST
,
1311 pthread_cond_t
*,cond
, pthread_mutex_t
*,mutex
,
1312 long,ret
== timeout_error
,
1313 long, (ret
== 0 || ret
== timeout_error
) && mutex_is_valid
1316 if (ret
!= 0 && ret
!= timeout_error
) {
1317 DO_PthAPIerror( "pthread_cond_timedwait", ret
);
1320 if (TRACE_PTH_FNS
) {
1321 fprintf(stderr
, " cotimedwait -> %d >>\n", ret
);
1326 #if defined(VGO_linux)
1327 PTH_FUNC(int, pthreadZucondZutimedwaitZAZa
, // pthread_cond_timedwait@*
1328 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
,
1329 struct timespec
* abstime
) {
1330 return pthread_cond_timedwait_WRK(cond
, mutex
, abstime
, ETIMEDOUT
);
1332 #elif defined(VGO_darwin)
1333 PTH_FUNC(int, pthreadZucondZutimedwait
, // pthread_cond_timedwait
1334 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
,
1335 struct timespec
* abstime
) {
1336 return pthread_cond_timedwait_WRK(cond
, mutex
, abstime
, ETIMEDOUT
);
1338 PTH_FUNC(int, pthreadZucondZutimedwaitZDZa
, // pthread_cond_timedwait$*
1339 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
,
1340 struct timespec
* abstime
) {
1341 return pthread_cond_timedwait_WRK(cond
, mutex
, abstime
, ETIMEDOUT
);
1343 PTH_FUNC(int, pthreadZucondZutimedwaitZuZa
, // pthread_cond_timedwait_*
1344 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
,
1345 struct timespec
* abstime
) {
1348 #elif defined(VGO_solaris)
1349 PTH_FUNC(int, condZutimedwait
, // cond_timedwait
1350 pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1351 struct timespec
*abstime
) {
1352 return pthread_cond_timedwait_WRK(cond
, mutex
, abstime
, ETIME
);
1354 PTH_FUNC(int, condZureltimedwait
, // cond_reltimedwait
1355 pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1356 struct timespec
*reltime
) {
1357 return pthread_cond_timedwait_WRK(cond
, mutex
, reltime
, ETIME
);
1360 # error "Unsupported OS"
1364 //-----------------------------------------------------------
1365 // glibc: pthread_cond_signal@GLIBC_2.0
1366 // glibc: pthread_cond_signal@GLIBC_2.2.5
1367 // glibc: pthread_cond_signal@@GLIBC_2.3.2
1368 // darwin: pthread_cond_signal
1369 // darwin: pthread_cond_signal_thread_np (don't intercept this)
1370 // Solaris: cond_signal (pthread_cond_signal is a weak alias)
1372 __attribute__((noinline
))
1373 static int pthread_cond_signal_WRK(pthread_cond_t
* cond
)
1377 VALGRIND_GET_ORIG_FN(fn
);
1379 if (TRACE_PTH_FNS
) {
1380 fprintf(stderr
, "<< pthread_cond_signal %p", cond
);
1384 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE
,
1385 pthread_cond_t
*,cond
);
1387 CALL_FN_W_W(ret
, fn
, cond
);
1389 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_POST
,
1390 pthread_cond_t
*,cond
);
1393 DO_PthAPIerror( "pthread_cond_signal", ret
);
1396 if (TRACE_PTH_FNS
) {
1397 fprintf(stderr
, " cosig -> %d >>\n", ret
);
1402 #if defined(VGO_linux)
1403 PTH_FUNC(int, pthreadZucondZusignalZAZa
, // pthread_cond_signal@*
1404 pthread_cond_t
* cond
) {
1405 return pthread_cond_signal_WRK(cond
);
1407 #elif defined(VGO_darwin)
1408 PTH_FUNC(int, pthreadZucondZusignal
, // pthread_cond_signal
1409 pthread_cond_t
* cond
) {
1410 return pthread_cond_signal_WRK(cond
);
1412 #elif defined(VGO_solaris)
1413 PTH_FUNC(int, condZusignal
, // cond_signal
1414 pthread_cond_t
*cond
) {
1415 return pthread_cond_signal_WRK(cond
);
1418 # error "Unsupported OS"
1422 //-----------------------------------------------------------
1423 // glibc: pthread_cond_broadcast@GLIBC_2.0
1424 // glibc: pthread_cond_broadcast@GLIBC_2.2.5
1425 // glibc: pthread_cond_broadcast@@GLIBC_2.3.2
1426 // darwin: pthread_cond_broadcast
1427 // Solaris: cond_broadcast (pthread_cond_broadcast is a weak alias)
1429 // Note, this is pretty much identical, from a dependency-graph
1430 // point of view, with cond_signal, so the code is duplicated.
1431 // Maybe it should be commoned up.
1433 __attribute__((noinline
))
1434 static int pthread_cond_broadcast_WRK(pthread_cond_t
* cond
)
1438 VALGRIND_GET_ORIG_FN(fn
);
1440 if (TRACE_PTH_FNS
) {
1441 fprintf(stderr
, "<< pthread_cond_broadcast %p", cond
);
1445 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE
,
1446 pthread_cond_t
*,cond
);
1448 CALL_FN_W_W(ret
, fn
, cond
);
1450 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_POST
,
1451 pthread_cond_t
*,cond
);
1454 DO_PthAPIerror( "pthread_cond_broadcast", ret
);
1457 if (TRACE_PTH_FNS
) {
1458 fprintf(stderr
, " cobro -> %d >>\n", ret
);
1463 #if defined(VGO_linux)
1464 PTH_FUNC(int, pthreadZucondZubroadcastZAZa
, // pthread_cond_broadcast@*
1465 pthread_cond_t
* cond
) {
1466 return pthread_cond_broadcast_WRK(cond
);
1468 #elif defined(VGO_darwin)
1469 PTH_FUNC(int, pthreadZucondZubroadcast
, // pthread_cond_broadcast
1470 pthread_cond_t
* cond
) {
1471 return pthread_cond_broadcast_WRK(cond
);
1473 #elif defined(VGO_solaris)
1474 PTH_FUNC(int, condZubroadcast
, // cond_broadcast
1475 pthread_cond_t
*cond
) {
1476 return pthread_cond_broadcast_WRK(cond
);
1479 # error "Unsupported OS"
1482 // glibc: pthread_cond_init@GLIBC_2.0
1483 // glibc: pthread_cond_init@GLIBC_2.2.5
1484 // glibc: pthread_cond_init@@GLIBC_2.3.2
1485 // darwin: pthread_cond_init
1486 // Solaris: cond_init (pthread_cond_init is built atop on this function)
1487 // Easy way out: Handling of attr could have been messier.
1488 // It turns out that pthread_cond_init under linux ignores
1489 // all information in cond_attr, so do we.
1491 #if !defined(VGO_solaris)
1492 __attribute__((noinline
))
1493 static int pthread_cond_init_WRK(pthread_cond_t
* cond
, pthread_condattr_t
*cond_attr
)
1497 VALGRIND_GET_ORIG_FN(fn
);
1499 if (TRACE_PTH_FNS
) {
1500 fprintf(stderr
, "<< pthread_cond_init %p", cond
);
1504 CALL_FN_W_WW(ret
, fn
, cond
, cond_attr
);
1507 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST
,
1508 pthread_cond_t
*,cond
, pthread_condattr_t
*, cond_attr
);
1510 DO_PthAPIerror( "pthread_cond_init", ret
);
1513 if (TRACE_PTH_FNS
) {
1514 fprintf(stderr
, " coinit -> %d >>\n", ret
);
1519 #if defined(VGO_linux)
1520 PTH_FUNC(int, pthreadZucondZuinitZAZa
, // pthread_cond_init@*
1521 pthread_cond_t
* cond
, pthread_condattr_t
* cond_attr
) {
1522 return pthread_cond_init_WRK(cond
, cond_attr
);
1524 #elif defined(VGO_darwin)
1525 PTH_FUNC(int, pthreadZucondZuinit
, // pthread_cond_init
1526 pthread_cond_t
* cond
, pthread_condattr_t
* cond_attr
) {
1527 return pthread_cond_init_WRK(cond
, cond_attr
);
1530 # error "Unsupported OS"
1533 #else /* VGO_solaris */
1534 __attribute__((noinline
))
1535 PTH_FUNC(int, condZuinit
, // cond_init
1536 cond_t
*cond
, int type
, void *arg
)
1540 VALGRIND_GET_ORIG_FN(fn
);
1542 if (TRACE_PTH_FNS
) {
1543 fprintf(stderr
, "<< cond_init %p", cond
); fflush(stderr
);
1546 CALL_FN_W_WWW(ret
, fn
, cond
, type
, arg
);
1549 /* Luckily evh__HG_PTHREAD_COND_INIT_POST() ignores cond_attr.
1550 See also comment for pthread_cond_init_WRK(). */
1551 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST
,
1552 cond_t
*, cond
, void *, NULL
);
1554 DO_PthAPIerror("cond_init", ret
);
1557 if (TRACE_PTH_FNS
) {
1558 fprintf(stderr
, " cond_init -> %d >>\n", ret
);
1563 #endif /* VGO_solaris */
1566 //-----------------------------------------------------------
1567 // glibc: pthread_cond_destroy@@GLIBC_2.3.2
1568 // glibc: pthread_cond_destroy@GLIBC_2.2.5
1569 // glibc: pthread_cond_destroy@GLIBC_2.0
1570 // darwin: pthread_cond_destroy
1571 // Solaris: cond_destroy (pthread_cond_destroy is a weak alias)
1573 __attribute__((noinline
))
1574 static int pthread_cond_destroy_WRK(pthread_cond_t
* cond
)
1577 unsigned long cond_is_init
;
1580 VALGRIND_GET_ORIG_FN(fn
);
1582 if (TRACE_PTH_FNS
) {
1583 fprintf(stderr
, "<< pthread_cond_destroy %p", cond
);
1588 const pthread_cond_t cond_init
= PTHREAD_COND_INITIALIZER
;
1589 cond_is_init
= my_memcmp(cond
, &cond_init
, sizeof(*cond
)) == 0;
1594 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_DESTROY_PRE
,
1595 pthread_cond_t
*, cond
, unsigned long, cond_is_init
);
1597 CALL_FN_W_W(ret
, fn
, cond
);
1600 DO_PthAPIerror( "pthread_cond_destroy", ret
);
1603 if (TRACE_PTH_FNS
) {
1604 fprintf(stderr
, " codestr -> %d >>\n", ret
);
1609 #if defined(VGO_linux)
1610 PTH_FUNC(int, pthreadZucondZudestroyZAZa
, // pthread_cond_destroy@*
1611 pthread_cond_t
* cond
) {
1612 return pthread_cond_destroy_WRK(cond
);
1614 #elif defined(VGO_darwin)
1615 PTH_FUNC(int, pthreadZucondZudestroy
, // pthread_cond_destroy
1616 pthread_cond_t
* cond
) {
1617 return pthread_cond_destroy_WRK(cond
);
1619 #elif defined(VGO_solaris)
1620 PTH_FUNC(int, condZudestroy
, // cond_destroy
1621 pthread_cond_t
*cond
) {
1622 return pthread_cond_destroy_WRK(cond
);
1625 # error "Unsupported OS"
1629 /*----------------------------------------------------------------*/
1630 /*--- pthread_barrier_t functions ---*/
1631 /*----------------------------------------------------------------*/
1633 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1635 /* Handled: pthread_barrier_init
1636 pthread_barrier_wait
1637 pthread_barrier_destroy
1639 Unhandled: pthread_barrierattr_destroy
1640 pthread_barrierattr_getpshared
1641 pthread_barrierattr_init
1642 pthread_barrierattr_setpshared
1643 -- are these important?
1646 //-----------------------------------------------------------
1647 // glibc: pthread_barrier_init
1648 // darwin: (doesn't appear to exist)
1649 // Solaris: pthread_barrier_init
1650 PTH_FUNC(int, pthreadZubarrierZuinit
, // pthread_barrier_init
1651 pthread_barrier_t
* bar
,
1652 pthread_barrierattr_t
* attr
, unsigned long count
)
1656 VALGRIND_GET_ORIG_FN(fn
);
1658 if (TRACE_PTH_FNS
) {
1659 fprintf(stderr
, "<< pthread_barrier_init %p %p %lu",
1664 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE
,
1665 pthread_barrier_t
*, bar
,
1666 unsigned long, count
,
1667 unsigned long, 0/*!resizable*/);
1669 CALL_FN_W_WWW(ret
, fn
, bar
,attr
,count
);
1672 DO_PthAPIerror( "pthread_barrier_init", ret
);
1675 if (TRACE_PTH_FNS
) {
1676 fprintf(stderr
, " pthread_barrier_init -> %d >>\n", ret
);
1683 //-----------------------------------------------------------
1684 // glibc: pthread_barrier_wait
1685 // darwin: (doesn't appear to exist)
1686 // Solaris: pthread_barrier_wait
1687 PTH_FUNC(int, pthreadZubarrierZuwait
, // pthread_barrier_wait
1688 pthread_barrier_t
* bar
)
1692 VALGRIND_GET_ORIG_FN(fn
);
1694 if (TRACE_PTH_FNS
) {
1695 fprintf(stderr
, "<< pthread_barrier_wait %p", bar
);
1699 /* That this works correctly, and doesn't screw up when a thread
1700 leaving the barrier races round to the front and re-enters while
1701 other threads are still leaving it, is quite subtle. See
1702 comments in the handler for PTHREAD_BARRIER_WAIT_PRE in
1704 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE
,
1705 pthread_barrier_t
*,bar
);
1707 CALL_FN_W_W(ret
, fn
, bar
);
1709 if (ret
!= 0 && ret
!= PTHREAD_BARRIER_SERIAL_THREAD
) {
1710 DO_PthAPIerror( "pthread_barrier_wait", ret
);
1713 if (TRACE_PTH_FNS
) {
1714 fprintf(stderr
, " pthread_barrier_wait -> %d >>\n", ret
);
1721 //-----------------------------------------------------------
1722 // glibc: pthread_barrier_destroy
1723 // darwin: (doesn't appear to exist)
1724 // Solaris: pthread_barrier_destroy
1725 PTH_FUNC(int, pthreadZubarrierZudestroy
, // pthread_barrier_destroy
1726 pthread_barrier_t
* bar
)
1730 VALGRIND_GET_ORIG_FN(fn
);
1732 if (TRACE_PTH_FNS
) {
1733 fprintf(stderr
, "<< pthread_barrier_destroy %p", bar
);
1737 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE
,
1738 pthread_barrier_t
*,bar
);
1740 CALL_FN_W_W(ret
, fn
, bar
);
1743 DO_PthAPIerror( "pthread_barrier_destroy", ret
);
1746 if (TRACE_PTH_FNS
) {
1747 fprintf(stderr
, " pthread_barrier_destroy -> %d >>\n", ret
);
1753 #endif // defined(HAVE_PTHREAD_BARRIER_INIT)
1756 /*----------------------------------------------------------------*/
1757 /*--- pthread_spinlock_t functions ---*/
1758 /*----------------------------------------------------------------*/
1760 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1761 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1763 /* Handled: pthread_spin_init pthread_spin_destroy
1764 pthread_spin_lock pthread_spin_trylock
1770 /* This is a nasty kludge, in that glibc "knows" that initialising a
1771 spin lock unlocks it, and pthread_spin_{init,unlock} are names for
1772 the same function. Hence we have to have a wrapper which does both
1773 things, without knowing which the user intended to happen.
1774 Solaris has distinct functions for init/unlock but client requests
1775 are immutable in helgrind.h so follow the glibc lead. */
1777 //-----------------------------------------------------------
1778 // glibc: pthread_spin_init
1779 // glibc: pthread_spin_unlock
1780 // darwin: (doesn't appear to exist)
1781 // Solaris: pthread_spin_init
1782 // Solaris: pthread_spin_unlock
1783 __attribute__((noinline
))
1784 static int pthread_spin_init_or_unlock_WRK(pthread_spinlock_t
* lock
,
1788 VALGRIND_GET_ORIG_FN(fn
);
1789 if (TRACE_PTH_FNS
) {
1790 fprintf(stderr
, "<< pthread_spin_iORu %p", lock
); fflush(stderr
);
1793 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE
,
1794 pthread_spinlock_t
*, lock
);
1796 CALL_FN_W_WW(ret
, fn
, lock
,pshared
);
1798 if (ret
== 0 /*success*/) {
1799 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST
,
1800 pthread_spinlock_t
*,lock
);
1802 DO_PthAPIerror( "pthread_spinlock_{init,unlock}", ret
);
1805 if (TRACE_PTH_FNS
) {
1806 fprintf(stderr
, " :: spiniORu -> %d >>\n", ret
);
1810 #if defined(VGO_linux)
1811 PTH_FUNC(int, pthreadZuspinZuinit
, // pthread_spin_init
1812 pthread_spinlock_t
* lock
, int pshared
) {
1813 return pthread_spin_init_or_unlock_WRK(lock
, pshared
);
1815 PTH_FUNC(int, pthreadZuspinZuunlock
, // pthread_spin_unlock
1816 pthread_spinlock_t
* lock
) {
1817 /* this is never actually called */
1818 return pthread_spin_init_or_unlock_WRK(lock
, 0/*pshared*/);
1820 #elif defined(VGO_darwin)
1821 #elif defined(VGO_solaris)
1822 PTH_FUNC(int, pthreadZuspinZuinit
, // pthread_spin_init
1823 pthread_spinlock_t
*lock
, int pshared
) {
1824 return pthread_spin_init_or_unlock_WRK(lock
, pshared
);
1826 PTH_FUNC(int, pthreadZuspinZuunlock
, // pthread_spin_unlock
1827 pthread_spinlock_t
*lock
) {
1828 return pthread_spin_init_or_unlock_WRK(lock
, 0/*pshared*/);
1831 # error "Unsupported OS"
1835 //-----------------------------------------------------------
1836 // glibc: pthread_spin_destroy
1837 // darwin: (doesn't appear to exist)
1838 // Solaris: pthread_spin_destroy
1839 __attribute__((noinline
))
1840 static int pthread_spin_destroy_WRK(pthread_spinlock_t
*lock
)
1844 VALGRIND_GET_ORIG_FN(fn
);
1845 if (TRACE_PTH_FNS
) {
1846 fprintf(stderr
, "<< pthread_spin_destroy %p", lock
);
1850 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_DESTROY_PRE
,
1851 pthread_spinlock_t
*,lock
);
1853 CALL_FN_W_W(ret
, fn
, lock
);
1856 DO_PthAPIerror( "pthread_spin_destroy", ret
);
1859 if (TRACE_PTH_FNS
) {
1860 fprintf(stderr
, " :: spindestroy -> %d >>\n", ret
);
1864 #if defined(VGO_linux)
1865 PTH_FUNC(int, pthreadZuspinZudestroy
, // pthread_spin_destroy
1866 pthread_spinlock_t
*lock
) {
1867 return pthread_spin_destroy_WRK(lock
);
1869 #elif defined(VGO_darwin)
1870 #elif defined(VGO_solaris)
1871 PTH_FUNC(int, pthreadZuspinZudestroy
, // pthread_spin_destroy
1872 pthread_spinlock_t
*lock
) {
1873 return pthread_spin_destroy_WRK(lock
);
1876 # error "Unsupported OS"
1880 //-----------------------------------------------------------
1881 // glibc: pthread_spin_lock
1882 // darwin: (doesn't appear to exist)
1883 // Solaris: pthread_spin_lock
1884 __attribute__((noinline
))
1885 static int pthread_spin_lock_WRK(pthread_spinlock_t
*lock
)
1889 VALGRIND_GET_ORIG_FN(fn
);
1890 if (TRACE_PTH_FNS
) {
1891 fprintf(stderr
, "<< pthread_spinlock %p", lock
);
1895 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE
,
1896 pthread_spinlock_t
*,lock
, long,0/*!isTryLock*/);
1898 CALL_FN_W_W(ret
, fn
, lock
);
1900 /* There's a hole here: libpthread now knows the lock is locked,
1901 but the tool doesn't, so some other thread could run and detect
1902 that the lock has been acquired by someone (this thread). Does
1903 this matter? Not sure, but I don't think so. */
1905 if (ret
== 0 /*success*/) {
1906 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST
,
1907 pthread_spinlock_t
*,lock
);
1909 DO_PthAPIerror( "pthread_spin_lock", ret
);
1912 if (TRACE_PTH_FNS
) {
1913 fprintf(stderr
, " :: spinlock -> %d >>\n", ret
);
1917 #if defined(VGO_linux)
1918 PTH_FUNC(int, pthreadZuspinZulock
, // pthread_spin_lock
1919 pthread_spinlock_t
*lock
) {
1920 return pthread_spin_lock_WRK(lock
);
1922 #elif defined(VGO_darwin)
1923 #elif defined(VGO_solaris)
1924 PTH_FUNC(int, pthreadZuspinZulock
, // pthread_spin_lock
1925 pthread_spinlock_t
*lock
) {
1926 return pthread_spin_lock_WRK(lock
);
1929 # error "Unsupported OS"
1933 //-----------------------------------------------------------
1934 // glibc: pthread_spin_trylock
1935 // darwin: (doesn't appear to exist)
1936 // Solaris: pthread_spin_trylock
1937 __attribute__((noinline
))
1938 static int pthread_spin_trylock_WRK(pthread_spinlock_t
*lock
)
1942 VALGRIND_GET_ORIG_FN(fn
);
1943 if (TRACE_PTH_FNS
) {
1944 fprintf(stderr
, "<< pthread_spin_trylock %p", lock
);
1948 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE
,
1949 pthread_spinlock_t
*,lock
, long,1/*isTryLock*/);
1951 CALL_FN_W_W(ret
, fn
, lock
);
1953 /* There's a hole here: libpthread now knows the lock is locked,
1954 but the tool doesn't, so some other thread could run and detect
1955 that the lock has been acquired by someone (this thread). Does
1956 this matter? Not sure, but I don't think so. */
1958 if (ret
== 0 /*success*/) {
1959 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST
,
1960 pthread_spinlock_t
*,lock
);
1963 DO_PthAPIerror( "pthread_spin_trylock", ret
);
1966 if (TRACE_PTH_FNS
) {
1967 fprintf(stderr
, " :: spin_trylock -> %d >>\n", ret
);
1971 #if defined(VGO_linux)
1972 PTH_FUNC(int, pthreadZuspinZutrylock
, // pthread_spin_trylock
1973 pthread_spinlock_t
*lock
) {
1974 return pthread_spin_trylock_WRK(lock
);
1976 #elif defined(VGO_darwin)
1977 #elif defined(VGO_solaris)
1978 PTH_FUNC(int, pthreadZuspinZutrylock
, // pthread_spin_trylock
1979 pthread_spinlock_t
*lock
) {
1980 return pthread_spin_trylock_WRK(lock
);
1983 # error "Unsupported OS"
1986 #endif // defined(HAVE_PTHREAD_SPIN_LOCK)
1989 /*----------------------------------------------------------------*/
1990 /*--- pthread_rwlock_t functions ---*/
1991 /*----------------------------------------------------------------*/
1993 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1994 functions have to be conditionally compiled. */
1995 #if defined(HAVE_PTHREAD_RWLOCK_T)
1997 /* Handled: pthread_rwlock_init pthread_rwlock_destroy
1998 pthread_rwlock_rdlock
1999 pthread_rwlock_wrlock
2000 pthread_rwlock_unlock
2001 pthread_rwlock_tryrdlock
2002 pthread_rwlock_trywrlock
2004 Unhandled: pthread_rwlock_timedrdlock
2005 pthread_rwlock_timedwrlock
2008 //-----------------------------------------------------------
2009 // glibc: pthread_rwlock_init
2010 // darwin: pthread_rwlock_init
2011 // darwin: pthread_rwlock_init$UNIX2003
2012 // Solaris: rwlock_init (pthread_rwlock_init is built atop of rwlock_init)
2013 __attribute__((noinline
))
2014 static int pthread_rwlock_init_WRK(pthread_rwlock_t
*rwl
,
2015 pthread_rwlockattr_t
* attr
)
2019 VALGRIND_GET_ORIG_FN(fn
);
2020 if (TRACE_PTH_FNS
) {
2021 fprintf(stderr
, "<< pthread_rwl_init %p", rwl
); fflush(stderr
);
2024 CALL_FN_W_WW(ret
, fn
, rwl
,attr
);
2026 if (ret
== 0 /*success*/) {
2027 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST
,
2028 pthread_rwlock_t
*,rwl
);
2030 DO_PthAPIerror( "pthread_rwlock_init", ret
);
2033 if (TRACE_PTH_FNS
) {
2034 fprintf(stderr
, " :: rwl_init -> %d >>\n", ret
);
2038 #if defined(VGO_linux)
2039 PTH_FUNC(int, pthreadZurwlockZuinit
, // pthread_rwlock_init
2040 pthread_rwlock_t
*rwl
,
2041 pthread_rwlockattr_t
* attr
) {
2042 return pthread_rwlock_init_WRK(rwl
, attr
);
2044 #elif defined(VGO_darwin)
2045 PTH_FUNC(int, pthreadZurwlockZuinitZa
, // pthread_rwlock_init*
2046 pthread_rwlock_t
*rwl
,
2047 pthread_rwlockattr_t
* attr
) {
2048 return pthread_rwlock_init_WRK(rwl
, attr
);
2050 #elif defined(VGO_solaris)
2051 static int pthread_rwlock_init_WRK(pthread_rwlock_t
*rwl
,
2052 pthread_rwlockattr_t
* attr
)
2053 __attribute__((unused
));
2055 # error "Unsupported OS"
2058 #if defined(VGO_solaris)
2059 PTH_FUNC(int, rwlockZuinit
, // rwlock_init
2066 VALGRIND_GET_ORIG_FN(fn
);
2067 if (TRACE_PTH_FNS
) {
2068 fprintf(stderr
, "<< rwl_init %p", rwlock
); fflush(stderr
);
2071 CALL_FN_W_WWW(ret
, fn
, rwlock
, type
, arg
);
2073 if (ret
== 0 /*success*/) {
2074 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST
,
2075 rwlock_t
*, rwlock
);
2077 DO_PthAPIerror("rwlock_init", ret
);
2080 if (TRACE_PTH_FNS
) {
2081 fprintf(stderr
, " :: rwl_init -> %d >>\n", ret
);
2085 #endif /* VGO_solaris */
2088 //-----------------------------------------------------------
2089 // glibc: pthread_rwlock_destroy
2090 // darwin: pthread_rwlock_destroy
2091 // darwin: pthread_rwlock_destroy$UNIX2003
2092 // Solaris: rwlock_destroy (pthread_rwlock_destroy is a weak alias)
2094 __attribute__((noinline
))
2095 static int pthread_rwlock_destroy_WRK(pthread_rwlock_t
* rwl
)
2099 VALGRIND_GET_ORIG_FN(fn
);
2100 if (TRACE_PTH_FNS
) {
2101 fprintf(stderr
, "<< pthread_rwl_destroy %p", rwl
); fflush(stderr
);
2104 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE
,
2105 pthread_rwlock_t
*,rwl
);
2107 CALL_FN_W_W(ret
, fn
, rwl
);
2110 DO_PthAPIerror( "pthread_rwlock_destroy", ret
);
2113 if (TRACE_PTH_FNS
) {
2114 fprintf(stderr
, " :: rwl_destroy -> %d >>\n", ret
);
2118 #if defined(VGO_linux)
2119 PTH_FUNC(int, pthreadZurwlockZudestroy
, // pthread_rwlock_destroy
2120 pthread_rwlock_t
*rwl
) {
2121 return pthread_rwlock_destroy_WRK(rwl
);
2123 #elif defined(VGO_darwin)
2124 PTH_FUNC(int, pthreadZurwlockZudestroyZa
, // pthread_rwlock_destroy*
2125 pthread_rwlock_t
*rwl
) {
2126 return pthread_rwlock_destroy_WRK(rwl
);
2128 #elif defined(VGO_solaris)
2129 PTH_FUNC(int, rwlockZudestroy
, // rwlock_destroy
2130 pthread_rwlock_t
*rwl
) {
2131 return pthread_rwlock_destroy_WRK(rwl
);
2134 # error "Unsupported OS"
2138 //-----------------------------------------------------------
2139 // glibc: pthread_rwlock_wrlock
2140 // darwin: pthread_rwlock_wrlock
2141 // darwin: pthread_rwlock_wrlock$UNIX2003
2142 // Solaris: rw_wrlock (pthread_rwlock_wrlock is a weak alias)
2144 __attribute__((noinline
))
2145 static int pthread_rwlock_wrlock_WRK(pthread_rwlock_t
* rwlock
)
2149 VALGRIND_GET_ORIG_FN(fn
);
2150 if (TRACE_PTH_FNS
) {
2151 fprintf(stderr
, "<< pthread_rwl_wlk %p", rwlock
); fflush(stderr
);
2154 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
2155 pthread_rwlock_t
*,rwlock
,
2156 long,1/*isW*/, long,0/*!isTryLock*/);
2158 CALL_FN_W_W(ret
, fn
, rwlock
);
2160 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
2161 pthread_rwlock_t
*,rwlock
, long,1/*isW*/,
2162 long, (ret
== 0) ? True
: False
);
2164 DO_PthAPIerror( "pthread_rwlock_wrlock", ret
);
2167 if (TRACE_PTH_FNS
) {
2168 fprintf(stderr
, " :: rwl_wlk -> %d >>\n", ret
);
2172 #if defined(VGO_linux)
2173 PTH_FUNC(int, pthreadZurwlockZuwrlock
, // pthread_rwlock_wrlock
2174 pthread_rwlock_t
* rwlock
) {
2175 return pthread_rwlock_wrlock_WRK(rwlock
);
2177 #elif defined(VGO_darwin)
2178 PTH_FUNC(int, pthreadZurwlockZuwrlockZa
, // pthread_rwlock_wrlock*
2179 pthread_rwlock_t
* rwlock
) {
2180 return pthread_rwlock_wrlock_WRK(rwlock
);
2182 #elif defined(VGO_solaris)
2183 PTH_FUNC(int, rwZuwrlock
, // rw_wrlock
2184 pthread_rwlock_t
*rwlock
) {
2185 return pthread_rwlock_wrlock_WRK(rwlock
);
2188 # error "Unsupported OS"
2191 #if defined(VGO_solaris)
2192 /* Internal to libc. */
2193 PTH_FUNC(void, lrwZuwrlock
, // lrw_wrlock
2197 VALGRIND_GET_ORIG_FN(fn
);
2198 if (TRACE_PTH_FNS
) {
2199 fprintf(stderr
, "<< lrw_wlk %p", rwlock
); fflush(stderr
);
2202 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
2203 pthread_rwlock_t
*, rwlock
,
2204 long, 1/*isW*/, long, 0/*!isTryLock*/);
2206 CALL_FN_v_W(fn
, rwlock
);
2208 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
2209 pthread_rwlock_t
*, rwlock
, long, 1/*isW*/, long, True
);
2211 if (TRACE_PTH_FNS
) {
2212 fprintf(stderr
, " :: lrw_wlk >>\n");
2215 #endif /* VGO_solaris */
2218 //-----------------------------------------------------------
2219 // glibc: pthread_rwlock_rdlock
2220 // darwin: pthread_rwlock_rdlock
2221 // darwin: pthread_rwlock_rdlock$UNIX2003
2222 // Solaris: rw_rdlock (pthread_rwlock_rdlock is a weak alias)
2224 __attribute__((noinline
))
2225 static int pthread_rwlock_rdlock_WRK(pthread_rwlock_t
* rwlock
)
2229 VALGRIND_GET_ORIG_FN(fn
);
2230 if (TRACE_PTH_FNS
) {
2231 fprintf(stderr
, "<< pthread_rwl_rlk %p", rwlock
); fflush(stderr
);
2234 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
2235 pthread_rwlock_t
*,rwlock
,
2236 long,0/*!isW*/, long,0/*!isTryLock*/);
2238 CALL_FN_W_W(ret
, fn
, rwlock
);
2240 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
2241 pthread_rwlock_t
*,rwlock
, long,0/*!isW*/,
2242 long, (ret
== 0) ? True
: False
);
2244 DO_PthAPIerror( "pthread_rwlock_rdlock", ret
);
2247 if (TRACE_PTH_FNS
) {
2248 fprintf(stderr
, " :: rwl_rlk -> %d >>\n", ret
);
2252 #if defined(VGO_linux)
2253 PTH_FUNC(int, pthreadZurwlockZurdlock
, // pthread_rwlock_rdlock
2254 pthread_rwlock_t
* rwlock
) {
2255 return pthread_rwlock_rdlock_WRK(rwlock
);
2257 #elif defined(VGO_darwin)
2258 PTH_FUNC(int, pthreadZurwlockZurdlockZa
, // pthread_rwlock_rdlock*
2259 pthread_rwlock_t
* rwlock
) {
2260 return pthread_rwlock_rdlock_WRK(rwlock
);
2262 #elif defined(VGO_solaris)
2263 PTH_FUNC(int, rwZurdlock
, // rw_rdlock
2264 pthread_rwlock_t
*rwlock
) {
2265 return pthread_rwlock_rdlock_WRK(rwlock
);
2268 # error "Unsupported OS"
2271 #if defined(VGO_solaris)
2272 /* Internal to libc. */
2273 PTH_FUNC(void, lrwZurdlock
, // lrw_rdlock
2277 VALGRIND_GET_ORIG_FN(fn
);
2278 if (TRACE_PTH_FNS
) {
2279 fprintf(stderr
, "<< lrw_rlk %p", rwlock
); fflush(stderr
);
2282 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
2283 pthread_rwlock_t
*, rwlock
,
2284 long, 0/*!isW*/, long, 0/*!isTryLock*/);
2286 CALL_FN_v_W(fn
, rwlock
);
2288 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
2289 pthread_rwlock_t
*, rwlock
, long, 0/*!isW*/, long, True
);
2291 if (TRACE_PTH_FNS
) {
2292 fprintf(stderr
, " :: lrw_rlk ->>\n");
2295 #endif /* VGO_solaris */
2298 //-----------------------------------------------------------
2299 // glibc: pthread_rwlock_trywrlock
2300 // darwin: pthread_rwlock_trywrlock
2301 // darwin: pthread_rwlock_trywrlock$UNIX2003
2302 // Solaris: rw_trywrlock (pthread_rwlock_trywrlock is a weak alias)
2304 __attribute__((noinline
))
2305 static int pthread_rwlock_trywrlock_WRK(pthread_rwlock_t
* rwlock
)
2309 VALGRIND_GET_ORIG_FN(fn
);
2310 if (TRACE_PTH_FNS
) {
2311 fprintf(stderr
, "<< pthread_rwl_trywlk %p", rwlock
); fflush(stderr
);
2314 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
2315 pthread_rwlock_t
*,rwlock
,
2316 long,1/*isW*/, long,1/*isTryLock*/);
2318 CALL_FN_W_W(ret
, fn
, rwlock
);
2320 /* There's a hole here: libpthread now knows the lock is locked,
2321 but the tool doesn't, so some other thread could run and detect
2322 that the lock has been acquired by someone (this thread). Does
2323 this matter? Not sure, but I don't think so. */
2325 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
2326 pthread_rwlock_t
*,rwlock
, long,1/*isW*/,
2327 long, (ret
== 0) ? True
: False
);
2330 DO_PthAPIerror( "pthread_rwlock_trywrlock", ret
);
2333 if (TRACE_PTH_FNS
) {
2334 fprintf(stderr
, " :: rwl_trywlk -> %d >>\n", ret
);
2338 #if defined(VGO_linux)
2339 PTH_FUNC(int, pthreadZurwlockZutrywrlock
, // pthread_rwlock_trywrlock
2340 pthread_rwlock_t
* rwlock
) {
2341 return pthread_rwlock_trywrlock_WRK(rwlock
);
2343 #elif defined(VGO_darwin)
2344 PTH_FUNC(int, pthreadZurwlockZutrywrlockZa
, // pthread_rwlock_trywrlock*
2345 pthread_rwlock_t
* rwlock
) {
2346 return pthread_rwlock_trywrlock_WRK(rwlock
);
2348 #elif defined(VGO_solaris)
2349 PTH_FUNC(int, rwZutrywrlock
, // rw_trywrlock
2350 pthread_rwlock_t
*rwlock
) {
2351 return pthread_rwlock_trywrlock_WRK(rwlock
);
2354 # error "Unsupported OS"
2358 //-----------------------------------------------------------
2359 // glibc: pthread_rwlock_tryrdlock
2360 // darwin: pthread_rwlock_tryrdlock
2361 // darwin: pthread_rwlock_tryrdlock$UNIX2003
2362 // Solaris: rw_tryrdlock (pthread_rwlock_tryrdlock is a weak alias)
2364 __attribute__((noinline
))
2365 static int pthread_rwlock_tryrdlock_WRK(pthread_rwlock_t
* rwlock
)
2369 VALGRIND_GET_ORIG_FN(fn
);
2370 if (TRACE_PTH_FNS
) {
2371 fprintf(stderr
, "<< pthread_rwl_tryrlk %p", rwlock
); fflush(stderr
);
2374 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
2375 pthread_rwlock_t
*,rwlock
,
2376 long,0/*!isW*/, long,1/*isTryLock*/);
2378 CALL_FN_W_W(ret
, fn
, rwlock
);
2380 /* There's a hole here: libpthread now knows the lock is locked,
2381 but the tool doesn't, so some other thread could run and detect
2382 that the lock has been acquired by someone (this thread). Does
2383 this matter? Not sure, but I don't think so. */
2385 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
2386 pthread_rwlock_t
*,rwlock
, long,0/*!isW*/,
2387 long, (ret
== 0) ? True
: False
);
2391 DO_PthAPIerror( "pthread_rwlock_tryrdlock", ret
);
2394 if (TRACE_PTH_FNS
) {
2395 fprintf(stderr
, " :: rwl_tryrlk -> %d >>\n", ret
);
2399 #if defined(VGO_linux)
2400 PTH_FUNC(int, pthreadZurwlockZutryrdlock
, // pthread_rwlock_tryrdlock
2401 pthread_rwlock_t
* rwlock
) {
2402 return pthread_rwlock_tryrdlock_WRK(rwlock
);
2404 #elif defined(VGO_darwin)
2405 PTH_FUNC(int, pthreadZurwlockZutryrdlockZa
, // pthread_rwlock_tryrdlock*
2406 pthread_rwlock_t
* rwlock
) {
2407 return pthread_rwlock_tryrdlock_WRK(rwlock
);
2409 #elif defined(VGO_solaris)
2410 PTH_FUNC(int, rwZutryrdlock
, // rw_tryrdlock
2411 pthread_rwlock_t
*rwlock
) {
2412 return pthread_rwlock_tryrdlock_WRK(rwlock
);
2415 # error "Unsupported OS"
2419 //-----------------------------------------------------------
2421 // darwin: Unhandled
2422 // Solaris: pthread_rwlock_timedrdlock
2423 // Solaris: pthread_rwlock_reltimedrdlock_np
2425 __attribute__((noinline
)) __attribute__((unused
))
2426 static int pthread_rwlock_timedrdlock_WRK(pthread_rwlock_t
*rwlock
,
2427 const struct timespec
*timeout
)
2431 VALGRIND_GET_ORIG_FN(fn
);
2432 if (TRACE_PTH_FNS
) {
2433 fprintf(stderr
, "<< pthread_rwl_timedrdl %p", rwlock
); fflush(stderr
);
2436 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
2437 pthread_rwlock_t
*, rwlock
,
2438 long, 0/*isW*/, long, 0/*isTryLock*/);
2440 CALL_FN_W_WW(ret
, fn
, rwlock
, timeout
);
2442 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
2443 pthread_rwlock_t
*, rwlock
, long, 0/*isW*/,
2444 long, (ret
== 0) ? True
: False
);
2446 DO_PthAPIerror("pthread_rwlock_timedrdlock", ret
);
2449 if (TRACE_PTH_FNS
) {
2450 fprintf(stderr
, " :: rwl_timedrdl -> %d >>\n", ret
);
2454 #if defined(VGO_linux)
2455 #elif defined(VGO_darwin)
2456 #elif defined(VGO_solaris)
2457 PTH_FUNC(int, pthreadZurwlockZutimedrdlock
, // pthread_rwlock_timedrdlock
2458 pthread_rwlock_t
*rwlock
,
2459 const struct timespec
*timeout
) {
2460 return pthread_rwlock_timedrdlock_WRK(rwlock
, timeout
);
2462 PTH_FUNC(int, pthreadZurwlockZureltimedrdlockZunp
, // pthread_rwlock_timedrdlock_np
2463 pthread_rwlock_t
*rwlock
,
2464 const struct timespec
*timeout
) {
2465 return pthread_rwlock_timedrdlock_WRK(rwlock
, timeout
);
2468 # error "Unsupported OS"
2472 //-----------------------------------------------------------
2474 // darwin: Unhandled
2475 // Solaris: pthread_rwlock_timedwrlock
2476 // Solaris: pthread_rwlock_reltimedwrlock_np
2478 __attribute__((noinline
)) __attribute__((unused
))
2479 static int pthread_rwlock_timedwrlock_WRK(pthread_rwlock_t
*rwlock
,
2480 const struct timespec
*timeout
)
2484 VALGRIND_GET_ORIG_FN(fn
);
2485 if (TRACE_PTH_FNS
) {
2486 fprintf(stderr
, "<< pthread_rwl_timedwrl %p", rwlock
); fflush(stderr
);
2489 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
2490 pthread_rwlock_t
*, rwlock
,
2491 long, 1/*isW*/, long, 0/*isTryLock*/);
2493 CALL_FN_W_WW(ret
, fn
, rwlock
, timeout
);
2495 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
2496 pthread_rwlock_t
*, rwlock
, long, 1/*isW*/,
2497 long, (ret
== 0) ? True
: False
);
2499 DO_PthAPIerror("pthread_rwlock_timedwrlock", ret
);
2502 if (TRACE_PTH_FNS
) {
2503 fprintf(stderr
, " :: rwl_timedwrl -> %d >>\n", ret
);
2507 #if defined(VGO_linux)
2508 #elif defined(VGO_darwin)
2509 #elif defined(VGO_solaris)
2510 PTH_FUNC(int, pthreadZurwlockZutimedwrlock
, // pthread_rwlock_timedwrlock
2511 pthread_rwlock_t
*rwlock
,
2512 const struct timespec
*timeout
) {
2513 return pthread_rwlock_timedwrlock_WRK(rwlock
, timeout
);
2515 PTH_FUNC(int, pthreadZurwlockZureltimedwrlockZunp
, // pthread_rwlock_timedwrlock_np
2516 pthread_rwlock_t
*rwlock
,
2517 const struct timespec
*timeout
) {
2518 return pthread_rwlock_timedwrlock_WRK(rwlock
, timeout
);
2521 # error "Unsupported OS"
2525 //-----------------------------------------------------------
2526 // glibc: pthread_rwlock_unlock
2527 // darwin: pthread_rwlock_unlock
2528 // darwin: pthread_rwlock_unlock$UNIX2003
2529 // Solaris: rw_unlock (pthread_rwlock_unlock is a weak alias)
2530 __attribute__((noinline
))
2531 static int pthread_rwlock_unlock_WRK(pthread_rwlock_t
* rwlock
)
2535 VALGRIND_GET_ORIG_FN(fn
);
2536 if (TRACE_PTH_FNS
) {
2537 fprintf(stderr
, "<< pthread_rwl_unlk %p", rwlock
); fflush(stderr
);
2540 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE
,
2541 pthread_rwlock_t
*,rwlock
);
2543 CALL_FN_W_W(ret
, fn
, rwlock
);
2545 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST
,
2546 pthread_rwlock_t
*,rwlock
);
2548 DO_PthAPIerror( "pthread_rwlock_unlock", ret
);
2551 if (TRACE_PTH_FNS
) {
2552 fprintf(stderr
, " :: rwl_unlk -> %d >>\n", ret
);
2556 #if defined(VGO_linux)
2557 PTH_FUNC(int, pthreadZurwlockZuunlock
, // pthread_rwlock_unlock
2558 pthread_rwlock_t
* rwlock
) {
2559 return pthread_rwlock_unlock_WRK(rwlock
);
2561 #elif defined(VGO_darwin)
2562 PTH_FUNC(int, pthreadZurwlockZuunlockZa
, // pthread_rwlock_unlock*
2563 pthread_rwlock_t
* rwlock
) {
2564 return pthread_rwlock_unlock_WRK(rwlock
);
2566 #elif defined(VGO_solaris)
2567 PTH_FUNC(int, rwZuunlock
, // rw_unlock
2568 pthread_rwlock_t
*rwlock
) {
2569 return pthread_rwlock_unlock_WRK(rwlock
);
2572 # error "Unsupported OS"
2575 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
2578 /*----------------------------------------------------------------*/
2579 /*--- POSIX semaphores ---*/
2580 /*----------------------------------------------------------------*/
2582 #include <semaphore.h>
2583 #include <fcntl.h> /* O_CREAT */
2585 #define TRACE_SEM_FNS 0
2588 int sem_init(sem_t *sem, int pshared, unsigned value);
2589 int sem_destroy(sem_t *sem);
2590 int sem_wait(sem_t *sem);
2591 int sem_post(sem_t *sem);
2592 sem_t* sem_open(const char *name, int oflag,
2593 ... [mode_t mode, unsigned value]);
2594 [complete with its idiotic semantics]
2595 int sem_close(sem_t* sem);
2598 int sem_trywait(sem_t *sem);
2599 int sem_timedwait(sem_t *restrict sem,
2600 const struct timespec *restrict abs_timeout);
2603 //-----------------------------------------------------------
2604 // glibc: sem_init@@GLIBC_2.2.5
2605 // glibc: sem_init@@GLIBC_2.1
2606 // glibc: sem_init@GLIBC_2.0
2608 // Solaris: sema_init (sem_init is built on top of sem_init)
2610 #if !defined(VGO_solaris)
2611 __attribute__((noinline
))
2612 static int sem_init_WRK(sem_t
* sem
, int pshared
, unsigned long value
)
2616 VALGRIND_GET_ORIG_FN(fn
);
2618 if (TRACE_SEM_FNS
) {
2619 fprintf(stderr
, "<< sem_init(%p,%d,%lu) ", sem
,pshared
,value
);
2623 CALL_FN_W_WWW(ret
, fn
, sem
,pshared
,value
);
2626 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST
,
2627 sem_t
*, sem
, unsigned long, value
);
2629 DO_PthAPIerror( "sem_init", errno
);
2632 if (TRACE_SEM_FNS
) {
2633 fprintf(stderr
, " sem_init -> %d >>\n", ret
);
2639 #if defined(VGO_linux)
2640 PTH_FUNC(int, semZuinitZAZa
, // sem_init@*
2641 sem_t
* sem
, int pshared
, unsigned long value
) {
2642 return sem_init_WRK(sem
, pshared
, value
);
2644 #elif defined(VGO_darwin)
2645 PTH_FUNC(int, semZuinit
, // sem_init
2646 sem_t
* sem
, int pshared
, unsigned long value
) {
2647 return sem_init_WRK(sem
, pshared
, value
);
2650 # error "Unsupported OS"
2653 #else /* VGO_solaris */
2654 PTH_FUNC(int, semaZuinit
, // sema_init
2662 VALGRIND_GET_ORIG_FN(fn
);
2664 if (TRACE_SEM_FNS
) {
2665 fprintf(stderr
, "<< sema_init(%p, %d, %u) ", sem
, type
, value
);
2669 CALL_FN_W_WWWW(ret
, fn
, sem
, value
, type
, arg
);
2672 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST
,
2673 sema_t
*, sem
, Word
, value
);
2675 DO_PthAPIerror("sema_init", ret
);
2678 if (TRACE_SEM_FNS
) {
2679 fprintf(stderr
, " sema_init -> %d >>\n", ret
);
2685 #endif /* VGO_solaris */
2688 //-----------------------------------------------------------
2689 // glibc: sem_destroy@GLIBC_2.0
2690 // glibc: sem_destroy@@GLIBC_2.1
2691 // glibc: sem_destroy@@GLIBC_2.2.5
2692 // darwin: sem_destroy
2693 // Solaris: sema_destroy (sem_destroy is built on top of sema_destroy)
2694 __attribute__((noinline
))
2695 static int sem_destroy_WRK(sem_t
* sem
)
2699 VALGRIND_GET_ORIG_FN(fn
);
2701 if (TRACE_SEM_FNS
) {
2702 fprintf(stderr
, "<< sem_destroy(%p) ", sem
);
2706 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE
, sem_t
*, sem
);
2708 CALL_FN_W_W(ret
, fn
, sem
);
2711 DO_PthAPIerror( "sem_destroy", SEM_ERROR
);
2714 if (TRACE_SEM_FNS
) {
2715 fprintf(stderr
, " sem_destroy -> %d >>\n", ret
);
2721 #if defined(VGO_linux)
2722 PTH_FUNC(int, semZudestroyZAZa
, // sem_destroy*
2724 return sem_destroy_WRK(sem
);
2726 #elif defined(VGO_darwin)
2727 PTH_FUNC(int, semZudestroy
, // sem_destroy
2729 return sem_destroy_WRK(sem
);
2731 #elif defined(VGO_solaris)
2732 PTH_FUNC(int, semaZudestroy
, // sema_destroy
2734 return sem_destroy_WRK(sem
);
2737 # error "Unsupported OS"
2741 //-----------------------------------------------------------
2743 // glibc: sem_wait@GLIBC_2.0
2744 // glibc: sem_wait@@GLIBC_2.1
2746 // darwin: sem_wait$NOCANCEL$UNIX2003
2747 // darwin: sem_wait$UNIX2003
2748 // Solaris: sema_wait (sem_wait is built on top of sema_wait)
2750 /* wait: decrement semaphore - acquire lockage */
2751 __attribute__((noinline
))
2752 static int sem_wait_WRK(sem_t
* sem
)
2756 VALGRIND_GET_ORIG_FN(fn
);
2758 if (TRACE_SEM_FNS
) {
2759 fprintf(stderr
, "<< sem_wait(%p) ", sem
);
2763 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_PRE
, sem_t
*,sem
);
2765 CALL_FN_W_W(ret
, fn
, sem
);
2767 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST
, sem_t
*,sem
,
2768 long, (ret
== 0) ? True
: False
);
2771 DO_PthAPIerror( "sem_wait", SEM_ERROR
);
2774 if (TRACE_SEM_FNS
) {
2775 fprintf(stderr
, " sem_wait -> %d >>\n", ret
);
2781 #if defined(VGO_linux)
2782 PTH_FUNC(int, semZuwait
, sem_t
* sem
) { /* sem_wait */
2783 return sem_wait_WRK(sem
);
2785 PTH_FUNC(int, semZuwaitZAZa
, sem_t
* sem
) { /* sem_wait@* */
2786 return sem_wait_WRK(sem
);
2788 #elif defined(VGO_darwin)
2789 PTH_FUNC(int, semZuwait
, sem_t
* sem
) { /* sem_wait */
2790 return sem_wait_WRK(sem
);
2792 PTH_FUNC(int, semZuwaitZDZa
, sem_t
* sem
) { /* sem_wait$* */
2793 return sem_wait_WRK(sem
);
2795 #elif defined(VGO_solaris)
2796 PTH_FUNC(int, semaZuwait
, sem_t
*sem
) { /* sema_wait */
2797 return sem_wait_WRK(sem
);
2800 # error "Unsupported OS"
2804 //-----------------------------------------------------------
2806 // glibc: sem_post@GLIBC_2.0
2807 // glibc: sem_post@@GLIBC_2.1
2809 // Solaris: sema_post (sem_post is built on top of sema_post)
2811 /* post: increment semaphore - release lockage */
2812 __attribute__((noinline
))
2813 static int sem_post_WRK(sem_t
* sem
)
2818 VALGRIND_GET_ORIG_FN(fn
);
2820 if (TRACE_SEM_FNS
) {
2821 fprintf(stderr
, "<< sem_post(%p) ", sem
);
2825 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_PRE
, sem_t
*,sem
);
2827 CALL_FN_W_W(ret
, fn
, sem
);
2829 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_POST
, sem_t
*,sem
);
2832 DO_PthAPIerror( "sem_post", SEM_ERROR
);
2835 if (TRACE_SEM_FNS
) {
2836 fprintf(stderr
, " sem_post -> %d >>\n", ret
);
2842 #if defined(VGO_linux)
2843 PTH_FUNC(int, semZupost
, sem_t
* sem
) { /* sem_post */
2844 return sem_post_WRK(sem
);
2846 PTH_FUNC(int, semZupostZAZa
, sem_t
* sem
) { /* sem_post@* */
2847 return sem_post_WRK(sem
);
2849 #elif defined(VGO_darwin)
2850 PTH_FUNC(int, semZupost
, sem_t
* sem
) { /* sem_post */
2851 return sem_post_WRK(sem
);
2853 #elif defined(VGO_solaris)
2854 PTH_FUNC(int, semaZupost
, sem_t
*sem
) { /* sema_post */
2855 return sem_post_WRK(sem
);
2858 # error "Unsupported OS"
2862 //-----------------------------------------------------------
2865 // Solaris: sem_open
2867 PTH_FUNC(sem_t
*, semZuopen
,
2868 const char* name
, long oflag
,
2869 long mode
, unsigned long value
)
2871 /* A copy of sem_init_WRK (more or less). Is this correct? */
2874 VALGRIND_GET_ORIG_FN(fn
);
2876 if (TRACE_SEM_FNS
) {
2877 fprintf(stderr
, "<< sem_open(\"%s\",%ld,%lx,%lu) ",
2878 name
,oflag
,mode
,value
);
2882 CALL_FN_W_WWWW(ret
, fn
, name
,oflag
,mode
,value
);
2884 if (ret
!= SEM_FAILED
&& (oflag
& O_CREAT
)) {
2885 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST
,
2886 sem_t
*, ret
, unsigned long, value
);
2888 if (ret
== SEM_FAILED
) {
2889 DO_PthAPIerror( "sem_open", errno
);
2892 if (TRACE_SEM_FNS
) {
2893 fprintf(stderr
, " sem_open -> %p >>\n", ret
);
2901 //-----------------------------------------------------------
2903 // darwin: sem_close
2904 // Solaris: sem_close
2905 PTH_FUNC(int, sem_close
, sem_t
* sem
)
2909 VALGRIND_GET_ORIG_FN(fn
);
2911 if (TRACE_SEM_FNS
) {
2912 fprintf(stderr
, "<< sem_close(%p) ", sem
);
2916 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE
, sem_t
*, sem
);
2918 CALL_FN_W_W(ret
, fn
, sem
);
2921 DO_PthAPIerror( "sem_close", errno
);
2924 if (TRACE_SEM_FNS
) {
2925 fprintf(stderr
, " close -> %d >>\n", ret
);
2933 /*----------------------------------------------------------------*/
2934 /*--- Qt 4 threading functions (w/ GNU name mangling) ---*/
2935 /*----------------------------------------------------------------*/
2941 QMutex::tryLock(int)
2943 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC1ENS_13RecursionModeE
2944 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC2ENS_13RecursionModeE
2945 QMutex::~QMutex() _ZN6QMutexD1Ev
2946 QMutex::~QMutex() _ZN6QMutexD2Ev
2949 QReadWriteLock::lockForRead()
2950 QReadWriteLock::lockForWrite()
2951 QReadWriteLock::unlock()
2952 QReadWriteLock::tryLockForRead(int)
2953 QReadWriteLock::tryLockForRead()
2954 QReadWriteLock::tryLockForWrite(int)
2955 QReadWriteLock::tryLockForWrite()
2957 QWaitCondition::wait(QMutex*, unsigned long)
2958 QWaitCondition::wakeAll()
2959 QWaitCondition::wakeOne()
2963 /* More comments, 19 Nov 08, based on assessment of qt-4.5.0TP1,
2966 It's apparently only necessary to intercept QMutex, since that is
2967 not implemented using pthread_mutex_t; instead Qt4 has its own
2968 implementation based on atomics (to check the non-contended case)
2969 and pthread_cond_wait (to wait in the contended case).
2971 QReadWriteLock is built on top of QMutex, counters, and a wait
2972 queue. So we don't need to handle it specially once QMutex
2973 handling is correct -- presumably the dependencies through QMutex
2974 are sufficient to avoid any false race reports. On the other hand,
2975 it is an open question whether too many dependencies are observed
2976 -- in which case we may miss races (false negatives). I suspect
2977 this is likely to be the case, unfortunately.
2979 QWaitCondition is built on pthread_cond_t, pthread_mutex_t, QMutex
2980 and QReadWriteLock. Same compositional-correctness justificiation
2981 and limitations as fro QReadWriteLock.
2983 Ditto QSemaphore (from cursory examination).
2985 Does it matter that only QMutex is handled directly? Open
2986 question. From testing with drd/tests/qt4_* and with KDE4 apps, it
2987 appears that no false errors are reported; however it is not clear
2988 if this is causing false negatives.
2990 Another problem with Qt4 is thread exiting. Threads are created
2991 with pthread_create (fine); but they detach and simply exit when
2992 done. There is no use of pthread_join, and the provided
2993 wait-for-a-thread-to-exit mechanism (QThread::wait, I believe)
2994 relies on a system of mutexes and flags. I suspect this also
2995 causes too many dependencies to appear. Consequently H sometimes
2996 fails to detect races at exit in some very short-lived racy
2997 programs, because it appears that a thread can exit _and_ have an
2998 observed dependency edge back to the main thread (presumably)
2999 before the main thread reaps the child (that is, calls
3002 This theory is supported by the observation that if all threads are
3003 made to wait at a pthread_barrier_t immediately before they exit,
3004 then H's detection of races in such programs becomes reliable;
3005 without the barrier, it is varies from run to run, depending
3006 (according to investigation) on whether aforementioned
3007 exit-before-reaping behaviour happens or not.
3009 Finally, why is it necessary to intercept the QMutex constructors
3010 and destructors? The constructors are intercepted only as a matter
3011 of convenience, so H can print accurate "first observed at"
3012 clauses. However, it is actually necessary to intercept the
3013 destructors (as it is with pthread_mutex_destroy) in order that
3014 locks get removed from LAOG when they are destroyed.
3017 // soname is libQtCore.so.4 ; match against libQtCore.so*
3018 #define QT4_FUNC(ret_ty, f, args...) \
3019 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args); \
3020 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args)
3022 // soname is libQt5Core.so.4 ; match against libQt5Core.so*
3023 #define QT5_FUNC(ret_ty, f, args...) \
3024 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args); \
3025 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args)
3027 //-----------------------------------------------------------
3029 __attribute__((noinline
))
3030 static void QMutex_lock_WRK(void* self
)
3033 VALGRIND_GET_ORIG_FN(fn
);
3034 if (TRACE_QT4_FNS
) {
3035 fprintf(stderr
, "<< QMutex::lock %p", self
); fflush(stderr
);
3038 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
3039 void*,self
, long,0/*!isTryLock*/);
3041 CALL_FN_v_W(fn
, self
);
3043 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
3044 void *, self
, long, True
);
3046 if (TRACE_QT4_FNS
) {
3047 fprintf(stderr
, " :: Q::lock done >>\n");
3051 QT4_FUNC(void, _ZN6QMutex4lockEv
, void* self
) {
3052 QMutex_lock_WRK(self
);
3054 QT5_FUNC(void, _ZN6QMutex4lockEv
, void* self
) {
3055 QMutex_lock_WRK(self
);
3058 //-----------------------------------------------------------
3060 __attribute__((noinline
))
3061 static void QMutex_unlock_WRK(void* self
)
3064 VALGRIND_GET_ORIG_FN(fn
);
3066 if (TRACE_QT4_FNS
) {
3067 fprintf(stderr
, "<< QMutex::unlock %p", self
); fflush(stderr
);
3070 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE
,
3073 CALL_FN_v_W(fn
, self
);
3075 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST
,
3078 if (TRACE_QT4_FNS
) {
3079 fprintf(stderr
, " Q::unlock done >>\n");
3083 QT4_FUNC(void, _ZN6QMutex6unlockEv
, void* self
) {
3084 QMutex_unlock_WRK(self
);
3086 QT5_FUNC(void, _ZN6QMutex6unlockEv
, void* self
) {
3087 QMutex_unlock_WRK(self
);
3090 //-----------------------------------------------------------
3091 // bool QMutex::tryLock()
3092 // using 'long' to mimic C++ 'bool'
3093 __attribute__((noinline
))
3094 static long QMutex_tryLock_WRK(void* self
)
3098 VALGRIND_GET_ORIG_FN(fn
);
3099 if (TRACE_QT4_FNS
) {
3100 fprintf(stderr
, "<< QMutex::tryLock %p", self
); fflush(stderr
);
3103 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
3104 void*,self
, long,1/*isTryLock*/);
3106 CALL_FN_W_W(ret
, fn
, self
);
3108 // assumes that only the low 8 bits of the 'bool' are significant
3109 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
3110 void *, self
, long, (ret
& 0xFF) ? True
: False
);
3112 if (TRACE_QT4_FNS
) {
3113 fprintf(stderr
, " :: Q::tryLock -> %lu >>\n", ret
);
3119 QT4_FUNC(long, _ZN6QMutex7tryLockEv
, void* self
) {
3120 return QMutex_tryLock_WRK(self
);
3122 QT5_FUNC(long, _ZN6QMutex7tryLockEv
, void* self
) {
3123 return QMutex_tryLock_WRK(self
);
3126 //-----------------------------------------------------------
3127 // bool QMutex::tryLock(int)
3128 // using 'long' to mimic C++ 'bool'
3129 __attribute__((noinline
))
3130 static long QMutex_tryLock_int_WRK(void* self
, long arg2
)
3134 VALGRIND_GET_ORIG_FN(fn
);
3135 if (TRACE_QT4_FNS
) {
3136 fprintf(stderr
, "<< QMutex::tryLock(int) %p %d", self
, (int)arg2
);
3140 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
3141 void*,self
, long,1/*isTryLock*/);
3143 CALL_FN_W_WW(ret
, fn
, self
,arg2
);
3145 // assumes that only the low 8 bits of the 'bool' are significant
3146 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
3147 void *, self
, long, (ret
& 0xFF) ? True
: False
);
3149 if (TRACE_QT4_FNS
) {
3150 fprintf(stderr
, " :: Q::tryLock(int) -> %lu >>\n", ret
);
3156 QT4_FUNC(long, _ZN6QMutex7tryLockEi
, void* self
, long arg2
) {
3157 return QMutex_tryLock_int_WRK(self
, arg2
);
3159 QT5_FUNC(long, _ZN6QMutex7tryLockEi
, void* self
, long arg2
) {
3160 return QMutex_tryLock_int_WRK(self
, arg2
);
3163 //-----------------------------------------------------------
3164 // It's not really very clear what the args are here. But from
3165 // a bit of dataflow analysis of the generated machine code of
3166 // the original function, it appears this takes two args, and
3167 // returns nothing. Nevertheless preserve return value just in
3168 // case. A bit of debug printing indicates that the first arg
3169 // is that of the mutex and the second is either zero or one,
3170 // probably being the recursion mode, therefore.
3171 // QMutex::QMutex(QMutex::RecursionMode) ("C1ENS" variant)
3172 __attribute__((noinline
))
3173 static void* QMutex_constructor_WRK(void* mutex
, long recmode
)
3177 VALGRIND_GET_ORIG_FN(fn
);
3178 CALL_FN_W_WW(ret
, fn
, mutex
, recmode
);
3179 // fprintf(stderr, "QMutex constructor 1: %p <- %p %p\n", ret, arg1, arg2);
3180 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST
,
3181 void*,mutex
, long,1/*mbRec*/);
3185 QT4_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE
, void* self
, long recmode
) {
3186 return QMutex_constructor_WRK(self
, recmode
);
3188 QT5_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE
, void* self
, long recmode
) {
3189 return QMutex_constructor_WRK(self
, recmode
);
3192 //-----------------------------------------------------------
3193 // QMutex::~QMutex() ("D1Ev" variant)
3194 __attribute__((noinline
))
3195 static void* QMutex_destructor_WRK(void* mutex
)
3199 VALGRIND_GET_ORIG_FN(fn
);
3200 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE
,
3202 CALL_FN_W_W(ret
, fn
, mutex
);
3206 QT4_FUNC(void*, _ZN6QMutexD1Ev
, void* self
) {
3207 return QMutex_destructor_WRK(self
);
3209 QT5_FUNC(void*, _ZN6QMutexD1Ev
, void* self
) {
3210 return QMutex_destructor_WRK(self
);
3213 //-----------------------------------------------------------
3214 // QMutex::QMutex(QMutex::RecursionMode) ("C2ENS" variant)
3215 QT4_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE
,
3221 /* Android's gcc behaves like it doesn't know that assert(0)
3222 never returns. Hence: */
3226 QT5_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE
, void* self
, long recmode
)
3233 //-----------------------------------------------------------
3234 // QMutex::~QMutex() ("D2Ev" variant)
3235 QT4_FUNC(void*, _ZN6QMutexD2Ev
, void* mutex
)
3238 /* Android's gcc behaves like it doesn't know that assert(0)
3239 never returns. Hence: */
3243 QT5_FUNC(void*, _ZN6QMutexD2Ev
, void* self
)
3250 // QReadWriteLock is not intercepted directly. See comments
3253 //// QReadWriteLock::lockForRead()
3254 //// _ZN14QReadWriteLock11lockForReadEv == QReadWriteLock::lockForRead()
3255 //QT4_FUNC(void, ZuZZN14QReadWriteLock11lockForReadEv,
3256 // // _ZN14QReadWriteLock11lockForReadEv
3260 // VALGRIND_GET_ORIG_FN(fn);
3261 // if (TRACE_QT4_FNS) {
3262 // fprintf(stderr, "<< QReadWriteLock::lockForRead %p", self);
3266 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
3268 // long,0/*!isW*/, long,0/*!isTryLock*/);
3270 // CALL_FN_v_W(fn, self);
3272 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
3273 // void*,self, long,0/*!isW*/, long, True);
3275 // if (TRACE_QT4_FNS) {
3276 // fprintf(stderr, " :: Q::lockForRead :: done >>\n");
3280 //// QReadWriteLock::lockForWrite()
3281 //// _ZN14QReadWriteLock12lockForWriteEv == QReadWriteLock::lockForWrite()
3282 //QT4_FUNC(void, ZuZZN14QReadWriteLock12lockForWriteEv,
3283 // // _ZN14QReadWriteLock12lockForWriteEv
3287 // VALGRIND_GET_ORIG_FN(fn);
3288 // if (TRACE_QT4_FNS) {
3289 // fprintf(stderr, "<< QReadWriteLock::lockForWrite %p", self);
3293 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
3295 // long,1/*isW*/, long,0/*!isTryLock*/);
3297 // CALL_FN_v_W(fn, self);
3299 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
3300 // void*,self, long,1/*isW*/, long, True);
3302 // if (TRACE_QT4_FNS) {
3303 // fprintf(stderr, " :: Q::lockForWrite :: done >>\n");
3307 //// QReadWriteLock::unlock()
3308 //// _ZN14QReadWriteLock6unlockEv == QReadWriteLock::unlock()
3309 //QT4_FUNC(void, ZuZZN14QReadWriteLock6unlockEv,
3310 // // _ZN14QReadWriteLock6unlockEv
3314 // VALGRIND_GET_ORIG_FN(fn);
3315 // if (TRACE_QT4_FNS) {
3316 // fprintf(stderr, "<< QReadWriteLock::unlock %p", self);
3320 // DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
3323 // CALL_FN_v_W(fn, self);
3325 // DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
3328 // if (TRACE_QT4_FNS) {
3329 // fprintf(stderr, " :: Q::unlock :: done >>\n");
3334 /*----------------------------------------------------------------*/
3335 /*--- Replacements for basic string functions, that don't ---*/
3336 /*--- overrun the input arrays. ---*/
3337 /*----------------------------------------------------------------*/
3339 #include "../shared/vg_replace_strmem.c"
3341 /*--------------------------------------------------------------------*/
3342 /*--- end hg_intercepts.c ---*/
3343 /*--------------------------------------------------------------------*/