FreeBSD: Add a DRD supppression for getaddrinfo
[valgrind.git] / helgrind / hg_intercepts.c
blob8c98e4ee032ba9e3d0408e9485ee96392549623b
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 #if defined(VGO_freebsd)
113 #define LIBC_FUNC(ret_ty, f, args...) \
114 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)(args); \
115 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)(args)
116 #endif
118 // Do a client request. These are macros rather than a functions so
119 // as to avoid having an extra frame in stack traces.
121 // NB: these duplicate definitions in helgrind.h. But here, we
122 // can have better typing (Word etc) and assertions, whereas
123 // in helgrind.h we can't. Obviously it's important the two
124 // sets of definitions are kept in sync.
126 // nuke the previous definitions
127 #undef DO_CREQ_v_W
128 #undef DO_CREQ_v_WW
129 #undef DO_CREQ_W_WW
130 #undef DO_CREQ_v_WWW
132 #define DO_CREQ_v_W(_creqF, _ty1F,_arg1F) \
133 do { \
134 Word _arg1; \
135 assert(sizeof(_ty1F) == sizeof(Word)); \
136 _arg1 = (Word)(_arg1F); \
137 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
138 _arg1, 0,0,0,0); \
139 } while (0)
141 #define DO_CREQ_v_WW(_creqF, _ty1F,_arg1F, _ty2F,_arg2F) \
142 do { \
143 Word _arg1, _arg2; \
144 assert(sizeof(_ty1F) == sizeof(Word)); \
145 assert(sizeof(_ty2F) == sizeof(Word)); \
146 _arg1 = (Word)(_arg1F); \
147 _arg2 = (Word)(_arg2F); \
148 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
149 _arg1,_arg2,0,0,0); \
150 } while (0)
152 #define DO_CREQ_W_WW(_resF, _creqF, _ty1F,_arg1F, \
153 _ty2F,_arg2F) \
154 do { \
155 Word _res, _arg1, _arg2; \
156 assert(sizeof(_ty1F) == sizeof(Word)); \
157 assert(sizeof(_ty2F) == sizeof(Word)); \
158 _arg1 = (Word)(_arg1F); \
159 _arg2 = (Word)(_arg2F); \
160 _res = VALGRIND_DO_CLIENT_REQUEST_EXPR(2, \
161 (_creqF), \
162 _arg1,_arg2,0,0,0); \
163 _resF = _res; \
164 } while (0)
166 #define DO_CREQ_v_WWW(_creqF, _ty1F,_arg1F, \
167 _ty2F,_arg2F, _ty3F, _arg3F) \
168 do { \
169 Word _arg1, _arg2, _arg3; \
170 assert(sizeof(_ty1F) == sizeof(Word)); \
171 assert(sizeof(_ty2F) == sizeof(Word)); \
172 assert(sizeof(_ty3F) == sizeof(Word)); \
173 _arg1 = (Word)(_arg1F); \
174 _arg2 = (Word)(_arg2F); \
175 _arg3 = (Word)(_arg3F); \
176 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
177 _arg1,_arg2,_arg3,0,0); \
178 } while (0)
180 #define DO_CREQ_v_WWWW(_creqF, _ty1F,_arg1F, \
181 _ty2F, _arg2F, _ty3F, _arg3F, \
182 _ty4F, _arg4F) \
183 do { \
184 Word _arg1, _arg2, _arg3, _arg4; \
185 assert(sizeof(_ty1F) == sizeof(Word)); \
186 assert(sizeof(_ty2F) == sizeof(Word)); \
187 assert(sizeof(_ty3F) == sizeof(Word)); \
188 assert(sizeof(_ty4F) == sizeof(Word)); \
189 _arg1 = (Word)(_arg1F); \
190 _arg2 = (Word)(_arg2F); \
191 _arg3 = (Word)(_arg3F); \
192 _arg4 = (Word)(_arg4F); \
193 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
194 _arg1,_arg2,_arg3,_arg4,0); \
195 } while (0)
197 #define DO_PthAPIerror(_fnnameF, _errF) \
198 do { \
199 const char* _fnname = (_fnnameF); \
200 long _err = (long)(int)(_errF); \
201 const char* _errstr = lame_strerror(_err); \
202 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTH_API_ERROR, \
203 char*,_fnname, \
204 long,_err, char*,_errstr); \
205 } while (0)
208 /* Needed for older glibcs (2.3 and older, at least) who don't
209 otherwise "know" about pthread_rwlock_anything or about
210 PTHREAD_MUTEX_RECURSIVE (amongst things). */
211 #define _GNU_SOURCE 1
213 #include <stdio.h>
214 #include <assert.h>
215 #include <errno.h>
216 #include <pthread.h>
218 /* A standalone memcmp. */
219 __attribute__((noinline))
220 static int my_memcmp ( const void* ptr1, const void* ptr2, size_t size)
222 const unsigned char* uchar_ptr1 = (const unsigned char*) ptr1;
223 const unsigned char* uchar_ptr2 = (const unsigned char*) ptr2;
224 size_t i;
225 for (i = 0; i < size; ++i) {
226 if (uchar_ptr1[i] != uchar_ptr2[i])
227 return (uchar_ptr1[i] < uchar_ptr2[i]) ? -1 : 1;
229 return 0;
232 /* A lame version of strerror which doesn't use the real libc
233 strerror_r, since using the latter just generates endless more
234 threading errors (glibc goes off and does tons of crap w.r.t.
235 locales etc) */
236 static const HChar* lame_strerror ( long err )
238 switch (err) {
239 case EPERM: return "EPERM: Operation not permitted";
240 case ENOENT: return "ENOENT: No such file or directory";
241 case ESRCH: return "ESRCH: No such process";
242 case EINTR: return "EINTR: Interrupted system call";
243 case EBADF: return "EBADF: Bad file number";
244 case EAGAIN: return "EAGAIN: Try again";
245 case ENOMEM: return "ENOMEM: Out of memory";
246 case EACCES: return "EACCES: Permission denied";
247 case EFAULT: return "EFAULT: Bad address";
248 case EEXIST: return "EEXIST: File exists";
249 case EINVAL: return "EINVAL: Invalid argument";
250 case EMFILE: return "EMFILE: Too many open files";
251 case ENOSYS: return "ENOSYS: Function not implemented";
252 case EOVERFLOW: return "EOVERFLOW: Value too large "
253 "for defined data type";
254 case EBUSY: return "EBUSY: Device or resource busy";
255 case ETIMEDOUT: return "ETIMEDOUT: Connection timed out";
256 case EDEADLK: return "EDEADLK: Resource deadlock would occur";
257 case EOPNOTSUPP: return "EOPNOTSUPP: Operation not supported on "
258 "transport endpoint"; /* honest, guv */
259 #if !defined(VGO_freebsd)
260 case ETIME: return "ETIME: Timer expired";
261 #endif
262 default: return "hg_intercepts.c: lame_strerror(): "
263 "unhandled case -- please fix me!";
267 #if defined(VGO_solaris)
269 * Solaris provides higher throughput, parallelism and scalability than other
270 * operating systems, at the cost of more fine-grained locking activity.
271 * This means for example that when a thread is created under Linux, just one
272 * big lock in glibc is used for all thread setup. Solaris libc uses several
273 * fine-grained locks and the creator thread resumes its activities as soon
274 * as possible, leaving for example stack and TLS setup activities to the
275 * created thread.
277 * This situation confuses Helgrind as it assumes there is some false ordering
278 * in place between creator and created thread; and therefore many types of
279 * race conditions in the application would not be reported. To prevent such
280 * false ordering, command line option --ignore-thread-creation is set to
281 * 'yes' by default on Solaris. All activity (loads, stores, client requests)
282 * is therefore ignored during:
283 * - pthread_create() call in the creator thread [libc.so]
284 * - thread creation phase (stack and TLS setup) in the created thread [libc.so]
286 * As explained in the comments for _ti_bind_guard(), whenever the runtime
287 * linker has to perform any activity (such as resolving a symbol), it protects
288 * its data structures by calling into rt_bind_guard() which in turn invokes
289 * _ti_bind_guard() in libc. Pointers to _ti_bind_guard() and _ti_bind_clear()
290 * are passed from libc to runtime linker in _ld_libc() call during libc_init().
291 * All activity is also ignored during:
292 * - runtime dynamic linker work between rt_bind_guard() and rt_bind_clear()
293 * calls [ld.so]
295 * This also means that Helgrind does not report race conditions in libc (when
296 * --ignore-thread-creation=yes) and runtime linker itself (unconditionally)
297 * during these ignored sequences.
300 #include "pub_tool_libcassert.h"
301 #include "pub_tool_vki.h"
304 * Original function pointers for _ti_bind_guard() and _ti_bind_clear()
305 * from libc. They are intercepted in function wrapper of _ld_libc().
307 typedef int (*hg_rtld_guard_fn)(int flags);
308 static hg_rtld_guard_fn hg_rtld_bind_guard = NULL;
309 static hg_rtld_guard_fn hg_rtld_bind_clear = NULL;
311 static void hg_init(void) __attribute__((constructor));
312 static void hg_init(void)
314 if ((hg_rtld_bind_guard == NULL) || (hg_rtld_bind_clear == NULL)) {
315 fprintf(stderr,
316 "Bind guard functions for the runtime linker (ld.so.1) were not intercepted.\n"
317 "This means the interface between libc and runtime linker changed\n"
318 "and Helgrind needs to be ported properly. Giving up.\n");
319 tl_assert(0);
324 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
325 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
326 * and CI_BIND_CLEAR, to provide resilience against function renaming.
328 static int _ti_bind_guard_intercept_WRK(int flags)
330 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_RTLD_BIND_GUARD,
331 flags, 0, 0, 0, 0);
332 return hg_rtld_bind_guard(flags);
335 static int _ti_bind_clear_intercept_WRK(int flags)
337 int ret = hg_rtld_bind_clear(flags);
338 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_RTLD_BIND_CLEAR,
339 flags, 0, 0, 0, 0);
340 return ret;
344 * Wrapped _ld_libc() from the runtime linker ld.so.1.
346 void I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr);
347 void I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr)
349 OrigFn fn;
350 int tag;
352 VALGRIND_GET_ORIG_FN(fn);
354 vki_Lc_interface *funcs = ptr;
355 for (tag = funcs->ci_tag; tag != 0; tag = (++funcs)->ci_tag) {
356 switch (tag) {
357 case VKI_CI_BIND_GUARD:
358 if (funcs->vki_ci_un.ci_func != _ti_bind_guard_intercept_WRK) {
359 hg_rtld_bind_guard = funcs->vki_ci_un.ci_func;
360 funcs->vki_ci_un.ci_func = _ti_bind_guard_intercept_WRK;
362 break;
363 case VKI_CI_BIND_CLEAR:
364 if (funcs->vki_ci_un.ci_func != _ti_bind_clear_intercept_WRK) {
365 hg_rtld_bind_clear = funcs->vki_ci_un.ci_func;
366 funcs->vki_ci_un.ci_func = _ti_bind_clear_intercept_WRK;
368 break;
372 CALL_FN_v_W(fn, ptr);
374 #endif /* VGO_solaris */
377 /*----------------------------------------------------------------*/
378 /*--- pthread_create, pthread_join, pthread_exit ---*/
379 /*----------------------------------------------------------------*/
381 static void* mythread_wrapper ( void* xargsV )
383 volatile Word* xargs = (volatile Word*) xargsV;
384 void*(*fn)(void*) = (void*(*)(void*))xargs[0];
385 void* arg = (void*)xargs[1];
386 pthread_t me = pthread_self();
387 /* Tell the tool what my pthread_t is. */
388 DO_CREQ_v_W(_VG_USERREQ__HG_SET_MY_PTHREAD_T, CREQ_PTHREAD_T, me);
389 /* allow the parent to proceed. We can't let it proceed until
390 we're ready because (1) we need to make sure it doesn't exit and
391 hence deallocate xargs[] while we still need it, and (2) we
392 don't want either parent nor child to proceed until the tool has
393 been notified of the child's pthread_t.
395 Note that parent and child access args[] without a lock,
396 effectively using args[2] as a spinlock in order to get the
397 parent to wait until the child passes this point. The parent
398 disables checking on xargs[] before creating the child and
399 re-enables it once the child goes past this point, so the user
400 never sees the race. The previous approach (suppressing the
401 resulting error) was flawed, because it could leave shadow
402 memory for args[] in a state in which subsequent use of it by
403 the parent would report further races. */
404 xargs[2] = 0;
405 /* Now we can no longer safely use xargs[]. */
406 return (void*) fn( (void*)arg );
409 //-----------------------------------------------------------
410 // glibc: pthread_create@GLIBC_2.0
411 // glibc: pthread_create@@GLIBC_2.1
412 // glibc: pthread_create@@GLIBC_2.2.5
413 // darwin: pthread_create
414 // darwin: pthread_create_suspended_np (trapped)
415 // FreeBSD: pthread_create
417 /* ensure this has its own frame, so as to make it more distinguishable
418 in suppressions */
419 __attribute__((noinline))
420 static int pthread_create_WRK(pthread_t *thread, const pthread_attr_t *attr,
421 void *(*start) (void *), void *arg)
423 int ret;
424 OrigFn fn;
425 volatile Word xargs[3];
427 VALGRIND_GET_ORIG_FN(fn);
428 if (TRACE_PTH_FNS) {
429 fprintf(stderr, "<< pthread_create wrapper"); fflush(stderr);
431 xargs[0] = (Word)start;
432 xargs[1] = (Word)arg;
433 xargs[2] = 1; /* serves as a spinlock -- sigh */
434 /* Disable checking on the spinlock and the two words used to
435 convey args to the child. Basically we need to make it appear
436 as if the child never accessed this area, since merely
437 suppressing the resulting races does not address the issue that
438 that piece of the parent's stack winds up in the "wrong" state
439 and therefore may give rise to mysterious races when the parent
440 comes to re-use this piece of stack in some other frame. */
441 VALGRIND_HG_DISABLE_CHECKING(&xargs, sizeof(xargs));
443 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_BEGIN,
444 0, 0, 0, 0, 0);
445 CALL_FN_W_WWWW(ret, fn, thread,attr,mythread_wrapper,&xargs[0]);
446 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_END,
447 0, 0, 0, 0, 0);
449 if (ret == 0) {
450 /* we have to wait for the child to notify the tool of its
451 pthread_t before continuing */
452 while (xargs[2] != 0) {
453 /* Do nothing. We need to spin until the child writes to
454 xargs[2]. However, that can lead to starvation in the
455 child and very long delays (eg, tc19_shadowmem on
456 ppc64-linux Fedora Core 6). So yield the cpu if we can,
457 to let the child run at the earliest available
458 opportunity. */
459 sched_yield();
461 } else {
462 DO_PthAPIerror( "pthread_create", ret );
465 /* Reenable checking on the area previously used to communicate
466 with the child. */
467 VALGRIND_HG_ENABLE_CHECKING(&xargs, sizeof(xargs));
469 if (TRACE_PTH_FNS) {
470 fprintf(stderr, " :: pth_create -> %d >>\n", ret);
472 return ret;
474 #if defined(VGO_linux)
475 PTH_FUNC(int, pthreadZucreateZAZa, // pthread_create@*
476 pthread_t *thread, const pthread_attr_t *attr,
477 void *(*start) (void *), void *arg) {
478 return pthread_create_WRK(thread, attr, start, arg);
480 #elif defined(VGO_freebsd)
481 PTH_FUNC(int, pthreadZucreate, // pthread_create
482 pthread_t *thread, const pthread_attr_t *attr,
483 void *(*start) (void *), void *arg) {
484 return pthread_create_WRK(thread, attr, start, arg);
486 #elif defined(VGO_darwin)
487 PTH_FUNC(int, pthreadZucreate, // pthread_create
488 pthread_t *thread, const pthread_attr_t *attr,
489 void *(*start) (void *), void *arg) {
490 return pthread_create_WRK(thread, attr, start, arg);
492 PTH_FUNC(int, pthreadZucreateZuZa, // pthread_create_*
493 pthread_t *thread, const pthread_attr_t *attr,
494 void *(*start) (void *), void *arg) {
495 // trap anything else
496 assert(0);
498 #elif defined(VGO_solaris)
499 PTH_FUNC(int, pthreadZucreate, // pthread_create
500 pthread_t *thread, const pthread_attr_t *attr,
501 void *(*start) (void *), void *arg) {
502 return pthread_create_WRK(thread, attr, start, arg);
504 #else
505 # error "Unsupported OS"
506 #endif
508 #if defined(VGO_solaris)
509 /* Solaris also provides thr_create() in addition to pthread_create().
510 * Both pthread_create(3C) and thr_create(3C) are based on private
511 * _thrp_create().
513 __attribute__((noinline))
514 static int thr_create_WRK(void *stk, size_t stksize, void *(*start)(void *),
515 void *arg, long flags, thread_t *new_thread)
517 int ret;
518 OrigFn fn;
519 volatile Word xargs[3];
521 VALGRIND_GET_ORIG_FN(fn);
522 if (TRACE_PTH_FNS) {
523 fprintf(stderr, "<< thr_create wrapper"); fflush(stderr);
525 xargs[0] = (Word)start;
526 xargs[1] = (Word)arg;
527 xargs[2] = 1; /* serves as a spinlock -- sigh */
528 /* See comments in pthread_create_WRK() */
529 VALGRIND_HG_DISABLE_CHECKING(&xargs, sizeof(xargs));
531 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_BEGIN,
532 0, 0, 0, 0, 0);
533 CALL_FN_W_6W(ret, fn, stk, stksize, mythread_wrapper, start, flags,
534 new_thread);
535 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_END,
536 0, 0, 0, 0, 0);
538 if (ret == 0) {
539 while (xargs[2] != 0) {
540 /* See comments in pthread_create_WRK(). */
541 sched_yield();
543 } else {
544 DO_PthAPIerror("thr_create", ret);
547 VALGRIND_HG_ENABLE_CHECKING(&xargs, sizeof(xargs));
549 if (TRACE_PTH_FNS) {
550 fprintf(stderr, " :: thr_create -> %d >>\n", ret);
552 return ret;
554 PTH_FUNC(int, thrZucreate, // thr_create
555 void *stk, size_t stksize, void *(*start)(void *),
556 void *arg, long flags, thread_t *new_thread) {
557 return thr_create_WRK(stk, stksize, start, arg, flags, new_thread);
559 #endif /* VGO_solaris */
562 //-----------------------------------------------------------
563 // glibc: pthread_join
564 // darwin: pthread_join
565 // darwin: pthread_join$NOCANCEL$UNIX2003
566 // darwin pthread_join$UNIX2003
567 // FreeBSD: pthread_join
568 __attribute__((noinline))
569 static int pthread_join_WRK(pthread_t thread, void** value_pointer)
571 int ret;
572 OrigFn fn;
573 VALGRIND_GET_ORIG_FN(fn);
574 if (TRACE_PTH_FNS) {
575 fprintf(stderr, "<< pthread_join wrapper"); fflush(stderr);
578 CALL_FN_W_WW(ret, fn, thread,value_pointer);
580 /* At least with NPTL as the thread library, this is safe because
581 it is guaranteed (by NPTL) that the joiner will completely gone
582 before pthread_join (the original) returns. See email below.*/
583 if (ret == 0 /*success*/) {
584 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST, CREQ_PTHREAD_T, thread);
585 } else {
586 DO_PthAPIerror( "pthread_join", ret );
589 if (TRACE_PTH_FNS) {
590 fprintf(stderr, " :: pth_join -> %d >>\n", ret);
592 return ret;
594 #if defined(VGO_linux)
595 PTH_FUNC(int, pthreadZujoin, // pthread_join
596 pthread_t thread, void** value_pointer) {
597 return pthread_join_WRK(thread, value_pointer);
599 #elif defined(VGO_freebsd)
600 PTH_FUNC(int, pthreadZujoin, // pthread_join
601 pthread_t thread, void** value_pointer) {
602 return pthread_join_WRK(thread, value_pointer);
604 #elif defined(VGO_darwin)
605 PTH_FUNC(int, pthreadZujoinZa, // pthread_join*
606 pthread_t thread, void** value_pointer) {
607 return pthread_join_WRK(thread, value_pointer);
609 #elif defined(VGO_solaris)
610 PTH_FUNC(int, pthreadZujoin, // pthread_join
611 pthread_t thread, void** value_pointer) {
612 return pthread_join_WRK(thread, value_pointer);
614 #else
615 # error "Unsupported OS"
616 #endif
619 /* Behaviour of pthread_join on NPTL:
622 I have a question re the NPTL pthread_join implementation.
624 Suppose I am the thread 'stayer'.
626 If I call pthread_join(quitter), is it guaranteed that the
627 thread 'quitter' has really exited before pthread_join returns?
629 IOW, is it guaranteed that 'quitter' will not execute any further
630 instructions after pthread_join returns?
632 I believe this is true based on the following analysis of
633 glibc-2.5 sources. However am not 100% sure and would appreciate
634 confirmation.
636 'quitter' will be running start_thread() in nptl/pthread_create.c
638 The last action of start_thread() is to exit via
639 __exit_thread_inline(0), which simply does sys_exit
640 (nptl/pthread_create.c:403)
642 'stayer' meanwhile is waiting for lll_wait_tid (pd->tid)
643 (call at nptl/pthread_join.c:89)
645 As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
646 lll_wait_tid will not return until kernel notifies via futex
647 wakeup that 'quitter' has terminated.
649 Hence pthread_join cannot return until 'quitter' really has
650 completely disappeared.
652 Drepper:
653 > As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
654 > lll_wait_tid will not return until kernel notifies via futex
655 > wakeup that 'quitter' has terminated.
656 That's the key. The kernel resets the TID field after the thread is
657 done. No way the joiner can return before the thread is gone.
660 #if defined(VGO_solaris)
661 /* Solaris also provides thr_join() in addition to pthread_join().
662 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
664 * :TODO: No functionality is currently provided for joinee == 0 and departed.
665 * This would require another client request, of course.
667 __attribute__((noinline))
668 static int thr_join_WRK(thread_t joinee, thread_t *departed, void **thread_return)
670 int ret;
671 OrigFn fn;
672 VALGRIND_GET_ORIG_FN(fn);
673 if (TRACE_PTH_FNS) {
674 fprintf(stderr, "<< thr_join wrapper"); fflush(stderr);
677 CALL_FN_W_WWW(ret, fn, joinee, departed, thread_return);
679 if (ret == 0 /*success*/) {
680 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST, CREQ_PTHREAD_T, joinee);
681 } else {
682 DO_PthAPIerror("thr_join", ret);
685 if (TRACE_PTH_FNS) {
686 fprintf(stderr, " :: thr_join -> %d >>\n", ret);
688 return ret;
690 PTH_FUNC(int, thrZujoin, // thr_join
691 thread_t joinee, thread_t *departed, void **thread_return) {
692 return thr_join_WRK(joinee, departed, thread_return);
694 #endif /* VGO_solaris */
697 //-----------------------------------------------------------
698 // Ada gcc gnat runtime:
699 // The gnat gcc Ada runtime does not use pthread_join. Instead, it uses
700 // a combination of other pthread primitives to ensure a child thread
701 // is gone. This combination is somewhat functionally equivalent to a
702 // pthread_join.
703 // We wrap two hook procedures called by the gnat gcc Ada runtime
704 // that allows helgrind to understand the semantic of Ada task dependencies
705 // and termination.
706 // procedure Master_Hook
707 // (Dependent : Task_Id;
708 // Parent : Task_Id;
709 // Master_Level : Integer);
710 // where type Task_Id is access all Ada_Task_Control_Block;
711 // System.Tasking.Debug.Master_Hook is called by a task Dependent to
712 // indicate that its master is identified by master+master_level.
713 void I_WRAP_SONAME_FNNAME_ZU
714 (Za,
715 system__tasking__debug__master_hook)
716 (void *dependent, void *master, int master_level);
717 void I_WRAP_SONAME_FNNAME_ZU
718 (Za,
719 system__tasking__debug__master_hook)
720 (void *dependent, void *master, int master_level)
722 OrigFn fn;
723 VALGRIND_GET_ORIG_FN(fn);
724 if (TRACE_GNAT_FNS) {
725 fprintf(stderr, "<< GNAT master_hook wrapper "
726 "dependent %p master %p master_level %d\n",
727 dependent, master, master_level); fflush(stderr);
730 // We call the wrapped function, even if it is a null body.
731 CALL_FN_v_WWW(fn, dependent, master, master_level);
733 DO_CREQ_v_WWW(_VG_USERREQ__HG_GNAT_MASTER_HOOK,
734 void*,dependent, void*,master,
735 Word, (Word)master_level);
737 if (TRACE_GNAT_FNS) {
738 fprintf(stderr, " :: GNAT master_hook >>\n");
742 // System.Tasking.Debug.Master_Completed_Hook is called by a task to
743 // indicate that it has completed a master.
744 // procedure Master_Completed_Hook
745 // (Self_ID : Task_Id;
746 // Master_Level : Integer);
747 // where type Task_Id is access all Ada_Task_Control_Block;
748 // This indicates that all its Dependent tasks (that identified themselves
749 // with the Master_Hook call) are terminated. Helgrind can consider
750 // at this point that the equivalent of a 'pthread_join' has been done
751 // between self_id and all dependent tasks at master_level.
752 void I_WRAP_SONAME_FNNAME_ZU
753 (Za,
754 system__tasking__debug__master_completed_hook)
755 (void *self_id, int master_level);
756 void I_WRAP_SONAME_FNNAME_ZU
757 (Za,
758 system__tasking__debug__master_completed_hook)
759 (void *self_id, int master_level)
761 OrigFn fn;
762 VALGRIND_GET_ORIG_FN(fn);
763 if (TRACE_GNAT_FNS) {
764 fprintf(stderr, "<< GNAT master_completed_hook wrapper "
765 "self_id %p master_level %d\n",
766 self_id, master_level); fflush(stderr);
769 // We call the wrapped function, even if it is a null body.
770 CALL_FN_v_WW(fn, self_id, master_level);
772 DO_CREQ_v_WW(_VG_USERREQ__HG_GNAT_MASTER_COMPLETED_HOOK,
773 void*,self_id, Word,(Word)master_level);
775 if (TRACE_GNAT_FNS) {
776 fprintf(stderr, " :: GNAT master_completed_hook >>\n");
780 /*----------------------------------------------------------------*/
781 /*--- pthread_mutex_t functions ---*/
782 /*----------------------------------------------------------------*/
784 /* Handled: pthread_mutex_init pthread_mutex_destroy
785 pthread_mutex_lock
786 pthread_mutex_trylock pthread_mutex_timedlock
787 pthread_mutex_unlock
790 //-----------------------------------------------------------
791 #if !defined(VGO_solaris)
792 // glibc: pthread_mutex_init
793 // darwin: pthread_mutex_init
794 // FreeBSD: pthread_mutex_init
795 PTH_FUNC(int, pthreadZumutexZuinit, // pthread_mutex_init
796 pthread_mutex_t *mutex,
797 pthread_mutexattr_t* attr)
799 int ret;
800 long mbRec;
801 OrigFn fn;
802 VALGRIND_GET_ORIG_FN(fn);
803 if (TRACE_PTH_FNS) {
804 fprintf(stderr, "<< pthread_mxinit %p", mutex); fflush(stderr);
807 mbRec = 0;
808 if (attr) {
809 int ty, zzz;
810 zzz = pthread_mutexattr_gettype(attr, &ty);
811 if (zzz == 0 && ty == PTHREAD_MUTEX_RECURSIVE)
812 mbRec = 1;
815 CALL_FN_W_WW(ret, fn, mutex,attr);
817 if (ret == 0 /*success*/) {
818 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
819 pthread_mutex_t*,mutex, long,mbRec);
820 } else {
821 DO_PthAPIerror( "pthread_mutex_init", ret );
824 if (TRACE_PTH_FNS) {
825 fprintf(stderr, " :: mxinit -> %d >>\n", ret);
827 return ret;
830 #else /* VGO_solaris */
832 // Solaris: mutex_init (pthread_mutex_init calls here)
833 PTH_FUNC(int, mutexZuinit, // mutex_init
834 mutex_t *mutex, int type, void *arg)
836 int ret;
837 long mbRec;
838 OrigFn fn;
839 VALGRIND_GET_ORIG_FN(fn);
840 if (TRACE_PTH_FNS) {
841 fprintf(stderr, "<< mxinit %p", mutex); fflush(stderr);
844 mbRec = ((type & LOCK_RECURSIVE) != 0) ? 1 : 0;
846 CALL_FN_W_WWW(ret, fn, mutex, type, arg);
848 if (ret == 0 /*success*/) {
849 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
850 mutex_t *, mutex, long, mbRec);
851 } else {
852 DO_PthAPIerror("mutex_init", ret);
855 if (TRACE_PTH_FNS) {
856 fprintf(stderr, " :: mxinit -> %d >>\n", ret);
858 return ret;
860 #endif /* VGO_solaris */
863 //-----------------------------------------------------------
864 // glibc: pthread_mutex_destroy
865 // darwin: pthread_mutex_destroy
866 // Solaris: mutex_destroy (pthread_mutex_destroy is a weak alias)
867 // FreeBSD: pthread_mutex_destroy
868 __attribute__((noinline))
869 static int mutex_destroy_WRK(pthread_mutex_t *mutex)
871 int ret;
872 unsigned long mutex_is_init;
873 OrigFn fn;
875 VALGRIND_GET_ORIG_FN(fn);
876 if (TRACE_PTH_FNS) {
877 fprintf(stderr, "<< pthread_mxdestroy %p", mutex); fflush(stderr);
880 if (mutex != NULL) {
881 static const pthread_mutex_t mutex_init = PTHREAD_MUTEX_INITIALIZER;
882 VALGRIND_HG_DISABLE_CHECKING(mutex, sizeof(*mutex));
883 mutex_is_init = my_memcmp(mutex, &mutex_init, sizeof(*mutex)) == 0;
884 VALGRIND_HG_ENABLE_CHECKING(mutex, sizeof(*mutex));
885 } else {
886 mutex_is_init = 0;
889 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
890 pthread_mutex_t*, mutex, unsigned long, mutex_is_init);
892 CALL_FN_W_W(ret, fn, mutex);
894 if (ret != 0) {
895 DO_PthAPIerror( "pthread_mutex_destroy", ret );
898 if (TRACE_PTH_FNS) {
899 fprintf(stderr, " :: mxdestroy -> %d >>\n", ret);
901 return ret;
904 #if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd)
905 PTH_FUNC(int, pthreadZumutexZudestroy, // pthread_mutex_destroy
906 pthread_mutex_t *mutex) {
907 return mutex_destroy_WRK(mutex);
909 #elif defined(VGO_solaris)
910 PTH_FUNC(int, mutexZudestroy, // mutex_destroy
911 pthread_mutex_t *mutex) {
912 return mutex_destroy_WRK(mutex);
914 #else
915 # error "Unsupported OS"
916 #endif
919 //-----------------------------------------------------------
920 // glibc: pthread_mutex_lock
921 // darwin: pthread_mutex_lock
922 // Solaris: mutex_lock (pthread_mutex_lock is a weak alias)
923 // FreeBSD: pthread_mutex_lock
924 __attribute__((noinline))
925 static int mutex_lock_WRK(pthread_mutex_t *mutex)
927 int ret;
928 OrigFn fn;
929 VALGRIND_GET_ORIG_FN(fn);
930 if (TRACE_PTH_FNS) {
931 fprintf(stderr, "<< pthread_mxlock %p", mutex); fflush(stderr);
934 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
935 pthread_mutex_t*,mutex, long,0/*!isTryLock*/);
937 CALL_FN_W_W(ret, fn, mutex);
939 /* There's a hole here: libpthread now knows the lock is locked,
940 but the tool doesn't, so some other thread could run and detect
941 that the lock has been acquired by someone (this thread). Does
942 this matter? Not sure, but I don't think so. */
944 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
945 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
947 if (ret != 0) {
948 DO_PthAPIerror( "pthread_mutex_lock", ret );
951 if (TRACE_PTH_FNS) {
952 fprintf(stderr, " :: mxlock -> %d >>\n", ret);
954 return ret;
957 #if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd)
958 PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock
959 pthread_mutex_t *mutex) {
960 return mutex_lock_WRK(mutex);
962 #elif defined(VGO_solaris)
963 PTH_FUNC(int, mutexZulock, // mutex_lock
964 pthread_mutex_t *mutex) {
965 return mutex_lock_WRK(mutex);
967 #else
968 # error "Unsupported OS"
969 #endif
971 #if defined(VGO_solaris)
972 /* Internal to libc. Mutex is usually initialized only implicitly,
973 * by zeroing mutex_t structure.
975 __attribute__((noinline))
976 PTH_FUNC(void, lmutexZulock, // lmutex_lock
977 mutex_t *mutex)
979 OrigFn fn;
980 VALGRIND_GET_ORIG_FN(fn);
981 if (TRACE_PTH_FNS) {
982 fprintf(stderr, "<< lmxlock %p", mutex); fflush(stderr);
985 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
986 mutex_t *, mutex, long, 0 /*!isTryLock*/);
987 CALL_FN_v_W(fn, mutex);
988 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
989 mutex_t *, mutex, long, True);
991 if (TRACE_PTH_FNS) {
992 fprintf(stderr, " :: lmxlock >>\n");
995 #endif /* VGO_solaris */
998 //-----------------------------------------------------------
999 // glibc: pthread_mutex_trylock
1000 // darwin: pthread_mutex_trylock
1001 // Solaris: mutex_trylock (pthread_mutex_trylock is a weak alias)
1002 // FreeBSD: pthread_mutext_trylock
1004 // pthread_mutex_trylock. The handling needed here is very similar
1005 // to that for pthread_mutex_lock, except that we need to tell
1006 // the pre-lock creq that this is a trylock-style operation, and
1007 // therefore not to complain if the lock is nonrecursive and
1008 // already locked by this thread -- because then it'll just fail
1009 // immediately with EBUSY.
1010 __attribute__((noinline))
1011 static int mutex_trylock_WRK(pthread_mutex_t *mutex)
1013 int ret;
1014 OrigFn fn;
1015 VALGRIND_GET_ORIG_FN(fn);
1016 if (TRACE_PTH_FNS) {
1017 fprintf(stderr, "<< pthread_mxtrylock %p", mutex); fflush(stderr);
1020 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
1021 pthread_mutex_t*,mutex, long,1/*isTryLock*/);
1023 CALL_FN_W_W(ret, fn, mutex);
1025 /* There's a hole here: libpthread now knows the lock is locked,
1026 but the tool doesn't, so some other thread could run and detect
1027 that the lock has been acquired by someone (this thread). Does
1028 this matter? Not sure, but I don't think so. */
1030 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1031 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
1033 if (ret != 0) {
1034 if (ret != EBUSY)
1035 DO_PthAPIerror( "pthread_mutex_trylock", ret );
1038 if (TRACE_PTH_FNS) {
1039 fprintf(stderr, " :: mxtrylock -> %d >>\n", ret);
1041 return ret;
1044 #if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd)
1045 PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock
1046 pthread_mutex_t *mutex) {
1047 return mutex_trylock_WRK(mutex);
1049 #elif defined(VGO_solaris)
1050 PTH_FUNC(int, mutexZutrylock, // mutex_trylock
1051 pthread_mutex_t *mutex) {
1052 return mutex_trylock_WRK(mutex);
1054 #else
1055 # error "Unsupported OS"
1056 #endif
1059 //-----------------------------------------------------------
1060 // glibc: pthread_mutex_timedlock
1061 // darwin: (doesn't appear to exist)
1062 // Solaris: pthread_mutex_timedlock
1063 // FreeBSD: pthread_mutex_timedlock
1065 // pthread_mutex_timedlock. Identical logic to pthread_mutex_trylock.
1066 __attribute__((noinline))
1067 static int mutex_timedlock_WRK(pthread_mutex_t *mutex,
1068 void *timeout)
1070 int ret;
1071 OrigFn fn;
1072 VALGRIND_GET_ORIG_FN(fn);
1073 if (TRACE_PTH_FNS) {
1074 fprintf(stderr, "<< pthread_mxtimedlock %p %p", mutex, timeout);
1075 fflush(stderr);
1078 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
1079 pthread_mutex_t*,mutex, long,1/*isTryLock-ish*/);
1081 CALL_FN_W_WW(ret, fn, mutex,timeout);
1083 /* There's a hole here: libpthread now knows the lock is locked,
1084 but the tool doesn't, so some other thread could run and detect
1085 that the lock has been acquired by someone (this thread). Does
1086 this matter? Not sure, but I don't think so. */
1088 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1089 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
1091 if (ret != 0) {
1092 if (ret != ETIMEDOUT)
1093 DO_PthAPIerror( "pthread_mutex_timedlock", ret );
1096 if (TRACE_PTH_FNS) {
1097 fprintf(stderr, " :: mxtimedlock -> %d >>\n", ret);
1099 return ret;
1102 PTH_FUNC(int, pthreadZumutexZutimedlock, // pthread_mutex_timedlock
1103 pthread_mutex_t *mutex,
1104 void *timeout) {
1105 return mutex_timedlock_WRK(mutex, timeout);
1107 #if defined(VGO_solaris)
1108 PTH_FUNC(int, pthreadZumutexZureltimedlock, // pthread_mutex_reltimedlock
1109 pthread_mutex_t *mutex,
1110 void *timeout) {
1111 return mutex_timedlock_WRK(mutex, timeout);
1113 #endif
1115 #if defined(VGO_linux)
1116 //-----------------------------------------------------------
1117 // glibc: pthread_mutex_clocklock
1119 // pthread_mutex_clocklock. Identical logic to pthread_mutex_timedlock.
1120 __attribute__((noinline))
1121 static int mutex_clocklock_WRK(pthread_mutex_t *mutex,
1122 clockid_t clockid,
1123 void *timeout)
1125 int ret;
1126 OrigFn fn;
1127 VALGRIND_GET_ORIG_FN(fn);
1128 if (TRACE_PTH_FNS) {
1129 fprintf(stderr, "<< pthread_mxclocklock %p %p", mutex, timeout);
1130 fflush(stderr);
1133 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
1134 pthread_mutex_t*,mutex, long,1/*isTryLock-ish*/);
1136 CALL_FN_W_WWW(ret, fn, mutex, clockid, timeout);
1138 /* There's a hole here: libpthread now knows the lock is locked,
1139 but the tool doesn't, so some other thread could run and detect
1140 that the lock has been acquired by someone (this thread). Does
1141 this matter? Not sure, but I don't think so. */
1143 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1144 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
1146 if (ret != 0) {
1147 if (ret != ETIMEDOUT)
1148 DO_PthAPIerror( "pthread_mutex_clocklock", ret );
1151 if (TRACE_PTH_FNS) {
1152 fprintf(stderr, " :: mxclocklock -> %d >>\n", ret);
1154 return ret;
1157 PTH_FUNC(int, pthreadZumutexZuclocklock, // pthread_mutex_clocklock
1158 pthread_mutex_t *mutex,
1159 clockid_t clockid,
1160 void *timeout) {
1161 return mutex_clocklock_WRK(mutex, clockid, timeout);
1163 #endif
1165 //-----------------------------------------------------------
1166 // glibc: pthread_mutex_unlock
1167 // darwin: pthread_mutex_unlock
1168 // Solaris: mutex_unlock (pthread_mutex_unlock is a weak alias)
1169 // FreeBSD: pthread_mutex_unlock
1170 __attribute__((noinline))
1171 static int mutex_unlock_WRK(pthread_mutex_t *mutex)
1173 int ret;
1174 OrigFn fn;
1175 VALGRIND_GET_ORIG_FN(fn);
1177 if (TRACE_PTH_FNS) {
1178 fprintf(stderr, "<< pthread_mxunlk %p", mutex); fflush(stderr);
1181 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1182 pthread_mutex_t*,mutex);
1184 CALL_FN_W_W(ret, fn, mutex);
1186 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
1187 pthread_mutex_t*,mutex);
1189 if (ret != 0) {
1190 DO_PthAPIerror( "pthread_mutex_unlock", ret );
1193 if (TRACE_PTH_FNS) {
1194 fprintf(stderr, " mxunlk -> %d >>\n", ret);
1196 return ret;
1199 #if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd)
1200 PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock
1201 pthread_mutex_t *mutex) {
1202 return mutex_unlock_WRK(mutex);
1204 #elif defined(VGO_solaris)
1205 PTH_FUNC(int, mutexZuunlock, // mutex_unlock
1206 pthread_mutex_t *mutex) {
1207 return mutex_unlock_WRK(mutex);
1209 #else
1210 # error "Unsupported OS"
1211 #endif
1214 #if defined(VGO_solaris)
1215 /* Internal to libc. */
1216 __attribute__((noinline))
1217 PTH_FUNC(void, lmutexZuunlock, // lmutex_unlock
1218 mutex_t *mutex)
1220 OrigFn fn;
1221 VALGRIND_GET_ORIG_FN(fn);
1223 if (TRACE_PTH_FNS) {
1224 fprintf(stderr, "<< lmxunlk %p", mutex); fflush(stderr);
1227 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1228 mutex_t *, mutex);
1229 CALL_FN_v_W(fn, mutex);
1230 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
1231 mutex_t*, mutex);
1233 if (TRACE_PTH_FNS) {
1234 fprintf(stderr, " lmxunlk >>\n");
1237 #endif /* VGO_solaris */
1240 /*----------------------------------------------------------------*/
1241 /*--- pthread_cond_t functions ---*/
1242 /*----------------------------------------------------------------*/
1244 /* Handled: pthread_cond_wait pthread_cond_timedwait
1245 pthread_cond_signal pthread_cond_broadcast
1246 pthread_cond_init
1247 pthread_cond_destroy
1250 //-----------------------------------------------------------
1251 // glibc: pthread_cond_wait@GLIBC_2.2.5
1252 // glibc: pthread_cond_wait@@GLIBC_2.3.2
1253 // darwin: pthread_cond_wait
1254 // darwin: pthread_cond_wait$NOCANCEL$UNIX2003
1255 // darwin: pthread_cond_wait$UNIX2003
1256 // Solaris: cond_wait (pthread_cond_wait is built atop of cond_wait)
1257 // FreeBSD: pthread_cond_wait
1259 __attribute__((noinline))
1260 static int pthread_cond_wait_WRK(pthread_cond_t* cond,
1261 pthread_mutex_t* mutex)
1263 int ret;
1264 OrigFn fn;
1265 unsigned long mutex_is_valid;
1267 VALGRIND_GET_ORIG_FN(fn);
1269 if (TRACE_PTH_FNS) {
1270 fprintf(stderr, "<< pthread_cond_wait %p %p", cond, mutex);
1271 fflush(stderr);
1274 /* Tell the tool a cond-wait is about to happen, so it can check
1275 for bogus argument values. In return it tells us whether it
1276 thinks the mutex is valid or not. */
1277 DO_CREQ_W_WW(mutex_is_valid,
1278 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
1279 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
1280 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
1282 /* Tell the tool we're about to drop the mutex. This reflects the
1283 fact that in a cond_wait, we show up holding the mutex, and the
1284 call atomically drops the mutex and waits for the cv to be
1285 signalled. */
1286 if (mutex_is_valid) {
1287 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1288 pthread_mutex_t*,mutex);
1291 CALL_FN_W_WW(ret, fn, cond,mutex);
1293 /* this conditional look stupid, but compare w/ same logic for
1294 pthread_cond_timedwait below */
1295 if (mutex_is_valid) {
1296 /* and now we have the mutex again if (ret == 0) */
1297 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1298 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
1301 DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
1302 pthread_cond_t*,cond, pthread_mutex_t*,mutex, long,0,
1303 long, (ret == 0 && mutex_is_valid) ? True : False);
1305 if (ret != 0) {
1306 DO_PthAPIerror( "pthread_cond_wait", ret );
1309 if (TRACE_PTH_FNS) {
1310 fprintf(stderr, " cowait -> %d >>\n", ret);
1313 return ret;
1315 #if defined(VGO_linux)
1316 PTH_FUNC(int, pthreadZucondZuwaitZAZa, // pthread_cond_wait@*
1317 pthread_cond_t* cond, pthread_mutex_t* mutex) {
1318 return pthread_cond_wait_WRK(cond, mutex);
1320 #elif defined(VGO_freebsd)
1321 PTH_FUNC(int, pthreadZucondZuwait, // pthread_cond_wait
1322 pthread_cond_t* cond, pthread_mutex_t* mutex) {
1323 return pthread_cond_wait_WRK(cond, mutex);
1325 #elif defined(VGO_darwin)
1326 PTH_FUNC(int, pthreadZucondZuwaitZa, // pthread_cond_wait*
1327 pthread_cond_t* cond, pthread_mutex_t* mutex) {
1328 return pthread_cond_wait_WRK(cond, mutex);
1330 #elif defined(VGO_solaris)
1331 PTH_FUNC(int, condZuwait, // cond_wait
1332 pthread_cond_t *cond, pthread_mutex_t *mutex) {
1333 return pthread_cond_wait_WRK(cond, mutex);
1335 #else
1336 # error "Unsupported OS"
1337 #endif
1340 //-----------------------------------------------------------
1341 // glibc: pthread_cond_timedwait@@GLIBC_2.3.2
1342 // glibc: pthread_cond_timedwait@GLIBC_2.2.5
1343 // glibc: pthread_cond_timedwait@GLIBC_2.0
1344 // darwin: pthread_cond_timedwait
1345 // darwin: pthread_cond_timedwait$NOCANCEL$UNIX2003
1346 // darwin: pthread_cond_timedwait$UNIX2003
1347 // darwin: pthread_cond_timedwait_relative_np (trapped)
1348 // Solaris: cond_timedwait (pthread_cond_timedwait is built on cond_timedwait)
1349 // Solaris: cond_reltimedwait (pthread_cond_reltimedwait_np is built on this)
1350 // FreeBSD: pthread_cond_timedwait
1352 __attribute__((noinline))
1353 static int pthread_cond_timedwait_WRK(pthread_cond_t* cond,
1354 pthread_mutex_t* mutex,
1355 struct timespec* abstime,
1356 int timeout_error)
1358 int ret;
1359 OrigFn fn;
1360 unsigned long mutex_is_valid;
1361 Bool abstime_is_valid;
1362 VALGRIND_GET_ORIG_FN(fn);
1364 if (TRACE_PTH_FNS) {
1365 fprintf(stderr, "<< pthread_cond_timedwait %p %p %p",
1366 cond, mutex, abstime);
1367 fflush(stderr);
1370 /* Tell the tool a cond-wait is about to happen, so it can check
1371 for bogus argument values. In return it tells us whether it
1372 thinks the mutex is valid or not. */
1373 DO_CREQ_W_WW(mutex_is_valid,
1374 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
1375 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
1376 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
1378 abstime_is_valid = abstime->tv_nsec >= 0 && abstime->tv_nsec < 1000000000;
1380 /* Tell the tool we're about to drop the mutex. This reflects the
1381 fact that in a cond_wait, we show up holding the mutex, and the
1382 call atomically drops the mutex and waits for the cv to be
1383 signalled. */
1384 if (mutex_is_valid && abstime_is_valid) {
1385 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1386 pthread_mutex_t*,mutex);
1389 CALL_FN_W_WWW(ret, fn, cond,mutex,abstime);
1391 if (mutex_is_valid && !abstime_is_valid && ret != EINVAL) {
1392 DO_PthAPIerror("Bug in libpthread: pthread_cond_timedwait "
1393 "invalid abstime did not cause"
1394 " EINVAL", ret);
1397 if (mutex_is_valid && abstime_is_valid) {
1398 /* and now we have the mutex again if (ret == 0 || ret == timeout) */
1399 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1400 pthread_mutex_t *, mutex,
1401 long, (ret == 0 || ret == timeout_error) ? True : False);
1404 DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
1405 pthread_cond_t*,cond, pthread_mutex_t*,mutex,
1406 long,ret == timeout_error,
1407 long, (ret == 0 || ret == timeout_error) && mutex_is_valid
1408 ? True : False);
1410 if (ret != 0 && ret != timeout_error) {
1411 DO_PthAPIerror( "pthread_cond_timedwait", ret );
1414 if (TRACE_PTH_FNS) {
1415 fprintf(stderr, " cotimedwait -> %d >>\n", ret);
1418 return ret;
1420 #if defined(VGO_linux)
1421 PTH_FUNC(int, pthreadZucondZutimedwaitZAZa, // pthread_cond_timedwait@*
1422 pthread_cond_t* cond, pthread_mutex_t* mutex,
1423 struct timespec* abstime) {
1424 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
1426 #elif defined(VGO_freebsd)
1427 PTH_FUNC(int, pthreadZucondZutimedwait, // pthread_cond_timedwait
1428 pthread_cond_t* cond, pthread_mutex_t* mutex,
1429 struct timespec* abstime) {
1430 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
1432 #elif defined(VGO_darwin)
1433 PTH_FUNC(int, pthreadZucondZutimedwait, // pthread_cond_timedwait
1434 pthread_cond_t* cond, pthread_mutex_t* mutex,
1435 struct timespec* abstime) {
1436 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
1438 PTH_FUNC(int, pthreadZucondZutimedwaitZDZa, // pthread_cond_timedwait$*
1439 pthread_cond_t* cond, pthread_mutex_t* mutex,
1440 struct timespec* abstime) {
1441 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
1443 PTH_FUNC(int, pthreadZucondZutimedwaitZuZa, // pthread_cond_timedwait_*
1444 pthread_cond_t* cond, pthread_mutex_t* mutex,
1445 struct timespec* abstime) {
1446 assert(0);
1448 #elif defined(VGO_solaris)
1449 PTH_FUNC(int, condZutimedwait, // cond_timedwait
1450 pthread_cond_t *cond, pthread_mutex_t *mutex,
1451 struct timespec *abstime) {
1452 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIME);
1454 PTH_FUNC(int, condZureltimedwait, // cond_reltimedwait
1455 pthread_cond_t *cond, pthread_mutex_t *mutex,
1456 struct timespec *reltime) {
1457 return pthread_cond_timedwait_WRK(cond, mutex, reltime, ETIME);
1459 #else
1460 # error "Unsupported OS"
1461 #endif
1463 #if defined(VGO_linux)
1464 //-----------------------------------------------------------
1465 // glibc: pthread_cond_clockwait
1467 __attribute__((noinline))
1468 static int pthread_cond_clockwait_WRK(pthread_cond_t* cond,
1469 pthread_mutex_t* mutex,
1470 clockid_t clockid,
1471 struct timespec* abstime,
1472 int timeout_error)
1474 int ret;
1475 OrigFn fn;
1476 unsigned long mutex_is_valid;
1477 Bool abstime_is_valid;
1478 VALGRIND_GET_ORIG_FN(fn);
1480 if (TRACE_PTH_FNS) {
1481 fprintf(stderr, "<< pthread_cond_clockwait %p %p %p",
1482 cond, mutex, abstime);
1483 fflush(stderr);
1486 /* Tell the tool a cond-wait is about to happen, so it can check
1487 for bogus argument values. In return it tells us whether it
1488 thinks the mutex is valid or not. */
1489 DO_CREQ_W_WW(mutex_is_valid,
1490 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
1491 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
1492 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
1494 abstime_is_valid = abstime->tv_nsec >= 0 && abstime->tv_nsec < 1000000000;
1496 /* Tell the tool we're about to drop the mutex. This reflects the
1497 fact that in a cond_wait, we show up holding the mutex, and the
1498 call atomically drops the mutex and waits for the cv to be
1499 signalled. */
1500 if (mutex_is_valid && abstime_is_valid) {
1501 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1502 pthread_mutex_t*,mutex);
1505 CALL_FN_W_WWWW(ret, fn, cond,mutex,clockid,abstime);
1507 if (mutex_is_valid && !abstime_is_valid && ret != EINVAL) {
1508 DO_PthAPIerror("Bug in libpthread: pthread_cond_clockwait "
1509 "invalid abstime did not cause"
1510 " EINVAL", ret);
1513 if (mutex_is_valid && abstime_is_valid) {
1514 /* and now we have the mutex again if (ret == 0 || ret == timeout) */
1515 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1516 pthread_mutex_t *, mutex,
1517 long, (ret == 0 || ret == timeout_error) ? True : False);
1520 DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
1521 pthread_cond_t*,cond, pthread_mutex_t*,mutex,
1522 long,ret == timeout_error,
1523 long, (ret == 0 || ret == timeout_error) && mutex_is_valid
1524 ? True : False);
1526 if (ret != 0 && ret != timeout_error) {
1527 DO_PthAPIerror( "pthread_cond_clockwait", ret );
1530 if (TRACE_PTH_FNS) {
1531 fprintf(stderr, " cotimedwait -> %d >>\n", ret);
1534 return ret;
1537 PTH_FUNC(int, pthreadZucondZuclockwait, // pthread_cond_clockwait
1538 pthread_cond_t* cond, pthread_mutex_t* mutex,
1539 clockid_t clockid,
1540 struct timespec* abstime) {
1541 return pthread_cond_clockwait_WRK(cond, mutex, clockid, abstime, ETIMEDOUT);
1543 #endif
1546 //-----------------------------------------------------------
1547 // glibc: pthread_cond_signal@GLIBC_2.0
1548 // glibc: pthread_cond_signal@GLIBC_2.2.5
1549 // glibc: pthread_cond_signal@@GLIBC_2.3.2
1550 // darwin: pthread_cond_signal
1551 // darwin: pthread_cond_signal_thread_np (don't intercept this)
1552 // Solaris: cond_signal (pthread_cond_signal is a weak alias)
1553 // FreeBSD: pthread_cond_signal
1555 __attribute__((noinline))
1556 static int pthread_cond_signal_WRK(pthread_cond_t* cond)
1558 int ret;
1559 OrigFn fn;
1560 VALGRIND_GET_ORIG_FN(fn);
1562 if (TRACE_PTH_FNS) {
1563 fprintf(stderr, "<< pthread_cond_signal %p", cond);
1564 fflush(stderr);
1567 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE,
1568 pthread_cond_t*,cond);
1570 CALL_FN_W_W(ret, fn, cond);
1572 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_POST,
1573 pthread_cond_t*,cond);
1575 if (ret != 0) {
1576 DO_PthAPIerror( "pthread_cond_signal", ret );
1579 if (TRACE_PTH_FNS) {
1580 fprintf(stderr, " cosig -> %d >>\n", ret);
1583 return ret;
1585 #if defined(VGO_linux)
1586 PTH_FUNC(int, pthreadZucondZusignalZAZa, // pthread_cond_signal@*
1587 pthread_cond_t* cond) {
1588 return pthread_cond_signal_WRK(cond);
1590 #elif defined(VGO_freebsd)
1591 PTH_FUNC(int, pthreadZucondZusignal, // pthread_cond_signal
1592 pthread_cond_t* cond) {
1593 return pthread_cond_signal_WRK(cond);
1595 #elif defined(VGO_darwin)
1596 PTH_FUNC(int, pthreadZucondZusignal, // pthread_cond_signal
1597 pthread_cond_t* cond) {
1598 return pthread_cond_signal_WRK(cond);
1600 #elif defined(VGO_solaris)
1601 PTH_FUNC(int, condZusignal, // cond_signal
1602 pthread_cond_t *cond) {
1603 return pthread_cond_signal_WRK(cond);
1605 #else
1606 # error "Unsupported OS"
1607 #endif
1610 //-----------------------------------------------------------
1611 // glibc: pthread_cond_broadcast@GLIBC_2.0
1612 // glibc: pthread_cond_broadcast@GLIBC_2.2.5
1613 // glibc: pthread_cond_broadcast@@GLIBC_2.3.2
1614 // darwin: pthread_cond_broadcast
1615 // Solaris: cond_broadcast (pthread_cond_broadcast is a weak alias)
1616 // FreeBSD: pthread_cond_broadcast
1618 // Note, this is pretty much identical, from a dependency-graph
1619 // point of view, with cond_signal, so the code is duplicated.
1620 // Maybe it should be commoned up.
1622 __attribute__((noinline))
1623 static int pthread_cond_broadcast_WRK(pthread_cond_t* cond)
1625 int ret;
1626 OrigFn fn;
1627 VALGRIND_GET_ORIG_FN(fn);
1629 if (TRACE_PTH_FNS) {
1630 fprintf(stderr, "<< pthread_cond_broadcast %p", cond);
1631 fflush(stderr);
1634 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE,
1635 pthread_cond_t*,cond);
1637 CALL_FN_W_W(ret, fn, cond);
1639 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_POST,
1640 pthread_cond_t*,cond);
1642 if (ret != 0) {
1643 DO_PthAPIerror( "pthread_cond_broadcast", ret );
1646 if (TRACE_PTH_FNS) {
1647 fprintf(stderr, " cobro -> %d >>\n", ret);
1650 return ret;
1652 #if defined(VGO_linux)
1653 PTH_FUNC(int, pthreadZucondZubroadcastZAZa, // pthread_cond_broadcast@*
1654 pthread_cond_t* cond) {
1655 return pthread_cond_broadcast_WRK(cond);
1657 #elif defined(VGO_freebsd)
1658 PTH_FUNC(int, pthreadZucondZubroadcast, // pthread_cond_broadcast
1659 pthread_cond_t* cond) {
1660 return pthread_cond_broadcast_WRK(cond);
1662 #elif defined(VGO_darwin)
1663 PTH_FUNC(int, pthreadZucondZubroadcast, // pthread_cond_broadcast
1664 pthread_cond_t* cond) {
1665 return pthread_cond_broadcast_WRK(cond);
1667 #elif defined(VGO_solaris)
1668 PTH_FUNC(int, condZubroadcast, // cond_broadcast
1669 pthread_cond_t *cond) {
1670 return pthread_cond_broadcast_WRK(cond);
1672 #else
1673 # error "Unsupported OS"
1674 #endif
1676 // glibc: pthread_cond_init@GLIBC_2.0
1677 // glibc: pthread_cond_init@GLIBC_2.2.5
1678 // glibc: pthread_cond_init@@GLIBC_2.3.2
1679 // darwin: pthread_cond_init
1680 // Solaris: cond_init (pthread_cond_init is built atop on this function)
1681 // FreeBSD: pthread_cond_init
1682 // Easy way out: Handling of attr could have been messier.
1683 // It turns out that pthread_cond_init under linux ignores
1684 // all information in cond_attr, so do we.
1685 // FIXME: MacOS X?
1686 #if !defined(VGO_solaris)
1687 __attribute__((noinline))
1688 static int pthread_cond_init_WRK(pthread_cond_t* cond, pthread_condattr_t *cond_attr)
1690 int ret;
1691 OrigFn fn;
1692 VALGRIND_GET_ORIG_FN(fn);
1694 if (TRACE_PTH_FNS) {
1695 fprintf(stderr, "<< pthread_cond_init %p", cond);
1696 fflush(stderr);
1699 CALL_FN_W_WW(ret, fn, cond, cond_attr);
1701 if (ret == 0) {
1702 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST,
1703 pthread_cond_t*,cond, pthread_condattr_t*, cond_attr);
1704 } else {
1705 DO_PthAPIerror( "pthread_cond_init", ret );
1708 if (TRACE_PTH_FNS) {
1709 fprintf(stderr, " coinit -> %d >>\n", ret);
1712 return ret;
1714 #if defined(VGO_linux)
1715 PTH_FUNC(int, pthreadZucondZuinitZAZa, // pthread_cond_init@*
1716 pthread_cond_t* cond, pthread_condattr_t* cond_attr) {
1717 return pthread_cond_init_WRK(cond, cond_attr);
1719 #elif defined(VGO_freebsd)
1720 PTH_FUNC(int, pthreadZucondZuinit, // pthread_cond_init@*
1721 pthread_cond_t* cond, pthread_condattr_t* cond_attr) {
1722 return pthread_cond_init_WRK(cond, cond_attr);
1724 #elif defined(VGO_darwin)
1725 PTH_FUNC(int, pthreadZucondZuinit, // pthread_cond_init
1726 pthread_cond_t* cond, pthread_condattr_t * cond_attr) {
1727 return pthread_cond_init_WRK(cond, cond_attr);
1729 #else
1730 # error "Unsupported OS"
1731 #endif
1733 #else /* VGO_solaris */
1734 __attribute__((noinline))
1735 PTH_FUNC(int, condZuinit, // cond_init
1736 cond_t *cond, int type, void *arg)
1738 int ret;
1739 OrigFn fn;
1740 VALGRIND_GET_ORIG_FN(fn);
1742 if (TRACE_PTH_FNS) {
1743 fprintf(stderr, "<< cond_init %p", cond); fflush(stderr);
1746 CALL_FN_W_WWW(ret, fn, cond, type, arg);
1748 if (ret == 0) {
1749 /* Luckily evh__HG_PTHREAD_COND_INIT_POST() ignores cond_attr.
1750 See also comment for pthread_cond_init_WRK(). */
1751 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST,
1752 cond_t *, cond, void *, NULL);
1753 } else {
1754 DO_PthAPIerror("cond_init", ret);
1757 if (TRACE_PTH_FNS) {
1758 fprintf(stderr, " cond_init -> %d >>\n", ret);
1761 return ret;
1763 #endif /* VGO_solaris */
1766 //-----------------------------------------------------------
1767 // glibc: pthread_cond_destroy@@GLIBC_2.3.2
1768 // glibc: pthread_cond_destroy@GLIBC_2.2.5
1769 // glibc: pthread_cond_destroy@GLIBC_2.0
1770 // darwin: pthread_cond_destroy
1771 // Solaris: cond_destroy (pthread_cond_destroy is a weak alias)
1772 // FreeBSD: pthread_cond_destroy
1774 __attribute__((noinline))
1775 static int pthread_cond_destroy_WRK(pthread_cond_t* cond)
1777 int ret;
1778 unsigned long cond_is_init;
1779 OrigFn fn;
1781 VALGRIND_GET_ORIG_FN(fn);
1783 if (TRACE_PTH_FNS) {
1784 fprintf(stderr, "<< pthread_cond_destroy %p", cond);
1785 fflush(stderr);
1788 if (cond != NULL) {
1789 const pthread_cond_t cond_init = PTHREAD_COND_INITIALIZER;
1790 VALGRIND_HG_DISABLE_CHECKING(cond, sizeof(*cond));
1791 cond_is_init = my_memcmp(cond, &cond_init, sizeof(*cond)) == 0;
1792 VALGRIND_HG_ENABLE_CHECKING(cond, sizeof(*cond));
1793 } else {
1794 cond_is_init = 0;
1797 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_DESTROY_PRE,
1798 pthread_cond_t*, cond, unsigned long, cond_is_init);
1800 CALL_FN_W_W(ret, fn, cond);
1802 if (ret != 0) {
1803 DO_PthAPIerror( "pthread_cond_destroy", ret );
1806 if (TRACE_PTH_FNS) {
1807 fprintf(stderr, " codestr -> %d >>\n", ret);
1810 return ret;
1812 #if defined(VGO_linux)
1813 PTH_FUNC(int, pthreadZucondZudestroyZAZa, // pthread_cond_destroy@*
1814 pthread_cond_t* cond) {
1815 return pthread_cond_destroy_WRK(cond);
1817 #elif defined(VGO_freebsd)
1818 PTH_FUNC(int, pthreadZucondZudestroy, // pthread_cond_destroy@*
1819 pthread_cond_t* cond) {
1820 return pthread_cond_destroy_WRK(cond);
1822 #elif defined(VGO_darwin)
1823 PTH_FUNC(int, pthreadZucondZudestroy, // pthread_cond_destroy
1824 pthread_cond_t* cond) {
1825 return pthread_cond_destroy_WRK(cond);
1827 #elif defined(VGO_solaris)
1828 PTH_FUNC(int, condZudestroy, // cond_destroy
1829 pthread_cond_t *cond) {
1830 return pthread_cond_destroy_WRK(cond);
1832 #else
1833 # error "Unsupported OS"
1834 #endif
1837 /*----------------------------------------------------------------*/
1838 /*--- pthread_barrier_t functions ---*/
1839 /*----------------------------------------------------------------*/
1841 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1843 /* Handled: pthread_barrier_init
1844 pthread_barrier_wait
1845 pthread_barrier_destroy
1847 Unhandled: pthread_barrierattr_destroy
1848 pthread_barrierattr_getpshared
1849 pthread_barrierattr_init
1850 pthread_barrierattr_setpshared
1851 -- are these important?
1854 //-----------------------------------------------------------
1855 // glibc: pthread_barrier_init
1856 // darwin: (doesn't appear to exist)
1857 // Solaris: pthread_barrier_init
1858 // FreeBSD: pthread_barrier_init
1859 PTH_FUNC(int, pthreadZubarrierZuinit, // pthread_barrier_init
1860 pthread_barrier_t* bar,
1861 pthread_barrierattr_t* attr, unsigned long count)
1863 int ret;
1864 OrigFn fn;
1865 VALGRIND_GET_ORIG_FN(fn);
1867 if (TRACE_PTH_FNS) {
1868 fprintf(stderr, "<< pthread_barrier_init %p %p %lu",
1869 bar, attr, count);
1870 fflush(stderr);
1873 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE,
1874 pthread_barrier_t*, bar,
1875 unsigned long, count,
1876 unsigned long, 0/*!resizable*/);
1878 CALL_FN_W_WWW(ret, fn, bar,attr,count);
1880 if (ret != 0) {
1881 DO_PthAPIerror( "pthread_barrier_init", ret );
1884 if (TRACE_PTH_FNS) {
1885 fprintf(stderr, " pthread_barrier_init -> %d >>\n", ret);
1888 return ret;
1892 //-----------------------------------------------------------
1893 // glibc: pthread_barrier_wait
1894 // darwin: (doesn't appear to exist)
1895 // Solaris: pthread_barrier_wait
1896 // FreeBSD: pthread_barrier_wait
1897 PTH_FUNC(int, pthreadZubarrierZuwait, // pthread_barrier_wait
1898 pthread_barrier_t* bar)
1900 int ret;
1901 OrigFn fn;
1902 VALGRIND_GET_ORIG_FN(fn);
1904 if (TRACE_PTH_FNS) {
1905 fprintf(stderr, "<< pthread_barrier_wait %p", bar);
1906 fflush(stderr);
1909 /* That this works correctly, and doesn't screw up when a thread
1910 leaving the barrier races round to the front and re-enters while
1911 other threads are still leaving it, is quite subtle. See
1912 comments in the handler for PTHREAD_BARRIER_WAIT_PRE in
1913 hg_main.c. */
1914 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE,
1915 pthread_barrier_t*,bar);
1917 CALL_FN_W_W(ret, fn, bar);
1919 if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) {
1920 DO_PthAPIerror( "pthread_barrier_wait", ret );
1923 if (TRACE_PTH_FNS) {
1924 fprintf(stderr, " pthread_barrier_wait -> %d >>\n", ret);
1927 return ret;
1931 //-----------------------------------------------------------
1932 // glibc: pthread_barrier_destroy
1933 // darwin: (doesn't appear to exist)
1934 // Solaris: pthread_barrier_destroy
1935 // FreeBSD: pthread_barrier_destroy
1936 PTH_FUNC(int, pthreadZubarrierZudestroy, // pthread_barrier_destroy
1937 pthread_barrier_t* bar)
1939 int ret;
1940 OrigFn fn;
1941 VALGRIND_GET_ORIG_FN(fn);
1943 if (TRACE_PTH_FNS) {
1944 fprintf(stderr, "<< pthread_barrier_destroy %p", bar);
1945 fflush(stderr);
1948 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE,
1949 pthread_barrier_t*,bar);
1951 CALL_FN_W_W(ret, fn, bar);
1953 if (ret != 0) {
1954 DO_PthAPIerror( "pthread_barrier_destroy", ret );
1957 if (TRACE_PTH_FNS) {
1958 fprintf(stderr, " pthread_barrier_destroy -> %d >>\n", ret);
1961 return ret;
1964 #endif // defined(HAVE_PTHREAD_BARRIER_INIT)
1967 /*----------------------------------------------------------------*/
1968 /*--- pthread_spinlock_t functions ---*/
1969 /*----------------------------------------------------------------*/
1971 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1972 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1974 /* Handled: pthread_spin_init pthread_spin_destroy
1975 pthread_spin_lock pthread_spin_trylock
1976 pthread_spin_unlock
1978 Unhandled:
1981 /* This is a nasty kludge, in that glibc "knows" that initialising a
1982 spin lock unlocks it, and pthread_spin_{init,unlock} are names for
1983 the same function. Hence we have to have a wrapper which does both
1984 things, without knowing which the user intended to happen.
1985 Solaris has distinct functions for init/unlock but client requests
1986 are immutable in helgrind.h so follow the glibc lead. */
1988 //-----------------------------------------------------------
1989 // glibc: pthread_spin_init
1990 // glibc: pthread_spin_unlock
1991 // darwin: (doesn't appear to exist)
1992 // Solaris: pthread_spin_init
1993 // Solaris: pthread_spin_unlock
1994 // FreeBSD: pthread_spin_init
1995 // FreeBSD: pthread_spin_unlock
1996 __attribute__((noinline))
1997 static int pthread_spin_init_or_unlock_WRK(pthread_spinlock_t* lock,
1998 int pshared) {
1999 int ret;
2000 OrigFn fn;
2001 VALGRIND_GET_ORIG_FN(fn);
2002 if (TRACE_PTH_FNS) {
2003 fprintf(stderr, "<< pthread_spin_iORu %p", lock); fflush(stderr);
2006 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE,
2007 pthread_spinlock_t*, lock);
2009 CALL_FN_W_WW(ret, fn, lock,pshared);
2011 if (ret == 0 /*success*/) {
2012 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST,
2013 pthread_spinlock_t*,lock);
2014 } else {
2015 DO_PthAPIerror( "pthread_spinlock_{init,unlock}", ret );
2018 if (TRACE_PTH_FNS) {
2019 fprintf(stderr, " :: spiniORu -> %d >>\n", ret);
2021 return ret;
2023 #if defined(VGO_linux)
2024 PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
2025 pthread_spinlock_t* lock, int pshared) {
2026 return pthread_spin_init_or_unlock_WRK(lock, pshared);
2028 PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
2029 pthread_spinlock_t* lock) {
2030 /* this is never actually called */
2031 return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/);
2033 #elif defined(VGO_freebsd)
2034 PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
2035 pthread_spinlock_t* lock, int pshared) {
2036 return pthread_spin_init_or_unlock_WRK(lock, pshared);
2038 PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock@*
2039 pthread_spinlock_t* lock) {
2040 /* this is never actually called */
2041 return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/);
2043 #elif defined(VGO_darwin)
2044 #elif defined(VGO_solaris)
2045 PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
2046 pthread_spinlock_t *lock, int pshared) {
2047 return pthread_spin_init_or_unlock_WRK(lock, pshared);
2049 PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
2050 pthread_spinlock_t *lock) {
2051 return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/);
2053 #else
2054 # error "Unsupported OS"
2055 #endif
2058 //-----------------------------------------------------------
2059 // glibc: pthread_spin_destroy
2060 // darwin: (doesn't appear to exist)
2061 // Solaris: pthread_spin_destroy
2062 // FreeBSD: pthread_spin_destroy
2063 __attribute__((noinline))
2064 static int pthread_spin_destroy_WRK(pthread_spinlock_t *lock)
2066 int ret;
2067 OrigFn fn;
2068 VALGRIND_GET_ORIG_FN(fn);
2069 if (TRACE_PTH_FNS) {
2070 fprintf(stderr, "<< pthread_spin_destroy %p", lock);
2071 fflush(stderr);
2074 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_DESTROY_PRE,
2075 pthread_spinlock_t*,lock);
2077 CALL_FN_W_W(ret, fn, lock);
2079 if (ret != 0) {
2080 DO_PthAPIerror( "pthread_spin_destroy", ret );
2083 if (TRACE_PTH_FNS) {
2084 fprintf(stderr, " :: spindestroy -> %d >>\n", ret);
2086 return ret;
2088 #if defined(VGO_linux) || defined(VGO_freebsd)
2089 PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy
2090 pthread_spinlock_t *lock) {
2091 return pthread_spin_destroy_WRK(lock);
2093 #elif defined(VGO_darwin)
2094 #elif defined(VGO_solaris)
2095 PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy
2096 pthread_spinlock_t *lock) {
2097 return pthread_spin_destroy_WRK(lock);
2099 #else
2100 # error "Unsupported OS"
2101 #endif
2104 //-----------------------------------------------------------
2105 // glibc: pthread_spin_lock
2106 // darwin: (doesn't appear to exist)
2107 // Solaris: pthread_spin_lock
2108 // FreeBSD: pthread_spin_lock
2109 __attribute__((noinline))
2110 static int pthread_spin_lock_WRK(pthread_spinlock_t *lock)
2112 int ret;
2113 OrigFn fn;
2114 VALGRIND_GET_ORIG_FN(fn);
2115 if (TRACE_PTH_FNS) {
2116 fprintf(stderr, "<< pthread_spinlock %p", lock);
2117 fflush(stderr);
2120 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE,
2121 pthread_spinlock_t*,lock, long,0/*!isTryLock*/);
2123 CALL_FN_W_W(ret, fn, lock);
2125 /* There's a hole here: libpthread now knows the lock is locked,
2126 but the tool doesn't, so some other thread could run and detect
2127 that the lock has been acquired by someone (this thread). Does
2128 this matter? Not sure, but I don't think so. */
2130 if (ret == 0 /*success*/) {
2131 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST,
2132 pthread_spinlock_t*,lock);
2133 } else {
2134 DO_PthAPIerror( "pthread_spin_lock", ret );
2137 if (TRACE_PTH_FNS) {
2138 fprintf(stderr, " :: spinlock -> %d >>\n", ret);
2140 return ret;
2142 #if defined(VGO_linux) || defined(VGO_freebsd)
2143 PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
2144 pthread_spinlock_t *lock) {
2145 return pthread_spin_lock_WRK(lock);
2147 #elif defined(VGO_darwin)
2148 #elif defined(VGO_solaris)
2149 PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
2150 pthread_spinlock_t *lock) {
2151 return pthread_spin_lock_WRK(lock);
2153 #else
2154 # error "Unsupported OS"
2155 #endif
2158 //-----------------------------------------------------------
2159 // glibc: pthread_spin_trylock
2160 // darwin: (doesn't appear to exist)
2161 // Solaris: pthread_spin_trylock
2162 // FreeBSD: pthread_spin_trylock
2163 __attribute__((noinline))
2164 static int pthread_spin_trylock_WRK(pthread_spinlock_t *lock)
2166 int ret;
2167 OrigFn fn;
2168 VALGRIND_GET_ORIG_FN(fn);
2169 if (TRACE_PTH_FNS) {
2170 fprintf(stderr, "<< pthread_spin_trylock %p", lock);
2171 fflush(stderr);
2174 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE,
2175 pthread_spinlock_t*,lock, long,1/*isTryLock*/);
2177 CALL_FN_W_W(ret, fn, lock);
2179 /* There's a hole here: libpthread now knows the lock is locked,
2180 but the tool doesn't, so some other thread could run and detect
2181 that the lock has been acquired by someone (this thread). Does
2182 this matter? Not sure, but I don't think so. */
2184 if (ret == 0 /*success*/) {
2185 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST,
2186 pthread_spinlock_t*,lock);
2187 } else {
2188 if (ret != EBUSY)
2189 DO_PthAPIerror( "pthread_spin_trylock", ret );
2192 if (TRACE_PTH_FNS) {
2193 fprintf(stderr, " :: spin_trylock -> %d >>\n", ret);
2195 return ret;
2197 #if defined(VGO_linux) || defined(VGO_freebsd)
2198 PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
2199 pthread_spinlock_t *lock) {
2200 return pthread_spin_trylock_WRK(lock);
2202 #elif defined(VGO_darwin)
2203 #elif defined(VGO_solaris)
2204 PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
2205 pthread_spinlock_t *lock) {
2206 return pthread_spin_trylock_WRK(lock);
2208 #else
2209 # error "Unsupported OS"
2210 #endif
2212 #endif // defined(HAVE_PTHREAD_SPIN_LOCK)
2215 /*----------------------------------------------------------------*/
2216 /*--- pthread_rwlock_t functions ---*/
2217 /*----------------------------------------------------------------*/
2219 /* Android's pthread.h doesn't say anything about rwlocks, hence these
2220 functions have to be conditionally compiled. */
2221 #if defined(HAVE_PTHREAD_RWLOCK_T)
2223 /* Handled: pthread_rwlock_init pthread_rwlock_destroy
2224 pthread_rwlock_rdlock
2225 pthread_rwlock_wrlock
2226 pthread_rwlock_unlock
2227 pthread_rwlock_tryrdlock
2228 pthread_rwlock_trywrlock
2231 //-----------------------------------------------------------
2232 // glibc: pthread_rwlock_init
2233 // darwin: pthread_rwlock_init
2234 // darwin: pthread_rwlock_init$UNIX2003
2235 // Solaris: rwlock_init (pthread_rwlock_init is built atop of rwlock_init)
2236 // FreeBSD: pthread_rwlock_init
2237 __attribute__((noinline))
2238 static int pthread_rwlock_init_WRK(pthread_rwlock_t *rwl,
2239 pthread_rwlockattr_t* attr)
2241 int ret;
2242 OrigFn fn;
2243 VALGRIND_GET_ORIG_FN(fn);
2244 if (TRACE_PTH_FNS) {
2245 fprintf(stderr, "<< pthread_rwl_init %p", rwl); fflush(stderr);
2248 CALL_FN_W_WW(ret, fn, rwl,attr);
2250 if (ret == 0 /*success*/) {
2251 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
2252 pthread_rwlock_t*,rwl);
2253 } else {
2254 DO_PthAPIerror( "pthread_rwlock_init", ret );
2257 if (TRACE_PTH_FNS) {
2258 fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
2260 return ret;
2262 #if defined(VGO_linux)
2263 PTH_FUNC(int, pthreadZurwlockZuinit, // pthread_rwlock_init
2264 pthread_rwlock_t *rwl,
2265 pthread_rwlockattr_t* attr) {
2266 return pthread_rwlock_init_WRK(rwl, attr);
2268 #elif defined(VGO_freebsd)
2269 PTH_FUNC(int, pthreadZurwlockZuinit, // pthread_rwlock_init
2270 pthread_rwlock_t *rwl,
2271 pthread_rwlockattr_t* attr) {
2272 return pthread_rwlock_init_WRK(rwl, attr);
2274 #elif defined(VGO_darwin)
2275 PTH_FUNC(int, pthreadZurwlockZuinitZa, // pthread_rwlock_init*
2276 pthread_rwlock_t *rwl,
2277 pthread_rwlockattr_t* attr) {
2278 return pthread_rwlock_init_WRK(rwl, attr);
2280 #elif defined(VGO_solaris)
2281 static int pthread_rwlock_init_WRK(pthread_rwlock_t *rwl,
2282 pthread_rwlockattr_t* attr)
2283 __attribute__((unused));
2284 #else
2285 # error "Unsupported OS"
2286 #endif
2288 #if defined(VGO_solaris)
2289 PTH_FUNC(int, rwlockZuinit, // rwlock_init
2290 rwlock_t *rwlock,
2291 int type,
2292 void *arg)
2294 int ret;
2295 OrigFn fn;
2296 VALGRIND_GET_ORIG_FN(fn);
2297 if (TRACE_PTH_FNS) {
2298 fprintf(stderr, "<< rwl_init %p", rwlock); fflush(stderr);
2301 CALL_FN_W_WWW(ret, fn, rwlock, type, arg);
2303 if (ret == 0 /*success*/) {
2304 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
2305 rwlock_t *, rwlock);
2306 } else {
2307 DO_PthAPIerror("rwlock_init", ret);
2310 if (TRACE_PTH_FNS) {
2311 fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
2313 return ret;
2315 #endif /* VGO_solaris */
2318 //-----------------------------------------------------------
2319 // glibc: pthread_rwlock_destroy
2320 // darwin: pthread_rwlock_destroy
2321 // darwin: pthread_rwlock_destroy$UNIX2003
2322 // Solaris: rwlock_destroy (pthread_rwlock_destroy is a weak alias)
2323 // FreeBSD: pthread_rwlock_destroy
2325 __attribute__((noinline))
2326 static int pthread_rwlock_destroy_WRK(pthread_rwlock_t* rwl)
2328 int ret;
2329 OrigFn fn;
2330 VALGRIND_GET_ORIG_FN(fn);
2331 if (TRACE_PTH_FNS) {
2332 fprintf(stderr, "<< pthread_rwl_destroy %p", rwl); fflush(stderr);
2335 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE,
2336 pthread_rwlock_t*,rwl);
2338 CALL_FN_W_W(ret, fn, rwl);
2340 if (ret != 0) {
2341 DO_PthAPIerror( "pthread_rwlock_destroy", ret );
2344 if (TRACE_PTH_FNS) {
2345 fprintf(stderr, " :: rwl_destroy -> %d >>\n", ret);
2347 return ret;
2349 #if defined(VGO_linux)
2350 PTH_FUNC(int, pthreadZurwlockZudestroy, // pthread_rwlock_destroy
2351 pthread_rwlock_t *rwl) {
2352 return pthread_rwlock_destroy_WRK(rwl);
2354 #elif defined(VGO_freebsd)
2355 PTH_FUNC(int, pthreadZurwlockZudestroy, // pthread_rwlock_destroy
2356 pthread_rwlock_t *rwl) {
2357 return pthread_rwlock_destroy_WRK(rwl);
2359 #elif defined(VGO_darwin)
2360 PTH_FUNC(int, pthreadZurwlockZudestroyZa, // pthread_rwlock_destroy*
2361 pthread_rwlock_t *rwl) {
2362 return pthread_rwlock_destroy_WRK(rwl);
2364 #elif defined(VGO_solaris)
2365 PTH_FUNC(int, rwlockZudestroy, // rwlock_destroy
2366 pthread_rwlock_t *rwl) {
2367 return pthread_rwlock_destroy_WRK(rwl);
2369 #else
2370 # error "Unsupported OS"
2371 #endif
2374 //-----------------------------------------------------------
2375 // glibc: pthread_rwlock_wrlock
2376 // darwin: pthread_rwlock_wrlock
2377 // darwin: pthread_rwlock_wrlock$UNIX2003
2378 // Solaris: rw_wrlock (pthread_rwlock_wrlock is a weak alias)
2379 // FreeBSD: pthread_rwlock_wrlock
2381 __attribute__((noinline))
2382 static int pthread_rwlock_wrlock_WRK(pthread_rwlock_t* rwlock)
2384 int ret;
2385 OrigFn fn;
2386 VALGRIND_GET_ORIG_FN(fn);
2387 if (TRACE_PTH_FNS) {
2388 fprintf(stderr, "<< pthread_rwl_wlk %p", rwlock); fflush(stderr);
2391 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2392 pthread_rwlock_t*,rwlock,
2393 long,1/*isW*/, long,0/*!isTryLock*/);
2395 CALL_FN_W_W(ret, fn, rwlock);
2397 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2398 pthread_rwlock_t*,rwlock, long,1/*isW*/,
2399 long, (ret == 0) ? True : False);
2400 if (ret != 0) {
2401 DO_PthAPIerror( "pthread_rwlock_wrlock", ret );
2404 if (TRACE_PTH_FNS) {
2405 fprintf(stderr, " :: rwl_wlk -> %d >>\n", ret);
2407 return ret;
2409 #if defined(VGO_linux)
2410 PTH_FUNC(int, pthreadZurwlockZuwrlock, // pthread_rwlock_wrlock
2411 pthread_rwlock_t* rwlock) {
2412 return pthread_rwlock_wrlock_WRK(rwlock);
2414 #elif defined(VGO_freebsd)
2415 PTH_FUNC(int, pthreadZurwlockZuwrlock, // pthread_rwlock_wrlock
2416 pthread_rwlock_t* rwlock) {
2417 return pthread_rwlock_wrlock_WRK(rwlock);
2419 #elif defined(VGO_darwin)
2420 PTH_FUNC(int, pthreadZurwlockZuwrlockZa, // pthread_rwlock_wrlock*
2421 pthread_rwlock_t* rwlock) {
2422 return pthread_rwlock_wrlock_WRK(rwlock);
2424 #elif defined(VGO_solaris)
2425 PTH_FUNC(int, rwZuwrlock, // rw_wrlock
2426 pthread_rwlock_t *rwlock) {
2427 return pthread_rwlock_wrlock_WRK(rwlock);
2429 #else
2430 # error "Unsupported OS"
2431 #endif
2433 #if defined(VGO_solaris)
2434 /* Internal to libc. */
2435 PTH_FUNC(void, lrwZuwrlock, // lrw_wrlock
2436 rwlock_t *rwlock)
2438 OrigFn fn;
2439 VALGRIND_GET_ORIG_FN(fn);
2440 if (TRACE_PTH_FNS) {
2441 fprintf(stderr, "<< lrw_wlk %p", rwlock); fflush(stderr);
2444 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2445 pthread_rwlock_t *, rwlock,
2446 long, 1/*isW*/, long, 0/*!isTryLock*/);
2448 CALL_FN_v_W(fn, rwlock);
2450 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2451 pthread_rwlock_t *, rwlock, long, 1/*isW*/, long, True);
2453 if (TRACE_PTH_FNS) {
2454 fprintf(stderr, " :: lrw_wlk >>\n");
2457 #endif /* VGO_solaris */
2460 //-----------------------------------------------------------
2461 // glibc: pthread_rwlock_rdlock
2462 // darwin: pthread_rwlock_rdlock
2463 // darwin: pthread_rwlock_rdlock$UNIX2003
2464 // Solaris: rw_rdlock (pthread_rwlock_rdlock is a weak alias)
2465 // FreeBSD: pthread_rwlock_rdlock
2467 __attribute__((noinline))
2468 static int pthread_rwlock_rdlock_WRK(pthread_rwlock_t* rwlock)
2470 int ret;
2471 OrigFn fn;
2472 VALGRIND_GET_ORIG_FN(fn);
2473 if (TRACE_PTH_FNS) {
2474 fprintf(stderr, "<< pthread_rwl_rlk %p", rwlock); fflush(stderr);
2477 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2478 pthread_rwlock_t*,rwlock,
2479 long,0/*!isW*/, long,0/*!isTryLock*/);
2481 CALL_FN_W_W(ret, fn, rwlock);
2483 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2484 pthread_rwlock_t*,rwlock, long,0/*!isW*/,
2485 long, (ret == 0) ? True : False);
2486 if (ret != 0) {
2487 DO_PthAPIerror( "pthread_rwlock_rdlock", ret );
2490 if (TRACE_PTH_FNS) {
2491 fprintf(stderr, " :: rwl_rlk -> %d >>\n", ret);
2493 return ret;
2495 #if defined(VGO_linux)
2496 PTH_FUNC(int, pthreadZurwlockZurdlock, // pthread_rwlock_rdlock
2497 pthread_rwlock_t* rwlock) {
2498 return pthread_rwlock_rdlock_WRK(rwlock);
2500 #elif defined(VGO_freebsd)
2501 PTH_FUNC(int, pthreadZurwlockZurdlock, // pthread_rwlock_rdlock
2502 pthread_rwlock_t* rwlock) {
2503 return pthread_rwlock_rdlock_WRK(rwlock);
2505 #elif defined(VGO_darwin)
2506 PTH_FUNC(int, pthreadZurwlockZurdlockZa, // pthread_rwlock_rdlock*
2507 pthread_rwlock_t* rwlock) {
2508 return pthread_rwlock_rdlock_WRK(rwlock);
2510 #elif defined(VGO_solaris)
2511 PTH_FUNC(int, rwZurdlock, // rw_rdlock
2512 pthread_rwlock_t *rwlock) {
2513 return pthread_rwlock_rdlock_WRK(rwlock);
2515 #else
2516 # error "Unsupported OS"
2517 #endif
2519 #if defined(VGO_solaris)
2520 /* Internal to libc. */
2521 PTH_FUNC(void, lrwZurdlock, // lrw_rdlock
2522 rwlock_t *rwlock)
2524 OrigFn fn;
2525 VALGRIND_GET_ORIG_FN(fn);
2526 if (TRACE_PTH_FNS) {
2527 fprintf(stderr, "<< lrw_rlk %p", rwlock); fflush(stderr);
2530 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2531 pthread_rwlock_t *, rwlock,
2532 long, 0/*!isW*/, long, 0/*!isTryLock*/);
2534 CALL_FN_v_W(fn, rwlock);
2536 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2537 pthread_rwlock_t *, rwlock, long, 0/*!isW*/, long, True);
2539 if (TRACE_PTH_FNS) {
2540 fprintf(stderr, " :: lrw_rlk ->>\n");
2543 #endif /* VGO_solaris */
2546 //-----------------------------------------------------------
2547 // glibc: pthread_rwlock_trywrlock
2548 // darwin: pthread_rwlock_trywrlock
2549 // darwin: pthread_rwlock_trywrlock$UNIX2003
2550 // Solaris: rw_trywrlock (pthread_rwlock_trywrlock is a weak alias)
2551 // FreeBSD: pthread_rwlock_trywrlock
2553 __attribute__((noinline))
2554 static int pthread_rwlock_trywrlock_WRK(pthread_rwlock_t* rwlock)
2556 int ret;
2557 OrigFn fn;
2558 VALGRIND_GET_ORIG_FN(fn);
2559 if (TRACE_PTH_FNS) {
2560 fprintf(stderr, "<< pthread_rwl_trywlk %p", rwlock); fflush(stderr);
2563 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2564 pthread_rwlock_t*,rwlock,
2565 long,1/*isW*/, long,1/*isTryLock*/);
2567 CALL_FN_W_W(ret, fn, rwlock);
2569 /* There's a hole here: libpthread now knows the lock is locked,
2570 but the tool doesn't, so some other thread could run and detect
2571 that the lock has been acquired by someone (this thread). Does
2572 this matter? Not sure, but I don't think so. */
2574 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2575 pthread_rwlock_t*,rwlock, long,1/*isW*/,
2576 long, (ret == 0) ? True : False);
2577 if (ret != 0) {
2578 if (ret != EBUSY)
2579 DO_PthAPIerror( "pthread_rwlock_trywrlock", ret );
2582 if (TRACE_PTH_FNS) {
2583 fprintf(stderr, " :: rwl_trywlk -> %d >>\n", ret);
2585 return ret;
2587 #if defined(VGO_linux)
2588 PTH_FUNC(int, pthreadZurwlockZutrywrlock, // pthread_rwlock_trywrlock
2589 pthread_rwlock_t* rwlock) {
2590 return pthread_rwlock_trywrlock_WRK(rwlock);
2592 #elif defined(VGO_freebsd)
2593 PTH_FUNC(int, pthreadZurwlockZutrywrlock, // pthread_rwlock_trywrlock
2594 pthread_rwlock_t* rwlock) {
2595 return pthread_rwlock_trywrlock_WRK(rwlock);
2597 #elif defined(VGO_darwin)
2598 PTH_FUNC(int, pthreadZurwlockZutrywrlockZa, // pthread_rwlock_trywrlock*
2599 pthread_rwlock_t* rwlock) {
2600 return pthread_rwlock_trywrlock_WRK(rwlock);
2602 #elif defined(VGO_solaris)
2603 PTH_FUNC(int, rwZutrywrlock, // rw_trywrlock
2604 pthread_rwlock_t *rwlock) {
2605 return pthread_rwlock_trywrlock_WRK(rwlock);
2607 #else
2608 # error "Unsupported OS"
2609 #endif
2612 //-----------------------------------------------------------
2613 // glibc: pthread_rwlock_tryrdlock
2614 // darwin: pthread_rwlock_tryrdlock
2615 // darwin: pthread_rwlock_tryrdlock$UNIX2003
2616 // Solaris: rw_tryrdlock (pthread_rwlock_tryrdlock is a weak alias)
2617 // FreeBSD: pthread_rwlock_tryrdlock
2619 __attribute__((noinline))
2620 static int pthread_rwlock_tryrdlock_WRK(pthread_rwlock_t* rwlock)
2622 int ret;
2623 OrigFn fn;
2624 VALGRIND_GET_ORIG_FN(fn);
2625 if (TRACE_PTH_FNS) {
2626 fprintf(stderr, "<< pthread_rwl_tryrlk %p", rwlock); fflush(stderr);
2629 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2630 pthread_rwlock_t*,rwlock,
2631 long,0/*!isW*/, long,1/*isTryLock*/);
2633 CALL_FN_W_W(ret, fn, rwlock);
2635 /* There's a hole here: libpthread now knows the lock is locked,
2636 but the tool doesn't, so some other thread could run and detect
2637 that the lock has been acquired by someone (this thread). Does
2638 this matter? Not sure, but I don't think so. */
2640 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2641 pthread_rwlock_t*,rwlock, long,0/*!isW*/,
2642 long, (ret == 0) ? True : False);
2644 if (ret != 0) {
2645 if (ret != EBUSY)
2646 DO_PthAPIerror( "pthread_rwlock_tryrdlock", ret );
2649 if (TRACE_PTH_FNS) {
2650 fprintf(stderr, " :: rwl_tryrlk -> %d >>\n", ret);
2652 return ret;
2654 #if defined(VGO_linux)
2655 PTH_FUNC(int, pthreadZurwlockZutryrdlock, // pthread_rwlock_tryrdlock
2656 pthread_rwlock_t* rwlock) {
2657 return pthread_rwlock_tryrdlock_WRK(rwlock);
2659 #elif defined(VGO_freebsd)
2660 PTH_FUNC(int, pthreadZurwlockZutryrdlock, // pthread_rwlock_tryrdlock
2661 pthread_rwlock_t* rwlock) {
2662 return pthread_rwlock_tryrdlock_WRK(rwlock);
2664 #elif defined(VGO_darwin)
2665 PTH_FUNC(int, pthreadZurwlockZutryrdlockZa, // pthread_rwlock_tryrdlock*
2666 pthread_rwlock_t* rwlock) {
2667 return pthread_rwlock_tryrdlock_WRK(rwlock);
2669 #elif defined(VGO_solaris)
2670 PTH_FUNC(int, rwZutryrdlock, // rw_tryrdlock
2671 pthread_rwlock_t *rwlock) {
2672 return pthread_rwlock_tryrdlock_WRK(rwlock);
2674 #else
2675 # error "Unsupported OS"
2676 #endif
2679 //-----------------------------------------------------------
2680 // glibc: pthread_rwlock_timedrdlock
2681 // darwin: Unhandled
2682 // Solaris: pthread_rwlock_timedrdlock
2683 // Solaris: pthread_rwlock_reltimedrdlock_np
2684 // FreeBSD: pthread_rwlock_timedrdlock
2686 __attribute__((noinline)) __attribute__((unused))
2687 static int pthread_rwlock_timedrdlock_WRK(pthread_rwlock_t *rwlock,
2688 const struct timespec *timeout)
2690 int ret;
2691 OrigFn fn;
2692 VALGRIND_GET_ORIG_FN(fn);
2693 if (TRACE_PTH_FNS) {
2694 fprintf(stderr, "<< pthread_rwl_timedrdl %p", rwlock); fflush(stderr);
2697 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2698 pthread_rwlock_t *, rwlock,
2699 long, 0/*isW*/, long, 0/*isTryLock*/);
2701 CALL_FN_W_WW(ret, fn, rwlock, timeout);
2703 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2704 pthread_rwlock_t *, rwlock, long, 0/*isW*/,
2705 long, (ret == 0) ? True : False);
2706 if (ret != 0) {
2707 DO_PthAPIerror("pthread_rwlock_timedrdlock", ret);
2710 if (TRACE_PTH_FNS) {
2711 fprintf(stderr, " :: rwl_timedrdl -> %d >>\n", ret);
2713 return ret;
2715 #if defined(VGO_linux)
2716 PTH_FUNC(int, pthreadZurwlockZutimedrdlock, // pthread_rwlock_timedrdlock
2717 pthread_rwlock_t *rwlock,
2718 const struct timespec *timeout) {
2719 return pthread_rwlock_timedrdlock_WRK(rwlock, timeout);
2721 #elif defined(VGO_darwin)
2722 #elif defined(VGO_freebsd)
2723 PTH_FUNC(int, pthreadZurwlockZutimedrdlock, // pthread_rwlock_timedrdlock
2724 pthread_rwlock_t *rwlock,
2725 const struct timespec *timeout) {
2726 return pthread_rwlock_timedrdlock_WRK(rwlock, timeout);
2728 #elif defined(VGO_solaris)
2729 PTH_FUNC(int, pthreadZurwlockZutimedrdlock, // pthread_rwlock_timedrdlock
2730 pthread_rwlock_t *rwlock,
2731 const struct timespec *timeout) {
2732 return pthread_rwlock_timedrdlock_WRK(rwlock, timeout);
2734 PTH_FUNC(int, pthreadZurwlockZureltimedrdlockZunp, // pthread_rwlock_timedrdlock_np
2735 pthread_rwlock_t *rwlock,
2736 const struct timespec *timeout) {
2737 return pthread_rwlock_timedrdlock_WRK(rwlock, timeout);
2739 #else
2740 # error "Unsupported OS"
2741 #endif
2743 #if defined(VGO_linux)
2744 //-----------------------------------------------------------
2745 // glibc: pthread_rwlock_clockrdlock
2747 __attribute__((noinline)) __attribute__((unused))
2748 static int pthread_rwlock_clockrdlock_WRK(pthread_rwlock_t *rwlock,
2749 clockid_t clockid,
2750 const struct timespec *timeout)
2752 int ret;
2753 OrigFn fn;
2754 VALGRIND_GET_ORIG_FN(fn);
2755 if (TRACE_PTH_FNS) {
2756 fprintf(stderr, "<< pthread_rwl_clockrdl %p", rwlock); fflush(stderr);
2759 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2760 pthread_rwlock_t *, rwlock,
2761 long, 0/*isW*/, long, 0/*isTryLock*/);
2763 CALL_FN_W_WWW(ret, fn, rwlock, clockid, timeout);
2765 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2766 pthread_rwlock_t *, rwlock, long, 0/*isW*/,
2767 long, (ret == 0) ? True : False);
2768 if (ret != 0) {
2769 DO_PthAPIerror("pthread_rwlock_clockrdlock", ret);
2772 if (TRACE_PTH_FNS) {
2773 fprintf(stderr, " :: rwl_clockrdl -> %d >>\n", ret);
2775 return ret;
2778 PTH_FUNC(int, pthreadZurwlockZuclockrdlock, // pthread_rwlock_clockrdlock
2779 pthread_rwlock_t *rwlock,
2780 clockid_t clockid,
2781 const struct timespec *timeout) {
2782 return pthread_rwlock_clockrdlock_WRK(rwlock, clockid, timeout);
2784 #endif
2787 //-----------------------------------------------------------
2788 // glibc: pthread_rwlock_timedwrlock
2789 // Solaris: pthread_rwlock_timedwrlock
2790 // Solaris: pthread_rwlock_reltimedwrlock_np
2791 // FreeBSD: pthread_rwlock_timedwrlock
2793 __attribute__((noinline)) __attribute__((unused))
2794 static int pthread_rwlock_timedwrlock_WRK(pthread_rwlock_t *rwlock,
2795 const struct timespec *timeout)
2797 int ret;
2798 OrigFn fn;
2799 VALGRIND_GET_ORIG_FN(fn);
2800 if (TRACE_PTH_FNS) {
2801 fprintf(stderr, "<< pthread_rwl_timedwrl %p", rwlock); fflush(stderr);
2804 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2805 pthread_rwlock_t *, rwlock,
2806 long, 1/*isW*/, long, 0/*isTryLock*/);
2808 CALL_FN_W_WW(ret, fn, rwlock, timeout);
2810 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2811 pthread_rwlock_t *, rwlock, long, 1/*isW*/,
2812 long, (ret == 0) ? True : False);
2813 if (ret != 0) {
2814 DO_PthAPIerror("pthread_rwlock_timedwrlock", ret);
2817 if (TRACE_PTH_FNS) {
2818 fprintf(stderr, " :: rwl_timedwrl -> %d >>\n", ret);
2820 return ret;
2822 #if defined(VGO_linux)
2823 PTH_FUNC(int, pthreadZurwlockZutimedwrlock, // pthread_rwlock_timedwrlock
2824 pthread_rwlock_t *rwlock,
2825 const struct timespec *timeout) {
2826 return pthread_rwlock_timedwrlock_WRK(rwlock, timeout);
2828 #elif defined(VGO_darwin)
2829 #elif defined(VGO_freebsd)
2830 PTH_FUNC(int, pthreadZurwlockZutimedwrlock, // pthread_rwlock_timedwrlock
2831 pthread_rwlock_t *rwlock,
2832 const struct timespec *timeout) {
2833 return pthread_rwlock_timedwrlock_WRK(rwlock, timeout);
2835 #elif defined(VGO_solaris)
2836 PTH_FUNC(int, pthreadZurwlockZutimedwrlock, // pthread_rwlock_timedwrlock
2837 pthread_rwlock_t *rwlock,
2838 const struct timespec *timeout) {
2839 return pthread_rwlock_timedwrlock_WRK(rwlock, timeout);
2841 PTH_FUNC(int, pthreadZurwlockZureltimedwrlockZunp, // pthread_rwlock_timedwrlock_np
2842 pthread_rwlock_t *rwlock,
2843 const struct timespec *timeout) {
2844 return pthread_rwlock_timedwrlock_WRK(rwlock, timeout);
2846 #else
2847 # error "Unsupported OS"
2848 #endif
2850 #if defined(VGO_linux)
2851 //-----------------------------------------------------------
2852 // glibc: pthread_rwlock_clockwrlock
2854 __attribute__((noinline)) __attribute__((unused))
2855 static int pthread_rwlock_clockwrlock_WRK(pthread_rwlock_t *rwlock,
2856 clockid_t clockid,
2857 const struct timespec *timeout)
2859 int ret;
2860 OrigFn fn;
2861 VALGRIND_GET_ORIG_FN(fn);
2862 if (TRACE_PTH_FNS) {
2863 fprintf(stderr, "<< pthread_rwl_clockwrl %p", rwlock); fflush(stderr);
2866 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2867 pthread_rwlock_t *, rwlock,
2868 long, 1/*isW*/, long, 0/*isTryLock*/);
2870 CALL_FN_W_WWW(ret, fn, rwlock, clockid, timeout);
2872 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2873 pthread_rwlock_t *, rwlock, long, 1/*isW*/,
2874 long, (ret == 0) ? True : False);
2875 if (ret != 0) {
2876 DO_PthAPIerror("pthread_rwlock_clockwrlock", ret);
2879 if (TRACE_PTH_FNS) {
2880 fprintf(stderr, " :: rwl_clockwrl -> %d >>\n", ret);
2882 return ret;
2885 PTH_FUNC(int, pthreadZurwlockZuclockwrlock, // pthread_rwlock_clockwrlock
2886 pthread_rwlock_t *rwlock,
2887 clockid_t clockid,
2888 const struct timespec *timeout) {
2889 return pthread_rwlock_clockwrlock_WRK(rwlock, clockid, timeout);
2891 #endif
2894 //-----------------------------------------------------------
2895 // glibc: pthread_rwlock_unlock
2896 // darwin: pthread_rwlock_unlock
2897 // darwin: pthread_rwlock_unlock$UNIX2003
2898 // Solaris: rw_unlock (pthread_rwlock_unlock is a weak alias)
2899 // FreeBSD: pthread_rwlock_unlock
2900 __attribute__((noinline))
2901 static int pthread_rwlock_unlock_WRK(pthread_rwlock_t* rwlock)
2903 int ret;
2904 OrigFn fn;
2905 VALGRIND_GET_ORIG_FN(fn);
2906 if (TRACE_PTH_FNS) {
2907 fprintf(stderr, "<< pthread_rwl_unlk %p", rwlock); fflush(stderr);
2910 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
2911 pthread_rwlock_t*,rwlock);
2913 CALL_FN_W_W(ret, fn, rwlock);
2915 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
2916 pthread_rwlock_t*,rwlock);
2917 if (ret != 0) {
2918 DO_PthAPIerror( "pthread_rwlock_unlock", ret );
2921 if (TRACE_PTH_FNS) {
2922 fprintf(stderr, " :: rwl_unlk -> %d >>\n", ret);
2924 return ret;
2926 #if defined(VGO_linux)
2927 PTH_FUNC(int, pthreadZurwlockZuunlock, // pthread_rwlock_unlock
2928 pthread_rwlock_t* rwlock) {
2929 return pthread_rwlock_unlock_WRK(rwlock);
2931 #elif defined(VGO_freebsd)
2932 PTH_FUNC(int, pthreadZurwlockZuunlock, // pthread_rwlock_unlock
2933 pthread_rwlock_t* rwlock) {
2934 return pthread_rwlock_unlock_WRK(rwlock);
2936 #elif defined(VGO_darwin)
2937 PTH_FUNC(int, pthreadZurwlockZuunlockZa, // pthread_rwlock_unlock*
2938 pthread_rwlock_t* rwlock) {
2939 return pthread_rwlock_unlock_WRK(rwlock);
2941 #elif defined(VGO_solaris)
2942 PTH_FUNC(int, rwZuunlock, // rw_unlock
2943 pthread_rwlock_t *rwlock) {
2944 return pthread_rwlock_unlock_WRK(rwlock);
2946 #else
2947 # error "Unsupported OS"
2948 #endif
2950 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
2953 /*----------------------------------------------------------------*/
2954 /*--- POSIX semaphores ---*/
2955 /*----------------------------------------------------------------*/
2957 #include <semaphore.h>
2958 #include <fcntl.h> /* O_CREAT */
2960 #define TRACE_SEM_FNS 0
2962 /* Handled:
2963 int sem_init(sem_t *sem, int pshared, unsigned value);
2964 int sem_destroy(sem_t *sem);
2965 int sem_wait(sem_t *sem);
2966 int sem_post(sem_t *sem);
2967 sem_t* sem_open(const char *name, int oflag,
2968 ... [mode_t mode, unsigned value]);
2969 [complete with its idiotic semantics]
2970 int sem_close(sem_t* sem);
2972 Unhandled:
2973 int sem_trywait(sem_t *sem);
2974 int sem_timedwait(sem_t *restrict sem,
2975 const struct timespec *restrict abs_timeout);
2978 //-----------------------------------------------------------
2979 // glibc: sem_init@@GLIBC_2.2.5
2980 // glibc: sem_init@@GLIBC_2.1
2981 // glibc: sem_init@GLIBC_2.0
2982 // darwin: sem_init
2983 // Solaris: sema_init (sem_init is built on top of sem_init)
2984 // FreeBSD: sem_init (libc)
2986 #if !defined(VGO_solaris)
2987 __attribute__((noinline))
2988 static int sem_init_WRK(sem_t* sem, int pshared, unsigned long value)
2990 OrigFn fn;
2991 int ret;
2992 VALGRIND_GET_ORIG_FN(fn);
2994 if (TRACE_SEM_FNS) {
2995 fprintf(stderr, "<< sem_init(%p,%d,%lu) ", sem,pshared,value);
2996 fflush(stderr);
2999 CALL_FN_W_WWW(ret, fn, sem,pshared,value);
3001 if (ret == 0) {
3002 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
3003 sem_t*, sem, unsigned long, value);
3004 } else {
3005 DO_PthAPIerror( "sem_init", errno );
3008 if (TRACE_SEM_FNS) {
3009 fprintf(stderr, " sem_init -> %d >>\n", ret);
3010 fflush(stderr);
3013 return ret;
3015 #if defined(VGO_linux)
3016 PTH_FUNC(int, semZuinitZAZa, // sem_init@*
3017 sem_t* sem, int pshared, unsigned long value) {
3018 return sem_init_WRK(sem, pshared, value);
3020 #elif defined(VGO_darwin)
3021 PTH_FUNC(int, semZuinit, // sem_init
3022 sem_t* sem, int pshared, unsigned long value) {
3023 return sem_init_WRK(sem, pshared, value);
3025 #elif defined(VGO_freebsd)
3026 LIBC_FUNC(int, semZuinit, // sem_init
3027 sem_t* sem, int pshared, unsigned long value) {
3028 return sem_init_WRK(sem, pshared, value);
3030 #else
3031 # error "Unsupported OS"
3032 #endif
3034 #else /* VGO_solaris */
3035 PTH_FUNC(int, semaZuinit, // sema_init
3036 sema_t *sem,
3037 unsigned int value,
3038 int type,
3039 void *arg)
3041 OrigFn fn;
3042 int ret;
3043 VALGRIND_GET_ORIG_FN(fn);
3045 if (TRACE_SEM_FNS) {
3046 fprintf(stderr, "<< sema_init(%p, %d, %u) ", sem, type, value);
3047 fflush(stderr);
3050 CALL_FN_W_WWWW(ret, fn, sem, value, type, arg);
3052 if (ret == 0) {
3053 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
3054 sema_t *, sem, Word, value);
3055 } else {
3056 DO_PthAPIerror("sema_init", ret);
3059 if (TRACE_SEM_FNS) {
3060 fprintf(stderr, " sema_init -> %d >>\n", ret);
3061 fflush(stderr);
3064 return ret;
3066 #endif /* VGO_solaris */
3069 //-----------------------------------------------------------
3070 // glibc: sem_destroy@GLIBC_2.0
3071 // glibc: sem_destroy@@GLIBC_2.1
3072 // glibc: sem_destroy@@GLIBC_2.2.5
3073 // darwin: sem_destroy
3074 // Solaris: sema_destroy (sem_destroy is built on top of sema_destroy)
3075 // FreeBSD: sem_destroy (libc)
3076 __attribute__((noinline))
3077 static int sem_destroy_WRK(sem_t* sem)
3079 OrigFn fn;
3080 int ret;
3081 VALGRIND_GET_ORIG_FN(fn);
3083 if (TRACE_SEM_FNS) {
3084 fprintf(stderr, "<< sem_destroy(%p) ", sem);
3085 fflush(stderr);
3088 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
3090 CALL_FN_W_W(ret, fn, sem);
3092 if (ret != 0) {
3093 DO_PthAPIerror( "sem_destroy", SEM_ERROR );
3096 if (TRACE_SEM_FNS) {
3097 fprintf(stderr, " sem_destroy -> %d >>\n", ret);
3098 fflush(stderr);
3101 return ret;
3103 #if defined(VGO_linux)
3104 PTH_FUNC(int, semZudestroyZAZa, // sem_destroy*
3105 sem_t* sem) {
3106 return sem_destroy_WRK(sem);
3108 #elif defined(VGO_darwin)
3109 PTH_FUNC(int, semZudestroy, // sem_destroy
3110 sem_t* sem) {
3111 return sem_destroy_WRK(sem);
3113 #elif defined(VGO_freebsd)
3114 LIBC_FUNC(int, semZudestroy, // sem_destroy
3115 sem_t* sem) {
3116 return sem_destroy_WRK(sem);
3118 #elif defined(VGO_solaris)
3119 PTH_FUNC(int, semaZudestroy, // sema_destroy
3120 sem_t *sem) {
3121 return sem_destroy_WRK(sem);
3123 #else
3124 # error "Unsupported OS"
3125 #endif
3128 //-----------------------------------------------------------
3129 // glibc: sem_wait
3130 // glibc: sem_wait@GLIBC_2.0
3131 // glibc: sem_wait@@GLIBC_2.1
3132 // darwin: sem_wait
3133 // darwin: sem_wait$NOCANCEL$UNIX2003
3134 // darwin: sem_wait$UNIX2003
3135 // Solaris: sema_wait (sem_wait is built on top of sema_wait)
3136 // FreeBSD: sem_wait (libc)
3138 /* wait: decrement semaphore - acquire lockage */
3139 __attribute__((noinline))
3140 static int sem_wait_WRK(sem_t* sem)
3142 OrigFn fn;
3143 int ret;
3144 VALGRIND_GET_ORIG_FN(fn);
3146 if (TRACE_SEM_FNS) {
3147 fprintf(stderr, "<< sem_wait(%p) ", sem);
3148 fflush(stderr);
3151 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_PRE, sem_t*,sem);
3153 CALL_FN_W_W(ret, fn, sem);
3155 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST, sem_t*,sem,
3156 long, (ret == 0) ? True : False);
3158 if (ret != 0) {
3159 DO_PthAPIerror( "sem_wait", SEM_ERROR );
3162 if (TRACE_SEM_FNS) {
3163 fprintf(stderr, " sem_wait -> %d >>\n", ret);
3164 fflush(stderr);
3167 return ret;
3169 #if defined(VGO_linux)
3170 PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
3171 return sem_wait_WRK(sem);
3173 PTH_FUNC(int, semZuwaitZAZa, sem_t* sem) { /* sem_wait@* */
3174 return sem_wait_WRK(sem);
3176 #elif defined(VGO_darwin)
3177 PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
3178 return sem_wait_WRK(sem);
3180 PTH_FUNC(int, semZuwaitZDZa, sem_t* sem) { /* sem_wait$* */
3181 return sem_wait_WRK(sem);
3183 #elif defined(VGO_freebsd)
3184 LIBC_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
3185 return sem_wait_WRK(sem);
3187 #elif defined(VGO_solaris)
3188 PTH_FUNC(int, semaZuwait, sem_t *sem) { /* sema_wait */
3189 return sem_wait_WRK(sem);
3191 #else
3192 # error "Unsupported OS"
3193 #endif
3196 //-----------------------------------------------------------
3197 // glibc: sem_post
3198 // glibc: sem_post@GLIBC_2.0
3199 // glibc: sem_post@@GLIBC_2.1
3200 // darwin: sem_post
3201 // Solaris: sema_post (sem_post is built on top of sema_post)
3202 // FreeBSD: sem_post (libc)
3204 /* post: increment semaphore - release lockage */
3205 __attribute__((noinline))
3206 static int sem_post_WRK(sem_t* sem)
3208 OrigFn fn;
3209 int ret;
3211 VALGRIND_GET_ORIG_FN(fn);
3213 if (TRACE_SEM_FNS) {
3214 fprintf(stderr, "<< sem_post(%p) ", sem);
3215 fflush(stderr);
3218 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_PRE, sem_t*,sem);
3220 CALL_FN_W_W(ret, fn, sem);
3222 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_POST, sem_t*,sem);
3224 if (ret != 0) {
3225 DO_PthAPIerror( "sem_post", SEM_ERROR );
3228 if (TRACE_SEM_FNS) {
3229 fprintf(stderr, " sem_post -> %d >>\n", ret);
3230 fflush(stderr);
3233 return ret;
3235 #if defined(VGO_linux)
3236 PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
3237 return sem_post_WRK(sem);
3239 PTH_FUNC(int, semZupostZAZa, sem_t* sem) { /* sem_post@* */
3240 return sem_post_WRK(sem);
3242 #elif defined(VGO_darwin)
3243 PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
3244 return sem_post_WRK(sem);
3246 #elif defined(VGO_freebsd)
3247 LIBC_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
3248 return sem_post_WRK(sem);
3250 #elif defined(VGO_solaris)
3251 PTH_FUNC(int, semaZupost, sem_t *sem) { /* sema_post */
3252 return sem_post_WRK(sem);
3254 #else
3255 # error "Unsupported OS"
3256 #endif
3259 //-----------------------------------------------------------
3260 // glibc: sem_open
3261 // darwin: sem_open
3262 // Solaris: sem_open
3263 // FreeBSD: sem_open
3265 #if defined(VGO_freebsd)
3266 LIBC_FUNC(sem_t*, semZuopen,
3267 const char* name, long oflag,
3268 long mode, unsigned long value)
3269 #else
3270 PTH_FUNC(sem_t*, semZuopen,
3271 const char* name, long oflag,
3272 long mode, unsigned long value)
3273 #endif
3275 /* A copy of sem_init_WRK (more or less). Is this correct? */
3276 OrigFn fn;
3277 sem_t* ret;
3278 VALGRIND_GET_ORIG_FN(fn);
3280 if (TRACE_SEM_FNS) {
3281 fprintf(stderr, "<< sem_open(\"%s\",%ld,%lx,%lu) ",
3282 name,oflag,mode,value);
3283 fflush(stderr);
3286 CALL_FN_W_WWWW(ret, fn, name,oflag,mode,value);
3288 if (ret != SEM_FAILED && (oflag & O_CREAT)) {
3289 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
3290 sem_t*, ret, unsigned long, value);
3292 if (ret == SEM_FAILED) {
3293 DO_PthAPIerror( "sem_open", errno );
3296 if (TRACE_SEM_FNS) {
3297 fprintf(stderr, " sem_open -> %p >>\n", ret);
3298 fflush(stderr);
3301 return ret;
3305 //-----------------------------------------------------------
3306 // glibc: sem_close
3307 // darwin: sem_close
3308 // Solaris: sem_close
3309 // FreeBSD: sem_close
3310 #if defined (VGO_freebsd)
3311 LIBC_FUNC(int, sem_close, sem_t* sem)
3312 #else
3313 PTH_FUNC(int, sem_close, sem_t* sem)
3314 #endif
3316 OrigFn fn;
3317 int ret;
3318 VALGRIND_GET_ORIG_FN(fn);
3320 if (TRACE_SEM_FNS) {
3321 fprintf(stderr, "<< sem_close(%p) ", sem);
3322 fflush(stderr);
3325 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
3327 CALL_FN_W_W(ret, fn, sem);
3329 if (ret != 0) {
3330 DO_PthAPIerror( "sem_close", errno );
3333 if (TRACE_SEM_FNS) {
3334 fprintf(stderr, " close -> %d >>\n", ret);
3335 fflush(stderr);
3338 return ret;
3342 /*----------------------------------------------------------------*/
3343 /*--- Qt 4 threading functions (w/ GNU name mangling) ---*/
3344 /*----------------------------------------------------------------*/
3346 /* Handled:
3347 QMutex::lock()
3348 QMutex::unlock()
3349 QMutex::tryLock()
3350 QMutex::tryLock(int)
3352 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC1ENS_13RecursionModeE
3353 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC2ENS_13RecursionModeE
3354 QMutex::~QMutex() _ZN6QMutexD1Ev
3355 QMutex::~QMutex() _ZN6QMutexD2Ev
3357 Unhandled:
3358 QReadWriteLock::lockForRead()
3359 QReadWriteLock::lockForWrite()
3360 QReadWriteLock::unlock()
3361 QReadWriteLock::tryLockForRead(int)
3362 QReadWriteLock::tryLockForRead()
3363 QReadWriteLock::tryLockForWrite(int)
3364 QReadWriteLock::tryLockForWrite()
3366 QWaitCondition::wait(QMutex*, unsigned long)
3367 QWaitCondition::wakeAll()
3368 QWaitCondition::wakeOne()
3370 QSemaphore::*
3372 /* More comments, 19 Nov 08, based on assessment of qt-4.5.0TP1,
3373 at least on Unix:
3375 It's apparently only necessary to intercept QMutex, since that is
3376 not implemented using pthread_mutex_t; instead Qt4 has its own
3377 implementation based on atomics (to check the non-contended case)
3378 and pthread_cond_wait (to wait in the contended case).
3380 QReadWriteLock is built on top of QMutex, counters, and a wait
3381 queue. So we don't need to handle it specially once QMutex
3382 handling is correct -- presumably the dependencies through QMutex
3383 are sufficient to avoid any false race reports. On the other hand,
3384 it is an open question whether too many dependencies are observed
3385 -- in which case we may miss races (false negatives). I suspect
3386 this is likely to be the case, unfortunately.
3388 QWaitCondition is built on pthread_cond_t, pthread_mutex_t, QMutex
3389 and QReadWriteLock. Same compositional-correctness justificiation
3390 and limitations as fro QReadWriteLock.
3392 Ditto QSemaphore (from cursory examination).
3394 Does it matter that only QMutex is handled directly? Open
3395 question. From testing with drd/tests/qt4_* and with KDE4 apps, it
3396 appears that no false errors are reported; however it is not clear
3397 if this is causing false negatives.
3399 Another problem with Qt4 is thread exiting. Threads are created
3400 with pthread_create (fine); but they detach and simply exit when
3401 done. There is no use of pthread_join, and the provided
3402 wait-for-a-thread-to-exit mechanism (QThread::wait, I believe)
3403 relies on a system of mutexes and flags. I suspect this also
3404 causes too many dependencies to appear. Consequently H sometimes
3405 fails to detect races at exit in some very short-lived racy
3406 programs, because it appears that a thread can exit _and_ have an
3407 observed dependency edge back to the main thread (presumably)
3408 before the main thread reaps the child (that is, calls
3409 QThread::wait).
3411 This theory is supported by the observation that if all threads are
3412 made to wait at a pthread_barrier_t immediately before they exit,
3413 then H's detection of races in such programs becomes reliable;
3414 without the barrier, it is varies from run to run, depending
3415 (according to investigation) on whether aforementioned
3416 exit-before-reaping behaviour happens or not.
3418 Finally, why is it necessary to intercept the QMutex constructors
3419 and destructors? The constructors are intercepted only as a matter
3420 of convenience, so H can print accurate "first observed at"
3421 clauses. However, it is actually necessary to intercept the
3422 destructors (as it is with pthread_mutex_destroy) in order that
3423 locks get removed from LAOG when they are destroyed.
3426 // soname is libQtCore.so.4 ; match against libQtCore.so*
3427 #define QT4_FUNC(ret_ty, f, args...) \
3428 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args); \
3429 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args)
3431 // soname is libQt5Core.so.4 ; match against libQt5Core.so*
3432 #define QT5_FUNC(ret_ty, f, args...) \
3433 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args); \
3434 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args)
3436 //-----------------------------------------------------------
3437 // QMutex::lock()
3438 __attribute__((noinline))
3439 static void QMutex_lock_WRK(void* self)
3441 OrigFn fn;
3442 VALGRIND_GET_ORIG_FN(fn);
3443 if (TRACE_QT4_FNS) {
3444 fprintf(stderr, "<< QMutex::lock %p", self); fflush(stderr);
3447 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
3448 void*,self, long,0/*!isTryLock*/);
3450 CALL_FN_v_W(fn, self);
3452 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
3453 void *, self, long, True);
3455 if (TRACE_QT4_FNS) {
3456 fprintf(stderr, " :: Q::lock done >>\n");
3460 QT4_FUNC(void, _ZN6QMutex4lockEv, void* self) {
3461 QMutex_lock_WRK(self);
3463 QT5_FUNC(void, _ZN6QMutex4lockEv, void* self) {
3464 QMutex_lock_WRK(self);
3467 //-----------------------------------------------------------
3468 // QMutex::unlock()
3469 __attribute__((noinline))
3470 static void QMutex_unlock_WRK(void* self)
3472 OrigFn fn;
3473 VALGRIND_GET_ORIG_FN(fn);
3475 if (TRACE_QT4_FNS) {
3476 fprintf(stderr, "<< QMutex::unlock %p", self); fflush(stderr);
3479 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
3480 void*, self);
3482 CALL_FN_v_W(fn, self);
3484 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
3485 void*, self);
3487 if (TRACE_QT4_FNS) {
3488 fprintf(stderr, " Q::unlock done >>\n");
3492 QT4_FUNC(void, _ZN6QMutex6unlockEv, void* self) {
3493 QMutex_unlock_WRK(self);
3495 QT5_FUNC(void, _ZN6QMutex6unlockEv, void* self) {
3496 QMutex_unlock_WRK(self);
3499 //-----------------------------------------------------------
3500 // bool QMutex::tryLock()
3501 // using 'long' to mimic C++ 'bool'
3502 __attribute__((noinline))
3503 static long QMutex_tryLock_WRK(void* self)
3505 OrigFn fn;
3506 long ret;
3507 VALGRIND_GET_ORIG_FN(fn);
3508 if (TRACE_QT4_FNS) {
3509 fprintf(stderr, "<< QMutex::tryLock %p", self); fflush(stderr);
3512 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
3513 void*,self, long,1/*isTryLock*/);
3515 CALL_FN_W_W(ret, fn, self);
3517 // assumes that only the low 8 bits of the 'bool' are significant
3518 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
3519 void *, self, long, (ret & 0xFF) ? True : False);
3521 if (TRACE_QT4_FNS) {
3522 fprintf(stderr, " :: Q::tryLock -> %lu >>\n", ret);
3525 return ret;
3528 QT4_FUNC(long, _ZN6QMutex7tryLockEv, void* self) {
3529 return QMutex_tryLock_WRK(self);
3531 QT5_FUNC(long, _ZN6QMutex7tryLockEv, void* self) {
3532 return QMutex_tryLock_WRK(self);
3535 //-----------------------------------------------------------
3536 // bool QMutex::tryLock(int)
3537 // using 'long' to mimic C++ 'bool'
3538 __attribute__((noinline))
3539 static long QMutex_tryLock_int_WRK(void* self, long arg2)
3541 OrigFn fn;
3542 long ret;
3543 VALGRIND_GET_ORIG_FN(fn);
3544 if (TRACE_QT4_FNS) {
3545 fprintf(stderr, "<< QMutex::tryLock(int) %p %d", self, (int)arg2);
3546 fflush(stderr);
3549 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
3550 void*,self, long,1/*isTryLock*/);
3552 CALL_FN_W_WW(ret, fn, self,arg2);
3554 // assumes that only the low 8 bits of the 'bool' are significant
3555 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
3556 void *, self, long, (ret & 0xFF) ? True : False);
3558 if (TRACE_QT4_FNS) {
3559 fprintf(stderr, " :: Q::tryLock(int) -> %lu >>\n", ret);
3562 return ret;
3565 QT4_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2) {
3566 return QMutex_tryLock_int_WRK(self, arg2);
3568 QT5_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2) {
3569 return QMutex_tryLock_int_WRK(self, arg2);
3572 //-----------------------------------------------------------
3573 // It's not really very clear what the args are here. But from
3574 // a bit of dataflow analysis of the generated machine code of
3575 // the original function, it appears this takes two args, and
3576 // returns nothing. Nevertheless preserve return value just in
3577 // case. A bit of debug printing indicates that the first arg
3578 // is that of the mutex and the second is either zero or one,
3579 // probably being the recursion mode, therefore.
3580 // QMutex::QMutex(QMutex::RecursionMode) ("C1ENS" variant)
3581 __attribute__((noinline))
3582 static void* QMutex_constructor_WRK(void* mutex, long recmode)
3584 OrigFn fn;
3585 long ret;
3586 VALGRIND_GET_ORIG_FN(fn);
3587 CALL_FN_W_WW(ret, fn, mutex, recmode);
3588 // fprintf(stderr, "QMutex constructor 1: %p <- %p %p\n", ret, arg1, arg2);
3589 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
3590 void*,mutex, long,1/*mbRec*/);
3591 return (void*)ret;
3594 QT4_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE, void* self, long recmode) {
3595 return QMutex_constructor_WRK(self, recmode);
3597 QT5_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE, void* self, long recmode) {
3598 return QMutex_constructor_WRK(self, recmode);
3601 //-----------------------------------------------------------
3602 // QMutex::~QMutex() ("D1Ev" variant)
3603 __attribute__((noinline))
3604 static void* QMutex_destructor_WRK(void* mutex)
3606 OrigFn fn;
3607 long ret;
3608 VALGRIND_GET_ORIG_FN(fn);
3609 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
3610 void*,mutex);
3611 CALL_FN_W_W(ret, fn, mutex);
3612 return (void*)ret;
3615 QT4_FUNC(void*, _ZN6QMutexD1Ev, void* self) {
3616 return QMutex_destructor_WRK(self);
3618 QT5_FUNC(void*, _ZN6QMutexD1Ev, void* self) {
3619 return QMutex_destructor_WRK(self);
3622 //-----------------------------------------------------------
3623 // QMutex::QMutex(QMutex::RecursionMode) ("C2ENS" variant)
3624 QT4_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE,
3625 void* mutex,
3626 long recmode)
3628 assert(0);
3629 /*NOTREACHED*/
3630 /* Android's gcc behaves like it doesn't know that assert(0)
3631 never returns. Hence: */
3632 return NULL;
3635 QT5_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE, void* self, long recmode)
3637 assert(0);
3638 /*NOTREACHED*/
3639 return NULL;
3642 //-----------------------------------------------------------
3643 // QMutex::~QMutex() ("D2Ev" variant)
3644 QT4_FUNC(void*, _ZN6QMutexD2Ev, void* mutex)
3646 assert(0);
3647 /* Android's gcc behaves like it doesn't know that assert(0)
3648 never returns. Hence: */
3649 return NULL;
3652 QT5_FUNC(void*, _ZN6QMutexD2Ev, void* self)
3654 assert(0);
3655 /*NOTREACHED*/
3656 return NULL;
3659 // QReadWriteLock is not intercepted directly. See comments
3660 // above.
3662 //// QReadWriteLock::lockForRead()
3663 //// _ZN14QReadWriteLock11lockForReadEv == QReadWriteLock::lockForRead()
3664 //QT4_FUNC(void, ZuZZN14QReadWriteLock11lockForReadEv,
3665 // // _ZN14QReadWriteLock11lockForReadEv
3666 // void* self)
3668 // OrigFn fn;
3669 // VALGRIND_GET_ORIG_FN(fn);
3670 // if (TRACE_QT4_FNS) {
3671 // fprintf(stderr, "<< QReadWriteLock::lockForRead %p", self);
3672 // fflush(stderr);
3673 // }
3675 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
3676 // void*,self,
3677 // long,0/*!isW*/, long,0/*!isTryLock*/);
3679 // CALL_FN_v_W(fn, self);
3681 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
3682 // void*,self, long,0/*!isW*/, long, True);
3684 // if (TRACE_QT4_FNS) {
3685 // fprintf(stderr, " :: Q::lockForRead :: done >>\n");
3686 // }
3689 //// QReadWriteLock::lockForWrite()
3690 //// _ZN14QReadWriteLock12lockForWriteEv == QReadWriteLock::lockForWrite()
3691 //QT4_FUNC(void, ZuZZN14QReadWriteLock12lockForWriteEv,
3692 // // _ZN14QReadWriteLock12lockForWriteEv
3693 // void* self)
3695 // OrigFn fn;
3696 // VALGRIND_GET_ORIG_FN(fn);
3697 // if (TRACE_QT4_FNS) {
3698 // fprintf(stderr, "<< QReadWriteLock::lockForWrite %p", self);
3699 // fflush(stderr);
3700 // }
3702 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
3703 // void*,self,
3704 // long,1/*isW*/, long,0/*!isTryLock*/);
3706 // CALL_FN_v_W(fn, self);
3708 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
3709 // void*,self, long,1/*isW*/, long, True);
3711 // if (TRACE_QT4_FNS) {
3712 // fprintf(stderr, " :: Q::lockForWrite :: done >>\n");
3713 // }
3716 //// QReadWriteLock::unlock()
3717 //// _ZN14QReadWriteLock6unlockEv == QReadWriteLock::unlock()
3718 //QT4_FUNC(void, ZuZZN14QReadWriteLock6unlockEv,
3719 // // _ZN14QReadWriteLock6unlockEv
3720 // void* self)
3722 // OrigFn fn;
3723 // VALGRIND_GET_ORIG_FN(fn);
3724 // if (TRACE_QT4_FNS) {
3725 // fprintf(stderr, "<< QReadWriteLock::unlock %p", self);
3726 // fflush(stderr);
3727 // }
3729 // DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
3730 // void*,self);
3732 // CALL_FN_v_W(fn, self);
3734 // DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
3735 // void*,self);
3737 // if (TRACE_QT4_FNS) {
3738 // fprintf(stderr, " :: Q::unlock :: done >>\n");
3739 // }
3743 /*----------------------------------------------------------------*/
3744 /*--- Replacements for basic string functions, that don't ---*/
3745 /*--- overrun the input arrays. ---*/
3746 /*----------------------------------------------------------------*/
3748 #include "../shared/vg_replace_strmem.c"
3750 /*--------------------------------------------------------------------*/
3751 /*--- end hg_intercepts.c ---*/
3752 /*--------------------------------------------------------------------*/