drd: Add a consistency check
[valgrind.git] / helgrind / hg_intercepts.c
blobf109bf3e1f081d552f6e2ea263eaf3e19f3682ba
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
63 #define TRACE_GNAT_FNS 0
66 /*----------------------------------------------------------------*/
67 /*--- ---*/
68 /*----------------------------------------------------------------*/
70 #define PTH_FUNC(ret_ty, f, args...) \
71 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args); \
72 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args)
74 // Do a client request. These are macros rather than a functions so
75 // as to avoid having an extra frame in stack traces.
77 // NB: these duplicate definitions in helgrind.h. But here, we
78 // can have better typing (Word etc) and assertions, whereas
79 // in helgrind.h we can't. Obviously it's important the two
80 // sets of definitions are kept in sync.
82 // nuke the previous definitions
83 #undef DO_CREQ_v_W
84 #undef DO_CREQ_v_WW
85 #undef DO_CREQ_W_WW
86 #undef DO_CREQ_v_WWW
88 #define DO_CREQ_v_W(_creqF, _ty1F,_arg1F) \
89 do { \
90 Word _arg1; \
91 assert(sizeof(_ty1F) == sizeof(Word)); \
92 _arg1 = (Word)(_arg1F); \
93 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
94 _arg1, 0,0,0,0); \
95 } while (0)
97 #define DO_CREQ_v_WW(_creqF, _ty1F,_arg1F, _ty2F,_arg2F) \
98 do { \
99 Word _arg1, _arg2; \
100 assert(sizeof(_ty1F) == sizeof(Word)); \
101 assert(sizeof(_ty2F) == sizeof(Word)); \
102 _arg1 = (Word)(_arg1F); \
103 _arg2 = (Word)(_arg2F); \
104 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
105 _arg1,_arg2,0,0,0); \
106 } while (0)
108 #define DO_CREQ_W_WW(_resF, _creqF, _ty1F,_arg1F, \
109 _ty2F,_arg2F) \
110 do { \
111 Word _res, _arg1, _arg2; \
112 assert(sizeof(_ty1F) == sizeof(Word)); \
113 assert(sizeof(_ty2F) == sizeof(Word)); \
114 _arg1 = (Word)(_arg1F); \
115 _arg2 = (Word)(_arg2F); \
116 _res = VALGRIND_DO_CLIENT_REQUEST_EXPR(2, \
117 (_creqF), \
118 _arg1,_arg2,0,0,0); \
119 _resF = _res; \
120 } while (0)
122 #define DO_CREQ_v_WWW(_creqF, _ty1F,_arg1F, \
123 _ty2F,_arg2F, _ty3F, _arg3F) \
124 do { \
125 Word _arg1, _arg2, _arg3; \
126 assert(sizeof(_ty1F) == sizeof(Word)); \
127 assert(sizeof(_ty2F) == sizeof(Word)); \
128 assert(sizeof(_ty3F) == sizeof(Word)); \
129 _arg1 = (Word)(_arg1F); \
130 _arg2 = (Word)(_arg2F); \
131 _arg3 = (Word)(_arg3F); \
132 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
133 _arg1,_arg2,_arg3,0,0); \
134 } while (0)
137 #define DO_PthAPIerror(_fnnameF, _errF) \
138 do { \
139 const char* _fnname = (_fnnameF); \
140 long _err = (long)(int)(_errF); \
141 const char* _errstr = lame_strerror(_err); \
142 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTH_API_ERROR, \
143 char*,_fnname, \
144 long,_err, char*,_errstr); \
145 } while (0)
148 /* Needed for older glibcs (2.3 and older, at least) who don't
149 otherwise "know" about pthread_rwlock_anything or about
150 PTHREAD_MUTEX_RECURSIVE (amongst things). */
151 #define _GNU_SOURCE 1
153 #include <stdio.h>
154 #include <assert.h>
155 #include <errno.h>
156 #include <pthread.h>
158 /* A standalone memcmp. */
159 __attribute__((noinline))
160 static int my_memcmp ( const void* ptr1, const void* ptr2, size_t size)
162 const unsigned char* uchar_ptr1 = (const unsigned char*) ptr1;
163 const unsigned char* uchar_ptr2 = (const unsigned char*) ptr2;
164 size_t i;
165 for (i = 0; i < size; ++i) {
166 if (uchar_ptr1[i] != uchar_ptr2[i])
167 return (uchar_ptr1[i] < uchar_ptr2[i]) ? -1 : 1;
169 return 0;
172 /* A lame version of strerror which doesn't use the real libc
173 strerror_r, since using the latter just generates endless more
174 threading errors (glibc goes off and does tons of crap w.r.t.
175 locales etc) */
176 static const HChar* lame_strerror ( long err )
178 switch (err) {
179 case EPERM: return "EPERM: Operation not permitted";
180 case ENOENT: return "ENOENT: No such file or directory";
181 case ESRCH: return "ESRCH: No such process";
182 case EINTR: return "EINTR: Interrupted system call";
183 case EBADF: return "EBADF: Bad file number";
184 case EAGAIN: return "EAGAIN: Try again";
185 case ENOMEM: return "ENOMEM: Out of memory";
186 case EACCES: return "EACCES: Permission denied";
187 case EFAULT: return "EFAULT: Bad address";
188 case EEXIST: return "EEXIST: File exists";
189 case EINVAL: return "EINVAL: Invalid argument";
190 case EMFILE: return "EMFILE: Too many open files";
191 case ENOSYS: return "ENOSYS: Function not implemented";
192 case EOVERFLOW: return "EOVERFLOW: Value too large "
193 "for defined data type";
194 case EBUSY: return "EBUSY: Device or resource busy";
195 case ETIMEDOUT: return "ETIMEDOUT: Connection timed out";
196 case EDEADLK: return "EDEADLK: Resource deadlock would occur";
197 case EOPNOTSUPP: return "EOPNOTSUPP: Operation not supported on "
198 "transport endpoint"; /* honest, guv */
199 default: return "tc_intercepts.c: lame_strerror(): "
200 "unhandled case -- please fix me!";
205 /*----------------------------------------------------------------*/
206 /*--- pthread_create, pthread_join, pthread_exit ---*/
207 /*----------------------------------------------------------------*/
209 static void* mythread_wrapper ( void* xargsV )
211 volatile Word* xargs = (volatile Word*) xargsV;
212 void*(*fn)(void*) = (void*(*)(void*))xargs[0];
213 void* arg = (void*)xargs[1];
214 pthread_t me = pthread_self();
215 /* Tell the tool what my pthread_t is. */
216 DO_CREQ_v_W(_VG_USERREQ__HG_SET_MY_PTHREAD_T, pthread_t,me);
217 /* allow the parent to proceed. We can't let it proceed until
218 we're ready because (1) we need to make sure it doesn't exit and
219 hence deallocate xargs[] while we still need it, and (2) we
220 don't want either parent nor child to proceed until the tool has
221 been notified of the child's pthread_t.
223 Note that parent and child access args[] without a lock,
224 effectively using args[2] as a spinlock in order to get the
225 parent to wait until the child passes this point. The parent
226 disables checking on xargs[] before creating the child and
227 re-enables it once the child goes past this point, so the user
228 never sees the race. The previous approach (suppressing the
229 resulting error) was flawed, because it could leave shadow
230 memory for args[] in a state in which subsequent use of it by
231 the parent would report further races. */
232 xargs[2] = 0;
233 /* Now we can no longer safely use xargs[]. */
234 return (void*) fn( (void*)arg );
237 //-----------------------------------------------------------
238 // glibc: pthread_create@GLIBC_2.0
239 // glibc: pthread_create@@GLIBC_2.1
240 // glibc: pthread_create@@GLIBC_2.2.5
241 // darwin: pthread_create
242 // darwin: pthread_create_suspended_np (trapped)
244 /* ensure this has its own frame, so as to make it more distinguishable
245 in suppressions */
246 __attribute__((noinline))
247 static int pthread_create_WRK(pthread_t *thread, const pthread_attr_t *attr,
248 void *(*start) (void *), void *arg)
250 int ret;
251 OrigFn fn;
252 volatile Word xargs[3];
254 VALGRIND_GET_ORIG_FN(fn);
255 if (TRACE_PTH_FNS) {
256 fprintf(stderr, "<< pthread_create wrapper"); fflush(stderr);
258 xargs[0] = (Word)start;
259 xargs[1] = (Word)arg;
260 xargs[2] = 1; /* serves as a spinlock -- sigh */
261 /* Disable checking on the spinlock and the two words used to
262 convey args to the child. Basically we need to make it appear
263 as if the child never accessed this area, since merely
264 suppressing the resulting races does not address the issue that
265 that piece of the parent's stack winds up in the "wrong" state
266 and therefore may give rise to mysterious races when the parent
267 comes to re-use this piece of stack in some other frame. */
268 VALGRIND_HG_DISABLE_CHECKING(&xargs, sizeof(xargs));
270 CALL_FN_W_WWWW(ret, fn, thread,attr,mythread_wrapper,&xargs[0]);
272 if (ret == 0) {
273 /* we have to wait for the child to notify the tool of its
274 pthread_t before continuing */
275 while (xargs[2] != 0) {
276 /* Do nothing. We need to spin until the child writes to
277 xargs[2]. However, that can lead to starvation in the
278 child and very long delays (eg, tc19_shadowmem on
279 ppc64-linux Fedora Core 6). So yield the cpu if we can,
280 to let the child run at the earliest available
281 opportunity. */
282 sched_yield();
284 } else {
285 DO_PthAPIerror( "pthread_create", ret );
288 /* Reenable checking on the area previously used to communicate
289 with the child. */
290 VALGRIND_HG_ENABLE_CHECKING(&xargs, sizeof(xargs));
292 if (TRACE_PTH_FNS) {
293 fprintf(stderr, " :: pth_create -> %d >>\n", ret);
295 return ret;
297 #if defined(VGO_linux)
298 PTH_FUNC(int, pthreadZucreateZAZa, // pthread_create@*
299 pthread_t *thread, const pthread_attr_t *attr,
300 void *(*start) (void *), void *arg) {
301 return pthread_create_WRK(thread, attr, start, arg);
303 #elif defined(VGO_darwin)
304 PTH_FUNC(int, pthreadZucreate, // pthread_create
305 pthread_t *thread, const pthread_attr_t *attr,
306 void *(*start) (void *), void *arg) {
307 return pthread_create_WRK(thread, attr, start, arg);
309 PTH_FUNC(int, pthreadZucreateZuZa, // pthread_create_*
310 pthread_t *thread, const pthread_attr_t *attr,
311 void *(*start) (void *), void *arg) {
312 // trap anything else
313 assert(0);
315 #else
316 # error "Unsupported OS"
317 #endif
320 //-----------------------------------------------------------
321 // glibc: pthread_join
322 // darwin: pthread_join
323 // darwin: pthread_join$NOCANCEL$UNIX2003
324 // darwin pthread_join$UNIX2003
325 __attribute__((noinline))
326 static int pthread_join_WRK(pthread_t thread, void** value_pointer)
328 int ret;
329 OrigFn fn;
330 VALGRIND_GET_ORIG_FN(fn);
331 if (TRACE_PTH_FNS) {
332 fprintf(stderr, "<< pthread_join wrapper"); fflush(stderr);
335 CALL_FN_W_WW(ret, fn, thread,value_pointer);
337 /* At least with NPTL as the thread library, this is safe because
338 it is guaranteed (by NPTL) that the joiner will completely gone
339 before pthread_join (the original) returns. See email below.*/
340 if (ret == 0 /*success*/) {
341 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST, pthread_t,thread);
342 } else {
343 DO_PthAPIerror( "pthread_join", ret );
346 if (TRACE_PTH_FNS) {
347 fprintf(stderr, " :: pth_join -> %d >>\n", ret);
349 return ret;
351 #if defined(VGO_linux)
352 PTH_FUNC(int, pthreadZujoin, // pthread_join
353 pthread_t thread, void** value_pointer) {
354 return pthread_join_WRK(thread, value_pointer);
356 #elif defined(VGO_darwin)
357 PTH_FUNC(int, pthreadZujoinZa, // pthread_join*
358 pthread_t thread, void** value_pointer) {
359 return pthread_join_WRK(thread, value_pointer);
361 #else
362 # error "Unsupported OS"
363 #endif
366 /* Behaviour of pthread_join on NPTL:
369 I have a question re the NPTL pthread_join implementation.
371 Suppose I am the thread 'stayer'.
373 If I call pthread_join(quitter), is it guaranteed that the
374 thread 'quitter' has really exited before pthread_join returns?
376 IOW, is it guaranteed that 'quitter' will not execute any further
377 instructions after pthread_join returns?
379 I believe this is true based on the following analysis of
380 glibc-2.5 sources. However am not 100% sure and would appreciate
381 confirmation.
383 'quitter' will be running start_thread() in nptl/pthread_create.c
385 The last action of start_thread() is to exit via
386 __exit_thread_inline(0), which simply does sys_exit
387 (nptl/pthread_create.c:403)
389 'stayer' meanwhile is waiting for lll_wait_tid (pd->tid)
390 (call at nptl/pthread_join.c:89)
392 As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
393 lll_wait_tid will not return until kernel notifies via futex
394 wakeup that 'quitter' has terminated.
396 Hence pthread_join cannot return until 'quitter' really has
397 completely disappeared.
399 Drepper:
400 > As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
401 > lll_wait_tid will not return until kernel notifies via futex
402 > wakeup that 'quitter' has terminated.
403 That's the key. The kernel resets the TID field after the thread is
404 done. No way the joiner can return before the thread is gone.
407 //-----------------------------------------------------------
408 // Ada gcc gnat runtime:
409 // The gnat gcc Ada runtime does not use pthread_join. Instead, it uses
410 // a combination of other pthread primitives to ensure a child thread
411 // is gone. This combination is somewhat functionally equivalent to a
412 // pthread_join.
413 // We wrap two hook procedures called by the gnat gcc Ada runtime
414 // that allows helgrind to understand the semantic of Ada task dependencies
415 // and termination.
417 // System.Tasking.Debug.Master_Hook is called by a task Dependent to
418 // indicate that its master is identified by master+master_level.
419 void I_WRAP_SONAME_FNNAME_ZU
420 (Za,
421 system__tasking__debug__master_hook)
422 (void *dependent, void *master, int master_level);
423 void I_WRAP_SONAME_FNNAME_ZU
424 (Za,
425 system__tasking__debug__master_hook)
426 (void *dependent, void *master, int master_level)
428 OrigFn fn;
429 VALGRIND_GET_ORIG_FN(fn);
430 if (TRACE_GNAT_FNS) {
431 fprintf(stderr, "<< GNAT master_hook wrapper "
432 "dependent %p master %p master_level %d\n",
433 dependent, master, master_level); fflush(stderr);
436 // We call the wrapped function, even if it is a null body.
437 CALL_FN_v_WWW(fn, dependent, master, master_level);
439 DO_CREQ_v_WWW(_VG_USERREQ__HG_GNAT_MASTER_HOOK,
440 void*,dependent, void*,master,
441 Word, (Word)master_level);
443 if (TRACE_GNAT_FNS) {
444 fprintf(stderr, " :: GNAT master_hook >>\n");
448 // System.Tasking.Debug.Master_Completed_Hook is called by a task to
449 // indicate that it has completed a master.
450 // This indicates that all its Dependent tasks (that identified themselves
451 // with the Master_Hook call) are terminated. Helgrind can consider
452 // at this point that the equivalent of a 'pthread_join' has been done
453 // between self_id and all dependent tasks at master_level.
454 void I_WRAP_SONAME_FNNAME_ZU
455 (Za,
456 system__tasking__debug__master_completed_hook)
457 (void *self_id, int master_level);
458 void I_WRAP_SONAME_FNNAME_ZU
459 (Za,
460 system__tasking__debug__master_completed_hook)
461 (void *self_id, int master_level)
463 OrigFn fn;
464 VALGRIND_GET_ORIG_FN(fn);
465 if (TRACE_GNAT_FNS) {
466 fprintf(stderr, "<< GNAT master_completed_hook wrapper "
467 "self_id %p master_level %d\n",
468 self_id, master_level); fflush(stderr);
471 // We call the wrapped function, even if it is a null body.
472 CALL_FN_v_WW(fn, self_id, master_level);
474 DO_CREQ_v_WW(_VG_USERREQ__HG_GNAT_MASTER_COMPLETED_HOOK,
475 void*,self_id, Word,(Word)master_level);
477 if (TRACE_GNAT_FNS) {
478 fprintf(stderr, " :: GNAT master_completed_hook >>\n");
482 /*----------------------------------------------------------------*/
483 /*--- pthread_mutex_t functions ---*/
484 /*----------------------------------------------------------------*/
486 /* Handled: pthread_mutex_init pthread_mutex_destroy
487 pthread_mutex_lock
488 pthread_mutex_trylock pthread_mutex_timedlock
489 pthread_mutex_unlock
492 //-----------------------------------------------------------
493 // glibc: pthread_mutex_init
494 // darwin: pthread_mutex_init
495 PTH_FUNC(int, pthreadZumutexZuinit, // pthread_mutex_init
496 pthread_mutex_t *mutex,
497 pthread_mutexattr_t* attr)
499 int ret;
500 long mbRec;
501 OrigFn fn;
502 VALGRIND_GET_ORIG_FN(fn);
503 if (TRACE_PTH_FNS) {
504 fprintf(stderr, "<< pthread_mxinit %p", mutex); fflush(stderr);
507 mbRec = 0;
508 if (attr) {
509 int ty, zzz;
510 zzz = pthread_mutexattr_gettype(attr, &ty);
511 if (zzz == 0 && ty == PTHREAD_MUTEX_RECURSIVE)
512 mbRec = 1;
515 CALL_FN_W_WW(ret, fn, mutex,attr);
517 if (ret == 0 /*success*/) {
518 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
519 pthread_mutex_t*,mutex, long,mbRec);
520 } else {
521 DO_PthAPIerror( "pthread_mutex_init", ret );
524 if (TRACE_PTH_FNS) {
525 fprintf(stderr, " :: mxinit -> %d >>\n", ret);
527 return ret;
531 //-----------------------------------------------------------
532 // glibc: pthread_mutex_destroy
533 // darwin: pthread_mutex_destroy
534 PTH_FUNC(int, pthreadZumutexZudestroy, // pthread_mutex_destroy
535 pthread_mutex_t *mutex)
537 int ret;
538 unsigned long mutex_is_init;
539 OrigFn fn;
541 VALGRIND_GET_ORIG_FN(fn);
542 if (TRACE_PTH_FNS) {
543 fprintf(stderr, "<< pthread_mxdestroy %p", mutex); fflush(stderr);
546 if (mutex != NULL) {
547 static const pthread_mutex_t mutex_init = PTHREAD_MUTEX_INITIALIZER;
548 mutex_is_init = my_memcmp(mutex, &mutex_init, sizeof(*mutex)) == 0;
549 } else {
550 mutex_is_init = 0;
553 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
554 pthread_mutex_t*, mutex, unsigned long, mutex_is_init);
556 CALL_FN_W_W(ret, fn, mutex);
558 if (ret != 0) {
559 DO_PthAPIerror( "pthread_mutex_destroy", ret );
562 if (TRACE_PTH_FNS) {
563 fprintf(stderr, " :: mxdestroy -> %d >>\n", ret);
565 return ret;
569 //-----------------------------------------------------------
570 // glibc: pthread_mutex_lock
571 // darwin: pthread_mutex_lock
572 PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock
573 pthread_mutex_t *mutex)
575 int ret;
576 OrigFn fn;
577 VALGRIND_GET_ORIG_FN(fn);
578 if (TRACE_PTH_FNS) {
579 fprintf(stderr, "<< pthread_mxlock %p", mutex); fflush(stderr);
582 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
583 pthread_mutex_t*,mutex, long,0/*!isTryLock*/);
585 CALL_FN_W_W(ret, fn, mutex);
587 /* There's a hole here: libpthread now knows the lock is locked,
588 but the tool doesn't, so some other thread could run and detect
589 that the lock has been acquired by someone (this thread). Does
590 this matter? Not sure, but I don't think so. */
592 if (ret == 0 /*success*/) {
593 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
594 pthread_mutex_t*,mutex);
595 } else {
596 DO_PthAPIerror( "pthread_mutex_lock", ret );
599 if (TRACE_PTH_FNS) {
600 fprintf(stderr, " :: mxlock -> %d >>\n", ret);
602 return ret;
606 //-----------------------------------------------------------
607 // glibc: pthread_mutex_trylock
608 // darwin: pthread_mutex_trylock
610 // pthread_mutex_trylock. The handling needed here is very similar
611 // to that for pthread_mutex_lock, except that we need to tell
612 // the pre-lock creq that this is a trylock-style operation, and
613 // therefore not to complain if the lock is nonrecursive and
614 // already locked by this thread -- because then it'll just fail
615 // immediately with EBUSY.
616 PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock
617 pthread_mutex_t *mutex)
619 int ret;
620 OrigFn fn;
621 VALGRIND_GET_ORIG_FN(fn);
622 if (TRACE_PTH_FNS) {
623 fprintf(stderr, "<< pthread_mxtrylock %p", mutex); fflush(stderr);
626 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
627 pthread_mutex_t*,mutex, long,1/*isTryLock*/);
629 CALL_FN_W_W(ret, fn, mutex);
631 /* There's a hole here: libpthread now knows the lock is locked,
632 but the tool doesn't, so some other thread could run and detect
633 that the lock has been acquired by someone (this thread). Does
634 this matter? Not sure, but I don't think so. */
636 if (ret == 0 /*success*/) {
637 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
638 pthread_mutex_t*,mutex);
639 } else {
640 if (ret != EBUSY)
641 DO_PthAPIerror( "pthread_mutex_trylock", ret );
644 if (TRACE_PTH_FNS) {
645 fprintf(stderr, " :: mxtrylock -> %d >>\n", ret);
647 return ret;
651 //-----------------------------------------------------------
652 // glibc: pthread_mutex_timedlock
653 // darwin: (doesn't appear to exist)
655 // pthread_mutex_timedlock. Identical logic to pthread_mutex_trylock.
656 PTH_FUNC(int, pthreadZumutexZutimedlock, // pthread_mutex_timedlock
657 pthread_mutex_t *mutex,
658 void* timeout)
660 int ret;
661 OrigFn fn;
662 VALGRIND_GET_ORIG_FN(fn);
663 if (TRACE_PTH_FNS) {
664 fprintf(stderr, "<< pthread_mxtimedlock %p %p", mutex, timeout);
665 fflush(stderr);
668 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
669 pthread_mutex_t*,mutex, long,1/*isTryLock-ish*/);
671 CALL_FN_W_WW(ret, fn, mutex,timeout);
673 /* There's a hole here: libpthread now knows the lock is locked,
674 but the tool doesn't, so some other thread could run and detect
675 that the lock has been acquired by someone (this thread). Does
676 this matter? Not sure, but I don't think so. */
678 if (ret == 0 /*success*/) {
679 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
680 pthread_mutex_t*,mutex);
681 } else {
682 if (ret != ETIMEDOUT)
683 DO_PthAPIerror( "pthread_mutex_timedlock", ret );
686 if (TRACE_PTH_FNS) {
687 fprintf(stderr, " :: mxtimedlock -> %d >>\n", ret);
689 return ret;
693 //-----------------------------------------------------------
694 // glibc: pthread_mutex_unlock
695 // darwin: pthread_mutex_unlock
696 PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock
697 pthread_mutex_t *mutex)
699 int ret;
700 OrigFn fn;
701 VALGRIND_GET_ORIG_FN(fn);
703 if (TRACE_PTH_FNS) {
704 fprintf(stderr, "<< pthread_mxunlk %p", mutex); fflush(stderr);
707 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
708 pthread_mutex_t*,mutex);
710 CALL_FN_W_W(ret, fn, mutex);
712 if (ret == 0 /*success*/) {
713 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
714 pthread_mutex_t*,mutex);
715 } else {
716 DO_PthAPIerror( "pthread_mutex_unlock", ret );
719 if (TRACE_PTH_FNS) {
720 fprintf(stderr, " mxunlk -> %d >>\n", ret);
722 return ret;
726 /*----------------------------------------------------------------*/
727 /*--- pthread_cond_t functions ---*/
728 /*----------------------------------------------------------------*/
730 /* Handled: pthread_cond_wait pthread_cond_timedwait
731 pthread_cond_signal pthread_cond_broadcast
732 pthread_cond_init
733 pthread_cond_destroy
736 //-----------------------------------------------------------
737 // glibc: pthread_cond_wait@GLIBC_2.2.5
738 // glibc: pthread_cond_wait@@GLIBC_2.3.2
739 // darwin: pthread_cond_wait
740 // darwin: pthread_cond_wait$NOCANCEL$UNIX2003
741 // darwin: pthread_cond_wait$UNIX2003
743 __attribute__((noinline))
744 static int pthread_cond_wait_WRK(pthread_cond_t* cond,
745 pthread_mutex_t* mutex)
747 int ret;
748 OrigFn fn;
749 unsigned long mutex_is_valid;
751 VALGRIND_GET_ORIG_FN(fn);
753 if (TRACE_PTH_FNS) {
754 fprintf(stderr, "<< pthread_cond_wait %p %p", cond, mutex);
755 fflush(stderr);
758 /* Tell the tool a cond-wait is about to happen, so it can check
759 for bogus argument values. In return it tells us whether it
760 thinks the mutex is valid or not. */
761 DO_CREQ_W_WW(mutex_is_valid,
762 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
763 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
764 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
766 /* Tell the tool we're about to drop the mutex. This reflects the
767 fact that in a cond_wait, we show up holding the mutex, and the
768 call atomically drops the mutex and waits for the cv to be
769 signalled. */
770 if (mutex_is_valid) {
771 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
772 pthread_mutex_t*,mutex);
775 CALL_FN_W_WW(ret, fn, cond,mutex);
777 /* these conditionals look stupid, but compare w/ same logic for
778 pthread_cond_timedwait below */
779 if (ret == 0 && mutex_is_valid) {
780 /* and now we have the mutex again */
781 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
782 pthread_mutex_t*,mutex);
785 if (ret == 0 && mutex_is_valid) {
786 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
787 pthread_cond_t*,cond, pthread_mutex_t*,mutex, long,0);
790 if (ret != 0) {
791 DO_PthAPIerror( "pthread_cond_wait", ret );
794 if (TRACE_PTH_FNS) {
795 fprintf(stderr, " cowait -> %d >>\n", ret);
798 return ret;
800 #if defined(VGO_linux)
801 PTH_FUNC(int, pthreadZucondZuwaitZAZa, // pthread_cond_wait@*
802 pthread_cond_t* cond, pthread_mutex_t* mutex) {
803 return pthread_cond_wait_WRK(cond, mutex);
805 #elif defined(VGO_darwin)
806 PTH_FUNC(int, pthreadZucondZuwaitZa, // pthread_cond_wait*
807 pthread_cond_t* cond, pthread_mutex_t* mutex) {
808 return pthread_cond_wait_WRK(cond, mutex);
810 #else
811 # error "Unsupported OS"
812 #endif
815 //-----------------------------------------------------------
816 // glibc: pthread_cond_timedwait@@GLIBC_2.3.2
817 // glibc: pthread_cond_timedwait@GLIBC_2.2.5
818 // glibc: pthread_cond_timedwait@GLIBC_2.0
819 // darwin: pthread_cond_timedwait
820 // darwin: pthread_cond_timedwait$NOCANCEL$UNIX2003
821 // darwin: pthread_cond_timedwait$UNIX2003
822 // darwin: pthread_cond_timedwait_relative_np (trapped)
824 __attribute__((noinline))
825 static int pthread_cond_timedwait_WRK(pthread_cond_t* cond,
826 pthread_mutex_t* mutex,
827 struct timespec* abstime)
829 int ret;
830 OrigFn fn;
831 unsigned long mutex_is_valid;
832 Bool abstime_is_valid;
833 VALGRIND_GET_ORIG_FN(fn);
835 if (TRACE_PTH_FNS) {
836 fprintf(stderr, "<< pthread_cond_timedwait %p %p %p",
837 cond, mutex, abstime);
838 fflush(stderr);
841 /* Tell the tool a cond-wait is about to happen, so it can check
842 for bogus argument values. In return it tells us whether it
843 thinks the mutex is valid or not. */
844 DO_CREQ_W_WW(mutex_is_valid,
845 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
846 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
847 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
849 abstime_is_valid = abstime->tv_nsec >= 0 && abstime->tv_nsec < 1000000000;
851 /* Tell the tool we're about to drop the mutex. This reflects the
852 fact that in a cond_wait, we show up holding the mutex, and the
853 call atomically drops the mutex and waits for the cv to be
854 signalled. */
855 if (mutex_is_valid && abstime_is_valid) {
856 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
857 pthread_mutex_t*,mutex);
860 CALL_FN_W_WWW(ret, fn, cond,mutex,abstime);
862 if (!abstime_is_valid && ret != EINVAL) {
863 DO_PthAPIerror("Bug in libpthread: pthread_cond_timedwait "
864 "invalid abstime did not cause"
865 " EINVAL", ret);
868 if ((ret == 0 || ret == ETIMEDOUT) && mutex_is_valid) {
869 /* and now we have the mutex again */
870 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
871 pthread_mutex_t*,mutex);
874 if ((ret == 0 || ret == ETIMEDOUT) && mutex_is_valid) {
875 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
876 pthread_cond_t*,cond, pthread_mutex_t*,mutex,
877 long,ret == ETIMEDOUT);
880 if (ret != 0 && ret != ETIMEDOUT) {
881 DO_PthAPIerror( "pthread_cond_timedwait", ret );
884 if (TRACE_PTH_FNS) {
885 fprintf(stderr, " cotimedwait -> %d >>\n", ret);
888 return ret;
890 #if defined(VGO_linux)
891 PTH_FUNC(int, pthreadZucondZutimedwaitZAZa, // pthread_cond_timedwait@*
892 pthread_cond_t* cond, pthread_mutex_t* mutex,
893 struct timespec* abstime) {
894 return pthread_cond_timedwait_WRK(cond, mutex, abstime);
896 #elif defined(VGO_darwin)
897 PTH_FUNC(int, pthreadZucondZutimedwait, // pthread_cond_timedwait
898 pthread_cond_t* cond, pthread_mutex_t* mutex,
899 struct timespec* abstime) {
900 return pthread_cond_timedwait_WRK(cond, mutex, abstime);
902 PTH_FUNC(int, pthreadZucondZutimedwaitZDZa, // pthread_cond_timedwait$*
903 pthread_cond_t* cond, pthread_mutex_t* mutex,
904 struct timespec* abstime) {
905 return pthread_cond_timedwait_WRK(cond, mutex, abstime);
907 PTH_FUNC(int, pthreadZucondZutimedwaitZuZa, // pthread_cond_timedwait_*
908 pthread_cond_t* cond, pthread_mutex_t* mutex,
909 struct timespec* abstime) {
910 assert(0);
912 #else
913 # error "Unsupported OS"
914 #endif
917 //-----------------------------------------------------------
918 // glibc: pthread_cond_signal@GLIBC_2.0
919 // glibc: pthread_cond_signal@GLIBC_2.2.5
920 // glibc: pthread_cond_signal@@GLIBC_2.3.2
921 // darwin: pthread_cond_signal
922 // darwin: pthread_cond_signal_thread_np (don't intercept this)
924 __attribute__((noinline))
925 static int pthread_cond_signal_WRK(pthread_cond_t* cond)
927 int ret;
928 OrigFn fn;
929 VALGRIND_GET_ORIG_FN(fn);
931 if (TRACE_PTH_FNS) {
932 fprintf(stderr, "<< pthread_cond_signal %p", cond);
933 fflush(stderr);
936 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE,
937 pthread_cond_t*,cond);
939 CALL_FN_W_W(ret, fn, cond);
941 if (ret != 0) {
942 DO_PthAPIerror( "pthread_cond_signal", ret );
945 if (TRACE_PTH_FNS) {
946 fprintf(stderr, " cosig -> %d >>\n", ret);
949 return ret;
951 #if defined(VGO_linux)
952 PTH_FUNC(int, pthreadZucondZusignalZAZa, // pthread_cond_signal@*
953 pthread_cond_t* cond) {
954 return pthread_cond_signal_WRK(cond);
956 #elif defined(VGO_darwin)
957 PTH_FUNC(int, pthreadZucondZusignal, // pthread_cond_signal
958 pthread_cond_t* cond) {
959 return pthread_cond_signal_WRK(cond);
961 #else
962 # error "Unsupported OS"
963 #endif
966 //-----------------------------------------------------------
967 // glibc: pthread_cond_broadcast@GLIBC_2.0
968 // glibc: pthread_cond_broadcast@GLIBC_2.2.5
969 // glibc: pthread_cond_broadcast@@GLIBC_2.3.2
970 // darwin: pthread_cond_broadcast
972 // Note, this is pretty much identical, from a dependency-graph
973 // point of view, with cond_signal, so the code is duplicated.
974 // Maybe it should be commoned up.
976 __attribute__((noinline))
977 static int pthread_cond_broadcast_WRK(pthread_cond_t* cond)
979 int ret;
980 OrigFn fn;
981 VALGRIND_GET_ORIG_FN(fn);
983 if (TRACE_PTH_FNS) {
984 fprintf(stderr, "<< pthread_cond_broadcast %p", cond);
985 fflush(stderr);
988 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE,
989 pthread_cond_t*,cond);
991 CALL_FN_W_W(ret, fn, cond);
993 if (ret != 0) {
994 DO_PthAPIerror( "pthread_cond_broadcast", ret );
997 if (TRACE_PTH_FNS) {
998 fprintf(stderr, " cobro -> %d >>\n", ret);
1001 return ret;
1003 #if defined(VGO_linux)
1004 PTH_FUNC(int, pthreadZucondZubroadcastZAZa, // pthread_cond_broadcast@*
1005 pthread_cond_t* cond) {
1006 return pthread_cond_broadcast_WRK(cond);
1008 #elif defined(VGO_darwin)
1009 PTH_FUNC(int, pthreadZucondZubroadcast, // pthread_cond_broadcast
1010 pthread_cond_t* cond) {
1011 return pthread_cond_broadcast_WRK(cond);
1013 #else
1014 # error "Unsupported OS"
1015 #endif
1017 // glibc: pthread_cond_init@GLIBC_2.0
1018 // glibc: pthread_cond_init@GLIBC_2.2.5
1019 // glibc: pthread_cond_init@@GLIBC_2.3.2
1020 // darwin: pthread_cond_init
1021 // Easy way out: Handling of attr could have been messier.
1022 // It turns out that pthread_cond_init under linux ignores
1023 // all information in cond_attr, so do we.
1024 // FIXME: MacOS X?
1025 __attribute__((noinline))
1026 static int pthread_cond_init_WRK(pthread_cond_t* cond, pthread_condattr_t *cond_attr)
1028 int ret;
1029 OrigFn fn;
1030 VALGRIND_GET_ORIG_FN(fn);
1032 if (TRACE_PTH_FNS) {
1033 fprintf(stderr, "<< pthread_cond_init %p", cond);
1034 fflush(stderr);
1037 CALL_FN_W_WW(ret, fn, cond, cond_attr);
1039 if (ret == 0) {
1040 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST,
1041 pthread_cond_t*,cond, pthread_condattr_t*, cond_attr);
1042 } else {
1043 DO_PthAPIerror( "pthread_cond_init", ret );
1046 if (TRACE_PTH_FNS) {
1047 fprintf(stderr, " coinit -> %d >>\n", ret);
1050 return ret;
1052 #if defined(VGO_linux)
1053 PTH_FUNC(int, pthreadZucondZuinitZAZa, // pthread_cond_init@*
1054 pthread_cond_t* cond, pthread_condattr_t* cond_attr) {
1055 return pthread_cond_init_WRK(cond, cond_attr);
1057 #elif defined(VGO_darwin)
1058 PTH_FUNC(int, pthreadZucondZuinit, // pthread_cond_init
1059 pthread_cond_t* cond, pthread_condattr_t * cond_attr) {
1060 return pthread_cond_init_WRK(cond, cond_attr);
1062 #else
1063 # error "Unsupported OS"
1064 #endif
1067 //-----------------------------------------------------------
1068 // glibc: pthread_cond_destroy@@GLIBC_2.3.2
1069 // glibc: pthread_cond_destroy@GLIBC_2.2.5
1070 // glibc: pthread_cond_destroy@GLIBC_2.0
1071 // darwin: pthread_cond_destroy
1073 __attribute__((noinline))
1074 static int pthread_cond_destroy_WRK(pthread_cond_t* cond)
1076 int ret;
1077 unsigned long cond_is_init;
1078 OrigFn fn;
1080 VALGRIND_GET_ORIG_FN(fn);
1082 if (TRACE_PTH_FNS) {
1083 fprintf(stderr, "<< pthread_cond_destroy %p", cond);
1084 fflush(stderr);
1087 if (cond != NULL) {
1088 const pthread_cond_t cond_init = PTHREAD_COND_INITIALIZER;
1089 cond_is_init = my_memcmp(cond, &cond_init, sizeof(*cond)) == 0;
1090 } else {
1091 cond_is_init = 0;
1094 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_DESTROY_PRE,
1095 pthread_cond_t*, cond, unsigned long, cond_is_init);
1097 CALL_FN_W_W(ret, fn, cond);
1099 if (ret != 0) {
1100 DO_PthAPIerror( "pthread_cond_destroy", ret );
1103 if (TRACE_PTH_FNS) {
1104 fprintf(stderr, " codestr -> %d >>\n", ret);
1107 return ret;
1109 #if defined(VGO_linux)
1110 PTH_FUNC(int, pthreadZucondZudestroyZAZa, // pthread_cond_destroy@*
1111 pthread_cond_t* cond) {
1112 return pthread_cond_destroy_WRK(cond);
1114 #elif defined(VGO_darwin)
1115 PTH_FUNC(int, pthreadZucondZudestroy, // pthread_cond_destroy
1116 pthread_cond_t* cond) {
1117 return pthread_cond_destroy_WRK(cond);
1119 #else
1120 # error "Unsupported OS"
1121 #endif
1124 /*----------------------------------------------------------------*/
1125 /*--- pthread_barrier_t functions ---*/
1126 /*----------------------------------------------------------------*/
1128 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1130 /* Handled: pthread_barrier_init
1131 pthread_barrier_wait
1132 pthread_barrier_destroy
1134 Unhandled: pthread_barrierattr_destroy
1135 pthread_barrierattr_getpshared
1136 pthread_barrierattr_init
1137 pthread_barrierattr_setpshared
1138 -- are these important?
1141 //-----------------------------------------------------------
1142 // glibc: pthread_barrier_init
1143 // darwin: (doesn't appear to exist)
1144 PTH_FUNC(int, pthreadZubarrierZuinit, // pthread_barrier_init
1145 pthread_barrier_t* bar,
1146 pthread_barrierattr_t* attr, unsigned long count)
1148 int ret;
1149 OrigFn fn;
1150 VALGRIND_GET_ORIG_FN(fn);
1152 if (TRACE_PTH_FNS) {
1153 fprintf(stderr, "<< pthread_barrier_init %p %p %lu",
1154 bar, attr, count);
1155 fflush(stderr);
1158 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE,
1159 pthread_barrier_t*, bar,
1160 unsigned long, count,
1161 unsigned long, 0/*!resizable*/);
1163 CALL_FN_W_WWW(ret, fn, bar,attr,count);
1165 if (ret != 0) {
1166 DO_PthAPIerror( "pthread_barrier_init", ret );
1169 if (TRACE_PTH_FNS) {
1170 fprintf(stderr, " pthread_barrier_init -> %d >>\n", ret);
1173 return ret;
1177 //-----------------------------------------------------------
1178 // glibc: pthread_barrier_wait
1179 // darwin: (doesn't appear to exist)
1180 PTH_FUNC(int, pthreadZubarrierZuwait, // pthread_barrier_wait
1181 pthread_barrier_t* bar)
1183 int ret;
1184 OrigFn fn;
1185 VALGRIND_GET_ORIG_FN(fn);
1187 if (TRACE_PTH_FNS) {
1188 fprintf(stderr, "<< pthread_barrier_wait %p", bar);
1189 fflush(stderr);
1192 /* That this works correctly, and doesn't screw up when a thread
1193 leaving the barrier races round to the front and re-enters while
1194 other threads are still leaving it, is quite subtle. See
1195 comments in the handler for PTHREAD_BARRIER_WAIT_PRE in
1196 hg_main.c. */
1197 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE,
1198 pthread_barrier_t*,bar);
1200 CALL_FN_W_W(ret, fn, bar);
1202 if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) {
1203 DO_PthAPIerror( "pthread_barrier_wait", ret );
1206 if (TRACE_PTH_FNS) {
1207 fprintf(stderr, " pthread_barrier_wait -> %d >>\n", ret);
1210 return ret;
1214 //-----------------------------------------------------------
1215 // glibc: pthread_barrier_destroy
1216 // darwin: (doesn't appear to exist)
1217 PTH_FUNC(int, pthreadZubarrierZudestroy, // pthread_barrier_destroy
1218 pthread_barrier_t* bar)
1220 int ret;
1221 OrigFn fn;
1222 VALGRIND_GET_ORIG_FN(fn);
1224 if (TRACE_PTH_FNS) {
1225 fprintf(stderr, "<< pthread_barrier_destroy %p", bar);
1226 fflush(stderr);
1229 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE,
1230 pthread_barrier_t*,bar);
1232 CALL_FN_W_W(ret, fn, bar);
1234 if (ret != 0) {
1235 DO_PthAPIerror( "pthread_barrier_destroy", ret );
1238 if (TRACE_PTH_FNS) {
1239 fprintf(stderr, " pthread_barrier_destroy -> %d >>\n", ret);
1242 return ret;
1245 #endif // defined(HAVE_PTHREAD_BARRIER_INIT)
1248 /*----------------------------------------------------------------*/
1249 /*--- pthread_spinlock_t functions ---*/
1250 /*----------------------------------------------------------------*/
1252 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1253 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1255 /* Handled: pthread_spin_init pthread_spin_destroy
1256 pthread_spin_lock pthread_spin_trylock
1257 pthread_spin_unlock
1259 Unhandled:
1262 /* This is a nasty kludge, in that glibc "knows" that initialising a
1263 spin lock unlocks it, and pthread_spin_{init,unlock} are names for
1264 the same function. Hence we have to have a wrapper which does both
1265 things, without knowing which the user intended to happen. */
1267 //-----------------------------------------------------------
1268 // glibc: pthread_spin_init
1269 // glibc: pthread_spin_unlock
1270 // darwin: (doesn't appear to exist)
1271 __attribute__((noinline))
1272 static int pthread_spin_init_or_unlock_WRK(pthread_spinlock_t* lock,
1273 int pshared) {
1274 int ret;
1275 OrigFn fn;
1276 VALGRIND_GET_ORIG_FN(fn);
1277 if (TRACE_PTH_FNS) {
1278 fprintf(stderr, "<< pthread_spin_iORu %p", lock); fflush(stderr);
1281 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE,
1282 pthread_spinlock_t*, lock);
1284 CALL_FN_W_WW(ret, fn, lock,pshared);
1286 if (ret == 0 /*success*/) {
1287 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST,
1288 pthread_spinlock_t*,lock);
1289 } else {
1290 DO_PthAPIerror( "pthread_spinlock_{init,unlock}", ret );
1293 if (TRACE_PTH_FNS) {
1294 fprintf(stderr, " :: spiniORu -> %d >>\n", ret);
1296 return ret;
1298 #if defined(VGO_linux)
1299 PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
1300 pthread_spinlock_t* lock, int pshared) {
1301 return pthread_spin_init_or_unlock_WRK(lock, pshared);
1303 PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
1304 pthread_spinlock_t* lock) {
1305 /* this is never actually called */
1306 return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/);
1308 #elif defined(VGO_darwin)
1309 #else
1310 # error "Unsupported OS"
1311 #endif
1314 //-----------------------------------------------------------
1315 // glibc: pthread_spin_destroy
1316 // darwin: (doesn't appear to exist)
1317 #if defined(VGO_linux)
1319 PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy
1320 pthread_spinlock_t* lock)
1322 int ret;
1323 OrigFn fn;
1324 VALGRIND_GET_ORIG_FN(fn);
1325 if (TRACE_PTH_FNS) {
1326 fprintf(stderr, "<< pthread_spin_destroy %p", lock);
1327 fflush(stderr);
1330 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_DESTROY_PRE,
1331 pthread_spinlock_t*,lock);
1333 CALL_FN_W_W(ret, fn, lock);
1335 if (ret != 0) {
1336 DO_PthAPIerror( "pthread_spin_destroy", ret );
1339 if (TRACE_PTH_FNS) {
1340 fprintf(stderr, " :: spindestroy -> %d >>\n", ret);
1342 return ret;
1345 #elif defined(VGO_darwin)
1346 #else
1347 # error "Unsupported OS"
1348 #endif
1351 //-----------------------------------------------------------
1352 // glibc: pthread_spin_lock
1353 // darwin: (doesn't appear to exist)
1354 #if defined(VGO_linux)
1356 PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
1357 pthread_spinlock_t* lock)
1359 int ret;
1360 OrigFn fn;
1361 VALGRIND_GET_ORIG_FN(fn);
1362 if (TRACE_PTH_FNS) {
1363 fprintf(stderr, "<< pthread_spinlock %p", lock);
1364 fflush(stderr);
1367 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE,
1368 pthread_spinlock_t*,lock, long,0/*!isTryLock*/);
1370 CALL_FN_W_W(ret, fn, lock);
1372 /* There's a hole here: libpthread now knows the lock is locked,
1373 but the tool doesn't, so some other thread could run and detect
1374 that the lock has been acquired by someone (this thread). Does
1375 this matter? Not sure, but I don't think so. */
1377 if (ret == 0 /*success*/) {
1378 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST,
1379 pthread_spinlock_t*,lock);
1380 } else {
1381 DO_PthAPIerror( "pthread_spin_lock", ret );
1384 if (TRACE_PTH_FNS) {
1385 fprintf(stderr, " :: spinlock -> %d >>\n", ret);
1387 return ret;
1390 #elif defined(VGO_darwin)
1391 #else
1392 # error "Unsupported OS"
1393 #endif
1396 //-----------------------------------------------------------
1397 // glibc: pthread_spin_trylock
1398 // darwin: (doesn't appear to exist)
1399 #if defined(VGO_linux)
1401 PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
1402 pthread_spinlock_t* lock)
1404 int ret;
1405 OrigFn fn;
1406 VALGRIND_GET_ORIG_FN(fn);
1407 if (TRACE_PTH_FNS) {
1408 fprintf(stderr, "<< pthread_spin_trylock %p", lock);
1409 fflush(stderr);
1412 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE,
1413 pthread_spinlock_t*,lock, long,1/*isTryLock*/);
1415 CALL_FN_W_W(ret, fn, lock);
1417 /* There's a hole here: libpthread now knows the lock is locked,
1418 but the tool doesn't, so some other thread could run and detect
1419 that the lock has been acquired by someone (this thread). Does
1420 this matter? Not sure, but I don't think so. */
1422 if (ret == 0 /*success*/) {
1423 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST,
1424 pthread_spinlock_t*,lock);
1425 } else {
1426 if (ret != EBUSY)
1427 DO_PthAPIerror( "pthread_spin_trylock", ret );
1430 if (TRACE_PTH_FNS) {
1431 fprintf(stderr, " :: spin_trylock -> %d >>\n", ret);
1433 return ret;
1436 #elif defined(VGO_darwin)
1437 #else
1438 # error "Unsupported OS"
1439 #endif
1441 #endif // defined(HAVE_PTHREAD_SPIN_LOCK)
1444 /*----------------------------------------------------------------*/
1445 /*--- pthread_rwlock_t functions ---*/
1446 /*----------------------------------------------------------------*/
1448 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1449 functions have to be conditionally compiled. */
1450 #if defined(HAVE_PTHREAD_RWLOCK_T)
1452 /* Handled: pthread_rwlock_init pthread_rwlock_destroy
1453 pthread_rwlock_rdlock
1454 pthread_rwlock_wrlock
1455 pthread_rwlock_unlock
1457 Unhandled: pthread_rwlock_timedrdlock
1458 pthread_rwlock_tryrdlock
1460 pthread_rwlock_timedwrlock
1461 pthread_rwlock_trywrlock
1464 //-----------------------------------------------------------
1465 // glibc: pthread_rwlock_init
1466 // darwin: pthread_rwlock_init
1467 // darwin: pthread_rwlock_init$UNIX2003
1468 __attribute__((noinline))
1469 static int pthread_rwlock_init_WRK(pthread_rwlock_t *rwl,
1470 pthread_rwlockattr_t* attr)
1472 int ret;
1473 OrigFn fn;
1474 VALGRIND_GET_ORIG_FN(fn);
1475 if (TRACE_PTH_FNS) {
1476 fprintf(stderr, "<< pthread_rwl_init %p", rwl); fflush(stderr);
1479 CALL_FN_W_WW(ret, fn, rwl,attr);
1481 if (ret == 0 /*success*/) {
1482 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
1483 pthread_rwlock_t*,rwl);
1484 } else {
1485 DO_PthAPIerror( "pthread_rwlock_init", ret );
1488 if (TRACE_PTH_FNS) {
1489 fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
1491 return ret;
1493 #if defined(VGO_linux)
1494 PTH_FUNC(int, pthreadZurwlockZuinit, // pthread_rwlock_init
1495 pthread_rwlock_t *rwl,
1496 pthread_rwlockattr_t* attr) {
1497 return pthread_rwlock_init_WRK(rwl, attr);
1499 #elif defined(VGO_darwin)
1500 PTH_FUNC(int, pthreadZurwlockZuinitZa, // pthread_rwlock_init*
1501 pthread_rwlock_t *rwl,
1502 pthread_rwlockattr_t* attr) {
1503 return pthread_rwlock_init_WRK(rwl, attr);
1505 #else
1506 # error "Unsupported OS"
1507 #endif
1510 //-----------------------------------------------------------
1511 // glibc: pthread_rwlock_destroy
1512 // darwin: pthread_rwlock_destroy
1513 // darwin: pthread_rwlock_destroy$UNIX2003
1515 __attribute__((noinline))
1516 static int pthread_rwlock_destroy_WRK(pthread_rwlock_t* rwl)
1518 int ret;
1519 OrigFn fn;
1520 VALGRIND_GET_ORIG_FN(fn);
1521 if (TRACE_PTH_FNS) {
1522 fprintf(stderr, "<< pthread_rwl_destroy %p", rwl); fflush(stderr);
1525 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE,
1526 pthread_rwlock_t*,rwl);
1528 CALL_FN_W_W(ret, fn, rwl);
1530 if (ret != 0) {
1531 DO_PthAPIerror( "pthread_rwlock_destroy", ret );
1534 if (TRACE_PTH_FNS) {
1535 fprintf(stderr, " :: rwl_destroy -> %d >>\n", ret);
1537 return ret;
1539 #if defined(VGO_linux)
1540 PTH_FUNC(int, pthreadZurwlockZudestroy, // pthread_rwlock_destroy
1541 pthread_rwlock_t *rwl) {
1542 return pthread_rwlock_destroy_WRK(rwl);
1544 #elif defined(VGO_darwin)
1545 PTH_FUNC(int, pthreadZurwlockZudestroyZa, // pthread_rwlock_destroy*
1546 pthread_rwlock_t *rwl) {
1547 return pthread_rwlock_destroy_WRK(rwl);
1549 #else
1550 # error "Unsupported OS"
1551 #endif
1554 //-----------------------------------------------------------
1555 // glibc: pthread_rwlock_wrlock
1556 // darwin: pthread_rwlock_wrlock
1557 // darwin: pthread_rwlock_wrlock$UNIX2003
1559 __attribute__((noinline))
1560 static int pthread_rwlock_wrlock_WRK(pthread_rwlock_t* rwlock)
1562 int ret;
1563 OrigFn fn;
1564 VALGRIND_GET_ORIG_FN(fn);
1565 if (TRACE_PTH_FNS) {
1566 fprintf(stderr, "<< pthread_rwl_wlk %p", rwlock); fflush(stderr);
1569 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1570 pthread_rwlock_t*,rwlock,
1571 long,1/*isW*/, long,0/*!isTryLock*/);
1573 CALL_FN_W_W(ret, fn, rwlock);
1575 if (ret == 0 /*success*/) {
1576 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1577 pthread_rwlock_t*,rwlock, long,1/*isW*/);
1578 } else {
1579 DO_PthAPIerror( "pthread_rwlock_wrlock", ret );
1582 if (TRACE_PTH_FNS) {
1583 fprintf(stderr, " :: rwl_wlk -> %d >>\n", ret);
1585 return ret;
1587 #if defined(VGO_linux)
1588 PTH_FUNC(int, pthreadZurwlockZuwrlock, // pthread_rwlock_wrlock
1589 pthread_rwlock_t* rwlock) {
1590 return pthread_rwlock_wrlock_WRK(rwlock);
1592 #elif defined(VGO_darwin)
1593 PTH_FUNC(int, pthreadZurwlockZuwrlockZa, // pthread_rwlock_wrlock*
1594 pthread_rwlock_t* rwlock) {
1595 return pthread_rwlock_wrlock_WRK(rwlock);
1597 #else
1598 # error "Unsupported OS"
1599 #endif
1602 //-----------------------------------------------------------
1603 // glibc: pthread_rwlock_rdlock
1604 // darwin: pthread_rwlock_rdlock
1605 // darwin: pthread_rwlock_rdlock$UNIX2003
1607 __attribute__((noinline))
1608 static int pthread_rwlock_rdlock_WRK(pthread_rwlock_t* rwlock)
1610 int ret;
1611 OrigFn fn;
1612 VALGRIND_GET_ORIG_FN(fn);
1613 if (TRACE_PTH_FNS) {
1614 fprintf(stderr, "<< pthread_rwl_rlk %p", rwlock); fflush(stderr);
1617 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1618 pthread_rwlock_t*,rwlock,
1619 long,0/*!isW*/, long,0/*!isTryLock*/);
1621 CALL_FN_W_W(ret, fn, rwlock);
1623 if (ret == 0 /*success*/) {
1624 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1625 pthread_rwlock_t*,rwlock, long,0/*!isW*/);
1626 } else {
1627 DO_PthAPIerror( "pthread_rwlock_rdlock", ret );
1630 if (TRACE_PTH_FNS) {
1631 fprintf(stderr, " :: rwl_rlk -> %d >>\n", ret);
1633 return ret;
1635 #if defined(VGO_linux)
1636 PTH_FUNC(int, pthreadZurwlockZurdlock, // pthread_rwlock_rdlock
1637 pthread_rwlock_t* rwlock) {
1638 return pthread_rwlock_rdlock_WRK(rwlock);
1640 #elif defined(VGO_darwin)
1641 PTH_FUNC(int, pthreadZurwlockZurdlockZa, // pthread_rwlock_rdlock*
1642 pthread_rwlock_t* rwlock) {
1643 return pthread_rwlock_rdlock_WRK(rwlock);
1645 #else
1646 # error "Unsupported OS"
1647 #endif
1650 //-----------------------------------------------------------
1651 // glibc: pthread_rwlock_trywrlock
1652 // darwin: pthread_rwlock_trywrlock
1653 // darwin: pthread_rwlock_trywrlock$UNIX2003
1655 __attribute__((noinline))
1656 static int pthread_rwlock_trywrlock_WRK(pthread_rwlock_t* rwlock)
1658 int ret;
1659 OrigFn fn;
1660 VALGRIND_GET_ORIG_FN(fn);
1661 if (TRACE_PTH_FNS) {
1662 fprintf(stderr, "<< pthread_rwl_trywlk %p", rwlock); fflush(stderr);
1665 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1666 pthread_rwlock_t*,rwlock,
1667 long,1/*isW*/, long,1/*isTryLock*/);
1669 CALL_FN_W_W(ret, fn, rwlock);
1671 /* There's a hole here: libpthread now knows the lock is locked,
1672 but the tool doesn't, so some other thread could run and detect
1673 that the lock has been acquired by someone (this thread). Does
1674 this matter? Not sure, but I don't think so. */
1676 if (ret == 0 /*success*/) {
1677 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1678 pthread_rwlock_t*,rwlock, long,1/*isW*/);
1679 } else {
1680 if (ret != EBUSY)
1681 DO_PthAPIerror( "pthread_rwlock_trywrlock", ret );
1684 if (TRACE_PTH_FNS) {
1685 fprintf(stderr, " :: rwl_trywlk -> %d >>\n", ret);
1687 return ret;
1689 #if defined(VGO_linux)
1690 PTH_FUNC(int, pthreadZurwlockZutrywrlock, // pthread_rwlock_trywrlock
1691 pthread_rwlock_t* rwlock) {
1692 return pthread_rwlock_trywrlock_WRK(rwlock);
1694 #elif defined(VGO_darwin)
1695 PTH_FUNC(int, pthreadZurwlockZutrywrlockZa, // pthread_rwlock_trywrlock*
1696 pthread_rwlock_t* rwlock) {
1697 return pthread_rwlock_trywrlock_WRK(rwlock);
1699 #else
1700 # error "Unsupported OS"
1701 #endif
1704 //-----------------------------------------------------------
1705 // glibc: pthread_rwlock_tryrdlock
1706 // darwin: pthread_rwlock_trywrlock
1707 // darwin: pthread_rwlock_trywrlock$UNIX2003
1709 __attribute__((noinline))
1710 static int pthread_rwlock_tryrdlock_WRK(pthread_rwlock_t* rwlock)
1712 int ret;
1713 OrigFn fn;
1714 VALGRIND_GET_ORIG_FN(fn);
1715 if (TRACE_PTH_FNS) {
1716 fprintf(stderr, "<< pthread_rwl_tryrlk %p", rwlock); fflush(stderr);
1719 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1720 pthread_rwlock_t*,rwlock,
1721 long,0/*!isW*/, long,1/*isTryLock*/);
1723 CALL_FN_W_W(ret, fn, rwlock);
1725 /* There's a hole here: libpthread now knows the lock is locked,
1726 but the tool doesn't, so some other thread could run and detect
1727 that the lock has been acquired by someone (this thread). Does
1728 this matter? Not sure, but I don't think so. */
1730 if (ret == 0 /*success*/) {
1731 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1732 pthread_rwlock_t*,rwlock, long,0/*!isW*/);
1733 } else {
1734 if (ret != EBUSY)
1735 DO_PthAPIerror( "pthread_rwlock_tryrdlock", ret );
1738 if (TRACE_PTH_FNS) {
1739 fprintf(stderr, " :: rwl_tryrlk -> %d >>\n", ret);
1741 return ret;
1743 #if defined(VGO_linux)
1744 PTH_FUNC(int, pthreadZurwlockZutryrdlock, // pthread_rwlock_tryrdlock
1745 pthread_rwlock_t* rwlock) {
1746 return pthread_rwlock_tryrdlock_WRK(rwlock);
1748 #elif defined(VGO_darwin)
1749 PTH_FUNC(int, pthreadZurwlockZutryrdlockZa, // pthread_rwlock_tryrdlock*
1750 pthread_rwlock_t* rwlock) {
1751 return pthread_rwlock_tryrdlock_WRK(rwlock);
1753 #else
1754 # error "Unsupported OS"
1755 #endif
1758 //-----------------------------------------------------------
1759 // glibc: pthread_rwlock_unlock
1760 // darwin: pthread_rwlock_unlock
1761 // darwin: pthread_rwlock_unlock$UNIX2003
1762 __attribute__((noinline))
1763 static int pthread_rwlock_unlock_WRK(pthread_rwlock_t* rwlock)
1765 int ret;
1766 OrigFn fn;
1767 VALGRIND_GET_ORIG_FN(fn);
1768 if (TRACE_PTH_FNS) {
1769 fprintf(stderr, "<< pthread_rwl_unlk %p", rwlock); fflush(stderr);
1772 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
1773 pthread_rwlock_t*,rwlock);
1775 CALL_FN_W_W(ret, fn, rwlock);
1777 if (ret == 0 /*success*/) {
1778 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
1779 pthread_rwlock_t*,rwlock);
1780 } else {
1781 DO_PthAPIerror( "pthread_rwlock_unlock", ret );
1784 if (TRACE_PTH_FNS) {
1785 fprintf(stderr, " :: rwl_unlk -> %d >>\n", ret);
1787 return ret;
1789 #if defined(VGO_linux)
1790 PTH_FUNC(int, pthreadZurwlockZuunlock, // pthread_rwlock_unlock
1791 pthread_rwlock_t* rwlock) {
1792 return pthread_rwlock_unlock_WRK(rwlock);
1794 #elif defined(VGO_darwin)
1795 PTH_FUNC(int, pthreadZurwlockZuunlockZa, // pthread_rwlock_unlock*
1796 pthread_rwlock_t* rwlock) {
1797 return pthread_rwlock_unlock_WRK(rwlock);
1799 #else
1800 # error "Unsupported OS"
1801 #endif
1803 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
1806 /*----------------------------------------------------------------*/
1807 /*--- POSIX semaphores ---*/
1808 /*----------------------------------------------------------------*/
1810 #include <semaphore.h>
1811 #include <fcntl.h> /* O_CREAT */
1813 #define TRACE_SEM_FNS 0
1815 /* Handled:
1816 int sem_init(sem_t *sem, int pshared, unsigned value);
1817 int sem_destroy(sem_t *sem);
1818 int sem_wait(sem_t *sem);
1819 int sem_post(sem_t *sem);
1820 sem_t* sem_open(const char *name, int oflag,
1821 ... [mode_t mode, unsigned value]);
1822 [complete with its idiotic semantics]
1823 int sem_close(sem_t* sem);
1825 Unhandled:
1826 int sem_trywait(sem_t *sem);
1827 int sem_timedwait(sem_t *restrict sem,
1828 const struct timespec *restrict abs_timeout);
1831 //-----------------------------------------------------------
1832 // glibc: sem_init@@GLIBC_2.2.5
1833 // glibc: sem_init@@GLIBC_2.1
1834 // glibc: sem_init@GLIBC_2.0
1835 // darwin: sem_init
1837 __attribute__((noinline))
1838 static int sem_init_WRK(sem_t* sem, int pshared, unsigned long value)
1840 OrigFn fn;
1841 int ret;
1842 VALGRIND_GET_ORIG_FN(fn);
1844 if (TRACE_SEM_FNS) {
1845 fprintf(stderr, "<< sem_init(%p,%d,%lu) ", sem,pshared,value);
1846 fflush(stderr);
1849 CALL_FN_W_WWW(ret, fn, sem,pshared,value);
1851 if (ret == 0) {
1852 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
1853 sem_t*, sem, unsigned long, value);
1854 } else {
1855 DO_PthAPIerror( "sem_init", errno );
1858 if (TRACE_SEM_FNS) {
1859 fprintf(stderr, " sem_init -> %d >>\n", ret);
1860 fflush(stderr);
1863 return ret;
1865 #if defined(VGO_linux)
1866 PTH_FUNC(int, semZuinitZAZa, // sem_init@*
1867 sem_t* sem, int pshared, unsigned long value) {
1868 return sem_init_WRK(sem, pshared, value);
1870 #elif defined(VGO_darwin)
1871 PTH_FUNC(int, semZuinit, // sem_init
1872 sem_t* sem, int pshared, unsigned long value) {
1873 return sem_init_WRK(sem, pshared, value);
1875 #else
1876 # error "Unsupported OS"
1877 #endif
1880 //-----------------------------------------------------------
1881 // glibc: sem_destroy@GLIBC_2.0
1882 // glibc: sem_destroy@@GLIBC_2.1
1883 // glibc: sem_destroy@@GLIBC_2.2.5
1884 // darwin: sem_destroy
1885 __attribute__((noinline))
1886 static int sem_destroy_WRK(sem_t* sem)
1888 OrigFn fn;
1889 int ret;
1890 VALGRIND_GET_ORIG_FN(fn);
1892 if (TRACE_SEM_FNS) {
1893 fprintf(stderr, "<< sem_destroy(%p) ", sem);
1894 fflush(stderr);
1897 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
1899 CALL_FN_W_W(ret, fn, sem);
1901 if (ret != 0) {
1902 DO_PthAPIerror( "sem_destroy", errno );
1905 if (TRACE_SEM_FNS) {
1906 fprintf(stderr, " sem_destroy -> %d >>\n", ret);
1907 fflush(stderr);
1910 return ret;
1912 #if defined(VGO_linux)
1913 PTH_FUNC(int, semZudestroyZAZa, // sem_destroy*
1914 sem_t* sem) {
1915 return sem_destroy_WRK(sem);
1917 #elif defined(VGO_darwin)
1918 PTH_FUNC(int, semZudestroy, // sem_destroy
1919 sem_t* sem) {
1920 return sem_destroy_WRK(sem);
1922 #else
1923 # error "Unsupported OS"
1924 #endif
1927 //-----------------------------------------------------------
1928 // glibc: sem_wait
1929 // glibc: sem_wait@GLIBC_2.0
1930 // glibc: sem_wait@@GLIBC_2.1
1931 // darwin: sem_wait
1932 // darwin: sem_wait$NOCANCEL$UNIX2003
1933 // darwin: sem_wait$UNIX2003
1935 /* wait: decrement semaphore - acquire lockage */
1936 __attribute__((noinline))
1937 static int sem_wait_WRK(sem_t* sem)
1939 OrigFn fn;
1940 int ret;
1941 VALGRIND_GET_ORIG_FN(fn);
1943 if (TRACE_SEM_FNS) {
1944 fprintf(stderr, "<< sem_wait(%p) ", sem);
1945 fflush(stderr);
1948 CALL_FN_W_W(ret, fn, sem);
1950 if (ret == 0) {
1951 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST, sem_t*,sem);
1952 } else {
1953 DO_PthAPIerror( "sem_wait", errno );
1956 if (TRACE_SEM_FNS) {
1957 fprintf(stderr, " sem_wait -> %d >>\n", ret);
1958 fflush(stderr);
1961 return ret;
1963 #if defined(VGO_linux)
1964 PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
1965 return sem_wait_WRK(sem);
1967 PTH_FUNC(int, semZuwaitZAZa, sem_t* sem) { /* sem_wait@* */
1968 return sem_wait_WRK(sem);
1970 #elif defined(VGO_darwin)
1971 PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
1972 return sem_wait_WRK(sem);
1974 PTH_FUNC(int, semZuwaitZDZa, sem_t* sem) { /* sem_wait$* */
1975 return sem_wait_WRK(sem);
1977 #else
1978 # error "Unsupported OS"
1979 #endif
1982 //-----------------------------------------------------------
1983 // glibc: sem_post
1984 // glibc: sem_post@GLIBC_2.0
1985 // glibc: sem_post@@GLIBC_2.1
1986 // darwin: sem_post
1988 /* post: increment semaphore - release lockage */
1989 __attribute__((noinline))
1990 static int sem_post_WRK(sem_t* sem)
1992 OrigFn fn;
1993 int ret;
1995 VALGRIND_GET_ORIG_FN(fn);
1997 if (TRACE_SEM_FNS) {
1998 fprintf(stderr, "<< sem_post(%p) ", sem);
1999 fflush(stderr);
2002 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_PRE, sem_t*,sem);
2004 CALL_FN_W_W(ret, fn, sem);
2006 if (ret != 0) {
2007 DO_PthAPIerror( "sem_post", errno );
2010 if (TRACE_SEM_FNS) {
2011 fprintf(stderr, " sem_post -> %d >>\n", ret);
2012 fflush(stderr);
2015 return ret;
2017 #if defined(VGO_linux)
2018 PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
2019 return sem_post_WRK(sem);
2021 PTH_FUNC(int, semZupostZAZa, sem_t* sem) { /* sem_post@* */
2022 return sem_post_WRK(sem);
2024 #elif defined(VGO_darwin)
2025 PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
2026 return sem_post_WRK(sem);
2028 #else
2029 # error "Unsupported OS"
2030 #endif
2033 //-----------------------------------------------------------
2034 // glibc: sem_open
2035 // darwin: sem_open
2037 PTH_FUNC(sem_t*, semZuopen,
2038 const char* name, long oflag,
2039 long mode, unsigned long value)
2041 /* A copy of sem_init_WRK (more or less). Is this correct? */
2042 OrigFn fn;
2043 sem_t* ret;
2044 VALGRIND_GET_ORIG_FN(fn);
2046 if (TRACE_SEM_FNS) {
2047 fprintf(stderr, "<< sem_open(\"%s\",%ld,%lx,%lu) ",
2048 name,oflag,mode,value);
2049 fflush(stderr);
2052 CALL_FN_W_WWWW(ret, fn, name,oflag,mode,value);
2054 if (ret != SEM_FAILED && (oflag & O_CREAT)) {
2055 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
2056 sem_t*, ret, unsigned long, value);
2058 if (ret == SEM_FAILED) {
2059 DO_PthAPIerror( "sem_open", errno );
2062 if (TRACE_SEM_FNS) {
2063 fprintf(stderr, " sem_open -> %p >>\n", ret);
2064 fflush(stderr);
2067 return ret;
2071 //-----------------------------------------------------------
2072 // glibc: sem_close
2073 // darwin: sem_close
2074 PTH_FUNC(int, sem_close, sem_t* sem)
2076 OrigFn fn;
2077 int ret;
2078 VALGRIND_GET_ORIG_FN(fn);
2080 if (TRACE_SEM_FNS) {
2081 fprintf(stderr, "<< sem_close(%p) ", sem);
2082 fflush(stderr);
2085 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
2087 CALL_FN_W_W(ret, fn, sem);
2089 if (ret != 0) {
2090 DO_PthAPIerror( "sem_close", errno );
2093 if (TRACE_SEM_FNS) {
2094 fprintf(stderr, " close -> %d >>\n", ret);
2095 fflush(stderr);
2098 return ret;
2102 /*----------------------------------------------------------------*/
2103 /*--- Qt 4 threading functions (w/ GNU name mangling) ---*/
2104 /*----------------------------------------------------------------*/
2106 /* Handled:
2107 QMutex::lock()
2108 QMutex::unlock()
2109 QMutex::tryLock()
2110 QMutex::tryLock(int)
2112 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC1ENS_13RecursionModeE
2113 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC2ENS_13RecursionModeE
2114 QMutex::~QMutex() _ZN6QMutexD1Ev
2115 QMutex::~QMutex() _ZN6QMutexD2Ev
2117 Unhandled:
2118 QReadWriteLock::lockForRead()
2119 QReadWriteLock::lockForWrite()
2120 QReadWriteLock::unlock()
2121 QReadWriteLock::tryLockForRead(int)
2122 QReadWriteLock::tryLockForRead()
2123 QReadWriteLock::tryLockForWrite(int)
2124 QReadWriteLock::tryLockForWrite()
2126 QWaitCondition::wait(QMutex*, unsigned long)
2127 QWaitCondition::wakeAll()
2128 QWaitCondition::wakeOne()
2130 QSemaphore::*
2132 /* More comments, 19 Nov 08, based on assessment of qt-4.5.0TP1,
2133 at least on Unix:
2135 It's apparently only necessary to intercept QMutex, since that is
2136 not implemented using pthread_mutex_t; instead Qt4 has its own
2137 implementation based on atomics (to check the non-contended case)
2138 and pthread_cond_wait (to wait in the contended case).
2140 QReadWriteLock is built on top of QMutex, counters, and a wait
2141 queue. So we don't need to handle it specially once QMutex
2142 handling is correct -- presumably the dependencies through QMutex
2143 are sufficient to avoid any false race reports. On the other hand,
2144 it is an open question whether too many dependencies are observed
2145 -- in which case we may miss races (false negatives). I suspect
2146 this is likely to be the case, unfortunately.
2148 QWaitCondition is built on pthread_cond_t, pthread_mutex_t, QMutex
2149 and QReadWriteLock. Same compositional-correctness justificiation
2150 and limitations as fro QReadWriteLock.
2152 Ditto QSemaphore (from cursory examination).
2154 Does it matter that only QMutex is handled directly? Open
2155 question. From testing with drd/tests/qt4_* and with KDE4 apps, it
2156 appears that no false errors are reported; however it is not clear
2157 if this is causing false negatives.
2159 Another problem with Qt4 is thread exiting. Threads are created
2160 with pthread_create (fine); but they detach and simply exit when
2161 done. There is no use of pthread_join, and the provided
2162 wait-for-a-thread-to-exit mechanism (QThread::wait, I believe)
2163 relies on a system of mutexes and flags. I suspect this also
2164 causes too many dependencies to appear. Consequently H sometimes
2165 fails to detect races at exit in some very short-lived racy
2166 programs, because it appears that a thread can exit _and_ have an
2167 observed dependency edge back to the main thread (presumably)
2168 before the main thread reaps the child (that is, calls
2169 QThread::wait).
2171 This theory is supported by the observation that if all threads are
2172 made to wait at a pthread_barrier_t immediately before they exit,
2173 then H's detection of races in such programs becomes reliable;
2174 without the barrier, it is varies from run to run, depending
2175 (according to investigation) on whether aforementioned
2176 exit-before-reaping behaviour happens or not.
2178 Finally, why is it necessary to intercept the QMutex constructors
2179 and destructors? The constructors are intercepted only as a matter
2180 of convenience, so H can print accurate "first observed at"
2181 clauses. However, it is actually necessary to intercept the
2182 destructors (as it is with pthread_mutex_destroy) in order that
2183 locks get removed from LAOG when they are destroyed.
2186 // soname is libQtCore.so.4 ; match against libQtCore.so*
2187 #define QT4_FUNC(ret_ty, f, args...) \
2188 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args); \
2189 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args)
2191 // soname is libQt5Core.so.4 ; match against libQt5Core.so*
2192 #define QT5_FUNC(ret_ty, f, args...) \
2193 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args); \
2194 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args)
2196 //-----------------------------------------------------------
2197 // QMutex::lock()
2198 __attribute__((noinline))
2199 static void QMutex_lock_WRK(void* self)
2201 OrigFn fn;
2202 VALGRIND_GET_ORIG_FN(fn);
2203 if (TRACE_QT4_FNS) {
2204 fprintf(stderr, "<< QMutex::lock %p", self); fflush(stderr);
2207 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
2208 void*,self, long,0/*!isTryLock*/);
2210 CALL_FN_v_W(fn, self);
2212 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
2213 void*, self);
2215 if (TRACE_QT4_FNS) {
2216 fprintf(stderr, " :: Q::lock done >>\n");
2220 QT4_FUNC(void, _ZN6QMutex4lockEv, void* self) {
2221 QMutex_lock_WRK(self);
2223 QT5_FUNC(void, _ZN6QMutex4lockEv, void* self) {
2224 QMutex_lock_WRK(self);
2227 //-----------------------------------------------------------
2228 // QMutex::unlock()
2229 __attribute__((noinline))
2230 static void QMutex_unlock_WRK(void* self)
2232 OrigFn fn;
2233 VALGRIND_GET_ORIG_FN(fn);
2235 if (TRACE_QT4_FNS) {
2236 fprintf(stderr, "<< QMutex::unlock %p", self); fflush(stderr);
2239 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
2240 void*, self);
2242 CALL_FN_v_W(fn, self);
2244 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
2245 void*, self);
2247 if (TRACE_QT4_FNS) {
2248 fprintf(stderr, " Q::unlock done >>\n");
2252 QT4_FUNC(void, _ZN6QMutex6unlockEv, void* self) {
2253 QMutex_unlock_WRK(self);
2255 QT5_FUNC(void, _ZN6QMutex6unlockEv, void* self) {
2256 QMutex_unlock_WRK(self);
2259 //-----------------------------------------------------------
2260 // bool QMutex::tryLock()
2261 // using 'long' to mimic C++ 'bool'
2262 __attribute__((noinline))
2263 static long QMutex_tryLock_WRK(void* self)
2265 OrigFn fn;
2266 long ret;
2267 VALGRIND_GET_ORIG_FN(fn);
2268 if (TRACE_QT4_FNS) {
2269 fprintf(stderr, "<< QMutex::tryLock %p", self); fflush(stderr);
2272 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
2273 void*,self, long,1/*isTryLock*/);
2275 CALL_FN_W_W(ret, fn, self);
2277 // assumes that only the low 8 bits of the 'bool' are significant
2278 if (ret & 0xFF) {
2279 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
2280 void*, self);
2283 if (TRACE_QT4_FNS) {
2284 fprintf(stderr, " :: Q::tryLock -> %lu >>\n", ret);
2287 return ret;
2290 QT4_FUNC(long, _ZN6QMutex7tryLockEv, void* self) {
2291 return QMutex_tryLock_WRK(self);
2293 QT5_FUNC(long, _ZN6QMutex7tryLockEv, void* self) {
2294 return QMutex_tryLock_WRK(self);
2297 //-----------------------------------------------------------
2298 // bool QMutex::tryLock(int)
2299 // using 'long' to mimic C++ 'bool'
2300 __attribute__((noinline))
2301 static long QMutex_tryLock_int_WRK(void* self, long arg2)
2303 OrigFn fn;
2304 long ret;
2305 VALGRIND_GET_ORIG_FN(fn);
2306 if (TRACE_QT4_FNS) {
2307 fprintf(stderr, "<< QMutex::tryLock(int) %p %d", self, (int)arg2);
2308 fflush(stderr);
2311 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
2312 void*,self, long,1/*isTryLock*/);
2314 CALL_FN_W_WW(ret, fn, self,arg2);
2316 // assumes that only the low 8 bits of the 'bool' are significant
2317 if (ret & 0xFF) {
2318 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
2319 void*, self);
2322 if (TRACE_QT4_FNS) {
2323 fprintf(stderr, " :: Q::tryLock(int) -> %lu >>\n", ret);
2326 return ret;
2329 QT4_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2) {
2330 return QMutex_tryLock_int_WRK(self, arg2);
2332 QT5_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2) {
2333 return QMutex_tryLock_int_WRK(self, arg2);
2336 //-----------------------------------------------------------
2337 // It's not really very clear what the args are here. But from
2338 // a bit of dataflow analysis of the generated machine code of
2339 // the original function, it appears this takes two args, and
2340 // returns nothing. Nevertheless preserve return value just in
2341 // case. A bit of debug printing indicates that the first arg
2342 // is that of the mutex and the second is either zero or one,
2343 // probably being the recursion mode, therefore.
2344 // QMutex::QMutex(QMutex::RecursionMode) ("C1ENS" variant)
2345 __attribute__((noinline))
2346 static void* QMutex_constructor_WRK(void* mutex, long recmode)
2348 OrigFn fn;
2349 long ret;
2350 VALGRIND_GET_ORIG_FN(fn);
2351 CALL_FN_W_WW(ret, fn, mutex, recmode);
2352 // fprintf(stderr, "QMutex constructor 1: %p <- %p %p\n", ret, arg1, arg2);
2353 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
2354 void*,mutex, long,1/*mbRec*/);
2355 return (void*)ret;
2358 QT4_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE, void* self, long recmode) {
2359 return QMutex_constructor_WRK(self, recmode);
2361 QT5_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE, void* self, long recmode) {
2362 return QMutex_constructor_WRK(self, recmode);
2365 //-----------------------------------------------------------
2366 // QMutex::~QMutex() ("D1Ev" variant)
2367 __attribute__((noinline))
2368 static void* QMutex_destructor_WRK(void* mutex)
2370 OrigFn fn;
2371 long ret;
2372 VALGRIND_GET_ORIG_FN(fn);
2373 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
2374 void*,mutex);
2375 CALL_FN_W_W(ret, fn, mutex);
2376 return (void*)ret;
2379 QT4_FUNC(void*, _ZN6QMutexD1Ev, void* self) {
2380 return QMutex_destructor_WRK(self);
2382 QT5_FUNC(void*, _ZN6QMutexD1Ev, void* self) {
2383 return QMutex_destructor_WRK(self);
2386 //-----------------------------------------------------------
2387 // QMutex::QMutex(QMutex::RecursionMode) ("C2ENS" variant)
2388 QT4_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE,
2389 void* mutex,
2390 long recmode)
2392 assert(0);
2393 /*NOTREACHED*/
2394 /* Android's gcc behaves like it doesn't know that assert(0)
2395 never returns. Hence: */
2396 return NULL;
2399 QT5_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE, void* self, long recmode)
2401 assert(0);
2402 /*NOTREACHED*/
2403 return NULL;
2406 //-----------------------------------------------------------
2407 // QMutex::~QMutex() ("D2Ev" variant)
2408 QT4_FUNC(void*, _ZN6QMutexD2Ev, void* mutex)
2410 assert(0);
2411 /* Android's gcc behaves like it doesn't know that assert(0)
2412 never returns. Hence: */
2413 return NULL;
2416 QT5_FUNC(void*, _ZN6QMutexD2Ev, void* self)
2418 assert(0);
2419 /*NOTREACHED*/
2420 return NULL;
2423 // QReadWriteLock is not intercepted directly. See comments
2424 // above.
2426 //// QReadWriteLock::lockForRead()
2427 //// _ZN14QReadWriteLock11lockForReadEv == QReadWriteLock::lockForRead()
2428 //QT4_FUNC(void, ZuZZN14QReadWriteLock11lockForReadEv,
2429 // // _ZN14QReadWriteLock11lockForReadEv
2430 // void* self)
2432 // OrigFn fn;
2433 // VALGRIND_GET_ORIG_FN(fn);
2434 // if (TRACE_QT4_FNS) {
2435 // fprintf(stderr, "<< QReadWriteLock::lockForRead %p", self);
2436 // fflush(stderr);
2437 // }
2439 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2440 // void*,self,
2441 // long,0/*!isW*/, long,0/*!isTryLock*/);
2443 // CALL_FN_v_W(fn, self);
2445 // DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2446 // void*,self, long,0/*!isW*/);
2448 // if (TRACE_QT4_FNS) {
2449 // fprintf(stderr, " :: Q::lockForRead :: done >>\n");
2450 // }
2453 //// QReadWriteLock::lockForWrite()
2454 //// _ZN14QReadWriteLock12lockForWriteEv == QReadWriteLock::lockForWrite()
2455 //QT4_FUNC(void, ZuZZN14QReadWriteLock12lockForWriteEv,
2456 // // _ZN14QReadWriteLock12lockForWriteEv
2457 // void* self)
2459 // OrigFn fn;
2460 // VALGRIND_GET_ORIG_FN(fn);
2461 // if (TRACE_QT4_FNS) {
2462 // fprintf(stderr, "<< QReadWriteLock::lockForWrite %p", self);
2463 // fflush(stderr);
2464 // }
2466 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2467 // void*,self,
2468 // long,1/*isW*/, long,0/*!isTryLock*/);
2470 // CALL_FN_v_W(fn, self);
2472 // DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2473 // void*,self, long,1/*isW*/);
2475 // if (TRACE_QT4_FNS) {
2476 // fprintf(stderr, " :: Q::lockForWrite :: done >>\n");
2477 // }
2480 //// QReadWriteLock::unlock()
2481 //// _ZN14QReadWriteLock6unlockEv == QReadWriteLock::unlock()
2482 //QT4_FUNC(void, ZuZZN14QReadWriteLock6unlockEv,
2483 // // _ZN14QReadWriteLock6unlockEv
2484 // void* self)
2486 // OrigFn fn;
2487 // VALGRIND_GET_ORIG_FN(fn);
2488 // if (TRACE_QT4_FNS) {
2489 // fprintf(stderr, "<< QReadWriteLock::unlock %p", self);
2490 // fflush(stderr);
2491 // }
2493 // DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
2494 // void*,self);
2496 // CALL_FN_v_W(fn, self);
2498 // DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
2499 // void*,self);
2501 // if (TRACE_QT4_FNS) {
2502 // fprintf(stderr, " :: Q::unlock :: done >>\n");
2503 // }
2507 /*----------------------------------------------------------------*/
2508 /*--- Replacements for basic string functions, that don't ---*/
2509 /*--- overrun the input arrays. ---*/
2510 /*----------------------------------------------------------------*/
2512 #include "../shared/vg_replace_strmem.c"
2514 /*--------------------------------------------------------------------*/
2515 /*--- end hg_intercepts.c ---*/
2516 /*--------------------------------------------------------------------*/