linux x86 and amd64 memory protection key syscalls.
[valgrind.git] / helgrind / hg_intercepts.c
bloba10c3a4a3bff5f9dfb9c1fecd76e07fef5a47a31
2 /*--------------------------------------------------------------------*/
3 /*--- pthread intercepts for thread checking. ---*/
4 /*--- hg_intercepts.c ---*/
5 /*--------------------------------------------------------------------*/
7 /*
8 This file is part of Helgrind, a Valgrind tool for detecting errors
9 in threaded programs.
11 Copyright (C) 2007-2017 OpenWorks LLP
12 info@open-works.co.uk
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
43 doing something.
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"
56 #include "helgrind.h"
57 #include "config.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. */
66 #include <synch.h>
67 #include <thread.h>
68 #endif /* VGO_solaris */
71 #define TRACE_PTH_FNS 0
72 #define TRACE_QT4_FNS 0
73 #define TRACE_GNAT_FNS 0
76 /*----------------------------------------------------------------*/
77 /*--- ---*/
78 /*----------------------------------------------------------------*/
80 #if defined(VGO_solaris)
81 /* On Solaris, libpthread is just a filter library on top of libc.
82 * Threading and synchronization functions in runtime linker are not
83 * intercepted.
85 #define PTH_FUNC(ret_ty, f, args...) \
86 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)(args); \
87 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)(args)
89 /* pthread_t is typedef'd to 'unsigned int' but in DO_CREQ_* macros
90 sizeof(Word) is expected. */
91 #define CREQ_PTHREAD_T Word
92 #define SEM_ERROR ret
93 #else
94 #define PTH_FUNC(ret_ty, f, args...) \
95 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args); \
96 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args)
97 #define CREQ_PTHREAD_T pthread_t
98 #define SEM_ERROR errno
99 #endif /* VGO_solaris */
101 // Do a client request. These are macros rather than a functions so
102 // as to avoid having an extra frame in stack traces.
104 // NB: these duplicate definitions in helgrind.h. But here, we
105 // can have better typing (Word etc) and assertions, whereas
106 // in helgrind.h we can't. Obviously it's important the two
107 // sets of definitions are kept in sync.
109 // nuke the previous definitions
110 #undef DO_CREQ_v_W
111 #undef DO_CREQ_v_WW
112 #undef DO_CREQ_W_WW
113 #undef DO_CREQ_v_WWW
115 #define DO_CREQ_v_W(_creqF, _ty1F,_arg1F) \
116 do { \
117 Word _arg1; \
118 assert(sizeof(_ty1F) == sizeof(Word)); \
119 _arg1 = (Word)(_arg1F); \
120 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
121 _arg1, 0,0,0,0); \
122 } while (0)
124 #define DO_CREQ_v_WW(_creqF, _ty1F,_arg1F, _ty2F,_arg2F) \
125 do { \
126 Word _arg1, _arg2; \
127 assert(sizeof(_ty1F) == sizeof(Word)); \
128 assert(sizeof(_ty2F) == sizeof(Word)); \
129 _arg1 = (Word)(_arg1F); \
130 _arg2 = (Word)(_arg2F); \
131 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
132 _arg1,_arg2,0,0,0); \
133 } while (0)
135 #define DO_CREQ_W_WW(_resF, _creqF, _ty1F,_arg1F, \
136 _ty2F,_arg2F) \
137 do { \
138 Word _res, _arg1, _arg2; \
139 assert(sizeof(_ty1F) == sizeof(Word)); \
140 assert(sizeof(_ty2F) == sizeof(Word)); \
141 _arg1 = (Word)(_arg1F); \
142 _arg2 = (Word)(_arg2F); \
143 _res = VALGRIND_DO_CLIENT_REQUEST_EXPR(2, \
144 (_creqF), \
145 _arg1,_arg2,0,0,0); \
146 _resF = _res; \
147 } while (0)
149 #define DO_CREQ_v_WWW(_creqF, _ty1F,_arg1F, \
150 _ty2F,_arg2F, _ty3F, _arg3F) \
151 do { \
152 Word _arg1, _arg2, _arg3; \
153 assert(sizeof(_ty1F) == sizeof(Word)); \
154 assert(sizeof(_ty2F) == sizeof(Word)); \
155 assert(sizeof(_ty3F) == sizeof(Word)); \
156 _arg1 = (Word)(_arg1F); \
157 _arg2 = (Word)(_arg2F); \
158 _arg3 = (Word)(_arg3F); \
159 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
160 _arg1,_arg2,_arg3,0,0); \
161 } while (0)
163 #define DO_CREQ_v_WWWW(_creqF, _ty1F,_arg1F, \
164 _ty2F, _arg2F, _ty3F, _arg3F, \
165 _ty4F, _arg4F) \
166 do { \
167 Word _arg1, _arg2, _arg3, _arg4; \
168 assert(sizeof(_ty1F) == sizeof(Word)); \
169 assert(sizeof(_ty2F) == sizeof(Word)); \
170 assert(sizeof(_ty3F) == sizeof(Word)); \
171 assert(sizeof(_ty4F) == sizeof(Word)); \
172 _arg1 = (Word)(_arg1F); \
173 _arg2 = (Word)(_arg2F); \
174 _arg3 = (Word)(_arg3F); \
175 _arg4 = (Word)(_arg4F); \
176 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
177 _arg1,_arg2,_arg3,_arg4,0); \
178 } while (0)
180 #define DO_PthAPIerror(_fnnameF, _errF) \
181 do { \
182 const char* _fnname = (_fnnameF); \
183 long _err = (long)(int)(_errF); \
184 const char* _errstr = lame_strerror(_err); \
185 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTH_API_ERROR, \
186 char*,_fnname, \
187 long,_err, char*,_errstr); \
188 } while (0)
191 /* Needed for older glibcs (2.3 and older, at least) who don't
192 otherwise "know" about pthread_rwlock_anything or about
193 PTHREAD_MUTEX_RECURSIVE (amongst things). */
194 #define _GNU_SOURCE 1
196 #include <stdio.h>
197 #include <assert.h>
198 #include <errno.h>
199 #include <pthread.h>
201 /* A standalone memcmp. */
202 __attribute__((noinline))
203 static int my_memcmp ( const void* ptr1, const void* ptr2, size_t size)
205 const unsigned char* uchar_ptr1 = (const unsigned char*) ptr1;
206 const unsigned char* uchar_ptr2 = (const unsigned char*) ptr2;
207 size_t i;
208 for (i = 0; i < size; ++i) {
209 if (uchar_ptr1[i] != uchar_ptr2[i])
210 return (uchar_ptr1[i] < uchar_ptr2[i]) ? -1 : 1;
212 return 0;
215 /* A lame version of strerror which doesn't use the real libc
216 strerror_r, since using the latter just generates endless more
217 threading errors (glibc goes off and does tons of crap w.r.t.
218 locales etc) */
219 static const HChar* lame_strerror ( long err )
221 switch (err) {
222 case EPERM: return "EPERM: Operation not permitted";
223 case ENOENT: return "ENOENT: No such file or directory";
224 case ESRCH: return "ESRCH: No such process";
225 case EINTR: return "EINTR: Interrupted system call";
226 case EBADF: return "EBADF: Bad file number";
227 case EAGAIN: return "EAGAIN: Try again";
228 case ENOMEM: return "ENOMEM: Out of memory";
229 case EACCES: return "EACCES: Permission denied";
230 case EFAULT: return "EFAULT: Bad address";
231 case EEXIST: return "EEXIST: File exists";
232 case EINVAL: return "EINVAL: Invalid argument";
233 case EMFILE: return "EMFILE: Too many open files";
234 case ENOSYS: return "ENOSYS: Function not implemented";
235 case EOVERFLOW: return "EOVERFLOW: Value too large "
236 "for defined data type";
237 case EBUSY: return "EBUSY: Device or resource busy";
238 case ETIMEDOUT: return "ETIMEDOUT: Connection timed out";
239 case EDEADLK: return "EDEADLK: Resource deadlock would occur";
240 case EOPNOTSUPP: return "EOPNOTSUPP: Operation not supported on "
241 "transport endpoint"; /* honest, guv */
242 case ETIME: return "ETIME: Timer expired";
243 default: return "hg_intercepts.c: lame_strerror(): "
244 "unhandled case -- please fix me!";
248 #if defined(VGO_solaris)
250 * Solaris provides higher throughput, parallelism and scalability than other
251 * operating systems, at the cost of more fine-grained locking activity.
252 * This means for example that when a thread is created under Linux, just one
253 * big lock in glibc is used for all thread setup. Solaris libc uses several
254 * fine-grained locks and the creator thread resumes its activities as soon
255 * as possible, leaving for example stack and TLS setup activities to the
256 * created thread.
258 * This situation confuses Helgrind as it assumes there is some false ordering
259 * in place between creator and created thread; and therefore many types of
260 * race conditions in the application would not be reported. To prevent such
261 * false ordering, command line option --ignore-thread-creation is set to
262 * 'yes' by default on Solaris. All activity (loads, stores, client requests)
263 * is therefore ignored during:
264 * - pthread_create() call in the creator thread [libc.so]
265 * - thread creation phase (stack and TLS setup) in the created thread [libc.so]
267 * As explained in the comments for _ti_bind_guard(), whenever the runtime
268 * linker has to perform any activity (such as resolving a symbol), it protects
269 * its data structures by calling into rt_bind_guard() which in turn invokes
270 * _ti_bind_guard() in libc. Pointers to _ti_bind_guard() and _ti_bind_clear()
271 * are passed from libc to runtime linker in _ld_libc() call during libc_init().
272 * All activity is also ignored during:
273 * - runtime dynamic linker work between rt_bind_guard() and rt_bind_clear()
274 * calls [ld.so]
276 * This also means that Helgrind does not report race conditions in libc (when
277 * --ignore-thread-creation=yes) and runtime linker itself (unconditionally)
278 * during these ignored sequences.
281 #include "pub_tool_libcassert.h"
282 #include "pub_tool_vki.h"
285 * Original function pointers for _ti_bind_guard() and _ti_bind_clear()
286 * from libc. They are intercepted in function wrapper of _ld_libc().
288 typedef int (*hg_rtld_guard_fn)(int flags);
289 static hg_rtld_guard_fn hg_rtld_bind_guard = NULL;
290 static hg_rtld_guard_fn hg_rtld_bind_clear = NULL;
292 static void hg_init(void) __attribute__((constructor));
293 static void hg_init(void)
295 if ((hg_rtld_bind_guard == NULL) || (hg_rtld_bind_clear == NULL)) {
296 fprintf(stderr,
297 "Bind guard functions for the runtime linker (ld.so.1) were not intercepted.\n"
298 "This means the interface between libc and runtime linker changed\n"
299 "and Helgrind needs to be ported properly. Giving up.\n");
300 tl_assert(0);
305 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
306 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
307 * and CI_BIND_CLEAR, to provide resilience against function renaming.
309 static int _ti_bind_guard_intercept_WRK(int flags)
311 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_RTLD_BIND_GUARD,
312 flags, 0, 0, 0, 0);
313 return hg_rtld_bind_guard(flags);
316 static int _ti_bind_clear_intercept_WRK(int flags)
318 int ret = hg_rtld_bind_clear(flags);
319 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_RTLD_BIND_CLEAR,
320 flags, 0, 0, 0, 0);
321 return ret;
325 * Wrapped _ld_libc() from the runtime linker ld.so.1.
327 void I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr);
328 void I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr)
330 OrigFn fn;
331 int tag;
333 VALGRIND_GET_ORIG_FN(fn);
335 vki_Lc_interface *funcs = ptr;
336 for (tag = funcs->ci_tag; tag != 0; tag = (++funcs)->ci_tag) {
337 switch (tag) {
338 case VKI_CI_BIND_GUARD:
339 if (funcs->vki_ci_un.ci_func != _ti_bind_guard_intercept_WRK) {
340 hg_rtld_bind_guard = funcs->vki_ci_un.ci_func;
341 funcs->vki_ci_un.ci_func = _ti_bind_guard_intercept_WRK;
343 break;
344 case VKI_CI_BIND_CLEAR:
345 if (funcs->vki_ci_un.ci_func != _ti_bind_clear_intercept_WRK) {
346 hg_rtld_bind_clear = funcs->vki_ci_un.ci_func;
347 funcs->vki_ci_un.ci_func = _ti_bind_clear_intercept_WRK;
349 break;
353 CALL_FN_v_W(fn, ptr);
355 #endif /* VGO_solaris */
358 /*----------------------------------------------------------------*/
359 /*--- pthread_create, pthread_join, pthread_exit ---*/
360 /*----------------------------------------------------------------*/
362 static void* mythread_wrapper ( void* xargsV )
364 volatile Word* xargs = (volatile Word*) xargsV;
365 void*(*fn)(void*) = (void*(*)(void*))xargs[0];
366 void* arg = (void*)xargs[1];
367 pthread_t me = pthread_self();
368 /* Tell the tool what my pthread_t is. */
369 DO_CREQ_v_W(_VG_USERREQ__HG_SET_MY_PTHREAD_T, CREQ_PTHREAD_T, me);
370 /* allow the parent to proceed. We can't let it proceed until
371 we're ready because (1) we need to make sure it doesn't exit and
372 hence deallocate xargs[] while we still need it, and (2) we
373 don't want either parent nor child to proceed until the tool has
374 been notified of the child's pthread_t.
376 Note that parent and child access args[] without a lock,
377 effectively using args[2] as a spinlock in order to get the
378 parent to wait until the child passes this point. The parent
379 disables checking on xargs[] before creating the child and
380 re-enables it once the child goes past this point, so the user
381 never sees the race. The previous approach (suppressing the
382 resulting error) was flawed, because it could leave shadow
383 memory for args[] in a state in which subsequent use of it by
384 the parent would report further races. */
385 xargs[2] = 0;
386 /* Now we can no longer safely use xargs[]. */
387 return (void*) fn( (void*)arg );
390 //-----------------------------------------------------------
391 // glibc: pthread_create@GLIBC_2.0
392 // glibc: pthread_create@@GLIBC_2.1
393 // glibc: pthread_create@@GLIBC_2.2.5
394 // darwin: pthread_create
395 // darwin: pthread_create_suspended_np (trapped)
397 /* ensure this has its own frame, so as to make it more distinguishable
398 in suppressions */
399 __attribute__((noinline))
400 static int pthread_create_WRK(pthread_t *thread, const pthread_attr_t *attr,
401 void *(*start) (void *), void *arg)
403 int ret;
404 OrigFn fn;
405 volatile Word xargs[3];
407 VALGRIND_GET_ORIG_FN(fn);
408 if (TRACE_PTH_FNS) {
409 fprintf(stderr, "<< pthread_create wrapper"); fflush(stderr);
411 xargs[0] = (Word)start;
412 xargs[1] = (Word)arg;
413 xargs[2] = 1; /* serves as a spinlock -- sigh */
414 /* Disable checking on the spinlock and the two words used to
415 convey args to the child. Basically we need to make it appear
416 as if the child never accessed this area, since merely
417 suppressing the resulting races does not address the issue that
418 that piece of the parent's stack winds up in the "wrong" state
419 and therefore may give rise to mysterious races when the parent
420 comes to re-use this piece of stack in some other frame. */
421 VALGRIND_HG_DISABLE_CHECKING(&xargs, sizeof(xargs));
423 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_BEGIN,
424 0, 0, 0, 0, 0);
425 CALL_FN_W_WWWW(ret, fn, thread,attr,mythread_wrapper,&xargs[0]);
426 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_END,
427 0, 0, 0, 0, 0);
429 if (ret == 0) {
430 /* we have to wait for the child to notify the tool of its
431 pthread_t before continuing */
432 while (xargs[2] != 0) {
433 /* Do nothing. We need to spin until the child writes to
434 xargs[2]. However, that can lead to starvation in the
435 child and very long delays (eg, tc19_shadowmem on
436 ppc64-linux Fedora Core 6). So yield the cpu if we can,
437 to let the child run at the earliest available
438 opportunity. */
439 sched_yield();
441 } else {
442 DO_PthAPIerror( "pthread_create", ret );
445 /* Reenable checking on the area previously used to communicate
446 with the child. */
447 VALGRIND_HG_ENABLE_CHECKING(&xargs, sizeof(xargs));
449 if (TRACE_PTH_FNS) {
450 fprintf(stderr, " :: pth_create -> %d >>\n", ret);
452 return ret;
454 #if defined(VGO_linux)
455 PTH_FUNC(int, pthreadZucreateZAZa, // pthread_create@*
456 pthread_t *thread, const pthread_attr_t *attr,
457 void *(*start) (void *), void *arg) {
458 return pthread_create_WRK(thread, attr, start, arg);
460 #elif defined(VGO_darwin)
461 PTH_FUNC(int, pthreadZucreate, // pthread_create
462 pthread_t *thread, const pthread_attr_t *attr,
463 void *(*start) (void *), void *arg) {
464 return pthread_create_WRK(thread, attr, start, arg);
466 PTH_FUNC(int, pthreadZucreateZuZa, // pthread_create_*
467 pthread_t *thread, const pthread_attr_t *attr,
468 void *(*start) (void *), void *arg) {
469 // trap anything else
470 assert(0);
472 #elif defined(VGO_solaris)
473 PTH_FUNC(int, pthreadZucreate, // pthread_create
474 pthread_t *thread, const pthread_attr_t *attr,
475 void *(*start) (void *), void *arg) {
476 return pthread_create_WRK(thread, attr, start, arg);
478 #else
479 # error "Unsupported OS"
480 #endif
482 #if defined(VGO_solaris)
483 /* Solaris also provides thr_create() in addition to pthread_create().
484 * Both pthread_create(3C) and thr_create(3C) are based on private
485 * _thrp_create().
487 __attribute__((noinline))
488 static int thr_create_WRK(void *stk, size_t stksize, void *(*start)(void *),
489 void *arg, long flags, thread_t *new_thread)
491 int ret;
492 OrigFn fn;
493 volatile Word xargs[3];
495 VALGRIND_GET_ORIG_FN(fn);
496 if (TRACE_PTH_FNS) {
497 fprintf(stderr, "<< thr_create wrapper"); fflush(stderr);
499 xargs[0] = (Word)start;
500 xargs[1] = (Word)arg;
501 xargs[2] = 1; /* serves as a spinlock -- sigh */
502 /* See comments in pthread_create_WRK() */
503 VALGRIND_HG_DISABLE_CHECKING(&xargs, sizeof(xargs));
505 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_BEGIN,
506 0, 0, 0, 0, 0);
507 CALL_FN_W_6W(ret, fn, stk, stksize, mythread_wrapper, start, flags,
508 new_thread);
509 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_END,
510 0, 0, 0, 0, 0);
512 if (ret == 0) {
513 while (xargs[2] != 0) {
514 /* See comments in pthread_create_WRK(). */
515 sched_yield();
517 } else {
518 DO_PthAPIerror("thr_create", ret);
521 VALGRIND_HG_ENABLE_CHECKING(&xargs, sizeof(xargs));
523 if (TRACE_PTH_FNS) {
524 fprintf(stderr, " :: thr_create -> %d >>\n", ret);
526 return ret;
528 PTH_FUNC(int, thrZucreate, // thr_create
529 void *stk, size_t stksize, void *(*start)(void *),
530 void *arg, long flags, thread_t *new_thread) {
531 return thr_create_WRK(stk, stksize, start, arg, flags, new_thread);
533 #endif /* VGO_solaris */
536 //-----------------------------------------------------------
537 // glibc: pthread_join
538 // darwin: pthread_join
539 // darwin: pthread_join$NOCANCEL$UNIX2003
540 // darwin pthread_join$UNIX2003
541 __attribute__((noinline))
542 static int pthread_join_WRK(pthread_t thread, void** value_pointer)
544 int ret;
545 OrigFn fn;
546 VALGRIND_GET_ORIG_FN(fn);
547 if (TRACE_PTH_FNS) {
548 fprintf(stderr, "<< pthread_join wrapper"); fflush(stderr);
551 CALL_FN_W_WW(ret, fn, thread,value_pointer);
553 /* At least with NPTL as the thread library, this is safe because
554 it is guaranteed (by NPTL) that the joiner will completely gone
555 before pthread_join (the original) returns. See email below.*/
556 if (ret == 0 /*success*/) {
557 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST, CREQ_PTHREAD_T, thread);
558 } else {
559 DO_PthAPIerror( "pthread_join", ret );
562 if (TRACE_PTH_FNS) {
563 fprintf(stderr, " :: pth_join -> %d >>\n", ret);
565 return ret;
567 #if defined(VGO_linux)
568 PTH_FUNC(int, pthreadZujoin, // pthread_join
569 pthread_t thread, void** value_pointer) {
570 return pthread_join_WRK(thread, value_pointer);
572 #elif defined(VGO_darwin)
573 PTH_FUNC(int, pthreadZujoinZa, // pthread_join*
574 pthread_t thread, void** value_pointer) {
575 return pthread_join_WRK(thread, value_pointer);
577 #elif defined(VGO_solaris)
578 PTH_FUNC(int, pthreadZujoin, // pthread_join
579 pthread_t thread, void** value_pointer) {
580 return pthread_join_WRK(thread, value_pointer);
582 #else
583 # error "Unsupported OS"
584 #endif
587 /* Behaviour of pthread_join on NPTL:
590 I have a question re the NPTL pthread_join implementation.
592 Suppose I am the thread 'stayer'.
594 If I call pthread_join(quitter), is it guaranteed that the
595 thread 'quitter' has really exited before pthread_join returns?
597 IOW, is it guaranteed that 'quitter' will not execute any further
598 instructions after pthread_join returns?
600 I believe this is true based on the following analysis of
601 glibc-2.5 sources. However am not 100% sure and would appreciate
602 confirmation.
604 'quitter' will be running start_thread() in nptl/pthread_create.c
606 The last action of start_thread() is to exit via
607 __exit_thread_inline(0), which simply does sys_exit
608 (nptl/pthread_create.c:403)
610 'stayer' meanwhile is waiting for lll_wait_tid (pd->tid)
611 (call at nptl/pthread_join.c:89)
613 As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
614 lll_wait_tid will not return until kernel notifies via futex
615 wakeup that 'quitter' has terminated.
617 Hence pthread_join cannot return until 'quitter' really has
618 completely disappeared.
620 Drepper:
621 > As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
622 > lll_wait_tid will not return until kernel notifies via futex
623 > wakeup that 'quitter' has terminated.
624 That's the key. The kernel resets the TID field after the thread is
625 done. No way the joiner can return before the thread is gone.
628 #if defined(VGO_solaris)
629 /* Solaris also provides thr_join() in addition to pthread_join().
630 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
632 * :TODO: No functionality is currently provided for joinee == 0 and departed.
633 * This would require another client request, of course.
635 __attribute__((noinline))
636 static int thr_join_WRK(thread_t joinee, thread_t *departed, void **thread_return)
638 int ret;
639 OrigFn fn;
640 VALGRIND_GET_ORIG_FN(fn);
641 if (TRACE_PTH_FNS) {
642 fprintf(stderr, "<< thr_join wrapper"); fflush(stderr);
645 CALL_FN_W_WWW(ret, fn, joinee, departed, thread_return);
647 if (ret == 0 /*success*/) {
648 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST, CREQ_PTHREAD_T, joinee);
649 } else {
650 DO_PthAPIerror("thr_join", ret);
653 if (TRACE_PTH_FNS) {
654 fprintf(stderr, " :: thr_join -> %d >>\n", ret);
656 return ret;
658 PTH_FUNC(int, thrZujoin, // thr_join
659 thread_t joinee, thread_t *departed, void **thread_return) {
660 return thr_join_WRK(joinee, departed, thread_return);
662 #endif /* VGO_solaris */
665 //-----------------------------------------------------------
666 // Ada gcc gnat runtime:
667 // The gnat gcc Ada runtime does not use pthread_join. Instead, it uses
668 // a combination of other pthread primitives to ensure a child thread
669 // is gone. This combination is somewhat functionally equivalent to a
670 // pthread_join.
671 // We wrap two hook procedures called by the gnat gcc Ada runtime
672 // that allows helgrind to understand the semantic of Ada task dependencies
673 // and termination.
674 // procedure Master_Hook
675 // (Dependent : Task_Id;
676 // Parent : Task_Id;
677 // Master_Level : Integer);
678 // where type Task_Id is access all Ada_Task_Control_Block;
679 // System.Tasking.Debug.Master_Hook is called by a task Dependent to
680 // indicate that its master is identified by master+master_level.
681 void I_WRAP_SONAME_FNNAME_ZU
682 (Za,
683 system__tasking__debug__master_hook)
684 (void *dependent, void *master, int master_level);
685 void I_WRAP_SONAME_FNNAME_ZU
686 (Za,
687 system__tasking__debug__master_hook)
688 (void *dependent, void *master, int master_level)
690 OrigFn fn;
691 VALGRIND_GET_ORIG_FN(fn);
692 if (TRACE_GNAT_FNS) {
693 fprintf(stderr, "<< GNAT master_hook wrapper "
694 "dependent %p master %p master_level %d\n",
695 dependent, master, master_level); fflush(stderr);
698 // We call the wrapped function, even if it is a null body.
699 CALL_FN_v_WWW(fn, dependent, master, master_level);
701 DO_CREQ_v_WWW(_VG_USERREQ__HG_GNAT_MASTER_HOOK,
702 void*,dependent, void*,master,
703 Word, (Word)master_level);
705 if (TRACE_GNAT_FNS) {
706 fprintf(stderr, " :: GNAT master_hook >>\n");
710 // System.Tasking.Debug.Master_Completed_Hook is called by a task to
711 // indicate that it has completed a master.
712 // procedure Master_Completed_Hook
713 // (Self_ID : Task_Id;
714 // Master_Level : Integer);
715 // where type Task_Id is access all Ada_Task_Control_Block;
716 // This indicates that all its Dependent tasks (that identified themselves
717 // with the Master_Hook call) are terminated. Helgrind can consider
718 // at this point that the equivalent of a 'pthread_join' has been done
719 // between self_id and all dependent tasks at master_level.
720 void I_WRAP_SONAME_FNNAME_ZU
721 (Za,
722 system__tasking__debug__master_completed_hook)
723 (void *self_id, int master_level);
724 void I_WRAP_SONAME_FNNAME_ZU
725 (Za,
726 system__tasking__debug__master_completed_hook)
727 (void *self_id, int master_level)
729 OrigFn fn;
730 VALGRIND_GET_ORIG_FN(fn);
731 if (TRACE_GNAT_FNS) {
732 fprintf(stderr, "<< GNAT master_completed_hook wrapper "
733 "self_id %p master_level %d\n",
734 self_id, master_level); fflush(stderr);
737 // We call the wrapped function, even if it is a null body.
738 CALL_FN_v_WW(fn, self_id, master_level);
740 DO_CREQ_v_WW(_VG_USERREQ__HG_GNAT_MASTER_COMPLETED_HOOK,
741 void*,self_id, Word,(Word)master_level);
743 if (TRACE_GNAT_FNS) {
744 fprintf(stderr, " :: GNAT master_completed_hook >>\n");
748 /*----------------------------------------------------------------*/
749 /*--- pthread_mutex_t functions ---*/
750 /*----------------------------------------------------------------*/
752 /* Handled: pthread_mutex_init pthread_mutex_destroy
753 pthread_mutex_lock
754 pthread_mutex_trylock pthread_mutex_timedlock
755 pthread_mutex_unlock
758 //-----------------------------------------------------------
759 #if !defined(VGO_solaris)
760 // glibc: pthread_mutex_init
761 // darwin: pthread_mutex_init
762 PTH_FUNC(int, pthreadZumutexZuinit, // pthread_mutex_init
763 pthread_mutex_t *mutex,
764 pthread_mutexattr_t* attr)
766 int ret;
767 long mbRec;
768 OrigFn fn;
769 VALGRIND_GET_ORIG_FN(fn);
770 if (TRACE_PTH_FNS) {
771 fprintf(stderr, "<< pthread_mxinit %p", mutex); fflush(stderr);
774 mbRec = 0;
775 if (attr) {
776 int ty, zzz;
777 zzz = pthread_mutexattr_gettype(attr, &ty);
778 if (zzz == 0 && ty == PTHREAD_MUTEX_RECURSIVE)
779 mbRec = 1;
782 CALL_FN_W_WW(ret, fn, mutex,attr);
784 if (ret == 0 /*success*/) {
785 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
786 pthread_mutex_t*,mutex, long,mbRec);
787 } else {
788 DO_PthAPIerror( "pthread_mutex_init", ret );
791 if (TRACE_PTH_FNS) {
792 fprintf(stderr, " :: mxinit -> %d >>\n", ret);
794 return ret;
797 #else /* VGO_solaris */
799 // Solaris: mutex_init (pthread_mutex_init calls here)
800 PTH_FUNC(int, mutexZuinit, // mutex_init
801 mutex_t *mutex, int type, void *arg)
803 int ret;
804 long mbRec;
805 OrigFn fn;
806 VALGRIND_GET_ORIG_FN(fn);
807 if (TRACE_PTH_FNS) {
808 fprintf(stderr, "<< mxinit %p", mutex); fflush(stderr);
811 mbRec = ((type & LOCK_RECURSIVE) != 0) ? 1 : 0;
813 CALL_FN_W_WWW(ret, fn, mutex, type, arg);
815 if (ret == 0 /*success*/) {
816 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
817 mutex_t *, mutex, long, mbRec);
818 } else {
819 DO_PthAPIerror("mutex_init", ret);
822 if (TRACE_PTH_FNS) {
823 fprintf(stderr, " :: mxinit -> %d >>\n", ret);
825 return ret;
827 #endif /* VGO_solaris */
830 //-----------------------------------------------------------
831 // glibc: pthread_mutex_destroy
832 // darwin: pthread_mutex_destroy
833 // Solaris: mutex_destroy (pthread_mutex_destroy is a weak alias)
834 __attribute__((noinline))
835 static int mutex_destroy_WRK(pthread_mutex_t *mutex)
837 int ret;
838 unsigned long mutex_is_init;
839 OrigFn fn;
841 VALGRIND_GET_ORIG_FN(fn);
842 if (TRACE_PTH_FNS) {
843 fprintf(stderr, "<< pthread_mxdestroy %p", mutex); fflush(stderr);
846 if (mutex != NULL) {
847 static const pthread_mutex_t mutex_init = PTHREAD_MUTEX_INITIALIZER;
848 mutex_is_init = my_memcmp(mutex, &mutex_init, sizeof(*mutex)) == 0;
849 } else {
850 mutex_is_init = 0;
853 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
854 pthread_mutex_t*, mutex, unsigned long, mutex_is_init);
856 CALL_FN_W_W(ret, fn, mutex);
858 if (ret != 0) {
859 DO_PthAPIerror( "pthread_mutex_destroy", ret );
862 if (TRACE_PTH_FNS) {
863 fprintf(stderr, " :: mxdestroy -> %d >>\n", ret);
865 return ret;
868 #if defined(VGO_linux) || defined(VGO_darwin)
869 PTH_FUNC(int, pthreadZumutexZudestroy, // pthread_mutex_destroy
870 pthread_mutex_t *mutex) {
871 return mutex_destroy_WRK(mutex);
873 #elif defined(VGO_solaris)
874 PTH_FUNC(int, mutexZudestroy, // mutex_destroy
875 pthread_mutex_t *mutex) {
876 return mutex_destroy_WRK(mutex);
878 #else
879 # error "Unsupported OS"
880 #endif
883 //-----------------------------------------------------------
884 // glibc: pthread_mutex_lock
885 // darwin: pthread_mutex_lock
886 // Solaris: mutex_lock (pthread_mutex_lock is a weak alias)
887 __attribute__((noinline))
888 static int mutex_lock_WRK(pthread_mutex_t *mutex)
890 int ret;
891 OrigFn fn;
892 VALGRIND_GET_ORIG_FN(fn);
893 if (TRACE_PTH_FNS) {
894 fprintf(stderr, "<< pthread_mxlock %p", mutex); fflush(stderr);
897 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
898 pthread_mutex_t*,mutex, long,0/*!isTryLock*/);
900 CALL_FN_W_W(ret, fn, mutex);
902 /* There's a hole here: libpthread now knows the lock is locked,
903 but the tool doesn't, so some other thread could run and detect
904 that the lock has been acquired by someone (this thread). Does
905 this matter? Not sure, but I don't think so. */
907 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
908 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
910 if (ret != 0) {
911 DO_PthAPIerror( "pthread_mutex_lock", ret );
914 if (TRACE_PTH_FNS) {
915 fprintf(stderr, " :: mxlock -> %d >>\n", ret);
917 return ret;
920 #if defined(VGO_linux) || defined(VGO_darwin)
921 PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock
922 pthread_mutex_t *mutex) {
923 return mutex_lock_WRK(mutex);
925 #elif defined(VGO_solaris)
926 PTH_FUNC(int, mutexZulock, // mutex_lock
927 pthread_mutex_t *mutex) {
928 return mutex_lock_WRK(mutex);
930 #else
931 # error "Unsupported OS"
932 #endif
934 #if defined(VGO_solaris)
935 /* Internal to libc. Mutex is usually initialized only implicitly,
936 * by zeroing mutex_t structure.
938 __attribute__((noinline))
939 PTH_FUNC(void, lmutexZulock, // lmutex_lock
940 mutex_t *mutex)
942 OrigFn fn;
943 VALGRIND_GET_ORIG_FN(fn);
944 if (TRACE_PTH_FNS) {
945 fprintf(stderr, "<< lmxlock %p", mutex); fflush(stderr);
948 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
949 mutex_t *, mutex, long, 0 /*!isTryLock*/);
950 CALL_FN_v_W(fn, mutex);
951 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
952 mutex_t *, mutex, long, True);
954 if (TRACE_PTH_FNS) {
955 fprintf(stderr, " :: lmxlock >>\n");
958 #endif /* VGO_solaris */
961 //-----------------------------------------------------------
962 // glibc: pthread_mutex_trylock
963 // darwin: pthread_mutex_trylock
964 // Solaris: mutex_trylock (pthread_mutex_trylock is a weak alias)
966 // pthread_mutex_trylock. The handling needed here is very similar
967 // to that for pthread_mutex_lock, except that we need to tell
968 // the pre-lock creq that this is a trylock-style operation, and
969 // therefore not to complain if the lock is nonrecursive and
970 // already locked by this thread -- because then it'll just fail
971 // immediately with EBUSY.
972 __attribute__((noinline))
973 static int mutex_trylock_WRK(pthread_mutex_t *mutex)
975 int ret;
976 OrigFn fn;
977 VALGRIND_GET_ORIG_FN(fn);
978 if (TRACE_PTH_FNS) {
979 fprintf(stderr, "<< pthread_mxtrylock %p", mutex); fflush(stderr);
982 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
983 pthread_mutex_t*,mutex, long,1/*isTryLock*/);
985 CALL_FN_W_W(ret, fn, mutex);
987 /* There's a hole here: libpthread now knows the lock is locked,
988 but the tool doesn't, so some other thread could run and detect
989 that the lock has been acquired by someone (this thread). Does
990 this matter? Not sure, but I don't think so. */
992 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
993 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
995 if (ret != 0) {
996 if (ret != EBUSY)
997 DO_PthAPIerror( "pthread_mutex_trylock", ret );
1000 if (TRACE_PTH_FNS) {
1001 fprintf(stderr, " :: mxtrylock -> %d >>\n", ret);
1003 return ret;
1006 #if defined(VGO_linux) || defined(VGO_darwin)
1007 PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock
1008 pthread_mutex_t *mutex) {
1009 return mutex_trylock_WRK(mutex);
1011 #elif defined(VGO_solaris)
1012 PTH_FUNC(int, mutexZutrylock, // mutex_trylock
1013 pthread_mutex_t *mutex) {
1014 return mutex_trylock_WRK(mutex);
1016 #else
1017 # error "Unsupported OS"
1018 #endif
1021 //-----------------------------------------------------------
1022 // glibc: pthread_mutex_timedlock
1023 // darwin: (doesn't appear to exist)
1024 // Solaris: pthread_mutex_timedlock
1026 // pthread_mutex_timedlock. Identical logic to pthread_mutex_trylock.
1027 __attribute__((noinline))
1028 static int mutex_timedlock_WRK(pthread_mutex_t *mutex,
1029 void *timeout)
1031 int ret;
1032 OrigFn fn;
1033 VALGRIND_GET_ORIG_FN(fn);
1034 if (TRACE_PTH_FNS) {
1035 fprintf(stderr, "<< pthread_mxtimedlock %p %p", mutex, timeout);
1036 fflush(stderr);
1039 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
1040 pthread_mutex_t*,mutex, long,1/*isTryLock-ish*/);
1042 CALL_FN_W_WW(ret, fn, mutex,timeout);
1044 /* There's a hole here: libpthread now knows the lock is locked,
1045 but the tool doesn't, so some other thread could run and detect
1046 that the lock has been acquired by someone (this thread). Does
1047 this matter? Not sure, but I don't think so. */
1049 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1050 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
1052 if (ret != 0) {
1053 if (ret != ETIMEDOUT)
1054 DO_PthAPIerror( "pthread_mutex_timedlock", ret );
1057 if (TRACE_PTH_FNS) {
1058 fprintf(stderr, " :: mxtimedlock -> %d >>\n", ret);
1060 return ret;
1063 PTH_FUNC(int, pthreadZumutexZutimedlock, // pthread_mutex_timedlock
1064 pthread_mutex_t *mutex,
1065 void *timeout) {
1066 return mutex_timedlock_WRK(mutex, timeout);
1068 #if defined(VGO_solaris)
1069 PTH_FUNC(int, pthreadZumutexZureltimedlock, // pthread_mutex_reltimedlock
1070 pthread_mutex_t *mutex,
1071 void *timeout) {
1072 return mutex_timedlock_WRK(mutex, timeout);
1074 #endif
1077 //-----------------------------------------------------------
1078 // glibc: pthread_mutex_unlock
1079 // darwin: pthread_mutex_unlock
1080 // Solaris: mutex_unlock (pthread_mutex_unlock is a weak alias)
1081 __attribute__((noinline))
1082 static int mutex_unlock_WRK(pthread_mutex_t *mutex)
1084 int ret;
1085 OrigFn fn;
1086 VALGRIND_GET_ORIG_FN(fn);
1088 if (TRACE_PTH_FNS) {
1089 fprintf(stderr, "<< pthread_mxunlk %p", mutex); fflush(stderr);
1092 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1093 pthread_mutex_t*,mutex);
1095 CALL_FN_W_W(ret, fn, mutex);
1097 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
1098 pthread_mutex_t*,mutex);
1100 if (ret != 0) {
1101 DO_PthAPIerror( "pthread_mutex_unlock", ret );
1104 if (TRACE_PTH_FNS) {
1105 fprintf(stderr, " mxunlk -> %d >>\n", ret);
1107 return ret;
1110 #if defined(VGO_linux) || defined(VGO_darwin)
1111 PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock
1112 pthread_mutex_t *mutex) {
1113 return mutex_unlock_WRK(mutex);
1115 #elif defined(VGO_solaris)
1116 PTH_FUNC(int, mutexZuunlock, // mutex_unlock
1117 pthread_mutex_t *mutex) {
1118 return mutex_unlock_WRK(mutex);
1120 #else
1121 # error "Unsupported OS"
1122 #endif
1125 #if defined(VGO_solaris)
1126 /* Internal to libc. */
1127 __attribute__((noinline))
1128 PTH_FUNC(void, lmutexZuunlock, // lmutex_unlock
1129 mutex_t *mutex)
1131 OrigFn fn;
1132 VALGRIND_GET_ORIG_FN(fn);
1134 if (TRACE_PTH_FNS) {
1135 fprintf(stderr, "<< lmxunlk %p", mutex); fflush(stderr);
1138 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1139 mutex_t *, mutex);
1140 CALL_FN_v_W(fn, mutex);
1141 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
1142 mutex_t*, mutex);
1144 if (TRACE_PTH_FNS) {
1145 fprintf(stderr, " lmxunlk >>\n");
1148 #endif /* VGO_solaris */
1151 /*----------------------------------------------------------------*/
1152 /*--- pthread_cond_t functions ---*/
1153 /*----------------------------------------------------------------*/
1155 /* Handled: pthread_cond_wait pthread_cond_timedwait
1156 pthread_cond_signal pthread_cond_broadcast
1157 pthread_cond_init
1158 pthread_cond_destroy
1161 //-----------------------------------------------------------
1162 // glibc: pthread_cond_wait@GLIBC_2.2.5
1163 // glibc: pthread_cond_wait@@GLIBC_2.3.2
1164 // darwin: pthread_cond_wait
1165 // darwin: pthread_cond_wait$NOCANCEL$UNIX2003
1166 // darwin: pthread_cond_wait$UNIX2003
1167 // Solaris: cond_wait (pthread_cond_wait is built atop of cond_wait)
1169 __attribute__((noinline))
1170 static int pthread_cond_wait_WRK(pthread_cond_t* cond,
1171 pthread_mutex_t* mutex)
1173 int ret;
1174 OrigFn fn;
1175 unsigned long mutex_is_valid;
1177 VALGRIND_GET_ORIG_FN(fn);
1179 if (TRACE_PTH_FNS) {
1180 fprintf(stderr, "<< pthread_cond_wait %p %p", cond, mutex);
1181 fflush(stderr);
1184 /* Tell the tool a cond-wait is about to happen, so it can check
1185 for bogus argument values. In return it tells us whether it
1186 thinks the mutex is valid or not. */
1187 DO_CREQ_W_WW(mutex_is_valid,
1188 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
1189 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
1190 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
1192 /* Tell the tool we're about to drop the mutex. This reflects the
1193 fact that in a cond_wait, we show up holding the mutex, and the
1194 call atomically drops the mutex and waits for the cv to be
1195 signalled. */
1196 if (mutex_is_valid) {
1197 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1198 pthread_mutex_t*,mutex);
1201 CALL_FN_W_WW(ret, fn, cond,mutex);
1203 /* this conditional look stupid, but compare w/ same logic for
1204 pthread_cond_timedwait below */
1205 if (mutex_is_valid) {
1206 /* and now we have the mutex again if (ret == 0) */
1207 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1208 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
1211 DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
1212 pthread_cond_t*,cond, pthread_mutex_t*,mutex, long,0,
1213 long, (ret == 0 && mutex_is_valid) ? True : False);
1215 if (ret != 0) {
1216 DO_PthAPIerror( "pthread_cond_wait", ret );
1219 if (TRACE_PTH_FNS) {
1220 fprintf(stderr, " cowait -> %d >>\n", ret);
1223 return ret;
1225 #if defined(VGO_linux)
1226 PTH_FUNC(int, pthreadZucondZuwaitZAZa, // pthread_cond_wait@*
1227 pthread_cond_t* cond, pthread_mutex_t* mutex) {
1228 return pthread_cond_wait_WRK(cond, mutex);
1230 #elif defined(VGO_darwin)
1231 PTH_FUNC(int, pthreadZucondZuwaitZa, // pthread_cond_wait*
1232 pthread_cond_t* cond, pthread_mutex_t* mutex) {
1233 return pthread_cond_wait_WRK(cond, mutex);
1235 #elif defined(VGO_solaris)
1236 PTH_FUNC(int, condZuwait, // cond_wait
1237 pthread_cond_t *cond, pthread_mutex_t *mutex) {
1238 return pthread_cond_wait_WRK(cond, mutex);
1240 #else
1241 # error "Unsupported OS"
1242 #endif
1245 //-----------------------------------------------------------
1246 // glibc: pthread_cond_timedwait@@GLIBC_2.3.2
1247 // glibc: pthread_cond_timedwait@GLIBC_2.2.5
1248 // glibc: pthread_cond_timedwait@GLIBC_2.0
1249 // darwin: pthread_cond_timedwait
1250 // darwin: pthread_cond_timedwait$NOCANCEL$UNIX2003
1251 // darwin: pthread_cond_timedwait$UNIX2003
1252 // darwin: pthread_cond_timedwait_relative_np (trapped)
1253 // Solaris: cond_timedwait (pthread_cond_timedwait is built on cond_timedwait)
1254 // Solaris: cond_reltimedwait (pthread_cond_reltimedwait_np is built on this)
1256 __attribute__((noinline))
1257 static int pthread_cond_timedwait_WRK(pthread_cond_t* cond,
1258 pthread_mutex_t* mutex,
1259 struct timespec* abstime,
1260 int timeout_error)
1262 int ret;
1263 OrigFn fn;
1264 unsigned long mutex_is_valid;
1265 Bool abstime_is_valid;
1266 VALGRIND_GET_ORIG_FN(fn);
1268 if (TRACE_PTH_FNS) {
1269 fprintf(stderr, "<< pthread_cond_timedwait %p %p %p",
1270 cond, mutex, abstime);
1271 fflush(stderr);
1274 /* Tell the tool a cond-wait is about to happen, so it can check
1275 for bogus argument values. In return it tells us whether it
1276 thinks the mutex is valid or not. */
1277 DO_CREQ_W_WW(mutex_is_valid,
1278 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
1279 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
1280 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
1282 abstime_is_valid = abstime->tv_nsec >= 0 && abstime->tv_nsec < 1000000000;
1284 /* Tell the tool we're about to drop the mutex. This reflects the
1285 fact that in a cond_wait, we show up holding the mutex, and the
1286 call atomically drops the mutex and waits for the cv to be
1287 signalled. */
1288 if (mutex_is_valid && abstime_is_valid) {
1289 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1290 pthread_mutex_t*,mutex);
1293 CALL_FN_W_WWW(ret, fn, cond,mutex,abstime);
1295 if (mutex_is_valid && !abstime_is_valid && ret != EINVAL) {
1296 DO_PthAPIerror("Bug in libpthread: pthread_cond_timedwait "
1297 "invalid abstime did not cause"
1298 " EINVAL", ret);
1301 if (mutex_is_valid && abstime_is_valid) {
1302 /* and now we have the mutex again if (ret == 0 || ret == timeout) */
1303 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1304 pthread_mutex_t *, mutex,
1305 long, (ret == 0 || ret == timeout_error) ? True : False);
1308 DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
1309 pthread_cond_t*,cond, pthread_mutex_t*,mutex,
1310 long,ret == timeout_error,
1311 long, (ret == 0 || ret == timeout_error) && mutex_is_valid
1312 ? True : False);
1314 if (ret != 0 && ret != timeout_error) {
1315 DO_PthAPIerror( "pthread_cond_timedwait", ret );
1318 if (TRACE_PTH_FNS) {
1319 fprintf(stderr, " cotimedwait -> %d >>\n", ret);
1322 return ret;
1324 #if defined(VGO_linux)
1325 PTH_FUNC(int, pthreadZucondZutimedwaitZAZa, // pthread_cond_timedwait@*
1326 pthread_cond_t* cond, pthread_mutex_t* mutex,
1327 struct timespec* abstime) {
1328 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
1330 #elif defined(VGO_darwin)
1331 PTH_FUNC(int, pthreadZucondZutimedwait, // pthread_cond_timedwait
1332 pthread_cond_t* cond, pthread_mutex_t* mutex,
1333 struct timespec* abstime) {
1334 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
1336 PTH_FUNC(int, pthreadZucondZutimedwaitZDZa, // pthread_cond_timedwait$*
1337 pthread_cond_t* cond, pthread_mutex_t* mutex,
1338 struct timespec* abstime) {
1339 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
1341 PTH_FUNC(int, pthreadZucondZutimedwaitZuZa, // pthread_cond_timedwait_*
1342 pthread_cond_t* cond, pthread_mutex_t* mutex,
1343 struct timespec* abstime) {
1344 assert(0);
1346 #elif defined(VGO_solaris)
1347 PTH_FUNC(int, condZutimedwait, // cond_timedwait
1348 pthread_cond_t *cond, pthread_mutex_t *mutex,
1349 struct timespec *abstime) {
1350 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIME);
1352 PTH_FUNC(int, condZureltimedwait, // cond_reltimedwait
1353 pthread_cond_t *cond, pthread_mutex_t *mutex,
1354 struct timespec *reltime) {
1355 return pthread_cond_timedwait_WRK(cond, mutex, reltime, ETIME);
1357 #else
1358 # error "Unsupported OS"
1359 #endif
1362 //-----------------------------------------------------------
1363 // glibc: pthread_cond_signal@GLIBC_2.0
1364 // glibc: pthread_cond_signal@GLIBC_2.2.5
1365 // glibc: pthread_cond_signal@@GLIBC_2.3.2
1366 // darwin: pthread_cond_signal
1367 // darwin: pthread_cond_signal_thread_np (don't intercept this)
1368 // Solaris: cond_signal (pthread_cond_signal is a weak alias)
1370 __attribute__((noinline))
1371 static int pthread_cond_signal_WRK(pthread_cond_t* cond)
1373 int ret;
1374 OrigFn fn;
1375 VALGRIND_GET_ORIG_FN(fn);
1377 if (TRACE_PTH_FNS) {
1378 fprintf(stderr, "<< pthread_cond_signal %p", cond);
1379 fflush(stderr);
1382 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE,
1383 pthread_cond_t*,cond);
1385 CALL_FN_W_W(ret, fn, cond);
1387 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_POST,
1388 pthread_cond_t*,cond);
1390 if (ret != 0) {
1391 DO_PthAPIerror( "pthread_cond_signal", ret );
1394 if (TRACE_PTH_FNS) {
1395 fprintf(stderr, " cosig -> %d >>\n", ret);
1398 return ret;
1400 #if defined(VGO_linux)
1401 PTH_FUNC(int, pthreadZucondZusignalZAZa, // pthread_cond_signal@*
1402 pthread_cond_t* cond) {
1403 return pthread_cond_signal_WRK(cond);
1405 #elif defined(VGO_darwin)
1406 PTH_FUNC(int, pthreadZucondZusignal, // pthread_cond_signal
1407 pthread_cond_t* cond) {
1408 return pthread_cond_signal_WRK(cond);
1410 #elif defined(VGO_solaris)
1411 PTH_FUNC(int, condZusignal, // cond_signal
1412 pthread_cond_t *cond) {
1413 return pthread_cond_signal_WRK(cond);
1415 #else
1416 # error "Unsupported OS"
1417 #endif
1420 //-----------------------------------------------------------
1421 // glibc: pthread_cond_broadcast@GLIBC_2.0
1422 // glibc: pthread_cond_broadcast@GLIBC_2.2.5
1423 // glibc: pthread_cond_broadcast@@GLIBC_2.3.2
1424 // darwin: pthread_cond_broadcast
1425 // Solaris: cond_broadcast (pthread_cond_broadcast is a weak alias)
1427 // Note, this is pretty much identical, from a dependency-graph
1428 // point of view, with cond_signal, so the code is duplicated.
1429 // Maybe it should be commoned up.
1431 __attribute__((noinline))
1432 static int pthread_cond_broadcast_WRK(pthread_cond_t* cond)
1434 int ret;
1435 OrigFn fn;
1436 VALGRIND_GET_ORIG_FN(fn);
1438 if (TRACE_PTH_FNS) {
1439 fprintf(stderr, "<< pthread_cond_broadcast %p", cond);
1440 fflush(stderr);
1443 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE,
1444 pthread_cond_t*,cond);
1446 CALL_FN_W_W(ret, fn, cond);
1448 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_POST,
1449 pthread_cond_t*,cond);
1451 if (ret != 0) {
1452 DO_PthAPIerror( "pthread_cond_broadcast", ret );
1455 if (TRACE_PTH_FNS) {
1456 fprintf(stderr, " cobro -> %d >>\n", ret);
1459 return ret;
1461 #if defined(VGO_linux)
1462 PTH_FUNC(int, pthreadZucondZubroadcastZAZa, // pthread_cond_broadcast@*
1463 pthread_cond_t* cond) {
1464 return pthread_cond_broadcast_WRK(cond);
1466 #elif defined(VGO_darwin)
1467 PTH_FUNC(int, pthreadZucondZubroadcast, // pthread_cond_broadcast
1468 pthread_cond_t* cond) {
1469 return pthread_cond_broadcast_WRK(cond);
1471 #elif defined(VGO_solaris)
1472 PTH_FUNC(int, condZubroadcast, // cond_broadcast
1473 pthread_cond_t *cond) {
1474 return pthread_cond_broadcast_WRK(cond);
1476 #else
1477 # error "Unsupported OS"
1478 #endif
1480 // glibc: pthread_cond_init@GLIBC_2.0
1481 // glibc: pthread_cond_init@GLIBC_2.2.5
1482 // glibc: pthread_cond_init@@GLIBC_2.3.2
1483 // darwin: pthread_cond_init
1484 // Solaris: cond_init (pthread_cond_init is built atop on this function)
1485 // Easy way out: Handling of attr could have been messier.
1486 // It turns out that pthread_cond_init under linux ignores
1487 // all information in cond_attr, so do we.
1488 // FIXME: MacOS X?
1489 #if !defined(VGO_solaris)
1490 __attribute__((noinline))
1491 static int pthread_cond_init_WRK(pthread_cond_t* cond, pthread_condattr_t *cond_attr)
1493 int ret;
1494 OrigFn fn;
1495 VALGRIND_GET_ORIG_FN(fn);
1497 if (TRACE_PTH_FNS) {
1498 fprintf(stderr, "<< pthread_cond_init %p", cond);
1499 fflush(stderr);
1502 CALL_FN_W_WW(ret, fn, cond, cond_attr);
1504 if (ret == 0) {
1505 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST,
1506 pthread_cond_t*,cond, pthread_condattr_t*, cond_attr);
1507 } else {
1508 DO_PthAPIerror( "pthread_cond_init", ret );
1511 if (TRACE_PTH_FNS) {
1512 fprintf(stderr, " coinit -> %d >>\n", ret);
1515 return ret;
1517 #if defined(VGO_linux)
1518 PTH_FUNC(int, pthreadZucondZuinitZAZa, // pthread_cond_init@*
1519 pthread_cond_t* cond, pthread_condattr_t* cond_attr) {
1520 return pthread_cond_init_WRK(cond, cond_attr);
1522 #elif defined(VGO_darwin)
1523 PTH_FUNC(int, pthreadZucondZuinit, // pthread_cond_init
1524 pthread_cond_t* cond, pthread_condattr_t * cond_attr) {
1525 return pthread_cond_init_WRK(cond, cond_attr);
1527 #else
1528 # error "Unsupported OS"
1529 #endif
1531 #else /* VGO_solaris */
1532 __attribute__((noinline))
1533 PTH_FUNC(int, condZuinit, // cond_init
1534 cond_t *cond, int type, void *arg)
1536 int ret;
1537 OrigFn fn;
1538 VALGRIND_GET_ORIG_FN(fn);
1540 if (TRACE_PTH_FNS) {
1541 fprintf(stderr, "<< cond_init %p", cond); fflush(stderr);
1544 CALL_FN_W_WWW(ret, fn, cond, type, arg);
1546 if (ret == 0) {
1547 /* Luckily evh__HG_PTHREAD_COND_INIT_POST() ignores cond_attr.
1548 See also comment for pthread_cond_init_WRK(). */
1549 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST,
1550 cond_t *, cond, void *, NULL);
1551 } else {
1552 DO_PthAPIerror("cond_init", ret);
1555 if (TRACE_PTH_FNS) {
1556 fprintf(stderr, " cond_init -> %d >>\n", ret);
1559 return ret;
1561 #endif /* VGO_solaris */
1564 //-----------------------------------------------------------
1565 // glibc: pthread_cond_destroy@@GLIBC_2.3.2
1566 // glibc: pthread_cond_destroy@GLIBC_2.2.5
1567 // glibc: pthread_cond_destroy@GLIBC_2.0
1568 // darwin: pthread_cond_destroy
1569 // Solaris: cond_destroy (pthread_cond_destroy is a weak alias)
1571 __attribute__((noinline))
1572 static int pthread_cond_destroy_WRK(pthread_cond_t* cond)
1574 int ret;
1575 unsigned long cond_is_init;
1576 OrigFn fn;
1578 VALGRIND_GET_ORIG_FN(fn);
1580 if (TRACE_PTH_FNS) {
1581 fprintf(stderr, "<< pthread_cond_destroy %p", cond);
1582 fflush(stderr);
1585 if (cond != NULL) {
1586 const pthread_cond_t cond_init = PTHREAD_COND_INITIALIZER;
1587 cond_is_init = my_memcmp(cond, &cond_init, sizeof(*cond)) == 0;
1588 } else {
1589 cond_is_init = 0;
1592 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_DESTROY_PRE,
1593 pthread_cond_t*, cond, unsigned long, cond_is_init);
1595 CALL_FN_W_W(ret, fn, cond);
1597 if (ret != 0) {
1598 DO_PthAPIerror( "pthread_cond_destroy", ret );
1601 if (TRACE_PTH_FNS) {
1602 fprintf(stderr, " codestr -> %d >>\n", ret);
1605 return ret;
1607 #if defined(VGO_linux)
1608 PTH_FUNC(int, pthreadZucondZudestroyZAZa, // pthread_cond_destroy@*
1609 pthread_cond_t* cond) {
1610 return pthread_cond_destroy_WRK(cond);
1612 #elif defined(VGO_darwin)
1613 PTH_FUNC(int, pthreadZucondZudestroy, // pthread_cond_destroy
1614 pthread_cond_t* cond) {
1615 return pthread_cond_destroy_WRK(cond);
1617 #elif defined(VGO_solaris)
1618 PTH_FUNC(int, condZudestroy, // cond_destroy
1619 pthread_cond_t *cond) {
1620 return pthread_cond_destroy_WRK(cond);
1622 #else
1623 # error "Unsupported OS"
1624 #endif
1627 /*----------------------------------------------------------------*/
1628 /*--- pthread_barrier_t functions ---*/
1629 /*----------------------------------------------------------------*/
1631 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1633 /* Handled: pthread_barrier_init
1634 pthread_barrier_wait
1635 pthread_barrier_destroy
1637 Unhandled: pthread_barrierattr_destroy
1638 pthread_barrierattr_getpshared
1639 pthread_barrierattr_init
1640 pthread_barrierattr_setpshared
1641 -- are these important?
1644 //-----------------------------------------------------------
1645 // glibc: pthread_barrier_init
1646 // darwin: (doesn't appear to exist)
1647 // Solaris: pthread_barrier_init
1648 PTH_FUNC(int, pthreadZubarrierZuinit, // pthread_barrier_init
1649 pthread_barrier_t* bar,
1650 pthread_barrierattr_t* attr, unsigned long count)
1652 int ret;
1653 OrigFn fn;
1654 VALGRIND_GET_ORIG_FN(fn);
1656 if (TRACE_PTH_FNS) {
1657 fprintf(stderr, "<< pthread_barrier_init %p %p %lu",
1658 bar, attr, count);
1659 fflush(stderr);
1662 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE,
1663 pthread_barrier_t*, bar,
1664 unsigned long, count,
1665 unsigned long, 0/*!resizable*/);
1667 CALL_FN_W_WWW(ret, fn, bar,attr,count);
1669 if (ret != 0) {
1670 DO_PthAPIerror( "pthread_barrier_init", ret );
1673 if (TRACE_PTH_FNS) {
1674 fprintf(stderr, " pthread_barrier_init -> %d >>\n", ret);
1677 return ret;
1681 //-----------------------------------------------------------
1682 // glibc: pthread_barrier_wait
1683 // darwin: (doesn't appear to exist)
1684 // Solaris: pthread_barrier_wait
1685 PTH_FUNC(int, pthreadZubarrierZuwait, // pthread_barrier_wait
1686 pthread_barrier_t* bar)
1688 int ret;
1689 OrigFn fn;
1690 VALGRIND_GET_ORIG_FN(fn);
1692 if (TRACE_PTH_FNS) {
1693 fprintf(stderr, "<< pthread_barrier_wait %p", bar);
1694 fflush(stderr);
1697 /* That this works correctly, and doesn't screw up when a thread
1698 leaving the barrier races round to the front and re-enters while
1699 other threads are still leaving it, is quite subtle. See
1700 comments in the handler for PTHREAD_BARRIER_WAIT_PRE in
1701 hg_main.c. */
1702 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE,
1703 pthread_barrier_t*,bar);
1705 CALL_FN_W_W(ret, fn, bar);
1707 if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) {
1708 DO_PthAPIerror( "pthread_barrier_wait", ret );
1711 if (TRACE_PTH_FNS) {
1712 fprintf(stderr, " pthread_barrier_wait -> %d >>\n", ret);
1715 return ret;
1719 //-----------------------------------------------------------
1720 // glibc: pthread_barrier_destroy
1721 // darwin: (doesn't appear to exist)
1722 // Solaris: pthread_barrier_destroy
1723 PTH_FUNC(int, pthreadZubarrierZudestroy, // pthread_barrier_destroy
1724 pthread_barrier_t* bar)
1726 int ret;
1727 OrigFn fn;
1728 VALGRIND_GET_ORIG_FN(fn);
1730 if (TRACE_PTH_FNS) {
1731 fprintf(stderr, "<< pthread_barrier_destroy %p", bar);
1732 fflush(stderr);
1735 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE,
1736 pthread_barrier_t*,bar);
1738 CALL_FN_W_W(ret, fn, bar);
1740 if (ret != 0) {
1741 DO_PthAPIerror( "pthread_barrier_destroy", ret );
1744 if (TRACE_PTH_FNS) {
1745 fprintf(stderr, " pthread_barrier_destroy -> %d >>\n", ret);
1748 return ret;
1751 #endif // defined(HAVE_PTHREAD_BARRIER_INIT)
1754 /*----------------------------------------------------------------*/
1755 /*--- pthread_spinlock_t functions ---*/
1756 /*----------------------------------------------------------------*/
1758 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1759 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1761 /* Handled: pthread_spin_init pthread_spin_destroy
1762 pthread_spin_lock pthread_spin_trylock
1763 pthread_spin_unlock
1765 Unhandled:
1768 /* This is a nasty kludge, in that glibc "knows" that initialising a
1769 spin lock unlocks it, and pthread_spin_{init,unlock} are names for
1770 the same function. Hence we have to have a wrapper which does both
1771 things, without knowing which the user intended to happen.
1772 Solaris has distinct functions for init/unlock but client requests
1773 are immutable in helgrind.h so follow the glibc lead. */
1775 //-----------------------------------------------------------
1776 // glibc: pthread_spin_init
1777 // glibc: pthread_spin_unlock
1778 // darwin: (doesn't appear to exist)
1779 // Solaris: pthread_spin_init
1780 // Solaris: pthread_spin_unlock
1781 __attribute__((noinline))
1782 static int pthread_spin_init_or_unlock_WRK(pthread_spinlock_t* lock,
1783 int pshared) {
1784 int ret;
1785 OrigFn fn;
1786 VALGRIND_GET_ORIG_FN(fn);
1787 if (TRACE_PTH_FNS) {
1788 fprintf(stderr, "<< pthread_spin_iORu %p", lock); fflush(stderr);
1791 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE,
1792 pthread_spinlock_t*, lock);
1794 CALL_FN_W_WW(ret, fn, lock,pshared);
1796 if (ret == 0 /*success*/) {
1797 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST,
1798 pthread_spinlock_t*,lock);
1799 } else {
1800 DO_PthAPIerror( "pthread_spinlock_{init,unlock}", ret );
1803 if (TRACE_PTH_FNS) {
1804 fprintf(stderr, " :: spiniORu -> %d >>\n", ret);
1806 return ret;
1808 #if defined(VGO_linux)
1809 PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
1810 pthread_spinlock_t* lock, int pshared) {
1811 return pthread_spin_init_or_unlock_WRK(lock, pshared);
1813 PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
1814 pthread_spinlock_t* lock) {
1815 /* this is never actually called */
1816 return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/);
1818 #elif defined(VGO_darwin)
1819 #elif defined(VGO_solaris)
1820 PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
1821 pthread_spinlock_t *lock, int pshared) {
1822 return pthread_spin_init_or_unlock_WRK(lock, pshared);
1824 PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
1825 pthread_spinlock_t *lock) {
1826 return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/);
1828 #else
1829 # error "Unsupported OS"
1830 #endif
1833 //-----------------------------------------------------------
1834 // glibc: pthread_spin_destroy
1835 // darwin: (doesn't appear to exist)
1836 // Solaris: pthread_spin_destroy
1837 __attribute__((noinline))
1838 static int pthread_spin_destroy_WRK(pthread_spinlock_t *lock)
1840 int ret;
1841 OrigFn fn;
1842 VALGRIND_GET_ORIG_FN(fn);
1843 if (TRACE_PTH_FNS) {
1844 fprintf(stderr, "<< pthread_spin_destroy %p", lock);
1845 fflush(stderr);
1848 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_DESTROY_PRE,
1849 pthread_spinlock_t*,lock);
1851 CALL_FN_W_W(ret, fn, lock);
1853 if (ret != 0) {
1854 DO_PthAPIerror( "pthread_spin_destroy", ret );
1857 if (TRACE_PTH_FNS) {
1858 fprintf(stderr, " :: spindestroy -> %d >>\n", ret);
1860 return ret;
1862 #if defined(VGO_linux)
1863 PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy
1864 pthread_spinlock_t *lock) {
1865 return pthread_spin_destroy_WRK(lock);
1867 #elif defined(VGO_darwin)
1868 #elif defined(VGO_solaris)
1869 PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy
1870 pthread_spinlock_t *lock) {
1871 return pthread_spin_destroy_WRK(lock);
1873 #else
1874 # error "Unsupported OS"
1875 #endif
1878 //-----------------------------------------------------------
1879 // glibc: pthread_spin_lock
1880 // darwin: (doesn't appear to exist)
1881 // Solaris: pthread_spin_lock
1882 __attribute__((noinline))
1883 static int pthread_spin_lock_WRK(pthread_spinlock_t *lock)
1885 int ret;
1886 OrigFn fn;
1887 VALGRIND_GET_ORIG_FN(fn);
1888 if (TRACE_PTH_FNS) {
1889 fprintf(stderr, "<< pthread_spinlock %p", lock);
1890 fflush(stderr);
1893 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE,
1894 pthread_spinlock_t*,lock, long,0/*!isTryLock*/);
1896 CALL_FN_W_W(ret, fn, lock);
1898 /* There's a hole here: libpthread now knows the lock is locked,
1899 but the tool doesn't, so some other thread could run and detect
1900 that the lock has been acquired by someone (this thread). Does
1901 this matter? Not sure, but I don't think so. */
1903 if (ret == 0 /*success*/) {
1904 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST,
1905 pthread_spinlock_t*,lock);
1906 } else {
1907 DO_PthAPIerror( "pthread_spin_lock", ret );
1910 if (TRACE_PTH_FNS) {
1911 fprintf(stderr, " :: spinlock -> %d >>\n", ret);
1913 return ret;
1915 #if defined(VGO_linux)
1916 PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
1917 pthread_spinlock_t *lock) {
1918 return pthread_spin_lock_WRK(lock);
1920 #elif defined(VGO_darwin)
1921 #elif defined(VGO_solaris)
1922 PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
1923 pthread_spinlock_t *lock) {
1924 return pthread_spin_lock_WRK(lock);
1926 #else
1927 # error "Unsupported OS"
1928 #endif
1931 //-----------------------------------------------------------
1932 // glibc: pthread_spin_trylock
1933 // darwin: (doesn't appear to exist)
1934 // Solaris: pthread_spin_trylock
1935 __attribute__((noinline))
1936 static int pthread_spin_trylock_WRK(pthread_spinlock_t *lock)
1938 int ret;
1939 OrigFn fn;
1940 VALGRIND_GET_ORIG_FN(fn);
1941 if (TRACE_PTH_FNS) {
1942 fprintf(stderr, "<< pthread_spin_trylock %p", lock);
1943 fflush(stderr);
1946 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE,
1947 pthread_spinlock_t*,lock, long,1/*isTryLock*/);
1949 CALL_FN_W_W(ret, fn, lock);
1951 /* There's a hole here: libpthread now knows the lock is locked,
1952 but the tool doesn't, so some other thread could run and detect
1953 that the lock has been acquired by someone (this thread). Does
1954 this matter? Not sure, but I don't think so. */
1956 if (ret == 0 /*success*/) {
1957 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST,
1958 pthread_spinlock_t*,lock);
1959 } else {
1960 if (ret != EBUSY)
1961 DO_PthAPIerror( "pthread_spin_trylock", ret );
1964 if (TRACE_PTH_FNS) {
1965 fprintf(stderr, " :: spin_trylock -> %d >>\n", ret);
1967 return ret;
1969 #if defined(VGO_linux)
1970 PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
1971 pthread_spinlock_t *lock) {
1972 return pthread_spin_trylock_WRK(lock);
1974 #elif defined(VGO_darwin)
1975 #elif defined(VGO_solaris)
1976 PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
1977 pthread_spinlock_t *lock) {
1978 return pthread_spin_trylock_WRK(lock);
1980 #else
1981 # error "Unsupported OS"
1982 #endif
1984 #endif // defined(HAVE_PTHREAD_SPIN_LOCK)
1987 /*----------------------------------------------------------------*/
1988 /*--- pthread_rwlock_t functions ---*/
1989 /*----------------------------------------------------------------*/
1991 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1992 functions have to be conditionally compiled. */
1993 #if defined(HAVE_PTHREAD_RWLOCK_T)
1995 /* Handled: pthread_rwlock_init pthread_rwlock_destroy
1996 pthread_rwlock_rdlock
1997 pthread_rwlock_wrlock
1998 pthread_rwlock_unlock
1999 pthread_rwlock_tryrdlock
2000 pthread_rwlock_trywrlock
2002 Unhandled: pthread_rwlock_timedrdlock
2003 pthread_rwlock_timedwrlock
2006 //-----------------------------------------------------------
2007 // glibc: pthread_rwlock_init
2008 // darwin: pthread_rwlock_init
2009 // darwin: pthread_rwlock_init$UNIX2003
2010 // Solaris: rwlock_init (pthread_rwlock_init is built atop of rwlock_init)
2011 __attribute__((noinline))
2012 static int pthread_rwlock_init_WRK(pthread_rwlock_t *rwl,
2013 pthread_rwlockattr_t* attr)
2015 int ret;
2016 OrigFn fn;
2017 VALGRIND_GET_ORIG_FN(fn);
2018 if (TRACE_PTH_FNS) {
2019 fprintf(stderr, "<< pthread_rwl_init %p", rwl); fflush(stderr);
2022 CALL_FN_W_WW(ret, fn, rwl,attr);
2024 if (ret == 0 /*success*/) {
2025 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
2026 pthread_rwlock_t*,rwl);
2027 } else {
2028 DO_PthAPIerror( "pthread_rwlock_init", ret );
2031 if (TRACE_PTH_FNS) {
2032 fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
2034 return ret;
2036 #if defined(VGO_linux)
2037 PTH_FUNC(int, pthreadZurwlockZuinit, // pthread_rwlock_init
2038 pthread_rwlock_t *rwl,
2039 pthread_rwlockattr_t* attr) {
2040 return pthread_rwlock_init_WRK(rwl, attr);
2042 #elif defined(VGO_darwin)
2043 PTH_FUNC(int, pthreadZurwlockZuinitZa, // pthread_rwlock_init*
2044 pthread_rwlock_t *rwl,
2045 pthread_rwlockattr_t* attr) {
2046 return pthread_rwlock_init_WRK(rwl, attr);
2048 #elif defined(VGO_solaris)
2049 static int pthread_rwlock_init_WRK(pthread_rwlock_t *rwl,
2050 pthread_rwlockattr_t* attr)
2051 __attribute__((unused));
2052 #else
2053 # error "Unsupported OS"
2054 #endif
2056 #if defined(VGO_solaris)
2057 PTH_FUNC(int, rwlockZuinit, // rwlock_init
2058 rwlock_t *rwlock,
2059 int type,
2060 void *arg)
2062 int ret;
2063 OrigFn fn;
2064 VALGRIND_GET_ORIG_FN(fn);
2065 if (TRACE_PTH_FNS) {
2066 fprintf(stderr, "<< rwl_init %p", rwlock); fflush(stderr);
2069 CALL_FN_W_WWW(ret, fn, rwlock, type, arg);
2071 if (ret == 0 /*success*/) {
2072 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
2073 rwlock_t *, rwlock);
2074 } else {
2075 DO_PthAPIerror("rwlock_init", ret);
2078 if (TRACE_PTH_FNS) {
2079 fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
2081 return ret;
2083 #endif /* VGO_solaris */
2086 //-----------------------------------------------------------
2087 // glibc: pthread_rwlock_destroy
2088 // darwin: pthread_rwlock_destroy
2089 // darwin: pthread_rwlock_destroy$UNIX2003
2090 // Solaris: rwlock_destroy (pthread_rwlock_destroy is a weak alias)
2092 __attribute__((noinline))
2093 static int pthread_rwlock_destroy_WRK(pthread_rwlock_t* rwl)
2095 int ret;
2096 OrigFn fn;
2097 VALGRIND_GET_ORIG_FN(fn);
2098 if (TRACE_PTH_FNS) {
2099 fprintf(stderr, "<< pthread_rwl_destroy %p", rwl); fflush(stderr);
2102 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE,
2103 pthread_rwlock_t*,rwl);
2105 CALL_FN_W_W(ret, fn, rwl);
2107 if (ret != 0) {
2108 DO_PthAPIerror( "pthread_rwlock_destroy", ret );
2111 if (TRACE_PTH_FNS) {
2112 fprintf(stderr, " :: rwl_destroy -> %d >>\n", ret);
2114 return ret;
2116 #if defined(VGO_linux)
2117 PTH_FUNC(int, pthreadZurwlockZudestroy, // pthread_rwlock_destroy
2118 pthread_rwlock_t *rwl) {
2119 return pthread_rwlock_destroy_WRK(rwl);
2121 #elif defined(VGO_darwin)
2122 PTH_FUNC(int, pthreadZurwlockZudestroyZa, // pthread_rwlock_destroy*
2123 pthread_rwlock_t *rwl) {
2124 return pthread_rwlock_destroy_WRK(rwl);
2126 #elif defined(VGO_solaris)
2127 PTH_FUNC(int, rwlockZudestroy, // rwlock_destroy
2128 pthread_rwlock_t *rwl) {
2129 return pthread_rwlock_destroy_WRK(rwl);
2131 #else
2132 # error "Unsupported OS"
2133 #endif
2136 //-----------------------------------------------------------
2137 // glibc: pthread_rwlock_wrlock
2138 // darwin: pthread_rwlock_wrlock
2139 // darwin: pthread_rwlock_wrlock$UNIX2003
2140 // Solaris: rw_wrlock (pthread_rwlock_wrlock is a weak alias)
2142 __attribute__((noinline))
2143 static int pthread_rwlock_wrlock_WRK(pthread_rwlock_t* rwlock)
2145 int ret;
2146 OrigFn fn;
2147 VALGRIND_GET_ORIG_FN(fn);
2148 if (TRACE_PTH_FNS) {
2149 fprintf(stderr, "<< pthread_rwl_wlk %p", rwlock); fflush(stderr);
2152 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2153 pthread_rwlock_t*,rwlock,
2154 long,1/*isW*/, long,0/*!isTryLock*/);
2156 CALL_FN_W_W(ret, fn, rwlock);
2158 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2159 pthread_rwlock_t*,rwlock, long,1/*isW*/,
2160 long, (ret == 0) ? True : False);
2161 if (ret != 0) {
2162 DO_PthAPIerror( "pthread_rwlock_wrlock", ret );
2165 if (TRACE_PTH_FNS) {
2166 fprintf(stderr, " :: rwl_wlk -> %d >>\n", ret);
2168 return ret;
2170 #if defined(VGO_linux)
2171 PTH_FUNC(int, pthreadZurwlockZuwrlock, // pthread_rwlock_wrlock
2172 pthread_rwlock_t* rwlock) {
2173 return pthread_rwlock_wrlock_WRK(rwlock);
2175 #elif defined(VGO_darwin)
2176 PTH_FUNC(int, pthreadZurwlockZuwrlockZa, // pthread_rwlock_wrlock*
2177 pthread_rwlock_t* rwlock) {
2178 return pthread_rwlock_wrlock_WRK(rwlock);
2180 #elif defined(VGO_solaris)
2181 PTH_FUNC(int, rwZuwrlock, // rw_wrlock
2182 pthread_rwlock_t *rwlock) {
2183 return pthread_rwlock_wrlock_WRK(rwlock);
2185 #else
2186 # error "Unsupported OS"
2187 #endif
2189 #if defined(VGO_solaris)
2190 /* Internal to libc. */
2191 PTH_FUNC(void, lrwZuwrlock, // lrw_wrlock
2192 rwlock_t *rwlock)
2194 OrigFn fn;
2195 VALGRIND_GET_ORIG_FN(fn);
2196 if (TRACE_PTH_FNS) {
2197 fprintf(stderr, "<< lrw_wlk %p", rwlock); fflush(stderr);
2200 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2201 pthread_rwlock_t *, rwlock,
2202 long, 1/*isW*/, long, 0/*!isTryLock*/);
2204 CALL_FN_v_W(fn, rwlock);
2206 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2207 pthread_rwlock_t *, rwlock, long, 1/*isW*/, long, True);
2209 if (TRACE_PTH_FNS) {
2210 fprintf(stderr, " :: lrw_wlk >>\n");
2213 #endif /* VGO_solaris */
2216 //-----------------------------------------------------------
2217 // glibc: pthread_rwlock_rdlock
2218 // darwin: pthread_rwlock_rdlock
2219 // darwin: pthread_rwlock_rdlock$UNIX2003
2220 // Solaris: rw_rdlock (pthread_rwlock_rdlock is a weak alias)
2222 __attribute__((noinline))
2223 static int pthread_rwlock_rdlock_WRK(pthread_rwlock_t* rwlock)
2225 int ret;
2226 OrigFn fn;
2227 VALGRIND_GET_ORIG_FN(fn);
2228 if (TRACE_PTH_FNS) {
2229 fprintf(stderr, "<< pthread_rwl_rlk %p", rwlock); fflush(stderr);
2232 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2233 pthread_rwlock_t*,rwlock,
2234 long,0/*!isW*/, long,0/*!isTryLock*/);
2236 CALL_FN_W_W(ret, fn, rwlock);
2238 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2239 pthread_rwlock_t*,rwlock, long,0/*!isW*/,
2240 long, (ret == 0) ? True : False);
2241 if (ret != 0) {
2242 DO_PthAPIerror( "pthread_rwlock_rdlock", ret );
2245 if (TRACE_PTH_FNS) {
2246 fprintf(stderr, " :: rwl_rlk -> %d >>\n", ret);
2248 return ret;
2250 #if defined(VGO_linux)
2251 PTH_FUNC(int, pthreadZurwlockZurdlock, // pthread_rwlock_rdlock
2252 pthread_rwlock_t* rwlock) {
2253 return pthread_rwlock_rdlock_WRK(rwlock);
2255 #elif defined(VGO_darwin)
2256 PTH_FUNC(int, pthreadZurwlockZurdlockZa, // pthread_rwlock_rdlock*
2257 pthread_rwlock_t* rwlock) {
2258 return pthread_rwlock_rdlock_WRK(rwlock);
2260 #elif defined(VGO_solaris)
2261 PTH_FUNC(int, rwZurdlock, // rw_rdlock
2262 pthread_rwlock_t *rwlock) {
2263 return pthread_rwlock_rdlock_WRK(rwlock);
2265 #else
2266 # error "Unsupported OS"
2267 #endif
2269 #if defined(VGO_solaris)
2270 /* Internal to libc. */
2271 PTH_FUNC(void, lrwZurdlock, // lrw_rdlock
2272 rwlock_t *rwlock)
2274 OrigFn fn;
2275 VALGRIND_GET_ORIG_FN(fn);
2276 if (TRACE_PTH_FNS) {
2277 fprintf(stderr, "<< lrw_rlk %p", rwlock); fflush(stderr);
2280 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2281 pthread_rwlock_t *, rwlock,
2282 long, 0/*!isW*/, long, 0/*!isTryLock*/);
2284 CALL_FN_v_W(fn, rwlock);
2286 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2287 pthread_rwlock_t *, rwlock, long, 0/*!isW*/, long, True);
2289 if (TRACE_PTH_FNS) {
2290 fprintf(stderr, " :: lrw_rlk ->>\n");
2293 #endif /* VGO_solaris */
2296 //-----------------------------------------------------------
2297 // glibc: pthread_rwlock_trywrlock
2298 // darwin: pthread_rwlock_trywrlock
2299 // darwin: pthread_rwlock_trywrlock$UNIX2003
2300 // Solaris: rw_trywrlock (pthread_rwlock_trywrlock is a weak alias)
2302 __attribute__((noinline))
2303 static int pthread_rwlock_trywrlock_WRK(pthread_rwlock_t* rwlock)
2305 int ret;
2306 OrigFn fn;
2307 VALGRIND_GET_ORIG_FN(fn);
2308 if (TRACE_PTH_FNS) {
2309 fprintf(stderr, "<< pthread_rwl_trywlk %p", rwlock); fflush(stderr);
2312 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2313 pthread_rwlock_t*,rwlock,
2314 long,1/*isW*/, long,1/*isTryLock*/);
2316 CALL_FN_W_W(ret, fn, rwlock);
2318 /* There's a hole here: libpthread now knows the lock is locked,
2319 but the tool doesn't, so some other thread could run and detect
2320 that the lock has been acquired by someone (this thread). Does
2321 this matter? Not sure, but I don't think so. */
2323 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2324 pthread_rwlock_t*,rwlock, long,1/*isW*/,
2325 long, (ret == 0) ? True : False);
2326 if (ret != 0) {
2327 if (ret != EBUSY)
2328 DO_PthAPIerror( "pthread_rwlock_trywrlock", ret );
2331 if (TRACE_PTH_FNS) {
2332 fprintf(stderr, " :: rwl_trywlk -> %d >>\n", ret);
2334 return ret;
2336 #if defined(VGO_linux)
2337 PTH_FUNC(int, pthreadZurwlockZutrywrlock, // pthread_rwlock_trywrlock
2338 pthread_rwlock_t* rwlock) {
2339 return pthread_rwlock_trywrlock_WRK(rwlock);
2341 #elif defined(VGO_darwin)
2342 PTH_FUNC(int, pthreadZurwlockZutrywrlockZa, // pthread_rwlock_trywrlock*
2343 pthread_rwlock_t* rwlock) {
2344 return pthread_rwlock_trywrlock_WRK(rwlock);
2346 #elif defined(VGO_solaris)
2347 PTH_FUNC(int, rwZutrywrlock, // rw_trywrlock
2348 pthread_rwlock_t *rwlock) {
2349 return pthread_rwlock_trywrlock_WRK(rwlock);
2351 #else
2352 # error "Unsupported OS"
2353 #endif
2356 //-----------------------------------------------------------
2357 // glibc: pthread_rwlock_tryrdlock
2358 // darwin: pthread_rwlock_tryrdlock
2359 // darwin: pthread_rwlock_tryrdlock$UNIX2003
2360 // Solaris: rw_tryrdlock (pthread_rwlock_tryrdlock is a weak alias)
2362 __attribute__((noinline))
2363 static int pthread_rwlock_tryrdlock_WRK(pthread_rwlock_t* rwlock)
2365 int ret;
2366 OrigFn fn;
2367 VALGRIND_GET_ORIG_FN(fn);
2368 if (TRACE_PTH_FNS) {
2369 fprintf(stderr, "<< pthread_rwl_tryrlk %p", rwlock); fflush(stderr);
2372 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2373 pthread_rwlock_t*,rwlock,
2374 long,0/*!isW*/, long,1/*isTryLock*/);
2376 CALL_FN_W_W(ret, fn, rwlock);
2378 /* There's a hole here: libpthread now knows the lock is locked,
2379 but the tool doesn't, so some other thread could run and detect
2380 that the lock has been acquired by someone (this thread). Does
2381 this matter? Not sure, but I don't think so. */
2383 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2384 pthread_rwlock_t*,rwlock, long,0/*!isW*/,
2385 long, (ret == 0) ? True : False);
2387 if (ret != 0) {
2388 if (ret != EBUSY)
2389 DO_PthAPIerror( "pthread_rwlock_tryrdlock", ret );
2392 if (TRACE_PTH_FNS) {
2393 fprintf(stderr, " :: rwl_tryrlk -> %d >>\n", ret);
2395 return ret;
2397 #if defined(VGO_linux)
2398 PTH_FUNC(int, pthreadZurwlockZutryrdlock, // pthread_rwlock_tryrdlock
2399 pthread_rwlock_t* rwlock) {
2400 return pthread_rwlock_tryrdlock_WRK(rwlock);
2402 #elif defined(VGO_darwin)
2403 PTH_FUNC(int, pthreadZurwlockZutryrdlockZa, // pthread_rwlock_tryrdlock*
2404 pthread_rwlock_t* rwlock) {
2405 return pthread_rwlock_tryrdlock_WRK(rwlock);
2407 #elif defined(VGO_solaris)
2408 PTH_FUNC(int, rwZutryrdlock, // rw_tryrdlock
2409 pthread_rwlock_t *rwlock) {
2410 return pthread_rwlock_tryrdlock_WRK(rwlock);
2412 #else
2413 # error "Unsupported OS"
2414 #endif
2417 //-----------------------------------------------------------
2418 // glibc: Unhandled
2419 // darwin: Unhandled
2420 // Solaris: pthread_rwlock_timedrdlock
2421 // Solaris: pthread_rwlock_reltimedrdlock_np
2423 __attribute__((noinline)) __attribute__((unused))
2424 static int pthread_rwlock_timedrdlock_WRK(pthread_rwlock_t *rwlock,
2425 const struct timespec *timeout)
2427 int ret;
2428 OrigFn fn;
2429 VALGRIND_GET_ORIG_FN(fn);
2430 if (TRACE_PTH_FNS) {
2431 fprintf(stderr, "<< pthread_rwl_timedrdl %p", rwlock); fflush(stderr);
2434 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2435 pthread_rwlock_t *, rwlock,
2436 long, 0/*isW*/, long, 0/*isTryLock*/);
2438 CALL_FN_W_WW(ret, fn, rwlock, timeout);
2440 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2441 pthread_rwlock_t *, rwlock, long, 0/*isW*/,
2442 long, (ret == 0) ? True : False);
2443 if (ret != 0) {
2444 DO_PthAPIerror("pthread_rwlock_timedrdlock", ret);
2447 if (TRACE_PTH_FNS) {
2448 fprintf(stderr, " :: rwl_timedrdl -> %d >>\n", ret);
2450 return ret;
2452 #if defined(VGO_linux)
2453 #elif defined(VGO_darwin)
2454 #elif defined(VGO_solaris)
2455 PTH_FUNC(int, pthreadZurwlockZutimedrdlock, // pthread_rwlock_timedrdlock
2456 pthread_rwlock_t *rwlock,
2457 const struct timespec *timeout) {
2458 return pthread_rwlock_timedrdlock_WRK(rwlock, timeout);
2460 PTH_FUNC(int, pthreadZurwlockZureltimedrdlockZunp, // pthread_rwlock_timedrdlock_np
2461 pthread_rwlock_t *rwlock,
2462 const struct timespec *timeout) {
2463 return pthread_rwlock_timedrdlock_WRK(rwlock, timeout);
2465 #else
2466 # error "Unsupported OS"
2467 #endif
2470 //-----------------------------------------------------------
2471 // glibc: Unhandled
2472 // darwin: Unhandled
2473 // Solaris: pthread_rwlock_timedwrlock
2474 // Solaris: pthread_rwlock_reltimedwrlock_np
2476 __attribute__((noinline)) __attribute__((unused))
2477 static int pthread_rwlock_timedwrlock_WRK(pthread_rwlock_t *rwlock,
2478 const struct timespec *timeout)
2480 int ret;
2481 OrigFn fn;
2482 VALGRIND_GET_ORIG_FN(fn);
2483 if (TRACE_PTH_FNS) {
2484 fprintf(stderr, "<< pthread_rwl_timedwrl %p", rwlock); fflush(stderr);
2487 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2488 pthread_rwlock_t *, rwlock,
2489 long, 1/*isW*/, long, 0/*isTryLock*/);
2491 CALL_FN_W_WW(ret, fn, rwlock, timeout);
2493 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2494 pthread_rwlock_t *, rwlock, long, 1/*isW*/,
2495 long, (ret == 0) ? True : False);
2496 if (ret != 0) {
2497 DO_PthAPIerror("pthread_rwlock_timedwrlock", ret);
2500 if (TRACE_PTH_FNS) {
2501 fprintf(stderr, " :: rwl_timedwrl -> %d >>\n", ret);
2503 return ret;
2505 #if defined(VGO_linux)
2506 #elif defined(VGO_darwin)
2507 #elif defined(VGO_solaris)
2508 PTH_FUNC(int, pthreadZurwlockZutimedwrlock, // pthread_rwlock_timedwrlock
2509 pthread_rwlock_t *rwlock,
2510 const struct timespec *timeout) {
2511 return pthread_rwlock_timedwrlock_WRK(rwlock, timeout);
2513 PTH_FUNC(int, pthreadZurwlockZureltimedwrlockZunp, // pthread_rwlock_timedwrlock_np
2514 pthread_rwlock_t *rwlock,
2515 const struct timespec *timeout) {
2516 return pthread_rwlock_timedwrlock_WRK(rwlock, timeout);
2518 #else
2519 # error "Unsupported OS"
2520 #endif
2523 //-----------------------------------------------------------
2524 // glibc: pthread_rwlock_unlock
2525 // darwin: pthread_rwlock_unlock
2526 // darwin: pthread_rwlock_unlock$UNIX2003
2527 // Solaris: rw_unlock (pthread_rwlock_unlock is a weak alias)
2528 __attribute__((noinline))
2529 static int pthread_rwlock_unlock_WRK(pthread_rwlock_t* rwlock)
2531 int ret;
2532 OrigFn fn;
2533 VALGRIND_GET_ORIG_FN(fn);
2534 if (TRACE_PTH_FNS) {
2535 fprintf(stderr, "<< pthread_rwl_unlk %p", rwlock); fflush(stderr);
2538 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
2539 pthread_rwlock_t*,rwlock);
2541 CALL_FN_W_W(ret, fn, rwlock);
2543 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
2544 pthread_rwlock_t*,rwlock);
2545 if (ret != 0) {
2546 DO_PthAPIerror( "pthread_rwlock_unlock", ret );
2549 if (TRACE_PTH_FNS) {
2550 fprintf(stderr, " :: rwl_unlk -> %d >>\n", ret);
2552 return ret;
2554 #if defined(VGO_linux)
2555 PTH_FUNC(int, pthreadZurwlockZuunlock, // pthread_rwlock_unlock
2556 pthread_rwlock_t* rwlock) {
2557 return pthread_rwlock_unlock_WRK(rwlock);
2559 #elif defined(VGO_darwin)
2560 PTH_FUNC(int, pthreadZurwlockZuunlockZa, // pthread_rwlock_unlock*
2561 pthread_rwlock_t* rwlock) {
2562 return pthread_rwlock_unlock_WRK(rwlock);
2564 #elif defined(VGO_solaris)
2565 PTH_FUNC(int, rwZuunlock, // rw_unlock
2566 pthread_rwlock_t *rwlock) {
2567 return pthread_rwlock_unlock_WRK(rwlock);
2569 #else
2570 # error "Unsupported OS"
2571 #endif
2573 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
2576 /*----------------------------------------------------------------*/
2577 /*--- POSIX semaphores ---*/
2578 /*----------------------------------------------------------------*/
2580 #include <semaphore.h>
2581 #include <fcntl.h> /* O_CREAT */
2583 #define TRACE_SEM_FNS 0
2585 /* Handled:
2586 int sem_init(sem_t *sem, int pshared, unsigned value);
2587 int sem_destroy(sem_t *sem);
2588 int sem_wait(sem_t *sem);
2589 int sem_post(sem_t *sem);
2590 sem_t* sem_open(const char *name, int oflag,
2591 ... [mode_t mode, unsigned value]);
2592 [complete with its idiotic semantics]
2593 int sem_close(sem_t* sem);
2595 Unhandled:
2596 int sem_trywait(sem_t *sem);
2597 int sem_timedwait(sem_t *restrict sem,
2598 const struct timespec *restrict abs_timeout);
2601 //-----------------------------------------------------------
2602 // glibc: sem_init@@GLIBC_2.2.5
2603 // glibc: sem_init@@GLIBC_2.1
2604 // glibc: sem_init@GLIBC_2.0
2605 // darwin: sem_init
2606 // Solaris: sema_init (sem_init is built on top of sem_init)
2608 #if !defined(VGO_solaris)
2609 __attribute__((noinline))
2610 static int sem_init_WRK(sem_t* sem, int pshared, unsigned long value)
2612 OrigFn fn;
2613 int ret;
2614 VALGRIND_GET_ORIG_FN(fn);
2616 if (TRACE_SEM_FNS) {
2617 fprintf(stderr, "<< sem_init(%p,%d,%lu) ", sem,pshared,value);
2618 fflush(stderr);
2621 CALL_FN_W_WWW(ret, fn, sem,pshared,value);
2623 if (ret == 0) {
2624 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
2625 sem_t*, sem, unsigned long, value);
2626 } else {
2627 DO_PthAPIerror( "sem_init", errno );
2630 if (TRACE_SEM_FNS) {
2631 fprintf(stderr, " sem_init -> %d >>\n", ret);
2632 fflush(stderr);
2635 return ret;
2637 #if defined(VGO_linux)
2638 PTH_FUNC(int, semZuinitZAZa, // sem_init@*
2639 sem_t* sem, int pshared, unsigned long value) {
2640 return sem_init_WRK(sem, pshared, value);
2642 #elif defined(VGO_darwin)
2643 PTH_FUNC(int, semZuinit, // sem_init
2644 sem_t* sem, int pshared, unsigned long value) {
2645 return sem_init_WRK(sem, pshared, value);
2647 #else
2648 # error "Unsupported OS"
2649 #endif
2651 #else /* VGO_solaris */
2652 PTH_FUNC(int, semaZuinit, // sema_init
2653 sema_t *sem,
2654 unsigned int value,
2655 int type,
2656 void *arg)
2658 OrigFn fn;
2659 int ret;
2660 VALGRIND_GET_ORIG_FN(fn);
2662 if (TRACE_SEM_FNS) {
2663 fprintf(stderr, "<< sema_init(%p, %d, %u) ", sem, type, value);
2664 fflush(stderr);
2667 CALL_FN_W_WWWW(ret, fn, sem, value, type, arg);
2669 if (ret == 0) {
2670 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
2671 sema_t *, sem, Word, value);
2672 } else {
2673 DO_PthAPIerror("sema_init", ret);
2676 if (TRACE_SEM_FNS) {
2677 fprintf(stderr, " sema_init -> %d >>\n", ret);
2678 fflush(stderr);
2681 return ret;
2683 #endif /* VGO_solaris */
2686 //-----------------------------------------------------------
2687 // glibc: sem_destroy@GLIBC_2.0
2688 // glibc: sem_destroy@@GLIBC_2.1
2689 // glibc: sem_destroy@@GLIBC_2.2.5
2690 // darwin: sem_destroy
2691 // Solaris: sema_destroy (sem_destroy is built on top of sema_destroy)
2692 __attribute__((noinline))
2693 static int sem_destroy_WRK(sem_t* sem)
2695 OrigFn fn;
2696 int ret;
2697 VALGRIND_GET_ORIG_FN(fn);
2699 if (TRACE_SEM_FNS) {
2700 fprintf(stderr, "<< sem_destroy(%p) ", sem);
2701 fflush(stderr);
2704 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
2706 CALL_FN_W_W(ret, fn, sem);
2708 if (ret != 0) {
2709 DO_PthAPIerror( "sem_destroy", SEM_ERROR );
2712 if (TRACE_SEM_FNS) {
2713 fprintf(stderr, " sem_destroy -> %d >>\n", ret);
2714 fflush(stderr);
2717 return ret;
2719 #if defined(VGO_linux)
2720 PTH_FUNC(int, semZudestroyZAZa, // sem_destroy*
2721 sem_t* sem) {
2722 return sem_destroy_WRK(sem);
2724 #elif defined(VGO_darwin)
2725 PTH_FUNC(int, semZudestroy, // sem_destroy
2726 sem_t* sem) {
2727 return sem_destroy_WRK(sem);
2729 #elif defined(VGO_solaris)
2730 PTH_FUNC(int, semaZudestroy, // sema_destroy
2731 sem_t *sem) {
2732 return sem_destroy_WRK(sem);
2734 #else
2735 # error "Unsupported OS"
2736 #endif
2739 //-----------------------------------------------------------
2740 // glibc: sem_wait
2741 // glibc: sem_wait@GLIBC_2.0
2742 // glibc: sem_wait@@GLIBC_2.1
2743 // darwin: sem_wait
2744 // darwin: sem_wait$NOCANCEL$UNIX2003
2745 // darwin: sem_wait$UNIX2003
2746 // Solaris: sema_wait (sem_wait is built on top of sema_wait)
2748 /* wait: decrement semaphore - acquire lockage */
2749 __attribute__((noinline))
2750 static int sem_wait_WRK(sem_t* sem)
2752 OrigFn fn;
2753 int ret;
2754 VALGRIND_GET_ORIG_FN(fn);
2756 if (TRACE_SEM_FNS) {
2757 fprintf(stderr, "<< sem_wait(%p) ", sem);
2758 fflush(stderr);
2761 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_PRE, sem_t*,sem);
2763 CALL_FN_W_W(ret, fn, sem);
2765 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST, sem_t*,sem,
2766 long, (ret == 0) ? True : False);
2768 if (ret != 0) {
2769 DO_PthAPIerror( "sem_wait", SEM_ERROR );
2772 if (TRACE_SEM_FNS) {
2773 fprintf(stderr, " sem_wait -> %d >>\n", ret);
2774 fflush(stderr);
2777 return ret;
2779 #if defined(VGO_linux)
2780 PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
2781 return sem_wait_WRK(sem);
2783 PTH_FUNC(int, semZuwaitZAZa, sem_t* sem) { /* sem_wait@* */
2784 return sem_wait_WRK(sem);
2786 #elif defined(VGO_darwin)
2787 PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
2788 return sem_wait_WRK(sem);
2790 PTH_FUNC(int, semZuwaitZDZa, sem_t* sem) { /* sem_wait$* */
2791 return sem_wait_WRK(sem);
2793 #elif defined(VGO_solaris)
2794 PTH_FUNC(int, semaZuwait, sem_t *sem) { /* sema_wait */
2795 return sem_wait_WRK(sem);
2797 #else
2798 # error "Unsupported OS"
2799 #endif
2802 //-----------------------------------------------------------
2803 // glibc: sem_post
2804 // glibc: sem_post@GLIBC_2.0
2805 // glibc: sem_post@@GLIBC_2.1
2806 // darwin: sem_post
2807 // Solaris: sema_post (sem_post is built on top of sema_post)
2809 /* post: increment semaphore - release lockage */
2810 __attribute__((noinline))
2811 static int sem_post_WRK(sem_t* sem)
2813 OrigFn fn;
2814 int ret;
2816 VALGRIND_GET_ORIG_FN(fn);
2818 if (TRACE_SEM_FNS) {
2819 fprintf(stderr, "<< sem_post(%p) ", sem);
2820 fflush(stderr);
2823 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_PRE, sem_t*,sem);
2825 CALL_FN_W_W(ret, fn, sem);
2827 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_POST, sem_t*,sem);
2829 if (ret != 0) {
2830 DO_PthAPIerror( "sem_post", SEM_ERROR );
2833 if (TRACE_SEM_FNS) {
2834 fprintf(stderr, " sem_post -> %d >>\n", ret);
2835 fflush(stderr);
2838 return ret;
2840 #if defined(VGO_linux)
2841 PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
2842 return sem_post_WRK(sem);
2844 PTH_FUNC(int, semZupostZAZa, sem_t* sem) { /* sem_post@* */
2845 return sem_post_WRK(sem);
2847 #elif defined(VGO_darwin)
2848 PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
2849 return sem_post_WRK(sem);
2851 #elif defined(VGO_solaris)
2852 PTH_FUNC(int, semaZupost, sem_t *sem) { /* sema_post */
2853 return sem_post_WRK(sem);
2855 #else
2856 # error "Unsupported OS"
2857 #endif
2860 //-----------------------------------------------------------
2861 // glibc: sem_open
2862 // darwin: sem_open
2863 // Solaris: sem_open
2865 PTH_FUNC(sem_t*, semZuopen,
2866 const char* name, long oflag,
2867 long mode, unsigned long value)
2869 /* A copy of sem_init_WRK (more or less). Is this correct? */
2870 OrigFn fn;
2871 sem_t* ret;
2872 VALGRIND_GET_ORIG_FN(fn);
2874 if (TRACE_SEM_FNS) {
2875 fprintf(stderr, "<< sem_open(\"%s\",%ld,%lx,%lu) ",
2876 name,oflag,mode,value);
2877 fflush(stderr);
2880 CALL_FN_W_WWWW(ret, fn, name,oflag,mode,value);
2882 if (ret != SEM_FAILED && (oflag & O_CREAT)) {
2883 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
2884 sem_t*, ret, unsigned long, value);
2886 if (ret == SEM_FAILED) {
2887 DO_PthAPIerror( "sem_open", errno );
2890 if (TRACE_SEM_FNS) {
2891 fprintf(stderr, " sem_open -> %p >>\n", ret);
2892 fflush(stderr);
2895 return ret;
2899 //-----------------------------------------------------------
2900 // glibc: sem_close
2901 // darwin: sem_close
2902 // Solaris: sem_close
2903 PTH_FUNC(int, sem_close, sem_t* sem)
2905 OrigFn fn;
2906 int ret;
2907 VALGRIND_GET_ORIG_FN(fn);
2909 if (TRACE_SEM_FNS) {
2910 fprintf(stderr, "<< sem_close(%p) ", sem);
2911 fflush(stderr);
2914 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
2916 CALL_FN_W_W(ret, fn, sem);
2918 if (ret != 0) {
2919 DO_PthAPIerror( "sem_close", errno );
2922 if (TRACE_SEM_FNS) {
2923 fprintf(stderr, " close -> %d >>\n", ret);
2924 fflush(stderr);
2927 return ret;
2931 /*----------------------------------------------------------------*/
2932 /*--- Qt 4 threading functions (w/ GNU name mangling) ---*/
2933 /*----------------------------------------------------------------*/
2935 /* Handled:
2936 QMutex::lock()
2937 QMutex::unlock()
2938 QMutex::tryLock()
2939 QMutex::tryLock(int)
2941 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC1ENS_13RecursionModeE
2942 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC2ENS_13RecursionModeE
2943 QMutex::~QMutex() _ZN6QMutexD1Ev
2944 QMutex::~QMutex() _ZN6QMutexD2Ev
2946 Unhandled:
2947 QReadWriteLock::lockForRead()
2948 QReadWriteLock::lockForWrite()
2949 QReadWriteLock::unlock()
2950 QReadWriteLock::tryLockForRead(int)
2951 QReadWriteLock::tryLockForRead()
2952 QReadWriteLock::tryLockForWrite(int)
2953 QReadWriteLock::tryLockForWrite()
2955 QWaitCondition::wait(QMutex*, unsigned long)
2956 QWaitCondition::wakeAll()
2957 QWaitCondition::wakeOne()
2959 QSemaphore::*
2961 /* More comments, 19 Nov 08, based on assessment of qt-4.5.0TP1,
2962 at least on Unix:
2964 It's apparently only necessary to intercept QMutex, since that is
2965 not implemented using pthread_mutex_t; instead Qt4 has its own
2966 implementation based on atomics (to check the non-contended case)
2967 and pthread_cond_wait (to wait in the contended case).
2969 QReadWriteLock is built on top of QMutex, counters, and a wait
2970 queue. So we don't need to handle it specially once QMutex
2971 handling is correct -- presumably the dependencies through QMutex
2972 are sufficient to avoid any false race reports. On the other hand,
2973 it is an open question whether too many dependencies are observed
2974 -- in which case we may miss races (false negatives). I suspect
2975 this is likely to be the case, unfortunately.
2977 QWaitCondition is built on pthread_cond_t, pthread_mutex_t, QMutex
2978 and QReadWriteLock. Same compositional-correctness justificiation
2979 and limitations as fro QReadWriteLock.
2981 Ditto QSemaphore (from cursory examination).
2983 Does it matter that only QMutex is handled directly? Open
2984 question. From testing with drd/tests/qt4_* and with KDE4 apps, it
2985 appears that no false errors are reported; however it is not clear
2986 if this is causing false negatives.
2988 Another problem with Qt4 is thread exiting. Threads are created
2989 with pthread_create (fine); but they detach and simply exit when
2990 done. There is no use of pthread_join, and the provided
2991 wait-for-a-thread-to-exit mechanism (QThread::wait, I believe)
2992 relies on a system of mutexes and flags. I suspect this also
2993 causes too many dependencies to appear. Consequently H sometimes
2994 fails to detect races at exit in some very short-lived racy
2995 programs, because it appears that a thread can exit _and_ have an
2996 observed dependency edge back to the main thread (presumably)
2997 before the main thread reaps the child (that is, calls
2998 QThread::wait).
3000 This theory is supported by the observation that if all threads are
3001 made to wait at a pthread_barrier_t immediately before they exit,
3002 then H's detection of races in such programs becomes reliable;
3003 without the barrier, it is varies from run to run, depending
3004 (according to investigation) on whether aforementioned
3005 exit-before-reaping behaviour happens or not.
3007 Finally, why is it necessary to intercept the QMutex constructors
3008 and destructors? The constructors are intercepted only as a matter
3009 of convenience, so H can print accurate "first observed at"
3010 clauses. However, it is actually necessary to intercept the
3011 destructors (as it is with pthread_mutex_destroy) in order that
3012 locks get removed from LAOG when they are destroyed.
3015 // soname is libQtCore.so.4 ; match against libQtCore.so*
3016 #define QT4_FUNC(ret_ty, f, args...) \
3017 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args); \
3018 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args)
3020 // soname is libQt5Core.so.4 ; match against libQt5Core.so*
3021 #define QT5_FUNC(ret_ty, f, args...) \
3022 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args); \
3023 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args)
3025 //-----------------------------------------------------------
3026 // QMutex::lock()
3027 __attribute__((noinline))
3028 static void QMutex_lock_WRK(void* self)
3030 OrigFn fn;
3031 VALGRIND_GET_ORIG_FN(fn);
3032 if (TRACE_QT4_FNS) {
3033 fprintf(stderr, "<< QMutex::lock %p", self); fflush(stderr);
3036 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
3037 void*,self, long,0/*!isTryLock*/);
3039 CALL_FN_v_W(fn, self);
3041 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
3042 void *, self, long, True);
3044 if (TRACE_QT4_FNS) {
3045 fprintf(stderr, " :: Q::lock done >>\n");
3049 QT4_FUNC(void, _ZN6QMutex4lockEv, void* self) {
3050 QMutex_lock_WRK(self);
3052 QT5_FUNC(void, _ZN6QMutex4lockEv, void* self) {
3053 QMutex_lock_WRK(self);
3056 //-----------------------------------------------------------
3057 // QMutex::unlock()
3058 __attribute__((noinline))
3059 static void QMutex_unlock_WRK(void* self)
3061 OrigFn fn;
3062 VALGRIND_GET_ORIG_FN(fn);
3064 if (TRACE_QT4_FNS) {
3065 fprintf(stderr, "<< QMutex::unlock %p", self); fflush(stderr);
3068 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
3069 void*, self);
3071 CALL_FN_v_W(fn, self);
3073 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
3074 void*, self);
3076 if (TRACE_QT4_FNS) {
3077 fprintf(stderr, " Q::unlock done >>\n");
3081 QT4_FUNC(void, _ZN6QMutex6unlockEv, void* self) {
3082 QMutex_unlock_WRK(self);
3084 QT5_FUNC(void, _ZN6QMutex6unlockEv, void* self) {
3085 QMutex_unlock_WRK(self);
3088 //-----------------------------------------------------------
3089 // bool QMutex::tryLock()
3090 // using 'long' to mimic C++ 'bool'
3091 __attribute__((noinline))
3092 static long QMutex_tryLock_WRK(void* self)
3094 OrigFn fn;
3095 long ret;
3096 VALGRIND_GET_ORIG_FN(fn);
3097 if (TRACE_QT4_FNS) {
3098 fprintf(stderr, "<< QMutex::tryLock %p", self); fflush(stderr);
3101 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
3102 void*,self, long,1/*isTryLock*/);
3104 CALL_FN_W_W(ret, fn, self);
3106 // assumes that only the low 8 bits of the 'bool' are significant
3107 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
3108 void *, self, long, (ret & 0xFF) ? True : False);
3110 if (TRACE_QT4_FNS) {
3111 fprintf(stderr, " :: Q::tryLock -> %lu >>\n", ret);
3114 return ret;
3117 QT4_FUNC(long, _ZN6QMutex7tryLockEv, void* self) {
3118 return QMutex_tryLock_WRK(self);
3120 QT5_FUNC(long, _ZN6QMutex7tryLockEv, void* self) {
3121 return QMutex_tryLock_WRK(self);
3124 //-----------------------------------------------------------
3125 // bool QMutex::tryLock(int)
3126 // using 'long' to mimic C++ 'bool'
3127 __attribute__((noinline))
3128 static long QMutex_tryLock_int_WRK(void* self, long arg2)
3130 OrigFn fn;
3131 long ret;
3132 VALGRIND_GET_ORIG_FN(fn);
3133 if (TRACE_QT4_FNS) {
3134 fprintf(stderr, "<< QMutex::tryLock(int) %p %d", self, (int)arg2);
3135 fflush(stderr);
3138 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
3139 void*,self, long,1/*isTryLock*/);
3141 CALL_FN_W_WW(ret, fn, self,arg2);
3143 // assumes that only the low 8 bits of the 'bool' are significant
3144 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
3145 void *, self, long, (ret & 0xFF) ? True : False);
3147 if (TRACE_QT4_FNS) {
3148 fprintf(stderr, " :: Q::tryLock(int) -> %lu >>\n", ret);
3151 return ret;
3154 QT4_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2) {
3155 return QMutex_tryLock_int_WRK(self, arg2);
3157 QT5_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2) {
3158 return QMutex_tryLock_int_WRK(self, arg2);
3161 //-----------------------------------------------------------
3162 // It's not really very clear what the args are here. But from
3163 // a bit of dataflow analysis of the generated machine code of
3164 // the original function, it appears this takes two args, and
3165 // returns nothing. Nevertheless preserve return value just in
3166 // case. A bit of debug printing indicates that the first arg
3167 // is that of the mutex and the second is either zero or one,
3168 // probably being the recursion mode, therefore.
3169 // QMutex::QMutex(QMutex::RecursionMode) ("C1ENS" variant)
3170 __attribute__((noinline))
3171 static void* QMutex_constructor_WRK(void* mutex, long recmode)
3173 OrigFn fn;
3174 long ret;
3175 VALGRIND_GET_ORIG_FN(fn);
3176 CALL_FN_W_WW(ret, fn, mutex, recmode);
3177 // fprintf(stderr, "QMutex constructor 1: %p <- %p %p\n", ret, arg1, arg2);
3178 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
3179 void*,mutex, long,1/*mbRec*/);
3180 return (void*)ret;
3183 QT4_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE, void* self, long recmode) {
3184 return QMutex_constructor_WRK(self, recmode);
3186 QT5_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE, void* self, long recmode) {
3187 return QMutex_constructor_WRK(self, recmode);
3190 //-----------------------------------------------------------
3191 // QMutex::~QMutex() ("D1Ev" variant)
3192 __attribute__((noinline))
3193 static void* QMutex_destructor_WRK(void* mutex)
3195 OrigFn fn;
3196 long ret;
3197 VALGRIND_GET_ORIG_FN(fn);
3198 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
3199 void*,mutex);
3200 CALL_FN_W_W(ret, fn, mutex);
3201 return (void*)ret;
3204 QT4_FUNC(void*, _ZN6QMutexD1Ev, void* self) {
3205 return QMutex_destructor_WRK(self);
3207 QT5_FUNC(void*, _ZN6QMutexD1Ev, void* self) {
3208 return QMutex_destructor_WRK(self);
3211 //-----------------------------------------------------------
3212 // QMutex::QMutex(QMutex::RecursionMode) ("C2ENS" variant)
3213 QT4_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE,
3214 void* mutex,
3215 long recmode)
3217 assert(0);
3218 /*NOTREACHED*/
3219 /* Android's gcc behaves like it doesn't know that assert(0)
3220 never returns. Hence: */
3221 return NULL;
3224 QT5_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE, void* self, long recmode)
3226 assert(0);
3227 /*NOTREACHED*/
3228 return NULL;
3231 //-----------------------------------------------------------
3232 // QMutex::~QMutex() ("D2Ev" variant)
3233 QT4_FUNC(void*, _ZN6QMutexD2Ev, void* mutex)
3235 assert(0);
3236 /* Android's gcc behaves like it doesn't know that assert(0)
3237 never returns. Hence: */
3238 return NULL;
3241 QT5_FUNC(void*, _ZN6QMutexD2Ev, void* self)
3243 assert(0);
3244 /*NOTREACHED*/
3245 return NULL;
3248 // QReadWriteLock is not intercepted directly. See comments
3249 // above.
3251 //// QReadWriteLock::lockForRead()
3252 //// _ZN14QReadWriteLock11lockForReadEv == QReadWriteLock::lockForRead()
3253 //QT4_FUNC(void, ZuZZN14QReadWriteLock11lockForReadEv,
3254 // // _ZN14QReadWriteLock11lockForReadEv
3255 // void* self)
3257 // OrigFn fn;
3258 // VALGRIND_GET_ORIG_FN(fn);
3259 // if (TRACE_QT4_FNS) {
3260 // fprintf(stderr, "<< QReadWriteLock::lockForRead %p", self);
3261 // fflush(stderr);
3262 // }
3264 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
3265 // void*,self,
3266 // long,0/*!isW*/, long,0/*!isTryLock*/);
3268 // CALL_FN_v_W(fn, self);
3270 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
3271 // void*,self, long,0/*!isW*/, long, True);
3273 // if (TRACE_QT4_FNS) {
3274 // fprintf(stderr, " :: Q::lockForRead :: done >>\n");
3275 // }
3278 //// QReadWriteLock::lockForWrite()
3279 //// _ZN14QReadWriteLock12lockForWriteEv == QReadWriteLock::lockForWrite()
3280 //QT4_FUNC(void, ZuZZN14QReadWriteLock12lockForWriteEv,
3281 // // _ZN14QReadWriteLock12lockForWriteEv
3282 // void* self)
3284 // OrigFn fn;
3285 // VALGRIND_GET_ORIG_FN(fn);
3286 // if (TRACE_QT4_FNS) {
3287 // fprintf(stderr, "<< QReadWriteLock::lockForWrite %p", self);
3288 // fflush(stderr);
3289 // }
3291 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
3292 // void*,self,
3293 // long,1/*isW*/, long,0/*!isTryLock*/);
3295 // CALL_FN_v_W(fn, self);
3297 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
3298 // void*,self, long,1/*isW*/, long, True);
3300 // if (TRACE_QT4_FNS) {
3301 // fprintf(stderr, " :: Q::lockForWrite :: done >>\n");
3302 // }
3305 //// QReadWriteLock::unlock()
3306 //// _ZN14QReadWriteLock6unlockEv == QReadWriteLock::unlock()
3307 //QT4_FUNC(void, ZuZZN14QReadWriteLock6unlockEv,
3308 // // _ZN14QReadWriteLock6unlockEv
3309 // void* self)
3311 // OrigFn fn;
3312 // VALGRIND_GET_ORIG_FN(fn);
3313 // if (TRACE_QT4_FNS) {
3314 // fprintf(stderr, "<< QReadWriteLock::unlock %p", self);
3315 // fflush(stderr);
3316 // }
3318 // DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
3319 // void*,self);
3321 // CALL_FN_v_W(fn, self);
3323 // DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
3324 // void*,self);
3326 // if (TRACE_QT4_FNS) {
3327 // fprintf(stderr, " :: Q::unlock :: done >>\n");
3328 // }
3332 /*----------------------------------------------------------------*/
3333 /*--- Replacements for basic string functions, that don't ---*/
3334 /*--- overrun the input arrays. ---*/
3335 /*----------------------------------------------------------------*/
3337 #include "../shared/vg_replace_strmem.c"
3339 /*--------------------------------------------------------------------*/
3340 /*--- end hg_intercepts.c ---*/
3341 /*--------------------------------------------------------------------*/