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"
60 #if defined(VGO_solaris)
61 /* See porting comments in drd/drd_pthread_intercepts.c
62 However when a POSIX threads API function (for example pthread_cond_init)
63 is built upon the Solaris one (cond_init), intercept only the bottom one.
64 Helgrind does not contain generic synchronization nesting like DRD
65 and double intercept confuses it. */
68 #endif /* VGO_solaris */
71 #define TRACE_PTH_FNS 0
72 #define TRACE_QT4_FNS 0
73 #define TRACE_GNAT_FNS 0
76 /*----------------------------------------------------------------*/
78 /*----------------------------------------------------------------*/
80 #if defined(VGO_solaris)
81 /* pthread_t is typedef'd to 'unsigned int' but in DO_CREQ_* macros
82 sizeof(Word) is expected. */
83 #define CREQ_PTHREAD_T Word
86 #define CREQ_PTHREAD_T pthread_t
87 #define SEM_ERROR errno
88 #endif /* VGO_solaris */
90 #define HG_EXPAND(tok) #tok
91 #define HG_STR(tok) HG_EXPAND(tok)
92 #define HG_WEAK_ALIAS(name, aliasname) \
93 extern __typeof (name) aliasname __attribute__ ((weak, alias(HG_STR(name))))
95 #if defined(VG_WRAP_THREAD_FUNCTION_LIBPTHREAD_ONLY)
96 #define PTH_FUNC(ret_ty, f, args...) \
97 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args); \
98 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args)
99 #elif defined(VG_WRAP_THREAD_FUNCTION_LIBC_AND_LIBPTHREAD)
100 #define PTH_FUNC(ret_ty, f, args...) \
101 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args); \
102 HG_WEAK_ALIAS(I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f), I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)); \
103 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args)
104 #elif defined(VG_WRAP_THREAD_FUNCTION_LIBC_ONLY)
105 #define PTH_FUNC(ret_ty, f, args...) \
106 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)(args); \
107 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)(args)
109 # error "Unknown platform/thread wrapping"
112 #if defined(VGO_freebsd)
113 #define LIBC_FUNC(ret_ty, f, args...) \
114 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)(args); \
115 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)(args)
118 // Do a client request. These are macros rather than a functions so
119 // as to avoid having an extra frame in stack traces.
121 // NB: these duplicate definitions in helgrind.h. But here, we
122 // can have better typing (Word etc) and assertions, whereas
123 // in helgrind.h we can't. Obviously it's important the two
124 // sets of definitions are kept in sync.
126 // nuke the previous definitions
132 #define DO_CREQ_v_W(_creqF, _ty1F,_arg1F) \
135 assert(sizeof(_ty1F) == sizeof(Word)); \
136 _arg1 = (Word)(_arg1F); \
137 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
141 #define DO_CREQ_v_WW(_creqF, _ty1F,_arg1F, _ty2F,_arg2F) \
144 assert(sizeof(_ty1F) == sizeof(Word)); \
145 assert(sizeof(_ty2F) == sizeof(Word)); \
146 _arg1 = (Word)(_arg1F); \
147 _arg2 = (Word)(_arg2F); \
148 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
149 _arg1,_arg2,0,0,0); \
152 #define DO_CREQ_W_WW(_resF, _creqF, _ty1F,_arg1F, \
155 Word _res, _arg1, _arg2; \
156 assert(sizeof(_ty1F) == sizeof(Word)); \
157 assert(sizeof(_ty2F) == sizeof(Word)); \
158 _arg1 = (Word)(_arg1F); \
159 _arg2 = (Word)(_arg2F); \
160 _res = VALGRIND_DO_CLIENT_REQUEST_EXPR(2, \
162 _arg1,_arg2,0,0,0); \
166 #define DO_CREQ_v_WWW(_creqF, _ty1F,_arg1F, \
167 _ty2F,_arg2F, _ty3F, _arg3F) \
169 Word _arg1, _arg2, _arg3; \
170 assert(sizeof(_ty1F) == sizeof(Word)); \
171 assert(sizeof(_ty2F) == sizeof(Word)); \
172 assert(sizeof(_ty3F) == sizeof(Word)); \
173 _arg1 = (Word)(_arg1F); \
174 _arg2 = (Word)(_arg2F); \
175 _arg3 = (Word)(_arg3F); \
176 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
177 _arg1,_arg2,_arg3,0,0); \
180 #define DO_CREQ_v_WWWW(_creqF, _ty1F,_arg1F, \
181 _ty2F, _arg2F, _ty3F, _arg3F, \
184 Word _arg1, _arg2, _arg3, _arg4; \
185 assert(sizeof(_ty1F) == sizeof(Word)); \
186 assert(sizeof(_ty2F) == sizeof(Word)); \
187 assert(sizeof(_ty3F) == sizeof(Word)); \
188 assert(sizeof(_ty4F) == sizeof(Word)); \
189 _arg1 = (Word)(_arg1F); \
190 _arg2 = (Word)(_arg2F); \
191 _arg3 = (Word)(_arg3F); \
192 _arg4 = (Word)(_arg4F); \
193 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
194 _arg1,_arg2,_arg3,_arg4,0); \
197 #define DO_PthAPIerror(_fnnameF, _errF) \
199 const char* _fnname = (_fnnameF); \
200 long _err = (long)(int)(_errF); \
201 const char* _errstr = lame_strerror(_err); \
202 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTH_API_ERROR, \
204 long,_err, char*,_errstr); \
208 /* Needed for older glibcs (2.3 and older, at least) who don't
209 otherwise "know" about pthread_rwlock_anything or about
210 PTHREAD_MUTEX_RECURSIVE (amongst things). */
211 #define _GNU_SOURCE 1
218 /* A standalone memcmp. */
219 __attribute__((noinline
))
220 static int my_memcmp ( const void* ptr1
, const void* ptr2
, size_t size
)
222 const unsigned char* uchar_ptr1
= (const unsigned char*) ptr1
;
223 const unsigned char* uchar_ptr2
= (const unsigned char*) ptr2
;
225 for (i
= 0; i
< size
; ++i
) {
226 if (uchar_ptr1
[i
] != uchar_ptr2
[i
])
227 return (uchar_ptr1
[i
] < uchar_ptr2
[i
]) ? -1 : 1;
232 /* A lame version of strerror which doesn't use the real libc
233 strerror_r, since using the latter just generates endless more
234 threading errors (glibc goes off and does tons of crap w.r.t.
236 static const HChar
* lame_strerror ( long err
)
239 case EPERM
: return "EPERM: Operation not permitted";
240 case ENOENT
: return "ENOENT: No such file or directory";
241 case ESRCH
: return "ESRCH: No such process";
242 case EINTR
: return "EINTR: Interrupted system call";
243 case EBADF
: return "EBADF: Bad file number";
244 case EAGAIN
: return "EAGAIN: Try again";
245 case ENOMEM
: return "ENOMEM: Out of memory";
246 case EACCES
: return "EACCES: Permission denied";
247 case EFAULT
: return "EFAULT: Bad address";
248 case EEXIST
: return "EEXIST: File exists";
249 case EINVAL
: return "EINVAL: Invalid argument";
250 case EMFILE
: return "EMFILE: Too many open files";
251 case ENOSYS
: return "ENOSYS: Function not implemented";
252 case EOVERFLOW
: return "EOVERFLOW: Value too large "
253 "for defined data type";
254 case EBUSY
: return "EBUSY: Device or resource busy";
255 case ETIMEDOUT
: return "ETIMEDOUT: Connection timed out";
256 case EDEADLK
: return "EDEADLK: Resource deadlock would occur";
257 case EOPNOTSUPP
: return "EOPNOTSUPP: Operation not supported on "
258 "transport endpoint"; /* honest, guv */
259 #if !defined(VGO_freebsd)
260 case ETIME
: return "ETIME: Timer expired";
262 default: return "hg_intercepts.c: lame_strerror(): "
263 "unhandled case -- please fix me!";
267 #if defined(VGO_solaris)
269 * Solaris provides higher throughput, parallelism and scalability than other
270 * operating systems, at the cost of more fine-grained locking activity.
271 * This means for example that when a thread is created under Linux, just one
272 * big lock in glibc is used for all thread setup. Solaris libc uses several
273 * fine-grained locks and the creator thread resumes its activities as soon
274 * as possible, leaving for example stack and TLS setup activities to the
277 * This situation confuses Helgrind as it assumes there is some false ordering
278 * in place between creator and created thread; and therefore many types of
279 * race conditions in the application would not be reported. To prevent such
280 * false ordering, command line option --ignore-thread-creation is set to
281 * 'yes' by default on Solaris. All activity (loads, stores, client requests)
282 * is therefore ignored during:
283 * - pthread_create() call in the creator thread [libc.so]
284 * - thread creation phase (stack and TLS setup) in the created thread [libc.so]
286 * As explained in the comments for _ti_bind_guard(), whenever the runtime
287 * linker has to perform any activity (such as resolving a symbol), it protects
288 * its data structures by calling into rt_bind_guard() which in turn invokes
289 * _ti_bind_guard() in libc. Pointers to _ti_bind_guard() and _ti_bind_clear()
290 * are passed from libc to runtime linker in _ld_libc() call during libc_init().
291 * All activity is also ignored during:
292 * - runtime dynamic linker work between rt_bind_guard() and rt_bind_clear()
295 * This also means that Helgrind does not report race conditions in libc (when
296 * --ignore-thread-creation=yes) and runtime linker itself (unconditionally)
297 * during these ignored sequences.
300 #include "pub_tool_libcassert.h"
301 #include "pub_tool_vki.h"
304 * Original function pointers for _ti_bind_guard() and _ti_bind_clear()
305 * from libc. They are intercepted in function wrapper of _ld_libc().
307 typedef int (*hg_rtld_guard_fn
)(int flags
);
308 static hg_rtld_guard_fn hg_rtld_bind_guard
= NULL
;
309 static hg_rtld_guard_fn hg_rtld_bind_clear
= NULL
;
311 static void hg_init(void) __attribute__((constructor
));
312 static void hg_init(void)
314 if ((hg_rtld_bind_guard
== NULL
) || (hg_rtld_bind_clear
== NULL
)) {
316 "Bind guard functions for the runtime linker (ld.so.1) were not intercepted.\n"
317 "This means the interface between libc and runtime linker changed\n"
318 "and Helgrind needs to be ported properly. Giving up.\n");
324 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
325 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
326 * and CI_BIND_CLEAR, to provide resilience against function renaming.
328 static int _ti_bind_guard_intercept_WRK(int flags
)
330 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_RTLD_BIND_GUARD
,
332 return hg_rtld_bind_guard(flags
);
335 static int _ti_bind_clear_intercept_WRK(int flags
)
337 int ret
= hg_rtld_bind_clear(flags
);
338 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_RTLD_BIND_CLEAR
,
344 * Wrapped _ld_libc() from the runtime linker ld.so.1.
346 void I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LD_SO_1
, ZuldZulibc
)(vki_Lc_interface
*ptr
);
347 void I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LD_SO_1
, ZuldZulibc
)(vki_Lc_interface
*ptr
)
352 VALGRIND_GET_ORIG_FN(fn
);
354 vki_Lc_interface
*funcs
= ptr
;
355 for (tag
= funcs
->ci_tag
; tag
!= 0; tag
= (++funcs
)->ci_tag
) {
357 case VKI_CI_BIND_GUARD
:
358 if (funcs
->vki_ci_un
.ci_func
!= _ti_bind_guard_intercept_WRK
) {
359 hg_rtld_bind_guard
= funcs
->vki_ci_un
.ci_func
;
360 funcs
->vki_ci_un
.ci_func
= _ti_bind_guard_intercept_WRK
;
363 case VKI_CI_BIND_CLEAR
:
364 if (funcs
->vki_ci_un
.ci_func
!= _ti_bind_clear_intercept_WRK
) {
365 hg_rtld_bind_clear
= funcs
->vki_ci_un
.ci_func
;
366 funcs
->vki_ci_un
.ci_func
= _ti_bind_clear_intercept_WRK
;
372 CALL_FN_v_W(fn
, ptr
);
374 #endif /* VGO_solaris */
377 /*----------------------------------------------------------------*/
378 /*--- pthread_create, pthread_join, pthread_exit ---*/
379 /*----------------------------------------------------------------*/
381 static void* mythread_wrapper ( void* xargsV
)
383 volatile Word
* xargs
= (volatile Word
*) xargsV
;
384 void*(*fn
)(void*) = (void*(*)(void*))xargs
[0];
385 void* arg
= (void*)xargs
[1];
386 pthread_t me
= pthread_self();
387 /* Tell the tool what my pthread_t is. */
388 DO_CREQ_v_W(_VG_USERREQ__HG_SET_MY_PTHREAD_T
, CREQ_PTHREAD_T
, me
);
389 /* allow the parent to proceed. We can't let it proceed until
390 we're ready because (1) we need to make sure it doesn't exit and
391 hence deallocate xargs[] while we still need it, and (2) we
392 don't want either parent nor child to proceed until the tool has
393 been notified of the child's pthread_t.
395 Note that parent and child access args[] without a lock,
396 effectively using args[2] as a spinlock in order to get the
397 parent to wait until the child passes this point. The parent
398 disables checking on xargs[] before creating the child and
399 re-enables it once the child goes past this point, so the user
400 never sees the race. The previous approach (suppressing the
401 resulting error) was flawed, because it could leave shadow
402 memory for args[] in a state in which subsequent use of it by
403 the parent would report further races. */
405 /* Now we can no longer safely use xargs[]. */
406 return (void*) fn( (void*)arg
);
409 //-----------------------------------------------------------
410 // glibc: pthread_create@GLIBC_2.0
411 // glibc: pthread_create@@GLIBC_2.1
412 // glibc: pthread_create@@GLIBC_2.2.5
413 // darwin: pthread_create
414 // darwin: pthread_create_suspended_np (trapped)
415 // FreeBSD: pthread_create
417 /* ensure this has its own frame, so as to make it more distinguishable
419 __attribute__((noinline
))
420 static int pthread_create_WRK(pthread_t
*thread
, const pthread_attr_t
*attr
,
421 void *(*start
) (void *), void *arg
)
425 volatile Word xargs
[3];
427 VALGRIND_GET_ORIG_FN(fn
);
429 fprintf(stderr
, "<< pthread_create wrapper"); fflush(stderr
);
431 xargs
[0] = (Word
)start
;
432 xargs
[1] = (Word
)arg
;
433 xargs
[2] = 1; /* serves as a spinlock -- sigh */
434 /* Disable checking on the spinlock and the two words used to
435 convey args to the child. Basically we need to make it appear
436 as if the child never accessed this area, since merely
437 suppressing the resulting races does not address the issue that
438 that piece of the parent's stack winds up in the "wrong" state
439 and therefore may give rise to mysterious races when the parent
440 comes to re-use this piece of stack in some other frame. */
441 VALGRIND_HG_DISABLE_CHECKING(&xargs
, sizeof(xargs
));
443 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_BEGIN
,
445 CALL_FN_W_WWWW(ret
, fn
, thread
,attr
,mythread_wrapper
,&xargs
[0]);
446 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_END
,
450 /* we have to wait for the child to notify the tool of its
451 pthread_t before continuing */
452 while (xargs
[2] != 0) {
453 /* Do nothing. We need to spin until the child writes to
454 xargs[2]. However, that can lead to starvation in the
455 child and very long delays (eg, tc19_shadowmem on
456 ppc64-linux Fedora Core 6). So yield the cpu if we can,
457 to let the child run at the earliest available
462 DO_PthAPIerror( "pthread_create", ret
);
465 /* Reenable checking on the area previously used to communicate
467 VALGRIND_HG_ENABLE_CHECKING(&xargs
, sizeof(xargs
));
470 fprintf(stderr
, " :: pth_create -> %d >>\n", ret
);
474 #if defined(VGO_linux)
475 PTH_FUNC(int, pthreadZucreateZAZa
, // pthread_create@*
476 pthread_t
*thread
, const pthread_attr_t
*attr
,
477 void *(*start
) (void *), void *arg
) {
478 return pthread_create_WRK(thread
, attr
, start
, arg
);
480 #elif defined(VGO_freebsd)
481 PTH_FUNC(int, pthreadZucreate
, // pthread_create
482 pthread_t
*thread
, const pthread_attr_t
*attr
,
483 void *(*start
) (void *), void *arg
) {
484 return pthread_create_WRK(thread
, attr
, start
, arg
);
486 #elif defined(VGO_darwin)
487 PTH_FUNC(int, pthreadZucreate
, // pthread_create
488 pthread_t
*thread
, const pthread_attr_t
*attr
,
489 void *(*start
) (void *), void *arg
) {
490 return pthread_create_WRK(thread
, attr
, start
, arg
);
492 PTH_FUNC(int, pthreadZucreateZuZa
, // pthread_create_*
493 pthread_t
*thread
, const pthread_attr_t
*attr
,
494 void *(*start
) (void *), void *arg
) {
495 // trap anything else
498 #elif defined(VGO_solaris)
499 PTH_FUNC(int, pthreadZucreate
, // pthread_create
500 pthread_t
*thread
, const pthread_attr_t
*attr
,
501 void *(*start
) (void *), void *arg
) {
502 return pthread_create_WRK(thread
, attr
, start
, arg
);
505 # error "Unsupported OS"
508 #if defined(VGO_solaris)
509 /* Solaris also provides thr_create() in addition to pthread_create().
510 * Both pthread_create(3C) and thr_create(3C) are based on private
513 __attribute__((noinline
))
514 static int thr_create_WRK(void *stk
, size_t stksize
, void *(*start
)(void *),
515 void *arg
, long flags
, thread_t
*new_thread
)
519 volatile Word xargs
[3];
521 VALGRIND_GET_ORIG_FN(fn
);
523 fprintf(stderr
, "<< thr_create wrapper"); fflush(stderr
);
525 xargs
[0] = (Word
)start
;
526 xargs
[1] = (Word
)arg
;
527 xargs
[2] = 1; /* serves as a spinlock -- sigh */
528 /* See comments in pthread_create_WRK() */
529 VALGRIND_HG_DISABLE_CHECKING(&xargs
, sizeof(xargs
));
531 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_BEGIN
,
533 CALL_FN_W_6W(ret
, fn
, stk
, stksize
, mythread_wrapper
, start
, flags
,
535 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_END
,
539 while (xargs
[2] != 0) {
540 /* See comments in pthread_create_WRK(). */
544 DO_PthAPIerror("thr_create", ret
);
547 VALGRIND_HG_ENABLE_CHECKING(&xargs
, sizeof(xargs
));
550 fprintf(stderr
, " :: thr_create -> %d >>\n", ret
);
554 PTH_FUNC(int, thrZucreate
, // thr_create
555 void *stk
, size_t stksize
, void *(*start
)(void *),
556 void *arg
, long flags
, thread_t
*new_thread
) {
557 return thr_create_WRK(stk
, stksize
, start
, arg
, flags
, new_thread
);
559 #endif /* VGO_solaris */
562 //-----------------------------------------------------------
563 // glibc: pthread_join
564 // darwin: pthread_join
565 // darwin: pthread_join$NOCANCEL$UNIX2003
566 // darwin pthread_join$UNIX2003
567 // FreeBSD: pthread_join
568 __attribute__((noinline
))
569 static int pthread_join_WRK(pthread_t thread
, void** value_pointer
)
573 VALGRIND_GET_ORIG_FN(fn
);
575 fprintf(stderr
, "<< pthread_join wrapper"); fflush(stderr
);
578 CALL_FN_W_WW(ret
, fn
, thread
,value_pointer
);
580 /* At least with NPTL as the thread library, this is safe because
581 it is guaranteed (by NPTL) that the joiner will completely gone
582 before pthread_join (the original) returns. See email below.*/
583 if (ret
== 0 /*success*/) {
584 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST
, CREQ_PTHREAD_T
, thread
);
586 DO_PthAPIerror( "pthread_join", ret
);
590 fprintf(stderr
, " :: pth_join -> %d >>\n", ret
);
594 #if defined(VGO_linux)
595 PTH_FUNC(int, pthreadZujoin
, // pthread_join
596 pthread_t thread
, void** value_pointer
) {
597 return pthread_join_WRK(thread
, value_pointer
);
599 #elif defined(VGO_freebsd)
600 PTH_FUNC(int, pthreadZujoin
, // pthread_join
601 pthread_t thread
, void** value_pointer
) {
602 return pthread_join_WRK(thread
, value_pointer
);
604 #elif defined(VGO_darwin)
605 PTH_FUNC(int, pthreadZujoinZa
, // pthread_join*
606 pthread_t thread
, void** value_pointer
) {
607 return pthread_join_WRK(thread
, value_pointer
);
609 #elif defined(VGO_solaris)
610 PTH_FUNC(int, pthreadZujoin
, // pthread_join
611 pthread_t thread
, void** value_pointer
) {
612 return pthread_join_WRK(thread
, value_pointer
);
615 # error "Unsupported OS"
619 /* Behaviour of pthread_join on NPTL:
622 I have a question re the NPTL pthread_join implementation.
624 Suppose I am the thread 'stayer'.
626 If I call pthread_join(quitter), is it guaranteed that the
627 thread 'quitter' has really exited before pthread_join returns?
629 IOW, is it guaranteed that 'quitter' will not execute any further
630 instructions after pthread_join returns?
632 I believe this is true based on the following analysis of
633 glibc-2.5 sources. However am not 100% sure and would appreciate
636 'quitter' will be running start_thread() in nptl/pthread_create.c
638 The last action of start_thread() is to exit via
639 __exit_thread_inline(0), which simply does sys_exit
640 (nptl/pthread_create.c:403)
642 'stayer' meanwhile is waiting for lll_wait_tid (pd->tid)
643 (call at nptl/pthread_join.c:89)
645 As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
646 lll_wait_tid will not return until kernel notifies via futex
647 wakeup that 'quitter' has terminated.
649 Hence pthread_join cannot return until 'quitter' really has
650 completely disappeared.
653 > As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
654 > lll_wait_tid will not return until kernel notifies via futex
655 > wakeup that 'quitter' has terminated.
656 That's the key. The kernel resets the TID field after the thread is
657 done. No way the joiner can return before the thread is gone.
660 #if defined(VGO_solaris)
661 /* Solaris also provides thr_join() in addition to pthread_join().
662 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
664 * :TODO: No functionality is currently provided for joinee == 0 and departed.
665 * This would require another client request, of course.
667 __attribute__((noinline
))
668 static int thr_join_WRK(thread_t joinee
, thread_t
*departed
, void **thread_return
)
672 VALGRIND_GET_ORIG_FN(fn
);
674 fprintf(stderr
, "<< thr_join wrapper"); fflush(stderr
);
677 CALL_FN_W_WWW(ret
, fn
, joinee
, departed
, thread_return
);
679 if (ret
== 0 /*success*/) {
680 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST
, CREQ_PTHREAD_T
, joinee
);
682 DO_PthAPIerror("thr_join", ret
);
686 fprintf(stderr
, " :: thr_join -> %d >>\n", ret
);
690 PTH_FUNC(int, thrZujoin
, // thr_join
691 thread_t joinee
, thread_t
*departed
, void **thread_return
) {
692 return thr_join_WRK(joinee
, departed
, thread_return
);
694 #endif /* VGO_solaris */
697 //-----------------------------------------------------------
698 // Ada gcc gnat runtime:
699 // The gnat gcc Ada runtime does not use pthread_join. Instead, it uses
700 // a combination of other pthread primitives to ensure a child thread
701 // is gone. This combination is somewhat functionally equivalent to a
703 // We wrap two hook procedures called by the gnat gcc Ada runtime
704 // that allows helgrind to understand the semantic of Ada task dependencies
706 // procedure Master_Hook
707 // (Dependent : Task_Id;
709 // Master_Level : Integer);
710 // where type Task_Id is access all Ada_Task_Control_Block;
711 // System.Tasking.Debug.Master_Hook is called by a task Dependent to
712 // indicate that its master is identified by master+master_level.
713 void I_WRAP_SONAME_FNNAME_ZU
715 system__tasking__debug__master_hook
)
716 (void *dependent
, void *master
, int master_level
);
717 void I_WRAP_SONAME_FNNAME_ZU
719 system__tasking__debug__master_hook
)
720 (void *dependent
, void *master
, int master_level
)
723 VALGRIND_GET_ORIG_FN(fn
);
724 if (TRACE_GNAT_FNS
) {
725 fprintf(stderr
, "<< GNAT master_hook wrapper "
726 "dependent %p master %p master_level %d\n",
727 dependent
, master
, master_level
); fflush(stderr
);
730 // We call the wrapped function, even if it is a null body.
731 CALL_FN_v_WWW(fn
, dependent
, master
, master_level
);
733 DO_CREQ_v_WWW(_VG_USERREQ__HG_GNAT_MASTER_HOOK
,
734 void*,dependent
, void*,master
,
735 Word
, (Word
)master_level
);
737 if (TRACE_GNAT_FNS
) {
738 fprintf(stderr
, " :: GNAT master_hook >>\n");
742 // System.Tasking.Debug.Master_Completed_Hook is called by a task to
743 // indicate that it has completed a master.
744 // procedure Master_Completed_Hook
745 // (Self_ID : Task_Id;
746 // Master_Level : Integer);
747 // where type Task_Id is access all Ada_Task_Control_Block;
748 // This indicates that all its Dependent tasks (that identified themselves
749 // with the Master_Hook call) are terminated. Helgrind can consider
750 // at this point that the equivalent of a 'pthread_join' has been done
751 // between self_id and all dependent tasks at master_level.
752 void I_WRAP_SONAME_FNNAME_ZU
754 system__tasking__debug__master_completed_hook
)
755 (void *self_id
, int master_level
);
756 void I_WRAP_SONAME_FNNAME_ZU
758 system__tasking__debug__master_completed_hook
)
759 (void *self_id
, int master_level
)
762 VALGRIND_GET_ORIG_FN(fn
);
763 if (TRACE_GNAT_FNS
) {
764 fprintf(stderr
, "<< GNAT master_completed_hook wrapper "
765 "self_id %p master_level %d\n",
766 self_id
, master_level
); fflush(stderr
);
769 // We call the wrapped function, even if it is a null body.
770 CALL_FN_v_WW(fn
, self_id
, master_level
);
772 DO_CREQ_v_WW(_VG_USERREQ__HG_GNAT_MASTER_COMPLETED_HOOK
,
773 void*,self_id
, Word
,(Word
)master_level
);
775 if (TRACE_GNAT_FNS
) {
776 fprintf(stderr
, " :: GNAT master_completed_hook >>\n");
780 /*----------------------------------------------------------------*/
781 /*--- pthread_mutex_t functions ---*/
782 /*----------------------------------------------------------------*/
784 /* Handled: pthread_mutex_init pthread_mutex_destroy
786 pthread_mutex_trylock pthread_mutex_timedlock
790 //-----------------------------------------------------------
791 #if !defined(VGO_solaris)
792 // glibc: pthread_mutex_init
793 // darwin: pthread_mutex_init
794 // FreeBSD: pthread_mutex_init
795 PTH_FUNC(int, pthreadZumutexZuinit
, // pthread_mutex_init
796 pthread_mutex_t
*mutex
,
797 pthread_mutexattr_t
* attr
)
802 VALGRIND_GET_ORIG_FN(fn
);
804 fprintf(stderr
, "<< pthread_mxinit %p", mutex
); fflush(stderr
);
810 zzz
= pthread_mutexattr_gettype(attr
, &ty
);
811 if (zzz
== 0 && ty
== PTHREAD_MUTEX_RECURSIVE
)
815 CALL_FN_W_WW(ret
, fn
, mutex
,attr
);
817 if (ret
== 0 /*success*/) {
818 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST
,
819 pthread_mutex_t
*,mutex
, long,mbRec
);
821 DO_PthAPIerror( "pthread_mutex_init", ret
);
825 fprintf(stderr
, " :: mxinit -> %d >>\n", ret
);
830 #else /* VGO_solaris */
832 // Solaris: mutex_init (pthread_mutex_init calls here)
833 PTH_FUNC(int, mutexZuinit
, // mutex_init
834 mutex_t
*mutex
, int type
, void *arg
)
839 VALGRIND_GET_ORIG_FN(fn
);
841 fprintf(stderr
, "<< mxinit %p", mutex
); fflush(stderr
);
844 mbRec
= ((type
& LOCK_RECURSIVE
) != 0) ? 1 : 0;
846 CALL_FN_W_WWW(ret
, fn
, mutex
, type
, arg
);
848 if (ret
== 0 /*success*/) {
849 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST
,
850 mutex_t
*, mutex
, long, mbRec
);
852 DO_PthAPIerror("mutex_init", ret
);
856 fprintf(stderr
, " :: mxinit -> %d >>\n", ret
);
860 #endif /* VGO_solaris */
863 //-----------------------------------------------------------
864 // glibc: pthread_mutex_destroy
865 // darwin: pthread_mutex_destroy
866 // Solaris: mutex_destroy (pthread_mutex_destroy is a weak alias)
867 // FreeBSD: pthread_mutex_destroy
868 __attribute__((noinline
))
869 static int mutex_destroy_WRK(pthread_mutex_t
*mutex
)
872 unsigned long mutex_is_init
;
875 VALGRIND_GET_ORIG_FN(fn
);
877 fprintf(stderr
, "<< pthread_mxdestroy %p", mutex
); fflush(stderr
);
881 static const pthread_mutex_t mutex_init
= PTHREAD_MUTEX_INITIALIZER
;
882 mutex_is_init
= my_memcmp(mutex
, &mutex_init
, sizeof(*mutex
)) == 0;
887 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE
,
888 pthread_mutex_t
*, mutex
, unsigned long, mutex_is_init
);
890 CALL_FN_W_W(ret
, fn
, mutex
);
893 DO_PthAPIerror( "pthread_mutex_destroy", ret
);
897 fprintf(stderr
, " :: mxdestroy -> %d >>\n", ret
);
902 #if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd)
903 PTH_FUNC(int, pthreadZumutexZudestroy
, // pthread_mutex_destroy
904 pthread_mutex_t
*mutex
) {
905 return mutex_destroy_WRK(mutex
);
907 #elif defined(VGO_solaris)
908 PTH_FUNC(int, mutexZudestroy
, // mutex_destroy
909 pthread_mutex_t
*mutex
) {
910 return mutex_destroy_WRK(mutex
);
913 # error "Unsupported OS"
917 //-----------------------------------------------------------
918 // glibc: pthread_mutex_lock
919 // darwin: pthread_mutex_lock
920 // Solaris: mutex_lock (pthread_mutex_lock is a weak alias)
921 // FreeBSD: pthread_mutex_lock
922 __attribute__((noinline
))
923 static int mutex_lock_WRK(pthread_mutex_t
*mutex
)
927 VALGRIND_GET_ORIG_FN(fn
);
929 fprintf(stderr
, "<< pthread_mxlock %p", mutex
); fflush(stderr
);
932 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
933 pthread_mutex_t
*,mutex
, long,0/*!isTryLock*/);
935 CALL_FN_W_W(ret
, fn
, mutex
);
937 /* There's a hole here: libpthread now knows the lock is locked,
938 but the tool doesn't, so some other thread could run and detect
939 that the lock has been acquired by someone (this thread). Does
940 this matter? Not sure, but I don't think so. */
942 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
943 pthread_mutex_t
*, mutex
, long, (ret
== 0) ? True
: False
);
946 DO_PthAPIerror( "pthread_mutex_lock", ret
);
950 fprintf(stderr
, " :: mxlock -> %d >>\n", ret
);
955 #if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd)
956 PTH_FUNC(int, pthreadZumutexZulock
, // pthread_mutex_lock
957 pthread_mutex_t
*mutex
) {
958 return mutex_lock_WRK(mutex
);
960 #elif defined(VGO_solaris)
961 PTH_FUNC(int, mutexZulock
, // mutex_lock
962 pthread_mutex_t
*mutex
) {
963 return mutex_lock_WRK(mutex
);
966 # error "Unsupported OS"
969 #if defined(VGO_solaris)
970 /* Internal to libc. Mutex is usually initialized only implicitly,
971 * by zeroing mutex_t structure.
973 __attribute__((noinline
))
974 PTH_FUNC(void, lmutexZulock
, // lmutex_lock
978 VALGRIND_GET_ORIG_FN(fn
);
980 fprintf(stderr
, "<< lmxlock %p", mutex
); fflush(stderr
);
983 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
984 mutex_t
*, mutex
, long, 0 /*!isTryLock*/);
985 CALL_FN_v_W(fn
, mutex
);
986 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
987 mutex_t
*, mutex
, long, True
);
990 fprintf(stderr
, " :: lmxlock >>\n");
993 #endif /* VGO_solaris */
996 //-----------------------------------------------------------
997 // glibc: pthread_mutex_trylock
998 // darwin: pthread_mutex_trylock
999 // Solaris: mutex_trylock (pthread_mutex_trylock is a weak alias)
1000 // FreeBSD: pthread_mutext_trylock
1002 // pthread_mutex_trylock. The handling needed here is very similar
1003 // to that for pthread_mutex_lock, except that we need to tell
1004 // the pre-lock creq that this is a trylock-style operation, and
1005 // therefore not to complain if the lock is nonrecursive and
1006 // already locked by this thread -- because then it'll just fail
1007 // immediately with EBUSY.
1008 __attribute__((noinline
))
1009 static int mutex_trylock_WRK(pthread_mutex_t
*mutex
)
1013 VALGRIND_GET_ORIG_FN(fn
);
1014 if (TRACE_PTH_FNS
) {
1015 fprintf(stderr
, "<< pthread_mxtrylock %p", mutex
); fflush(stderr
);
1018 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
1019 pthread_mutex_t
*,mutex
, long,1/*isTryLock*/);
1021 CALL_FN_W_W(ret
, fn
, mutex
);
1023 /* There's a hole here: libpthread now knows the lock is locked,
1024 but the tool doesn't, so some other thread could run and detect
1025 that the lock has been acquired by someone (this thread). Does
1026 this matter? Not sure, but I don't think so. */
1028 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
1029 pthread_mutex_t
*, mutex
, long, (ret
== 0) ? True
: False
);
1033 DO_PthAPIerror( "pthread_mutex_trylock", ret
);
1036 if (TRACE_PTH_FNS
) {
1037 fprintf(stderr
, " :: mxtrylock -> %d >>\n", ret
);
1042 #if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd)
1043 PTH_FUNC(int, pthreadZumutexZutrylock
, // pthread_mutex_trylock
1044 pthread_mutex_t
*mutex
) {
1045 return mutex_trylock_WRK(mutex
);
1047 #elif defined(VGO_solaris)
1048 PTH_FUNC(int, mutexZutrylock
, // mutex_trylock
1049 pthread_mutex_t
*mutex
) {
1050 return mutex_trylock_WRK(mutex
);
1053 # error "Unsupported OS"
1057 //-----------------------------------------------------------
1058 // glibc: pthread_mutex_timedlock
1059 // darwin: (doesn't appear to exist)
1060 // Solaris: pthread_mutex_timedlock
1061 // FreeBSD: pthread_mutex_timedlock
1063 // pthread_mutex_timedlock. Identical logic to pthread_mutex_trylock.
1064 __attribute__((noinline
))
1065 static int mutex_timedlock_WRK(pthread_mutex_t
*mutex
,
1070 VALGRIND_GET_ORIG_FN(fn
);
1071 if (TRACE_PTH_FNS
) {
1072 fprintf(stderr
, "<< pthread_mxtimedlock %p %p", mutex
, timeout
);
1076 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
1077 pthread_mutex_t
*,mutex
, long,1/*isTryLock-ish*/);
1079 CALL_FN_W_WW(ret
, fn
, mutex
,timeout
);
1081 /* There's a hole here: libpthread now knows the lock is locked,
1082 but the tool doesn't, so some other thread could run and detect
1083 that the lock has been acquired by someone (this thread). Does
1084 this matter? Not sure, but I don't think so. */
1086 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
1087 pthread_mutex_t
*, mutex
, long, (ret
== 0) ? True
: False
);
1090 if (ret
!= ETIMEDOUT
)
1091 DO_PthAPIerror( "pthread_mutex_timedlock", ret
);
1094 if (TRACE_PTH_FNS
) {
1095 fprintf(stderr
, " :: mxtimedlock -> %d >>\n", ret
);
1100 PTH_FUNC(int, pthreadZumutexZutimedlock
, // pthread_mutex_timedlock
1101 pthread_mutex_t
*mutex
,
1103 return mutex_timedlock_WRK(mutex
, timeout
);
1105 #if defined(VGO_solaris)
1106 PTH_FUNC(int, pthreadZumutexZureltimedlock
, // pthread_mutex_reltimedlock
1107 pthread_mutex_t
*mutex
,
1109 return mutex_timedlock_WRK(mutex
, timeout
);
1113 #if defined(VGP_linux)
1114 //-----------------------------------------------------------
1115 // glibc: pthread_mutex_clocklock
1117 // pthread_mutex_clocklock. Identical logic to pthread_mutex_timedlock.
1118 __attribute__((noinline
))
1119 static int mutex_clocklock_WRK(pthread_mutex_t
*mutex
,
1125 VALGRIND_GET_ORIG_FN(fn
);
1126 if (TRACE_PTH_FNS
) {
1127 fprintf(stderr
, "<< pthread_mxclocklock %p %p", mutex
, timeout
);
1131 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
1132 pthread_mutex_t
*,mutex
, long,1/*isTryLock-ish*/);
1134 CALL_FN_W_WWW(ret
, fn
, mutex
, clockid
, timeout
);
1136 /* There's a hole here: libpthread now knows the lock is locked,
1137 but the tool doesn't, so some other thread could run and detect
1138 that the lock has been acquired by someone (this thread). Does
1139 this matter? Not sure, but I don't think so. */
1141 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
1142 pthread_mutex_t
*, mutex
, long, (ret
== 0) ? True
: False
);
1145 if (ret
!= ETIMEDOUT
)
1146 DO_PthAPIerror( "pthread_mutex_clocklock", ret
);
1149 if (TRACE_PTH_FNS
) {
1150 fprintf(stderr
, " :: mxclocklock -> %d >>\n", ret
);
1155 PTH_FUNC(int, pthreadZumutexZuclocklock
, // pthread_mutex_clocklock
1156 pthread_mutex_t
*mutex
,
1159 return mutex_clocklock_WRK(mutex
, clockid
, timeout
);
1163 //-----------------------------------------------------------
1164 // glibc: pthread_mutex_unlock
1165 // darwin: pthread_mutex_unlock
1166 // Solaris: mutex_unlock (pthread_mutex_unlock is a weak alias)
1167 // FreeBSD: pthread_mutex_unlock
1168 __attribute__((noinline
))
1169 static int mutex_unlock_WRK(pthread_mutex_t
*mutex
)
1173 VALGRIND_GET_ORIG_FN(fn
);
1175 if (TRACE_PTH_FNS
) {
1176 fprintf(stderr
, "<< pthread_mxunlk %p", mutex
); fflush(stderr
);
1179 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE
,
1180 pthread_mutex_t
*,mutex
);
1182 CALL_FN_W_W(ret
, fn
, mutex
);
1184 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST
,
1185 pthread_mutex_t
*,mutex
);
1188 DO_PthAPIerror( "pthread_mutex_unlock", ret
);
1191 if (TRACE_PTH_FNS
) {
1192 fprintf(stderr
, " mxunlk -> %d >>\n", ret
);
1197 #if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd)
1198 PTH_FUNC(int, pthreadZumutexZuunlock
, // pthread_mutex_unlock
1199 pthread_mutex_t
*mutex
) {
1200 return mutex_unlock_WRK(mutex
);
1202 #elif defined(VGO_solaris)
1203 PTH_FUNC(int, mutexZuunlock
, // mutex_unlock
1204 pthread_mutex_t
*mutex
) {
1205 return mutex_unlock_WRK(mutex
);
1208 # error "Unsupported OS"
1212 #if defined(VGO_solaris)
1213 /* Internal to libc. */
1214 __attribute__((noinline
))
1215 PTH_FUNC(void, lmutexZuunlock
, // lmutex_unlock
1219 VALGRIND_GET_ORIG_FN(fn
);
1221 if (TRACE_PTH_FNS
) {
1222 fprintf(stderr
, "<< lmxunlk %p", mutex
); fflush(stderr
);
1225 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE
,
1227 CALL_FN_v_W(fn
, mutex
);
1228 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST
,
1231 if (TRACE_PTH_FNS
) {
1232 fprintf(stderr
, " lmxunlk >>\n");
1235 #endif /* VGO_solaris */
1238 /*----------------------------------------------------------------*/
1239 /*--- pthread_cond_t functions ---*/
1240 /*----------------------------------------------------------------*/
1242 /* Handled: pthread_cond_wait pthread_cond_timedwait
1243 pthread_cond_signal pthread_cond_broadcast
1245 pthread_cond_destroy
1248 //-----------------------------------------------------------
1249 // glibc: pthread_cond_wait@GLIBC_2.2.5
1250 // glibc: pthread_cond_wait@@GLIBC_2.3.2
1251 // darwin: pthread_cond_wait
1252 // darwin: pthread_cond_wait$NOCANCEL$UNIX2003
1253 // darwin: pthread_cond_wait$UNIX2003
1254 // Solaris: cond_wait (pthread_cond_wait is built atop of cond_wait)
1255 // FreeBSD: pthread_cond_wait
1257 __attribute__((noinline
))
1258 static int pthread_cond_wait_WRK(pthread_cond_t
* cond
,
1259 pthread_mutex_t
* mutex
)
1263 unsigned long mutex_is_valid
;
1265 VALGRIND_GET_ORIG_FN(fn
);
1267 if (TRACE_PTH_FNS
) {
1268 fprintf(stderr
, "<< pthread_cond_wait %p %p", cond
, mutex
);
1272 /* Tell the tool a cond-wait is about to happen, so it can check
1273 for bogus argument values. In return it tells us whether it
1274 thinks the mutex is valid or not. */
1275 DO_CREQ_W_WW(mutex_is_valid
,
1276 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE
,
1277 pthread_cond_t
*,cond
, pthread_mutex_t
*,mutex
);
1278 assert(mutex_is_valid
== 1 || mutex_is_valid
== 0);
1280 /* Tell the tool we're about to drop the mutex. This reflects the
1281 fact that in a cond_wait, we show up holding the mutex, and the
1282 call atomically drops the mutex and waits for the cv to be
1284 if (mutex_is_valid
) {
1285 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE
,
1286 pthread_mutex_t
*,mutex
);
1289 CALL_FN_W_WW(ret
, fn
, cond
,mutex
);
1291 /* this conditional look stupid, but compare w/ same logic for
1292 pthread_cond_timedwait below */
1293 if (mutex_is_valid
) {
1294 /* and now we have the mutex again if (ret == 0) */
1295 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
1296 pthread_mutex_t
*, mutex
, long, (ret
== 0) ? True
: False
);
1299 DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST
,
1300 pthread_cond_t
*,cond
, pthread_mutex_t
*,mutex
, long,0,
1301 long, (ret
== 0 && mutex_is_valid
) ? True
: False
);
1304 DO_PthAPIerror( "pthread_cond_wait", ret
);
1307 if (TRACE_PTH_FNS
) {
1308 fprintf(stderr
, " cowait -> %d >>\n", ret
);
1313 #if defined(VGO_linux)
1314 PTH_FUNC(int, pthreadZucondZuwaitZAZa
, // pthread_cond_wait@*
1315 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
) {
1316 return pthread_cond_wait_WRK(cond
, mutex
);
1318 #elif defined(VGO_freebsd)
1319 PTH_FUNC(int, pthreadZucondZuwait
, // pthread_cond_wait
1320 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
) {
1321 return pthread_cond_wait_WRK(cond
, mutex
);
1323 #elif defined(VGO_darwin)
1324 PTH_FUNC(int, pthreadZucondZuwaitZa
, // pthread_cond_wait*
1325 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
) {
1326 return pthread_cond_wait_WRK(cond
, mutex
);
1328 #elif defined(VGO_solaris)
1329 PTH_FUNC(int, condZuwait
, // cond_wait
1330 pthread_cond_t
*cond
, pthread_mutex_t
*mutex
) {
1331 return pthread_cond_wait_WRK(cond
, mutex
);
1334 # error "Unsupported OS"
1338 //-----------------------------------------------------------
1339 // glibc: pthread_cond_timedwait@@GLIBC_2.3.2
1340 // glibc: pthread_cond_timedwait@GLIBC_2.2.5
1341 // glibc: pthread_cond_timedwait@GLIBC_2.0
1342 // darwin: pthread_cond_timedwait
1343 // darwin: pthread_cond_timedwait$NOCANCEL$UNIX2003
1344 // darwin: pthread_cond_timedwait$UNIX2003
1345 // darwin: pthread_cond_timedwait_relative_np (trapped)
1346 // Solaris: cond_timedwait (pthread_cond_timedwait is built on cond_timedwait)
1347 // Solaris: cond_reltimedwait (pthread_cond_reltimedwait_np is built on this)
1348 // FreeBSD: pthread_cond_timedwait
1350 __attribute__((noinline
))
1351 static int pthread_cond_timedwait_WRK(pthread_cond_t
* cond
,
1352 pthread_mutex_t
* mutex
,
1353 struct timespec
* abstime
,
1358 unsigned long mutex_is_valid
;
1359 Bool abstime_is_valid
;
1360 VALGRIND_GET_ORIG_FN(fn
);
1362 if (TRACE_PTH_FNS
) {
1363 fprintf(stderr
, "<< pthread_cond_timedwait %p %p %p",
1364 cond
, mutex
, abstime
);
1368 /* Tell the tool a cond-wait is about to happen, so it can check
1369 for bogus argument values. In return it tells us whether it
1370 thinks the mutex is valid or not. */
1371 DO_CREQ_W_WW(mutex_is_valid
,
1372 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE
,
1373 pthread_cond_t
*,cond
, pthread_mutex_t
*,mutex
);
1374 assert(mutex_is_valid
== 1 || mutex_is_valid
== 0);
1376 abstime_is_valid
= abstime
->tv_nsec
>= 0 && abstime
->tv_nsec
< 1000000000;
1378 /* Tell the tool we're about to drop the mutex. This reflects the
1379 fact that in a cond_wait, we show up holding the mutex, and the
1380 call atomically drops the mutex and waits for the cv to be
1382 if (mutex_is_valid
&& abstime_is_valid
) {
1383 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE
,
1384 pthread_mutex_t
*,mutex
);
1387 CALL_FN_W_WWW(ret
, fn
, cond
,mutex
,abstime
);
1389 if (mutex_is_valid
&& !abstime_is_valid
&& ret
!= EINVAL
) {
1390 DO_PthAPIerror("Bug in libpthread: pthread_cond_timedwait "
1391 "invalid abstime did not cause"
1395 if (mutex_is_valid
&& abstime_is_valid
) {
1396 /* and now we have the mutex again if (ret == 0 || ret == timeout) */
1397 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
1398 pthread_mutex_t
*, mutex
,
1399 long, (ret
== 0 || ret
== timeout_error
) ? True
: False
);
1402 DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST
,
1403 pthread_cond_t
*,cond
, pthread_mutex_t
*,mutex
,
1404 long,ret
== timeout_error
,
1405 long, (ret
== 0 || ret
== timeout_error
) && mutex_is_valid
1408 if (ret
!= 0 && ret
!= timeout_error
) {
1409 DO_PthAPIerror( "pthread_cond_timedwait", ret
);
1412 if (TRACE_PTH_FNS
) {
1413 fprintf(stderr
, " cotimedwait -> %d >>\n", ret
);
1418 #if defined(VGO_linux)
1419 PTH_FUNC(int, pthreadZucondZutimedwaitZAZa
, // pthread_cond_timedwait@*
1420 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
,
1421 struct timespec
* abstime
) {
1422 return pthread_cond_timedwait_WRK(cond
, mutex
, abstime
, ETIMEDOUT
);
1424 #elif defined(VGO_freebsd)
1425 PTH_FUNC(int, pthreadZucondZutimedwait
, // pthread_cond_timedwait
1426 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
,
1427 struct timespec
* abstime
) {
1428 return pthread_cond_timedwait_WRK(cond
, mutex
, abstime
, ETIMEDOUT
);
1430 #elif defined(VGO_darwin)
1431 PTH_FUNC(int, pthreadZucondZutimedwait
, // pthread_cond_timedwait
1432 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
,
1433 struct timespec
* abstime
) {
1434 return pthread_cond_timedwait_WRK(cond
, mutex
, abstime
, ETIMEDOUT
);
1436 PTH_FUNC(int, pthreadZucondZutimedwaitZDZa
, // pthread_cond_timedwait$*
1437 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
,
1438 struct timespec
* abstime
) {
1439 return pthread_cond_timedwait_WRK(cond
, mutex
, abstime
, ETIMEDOUT
);
1441 PTH_FUNC(int, pthreadZucondZutimedwaitZuZa
, // pthread_cond_timedwait_*
1442 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
,
1443 struct timespec
* abstime
) {
1446 #elif defined(VGO_solaris)
1447 PTH_FUNC(int, condZutimedwait
, // cond_timedwait
1448 pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1449 struct timespec
*abstime
) {
1450 return pthread_cond_timedwait_WRK(cond
, mutex
, abstime
, ETIME
);
1452 PTH_FUNC(int, condZureltimedwait
, // cond_reltimedwait
1453 pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
1454 struct timespec
*reltime
) {
1455 return pthread_cond_timedwait_WRK(cond
, mutex
, reltime
, ETIME
);
1458 # error "Unsupported OS"
1461 #if defined(VGO_linux)
1462 //-----------------------------------------------------------
1463 // glibc: pthread_cond_clockwait
1465 __attribute__((noinline
))
1466 static int pthread_cond_clockwait_WRK(pthread_cond_t
* cond
,
1467 pthread_mutex_t
* mutex
,
1469 struct timespec
* abstime
,
1474 unsigned long mutex_is_valid
;
1475 Bool abstime_is_valid
;
1476 VALGRIND_GET_ORIG_FN(fn
);
1478 if (TRACE_PTH_FNS
) {
1479 fprintf(stderr
, "<< pthread_cond_clockwait %p %p %p",
1480 cond
, mutex
, abstime
);
1484 /* Tell the tool a cond-wait is about to happen, so it can check
1485 for bogus argument values. In return it tells us whether it
1486 thinks the mutex is valid or not. */
1487 DO_CREQ_W_WW(mutex_is_valid
,
1488 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE
,
1489 pthread_cond_t
*,cond
, pthread_mutex_t
*,mutex
);
1490 assert(mutex_is_valid
== 1 || mutex_is_valid
== 0);
1492 abstime_is_valid
= abstime
->tv_nsec
>= 0 && abstime
->tv_nsec
< 1000000000;
1494 /* Tell the tool we're about to drop the mutex. This reflects the
1495 fact that in a cond_wait, we show up holding the mutex, and the
1496 call atomically drops the mutex and waits for the cv to be
1498 if (mutex_is_valid
&& abstime_is_valid
) {
1499 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE
,
1500 pthread_mutex_t
*,mutex
);
1503 CALL_FN_W_WWWW(ret
, fn
, cond
,mutex
,clockid
,abstime
);
1505 if (mutex_is_valid
&& !abstime_is_valid
&& ret
!= EINVAL
) {
1506 DO_PthAPIerror("Bug in libpthread: pthread_cond_clockwait "
1507 "invalid abstime did not cause"
1511 if (mutex_is_valid
&& abstime_is_valid
) {
1512 /* and now we have the mutex again if (ret == 0 || ret == timeout) */
1513 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
1514 pthread_mutex_t
*, mutex
,
1515 long, (ret
== 0 || ret
== timeout_error
) ? True
: False
);
1518 DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST
,
1519 pthread_cond_t
*,cond
, pthread_mutex_t
*,mutex
,
1520 long,ret
== timeout_error
,
1521 long, (ret
== 0 || ret
== timeout_error
) && mutex_is_valid
1524 if (ret
!= 0 && ret
!= timeout_error
) {
1525 DO_PthAPIerror( "pthread_cond_clockwait", ret
);
1528 if (TRACE_PTH_FNS
) {
1529 fprintf(stderr
, " cotimedwait -> %d >>\n", ret
);
1535 PTH_FUNC(int, pthreadZucondZuclockwait
, // pthread_cond_clockwait
1536 pthread_cond_t
* cond
, pthread_mutex_t
* mutex
,
1538 struct timespec
* abstime
) {
1539 return pthread_cond_clockwait_WRK(cond
, mutex
, clockid
, abstime
, ETIMEDOUT
);
1544 //-----------------------------------------------------------
1545 // glibc: pthread_cond_signal@GLIBC_2.0
1546 // glibc: pthread_cond_signal@GLIBC_2.2.5
1547 // glibc: pthread_cond_signal@@GLIBC_2.3.2
1548 // darwin: pthread_cond_signal
1549 // darwin: pthread_cond_signal_thread_np (don't intercept this)
1550 // Solaris: cond_signal (pthread_cond_signal is a weak alias)
1551 // FreeBSD: pthread_cond_signal
1553 __attribute__((noinline
))
1554 static int pthread_cond_signal_WRK(pthread_cond_t
* cond
)
1558 VALGRIND_GET_ORIG_FN(fn
);
1560 if (TRACE_PTH_FNS
) {
1561 fprintf(stderr
, "<< pthread_cond_signal %p", cond
);
1565 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE
,
1566 pthread_cond_t
*,cond
);
1568 CALL_FN_W_W(ret
, fn
, cond
);
1570 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_POST
,
1571 pthread_cond_t
*,cond
);
1574 DO_PthAPIerror( "pthread_cond_signal", ret
);
1577 if (TRACE_PTH_FNS
) {
1578 fprintf(stderr
, " cosig -> %d >>\n", ret
);
1583 #if defined(VGO_linux)
1584 PTH_FUNC(int, pthreadZucondZusignalZAZa
, // pthread_cond_signal@*
1585 pthread_cond_t
* cond
) {
1586 return pthread_cond_signal_WRK(cond
);
1588 #elif defined(VGO_freebsd)
1589 PTH_FUNC(int, pthreadZucondZusignal
, // pthread_cond_signal
1590 pthread_cond_t
* cond
) {
1591 return pthread_cond_signal_WRK(cond
);
1593 #elif defined(VGO_darwin)
1594 PTH_FUNC(int, pthreadZucondZusignal
, // pthread_cond_signal
1595 pthread_cond_t
* cond
) {
1596 return pthread_cond_signal_WRK(cond
);
1598 #elif defined(VGO_solaris)
1599 PTH_FUNC(int, condZusignal
, // cond_signal
1600 pthread_cond_t
*cond
) {
1601 return pthread_cond_signal_WRK(cond
);
1604 # error "Unsupported OS"
1608 //-----------------------------------------------------------
1609 // glibc: pthread_cond_broadcast@GLIBC_2.0
1610 // glibc: pthread_cond_broadcast@GLIBC_2.2.5
1611 // glibc: pthread_cond_broadcast@@GLIBC_2.3.2
1612 // darwin: pthread_cond_broadcast
1613 // Solaris: cond_broadcast (pthread_cond_broadcast is a weak alias)
1614 // FreeBSD: pthread_cond_broadcast
1616 // Note, this is pretty much identical, from a dependency-graph
1617 // point of view, with cond_signal, so the code is duplicated.
1618 // Maybe it should be commoned up.
1620 __attribute__((noinline
))
1621 static int pthread_cond_broadcast_WRK(pthread_cond_t
* cond
)
1625 VALGRIND_GET_ORIG_FN(fn
);
1627 if (TRACE_PTH_FNS
) {
1628 fprintf(stderr
, "<< pthread_cond_broadcast %p", cond
);
1632 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE
,
1633 pthread_cond_t
*,cond
);
1635 CALL_FN_W_W(ret
, fn
, cond
);
1637 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_POST
,
1638 pthread_cond_t
*,cond
);
1641 DO_PthAPIerror( "pthread_cond_broadcast", ret
);
1644 if (TRACE_PTH_FNS
) {
1645 fprintf(stderr
, " cobro -> %d >>\n", ret
);
1650 #if defined(VGO_linux)
1651 PTH_FUNC(int, pthreadZucondZubroadcastZAZa
, // pthread_cond_broadcast@*
1652 pthread_cond_t
* cond
) {
1653 return pthread_cond_broadcast_WRK(cond
);
1655 #elif defined(VGO_freebsd)
1656 PTH_FUNC(int, pthreadZucondZubroadcast
, // pthread_cond_broadcast
1657 pthread_cond_t
* cond
) {
1658 return pthread_cond_broadcast_WRK(cond
);
1660 #elif defined(VGO_darwin)
1661 PTH_FUNC(int, pthreadZucondZubroadcast
, // pthread_cond_broadcast
1662 pthread_cond_t
* cond
) {
1663 return pthread_cond_broadcast_WRK(cond
);
1665 #elif defined(VGO_solaris)
1666 PTH_FUNC(int, condZubroadcast
, // cond_broadcast
1667 pthread_cond_t
*cond
) {
1668 return pthread_cond_broadcast_WRK(cond
);
1671 # error "Unsupported OS"
1674 // glibc: pthread_cond_init@GLIBC_2.0
1675 // glibc: pthread_cond_init@GLIBC_2.2.5
1676 // glibc: pthread_cond_init@@GLIBC_2.3.2
1677 // darwin: pthread_cond_init
1678 // Solaris: cond_init (pthread_cond_init is built atop on this function)
1679 // FreeBSD: pthread_cond_init
1680 // Easy way out: Handling of attr could have been messier.
1681 // It turns out that pthread_cond_init under linux ignores
1682 // all information in cond_attr, so do we.
1684 #if !defined(VGO_solaris)
1685 __attribute__((noinline
))
1686 static int pthread_cond_init_WRK(pthread_cond_t
* cond
, pthread_condattr_t
*cond_attr
)
1690 VALGRIND_GET_ORIG_FN(fn
);
1692 if (TRACE_PTH_FNS
) {
1693 fprintf(stderr
, "<< pthread_cond_init %p", cond
);
1697 CALL_FN_W_WW(ret
, fn
, cond
, cond_attr
);
1700 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST
,
1701 pthread_cond_t
*,cond
, pthread_condattr_t
*, cond_attr
);
1703 DO_PthAPIerror( "pthread_cond_init", ret
);
1706 if (TRACE_PTH_FNS
) {
1707 fprintf(stderr
, " coinit -> %d >>\n", ret
);
1712 #if defined(VGO_linux)
1713 PTH_FUNC(int, pthreadZucondZuinitZAZa
, // pthread_cond_init@*
1714 pthread_cond_t
* cond
, pthread_condattr_t
* cond_attr
) {
1715 return pthread_cond_init_WRK(cond
, cond_attr
);
1717 #elif defined(VGO_freebsd)
1718 PTH_FUNC(int, pthreadZucondZuinit
, // pthread_cond_init@*
1719 pthread_cond_t
* cond
, pthread_condattr_t
* cond_attr
) {
1720 return pthread_cond_init_WRK(cond
, cond_attr
);
1722 #elif defined(VGO_darwin)
1723 PTH_FUNC(int, pthreadZucondZuinit
, // pthread_cond_init
1724 pthread_cond_t
* cond
, pthread_condattr_t
* cond_attr
) {
1725 return pthread_cond_init_WRK(cond
, cond_attr
);
1728 # error "Unsupported OS"
1731 #else /* VGO_solaris */
1732 __attribute__((noinline
))
1733 PTH_FUNC(int, condZuinit
, // cond_init
1734 cond_t
*cond
, int type
, void *arg
)
1738 VALGRIND_GET_ORIG_FN(fn
);
1740 if (TRACE_PTH_FNS
) {
1741 fprintf(stderr
, "<< cond_init %p", cond
); fflush(stderr
);
1744 CALL_FN_W_WWW(ret
, fn
, cond
, type
, arg
);
1747 /* Luckily evh__HG_PTHREAD_COND_INIT_POST() ignores cond_attr.
1748 See also comment for pthread_cond_init_WRK(). */
1749 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST
,
1750 cond_t
*, cond
, void *, NULL
);
1752 DO_PthAPIerror("cond_init", ret
);
1755 if (TRACE_PTH_FNS
) {
1756 fprintf(stderr
, " cond_init -> %d >>\n", ret
);
1761 #endif /* VGO_solaris */
1764 //-----------------------------------------------------------
1765 // glibc: pthread_cond_destroy@@GLIBC_2.3.2
1766 // glibc: pthread_cond_destroy@GLIBC_2.2.5
1767 // glibc: pthread_cond_destroy@GLIBC_2.0
1768 // darwin: pthread_cond_destroy
1769 // Solaris: cond_destroy (pthread_cond_destroy is a weak alias)
1770 // FreeBSD: pthread_cond_destroy
1772 __attribute__((noinline
))
1773 static int pthread_cond_destroy_WRK(pthread_cond_t
* cond
)
1776 unsigned long cond_is_init
;
1779 VALGRIND_GET_ORIG_FN(fn
);
1781 if (TRACE_PTH_FNS
) {
1782 fprintf(stderr
, "<< pthread_cond_destroy %p", cond
);
1787 const pthread_cond_t cond_init
= PTHREAD_COND_INITIALIZER
;
1788 cond_is_init
= my_memcmp(cond
, &cond_init
, sizeof(*cond
)) == 0;
1793 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_DESTROY_PRE
,
1794 pthread_cond_t
*, cond
, unsigned long, cond_is_init
);
1796 CALL_FN_W_W(ret
, fn
, cond
);
1799 DO_PthAPIerror( "pthread_cond_destroy", ret
);
1802 if (TRACE_PTH_FNS
) {
1803 fprintf(stderr
, " codestr -> %d >>\n", ret
);
1808 #if defined(VGO_linux)
1809 PTH_FUNC(int, pthreadZucondZudestroyZAZa
, // pthread_cond_destroy@*
1810 pthread_cond_t
* cond
) {
1811 return pthread_cond_destroy_WRK(cond
);
1813 #elif defined(VGO_freebsd)
1814 PTH_FUNC(int, pthreadZucondZudestroy
, // pthread_cond_destroy@*
1815 pthread_cond_t
* cond
) {
1816 return pthread_cond_destroy_WRK(cond
);
1818 #elif defined(VGO_darwin)
1819 PTH_FUNC(int, pthreadZucondZudestroy
, // pthread_cond_destroy
1820 pthread_cond_t
* cond
) {
1821 return pthread_cond_destroy_WRK(cond
);
1823 #elif defined(VGO_solaris)
1824 PTH_FUNC(int, condZudestroy
, // cond_destroy
1825 pthread_cond_t
*cond
) {
1826 return pthread_cond_destroy_WRK(cond
);
1829 # error "Unsupported OS"
1833 /*----------------------------------------------------------------*/
1834 /*--- pthread_barrier_t functions ---*/
1835 /*----------------------------------------------------------------*/
1837 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1839 /* Handled: pthread_barrier_init
1840 pthread_barrier_wait
1841 pthread_barrier_destroy
1843 Unhandled: pthread_barrierattr_destroy
1844 pthread_barrierattr_getpshared
1845 pthread_barrierattr_init
1846 pthread_barrierattr_setpshared
1847 -- are these important?
1850 //-----------------------------------------------------------
1851 // glibc: pthread_barrier_init
1852 // darwin: (doesn't appear to exist)
1853 // Solaris: pthread_barrier_init
1854 // FreeBSD: pthread_barrier_init
1855 PTH_FUNC(int, pthreadZubarrierZuinit
, // pthread_barrier_init
1856 pthread_barrier_t
* bar
,
1857 pthread_barrierattr_t
* attr
, unsigned long count
)
1861 VALGRIND_GET_ORIG_FN(fn
);
1863 if (TRACE_PTH_FNS
) {
1864 fprintf(stderr
, "<< pthread_barrier_init %p %p %lu",
1869 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE
,
1870 pthread_barrier_t
*, bar
,
1871 unsigned long, count
,
1872 unsigned long, 0/*!resizable*/);
1874 CALL_FN_W_WWW(ret
, fn
, bar
,attr
,count
);
1877 DO_PthAPIerror( "pthread_barrier_init", ret
);
1880 if (TRACE_PTH_FNS
) {
1881 fprintf(stderr
, " pthread_barrier_init -> %d >>\n", ret
);
1888 //-----------------------------------------------------------
1889 // glibc: pthread_barrier_wait
1890 // darwin: (doesn't appear to exist)
1891 // Solaris: pthread_barrier_wait
1892 // FreeBSD: pthread_barrier_wait
1893 PTH_FUNC(int, pthreadZubarrierZuwait
, // pthread_barrier_wait
1894 pthread_barrier_t
* bar
)
1898 VALGRIND_GET_ORIG_FN(fn
);
1900 if (TRACE_PTH_FNS
) {
1901 fprintf(stderr
, "<< pthread_barrier_wait %p", bar
);
1905 /* That this works correctly, and doesn't screw up when a thread
1906 leaving the barrier races round to the front and re-enters while
1907 other threads are still leaving it, is quite subtle. See
1908 comments in the handler for PTHREAD_BARRIER_WAIT_PRE in
1910 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE
,
1911 pthread_barrier_t
*,bar
);
1913 CALL_FN_W_W(ret
, fn
, bar
);
1915 if (ret
!= 0 && ret
!= PTHREAD_BARRIER_SERIAL_THREAD
) {
1916 DO_PthAPIerror( "pthread_barrier_wait", ret
);
1919 if (TRACE_PTH_FNS
) {
1920 fprintf(stderr
, " pthread_barrier_wait -> %d >>\n", ret
);
1927 //-----------------------------------------------------------
1928 // glibc: pthread_barrier_destroy
1929 // darwin: (doesn't appear to exist)
1930 // Solaris: pthread_barrier_destroy
1931 // FreeBSD: pthread_barrier_destroy
1932 PTH_FUNC(int, pthreadZubarrierZudestroy
, // pthread_barrier_destroy
1933 pthread_barrier_t
* bar
)
1937 VALGRIND_GET_ORIG_FN(fn
);
1939 if (TRACE_PTH_FNS
) {
1940 fprintf(stderr
, "<< pthread_barrier_destroy %p", bar
);
1944 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE
,
1945 pthread_barrier_t
*,bar
);
1947 CALL_FN_W_W(ret
, fn
, bar
);
1950 DO_PthAPIerror( "pthread_barrier_destroy", ret
);
1953 if (TRACE_PTH_FNS
) {
1954 fprintf(stderr
, " pthread_barrier_destroy -> %d >>\n", ret
);
1960 #endif // defined(HAVE_PTHREAD_BARRIER_INIT)
1963 /*----------------------------------------------------------------*/
1964 /*--- pthread_spinlock_t functions ---*/
1965 /*----------------------------------------------------------------*/
1967 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1968 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1970 /* Handled: pthread_spin_init pthread_spin_destroy
1971 pthread_spin_lock pthread_spin_trylock
1977 /* This is a nasty kludge, in that glibc "knows" that initialising a
1978 spin lock unlocks it, and pthread_spin_{init,unlock} are names for
1979 the same function. Hence we have to have a wrapper which does both
1980 things, without knowing which the user intended to happen.
1981 Solaris has distinct functions for init/unlock but client requests
1982 are immutable in helgrind.h so follow the glibc lead. */
1984 //-----------------------------------------------------------
1985 // glibc: pthread_spin_init
1986 // glibc: pthread_spin_unlock
1987 // darwin: (doesn't appear to exist)
1988 // Solaris: pthread_spin_init
1989 // Solaris: pthread_spin_unlock
1990 // FreeBSD: pthread_spin_init
1991 // FreeBSD: pthread_spin_unlock
1992 __attribute__((noinline
))
1993 static int pthread_spin_init_or_unlock_WRK(pthread_spinlock_t
* lock
,
1997 VALGRIND_GET_ORIG_FN(fn
);
1998 if (TRACE_PTH_FNS
) {
1999 fprintf(stderr
, "<< pthread_spin_iORu %p", lock
); fflush(stderr
);
2002 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE
,
2003 pthread_spinlock_t
*, lock
);
2005 CALL_FN_W_WW(ret
, fn
, lock
,pshared
);
2007 if (ret
== 0 /*success*/) {
2008 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST
,
2009 pthread_spinlock_t
*,lock
);
2011 DO_PthAPIerror( "pthread_spinlock_{init,unlock}", ret
);
2014 if (TRACE_PTH_FNS
) {
2015 fprintf(stderr
, " :: spiniORu -> %d >>\n", ret
);
2019 #if defined(VGO_linux)
2020 PTH_FUNC(int, pthreadZuspinZuinit
, // pthread_spin_init
2021 pthread_spinlock_t
* lock
, int pshared
) {
2022 return pthread_spin_init_or_unlock_WRK(lock
, pshared
);
2024 PTH_FUNC(int, pthreadZuspinZuunlock
, // pthread_spin_unlock
2025 pthread_spinlock_t
* lock
) {
2026 /* this is never actually called */
2027 return pthread_spin_init_or_unlock_WRK(lock
, 0/*pshared*/);
2029 #elif defined(VGO_freebsd)
2030 PTH_FUNC(int, pthreadZuspinZuinit
, // pthread_spin_init
2031 pthread_spinlock_t
* lock
, int pshared
) {
2032 return pthread_spin_init_or_unlock_WRK(lock
, pshared
);
2034 PTH_FUNC(int, pthreadZuspinZuunlock
, // pthread_spin_unlock@*
2035 pthread_spinlock_t
* lock
) {
2036 /* this is never actually called */
2037 return pthread_spin_init_or_unlock_WRK(lock
, 0/*pshared*/);
2039 #elif defined(VGO_darwin)
2040 #elif defined(VGO_solaris)
2041 PTH_FUNC(int, pthreadZuspinZuinit
, // pthread_spin_init
2042 pthread_spinlock_t
*lock
, int pshared
) {
2043 return pthread_spin_init_or_unlock_WRK(lock
, pshared
);
2045 PTH_FUNC(int, pthreadZuspinZuunlock
, // pthread_spin_unlock
2046 pthread_spinlock_t
*lock
) {
2047 return pthread_spin_init_or_unlock_WRK(lock
, 0/*pshared*/);
2050 # error "Unsupported OS"
2054 //-----------------------------------------------------------
2055 // glibc: pthread_spin_destroy
2056 // darwin: (doesn't appear to exist)
2057 // Solaris: pthread_spin_destroy
2058 // FreeBSD: pthread_spin_destroy
2059 __attribute__((noinline
))
2060 static int pthread_spin_destroy_WRK(pthread_spinlock_t
*lock
)
2064 VALGRIND_GET_ORIG_FN(fn
);
2065 if (TRACE_PTH_FNS
) {
2066 fprintf(stderr
, "<< pthread_spin_destroy %p", lock
);
2070 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_DESTROY_PRE
,
2071 pthread_spinlock_t
*,lock
);
2073 CALL_FN_W_W(ret
, fn
, lock
);
2076 DO_PthAPIerror( "pthread_spin_destroy", ret
);
2079 if (TRACE_PTH_FNS
) {
2080 fprintf(stderr
, " :: spindestroy -> %d >>\n", ret
);
2084 #if defined(VGO_linux) || defined(VGO_freebsd)
2085 PTH_FUNC(int, pthreadZuspinZudestroy
, // pthread_spin_destroy
2086 pthread_spinlock_t
*lock
) {
2087 return pthread_spin_destroy_WRK(lock
);
2089 #elif defined(VGO_darwin)
2090 #elif defined(VGO_solaris)
2091 PTH_FUNC(int, pthreadZuspinZudestroy
, // pthread_spin_destroy
2092 pthread_spinlock_t
*lock
) {
2093 return pthread_spin_destroy_WRK(lock
);
2096 # error "Unsupported OS"
2100 //-----------------------------------------------------------
2101 // glibc: pthread_spin_lock
2102 // darwin: (doesn't appear to exist)
2103 // Solaris: pthread_spin_lock
2104 // FreeBSD: pthread_spin_lock
2105 __attribute__((noinline
))
2106 static int pthread_spin_lock_WRK(pthread_spinlock_t
*lock
)
2110 VALGRIND_GET_ORIG_FN(fn
);
2111 if (TRACE_PTH_FNS
) {
2112 fprintf(stderr
, "<< pthread_spinlock %p", lock
);
2116 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE
,
2117 pthread_spinlock_t
*,lock
, long,0/*!isTryLock*/);
2119 CALL_FN_W_W(ret
, fn
, lock
);
2121 /* There's a hole here: libpthread now knows the lock is locked,
2122 but the tool doesn't, so some other thread could run and detect
2123 that the lock has been acquired by someone (this thread). Does
2124 this matter? Not sure, but I don't think so. */
2126 if (ret
== 0 /*success*/) {
2127 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST
,
2128 pthread_spinlock_t
*,lock
);
2130 DO_PthAPIerror( "pthread_spin_lock", ret
);
2133 if (TRACE_PTH_FNS
) {
2134 fprintf(stderr
, " :: spinlock -> %d >>\n", ret
);
2138 #if defined(VGO_linux) || defined(VGO_freebsd)
2139 PTH_FUNC(int, pthreadZuspinZulock
, // pthread_spin_lock
2140 pthread_spinlock_t
*lock
) {
2141 return pthread_spin_lock_WRK(lock
);
2143 #elif defined(VGO_darwin)
2144 #elif defined(VGO_solaris)
2145 PTH_FUNC(int, pthreadZuspinZulock
, // pthread_spin_lock
2146 pthread_spinlock_t
*lock
) {
2147 return pthread_spin_lock_WRK(lock
);
2150 # error "Unsupported OS"
2154 //-----------------------------------------------------------
2155 // glibc: pthread_spin_trylock
2156 // darwin: (doesn't appear to exist)
2157 // Solaris: pthread_spin_trylock
2158 // FreeBSD: pthread_spin_trylock
2159 __attribute__((noinline
))
2160 static int pthread_spin_trylock_WRK(pthread_spinlock_t
*lock
)
2164 VALGRIND_GET_ORIG_FN(fn
);
2165 if (TRACE_PTH_FNS
) {
2166 fprintf(stderr
, "<< pthread_spin_trylock %p", lock
);
2170 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE
,
2171 pthread_spinlock_t
*,lock
, long,1/*isTryLock*/);
2173 CALL_FN_W_W(ret
, fn
, lock
);
2175 /* There's a hole here: libpthread now knows the lock is locked,
2176 but the tool doesn't, so some other thread could run and detect
2177 that the lock has been acquired by someone (this thread). Does
2178 this matter? Not sure, but I don't think so. */
2180 if (ret
== 0 /*success*/) {
2181 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST
,
2182 pthread_spinlock_t
*,lock
);
2185 DO_PthAPIerror( "pthread_spin_trylock", ret
);
2188 if (TRACE_PTH_FNS
) {
2189 fprintf(stderr
, " :: spin_trylock -> %d >>\n", ret
);
2193 #if defined(VGO_linux) || defined(VGO_freebsd)
2194 PTH_FUNC(int, pthreadZuspinZutrylock
, // pthread_spin_trylock
2195 pthread_spinlock_t
*lock
) {
2196 return pthread_spin_trylock_WRK(lock
);
2198 #elif defined(VGO_darwin)
2199 #elif defined(VGO_solaris)
2200 PTH_FUNC(int, pthreadZuspinZutrylock
, // pthread_spin_trylock
2201 pthread_spinlock_t
*lock
) {
2202 return pthread_spin_trylock_WRK(lock
);
2205 # error "Unsupported OS"
2208 #endif // defined(HAVE_PTHREAD_SPIN_LOCK)
2211 /*----------------------------------------------------------------*/
2212 /*--- pthread_rwlock_t functions ---*/
2213 /*----------------------------------------------------------------*/
2215 /* Android's pthread.h doesn't say anything about rwlocks, hence these
2216 functions have to be conditionally compiled. */
2217 #if defined(HAVE_PTHREAD_RWLOCK_T)
2219 /* Handled: pthread_rwlock_init pthread_rwlock_destroy
2220 pthread_rwlock_rdlock
2221 pthread_rwlock_wrlock
2222 pthread_rwlock_unlock
2223 pthread_rwlock_tryrdlock
2224 pthread_rwlock_trywrlock
2226 Unhandled: pthread_rwlock_timedrdlock
2227 pthread_rwlock_timedwrlock
2230 //-----------------------------------------------------------
2231 // glibc: pthread_rwlock_init
2232 // darwin: pthread_rwlock_init
2233 // darwin: pthread_rwlock_init$UNIX2003
2234 // Solaris: rwlock_init (pthread_rwlock_init is built atop of rwlock_init)
2235 // FreeBSD: pthread_rwlock_init
2236 __attribute__((noinline
))
2237 static int pthread_rwlock_init_WRK(pthread_rwlock_t
*rwl
,
2238 pthread_rwlockattr_t
* attr
)
2242 VALGRIND_GET_ORIG_FN(fn
);
2243 if (TRACE_PTH_FNS
) {
2244 fprintf(stderr
, "<< pthread_rwl_init %p", rwl
); fflush(stderr
);
2247 CALL_FN_W_WW(ret
, fn
, rwl
,attr
);
2249 if (ret
== 0 /*success*/) {
2250 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST
,
2251 pthread_rwlock_t
*,rwl
);
2253 DO_PthAPIerror( "pthread_rwlock_init", ret
);
2256 if (TRACE_PTH_FNS
) {
2257 fprintf(stderr
, " :: rwl_init -> %d >>\n", ret
);
2261 #if defined(VGO_linux)
2262 PTH_FUNC(int, pthreadZurwlockZuinit
, // pthread_rwlock_init
2263 pthread_rwlock_t
*rwl
,
2264 pthread_rwlockattr_t
* attr
) {
2265 return pthread_rwlock_init_WRK(rwl
, attr
);
2267 #elif defined(VGO_freebsd)
2268 PTH_FUNC(int, pthreadZurwlockZuinit
, // pthread_rwlock_init
2269 pthread_rwlock_t
*rwl
,
2270 pthread_rwlockattr_t
* attr
) {
2271 return pthread_rwlock_init_WRK(rwl
, attr
);
2273 #elif defined(VGO_darwin)
2274 PTH_FUNC(int, pthreadZurwlockZuinitZa
, // pthread_rwlock_init*
2275 pthread_rwlock_t
*rwl
,
2276 pthread_rwlockattr_t
* attr
) {
2277 return pthread_rwlock_init_WRK(rwl
, attr
);
2279 #elif defined(VGO_solaris)
2280 static int pthread_rwlock_init_WRK(pthread_rwlock_t
*rwl
,
2281 pthread_rwlockattr_t
* attr
)
2282 __attribute__((unused
));
2284 # error "Unsupported OS"
2287 #if defined(VGO_solaris)
2288 PTH_FUNC(int, rwlockZuinit
, // rwlock_init
2295 VALGRIND_GET_ORIG_FN(fn
);
2296 if (TRACE_PTH_FNS
) {
2297 fprintf(stderr
, "<< rwl_init %p", rwlock
); fflush(stderr
);
2300 CALL_FN_W_WWW(ret
, fn
, rwlock
, type
, arg
);
2302 if (ret
== 0 /*success*/) {
2303 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST
,
2304 rwlock_t
*, rwlock
);
2306 DO_PthAPIerror("rwlock_init", ret
);
2309 if (TRACE_PTH_FNS
) {
2310 fprintf(stderr
, " :: rwl_init -> %d >>\n", ret
);
2314 #endif /* VGO_solaris */
2317 //-----------------------------------------------------------
2318 // glibc: pthread_rwlock_destroy
2319 // darwin: pthread_rwlock_destroy
2320 // darwin: pthread_rwlock_destroy$UNIX2003
2321 // Solaris: rwlock_destroy (pthread_rwlock_destroy is a weak alias)
2322 // FreeBSD: pthread_rwlock_destroy
2324 __attribute__((noinline
))
2325 static int pthread_rwlock_destroy_WRK(pthread_rwlock_t
* rwl
)
2329 VALGRIND_GET_ORIG_FN(fn
);
2330 if (TRACE_PTH_FNS
) {
2331 fprintf(stderr
, "<< pthread_rwl_destroy %p", rwl
); fflush(stderr
);
2334 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE
,
2335 pthread_rwlock_t
*,rwl
);
2337 CALL_FN_W_W(ret
, fn
, rwl
);
2340 DO_PthAPIerror( "pthread_rwlock_destroy", ret
);
2343 if (TRACE_PTH_FNS
) {
2344 fprintf(stderr
, " :: rwl_destroy -> %d >>\n", ret
);
2348 #if defined(VGO_linux)
2349 PTH_FUNC(int, pthreadZurwlockZudestroy
, // pthread_rwlock_destroy
2350 pthread_rwlock_t
*rwl
) {
2351 return pthread_rwlock_destroy_WRK(rwl
);
2353 #elif defined(VGO_freebsd)
2354 PTH_FUNC(int, pthreadZurwlockZudestroy
, // pthread_rwlock_destroy
2355 pthread_rwlock_t
*rwl
) {
2356 return pthread_rwlock_destroy_WRK(rwl
);
2358 #elif defined(VGO_darwin)
2359 PTH_FUNC(int, pthreadZurwlockZudestroyZa
, // pthread_rwlock_destroy*
2360 pthread_rwlock_t
*rwl
) {
2361 return pthread_rwlock_destroy_WRK(rwl
);
2363 #elif defined(VGO_solaris)
2364 PTH_FUNC(int, rwlockZudestroy
, // rwlock_destroy
2365 pthread_rwlock_t
*rwl
) {
2366 return pthread_rwlock_destroy_WRK(rwl
);
2369 # error "Unsupported OS"
2373 //-----------------------------------------------------------
2374 // glibc: pthread_rwlock_wrlock
2375 // darwin: pthread_rwlock_wrlock
2376 // darwin: pthread_rwlock_wrlock$UNIX2003
2377 // Solaris: rw_wrlock (pthread_rwlock_wrlock is a weak alias)
2378 // FreeBSD: pthread_rwlock_wrlock
2380 __attribute__((noinline
))
2381 static int pthread_rwlock_wrlock_WRK(pthread_rwlock_t
* rwlock
)
2385 VALGRIND_GET_ORIG_FN(fn
);
2386 if (TRACE_PTH_FNS
) {
2387 fprintf(stderr
, "<< pthread_rwl_wlk %p", rwlock
); fflush(stderr
);
2390 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
2391 pthread_rwlock_t
*,rwlock
,
2392 long,1/*isW*/, long,0/*!isTryLock*/);
2394 CALL_FN_W_W(ret
, fn
, rwlock
);
2396 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
2397 pthread_rwlock_t
*,rwlock
, long,1/*isW*/,
2398 long, (ret
== 0) ? True
: False
);
2400 DO_PthAPIerror( "pthread_rwlock_wrlock", ret
);
2403 if (TRACE_PTH_FNS
) {
2404 fprintf(stderr
, " :: rwl_wlk -> %d >>\n", ret
);
2408 #if defined(VGO_linux)
2409 PTH_FUNC(int, pthreadZurwlockZuwrlock
, // pthread_rwlock_wrlock
2410 pthread_rwlock_t
* rwlock
) {
2411 return pthread_rwlock_wrlock_WRK(rwlock
);
2413 #elif defined(VGO_freebsd)
2414 PTH_FUNC(int, pthreadZurwlockZuwrlock
, // pthread_rwlock_wrlock
2415 pthread_rwlock_t
* rwlock
) {
2416 return pthread_rwlock_wrlock_WRK(rwlock
);
2418 #elif defined(VGO_darwin)
2419 PTH_FUNC(int, pthreadZurwlockZuwrlockZa
, // pthread_rwlock_wrlock*
2420 pthread_rwlock_t
* rwlock
) {
2421 return pthread_rwlock_wrlock_WRK(rwlock
);
2423 #elif defined(VGO_solaris)
2424 PTH_FUNC(int, rwZuwrlock
, // rw_wrlock
2425 pthread_rwlock_t
*rwlock
) {
2426 return pthread_rwlock_wrlock_WRK(rwlock
);
2429 # error "Unsupported OS"
2432 #if defined(VGO_solaris)
2433 /* Internal to libc. */
2434 PTH_FUNC(void, lrwZuwrlock
, // lrw_wrlock
2438 VALGRIND_GET_ORIG_FN(fn
);
2439 if (TRACE_PTH_FNS
) {
2440 fprintf(stderr
, "<< lrw_wlk %p", rwlock
); fflush(stderr
);
2443 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
2444 pthread_rwlock_t
*, rwlock
,
2445 long, 1/*isW*/, long, 0/*!isTryLock*/);
2447 CALL_FN_v_W(fn
, rwlock
);
2449 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
2450 pthread_rwlock_t
*, rwlock
, long, 1/*isW*/, long, True
);
2452 if (TRACE_PTH_FNS
) {
2453 fprintf(stderr
, " :: lrw_wlk >>\n");
2456 #endif /* VGO_solaris */
2459 //-----------------------------------------------------------
2460 // glibc: pthread_rwlock_rdlock
2461 // darwin: pthread_rwlock_rdlock
2462 // darwin: pthread_rwlock_rdlock$UNIX2003
2463 // Solaris: rw_rdlock (pthread_rwlock_rdlock is a weak alias)
2464 // FreeBSD: pthread_rwlock_rdlock
2466 __attribute__((noinline
))
2467 static int pthread_rwlock_rdlock_WRK(pthread_rwlock_t
* rwlock
)
2471 VALGRIND_GET_ORIG_FN(fn
);
2472 if (TRACE_PTH_FNS
) {
2473 fprintf(stderr
, "<< pthread_rwl_rlk %p", rwlock
); fflush(stderr
);
2476 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
2477 pthread_rwlock_t
*,rwlock
,
2478 long,0/*!isW*/, long,0/*!isTryLock*/);
2480 CALL_FN_W_W(ret
, fn
, rwlock
);
2482 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
2483 pthread_rwlock_t
*,rwlock
, long,0/*!isW*/,
2484 long, (ret
== 0) ? True
: False
);
2486 DO_PthAPIerror( "pthread_rwlock_rdlock", ret
);
2489 if (TRACE_PTH_FNS
) {
2490 fprintf(stderr
, " :: rwl_rlk -> %d >>\n", ret
);
2494 #if defined(VGO_linux)
2495 PTH_FUNC(int, pthreadZurwlockZurdlock
, // pthread_rwlock_rdlock
2496 pthread_rwlock_t
* rwlock
) {
2497 return pthread_rwlock_rdlock_WRK(rwlock
);
2499 #elif defined(VGO_freebsd)
2500 PTH_FUNC(int, pthreadZurwlockZurdlock
, // pthread_rwlock_rdlock
2501 pthread_rwlock_t
* rwlock
) {
2502 return pthread_rwlock_rdlock_WRK(rwlock
);
2504 #elif defined(VGO_darwin)
2505 PTH_FUNC(int, pthreadZurwlockZurdlockZa
, // pthread_rwlock_rdlock*
2506 pthread_rwlock_t
* rwlock
) {
2507 return pthread_rwlock_rdlock_WRK(rwlock
);
2509 #elif defined(VGO_solaris)
2510 PTH_FUNC(int, rwZurdlock
, // rw_rdlock
2511 pthread_rwlock_t
*rwlock
) {
2512 return pthread_rwlock_rdlock_WRK(rwlock
);
2515 # error "Unsupported OS"
2518 #if defined(VGO_solaris)
2519 /* Internal to libc. */
2520 PTH_FUNC(void, lrwZurdlock
, // lrw_rdlock
2524 VALGRIND_GET_ORIG_FN(fn
);
2525 if (TRACE_PTH_FNS
) {
2526 fprintf(stderr
, "<< lrw_rlk %p", rwlock
); fflush(stderr
);
2529 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
2530 pthread_rwlock_t
*, rwlock
,
2531 long, 0/*!isW*/, long, 0/*!isTryLock*/);
2533 CALL_FN_v_W(fn
, rwlock
);
2535 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
2536 pthread_rwlock_t
*, rwlock
, long, 0/*!isW*/, long, True
);
2538 if (TRACE_PTH_FNS
) {
2539 fprintf(stderr
, " :: lrw_rlk ->>\n");
2542 #endif /* VGO_solaris */
2545 //-----------------------------------------------------------
2546 // glibc: pthread_rwlock_trywrlock
2547 // darwin: pthread_rwlock_trywrlock
2548 // darwin: pthread_rwlock_trywrlock$UNIX2003
2549 // Solaris: rw_trywrlock (pthread_rwlock_trywrlock is a weak alias)
2550 // FreeBSD: pthread_rwlock_trywrlock
2552 __attribute__((noinline
))
2553 static int pthread_rwlock_trywrlock_WRK(pthread_rwlock_t
* rwlock
)
2557 VALGRIND_GET_ORIG_FN(fn
);
2558 if (TRACE_PTH_FNS
) {
2559 fprintf(stderr
, "<< pthread_rwl_trywlk %p", rwlock
); fflush(stderr
);
2562 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
2563 pthread_rwlock_t
*,rwlock
,
2564 long,1/*isW*/, long,1/*isTryLock*/);
2566 CALL_FN_W_W(ret
, fn
, rwlock
);
2568 /* There's a hole here: libpthread now knows the lock is locked,
2569 but the tool doesn't, so some other thread could run and detect
2570 that the lock has been acquired by someone (this thread). Does
2571 this matter? Not sure, but I don't think so. */
2573 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
2574 pthread_rwlock_t
*,rwlock
, long,1/*isW*/,
2575 long, (ret
== 0) ? True
: False
);
2578 DO_PthAPIerror( "pthread_rwlock_trywrlock", ret
);
2581 if (TRACE_PTH_FNS
) {
2582 fprintf(stderr
, " :: rwl_trywlk -> %d >>\n", ret
);
2586 #if defined(VGO_linux)
2587 PTH_FUNC(int, pthreadZurwlockZutrywrlock
, // pthread_rwlock_trywrlock
2588 pthread_rwlock_t
* rwlock
) {
2589 return pthread_rwlock_trywrlock_WRK(rwlock
);
2591 #elif defined(VGO_freebsd)
2592 PTH_FUNC(int, pthreadZurwlockZutrywrlock
, // pthread_rwlock_trywrlock
2593 pthread_rwlock_t
* rwlock
) {
2594 return pthread_rwlock_trywrlock_WRK(rwlock
);
2596 #elif defined(VGO_darwin)
2597 PTH_FUNC(int, pthreadZurwlockZutrywrlockZa
, // pthread_rwlock_trywrlock*
2598 pthread_rwlock_t
* rwlock
) {
2599 return pthread_rwlock_trywrlock_WRK(rwlock
);
2601 #elif defined(VGO_solaris)
2602 PTH_FUNC(int, rwZutrywrlock
, // rw_trywrlock
2603 pthread_rwlock_t
*rwlock
) {
2604 return pthread_rwlock_trywrlock_WRK(rwlock
);
2607 # error "Unsupported OS"
2611 //-----------------------------------------------------------
2612 // glibc: pthread_rwlock_tryrdlock
2613 // darwin: pthread_rwlock_tryrdlock
2614 // darwin: pthread_rwlock_tryrdlock$UNIX2003
2615 // Solaris: rw_tryrdlock (pthread_rwlock_tryrdlock is a weak alias)
2616 // FreeBSD: pthread_rwlock_tryrdlock
2618 __attribute__((noinline
))
2619 static int pthread_rwlock_tryrdlock_WRK(pthread_rwlock_t
* rwlock
)
2623 VALGRIND_GET_ORIG_FN(fn
);
2624 if (TRACE_PTH_FNS
) {
2625 fprintf(stderr
, "<< pthread_rwl_tryrlk %p", rwlock
); fflush(stderr
);
2628 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
2629 pthread_rwlock_t
*,rwlock
,
2630 long,0/*!isW*/, long,1/*isTryLock*/);
2632 CALL_FN_W_W(ret
, fn
, rwlock
);
2634 /* There's a hole here: libpthread now knows the lock is locked,
2635 but the tool doesn't, so some other thread could run and detect
2636 that the lock has been acquired by someone (this thread). Does
2637 this matter? Not sure, but I don't think so. */
2639 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
2640 pthread_rwlock_t
*,rwlock
, long,0/*!isW*/,
2641 long, (ret
== 0) ? True
: False
);
2645 DO_PthAPIerror( "pthread_rwlock_tryrdlock", ret
);
2648 if (TRACE_PTH_FNS
) {
2649 fprintf(stderr
, " :: rwl_tryrlk -> %d >>\n", ret
);
2653 #if defined(VGO_linux)
2654 PTH_FUNC(int, pthreadZurwlockZutryrdlock
, // pthread_rwlock_tryrdlock
2655 pthread_rwlock_t
* rwlock
) {
2656 return pthread_rwlock_tryrdlock_WRK(rwlock
);
2658 #elif defined(VGO_freebsd)
2659 PTH_FUNC(int, pthreadZurwlockZutryrdlock
, // pthread_rwlock_tryrdlock
2660 pthread_rwlock_t
* rwlock
) {
2661 return pthread_rwlock_tryrdlock_WRK(rwlock
);
2663 #elif defined(VGO_darwin)
2664 PTH_FUNC(int, pthreadZurwlockZutryrdlockZa
, // pthread_rwlock_tryrdlock*
2665 pthread_rwlock_t
* rwlock
) {
2666 return pthread_rwlock_tryrdlock_WRK(rwlock
);
2668 #elif defined(VGO_solaris)
2669 PTH_FUNC(int, rwZutryrdlock
, // rw_tryrdlock
2670 pthread_rwlock_t
*rwlock
) {
2671 return pthread_rwlock_tryrdlock_WRK(rwlock
);
2674 # error "Unsupported OS"
2678 //-----------------------------------------------------------
2680 // darwin: Unhandled
2681 // Solaris: pthread_rwlock_timedrdlock
2682 // Solaris: pthread_rwlock_reltimedrdlock_np
2683 // FreeBSD: pthread_rwlock_timedrdlock
2685 __attribute__((noinline
)) __attribute__((unused
))
2686 static int pthread_rwlock_timedrdlock_WRK(pthread_rwlock_t
*rwlock
,
2687 const struct timespec
*timeout
)
2691 VALGRIND_GET_ORIG_FN(fn
);
2692 if (TRACE_PTH_FNS
) {
2693 fprintf(stderr
, "<< pthread_rwl_timedrdl %p", rwlock
); fflush(stderr
);
2696 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
2697 pthread_rwlock_t
*, rwlock
,
2698 long, 0/*isW*/, long, 0/*isTryLock*/);
2700 CALL_FN_W_WW(ret
, fn
, rwlock
, timeout
);
2702 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
2703 pthread_rwlock_t
*, rwlock
, long, 0/*isW*/,
2704 long, (ret
== 0) ? True
: False
);
2706 DO_PthAPIerror("pthread_rwlock_timedrdlock", ret
);
2709 if (TRACE_PTH_FNS
) {
2710 fprintf(stderr
, " :: rwl_timedrdl -> %d >>\n", ret
);
2714 #if defined(VGO_linux)
2715 #elif defined(VGO_darwin)
2716 #elif defined(VGO_freebsd)
2717 PTH_FUNC(int, pthreadZurwlockZutimedrdlock
, // pthread_rwlock_timedrdlock
2718 pthread_rwlock_t
*rwlock
,
2719 const struct timespec
*timeout
) {
2720 return pthread_rwlock_timedrdlock_WRK(rwlock
, timeout
);
2722 #elif defined(VGO_solaris)
2723 PTH_FUNC(int, pthreadZurwlockZutimedrdlock
, // pthread_rwlock_timedrdlock
2724 pthread_rwlock_t
*rwlock
,
2725 const struct timespec
*timeout
) {
2726 return pthread_rwlock_timedrdlock_WRK(rwlock
, timeout
);
2728 PTH_FUNC(int, pthreadZurwlockZureltimedrdlockZunp
, // pthread_rwlock_timedrdlock_np
2729 pthread_rwlock_t
*rwlock
,
2730 const struct timespec
*timeout
) {
2731 return pthread_rwlock_timedrdlock_WRK(rwlock
, timeout
);
2734 # error "Unsupported OS"
2737 #if defined(VGO_linux)
2738 //-----------------------------------------------------------
2739 // glibc: pthread_rwlock_clockrdlock
2741 __attribute__((noinline
)) __attribute__((unused
))
2742 static int pthread_rwlock_clockrdlock_WRK(pthread_rwlock_t
*rwlock
,
2744 const struct timespec
*timeout
)
2748 VALGRIND_GET_ORIG_FN(fn
);
2749 if (TRACE_PTH_FNS
) {
2750 fprintf(stderr
, "<< pthread_rwl_clockrdl %p", rwlock
); fflush(stderr
);
2753 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
2754 pthread_rwlock_t
*, rwlock
,
2755 long, 0/*isW*/, long, 0/*isTryLock*/);
2757 CALL_FN_W_WWW(ret
, fn
, rwlock
, clockid
, timeout
);
2759 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
2760 pthread_rwlock_t
*, rwlock
, long, 0/*isW*/,
2761 long, (ret
== 0) ? True
: False
);
2763 DO_PthAPIerror("pthread_rwlock_clockrdlock", ret
);
2766 if (TRACE_PTH_FNS
) {
2767 fprintf(stderr
, " :: rwl_clockrdl -> %d >>\n", ret
);
2772 PTH_FUNC(int, pthreadZurwlockZuclockrdlock
, // pthread_rwlock_clockrdlock
2773 pthread_rwlock_t
*rwlock
,
2775 const struct timespec
*timeout
) {
2776 return pthread_rwlock_clockrdlock_WRK(rwlock
, clockid
, timeout
);
2781 //-----------------------------------------------------------
2783 // darwin: Unhandled
2784 // Solaris: pthread_rwlock_timedwrlock
2785 // Solaris: pthread_rwlock_reltimedwrlock_np
2786 // FreeBSD: pthread_rwlock_timedwrlock
2788 __attribute__((noinline
)) __attribute__((unused
))
2789 static int pthread_rwlock_timedwrlock_WRK(pthread_rwlock_t
*rwlock
,
2790 const struct timespec
*timeout
)
2794 VALGRIND_GET_ORIG_FN(fn
);
2795 if (TRACE_PTH_FNS
) {
2796 fprintf(stderr
, "<< pthread_rwl_timedwrl %p", rwlock
); fflush(stderr
);
2799 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
2800 pthread_rwlock_t
*, rwlock
,
2801 long, 1/*isW*/, long, 0/*isTryLock*/);
2803 CALL_FN_W_WW(ret
, fn
, rwlock
, timeout
);
2805 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
2806 pthread_rwlock_t
*, rwlock
, long, 1/*isW*/,
2807 long, (ret
== 0) ? True
: False
);
2809 DO_PthAPIerror("pthread_rwlock_timedwrlock", ret
);
2812 if (TRACE_PTH_FNS
) {
2813 fprintf(stderr
, " :: rwl_timedwrl -> %d >>\n", ret
);
2817 #if defined(VGO_linux)
2818 #elif defined(VGO_darwin)
2819 #elif defined(VGO_freebsd)
2820 PTH_FUNC(int, pthreadZurwlockZutimedwrlock
, // pthread_rwlock_timedwrlock
2821 pthread_rwlock_t
*rwlock
,
2822 const struct timespec
*timeout
) {
2823 return pthread_rwlock_timedwrlock_WRK(rwlock
, timeout
);
2825 #elif defined(VGO_solaris)
2826 PTH_FUNC(int, pthreadZurwlockZutimedwrlock
, // pthread_rwlock_timedwrlock
2827 pthread_rwlock_t
*rwlock
,
2828 const struct timespec
*timeout
) {
2829 return pthread_rwlock_timedwrlock_WRK(rwlock
, timeout
);
2831 PTH_FUNC(int, pthreadZurwlockZureltimedwrlockZunp
, // pthread_rwlock_timedwrlock_np
2832 pthread_rwlock_t
*rwlock
,
2833 const struct timespec
*timeout
) {
2834 return pthread_rwlock_timedwrlock_WRK(rwlock
, timeout
);
2837 # error "Unsupported OS"
2840 #if defined(VGO_linux)
2841 //-----------------------------------------------------------
2842 // glibc: pthread_rwlock_clockwrlock
2844 __attribute__((noinline
)) __attribute__((unused
))
2845 static int pthread_rwlock_clockwrlock_WRK(pthread_rwlock_t
*rwlock
,
2847 const struct timespec
*timeout
)
2851 VALGRIND_GET_ORIG_FN(fn
);
2852 if (TRACE_PTH_FNS
) {
2853 fprintf(stderr
, "<< pthread_rwl_clockwrl %p", rwlock
); fflush(stderr
);
2856 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE
,
2857 pthread_rwlock_t
*, rwlock
,
2858 long, 1/*isW*/, long, 0/*isTryLock*/);
2860 CALL_FN_W_WWW(ret
, fn
, rwlock
, clockid
, timeout
);
2862 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST
,
2863 pthread_rwlock_t
*, rwlock
, long, 1/*isW*/,
2864 long, (ret
== 0) ? True
: False
);
2866 DO_PthAPIerror("pthread_rwlock_clockwrlock", ret
);
2869 if (TRACE_PTH_FNS
) {
2870 fprintf(stderr
, " :: rwl_clockwrl -> %d >>\n", ret
);
2875 PTH_FUNC(int, pthreadZurwlockZuclockwrlock
, // pthread_rwlock_clockwrlock
2876 pthread_rwlock_t
*rwlock
,
2878 const struct timespec
*timeout
) {
2879 return pthread_rwlock_clockwrlock_WRK(rwlock
, clockid
, timeout
);
2884 //-----------------------------------------------------------
2885 // glibc: pthread_rwlock_unlock
2886 // darwin: pthread_rwlock_unlock
2887 // darwin: pthread_rwlock_unlock$UNIX2003
2888 // Solaris: rw_unlock (pthread_rwlock_unlock is a weak alias)
2889 // FreeBSD: pthread_rwlock_unlock
2890 __attribute__((noinline
))
2891 static int pthread_rwlock_unlock_WRK(pthread_rwlock_t
* rwlock
)
2895 VALGRIND_GET_ORIG_FN(fn
);
2896 if (TRACE_PTH_FNS
) {
2897 fprintf(stderr
, "<< pthread_rwl_unlk %p", rwlock
); fflush(stderr
);
2900 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE
,
2901 pthread_rwlock_t
*,rwlock
);
2903 CALL_FN_W_W(ret
, fn
, rwlock
);
2905 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST
,
2906 pthread_rwlock_t
*,rwlock
);
2908 DO_PthAPIerror( "pthread_rwlock_unlock", ret
);
2911 if (TRACE_PTH_FNS
) {
2912 fprintf(stderr
, " :: rwl_unlk -> %d >>\n", ret
);
2916 #if defined(VGO_linux)
2917 PTH_FUNC(int, pthreadZurwlockZuunlock
, // pthread_rwlock_unlock
2918 pthread_rwlock_t
* rwlock
) {
2919 return pthread_rwlock_unlock_WRK(rwlock
);
2921 #elif defined(VGO_freebsd)
2922 PTH_FUNC(int, pthreadZurwlockZuunlock
, // pthread_rwlock_unlock
2923 pthread_rwlock_t
* rwlock
) {
2924 return pthread_rwlock_unlock_WRK(rwlock
);
2926 #elif defined(VGO_darwin)
2927 PTH_FUNC(int, pthreadZurwlockZuunlockZa
, // pthread_rwlock_unlock*
2928 pthread_rwlock_t
* rwlock
) {
2929 return pthread_rwlock_unlock_WRK(rwlock
);
2931 #elif defined(VGO_solaris)
2932 PTH_FUNC(int, rwZuunlock
, // rw_unlock
2933 pthread_rwlock_t
*rwlock
) {
2934 return pthread_rwlock_unlock_WRK(rwlock
);
2937 # error "Unsupported OS"
2940 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
2943 /*----------------------------------------------------------------*/
2944 /*--- POSIX semaphores ---*/
2945 /*----------------------------------------------------------------*/
2947 #include <semaphore.h>
2948 #include <fcntl.h> /* O_CREAT */
2950 #define TRACE_SEM_FNS 0
2953 int sem_init(sem_t *sem, int pshared, unsigned value);
2954 int sem_destroy(sem_t *sem);
2955 int sem_wait(sem_t *sem);
2956 int sem_post(sem_t *sem);
2957 sem_t* sem_open(const char *name, int oflag,
2958 ... [mode_t mode, unsigned value]);
2959 [complete with its idiotic semantics]
2960 int sem_close(sem_t* sem);
2963 int sem_trywait(sem_t *sem);
2964 int sem_timedwait(sem_t *restrict sem,
2965 const struct timespec *restrict abs_timeout);
2968 //-----------------------------------------------------------
2969 // glibc: sem_init@@GLIBC_2.2.5
2970 // glibc: sem_init@@GLIBC_2.1
2971 // glibc: sem_init@GLIBC_2.0
2973 // Solaris: sema_init (sem_init is built on top of sem_init)
2974 // FreeBSD: sem_init (libc)
2976 #if !defined(VGO_solaris)
2977 __attribute__((noinline
))
2978 static int sem_init_WRK(sem_t
* sem
, int pshared
, unsigned long value
)
2982 VALGRIND_GET_ORIG_FN(fn
);
2984 if (TRACE_SEM_FNS
) {
2985 fprintf(stderr
, "<< sem_init(%p,%d,%lu) ", sem
,pshared
,value
);
2989 CALL_FN_W_WWW(ret
, fn
, sem
,pshared
,value
);
2992 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST
,
2993 sem_t
*, sem
, unsigned long, value
);
2995 DO_PthAPIerror( "sem_init", errno
);
2998 if (TRACE_SEM_FNS
) {
2999 fprintf(stderr
, " sem_init -> %d >>\n", ret
);
3005 #if defined(VGO_linux)
3006 PTH_FUNC(int, semZuinitZAZa
, // sem_init@*
3007 sem_t
* sem
, int pshared
, unsigned long value
) {
3008 return sem_init_WRK(sem
, pshared
, value
);
3010 #elif defined(VGO_darwin)
3011 PTH_FUNC(int, semZuinit
, // sem_init
3012 sem_t
* sem
, int pshared
, unsigned long value
) {
3013 return sem_init_WRK(sem
, pshared
, value
);
3015 #elif defined(VGO_freebsd)
3016 LIBC_FUNC(int, semZuinit
, // sem_init
3017 sem_t
* sem
, int pshared
, unsigned long value
) {
3018 return sem_init_WRK(sem
, pshared
, value
);
3021 # error "Unsupported OS"
3024 #else /* VGO_solaris */
3025 PTH_FUNC(int, semaZuinit
, // sema_init
3033 VALGRIND_GET_ORIG_FN(fn
);
3035 if (TRACE_SEM_FNS
) {
3036 fprintf(stderr
, "<< sema_init(%p, %d, %u) ", sem
, type
, value
);
3040 CALL_FN_W_WWWW(ret
, fn
, sem
, value
, type
, arg
);
3043 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST
,
3044 sema_t
*, sem
, Word
, value
);
3046 DO_PthAPIerror("sema_init", ret
);
3049 if (TRACE_SEM_FNS
) {
3050 fprintf(stderr
, " sema_init -> %d >>\n", ret
);
3056 #endif /* VGO_solaris */
3059 //-----------------------------------------------------------
3060 // glibc: sem_destroy@GLIBC_2.0
3061 // glibc: sem_destroy@@GLIBC_2.1
3062 // glibc: sem_destroy@@GLIBC_2.2.5
3063 // darwin: sem_destroy
3064 // Solaris: sema_destroy (sem_destroy is built on top of sema_destroy)
3065 // FreeBSD: sem_destroy (libc)
3066 __attribute__((noinline
))
3067 static int sem_destroy_WRK(sem_t
* sem
)
3071 VALGRIND_GET_ORIG_FN(fn
);
3073 if (TRACE_SEM_FNS
) {
3074 fprintf(stderr
, "<< sem_destroy(%p) ", sem
);
3078 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE
, sem_t
*, sem
);
3080 CALL_FN_W_W(ret
, fn
, sem
);
3083 DO_PthAPIerror( "sem_destroy", SEM_ERROR
);
3086 if (TRACE_SEM_FNS
) {
3087 fprintf(stderr
, " sem_destroy -> %d >>\n", ret
);
3093 #if defined(VGO_linux)
3094 PTH_FUNC(int, semZudestroyZAZa
, // sem_destroy*
3096 return sem_destroy_WRK(sem
);
3098 #elif defined(VGO_darwin)
3099 PTH_FUNC(int, semZudestroy
, // sem_destroy
3101 return sem_destroy_WRK(sem
);
3103 #elif defined(VGO_freebsd)
3104 LIBC_FUNC(int, semZudestroy
, // sem_destroy
3106 return sem_destroy_WRK(sem
);
3108 #elif defined(VGO_solaris)
3109 PTH_FUNC(int, semaZudestroy
, // sema_destroy
3111 return sem_destroy_WRK(sem
);
3114 # error "Unsupported OS"
3118 //-----------------------------------------------------------
3120 // glibc: sem_wait@GLIBC_2.0
3121 // glibc: sem_wait@@GLIBC_2.1
3123 // darwin: sem_wait$NOCANCEL$UNIX2003
3124 // darwin: sem_wait$UNIX2003
3125 // Solaris: sema_wait (sem_wait is built on top of sema_wait)
3126 // FreeBSD: sem_wait (libc)
3128 /* wait: decrement semaphore - acquire lockage */
3129 __attribute__((noinline
))
3130 static int sem_wait_WRK(sem_t
* sem
)
3134 VALGRIND_GET_ORIG_FN(fn
);
3136 if (TRACE_SEM_FNS
) {
3137 fprintf(stderr
, "<< sem_wait(%p) ", sem
);
3141 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_PRE
, sem_t
*,sem
);
3143 CALL_FN_W_W(ret
, fn
, sem
);
3145 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST
, sem_t
*,sem
,
3146 long, (ret
== 0) ? True
: False
);
3149 DO_PthAPIerror( "sem_wait", SEM_ERROR
);
3152 if (TRACE_SEM_FNS
) {
3153 fprintf(stderr
, " sem_wait -> %d >>\n", ret
);
3159 #if defined(VGO_linux)
3160 PTH_FUNC(int, semZuwait
, sem_t
* sem
) { /* sem_wait */
3161 return sem_wait_WRK(sem
);
3163 PTH_FUNC(int, semZuwaitZAZa
, sem_t
* sem
) { /* sem_wait@* */
3164 return sem_wait_WRK(sem
);
3166 #elif defined(VGO_darwin)
3167 PTH_FUNC(int, semZuwait
, sem_t
* sem
) { /* sem_wait */
3168 return sem_wait_WRK(sem
);
3170 PTH_FUNC(int, semZuwaitZDZa
, sem_t
* sem
) { /* sem_wait$* */
3171 return sem_wait_WRK(sem
);
3173 #elif defined(VGO_freebsd)
3174 LIBC_FUNC(int, semZuwait
, sem_t
* sem
) { /* sem_wait */
3175 return sem_wait_WRK(sem
);
3177 #elif defined(VGO_solaris)
3178 PTH_FUNC(int, semaZuwait
, sem_t
*sem
) { /* sema_wait */
3179 return sem_wait_WRK(sem
);
3182 # error "Unsupported OS"
3186 //-----------------------------------------------------------
3188 // glibc: sem_post@GLIBC_2.0
3189 // glibc: sem_post@@GLIBC_2.1
3191 // Solaris: sema_post (sem_post is built on top of sema_post)
3192 // FreeBSD: sem_post (libc)
3194 /* post: increment semaphore - release lockage */
3195 __attribute__((noinline
))
3196 static int sem_post_WRK(sem_t
* sem
)
3201 VALGRIND_GET_ORIG_FN(fn
);
3203 if (TRACE_SEM_FNS
) {
3204 fprintf(stderr
, "<< sem_post(%p) ", sem
);
3208 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_PRE
, sem_t
*,sem
);
3210 CALL_FN_W_W(ret
, fn
, sem
);
3212 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_POST
, sem_t
*,sem
);
3215 DO_PthAPIerror( "sem_post", SEM_ERROR
);
3218 if (TRACE_SEM_FNS
) {
3219 fprintf(stderr
, " sem_post -> %d >>\n", ret
);
3225 #if defined(VGO_linux)
3226 PTH_FUNC(int, semZupost
, sem_t
* sem
) { /* sem_post */
3227 return sem_post_WRK(sem
);
3229 PTH_FUNC(int, semZupostZAZa
, sem_t
* sem
) { /* sem_post@* */
3230 return sem_post_WRK(sem
);
3232 #elif defined(VGO_darwin)
3233 PTH_FUNC(int, semZupost
, sem_t
* sem
) { /* sem_post */
3234 return sem_post_WRK(sem
);
3236 #elif defined(VGO_freebsd)
3237 LIBC_FUNC(int, semZupost
, sem_t
* sem
) { /* sem_post */
3238 return sem_post_WRK(sem
);
3240 #elif defined(VGO_solaris)
3241 PTH_FUNC(int, semaZupost
, sem_t
*sem
) { /* sema_post */
3242 return sem_post_WRK(sem
);
3245 # error "Unsupported OS"
3249 //-----------------------------------------------------------
3252 // Solaris: sem_open
3253 // FreeBSD: sem_open
3255 #if defined(VGO_freebsd)
3256 LIBC_FUNC(sem_t
*, semZuopen
,
3257 const char* name
, long oflag
,
3258 long mode
, unsigned long value
)
3260 PTH_FUNC(sem_t
*, semZuopen
,
3261 const char* name
, long oflag
,
3262 long mode
, unsigned long value
)
3265 /* A copy of sem_init_WRK (more or less). Is this correct? */
3268 VALGRIND_GET_ORIG_FN(fn
);
3270 if (TRACE_SEM_FNS
) {
3271 fprintf(stderr
, "<< sem_open(\"%s\",%ld,%lx,%lu) ",
3272 name
,oflag
,mode
,value
);
3276 CALL_FN_W_WWWW(ret
, fn
, name
,oflag
,mode
,value
);
3278 if (ret
!= SEM_FAILED
&& (oflag
& O_CREAT
)) {
3279 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST
,
3280 sem_t
*, ret
, unsigned long, value
);
3282 if (ret
== SEM_FAILED
) {
3283 DO_PthAPIerror( "sem_open", errno
);
3286 if (TRACE_SEM_FNS
) {
3287 fprintf(stderr
, " sem_open -> %p >>\n", ret
);
3295 //-----------------------------------------------------------
3297 // darwin: sem_close
3298 // Solaris: sem_close
3299 // FreeBSD: sem_close
3300 #if defined (VGO_freebsd)
3301 LIBC_FUNC(int, sem_close
, sem_t
* sem
)
3303 PTH_FUNC(int, sem_close
, sem_t
* sem
)
3308 VALGRIND_GET_ORIG_FN(fn
);
3310 if (TRACE_SEM_FNS
) {
3311 fprintf(stderr
, "<< sem_close(%p) ", sem
);
3315 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE
, sem_t
*, sem
);
3317 CALL_FN_W_W(ret
, fn
, sem
);
3320 DO_PthAPIerror( "sem_close", errno
);
3323 if (TRACE_SEM_FNS
) {
3324 fprintf(stderr
, " close -> %d >>\n", ret
);
3332 /*----------------------------------------------------------------*/
3333 /*--- Qt 4 threading functions (w/ GNU name mangling) ---*/
3334 /*----------------------------------------------------------------*/
3340 QMutex::tryLock(int)
3342 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC1ENS_13RecursionModeE
3343 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC2ENS_13RecursionModeE
3344 QMutex::~QMutex() _ZN6QMutexD1Ev
3345 QMutex::~QMutex() _ZN6QMutexD2Ev
3348 QReadWriteLock::lockForRead()
3349 QReadWriteLock::lockForWrite()
3350 QReadWriteLock::unlock()
3351 QReadWriteLock::tryLockForRead(int)
3352 QReadWriteLock::tryLockForRead()
3353 QReadWriteLock::tryLockForWrite(int)
3354 QReadWriteLock::tryLockForWrite()
3356 QWaitCondition::wait(QMutex*, unsigned long)
3357 QWaitCondition::wakeAll()
3358 QWaitCondition::wakeOne()
3362 /* More comments, 19 Nov 08, based on assessment of qt-4.5.0TP1,
3365 It's apparently only necessary to intercept QMutex, since that is
3366 not implemented using pthread_mutex_t; instead Qt4 has its own
3367 implementation based on atomics (to check the non-contended case)
3368 and pthread_cond_wait (to wait in the contended case).
3370 QReadWriteLock is built on top of QMutex, counters, and a wait
3371 queue. So we don't need to handle it specially once QMutex
3372 handling is correct -- presumably the dependencies through QMutex
3373 are sufficient to avoid any false race reports. On the other hand,
3374 it is an open question whether too many dependencies are observed
3375 -- in which case we may miss races (false negatives). I suspect
3376 this is likely to be the case, unfortunately.
3378 QWaitCondition is built on pthread_cond_t, pthread_mutex_t, QMutex
3379 and QReadWriteLock. Same compositional-correctness justificiation
3380 and limitations as fro QReadWriteLock.
3382 Ditto QSemaphore (from cursory examination).
3384 Does it matter that only QMutex is handled directly? Open
3385 question. From testing with drd/tests/qt4_* and with KDE4 apps, it
3386 appears that no false errors are reported; however it is not clear
3387 if this is causing false negatives.
3389 Another problem with Qt4 is thread exiting. Threads are created
3390 with pthread_create (fine); but they detach and simply exit when
3391 done. There is no use of pthread_join, and the provided
3392 wait-for-a-thread-to-exit mechanism (QThread::wait, I believe)
3393 relies on a system of mutexes and flags. I suspect this also
3394 causes too many dependencies to appear. Consequently H sometimes
3395 fails to detect races at exit in some very short-lived racy
3396 programs, because it appears that a thread can exit _and_ have an
3397 observed dependency edge back to the main thread (presumably)
3398 before the main thread reaps the child (that is, calls
3401 This theory is supported by the observation that if all threads are
3402 made to wait at a pthread_barrier_t immediately before they exit,
3403 then H's detection of races in such programs becomes reliable;
3404 without the barrier, it is varies from run to run, depending
3405 (according to investigation) on whether aforementioned
3406 exit-before-reaping behaviour happens or not.
3408 Finally, why is it necessary to intercept the QMutex constructors
3409 and destructors? The constructors are intercepted only as a matter
3410 of convenience, so H can print accurate "first observed at"
3411 clauses. However, it is actually necessary to intercept the
3412 destructors (as it is with pthread_mutex_destroy) in order that
3413 locks get removed from LAOG when they are destroyed.
3416 // soname is libQtCore.so.4 ; match against libQtCore.so*
3417 #define QT4_FUNC(ret_ty, f, args...) \
3418 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args); \
3419 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args)
3421 // soname is libQt5Core.so.4 ; match against libQt5Core.so*
3422 #define QT5_FUNC(ret_ty, f, args...) \
3423 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args); \
3424 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args)
3426 //-----------------------------------------------------------
3428 __attribute__((noinline
))
3429 static void QMutex_lock_WRK(void* self
)
3432 VALGRIND_GET_ORIG_FN(fn
);
3433 if (TRACE_QT4_FNS
) {
3434 fprintf(stderr
, "<< QMutex::lock %p", self
); fflush(stderr
);
3437 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
3438 void*,self
, long,0/*!isTryLock*/);
3440 CALL_FN_v_W(fn
, self
);
3442 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
3443 void *, self
, long, True
);
3445 if (TRACE_QT4_FNS
) {
3446 fprintf(stderr
, " :: Q::lock done >>\n");
3450 QT4_FUNC(void, _ZN6QMutex4lockEv
, void* self
) {
3451 QMutex_lock_WRK(self
);
3453 QT5_FUNC(void, _ZN6QMutex4lockEv
, void* self
) {
3454 QMutex_lock_WRK(self
);
3457 //-----------------------------------------------------------
3459 __attribute__((noinline
))
3460 static void QMutex_unlock_WRK(void* self
)
3463 VALGRIND_GET_ORIG_FN(fn
);
3465 if (TRACE_QT4_FNS
) {
3466 fprintf(stderr
, "<< QMutex::unlock %p", self
); fflush(stderr
);
3469 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE
,
3472 CALL_FN_v_W(fn
, self
);
3474 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST
,
3477 if (TRACE_QT4_FNS
) {
3478 fprintf(stderr
, " Q::unlock done >>\n");
3482 QT4_FUNC(void, _ZN6QMutex6unlockEv
, void* self
) {
3483 QMutex_unlock_WRK(self
);
3485 QT5_FUNC(void, _ZN6QMutex6unlockEv
, void* self
) {
3486 QMutex_unlock_WRK(self
);
3489 //-----------------------------------------------------------
3490 // bool QMutex::tryLock()
3491 // using 'long' to mimic C++ 'bool'
3492 __attribute__((noinline
))
3493 static long QMutex_tryLock_WRK(void* self
)
3497 VALGRIND_GET_ORIG_FN(fn
);
3498 if (TRACE_QT4_FNS
) {
3499 fprintf(stderr
, "<< QMutex::tryLock %p", self
); fflush(stderr
);
3502 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
3503 void*,self
, long,1/*isTryLock*/);
3505 CALL_FN_W_W(ret
, fn
, self
);
3507 // assumes that only the low 8 bits of the 'bool' are significant
3508 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
3509 void *, self
, long, (ret
& 0xFF) ? True
: False
);
3511 if (TRACE_QT4_FNS
) {
3512 fprintf(stderr
, " :: Q::tryLock -> %lu >>\n", ret
);
3518 QT4_FUNC(long, _ZN6QMutex7tryLockEv
, void* self
) {
3519 return QMutex_tryLock_WRK(self
);
3521 QT5_FUNC(long, _ZN6QMutex7tryLockEv
, void* self
) {
3522 return QMutex_tryLock_WRK(self
);
3525 //-----------------------------------------------------------
3526 // bool QMutex::tryLock(int)
3527 // using 'long' to mimic C++ 'bool'
3528 __attribute__((noinline
))
3529 static long QMutex_tryLock_int_WRK(void* self
, long arg2
)
3533 VALGRIND_GET_ORIG_FN(fn
);
3534 if (TRACE_QT4_FNS
) {
3535 fprintf(stderr
, "<< QMutex::tryLock(int) %p %d", self
, (int)arg2
);
3539 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE
,
3540 void*,self
, long,1/*isTryLock*/);
3542 CALL_FN_W_WW(ret
, fn
, self
,arg2
);
3544 // assumes that only the low 8 bits of the 'bool' are significant
3545 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST
,
3546 void *, self
, long, (ret
& 0xFF) ? True
: False
);
3548 if (TRACE_QT4_FNS
) {
3549 fprintf(stderr
, " :: Q::tryLock(int) -> %lu >>\n", ret
);
3555 QT4_FUNC(long, _ZN6QMutex7tryLockEi
, void* self
, long arg2
) {
3556 return QMutex_tryLock_int_WRK(self
, arg2
);
3558 QT5_FUNC(long, _ZN6QMutex7tryLockEi
, void* self
, long arg2
) {
3559 return QMutex_tryLock_int_WRK(self
, arg2
);
3562 //-----------------------------------------------------------
3563 // It's not really very clear what the args are here. But from
3564 // a bit of dataflow analysis of the generated machine code of
3565 // the original function, it appears this takes two args, and
3566 // returns nothing. Nevertheless preserve return value just in
3567 // case. A bit of debug printing indicates that the first arg
3568 // is that of the mutex and the second is either zero or one,
3569 // probably being the recursion mode, therefore.
3570 // QMutex::QMutex(QMutex::RecursionMode) ("C1ENS" variant)
3571 __attribute__((noinline
))
3572 static void* QMutex_constructor_WRK(void* mutex
, long recmode
)
3576 VALGRIND_GET_ORIG_FN(fn
);
3577 CALL_FN_W_WW(ret
, fn
, mutex
, recmode
);
3578 // fprintf(stderr, "QMutex constructor 1: %p <- %p %p\n", ret, arg1, arg2);
3579 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST
,
3580 void*,mutex
, long,1/*mbRec*/);
3584 QT4_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE
, void* self
, long recmode
) {
3585 return QMutex_constructor_WRK(self
, recmode
);
3587 QT5_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE
, void* self
, long recmode
) {
3588 return QMutex_constructor_WRK(self
, recmode
);
3591 //-----------------------------------------------------------
3592 // QMutex::~QMutex() ("D1Ev" variant)
3593 __attribute__((noinline
))
3594 static void* QMutex_destructor_WRK(void* mutex
)
3598 VALGRIND_GET_ORIG_FN(fn
);
3599 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE
,
3601 CALL_FN_W_W(ret
, fn
, mutex
);
3605 QT4_FUNC(void*, _ZN6QMutexD1Ev
, void* self
) {
3606 return QMutex_destructor_WRK(self
);
3608 QT5_FUNC(void*, _ZN6QMutexD1Ev
, void* self
) {
3609 return QMutex_destructor_WRK(self
);
3612 //-----------------------------------------------------------
3613 // QMutex::QMutex(QMutex::RecursionMode) ("C2ENS" variant)
3614 QT4_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE
,
3620 /* Android's gcc behaves like it doesn't know that assert(0)
3621 never returns. Hence: */
3625 QT5_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE
, void* self
, long recmode
)
3632 //-----------------------------------------------------------
3633 // QMutex::~QMutex() ("D2Ev" variant)
3634 QT4_FUNC(void*, _ZN6QMutexD2Ev
, void* mutex
)
3637 /* Android's gcc behaves like it doesn't know that assert(0)
3638 never returns. Hence: */
3642 QT5_FUNC(void*, _ZN6QMutexD2Ev
, void* self
)
3649 // QReadWriteLock is not intercepted directly. See comments
3652 //// QReadWriteLock::lockForRead()
3653 //// _ZN14QReadWriteLock11lockForReadEv == QReadWriteLock::lockForRead()
3654 //QT4_FUNC(void, ZuZZN14QReadWriteLock11lockForReadEv,
3655 // // _ZN14QReadWriteLock11lockForReadEv
3659 // VALGRIND_GET_ORIG_FN(fn);
3660 // if (TRACE_QT4_FNS) {
3661 // fprintf(stderr, "<< QReadWriteLock::lockForRead %p", self);
3665 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
3667 // long,0/*!isW*/, long,0/*!isTryLock*/);
3669 // CALL_FN_v_W(fn, self);
3671 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
3672 // void*,self, long,0/*!isW*/, long, True);
3674 // if (TRACE_QT4_FNS) {
3675 // fprintf(stderr, " :: Q::lockForRead :: done >>\n");
3679 //// QReadWriteLock::lockForWrite()
3680 //// _ZN14QReadWriteLock12lockForWriteEv == QReadWriteLock::lockForWrite()
3681 //QT4_FUNC(void, ZuZZN14QReadWriteLock12lockForWriteEv,
3682 // // _ZN14QReadWriteLock12lockForWriteEv
3686 // VALGRIND_GET_ORIG_FN(fn);
3687 // if (TRACE_QT4_FNS) {
3688 // fprintf(stderr, "<< QReadWriteLock::lockForWrite %p", self);
3692 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
3694 // long,1/*isW*/, long,0/*!isTryLock*/);
3696 // CALL_FN_v_W(fn, self);
3698 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
3699 // void*,self, long,1/*isW*/, long, True);
3701 // if (TRACE_QT4_FNS) {
3702 // fprintf(stderr, " :: Q::lockForWrite :: done >>\n");
3706 //// QReadWriteLock::unlock()
3707 //// _ZN14QReadWriteLock6unlockEv == QReadWriteLock::unlock()
3708 //QT4_FUNC(void, ZuZZN14QReadWriteLock6unlockEv,
3709 // // _ZN14QReadWriteLock6unlockEv
3713 // VALGRIND_GET_ORIG_FN(fn);
3714 // if (TRACE_QT4_FNS) {
3715 // fprintf(stderr, "<< QReadWriteLock::unlock %p", self);
3719 // DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
3722 // CALL_FN_v_W(fn, self);
3724 // DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
3727 // if (TRACE_QT4_FNS) {
3728 // fprintf(stderr, " :: Q::unlock :: done >>\n");
3733 /*----------------------------------------------------------------*/
3734 /*--- Replacements for basic string functions, that don't ---*/
3735 /*--- overrun the input arrays. ---*/
3736 /*----------------------------------------------------------------*/
3738 #include "../shared/vg_replace_strmem.c"
3740 /*--------------------------------------------------------------------*/
3741 /*--- end hg_intercepts.c ---*/
3742 /*--------------------------------------------------------------------*/