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, see <http://www.gnu.org/licenses/>.
27 The GNU General Public License is contained in the file COPYING.
29 Neither the names of the U.S. Department of Energy nor the
30 University of California nor the names of its contributors may be
31 used to endorse or promote products derived from this software
32 without prior written permission.
35 /* RUNS ON SIMULATED CPU
36 Interceptors for pthread_* functions, so that tc_main can see
37 significant thread events.
39 Important: when adding a function wrapper to this file, remember to
40 add a test case to tc20_verifywrap.c. A common cause of failure is
41 for wrappers to not engage on different distros, and
42 tc20_verifywrap essentially checks that each wrapper is really
46 // DDD: for Darwin, need to have non-"@*"-suffixed versions for all pthread
47 // functions that currently have them.
48 // Note also, in the comments and code below, all Darwin symbols start
49 // with a leading underscore, which is not shown either in the comments
50 // nor in the redirect specs.
53 #include "pub_tool_basics.h"
54 #include "pub_tool_redir.h"
55 #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 /* pthread_t is typedef'd to 'unsigned int' but in DO_CREQ_* macros
84 sizeof(Word) is expected. */
85 #define CREQ_PTHREAD_T Word
88 #define CREQ_PTHREAD_T pthread_t
89 #define SEM_ERROR errno
90 #endif /* VGO_solaris */
92 #define HG_EXPAND(tok) #tok
93 #define HG_STR(tok) HG_EXPAND(tok)
94 #define HG_WEAK_ALIAS(name, aliasname) \
95 extern __typeof (name) aliasname __attribute__ ((weak, alias(HG_STR(name))))
97 #if defined(VG_WRAP_THREAD_FUNCTION_LIBPTHREAD_ONLY)
98 #define PTH_FUNC(ret_ty, f, args...) \
99 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args); \
100 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args)
101 #elif defined(VG_WRAP_THREAD_FUNCTION_LIBC_AND_LIBPTHREAD)
102 #define PTH_FUNC(ret_ty, f, args...) \
103 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args); \
104 HG_WEAK_ALIAS(I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f), I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)); \
105 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args)
106 #elif defined(VG_WRAP_THREAD_FUNCTION_LIBC_ONLY)
107 #define PTH_FUNC(ret_ty, f, args...) \
108 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)(args); \
109 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)(args)
111 # error "Unknown platform/thread wrapping"
114 #if defined(VGO_freebsd)
115 #define LIBC_FUNC(ret_ty, f, args...) \
116 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)(args); \
117 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)(args)
119 #include <osreldate.h>
122 // Do a client request. These are macros rather than a functions so
123 // as to avoid having an extra frame in stack traces.
125 // NB: these duplicate definitions in helgrind.h. But here, we
126 // can have better typing (Word etc) and assertions, whereas
127 // in helgrind.h we can't. Obviously it's important the two
128 // sets of definitions are kept in sync.
130 // nuke the previous definitions
136 #define DO_CREQ_v_W(_creqF, _ty1F,_arg1F) \
139 STATIC_ASSERT(sizeof(_ty1F) == sizeof(Word)); \
140 _arg1 = (Word)(_arg1F); \
141 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
145 #define DO_CREQ_v_WW(_creqF, _ty1F,_arg1F, _ty2F,_arg2F) \
148 STATIC_ASSERT(sizeof(_ty1F) == sizeof(Word)); \
149 STATIC_ASSERT(sizeof(_ty2F) == sizeof(Word)); \
150 _arg1 = (Word)(_arg1F); \
151 _arg2 = (Word)(_arg2F); \
152 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
153 _arg1,_arg2,0,0,0); \
156 #define DO_CREQ_W_WW(_resF, _creqF, _ty1F,_arg1F, \
159 Word _res, _arg1, _arg2; \
160 STATIC_ASSERT(sizeof(_ty1F) == sizeof(Word)); \
161 STATIC_ASSERT(sizeof(_ty2F) == sizeof(Word)); \
162 _arg1 = (Word)(_arg1F); \
163 _arg2 = (Word)(_arg2F); \
164 _res = VALGRIND_DO_CLIENT_REQUEST_EXPR(2, \
166 _arg1,_arg2,0,0,0); \
170 #define DO_CREQ_v_WWW(_creqF, _ty1F,_arg1F, \
171 _ty2F,_arg2F, _ty3F, _arg3F) \
173 Word _arg1, _arg2, _arg3; \
174 STATIC_ASSERT(sizeof(_ty1F) == sizeof(Word)); \
175 STATIC_ASSERT(sizeof(_ty2F) == sizeof(Word)); \
176 STATIC_ASSERT(sizeof(_ty3F) == sizeof(Word)); \
177 _arg1 = (Word)(_arg1F); \
178 _arg2 = (Word)(_arg2F); \
179 _arg3 = (Word)(_arg3F); \
180 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
181 _arg1,_arg2,_arg3,0,0); \
184 #define DO_CREQ_v_WWWW(_creqF, _ty1F,_arg1F, \
185 _ty2F, _arg2F, _ty3F, _arg3F, \
188 Word _arg1, _arg2, _arg3, _arg4; \
189 STATIC_ASSERT(sizeof(_ty1F) == sizeof(Word)); \
190 STATIC_ASSERT(sizeof(_ty2F) == sizeof(Word)); \
191 STATIC_ASSERT(sizeof(_ty3F) == sizeof(Word)); \
192 STATIC_ASSERT(sizeof(_ty4F) == sizeof(Word)); \
193 _arg1 = (Word)(_arg1F); \
194 _arg2 = (Word)(_arg2F); \
195 _arg3 = (Word)(_arg3F); \
196 _arg4 = (Word)(_arg4F); \
197 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
198 _arg1,_arg2,_arg3,_arg4,0); \
201 #define DO_PthAPIerror(_fnnameF, _errF) \
203 const char* _fnname = (_fnnameF); \
204 long _err = (long)(int)(_errF); \
205 const char* _errstr = lame_strerror(_err); \
206 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTH_API_ERROR, \
208 long,_err, char*,_errstr); \
212 /* Needed for older glibcs (2.3 and older, at least) who don't
213 otherwise "know" about pthread_rwlock_anything or about
214 PTHREAD_MUTEX_RECURSIVE (amongst things). */
215 #define _GNU_SOURCE 1
222 /* A standalone memcmp. */
223 __attribute__((noinline
))
224 static int my_memcmp ( const void* ptr1
, const void* ptr2
, size_t size
)
226 const unsigned char* uchar_ptr1
= (const unsigned char*) ptr1
;
227 const unsigned char* uchar_ptr2
= (const unsigned char*) ptr2
;
229 for (i
= 0; i
< size
; ++i
) {
230 if (uchar_ptr1
[i
] != uchar_ptr2
[i
])
231 return (uchar_ptr1
[i
] < uchar_ptr2
[i
]) ? -1 : 1;
236 /* A lame version of strerror which doesn't use the real libc
237 strerror_r, since using the latter just generates endless more
238 threading errors (glibc goes off and does tons of crap w.r.t.
240 static const HChar
* lame_strerror ( long err
)
243 case EPERM
: return "EPERM: Operation not permitted";
244 case ENOENT
: return "ENOENT: No such file or directory";
245 case ESRCH
: return "ESRCH: No such process";
246 case EINTR
: return "EINTR: Interrupted system call";
247 case EBADF
: return "EBADF: Bad file number";
248 case EAGAIN
: return "EAGAIN: Try again";
249 case ENOMEM
: return "ENOMEM: Out of memory";
250 case EACCES
: return "EACCES: Permission denied";
251 case EFAULT
: return "EFAULT: Bad address";
252 case EEXIST
: return "EEXIST: File exists";
253 case EINVAL
: return "EINVAL: Invalid argument";
254 case EMFILE
: return "EMFILE: Too many open files";
255 case ENOSYS
: return "ENOSYS: Function not implemented";
256 case EOVERFLOW
: return "EOVERFLOW: Value too large "
257 "for defined data type";
258 case EBUSY
: return "EBUSY: Device or resource busy";
259 case ETIMEDOUT
: return "ETIMEDOUT: Connection timed out";
260 case EDEADLK
: return "EDEADLK: Resource deadlock would occur";
261 case EOPNOTSUPP
: return "EOPNOTSUPP: Operation not supported on "
262 "transport endpoint"; /* honest, guv */
263 #if !defined(VGO_freebsd)
264 case ETIME
: return "ETIME: Timer expired";
266 default: return "hg_intercepts.c: lame_strerror(): "
267 "unhandled case -- please fix me!";
271 #if defined(VGO_solaris)
273 * Solaris provides higher throughput, parallelism and scalability than other
274 * operating systems, at the cost of more fine-grained locking activity.
275 * This means for example that when a thread is created under Linux, just one
276 * big lock in glibc is used for all thread setup. Solaris libc uses several
277 * fine-grained locks and the creator thread resumes its activities as soon
278 * as possible, leaving for example stack and TLS setup activities to the
281 * This situation confuses Helgrind as it assumes there is some false ordering
282 * in place between creator and created thread; and therefore many types of
283 * race conditions in the application would not be reported. To prevent such
284 * false ordering, command line option --ignore-thread-creation is set to
285 * 'yes' by default on Solaris. All activity (loads, stores, client requests)
286 * is therefore ignored during:
287 * - pthread_create() call in the creator thread [libc.so]
288 * - thread creation phase (stack and TLS setup) in the created thread [libc.so]
290 * As explained in the comments for _ti_bind_guard(), whenever the runtime
291 * linker has to perform any activity (such as resolving a symbol), it protects
292 * its data structures by calling into rt_bind_guard() which in turn invokes
293 * _ti_bind_guard() in libc. Pointers to _ti_bind_guard() and _ti_bind_clear()
294 * are passed from libc to runtime linker in _ld_libc() call during libc_init().
295 * All activity is also ignored during:
296 * - runtime dynamic linker work between rt_bind_guard() and rt_bind_clear()
299 * This also means that Helgrind does not report race conditions in libc (when
300 * --ignore-thread-creation=yes) and runtime linker itself (unconditionally)
301 * during these ignored sequences.
304 #include "pub_tool_libcassert.h"
305 #include "pub_tool_vki.h"
308 * Original function pointers for _ti_bind_guard() and _ti_bind_clear()
309 * from libc. They are intercepted in function wrapper of _ld_libc().
311 typedef int (*hg_rtld_guard_fn
)(int flags
);
312 static hg_rtld_guard_fn hg_rtld_bind_guard
= NULL
;
313 static hg_rtld_guard_fn hg_rtld_bind_clear
= NULL
;
315 static void hg_init(void) __attribute__((constructor
));
316 static void hg_init(void)
318 if ((hg_rtld_bind_guard
== NULL
) || (hg_rtld_bind_clear
== NULL
)) {
320 "Bind guard functions for the runtime linker (ld.so.1) were not intercepted.\n"
321 "This means the interface between libc and runtime linker changed\n"
322 "and Helgrind needs to be ported properly. Giving up.\n");
328 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
329 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
330 * and CI_BIND_CLEAR, to provide resilience against function renaming.
332 static int _ti_bind_guard_intercept_WRK(int flags
)
334 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_RTLD_BIND_GUARD
,
336 return hg_rtld_bind_guard(flags
);
339 static int _ti_bind_clear_intercept_WRK(int flags
)
341 int ret
= hg_rtld_bind_clear(flags
);
342 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_RTLD_BIND_CLEAR
,
348 * Wrapped _ld_libc() from the runtime linker ld.so.1.
350 void I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LD_SO_1
, ZuldZulibc
)(vki_Lc_interface
*ptr
);
351 void I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LD_SO_1
, ZuldZulibc
)(vki_Lc_interface
*ptr
)
356 VALGRIND_GET_ORIG_FN(fn
);
358 vki_Lc_interface
*funcs
= ptr
;
359 for (tag
= funcs
->ci_tag
; tag
!= 0; tag
= (++funcs
)->ci_tag
) {
361 case VKI_CI_BIND_GUARD
:
362 if (funcs
->vki_ci_un
.ci_func
!= _ti_bind_guard_intercept_WRK
) {
363 hg_rtld_bind_guard
= funcs
->vki_ci_un
.ci_func
;
364 funcs
->vki_ci_un
.ci_func
= _ti_bind_guard_intercept_WRK
;
367 case VKI_CI_BIND_CLEAR
:
368 if (funcs
->vki_ci_un
.ci_func
!= _ti_bind_clear_intercept_WRK
) {
369 hg_rtld_bind_clear
= funcs
->vki_ci_un
.ci_func
;
370 funcs
->vki_ci_un
.ci_func
= _ti_bind_clear_intercept_WRK
;
376 CALL_FN_v_W(fn
, ptr
);
378 #endif /* VGO_solaris */
381 /*----------------------------------------------------------------*/
382 /*--- pthread_create, pthread_join, pthread_exit ---*/
383 /*----------------------------------------------------------------*/
385 static void* mythread_wrapper ( void* xargsV
)
387 volatile Word
* xargs
= (volatile Word
*) xargsV
;
388 void*(*fn
)(void*) = (void*(*)(void*))xargs
[0];
389 void* arg
= (void*)xargs
[1];
390 pthread_t me
= pthread_self();
391 /* Tell the tool what my pthread_t is. */
392 DO_CREQ_v_W(_VG_USERREQ__HG_SET_MY_PTHREAD_T
, CREQ_PTHREAD_T
, me
);
393 /* allow the parent to proceed. We can't let it proceed until
394 we're ready because (1) we need to make sure it doesn't exit and
395 hence deallocate xargs[] while we still need it, and (2) we
396 don't want either parent nor child to proceed until the tool has
397 been notified of the child's pthread_t.
399 Note that parent and child access args[] without a lock,
400 effectively using args[2] as a spinlock in order to get the
401 parent to wait until the child passes this point. The parent
402 disables checking on xargs[] before creating the child and
403 re-enables it once the child goes past this point, so the user
404 never sees the race. The previous approach (suppressing the
405 resulting error) was flawed, because it could leave shadow
406 memory for args[] in a state in which subsequent use of it by
407 the parent would report further races. */
409 /* Now we can no longer safely use xargs[]. */
410 return (void*) fn( (void*)arg
);
413 //-----------------------------------------------------------
414 // glibc: pthread_create@GLIBC_2.0
415 // glibc: pthread_create@@GLIBC_2.1
416 // glibc: pthread_create@@GLIBC_2.2.5
417 // darwin: pthread_create
418 // darwin: pthread_create_suspended_np (trapped)
419 // FreeBSD: pthread_create
421 /* ensure this has its own frame, so as to make it more distinguishable
423 __attribute__((noinline
))
424 static int pthread_create_WRK(pthread_t
*thread
, const pthread_attr_t
*attr
,
425 void *(*start
) (void *), void *arg
)
429 volatile Word xargs
[3];
431 VALGRIND_GET_ORIG_FN(fn
);
433 fprintf(stderr
, "<< pthread_create wrapper"); fflush(stderr
);
435 xargs
[0] = (Word
)start
;
436 xargs
[1] = (Word
)arg
;
437 xargs
[2] = 1; /* serves as a spinlock -- sigh */
438 /* Disable checking on the spinlock and the two words used to
439 convey args to the child. Basically we need to make it appear
440 as if the child never accessed this area, since merely
441 suppressing the resulting races does not address the issue that
442 that piece of the parent's stack winds up in the "wrong" state
443 and therefore may give rise to mysterious races when the parent
444 comes to re-use this piece of stack in some other frame. */
445 VALGRIND_HG_DISABLE_CHECKING(&xargs
, sizeof(xargs
));
447 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_BEGIN
,
449 CALL_FN_W_WWWW(ret
, fn
, thread
,attr
,mythread_wrapper
,&xargs
[0]);
450 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_END
,
454 /* we have to wait for the child to notify the tool of its
455 pthread_t before continuing */
456 while (xargs
[2] != 0) {
457 /* Do nothing. We need to spin until the child writes to
458 xargs[2]. However, that can lead to starvation in the
459 child and very long delays (eg, tc19_shadowmem on
460 ppc64-linux Fedora Core 6). So yield the cpu if we can,
461 to let the child run at the earliest available
466 DO_PthAPIerror( "pthread_create", ret
);
469 /* Reenable checking on the area previously used to communicate
471 VALGRIND_HG_ENABLE_CHECKING(&xargs
, sizeof(xargs
));
474 fprintf(stderr
, " :: pth_create -> %d >>\n", ret
);
478 #if defined(VGO_linux)
479 PTH_FUNC(int, pthreadZucreateZAZa
, // pthread_create@*
480 pthread_t
*thread
, const pthread_attr_t
*attr
,
481 void *(*start
) (void *), void *arg
) {
482 return pthread_create_WRK(thread
, attr
, start
, arg
);
484 #elif defined(VGO_freebsd)
485 PTH_FUNC(int, pthreadZucreate
, // pthread_create
486 pthread_t
*thread
, const pthread_attr_t
*attr
,
487 void *(*start
) (void *), void *arg
) {
488 return pthread_create_WRK(thread
, attr
, start
, arg
);
490 #elif defined(VGO_darwin)
491 PTH_FUNC(int, pthreadZucreate
, // pthread_create
492 pthread_t
*thread
, const pthread_attr_t
*attr
,
493 void *(*start
) (void *), void *arg
) {
494 return pthread_create_WRK(thread
, attr
, start
, arg
);
496 PTH_FUNC(int, pthreadZucreateZuZa
, // pthread_create_*
497 pthread_t
*thread
, const pthread_attr_t
*attr
,
498 void *(*start
) (void *), void *arg
) {
499 // trap anything else
502 #elif defined(VGO_solaris)
503 PTH_FUNC(int, pthreadZucreate
, // pthread_create
504 pthread_t
*thread
, const pthread_attr_t
*attr
,
505 void *(*start
) (void *), void *arg
) {
506 return pthread_create_WRK(thread
, attr
, start
, arg
);
509 # error "Unsupported OS"
512 #if defined(VGO_solaris)
513 /* Solaris also provides thr_create() in addition to pthread_create().
514 * Both pthread_create(3C) and thr_create(3C) are based on private
517 __attribute__((noinline
))
518 static int thr_create_WRK(void *stk
, size_t stksize
, void *(*start
)(void *),
519 void *arg
, long flags
, thread_t
*new_thread
)
523 volatile Word xargs
[3];
525 VALGRIND_GET_ORIG_FN(fn
);
527 fprintf(stderr
, "<< thr_create wrapper"); fflush(stderr
);
529 xargs
[0] = (Word
)start
;
530 xargs
[1] = (Word
)arg
;
531 xargs
[2] = 1; /* serves as a spinlock -- sigh */
532 /* See comments in pthread_create_WRK() */
533 VALGRIND_HG_DISABLE_CHECKING(&xargs
, sizeof(xargs
));
535 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_BEGIN
,
537 CALL_FN_W_6W(ret
, fn
, stk
, stksize
, mythread_wrapper
, start
, flags
,
539 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_END
,
543 while (xargs
[2] != 0) {
544 /* See comments in pthread_create_WRK(). */
548 DO_PthAPIerror("thr_create", ret
);
551 VALGRIND_HG_ENABLE_CHECKING(&xargs
, sizeof(xargs
));
554 fprintf(stderr
, " :: thr_create -> %d >>\n", ret
);
558 PTH_FUNC(int, thrZucreate
, // thr_create
559 void *stk
, size_t stksize
, void *(*start
)(void *),
560 void *arg
, long flags
, thread_t
*new_thread
) {
561 return thr_create_WRK(stk
, stksize
, start
, arg
, flags
, new_thread
);
563 #endif /* VGO_solaris */
566 //-----------------------------------------------------------
567 // glibc: pthread_join
568 // darwin: pthread_join
569 // darwin: pthread_join$NOCANCEL$UNIX2003
570 // darwin pthread_join$UNIX2003
571 // FreeBSD: pthread_join
572 __attribute__((noinline
))
573 static int pthread_join_WRK(pthread_t thread
, void** value_pointer
)
577 VALGRIND_GET_ORIG_FN(fn
);
579 fprintf(stderr
, "<< pthread_join wrapper"); fflush(stderr
);
582 CALL_FN_W_WW(ret
, fn
, thread
,value_pointer
);
584 /* At least with NPTL as the thread library, this is safe because
585 it is guaranteed (by NPTL) that the joiner will completely gone
586 before pthread_join (the original) returns. See email below.*/
587 if (ret
== 0 /*success*/) {
588 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST
, CREQ_PTHREAD_T
, thread
);
590 DO_PthAPIerror( "pthread_join", ret
);
594 fprintf(stderr
, " :: pth_join -> %d >>\n", ret
);
598 #if defined(VGO_linux)
599 PTH_FUNC(int, pthreadZujoin
, // pthread_join
600 pthread_t thread
, void** value_pointer
) {
601 return pthread_join_WRK(thread
, value_pointer
);
603 #elif defined(VGO_freebsd)
604 PTH_FUNC(int, pthreadZujoin
, // pthread_join
605 pthread_t thread
, void** value_pointer
) {
606 return pthread_join_WRK(thread
, value_pointer
);
608 #elif defined(VGO_darwin)
609 PTH_FUNC(int, pthreadZujoinZa
, // pthread_join*
610 pthread_t thread
, void** value_pointer
) {
611 return pthread_join_WRK(thread
, value_pointer
);
613 #elif defined(VGO_solaris)
614 PTH_FUNC(int, pthreadZujoin
, // pthread_join
615 pthread_t thread
, void** value_pointer
) {
616 return pthread_join_WRK(thread
, value_pointer
);
619 # error "Unsupported OS"
623 /* Behaviour of pthread_join on NPTL:
626 I have a question re the NPTL pthread_join implementation.
628 Suppose I am the thread 'stayer'.
630 If I call pthread_join(quitter), is it guaranteed that the
631 thread 'quitter' has really exited before pthread_join returns?
633 IOW, is it guaranteed that 'quitter' will not execute any further
634 instructions after pthread_join returns?
636 I believe this is true based on the following analysis of
637 glibc-2.5 sources. However am not 100% sure and would appreciate
640 'quitter' will be running start_thread() in nptl/pthread_create.c
642 The last action of start_thread() is to exit via
643 __exit_thread_inline(0), which simply does sys_exit
644 (nptl/pthread_create.c:403)
646 'stayer' meanwhile is waiting for lll_wait_tid (pd->tid)
647 (call at nptl/pthread_join.c:89)
649 As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
650 lll_wait_tid will not return until kernel notifies via futex
651 wakeup that 'quitter' has terminated.
653 Hence pthread_join cannot return until 'quitter' really has
654 completely disappeared.
657 > As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
658 > lll_wait_tid will not return until kernel notifies via futex
659 > wakeup that 'quitter' has terminated.
660 That's the key. The kernel resets the TID field after the thread is
661 done. No way the joiner can return before the thread is gone.
664 #if defined(VGO_solaris)
665 /* Solaris also provides thr_join() in addition to pthread_join().
666 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
668 * :TODO: No functionality is currently provided for joinee == 0 and departed.
669 * This would require another client request, of course.
671 __attribute__((noinline
))
672 static int thr_join_WRK(thread_t joinee
, thread_t
*departed
, void **thread_return
)
676 VALGRIND_GET_ORIG_FN(fn
);
678 fprintf(stderr
, "<< thr_join wrapper"); fflush(stderr
);
681 CALL_FN_W_WWW(ret
, fn
, joinee
, departed
, thread_return
);
683 if (ret
== 0 /*success*/) {
684 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST
, CREQ_PTHREAD_T
, joinee
);
686 DO_PthAPIerror("thr_join", ret
);
690 fprintf(stderr
, " :: thr_join -> %d >>\n", ret
);
694 PTH_FUNC(int, thrZujoin
, // thr_join
695 thread_t joinee
, thread_t
*departed
, void **thread_return
) {
696 return thr_join_WRK(joinee
, departed
, thread_return
);
698 #endif /* VGO_solaris */
701 //-----------------------------------------------------------
702 // Ada gcc gnat runtime:
703 // The gnat gcc Ada runtime does not use pthread_join. Instead, it uses
704 // a combination of other pthread primitives to ensure a child thread
705 // is gone. This combination is somewhat functionally equivalent to a
707 // We wrap two hook procedures called by the gnat gcc Ada runtime
708 // that allows helgrind to understand the semantic of Ada task dependencies
710 // procedure Master_Hook
711 // (Dependent : Task_Id;
713 // Master_Level : Integer);
714 // where type Task_Id is access all Ada_Task_Control_Block;
715 // System.Tasking.Debug.Master_Hook is called by a task Dependent to
716 // indicate that its master is identified by master+master_level.
717 void I_WRAP_SONAME_FNNAME_ZU
719 system__tasking__debug__master_hook
)
720 (void *dependent
, void *master
, int master_level
);
721 void I_WRAP_SONAME_FNNAME_ZU
723 system__tasking__debug__master_hook
)
724 (void *dependent
, void *master
, int master_level
)
727 VALGRIND_GET_ORIG_FN(fn
);
728 if (TRACE_GNAT_FNS
) {
729 fprintf(stderr
, "<< GNAT master_hook wrapper "
730 "dependent %p master %p master_level %d\n",
731 dependent
, master
, master_level
); fflush(stderr
);
734 // We call the wrapped function, even if it is a null body.
735 CALL_FN_v_WWW(fn
, dependent
, master
, master_level
);
737 DO_CREQ_v_WWW(_VG_USERREQ__HG_GNAT_MASTER_HOOK
,
738 void*,dependent
, void*,master
,
739 Word
, (Word
)master_level
);
741 if (TRACE_GNAT_FNS
) {
742 fprintf(stderr
, " :: GNAT master_hook >>\n");
746 // System.Tasking.Debug.Master_Completed_Hook is called by a task to
747 // indicate that it has completed a master.
748 // procedure Master_Completed_Hook
749 // (Self_ID : Task_Id;
750 // Master_Level : Integer);
751 // where type Task_Id is access all Ada_Task_Control_Block;
752 // This indicates that all its Dependent tasks (that identified themselves
753 // with the Master_Hook call) are terminated. Helgrind can consider
754 // at this point that the equivalent of a 'pthread_join' has been done
755 // between self_id and all dependent tasks at master_level.
756 void I_WRAP_SONAME_FNNAME_ZU
758 system__tasking__debug__master_completed_hook
)
759 (void *self_id
, int master_level
);
760 void I_WRAP_SONAME_FNNAME_ZU
762 system__tasking__debug__master_completed_hook
)
763 (void *self_id
, int master_level
)
766 VALGRIND_GET_ORIG_FN(fn
);
767 if (TRACE_GNAT_FNS
) {
768 fprintf(stderr
, "<< GNAT master_completed_hook wrapper "
769 "self_id %p master_level %d\n",
770 self_id
, master_level
); fflush(stderr
);
773 // We call the wrapped function, even if it is a null body.
774 CALL_FN_v_WW(fn
, self_id
, master_level
);
776 DO_CREQ_v_WW(_VG_USERREQ__HG_GNAT_MASTER_COMPLETED_HOOK
,
777 void*,self_id
, Word
,(Word
)master_level
);
779 if (TRACE_GNAT_FNS
) {
780 fprintf(stderr
, " :: GNAT master_completed_hook >>\n");
784 /*----------------------------------------------------------------*/
785 /*--- pthread_mutex_t functions ---*/
786 /*----------------------------------------------------------------*/
788 /* Handled: pthread_mutex_init pthread_mutex_destroy
790 pthread_mutex_trylock pthread_mutex_timedlock
794 //-----------------------------------------------------------
795 #if !defined(VGO_solaris)
796 // glibc: pthread_mutex_init
797 // darwin: pthread_mutex_init
798 // FreeBSD: pthread_mutex_init
799 PTH_FUNC(int, pthreadZumutexZuinit
, // pthread_mutex_init
800 pthread_mutex_t
*mutex
,
801 pthread_mutexattr_t
* attr
)
806 VALGRIND_GET_ORIG_FN(fn
);
808 fprintf(stderr
, "<< pthread_mxinit %p", mutex
); fflush(stderr
);
814 zzz
= pthread_mutexattr_gettype(attr
, &ty
);
815 if (zzz
== 0 && ty
== PTHREAD_MUTEX_RECURSIVE
)
819 CALL_FN_W_WW(ret
, fn
, mutex
,attr
);
821 if (ret
== 0 /*success*/) {
822 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST
,
823 pthread_mutex_t
*,mutex
, long,mbRec
);
825 DO_PthAPIerror( "pthread_mutex_init", ret
);
829 fprintf(stderr
, " :: mxinit -> %d >>\n", ret
);
834 #else /* VGO_solaris */
836 // Solaris: mutex_init (pthread_mutex_init calls here)
837 PTH_FUNC(int, mutexZuinit
, // mutex_init
838 mutex_t
*mutex
, int type
, void *arg
)
843 VALGRIND_GET_ORIG_FN(fn
);
845 fprintf(stderr
, "<< mxinit %p", mutex
); fflush(stderr
);
848 mbRec
= ((type
& LOCK_RECURSIVE
) != 0) ? 1 : 0;
850 CALL_FN_W_WWW(ret
, fn
, mutex
, type
, arg
);
852 if (ret
== 0 /*success*/) {
853 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST
,
854 mutex_t
*, mutex
, long, mbRec
);
856 DO_PthAPIerror("mutex_init", ret
);
860 fprintf(stderr
, " :: mxinit -> %d >>\n", ret
);
864 #endif /* VGO_solaris */
867 //-----------------------------------------------------------
868 // glibc: pthread_mutex_destroy
869 // darwin: pthread_mutex_destroy
870 // Solaris: mutex_destroy (pthread_mutex_destroy is a weak alias)
871 // FreeBSD: pthread_mutex_destroy
872 __attribute__((noinline
))
873 static int mutex_destroy_WRK(pthread_mutex_t
*mutex
)
876 unsigned long mutex_is_init
;
879 VALGRIND_GET_ORIG_FN(fn
);
881 fprintf(stderr
, "<< pthread_mxdestroy %p", mutex
); fflush(stderr
);
885 static const pthread_mutex_t mutex_init
= PTHREAD_MUTEX_INITIALIZER
;
886 VALGRIND_HG_DISABLE_CHECKING(mutex
, sizeof(*mutex
));
887 mutex_is_init
= my_memcmp(mutex
, &mutex_init
, sizeof(*mutex
)) == 0;
888 VALGRIND_HG_ENABLE_CHECKING(mutex
, sizeof(*mutex
));
893 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE
,
894 pthread_mutex_t
*, mutex
, unsigned long, mutex_is_init
);
896 CALL_FN_W_W(ret
, fn
, mutex
);
899 DO_PthAPIerror( "pthread_mutex_destroy", ret
);
903 fprintf(stderr
, " :: mxdestroy -> %d >>\n", ret
);
908 #if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd)
909 PTH_FUNC(int, pthreadZumutexZudestroy
, // pthread_mutex_destroy
910 pthread_mutex_t
*mutex
) {
911 return mutex_destroy_WRK(mutex
);
913 #elif defined(VGO_solaris)
914 PTH_FUNC(int, mutexZudestroy
, // mutex_destroy
915 pthread_mutex_t
*mutex
) {
916 return mutex_destroy_WRK(mutex
);
919 # error "Unsupported OS"
922 #if defined(VGO_freebsd)
928 * FreeBSD 15 (backported to 14.2) add a mutex lock to
929 * exit to ensure that it is thread-safe. But this lock
930 * never gets unlocked. That meant this lock was causing
931 * all threaded apps to generate a Helgrind still holding
932 * lock errors. So in time honoured tradition, this can
933 * be fixed with a hack. This adds a wrapper to exit()
934 * that sets a global variable hg_in_exit. In the next
935 * call to pthread_mutex_lock, if that variable is 1
936 * then the pthread_mutex_lock wrapper only calls the
937 * wrapped function. It does not call the PRE and POST
938 * userreq functions. It then resets hg_in_exit to 0
939 * (because there will be more locks in the atexit
945 static int exit_WRK(int status
)
949 VALGRIND_GET_ORIG_FN(fn
);
951 #if (__FreeBSD_version >= 1401500)
955 CALL_FN_W_W(ret
, fn
, status
);
960 LIBC_FUNC(int, exit
, int res
) {
961 return exit_WRK(res
);
967 //-----------------------------------------------------------
968 // glibc: pthread_mutex_lock
969 // darwin: pthread_mutex_lock
970 // Solaris: mutex_lock (pthread_mutex_lock is a weak alias)
971 // FreeBSD: pthread_mutex_lock
972 __attribute__((noinline
))
973 static int mutex_lock_WRK(pthread_mutex_t
*mutex
)
977 VALGRIND_GET_ORIG_FN(fn
);
980 snprintf(buf
, 30, "<< pthread_mxlock %p", mutex
);
981 (void)write(STDERR_FILENO
, buf
, strlen(buf
));
982 fsync(STDERR_FILENO
);
985 #if defined(VGO_freebsd)
987 CALL_FN_W_W(ret
, fn
, mutex
);
989 goto HG_MUTEX_LOCK_OUT
;
993 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
994 pthread_mutex_t
*,mutex
, long,0/*!isTryLock*/);
996 CALL_FN_W_W(ret
, fn
, mutex
);
998 /* There's a hole here: libpthread now knows the lock is locked,
999 but the tool doesn't, so some other thread could run and detect
1000 that the lock has been acquired by someone (this thread). Does
1001 this matter? Not sure, but I don't think so. */
1003 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
1004 pthread_mutex_t
*, mutex
, long, (ret
== 0) ? True
: False
);
1006 #if defined(VGO_freebsd)
1011 DO_PthAPIerror( "pthread_mutex_lock", ret
);
1014 if (TRACE_PTH_FNS
) {
1016 snprintf(buf
, 30, " :: mxlock -> %d >>\n", ret
);
1017 (void)write(STDERR_FILENO
, buf
, strlen(buf
));
1022 #if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd)
1023 PTH_FUNC(int, pthreadZumutexZulock
, // pthread_mutex_lock
1024 pthread_mutex_t
*mutex
) {
1025 return mutex_lock_WRK(mutex
);
1027 #elif defined(VGO_solaris)
1028 PTH_FUNC(int, mutexZulock
, // mutex_lock
1029 pthread_mutex_t
*mutex
) {
1030 return mutex_lock_WRK(mutex
);
1033 # error "Unsupported OS"
1036 #if defined(VGO_solaris)
1037 /* Internal to libc. Mutex is usually initialized only implicitly,
1038 * by zeroing mutex_t structure.
1040 __attribute__((noinline
))
1041 PTH_FUNC(void, lmutexZulock
, // lmutex_lock
1045 VALGRIND_GET_ORIG_FN(fn
);
1046 if (TRACE_PTH_FNS
) {
1047 fprintf(stderr
, "<< lmxlock %p", mutex
); fflush(stderr
);
1050 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
1051 mutex_t
*, mutex
, long, 0 /*!isTryLock*/);
1052 CALL_FN_v_W(fn
, mutex
);
1053 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
1054 mutex_t
*, mutex
, long, True
);
1056 if (TRACE_PTH_FNS
) {
1057 fprintf(stderr
, " :: lmxlock >>\n");
1060 #endif /* VGO_solaris */
1063 //-----------------------------------------------------------
1064 // glibc: pthread_mutex_trylock
1065 // darwin: pthread_mutex_trylock
1066 // Solaris: mutex_trylock (pthread_mutex_trylock is a weak alias)
1067 // FreeBSD: pthread_mutext_trylock
1069 // pthread_mutex_trylock. The handling needed here is very similar
1070 // to that for pthread_mutex_lock, except that we need to tell
1071 // the pre-lock creq that this is a trylock-style operation, and
1072 // therefore not to complain if the lock is nonrecursive and
1073 // already locked by this thread -- because then it'll just fail
1074 // immediately with EBUSY.
1075 __attribute__((noinline
))
1076 static int mutex_trylock_WRK(pthread_mutex_t
*mutex
)
1080 VALGRIND_GET_ORIG_FN(fn
);
1081 if (TRACE_PTH_FNS
) {
1082 fprintf(stderr
, "<< pthread_mxtrylock %p", mutex
); fflush(stderr
);
1085 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
1086 pthread_mutex_t
*,mutex
, long,1/*isTryLock*/);
1088 CALL_FN_W_W(ret
, fn
, mutex
);
1090 /* There's a hole here: libpthread now knows the lock is locked,
1091 but the tool doesn't, so some other thread could run and detect
1092 that the lock has been acquired by someone (this thread). Does
1093 this matter? Not sure, but I don't think so. */
1095 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
1096 pthread_mutex_t
*, mutex
, long, (ret
== 0) ? True
: False
);
1100 DO_PthAPIerror( "pthread_mutex_trylock", ret
);
1103 if (TRACE_PTH_FNS
) {
1104 fprintf(stderr
, " :: mxtrylock -> %d >>\n", ret
);
1109 #if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd)
1110 PTH_FUNC(int, pthreadZumutexZutrylock
, // pthread_mutex_trylock
1111 pthread_mutex_t
*mutex
) {
1112 return mutex_trylock_WRK(mutex
);
1114 #elif defined(VGO_solaris)
1115 PTH_FUNC(int, mutexZutrylock
, // mutex_trylock
1116 pthread_mutex_t
*mutex
) {
1117 return mutex_trylock_WRK(mutex
);
1120 # error "Unsupported OS"
1124 //-----------------------------------------------------------
1125 // glibc: pthread_mutex_timedlock
1126 // darwin: (doesn't appear to exist)
1127 // Solaris: pthread_mutex_timedlock
1128 // FreeBSD: pthread_mutex_timedlock
1130 // pthread_mutex_timedlock. Identical logic to pthread_mutex_trylock.
1131 __attribute__((noinline
))
1132 static int mutex_timedlock_WRK(pthread_mutex_t
*mutex
,
1137 VALGRIND_GET_ORIG_FN(fn
);
1138 if (TRACE_PTH_FNS
) {
1139 fprintf(stderr
, "<< pthread_mxtimedlock %p %p", mutex
, timeout
);
1143 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
1144 pthread_mutex_t
*,mutex
, long,1/*isTryLock-ish*/);
1146 CALL_FN_W_WW(ret
, fn
, mutex
,timeout
);
1148 /* There's a hole here: libpthread now knows the lock is locked,
1149 but the tool doesn't, so some other thread could run and detect
1150 that the lock has been acquired by someone (this thread). Does
1151 this matter? Not sure, but I don't think so. */
1153 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
1154 pthread_mutex_t
*, mutex
, long, (ret
== 0) ? True
: False
);
1157 if (ret
!= ETIMEDOUT
)
1158 DO_PthAPIerror( "pthread_mutex_timedlock", ret
);
1161 if (TRACE_PTH_FNS
) {
1162 fprintf(stderr
, " :: mxtimedlock -> %d >>\n", ret
);
1167 PTH_FUNC(int, pthreadZumutexZutimedlock
, // pthread_mutex_timedlock
1168 pthread_mutex_t
*mutex
,
1170 return mutex_timedlock_WRK(mutex
, timeout
);
1172 #if defined(VGO_solaris)
1173 PTH_FUNC(int, pthreadZumutexZureltimedlock
, // pthread_mutex_reltimedlock
1174 pthread_mutex_t
*mutex
,
1176 return mutex_timedlock_WRK(mutex
, timeout
);
1180 #if defined(VGO_linux)
1181 //-----------------------------------------------------------
1182 // glibc: pthread_mutex_clocklock
1184 // pthread_mutex_clocklock. Identical logic to pthread_mutex_timedlock.
1185 __attribute__((noinline
))
1186 static int mutex_clocklock_WRK(pthread_mutex_t
*mutex
,
1192 VALGRIND_GET_ORIG_FN(fn
);
1193 if (TRACE_PTH_FNS
) {
1194 fprintf(stderr
, "<< pthread_mxclocklock %p %p", mutex
, timeout
);
1198 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
1199 pthread_mutex_t
*,mutex
, long,1/*isTryLock-ish*/);
1201 CALL_FN_W_WWW(ret
, fn
, mutex
, clockid
, timeout
);
1203 /* There's a hole here: libpthread now knows the lock is locked,
1204 but the tool doesn't, so some other thread could run and detect
1205 that the lock has been acquired by someone (this thread). Does
1206 this matter? Not sure, but I don't think so. */
1208 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
1209 pthread_mutex_t
*, mutex
, long, (ret
== 0) ? True
: False
);
1212 if (ret
!= ETIMEDOUT
)
1213 DO_PthAPIerror( "pthread_mutex_clocklock", ret
);
1216 if (TRACE_PTH_FNS
) {
1217 fprintf(stderr
, " :: mxclocklock -> %d >>\n", ret
);
1222 PTH_FUNC(int, pthreadZumutexZuclocklock
, // pthread_mutex_clocklock
1223 pthread_mutex_t
*mutex
,
1226 return mutex_clocklock_WRK(mutex
, clockid
, timeout
);
1230 //-----------------------------------------------------------
1231 // glibc: pthread_mutex_unlock
1232 // darwin: pthread_mutex_unlock
1233 // Solaris: mutex_unlock (pthread_mutex_unlock is a weak alias)
1234 // FreeBSD: pthread_mutex_unlock
1235 __attribute__((noinline
))
1236 static int mutex_unlock_WRK(pthread_mutex_t
*mutex
)
1240 VALGRIND_GET_ORIG_FN(fn
);
1242 if (TRACE_PTH_FNS
) {
1244 snprintf(buf
, 30, "<< pthread_mxunlk %p", mutex
);
1245 (void)write(STDERR_FILENO
, buf
, strlen(buf
));
1246 fsync(STDERR_FILENO
);
1249 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE
,
1250 pthread_mutex_t
*,mutex
);
1252 CALL_FN_W_W(ret
, fn
, mutex
);
1254 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST
,
1255 pthread_mutex_t
*,mutex
);
1258 DO_PthAPIerror( "pthread_mutex_unlock", ret
);
1261 if (TRACE_PTH_FNS
) {
1263 snprintf(buf
, 30, " :: mxunlk -> %d >>\n", ret
);
1264 (void)write(STDERR_FILENO
, buf
, strlen(buf
));
1269 #if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd)
1270 PTH_FUNC(int, pthreadZumutexZuunlock
, // pthread_mutex_unlock
1271 pthread_mutex_t
*mutex
) {
1272 return mutex_unlock_WRK(mutex
);
1274 #elif defined(VGO_solaris)
1275 PTH_FUNC(int, mutexZuunlock
, // mutex_unlock
1276 pthread_mutex_t
*mutex
) {
1277 return mutex_unlock_WRK(mutex
);
1280 # error "Unsupported OS"
1284 #if defined(VGO_solaris)
1285 /* Internal to libc. */
1286 __attribute__((noinline
))
1287 PTH_FUNC(void, lmutexZuunlock
, // lmutex_unlock
1291 VALGRIND_GET_ORIG_FN(fn
);
1293 if (TRACE_PTH_FNS
) {
1294 fprintf(stderr
, "<< lmxunlk %p", mutex
); fflush(stderr
);
1297 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE
,
1299 CALL_FN_v_W(fn
, mutex
);
1300 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST
,
1303 if (TRACE_PTH_FNS
) {
1304 fprintf(stderr
, " lmxunlk >>\n");
1307 #endif /* VGO_solaris */
1310 /*----------------------------------------------------------------*/
1311 /*--- pthread_cond_t functions ---*/
1312 /*----------------------------------------------------------------*/
1314 /* Handled: pthread_cond_wait pthread_cond_timedwait
1315 pthread_cond_signal pthread_cond_broadcast
1317 pthread_cond_destroy
1320 //-----------------------------------------------------------
1321 // glibc: pthread_cond_wait@GLIBC_2.2.5
1322 // glibc: pthread_cond_wait@@GLIBC_2.3.2
1323 // darwin: pthread_cond_wait
1324 // darwin: pthread_cond_wait$NOCANCEL$UNIX2003
1325 // darwin: pthread_cond_wait$UNIX2003
1326 // Solaris: cond_wait (pthread_cond_wait is built atop of cond_wait)
1327 // FreeBSD: pthread_cond_wait
1329 __attribute__((noinline
))
1330 static int pthread_cond_wait_WRK(pthread_cond_t
* cond
,
1331 pthread_mutex_t
* mutex
)
1335 unsigned long mutex_is_valid
;
1337 VALGRIND_GET_ORIG_FN(fn
);
1339 if (TRACE_PTH_FNS
) {
1340 fprintf(stderr
, "<< pthread_cond_wait %p %p", cond
, mutex
);
1344 /* Tell the tool a cond-wait is about to happen, so it can check
1345 for bogus argument values. In return it tells us whether it
1346 thinks the mutex is valid or not. */
1347 DO_CREQ_W_WW(mutex_is_valid
,
1348 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE
,
1349 pthread_cond_t
*,cond
, pthread_mutex_t
*,mutex
);
1350 assert(mutex_is_valid
== 1 || mutex_is_valid
== 0);
1352 /* Tell the tool we're about to drop the mutex. This reflects the
1353 fact that in a cond_wait, we show up holding the mutex, and the
1354 call atomically drops the mutex and waits for the cv to be
1356 if (mutex_is_valid
) {
1357 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE
,
1358 pthread_mutex_t
*,mutex
);
1361 CALL_FN_W_WW(ret
, fn
, cond
,mutex
);
1363 /* this conditional look stupid, but compare w/ same logic for
1364 pthread_cond_timedwait below */
1365 if (mutex_is_valid
) {
1366 /* and now we have the mutex again if (ret == 0) */
1367 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
1368 pthread_mutex_t
*, mutex
, long, (ret
== 0) ? True
: False
);
1371 DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST
,
1372 pthread_cond_t
*,cond
, pthread_mutex_t
*,mutex
, long,0,
1373 long, (ret
== 0 && mutex_is_valid
) ? True
: False
);
1376 DO_PthAPIerror( "pthread_cond_wait", ret
);
1379 if (TRACE_PTH_FNS
) {
1380 fprintf(stderr
, " cowait -> %d >>\n", ret
);
1385 #if defined(VGO_linux)
1386 PTH_FUNC(int, pthreadZucondZuwaitZAZa
, // pthread_cond_wait@*
1387 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
) {
1388 return pthread_cond_wait_WRK(cond
, mutex
);
1390 #elif defined(VGO_freebsd)
1391 PTH_FUNC(int, pthreadZucondZuwait
, // pthread_cond_wait
1392 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
) {
1393 return pthread_cond_wait_WRK(cond
, mutex
);
1395 #elif defined(VGO_darwin)
1396 PTH_FUNC(int, pthreadZucondZuwaitZa
, // pthread_cond_wait*
1397 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
) {
1398 return pthread_cond_wait_WRK(cond
, mutex
);
1400 #elif defined(VGO_solaris)
1401 PTH_FUNC(int, condZuwait
, // cond_wait
1402 pthread_cond_t
*cond
, pthread_mutex_t
*mutex
) {
1403 return pthread_cond_wait_WRK(cond
, mutex
);
1406 # error "Unsupported OS"
1410 //-----------------------------------------------------------
1411 // glibc: pthread_cond_timedwait@@GLIBC_2.3.2
1412 // glibc: pthread_cond_timedwait@GLIBC_2.2.5
1413 // glibc: pthread_cond_timedwait@GLIBC_2.0
1414 // darwin: pthread_cond_timedwait
1415 // darwin: pthread_cond_timedwait$NOCANCEL$UNIX2003
1416 // darwin: pthread_cond_timedwait$UNIX2003
1417 // darwin: pthread_cond_timedwait_relative_np (trapped)
1418 // Solaris: cond_timedwait (pthread_cond_timedwait is built on cond_timedwait)
1419 // Solaris: cond_reltimedwait (pthread_cond_reltimedwait_np is built on this)
1420 // FreeBSD: pthread_cond_timedwait
1422 __attribute__((noinline
))
1423 static int pthread_cond_timedwait_WRK(pthread_cond_t
* cond
,
1424 pthread_mutex_t
* mutex
,
1425 struct timespec
* abstime
,
1430 unsigned long mutex_is_valid
;
1431 Bool abstime_is_valid
;
1432 VALGRIND_GET_ORIG_FN(fn
);
1434 if (TRACE_PTH_FNS
) {
1435 fprintf(stderr
, "<< pthread_cond_timedwait %p %p %p",
1436 cond
, mutex
, abstime
);
1440 /* Tell the tool a cond-wait is about to happen, so it can check
1441 for bogus argument values. In return it tells us whether it
1442 thinks the mutex is valid or not. */
1443 DO_CREQ_W_WW(mutex_is_valid
,
1444 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE
,
1445 pthread_cond_t
*,cond
, pthread_mutex_t
*,mutex
);
1446 assert(mutex_is_valid
== 1 || mutex_is_valid
== 0);
1448 abstime_is_valid
= abstime
->tv_nsec
>= 0 && abstime
->tv_nsec
< 1000000000;
1450 /* Tell the tool we're about to drop the mutex. This reflects the
1451 fact that in a cond_wait, we show up holding the mutex, and the
1452 call atomically drops the mutex and waits for the cv to be
1454 if (mutex_is_valid
&& abstime_is_valid
) {
1455 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE
,
1456 pthread_mutex_t
*,mutex
);
1459 CALL_FN_W_WWW(ret
, fn
, cond
,mutex
,abstime
);
1461 if (mutex_is_valid
&& !abstime_is_valid
&& ret
!= EINVAL
) {
1462 DO_PthAPIerror("Bug in libpthread: pthread_cond_timedwait "
1463 "invalid abstime did not cause"
1467 if (mutex_is_valid
&& abstime_is_valid
) {
1468 /* and now we have the mutex again if (ret == 0 || ret == timeout) */
1469 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
1470 pthread_mutex_t
*, mutex
,
1471 long, (ret
== 0 || ret
== timeout_error
) ? True
: False
);
1474 DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST
,
1475 pthread_cond_t
*,cond
, pthread_mutex_t
*,mutex
,
1476 long,ret
== timeout_error
,
1477 long, (ret
== 0 || ret
== timeout_error
) && mutex_is_valid
1480 if (ret
!= 0 && ret
!= timeout_error
) {
1481 DO_PthAPIerror( "pthread_cond_timedwait", ret
);
1484 if (TRACE_PTH_FNS
) {
1485 fprintf(stderr
, " cotimedwait -> %d >>\n", ret
);
1490 #if defined(VGO_linux)
1491 PTH_FUNC(int, pthreadZucondZutimedwaitZAZa
, // pthread_cond_timedwait@*
1492 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
,
1493 struct timespec
* abstime
) {
1494 return pthread_cond_timedwait_WRK(cond
, mutex
, abstime
, ETIMEDOUT
);
1496 #elif defined(VGO_freebsd)
1497 PTH_FUNC(int, pthreadZucondZutimedwait
, // pthread_cond_timedwait
1498 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
,
1499 struct timespec
* abstime
) {
1500 return pthread_cond_timedwait_WRK(cond
, mutex
, abstime
, ETIMEDOUT
);
1502 #elif defined(VGO_darwin)
1503 PTH_FUNC(int, pthreadZucondZutimedwait
, // pthread_cond_timedwait
1504 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
,
1505 struct timespec
* abstime
) {
1506 return pthread_cond_timedwait_WRK(cond
, mutex
, abstime
, ETIMEDOUT
);
1508 PTH_FUNC(int, pthreadZucondZutimedwaitZDZa
, // pthread_cond_timedwait$*
1509 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
,
1510 struct timespec
* abstime
) {
1511 return pthread_cond_timedwait_WRK(cond
, mutex
, abstime
, ETIMEDOUT
);
1513 PTH_FUNC(int, pthreadZucondZutimedwaitZuZa
, // pthread_cond_timedwait_*
1514 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
,
1515 struct timespec
* abstime
) {
1518 #elif defined(VGO_solaris)
1519 PTH_FUNC(int, condZutimedwait
, // cond_timedwait
1520 pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1521 struct timespec
*abstime
) {
1522 return pthread_cond_timedwait_WRK(cond
, mutex
, abstime
, ETIME
);
1524 PTH_FUNC(int, condZureltimedwait
, // cond_reltimedwait
1525 pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1526 struct timespec
*reltime
) {
1527 return pthread_cond_timedwait_WRK(cond
, mutex
, reltime
, ETIME
);
1530 # error "Unsupported OS"
1533 #if defined(VGO_linux)
1534 //-----------------------------------------------------------
1535 // glibc: pthread_cond_clockwait
1537 __attribute__((noinline
))
1538 static int pthread_cond_clockwait_WRK(pthread_cond_t
* cond
,
1539 pthread_mutex_t
* mutex
,
1541 struct timespec
* abstime
,
1546 unsigned long mutex_is_valid
;
1547 Bool abstime_is_valid
;
1548 VALGRIND_GET_ORIG_FN(fn
);
1550 if (TRACE_PTH_FNS
) {
1551 fprintf(stderr
, "<< pthread_cond_clockwait %p %p %p",
1552 cond
, mutex
, abstime
);
1556 /* Tell the tool a cond-wait is about to happen, so it can check
1557 for bogus argument values. In return it tells us whether it
1558 thinks the mutex is valid or not. */
1559 DO_CREQ_W_WW(mutex_is_valid
,
1560 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE
,
1561 pthread_cond_t
*,cond
, pthread_mutex_t
*,mutex
);
1562 assert(mutex_is_valid
== 1 || mutex_is_valid
== 0);
1564 abstime_is_valid
= abstime
->tv_nsec
>= 0 && abstime
->tv_nsec
< 1000000000;
1566 /* Tell the tool we're about to drop the mutex. This reflects the
1567 fact that in a cond_wait, we show up holding the mutex, and the
1568 call atomically drops the mutex and waits for the cv to be
1570 if (mutex_is_valid
&& abstime_is_valid
) {
1571 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE
,
1572 pthread_mutex_t
*,mutex
);
1575 CALL_FN_W_WWWW(ret
, fn
, cond
,mutex
,clockid
,abstime
);
1577 if (mutex_is_valid
&& !abstime_is_valid
&& ret
!= EINVAL
) {
1578 DO_PthAPIerror("Bug in libpthread: pthread_cond_clockwait "
1579 "invalid abstime did not cause"
1583 if (mutex_is_valid
&& abstime_is_valid
) {
1584 /* and now we have the mutex again if (ret == 0 || ret == timeout) */
1585 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
1586 pthread_mutex_t
*, mutex
,
1587 long, (ret
== 0 || ret
== timeout_error
) ? True
: False
);
1590 DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST
,
1591 pthread_cond_t
*,cond
, pthread_mutex_t
*,mutex
,
1592 long,ret
== timeout_error
,
1593 long, (ret
== 0 || ret
== timeout_error
) && mutex_is_valid
1596 if (ret
!= 0 && ret
!= timeout_error
) {
1597 DO_PthAPIerror( "pthread_cond_clockwait", ret
);
1600 if (TRACE_PTH_FNS
) {
1601 fprintf(stderr
, " cotimedwait -> %d >>\n", ret
);
1607 PTH_FUNC(int, pthreadZucondZuclockwait
, // pthread_cond_clockwait
1608 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
,
1610 struct timespec
* abstime
) {
1611 return pthread_cond_clockwait_WRK(cond
, mutex
, clockid
, abstime
, ETIMEDOUT
);
1616 //-----------------------------------------------------------
1617 // glibc: pthread_cond_signal@GLIBC_2.0
1618 // glibc: pthread_cond_signal@GLIBC_2.2.5
1619 // glibc: pthread_cond_signal@@GLIBC_2.3.2
1620 // darwin: pthread_cond_signal
1621 // darwin: pthread_cond_signal_thread_np (don't intercept this)
1622 // Solaris: cond_signal (pthread_cond_signal is a weak alias)
1623 // FreeBSD: pthread_cond_signal
1625 __attribute__((noinline
))
1626 static int pthread_cond_signal_WRK(pthread_cond_t
* cond
)
1630 VALGRIND_GET_ORIG_FN(fn
);
1632 if (TRACE_PTH_FNS
) {
1633 fprintf(stderr
, "<< pthread_cond_signal %p", cond
);
1637 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE
,
1638 pthread_cond_t
*,cond
);
1640 CALL_FN_W_W(ret
, fn
, cond
);
1642 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_POST
,
1643 pthread_cond_t
*,cond
);
1646 DO_PthAPIerror( "pthread_cond_signal", ret
);
1649 if (TRACE_PTH_FNS
) {
1650 fprintf(stderr
, " cosig -> %d >>\n", ret
);
1655 #if defined(VGO_linux)
1656 PTH_FUNC(int, pthreadZucondZusignalZAZa
, // pthread_cond_signal@*
1657 pthread_cond_t
* cond
) {
1658 return pthread_cond_signal_WRK(cond
);
1660 #elif defined(VGO_freebsd)
1661 PTH_FUNC(int, pthreadZucondZusignal
, // pthread_cond_signal
1662 pthread_cond_t
* cond
) {
1663 return pthread_cond_signal_WRK(cond
);
1665 #elif defined(VGO_darwin)
1666 PTH_FUNC(int, pthreadZucondZusignal
, // pthread_cond_signal
1667 pthread_cond_t
* cond
) {
1668 return pthread_cond_signal_WRK(cond
);
1670 #elif defined(VGO_solaris)
1671 PTH_FUNC(int, condZusignal
, // cond_signal
1672 pthread_cond_t
*cond
) {
1673 return pthread_cond_signal_WRK(cond
);
1676 # error "Unsupported OS"
1680 //-----------------------------------------------------------
1681 // glibc: pthread_cond_broadcast@GLIBC_2.0
1682 // glibc: pthread_cond_broadcast@GLIBC_2.2.5
1683 // glibc: pthread_cond_broadcast@@GLIBC_2.3.2
1684 // darwin: pthread_cond_broadcast
1685 // Solaris: cond_broadcast (pthread_cond_broadcast is a weak alias)
1686 // FreeBSD: pthread_cond_broadcast
1688 // Note, this is pretty much identical, from a dependency-graph
1689 // point of view, with cond_signal, so the code is duplicated.
1690 // Maybe it should be commoned up.
1692 __attribute__((noinline
))
1693 static int pthread_cond_broadcast_WRK(pthread_cond_t
* cond
)
1697 VALGRIND_GET_ORIG_FN(fn
);
1699 if (TRACE_PTH_FNS
) {
1700 fprintf(stderr
, "<< pthread_cond_broadcast %p", cond
);
1704 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE
,
1705 pthread_cond_t
*,cond
);
1707 CALL_FN_W_W(ret
, fn
, cond
);
1709 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_POST
,
1710 pthread_cond_t
*,cond
);
1713 DO_PthAPIerror( "pthread_cond_broadcast", ret
);
1716 if (TRACE_PTH_FNS
) {
1717 fprintf(stderr
, " cobro -> %d >>\n", ret
);
1722 #if defined(VGO_linux)
1723 PTH_FUNC(int, pthreadZucondZubroadcastZAZa
, // pthread_cond_broadcast@*
1724 pthread_cond_t
* cond
) {
1725 return pthread_cond_broadcast_WRK(cond
);
1727 #elif defined(VGO_freebsd)
1728 PTH_FUNC(int, pthreadZucondZubroadcast
, // pthread_cond_broadcast
1729 pthread_cond_t
* cond
) {
1730 return pthread_cond_broadcast_WRK(cond
);
1732 #elif defined(VGO_darwin)
1733 PTH_FUNC(int, pthreadZucondZubroadcast
, // pthread_cond_broadcast
1734 pthread_cond_t
* cond
) {
1735 return pthread_cond_broadcast_WRK(cond
);
1737 #elif defined(VGO_solaris)
1738 PTH_FUNC(int, condZubroadcast
, // cond_broadcast
1739 pthread_cond_t
*cond
) {
1740 return pthread_cond_broadcast_WRK(cond
);
1743 # error "Unsupported OS"
1746 // glibc: pthread_cond_init@GLIBC_2.0
1747 // glibc: pthread_cond_init@GLIBC_2.2.5
1748 // glibc: pthread_cond_init@@GLIBC_2.3.2
1749 // darwin: pthread_cond_init
1750 // Solaris: cond_init (pthread_cond_init is built atop on this function)
1751 // FreeBSD: pthread_cond_init
1752 // Easy way out: Handling of attr could have been messier.
1753 // It turns out that pthread_cond_init under linux ignores
1754 // all information in cond_attr, so do we.
1756 #if !defined(VGO_solaris)
1757 __attribute__((noinline
))
1758 static int pthread_cond_init_WRK(pthread_cond_t
* cond
, pthread_condattr_t
*cond_attr
)
1762 VALGRIND_GET_ORIG_FN(fn
);
1764 if (TRACE_PTH_FNS
) {
1765 fprintf(stderr
, "<< pthread_cond_init %p", cond
);
1769 CALL_FN_W_WW(ret
, fn
, cond
, cond_attr
);
1772 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST
,
1773 pthread_cond_t
*,cond
, pthread_condattr_t
*, cond_attr
);
1775 DO_PthAPIerror( "pthread_cond_init", ret
);
1778 if (TRACE_PTH_FNS
) {
1779 fprintf(stderr
, " coinit -> %d >>\n", ret
);
1784 #if defined(VGO_linux)
1785 PTH_FUNC(int, pthreadZucondZuinitZAZa
, // pthread_cond_init@*
1786 pthread_cond_t
* cond
, pthread_condattr_t
* cond_attr
) {
1787 return pthread_cond_init_WRK(cond
, cond_attr
);
1789 #elif defined(VGO_freebsd)
1790 PTH_FUNC(int, pthreadZucondZuinit
, // pthread_cond_init@*
1791 pthread_cond_t
* cond
, pthread_condattr_t
* cond_attr
) {
1792 return pthread_cond_init_WRK(cond
, cond_attr
);
1794 #elif defined(VGO_darwin)
1795 PTH_FUNC(int, pthreadZucondZuinit
, // pthread_cond_init
1796 pthread_cond_t
* cond
, pthread_condattr_t
* cond_attr
) {
1797 return pthread_cond_init_WRK(cond
, cond_attr
);
1800 # error "Unsupported OS"
1803 #else /* VGO_solaris */
1804 __attribute__((noinline
))
1805 PTH_FUNC(int, condZuinit
, // cond_init
1806 cond_t
*cond
, int type
, void *arg
)
1810 VALGRIND_GET_ORIG_FN(fn
);
1812 if (TRACE_PTH_FNS
) {
1813 fprintf(stderr
, "<< cond_init %p", cond
); fflush(stderr
);
1816 CALL_FN_W_WWW(ret
, fn
, cond
, type
, arg
);
1819 /* Luckily evh__HG_PTHREAD_COND_INIT_POST() ignores cond_attr.
1820 See also comment for pthread_cond_init_WRK(). */
1821 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST
,
1822 cond_t
*, cond
, void *, NULL
);
1824 DO_PthAPIerror("cond_init", ret
);
1827 if (TRACE_PTH_FNS
) {
1828 fprintf(stderr
, " cond_init -> %d >>\n", ret
);
1833 #endif /* VGO_solaris */
1836 //-----------------------------------------------------------
1837 // glibc: pthread_cond_destroy@@GLIBC_2.3.2
1838 // glibc: pthread_cond_destroy@GLIBC_2.2.5
1839 // glibc: pthread_cond_destroy@GLIBC_2.0
1840 // darwin: pthread_cond_destroy
1841 // Solaris: cond_destroy (pthread_cond_destroy is a weak alias)
1842 // FreeBSD: pthread_cond_destroy
1844 __attribute__((noinline
))
1845 static int pthread_cond_destroy_WRK(pthread_cond_t
* cond
)
1848 unsigned long cond_is_init
;
1851 VALGRIND_GET_ORIG_FN(fn
);
1853 if (TRACE_PTH_FNS
) {
1854 fprintf(stderr
, "<< pthread_cond_destroy %p", cond
);
1859 const pthread_cond_t cond_init
= PTHREAD_COND_INITIALIZER
;
1860 VALGRIND_HG_DISABLE_CHECKING(cond
, sizeof(*cond
));
1861 cond_is_init
= my_memcmp(cond
, &cond_init
, sizeof(*cond
)) == 0;
1862 VALGRIND_HG_ENABLE_CHECKING(cond
, sizeof(*cond
));
1867 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_DESTROY_PRE
,
1868 pthread_cond_t
*, cond
, unsigned long, cond_is_init
);
1870 CALL_FN_W_W(ret
, fn
, cond
);
1873 DO_PthAPIerror( "pthread_cond_destroy", ret
);
1876 if (TRACE_PTH_FNS
) {
1877 fprintf(stderr
, " codestr -> %d >>\n", ret
);
1882 #if defined(VGO_linux)
1883 PTH_FUNC(int, pthreadZucondZudestroyZAZa
, // pthread_cond_destroy@*
1884 pthread_cond_t
* cond
) {
1885 return pthread_cond_destroy_WRK(cond
);
1887 #elif defined(VGO_freebsd)
1888 PTH_FUNC(int, pthreadZucondZudestroy
, // pthread_cond_destroy@*
1889 pthread_cond_t
* cond
) {
1890 return pthread_cond_destroy_WRK(cond
);
1892 #elif defined(VGO_darwin)
1893 PTH_FUNC(int, pthreadZucondZudestroy
, // pthread_cond_destroy
1894 pthread_cond_t
* cond
) {
1895 return pthread_cond_destroy_WRK(cond
);
1897 #elif defined(VGO_solaris)
1898 PTH_FUNC(int, condZudestroy
, // cond_destroy
1899 pthread_cond_t
*cond
) {
1900 return pthread_cond_destroy_WRK(cond
);
1903 # error "Unsupported OS"
1907 /*----------------------------------------------------------------*/
1908 /*--- pthread_barrier_t functions ---*/
1909 /*----------------------------------------------------------------*/
1911 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1913 /* Handled: pthread_barrier_init
1914 pthread_barrier_wait
1915 pthread_barrier_destroy
1917 Unhandled: pthread_barrierattr_destroy
1918 pthread_barrierattr_getpshared
1919 pthread_barrierattr_init
1920 pthread_barrierattr_setpshared
1921 -- are these important?
1924 //-----------------------------------------------------------
1925 // glibc: pthread_barrier_init
1926 // darwin: (doesn't appear to exist)
1927 // Solaris: pthread_barrier_init
1928 // FreeBSD: pthread_barrier_init
1929 PTH_FUNC(int, pthreadZubarrierZuinit
, // pthread_barrier_init
1930 pthread_barrier_t
* bar
,
1931 pthread_barrierattr_t
* attr
, unsigned long count
)
1935 VALGRIND_GET_ORIG_FN(fn
);
1937 if (TRACE_PTH_FNS
) {
1938 fprintf(stderr
, "<< pthread_barrier_init %p %p %lu",
1943 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE
,
1944 pthread_barrier_t
*, bar
,
1945 unsigned long, count
,
1946 unsigned long, 0/*!resizable*/);
1948 CALL_FN_W_WWW(ret
, fn
, bar
,attr
,count
);
1951 DO_PthAPIerror( "pthread_barrier_init", ret
);
1954 if (TRACE_PTH_FNS
) {
1955 fprintf(stderr
, " pthread_barrier_init -> %d >>\n", ret
);
1962 //-----------------------------------------------------------
1963 // glibc: pthread_barrier_wait
1964 // darwin: (doesn't appear to exist)
1965 // Solaris: pthread_barrier_wait
1966 // FreeBSD: pthread_barrier_wait
1967 PTH_FUNC(int, pthreadZubarrierZuwait
, // pthread_barrier_wait
1968 pthread_barrier_t
* bar
)
1972 VALGRIND_GET_ORIG_FN(fn
);
1974 if (TRACE_PTH_FNS
) {
1975 fprintf(stderr
, "<< pthread_barrier_wait %p", bar
);
1979 /* That this works correctly, and doesn't screw up when a thread
1980 leaving the barrier races round to the front and re-enters while
1981 other threads are still leaving it, is quite subtle. See
1982 comments in the handler for PTHREAD_BARRIER_WAIT_PRE in
1984 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE
,
1985 pthread_barrier_t
*,bar
);
1987 CALL_FN_W_W(ret
, fn
, bar
);
1989 if (ret
!= 0 && ret
!= PTHREAD_BARRIER_SERIAL_THREAD
) {
1990 DO_PthAPIerror( "pthread_barrier_wait", ret
);
1993 if (TRACE_PTH_FNS
) {
1994 fprintf(stderr
, " pthread_barrier_wait -> %d >>\n", ret
);
2001 //-----------------------------------------------------------
2002 // glibc: pthread_barrier_destroy
2003 // darwin: (doesn't appear to exist)
2004 // Solaris: pthread_barrier_destroy
2005 // FreeBSD: pthread_barrier_destroy
2006 PTH_FUNC(int, pthreadZubarrierZudestroy
, // pthread_barrier_destroy
2007 pthread_barrier_t
* bar
)
2011 VALGRIND_GET_ORIG_FN(fn
);
2013 if (TRACE_PTH_FNS
) {
2014 fprintf(stderr
, "<< pthread_barrier_destroy %p", bar
);
2018 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE
,
2019 pthread_barrier_t
*,bar
);
2021 CALL_FN_W_W(ret
, fn
, bar
);
2024 DO_PthAPIerror( "pthread_barrier_destroy", ret
);
2027 if (TRACE_PTH_FNS
) {
2028 fprintf(stderr
, " pthread_barrier_destroy -> %d >>\n", ret
);
2034 #endif // defined(HAVE_PTHREAD_BARRIER_INIT)
2037 /*----------------------------------------------------------------*/
2038 /*--- pthread_spinlock_t functions ---*/
2039 /*----------------------------------------------------------------*/
2041 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
2042 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
2044 /* Handled: pthread_spin_init pthread_spin_destroy
2045 pthread_spin_lock pthread_spin_trylock
2051 /* This is a nasty kludge, in that glibc "knows" that initialising a
2052 spin lock unlocks it, and pthread_spin_{init,unlock} are names for
2053 the same function. Hence we have to have a wrapper which does both
2054 things, without knowing which the user intended to happen.
2055 Solaris has distinct functions for init/unlock but client requests
2056 are immutable in helgrind.h so follow the glibc lead. */
2058 //-----------------------------------------------------------
2059 // glibc: pthread_spin_init
2060 // glibc: pthread_spin_unlock
2061 // darwin: (doesn't appear to exist)
2062 // Solaris: pthread_spin_init
2063 // Solaris: pthread_spin_unlock
2064 // FreeBSD: pthread_spin_init
2065 // FreeBSD: pthread_spin_unlock
2066 __attribute__((noinline
))
2067 static int pthread_spin_init_or_unlock_WRK(pthread_spinlock_t
* lock
,
2071 VALGRIND_GET_ORIG_FN(fn
);
2072 if (TRACE_PTH_FNS
) {
2073 fprintf(stderr
, "<< pthread_spin_iORu %p", lock
); fflush(stderr
);
2076 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE
,
2077 pthread_spinlock_t
*, lock
);
2079 CALL_FN_W_WW(ret
, fn
, lock
,pshared
);
2081 if (ret
== 0 /*success*/) {
2082 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST
,
2083 pthread_spinlock_t
*,lock
);
2085 DO_PthAPIerror( "pthread_spinlock_{init,unlock}", ret
);
2088 if (TRACE_PTH_FNS
) {
2089 fprintf(stderr
, " :: spiniORu -> %d >>\n", ret
);
2093 #if defined(VGO_linux)
2094 PTH_FUNC(int, pthreadZuspinZuinit
, // pthread_spin_init
2095 pthread_spinlock_t
* lock
, int pshared
) {
2096 return pthread_spin_init_or_unlock_WRK(lock
, pshared
);
2098 PTH_FUNC(int, pthreadZuspinZuunlock
, // pthread_spin_unlock
2099 pthread_spinlock_t
* lock
) {
2100 /* this is never actually called */
2101 return pthread_spin_init_or_unlock_WRK(lock
, 0/*pshared*/);
2103 #elif defined(VGO_freebsd)
2104 PTH_FUNC(int, pthreadZuspinZuinit
, // pthread_spin_init
2105 pthread_spinlock_t
* lock
, int pshared
) {
2106 return pthread_spin_init_or_unlock_WRK(lock
, pshared
);
2108 PTH_FUNC(int, pthreadZuspinZuunlock
, // pthread_spin_unlock@*
2109 pthread_spinlock_t
* lock
) {
2110 /* this is never actually called */
2111 return pthread_spin_init_or_unlock_WRK(lock
, 0/*pshared*/);
2113 #elif defined(VGO_darwin)
2114 #elif defined(VGO_solaris)
2115 PTH_FUNC(int, pthreadZuspinZuinit
, // pthread_spin_init
2116 pthread_spinlock_t
*lock
, int pshared
) {
2117 return pthread_spin_init_or_unlock_WRK(lock
, pshared
);
2119 PTH_FUNC(int, pthreadZuspinZuunlock
, // pthread_spin_unlock
2120 pthread_spinlock_t
*lock
) {
2121 return pthread_spin_init_or_unlock_WRK(lock
, 0/*pshared*/);
2124 # error "Unsupported OS"
2128 //-----------------------------------------------------------
2129 // glibc: pthread_spin_destroy
2130 // darwin: (doesn't appear to exist)
2131 // Solaris: pthread_spin_destroy
2132 // FreeBSD: pthread_spin_destroy
2133 __attribute__((noinline
))
2134 static int pthread_spin_destroy_WRK(pthread_spinlock_t
*lock
)
2138 VALGRIND_GET_ORIG_FN(fn
);
2139 if (TRACE_PTH_FNS
) {
2140 fprintf(stderr
, "<< pthread_spin_destroy %p", lock
);
2144 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_DESTROY_PRE
,
2145 pthread_spinlock_t
*,lock
);
2147 CALL_FN_W_W(ret
, fn
, lock
);
2150 DO_PthAPIerror( "pthread_spin_destroy", ret
);
2153 if (TRACE_PTH_FNS
) {
2154 fprintf(stderr
, " :: spindestroy -> %d >>\n", ret
);
2158 #if defined(VGO_linux) || defined(VGO_freebsd)
2159 PTH_FUNC(int, pthreadZuspinZudestroy
, // pthread_spin_destroy
2160 pthread_spinlock_t
*lock
) {
2161 return pthread_spin_destroy_WRK(lock
);
2163 #elif defined(VGO_darwin)
2164 #elif defined(VGO_solaris)
2165 PTH_FUNC(int, pthreadZuspinZudestroy
, // pthread_spin_destroy
2166 pthread_spinlock_t
*lock
) {
2167 return pthread_spin_destroy_WRK(lock
);
2170 # error "Unsupported OS"
2174 //-----------------------------------------------------------
2175 // glibc: pthread_spin_lock
2176 // darwin: (doesn't appear to exist)
2177 // Solaris: pthread_spin_lock
2178 // FreeBSD: pthread_spin_lock
2179 __attribute__((noinline
))
2180 static int pthread_spin_lock_WRK(pthread_spinlock_t
*lock
)
2184 VALGRIND_GET_ORIG_FN(fn
);
2185 if (TRACE_PTH_FNS
) {
2186 fprintf(stderr
, "<< pthread_spinlock %p", lock
);
2190 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE
,
2191 pthread_spinlock_t
*,lock
, long,0/*!isTryLock*/);
2193 CALL_FN_W_W(ret
, fn
, lock
);
2195 /* There's a hole here: libpthread now knows the lock is locked,
2196 but the tool doesn't, so some other thread could run and detect
2197 that the lock has been acquired by someone (this thread). Does
2198 this matter? Not sure, but I don't think so. */
2200 if (ret
== 0 /*success*/) {
2201 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST
,
2202 pthread_spinlock_t
*,lock
);
2204 DO_PthAPIerror( "pthread_spin_lock", ret
);
2207 if (TRACE_PTH_FNS
) {
2208 fprintf(stderr
, " :: spinlock -> %d >>\n", ret
);
2212 #if defined(VGO_linux) || defined(VGO_freebsd)
2213 PTH_FUNC(int, pthreadZuspinZulock
, // pthread_spin_lock
2214 pthread_spinlock_t
*lock
) {
2215 return pthread_spin_lock_WRK(lock
);
2217 #elif defined(VGO_darwin)
2218 #elif defined(VGO_solaris)
2219 PTH_FUNC(int, pthreadZuspinZulock
, // pthread_spin_lock
2220 pthread_spinlock_t
*lock
) {
2221 return pthread_spin_lock_WRK(lock
);
2224 # error "Unsupported OS"
2228 //-----------------------------------------------------------
2229 // glibc: pthread_spin_trylock
2230 // darwin: (doesn't appear to exist)
2231 // Solaris: pthread_spin_trylock
2232 // FreeBSD: pthread_spin_trylock
2233 __attribute__((noinline
))
2234 static int pthread_spin_trylock_WRK(pthread_spinlock_t
*lock
)
2238 VALGRIND_GET_ORIG_FN(fn
);
2239 if (TRACE_PTH_FNS
) {
2240 fprintf(stderr
, "<< pthread_spin_trylock %p", lock
);
2244 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE
,
2245 pthread_spinlock_t
*,lock
, long,1/*isTryLock*/);
2247 CALL_FN_W_W(ret
, fn
, lock
);
2249 /* There's a hole here: libpthread now knows the lock is locked,
2250 but the tool doesn't, so some other thread could run and detect
2251 that the lock has been acquired by someone (this thread). Does
2252 this matter? Not sure, but I don't think so. */
2254 if (ret
== 0 /*success*/) {
2255 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST
,
2256 pthread_spinlock_t
*,lock
);
2259 DO_PthAPIerror( "pthread_spin_trylock", ret
);
2262 if (TRACE_PTH_FNS
) {
2263 fprintf(stderr
, " :: spin_trylock -> %d >>\n", ret
);
2267 #if defined(VGO_linux) || defined(VGO_freebsd)
2268 PTH_FUNC(int, pthreadZuspinZutrylock
, // pthread_spin_trylock
2269 pthread_spinlock_t
*lock
) {
2270 return pthread_spin_trylock_WRK(lock
);
2272 #elif defined(VGO_darwin)
2273 #elif defined(VGO_solaris)
2274 PTH_FUNC(int, pthreadZuspinZutrylock
, // pthread_spin_trylock
2275 pthread_spinlock_t
*lock
) {
2276 return pthread_spin_trylock_WRK(lock
);
2279 # error "Unsupported OS"
2282 #endif // defined(HAVE_PTHREAD_SPIN_LOCK)
2285 /*----------------------------------------------------------------*/
2286 /*--- pthread_rwlock_t functions ---*/
2287 /*----------------------------------------------------------------*/
2289 /* Android's pthread.h doesn't say anything about rwlocks, hence these
2290 functions have to be conditionally compiled. */
2291 #if defined(HAVE_PTHREAD_RWLOCK_T)
2293 /* Handled: pthread_rwlock_init pthread_rwlock_destroy
2294 pthread_rwlock_rdlock
2295 pthread_rwlock_wrlock
2296 pthread_rwlock_unlock
2297 pthread_rwlock_tryrdlock
2298 pthread_rwlock_trywrlock
2301 //-----------------------------------------------------------
2302 // glibc: pthread_rwlock_init
2303 // darwin: pthread_rwlock_init
2304 // darwin: pthread_rwlock_init$UNIX2003
2305 // Solaris: rwlock_init (pthread_rwlock_init is built atop of rwlock_init)
2306 // FreeBSD: pthread_rwlock_init
2307 __attribute__((noinline
))
2308 static int pthread_rwlock_init_WRK(pthread_rwlock_t
*rwl
,
2309 pthread_rwlockattr_t
* attr
)
2313 VALGRIND_GET_ORIG_FN(fn
);
2314 if (TRACE_PTH_FNS
) {
2315 fprintf(stderr
, "<< pthread_rwl_init %p", rwl
); fflush(stderr
);
2318 CALL_FN_W_WW(ret
, fn
, rwl
,attr
);
2320 if (ret
== 0 /*success*/) {
2321 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST
,
2322 pthread_rwlock_t
*,rwl
);
2324 DO_PthAPIerror( "pthread_rwlock_init", ret
);
2327 if (TRACE_PTH_FNS
) {
2328 fprintf(stderr
, " :: rwl_init -> %d >>\n", ret
);
2332 #if defined(VGO_linux)
2333 PTH_FUNC(int, pthreadZurwlockZuinit
, // pthread_rwlock_init
2334 pthread_rwlock_t
*rwl
,
2335 pthread_rwlockattr_t
* attr
) {
2336 return pthread_rwlock_init_WRK(rwl
, attr
);
2338 #elif defined(VGO_freebsd)
2339 PTH_FUNC(int, pthreadZurwlockZuinit
, // pthread_rwlock_init
2340 pthread_rwlock_t
*rwl
,
2341 pthread_rwlockattr_t
* attr
) {
2342 return pthread_rwlock_init_WRK(rwl
, attr
);
2344 #elif defined(VGO_darwin)
2345 PTH_FUNC(int, pthreadZurwlockZuinitZa
, // pthread_rwlock_init*
2346 pthread_rwlock_t
*rwl
,
2347 pthread_rwlockattr_t
* attr
) {
2348 return pthread_rwlock_init_WRK(rwl
, attr
);
2350 #elif defined(VGO_solaris)
2351 static int pthread_rwlock_init_WRK(pthread_rwlock_t
*rwl
,
2352 pthread_rwlockattr_t
* attr
)
2353 __attribute__((unused
));
2355 # error "Unsupported OS"
2358 #if defined(VGO_solaris)
2359 PTH_FUNC(int, rwlockZuinit
, // rwlock_init
2366 VALGRIND_GET_ORIG_FN(fn
);
2367 if (TRACE_PTH_FNS
) {
2368 fprintf(stderr
, "<< rwl_init %p", rwlock
); fflush(stderr
);
2371 CALL_FN_W_WWW(ret
, fn
, rwlock
, type
, arg
);
2373 if (ret
== 0 /*success*/) {
2374 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST
,
2375 rwlock_t
*, rwlock
);
2377 DO_PthAPIerror("rwlock_init", ret
);
2380 if (TRACE_PTH_FNS
) {
2381 fprintf(stderr
, " :: rwl_init -> %d >>\n", ret
);
2385 #endif /* VGO_solaris */
2388 //-----------------------------------------------------------
2389 // glibc: pthread_rwlock_destroy
2390 // darwin: pthread_rwlock_destroy
2391 // darwin: pthread_rwlock_destroy$UNIX2003
2392 // Solaris: rwlock_destroy (pthread_rwlock_destroy is a weak alias)
2393 // FreeBSD: pthread_rwlock_destroy
2395 __attribute__((noinline
))
2396 static int pthread_rwlock_destroy_WRK(pthread_rwlock_t
* rwl
)
2400 VALGRIND_GET_ORIG_FN(fn
);
2401 if (TRACE_PTH_FNS
) {
2402 fprintf(stderr
, "<< pthread_rwl_destroy %p", rwl
); fflush(stderr
);
2405 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE
,
2406 pthread_rwlock_t
*,rwl
);
2408 CALL_FN_W_W(ret
, fn
, rwl
);
2411 DO_PthAPIerror( "pthread_rwlock_destroy", ret
);
2414 if (TRACE_PTH_FNS
) {
2415 fprintf(stderr
, " :: rwl_destroy -> %d >>\n", ret
);
2419 #if defined(VGO_linux)
2420 PTH_FUNC(int, pthreadZurwlockZudestroy
, // pthread_rwlock_destroy
2421 pthread_rwlock_t
*rwl
) {
2422 return pthread_rwlock_destroy_WRK(rwl
);
2424 #elif defined(VGO_freebsd)
2425 PTH_FUNC(int, pthreadZurwlockZudestroy
, // pthread_rwlock_destroy
2426 pthread_rwlock_t
*rwl
) {
2427 return pthread_rwlock_destroy_WRK(rwl
);
2429 #elif defined(VGO_darwin)
2430 PTH_FUNC(int, pthreadZurwlockZudestroyZa
, // pthread_rwlock_destroy*
2431 pthread_rwlock_t
*rwl
) {
2432 return pthread_rwlock_destroy_WRK(rwl
);
2434 #elif defined(VGO_solaris)
2435 PTH_FUNC(int, rwlockZudestroy
, // rwlock_destroy
2436 pthread_rwlock_t
*rwl
) {
2437 return pthread_rwlock_destroy_WRK(rwl
);
2440 # error "Unsupported OS"
2444 //-----------------------------------------------------------
2445 // glibc: pthread_rwlock_wrlock
2446 // darwin: pthread_rwlock_wrlock
2447 // darwin: pthread_rwlock_wrlock$UNIX2003
2448 // Solaris: rw_wrlock (pthread_rwlock_wrlock is a weak alias)
2449 // FreeBSD: pthread_rwlock_wrlock
2451 __attribute__((noinline
))
2452 static int pthread_rwlock_wrlock_WRK(pthread_rwlock_t
* rwlock
)
2456 VALGRIND_GET_ORIG_FN(fn
);
2457 if (TRACE_PTH_FNS
) {
2458 fprintf(stderr
, "<< pthread_rwl_wlk %p", rwlock
); fflush(stderr
);
2461 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
2462 pthread_rwlock_t
*,rwlock
,
2463 long,1/*isW*/, long,0/*!isTryLock*/);
2465 CALL_FN_W_W(ret
, fn
, rwlock
);
2467 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
2468 pthread_rwlock_t
*,rwlock
, long,1/*isW*/,
2469 long, (ret
== 0) ? True
: False
);
2471 DO_PthAPIerror( "pthread_rwlock_wrlock", ret
);
2474 if (TRACE_PTH_FNS
) {
2475 fprintf(stderr
, " :: rwl_wlk -> %d >>\n", ret
);
2479 #if defined(VGO_linux)
2480 PTH_FUNC(int, pthreadZurwlockZuwrlock
, // pthread_rwlock_wrlock
2481 pthread_rwlock_t
* rwlock
) {
2482 return pthread_rwlock_wrlock_WRK(rwlock
);
2484 #elif defined(VGO_freebsd)
2485 PTH_FUNC(int, pthreadZurwlockZuwrlock
, // pthread_rwlock_wrlock
2486 pthread_rwlock_t
* rwlock
) {
2487 return pthread_rwlock_wrlock_WRK(rwlock
);
2489 #elif defined(VGO_darwin)
2490 PTH_FUNC(int, pthreadZurwlockZuwrlockZa
, // pthread_rwlock_wrlock*
2491 pthread_rwlock_t
* rwlock
) {
2492 return pthread_rwlock_wrlock_WRK(rwlock
);
2494 #elif defined(VGO_solaris)
2495 PTH_FUNC(int, rwZuwrlock
, // rw_wrlock
2496 pthread_rwlock_t
*rwlock
) {
2497 return pthread_rwlock_wrlock_WRK(rwlock
);
2500 # error "Unsupported OS"
2503 #if defined(VGO_solaris)
2504 /* Internal to libc. */
2505 PTH_FUNC(void, lrwZuwrlock
, // lrw_wrlock
2509 VALGRIND_GET_ORIG_FN(fn
);
2510 if (TRACE_PTH_FNS
) {
2511 fprintf(stderr
, "<< lrw_wlk %p", rwlock
); fflush(stderr
);
2514 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
2515 pthread_rwlock_t
*, rwlock
,
2516 long, 1/*isW*/, long, 0/*!isTryLock*/);
2518 CALL_FN_v_W(fn
, rwlock
);
2520 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
2521 pthread_rwlock_t
*, rwlock
, long, 1/*isW*/, long, True
);
2523 if (TRACE_PTH_FNS
) {
2524 fprintf(stderr
, " :: lrw_wlk >>\n");
2527 #endif /* VGO_solaris */
2530 //-----------------------------------------------------------
2531 // glibc: pthread_rwlock_rdlock
2532 // darwin: pthread_rwlock_rdlock
2533 // darwin: pthread_rwlock_rdlock$UNIX2003
2534 // Solaris: rw_rdlock (pthread_rwlock_rdlock is a weak alias)
2535 // FreeBSD: pthread_rwlock_rdlock
2537 __attribute__((noinline
))
2538 static int pthread_rwlock_rdlock_WRK(pthread_rwlock_t
* rwlock
)
2542 VALGRIND_GET_ORIG_FN(fn
);
2543 if (TRACE_PTH_FNS
) {
2544 fprintf(stderr
, "<< pthread_rwl_rlk %p", rwlock
); fflush(stderr
);
2547 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
2548 pthread_rwlock_t
*,rwlock
,
2549 long,0/*!isW*/, long,0/*!isTryLock*/);
2551 CALL_FN_W_W(ret
, fn
, rwlock
);
2553 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
2554 pthread_rwlock_t
*,rwlock
, long,0/*!isW*/,
2555 long, (ret
== 0) ? True
: False
);
2557 DO_PthAPIerror( "pthread_rwlock_rdlock", ret
);
2560 if (TRACE_PTH_FNS
) {
2561 fprintf(stderr
, " :: rwl_rlk -> %d >>\n", ret
);
2565 #if defined(VGO_linux)
2566 PTH_FUNC(int, pthreadZurwlockZurdlock
, // pthread_rwlock_rdlock
2567 pthread_rwlock_t
* rwlock
) {
2568 return pthread_rwlock_rdlock_WRK(rwlock
);
2570 #elif defined(VGO_freebsd)
2571 PTH_FUNC(int, pthreadZurwlockZurdlock
, // pthread_rwlock_rdlock
2572 pthread_rwlock_t
* rwlock
) {
2573 return pthread_rwlock_rdlock_WRK(rwlock
);
2575 #elif defined(VGO_darwin)
2576 PTH_FUNC(int, pthreadZurwlockZurdlockZa
, // pthread_rwlock_rdlock*
2577 pthread_rwlock_t
* rwlock
) {
2578 return pthread_rwlock_rdlock_WRK(rwlock
);
2580 #elif defined(VGO_solaris)
2581 PTH_FUNC(int, rwZurdlock
, // rw_rdlock
2582 pthread_rwlock_t
*rwlock
) {
2583 return pthread_rwlock_rdlock_WRK(rwlock
);
2586 # error "Unsupported OS"
2589 #if defined(VGO_solaris)
2590 /* Internal to libc. */
2591 PTH_FUNC(void, lrwZurdlock
, // lrw_rdlock
2595 VALGRIND_GET_ORIG_FN(fn
);
2596 if (TRACE_PTH_FNS
) {
2597 fprintf(stderr
, "<< lrw_rlk %p", rwlock
); fflush(stderr
);
2600 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
2601 pthread_rwlock_t
*, rwlock
,
2602 long, 0/*!isW*/, long, 0/*!isTryLock*/);
2604 CALL_FN_v_W(fn
, rwlock
);
2606 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
2607 pthread_rwlock_t
*, rwlock
, long, 0/*!isW*/, long, True
);
2609 if (TRACE_PTH_FNS
) {
2610 fprintf(stderr
, " :: lrw_rlk ->>\n");
2613 #endif /* VGO_solaris */
2616 //-----------------------------------------------------------
2617 // glibc: pthread_rwlock_trywrlock
2618 // darwin: pthread_rwlock_trywrlock
2619 // darwin: pthread_rwlock_trywrlock$UNIX2003
2620 // Solaris: rw_trywrlock (pthread_rwlock_trywrlock is a weak alias)
2621 // FreeBSD: pthread_rwlock_trywrlock
2623 __attribute__((noinline
))
2624 static int pthread_rwlock_trywrlock_WRK(pthread_rwlock_t
* rwlock
)
2628 VALGRIND_GET_ORIG_FN(fn
);
2629 if (TRACE_PTH_FNS
) {
2630 fprintf(stderr
, "<< pthread_rwl_trywlk %p", rwlock
); fflush(stderr
);
2633 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
2634 pthread_rwlock_t
*,rwlock
,
2635 long,1/*isW*/, long,1/*isTryLock*/);
2637 CALL_FN_W_W(ret
, fn
, rwlock
);
2639 /* There's a hole here: libpthread now knows the lock is locked,
2640 but the tool doesn't, so some other thread could run and detect
2641 that the lock has been acquired by someone (this thread). Does
2642 this matter? Not sure, but I don't think so. */
2644 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
2645 pthread_rwlock_t
*,rwlock
, long,1/*isW*/,
2646 long, (ret
== 0) ? True
: False
);
2649 DO_PthAPIerror( "pthread_rwlock_trywrlock", ret
);
2652 if (TRACE_PTH_FNS
) {
2653 fprintf(stderr
, " :: rwl_trywlk -> %d >>\n", ret
);
2657 #if defined(VGO_linux)
2658 PTH_FUNC(int, pthreadZurwlockZutrywrlock
, // pthread_rwlock_trywrlock
2659 pthread_rwlock_t
* rwlock
) {
2660 return pthread_rwlock_trywrlock_WRK(rwlock
);
2662 #elif defined(VGO_freebsd)
2663 PTH_FUNC(int, pthreadZurwlockZutrywrlock
, // pthread_rwlock_trywrlock
2664 pthread_rwlock_t
* rwlock
) {
2665 return pthread_rwlock_trywrlock_WRK(rwlock
);
2667 #elif defined(VGO_darwin)
2668 PTH_FUNC(int, pthreadZurwlockZutrywrlockZa
, // pthread_rwlock_trywrlock*
2669 pthread_rwlock_t
* rwlock
) {
2670 return pthread_rwlock_trywrlock_WRK(rwlock
);
2672 #elif defined(VGO_solaris)
2673 PTH_FUNC(int, rwZutrywrlock
, // rw_trywrlock
2674 pthread_rwlock_t
*rwlock
) {
2675 return pthread_rwlock_trywrlock_WRK(rwlock
);
2678 # error "Unsupported OS"
2682 //-----------------------------------------------------------
2683 // glibc: pthread_rwlock_tryrdlock
2684 // darwin: pthread_rwlock_tryrdlock
2685 // darwin: pthread_rwlock_tryrdlock$UNIX2003
2686 // Solaris: rw_tryrdlock (pthread_rwlock_tryrdlock is a weak alias)
2687 // FreeBSD: pthread_rwlock_tryrdlock
2689 __attribute__((noinline
))
2690 static int pthread_rwlock_tryrdlock_WRK(pthread_rwlock_t
* rwlock
)
2694 VALGRIND_GET_ORIG_FN(fn
);
2695 if (TRACE_PTH_FNS
) {
2696 fprintf(stderr
, "<< pthread_rwl_tryrlk %p", rwlock
); fflush(stderr
);
2699 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
2700 pthread_rwlock_t
*,rwlock
,
2701 long,0/*!isW*/, long,1/*isTryLock*/);
2703 CALL_FN_W_W(ret
, fn
, rwlock
);
2705 /* There's a hole here: libpthread now knows the lock is locked,
2706 but the tool doesn't, so some other thread could run and detect
2707 that the lock has been acquired by someone (this thread). Does
2708 this matter? Not sure, but I don't think so. */
2710 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
2711 pthread_rwlock_t
*,rwlock
, long,0/*!isW*/,
2712 long, (ret
== 0) ? True
: False
);
2716 DO_PthAPIerror( "pthread_rwlock_tryrdlock", ret
);
2719 if (TRACE_PTH_FNS
) {
2720 fprintf(stderr
, " :: rwl_tryrlk -> %d >>\n", ret
);
2724 #if defined(VGO_linux)
2725 PTH_FUNC(int, pthreadZurwlockZutryrdlock
, // pthread_rwlock_tryrdlock
2726 pthread_rwlock_t
* rwlock
) {
2727 return pthread_rwlock_tryrdlock_WRK(rwlock
);
2729 #elif defined(VGO_freebsd)
2730 PTH_FUNC(int, pthreadZurwlockZutryrdlock
, // pthread_rwlock_tryrdlock
2731 pthread_rwlock_t
* rwlock
) {
2732 return pthread_rwlock_tryrdlock_WRK(rwlock
);
2734 #elif defined(VGO_darwin)
2735 PTH_FUNC(int, pthreadZurwlockZutryrdlockZa
, // pthread_rwlock_tryrdlock*
2736 pthread_rwlock_t
* rwlock
) {
2737 return pthread_rwlock_tryrdlock_WRK(rwlock
);
2739 #elif defined(VGO_solaris)
2740 PTH_FUNC(int, rwZutryrdlock
, // rw_tryrdlock
2741 pthread_rwlock_t
*rwlock
) {
2742 return pthread_rwlock_tryrdlock_WRK(rwlock
);
2745 # error "Unsupported OS"
2749 //-----------------------------------------------------------
2750 // glibc: pthread_rwlock_timedrdlock
2751 // darwin: Unhandled
2752 // Solaris: pthread_rwlock_timedrdlock
2753 // Solaris: pthread_rwlock_reltimedrdlock_np
2754 // FreeBSD: pthread_rwlock_timedrdlock
2756 __attribute__((noinline
)) __attribute__((unused
))
2757 static int pthread_rwlock_timedrdlock_WRK(pthread_rwlock_t
*rwlock
,
2758 const struct timespec
*timeout
)
2762 VALGRIND_GET_ORIG_FN(fn
);
2763 if (TRACE_PTH_FNS
) {
2764 fprintf(stderr
, "<< pthread_rwl_timedrdl %p", rwlock
); fflush(stderr
);
2767 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
2768 pthread_rwlock_t
*, rwlock
,
2769 long, 0/*isW*/, long, 0/*isTryLock*/);
2771 CALL_FN_W_WW(ret
, fn
, rwlock
, timeout
);
2773 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
2774 pthread_rwlock_t
*, rwlock
, long, 0/*isW*/,
2775 long, (ret
== 0) ? True
: False
);
2777 DO_PthAPIerror("pthread_rwlock_timedrdlock", ret
);
2780 if (TRACE_PTH_FNS
) {
2781 fprintf(stderr
, " :: rwl_timedrdl -> %d >>\n", ret
);
2785 #if defined(VGO_linux)
2786 PTH_FUNC(int, pthreadZurwlockZutimedrdlock
, // pthread_rwlock_timedrdlock
2787 pthread_rwlock_t
*rwlock
,
2788 const struct timespec
*timeout
) {
2789 return pthread_rwlock_timedrdlock_WRK(rwlock
, timeout
);
2791 #elif defined(VGO_darwin)
2792 #elif defined(VGO_freebsd)
2793 PTH_FUNC(int, pthreadZurwlockZutimedrdlock
, // pthread_rwlock_timedrdlock
2794 pthread_rwlock_t
*rwlock
,
2795 const struct timespec
*timeout
) {
2796 return pthread_rwlock_timedrdlock_WRK(rwlock
, timeout
);
2798 #elif defined(VGO_solaris)
2799 PTH_FUNC(int, pthreadZurwlockZutimedrdlock
, // pthread_rwlock_timedrdlock
2800 pthread_rwlock_t
*rwlock
,
2801 const struct timespec
*timeout
) {
2802 return pthread_rwlock_timedrdlock_WRK(rwlock
, timeout
);
2804 PTH_FUNC(int, pthreadZurwlockZureltimedrdlockZunp
, // pthread_rwlock_timedrdlock_np
2805 pthread_rwlock_t
*rwlock
,
2806 const struct timespec
*timeout
) {
2807 return pthread_rwlock_timedrdlock_WRK(rwlock
, timeout
);
2810 # error "Unsupported OS"
2813 #if defined(VGO_linux)
2814 //-----------------------------------------------------------
2815 // glibc: pthread_rwlock_clockrdlock
2817 __attribute__((noinline
)) __attribute__((unused
))
2818 static int pthread_rwlock_clockrdlock_WRK(pthread_rwlock_t
*rwlock
,
2820 const struct timespec
*timeout
)
2824 VALGRIND_GET_ORIG_FN(fn
);
2825 if (TRACE_PTH_FNS
) {
2826 fprintf(stderr
, "<< pthread_rwl_clockrdl %p", rwlock
); fflush(stderr
);
2829 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
2830 pthread_rwlock_t
*, rwlock
,
2831 long, 0/*isW*/, long, 0/*isTryLock*/);
2833 CALL_FN_W_WWW(ret
, fn
, rwlock
, clockid
, timeout
);
2835 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
2836 pthread_rwlock_t
*, rwlock
, long, 0/*isW*/,
2837 long, (ret
== 0) ? True
: False
);
2839 DO_PthAPIerror("pthread_rwlock_clockrdlock", ret
);
2842 if (TRACE_PTH_FNS
) {
2843 fprintf(stderr
, " :: rwl_clockrdl -> %d >>\n", ret
);
2848 PTH_FUNC(int, pthreadZurwlockZuclockrdlock
, // pthread_rwlock_clockrdlock
2849 pthread_rwlock_t
*rwlock
,
2851 const struct timespec
*timeout
) {
2852 return pthread_rwlock_clockrdlock_WRK(rwlock
, clockid
, timeout
);
2857 //-----------------------------------------------------------
2858 // glibc: pthread_rwlock_timedwrlock
2859 // Solaris: pthread_rwlock_timedwrlock
2860 // Solaris: pthread_rwlock_reltimedwrlock_np
2861 // FreeBSD: pthread_rwlock_timedwrlock
2863 __attribute__((noinline
)) __attribute__((unused
))
2864 static int pthread_rwlock_timedwrlock_WRK(pthread_rwlock_t
*rwlock
,
2865 const struct timespec
*timeout
)
2869 VALGRIND_GET_ORIG_FN(fn
);
2870 if (TRACE_PTH_FNS
) {
2871 fprintf(stderr
, "<< pthread_rwl_timedwrl %p", rwlock
); fflush(stderr
);
2874 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
2875 pthread_rwlock_t
*, rwlock
,
2876 long, 1/*isW*/, long, 0/*isTryLock*/);
2878 CALL_FN_W_WW(ret
, fn
, rwlock
, timeout
);
2880 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
2881 pthread_rwlock_t
*, rwlock
, long, 1/*isW*/,
2882 long, (ret
== 0) ? True
: False
);
2884 DO_PthAPIerror("pthread_rwlock_timedwrlock", ret
);
2887 if (TRACE_PTH_FNS
) {
2888 fprintf(stderr
, " :: rwl_timedwrl -> %d >>\n", ret
);
2892 #if defined(VGO_linux)
2893 PTH_FUNC(int, pthreadZurwlockZutimedwrlock
, // pthread_rwlock_timedwrlock
2894 pthread_rwlock_t
*rwlock
,
2895 const struct timespec
*timeout
) {
2896 return pthread_rwlock_timedwrlock_WRK(rwlock
, timeout
);
2898 #elif defined(VGO_darwin)
2899 #elif defined(VGO_freebsd)
2900 PTH_FUNC(int, pthreadZurwlockZutimedwrlock
, // pthread_rwlock_timedwrlock
2901 pthread_rwlock_t
*rwlock
,
2902 const struct timespec
*timeout
) {
2903 return pthread_rwlock_timedwrlock_WRK(rwlock
, timeout
);
2905 #elif defined(VGO_solaris)
2906 PTH_FUNC(int, pthreadZurwlockZutimedwrlock
, // pthread_rwlock_timedwrlock
2907 pthread_rwlock_t
*rwlock
,
2908 const struct timespec
*timeout
) {
2909 return pthread_rwlock_timedwrlock_WRK(rwlock
, timeout
);
2911 PTH_FUNC(int, pthreadZurwlockZureltimedwrlockZunp
, // pthread_rwlock_timedwrlock_np
2912 pthread_rwlock_t
*rwlock
,
2913 const struct timespec
*timeout
) {
2914 return pthread_rwlock_timedwrlock_WRK(rwlock
, timeout
);
2917 # error "Unsupported OS"
2920 #if defined(VGO_linux)
2921 //-----------------------------------------------------------
2922 // glibc: pthread_rwlock_clockwrlock
2924 __attribute__((noinline
)) __attribute__((unused
))
2925 static int pthread_rwlock_clockwrlock_WRK(pthread_rwlock_t
*rwlock
,
2927 const struct timespec
*timeout
)
2931 VALGRIND_GET_ORIG_FN(fn
);
2932 if (TRACE_PTH_FNS
) {
2933 fprintf(stderr
, "<< pthread_rwl_clockwrl %p", rwlock
); fflush(stderr
);
2936 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
2937 pthread_rwlock_t
*, rwlock
,
2938 long, 1/*isW*/, long, 0/*isTryLock*/);
2940 CALL_FN_W_WWW(ret
, fn
, rwlock
, clockid
, timeout
);
2942 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
2943 pthread_rwlock_t
*, rwlock
, long, 1/*isW*/,
2944 long, (ret
== 0) ? True
: False
);
2946 DO_PthAPIerror("pthread_rwlock_clockwrlock", ret
);
2949 if (TRACE_PTH_FNS
) {
2950 fprintf(stderr
, " :: rwl_clockwrl -> %d >>\n", ret
);
2955 PTH_FUNC(int, pthreadZurwlockZuclockwrlock
, // pthread_rwlock_clockwrlock
2956 pthread_rwlock_t
*rwlock
,
2958 const struct timespec
*timeout
) {
2959 return pthread_rwlock_clockwrlock_WRK(rwlock
, clockid
, timeout
);
2964 //-----------------------------------------------------------
2965 // glibc: pthread_rwlock_unlock
2966 // darwin: pthread_rwlock_unlock
2967 // darwin: pthread_rwlock_unlock$UNIX2003
2968 // Solaris: rw_unlock (pthread_rwlock_unlock is a weak alias)
2969 // FreeBSD: pthread_rwlock_unlock
2970 __attribute__((noinline
))
2971 static int pthread_rwlock_unlock_WRK(pthread_rwlock_t
* rwlock
)
2975 VALGRIND_GET_ORIG_FN(fn
);
2976 if (TRACE_PTH_FNS
) {
2977 fprintf(stderr
, "<< pthread_rwl_unlk %p", rwlock
); fflush(stderr
);
2980 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE
,
2981 pthread_rwlock_t
*,rwlock
);
2983 CALL_FN_W_W(ret
, fn
, rwlock
);
2985 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST
,
2986 pthread_rwlock_t
*,rwlock
);
2988 DO_PthAPIerror( "pthread_rwlock_unlock", ret
);
2991 if (TRACE_PTH_FNS
) {
2992 fprintf(stderr
, " :: rwl_unlk -> %d >>\n", ret
);
2996 #if defined(VGO_linux)
2997 PTH_FUNC(int, pthreadZurwlockZuunlock
, // pthread_rwlock_unlock
2998 pthread_rwlock_t
* rwlock
) {
2999 return pthread_rwlock_unlock_WRK(rwlock
);
3001 #elif defined(VGO_freebsd)
3002 PTH_FUNC(int, pthreadZurwlockZuunlock
, // pthread_rwlock_unlock
3003 pthread_rwlock_t
* rwlock
) {
3004 return pthread_rwlock_unlock_WRK(rwlock
);
3006 #elif defined(VGO_darwin)
3007 PTH_FUNC(int, pthreadZurwlockZuunlockZa
, // pthread_rwlock_unlock*
3008 pthread_rwlock_t
* rwlock
) {
3009 return pthread_rwlock_unlock_WRK(rwlock
);
3011 #elif defined(VGO_solaris)
3012 PTH_FUNC(int, rwZuunlock
, // rw_unlock
3013 pthread_rwlock_t
*rwlock
) {
3014 return pthread_rwlock_unlock_WRK(rwlock
);
3017 # error "Unsupported OS"
3020 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
3023 /*----------------------------------------------------------------*/
3024 /*--- POSIX semaphores ---*/
3025 /*----------------------------------------------------------------*/
3027 #include <semaphore.h>
3028 #include <fcntl.h> /* O_CREAT */
3030 #define TRACE_SEM_FNS 0
3033 int sem_init(sem_t *sem, int pshared, unsigned value);
3034 int sem_destroy(sem_t *sem);
3035 int sem_wait(sem_t *sem);
3036 int sem_post(sem_t *sem);
3037 sem_t* sem_open(const char *name, int oflag,
3038 ... [mode_t mode, unsigned value]);
3039 [complete with its idiotic semantics]
3040 int sem_close(sem_t* sem);
3043 int sem_trywait(sem_t *sem);
3044 int sem_timedwait(sem_t *restrict sem,
3045 const struct timespec *restrict abs_timeout);
3048 //-----------------------------------------------------------
3049 // glibc: sem_init@@GLIBC_2.2.5
3050 // glibc: sem_init@@GLIBC_2.1
3051 // glibc: sem_init@GLIBC_2.0
3053 // Solaris: sema_init (sem_init is built on top of sem_init)
3054 // FreeBSD: sem_init (libc)
3056 #if !defined(VGO_solaris)
3057 __attribute__((noinline
))
3058 static int sem_init_WRK(sem_t
* sem
, int pshared
, unsigned long value
)
3062 VALGRIND_GET_ORIG_FN(fn
);
3064 if (TRACE_SEM_FNS
) {
3065 fprintf(stderr
, "<< sem_init(%p,%d,%lu) ", sem
,pshared
,value
);
3069 CALL_FN_W_WWW(ret
, fn
, sem
,pshared
,value
);
3072 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST
,
3073 sem_t
*, sem
, unsigned long, value
);
3075 DO_PthAPIerror( "sem_init", errno
);
3078 if (TRACE_SEM_FNS
) {
3079 fprintf(stderr
, " sem_init -> %d >>\n", ret
);
3085 #if defined(VGO_linux)
3086 PTH_FUNC(int, semZuinitZAZa
, // sem_init@*
3087 sem_t
* sem
, int pshared
, unsigned long value
) {
3088 return sem_init_WRK(sem
, pshared
, value
);
3090 #elif defined(VGO_darwin)
3091 PTH_FUNC(int, semZuinit
, // sem_init
3092 sem_t
* sem
, int pshared
, unsigned long value
) {
3093 return sem_init_WRK(sem
, pshared
, value
);
3095 #elif defined(VGO_freebsd)
3096 LIBC_FUNC(int, semZuinit
, // sem_init
3097 sem_t
* sem
, int pshared
, unsigned long value
) {
3098 return sem_init_WRK(sem
, pshared
, value
);
3101 # error "Unsupported OS"
3104 #else /* VGO_solaris */
3105 PTH_FUNC(int, semaZuinit
, // sema_init
3113 VALGRIND_GET_ORIG_FN(fn
);
3115 if (TRACE_SEM_FNS
) {
3116 fprintf(stderr
, "<< sema_init(%p, %d, %u) ", sem
, type
, value
);
3120 CALL_FN_W_WWWW(ret
, fn
, sem
, value
, type
, arg
);
3123 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST
,
3124 sema_t
*, sem
, Word
, value
);
3126 DO_PthAPIerror("sema_init", ret
);
3129 if (TRACE_SEM_FNS
) {
3130 fprintf(stderr
, " sema_init -> %d >>\n", ret
);
3136 #endif /* VGO_solaris */
3139 //-----------------------------------------------------------
3140 // glibc: sem_destroy@GLIBC_2.0
3141 // glibc: sem_destroy@@GLIBC_2.1
3142 // glibc: sem_destroy@@GLIBC_2.2.5
3143 // darwin: sem_destroy
3144 // Solaris: sema_destroy (sem_destroy is built on top of sema_destroy)
3145 // FreeBSD: sem_destroy (libc)
3146 __attribute__((noinline
))
3147 static int sem_destroy_WRK(sem_t
* sem
)
3151 VALGRIND_GET_ORIG_FN(fn
);
3153 if (TRACE_SEM_FNS
) {
3154 fprintf(stderr
, "<< sem_destroy(%p) ", sem
);
3158 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE
, sem_t
*, sem
);
3160 CALL_FN_W_W(ret
, fn
, sem
);
3163 DO_PthAPIerror( "sem_destroy", SEM_ERROR
);
3166 if (TRACE_SEM_FNS
) {
3167 fprintf(stderr
, " sem_destroy -> %d >>\n", ret
);
3173 #if defined(VGO_linux)
3174 PTH_FUNC(int, semZudestroyZAZa
, // sem_destroy*
3176 return sem_destroy_WRK(sem
);
3178 #elif defined(VGO_darwin)
3179 PTH_FUNC(int, semZudestroy
, // sem_destroy
3181 return sem_destroy_WRK(sem
);
3183 #elif defined(VGO_freebsd)
3184 LIBC_FUNC(int, semZudestroy
, // sem_destroy
3186 return sem_destroy_WRK(sem
);
3188 #elif defined(VGO_solaris)
3189 PTH_FUNC(int, semaZudestroy
, // sema_destroy
3191 return sem_destroy_WRK(sem
);
3194 # error "Unsupported OS"
3198 //-----------------------------------------------------------
3200 // glibc: sem_wait@GLIBC_2.0
3201 // glibc: sem_wait@@GLIBC_2.1
3203 // darwin: sem_wait$NOCANCEL$UNIX2003
3204 // darwin: sem_wait$UNIX2003
3205 // Solaris: sema_wait (sem_wait is built on top of sema_wait)
3206 // FreeBSD: sem_wait (libc)
3208 /* wait: decrement semaphore - acquire lockage */
3209 __attribute__((noinline
))
3210 static int sem_wait_WRK(sem_t
* sem
)
3214 VALGRIND_GET_ORIG_FN(fn
);
3216 if (TRACE_SEM_FNS
) {
3217 fprintf(stderr
, "<< sem_wait(%p) ", sem
);
3221 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_PRE
, sem_t
*,sem
);
3223 CALL_FN_W_W(ret
, fn
, sem
);
3225 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST
, sem_t
*,sem
,
3226 long, (ret
== 0) ? True
: False
);
3229 DO_PthAPIerror( "sem_wait", SEM_ERROR
);
3232 if (TRACE_SEM_FNS
) {
3233 fprintf(stderr
, " sem_wait -> %d >>\n", ret
);
3239 #if defined(VGO_linux)
3240 PTH_FUNC(int, semZuwait
, sem_t
* sem
) { /* sem_wait */
3241 return sem_wait_WRK(sem
);
3243 PTH_FUNC(int, semZuwaitZAZa
, sem_t
* sem
) { /* sem_wait@* */
3244 return sem_wait_WRK(sem
);
3246 #elif defined(VGO_darwin)
3247 PTH_FUNC(int, semZuwait
, sem_t
* sem
) { /* sem_wait */
3248 return sem_wait_WRK(sem
);
3250 PTH_FUNC(int, semZuwaitZDZa
, sem_t
* sem
) { /* sem_wait$* */
3251 return sem_wait_WRK(sem
);
3253 #elif defined(VGO_freebsd)
3254 LIBC_FUNC(int, semZuwait
, sem_t
* sem
) { /* sem_wait */
3255 return sem_wait_WRK(sem
);
3257 #elif defined(VGO_solaris)
3258 PTH_FUNC(int, semaZuwait
, sem_t
*sem
) { /* sema_wait */
3259 return sem_wait_WRK(sem
);
3262 # error "Unsupported OS"
3265 //-----------------------------------------------------------
3266 // glibc: sem_trywait
3267 // glibc: sem_trywait@GLIBC_2.0
3268 // glibc: sem_trywait@@GLIBC_2.1
3269 // darwin: sem_trywait
3270 // Solaris: sema_trywait (sem_teywait is built on top of sema_trywait)
3271 // FreeBSD: sem_trywait (libc)
3273 /* trywait: decrement semaphore if non-zero otherwise return error */
3274 __attribute__((noinline
))
3275 static int sem_trywait_WRK(sem_t
* sem
)
3279 VALGRIND_GET_ORIG_FN(fn
);
3281 if (TRACE_SEM_FNS
) {
3282 fprintf(stderr
, "<< sem_trywait(%p) ", sem
);
3286 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_PRE
, sem_t
*,sem
);
3288 CALL_FN_W_W(ret
, fn
, sem
);
3290 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST
, sem_t
*,sem
,
3291 long, (ret
== 0) ? True
: False
);
3294 DO_PthAPIerror( "sem_trywait", SEM_ERROR
);
3297 if (TRACE_SEM_FNS
) {
3298 fprintf(stderr
, " sem_trywait -> %d >>\n", ret
);
3305 #if defined(VGO_linux)
3306 PTH_FUNC(int, semZutrywait
, sem_t
* sem
) { /* sem_trywait */
3307 return sem_trywait_WRK(sem
);
3309 PTH_FUNC(int, semZutrywaitZAZa
, sem_t
* sem
) { /* sem_trywait@* */
3310 return sem_trywait_WRK(sem
);
3312 #elif defined(VGO_darwin)
3313 PTH_FUNC(int, semZutrywait
, sem_t
* sem
) { /* sem_trywait */
3314 return sem_trywait_WRK(sem
);
3316 #elif defined(VGO_freebsd)
3317 LIBC_FUNC(int, semZutrywait
, sem_t
* sem
) { /* sem_trywait */
3318 return sem_trywait_WRK(sem
);
3320 #elif defined(VGO_solaris)
3321 PTH_FUNC(int, semaZutrywait
, sem_t
*sem
) { /* sema_trywait */
3322 return sem_trywait_WRK(sem
);
3325 # error "Unsupported OS"
3328 //-----------------------------------------------------------
3329 // glibc: sem_timedwait
3330 // glibc: sem_timedwait@GLIBC_2.0
3331 // glibc: sem_timedwait@@GLIBC_2.1
3332 // darwin: does not exist
3333 // Solaris: sema_timedwait (sem_timedwait is built on top of sema_timedwait)
3334 // FreeBSD: sem_timedwait (libc)
3336 #if !defined(VGO_darwin)
3337 /* timedwait: decrement semaphore if non-zero otherwise wait for specified
3338 time then return an error */
3339 __attribute__((noinline
))
3340 static int sem_timedwait_WRK(sem_t
* sem
, const struct timespec
* abs_timeout
)
3344 VALGRIND_GET_ORIG_FN(fn
);
3346 if (TRACE_SEM_FNS
) {
3347 fprintf(stderr
, "<< sem_timedwait(%p, %p) ", sem
, abs_timeout
);
3351 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_PRE
, sem_t
*,sem
);
3353 CALL_FN_W_WW(ret
, fn
, sem
, abs_timeout
);
3355 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST
, sem_t
*,sem
,
3356 long, (ret
== 0) ? True
: False
);
3359 DO_PthAPIerror( "sem_timedwait", SEM_ERROR
);
3362 if (TRACE_SEM_FNS
) {
3363 fprintf(stderr
, " sem_timedwait -> %d >>\n", ret
);
3370 #if defined(VGO_linux)
3371 PTH_FUNC(int, semZutimedwait
, sem_t
* sem
, const struct timespec
* abs_timeout
) { /* sem_timedwait */
3372 return sem_timedwait_WRK(sem
, abs_timeout
);
3374 PTH_FUNC(int, semZutimedwaitZAZa
, sem_t
* sem
, const struct timespec
* abs_timeout
) { /* sem_timedwait@* */
3375 return sem_timedwait_WRK(sem
, abs_timeout
);
3377 #elif defined(VGO_freebsd)
3378 LIBC_FUNC(int, semZutimedwait
, sem_t
* sem
, const struct timespec
* abs_timeout
) { /* sem_timedwait */
3379 return sem_timedwait_WRK(sem
, abs_timeout
);
3381 #elif defined(VGO_solaris)
3382 PTH_FUNC(int, semaZutimedwait
, sem_t
*sem
, const struct timespec
* abs_timeout
) { /* sema_timedwait */
3383 return sem_timedwait_WRK(sem
, abs_timeout
);
3386 # error "Unsupported OS"
3388 #endif // not VGO_darwin
3390 //-----------------------------------------------------------
3391 // glibc: does not exist
3392 // darwin: does not exist
3393 // Solaris: does not exist
3394 // FreeBSD: sem_clockwait_np (libc)
3396 /* clockwait_np: decrement semaphore if non-zero otherwise wait for specified
3397 time then return an error with a flag to select the kind of clock and
3398 a timespec for the remaining time */
3399 #if defined (VGO_freebsd)
3400 __attribute__((noinline
))
3401 static int sem_clockwait_np_WRK(sem_t
* sem
, clockid_t clock_id
, int flags
,
3402 const struct timespec
* rqtp
, struct timespec
* rmtp
)
3406 VALGRIND_GET_ORIG_FN(fn
);
3408 if (TRACE_SEM_FNS
) {
3409 fprintf(stderr
, "<< sem_clockwait_np(%p, %d, %d, %p, %p) ", sem
, clock_id
, flags
, rqtp
, rmtp
);
3413 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_PRE
, sem_t
*,sem
);
3415 CALL_FN_W_5W(ret
, fn
, sem
, clock_id
, flags
, rqtp
, rmtp
);
3417 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST
, sem_t
*,sem
,
3418 long, (ret
== 0) ? True
: False
);
3421 DO_PthAPIerror( "sem_clockwait_np", SEM_ERROR
);
3424 if (TRACE_SEM_FNS
) {
3425 fprintf(stderr
, " sem_clockwait_np -> %d >>\n", ret
);
3432 LIBC_FUNC(int, semZuclockwaitZunp
, sem_t
* sem
, clockid_t clock_id
, int flags
,
3433 const struct timespec
* rqtp
, struct timespec
* rmtp
) { /* sem_clockwait_np */
3434 return sem_clockwait_np_WRK(sem
, clock_id
, flags
, rqtp
, rmtp
);
3438 //-----------------------------------------------------------
3440 // glibc: sem_post@GLIBC_2.0
3441 // glibc: sem_post@@GLIBC_2.1
3443 // Solaris: sema_post (sem_post is built on top of sema_post)
3444 // FreeBSD: sem_post (libc)
3446 /* post: increment semaphore - release lockage */
3447 __attribute__((noinline
))
3448 static int sem_post_WRK(sem_t
* sem
)
3453 VALGRIND_GET_ORIG_FN(fn
);
3455 if (TRACE_SEM_FNS
) {
3456 fprintf(stderr
, "<< sem_post(%p) ", sem
);
3460 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_PRE
, sem_t
*,sem
);
3462 CALL_FN_W_W(ret
, fn
, sem
);
3464 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_POST
, sem_t
*,sem
);
3467 DO_PthAPIerror( "sem_post", SEM_ERROR
);
3470 if (TRACE_SEM_FNS
) {
3471 fprintf(stderr
, " sem_post -> %d >>\n", ret
);
3477 #if defined(VGO_linux)
3478 PTH_FUNC(int, semZupost
, sem_t
* sem
) { /* sem_post */
3479 return sem_post_WRK(sem
);
3481 PTH_FUNC(int, semZupostZAZa
, sem_t
* sem
) { /* sem_post@* */
3482 return sem_post_WRK(sem
);
3484 #elif defined(VGO_darwin)
3485 PTH_FUNC(int, semZupost
, sem_t
* sem
) { /* sem_post */
3486 return sem_post_WRK(sem
);
3488 #elif defined(VGO_freebsd)
3489 LIBC_FUNC(int, semZupost
, sem_t
* sem
) { /* sem_post */
3490 return sem_post_WRK(sem
);
3492 #elif defined(VGO_solaris)
3493 PTH_FUNC(int, semaZupost
, sem_t
*sem
) { /* sema_post */
3494 return sem_post_WRK(sem
);
3497 # error "Unsupported OS"
3501 //-----------------------------------------------------------
3504 // Solaris: sem_open
3505 // FreeBSD: sem_open
3507 #if defined(VGO_freebsd)
3508 LIBC_FUNC(sem_t
*, semZuopen
,
3509 const char* name
, long oflag
,
3510 long mode
, unsigned long value
)
3512 PTH_FUNC(sem_t
*, semZuopen
,
3513 const char* name
, long oflag
,
3514 long mode
, unsigned long value
)
3517 /* A copy of sem_init_WRK (more or less). Is this correct? */
3520 VALGRIND_GET_ORIG_FN(fn
);
3522 if (TRACE_SEM_FNS
) {
3523 fprintf(stderr
, "<< sem_open(\"%s\",%ld,%lx,%lu) ",
3524 name
,oflag
,mode
,value
);
3528 CALL_FN_W_WWWW(ret
, fn
, name
,oflag
,mode
,value
);
3530 if (ret
!= SEM_FAILED
&& (oflag
& O_CREAT
)) {
3531 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST
,
3532 sem_t
*, ret
, unsigned long, value
);
3534 if (ret
== SEM_FAILED
) {
3535 DO_PthAPIerror( "sem_open", errno
);
3538 if (TRACE_SEM_FNS
) {
3539 fprintf(stderr
, " sem_open -> %p >>\n", ret
);
3547 //-----------------------------------------------------------
3549 // darwin: sem_close
3550 // Solaris: sem_close
3551 // FreeBSD: sem_close
3552 #if defined (VGO_freebsd)
3553 LIBC_FUNC(int, sem_close
, sem_t
* sem
)
3555 PTH_FUNC(int, sem_close
, sem_t
* sem
)
3560 VALGRIND_GET_ORIG_FN(fn
);
3562 if (TRACE_SEM_FNS
) {
3563 fprintf(stderr
, "<< sem_close(%p) ", sem
);
3567 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE
, sem_t
*, sem
);
3569 CALL_FN_W_W(ret
, fn
, sem
);
3572 DO_PthAPIerror( "sem_close", errno
);
3575 if (TRACE_SEM_FNS
) {
3576 fprintf(stderr
, " close -> %d >>\n", ret
);
3584 /*----------------------------------------------------------------*/
3585 /*--- Qt 4 threading functions (w/ GNU name mangling) ---*/
3586 /*----------------------------------------------------------------*/
3592 QMutex::tryLock(int)
3594 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC1ENS_13RecursionModeE
3595 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC2ENS_13RecursionModeE
3596 QMutex::~QMutex() _ZN6QMutexD1Ev
3597 QMutex::~QMutex() _ZN6QMutexD2Ev
3600 QReadWriteLock::lockForRead()
3601 QReadWriteLock::lockForWrite()
3602 QReadWriteLock::unlock()
3603 QReadWriteLock::tryLockForRead(int)
3604 QReadWriteLock::tryLockForRead()
3605 QReadWriteLock::tryLockForWrite(int)
3606 QReadWriteLock::tryLockForWrite()
3608 QWaitCondition::wait(QMutex*, unsigned long)
3609 QWaitCondition::wakeAll()
3610 QWaitCondition::wakeOne()
3614 /* More comments, 19 Nov 08, based on assessment of qt-4.5.0TP1,
3617 It's apparently only necessary to intercept QMutex, since that is
3618 not implemented using pthread_mutex_t; instead Qt4 has its own
3619 implementation based on atomics (to check the non-contended case)
3620 and pthread_cond_wait (to wait in the contended case).
3622 QReadWriteLock is built on top of QMutex, counters, and a wait
3623 queue. So we don't need to handle it specially once QMutex
3624 handling is correct -- presumably the dependencies through QMutex
3625 are sufficient to avoid any false race reports. On the other hand,
3626 it is an open question whether too many dependencies are observed
3627 -- in which case we may miss races (false negatives). I suspect
3628 this is likely to be the case, unfortunately.
3630 QWaitCondition is built on pthread_cond_t, pthread_mutex_t, QMutex
3631 and QReadWriteLock. Same compositional-correctness justificiation
3632 and limitations as fro QReadWriteLock.
3634 Ditto QSemaphore (from cursory examination).
3636 Does it matter that only QMutex is handled directly? Open
3637 question. From testing with drd/tests/qt4_* and with KDE4 apps, it
3638 appears that no false errors are reported; however it is not clear
3639 if this is causing false negatives.
3641 Another problem with Qt4 is thread exiting. Threads are created
3642 with pthread_create (fine); but they detach and simply exit when
3643 done. There is no use of pthread_join, and the provided
3644 wait-for-a-thread-to-exit mechanism (QThread::wait, I believe)
3645 relies on a system of mutexes and flags. I suspect this also
3646 causes too many dependencies to appear. Consequently H sometimes
3647 fails to detect races at exit in some very short-lived racy
3648 programs, because it appears that a thread can exit _and_ have an
3649 observed dependency edge back to the main thread (presumably)
3650 before the main thread reaps the child (that is, calls
3653 This theory is supported by the observation that if all threads are
3654 made to wait at a pthread_barrier_t immediately before they exit,
3655 then H's detection of races in such programs becomes reliable;
3656 without the barrier, it is varies from run to run, depending
3657 (according to investigation) on whether aforementioned
3658 exit-before-reaping behaviour happens or not.
3660 Finally, why is it necessary to intercept the QMutex constructors
3661 and destructors? The constructors are intercepted only as a matter
3662 of convenience, so H can print accurate "first observed at"
3663 clauses. However, it is actually necessary to intercept the
3664 destructors (as it is with pthread_mutex_destroy) in order that
3665 locks get removed from LAOG when they are destroyed.
3668 // soname is libQtCore.so.4 ; match against libQtCore.so*
3669 #define QT4_FUNC(ret_ty, f, args...) \
3670 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args); \
3671 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args)
3673 // soname is libQt5Core.so.4 ; match against libQt5Core.so*
3674 #define QT5_FUNC(ret_ty, f, args...) \
3675 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args); \
3676 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args)
3678 //-----------------------------------------------------------
3680 __attribute__((noinline
))
3681 static void QMutex_lock_WRK(void* self
)
3684 VALGRIND_GET_ORIG_FN(fn
);
3685 if (TRACE_QT4_FNS
) {
3686 fprintf(stderr
, "<< QMutex::lock %p", self
); fflush(stderr
);
3689 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
3690 void*,self
, long,0/*!isTryLock*/);
3692 CALL_FN_v_W(fn
, self
);
3694 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
3695 void *, self
, long, True
);
3697 if (TRACE_QT4_FNS
) {
3698 fprintf(stderr
, " :: Q::lock done >>\n");
3702 QT4_FUNC(void, _ZN6QMutex4lockEv
, void* self
) {
3703 QMutex_lock_WRK(self
);
3705 QT5_FUNC(void, _ZN6QMutex4lockEv
, void* self
) {
3706 QMutex_lock_WRK(self
);
3709 //-----------------------------------------------------------
3711 __attribute__((noinline
))
3712 static void QMutex_unlock_WRK(void* self
)
3715 VALGRIND_GET_ORIG_FN(fn
);
3717 if (TRACE_QT4_FNS
) {
3718 fprintf(stderr
, "<< QMutex::unlock %p", self
); fflush(stderr
);
3721 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE
,
3724 CALL_FN_v_W(fn
, self
);
3726 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST
,
3729 if (TRACE_QT4_FNS
) {
3730 fprintf(stderr
, " Q::unlock done >>\n");
3734 QT4_FUNC(void, _ZN6QMutex6unlockEv
, void* self
) {
3735 QMutex_unlock_WRK(self
);
3737 QT5_FUNC(void, _ZN6QMutex6unlockEv
, void* self
) {
3738 QMutex_unlock_WRK(self
);
3741 //-----------------------------------------------------------
3742 // bool QMutex::tryLock()
3743 // using 'long' to mimic C++ 'bool'
3744 __attribute__((noinline
))
3745 static long QMutex_tryLock_WRK(void* self
)
3749 VALGRIND_GET_ORIG_FN(fn
);
3750 if (TRACE_QT4_FNS
) {
3751 fprintf(stderr
, "<< QMutex::tryLock %p", self
); fflush(stderr
);
3754 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
3755 void*,self
, long,1/*isTryLock*/);
3757 CALL_FN_W_W(ret
, fn
, self
);
3759 // assumes that only the low 8 bits of the 'bool' are significant
3760 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
3761 void *, self
, long, (ret
& 0xFF) ? True
: False
);
3763 if (TRACE_QT4_FNS
) {
3764 fprintf(stderr
, " :: Q::tryLock -> %lu >>\n", ret
);
3770 QT4_FUNC(long, _ZN6QMutex7tryLockEv
, void* self
) {
3771 return QMutex_tryLock_WRK(self
);
3773 QT5_FUNC(long, _ZN6QMutex7tryLockEv
, void* self
) {
3774 return QMutex_tryLock_WRK(self
);
3777 //-----------------------------------------------------------
3778 // bool QMutex::tryLock(int)
3779 // using 'long' to mimic C++ 'bool'
3780 __attribute__((noinline
))
3781 static long QMutex_tryLock_int_WRK(void* self
, long arg2
)
3785 VALGRIND_GET_ORIG_FN(fn
);
3786 if (TRACE_QT4_FNS
) {
3787 fprintf(stderr
, "<< QMutex::tryLock(int) %p %d", self
, (int)arg2
);
3791 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
3792 void*,self
, long,1/*isTryLock*/);
3794 CALL_FN_W_WW(ret
, fn
, self
,arg2
);
3796 // assumes that only the low 8 bits of the 'bool' are significant
3797 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
3798 void *, self
, long, (ret
& 0xFF) ? True
: False
);
3800 if (TRACE_QT4_FNS
) {
3801 fprintf(stderr
, " :: Q::tryLock(int) -> %lu >>\n", ret
);
3807 QT4_FUNC(long, _ZN6QMutex7tryLockEi
, void* self
, long arg2
) {
3808 return QMutex_tryLock_int_WRK(self
, arg2
);
3810 QT5_FUNC(long, _ZN6QMutex7tryLockEi
, void* self
, long arg2
) {
3811 return QMutex_tryLock_int_WRK(self
, arg2
);
3814 //-----------------------------------------------------------
3815 // It's not really very clear what the args are here. But from
3816 // a bit of dataflow analysis of the generated machine code of
3817 // the original function, it appears this takes two args, and
3818 // returns nothing. Nevertheless preserve return value just in
3819 // case. A bit of debug printing indicates that the first arg
3820 // is that of the mutex and the second is either zero or one,
3821 // probably being the recursion mode, therefore.
3822 // QMutex::QMutex(QMutex::RecursionMode) ("C1ENS" variant)
3823 __attribute__((noinline
))
3824 static void* QMutex_constructor_WRK(void* mutex
, long recmode
)
3828 VALGRIND_GET_ORIG_FN(fn
);
3829 CALL_FN_W_WW(ret
, fn
, mutex
, recmode
);
3830 // fprintf(stderr, "QMutex constructor 1: %p <- %p %p\n", ret, arg1, arg2);
3831 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST
,
3832 void*,mutex
, long,1/*mbRec*/);
3836 QT4_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE
, void* self
, long recmode
) {
3837 return QMutex_constructor_WRK(self
, recmode
);
3839 QT5_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE
, void* self
, long recmode
) {
3840 return QMutex_constructor_WRK(self
, recmode
);
3843 //-----------------------------------------------------------
3844 // QMutex::~QMutex() ("D1Ev" variant)
3845 __attribute__((noinline
))
3846 static void* QMutex_destructor_WRK(void* mutex
)
3850 VALGRIND_GET_ORIG_FN(fn
);
3851 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE
,
3853 CALL_FN_W_W(ret
, fn
, mutex
);
3857 QT4_FUNC(void*, _ZN6QMutexD1Ev
, void* self
) {
3858 return QMutex_destructor_WRK(self
);
3860 QT5_FUNC(void*, _ZN6QMutexD1Ev
, void* self
) {
3861 return QMutex_destructor_WRK(self
);
3864 //-----------------------------------------------------------
3865 // QMutex::QMutex(QMutex::RecursionMode) ("C2ENS" variant)
3866 QT4_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE
,
3872 /* Android's gcc behaves like it doesn't know that assert(0)
3873 never returns. Hence: */
3877 QT5_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE
, void* self
, long recmode
)
3884 //-----------------------------------------------------------
3885 // QMutex::~QMutex() ("D2Ev" variant)
3886 QT4_FUNC(void*, _ZN6QMutexD2Ev
, void* mutex
)
3889 /* Android's gcc behaves like it doesn't know that assert(0)
3890 never returns. Hence: */
3894 QT5_FUNC(void*, _ZN6QMutexD2Ev
, void* self
)
3901 // QReadWriteLock is not intercepted directly. See comments
3904 //// QReadWriteLock::lockForRead()
3905 //// _ZN14QReadWriteLock11lockForReadEv == QReadWriteLock::lockForRead()
3906 //QT4_FUNC(void, ZuZZN14QReadWriteLock11lockForReadEv,
3907 // // _ZN14QReadWriteLock11lockForReadEv
3911 // VALGRIND_GET_ORIG_FN(fn);
3912 // if (TRACE_QT4_FNS) {
3913 // fprintf(stderr, "<< QReadWriteLock::lockForRead %p", self);
3917 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
3919 // long,0/*!isW*/, long,0/*!isTryLock*/);
3921 // CALL_FN_v_W(fn, self);
3923 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
3924 // void*,self, long,0/*!isW*/, long, True);
3926 // if (TRACE_QT4_FNS) {
3927 // fprintf(stderr, " :: Q::lockForRead :: done >>\n");
3931 //// QReadWriteLock::lockForWrite()
3932 //// _ZN14QReadWriteLock12lockForWriteEv == QReadWriteLock::lockForWrite()
3933 //QT4_FUNC(void, ZuZZN14QReadWriteLock12lockForWriteEv,
3934 // // _ZN14QReadWriteLock12lockForWriteEv
3938 // VALGRIND_GET_ORIG_FN(fn);
3939 // if (TRACE_QT4_FNS) {
3940 // fprintf(stderr, "<< QReadWriteLock::lockForWrite %p", self);
3944 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
3946 // long,1/*isW*/, long,0/*!isTryLock*/);
3948 // CALL_FN_v_W(fn, self);
3950 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
3951 // void*,self, long,1/*isW*/, long, True);
3953 // if (TRACE_QT4_FNS) {
3954 // fprintf(stderr, " :: Q::lockForWrite :: done >>\n");
3958 //// QReadWriteLock::unlock()
3959 //// _ZN14QReadWriteLock6unlockEv == QReadWriteLock::unlock()
3960 //QT4_FUNC(void, ZuZZN14QReadWriteLock6unlockEv,
3961 // // _ZN14QReadWriteLock6unlockEv
3965 // VALGRIND_GET_ORIG_FN(fn);
3966 // if (TRACE_QT4_FNS) {
3967 // fprintf(stderr, "<< QReadWriteLock::unlock %p", self);
3971 // DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
3974 // CALL_FN_v_W(fn, self);
3976 // DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
3979 // if (TRACE_QT4_FNS) {
3980 // fprintf(stderr, " :: Q::unlock :: done >>\n");
3985 /*----------------------------------------------------------------*/
3986 /*--- Replacements for basic string functions, that don't ---*/
3987 /*--- overrun the input arrays. ---*/
3988 /*----------------------------------------------------------------*/
3990 #include "../shared/vg_replace_strmem.c"
3992 /*--------------------------------------------------------------------*/
3993 /*--- end hg_intercepts.c ---*/
3994 /*--------------------------------------------------------------------*/