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