-> 3.17.0.RC2
[valgrind.git] / helgrind / hg_intercepts.c
blob2bc89f8a09b953fb437e07b5b83c1e28cb48fcd3
2 /*--------------------------------------------------------------------*/
3 /*--- pthread intercepts for thread checking. ---*/
4 /*--- hg_intercepts.c ---*/
5 /*--------------------------------------------------------------------*/
7 /*
8 This file is part of Helgrind, a Valgrind tool for detecting errors
9 in threaded programs.
11 Copyright (C) 2007-2017 OpenWorks LLP
12 info@open-works.co.uk
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, see <http://www.gnu.org/licenses/>.
27 The GNU General Public License is contained in the file COPYING.
29 Neither the names of the U.S. Department of Energy nor the
30 University of California nor the names of its contributors may be
31 used to endorse or promote products derived from this software
32 without prior written permission.
35 /* RUNS ON SIMULATED CPU
36 Interceptors for pthread_* functions, so that tc_main can see
37 significant thread events.
39 Important: when adding a function wrapper to this file, remember to
40 add a test case to tc20_verifywrap.c. A common cause of failure is
41 for wrappers to not engage on different distros, and
42 tc20_verifywrap essentially checks that each wrapper is really
43 doing something.
46 // DDD: for Darwin, need to have non-"@*"-suffixed versions for all pthread
47 // functions that currently have them.
48 // Note also, in the comments and code below, all Darwin symbols start
49 // with a leading underscore, which is not shown either in the comments
50 // nor in the redirect specs.
53 #include "pub_tool_basics.h"
54 #include "pub_tool_redir.h"
55 #include "pub_tool_clreq.h"
56 #include "helgrind.h"
57 #include "config.h"
60 #if defined(VGO_solaris)
61 /* See porting comments in drd/drd_pthread_intercepts.c
62 However when a POSIX threads API function (for example pthread_cond_init)
63 is built upon the Solaris one (cond_init), intercept only the bottom one.
64 Helgrind does not contain generic synchronization nesting like DRD
65 and double intercept confuses it. */
66 #include <synch.h>
67 #include <thread.h>
68 #endif /* VGO_solaris */
71 #define TRACE_PTH_FNS 0
72 #define TRACE_QT4_FNS 0
73 #define TRACE_GNAT_FNS 0
76 /*----------------------------------------------------------------*/
77 /*--- ---*/
78 /*----------------------------------------------------------------*/
80 #if defined(VGO_solaris)
81 /* pthread_t is typedef'd to 'unsigned int' but in DO_CREQ_* macros
82 sizeof(Word) is expected. */
83 #define CREQ_PTHREAD_T Word
84 #define SEM_ERROR ret
85 #else
86 #define CREQ_PTHREAD_T pthread_t
87 #define SEM_ERROR errno
88 #endif /* VGO_solaris */
90 #define HG_EXPAND(tok) #tok
91 #define HG_STR(tok) HG_EXPAND(tok)
92 #define HG_WEAK_ALIAS(name, aliasname) \
93 extern __typeof (name) aliasname __attribute__ ((weak, alias(HG_STR(name))))
95 #if defined(VG_WRAP_THREAD_FUNCTION_LIBPTHREAD_ONLY)
96 #define PTH_FUNC(ret_ty, f, args...) \
97 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args); \
98 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args)
99 #elif defined(VG_WRAP_THREAD_FUNCTION_LIBC_AND_LIBPTHREAD)
100 #define PTH_FUNC(ret_ty, f, args...) \
101 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args); \
102 HG_WEAK_ALIAS(I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f), I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)); \
103 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args)
104 #elif defined(VG_WRAP_THREAD_FUNCTION_LIBC_ONLY)
105 #define PTH_FUNC(ret_ty, f, args...) \
106 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)(args); \
107 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)(args)
108 #else
109 # error "Unknown platform/thread wrapping"
110 #endif
112 // Do a client request. These are macros rather than a functions so
113 // as to avoid having an extra frame in stack traces.
115 // NB: these duplicate definitions in helgrind.h. But here, we
116 // can have better typing (Word etc) and assertions, whereas
117 // in helgrind.h we can't. Obviously it's important the two
118 // sets of definitions are kept in sync.
120 // nuke the previous definitions
121 #undef DO_CREQ_v_W
122 #undef DO_CREQ_v_WW
123 #undef DO_CREQ_W_WW
124 #undef DO_CREQ_v_WWW
126 #define DO_CREQ_v_W(_creqF, _ty1F,_arg1F) \
127 do { \
128 Word _arg1; \
129 assert(sizeof(_ty1F) == sizeof(Word)); \
130 _arg1 = (Word)(_arg1F); \
131 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
132 _arg1, 0,0,0,0); \
133 } while (0)
135 #define DO_CREQ_v_WW(_creqF, _ty1F,_arg1F, _ty2F,_arg2F) \
136 do { \
137 Word _arg1, _arg2; \
138 assert(sizeof(_ty1F) == sizeof(Word)); \
139 assert(sizeof(_ty2F) == sizeof(Word)); \
140 _arg1 = (Word)(_arg1F); \
141 _arg2 = (Word)(_arg2F); \
142 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
143 _arg1,_arg2,0,0,0); \
144 } while (0)
146 #define DO_CREQ_W_WW(_resF, _creqF, _ty1F,_arg1F, \
147 _ty2F,_arg2F) \
148 do { \
149 Word _res, _arg1, _arg2; \
150 assert(sizeof(_ty1F) == sizeof(Word)); \
151 assert(sizeof(_ty2F) == sizeof(Word)); \
152 _arg1 = (Word)(_arg1F); \
153 _arg2 = (Word)(_arg2F); \
154 _res = VALGRIND_DO_CLIENT_REQUEST_EXPR(2, \
155 (_creqF), \
156 _arg1,_arg2,0,0,0); \
157 _resF = _res; \
158 } while (0)
160 #define DO_CREQ_v_WWW(_creqF, _ty1F,_arg1F, \
161 _ty2F,_arg2F, _ty3F, _arg3F) \
162 do { \
163 Word _arg1, _arg2, _arg3; \
164 assert(sizeof(_ty1F) == sizeof(Word)); \
165 assert(sizeof(_ty2F) == sizeof(Word)); \
166 assert(sizeof(_ty3F) == sizeof(Word)); \
167 _arg1 = (Word)(_arg1F); \
168 _arg2 = (Word)(_arg2F); \
169 _arg3 = (Word)(_arg3F); \
170 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
171 _arg1,_arg2,_arg3,0,0); \
172 } while (0)
174 #define DO_CREQ_v_WWWW(_creqF, _ty1F,_arg1F, \
175 _ty2F, _arg2F, _ty3F, _arg3F, \
176 _ty4F, _arg4F) \
177 do { \
178 Word _arg1, _arg2, _arg3, _arg4; \
179 assert(sizeof(_ty1F) == sizeof(Word)); \
180 assert(sizeof(_ty2F) == sizeof(Word)); \
181 assert(sizeof(_ty3F) == sizeof(Word)); \
182 assert(sizeof(_ty4F) == sizeof(Word)); \
183 _arg1 = (Word)(_arg1F); \
184 _arg2 = (Word)(_arg2F); \
185 _arg3 = (Word)(_arg3F); \
186 _arg4 = (Word)(_arg4F); \
187 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
188 _arg1,_arg2,_arg3,_arg4,0); \
189 } while (0)
191 #define DO_PthAPIerror(_fnnameF, _errF) \
192 do { \
193 const char* _fnname = (_fnnameF); \
194 long _err = (long)(int)(_errF); \
195 const char* _errstr = lame_strerror(_err); \
196 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTH_API_ERROR, \
197 char*,_fnname, \
198 long,_err, char*,_errstr); \
199 } while (0)
202 /* Needed for older glibcs (2.3 and older, at least) who don't
203 otherwise "know" about pthread_rwlock_anything or about
204 PTHREAD_MUTEX_RECURSIVE (amongst things). */
205 #define _GNU_SOURCE 1
207 #include <stdio.h>
208 #include <assert.h>
209 #include <errno.h>
210 #include <pthread.h>
212 /* A standalone memcmp. */
213 __attribute__((noinline))
214 static int my_memcmp ( const void* ptr1, const void* ptr2, size_t size)
216 const unsigned char* uchar_ptr1 = (const unsigned char*) ptr1;
217 const unsigned char* uchar_ptr2 = (const unsigned char*) ptr2;
218 size_t i;
219 for (i = 0; i < size; ++i) {
220 if (uchar_ptr1[i] != uchar_ptr2[i])
221 return (uchar_ptr1[i] < uchar_ptr2[i]) ? -1 : 1;
223 return 0;
226 /* A lame version of strerror which doesn't use the real libc
227 strerror_r, since using the latter just generates endless more
228 threading errors (glibc goes off and does tons of crap w.r.t.
229 locales etc) */
230 static const HChar* lame_strerror ( long err )
232 switch (err) {
233 case EPERM: return "EPERM: Operation not permitted";
234 case ENOENT: return "ENOENT: No such file or directory";
235 case ESRCH: return "ESRCH: No such process";
236 case EINTR: return "EINTR: Interrupted system call";
237 case EBADF: return "EBADF: Bad file number";
238 case EAGAIN: return "EAGAIN: Try again";
239 case ENOMEM: return "ENOMEM: Out of memory";
240 case EACCES: return "EACCES: Permission denied";
241 case EFAULT: return "EFAULT: Bad address";
242 case EEXIST: return "EEXIST: File exists";
243 case EINVAL: return "EINVAL: Invalid argument";
244 case EMFILE: return "EMFILE: Too many open files";
245 case ENOSYS: return "ENOSYS: Function not implemented";
246 case EOVERFLOW: return "EOVERFLOW: Value too large "
247 "for defined data type";
248 case EBUSY: return "EBUSY: Device or resource busy";
249 case ETIMEDOUT: return "ETIMEDOUT: Connection timed out";
250 case EDEADLK: return "EDEADLK: Resource deadlock would occur";
251 case EOPNOTSUPP: return "EOPNOTSUPP: Operation not supported on "
252 "transport endpoint"; /* honest, guv */
253 case ETIME: return "ETIME: Timer expired";
254 default: return "hg_intercepts.c: lame_strerror(): "
255 "unhandled case -- please fix me!";
259 #if defined(VGO_solaris)
261 * Solaris provides higher throughput, parallelism and scalability than other
262 * operating systems, at the cost of more fine-grained locking activity.
263 * This means for example that when a thread is created under Linux, just one
264 * big lock in glibc is used for all thread setup. Solaris libc uses several
265 * fine-grained locks and the creator thread resumes its activities as soon
266 * as possible, leaving for example stack and TLS setup activities to the
267 * created thread.
269 * This situation confuses Helgrind as it assumes there is some false ordering
270 * in place between creator and created thread; and therefore many types of
271 * race conditions in the application would not be reported. To prevent such
272 * false ordering, command line option --ignore-thread-creation is set to
273 * 'yes' by default on Solaris. All activity (loads, stores, client requests)
274 * is therefore ignored during:
275 * - pthread_create() call in the creator thread [libc.so]
276 * - thread creation phase (stack and TLS setup) in the created thread [libc.so]
278 * As explained in the comments for _ti_bind_guard(), whenever the runtime
279 * linker has to perform any activity (such as resolving a symbol), it protects
280 * its data structures by calling into rt_bind_guard() which in turn invokes
281 * _ti_bind_guard() in libc. Pointers to _ti_bind_guard() and _ti_bind_clear()
282 * are passed from libc to runtime linker in _ld_libc() call during libc_init().
283 * All activity is also ignored during:
284 * - runtime dynamic linker work between rt_bind_guard() and rt_bind_clear()
285 * calls [ld.so]
287 * This also means that Helgrind does not report race conditions in libc (when
288 * --ignore-thread-creation=yes) and runtime linker itself (unconditionally)
289 * during these ignored sequences.
292 #include "pub_tool_libcassert.h"
293 #include "pub_tool_vki.h"
296 * Original function pointers for _ti_bind_guard() and _ti_bind_clear()
297 * from libc. They are intercepted in function wrapper of _ld_libc().
299 typedef int (*hg_rtld_guard_fn)(int flags);
300 static hg_rtld_guard_fn hg_rtld_bind_guard = NULL;
301 static hg_rtld_guard_fn hg_rtld_bind_clear = NULL;
303 static void hg_init(void) __attribute__((constructor));
304 static void hg_init(void)
306 if ((hg_rtld_bind_guard == NULL) || (hg_rtld_bind_clear == NULL)) {
307 fprintf(stderr,
308 "Bind guard functions for the runtime linker (ld.so.1) were not intercepted.\n"
309 "This means the interface between libc and runtime linker changed\n"
310 "and Helgrind needs to be ported properly. Giving up.\n");
311 tl_assert(0);
316 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
317 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
318 * and CI_BIND_CLEAR, to provide resilience against function renaming.
320 static int _ti_bind_guard_intercept_WRK(int flags)
322 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_RTLD_BIND_GUARD,
323 flags, 0, 0, 0, 0);
324 return hg_rtld_bind_guard(flags);
327 static int _ti_bind_clear_intercept_WRK(int flags)
329 int ret = hg_rtld_bind_clear(flags);
330 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_RTLD_BIND_CLEAR,
331 flags, 0, 0, 0, 0);
332 return ret;
336 * Wrapped _ld_libc() from the runtime linker ld.so.1.
338 void I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr);
339 void I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr)
341 OrigFn fn;
342 int tag;
344 VALGRIND_GET_ORIG_FN(fn);
346 vki_Lc_interface *funcs = ptr;
347 for (tag = funcs->ci_tag; tag != 0; tag = (++funcs)->ci_tag) {
348 switch (tag) {
349 case VKI_CI_BIND_GUARD:
350 if (funcs->vki_ci_un.ci_func != _ti_bind_guard_intercept_WRK) {
351 hg_rtld_bind_guard = funcs->vki_ci_un.ci_func;
352 funcs->vki_ci_un.ci_func = _ti_bind_guard_intercept_WRK;
354 break;
355 case VKI_CI_BIND_CLEAR:
356 if (funcs->vki_ci_un.ci_func != _ti_bind_clear_intercept_WRK) {
357 hg_rtld_bind_clear = funcs->vki_ci_un.ci_func;
358 funcs->vki_ci_un.ci_func = _ti_bind_clear_intercept_WRK;
360 break;
364 CALL_FN_v_W(fn, ptr);
366 #endif /* VGO_solaris */
369 /*----------------------------------------------------------------*/
370 /*--- pthread_create, pthread_join, pthread_exit ---*/
371 /*----------------------------------------------------------------*/
373 static void* mythread_wrapper ( void* xargsV )
375 volatile Word* xargs = (volatile Word*) xargsV;
376 void*(*fn)(void*) = (void*(*)(void*))xargs[0];
377 void* arg = (void*)xargs[1];
378 pthread_t me = pthread_self();
379 /* Tell the tool what my pthread_t is. */
380 DO_CREQ_v_W(_VG_USERREQ__HG_SET_MY_PTHREAD_T, CREQ_PTHREAD_T, me);
381 /* allow the parent to proceed. We can't let it proceed until
382 we're ready because (1) we need to make sure it doesn't exit and
383 hence deallocate xargs[] while we still need it, and (2) we
384 don't want either parent nor child to proceed until the tool has
385 been notified of the child's pthread_t.
387 Note that parent and child access args[] without a lock,
388 effectively using args[2] as a spinlock in order to get the
389 parent to wait until the child passes this point. The parent
390 disables checking on xargs[] before creating the child and
391 re-enables it once the child goes past this point, so the user
392 never sees the race. The previous approach (suppressing the
393 resulting error) was flawed, because it could leave shadow
394 memory for args[] in a state in which subsequent use of it by
395 the parent would report further races. */
396 xargs[2] = 0;
397 /* Now we can no longer safely use xargs[]. */
398 return (void*) fn( (void*)arg );
401 //-----------------------------------------------------------
402 // glibc: pthread_create@GLIBC_2.0
403 // glibc: pthread_create@@GLIBC_2.1
404 // glibc: pthread_create@@GLIBC_2.2.5
405 // darwin: pthread_create
406 // darwin: pthread_create_suspended_np (trapped)
408 /* ensure this has its own frame, so as to make it more distinguishable
409 in suppressions */
410 __attribute__((noinline))
411 static int pthread_create_WRK(pthread_t *thread, const pthread_attr_t *attr,
412 void *(*start) (void *), void *arg)
414 int ret;
415 OrigFn fn;
416 volatile Word xargs[3];
418 VALGRIND_GET_ORIG_FN(fn);
419 if (TRACE_PTH_FNS) {
420 fprintf(stderr, "<< pthread_create wrapper"); fflush(stderr);
422 xargs[0] = (Word)start;
423 xargs[1] = (Word)arg;
424 xargs[2] = 1; /* serves as a spinlock -- sigh */
425 /* Disable checking on the spinlock and the two words used to
426 convey args to the child. Basically we need to make it appear
427 as if the child never accessed this area, since merely
428 suppressing the resulting races does not address the issue that
429 that piece of the parent's stack winds up in the "wrong" state
430 and therefore may give rise to mysterious races when the parent
431 comes to re-use this piece of stack in some other frame. */
432 VALGRIND_HG_DISABLE_CHECKING(&xargs, sizeof(xargs));
434 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_BEGIN,
435 0, 0, 0, 0, 0);
436 CALL_FN_W_WWWW(ret, fn, thread,attr,mythread_wrapper,&xargs[0]);
437 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_END,
438 0, 0, 0, 0, 0);
440 if (ret == 0) {
441 /* we have to wait for the child to notify the tool of its
442 pthread_t before continuing */
443 while (xargs[2] != 0) {
444 /* Do nothing. We need to spin until the child writes to
445 xargs[2]. However, that can lead to starvation in the
446 child and very long delays (eg, tc19_shadowmem on
447 ppc64-linux Fedora Core 6). So yield the cpu if we can,
448 to let the child run at the earliest available
449 opportunity. */
450 sched_yield();
452 } else {
453 DO_PthAPIerror( "pthread_create", ret );
456 /* Reenable checking on the area previously used to communicate
457 with the child. */
458 VALGRIND_HG_ENABLE_CHECKING(&xargs, sizeof(xargs));
460 if (TRACE_PTH_FNS) {
461 fprintf(stderr, " :: pth_create -> %d >>\n", ret);
463 return ret;
465 #if defined(VGO_linux)
466 PTH_FUNC(int, pthreadZucreateZAZa, // pthread_create@*
467 pthread_t *thread, const pthread_attr_t *attr,
468 void *(*start) (void *), void *arg) {
469 return pthread_create_WRK(thread, attr, start, arg);
471 #elif defined(VGO_darwin)
472 PTH_FUNC(int, pthreadZucreate, // pthread_create
473 pthread_t *thread, const pthread_attr_t *attr,
474 void *(*start) (void *), void *arg) {
475 return pthread_create_WRK(thread, attr, start, arg);
477 PTH_FUNC(int, pthreadZucreateZuZa, // pthread_create_*
478 pthread_t *thread, const pthread_attr_t *attr,
479 void *(*start) (void *), void *arg) {
480 // trap anything else
481 assert(0);
483 #elif defined(VGO_solaris)
484 PTH_FUNC(int, pthreadZucreate, // pthread_create
485 pthread_t *thread, const pthread_attr_t *attr,
486 void *(*start) (void *), void *arg) {
487 return pthread_create_WRK(thread, attr, start, arg);
489 #else
490 # error "Unsupported OS"
491 #endif
493 #if defined(VGO_solaris)
494 /* Solaris also provides thr_create() in addition to pthread_create().
495 * Both pthread_create(3C) and thr_create(3C) are based on private
496 * _thrp_create().
498 __attribute__((noinline))
499 static int thr_create_WRK(void *stk, size_t stksize, void *(*start)(void *),
500 void *arg, long flags, thread_t *new_thread)
502 int ret;
503 OrigFn fn;
504 volatile Word xargs[3];
506 VALGRIND_GET_ORIG_FN(fn);
507 if (TRACE_PTH_FNS) {
508 fprintf(stderr, "<< thr_create wrapper"); fflush(stderr);
510 xargs[0] = (Word)start;
511 xargs[1] = (Word)arg;
512 xargs[2] = 1; /* serves as a spinlock -- sigh */
513 /* See comments in pthread_create_WRK() */
514 VALGRIND_HG_DISABLE_CHECKING(&xargs, sizeof(xargs));
516 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_BEGIN,
517 0, 0, 0, 0, 0);
518 CALL_FN_W_6W(ret, fn, stk, stksize, mythread_wrapper, start, flags,
519 new_thread);
520 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_END,
521 0, 0, 0, 0, 0);
523 if (ret == 0) {
524 while (xargs[2] != 0) {
525 /* See comments in pthread_create_WRK(). */
526 sched_yield();
528 } else {
529 DO_PthAPIerror("thr_create", ret);
532 VALGRIND_HG_ENABLE_CHECKING(&xargs, sizeof(xargs));
534 if (TRACE_PTH_FNS) {
535 fprintf(stderr, " :: thr_create -> %d >>\n", ret);
537 return ret;
539 PTH_FUNC(int, thrZucreate, // thr_create
540 void *stk, size_t stksize, void *(*start)(void *),
541 void *arg, long flags, thread_t *new_thread) {
542 return thr_create_WRK(stk, stksize, start, arg, flags, new_thread);
544 #endif /* VGO_solaris */
547 //-----------------------------------------------------------
548 // glibc: pthread_join
549 // darwin: pthread_join
550 // darwin: pthread_join$NOCANCEL$UNIX2003
551 // darwin pthread_join$UNIX2003
552 __attribute__((noinline))
553 static int pthread_join_WRK(pthread_t thread, void** value_pointer)
555 int ret;
556 OrigFn fn;
557 VALGRIND_GET_ORIG_FN(fn);
558 if (TRACE_PTH_FNS) {
559 fprintf(stderr, "<< pthread_join wrapper"); fflush(stderr);
562 CALL_FN_W_WW(ret, fn, thread,value_pointer);
564 /* At least with NPTL as the thread library, this is safe because
565 it is guaranteed (by NPTL) that the joiner will completely gone
566 before pthread_join (the original) returns. See email below.*/
567 if (ret == 0 /*success*/) {
568 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST, CREQ_PTHREAD_T, thread);
569 } else {
570 DO_PthAPIerror( "pthread_join", ret );
573 if (TRACE_PTH_FNS) {
574 fprintf(stderr, " :: pth_join -> %d >>\n", ret);
576 return ret;
578 #if defined(VGO_linux)
579 PTH_FUNC(int, pthreadZujoin, // pthread_join
580 pthread_t thread, void** value_pointer) {
581 return pthread_join_WRK(thread, value_pointer);
583 #elif defined(VGO_darwin)
584 PTH_FUNC(int, pthreadZujoinZa, // pthread_join*
585 pthread_t thread, void** value_pointer) {
586 return pthread_join_WRK(thread, value_pointer);
588 #elif defined(VGO_solaris)
589 PTH_FUNC(int, pthreadZujoin, // pthread_join
590 pthread_t thread, void** value_pointer) {
591 return pthread_join_WRK(thread, value_pointer);
593 #else
594 # error "Unsupported OS"
595 #endif
598 /* Behaviour of pthread_join on NPTL:
601 I have a question re the NPTL pthread_join implementation.
603 Suppose I am the thread 'stayer'.
605 If I call pthread_join(quitter), is it guaranteed that the
606 thread 'quitter' has really exited before pthread_join returns?
608 IOW, is it guaranteed that 'quitter' will not execute any further
609 instructions after pthread_join returns?
611 I believe this is true based on the following analysis of
612 glibc-2.5 sources. However am not 100% sure and would appreciate
613 confirmation.
615 'quitter' will be running start_thread() in nptl/pthread_create.c
617 The last action of start_thread() is to exit via
618 __exit_thread_inline(0), which simply does sys_exit
619 (nptl/pthread_create.c:403)
621 'stayer' meanwhile is waiting for lll_wait_tid (pd->tid)
622 (call at nptl/pthread_join.c:89)
624 As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
625 lll_wait_tid will not return until kernel notifies via futex
626 wakeup that 'quitter' has terminated.
628 Hence pthread_join cannot return until 'quitter' really has
629 completely disappeared.
631 Drepper:
632 > As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
633 > lll_wait_tid will not return until kernel notifies via futex
634 > wakeup that 'quitter' has terminated.
635 That's the key. The kernel resets the TID field after the thread is
636 done. No way the joiner can return before the thread is gone.
639 #if defined(VGO_solaris)
640 /* Solaris also provides thr_join() in addition to pthread_join().
641 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
643 * :TODO: No functionality is currently provided for joinee == 0 and departed.
644 * This would require another client request, of course.
646 __attribute__((noinline))
647 static int thr_join_WRK(thread_t joinee, thread_t *departed, void **thread_return)
649 int ret;
650 OrigFn fn;
651 VALGRIND_GET_ORIG_FN(fn);
652 if (TRACE_PTH_FNS) {
653 fprintf(stderr, "<< thr_join wrapper"); fflush(stderr);
656 CALL_FN_W_WWW(ret, fn, joinee, departed, thread_return);
658 if (ret == 0 /*success*/) {
659 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST, CREQ_PTHREAD_T, joinee);
660 } else {
661 DO_PthAPIerror("thr_join", ret);
664 if (TRACE_PTH_FNS) {
665 fprintf(stderr, " :: thr_join -> %d >>\n", ret);
667 return ret;
669 PTH_FUNC(int, thrZujoin, // thr_join
670 thread_t joinee, thread_t *departed, void **thread_return) {
671 return thr_join_WRK(joinee, departed, thread_return);
673 #endif /* VGO_solaris */
676 //-----------------------------------------------------------
677 // Ada gcc gnat runtime:
678 // The gnat gcc Ada runtime does not use pthread_join. Instead, it uses
679 // a combination of other pthread primitives to ensure a child thread
680 // is gone. This combination is somewhat functionally equivalent to a
681 // pthread_join.
682 // We wrap two hook procedures called by the gnat gcc Ada runtime
683 // that allows helgrind to understand the semantic of Ada task dependencies
684 // and termination.
685 // procedure Master_Hook
686 // (Dependent : Task_Id;
687 // Parent : Task_Id;
688 // Master_Level : Integer);
689 // where type Task_Id is access all Ada_Task_Control_Block;
690 // System.Tasking.Debug.Master_Hook is called by a task Dependent to
691 // indicate that its master is identified by master+master_level.
692 void I_WRAP_SONAME_FNNAME_ZU
693 (Za,
694 system__tasking__debug__master_hook)
695 (void *dependent, void *master, int master_level);
696 void I_WRAP_SONAME_FNNAME_ZU
697 (Za,
698 system__tasking__debug__master_hook)
699 (void *dependent, void *master, int master_level)
701 OrigFn fn;
702 VALGRIND_GET_ORIG_FN(fn);
703 if (TRACE_GNAT_FNS) {
704 fprintf(stderr, "<< GNAT master_hook wrapper "
705 "dependent %p master %p master_level %d\n",
706 dependent, master, master_level); fflush(stderr);
709 // We call the wrapped function, even if it is a null body.
710 CALL_FN_v_WWW(fn, dependent, master, master_level);
712 DO_CREQ_v_WWW(_VG_USERREQ__HG_GNAT_MASTER_HOOK,
713 void*,dependent, void*,master,
714 Word, (Word)master_level);
716 if (TRACE_GNAT_FNS) {
717 fprintf(stderr, " :: GNAT master_hook >>\n");
721 // System.Tasking.Debug.Master_Completed_Hook is called by a task to
722 // indicate that it has completed a master.
723 // procedure Master_Completed_Hook
724 // (Self_ID : Task_Id;
725 // Master_Level : Integer);
726 // where type Task_Id is access all Ada_Task_Control_Block;
727 // This indicates that all its Dependent tasks (that identified themselves
728 // with the Master_Hook call) are terminated. Helgrind can consider
729 // at this point that the equivalent of a 'pthread_join' has been done
730 // between self_id and all dependent tasks at master_level.
731 void I_WRAP_SONAME_FNNAME_ZU
732 (Za,
733 system__tasking__debug__master_completed_hook)
734 (void *self_id, int master_level);
735 void I_WRAP_SONAME_FNNAME_ZU
736 (Za,
737 system__tasking__debug__master_completed_hook)
738 (void *self_id, int master_level)
740 OrigFn fn;
741 VALGRIND_GET_ORIG_FN(fn);
742 if (TRACE_GNAT_FNS) {
743 fprintf(stderr, "<< GNAT master_completed_hook wrapper "
744 "self_id %p master_level %d\n",
745 self_id, master_level); fflush(stderr);
748 // We call the wrapped function, even if it is a null body.
749 CALL_FN_v_WW(fn, self_id, master_level);
751 DO_CREQ_v_WW(_VG_USERREQ__HG_GNAT_MASTER_COMPLETED_HOOK,
752 void*,self_id, Word,(Word)master_level);
754 if (TRACE_GNAT_FNS) {
755 fprintf(stderr, " :: GNAT master_completed_hook >>\n");
759 /*----------------------------------------------------------------*/
760 /*--- pthread_mutex_t functions ---*/
761 /*----------------------------------------------------------------*/
763 /* Handled: pthread_mutex_init pthread_mutex_destroy
764 pthread_mutex_lock
765 pthread_mutex_trylock pthread_mutex_timedlock
766 pthread_mutex_unlock
769 //-----------------------------------------------------------
770 #if !defined(VGO_solaris)
771 // glibc: pthread_mutex_init
772 // darwin: pthread_mutex_init
773 PTH_FUNC(int, pthreadZumutexZuinit, // pthread_mutex_init
774 pthread_mutex_t *mutex,
775 pthread_mutexattr_t* attr)
777 int ret;
778 long mbRec;
779 OrigFn fn;
780 VALGRIND_GET_ORIG_FN(fn);
781 if (TRACE_PTH_FNS) {
782 fprintf(stderr, "<< pthread_mxinit %p", mutex); fflush(stderr);
785 mbRec = 0;
786 if (attr) {
787 int ty, zzz;
788 zzz = pthread_mutexattr_gettype(attr, &ty);
789 if (zzz == 0 && ty == PTHREAD_MUTEX_RECURSIVE)
790 mbRec = 1;
793 CALL_FN_W_WW(ret, fn, mutex,attr);
795 if (ret == 0 /*success*/) {
796 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
797 pthread_mutex_t*,mutex, long,mbRec);
798 } else {
799 DO_PthAPIerror( "pthread_mutex_init", ret );
802 if (TRACE_PTH_FNS) {
803 fprintf(stderr, " :: mxinit -> %d >>\n", ret);
805 return ret;
808 #else /* VGO_solaris */
810 // Solaris: mutex_init (pthread_mutex_init calls here)
811 PTH_FUNC(int, mutexZuinit, // mutex_init
812 mutex_t *mutex, int type, void *arg)
814 int ret;
815 long mbRec;
816 OrigFn fn;
817 VALGRIND_GET_ORIG_FN(fn);
818 if (TRACE_PTH_FNS) {
819 fprintf(stderr, "<< mxinit %p", mutex); fflush(stderr);
822 mbRec = ((type & LOCK_RECURSIVE) != 0) ? 1 : 0;
824 CALL_FN_W_WWW(ret, fn, mutex, type, arg);
826 if (ret == 0 /*success*/) {
827 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
828 mutex_t *, mutex, long, mbRec);
829 } else {
830 DO_PthAPIerror("mutex_init", ret);
833 if (TRACE_PTH_FNS) {
834 fprintf(stderr, " :: mxinit -> %d >>\n", ret);
836 return ret;
838 #endif /* VGO_solaris */
841 //-----------------------------------------------------------
842 // glibc: pthread_mutex_destroy
843 // darwin: pthread_mutex_destroy
844 // Solaris: mutex_destroy (pthread_mutex_destroy is a weak alias)
845 __attribute__((noinline))
846 static int mutex_destroy_WRK(pthread_mutex_t *mutex)
848 int ret;
849 unsigned long mutex_is_init;
850 OrigFn fn;
852 VALGRIND_GET_ORIG_FN(fn);
853 if (TRACE_PTH_FNS) {
854 fprintf(stderr, "<< pthread_mxdestroy %p", mutex); fflush(stderr);
857 if (mutex != NULL) {
858 static const pthread_mutex_t mutex_init = PTHREAD_MUTEX_INITIALIZER;
859 mutex_is_init = my_memcmp(mutex, &mutex_init, sizeof(*mutex)) == 0;
860 } else {
861 mutex_is_init = 0;
864 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
865 pthread_mutex_t*, mutex, unsigned long, mutex_is_init);
867 CALL_FN_W_W(ret, fn, mutex);
869 if (ret != 0) {
870 DO_PthAPIerror( "pthread_mutex_destroy", ret );
873 if (TRACE_PTH_FNS) {
874 fprintf(stderr, " :: mxdestroy -> %d >>\n", ret);
876 return ret;
879 #if defined(VGO_linux) || defined(VGO_darwin)
880 PTH_FUNC(int, pthreadZumutexZudestroy, // pthread_mutex_destroy
881 pthread_mutex_t *mutex) {
882 return mutex_destroy_WRK(mutex);
884 #elif defined(VGO_solaris)
885 PTH_FUNC(int, mutexZudestroy, // mutex_destroy
886 pthread_mutex_t *mutex) {
887 return mutex_destroy_WRK(mutex);
889 #else
890 # error "Unsupported OS"
891 #endif
894 //-----------------------------------------------------------
895 // glibc: pthread_mutex_lock
896 // darwin: pthread_mutex_lock
897 // Solaris: mutex_lock (pthread_mutex_lock is a weak alias)
898 __attribute__((noinline))
899 static int mutex_lock_WRK(pthread_mutex_t *mutex)
901 int ret;
902 OrigFn fn;
903 VALGRIND_GET_ORIG_FN(fn);
904 if (TRACE_PTH_FNS) {
905 fprintf(stderr, "<< pthread_mxlock %p", mutex); fflush(stderr);
908 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
909 pthread_mutex_t*,mutex, long,0/*!isTryLock*/);
911 CALL_FN_W_W(ret, fn, mutex);
913 /* There's a hole here: libpthread now knows the lock is locked,
914 but the tool doesn't, so some other thread could run and detect
915 that the lock has been acquired by someone (this thread). Does
916 this matter? Not sure, but I don't think so. */
918 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
919 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
921 if (ret != 0) {
922 DO_PthAPIerror( "pthread_mutex_lock", ret );
925 if (TRACE_PTH_FNS) {
926 fprintf(stderr, " :: mxlock -> %d >>\n", ret);
928 return ret;
931 #if defined(VGO_linux) || defined(VGO_darwin)
932 PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock
933 pthread_mutex_t *mutex) {
934 return mutex_lock_WRK(mutex);
936 #elif defined(VGO_solaris)
937 PTH_FUNC(int, mutexZulock, // mutex_lock
938 pthread_mutex_t *mutex) {
939 return mutex_lock_WRK(mutex);
941 #else
942 # error "Unsupported OS"
943 #endif
945 #if defined(VGO_solaris)
946 /* Internal to libc. Mutex is usually initialized only implicitly,
947 * by zeroing mutex_t structure.
949 __attribute__((noinline))
950 PTH_FUNC(void, lmutexZulock, // lmutex_lock
951 mutex_t *mutex)
953 OrigFn fn;
954 VALGRIND_GET_ORIG_FN(fn);
955 if (TRACE_PTH_FNS) {
956 fprintf(stderr, "<< lmxlock %p", mutex); fflush(stderr);
959 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
960 mutex_t *, mutex, long, 0 /*!isTryLock*/);
961 CALL_FN_v_W(fn, mutex);
962 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
963 mutex_t *, mutex, long, True);
965 if (TRACE_PTH_FNS) {
966 fprintf(stderr, " :: lmxlock >>\n");
969 #endif /* VGO_solaris */
972 //-----------------------------------------------------------
973 // glibc: pthread_mutex_trylock
974 // darwin: pthread_mutex_trylock
975 // Solaris: mutex_trylock (pthread_mutex_trylock is a weak alias)
977 // pthread_mutex_trylock. The handling needed here is very similar
978 // to that for pthread_mutex_lock, except that we need to tell
979 // the pre-lock creq that this is a trylock-style operation, and
980 // therefore not to complain if the lock is nonrecursive and
981 // already locked by this thread -- because then it'll just fail
982 // immediately with EBUSY.
983 __attribute__((noinline))
984 static int mutex_trylock_WRK(pthread_mutex_t *mutex)
986 int ret;
987 OrigFn fn;
988 VALGRIND_GET_ORIG_FN(fn);
989 if (TRACE_PTH_FNS) {
990 fprintf(stderr, "<< pthread_mxtrylock %p", mutex); fflush(stderr);
993 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
994 pthread_mutex_t*,mutex, long,1/*isTryLock*/);
996 CALL_FN_W_W(ret, fn, mutex);
998 /* There's a hole here: libpthread now knows the lock is locked,
999 but the tool doesn't, so some other thread could run and detect
1000 that the lock has been acquired by someone (this thread). Does
1001 this matter? Not sure, but I don't think so. */
1003 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1004 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
1006 if (ret != 0) {
1007 if (ret != EBUSY)
1008 DO_PthAPIerror( "pthread_mutex_trylock", ret );
1011 if (TRACE_PTH_FNS) {
1012 fprintf(stderr, " :: mxtrylock -> %d >>\n", ret);
1014 return ret;
1017 #if defined(VGO_linux) || defined(VGO_darwin)
1018 PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock
1019 pthread_mutex_t *mutex) {
1020 return mutex_trylock_WRK(mutex);
1022 #elif defined(VGO_solaris)
1023 PTH_FUNC(int, mutexZutrylock, // mutex_trylock
1024 pthread_mutex_t *mutex) {
1025 return mutex_trylock_WRK(mutex);
1027 #else
1028 # error "Unsupported OS"
1029 #endif
1032 //-----------------------------------------------------------
1033 // glibc: pthread_mutex_timedlock
1034 // darwin: (doesn't appear to exist)
1035 // Solaris: pthread_mutex_timedlock
1037 // pthread_mutex_timedlock. Identical logic to pthread_mutex_trylock.
1038 __attribute__((noinline))
1039 static int mutex_timedlock_WRK(pthread_mutex_t *mutex,
1040 void *timeout)
1042 int ret;
1043 OrigFn fn;
1044 VALGRIND_GET_ORIG_FN(fn);
1045 if (TRACE_PTH_FNS) {
1046 fprintf(stderr, "<< pthread_mxtimedlock %p %p", mutex, timeout);
1047 fflush(stderr);
1050 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
1051 pthread_mutex_t*,mutex, long,1/*isTryLock-ish*/);
1053 CALL_FN_W_WW(ret, fn, mutex,timeout);
1055 /* There's a hole here: libpthread now knows the lock is locked,
1056 but the tool doesn't, so some other thread could run and detect
1057 that the lock has been acquired by someone (this thread). Does
1058 this matter? Not sure, but I don't think so. */
1060 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1061 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
1063 if (ret != 0) {
1064 if (ret != ETIMEDOUT)
1065 DO_PthAPIerror( "pthread_mutex_timedlock", ret );
1068 if (TRACE_PTH_FNS) {
1069 fprintf(stderr, " :: mxtimedlock -> %d >>\n", ret);
1071 return ret;
1074 PTH_FUNC(int, pthreadZumutexZutimedlock, // pthread_mutex_timedlock
1075 pthread_mutex_t *mutex,
1076 void *timeout) {
1077 return mutex_timedlock_WRK(mutex, timeout);
1079 #if defined(VGO_solaris)
1080 PTH_FUNC(int, pthreadZumutexZureltimedlock, // pthread_mutex_reltimedlock
1081 pthread_mutex_t *mutex,
1082 void *timeout) {
1083 return mutex_timedlock_WRK(mutex, timeout);
1085 #endif
1088 //-----------------------------------------------------------
1089 // glibc: pthread_mutex_unlock
1090 // darwin: pthread_mutex_unlock
1091 // Solaris: mutex_unlock (pthread_mutex_unlock is a weak alias)
1092 __attribute__((noinline))
1093 static int mutex_unlock_WRK(pthread_mutex_t *mutex)
1095 int ret;
1096 OrigFn fn;
1097 VALGRIND_GET_ORIG_FN(fn);
1099 if (TRACE_PTH_FNS) {
1100 fprintf(stderr, "<< pthread_mxunlk %p", mutex); fflush(stderr);
1103 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1104 pthread_mutex_t*,mutex);
1106 CALL_FN_W_W(ret, fn, mutex);
1108 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
1109 pthread_mutex_t*,mutex);
1111 if (ret != 0) {
1112 DO_PthAPIerror( "pthread_mutex_unlock", ret );
1115 if (TRACE_PTH_FNS) {
1116 fprintf(stderr, " mxunlk -> %d >>\n", ret);
1118 return ret;
1121 #if defined(VGO_linux) || defined(VGO_darwin)
1122 PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock
1123 pthread_mutex_t *mutex) {
1124 return mutex_unlock_WRK(mutex);
1126 #elif defined(VGO_solaris)
1127 PTH_FUNC(int, mutexZuunlock, // mutex_unlock
1128 pthread_mutex_t *mutex) {
1129 return mutex_unlock_WRK(mutex);
1131 #else
1132 # error "Unsupported OS"
1133 #endif
1136 #if defined(VGO_solaris)
1137 /* Internal to libc. */
1138 __attribute__((noinline))
1139 PTH_FUNC(void, lmutexZuunlock, // lmutex_unlock
1140 mutex_t *mutex)
1142 OrigFn fn;
1143 VALGRIND_GET_ORIG_FN(fn);
1145 if (TRACE_PTH_FNS) {
1146 fprintf(stderr, "<< lmxunlk %p", mutex); fflush(stderr);
1149 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1150 mutex_t *, mutex);
1151 CALL_FN_v_W(fn, mutex);
1152 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
1153 mutex_t*, mutex);
1155 if (TRACE_PTH_FNS) {
1156 fprintf(stderr, " lmxunlk >>\n");
1159 #endif /* VGO_solaris */
1162 /*----------------------------------------------------------------*/
1163 /*--- pthread_cond_t functions ---*/
1164 /*----------------------------------------------------------------*/
1166 /* Handled: pthread_cond_wait pthread_cond_timedwait
1167 pthread_cond_signal pthread_cond_broadcast
1168 pthread_cond_init
1169 pthread_cond_destroy
1172 //-----------------------------------------------------------
1173 // glibc: pthread_cond_wait@GLIBC_2.2.5
1174 // glibc: pthread_cond_wait@@GLIBC_2.3.2
1175 // darwin: pthread_cond_wait
1176 // darwin: pthread_cond_wait$NOCANCEL$UNIX2003
1177 // darwin: pthread_cond_wait$UNIX2003
1178 // Solaris: cond_wait (pthread_cond_wait is built atop of cond_wait)
1180 __attribute__((noinline))
1181 static int pthread_cond_wait_WRK(pthread_cond_t* cond,
1182 pthread_mutex_t* mutex)
1184 int ret;
1185 OrigFn fn;
1186 unsigned long mutex_is_valid;
1188 VALGRIND_GET_ORIG_FN(fn);
1190 if (TRACE_PTH_FNS) {
1191 fprintf(stderr, "<< pthread_cond_wait %p %p", cond, mutex);
1192 fflush(stderr);
1195 /* Tell the tool a cond-wait is about to happen, so it can check
1196 for bogus argument values. In return it tells us whether it
1197 thinks the mutex is valid or not. */
1198 DO_CREQ_W_WW(mutex_is_valid,
1199 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
1200 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
1201 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
1203 /* Tell the tool we're about to drop the mutex. This reflects the
1204 fact that in a cond_wait, we show up holding the mutex, and the
1205 call atomically drops the mutex and waits for the cv to be
1206 signalled. */
1207 if (mutex_is_valid) {
1208 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1209 pthread_mutex_t*,mutex);
1212 CALL_FN_W_WW(ret, fn, cond,mutex);
1214 /* this conditional look stupid, but compare w/ same logic for
1215 pthread_cond_timedwait below */
1216 if (mutex_is_valid) {
1217 /* and now we have the mutex again if (ret == 0) */
1218 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1219 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
1222 DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
1223 pthread_cond_t*,cond, pthread_mutex_t*,mutex, long,0,
1224 long, (ret == 0 && mutex_is_valid) ? True : False);
1226 if (ret != 0) {
1227 DO_PthAPIerror( "pthread_cond_wait", ret );
1230 if (TRACE_PTH_FNS) {
1231 fprintf(stderr, " cowait -> %d >>\n", ret);
1234 return ret;
1236 #if defined(VGO_linux)
1237 PTH_FUNC(int, pthreadZucondZuwaitZAZa, // pthread_cond_wait@*
1238 pthread_cond_t* cond, pthread_mutex_t* mutex) {
1239 return pthread_cond_wait_WRK(cond, mutex);
1241 #elif defined(VGO_darwin)
1242 PTH_FUNC(int, pthreadZucondZuwaitZa, // pthread_cond_wait*
1243 pthread_cond_t* cond, pthread_mutex_t* mutex) {
1244 return pthread_cond_wait_WRK(cond, mutex);
1246 #elif defined(VGO_solaris)
1247 PTH_FUNC(int, condZuwait, // cond_wait
1248 pthread_cond_t *cond, pthread_mutex_t *mutex) {
1249 return pthread_cond_wait_WRK(cond, mutex);
1251 #else
1252 # error "Unsupported OS"
1253 #endif
1256 //-----------------------------------------------------------
1257 // glibc: pthread_cond_timedwait@@GLIBC_2.3.2
1258 // glibc: pthread_cond_timedwait@GLIBC_2.2.5
1259 // glibc: pthread_cond_timedwait@GLIBC_2.0
1260 // darwin: pthread_cond_timedwait
1261 // darwin: pthread_cond_timedwait$NOCANCEL$UNIX2003
1262 // darwin: pthread_cond_timedwait$UNIX2003
1263 // darwin: pthread_cond_timedwait_relative_np (trapped)
1264 // Solaris: cond_timedwait (pthread_cond_timedwait is built on cond_timedwait)
1265 // Solaris: cond_reltimedwait (pthread_cond_reltimedwait_np is built on this)
1267 __attribute__((noinline))
1268 static int pthread_cond_timedwait_WRK(pthread_cond_t* cond,
1269 pthread_mutex_t* mutex,
1270 struct timespec* abstime,
1271 int timeout_error)
1273 int ret;
1274 OrigFn fn;
1275 unsigned long mutex_is_valid;
1276 Bool abstime_is_valid;
1277 VALGRIND_GET_ORIG_FN(fn);
1279 if (TRACE_PTH_FNS) {
1280 fprintf(stderr, "<< pthread_cond_timedwait %p %p %p",
1281 cond, mutex, abstime);
1282 fflush(stderr);
1285 /* Tell the tool a cond-wait is about to happen, so it can check
1286 for bogus argument values. In return it tells us whether it
1287 thinks the mutex is valid or not. */
1288 DO_CREQ_W_WW(mutex_is_valid,
1289 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
1290 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
1291 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
1293 abstime_is_valid = abstime->tv_nsec >= 0 && abstime->tv_nsec < 1000000000;
1295 /* Tell the tool we're about to drop the mutex. This reflects the
1296 fact that in a cond_wait, we show up holding the mutex, and the
1297 call atomically drops the mutex and waits for the cv to be
1298 signalled. */
1299 if (mutex_is_valid && abstime_is_valid) {
1300 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1301 pthread_mutex_t*,mutex);
1304 CALL_FN_W_WWW(ret, fn, cond,mutex,abstime);
1306 if (mutex_is_valid && !abstime_is_valid && ret != EINVAL) {
1307 DO_PthAPIerror("Bug in libpthread: pthread_cond_timedwait "
1308 "invalid abstime did not cause"
1309 " EINVAL", ret);
1312 if (mutex_is_valid && abstime_is_valid) {
1313 /* and now we have the mutex again if (ret == 0 || ret == timeout) */
1314 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1315 pthread_mutex_t *, mutex,
1316 long, (ret == 0 || ret == timeout_error) ? True : False);
1319 DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
1320 pthread_cond_t*,cond, pthread_mutex_t*,mutex,
1321 long,ret == timeout_error,
1322 long, (ret == 0 || ret == timeout_error) && mutex_is_valid
1323 ? True : False);
1325 if (ret != 0 && ret != timeout_error) {
1326 DO_PthAPIerror( "pthread_cond_timedwait", ret );
1329 if (TRACE_PTH_FNS) {
1330 fprintf(stderr, " cotimedwait -> %d >>\n", ret);
1333 return ret;
1335 #if defined(VGO_linux)
1336 PTH_FUNC(int, pthreadZucondZutimedwaitZAZa, // pthread_cond_timedwait@*
1337 pthread_cond_t* cond, pthread_mutex_t* mutex,
1338 struct timespec* abstime) {
1339 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
1341 #elif defined(VGO_darwin)
1342 PTH_FUNC(int, pthreadZucondZutimedwait, // pthread_cond_timedwait
1343 pthread_cond_t* cond, pthread_mutex_t* mutex,
1344 struct timespec* abstime) {
1345 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
1347 PTH_FUNC(int, pthreadZucondZutimedwaitZDZa, // pthread_cond_timedwait$*
1348 pthread_cond_t* cond, pthread_mutex_t* mutex,
1349 struct timespec* abstime) {
1350 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
1352 PTH_FUNC(int, pthreadZucondZutimedwaitZuZa, // pthread_cond_timedwait_*
1353 pthread_cond_t* cond, pthread_mutex_t* mutex,
1354 struct timespec* abstime) {
1355 assert(0);
1357 #elif defined(VGO_solaris)
1358 PTH_FUNC(int, condZutimedwait, // cond_timedwait
1359 pthread_cond_t *cond, pthread_mutex_t *mutex,
1360 struct timespec *abstime) {
1361 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIME);
1363 PTH_FUNC(int, condZureltimedwait, // cond_reltimedwait
1364 pthread_cond_t *cond, pthread_mutex_t *mutex,
1365 struct timespec *reltime) {
1366 return pthread_cond_timedwait_WRK(cond, mutex, reltime, ETIME);
1368 #else
1369 # error "Unsupported OS"
1370 #endif
1373 //-----------------------------------------------------------
1374 // glibc: pthread_cond_signal@GLIBC_2.0
1375 // glibc: pthread_cond_signal@GLIBC_2.2.5
1376 // glibc: pthread_cond_signal@@GLIBC_2.3.2
1377 // darwin: pthread_cond_signal
1378 // darwin: pthread_cond_signal_thread_np (don't intercept this)
1379 // Solaris: cond_signal (pthread_cond_signal is a weak alias)
1381 __attribute__((noinline))
1382 static int pthread_cond_signal_WRK(pthread_cond_t* cond)
1384 int ret;
1385 OrigFn fn;
1386 VALGRIND_GET_ORIG_FN(fn);
1388 if (TRACE_PTH_FNS) {
1389 fprintf(stderr, "<< pthread_cond_signal %p", cond);
1390 fflush(stderr);
1393 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE,
1394 pthread_cond_t*,cond);
1396 CALL_FN_W_W(ret, fn, cond);
1398 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_POST,
1399 pthread_cond_t*,cond);
1401 if (ret != 0) {
1402 DO_PthAPIerror( "pthread_cond_signal", ret );
1405 if (TRACE_PTH_FNS) {
1406 fprintf(stderr, " cosig -> %d >>\n", ret);
1409 return ret;
1411 #if defined(VGO_linux)
1412 PTH_FUNC(int, pthreadZucondZusignalZAZa, // pthread_cond_signal@*
1413 pthread_cond_t* cond) {
1414 return pthread_cond_signal_WRK(cond);
1416 #elif defined(VGO_darwin)
1417 PTH_FUNC(int, pthreadZucondZusignal, // pthread_cond_signal
1418 pthread_cond_t* cond) {
1419 return pthread_cond_signal_WRK(cond);
1421 #elif defined(VGO_solaris)
1422 PTH_FUNC(int, condZusignal, // cond_signal
1423 pthread_cond_t *cond) {
1424 return pthread_cond_signal_WRK(cond);
1426 #else
1427 # error "Unsupported OS"
1428 #endif
1431 //-----------------------------------------------------------
1432 // glibc: pthread_cond_broadcast@GLIBC_2.0
1433 // glibc: pthread_cond_broadcast@GLIBC_2.2.5
1434 // glibc: pthread_cond_broadcast@@GLIBC_2.3.2
1435 // darwin: pthread_cond_broadcast
1436 // Solaris: cond_broadcast (pthread_cond_broadcast is a weak alias)
1438 // Note, this is pretty much identical, from a dependency-graph
1439 // point of view, with cond_signal, so the code is duplicated.
1440 // Maybe it should be commoned up.
1442 __attribute__((noinline))
1443 static int pthread_cond_broadcast_WRK(pthread_cond_t* cond)
1445 int ret;
1446 OrigFn fn;
1447 VALGRIND_GET_ORIG_FN(fn);
1449 if (TRACE_PTH_FNS) {
1450 fprintf(stderr, "<< pthread_cond_broadcast %p", cond);
1451 fflush(stderr);
1454 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE,
1455 pthread_cond_t*,cond);
1457 CALL_FN_W_W(ret, fn, cond);
1459 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_POST,
1460 pthread_cond_t*,cond);
1462 if (ret != 0) {
1463 DO_PthAPIerror( "pthread_cond_broadcast", ret );
1466 if (TRACE_PTH_FNS) {
1467 fprintf(stderr, " cobro -> %d >>\n", ret);
1470 return ret;
1472 #if defined(VGO_linux)
1473 PTH_FUNC(int, pthreadZucondZubroadcastZAZa, // pthread_cond_broadcast@*
1474 pthread_cond_t* cond) {
1475 return pthread_cond_broadcast_WRK(cond);
1477 #elif defined(VGO_darwin)
1478 PTH_FUNC(int, pthreadZucondZubroadcast, // pthread_cond_broadcast
1479 pthread_cond_t* cond) {
1480 return pthread_cond_broadcast_WRK(cond);
1482 #elif defined(VGO_solaris)
1483 PTH_FUNC(int, condZubroadcast, // cond_broadcast
1484 pthread_cond_t *cond) {
1485 return pthread_cond_broadcast_WRK(cond);
1487 #else
1488 # error "Unsupported OS"
1489 #endif
1491 // glibc: pthread_cond_init@GLIBC_2.0
1492 // glibc: pthread_cond_init@GLIBC_2.2.5
1493 // glibc: pthread_cond_init@@GLIBC_2.3.2
1494 // darwin: pthread_cond_init
1495 // Solaris: cond_init (pthread_cond_init is built atop on this function)
1496 // Easy way out: Handling of attr could have been messier.
1497 // It turns out that pthread_cond_init under linux ignores
1498 // all information in cond_attr, so do we.
1499 // FIXME: MacOS X?
1500 #if !defined(VGO_solaris)
1501 __attribute__((noinline))
1502 static int pthread_cond_init_WRK(pthread_cond_t* cond, pthread_condattr_t *cond_attr)
1504 int ret;
1505 OrigFn fn;
1506 VALGRIND_GET_ORIG_FN(fn);
1508 if (TRACE_PTH_FNS) {
1509 fprintf(stderr, "<< pthread_cond_init %p", cond);
1510 fflush(stderr);
1513 CALL_FN_W_WW(ret, fn, cond, cond_attr);
1515 if (ret == 0) {
1516 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST,
1517 pthread_cond_t*,cond, pthread_condattr_t*, cond_attr);
1518 } else {
1519 DO_PthAPIerror( "pthread_cond_init", ret );
1522 if (TRACE_PTH_FNS) {
1523 fprintf(stderr, " coinit -> %d >>\n", ret);
1526 return ret;
1528 #if defined(VGO_linux)
1529 PTH_FUNC(int, pthreadZucondZuinitZAZa, // pthread_cond_init@*
1530 pthread_cond_t* cond, pthread_condattr_t* cond_attr) {
1531 return pthread_cond_init_WRK(cond, cond_attr);
1533 #elif defined(VGO_darwin)
1534 PTH_FUNC(int, pthreadZucondZuinit, // pthread_cond_init
1535 pthread_cond_t* cond, pthread_condattr_t * cond_attr) {
1536 return pthread_cond_init_WRK(cond, cond_attr);
1538 #else
1539 # error "Unsupported OS"
1540 #endif
1542 #else /* VGO_solaris */
1543 __attribute__((noinline))
1544 PTH_FUNC(int, condZuinit, // cond_init
1545 cond_t *cond, int type, void *arg)
1547 int ret;
1548 OrigFn fn;
1549 VALGRIND_GET_ORIG_FN(fn);
1551 if (TRACE_PTH_FNS) {
1552 fprintf(stderr, "<< cond_init %p", cond); fflush(stderr);
1555 CALL_FN_W_WWW(ret, fn, cond, type, arg);
1557 if (ret == 0) {
1558 /* Luckily evh__HG_PTHREAD_COND_INIT_POST() ignores cond_attr.
1559 See also comment for pthread_cond_init_WRK(). */
1560 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST,
1561 cond_t *, cond, void *, NULL);
1562 } else {
1563 DO_PthAPIerror("cond_init", ret);
1566 if (TRACE_PTH_FNS) {
1567 fprintf(stderr, " cond_init -> %d >>\n", ret);
1570 return ret;
1572 #endif /* VGO_solaris */
1575 //-----------------------------------------------------------
1576 // glibc: pthread_cond_destroy@@GLIBC_2.3.2
1577 // glibc: pthread_cond_destroy@GLIBC_2.2.5
1578 // glibc: pthread_cond_destroy@GLIBC_2.0
1579 // darwin: pthread_cond_destroy
1580 // Solaris: cond_destroy (pthread_cond_destroy is a weak alias)
1582 __attribute__((noinline))
1583 static int pthread_cond_destroy_WRK(pthread_cond_t* cond)
1585 int ret;
1586 unsigned long cond_is_init;
1587 OrigFn fn;
1589 VALGRIND_GET_ORIG_FN(fn);
1591 if (TRACE_PTH_FNS) {
1592 fprintf(stderr, "<< pthread_cond_destroy %p", cond);
1593 fflush(stderr);
1596 if (cond != NULL) {
1597 const pthread_cond_t cond_init = PTHREAD_COND_INITIALIZER;
1598 cond_is_init = my_memcmp(cond, &cond_init, sizeof(*cond)) == 0;
1599 } else {
1600 cond_is_init = 0;
1603 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_DESTROY_PRE,
1604 pthread_cond_t*, cond, unsigned long, cond_is_init);
1606 CALL_FN_W_W(ret, fn, cond);
1608 if (ret != 0) {
1609 DO_PthAPIerror( "pthread_cond_destroy", ret );
1612 if (TRACE_PTH_FNS) {
1613 fprintf(stderr, " codestr -> %d >>\n", ret);
1616 return ret;
1618 #if defined(VGO_linux)
1619 PTH_FUNC(int, pthreadZucondZudestroyZAZa, // pthread_cond_destroy@*
1620 pthread_cond_t* cond) {
1621 return pthread_cond_destroy_WRK(cond);
1623 #elif defined(VGO_darwin)
1624 PTH_FUNC(int, pthreadZucondZudestroy, // pthread_cond_destroy
1625 pthread_cond_t* cond) {
1626 return pthread_cond_destroy_WRK(cond);
1628 #elif defined(VGO_solaris)
1629 PTH_FUNC(int, condZudestroy, // cond_destroy
1630 pthread_cond_t *cond) {
1631 return pthread_cond_destroy_WRK(cond);
1633 #else
1634 # error "Unsupported OS"
1635 #endif
1638 /*----------------------------------------------------------------*/
1639 /*--- pthread_barrier_t functions ---*/
1640 /*----------------------------------------------------------------*/
1642 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1644 /* Handled: pthread_barrier_init
1645 pthread_barrier_wait
1646 pthread_barrier_destroy
1648 Unhandled: pthread_barrierattr_destroy
1649 pthread_barrierattr_getpshared
1650 pthread_barrierattr_init
1651 pthread_barrierattr_setpshared
1652 -- are these important?
1655 //-----------------------------------------------------------
1656 // glibc: pthread_barrier_init
1657 // darwin: (doesn't appear to exist)
1658 // Solaris: pthread_barrier_init
1659 PTH_FUNC(int, pthreadZubarrierZuinit, // pthread_barrier_init
1660 pthread_barrier_t* bar,
1661 pthread_barrierattr_t* attr, unsigned long count)
1663 int ret;
1664 OrigFn fn;
1665 VALGRIND_GET_ORIG_FN(fn);
1667 if (TRACE_PTH_FNS) {
1668 fprintf(stderr, "<< pthread_barrier_init %p %p %lu",
1669 bar, attr, count);
1670 fflush(stderr);
1673 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE,
1674 pthread_barrier_t*, bar,
1675 unsigned long, count,
1676 unsigned long, 0/*!resizable*/);
1678 CALL_FN_W_WWW(ret, fn, bar,attr,count);
1680 if (ret != 0) {
1681 DO_PthAPIerror( "pthread_barrier_init", ret );
1684 if (TRACE_PTH_FNS) {
1685 fprintf(stderr, " pthread_barrier_init -> %d >>\n", ret);
1688 return ret;
1692 //-----------------------------------------------------------
1693 // glibc: pthread_barrier_wait
1694 // darwin: (doesn't appear to exist)
1695 // Solaris: pthread_barrier_wait
1696 PTH_FUNC(int, pthreadZubarrierZuwait, // pthread_barrier_wait
1697 pthread_barrier_t* bar)
1699 int ret;
1700 OrigFn fn;
1701 VALGRIND_GET_ORIG_FN(fn);
1703 if (TRACE_PTH_FNS) {
1704 fprintf(stderr, "<< pthread_barrier_wait %p", bar);
1705 fflush(stderr);
1708 /* That this works correctly, and doesn't screw up when a thread
1709 leaving the barrier races round to the front and re-enters while
1710 other threads are still leaving it, is quite subtle. See
1711 comments in the handler for PTHREAD_BARRIER_WAIT_PRE in
1712 hg_main.c. */
1713 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE,
1714 pthread_barrier_t*,bar);
1716 CALL_FN_W_W(ret, fn, bar);
1718 if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) {
1719 DO_PthAPIerror( "pthread_barrier_wait", ret );
1722 if (TRACE_PTH_FNS) {
1723 fprintf(stderr, " pthread_barrier_wait -> %d >>\n", ret);
1726 return ret;
1730 //-----------------------------------------------------------
1731 // glibc: pthread_barrier_destroy
1732 // darwin: (doesn't appear to exist)
1733 // Solaris: pthread_barrier_destroy
1734 PTH_FUNC(int, pthreadZubarrierZudestroy, // pthread_barrier_destroy
1735 pthread_barrier_t* bar)
1737 int ret;
1738 OrigFn fn;
1739 VALGRIND_GET_ORIG_FN(fn);
1741 if (TRACE_PTH_FNS) {
1742 fprintf(stderr, "<< pthread_barrier_destroy %p", bar);
1743 fflush(stderr);
1746 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE,
1747 pthread_barrier_t*,bar);
1749 CALL_FN_W_W(ret, fn, bar);
1751 if (ret != 0) {
1752 DO_PthAPIerror( "pthread_barrier_destroy", ret );
1755 if (TRACE_PTH_FNS) {
1756 fprintf(stderr, " pthread_barrier_destroy -> %d >>\n", ret);
1759 return ret;
1762 #endif // defined(HAVE_PTHREAD_BARRIER_INIT)
1765 /*----------------------------------------------------------------*/
1766 /*--- pthread_spinlock_t functions ---*/
1767 /*----------------------------------------------------------------*/
1769 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1770 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1772 /* Handled: pthread_spin_init pthread_spin_destroy
1773 pthread_spin_lock pthread_spin_trylock
1774 pthread_spin_unlock
1776 Unhandled:
1779 /* This is a nasty kludge, in that glibc "knows" that initialising a
1780 spin lock unlocks it, and pthread_spin_{init,unlock} are names for
1781 the same function. Hence we have to have a wrapper which does both
1782 things, without knowing which the user intended to happen.
1783 Solaris has distinct functions for init/unlock but client requests
1784 are immutable in helgrind.h so follow the glibc lead. */
1786 //-----------------------------------------------------------
1787 // glibc: pthread_spin_init
1788 // glibc: pthread_spin_unlock
1789 // darwin: (doesn't appear to exist)
1790 // Solaris: pthread_spin_init
1791 // Solaris: pthread_spin_unlock
1792 __attribute__((noinline))
1793 static int pthread_spin_init_or_unlock_WRK(pthread_spinlock_t* lock,
1794 int pshared) {
1795 int ret;
1796 OrigFn fn;
1797 VALGRIND_GET_ORIG_FN(fn);
1798 if (TRACE_PTH_FNS) {
1799 fprintf(stderr, "<< pthread_spin_iORu %p", lock); fflush(stderr);
1802 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE,
1803 pthread_spinlock_t*, lock);
1805 CALL_FN_W_WW(ret, fn, lock,pshared);
1807 if (ret == 0 /*success*/) {
1808 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST,
1809 pthread_spinlock_t*,lock);
1810 } else {
1811 DO_PthAPIerror( "pthread_spinlock_{init,unlock}", ret );
1814 if (TRACE_PTH_FNS) {
1815 fprintf(stderr, " :: spiniORu -> %d >>\n", ret);
1817 return ret;
1819 #if defined(VGO_linux)
1820 PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
1821 pthread_spinlock_t* lock, int pshared) {
1822 return pthread_spin_init_or_unlock_WRK(lock, pshared);
1824 PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
1825 pthread_spinlock_t* lock) {
1826 /* this is never actually called */
1827 return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/);
1829 #elif defined(VGO_darwin)
1830 #elif defined(VGO_solaris)
1831 PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
1832 pthread_spinlock_t *lock, int pshared) {
1833 return pthread_spin_init_or_unlock_WRK(lock, pshared);
1835 PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
1836 pthread_spinlock_t *lock) {
1837 return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/);
1839 #else
1840 # error "Unsupported OS"
1841 #endif
1844 //-----------------------------------------------------------
1845 // glibc: pthread_spin_destroy
1846 // darwin: (doesn't appear to exist)
1847 // Solaris: pthread_spin_destroy
1848 __attribute__((noinline))
1849 static int pthread_spin_destroy_WRK(pthread_spinlock_t *lock)
1851 int ret;
1852 OrigFn fn;
1853 VALGRIND_GET_ORIG_FN(fn);
1854 if (TRACE_PTH_FNS) {
1855 fprintf(stderr, "<< pthread_spin_destroy %p", lock);
1856 fflush(stderr);
1859 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_DESTROY_PRE,
1860 pthread_spinlock_t*,lock);
1862 CALL_FN_W_W(ret, fn, lock);
1864 if (ret != 0) {
1865 DO_PthAPIerror( "pthread_spin_destroy", ret );
1868 if (TRACE_PTH_FNS) {
1869 fprintf(stderr, " :: spindestroy -> %d >>\n", ret);
1871 return ret;
1873 #if defined(VGO_linux)
1874 PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy
1875 pthread_spinlock_t *lock) {
1876 return pthread_spin_destroy_WRK(lock);
1878 #elif defined(VGO_darwin)
1879 #elif defined(VGO_solaris)
1880 PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy
1881 pthread_spinlock_t *lock) {
1882 return pthread_spin_destroy_WRK(lock);
1884 #else
1885 # error "Unsupported OS"
1886 #endif
1889 //-----------------------------------------------------------
1890 // glibc: pthread_spin_lock
1891 // darwin: (doesn't appear to exist)
1892 // Solaris: pthread_spin_lock
1893 __attribute__((noinline))
1894 static int pthread_spin_lock_WRK(pthread_spinlock_t *lock)
1896 int ret;
1897 OrigFn fn;
1898 VALGRIND_GET_ORIG_FN(fn);
1899 if (TRACE_PTH_FNS) {
1900 fprintf(stderr, "<< pthread_spinlock %p", lock);
1901 fflush(stderr);
1904 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE,
1905 pthread_spinlock_t*,lock, long,0/*!isTryLock*/);
1907 CALL_FN_W_W(ret, fn, lock);
1909 /* There's a hole here: libpthread now knows the lock is locked,
1910 but the tool doesn't, so some other thread could run and detect
1911 that the lock has been acquired by someone (this thread). Does
1912 this matter? Not sure, but I don't think so. */
1914 if (ret == 0 /*success*/) {
1915 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST,
1916 pthread_spinlock_t*,lock);
1917 } else {
1918 DO_PthAPIerror( "pthread_spin_lock", ret );
1921 if (TRACE_PTH_FNS) {
1922 fprintf(stderr, " :: spinlock -> %d >>\n", ret);
1924 return ret;
1926 #if defined(VGO_linux)
1927 PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
1928 pthread_spinlock_t *lock) {
1929 return pthread_spin_lock_WRK(lock);
1931 #elif defined(VGO_darwin)
1932 #elif defined(VGO_solaris)
1933 PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
1934 pthread_spinlock_t *lock) {
1935 return pthread_spin_lock_WRK(lock);
1937 #else
1938 # error "Unsupported OS"
1939 #endif
1942 //-----------------------------------------------------------
1943 // glibc: pthread_spin_trylock
1944 // darwin: (doesn't appear to exist)
1945 // Solaris: pthread_spin_trylock
1946 __attribute__((noinline))
1947 static int pthread_spin_trylock_WRK(pthread_spinlock_t *lock)
1949 int ret;
1950 OrigFn fn;
1951 VALGRIND_GET_ORIG_FN(fn);
1952 if (TRACE_PTH_FNS) {
1953 fprintf(stderr, "<< pthread_spin_trylock %p", lock);
1954 fflush(stderr);
1957 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE,
1958 pthread_spinlock_t*,lock, long,1/*isTryLock*/);
1960 CALL_FN_W_W(ret, fn, lock);
1962 /* There's a hole here: libpthread now knows the lock is locked,
1963 but the tool doesn't, so some other thread could run and detect
1964 that the lock has been acquired by someone (this thread). Does
1965 this matter? Not sure, but I don't think so. */
1967 if (ret == 0 /*success*/) {
1968 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST,
1969 pthread_spinlock_t*,lock);
1970 } else {
1971 if (ret != EBUSY)
1972 DO_PthAPIerror( "pthread_spin_trylock", ret );
1975 if (TRACE_PTH_FNS) {
1976 fprintf(stderr, " :: spin_trylock -> %d >>\n", ret);
1978 return ret;
1980 #if defined(VGO_linux)
1981 PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
1982 pthread_spinlock_t *lock) {
1983 return pthread_spin_trylock_WRK(lock);
1985 #elif defined(VGO_darwin)
1986 #elif defined(VGO_solaris)
1987 PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
1988 pthread_spinlock_t *lock) {
1989 return pthread_spin_trylock_WRK(lock);
1991 #else
1992 # error "Unsupported OS"
1993 #endif
1995 #endif // defined(HAVE_PTHREAD_SPIN_LOCK)
1998 /*----------------------------------------------------------------*/
1999 /*--- pthread_rwlock_t functions ---*/
2000 /*----------------------------------------------------------------*/
2002 /* Android's pthread.h doesn't say anything about rwlocks, hence these
2003 functions have to be conditionally compiled. */
2004 #if defined(HAVE_PTHREAD_RWLOCK_T)
2006 /* Handled: pthread_rwlock_init pthread_rwlock_destroy
2007 pthread_rwlock_rdlock
2008 pthread_rwlock_wrlock
2009 pthread_rwlock_unlock
2010 pthread_rwlock_tryrdlock
2011 pthread_rwlock_trywrlock
2013 Unhandled: pthread_rwlock_timedrdlock
2014 pthread_rwlock_timedwrlock
2017 //-----------------------------------------------------------
2018 // glibc: pthread_rwlock_init
2019 // darwin: pthread_rwlock_init
2020 // darwin: pthread_rwlock_init$UNIX2003
2021 // Solaris: rwlock_init (pthread_rwlock_init is built atop of rwlock_init)
2022 __attribute__((noinline))
2023 static int pthread_rwlock_init_WRK(pthread_rwlock_t *rwl,
2024 pthread_rwlockattr_t* attr)
2026 int ret;
2027 OrigFn fn;
2028 VALGRIND_GET_ORIG_FN(fn);
2029 if (TRACE_PTH_FNS) {
2030 fprintf(stderr, "<< pthread_rwl_init %p", rwl); fflush(stderr);
2033 CALL_FN_W_WW(ret, fn, rwl,attr);
2035 if (ret == 0 /*success*/) {
2036 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
2037 pthread_rwlock_t*,rwl);
2038 } else {
2039 DO_PthAPIerror( "pthread_rwlock_init", ret );
2042 if (TRACE_PTH_FNS) {
2043 fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
2045 return ret;
2047 #if defined(VGO_linux)
2048 PTH_FUNC(int, pthreadZurwlockZuinit, // pthread_rwlock_init
2049 pthread_rwlock_t *rwl,
2050 pthread_rwlockattr_t* attr) {
2051 return pthread_rwlock_init_WRK(rwl, attr);
2053 #elif defined(VGO_darwin)
2054 PTH_FUNC(int, pthreadZurwlockZuinitZa, // pthread_rwlock_init*
2055 pthread_rwlock_t *rwl,
2056 pthread_rwlockattr_t* attr) {
2057 return pthread_rwlock_init_WRK(rwl, attr);
2059 #elif defined(VGO_solaris)
2060 static int pthread_rwlock_init_WRK(pthread_rwlock_t *rwl,
2061 pthread_rwlockattr_t* attr)
2062 __attribute__((unused));
2063 #else
2064 # error "Unsupported OS"
2065 #endif
2067 #if defined(VGO_solaris)
2068 PTH_FUNC(int, rwlockZuinit, // rwlock_init
2069 rwlock_t *rwlock,
2070 int type,
2071 void *arg)
2073 int ret;
2074 OrigFn fn;
2075 VALGRIND_GET_ORIG_FN(fn);
2076 if (TRACE_PTH_FNS) {
2077 fprintf(stderr, "<< rwl_init %p", rwlock); fflush(stderr);
2080 CALL_FN_W_WWW(ret, fn, rwlock, type, arg);
2082 if (ret == 0 /*success*/) {
2083 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
2084 rwlock_t *, rwlock);
2085 } else {
2086 DO_PthAPIerror("rwlock_init", ret);
2089 if (TRACE_PTH_FNS) {
2090 fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
2092 return ret;
2094 #endif /* VGO_solaris */
2097 //-----------------------------------------------------------
2098 // glibc: pthread_rwlock_destroy
2099 // darwin: pthread_rwlock_destroy
2100 // darwin: pthread_rwlock_destroy$UNIX2003
2101 // Solaris: rwlock_destroy (pthread_rwlock_destroy is a weak alias)
2103 __attribute__((noinline))
2104 static int pthread_rwlock_destroy_WRK(pthread_rwlock_t* rwl)
2106 int ret;
2107 OrigFn fn;
2108 VALGRIND_GET_ORIG_FN(fn);
2109 if (TRACE_PTH_FNS) {
2110 fprintf(stderr, "<< pthread_rwl_destroy %p", rwl); fflush(stderr);
2113 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE,
2114 pthread_rwlock_t*,rwl);
2116 CALL_FN_W_W(ret, fn, rwl);
2118 if (ret != 0) {
2119 DO_PthAPIerror( "pthread_rwlock_destroy", ret );
2122 if (TRACE_PTH_FNS) {
2123 fprintf(stderr, " :: rwl_destroy -> %d >>\n", ret);
2125 return ret;
2127 #if defined(VGO_linux)
2128 PTH_FUNC(int, pthreadZurwlockZudestroy, // pthread_rwlock_destroy
2129 pthread_rwlock_t *rwl) {
2130 return pthread_rwlock_destroy_WRK(rwl);
2132 #elif defined(VGO_darwin)
2133 PTH_FUNC(int, pthreadZurwlockZudestroyZa, // pthread_rwlock_destroy*
2134 pthread_rwlock_t *rwl) {
2135 return pthread_rwlock_destroy_WRK(rwl);
2137 #elif defined(VGO_solaris)
2138 PTH_FUNC(int, rwlockZudestroy, // rwlock_destroy
2139 pthread_rwlock_t *rwl) {
2140 return pthread_rwlock_destroy_WRK(rwl);
2142 #else
2143 # error "Unsupported OS"
2144 #endif
2147 //-----------------------------------------------------------
2148 // glibc: pthread_rwlock_wrlock
2149 // darwin: pthread_rwlock_wrlock
2150 // darwin: pthread_rwlock_wrlock$UNIX2003
2151 // Solaris: rw_wrlock (pthread_rwlock_wrlock is a weak alias)
2153 __attribute__((noinline))
2154 static int pthread_rwlock_wrlock_WRK(pthread_rwlock_t* rwlock)
2156 int ret;
2157 OrigFn fn;
2158 VALGRIND_GET_ORIG_FN(fn);
2159 if (TRACE_PTH_FNS) {
2160 fprintf(stderr, "<< pthread_rwl_wlk %p", rwlock); fflush(stderr);
2163 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2164 pthread_rwlock_t*,rwlock,
2165 long,1/*isW*/, long,0/*!isTryLock*/);
2167 CALL_FN_W_W(ret, fn, rwlock);
2169 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2170 pthread_rwlock_t*,rwlock, long,1/*isW*/,
2171 long, (ret == 0) ? True : False);
2172 if (ret != 0) {
2173 DO_PthAPIerror( "pthread_rwlock_wrlock", ret );
2176 if (TRACE_PTH_FNS) {
2177 fprintf(stderr, " :: rwl_wlk -> %d >>\n", ret);
2179 return ret;
2181 #if defined(VGO_linux)
2182 PTH_FUNC(int, pthreadZurwlockZuwrlock, // pthread_rwlock_wrlock
2183 pthread_rwlock_t* rwlock) {
2184 return pthread_rwlock_wrlock_WRK(rwlock);
2186 #elif defined(VGO_darwin)
2187 PTH_FUNC(int, pthreadZurwlockZuwrlockZa, // pthread_rwlock_wrlock*
2188 pthread_rwlock_t* rwlock) {
2189 return pthread_rwlock_wrlock_WRK(rwlock);
2191 #elif defined(VGO_solaris)
2192 PTH_FUNC(int, rwZuwrlock, // rw_wrlock
2193 pthread_rwlock_t *rwlock) {
2194 return pthread_rwlock_wrlock_WRK(rwlock);
2196 #else
2197 # error "Unsupported OS"
2198 #endif
2200 #if defined(VGO_solaris)
2201 /* Internal to libc. */
2202 PTH_FUNC(void, lrwZuwrlock, // lrw_wrlock
2203 rwlock_t *rwlock)
2205 OrigFn fn;
2206 VALGRIND_GET_ORIG_FN(fn);
2207 if (TRACE_PTH_FNS) {
2208 fprintf(stderr, "<< lrw_wlk %p", rwlock); fflush(stderr);
2211 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2212 pthread_rwlock_t *, rwlock,
2213 long, 1/*isW*/, long, 0/*!isTryLock*/);
2215 CALL_FN_v_W(fn, rwlock);
2217 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2218 pthread_rwlock_t *, rwlock, long, 1/*isW*/, long, True);
2220 if (TRACE_PTH_FNS) {
2221 fprintf(stderr, " :: lrw_wlk >>\n");
2224 #endif /* VGO_solaris */
2227 //-----------------------------------------------------------
2228 // glibc: pthread_rwlock_rdlock
2229 // darwin: pthread_rwlock_rdlock
2230 // darwin: pthread_rwlock_rdlock$UNIX2003
2231 // Solaris: rw_rdlock (pthread_rwlock_rdlock is a weak alias)
2233 __attribute__((noinline))
2234 static int pthread_rwlock_rdlock_WRK(pthread_rwlock_t* rwlock)
2236 int ret;
2237 OrigFn fn;
2238 VALGRIND_GET_ORIG_FN(fn);
2239 if (TRACE_PTH_FNS) {
2240 fprintf(stderr, "<< pthread_rwl_rlk %p", rwlock); fflush(stderr);
2243 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2244 pthread_rwlock_t*,rwlock,
2245 long,0/*!isW*/, long,0/*!isTryLock*/);
2247 CALL_FN_W_W(ret, fn, rwlock);
2249 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2250 pthread_rwlock_t*,rwlock, long,0/*!isW*/,
2251 long, (ret == 0) ? True : False);
2252 if (ret != 0) {
2253 DO_PthAPIerror( "pthread_rwlock_rdlock", ret );
2256 if (TRACE_PTH_FNS) {
2257 fprintf(stderr, " :: rwl_rlk -> %d >>\n", ret);
2259 return ret;
2261 #if defined(VGO_linux)
2262 PTH_FUNC(int, pthreadZurwlockZurdlock, // pthread_rwlock_rdlock
2263 pthread_rwlock_t* rwlock) {
2264 return pthread_rwlock_rdlock_WRK(rwlock);
2266 #elif defined(VGO_darwin)
2267 PTH_FUNC(int, pthreadZurwlockZurdlockZa, // pthread_rwlock_rdlock*
2268 pthread_rwlock_t* rwlock) {
2269 return pthread_rwlock_rdlock_WRK(rwlock);
2271 #elif defined(VGO_solaris)
2272 PTH_FUNC(int, rwZurdlock, // rw_rdlock
2273 pthread_rwlock_t *rwlock) {
2274 return pthread_rwlock_rdlock_WRK(rwlock);
2276 #else
2277 # error "Unsupported OS"
2278 #endif
2280 #if defined(VGO_solaris)
2281 /* Internal to libc. */
2282 PTH_FUNC(void, lrwZurdlock, // lrw_rdlock
2283 rwlock_t *rwlock)
2285 OrigFn fn;
2286 VALGRIND_GET_ORIG_FN(fn);
2287 if (TRACE_PTH_FNS) {
2288 fprintf(stderr, "<< lrw_rlk %p", rwlock); fflush(stderr);
2291 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2292 pthread_rwlock_t *, rwlock,
2293 long, 0/*!isW*/, long, 0/*!isTryLock*/);
2295 CALL_FN_v_W(fn, rwlock);
2297 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2298 pthread_rwlock_t *, rwlock, long, 0/*!isW*/, long, True);
2300 if (TRACE_PTH_FNS) {
2301 fprintf(stderr, " :: lrw_rlk ->>\n");
2304 #endif /* VGO_solaris */
2307 //-----------------------------------------------------------
2308 // glibc: pthread_rwlock_trywrlock
2309 // darwin: pthread_rwlock_trywrlock
2310 // darwin: pthread_rwlock_trywrlock$UNIX2003
2311 // Solaris: rw_trywrlock (pthread_rwlock_trywrlock is a weak alias)
2313 __attribute__((noinline))
2314 static int pthread_rwlock_trywrlock_WRK(pthread_rwlock_t* rwlock)
2316 int ret;
2317 OrigFn fn;
2318 VALGRIND_GET_ORIG_FN(fn);
2319 if (TRACE_PTH_FNS) {
2320 fprintf(stderr, "<< pthread_rwl_trywlk %p", rwlock); fflush(stderr);
2323 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2324 pthread_rwlock_t*,rwlock,
2325 long,1/*isW*/, long,1/*isTryLock*/);
2327 CALL_FN_W_W(ret, fn, rwlock);
2329 /* There's a hole here: libpthread now knows the lock is locked,
2330 but the tool doesn't, so some other thread could run and detect
2331 that the lock has been acquired by someone (this thread). Does
2332 this matter? Not sure, but I don't think so. */
2334 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2335 pthread_rwlock_t*,rwlock, long,1/*isW*/,
2336 long, (ret == 0) ? True : False);
2337 if (ret != 0) {
2338 if (ret != EBUSY)
2339 DO_PthAPIerror( "pthread_rwlock_trywrlock", ret );
2342 if (TRACE_PTH_FNS) {
2343 fprintf(stderr, " :: rwl_trywlk -> %d >>\n", ret);
2345 return ret;
2347 #if defined(VGO_linux)
2348 PTH_FUNC(int, pthreadZurwlockZutrywrlock, // pthread_rwlock_trywrlock
2349 pthread_rwlock_t* rwlock) {
2350 return pthread_rwlock_trywrlock_WRK(rwlock);
2352 #elif defined(VGO_darwin)
2353 PTH_FUNC(int, pthreadZurwlockZutrywrlockZa, // pthread_rwlock_trywrlock*
2354 pthread_rwlock_t* rwlock) {
2355 return pthread_rwlock_trywrlock_WRK(rwlock);
2357 #elif defined(VGO_solaris)
2358 PTH_FUNC(int, rwZutrywrlock, // rw_trywrlock
2359 pthread_rwlock_t *rwlock) {
2360 return pthread_rwlock_trywrlock_WRK(rwlock);
2362 #else
2363 # error "Unsupported OS"
2364 #endif
2367 //-----------------------------------------------------------
2368 // glibc: pthread_rwlock_tryrdlock
2369 // darwin: pthread_rwlock_tryrdlock
2370 // darwin: pthread_rwlock_tryrdlock$UNIX2003
2371 // Solaris: rw_tryrdlock (pthread_rwlock_tryrdlock is a weak alias)
2373 __attribute__((noinline))
2374 static int pthread_rwlock_tryrdlock_WRK(pthread_rwlock_t* rwlock)
2376 int ret;
2377 OrigFn fn;
2378 VALGRIND_GET_ORIG_FN(fn);
2379 if (TRACE_PTH_FNS) {
2380 fprintf(stderr, "<< pthread_rwl_tryrlk %p", rwlock); fflush(stderr);
2383 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2384 pthread_rwlock_t*,rwlock,
2385 long,0/*!isW*/, long,1/*isTryLock*/);
2387 CALL_FN_W_W(ret, fn, rwlock);
2389 /* There's a hole here: libpthread now knows the lock is locked,
2390 but the tool doesn't, so some other thread could run and detect
2391 that the lock has been acquired by someone (this thread). Does
2392 this matter? Not sure, but I don't think so. */
2394 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2395 pthread_rwlock_t*,rwlock, long,0/*!isW*/,
2396 long, (ret == 0) ? True : False);
2398 if (ret != 0) {
2399 if (ret != EBUSY)
2400 DO_PthAPIerror( "pthread_rwlock_tryrdlock", ret );
2403 if (TRACE_PTH_FNS) {
2404 fprintf(stderr, " :: rwl_tryrlk -> %d >>\n", ret);
2406 return ret;
2408 #if defined(VGO_linux)
2409 PTH_FUNC(int, pthreadZurwlockZutryrdlock, // pthread_rwlock_tryrdlock
2410 pthread_rwlock_t* rwlock) {
2411 return pthread_rwlock_tryrdlock_WRK(rwlock);
2413 #elif defined(VGO_darwin)
2414 PTH_FUNC(int, pthreadZurwlockZutryrdlockZa, // pthread_rwlock_tryrdlock*
2415 pthread_rwlock_t* rwlock) {
2416 return pthread_rwlock_tryrdlock_WRK(rwlock);
2418 #elif defined(VGO_solaris)
2419 PTH_FUNC(int, rwZutryrdlock, // rw_tryrdlock
2420 pthread_rwlock_t *rwlock) {
2421 return pthread_rwlock_tryrdlock_WRK(rwlock);
2423 #else
2424 # error "Unsupported OS"
2425 #endif
2428 //-----------------------------------------------------------
2429 // glibc: Unhandled
2430 // darwin: Unhandled
2431 // Solaris: pthread_rwlock_timedrdlock
2432 // Solaris: pthread_rwlock_reltimedrdlock_np
2434 __attribute__((noinline)) __attribute__((unused))
2435 static int pthread_rwlock_timedrdlock_WRK(pthread_rwlock_t *rwlock,
2436 const struct timespec *timeout)
2438 int ret;
2439 OrigFn fn;
2440 VALGRIND_GET_ORIG_FN(fn);
2441 if (TRACE_PTH_FNS) {
2442 fprintf(stderr, "<< pthread_rwl_timedrdl %p", rwlock); fflush(stderr);
2445 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2446 pthread_rwlock_t *, rwlock,
2447 long, 0/*isW*/, long, 0/*isTryLock*/);
2449 CALL_FN_W_WW(ret, fn, rwlock, timeout);
2451 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2452 pthread_rwlock_t *, rwlock, long, 0/*isW*/,
2453 long, (ret == 0) ? True : False);
2454 if (ret != 0) {
2455 DO_PthAPIerror("pthread_rwlock_timedrdlock", ret);
2458 if (TRACE_PTH_FNS) {
2459 fprintf(stderr, " :: rwl_timedrdl -> %d >>\n", ret);
2461 return ret;
2463 #if defined(VGO_linux)
2464 #elif defined(VGO_darwin)
2465 #elif defined(VGO_solaris)
2466 PTH_FUNC(int, pthreadZurwlockZutimedrdlock, // pthread_rwlock_timedrdlock
2467 pthread_rwlock_t *rwlock,
2468 const struct timespec *timeout) {
2469 return pthread_rwlock_timedrdlock_WRK(rwlock, timeout);
2471 PTH_FUNC(int, pthreadZurwlockZureltimedrdlockZunp, // pthread_rwlock_timedrdlock_np
2472 pthread_rwlock_t *rwlock,
2473 const struct timespec *timeout) {
2474 return pthread_rwlock_timedrdlock_WRK(rwlock, timeout);
2476 #else
2477 # error "Unsupported OS"
2478 #endif
2481 //-----------------------------------------------------------
2482 // glibc: Unhandled
2483 // darwin: Unhandled
2484 // Solaris: pthread_rwlock_timedwrlock
2485 // Solaris: pthread_rwlock_reltimedwrlock_np
2487 __attribute__((noinline)) __attribute__((unused))
2488 static int pthread_rwlock_timedwrlock_WRK(pthread_rwlock_t *rwlock,
2489 const struct timespec *timeout)
2491 int ret;
2492 OrigFn fn;
2493 VALGRIND_GET_ORIG_FN(fn);
2494 if (TRACE_PTH_FNS) {
2495 fprintf(stderr, "<< pthread_rwl_timedwrl %p", rwlock); fflush(stderr);
2498 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2499 pthread_rwlock_t *, rwlock,
2500 long, 1/*isW*/, long, 0/*isTryLock*/);
2502 CALL_FN_W_WW(ret, fn, rwlock, timeout);
2504 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2505 pthread_rwlock_t *, rwlock, long, 1/*isW*/,
2506 long, (ret == 0) ? True : False);
2507 if (ret != 0) {
2508 DO_PthAPIerror("pthread_rwlock_timedwrlock", ret);
2511 if (TRACE_PTH_FNS) {
2512 fprintf(stderr, " :: rwl_timedwrl -> %d >>\n", ret);
2514 return ret;
2516 #if defined(VGO_linux)
2517 #elif defined(VGO_darwin)
2518 #elif defined(VGO_solaris)
2519 PTH_FUNC(int, pthreadZurwlockZutimedwrlock, // pthread_rwlock_timedwrlock
2520 pthread_rwlock_t *rwlock,
2521 const struct timespec *timeout) {
2522 return pthread_rwlock_timedwrlock_WRK(rwlock, timeout);
2524 PTH_FUNC(int, pthreadZurwlockZureltimedwrlockZunp, // pthread_rwlock_timedwrlock_np
2525 pthread_rwlock_t *rwlock,
2526 const struct timespec *timeout) {
2527 return pthread_rwlock_timedwrlock_WRK(rwlock, timeout);
2529 #else
2530 # error "Unsupported OS"
2531 #endif
2534 //-----------------------------------------------------------
2535 // glibc: pthread_rwlock_unlock
2536 // darwin: pthread_rwlock_unlock
2537 // darwin: pthread_rwlock_unlock$UNIX2003
2538 // Solaris: rw_unlock (pthread_rwlock_unlock is a weak alias)
2539 __attribute__((noinline))
2540 static int pthread_rwlock_unlock_WRK(pthread_rwlock_t* rwlock)
2542 int ret;
2543 OrigFn fn;
2544 VALGRIND_GET_ORIG_FN(fn);
2545 if (TRACE_PTH_FNS) {
2546 fprintf(stderr, "<< pthread_rwl_unlk %p", rwlock); fflush(stderr);
2549 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
2550 pthread_rwlock_t*,rwlock);
2552 CALL_FN_W_W(ret, fn, rwlock);
2554 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
2555 pthread_rwlock_t*,rwlock);
2556 if (ret != 0) {
2557 DO_PthAPIerror( "pthread_rwlock_unlock", ret );
2560 if (TRACE_PTH_FNS) {
2561 fprintf(stderr, " :: rwl_unlk -> %d >>\n", ret);
2563 return ret;
2565 #if defined(VGO_linux)
2566 PTH_FUNC(int, pthreadZurwlockZuunlock, // pthread_rwlock_unlock
2567 pthread_rwlock_t* rwlock) {
2568 return pthread_rwlock_unlock_WRK(rwlock);
2570 #elif defined(VGO_darwin)
2571 PTH_FUNC(int, pthreadZurwlockZuunlockZa, // pthread_rwlock_unlock*
2572 pthread_rwlock_t* rwlock) {
2573 return pthread_rwlock_unlock_WRK(rwlock);
2575 #elif defined(VGO_solaris)
2576 PTH_FUNC(int, rwZuunlock, // rw_unlock
2577 pthread_rwlock_t *rwlock) {
2578 return pthread_rwlock_unlock_WRK(rwlock);
2580 #else
2581 # error "Unsupported OS"
2582 #endif
2584 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
2587 /*----------------------------------------------------------------*/
2588 /*--- POSIX semaphores ---*/
2589 /*----------------------------------------------------------------*/
2591 #include <semaphore.h>
2592 #include <fcntl.h> /* O_CREAT */
2594 #define TRACE_SEM_FNS 0
2596 /* Handled:
2597 int sem_init(sem_t *sem, int pshared, unsigned value);
2598 int sem_destroy(sem_t *sem);
2599 int sem_wait(sem_t *sem);
2600 int sem_post(sem_t *sem);
2601 sem_t* sem_open(const char *name, int oflag,
2602 ... [mode_t mode, unsigned value]);
2603 [complete with its idiotic semantics]
2604 int sem_close(sem_t* sem);
2606 Unhandled:
2607 int sem_trywait(sem_t *sem);
2608 int sem_timedwait(sem_t *restrict sem,
2609 const struct timespec *restrict abs_timeout);
2612 //-----------------------------------------------------------
2613 // glibc: sem_init@@GLIBC_2.2.5
2614 // glibc: sem_init@@GLIBC_2.1
2615 // glibc: sem_init@GLIBC_2.0
2616 // darwin: sem_init
2617 // Solaris: sema_init (sem_init is built on top of sem_init)
2619 #if !defined(VGO_solaris)
2620 __attribute__((noinline))
2621 static int sem_init_WRK(sem_t* sem, int pshared, unsigned long value)
2623 OrigFn fn;
2624 int ret;
2625 VALGRIND_GET_ORIG_FN(fn);
2627 if (TRACE_SEM_FNS) {
2628 fprintf(stderr, "<< sem_init(%p,%d,%lu) ", sem,pshared,value);
2629 fflush(stderr);
2632 CALL_FN_W_WWW(ret, fn, sem,pshared,value);
2634 if (ret == 0) {
2635 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
2636 sem_t*, sem, unsigned long, value);
2637 } else {
2638 DO_PthAPIerror( "sem_init", errno );
2641 if (TRACE_SEM_FNS) {
2642 fprintf(stderr, " sem_init -> %d >>\n", ret);
2643 fflush(stderr);
2646 return ret;
2648 #if defined(VGO_linux)
2649 PTH_FUNC(int, semZuinitZAZa, // sem_init@*
2650 sem_t* sem, int pshared, unsigned long value) {
2651 return sem_init_WRK(sem, pshared, value);
2653 #elif defined(VGO_darwin)
2654 PTH_FUNC(int, semZuinit, // sem_init
2655 sem_t* sem, int pshared, unsigned long value) {
2656 return sem_init_WRK(sem, pshared, value);
2658 #else
2659 # error "Unsupported OS"
2660 #endif
2662 #else /* VGO_solaris */
2663 PTH_FUNC(int, semaZuinit, // sema_init
2664 sema_t *sem,
2665 unsigned int value,
2666 int type,
2667 void *arg)
2669 OrigFn fn;
2670 int ret;
2671 VALGRIND_GET_ORIG_FN(fn);
2673 if (TRACE_SEM_FNS) {
2674 fprintf(stderr, "<< sema_init(%p, %d, %u) ", sem, type, value);
2675 fflush(stderr);
2678 CALL_FN_W_WWWW(ret, fn, sem, value, type, arg);
2680 if (ret == 0) {
2681 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
2682 sema_t *, sem, Word, value);
2683 } else {
2684 DO_PthAPIerror("sema_init", ret);
2687 if (TRACE_SEM_FNS) {
2688 fprintf(stderr, " sema_init -> %d >>\n", ret);
2689 fflush(stderr);
2692 return ret;
2694 #endif /* VGO_solaris */
2697 //-----------------------------------------------------------
2698 // glibc: sem_destroy@GLIBC_2.0
2699 // glibc: sem_destroy@@GLIBC_2.1
2700 // glibc: sem_destroy@@GLIBC_2.2.5
2701 // darwin: sem_destroy
2702 // Solaris: sema_destroy (sem_destroy is built on top of sema_destroy)
2703 __attribute__((noinline))
2704 static int sem_destroy_WRK(sem_t* sem)
2706 OrigFn fn;
2707 int ret;
2708 VALGRIND_GET_ORIG_FN(fn);
2710 if (TRACE_SEM_FNS) {
2711 fprintf(stderr, "<< sem_destroy(%p) ", sem);
2712 fflush(stderr);
2715 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
2717 CALL_FN_W_W(ret, fn, sem);
2719 if (ret != 0) {
2720 DO_PthAPIerror( "sem_destroy", SEM_ERROR );
2723 if (TRACE_SEM_FNS) {
2724 fprintf(stderr, " sem_destroy -> %d >>\n", ret);
2725 fflush(stderr);
2728 return ret;
2730 #if defined(VGO_linux)
2731 PTH_FUNC(int, semZudestroyZAZa, // sem_destroy*
2732 sem_t* sem) {
2733 return sem_destroy_WRK(sem);
2735 #elif defined(VGO_darwin)
2736 PTH_FUNC(int, semZudestroy, // sem_destroy
2737 sem_t* sem) {
2738 return sem_destroy_WRK(sem);
2740 #elif defined(VGO_solaris)
2741 PTH_FUNC(int, semaZudestroy, // sema_destroy
2742 sem_t *sem) {
2743 return sem_destroy_WRK(sem);
2745 #else
2746 # error "Unsupported OS"
2747 #endif
2750 //-----------------------------------------------------------
2751 // glibc: sem_wait
2752 // glibc: sem_wait@GLIBC_2.0
2753 // glibc: sem_wait@@GLIBC_2.1
2754 // darwin: sem_wait
2755 // darwin: sem_wait$NOCANCEL$UNIX2003
2756 // darwin: sem_wait$UNIX2003
2757 // Solaris: sema_wait (sem_wait is built on top of sema_wait)
2759 /* wait: decrement semaphore - acquire lockage */
2760 __attribute__((noinline))
2761 static int sem_wait_WRK(sem_t* sem)
2763 OrigFn fn;
2764 int ret;
2765 VALGRIND_GET_ORIG_FN(fn);
2767 if (TRACE_SEM_FNS) {
2768 fprintf(stderr, "<< sem_wait(%p) ", sem);
2769 fflush(stderr);
2772 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_PRE, sem_t*,sem);
2774 CALL_FN_W_W(ret, fn, sem);
2776 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST, sem_t*,sem,
2777 long, (ret == 0) ? True : False);
2779 if (ret != 0) {
2780 DO_PthAPIerror( "sem_wait", SEM_ERROR );
2783 if (TRACE_SEM_FNS) {
2784 fprintf(stderr, " sem_wait -> %d >>\n", ret);
2785 fflush(stderr);
2788 return ret;
2790 #if defined(VGO_linux)
2791 PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
2792 return sem_wait_WRK(sem);
2794 PTH_FUNC(int, semZuwaitZAZa, sem_t* sem) { /* sem_wait@* */
2795 return sem_wait_WRK(sem);
2797 #elif defined(VGO_darwin)
2798 PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
2799 return sem_wait_WRK(sem);
2801 PTH_FUNC(int, semZuwaitZDZa, sem_t* sem) { /* sem_wait$* */
2802 return sem_wait_WRK(sem);
2804 #elif defined(VGO_solaris)
2805 PTH_FUNC(int, semaZuwait, sem_t *sem) { /* sema_wait */
2806 return sem_wait_WRK(sem);
2808 #else
2809 # error "Unsupported OS"
2810 #endif
2813 //-----------------------------------------------------------
2814 // glibc: sem_post
2815 // glibc: sem_post@GLIBC_2.0
2816 // glibc: sem_post@@GLIBC_2.1
2817 // darwin: sem_post
2818 // Solaris: sema_post (sem_post is built on top of sema_post)
2820 /* post: increment semaphore - release lockage */
2821 __attribute__((noinline))
2822 static int sem_post_WRK(sem_t* sem)
2824 OrigFn fn;
2825 int ret;
2827 VALGRIND_GET_ORIG_FN(fn);
2829 if (TRACE_SEM_FNS) {
2830 fprintf(stderr, "<< sem_post(%p) ", sem);
2831 fflush(stderr);
2834 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_PRE, sem_t*,sem);
2836 CALL_FN_W_W(ret, fn, sem);
2838 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_POST, sem_t*,sem);
2840 if (ret != 0) {
2841 DO_PthAPIerror( "sem_post", SEM_ERROR );
2844 if (TRACE_SEM_FNS) {
2845 fprintf(stderr, " sem_post -> %d >>\n", ret);
2846 fflush(stderr);
2849 return ret;
2851 #if defined(VGO_linux)
2852 PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
2853 return sem_post_WRK(sem);
2855 PTH_FUNC(int, semZupostZAZa, sem_t* sem) { /* sem_post@* */
2856 return sem_post_WRK(sem);
2858 #elif defined(VGO_darwin)
2859 PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
2860 return sem_post_WRK(sem);
2862 #elif defined(VGO_solaris)
2863 PTH_FUNC(int, semaZupost, sem_t *sem) { /* sema_post */
2864 return sem_post_WRK(sem);
2866 #else
2867 # error "Unsupported OS"
2868 #endif
2871 //-----------------------------------------------------------
2872 // glibc: sem_open
2873 // darwin: sem_open
2874 // Solaris: sem_open
2876 PTH_FUNC(sem_t*, semZuopen,
2877 const char* name, long oflag,
2878 long mode, unsigned long value)
2880 /* A copy of sem_init_WRK (more or less). Is this correct? */
2881 OrigFn fn;
2882 sem_t* ret;
2883 VALGRIND_GET_ORIG_FN(fn);
2885 if (TRACE_SEM_FNS) {
2886 fprintf(stderr, "<< sem_open(\"%s\",%ld,%lx,%lu) ",
2887 name,oflag,mode,value);
2888 fflush(stderr);
2891 CALL_FN_W_WWWW(ret, fn, name,oflag,mode,value);
2893 if (ret != SEM_FAILED && (oflag & O_CREAT)) {
2894 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
2895 sem_t*, ret, unsigned long, value);
2897 if (ret == SEM_FAILED) {
2898 DO_PthAPIerror( "sem_open", errno );
2901 if (TRACE_SEM_FNS) {
2902 fprintf(stderr, " sem_open -> %p >>\n", ret);
2903 fflush(stderr);
2906 return ret;
2910 //-----------------------------------------------------------
2911 // glibc: sem_close
2912 // darwin: sem_close
2913 // Solaris: sem_close
2914 PTH_FUNC(int, sem_close, sem_t* sem)
2916 OrigFn fn;
2917 int ret;
2918 VALGRIND_GET_ORIG_FN(fn);
2920 if (TRACE_SEM_FNS) {
2921 fprintf(stderr, "<< sem_close(%p) ", sem);
2922 fflush(stderr);
2925 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
2927 CALL_FN_W_W(ret, fn, sem);
2929 if (ret != 0) {
2930 DO_PthAPIerror( "sem_close", errno );
2933 if (TRACE_SEM_FNS) {
2934 fprintf(stderr, " close -> %d >>\n", ret);
2935 fflush(stderr);
2938 return ret;
2942 /*----------------------------------------------------------------*/
2943 /*--- Qt 4 threading functions (w/ GNU name mangling) ---*/
2944 /*----------------------------------------------------------------*/
2946 /* Handled:
2947 QMutex::lock()
2948 QMutex::unlock()
2949 QMutex::tryLock()
2950 QMutex::tryLock(int)
2952 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC1ENS_13RecursionModeE
2953 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC2ENS_13RecursionModeE
2954 QMutex::~QMutex() _ZN6QMutexD1Ev
2955 QMutex::~QMutex() _ZN6QMutexD2Ev
2957 Unhandled:
2958 QReadWriteLock::lockForRead()
2959 QReadWriteLock::lockForWrite()
2960 QReadWriteLock::unlock()
2961 QReadWriteLock::tryLockForRead(int)
2962 QReadWriteLock::tryLockForRead()
2963 QReadWriteLock::tryLockForWrite(int)
2964 QReadWriteLock::tryLockForWrite()
2966 QWaitCondition::wait(QMutex*, unsigned long)
2967 QWaitCondition::wakeAll()
2968 QWaitCondition::wakeOne()
2970 QSemaphore::*
2972 /* More comments, 19 Nov 08, based on assessment of qt-4.5.0TP1,
2973 at least on Unix:
2975 It's apparently only necessary to intercept QMutex, since that is
2976 not implemented using pthread_mutex_t; instead Qt4 has its own
2977 implementation based on atomics (to check the non-contended case)
2978 and pthread_cond_wait (to wait in the contended case).
2980 QReadWriteLock is built on top of QMutex, counters, and a wait
2981 queue. So we don't need to handle it specially once QMutex
2982 handling is correct -- presumably the dependencies through QMutex
2983 are sufficient to avoid any false race reports. On the other hand,
2984 it is an open question whether too many dependencies are observed
2985 -- in which case we may miss races (false negatives). I suspect
2986 this is likely to be the case, unfortunately.
2988 QWaitCondition is built on pthread_cond_t, pthread_mutex_t, QMutex
2989 and QReadWriteLock. Same compositional-correctness justificiation
2990 and limitations as fro QReadWriteLock.
2992 Ditto QSemaphore (from cursory examination).
2994 Does it matter that only QMutex is handled directly? Open
2995 question. From testing with drd/tests/qt4_* and with KDE4 apps, it
2996 appears that no false errors are reported; however it is not clear
2997 if this is causing false negatives.
2999 Another problem with Qt4 is thread exiting. Threads are created
3000 with pthread_create (fine); but they detach and simply exit when
3001 done. There is no use of pthread_join, and the provided
3002 wait-for-a-thread-to-exit mechanism (QThread::wait, I believe)
3003 relies on a system of mutexes and flags. I suspect this also
3004 causes too many dependencies to appear. Consequently H sometimes
3005 fails to detect races at exit in some very short-lived racy
3006 programs, because it appears that a thread can exit _and_ have an
3007 observed dependency edge back to the main thread (presumably)
3008 before the main thread reaps the child (that is, calls
3009 QThread::wait).
3011 This theory is supported by the observation that if all threads are
3012 made to wait at a pthread_barrier_t immediately before they exit,
3013 then H's detection of races in such programs becomes reliable;
3014 without the barrier, it is varies from run to run, depending
3015 (according to investigation) on whether aforementioned
3016 exit-before-reaping behaviour happens or not.
3018 Finally, why is it necessary to intercept the QMutex constructors
3019 and destructors? The constructors are intercepted only as a matter
3020 of convenience, so H can print accurate "first observed at"
3021 clauses. However, it is actually necessary to intercept the
3022 destructors (as it is with pthread_mutex_destroy) in order that
3023 locks get removed from LAOG when they are destroyed.
3026 // soname is libQtCore.so.4 ; match against libQtCore.so*
3027 #define QT4_FUNC(ret_ty, f, args...) \
3028 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args); \
3029 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args)
3031 // soname is libQt5Core.so.4 ; match against libQt5Core.so*
3032 #define QT5_FUNC(ret_ty, f, args...) \
3033 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args); \
3034 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args)
3036 //-----------------------------------------------------------
3037 // QMutex::lock()
3038 __attribute__((noinline))
3039 static void QMutex_lock_WRK(void* self)
3041 OrigFn fn;
3042 VALGRIND_GET_ORIG_FN(fn);
3043 if (TRACE_QT4_FNS) {
3044 fprintf(stderr, "<< QMutex::lock %p", self); fflush(stderr);
3047 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
3048 void*,self, long,0/*!isTryLock*/);
3050 CALL_FN_v_W(fn, self);
3052 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
3053 void *, self, long, True);
3055 if (TRACE_QT4_FNS) {
3056 fprintf(stderr, " :: Q::lock done >>\n");
3060 QT4_FUNC(void, _ZN6QMutex4lockEv, void* self) {
3061 QMutex_lock_WRK(self);
3063 QT5_FUNC(void, _ZN6QMutex4lockEv, void* self) {
3064 QMutex_lock_WRK(self);
3067 //-----------------------------------------------------------
3068 // QMutex::unlock()
3069 __attribute__((noinline))
3070 static void QMutex_unlock_WRK(void* self)
3072 OrigFn fn;
3073 VALGRIND_GET_ORIG_FN(fn);
3075 if (TRACE_QT4_FNS) {
3076 fprintf(stderr, "<< QMutex::unlock %p", self); fflush(stderr);
3079 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
3080 void*, self);
3082 CALL_FN_v_W(fn, self);
3084 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
3085 void*, self);
3087 if (TRACE_QT4_FNS) {
3088 fprintf(stderr, " Q::unlock done >>\n");
3092 QT4_FUNC(void, _ZN6QMutex6unlockEv, void* self) {
3093 QMutex_unlock_WRK(self);
3095 QT5_FUNC(void, _ZN6QMutex6unlockEv, void* self) {
3096 QMutex_unlock_WRK(self);
3099 //-----------------------------------------------------------
3100 // bool QMutex::tryLock()
3101 // using 'long' to mimic C++ 'bool'
3102 __attribute__((noinline))
3103 static long QMutex_tryLock_WRK(void* self)
3105 OrigFn fn;
3106 long ret;
3107 VALGRIND_GET_ORIG_FN(fn);
3108 if (TRACE_QT4_FNS) {
3109 fprintf(stderr, "<< QMutex::tryLock %p", self); fflush(stderr);
3112 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
3113 void*,self, long,1/*isTryLock*/);
3115 CALL_FN_W_W(ret, fn, self);
3117 // assumes that only the low 8 bits of the 'bool' are significant
3118 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
3119 void *, self, long, (ret & 0xFF) ? True : False);
3121 if (TRACE_QT4_FNS) {
3122 fprintf(stderr, " :: Q::tryLock -> %lu >>\n", ret);
3125 return ret;
3128 QT4_FUNC(long, _ZN6QMutex7tryLockEv, void* self) {
3129 return QMutex_tryLock_WRK(self);
3131 QT5_FUNC(long, _ZN6QMutex7tryLockEv, void* self) {
3132 return QMutex_tryLock_WRK(self);
3135 //-----------------------------------------------------------
3136 // bool QMutex::tryLock(int)
3137 // using 'long' to mimic C++ 'bool'
3138 __attribute__((noinline))
3139 static long QMutex_tryLock_int_WRK(void* self, long arg2)
3141 OrigFn fn;
3142 long ret;
3143 VALGRIND_GET_ORIG_FN(fn);
3144 if (TRACE_QT4_FNS) {
3145 fprintf(stderr, "<< QMutex::tryLock(int) %p %d", self, (int)arg2);
3146 fflush(stderr);
3149 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
3150 void*,self, long,1/*isTryLock*/);
3152 CALL_FN_W_WW(ret, fn, self,arg2);
3154 // assumes that only the low 8 bits of the 'bool' are significant
3155 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
3156 void *, self, long, (ret & 0xFF) ? True : False);
3158 if (TRACE_QT4_FNS) {
3159 fprintf(stderr, " :: Q::tryLock(int) -> %lu >>\n", ret);
3162 return ret;
3165 QT4_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2) {
3166 return QMutex_tryLock_int_WRK(self, arg2);
3168 QT5_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2) {
3169 return QMutex_tryLock_int_WRK(self, arg2);
3172 //-----------------------------------------------------------
3173 // It's not really very clear what the args are here. But from
3174 // a bit of dataflow analysis of the generated machine code of
3175 // the original function, it appears this takes two args, and
3176 // returns nothing. Nevertheless preserve return value just in
3177 // case. A bit of debug printing indicates that the first arg
3178 // is that of the mutex and the second is either zero or one,
3179 // probably being the recursion mode, therefore.
3180 // QMutex::QMutex(QMutex::RecursionMode) ("C1ENS" variant)
3181 __attribute__((noinline))
3182 static void* QMutex_constructor_WRK(void* mutex, long recmode)
3184 OrigFn fn;
3185 long ret;
3186 VALGRIND_GET_ORIG_FN(fn);
3187 CALL_FN_W_WW(ret, fn, mutex, recmode);
3188 // fprintf(stderr, "QMutex constructor 1: %p <- %p %p\n", ret, arg1, arg2);
3189 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
3190 void*,mutex, long,1/*mbRec*/);
3191 return (void*)ret;
3194 QT4_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE, void* self, long recmode) {
3195 return QMutex_constructor_WRK(self, recmode);
3197 QT5_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE, void* self, long recmode) {
3198 return QMutex_constructor_WRK(self, recmode);
3201 //-----------------------------------------------------------
3202 // QMutex::~QMutex() ("D1Ev" variant)
3203 __attribute__((noinline))
3204 static void* QMutex_destructor_WRK(void* mutex)
3206 OrigFn fn;
3207 long ret;
3208 VALGRIND_GET_ORIG_FN(fn);
3209 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
3210 void*,mutex);
3211 CALL_FN_W_W(ret, fn, mutex);
3212 return (void*)ret;
3215 QT4_FUNC(void*, _ZN6QMutexD1Ev, void* self) {
3216 return QMutex_destructor_WRK(self);
3218 QT5_FUNC(void*, _ZN6QMutexD1Ev, void* self) {
3219 return QMutex_destructor_WRK(self);
3222 //-----------------------------------------------------------
3223 // QMutex::QMutex(QMutex::RecursionMode) ("C2ENS" variant)
3224 QT4_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE,
3225 void* mutex,
3226 long recmode)
3228 assert(0);
3229 /*NOTREACHED*/
3230 /* Android's gcc behaves like it doesn't know that assert(0)
3231 never returns. Hence: */
3232 return NULL;
3235 QT5_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE, void* self, long recmode)
3237 assert(0);
3238 /*NOTREACHED*/
3239 return NULL;
3242 //-----------------------------------------------------------
3243 // QMutex::~QMutex() ("D2Ev" variant)
3244 QT4_FUNC(void*, _ZN6QMutexD2Ev, void* mutex)
3246 assert(0);
3247 /* Android's gcc behaves like it doesn't know that assert(0)
3248 never returns. Hence: */
3249 return NULL;
3252 QT5_FUNC(void*, _ZN6QMutexD2Ev, void* self)
3254 assert(0);
3255 /*NOTREACHED*/
3256 return NULL;
3259 // QReadWriteLock is not intercepted directly. See comments
3260 // above.
3262 //// QReadWriteLock::lockForRead()
3263 //// _ZN14QReadWriteLock11lockForReadEv == QReadWriteLock::lockForRead()
3264 //QT4_FUNC(void, ZuZZN14QReadWriteLock11lockForReadEv,
3265 // // _ZN14QReadWriteLock11lockForReadEv
3266 // void* self)
3268 // OrigFn fn;
3269 // VALGRIND_GET_ORIG_FN(fn);
3270 // if (TRACE_QT4_FNS) {
3271 // fprintf(stderr, "<< QReadWriteLock::lockForRead %p", self);
3272 // fflush(stderr);
3273 // }
3275 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
3276 // void*,self,
3277 // long,0/*!isW*/, long,0/*!isTryLock*/);
3279 // CALL_FN_v_W(fn, self);
3281 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
3282 // void*,self, long,0/*!isW*/, long, True);
3284 // if (TRACE_QT4_FNS) {
3285 // fprintf(stderr, " :: Q::lockForRead :: done >>\n");
3286 // }
3289 //// QReadWriteLock::lockForWrite()
3290 //// _ZN14QReadWriteLock12lockForWriteEv == QReadWriteLock::lockForWrite()
3291 //QT4_FUNC(void, ZuZZN14QReadWriteLock12lockForWriteEv,
3292 // // _ZN14QReadWriteLock12lockForWriteEv
3293 // void* self)
3295 // OrigFn fn;
3296 // VALGRIND_GET_ORIG_FN(fn);
3297 // if (TRACE_QT4_FNS) {
3298 // fprintf(stderr, "<< QReadWriteLock::lockForWrite %p", self);
3299 // fflush(stderr);
3300 // }
3302 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
3303 // void*,self,
3304 // long,1/*isW*/, long,0/*!isTryLock*/);
3306 // CALL_FN_v_W(fn, self);
3308 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
3309 // void*,self, long,1/*isW*/, long, True);
3311 // if (TRACE_QT4_FNS) {
3312 // fprintf(stderr, " :: Q::lockForWrite :: done >>\n");
3313 // }
3316 //// QReadWriteLock::unlock()
3317 //// _ZN14QReadWriteLock6unlockEv == QReadWriteLock::unlock()
3318 //QT4_FUNC(void, ZuZZN14QReadWriteLock6unlockEv,
3319 // // _ZN14QReadWriteLock6unlockEv
3320 // void* self)
3322 // OrigFn fn;
3323 // VALGRIND_GET_ORIG_FN(fn);
3324 // if (TRACE_QT4_FNS) {
3325 // fprintf(stderr, "<< QReadWriteLock::unlock %p", self);
3326 // fflush(stderr);
3327 // }
3329 // DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
3330 // void*,self);
3332 // CALL_FN_v_W(fn, self);
3334 // DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
3335 // void*,self);
3337 // if (TRACE_QT4_FNS) {
3338 // fprintf(stderr, " :: Q::unlock :: done >>\n");
3339 // }
3343 /*----------------------------------------------------------------*/
3344 /*--- Replacements for basic string functions, that don't ---*/
3345 /*--- overrun the input arrays. ---*/
3346 /*----------------------------------------------------------------*/
3348 #include "../shared/vg_replace_strmem.c"
3350 /*--------------------------------------------------------------------*/
3351 /*--- end hg_intercepts.c ---*/
3352 /*--------------------------------------------------------------------*/