Merge mc_replace_strmem.c, hg_intercepts.c and drd_strmem_intercepts.c
[valgrind.git] / helgrind / hg_intercepts.c
blob5f02e5b28020c2435bdd9c082de947deb07420dc
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-2013 OpenWorks LLP
12 info@open-works.co.uk
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
29 The GNU General Public License is contained in the file COPYING.
31 Neither the names of the U.S. Department of Energy nor the
32 University of California nor the names of its contributors may be
33 used to endorse or promote products derived from this software
34 without prior written permission.
37 /* RUNS ON SIMULATED CPU
38 Interceptors for pthread_* functions, so that tc_main can see
39 significant thread events.
41 Important: when adding a function wrapper to this file, remember to
42 add a test case to tc20_verifywrap.c. A common cause of failure is
43 for wrappers to not engage on different distros, and
44 tc20_verifywrap essentially checks that each wrapper is really
45 doing something.
48 // DDD: for Darwin, need to have non-"@*"-suffixed versions for all pthread
49 // functions that currently have them.
50 // Note also, in the comments and code below, all Darwin symbols start
51 // with a leading underscore, which is not shown either in the comments
52 // nor in the redirect specs.
55 #include "pub_tool_basics.h"
56 #include "pub_tool_redir.h"
57 #include "pub_tool_clreq.h"
58 #include "helgrind.h"
59 #include "config.h"
61 #define TRACE_PTH_FNS 0
62 #define TRACE_QT4_FNS 0
65 /*----------------------------------------------------------------*/
66 /*--- ---*/
67 /*----------------------------------------------------------------*/
69 #define PTH_FUNC(ret_ty, f, args...) \
70 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args); \
71 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args)
73 // Do a client request. These are macros rather than a functions so
74 // as to avoid having an extra frame in stack traces.
76 // NB: these duplicate definitions in helgrind.h. But here, we
77 // can have better typing (Word etc) and assertions, whereas
78 // in helgrind.h we can't. Obviously it's important the two
79 // sets of definitions are kept in sync.
81 // nuke the previous definitions
82 #undef DO_CREQ_v_W
83 #undef DO_CREQ_v_WW
84 #undef DO_CREQ_W_WW
85 #undef DO_CREQ_v_WWW
87 #define DO_CREQ_v_W(_creqF, _ty1F,_arg1F) \
88 do { \
89 Word _arg1; \
90 assert(sizeof(_ty1F) == sizeof(Word)); \
91 _arg1 = (Word)(_arg1F); \
92 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
93 _arg1, 0,0,0,0); \
94 } while (0)
96 #define DO_CREQ_v_WW(_creqF, _ty1F,_arg1F, _ty2F,_arg2F) \
97 do { \
98 Word _arg1, _arg2; \
99 assert(sizeof(_ty1F) == sizeof(Word)); \
100 assert(sizeof(_ty2F) == sizeof(Word)); \
101 _arg1 = (Word)(_arg1F); \
102 _arg2 = (Word)(_arg2F); \
103 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
104 _arg1,_arg2,0,0,0); \
105 } while (0)
107 #define DO_CREQ_W_WW(_resF, _creqF, _ty1F,_arg1F, \
108 _ty2F,_arg2F) \
109 do { \
110 Word _res, _arg1, _arg2; \
111 assert(sizeof(_ty1F) == sizeof(Word)); \
112 assert(sizeof(_ty2F) == sizeof(Word)); \
113 _arg1 = (Word)(_arg1F); \
114 _arg2 = (Word)(_arg2F); \
115 _res = VALGRIND_DO_CLIENT_REQUEST_EXPR(2, \
116 (_creqF), \
117 _arg1,_arg2,0,0,0); \
118 _resF = _res; \
119 } while (0)
121 #define DO_CREQ_v_WWW(_creqF, _ty1F,_arg1F, \
122 _ty2F,_arg2F, _ty3F, _arg3F) \
123 do { \
124 Word _arg1, _arg2, _arg3; \
125 assert(sizeof(_ty1F) == sizeof(Word)); \
126 assert(sizeof(_ty2F) == sizeof(Word)); \
127 assert(sizeof(_ty3F) == sizeof(Word)); \
128 _arg1 = (Word)(_arg1F); \
129 _arg2 = (Word)(_arg2F); \
130 _arg3 = (Word)(_arg3F); \
131 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
132 _arg1,_arg2,_arg3,0,0); \
133 } while (0)
136 #define DO_PthAPIerror(_fnnameF, _errF) \
137 do { \
138 char* _fnname = (char*)(_fnnameF); \
139 long _err = (long)(int)(_errF); \
140 const char* _errstr = lame_strerror(_err); \
141 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTH_API_ERROR, \
142 char*,_fnname, \
143 long,_err, char*,_errstr); \
144 } while (0)
147 /* Needed for older glibcs (2.3 and older, at least) who don't
148 otherwise "know" about pthread_rwlock_anything or about
149 PTHREAD_MUTEX_RECURSIVE (amongst things). */
150 #define _GNU_SOURCE 1
152 #include <stdio.h>
153 #include <assert.h>
154 #include <errno.h>
155 #include <pthread.h>
157 /* A standalone memcmp. */
158 __attribute__((noinline))
159 static int my_memcmp ( const void* ptr1, const void* ptr2, size_t size)
161 unsigned char* uchar_ptr1 = (unsigned char*) ptr1;
162 unsigned char* uchar_ptr2 = (unsigned char*) ptr2;
163 size_t i;
164 for (i = 0; i < size; ++i) {
165 if (uchar_ptr1[i] != uchar_ptr2[i])
166 return (uchar_ptr1[i] < uchar_ptr2[i]) ? -1 : 1;
168 return 0;
171 /* A lame version of strerror which doesn't use the real libc
172 strerror_r, since using the latter just generates endless more
173 threading errors (glibc goes off and does tons of crap w.r.t.
174 locales etc) */
175 static const HChar* lame_strerror ( long err )
177 switch (err) {
178 case EPERM: return "EPERM: Operation not permitted";
179 case ENOENT: return "ENOENT: No such file or directory";
180 case ESRCH: return "ESRCH: No such process";
181 case EINTR: return "EINTR: Interrupted system call";
182 case EBADF: return "EBADF: Bad file number";
183 case EAGAIN: return "EAGAIN: Try again";
184 case ENOMEM: return "ENOMEM: Out of memory";
185 case EACCES: return "EACCES: Permission denied";
186 case EFAULT: return "EFAULT: Bad address";
187 case EEXIST: return "EEXIST: File exists";
188 case EINVAL: return "EINVAL: Invalid argument";
189 case EMFILE: return "EMFILE: Too many open files";
190 case ENOSYS: return "ENOSYS: Function not implemented";
191 case EOVERFLOW: return "EOVERFLOW: Value too large "
192 "for defined data type";
193 case EBUSY: return "EBUSY: Device or resource busy";
194 case ETIMEDOUT: return "ETIMEDOUT: Connection timed out";
195 case EDEADLK: return "EDEADLK: Resource deadlock would occur";
196 case EOPNOTSUPP: return "EOPNOTSUPP: Operation not supported on "
197 "transport endpoint"; /* honest, guv */
198 default: return "tc_intercepts.c: lame_strerror(): "
199 "unhandled case -- please fix me!";
204 /*----------------------------------------------------------------*/
205 /*--- pthread_create, pthread_join, pthread_exit ---*/
206 /*----------------------------------------------------------------*/
208 static void* mythread_wrapper ( void* xargsV )
210 volatile Word* xargs = (volatile Word*) xargsV;
211 void*(*fn)(void*) = (void*(*)(void*))xargs[0];
212 void* arg = (void*)xargs[1];
213 pthread_t me = pthread_self();
214 /* Tell the tool what my pthread_t is. */
215 DO_CREQ_v_W(_VG_USERREQ__HG_SET_MY_PTHREAD_T, pthread_t,me);
216 /* allow the parent to proceed. We can't let it proceed until
217 we're ready because (1) we need to make sure it doesn't exit and
218 hence deallocate xargs[] while we still need it, and (2) we
219 don't want either parent nor child to proceed until the tool has
220 been notified of the child's pthread_t.
222 Note that parent and child access args[] without a lock,
223 effectively using args[2] as a spinlock in order to get the
224 parent to wait until the child passes this point. The parent
225 disables checking on xargs[] before creating the child and
226 re-enables it once the child goes past this point, so the user
227 never sees the race. The previous approach (suppressing the
228 resulting error) was flawed, because it could leave shadow
229 memory for args[] in a state in which subsequent use of it by
230 the parent would report further races. */
231 xargs[2] = 0;
232 /* Now we can no longer safely use xargs[]. */
233 return (void*) fn( (void*)arg );
236 //-----------------------------------------------------------
237 // glibc: pthread_create@GLIBC_2.0
238 // glibc: pthread_create@@GLIBC_2.1
239 // glibc: pthread_create@@GLIBC_2.2.5
240 // darwin: pthread_create
241 // darwin: pthread_create_suspended_np (trapped)
243 /* ensure this has its own frame, so as to make it more distinguishable
244 in suppressions */
245 __attribute__((noinline))
246 static int pthread_create_WRK(pthread_t *thread, const pthread_attr_t *attr,
247 void *(*start) (void *), void *arg)
249 int ret;
250 OrigFn fn;
251 volatile Word xargs[3];
253 VALGRIND_GET_ORIG_FN(fn);
254 if (TRACE_PTH_FNS) {
255 fprintf(stderr, "<< pthread_create wrapper"); fflush(stderr);
257 xargs[0] = (Word)start;
258 xargs[1] = (Word)arg;
259 xargs[2] = 1; /* serves as a spinlock -- sigh */
260 /* Disable checking on the spinlock and the two words used to
261 convey args to the child. Basically we need to make it appear
262 as if the child never accessed this area, since merely
263 suppressing the resulting races does not address the issue that
264 that piece of the parent's stack winds up in the "wrong" state
265 and therefore may give rise to mysterious races when the parent
266 comes to re-use this piece of stack in some other frame. */
267 VALGRIND_HG_DISABLE_CHECKING(&xargs, sizeof(xargs));
269 CALL_FN_W_WWWW(ret, fn, thread,attr,mythread_wrapper,&xargs[0]);
271 if (ret == 0) {
272 /* we have to wait for the child to notify the tool of its
273 pthread_t before continuing */
274 while (xargs[2] != 0) {
275 /* Do nothing. We need to spin until the child writes to
276 xargs[2]. However, that can lead to starvation in the
277 child and very long delays (eg, tc19_shadowmem on
278 ppc64-linux Fedora Core 6). So yield the cpu if we can,
279 to let the child run at the earliest available
280 opportunity. */
281 sched_yield();
283 } else {
284 DO_PthAPIerror( "pthread_create", ret );
287 /* Reenable checking on the area previously used to communicate
288 with the child. */
289 VALGRIND_HG_ENABLE_CHECKING(&xargs, sizeof(xargs));
291 if (TRACE_PTH_FNS) {
292 fprintf(stderr, " :: pth_create -> %d >>\n", ret);
294 return ret;
296 #if defined(VGO_linux)
297 PTH_FUNC(int, pthreadZucreateZAZa, // pthread_create@*
298 pthread_t *thread, const pthread_attr_t *attr,
299 void *(*start) (void *), void *arg) {
300 return pthread_create_WRK(thread, attr, start, arg);
302 #elif defined(VGO_darwin)
303 PTH_FUNC(int, pthreadZucreate, // pthread_create
304 pthread_t *thread, const pthread_attr_t *attr,
305 void *(*start) (void *), void *arg) {
306 return pthread_create_WRK(thread, attr, start, arg);
308 PTH_FUNC(int, pthreadZucreateZuZa, // pthread_create_*
309 pthread_t *thread, const pthread_attr_t *attr,
310 void *(*start) (void *), void *arg) {
311 // trap anything else
312 assert(0);
314 #else
315 # error "Unsupported OS"
316 #endif
319 //-----------------------------------------------------------
320 // glibc: pthread_join
321 // darwin: pthread_join
322 // darwin: pthread_join$NOCANCEL$UNIX2003
323 // darwin pthread_join$UNIX2003
324 __attribute__((noinline))
325 static int pthread_join_WRK(pthread_t thread, void** value_pointer)
327 int ret;
328 OrigFn fn;
329 VALGRIND_GET_ORIG_FN(fn);
330 if (TRACE_PTH_FNS) {
331 fprintf(stderr, "<< pthread_join wrapper"); fflush(stderr);
334 CALL_FN_W_WW(ret, fn, thread,value_pointer);
336 /* At least with NPTL as the thread library, this is safe because
337 it is guaranteed (by NPTL) that the joiner will completely gone
338 before pthread_join (the original) returns. See email below.*/
339 if (ret == 0 /*success*/) {
340 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST, pthread_t,thread);
341 } else {
342 DO_PthAPIerror( "pthread_join", ret );
345 if (TRACE_PTH_FNS) {
346 fprintf(stderr, " :: pth_join -> %d >>\n", ret);
348 return ret;
350 #if defined(VGO_linux)
351 PTH_FUNC(int, pthreadZujoin, // pthread_join
352 pthread_t thread, void** value_pointer) {
353 return pthread_join_WRK(thread, value_pointer);
355 #elif defined(VGO_darwin)
356 PTH_FUNC(int, pthreadZujoinZa, // pthread_join*
357 pthread_t thread, void** value_pointer) {
358 return pthread_join_WRK(thread, value_pointer);
360 #else
361 # error "Unsupported OS"
362 #endif
365 /* Behaviour of pthread_join on NPTL:
368 I have a question re the NPTL pthread_join implementation.
370 Suppose I am the thread 'stayer'.
372 If I call pthread_join(quitter), is it guaranteed that the
373 thread 'quitter' has really exited before pthread_join returns?
375 IOW, is it guaranteed that 'quitter' will not execute any further
376 instructions after pthread_join returns?
378 I believe this is true based on the following analysis of
379 glibc-2.5 sources. However am not 100% sure and would appreciate
380 confirmation.
382 'quitter' will be running start_thread() in nptl/pthread_create.c
384 The last action of start_thread() is to exit via
385 __exit_thread_inline(0), which simply does sys_exit
386 (nptl/pthread_create.c:403)
388 'stayer' meanwhile is waiting for lll_wait_tid (pd->tid)
389 (call at nptl/pthread_join.c:89)
391 As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
392 lll_wait_tid will not return until kernel notifies via futex
393 wakeup that 'quitter' has terminated.
395 Hence pthread_join cannot return until 'quitter' really has
396 completely disappeared.
398 Drepper:
399 > As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
400 > lll_wait_tid will not return until kernel notifies via futex
401 > wakeup that 'quitter' has terminated.
402 That's the key. The kernel resets the TID field after the thread is
403 done. No way the joiner can return before the thread is gone.
407 /*----------------------------------------------------------------*/
408 /*--- pthread_mutex_t functions ---*/
409 /*----------------------------------------------------------------*/
411 /* Handled: pthread_mutex_init pthread_mutex_destroy
412 pthread_mutex_lock
413 pthread_mutex_trylock pthread_mutex_timedlock
414 pthread_mutex_unlock
417 //-----------------------------------------------------------
418 // glibc: pthread_mutex_init
419 // darwin: pthread_mutex_init
420 PTH_FUNC(int, pthreadZumutexZuinit, // pthread_mutex_init
421 pthread_mutex_t *mutex,
422 pthread_mutexattr_t* attr)
424 int ret;
425 long mbRec;
426 OrigFn fn;
427 VALGRIND_GET_ORIG_FN(fn);
428 if (TRACE_PTH_FNS) {
429 fprintf(stderr, "<< pthread_mxinit %p", mutex); fflush(stderr);
432 mbRec = 0;
433 if (attr) {
434 int ty, zzz;
435 zzz = pthread_mutexattr_gettype(attr, &ty);
436 if (zzz == 0 && ty == PTHREAD_MUTEX_RECURSIVE)
437 mbRec = 1;
440 CALL_FN_W_WW(ret, fn, mutex,attr);
442 if (ret == 0 /*success*/) {
443 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
444 pthread_mutex_t*,mutex, long,mbRec);
445 } else {
446 DO_PthAPIerror( "pthread_mutex_init", ret );
449 if (TRACE_PTH_FNS) {
450 fprintf(stderr, " :: mxinit -> %d >>\n", ret);
452 return ret;
456 //-----------------------------------------------------------
457 // glibc: pthread_mutex_destroy
458 // darwin: pthread_mutex_destroy
459 PTH_FUNC(int, pthreadZumutexZudestroy, // pthread_mutex_destroy
460 pthread_mutex_t *mutex)
462 int ret;
463 unsigned long mutex_is_init;
464 OrigFn fn;
466 VALGRIND_GET_ORIG_FN(fn);
467 if (TRACE_PTH_FNS) {
468 fprintf(stderr, "<< pthread_mxdestroy %p", mutex); fflush(stderr);
471 if (mutex != NULL) {
472 static const pthread_mutex_t mutex_init = PTHREAD_MUTEX_INITIALIZER;
473 mutex_is_init = my_memcmp(mutex, &mutex_init, sizeof(*mutex)) == 0;
474 } else {
475 mutex_is_init = 0;
478 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
479 pthread_mutex_t*, mutex, unsigned long, mutex_is_init);
481 CALL_FN_W_W(ret, fn, mutex);
483 if (ret != 0) {
484 DO_PthAPIerror( "pthread_mutex_destroy", ret );
487 if (TRACE_PTH_FNS) {
488 fprintf(stderr, " :: mxdestroy -> %d >>\n", ret);
490 return ret;
494 //-----------------------------------------------------------
495 // glibc: pthread_mutex_lock
496 // darwin: pthread_mutex_lock
497 PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock
498 pthread_mutex_t *mutex)
500 int ret;
501 OrigFn fn;
502 VALGRIND_GET_ORIG_FN(fn);
503 if (TRACE_PTH_FNS) {
504 fprintf(stderr, "<< pthread_mxlock %p", mutex); fflush(stderr);
507 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
508 pthread_mutex_t*,mutex, long,0/*!isTryLock*/);
510 CALL_FN_W_W(ret, fn, mutex);
512 /* There's a hole here: libpthread now knows the lock is locked,
513 but the tool doesn't, so some other thread could run and detect
514 that the lock has been acquired by someone (this thread). Does
515 this matter? Not sure, but I don't think so. */
517 if (ret == 0 /*success*/) {
518 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
519 pthread_mutex_t*,mutex);
520 } else {
521 DO_PthAPIerror( "pthread_mutex_lock", ret );
524 if (TRACE_PTH_FNS) {
525 fprintf(stderr, " :: mxlock -> %d >>\n", ret);
527 return ret;
531 //-----------------------------------------------------------
532 // glibc: pthread_mutex_trylock
533 // darwin: pthread_mutex_trylock
535 // pthread_mutex_trylock. The handling needed here is very similar
536 // to that for pthread_mutex_lock, except that we need to tell
537 // the pre-lock creq that this is a trylock-style operation, and
538 // therefore not to complain if the lock is nonrecursive and
539 // already locked by this thread -- because then it'll just fail
540 // immediately with EBUSY.
541 PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock
542 pthread_mutex_t *mutex)
544 int ret;
545 OrigFn fn;
546 VALGRIND_GET_ORIG_FN(fn);
547 if (TRACE_PTH_FNS) {
548 fprintf(stderr, "<< pthread_mxtrylock %p", mutex); fflush(stderr);
551 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
552 pthread_mutex_t*,mutex, long,1/*isTryLock*/);
554 CALL_FN_W_W(ret, fn, mutex);
556 /* There's a hole here: libpthread now knows the lock is locked,
557 but the tool doesn't, so some other thread could run and detect
558 that the lock has been acquired by someone (this thread). Does
559 this matter? Not sure, but I don't think so. */
561 if (ret == 0 /*success*/) {
562 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
563 pthread_mutex_t*,mutex);
564 } else {
565 if (ret != EBUSY)
566 DO_PthAPIerror( "pthread_mutex_trylock", ret );
569 if (TRACE_PTH_FNS) {
570 fprintf(stderr, " :: mxtrylock -> %d >>\n", ret);
572 return ret;
576 //-----------------------------------------------------------
577 // glibc: pthread_mutex_timedlock
578 // darwin: (doesn't appear to exist)
580 // pthread_mutex_timedlock. Identical logic to pthread_mutex_trylock.
581 PTH_FUNC(int, pthreadZumutexZutimedlock, // pthread_mutex_timedlock
582 pthread_mutex_t *mutex,
583 void* timeout)
585 int ret;
586 OrigFn fn;
587 VALGRIND_GET_ORIG_FN(fn);
588 if (TRACE_PTH_FNS) {
589 fprintf(stderr, "<< pthread_mxtimedlock %p %p", mutex, timeout);
590 fflush(stderr);
593 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
594 pthread_mutex_t*,mutex, long,1/*isTryLock-ish*/);
596 CALL_FN_W_WW(ret, fn, mutex,timeout);
598 /* There's a hole here: libpthread now knows the lock is locked,
599 but the tool doesn't, so some other thread could run and detect
600 that the lock has been acquired by someone (this thread). Does
601 this matter? Not sure, but I don't think so. */
603 if (ret == 0 /*success*/) {
604 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
605 pthread_mutex_t*,mutex);
606 } else {
607 if (ret != ETIMEDOUT)
608 DO_PthAPIerror( "pthread_mutex_timedlock", ret );
611 if (TRACE_PTH_FNS) {
612 fprintf(stderr, " :: mxtimedlock -> %d >>\n", ret);
614 return ret;
618 //-----------------------------------------------------------
619 // glibc: pthread_mutex_unlock
620 // darwin: pthread_mutex_unlock
621 PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock
622 pthread_mutex_t *mutex)
624 int ret;
625 OrigFn fn;
626 VALGRIND_GET_ORIG_FN(fn);
628 if (TRACE_PTH_FNS) {
629 fprintf(stderr, "<< pthread_mxunlk %p", mutex); fflush(stderr);
632 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
633 pthread_mutex_t*,mutex);
635 CALL_FN_W_W(ret, fn, mutex);
637 if (ret == 0 /*success*/) {
638 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
639 pthread_mutex_t*,mutex);
640 } else {
641 DO_PthAPIerror( "pthread_mutex_unlock", ret );
644 if (TRACE_PTH_FNS) {
645 fprintf(stderr, " mxunlk -> %d >>\n", ret);
647 return ret;
651 /*----------------------------------------------------------------*/
652 /*--- pthread_cond_t functions ---*/
653 /*----------------------------------------------------------------*/
655 /* Handled: pthread_cond_wait pthread_cond_timedwait
656 pthread_cond_signal pthread_cond_broadcast
657 pthread_cond_init
658 pthread_cond_destroy
661 //-----------------------------------------------------------
662 // glibc: pthread_cond_wait@GLIBC_2.2.5
663 // glibc: pthread_cond_wait@@GLIBC_2.3.2
664 // darwin: pthread_cond_wait
665 // darwin: pthread_cond_wait$NOCANCEL$UNIX2003
666 // darwin: pthread_cond_wait$UNIX2003
668 __attribute__((noinline))
669 static int pthread_cond_wait_WRK(pthread_cond_t* cond,
670 pthread_mutex_t* mutex)
672 int ret;
673 OrigFn fn;
674 unsigned long mutex_is_valid;
676 VALGRIND_GET_ORIG_FN(fn);
678 if (TRACE_PTH_FNS) {
679 fprintf(stderr, "<< pthread_cond_wait %p %p", cond, mutex);
680 fflush(stderr);
683 /* Tell the tool a cond-wait is about to happen, so it can check
684 for bogus argument values. In return it tells us whether it
685 thinks the mutex is valid or not. */
686 DO_CREQ_W_WW(mutex_is_valid,
687 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
688 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
689 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
691 /* Tell the tool we're about to drop the mutex. This reflects the
692 fact that in a cond_wait, we show up holding the mutex, and the
693 call atomically drops the mutex and waits for the cv to be
694 signalled. */
695 if (mutex_is_valid) {
696 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
697 pthread_mutex_t*,mutex);
700 CALL_FN_W_WW(ret, fn, cond,mutex);
702 /* these conditionals look stupid, but compare w/ same logic for
703 pthread_cond_timedwait below */
704 if (ret == 0 && mutex_is_valid) {
705 /* and now we have the mutex again */
706 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
707 pthread_mutex_t*,mutex);
710 if (ret == 0 && mutex_is_valid) {
711 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
712 pthread_cond_t*,cond, pthread_mutex_t*,mutex, long,0);
715 if (ret != 0) {
716 DO_PthAPIerror( "pthread_cond_wait", ret );
719 if (TRACE_PTH_FNS) {
720 fprintf(stderr, " cowait -> %d >>\n", ret);
723 return ret;
725 #if defined(VGO_linux)
726 PTH_FUNC(int, pthreadZucondZuwaitZAZa, // pthread_cond_wait@*
727 pthread_cond_t* cond, pthread_mutex_t* mutex) {
728 return pthread_cond_wait_WRK(cond, mutex);
730 #elif defined(VGO_darwin)
731 PTH_FUNC(int, pthreadZucondZuwaitZa, // pthread_cond_wait*
732 pthread_cond_t* cond, pthread_mutex_t* mutex) {
733 return pthread_cond_wait_WRK(cond, mutex);
735 #else
736 # error "Unsupported OS"
737 #endif
740 //-----------------------------------------------------------
741 // glibc: pthread_cond_timedwait@@GLIBC_2.3.2
742 // glibc: pthread_cond_timedwait@GLIBC_2.2.5
743 // glibc: pthread_cond_timedwait@GLIBC_2.0
744 // darwin: pthread_cond_timedwait
745 // darwin: pthread_cond_timedwait$NOCANCEL$UNIX2003
746 // darwin: pthread_cond_timedwait$UNIX2003
747 // darwin: pthread_cond_timedwait_relative_np (trapped)
749 __attribute__((noinline))
750 static int pthread_cond_timedwait_WRK(pthread_cond_t* cond,
751 pthread_mutex_t* mutex,
752 struct timespec* abstime)
754 int ret;
755 OrigFn fn;
756 unsigned long mutex_is_valid;
757 Bool abstime_is_valid;
758 VALGRIND_GET_ORIG_FN(fn);
760 if (TRACE_PTH_FNS) {
761 fprintf(stderr, "<< pthread_cond_timedwait %p %p %p",
762 cond, mutex, abstime);
763 fflush(stderr);
766 /* Tell the tool a cond-wait is about to happen, so it can check
767 for bogus argument values. In return it tells us whether it
768 thinks the mutex is valid or not. */
769 DO_CREQ_W_WW(mutex_is_valid,
770 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
771 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
772 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
774 abstime_is_valid = abstime->tv_nsec >= 0 && abstime->tv_nsec < 1000000000;
776 /* Tell the tool we're about to drop the mutex. This reflects the
777 fact that in a cond_wait, we show up holding the mutex, and the
778 call atomically drops the mutex and waits for the cv to be
779 signalled. */
780 if (mutex_is_valid && abstime_is_valid) {
781 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
782 pthread_mutex_t*,mutex);
785 CALL_FN_W_WWW(ret, fn, cond,mutex,abstime);
787 if (!abstime_is_valid && ret != EINVAL) {
788 DO_PthAPIerror("Bug in libpthread: pthread_cond_timedwait "
789 "invalid abstime did not cause"
790 " EINVAL", ret);
793 if ((ret == 0 || ret == ETIMEDOUT) && mutex_is_valid) {
794 /* and now we have the mutex again */
795 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
796 pthread_mutex_t*,mutex);
799 if ((ret == 0 || ret == ETIMEDOUT) && mutex_is_valid) {
800 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
801 pthread_cond_t*,cond, pthread_mutex_t*,mutex,
802 long,ret == ETIMEDOUT);
805 if (ret != 0 && ret != ETIMEDOUT) {
806 DO_PthAPIerror( "pthread_cond_timedwait", ret );
809 if (TRACE_PTH_FNS) {
810 fprintf(stderr, " cotimedwait -> %d >>\n", ret);
813 return ret;
815 #if defined(VGO_linux)
816 PTH_FUNC(int, pthreadZucondZutimedwaitZAZa, // pthread_cond_timedwait@*
817 pthread_cond_t* cond, pthread_mutex_t* mutex,
818 struct timespec* abstime) {
819 return pthread_cond_timedwait_WRK(cond, mutex, abstime);
821 #elif defined(VGO_darwin)
822 PTH_FUNC(int, pthreadZucondZutimedwait, // pthread_cond_timedwait
823 pthread_cond_t* cond, pthread_mutex_t* mutex,
824 struct timespec* abstime) {
825 return pthread_cond_timedwait_WRK(cond, mutex, abstime);
827 PTH_FUNC(int, pthreadZucondZutimedwaitZDZa, // pthread_cond_timedwait$*
828 pthread_cond_t* cond, pthread_mutex_t* mutex,
829 struct timespec* abstime) {
830 return pthread_cond_timedwait_WRK(cond, mutex, abstime);
832 PTH_FUNC(int, pthreadZucondZutimedwaitZuZa, // pthread_cond_timedwait_*
833 pthread_cond_t* cond, pthread_mutex_t* mutex,
834 struct timespec* abstime) {
835 assert(0);
837 #else
838 # error "Unsupported OS"
839 #endif
842 //-----------------------------------------------------------
843 // glibc: pthread_cond_signal@GLIBC_2.0
844 // glibc: pthread_cond_signal@GLIBC_2.2.5
845 // glibc: pthread_cond_signal@@GLIBC_2.3.2
846 // darwin: pthread_cond_signal
847 // darwin: pthread_cond_signal_thread_np (don't intercept this)
849 __attribute__((noinline))
850 static int pthread_cond_signal_WRK(pthread_cond_t* cond)
852 int ret;
853 OrigFn fn;
854 VALGRIND_GET_ORIG_FN(fn);
856 if (TRACE_PTH_FNS) {
857 fprintf(stderr, "<< pthread_cond_signal %p", cond);
858 fflush(stderr);
861 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE,
862 pthread_cond_t*,cond);
864 CALL_FN_W_W(ret, fn, cond);
866 if (ret != 0) {
867 DO_PthAPIerror( "pthread_cond_signal", ret );
870 if (TRACE_PTH_FNS) {
871 fprintf(stderr, " cosig -> %d >>\n", ret);
874 return ret;
876 #if defined(VGO_linux)
877 PTH_FUNC(int, pthreadZucondZusignalZAZa, // pthread_cond_signal@*
878 pthread_cond_t* cond) {
879 return pthread_cond_signal_WRK(cond);
881 #elif defined(VGO_darwin)
882 PTH_FUNC(int, pthreadZucondZusignal, // pthread_cond_signal
883 pthread_cond_t* cond) {
884 return pthread_cond_signal_WRK(cond);
886 #else
887 # error "Unsupported OS"
888 #endif
891 //-----------------------------------------------------------
892 // glibc: pthread_cond_broadcast@GLIBC_2.0
893 // glibc: pthread_cond_broadcast@GLIBC_2.2.5
894 // glibc: pthread_cond_broadcast@@GLIBC_2.3.2
895 // darwin: pthread_cond_broadcast
897 // Note, this is pretty much identical, from a dependency-graph
898 // point of view, with cond_signal, so the code is duplicated.
899 // Maybe it should be commoned up.
901 __attribute__((noinline))
902 static int pthread_cond_broadcast_WRK(pthread_cond_t* cond)
904 int ret;
905 OrigFn fn;
906 VALGRIND_GET_ORIG_FN(fn);
908 if (TRACE_PTH_FNS) {
909 fprintf(stderr, "<< pthread_cond_broadcast %p", cond);
910 fflush(stderr);
913 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE,
914 pthread_cond_t*,cond);
916 CALL_FN_W_W(ret, fn, cond);
918 if (ret != 0) {
919 DO_PthAPIerror( "pthread_cond_broadcast", ret );
922 if (TRACE_PTH_FNS) {
923 fprintf(stderr, " cobro -> %d >>\n", ret);
926 return ret;
928 #if defined(VGO_linux)
929 PTH_FUNC(int, pthreadZucondZubroadcastZAZa, // pthread_cond_broadcast@*
930 pthread_cond_t* cond) {
931 return pthread_cond_broadcast_WRK(cond);
933 #elif defined(VGO_darwin)
934 PTH_FUNC(int, pthreadZucondZubroadcast, // pthread_cond_broadcast
935 pthread_cond_t* cond) {
936 return pthread_cond_broadcast_WRK(cond);
938 #else
939 # error "Unsupported OS"
940 #endif
942 // glibc: pthread_cond_init@GLIBC_2.0
943 // glibc: pthread_cond_init@GLIBC_2.2.5
944 // glibc: pthread_cond_init@@GLIBC_2.3.2
945 // darwin: pthread_cond_init
946 // Easy way out: Handling of attr could have been messier.
947 // It turns out that pthread_cond_init under linux ignores
948 // all information in cond_attr, so do we.
949 // FIXME: MacOS X?
950 __attribute__((noinline))
951 static int pthread_cond_init_WRK(pthread_cond_t* cond, pthread_condattr_t *cond_attr)
953 int ret;
954 OrigFn fn;
955 VALGRIND_GET_ORIG_FN(fn);
957 if (TRACE_PTH_FNS) {
958 fprintf(stderr, "<< pthread_cond_init %p", cond);
959 fflush(stderr);
962 CALL_FN_W_WW(ret, fn, cond, cond_attr);
964 if (ret == 0) {
965 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST,
966 pthread_cond_t*,cond, pthread_condattr_t*, cond_attr);
967 } else {
968 DO_PthAPIerror( "pthread_cond_init", ret );
971 if (TRACE_PTH_FNS) {
972 fprintf(stderr, " coinit -> %d >>\n", ret);
975 return ret;
977 #if defined(VGO_linux)
978 PTH_FUNC(int, pthreadZucondZuinitZAZa, // pthread_cond_init@*
979 pthread_cond_t* cond, pthread_condattr_t* cond_attr) {
980 return pthread_cond_init_WRK(cond, cond_attr);
982 #elif defined(VGO_darwin)
983 PTH_FUNC(int, pthreadZucondZuinit, // pthread_cond_init
984 pthread_cond_t* cond, pthread_condattr_t * cond_attr) {
985 return pthread_cond_init_WRK(cond, cond_attr);
987 #else
988 # error "Unsupported OS"
989 #endif
992 //-----------------------------------------------------------
993 // glibc: pthread_cond_destroy@@GLIBC_2.3.2
994 // glibc: pthread_cond_destroy@GLIBC_2.2.5
995 // glibc: pthread_cond_destroy@GLIBC_2.0
996 // darwin: pthread_cond_destroy
998 __attribute__((noinline))
999 static int pthread_cond_destroy_WRK(pthread_cond_t* cond)
1001 int ret;
1002 unsigned long cond_is_init;
1003 OrigFn fn;
1005 VALGRIND_GET_ORIG_FN(fn);
1007 if (TRACE_PTH_FNS) {
1008 fprintf(stderr, "<< pthread_cond_destroy %p", cond);
1009 fflush(stderr);
1012 if (cond != NULL) {
1013 const pthread_cond_t cond_init = PTHREAD_COND_INITIALIZER;
1014 cond_is_init = my_memcmp(cond, &cond_init, sizeof(*cond)) == 0;
1015 } else {
1016 cond_is_init = 0;
1019 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_DESTROY_PRE,
1020 pthread_cond_t*, cond, unsigned long, cond_is_init);
1022 CALL_FN_W_W(ret, fn, cond);
1024 if (ret != 0) {
1025 DO_PthAPIerror( "pthread_cond_destroy", ret );
1028 if (TRACE_PTH_FNS) {
1029 fprintf(stderr, " codestr -> %d >>\n", ret);
1032 return ret;
1034 #if defined(VGO_linux)
1035 PTH_FUNC(int, pthreadZucondZudestroyZAZa, // pthread_cond_destroy@*
1036 pthread_cond_t* cond) {
1037 return pthread_cond_destroy_WRK(cond);
1039 #elif defined(VGO_darwin)
1040 PTH_FUNC(int, pthreadZucondZudestroy, // pthread_cond_destroy
1041 pthread_cond_t* cond) {
1042 return pthread_cond_destroy_WRK(cond);
1044 #else
1045 # error "Unsupported OS"
1046 #endif
1049 /*----------------------------------------------------------------*/
1050 /*--- pthread_barrier_t functions ---*/
1051 /*----------------------------------------------------------------*/
1053 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1055 /* Handled: pthread_barrier_init
1056 pthread_barrier_wait
1057 pthread_barrier_destroy
1059 Unhandled: pthread_barrierattr_destroy
1060 pthread_barrierattr_getpshared
1061 pthread_barrierattr_init
1062 pthread_barrierattr_setpshared
1063 -- are these important?
1066 //-----------------------------------------------------------
1067 // glibc: pthread_barrier_init
1068 // darwin: (doesn't appear to exist)
1069 PTH_FUNC(int, pthreadZubarrierZuinit, // pthread_barrier_init
1070 pthread_barrier_t* bar,
1071 pthread_barrierattr_t* attr, unsigned long count)
1073 int ret;
1074 OrigFn fn;
1075 VALGRIND_GET_ORIG_FN(fn);
1077 if (TRACE_PTH_FNS) {
1078 fprintf(stderr, "<< pthread_barrier_init %p %p %lu",
1079 bar, attr, count);
1080 fflush(stderr);
1083 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE,
1084 pthread_barrier_t*, bar,
1085 unsigned long, count,
1086 unsigned long, 0/*!resizable*/);
1088 CALL_FN_W_WWW(ret, fn, bar,attr,count);
1090 if (ret != 0) {
1091 DO_PthAPIerror( "pthread_barrier_init", ret );
1094 if (TRACE_PTH_FNS) {
1095 fprintf(stderr, " pthread_barrier_init -> %d >>\n", ret);
1098 return ret;
1102 //-----------------------------------------------------------
1103 // glibc: pthread_barrier_wait
1104 // darwin: (doesn't appear to exist)
1105 PTH_FUNC(int, pthreadZubarrierZuwait, // pthread_barrier_wait
1106 pthread_barrier_t* bar)
1108 int ret;
1109 OrigFn fn;
1110 VALGRIND_GET_ORIG_FN(fn);
1112 if (TRACE_PTH_FNS) {
1113 fprintf(stderr, "<< pthread_barrier_wait %p", bar);
1114 fflush(stderr);
1117 /* That this works correctly, and doesn't screw up when a thread
1118 leaving the barrier races round to the front and re-enters while
1119 other threads are still leaving it, is quite subtle. See
1120 comments in the handler for PTHREAD_BARRIER_WAIT_PRE in
1121 hg_main.c. */
1122 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE,
1123 pthread_barrier_t*,bar);
1125 CALL_FN_W_W(ret, fn, bar);
1127 if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) {
1128 DO_PthAPIerror( "pthread_barrier_wait", ret );
1131 if (TRACE_PTH_FNS) {
1132 fprintf(stderr, " pthread_barrier_wait -> %d >>\n", ret);
1135 return ret;
1139 //-----------------------------------------------------------
1140 // glibc: pthread_barrier_destroy
1141 // darwin: (doesn't appear to exist)
1142 PTH_FUNC(int, pthreadZubarrierZudestroy, // pthread_barrier_destroy
1143 pthread_barrier_t* bar)
1145 int ret;
1146 OrigFn fn;
1147 VALGRIND_GET_ORIG_FN(fn);
1149 if (TRACE_PTH_FNS) {
1150 fprintf(stderr, "<< pthread_barrier_destroy %p", bar);
1151 fflush(stderr);
1154 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE,
1155 pthread_barrier_t*,bar);
1157 CALL_FN_W_W(ret, fn, bar);
1159 if (ret != 0) {
1160 DO_PthAPIerror( "pthread_barrier_destroy", ret );
1163 if (TRACE_PTH_FNS) {
1164 fprintf(stderr, " pthread_barrier_destroy -> %d >>\n", ret);
1167 return ret;
1170 #endif // defined(HAVE_PTHREAD_BARRIER_INIT)
1173 /*----------------------------------------------------------------*/
1174 /*--- pthread_spinlock_t functions ---*/
1175 /*----------------------------------------------------------------*/
1177 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1178 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1180 /* Handled: pthread_spin_init pthread_spin_destroy
1181 pthread_spin_lock pthread_spin_trylock
1182 pthread_spin_unlock
1184 Unhandled:
1187 /* This is a nasty kludge, in that glibc "knows" that initialising a
1188 spin lock unlocks it, and pthread_spin_{init,unlock} are names for
1189 the same function. Hence we have to have a wrapper which does both
1190 things, without knowing which the user intended to happen. */
1192 //-----------------------------------------------------------
1193 // glibc: pthread_spin_init
1194 // glibc: pthread_spin_unlock
1195 // darwin: (doesn't appear to exist)
1196 __attribute__((noinline))
1197 static int pthread_spin_init_or_unlock_WRK(pthread_spinlock_t* lock,
1198 int pshared) {
1199 int ret;
1200 OrigFn fn;
1201 VALGRIND_GET_ORIG_FN(fn);
1202 if (TRACE_PTH_FNS) {
1203 fprintf(stderr, "<< pthread_spin_iORu %p", lock); fflush(stderr);
1206 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE,
1207 pthread_spinlock_t*, lock);
1209 CALL_FN_W_WW(ret, fn, lock,pshared);
1211 if (ret == 0 /*success*/) {
1212 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST,
1213 pthread_spinlock_t*,lock);
1214 } else {
1215 DO_PthAPIerror( "pthread_spinlock_{init,unlock}", ret );
1218 if (TRACE_PTH_FNS) {
1219 fprintf(stderr, " :: spiniORu -> %d >>\n", ret);
1221 return ret;
1223 #if defined(VGO_linux)
1224 PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
1225 pthread_spinlock_t* lock, int pshared) {
1226 return pthread_spin_init_or_unlock_WRK(lock, pshared);
1228 PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
1229 pthread_spinlock_t* lock) {
1230 /* this is never actually called */
1231 return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/);
1233 #elif defined(VGO_darwin)
1234 #else
1235 # error "Unsupported OS"
1236 #endif
1239 //-----------------------------------------------------------
1240 // glibc: pthread_spin_destroy
1241 // darwin: (doesn't appear to exist)
1242 #if defined(VGO_linux)
1244 PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy
1245 pthread_spinlock_t* lock)
1247 int ret;
1248 OrigFn fn;
1249 VALGRIND_GET_ORIG_FN(fn);
1250 if (TRACE_PTH_FNS) {
1251 fprintf(stderr, "<< pthread_spin_destroy %p", lock);
1252 fflush(stderr);
1255 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_DESTROY_PRE,
1256 pthread_spinlock_t*,lock);
1258 CALL_FN_W_W(ret, fn, lock);
1260 if (ret != 0) {
1261 DO_PthAPIerror( "pthread_spin_destroy", ret );
1264 if (TRACE_PTH_FNS) {
1265 fprintf(stderr, " :: spindestroy -> %d >>\n", ret);
1267 return ret;
1270 #elif defined(VGO_darwin)
1271 #else
1272 # error "Unsupported OS"
1273 #endif
1276 //-----------------------------------------------------------
1277 // glibc: pthread_spin_lock
1278 // darwin: (doesn't appear to exist)
1279 #if defined(VGO_linux)
1281 PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
1282 pthread_spinlock_t* lock)
1284 int ret;
1285 OrigFn fn;
1286 VALGRIND_GET_ORIG_FN(fn);
1287 if (TRACE_PTH_FNS) {
1288 fprintf(stderr, "<< pthread_spinlock %p", lock);
1289 fflush(stderr);
1292 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE,
1293 pthread_spinlock_t*,lock, long,0/*!isTryLock*/);
1295 CALL_FN_W_W(ret, fn, lock);
1297 /* There's a hole here: libpthread now knows the lock is locked,
1298 but the tool doesn't, so some other thread could run and detect
1299 that the lock has been acquired by someone (this thread). Does
1300 this matter? Not sure, but I don't think so. */
1302 if (ret == 0 /*success*/) {
1303 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST,
1304 pthread_spinlock_t*,lock);
1305 } else {
1306 DO_PthAPIerror( "pthread_spin_lock", ret );
1309 if (TRACE_PTH_FNS) {
1310 fprintf(stderr, " :: spinlock -> %d >>\n", ret);
1312 return ret;
1315 #elif defined(VGO_darwin)
1316 #else
1317 # error "Unsupported OS"
1318 #endif
1321 //-----------------------------------------------------------
1322 // glibc: pthread_spin_trylock
1323 // darwin: (doesn't appear to exist)
1324 #if defined(VGO_linux)
1326 PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
1327 pthread_spinlock_t* lock)
1329 int ret;
1330 OrigFn fn;
1331 VALGRIND_GET_ORIG_FN(fn);
1332 if (TRACE_PTH_FNS) {
1333 fprintf(stderr, "<< pthread_spin_trylock %p", lock);
1334 fflush(stderr);
1337 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE,
1338 pthread_spinlock_t*,lock, long,1/*isTryLock*/);
1340 CALL_FN_W_W(ret, fn, lock);
1342 /* There's a hole here: libpthread now knows the lock is locked,
1343 but the tool doesn't, so some other thread could run and detect
1344 that the lock has been acquired by someone (this thread). Does
1345 this matter? Not sure, but I don't think so. */
1347 if (ret == 0 /*success*/) {
1348 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST,
1349 pthread_spinlock_t*,lock);
1350 } else {
1351 if (ret != EBUSY)
1352 DO_PthAPIerror( "pthread_spin_trylock", ret );
1355 if (TRACE_PTH_FNS) {
1356 fprintf(stderr, " :: spin_trylock -> %d >>\n", ret);
1358 return ret;
1361 #elif defined(VGO_darwin)
1362 #else
1363 # error "Unsupported OS"
1364 #endif
1366 #endif // defined(HAVE_PTHREAD_SPIN_LOCK)
1369 /*----------------------------------------------------------------*/
1370 /*--- pthread_rwlock_t functions ---*/
1371 /*----------------------------------------------------------------*/
1373 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1374 functions have to be conditionally compiled. */
1375 #if defined(HAVE_PTHREAD_RWLOCK_T)
1377 /* Handled: pthread_rwlock_init pthread_rwlock_destroy
1378 pthread_rwlock_rdlock
1379 pthread_rwlock_wrlock
1380 pthread_rwlock_unlock
1382 Unhandled: pthread_rwlock_timedrdlock
1383 pthread_rwlock_tryrdlock
1385 pthread_rwlock_timedwrlock
1386 pthread_rwlock_trywrlock
1389 //-----------------------------------------------------------
1390 // glibc: pthread_rwlock_init
1391 // darwin: pthread_rwlock_init
1392 // darwin: pthread_rwlock_init$UNIX2003
1393 __attribute__((noinline))
1394 static int pthread_rwlock_init_WRK(pthread_rwlock_t *rwl,
1395 pthread_rwlockattr_t* attr)
1397 int ret;
1398 OrigFn fn;
1399 VALGRIND_GET_ORIG_FN(fn);
1400 if (TRACE_PTH_FNS) {
1401 fprintf(stderr, "<< pthread_rwl_init %p", rwl); fflush(stderr);
1404 CALL_FN_W_WW(ret, fn, rwl,attr);
1406 if (ret == 0 /*success*/) {
1407 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
1408 pthread_rwlock_t*,rwl);
1409 } else {
1410 DO_PthAPIerror( "pthread_rwlock_init", ret );
1413 if (TRACE_PTH_FNS) {
1414 fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
1416 return ret;
1418 #if defined(VGO_linux)
1419 PTH_FUNC(int, pthreadZurwlockZuinit, // pthread_rwlock_init
1420 pthread_rwlock_t *rwl,
1421 pthread_rwlockattr_t* attr) {
1422 return pthread_rwlock_init_WRK(rwl, attr);
1424 #elif defined(VGO_darwin)
1425 PTH_FUNC(int, pthreadZurwlockZuinitZa, // pthread_rwlock_init*
1426 pthread_rwlock_t *rwl,
1427 pthread_rwlockattr_t* attr) {
1428 return pthread_rwlock_init_WRK(rwl, attr);
1430 #else
1431 # error "Unsupported OS"
1432 #endif
1435 //-----------------------------------------------------------
1436 // glibc: pthread_rwlock_destroy
1437 // darwin: pthread_rwlock_destroy
1438 // darwin: pthread_rwlock_destroy$UNIX2003
1440 __attribute__((noinline))
1441 static int pthread_rwlock_destroy_WRK(pthread_rwlock_t* rwl)
1443 int ret;
1444 OrigFn fn;
1445 VALGRIND_GET_ORIG_FN(fn);
1446 if (TRACE_PTH_FNS) {
1447 fprintf(stderr, "<< pthread_rwl_destroy %p", rwl); fflush(stderr);
1450 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE,
1451 pthread_rwlock_t*,rwl);
1453 CALL_FN_W_W(ret, fn, rwl);
1455 if (ret != 0) {
1456 DO_PthAPIerror( "pthread_rwlock_destroy", ret );
1459 if (TRACE_PTH_FNS) {
1460 fprintf(stderr, " :: rwl_destroy -> %d >>\n", ret);
1462 return ret;
1464 #if defined(VGO_linux)
1465 PTH_FUNC(int, pthreadZurwlockZudestroy, // pthread_rwlock_destroy
1466 pthread_rwlock_t *rwl) {
1467 return pthread_rwlock_destroy_WRK(rwl);
1469 #elif defined(VGO_darwin)
1470 PTH_FUNC(int, pthreadZurwlockZudestroyZa, // pthread_rwlock_destroy*
1471 pthread_rwlock_t *rwl) {
1472 return pthread_rwlock_destroy_WRK(rwl);
1474 #else
1475 # error "Unsupported OS"
1476 #endif
1479 //-----------------------------------------------------------
1480 // glibc: pthread_rwlock_wrlock
1481 // darwin: pthread_rwlock_wrlock
1482 // darwin: pthread_rwlock_wrlock$UNIX2003
1484 __attribute__((noinline))
1485 static int pthread_rwlock_wrlock_WRK(pthread_rwlock_t* rwlock)
1487 int ret;
1488 OrigFn fn;
1489 VALGRIND_GET_ORIG_FN(fn);
1490 if (TRACE_PTH_FNS) {
1491 fprintf(stderr, "<< pthread_rwl_wlk %p", rwlock); fflush(stderr);
1494 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1495 pthread_rwlock_t*,rwlock,
1496 long,1/*isW*/, long,0/*!isTryLock*/);
1498 CALL_FN_W_W(ret, fn, rwlock);
1500 if (ret == 0 /*success*/) {
1501 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1502 pthread_rwlock_t*,rwlock, long,1/*isW*/);
1503 } else {
1504 DO_PthAPIerror( "pthread_rwlock_wrlock", ret );
1507 if (TRACE_PTH_FNS) {
1508 fprintf(stderr, " :: rwl_wlk -> %d >>\n", ret);
1510 return ret;
1512 #if defined(VGO_linux)
1513 PTH_FUNC(int, pthreadZurwlockZuwrlock, // pthread_rwlock_wrlock
1514 pthread_rwlock_t* rwlock) {
1515 return pthread_rwlock_wrlock_WRK(rwlock);
1517 #elif defined(VGO_darwin)
1518 PTH_FUNC(int, pthreadZurwlockZuwrlockZa, // pthread_rwlock_wrlock*
1519 pthread_rwlock_t* rwlock) {
1520 return pthread_rwlock_wrlock_WRK(rwlock);
1522 #else
1523 # error "Unsupported OS"
1524 #endif
1527 //-----------------------------------------------------------
1528 // glibc: pthread_rwlock_rdlock
1529 // darwin: pthread_rwlock_rdlock
1530 // darwin: pthread_rwlock_rdlock$UNIX2003
1532 __attribute__((noinline))
1533 static int pthread_rwlock_rdlock_WRK(pthread_rwlock_t* rwlock)
1535 int ret;
1536 OrigFn fn;
1537 VALGRIND_GET_ORIG_FN(fn);
1538 if (TRACE_PTH_FNS) {
1539 fprintf(stderr, "<< pthread_rwl_rlk %p", rwlock); fflush(stderr);
1542 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1543 pthread_rwlock_t*,rwlock,
1544 long,0/*!isW*/, long,0/*!isTryLock*/);
1546 CALL_FN_W_W(ret, fn, rwlock);
1548 if (ret == 0 /*success*/) {
1549 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1550 pthread_rwlock_t*,rwlock, long,0/*!isW*/);
1551 } else {
1552 DO_PthAPIerror( "pthread_rwlock_rdlock", ret );
1555 if (TRACE_PTH_FNS) {
1556 fprintf(stderr, " :: rwl_rlk -> %d >>\n", ret);
1558 return ret;
1560 #if defined(VGO_linux)
1561 PTH_FUNC(int, pthreadZurwlockZurdlock, // pthread_rwlock_rdlock
1562 pthread_rwlock_t* rwlock) {
1563 return pthread_rwlock_rdlock_WRK(rwlock);
1565 #elif defined(VGO_darwin)
1566 PTH_FUNC(int, pthreadZurwlockZurdlockZa, // pthread_rwlock_rdlock*
1567 pthread_rwlock_t* rwlock) {
1568 return pthread_rwlock_rdlock_WRK(rwlock);
1570 #else
1571 # error "Unsupported OS"
1572 #endif
1575 //-----------------------------------------------------------
1576 // glibc: pthread_rwlock_trywrlock
1577 // darwin: pthread_rwlock_trywrlock
1578 // darwin: pthread_rwlock_trywrlock$UNIX2003
1580 __attribute__((noinline))
1581 static int pthread_rwlock_trywrlock_WRK(pthread_rwlock_t* rwlock)
1583 int ret;
1584 OrigFn fn;
1585 VALGRIND_GET_ORIG_FN(fn);
1586 if (TRACE_PTH_FNS) {
1587 fprintf(stderr, "<< pthread_rwl_trywlk %p", rwlock); fflush(stderr);
1590 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1591 pthread_rwlock_t*,rwlock,
1592 long,1/*isW*/, long,1/*isTryLock*/);
1594 CALL_FN_W_W(ret, fn, rwlock);
1596 /* There's a hole here: libpthread now knows the lock is locked,
1597 but the tool doesn't, so some other thread could run and detect
1598 that the lock has been acquired by someone (this thread). Does
1599 this matter? Not sure, but I don't think so. */
1601 if (ret == 0 /*success*/) {
1602 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1603 pthread_rwlock_t*,rwlock, long,1/*isW*/);
1604 } else {
1605 if (ret != EBUSY)
1606 DO_PthAPIerror( "pthread_rwlock_trywrlock", ret );
1609 if (TRACE_PTH_FNS) {
1610 fprintf(stderr, " :: rwl_trywlk -> %d >>\n", ret);
1612 return ret;
1614 #if defined(VGO_linux)
1615 PTH_FUNC(int, pthreadZurwlockZutrywrlock, // pthread_rwlock_trywrlock
1616 pthread_rwlock_t* rwlock) {
1617 return pthread_rwlock_trywrlock_WRK(rwlock);
1619 #elif defined(VGO_darwin)
1620 PTH_FUNC(int, pthreadZurwlockZutrywrlockZa, // pthread_rwlock_trywrlock*
1621 pthread_rwlock_t* rwlock) {
1622 return pthread_rwlock_trywrlock_WRK(rwlock);
1624 #else
1625 # error "Unsupported OS"
1626 #endif
1629 //-----------------------------------------------------------
1630 // glibc: pthread_rwlock_tryrdlock
1631 // darwin: pthread_rwlock_trywrlock
1632 // darwin: pthread_rwlock_trywrlock$UNIX2003
1634 __attribute__((noinline))
1635 static int pthread_rwlock_tryrdlock_WRK(pthread_rwlock_t* rwlock)
1637 int ret;
1638 OrigFn fn;
1639 VALGRIND_GET_ORIG_FN(fn);
1640 if (TRACE_PTH_FNS) {
1641 fprintf(stderr, "<< pthread_rwl_tryrlk %p", rwlock); fflush(stderr);
1644 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1645 pthread_rwlock_t*,rwlock,
1646 long,0/*!isW*/, long,1/*isTryLock*/);
1648 CALL_FN_W_W(ret, fn, rwlock);
1650 /* There's a hole here: libpthread now knows the lock is locked,
1651 but the tool doesn't, so some other thread could run and detect
1652 that the lock has been acquired by someone (this thread). Does
1653 this matter? Not sure, but I don't think so. */
1655 if (ret == 0 /*success*/) {
1656 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1657 pthread_rwlock_t*,rwlock, long,0/*!isW*/);
1658 } else {
1659 if (ret != EBUSY)
1660 DO_PthAPIerror( "pthread_rwlock_tryrdlock", ret );
1663 if (TRACE_PTH_FNS) {
1664 fprintf(stderr, " :: rwl_tryrlk -> %d >>\n", ret);
1666 return ret;
1668 #if defined(VGO_linux)
1669 PTH_FUNC(int, pthreadZurwlockZutryrdlock, // pthread_rwlock_tryrdlock
1670 pthread_rwlock_t* rwlock) {
1671 return pthread_rwlock_tryrdlock_WRK(rwlock);
1673 #elif defined(VGO_darwin)
1674 PTH_FUNC(int, pthreadZurwlockZutryrdlockZa, // pthread_rwlock_tryrdlock*
1675 pthread_rwlock_t* rwlock) {
1676 return pthread_rwlock_tryrdlock_WRK(rwlock);
1678 #else
1679 # error "Unsupported OS"
1680 #endif
1683 //-----------------------------------------------------------
1684 // glibc: pthread_rwlock_unlock
1685 // darwin: pthread_rwlock_unlock
1686 // darwin: pthread_rwlock_unlock$UNIX2003
1687 __attribute__((noinline))
1688 static int pthread_rwlock_unlock_WRK(pthread_rwlock_t* rwlock)
1690 int ret;
1691 OrigFn fn;
1692 VALGRIND_GET_ORIG_FN(fn);
1693 if (TRACE_PTH_FNS) {
1694 fprintf(stderr, "<< pthread_rwl_unlk %p", rwlock); fflush(stderr);
1697 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
1698 pthread_rwlock_t*,rwlock);
1700 CALL_FN_W_W(ret, fn, rwlock);
1702 if (ret == 0 /*success*/) {
1703 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
1704 pthread_rwlock_t*,rwlock);
1705 } else {
1706 DO_PthAPIerror( "pthread_rwlock_unlock", ret );
1709 if (TRACE_PTH_FNS) {
1710 fprintf(stderr, " :: rwl_unlk -> %d >>\n", ret);
1712 return ret;
1714 #if defined(VGO_linux)
1715 PTH_FUNC(int, pthreadZurwlockZuunlock, // pthread_rwlock_unlock
1716 pthread_rwlock_t* rwlock) {
1717 return pthread_rwlock_unlock_WRK(rwlock);
1719 #elif defined(VGO_darwin)
1720 PTH_FUNC(int, pthreadZurwlockZuunlockZa, // pthread_rwlock_unlock*
1721 pthread_rwlock_t* rwlock) {
1722 return pthread_rwlock_unlock_WRK(rwlock);
1724 #else
1725 # error "Unsupported OS"
1726 #endif
1728 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
1731 /*----------------------------------------------------------------*/
1732 /*--- POSIX semaphores ---*/
1733 /*----------------------------------------------------------------*/
1735 #include <semaphore.h>
1736 #include <fcntl.h> /* O_CREAT */
1738 #define TRACE_SEM_FNS 0
1740 /* Handled:
1741 int sem_init(sem_t *sem, int pshared, unsigned value);
1742 int sem_destroy(sem_t *sem);
1743 int sem_wait(sem_t *sem);
1744 int sem_post(sem_t *sem);
1745 sem_t* sem_open(const char *name, int oflag,
1746 ... [mode_t mode, unsigned value]);
1747 [complete with its idiotic semantics]
1748 int sem_close(sem_t* sem);
1750 Unhandled:
1751 int sem_trywait(sem_t *sem);
1752 int sem_timedwait(sem_t *restrict sem,
1753 const struct timespec *restrict abs_timeout);
1756 //-----------------------------------------------------------
1757 // glibc: sem_init@@GLIBC_2.2.5
1758 // glibc: sem_init@@GLIBC_2.1
1759 // glibc: sem_init@GLIBC_2.0
1760 // darwin: sem_init
1762 __attribute__((noinline))
1763 static int sem_init_WRK(sem_t* sem, int pshared, unsigned long value)
1765 OrigFn fn;
1766 int ret;
1767 VALGRIND_GET_ORIG_FN(fn);
1769 if (TRACE_SEM_FNS) {
1770 fprintf(stderr, "<< sem_init(%p,%d,%lu) ", sem,pshared,value);
1771 fflush(stderr);
1774 CALL_FN_W_WWW(ret, fn, sem,pshared,value);
1776 if (ret == 0) {
1777 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
1778 sem_t*, sem, unsigned long, value);
1779 } else {
1780 DO_PthAPIerror( "sem_init", errno );
1783 if (TRACE_SEM_FNS) {
1784 fprintf(stderr, " sem_init -> %d >>\n", ret);
1785 fflush(stderr);
1788 return ret;
1790 #if defined(VGO_linux)
1791 PTH_FUNC(int, semZuinitZAZa, // sem_init@*
1792 sem_t* sem, int pshared, unsigned long value) {
1793 return sem_init_WRK(sem, pshared, value);
1795 #elif defined(VGO_darwin)
1796 PTH_FUNC(int, semZuinit, // sem_init
1797 sem_t* sem, int pshared, unsigned long value) {
1798 return sem_init_WRK(sem, pshared, value);
1800 #else
1801 # error "Unsupported OS"
1802 #endif
1805 //-----------------------------------------------------------
1806 // glibc: sem_destroy@GLIBC_2.0
1807 // glibc: sem_destroy@@GLIBC_2.1
1808 // glibc: sem_destroy@@GLIBC_2.2.5
1809 // darwin: sem_destroy
1810 __attribute__((noinline))
1811 static int sem_destroy_WRK(sem_t* sem)
1813 OrigFn fn;
1814 int ret;
1815 VALGRIND_GET_ORIG_FN(fn);
1817 if (TRACE_SEM_FNS) {
1818 fprintf(stderr, "<< sem_destroy(%p) ", sem);
1819 fflush(stderr);
1822 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
1824 CALL_FN_W_W(ret, fn, sem);
1826 if (ret != 0) {
1827 DO_PthAPIerror( "sem_destroy", errno );
1830 if (TRACE_SEM_FNS) {
1831 fprintf(stderr, " sem_destroy -> %d >>\n", ret);
1832 fflush(stderr);
1835 return ret;
1837 #if defined(VGO_linux)
1838 PTH_FUNC(int, semZudestroyZAZa, // sem_destroy*
1839 sem_t* sem) {
1840 return sem_destroy_WRK(sem);
1842 #elif defined(VGO_darwin)
1843 PTH_FUNC(int, semZudestroy, // sem_destroy
1844 sem_t* sem) {
1845 return sem_destroy_WRK(sem);
1847 #else
1848 # error "Unsupported OS"
1849 #endif
1852 //-----------------------------------------------------------
1853 // glibc: sem_wait
1854 // glibc: sem_wait@GLIBC_2.0
1855 // glibc: sem_wait@@GLIBC_2.1
1856 // darwin: sem_wait
1857 // darwin: sem_wait$NOCANCEL$UNIX2003
1858 // darwin: sem_wait$UNIX2003
1860 /* wait: decrement semaphore - acquire lockage */
1861 __attribute__((noinline))
1862 static int sem_wait_WRK(sem_t* sem)
1864 OrigFn fn;
1865 int ret;
1866 VALGRIND_GET_ORIG_FN(fn);
1868 if (TRACE_SEM_FNS) {
1869 fprintf(stderr, "<< sem_wait(%p) ", sem);
1870 fflush(stderr);
1873 CALL_FN_W_W(ret, fn, sem);
1875 if (ret == 0) {
1876 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST, sem_t*,sem);
1877 } else {
1878 DO_PthAPIerror( "sem_wait", errno );
1881 if (TRACE_SEM_FNS) {
1882 fprintf(stderr, " sem_wait -> %d >>\n", ret);
1883 fflush(stderr);
1886 return ret;
1888 #if defined(VGO_linux)
1889 PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
1890 return sem_wait_WRK(sem);
1892 PTH_FUNC(int, semZuwaitZAZa, sem_t* sem) { /* sem_wait@* */
1893 return sem_wait_WRK(sem);
1895 #elif defined(VGO_darwin)
1896 PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
1897 return sem_wait_WRK(sem);
1899 PTH_FUNC(int, semZuwaitZDZa, sem_t* sem) { /* sem_wait$* */
1900 return sem_wait_WRK(sem);
1902 #else
1903 # error "Unsupported OS"
1904 #endif
1907 //-----------------------------------------------------------
1908 // glibc: sem_post
1909 // glibc: sem_post@GLIBC_2.0
1910 // glibc: sem_post@@GLIBC_2.1
1911 // darwin: sem_post
1913 /* post: increment semaphore - release lockage */
1914 __attribute__((noinline))
1915 static int sem_post_WRK(sem_t* sem)
1917 OrigFn fn;
1918 int ret;
1920 VALGRIND_GET_ORIG_FN(fn);
1922 if (TRACE_SEM_FNS) {
1923 fprintf(stderr, "<< sem_post(%p) ", sem);
1924 fflush(stderr);
1927 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_PRE, sem_t*,sem);
1929 CALL_FN_W_W(ret, fn, sem);
1931 if (ret != 0) {
1932 DO_PthAPIerror( "sem_post", errno );
1935 if (TRACE_SEM_FNS) {
1936 fprintf(stderr, " sem_post -> %d >>\n", ret);
1937 fflush(stderr);
1940 return ret;
1942 #if defined(VGO_linux)
1943 PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
1944 return sem_post_WRK(sem);
1946 PTH_FUNC(int, semZupostZAZa, sem_t* sem) { /* sem_post@* */
1947 return sem_post_WRK(sem);
1949 #elif defined(VGO_darwin)
1950 PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
1951 return sem_post_WRK(sem);
1953 #else
1954 # error "Unsupported OS"
1955 #endif
1958 //-----------------------------------------------------------
1959 // glibc: sem_open
1960 // darwin: sem_open
1962 PTH_FUNC(sem_t*, semZuopen,
1963 const char* name, long oflag,
1964 long mode, unsigned long value)
1966 /* A copy of sem_init_WRK (more or less). Is this correct? */
1967 OrigFn fn;
1968 sem_t* ret;
1969 VALGRIND_GET_ORIG_FN(fn);
1971 if (TRACE_SEM_FNS) {
1972 fprintf(stderr, "<< sem_open(\"%s\",%ld,%lx,%lu) ",
1973 name,oflag,mode,value);
1974 fflush(stderr);
1977 CALL_FN_W_WWWW(ret, fn, name,oflag,mode,value);
1979 if (ret != SEM_FAILED && (oflag & O_CREAT)) {
1980 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
1981 sem_t*, ret, unsigned long, value);
1983 if (ret == SEM_FAILED) {
1984 DO_PthAPIerror( "sem_open", errno );
1987 if (TRACE_SEM_FNS) {
1988 fprintf(stderr, " sem_open -> %p >>\n", ret);
1989 fflush(stderr);
1992 return ret;
1996 //-----------------------------------------------------------
1997 // glibc: sem_close
1998 // darwin: sem_close
1999 PTH_FUNC(int, sem_close, sem_t* sem)
2001 OrigFn fn;
2002 int ret;
2003 VALGRIND_GET_ORIG_FN(fn);
2005 if (TRACE_SEM_FNS) {
2006 fprintf(stderr, "<< sem_close(%p) ", sem);
2007 fflush(stderr);
2010 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
2012 CALL_FN_W_W(ret, fn, sem);
2014 if (ret != 0) {
2015 DO_PthAPIerror( "sem_close", errno );
2018 if (TRACE_SEM_FNS) {
2019 fprintf(stderr, " close -> %d >>\n", ret);
2020 fflush(stderr);
2023 return ret;
2027 /*----------------------------------------------------------------*/
2028 /*--- Qt 4 threading functions (w/ GNU name mangling) ---*/
2029 /*----------------------------------------------------------------*/
2031 /* Handled:
2032 QMutex::lock()
2033 QMutex::unlock()
2034 QMutex::tryLock()
2035 QMutex::tryLock(int)
2037 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC1ENS_13RecursionModeE
2038 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC2ENS_13RecursionModeE
2039 QMutex::~QMutex() _ZN6QMutexD1Ev
2040 QMutex::~QMutex() _ZN6QMutexD2Ev
2042 Unhandled:
2043 QReadWriteLock::lockForRead()
2044 QReadWriteLock::lockForWrite()
2045 QReadWriteLock::unlock()
2046 QReadWriteLock::tryLockForRead(int)
2047 QReadWriteLock::tryLockForRead()
2048 QReadWriteLock::tryLockForWrite(int)
2049 QReadWriteLock::tryLockForWrite()
2051 QWaitCondition::wait(QMutex*, unsigned long)
2052 QWaitCondition::wakeAll()
2053 QWaitCondition::wakeOne()
2055 QSemaphore::*
2057 /* More comments, 19 Nov 08, based on assessment of qt-4.5.0TP1,
2058 at least on Unix:
2060 It's apparently only necessary to intercept QMutex, since that is
2061 not implemented using pthread_mutex_t; instead Qt4 has its own
2062 implementation based on atomics (to check the non-contended case)
2063 and pthread_cond_wait (to wait in the contended case).
2065 QReadWriteLock is built on top of QMutex, counters, and a wait
2066 queue. So we don't need to handle it specially once QMutex
2067 handling is correct -- presumably the dependencies through QMutex
2068 are sufficient to avoid any false race reports. On the other hand,
2069 it is an open question whether too many dependencies are observed
2070 -- in which case we may miss races (false negatives). I suspect
2071 this is likely to be the case, unfortunately.
2073 QWaitCondition is built on pthread_cond_t, pthread_mutex_t, QMutex
2074 and QReadWriteLock. Same compositional-correctness justificiation
2075 and limitations as fro QReadWriteLock.
2077 Ditto QSemaphore (from cursory examination).
2079 Does it matter that only QMutex is handled directly? Open
2080 question. From testing with drd/tests/qt4_* and with KDE4 apps, it
2081 appears that no false errors are reported; however it is not clear
2082 if this is causing false negatives.
2084 Another problem with Qt4 is thread exiting. Threads are created
2085 with pthread_create (fine); but they detach and simply exit when
2086 done. There is no use of pthread_join, and the provided
2087 wait-for-a-thread-to-exit mechanism (QThread::wait, I believe)
2088 relies on a system of mutexes and flags. I suspect this also
2089 causes too many dependencies to appear. Consequently H sometimes
2090 fails to detect races at exit in some very short-lived racy
2091 programs, because it appears that a thread can exit _and_ have an
2092 observed dependency edge back to the main thread (presumably)
2093 before the main thread reaps the child (that is, calls
2094 QThread::wait).
2096 This theory is supported by the observation that if all threads are
2097 made to wait at a pthread_barrier_t immediately before they exit,
2098 then H's detection of races in such programs becomes reliable;
2099 without the barrier, it is varies from run to run, depending
2100 (according to investigation) on whether aforementioned
2101 exit-before-reaping behaviour happens or not.
2103 Finally, why is it necessary to intercept the QMutex constructors
2104 and destructors? The constructors are intercepted only as a matter
2105 of convenience, so H can print accurate "first observed at"
2106 clauses. However, it is actually necessary to intercept the
2107 destructors (as it is with pthread_mutex_destroy) in order that
2108 locks get removed from LAOG when they are destroyed.
2111 // soname is libQtCore.so.4 ; match against libQtCore.so*
2112 #define QT4_FUNC(ret_ty, f, args...) \
2113 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args); \
2114 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args)
2116 // soname is libQt5Core.so.4 ; match against libQt5Core.so*
2117 #define QT5_FUNC(ret_ty, f, args...) \
2118 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args); \
2119 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args)
2121 //-----------------------------------------------------------
2122 // QMutex::lock()
2123 __attribute__((noinline))
2124 static void QMutex_lock_WRK(void* self)
2126 OrigFn fn;
2127 VALGRIND_GET_ORIG_FN(fn);
2128 if (TRACE_QT4_FNS) {
2129 fprintf(stderr, "<< QMutex::lock %p", self); fflush(stderr);
2132 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
2133 void*,self, long,0/*!isTryLock*/);
2135 CALL_FN_v_W(fn, self);
2137 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
2138 void*, self);
2140 if (TRACE_QT4_FNS) {
2141 fprintf(stderr, " :: Q::lock done >>\n");
2145 QT4_FUNC(void, _ZN6QMutex4lockEv, void* self) {
2146 QMutex_lock_WRK(self);
2148 QT5_FUNC(void, _ZN6QMutex4lockEv, void* self) {
2149 QMutex_lock_WRK(self);
2152 //-----------------------------------------------------------
2153 // QMutex::unlock()
2154 __attribute__((noinline))
2155 static void QMutex_unlock_WRK(void* self)
2157 OrigFn fn;
2158 VALGRIND_GET_ORIG_FN(fn);
2160 if (TRACE_QT4_FNS) {
2161 fprintf(stderr, "<< QMutex::unlock %p", self); fflush(stderr);
2164 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
2165 void*, self);
2167 CALL_FN_v_W(fn, self);
2169 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
2170 void*, self);
2172 if (TRACE_QT4_FNS) {
2173 fprintf(stderr, " Q::unlock done >>\n");
2177 QT4_FUNC(void, _ZN6QMutex6unlockEv, void* self) {
2178 QMutex_unlock_WRK(self);
2180 QT5_FUNC(void, _ZN6QMutex6unlockEv, void* self) {
2181 QMutex_unlock_WRK(self);
2184 //-----------------------------------------------------------
2185 // bool QMutex::tryLock()
2186 // using 'long' to mimic C++ 'bool'
2187 __attribute__((noinline))
2188 static long QMutex_tryLock_WRK(void* self)
2190 OrigFn fn;
2191 long ret;
2192 VALGRIND_GET_ORIG_FN(fn);
2193 if (TRACE_QT4_FNS) {
2194 fprintf(stderr, "<< QMutex::tryLock %p", self); fflush(stderr);
2197 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
2198 void*,self, long,1/*isTryLock*/);
2200 CALL_FN_W_W(ret, fn, self);
2202 // assumes that only the low 8 bits of the 'bool' are significant
2203 if (ret & 0xFF) {
2204 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
2205 void*, self);
2208 if (TRACE_QT4_FNS) {
2209 fprintf(stderr, " :: Q::tryLock -> %lu >>\n", ret);
2212 return ret;
2215 QT4_FUNC(long, _ZN6QMutex7tryLockEv, void* self) {
2216 return QMutex_tryLock_WRK(self);
2218 QT5_FUNC(long, _ZN6QMutex7tryLockEv, void* self) {
2219 return QMutex_tryLock_WRK(self);
2222 //-----------------------------------------------------------
2223 // bool QMutex::tryLock(int)
2224 // using 'long' to mimic C++ 'bool'
2225 __attribute__((noinline))
2226 static long QMutex_tryLock_int_WRK(void* self, long arg2)
2228 OrigFn fn;
2229 long ret;
2230 VALGRIND_GET_ORIG_FN(fn);
2231 if (TRACE_QT4_FNS) {
2232 fprintf(stderr, "<< QMutex::tryLock(int) %p %d", self, (int)arg2);
2233 fflush(stderr);
2236 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
2237 void*,self, long,1/*isTryLock*/);
2239 CALL_FN_W_WW(ret, fn, self,arg2);
2241 // assumes that only the low 8 bits of the 'bool' are significant
2242 if (ret & 0xFF) {
2243 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
2244 void*, self);
2247 if (TRACE_QT4_FNS) {
2248 fprintf(stderr, " :: Q::tryLock(int) -> %lu >>\n", ret);
2251 return ret;
2254 QT4_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2) {
2255 return QMutex_tryLock_int_WRK(self, arg2);
2257 QT5_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2) {
2258 return QMutex_tryLock_int_WRK(self, arg2);
2261 //-----------------------------------------------------------
2262 // It's not really very clear what the args are here. But from
2263 // a bit of dataflow analysis of the generated machine code of
2264 // the original function, it appears this takes two args, and
2265 // returns nothing. Nevertheless preserve return value just in
2266 // case. A bit of debug printing indicates that the first arg
2267 // is that of the mutex and the second is either zero or one,
2268 // probably being the recursion mode, therefore.
2269 // QMutex::QMutex(QMutex::RecursionMode) ("C1ENS" variant)
2270 __attribute__((noinline))
2271 static void* QMutex_constructor_WRK(void* mutex, long recmode)
2273 OrigFn fn;
2274 long ret;
2275 VALGRIND_GET_ORIG_FN(fn);
2276 CALL_FN_W_WW(ret, fn, mutex, recmode);
2277 // fprintf(stderr, "QMutex constructor 1: %p <- %p %p\n", ret, arg1, arg2);
2278 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
2279 void*,mutex, long,1/*mbRec*/);
2280 return (void*)ret;
2283 QT4_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE, void* self, long recmode) {
2284 return QMutex_constructor_WRK(self, recmode);
2286 QT5_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE, void* self, long recmode) {
2287 return QMutex_constructor_WRK(self, recmode);
2290 //-----------------------------------------------------------
2291 // QMutex::~QMutex() ("D1Ev" variant)
2292 __attribute__((noinline))
2293 static void* QMutex_destructor_WRK(void* mutex)
2295 OrigFn fn;
2296 long ret;
2297 VALGRIND_GET_ORIG_FN(fn);
2298 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
2299 void*,mutex);
2300 CALL_FN_W_W(ret, fn, mutex);
2301 return (void*)ret;
2304 QT4_FUNC(void*, _ZN6QMutexD1Ev, void* self) {
2305 return QMutex_destructor_WRK(self);
2307 QT5_FUNC(void*, _ZN6QMutexD1Ev, void* self) {
2308 return QMutex_destructor_WRK(self);
2311 //-----------------------------------------------------------
2312 // QMutex::QMutex(QMutex::RecursionMode) ("C2ENS" variant)
2313 QT4_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE,
2314 void* mutex,
2315 long recmode)
2317 assert(0);
2318 /*NOTREACHED*/
2319 /* Android's gcc behaves like it doesn't know that assert(0)
2320 never returns. Hence: */
2321 return NULL;
2324 QT5_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE, void* self, long recmode)
2326 assert(0);
2327 /*NOTREACHED*/
2328 return NULL;
2331 //-----------------------------------------------------------
2332 // QMutex::~QMutex() ("D2Ev" variant)
2333 QT4_FUNC(void*, _ZN6QMutexD2Ev, void* mutex)
2335 assert(0);
2336 /* Android's gcc behaves like it doesn't know that assert(0)
2337 never returns. Hence: */
2338 return NULL;
2341 QT5_FUNC(void*, _ZN6QMutexD2Ev, void* self)
2343 assert(0);
2344 /*NOTREACHED*/
2345 return NULL;
2348 // QReadWriteLock is not intercepted directly. See comments
2349 // above.
2351 //// QReadWriteLock::lockForRead()
2352 //// _ZN14QReadWriteLock11lockForReadEv == QReadWriteLock::lockForRead()
2353 //QT4_FUNC(void, ZuZZN14QReadWriteLock11lockForReadEv,
2354 // // _ZN14QReadWriteLock11lockForReadEv
2355 // void* self)
2357 // OrigFn fn;
2358 // VALGRIND_GET_ORIG_FN(fn);
2359 // if (TRACE_QT4_FNS) {
2360 // fprintf(stderr, "<< QReadWriteLock::lockForRead %p", self);
2361 // fflush(stderr);
2362 // }
2364 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2365 // void*,self,
2366 // long,0/*!isW*/, long,0/*!isTryLock*/);
2368 // CALL_FN_v_W(fn, self);
2370 // DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2371 // void*,self, long,0/*!isW*/);
2373 // if (TRACE_QT4_FNS) {
2374 // fprintf(stderr, " :: Q::lockForRead :: done >>\n");
2375 // }
2378 //// QReadWriteLock::lockForWrite()
2379 //// _ZN14QReadWriteLock12lockForWriteEv == QReadWriteLock::lockForWrite()
2380 //QT4_FUNC(void, ZuZZN14QReadWriteLock12lockForWriteEv,
2381 // // _ZN14QReadWriteLock12lockForWriteEv
2382 // void* self)
2384 // OrigFn fn;
2385 // VALGRIND_GET_ORIG_FN(fn);
2386 // if (TRACE_QT4_FNS) {
2387 // fprintf(stderr, "<< QReadWriteLock::lockForWrite %p", self);
2388 // fflush(stderr);
2389 // }
2391 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2392 // void*,self,
2393 // long,1/*isW*/, long,0/*!isTryLock*/);
2395 // CALL_FN_v_W(fn, self);
2397 // DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2398 // void*,self, long,1/*isW*/);
2400 // if (TRACE_QT4_FNS) {
2401 // fprintf(stderr, " :: Q::lockForWrite :: done >>\n");
2402 // }
2405 //// QReadWriteLock::unlock()
2406 //// _ZN14QReadWriteLock6unlockEv == QReadWriteLock::unlock()
2407 //QT4_FUNC(void, ZuZZN14QReadWriteLock6unlockEv,
2408 // // _ZN14QReadWriteLock6unlockEv
2409 // void* self)
2411 // OrigFn fn;
2412 // VALGRIND_GET_ORIG_FN(fn);
2413 // if (TRACE_QT4_FNS) {
2414 // fprintf(stderr, "<< QReadWriteLock::unlock %p", self);
2415 // fflush(stderr);
2416 // }
2418 // DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
2419 // void*,self);
2421 // CALL_FN_v_W(fn, self);
2423 // DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
2424 // void*,self);
2426 // if (TRACE_QT4_FNS) {
2427 // fprintf(stderr, " :: Q::unlock :: done >>\n");
2428 // }
2432 /*----------------------------------------------------------------*/
2433 /*--- Replacements for basic string functions, that don't ---*/
2434 /*--- overrun the input arrays. ---*/
2435 /*----------------------------------------------------------------*/
2437 #include "../shared/vg_replace_strmem.c"
2439 /*--------------------------------------------------------------------*/
2440 /*--- end hg_intercepts.c ---*/
2441 /*--------------------------------------------------------------------*/