1
2 /*--------------------------------------------------------------------*/
3 /*--- pthread intercepts for thread checking. ---*/
4 /*--- hg_intercepts.c ---*/
5 /*--------------------------------------------------------------------*/
6
7 /*
8 This file is part of Helgrind, a Valgrind tool for detecting errors
9 in threaded programs.
10
11 Copyright (C) 2007-2011 OpenWorks LLP
12 info@open-works.co.uk
13
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.
18
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.
23
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.
28
29 The GNU General Public License is contained in the file COPYING.
30
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.
35 */
36
37 /* RUNS ON SIMULATED CPU
38 Interceptors for pthread_* functions, so that tc_main can see
39 significant thread events.
40
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.
46 */
47
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.
53
54
55 #include "pub_tool_basics.h"
56 #include "pub_tool_redir.h"
57 #include "valgrind.h"
58 #include "helgrind.h"
59 #include "config.h"
60
61 #define TRACE_PTH_FNS 0
62 #define TRACE_QT4_FNS 0
63
64
65 /*----------------------------------------------------------------*/
66 /*--- ---*/
67 /*----------------------------------------------------------------*/
68
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)
72
73 // Do a client request. These are macros rather than a functions so
74 // as to avoid having an extra frame in stack traces.
75
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.
80
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
86
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)
95
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)
106
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)
120
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)
134
135
136 #define DO_PthAPIerror(_fnnameF, _errF) \
137 do { \
138 char* _fnname = (char*)(_fnnameF); \
139 long _err = (long)(int)(_errF); \
140 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)
145
146
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
151
152 #include <stdio.h>
153 #include <assert.h>
154 #include <errno.h>
155 #include <pthread.h>
156
157
158 /* A lame version of strerror which doesn't use the real libc
159 strerror_r, since using the latter just generates endless more
160 threading errors (glibc goes off and does tons of crap w.r.t.
161 locales etc) */
lame_strerror(long err)162 static char* lame_strerror ( long err )
163 { switch (err) {
164 case EPERM: return "EPERM: Operation not permitted";
165 case ENOENT: return "ENOENT: No such file or directory";
166 case ESRCH: return "ESRCH: No such process";
167 case EINTR: return "EINTR: Interrupted system call";
168 case EBADF: return "EBADF: Bad file number";
169 case EAGAIN: return "EAGAIN: Try again";
170 case ENOMEM: return "ENOMEM: Out of memory";
171 case EACCES: return "EACCES: Permission denied";
172 case EFAULT: return "EFAULT: Bad address";
173 case EEXIST: return "EEXIST: File exists";
174 case EINVAL: return "EINVAL: Invalid argument";
175 case EMFILE: return "EMFILE: Too many open files";
176 case ENOSYS: return "ENOSYS: Function not implemented";
177 case EOVERFLOW: return "EOVERFLOW: Value too large "
178 "for defined data type";
179 case EBUSY: return "EBUSY: Device or resource busy";
180 case ETIMEDOUT: return "ETIMEDOUT: Connection timed out";
181 case EDEADLK: return "EDEADLK: Resource deadlock would occur";
182 case EOPNOTSUPP: return "EOPNOTSUPP: Operation not supported on "
183 "transport endpoint"; /* honest, guv */
184 default: return "tc_intercepts.c: lame_strerror(): "
185 "unhandled case -- please fix me!";
186 }
187 }
188
189
190 /*----------------------------------------------------------------*/
191 /*--- pthread_create, pthread_join, pthread_exit ---*/
192 /*----------------------------------------------------------------*/
193
mythread_wrapper(void * xargsV)194 static void* mythread_wrapper ( void* xargsV )
195 {
196 volatile Word* xargs = (volatile Word*) xargsV;
197 void*(*fn)(void*) = (void*(*)(void*))xargs[0];
198 void* arg = (void*)xargs[1];
199 pthread_t me = pthread_self();
200 /* Tell the tool what my pthread_t is. */
201 DO_CREQ_v_W(_VG_USERREQ__HG_SET_MY_PTHREAD_T, pthread_t,me);
202 /* allow the parent to proceed. We can't let it proceed until
203 we're ready because (1) we need to make sure it doesn't exit and
204 hence deallocate xargs[] while we still need it, and (2) we
205 don't want either parent nor child to proceed until the tool has
206 been notified of the child's pthread_t.
207
208 Note that parent and child access args[] without a lock,
209 effectively using args[2] as a spinlock in order to get the
210 parent to wait until the child passes this point. The parent
211 disables checking on xargs[] before creating the child and
212 re-enables it once the child goes past this point, so the user
213 never sees the race. The previous approach (suppressing the
214 resulting error) was flawed, because it could leave shadow
215 memory for args[] in a state in which subsequent use of it by
216 the parent would report further races. */
217 xargs[2] = 0;
218 /* Now we can no longer safely use xargs[]. */
219 return (void*) fn( (void*)arg );
220 }
221
222 //-----------------------------------------------------------
223 // glibc: pthread_create@GLIBC_2.0
224 // glibc: pthread_create@@GLIBC_2.1
225 // glibc: pthread_create@@GLIBC_2.2.5
226 // darwin: pthread_create
227 // darwin: pthread_create_suspended_np (trapped)
228 //
229 /* ensure this has its own frame, so as to make it more distinguishable
230 in suppressions */
231 __attribute__((noinline))
pthread_create_WRK(pthread_t * thread,const pthread_attr_t * attr,void * (* start)(void *),void * arg)232 static int pthread_create_WRK(pthread_t *thread, const pthread_attr_t *attr,
233 void *(*start) (void *), void *arg)
234 {
235 int ret;
236 OrigFn fn;
237 volatile Word xargs[3];
238
239 VALGRIND_GET_ORIG_FN(fn);
240 if (TRACE_PTH_FNS) {
241 fprintf(stderr, "<< pthread_create wrapper"); fflush(stderr);
242 }
243 xargs[0] = (Word)start;
244 xargs[1] = (Word)arg;
245 xargs[2] = 1; /* serves as a spinlock -- sigh */
246 /* Disable checking on the spinlock and the two words used to
247 convey args to the child. Basically we need to make it appear
248 as if the child never accessed this area, since merely
249 suppressing the resulting races does not address the issue that
250 that piece of the parent's stack winds up in the "wrong" state
251 and therefore may give rise to mysterious races when the parent
252 comes to re-use this piece of stack in some other frame. */
253 VALGRIND_HG_DISABLE_CHECKING(&xargs, sizeof(xargs));
254
255 CALL_FN_W_WWWW(ret, fn, thread,attr,mythread_wrapper,&xargs[0]);
256
257 if (ret == 0) {
258 /* we have to wait for the child to notify the tool of its
259 pthread_t before continuing */
260 while (xargs[2] != 0) {
261 /* Do nothing. We need to spin until the child writes to
262 xargs[2]. However, that can lead to starvation in the
263 child and very long delays (eg, tc19_shadowmem on
264 ppc64-linux Fedora Core 6). So yield the cpu if we can,
265 to let the child run at the earliest available
266 opportunity. */
267 sched_yield();
268 }
269 } else {
270 DO_PthAPIerror( "pthread_create", ret );
271 }
272
273 /* Reenable checking on the area previously used to communicate
274 with the child. */
275 VALGRIND_HG_ENABLE_CHECKING(&xargs, sizeof(xargs));
276
277 if (TRACE_PTH_FNS) {
278 fprintf(stderr, " :: pth_create -> %d >>\n", ret);
279 }
280 return ret;
281 }
282 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZucreateZAZa,pthread_t * thread,const pthread_attr_t * attr,void * (* start)(void *),void * arg)283 PTH_FUNC(int, pthreadZucreateZAZa, // pthread_create@*
284 pthread_t *thread, const pthread_attr_t *attr,
285 void *(*start) (void *), void *arg) {
286 return pthread_create_WRK(thread, attr, start, arg);
287 }
288 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZucreate,pthread_t * thread,const pthread_attr_t * attr,void * (* start)(void *),void * arg)289 PTH_FUNC(int, pthreadZucreate, // pthread_create
290 pthread_t *thread, const pthread_attr_t *attr,
291 void *(*start) (void *), void *arg) {
292 return pthread_create_WRK(thread, attr, start, arg);
293 }
PTH_FUNC(int,pthreadZucreateZuZa,pthread_t * thread,const pthread_attr_t * attr,void * (* start)(void *),void * arg)294 PTH_FUNC(int, pthreadZucreateZuZa, // pthread_create_*
295 pthread_t *thread, const pthread_attr_t *attr,
296 void *(*start) (void *), void *arg) {
297 // trap anything else
298 assert(0);
299 }
300 #else
301 # error "Unsupported OS"
302 #endif
303
304
305 //-----------------------------------------------------------
306 // glibc: pthread_join
307 // darwin: pthread_join
308 // darwin: pthread_join$NOCANCEL$UNIX2003
309 // darwin pthread_join$UNIX2003
310 __attribute__((noinline))
pthread_join_WRK(pthread_t thread,void ** value_pointer)311 static int pthread_join_WRK(pthread_t thread, void** value_pointer)
312 {
313 int ret;
314 OrigFn fn;
315 VALGRIND_GET_ORIG_FN(fn);
316 if (TRACE_PTH_FNS) {
317 fprintf(stderr, "<< pthread_join wrapper"); fflush(stderr);
318 }
319
320 CALL_FN_W_WW(ret, fn, thread,value_pointer);
321
322 /* At least with NPTL as the thread library, this is safe because
323 it is guaranteed (by NPTL) that the joiner will completely gone
324 before pthread_join (the original) returns. See email below.*/
325 if (ret == 0 /*success*/) {
326 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST, pthread_t,thread);
327 } else {
328 DO_PthAPIerror( "pthread_join", ret );
329 }
330
331 if (TRACE_PTH_FNS) {
332 fprintf(stderr, " :: pth_join -> %d >>\n", ret);
333 }
334 return ret;
335 }
336 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZujoin,pthread_t thread,void ** value_pointer)337 PTH_FUNC(int, pthreadZujoin, // pthread_join
338 pthread_t thread, void** value_pointer) {
339 return pthread_join_WRK(thread, value_pointer);
340 }
341 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZujoinZa,pthread_t thread,void ** value_pointer)342 PTH_FUNC(int, pthreadZujoinZa, // pthread_join*
343 pthread_t thread, void** value_pointer) {
344 return pthread_join_WRK(thread, value_pointer);
345 }
346 #else
347 # error "Unsupported OS"
348 #endif
349
350
351 /* Behaviour of pthread_join on NPTL:
352
353 Me:
354 I have a question re the NPTL pthread_join implementation.
355
356 Suppose I am the thread 'stayer'.
357
358 If I call pthread_join(quitter), is it guaranteed that the
359 thread 'quitter' has really exited before pthread_join returns?
360
361 IOW, is it guaranteed that 'quitter' will not execute any further
362 instructions after pthread_join returns?
363
364 I believe this is true based on the following analysis of
365 glibc-2.5 sources. However am not 100% sure and would appreciate
366 confirmation.
367
368 'quitter' will be running start_thread() in nptl/pthread_create.c
369
370 The last action of start_thread() is to exit via
371 __exit_thread_inline(0), which simply does sys_exit
372 (nptl/pthread_create.c:403)
373
374 'stayer' meanwhile is waiting for lll_wait_tid (pd->tid)
375 (call at nptl/pthread_join.c:89)
376
377 As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
378 lll_wait_tid will not return until kernel notifies via futex
379 wakeup that 'quitter' has terminated.
380
381 Hence pthread_join cannot return until 'quitter' really has
382 completely disappeared.
383
384 Drepper:
385 > As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
386 > lll_wait_tid will not return until kernel notifies via futex
387 > wakeup that 'quitter' has terminated.
388 That's the key. The kernel resets the TID field after the thread is
389 done. No way the joiner can return before the thread is gone.
390 */
391
392
393 /*----------------------------------------------------------------*/
394 /*--- pthread_mutex_t functions ---*/
395 /*----------------------------------------------------------------*/
396
397 /* Handled: pthread_mutex_init pthread_mutex_destroy
398 pthread_mutex_lock
399 pthread_mutex_trylock pthread_mutex_timedlock
400 pthread_mutex_unlock
401 */
402
403 //-----------------------------------------------------------
404 // glibc: pthread_mutex_init
405 // darwin: pthread_mutex_init
PTH_FUNC(int,pthreadZumutexZuinit,pthread_mutex_t * mutex,pthread_mutexattr_t * attr)406 PTH_FUNC(int, pthreadZumutexZuinit, // pthread_mutex_init
407 pthread_mutex_t *mutex,
408 pthread_mutexattr_t* attr)
409 {
410 int ret;
411 long mbRec;
412 OrigFn fn;
413 VALGRIND_GET_ORIG_FN(fn);
414 if (TRACE_PTH_FNS) {
415 fprintf(stderr, "<< pthread_mxinit %p", mutex); fflush(stderr);
416 }
417
418 mbRec = 0;
419 if (attr) {
420 int ty, zzz;
421 zzz = pthread_mutexattr_gettype(attr, &ty);
422 if (zzz == 0 && ty == PTHREAD_MUTEX_RECURSIVE)
423 mbRec = 1;
424 }
425
426 CALL_FN_W_WW(ret, fn, mutex,attr);
427
428 if (ret == 0 /*success*/) {
429 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
430 pthread_mutex_t*,mutex, long,mbRec);
431 } else {
432 DO_PthAPIerror( "pthread_mutex_init", ret );
433 }
434
435 if (TRACE_PTH_FNS) {
436 fprintf(stderr, " :: mxinit -> %d >>\n", ret);
437 }
438 return ret;
439 }
440
441
442 //-----------------------------------------------------------
443 // glibc: pthread_mutex_destroy
444 // darwin: pthread_mutex_destroy
PTH_FUNC(int,pthreadZumutexZudestroy,pthread_mutex_t * mutex)445 PTH_FUNC(int, pthreadZumutexZudestroy, // pthread_mutex_destroy
446 pthread_mutex_t *mutex)
447 {
448 int ret;
449 OrigFn fn;
450 VALGRIND_GET_ORIG_FN(fn);
451 if (TRACE_PTH_FNS) {
452 fprintf(stderr, "<< pthread_mxdestroy %p", mutex); fflush(stderr);
453 }
454
455 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
456 pthread_mutex_t*,mutex);
457
458 CALL_FN_W_W(ret, fn, mutex);
459
460 if (ret != 0) {
461 DO_PthAPIerror( "pthread_mutex_destroy", ret );
462 }
463
464 if (TRACE_PTH_FNS) {
465 fprintf(stderr, " :: mxdestroy -> %d >>\n", ret);
466 }
467 return ret;
468 }
469
470
471 //-----------------------------------------------------------
472 // glibc: pthread_mutex_lock
473 // darwin: pthread_mutex_lock
PTH_FUNC(int,pthreadZumutexZulock,pthread_mutex_t * mutex)474 PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock
475 pthread_mutex_t *mutex)
476 {
477 int ret;
478 OrigFn fn;
479 VALGRIND_GET_ORIG_FN(fn);
480 if (TRACE_PTH_FNS) {
481 fprintf(stderr, "<< pthread_mxlock %p", mutex); fflush(stderr);
482 }
483
484 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
485 pthread_mutex_t*,mutex, long,0/*!isTryLock*/);
486
487 CALL_FN_W_W(ret, fn, mutex);
488
489 /* There's a hole here: libpthread now knows the lock is locked,
490 but the tool doesn't, so some other thread could run and detect
491 that the lock has been acquired by someone (this thread). Does
492 this matter? Not sure, but I don't think so. */
493
494 if (ret == 0 /*success*/) {
495 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
496 pthread_mutex_t*,mutex);
497 } else {
498 DO_PthAPIerror( "pthread_mutex_lock", ret );
499 }
500
501 if (TRACE_PTH_FNS) {
502 fprintf(stderr, " :: mxlock -> %d >>\n", ret);
503 }
504 return ret;
505 }
506
507
508 //-----------------------------------------------------------
509 // glibc: pthread_mutex_trylock
510 // darwin: pthread_mutex_trylock
511 //
512 // pthread_mutex_trylock. The handling needed here is very similar
513 // to that for pthread_mutex_lock, except that we need to tell
514 // the pre-lock creq that this is a trylock-style operation, and
515 // therefore not to complain if the lock is nonrecursive and
516 // already locked by this thread -- because then it'll just fail
517 // immediately with EBUSY.
PTH_FUNC(int,pthreadZumutexZutrylock,pthread_mutex_t * mutex)518 PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock
519 pthread_mutex_t *mutex)
520 {
521 int ret;
522 OrigFn fn;
523 VALGRIND_GET_ORIG_FN(fn);
524 if (TRACE_PTH_FNS) {
525 fprintf(stderr, "<< pthread_mxtrylock %p", mutex); fflush(stderr);
526 }
527
528 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
529 pthread_mutex_t*,mutex, long,1/*isTryLock*/);
530
531 CALL_FN_W_W(ret, fn, mutex);
532
533 /* There's a hole here: libpthread now knows the lock is locked,
534 but the tool doesn't, so some other thread could run and detect
535 that the lock has been acquired by someone (this thread). Does
536 this matter? Not sure, but I don't think so. */
537
538 if (ret == 0 /*success*/) {
539 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
540 pthread_mutex_t*,mutex);
541 } else {
542 if (ret != EBUSY)
543 DO_PthAPIerror( "pthread_mutex_trylock", ret );
544 }
545
546 if (TRACE_PTH_FNS) {
547 fprintf(stderr, " :: mxtrylock -> %d >>\n", ret);
548 }
549 return ret;
550 }
551
552
553 //-----------------------------------------------------------
554 // glibc: pthread_mutex_timedlock
555 // darwin: (doesn't appear to exist)
556 //
557 // pthread_mutex_timedlock. Identical logic to pthread_mutex_trylock.
PTH_FUNC(int,pthreadZumutexZutimedlock,pthread_mutex_t * mutex,void * timeout)558 PTH_FUNC(int, pthreadZumutexZutimedlock, // pthread_mutex_timedlock
559 pthread_mutex_t *mutex,
560 void* timeout)
561 {
562 int ret;
563 OrigFn fn;
564 VALGRIND_GET_ORIG_FN(fn);
565 if (TRACE_PTH_FNS) {
566 fprintf(stderr, "<< pthread_mxtimedlock %p %p", mutex, timeout);
567 fflush(stderr);
568 }
569
570 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
571 pthread_mutex_t*,mutex, long,1/*isTryLock-ish*/);
572
573 CALL_FN_W_WW(ret, fn, mutex,timeout);
574
575 /* There's a hole here: libpthread now knows the lock is locked,
576 but the tool doesn't, so some other thread could run and detect
577 that the lock has been acquired by someone (this thread). Does
578 this matter? Not sure, but I don't think so. */
579
580 if (ret == 0 /*success*/) {
581 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
582 pthread_mutex_t*,mutex);
583 } else {
584 if (ret != ETIMEDOUT)
585 DO_PthAPIerror( "pthread_mutex_timedlock", ret );
586 }
587
588 if (TRACE_PTH_FNS) {
589 fprintf(stderr, " :: mxtimedlock -> %d >>\n", ret);
590 }
591 return ret;
592 }
593
594
595 //-----------------------------------------------------------
596 // glibc: pthread_mutex_unlock
597 // darwin: pthread_mutex_unlock
PTH_FUNC(int,pthreadZumutexZuunlock,pthread_mutex_t * mutex)598 PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock
599 pthread_mutex_t *mutex)
600 {
601 int ret;
602 OrigFn fn;
603 VALGRIND_GET_ORIG_FN(fn);
604
605 if (TRACE_PTH_FNS) {
606 fprintf(stderr, "<< pthread_mxunlk %p", mutex); fflush(stderr);
607 }
608
609 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
610 pthread_mutex_t*,mutex);
611
612 CALL_FN_W_W(ret, fn, mutex);
613
614 if (ret == 0 /*success*/) {
615 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
616 pthread_mutex_t*,mutex);
617 } else {
618 DO_PthAPIerror( "pthread_mutex_unlock", ret );
619 }
620
621 if (TRACE_PTH_FNS) {
622 fprintf(stderr, " mxunlk -> %d >>\n", ret);
623 }
624 return ret;
625 }
626
627
628 /*----------------------------------------------------------------*/
629 /*--- pthread_cond_t functions ---*/
630 /*----------------------------------------------------------------*/
631
632 /* Handled: pthread_cond_wait pthread_cond_timedwait
633 pthread_cond_signal pthread_cond_broadcast
634 pthread_cond_destroy
635
636 Unhandled: pthread_cond_init
637 -- is this important?
638 */
639
640 //-----------------------------------------------------------
641 // glibc: pthread_cond_wait@GLIBC_2.2.5
642 // glibc: pthread_cond_wait@@GLIBC_2.3.2
643 // darwin: pthread_cond_wait
644 // darwin: pthread_cond_wait$NOCANCEL$UNIX2003
645 // darwin: pthread_cond_wait$UNIX2003
646 //
647 __attribute__((noinline))
pthread_cond_wait_WRK(pthread_cond_t * cond,pthread_mutex_t * mutex)648 static int pthread_cond_wait_WRK(pthread_cond_t* cond,
649 pthread_mutex_t* mutex)
650 {
651 int ret;
652 OrigFn fn;
653 unsigned long mutex_is_valid;
654
655 VALGRIND_GET_ORIG_FN(fn);
656
657 if (TRACE_PTH_FNS) {
658 fprintf(stderr, "<< pthread_cond_wait %p %p", cond, mutex);
659 fflush(stderr);
660 }
661
662 /* Tell the tool a cond-wait is about to happen, so it can check
663 for bogus argument values. In return it tells us whether it
664 thinks the mutex is valid or not. */
665 DO_CREQ_W_WW(mutex_is_valid,
666 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
667 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
668 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
669
670 /* Tell the tool we're about to drop the mutex. This reflects the
671 fact that in a cond_wait, we show up holding the mutex, and the
672 call atomically drops the mutex and waits for the cv to be
673 signalled. */
674 if (mutex_is_valid) {
675 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
676 pthread_mutex_t*,mutex);
677 }
678
679 CALL_FN_W_WW(ret, fn, cond,mutex);
680
681 /* these conditionals look stupid, but compare w/ same logic for
682 pthread_cond_timedwait below */
683 if (ret == 0 && mutex_is_valid) {
684 /* and now we have the mutex again */
685 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
686 pthread_mutex_t*,mutex);
687 }
688
689 if (ret == 0 && mutex_is_valid) {
690 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
691 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
692 }
693
694 if (ret != 0) {
695 DO_PthAPIerror( "pthread_cond_wait", ret );
696 }
697
698 if (TRACE_PTH_FNS) {
699 fprintf(stderr, " cowait -> %d >>\n", ret);
700 }
701
702 return ret;
703 }
704 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZucondZuwaitZAZa,pthread_cond_t * cond,pthread_mutex_t * mutex)705 PTH_FUNC(int, pthreadZucondZuwaitZAZa, // pthread_cond_wait@*
706 pthread_cond_t* cond, pthread_mutex_t* mutex) {
707 return pthread_cond_wait_WRK(cond, mutex);
708 }
709 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZucondZuwaitZa,pthread_cond_t * cond,pthread_mutex_t * mutex)710 PTH_FUNC(int, pthreadZucondZuwaitZa, // pthread_cond_wait*
711 pthread_cond_t* cond, pthread_mutex_t* mutex) {
712 return pthread_cond_wait_WRK(cond, mutex);
713 }
714 #else
715 # error "Unsupported OS"
716 #endif
717
718
719 //-----------------------------------------------------------
720 // glibc: pthread_cond_timedwait@@GLIBC_2.3.2
721 // glibc: pthread_cond_timedwait@GLIBC_2.2.5
722 // glibc: pthread_cond_timedwait@GLIBC_2.0
723 // darwin: pthread_cond_timedwait
724 // darwin: pthread_cond_timedwait$NOCANCEL$UNIX2003
725 // darwin: pthread_cond_timedwait$UNIX2003
726 // darwin: pthread_cond_timedwait_relative_np (trapped)
727 //
728 __attribute__((noinline))
pthread_cond_timedwait_WRK(pthread_cond_t * cond,pthread_mutex_t * mutex,struct timespec * abstime)729 static int pthread_cond_timedwait_WRK(pthread_cond_t* cond,
730 pthread_mutex_t* mutex,
731 struct timespec* abstime)
732 {
733 int ret;
734 OrigFn fn;
735 unsigned long mutex_is_valid;
736 Bool abstime_is_valid;
737 VALGRIND_GET_ORIG_FN(fn);
738
739 if (TRACE_PTH_FNS) {
740 fprintf(stderr, "<< pthread_cond_timedwait %p %p %p",
741 cond, mutex, abstime);
742 fflush(stderr);
743 }
744
745 /* Tell the tool a cond-wait is about to happen, so it can check
746 for bogus argument values. In return it tells us whether it
747 thinks the mutex is valid or not. */
748 DO_CREQ_W_WW(mutex_is_valid,
749 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
750 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
751 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
752
753 abstime_is_valid = abstime->tv_nsec >= 0 && abstime->tv_nsec < 1000000000;
754
755 /* Tell the tool we're about to drop the mutex. This reflects the
756 fact that in a cond_wait, we show up holding the mutex, and the
757 call atomically drops the mutex and waits for the cv to be
758 signalled. */
759 if (mutex_is_valid && abstime_is_valid) {
760 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
761 pthread_mutex_t*,mutex);
762 }
763
764 CALL_FN_W_WWW(ret, fn, cond,mutex,abstime);
765
766 if (!abstime_is_valid && ret != EINVAL) {
767 DO_PthAPIerror("Bug in libpthread: pthread_cond_timedwait "
768 "invalid abstime did not cause"
769 " EINVAL", ret);
770 }
771
772 if ((ret == 0 || ret == ETIMEDOUT) && mutex_is_valid) {
773 /* and now we have the mutex again */
774 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
775 pthread_mutex_t*,mutex);
776 }
777
778 if (ret == 0 && mutex_is_valid) {
779 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
780 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
781 }
782
783 if (ret != 0 && ret != ETIMEDOUT) {
784 DO_PthAPIerror( "pthread_cond_timedwait", ret );
785 }
786
787 if (TRACE_PTH_FNS) {
788 fprintf(stderr, " cotimedwait -> %d >>\n", ret);
789 }
790
791 return ret;
792 }
793 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZucondZutimedwaitZAZa,pthread_cond_t * cond,pthread_mutex_t * mutex,struct timespec * abstime)794 PTH_FUNC(int, pthreadZucondZutimedwaitZAZa, // pthread_cond_timedwait@*
795 pthread_cond_t* cond, pthread_mutex_t* mutex,
796 struct timespec* abstime) {
797 return pthread_cond_timedwait_WRK(cond, mutex, abstime);
798 }
799 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZucondZutimedwait,pthread_cond_t * cond,pthread_mutex_t * mutex,struct timespec * abstime)800 PTH_FUNC(int, pthreadZucondZutimedwait, // pthread_cond_timedwait
801 pthread_cond_t* cond, pthread_mutex_t* mutex,
802 struct timespec* abstime) {
803 return pthread_cond_timedwait_WRK(cond, mutex, abstime);
804 }
PTH_FUNC(int,pthreadZucondZutimedwaitZDZa,pthread_cond_t * cond,pthread_mutex_t * mutex,struct timespec * abstime)805 PTH_FUNC(int, pthreadZucondZutimedwaitZDZa, // pthread_cond_timedwait$*
806 pthread_cond_t* cond, pthread_mutex_t* mutex,
807 struct timespec* abstime) {
808 return pthread_cond_timedwait_WRK(cond, mutex, abstime);
809 }
PTH_FUNC(int,pthreadZucondZutimedwaitZuZa,pthread_cond_t * cond,pthread_mutex_t * mutex,struct timespec * abstime)810 PTH_FUNC(int, pthreadZucondZutimedwaitZuZa, // pthread_cond_timedwait_*
811 pthread_cond_t* cond, pthread_mutex_t* mutex,
812 struct timespec* abstime) {
813 assert(0);
814 }
815 #else
816 # error "Unsupported OS"
817 #endif
818
819
820 //-----------------------------------------------------------
821 // glibc: pthread_cond_signal@GLIBC_2.0
822 // glibc: pthread_cond_signal@GLIBC_2.2.5
823 // glibc: pthread_cond_signal@@GLIBC_2.3.2
824 // darwin: pthread_cond_signal
825 // darwin: pthread_cond_signal_thread_np (don't intercept this)
826 //
827 __attribute__((noinline))
pthread_cond_signal_WRK(pthread_cond_t * cond)828 static int pthread_cond_signal_WRK(pthread_cond_t* cond)
829 {
830 int ret;
831 OrigFn fn;
832 VALGRIND_GET_ORIG_FN(fn);
833
834 if (TRACE_PTH_FNS) {
835 fprintf(stderr, "<< pthread_cond_signal %p", cond);
836 fflush(stderr);
837 }
838
839 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE,
840 pthread_cond_t*,cond);
841
842 CALL_FN_W_W(ret, fn, cond);
843
844 if (ret != 0) {
845 DO_PthAPIerror( "pthread_cond_signal", ret );
846 }
847
848 if (TRACE_PTH_FNS) {
849 fprintf(stderr, " cosig -> %d >>\n", ret);
850 }
851
852 return ret;
853 }
854 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZucondZusignalZAZa,pthread_cond_t * cond)855 PTH_FUNC(int, pthreadZucondZusignalZAZa, // pthread_cond_signal@*
856 pthread_cond_t* cond) {
857 return pthread_cond_signal_WRK(cond);
858 }
859 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZucondZusignal,pthread_cond_t * cond)860 PTH_FUNC(int, pthreadZucondZusignal, // pthread_cond_signal
861 pthread_cond_t* cond) {
862 return pthread_cond_signal_WRK(cond);
863 }
864 #else
865 # error "Unsupported OS"
866 #endif
867
868
869 //-----------------------------------------------------------
870 // glibc: pthread_cond_broadcast@GLIBC_2.0
871 // glibc: pthread_cond_broadcast@GLIBC_2.2.5
872 // glibc: pthread_cond_broadcast@@GLIBC_2.3.2
873 // darwin: pthread_cond_broadcast
874 //
875 // Note, this is pretty much identical, from a dependency-graph
876 // point of view, with cond_signal, so the code is duplicated.
877 // Maybe it should be commoned up.
878 //
879 __attribute__((noinline))
pthread_cond_broadcast_WRK(pthread_cond_t * cond)880 static int pthread_cond_broadcast_WRK(pthread_cond_t* cond)
881 {
882 int ret;
883 OrigFn fn;
884 VALGRIND_GET_ORIG_FN(fn);
885
886 if (TRACE_PTH_FNS) {
887 fprintf(stderr, "<< pthread_cond_broadcast %p", cond);
888 fflush(stderr);
889 }
890
891 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE,
892 pthread_cond_t*,cond);
893
894 CALL_FN_W_W(ret, fn, cond);
895
896 if (ret != 0) {
897 DO_PthAPIerror( "pthread_cond_broadcast", ret );
898 }
899
900 if (TRACE_PTH_FNS) {
901 fprintf(stderr, " cobro -> %d >>\n", ret);
902 }
903
904 return ret;
905 }
906 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZucondZubroadcastZAZa,pthread_cond_t * cond)907 PTH_FUNC(int, pthreadZucondZubroadcastZAZa, // pthread_cond_broadcast@*
908 pthread_cond_t* cond) {
909 return pthread_cond_broadcast_WRK(cond);
910 }
911 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZucondZubroadcast,pthread_cond_t * cond)912 PTH_FUNC(int, pthreadZucondZubroadcast, // pthread_cond_broadcast
913 pthread_cond_t* cond) {
914 return pthread_cond_broadcast_WRK(cond);
915 }
916 #else
917 # error "Unsupported OS"
918 #endif
919
920
921 //-----------------------------------------------------------
922 // glibc: pthread_cond_destroy@@GLIBC_2.3.2
923 // glibc: pthread_cond_destroy@GLIBC_2.2.5
924 // glibc: pthread_cond_destroy@GLIBC_2.0
925 // darwin: pthread_cond_destroy
926 //
927 __attribute__((noinline))
pthread_cond_destroy_WRK(pthread_cond_t * cond)928 static int pthread_cond_destroy_WRK(pthread_cond_t* cond)
929 {
930 int ret;
931 OrigFn fn;
932
933 VALGRIND_GET_ORIG_FN(fn);
934
935 if (TRACE_PTH_FNS) {
936 fprintf(stderr, "<< pthread_cond_destroy %p", cond);
937 fflush(stderr);
938 }
939
940 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_DESTROY_PRE,
941 pthread_cond_t*,cond);
942
943 CALL_FN_W_W(ret, fn, cond);
944
945 if (ret != 0) {
946 DO_PthAPIerror( "pthread_cond_destroy", ret );
947 }
948
949 if (TRACE_PTH_FNS) {
950 fprintf(stderr, " codestr -> %d >>\n", ret);
951 }
952
953 return ret;
954 }
955 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZucondZudestroyZAZa,pthread_cond_t * cond)956 PTH_FUNC(int, pthreadZucondZudestroyZAZa, // pthread_cond_destroy@*
957 pthread_cond_t* cond) {
958 return pthread_cond_destroy_WRK(cond);
959 }
960 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZucondZudestroy,pthread_cond_t * cond)961 PTH_FUNC(int, pthreadZucondZudestroy, // pthread_cond_destroy
962 pthread_cond_t* cond) {
963 return pthread_cond_destroy_WRK(cond);
964 }
965 #else
966 # error "Unsupported OS"
967 #endif
968
969
970 /*----------------------------------------------------------------*/
971 /*--- pthread_barrier_t functions ---*/
972 /*----------------------------------------------------------------*/
973
974 #if defined(HAVE_PTHREAD_BARRIER_INIT)
975
976 /* Handled: pthread_barrier_init
977 pthread_barrier_wait
978 pthread_barrier_destroy
979
980 Unhandled: pthread_barrierattr_destroy
981 pthread_barrierattr_getpshared
982 pthread_barrierattr_init
983 pthread_barrierattr_setpshared
984 -- are these important?
985 */
986
987 //-----------------------------------------------------------
988 // glibc: pthread_barrier_init
989 // darwin: (doesn't appear to exist)
PTH_FUNC(int,pthreadZubarrierZuinit,pthread_barrier_t * bar,pthread_barrierattr_t * attr,unsigned long count)990 PTH_FUNC(int, pthreadZubarrierZuinit, // pthread_barrier_init
991 pthread_barrier_t* bar,
992 pthread_barrierattr_t* attr, unsigned long count)
993 {
994 int ret;
995 OrigFn fn;
996 VALGRIND_GET_ORIG_FN(fn);
997
998 if (TRACE_PTH_FNS) {
999 fprintf(stderr, "<< pthread_barrier_init %p %p %lu",
1000 bar, attr, count);
1001 fflush(stderr);
1002 }
1003
1004 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE,
1005 pthread_barrier_t*, bar,
1006 unsigned long, count,
1007 unsigned long, 0/*!resizable*/);
1008
1009 CALL_FN_W_WWW(ret, fn, bar,attr,count);
1010
1011 if (ret != 0) {
1012 DO_PthAPIerror( "pthread_barrier_init", ret );
1013 }
1014
1015 if (TRACE_PTH_FNS) {
1016 fprintf(stderr, " pthread_barrier_init -> %d >>\n", ret);
1017 }
1018
1019 return ret;
1020 }
1021
1022
1023 //-----------------------------------------------------------
1024 // glibc: pthread_barrier_wait
1025 // darwin: (doesn't appear to exist)
PTH_FUNC(int,pthreadZubarrierZuwait,pthread_barrier_t * bar)1026 PTH_FUNC(int, pthreadZubarrierZuwait, // pthread_barrier_wait
1027 pthread_barrier_t* bar)
1028 {
1029 int ret;
1030 OrigFn fn;
1031 VALGRIND_GET_ORIG_FN(fn);
1032
1033 if (TRACE_PTH_FNS) {
1034 fprintf(stderr, "<< pthread_barrier_wait %p", bar);
1035 fflush(stderr);
1036 }
1037
1038 /* That this works correctly, and doesn't screw up when a thread
1039 leaving the barrier races round to the front and re-enters while
1040 other threads are still leaving it, is quite subtle. See
1041 comments in the handler for PTHREAD_BARRIER_WAIT_PRE in
1042 hg_main.c. */
1043 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE,
1044 pthread_barrier_t*,bar);
1045
1046 CALL_FN_W_W(ret, fn, bar);
1047
1048 if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) {
1049 DO_PthAPIerror( "pthread_barrier_wait", ret );
1050 }
1051
1052 if (TRACE_PTH_FNS) {
1053 fprintf(stderr, " pthread_barrier_wait -> %d >>\n", ret);
1054 }
1055
1056 return ret;
1057 }
1058
1059
1060 //-----------------------------------------------------------
1061 // glibc: pthread_barrier_destroy
1062 // darwin: (doesn't appear to exist)
PTH_FUNC(int,pthreadZubarrierZudestroy,pthread_barrier_t * bar)1063 PTH_FUNC(int, pthreadZubarrierZudestroy, // pthread_barrier_destroy
1064 pthread_barrier_t* bar)
1065 {
1066 int ret;
1067 OrigFn fn;
1068 VALGRIND_GET_ORIG_FN(fn);
1069
1070 if (TRACE_PTH_FNS) {
1071 fprintf(stderr, "<< pthread_barrier_destroy %p", bar);
1072 fflush(stderr);
1073 }
1074
1075 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE,
1076 pthread_barrier_t*,bar);
1077
1078 CALL_FN_W_W(ret, fn, bar);
1079
1080 if (ret != 0) {
1081 DO_PthAPIerror( "pthread_barrier_destroy", ret );
1082 }
1083
1084 if (TRACE_PTH_FNS) {
1085 fprintf(stderr, " pthread_barrier_destroy -> %d >>\n", ret);
1086 }
1087
1088 return ret;
1089 }
1090
1091 #endif // defined(HAVE_PTHREAD_BARRIER_INIT)
1092
1093
1094 /*----------------------------------------------------------------*/
1095 /*--- pthread_spinlock_t functions ---*/
1096 /*----------------------------------------------------------------*/
1097
1098 #if defined(HAVE_PTHREAD_SPIN_LOCK)
1099
1100 /* Handled: pthread_spin_init pthread_spin_destroy
1101 pthread_spin_lock pthread_spin_trylock
1102 pthread_spin_unlock
1103
1104 Unhandled:
1105 */
1106
1107 /* This is a nasty kludge, in that glibc "knows" that initialising a
1108 spin lock unlocks it, and pthread_spin_{init,unlock} are names for
1109 the same function. Hence we have to have a wrapper which does both
1110 things, without knowing which the user intended to happen. */
1111
1112 //-----------------------------------------------------------
1113 // glibc: pthread_spin_init
1114 // glibc: pthread_spin_unlock
1115 // darwin: (doesn't appear to exist)
1116 __attribute__((noinline))
pthread_spin_init_or_unlock_WRK(pthread_spinlock_t * lock,int pshared)1117 static int pthread_spin_init_or_unlock_WRK(pthread_spinlock_t* lock,
1118 int pshared) {
1119 int ret;
1120 OrigFn fn;
1121 VALGRIND_GET_ORIG_FN(fn);
1122 if (TRACE_PTH_FNS) {
1123 fprintf(stderr, "<< pthread_spin_iORu %p", lock); fflush(stderr);
1124 }
1125
1126 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE,
1127 pthread_spinlock_t*, lock);
1128
1129 CALL_FN_W_WW(ret, fn, lock,pshared);
1130
1131 if (ret == 0 /*success*/) {
1132 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST,
1133 pthread_spinlock_t*,lock);
1134 } else {
1135 DO_PthAPIerror( "pthread_spinlock_{init,unlock}", ret );
1136 }
1137
1138 if (TRACE_PTH_FNS) {
1139 fprintf(stderr, " :: spiniORu -> %d >>\n", ret);
1140 }
1141 return ret;
1142 }
1143 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZuspinZuinit,pthread_spinlock_t * lock,int pshared)1144 PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
1145 pthread_spinlock_t* lock, int pshared) {
1146 return pthread_spin_init_or_unlock_WRK(lock, pshared);
1147 }
PTH_FUNC(int,pthreadZuspinZuunlock,pthread_spinlock_t * lock)1148 PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
1149 pthread_spinlock_t* lock) {
1150 /* this is never actually called */
1151 return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/);
1152 }
1153 #elif defined(VGO_darwin)
1154 #else
1155 # error "Unsupported OS"
1156 #endif
1157
1158
1159 //-----------------------------------------------------------
1160 // glibc: pthread_spin_destroy
1161 // darwin: (doesn't appear to exist)
1162 #if defined(VGO_linux)
1163
PTH_FUNC(int,pthreadZuspinZudestroy,pthread_spinlock_t * lock)1164 PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy
1165 pthread_spinlock_t* lock)
1166 {
1167 int ret;
1168 OrigFn fn;
1169 VALGRIND_GET_ORIG_FN(fn);
1170 if (TRACE_PTH_FNS) {
1171 fprintf(stderr, "<< pthread_spin_destroy %p", lock);
1172 fflush(stderr);
1173 }
1174
1175 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_DESTROY_PRE,
1176 pthread_spinlock_t*,lock);
1177
1178 CALL_FN_W_W(ret, fn, lock);
1179
1180 if (ret != 0) {
1181 DO_PthAPIerror( "pthread_spin_destroy", ret );
1182 }
1183
1184 if (TRACE_PTH_FNS) {
1185 fprintf(stderr, " :: spindestroy -> %d >>\n", ret);
1186 }
1187 return ret;
1188 }
1189
1190 #elif defined(VGO_darwin)
1191 #else
1192 # error "Unsupported OS"
1193 #endif
1194
1195
1196 //-----------------------------------------------------------
1197 // glibc: pthread_spin_lock
1198 // darwin: (doesn't appear to exist)
1199 #if defined(VGO_linux)
1200
PTH_FUNC(int,pthreadZuspinZulock,pthread_spinlock_t * lock)1201 PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
1202 pthread_spinlock_t* lock)
1203 {
1204 int ret;
1205 OrigFn fn;
1206 VALGRIND_GET_ORIG_FN(fn);
1207 if (TRACE_PTH_FNS) {
1208 fprintf(stderr, "<< pthread_spinlock %p", lock);
1209 fflush(stderr);
1210 }
1211
1212 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE,
1213 pthread_spinlock_t*,lock, long,0/*!isTryLock*/);
1214
1215 CALL_FN_W_W(ret, fn, lock);
1216
1217 /* There's a hole here: libpthread now knows the lock is locked,
1218 but the tool doesn't, so some other thread could run and detect
1219 that the lock has been acquired by someone (this thread). Does
1220 this matter? Not sure, but I don't think so. */
1221
1222 if (ret == 0 /*success*/) {
1223 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST,
1224 pthread_spinlock_t*,lock);
1225 } else {
1226 DO_PthAPIerror( "pthread_spin_lock", ret );
1227 }
1228
1229 if (TRACE_PTH_FNS) {
1230 fprintf(stderr, " :: spinlock -> %d >>\n", ret);
1231 }
1232 return ret;
1233 }
1234
1235 #elif defined(VGO_darwin)
1236 #else
1237 # error "Unsupported OS"
1238 #endif
1239
1240
1241 //-----------------------------------------------------------
1242 // glibc: pthread_spin_trylock
1243 // darwin: (doesn't appear to exist)
1244 #if defined(VGO_linux)
1245
PTH_FUNC(int,pthreadZuspinZutrylock,pthread_spinlock_t * lock)1246 PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
1247 pthread_spinlock_t* lock)
1248 {
1249 int ret;
1250 OrigFn fn;
1251 VALGRIND_GET_ORIG_FN(fn);
1252 if (TRACE_PTH_FNS) {
1253 fprintf(stderr, "<< pthread_spin_trylock %p", lock);
1254 fflush(stderr);
1255 }
1256
1257 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE,
1258 pthread_spinlock_t*,lock, long,1/*isTryLock*/);
1259
1260 CALL_FN_W_W(ret, fn, lock);
1261
1262 /* There's a hole here: libpthread now knows the lock is locked,
1263 but the tool doesn't, so some other thread could run and detect
1264 that the lock has been acquired by someone (this thread). Does
1265 this matter? Not sure, but I don't think so. */
1266
1267 if (ret == 0 /*success*/) {
1268 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST,
1269 pthread_spinlock_t*,lock);
1270 } else {
1271 if (ret != EBUSY)
1272 DO_PthAPIerror( "pthread_spin_trylock", ret );
1273 }
1274
1275 if (TRACE_PTH_FNS) {
1276 fprintf(stderr, " :: spin_trylock -> %d >>\n", ret);
1277 }
1278 return ret;
1279 }
1280
1281 #elif defined(VGO_darwin)
1282 #else
1283 # error "Unsupported OS"
1284 #endif
1285
1286 #endif // defined(HAVE_PTHREAD_SPIN_LOCK)
1287
1288
1289 /*----------------------------------------------------------------*/
1290 /*--- pthread_rwlock_t functions ---*/
1291 /*----------------------------------------------------------------*/
1292
1293 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1294 functions have to be conditionally compiled. */
1295 #if defined(HAVE_PTHREAD_RWLOCK_T)
1296
1297 /* Handled: pthread_rwlock_init pthread_rwlock_destroy
1298 pthread_rwlock_rdlock
1299 pthread_rwlock_wrlock
1300 pthread_rwlock_unlock
1301
1302 Unhandled: pthread_rwlock_timedrdlock
1303 pthread_rwlock_tryrdlock
1304
1305 pthread_rwlock_timedwrlock
1306 pthread_rwlock_trywrlock
1307 */
1308
1309 //-----------------------------------------------------------
1310 // glibc: pthread_rwlock_init
1311 // darwin: pthread_rwlock_init
1312 // darwin: pthread_rwlock_init$UNIX2003
1313 __attribute__((noinline))
pthread_rwlock_init_WRK(pthread_rwlock_t * rwl,pthread_rwlockattr_t * attr)1314 static int pthread_rwlock_init_WRK(pthread_rwlock_t *rwl,
1315 pthread_rwlockattr_t* attr)
1316 {
1317 int ret;
1318 OrigFn fn;
1319 VALGRIND_GET_ORIG_FN(fn);
1320 if (TRACE_PTH_FNS) {
1321 fprintf(stderr, "<< pthread_rwl_init %p", rwl); fflush(stderr);
1322 }
1323
1324 CALL_FN_W_WW(ret, fn, rwl,attr);
1325
1326 if (ret == 0 /*success*/) {
1327 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
1328 pthread_rwlock_t*,rwl);
1329 } else {
1330 DO_PthAPIerror( "pthread_rwlock_init", ret );
1331 }
1332
1333 if (TRACE_PTH_FNS) {
1334 fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
1335 }
1336 return ret;
1337 }
1338 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZurwlockZuinit,pthread_rwlock_t * rwl,pthread_rwlockattr_t * attr)1339 PTH_FUNC(int, pthreadZurwlockZuinit, // pthread_rwlock_init
1340 pthread_rwlock_t *rwl,
1341 pthread_rwlockattr_t* attr) {
1342 return pthread_rwlock_init_WRK(rwl, attr);
1343 }
1344 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZurwlockZuinitZa,pthread_rwlock_t * rwl,pthread_rwlockattr_t * attr)1345 PTH_FUNC(int, pthreadZurwlockZuinitZa, // pthread_rwlock_init*
1346 pthread_rwlock_t *rwl,
1347 pthread_rwlockattr_t* attr) {
1348 return pthread_rwlock_init_WRK(rwl, attr);
1349 }
1350 #else
1351 # error "Unsupported OS"
1352 #endif
1353
1354
1355 //-----------------------------------------------------------
1356 // glibc: pthread_rwlock_destroy
1357 // darwin: pthread_rwlock_destroy
1358 // darwin: pthread_rwlock_destroy$UNIX2003
1359 //
1360 __attribute__((noinline))
pthread_rwlock_destroy_WRK(pthread_rwlock_t * rwl)1361 static int pthread_rwlock_destroy_WRK(pthread_rwlock_t* rwl)
1362 {
1363 int ret;
1364 OrigFn fn;
1365 VALGRIND_GET_ORIG_FN(fn);
1366 if (TRACE_PTH_FNS) {
1367 fprintf(stderr, "<< pthread_rwl_destroy %p", rwl); fflush(stderr);
1368 }
1369
1370 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE,
1371 pthread_rwlock_t*,rwl);
1372
1373 CALL_FN_W_W(ret, fn, rwl);
1374
1375 if (ret != 0) {
1376 DO_PthAPIerror( "pthread_rwlock_destroy", ret );
1377 }
1378
1379 if (TRACE_PTH_FNS) {
1380 fprintf(stderr, " :: rwl_destroy -> %d >>\n", ret);
1381 }
1382 return ret;
1383 }
1384 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZurwlockZudestroy,pthread_rwlock_t * rwl)1385 PTH_FUNC(int, pthreadZurwlockZudestroy, // pthread_rwlock_destroy
1386 pthread_rwlock_t *rwl) {
1387 return pthread_rwlock_destroy_WRK(rwl);
1388 }
1389 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZurwlockZudestroyZa,pthread_rwlock_t * rwl)1390 PTH_FUNC(int, pthreadZurwlockZudestroyZa, // pthread_rwlock_destroy*
1391 pthread_rwlock_t *rwl) {
1392 return pthread_rwlock_destroy_WRK(rwl);
1393 }
1394 #else
1395 # error "Unsupported OS"
1396 #endif
1397
1398
1399 //-----------------------------------------------------------
1400 // glibc: pthread_rwlock_wrlock
1401 // darwin: pthread_rwlock_wrlock
1402 // darwin: pthread_rwlock_wrlock$UNIX2003
1403 //
1404 __attribute__((noinline))
pthread_rwlock_wrlock_WRK(pthread_rwlock_t * rwlock)1405 static int pthread_rwlock_wrlock_WRK(pthread_rwlock_t* rwlock)
1406 {
1407 int ret;
1408 OrigFn fn;
1409 VALGRIND_GET_ORIG_FN(fn);
1410 if (TRACE_PTH_FNS) {
1411 fprintf(stderr, "<< pthread_rwl_wlk %p", rwlock); fflush(stderr);
1412 }
1413
1414 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1415 pthread_rwlock_t*,rwlock,
1416 long,1/*isW*/, long,0/*!isTryLock*/);
1417
1418 CALL_FN_W_W(ret, fn, rwlock);
1419
1420 if (ret == 0 /*success*/) {
1421 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1422 pthread_rwlock_t*,rwlock, long,1/*isW*/);
1423 } else {
1424 DO_PthAPIerror( "pthread_rwlock_wrlock", ret );
1425 }
1426
1427 if (TRACE_PTH_FNS) {
1428 fprintf(stderr, " :: rwl_wlk -> %d >>\n", ret);
1429 }
1430 return ret;
1431 }
1432 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZurwlockZuwrlock,pthread_rwlock_t * rwlock)1433 PTH_FUNC(int, pthreadZurwlockZuwrlock, // pthread_rwlock_wrlock
1434 pthread_rwlock_t* rwlock) {
1435 return pthread_rwlock_wrlock_WRK(rwlock);
1436 }
1437 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZurwlockZuwrlockZa,pthread_rwlock_t * rwlock)1438 PTH_FUNC(int, pthreadZurwlockZuwrlockZa, // pthread_rwlock_wrlock*
1439 pthread_rwlock_t* rwlock) {
1440 return pthread_rwlock_wrlock_WRK(rwlock);
1441 }
1442 #else
1443 # error "Unsupported OS"
1444 #endif
1445
1446
1447 //-----------------------------------------------------------
1448 // glibc: pthread_rwlock_rdlock
1449 // darwin: pthread_rwlock_rdlock
1450 // darwin: pthread_rwlock_rdlock$UNIX2003
1451 //
1452 __attribute__((noinline))
pthread_rwlock_rdlock_WRK(pthread_rwlock_t * rwlock)1453 static int pthread_rwlock_rdlock_WRK(pthread_rwlock_t* rwlock)
1454 {
1455 int ret;
1456 OrigFn fn;
1457 VALGRIND_GET_ORIG_FN(fn);
1458 if (TRACE_PTH_FNS) {
1459 fprintf(stderr, "<< pthread_rwl_rlk %p", rwlock); fflush(stderr);
1460 }
1461
1462 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1463 pthread_rwlock_t*,rwlock,
1464 long,0/*!isW*/, long,0/*!isTryLock*/);
1465
1466 CALL_FN_W_W(ret, fn, rwlock);
1467
1468 if (ret == 0 /*success*/) {
1469 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1470 pthread_rwlock_t*,rwlock, long,0/*!isW*/);
1471 } else {
1472 DO_PthAPIerror( "pthread_rwlock_rdlock", ret );
1473 }
1474
1475 if (TRACE_PTH_FNS) {
1476 fprintf(stderr, " :: rwl_rlk -> %d >>\n", ret);
1477 }
1478 return ret;
1479 }
1480 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZurwlockZurdlock,pthread_rwlock_t * rwlock)1481 PTH_FUNC(int, pthreadZurwlockZurdlock, // pthread_rwlock_rdlock
1482 pthread_rwlock_t* rwlock) {
1483 return pthread_rwlock_rdlock_WRK(rwlock);
1484 }
1485 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZurwlockZurdlockZa,pthread_rwlock_t * rwlock)1486 PTH_FUNC(int, pthreadZurwlockZurdlockZa, // pthread_rwlock_rdlock*
1487 pthread_rwlock_t* rwlock) {
1488 return pthread_rwlock_rdlock_WRK(rwlock);
1489 }
1490 #else
1491 # error "Unsupported OS"
1492 #endif
1493
1494
1495 //-----------------------------------------------------------
1496 // glibc: pthread_rwlock_trywrlock
1497 // darwin: pthread_rwlock_trywrlock
1498 // darwin: pthread_rwlock_trywrlock$UNIX2003
1499 //
1500 __attribute__((noinline))
pthread_rwlock_trywrlock_WRK(pthread_rwlock_t * rwlock)1501 static int pthread_rwlock_trywrlock_WRK(pthread_rwlock_t* rwlock)
1502 {
1503 int ret;
1504 OrigFn fn;
1505 VALGRIND_GET_ORIG_FN(fn);
1506 if (TRACE_PTH_FNS) {
1507 fprintf(stderr, "<< pthread_rwl_trywlk %p", rwlock); fflush(stderr);
1508 }
1509
1510 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1511 pthread_rwlock_t*,rwlock,
1512 long,1/*isW*/, long,1/*isTryLock*/);
1513
1514 CALL_FN_W_W(ret, fn, rwlock);
1515
1516 /* There's a hole here: libpthread now knows the lock is locked,
1517 but the tool doesn't, so some other thread could run and detect
1518 that the lock has been acquired by someone (this thread). Does
1519 this matter? Not sure, but I don't think so. */
1520
1521 if (ret == 0 /*success*/) {
1522 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1523 pthread_rwlock_t*,rwlock, long,1/*isW*/);
1524 } else {
1525 if (ret != EBUSY)
1526 DO_PthAPIerror( "pthread_rwlock_trywrlock", ret );
1527 }
1528
1529 if (TRACE_PTH_FNS) {
1530 fprintf(stderr, " :: rwl_trywlk -> %d >>\n", ret);
1531 }
1532 return ret;
1533 }
1534 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZurwlockZutrywrlock,pthread_rwlock_t * rwlock)1535 PTH_FUNC(int, pthreadZurwlockZutrywrlock, // pthread_rwlock_trywrlock
1536 pthread_rwlock_t* rwlock) {
1537 return pthread_rwlock_trywrlock_WRK(rwlock);
1538 }
1539 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZurwlockZutrywrlockZa,pthread_rwlock_t * rwlock)1540 PTH_FUNC(int, pthreadZurwlockZutrywrlockZa, // pthread_rwlock_trywrlock*
1541 pthread_rwlock_t* rwlock) {
1542 return pthread_rwlock_trywrlock_WRK(rwlock);
1543 }
1544 #else
1545 # error "Unsupported OS"
1546 #endif
1547
1548
1549 //-----------------------------------------------------------
1550 // glibc: pthread_rwlock_tryrdlock
1551 // darwin: pthread_rwlock_trywrlock
1552 // darwin: pthread_rwlock_trywrlock$UNIX2003
1553 //
1554 __attribute__((noinline))
pthread_rwlock_tryrdlock_WRK(pthread_rwlock_t * rwlock)1555 static int pthread_rwlock_tryrdlock_WRK(pthread_rwlock_t* rwlock)
1556 {
1557 int ret;
1558 OrigFn fn;
1559 VALGRIND_GET_ORIG_FN(fn);
1560 if (TRACE_PTH_FNS) {
1561 fprintf(stderr, "<< pthread_rwl_tryrlk %p", rwlock); fflush(stderr);
1562 }
1563
1564 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1565 pthread_rwlock_t*,rwlock,
1566 long,0/*!isW*/, long,1/*isTryLock*/);
1567
1568 CALL_FN_W_W(ret, fn, rwlock);
1569
1570 /* There's a hole here: libpthread now knows the lock is locked,
1571 but the tool doesn't, so some other thread could run and detect
1572 that the lock has been acquired by someone (this thread). Does
1573 this matter? Not sure, but I don't think so. */
1574
1575 if (ret == 0 /*success*/) {
1576 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1577 pthread_rwlock_t*,rwlock, long,0/*!isW*/);
1578 } else {
1579 if (ret != EBUSY)
1580 DO_PthAPIerror( "pthread_rwlock_tryrdlock", ret );
1581 }
1582
1583 if (TRACE_PTH_FNS) {
1584 fprintf(stderr, " :: rwl_tryrlk -> %d >>\n", ret);
1585 }
1586 return ret;
1587 }
1588 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZurwlockZutryrdlock,pthread_rwlock_t * rwlock)1589 PTH_FUNC(int, pthreadZurwlockZutryrdlock, // pthread_rwlock_tryrdlock
1590 pthread_rwlock_t* rwlock) {
1591 return pthread_rwlock_tryrdlock_WRK(rwlock);
1592 }
1593 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZurwlockZutryrdlockZa,pthread_rwlock_t * rwlock)1594 PTH_FUNC(int, pthreadZurwlockZutryrdlockZa, // pthread_rwlock_tryrdlock*
1595 pthread_rwlock_t* rwlock) {
1596 return pthread_rwlock_tryrdlock_WRK(rwlock);
1597 }
1598 #else
1599 # error "Unsupported OS"
1600 #endif
1601
1602
1603 //-----------------------------------------------------------
1604 // glibc: pthread_rwlock_unlock
1605 // darwin: pthread_rwlock_unlock
1606 // darwin: pthread_rwlock_unlock$UNIX2003
1607 __attribute__((noinline))
pthread_rwlock_unlock_WRK(pthread_rwlock_t * rwlock)1608 static int pthread_rwlock_unlock_WRK(pthread_rwlock_t* rwlock)
1609 {
1610 int ret;
1611 OrigFn fn;
1612 VALGRIND_GET_ORIG_FN(fn);
1613 if (TRACE_PTH_FNS) {
1614 fprintf(stderr, "<< pthread_rwl_unlk %p", rwlock); fflush(stderr);
1615 }
1616
1617 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
1618 pthread_rwlock_t*,rwlock);
1619
1620 CALL_FN_W_W(ret, fn, rwlock);
1621
1622 if (ret == 0 /*success*/) {
1623 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
1624 pthread_rwlock_t*,rwlock);
1625 } else {
1626 DO_PthAPIerror( "pthread_rwlock_unlock", ret );
1627 }
1628
1629 if (TRACE_PTH_FNS) {
1630 fprintf(stderr, " :: rwl_unlk -> %d >>\n", ret);
1631 }
1632 return ret;
1633 }
1634 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZurwlockZuunlock,pthread_rwlock_t * rwlock)1635 PTH_FUNC(int, pthreadZurwlockZuunlock, // pthread_rwlock_unlock
1636 pthread_rwlock_t* rwlock) {
1637 return pthread_rwlock_unlock_WRK(rwlock);
1638 }
1639 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZurwlockZuunlockZa,pthread_rwlock_t * rwlock)1640 PTH_FUNC(int, pthreadZurwlockZuunlockZa, // pthread_rwlock_unlock*
1641 pthread_rwlock_t* rwlock) {
1642 return pthread_rwlock_unlock_WRK(rwlock);
1643 }
1644 #else
1645 # error "Unsupported OS"
1646 #endif
1647
1648 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
1649
1650
1651 /*----------------------------------------------------------------*/
1652 /*--- POSIX semaphores ---*/
1653 /*----------------------------------------------------------------*/
1654
1655 #include <semaphore.h>
1656 #include <fcntl.h> /* O_CREAT */
1657
1658 #define TRACE_SEM_FNS 0
1659
1660 /* Handled:
1661 int sem_init(sem_t *sem, int pshared, unsigned value);
1662 int sem_destroy(sem_t *sem);
1663 int sem_wait(sem_t *sem);
1664 int sem_post(sem_t *sem);
1665 sem_t* sem_open(const char *name, int oflag,
1666 ... [mode_t mode, unsigned value]);
1667 [complete with its idiotic semantics]
1668 int sem_close(sem_t* sem);
1669
1670 Unhandled:
1671 int sem_trywait(sem_t *sem);
1672 int sem_timedwait(sem_t *restrict sem,
1673 const struct timespec *restrict abs_timeout);
1674 */
1675
1676 //-----------------------------------------------------------
1677 // glibc: sem_init@@GLIBC_2.2.5
1678 // glibc: sem_init@@GLIBC_2.1
1679 // glibc: sem_init@GLIBC_2.0
1680 // darwin: sem_init
1681 //
1682 __attribute__((noinline))
sem_init_WRK(sem_t * sem,int pshared,unsigned long value)1683 static int sem_init_WRK(sem_t* sem, int pshared, unsigned long value)
1684 {
1685 OrigFn fn;
1686 int ret;
1687 VALGRIND_GET_ORIG_FN(fn);
1688
1689 if (TRACE_SEM_FNS) {
1690 fprintf(stderr, "<< sem_init(%p,%d,%lu) ", sem,pshared,value);
1691 fflush(stderr);
1692 }
1693
1694 CALL_FN_W_WWW(ret, fn, sem,pshared,value);
1695
1696 if (ret == 0) {
1697 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
1698 sem_t*, sem, unsigned long, value);
1699 } else {
1700 DO_PthAPIerror( "sem_init", errno );
1701 }
1702
1703 if (TRACE_SEM_FNS) {
1704 fprintf(stderr, " sem_init -> %d >>\n", ret);
1705 fflush(stderr);
1706 }
1707
1708 return ret;
1709 }
1710 #if defined(VGO_linux)
PTH_FUNC(int,semZuinitZAZa,sem_t * sem,int pshared,unsigned long value)1711 PTH_FUNC(int, semZuinitZAZa, // sem_init@*
1712 sem_t* sem, int pshared, unsigned long value) {
1713 return sem_init_WRK(sem, pshared, value);
1714 }
1715 #elif defined(VGO_darwin)
PTH_FUNC(int,semZuinit,sem_t * sem,int pshared,unsigned long value)1716 PTH_FUNC(int, semZuinit, // sem_init
1717 sem_t* sem, int pshared, unsigned long value) {
1718 return sem_init_WRK(sem, pshared, value);
1719 }
1720 #else
1721 # error "Unsupported OS"
1722 #endif
1723
1724
1725 //-----------------------------------------------------------
1726 // glibc: sem_destroy@GLIBC_2.0
1727 // glibc: sem_destroy@@GLIBC_2.1
1728 // glibc: sem_destroy@@GLIBC_2.2.5
1729 // darwin: sem_destroy
1730 __attribute__((noinline))
sem_destroy_WRK(sem_t * sem)1731 static int sem_destroy_WRK(sem_t* sem)
1732 {
1733 OrigFn fn;
1734 int ret;
1735 VALGRIND_GET_ORIG_FN(fn);
1736
1737 if (TRACE_SEM_FNS) {
1738 fprintf(stderr, "<< sem_destroy(%p) ", sem);
1739 fflush(stderr);
1740 }
1741
1742 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
1743
1744 CALL_FN_W_W(ret, fn, sem);
1745
1746 if (ret != 0) {
1747 DO_PthAPIerror( "sem_destroy", errno );
1748 }
1749
1750 if (TRACE_SEM_FNS) {
1751 fprintf(stderr, " sem_destroy -> %d >>\n", ret);
1752 fflush(stderr);
1753 }
1754
1755 return ret;
1756 }
1757 #if defined(VGO_linux)
PTH_FUNC(int,semZudestroyZAZa,sem_t * sem)1758 PTH_FUNC(int, semZudestroyZAZa, // sem_destroy*
1759 sem_t* sem) {
1760 return sem_destroy_WRK(sem);
1761 }
1762 #elif defined(VGO_darwin)
PTH_FUNC(int,semZudestroy,sem_t * sem)1763 PTH_FUNC(int, semZudestroy, // sem_destroy
1764 sem_t* sem) {
1765 return sem_destroy_WRK(sem);
1766 }
1767 #else
1768 # error "Unsupported OS"
1769 #endif
1770
1771
1772 //-----------------------------------------------------------
1773 // glibc: sem_wait
1774 // glibc: sem_wait@GLIBC_2.0
1775 // glibc: sem_wait@@GLIBC_2.1
1776 // darwin: sem_wait
1777 // darwin: sem_wait$NOCANCEL$UNIX2003
1778 // darwin: sem_wait$UNIX2003
1779 //
1780 /* wait: decrement semaphore - acquire lockage */
1781 __attribute__((noinline))
sem_wait_WRK(sem_t * sem)1782 static int sem_wait_WRK(sem_t* sem)
1783 {
1784 OrigFn fn;
1785 int ret;
1786 VALGRIND_GET_ORIG_FN(fn);
1787
1788 if (TRACE_SEM_FNS) {
1789 fprintf(stderr, "<< sem_wait(%p) ", sem);
1790 fflush(stderr);
1791 }
1792
1793 CALL_FN_W_W(ret, fn, sem);
1794
1795 if (ret == 0) {
1796 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST, sem_t*,sem);
1797 } else {
1798 DO_PthAPIerror( "sem_wait", errno );
1799 }
1800
1801 if (TRACE_SEM_FNS) {
1802 fprintf(stderr, " sem_wait -> %d >>\n", ret);
1803 fflush(stderr);
1804 }
1805
1806 return ret;
1807 }
1808 #if defined(VGO_linux)
PTH_FUNC(int,semZuwait,sem_t * sem)1809 PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
1810 return sem_wait_WRK(sem);
1811 }
PTH_FUNC(int,semZuwaitZAZa,sem_t * sem)1812 PTH_FUNC(int, semZuwaitZAZa, sem_t* sem) { /* sem_wait@* */
1813 return sem_wait_WRK(sem);
1814 }
1815 #elif defined(VGO_darwin)
PTH_FUNC(int,semZuwait,sem_t * sem)1816 PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
1817 return sem_wait_WRK(sem);
1818 }
PTH_FUNC(int,semZuwaitZDZa,sem_t * sem)1819 PTH_FUNC(int, semZuwaitZDZa, sem_t* sem) { /* sem_wait$* */
1820 return sem_wait_WRK(sem);
1821 }
1822 #else
1823 # error "Unsupported OS"
1824 #endif
1825
1826
1827 //-----------------------------------------------------------
1828 // glibc: sem_post
1829 // glibc: sem_post@GLIBC_2.0
1830 // glibc: sem_post@@GLIBC_2.1
1831 // darwin: sem_post
1832 //
1833 /* post: increment semaphore - release lockage */
1834 __attribute__((noinline))
sem_post_WRK(sem_t * sem)1835 static int sem_post_WRK(sem_t* sem)
1836 {
1837 OrigFn fn;
1838 int ret;
1839
1840 VALGRIND_GET_ORIG_FN(fn);
1841
1842 if (TRACE_SEM_FNS) {
1843 fprintf(stderr, "<< sem_post(%p) ", sem);
1844 fflush(stderr);
1845 }
1846
1847 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_PRE, sem_t*,sem);
1848
1849 CALL_FN_W_W(ret, fn, sem);
1850
1851 if (ret != 0) {
1852 DO_PthAPIerror( "sem_post", errno );
1853 }
1854
1855 if (TRACE_SEM_FNS) {
1856 fprintf(stderr, " sem_post -> %d >>\n", ret);
1857 fflush(stderr);
1858 }
1859
1860 return ret;
1861 }
1862 #if defined(VGO_linux)
PTH_FUNC(int,semZupost,sem_t * sem)1863 PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
1864 return sem_post_WRK(sem);
1865 }
PTH_FUNC(int,semZupostZAZa,sem_t * sem)1866 PTH_FUNC(int, semZupostZAZa, sem_t* sem) { /* sem_post@* */
1867 return sem_post_WRK(sem);
1868 }
1869 #elif defined(VGO_darwin)
PTH_FUNC(int,semZupost,sem_t * sem)1870 PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
1871 return sem_post_WRK(sem);
1872 }
1873 #else
1874 # error "Unsupported OS"
1875 #endif
1876
1877
1878 //-----------------------------------------------------------
1879 // glibc: sem_open
1880 // darwin: sem_open
1881 //
PTH_FUNC(sem_t *,semZuopen,const char * name,long oflag,long mode,unsigned long value)1882 PTH_FUNC(sem_t*, semZuopen,
1883 const char* name, long oflag,
1884 long mode, unsigned long value)
1885 {
1886 /* A copy of sem_init_WRK (more or less). Is this correct? */
1887 OrigFn fn;
1888 sem_t* ret;
1889 VALGRIND_GET_ORIG_FN(fn);
1890
1891 if (TRACE_SEM_FNS) {
1892 fprintf(stderr, "<< sem_open(\"%s\",%ld,%lx,%lu) ",
1893 name,oflag,mode,value);
1894 fflush(stderr);
1895 }
1896
1897 CALL_FN_W_WWWW(ret, fn, name,oflag,mode,value);
1898
1899 if (ret != SEM_FAILED && (oflag & O_CREAT)) {
1900 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
1901 sem_t*, ret, unsigned long, value);
1902 }
1903 if (ret == SEM_FAILED) {
1904 DO_PthAPIerror( "sem_open", errno );
1905 }
1906
1907 if (TRACE_SEM_FNS) {
1908 fprintf(stderr, " sem_open -> %p >>\n", ret);
1909 fflush(stderr);
1910 }
1911
1912 return ret;
1913 }
1914
1915
1916 //-----------------------------------------------------------
1917 // glibc: sem_close
1918 // darwin: sem_close
PTH_FUNC(int,sem_close,sem_t * sem)1919 PTH_FUNC(int, sem_close, sem_t* sem)
1920 {
1921 OrigFn fn;
1922 int ret;
1923 VALGRIND_GET_ORIG_FN(fn);
1924
1925 if (TRACE_SEM_FNS) {
1926 fprintf(stderr, "<< sem_close(%p) ", sem);
1927 fflush(stderr);
1928 }
1929
1930 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
1931
1932 CALL_FN_W_W(ret, fn, sem);
1933
1934 if (ret != 0) {
1935 DO_PthAPIerror( "sem_close", errno );
1936 }
1937
1938 if (TRACE_SEM_FNS) {
1939 fprintf(stderr, " close -> %d >>\n", ret);
1940 fflush(stderr);
1941 }
1942
1943 return ret;
1944 }
1945
1946
1947 /*----------------------------------------------------------------*/
1948 /*--- Qt 4 threading functions (w/ GNU name mangling) ---*/
1949 /*----------------------------------------------------------------*/
1950
1951 /* Handled:
1952 QMutex::lock()
1953 QMutex::unlock()
1954 QMutex::tryLock()
1955 QMutex::tryLock(int)
1956
1957 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC1ENS_13RecursionModeE
1958 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC2ENS_13RecursionModeE
1959 QMutex::~QMutex() _ZN6QMutexD1Ev
1960 QMutex::~QMutex() _ZN6QMutexD2Ev
1961
1962 Unhandled:
1963 QReadWriteLock::lockForRead()
1964 QReadWriteLock::lockForWrite()
1965 QReadWriteLock::unlock()
1966 QReadWriteLock::tryLockForRead(int)
1967 QReadWriteLock::tryLockForRead()
1968 QReadWriteLock::tryLockForWrite(int)
1969 QReadWriteLock::tryLockForWrite()
1970
1971 QWaitCondition::wait(QMutex*, unsigned long)
1972 QWaitCondition::wakeAll()
1973 QWaitCondition::wakeOne()
1974
1975 QSemaphore::*
1976 */
1977 /* More comments, 19 Nov 08, based on assessment of qt-4.5.0TP1,
1978 at least on Unix:
1979
1980 It's apparently only necessary to intercept QMutex, since that is
1981 not implemented using pthread_mutex_t; instead Qt4 has its own
1982 implementation based on atomics (to check the non-contended case)
1983 and pthread_cond_wait (to wait in the contended case).
1984
1985 QReadWriteLock is built on top of QMutex, counters, and a wait
1986 queue. So we don't need to handle it specially once QMutex
1987 handling is correct -- presumably the dependencies through QMutex
1988 are sufficient to avoid any false race reports. On the other hand,
1989 it is an open question whether too many dependencies are observed
1990 -- in which case we may miss races (false negatives). I suspect
1991 this is likely to be the case, unfortunately.
1992
1993 QWaitCondition is built on pthread_cond_t, pthread_mutex_t, QMutex
1994 and QReadWriteLock. Same compositional-correctness justificiation
1995 and limitations as fro QReadWriteLock.
1996
1997 Ditto QSemaphore (from cursory examination).
1998
1999 Does it matter that only QMutex is handled directly? Open
2000 question. From testing with drd/tests/qt4_* and with KDE4 apps, it
2001 appears that no false errors are reported; however it is not clear
2002 if this is causing false negatives.
2003
2004 Another problem with Qt4 is thread exiting. Threads are created
2005 with pthread_create (fine); but they detach and simply exit when
2006 done. There is no use of pthread_join, and the provided
2007 wait-for-a-thread-to-exit mechanism (QThread::wait, I believe)
2008 relies on a system of mutexes and flags. I suspect this also
2009 causes too many dependencies to appear. Consequently H sometimes
2010 fails to detect races at exit in some very short-lived racy
2011 programs, because it appears that a thread can exit _and_ have an
2012 observed dependency edge back to the main thread (presumably)
2013 before the main thread reaps the child (that is, calls
2014 QThread::wait).
2015
2016 This theory is supported by the observation that if all threads are
2017 made to wait at a pthread_barrier_t immediately before they exit,
2018 then H's detection of races in such programs becomes reliable;
2019 without the barrier, it is varies from run to run, depending
2020 (according to investigation) on whether aforementioned
2021 exit-before-reaping behaviour happens or not.
2022
2023 Finally, why is it necessary to intercept the QMutex constructors
2024 and destructors? The constructors are intercepted only as a matter
2025 of convenience, so H can print accurate "first observed at"
2026 clauses. However, it is actually necessary to intercept the
2027 destructors (as it is with pthread_mutex_destroy) in order that
2028 locks get removed from LAOG when they are destroyed.
2029 */
2030
2031 // soname is libQtCore.so.4 ; match against libQtCore.so*
2032 #define QT4_FUNC(ret_ty, f, args...) \
2033 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args); \
2034 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args)
2035
2036 //-----------------------------------------------------------
2037 // QMutex::lock()
QT4_FUNC(void,_ZN6QMutex4lockEv,void * self)2038 QT4_FUNC(void, _ZN6QMutex4lockEv, void* self)
2039 {
2040 OrigFn fn;
2041 VALGRIND_GET_ORIG_FN(fn);
2042 if (TRACE_QT4_FNS) {
2043 fprintf(stderr, "<< QMutex::lock %p", self); fflush(stderr);
2044 }
2045
2046 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
2047 void*,self, long,0/*!isTryLock*/);
2048
2049 CALL_FN_v_W(fn, self);
2050
2051 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
2052 void*, self);
2053
2054 if (TRACE_QT4_FNS) {
2055 fprintf(stderr, " :: Q::lock done >>\n");
2056 }
2057 }
2058
2059 //-----------------------------------------------------------
2060 // QMutex::unlock()
QT4_FUNC(void,_ZN6QMutex6unlockEv,void * self)2061 QT4_FUNC(void, _ZN6QMutex6unlockEv, void* self)
2062 {
2063 OrigFn fn;
2064 VALGRIND_GET_ORIG_FN(fn);
2065
2066 if (TRACE_QT4_FNS) {
2067 fprintf(stderr, "<< QMutex::unlock %p", self); fflush(stderr);
2068 }
2069
2070 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
2071 void*, self);
2072
2073 CALL_FN_v_W(fn, self);
2074
2075 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
2076 void*, self);
2077
2078 if (TRACE_QT4_FNS) {
2079 fprintf(stderr, " Q::unlock done >>\n");
2080 }
2081 }
2082
2083 //-----------------------------------------------------------
2084 // bool QMutex::tryLock()
2085 // using 'long' to mimic C++ 'bool'
QT4_FUNC(long,_ZN6QMutex7tryLockEv,void * self)2086 QT4_FUNC(long, _ZN6QMutex7tryLockEv, void* self)
2087 {
2088 OrigFn fn;
2089 long ret;
2090 VALGRIND_GET_ORIG_FN(fn);
2091 if (TRACE_QT4_FNS) {
2092 fprintf(stderr, "<< QMutex::tryLock %p", self); fflush(stderr);
2093 }
2094
2095 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
2096 void*,self, long,1/*isTryLock*/);
2097
2098 CALL_FN_W_W(ret, fn, self);
2099
2100 // assumes that only the low 8 bits of the 'bool' are significant
2101 if (ret & 0xFF) {
2102 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
2103 void*, self);
2104 }
2105
2106 if (TRACE_QT4_FNS) {
2107 fprintf(stderr, " :: Q::tryLock -> %lu >>\n", ret);
2108 }
2109
2110 return ret;
2111 }
2112
2113 //-----------------------------------------------------------
2114 // bool QMutex::tryLock(int)
2115 // using 'long' to mimic C++ 'bool'
QT4_FUNC(long,_ZN6QMutex7tryLockEi,void * self,long arg2)2116 QT4_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2)
2117 {
2118 OrigFn fn;
2119 long ret;
2120 VALGRIND_GET_ORIG_FN(fn);
2121 if (TRACE_QT4_FNS) {
2122 fprintf(stderr, "<< QMutex::tryLock(int) %p %d", self, (int)arg2);
2123 fflush(stderr);
2124 }
2125
2126 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
2127 void*,self, long,1/*isTryLock*/);
2128
2129 CALL_FN_W_WW(ret, fn, self,arg2);
2130
2131 // assumes that only the low 8 bits of the 'bool' are significant
2132 if (ret & 0xFF) {
2133 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
2134 void*, self);
2135 }
2136
2137 if (TRACE_QT4_FNS) {
2138 fprintf(stderr, " :: Q::tryLock(int) -> %lu >>\n", ret);
2139 }
2140
2141 return ret;
2142 }
2143
2144
2145 //-----------------------------------------------------------
2146 // It's not really very clear what the args are here. But from
2147 // a bit of dataflow analysis of the generated machine code of
2148 // the original function, it appears this takes two args, and
2149 // returns nothing. Nevertheless preserve return value just in
2150 // case. A bit of debug printing indicates that the first arg
2151 // is that of the mutex and the second is either zero or one,
2152 // probably being the recursion mode, therefore.
2153 // QMutex::QMutex(QMutex::RecursionMode) ("C1ENS" variant)
QT4_FUNC(void *,_ZN6QMutexC1ENS_13RecursionModeE,void * mutex,long recmode)2154 QT4_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE,
2155 void* mutex,
2156 long recmode)
2157 {
2158 OrigFn fn;
2159 long ret;
2160 VALGRIND_GET_ORIG_FN(fn);
2161 CALL_FN_W_WW(ret, fn, mutex, recmode);
2162 // fprintf(stderr, "QMutex constructor 1: %p <- %p %p\n", ret, arg1, arg2);
2163 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
2164 void*,mutex, long,1/*mbRec*/);
2165 return (void*)ret;
2166 }
2167
2168 //-----------------------------------------------------------
2169 // QMutex::~QMutex() ("D1Ev" variant)
QT4_FUNC(void *,_ZN6QMutexD1Ev,void * mutex)2170 QT4_FUNC(void*, _ZN6QMutexD1Ev, void* mutex)
2171 {
2172 OrigFn fn;
2173 long ret;
2174 VALGRIND_GET_ORIG_FN(fn);
2175 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
2176 void*,mutex);
2177 CALL_FN_W_W(ret, fn, mutex);
2178 return (void*)ret;
2179 }
2180
2181
2182 //-----------------------------------------------------------
2183 // QMutex::QMutex(QMutex::RecursionMode) ("C2ENS" variant)
QT4_FUNC(void *,_ZN6QMutexC2ENS_13RecursionModeE,void * mutex,long recmode)2184 QT4_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE,
2185 void* mutex,
2186 long recmode)
2187 {
2188 assert(0);
2189 /*NOTREACHED*/
2190 /* Android's gcc behaves like it doesn't know that assert(0)
2191 never returns. Hence: */
2192 return NULL;
2193 }
2194
2195
2196 //-----------------------------------------------------------
2197 // QMutex::~QMutex() ("D2Ev" variant)
QT4_FUNC(void *,_ZN6QMutexD2Ev,void * mutex)2198 QT4_FUNC(void*, _ZN6QMutexD2Ev, void* mutex)
2199 {
2200 assert(0);
2201 /* Android's gcc behaves like it doesn't know that assert(0)
2202 never returns. Hence: */
2203 return NULL;
2204 }
2205
2206
2207 // QReadWriteLock is not intercepted directly. See comments
2208 // above.
2209
2210 //// QReadWriteLock::lockForRead()
2211 //// _ZN14QReadWriteLock11lockForReadEv == QReadWriteLock::lockForRead()
2212 //QT4_FUNC(void, ZuZZN14QReadWriteLock11lockForReadEv,
2213 // // _ZN14QReadWriteLock11lockForReadEv
2214 // void* self)
2215 //{
2216 // OrigFn fn;
2217 // VALGRIND_GET_ORIG_FN(fn);
2218 // if (TRACE_QT4_FNS) {
2219 // fprintf(stderr, "<< QReadWriteLock::lockForRead %p", self);
2220 // fflush(stderr);
2221 // }
2222 //
2223 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2224 // void*,self,
2225 // long,0/*!isW*/, long,0/*!isTryLock*/);
2226 //
2227 // CALL_FN_v_W(fn, self);
2228 //
2229 // DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2230 // void*,self, long,0/*!isW*/);
2231 //
2232 // if (TRACE_QT4_FNS) {
2233 // fprintf(stderr, " :: Q::lockForRead :: done >>\n");
2234 // }
2235 //}
2236 //
2237 //// QReadWriteLock::lockForWrite()
2238 //// _ZN14QReadWriteLock12lockForWriteEv == QReadWriteLock::lockForWrite()
2239 //QT4_FUNC(void, ZuZZN14QReadWriteLock12lockForWriteEv,
2240 // // _ZN14QReadWriteLock12lockForWriteEv
2241 // void* self)
2242 //{
2243 // OrigFn fn;
2244 // VALGRIND_GET_ORIG_FN(fn);
2245 // if (TRACE_QT4_FNS) {
2246 // fprintf(stderr, "<< QReadWriteLock::lockForWrite %p", self);
2247 // fflush(stderr);
2248 // }
2249 //
2250 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2251 // void*,self,
2252 // long,1/*isW*/, long,0/*!isTryLock*/);
2253 //
2254 // CALL_FN_v_W(fn, self);
2255 //
2256 // DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2257 // void*,self, long,1/*isW*/);
2258 //
2259 // if (TRACE_QT4_FNS) {
2260 // fprintf(stderr, " :: Q::lockForWrite :: done >>\n");
2261 // }
2262 //}
2263 //
2264 //// QReadWriteLock::unlock()
2265 //// _ZN14QReadWriteLock6unlockEv == QReadWriteLock::unlock()
2266 //QT4_FUNC(void, ZuZZN14QReadWriteLock6unlockEv,
2267 // // _ZN14QReadWriteLock6unlockEv
2268 // void* self)
2269 //{
2270 // OrigFn fn;
2271 // VALGRIND_GET_ORIG_FN(fn);
2272 // if (TRACE_QT4_FNS) {
2273 // fprintf(stderr, "<< QReadWriteLock::unlock %p", self);
2274 // fflush(stderr);
2275 // }
2276 //
2277 // DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
2278 // void*,self);
2279 //
2280 // CALL_FN_v_W(fn, self);
2281 //
2282 // DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
2283 // void*,self);
2284 //
2285 // if (TRACE_QT4_FNS) {
2286 // fprintf(stderr, " :: Q::unlock :: done >>\n");
2287 // }
2288 //}
2289
2290
2291 /*----------------------------------------------------------------*/
2292 /*--- Replacements for basic string functions, that don't ---*/
2293 /*--- overrun the input arrays. ---*/
2294 /*----------------------------------------------------------------*/
2295
2296 /* Copied verbatim from memcheck/mc_replace_strmem.c. When copying
2297 new functions, please keep them in the same order as they appear in
2298 mc_replace_strmem.c. */
2299
2300
2301 #define STRCHR(soname, fnname) \
2302 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( const char* s, int c ); \
2303 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( const char* s, int c ) \
2304 { \
2305 UChar ch = (UChar)((UInt)c); \
2306 UChar* p = (UChar*)s; \
2307 while (True) { \
2308 if (*p == ch) return p; \
2309 if (*p == 0) return NULL; \
2310 p++; \
2311 } \
2312 }
2313
2314 // Apparently index() is the same thing as strchr()
2315 #if defined(VGO_linux)
2316 STRCHR(VG_Z_LIBC_SONAME, strchr)
2317 STRCHR(VG_Z_LIBC_SONAME, index)
2318 STRCHR(VG_Z_LD_LINUX_SO_2, strchr)
2319 STRCHR(VG_Z_LD_LINUX_SO_2, index)
2320 STRCHR(VG_Z_LD_LINUX_X86_64_SO_2, strchr)
2321 STRCHR(VG_Z_LD_LINUX_X86_64_SO_2, index)
2322 #elif defined(VGO_darwin)
2323 STRCHR(VG_Z_LIBC_SONAME, strchr)
2324 STRCHR(VG_Z_LIBC_SONAME, index)
2325 #endif
2326
2327
2328 // Note that this replacement often doesn't get used because gcc inlines
2329 // calls to strlen() with its own built-in version. This can be very
2330 // confusing if you aren't expecting it. Other small functions in this file
2331 // may also be inline by gcc.
2332 #define STRLEN(soname, fnname) \
2333 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname)( const char* str ); \
2334 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname)( const char* str ) \
2335 { \
2336 SizeT i = 0; \
2337 while (str[i] != 0) i++; \
2338 return i; \
2339 }
2340
2341 #if defined(VGO_linux)
2342 STRLEN(VG_Z_LIBC_SONAME, strlen)
2343 STRLEN(VG_Z_LD_LINUX_SO_2, strlen)
2344 STRLEN(VG_Z_LD_LINUX_X86_64_SO_2, strlen)
2345 #elif defined(VGO_darwin)
2346 STRLEN(VG_Z_LIBC_SONAME, strlen)
2347 #endif
2348
2349
2350 #define STRCPY(soname, fnname) \
2351 char* VG_REPLACE_FUNCTION_ZU(soname, fnname) ( char* dst, const char* src ); \
2352 char* VG_REPLACE_FUNCTION_ZU(soname, fnname) ( char* dst, const char* src ) \
2353 { \
2354 const Char* dst_orig = dst; \
2355 \
2356 while (*src) *dst++ = *src++; \
2357 *dst = 0; \
2358 \
2359 return (char*)dst_orig; \
2360 }
2361
2362 #if defined(VGO_linux)
2363 STRCPY(VG_Z_LIBC_SONAME, strcpy)
2364 #elif defined(VGO_darwin)
2365 STRCPY(VG_Z_LIBC_SONAME, strcpy)
2366 #endif
2367
2368
2369 #define STRCMP(soname, fnname) \
2370 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
2371 ( const char* s1, const char* s2 ); \
2372 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
2373 ( const char* s1, const char* s2 ) \
2374 { \
2375 register unsigned char c1; \
2376 register unsigned char c2; \
2377 while (True) { \
2378 c1 = *(unsigned char *)s1; \
2379 c2 = *(unsigned char *)s2; \
2380 if (c1 != c2) break; \
2381 if (c1 == 0) break; \
2382 s1++; s2++; \
2383 } \
2384 if ((unsigned char)c1 < (unsigned char)c2) return -1; \
2385 if ((unsigned char)c1 > (unsigned char)c2) return 1; \
2386 return 0; \
2387 }
2388
2389 #if defined(VGO_linux)
2390 STRCMP(VG_Z_LIBC_SONAME, strcmp)
2391 STRCMP(VG_Z_LD_LINUX_X86_64_SO_2, strcmp)
2392 STRCMP(VG_Z_LD64_SO_1, strcmp)
2393 #elif defined(VGO_darwin)
2394 STRCMP(VG_Z_LIBC_SONAME, strcmp)
2395 #endif
2396
2397
2398 #define MEMCPY(soname, fnname) \
2399 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
2400 ( void *dst, const void *src, SizeT len ); \
2401 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
2402 ( void *dst, const void *src, SizeT len ) \
2403 { \
2404 register char *d; \
2405 register char *s; \
2406 \
2407 if (len == 0) \
2408 return dst; \
2409 \
2410 if ( dst > src ) { \
2411 d = (char *)dst + len - 1; \
2412 s = (char *)src + len - 1; \
2413 while ( len >= 4 ) { \
2414 *d-- = *s--; \
2415 *d-- = *s--; \
2416 *d-- = *s--; \
2417 *d-- = *s--; \
2418 len -= 4; \
2419 } \
2420 while ( len-- ) { \
2421 *d-- = *s--; \
2422 } \
2423 } else if ( dst < src ) { \
2424 d = (char *)dst; \
2425 s = (char *)src; \
2426 while ( len >= 4 ) { \
2427 *d++ = *s++; \
2428 *d++ = *s++; \
2429 *d++ = *s++; \
2430 *d++ = *s++; \
2431 len -= 4; \
2432 } \
2433 while ( len-- ) { \
2434 *d++ = *s++; \
2435 } \
2436 } \
2437 return dst; \
2438 }
2439
2440 #if defined(VGO_linux)
2441 MEMCPY(VG_Z_LIBC_SONAME, memcpy)
2442 MEMCPY(VG_Z_LD_SO_1, memcpy) /* ld.so.1 */
2443 MEMCPY(VG_Z_LD64_SO_1, memcpy) /* ld64.so.1 */
2444 /* icc9 blats these around all over the place. Not only in the main
2445 executable but various .so's. They are highly tuned and read
2446 memory beyond the source boundary (although work correctly and
2447 never go across page boundaries), so give errors when run
2448 natively, at least for misaligned source arg. Just intercepting
2449 in the exe only until we understand more about the problem. See
2450 http://bugs.kde.org/show_bug.cgi?id=139776
2451 */
2452 MEMCPY(NONE, _intel_fast_memcpy)
2453 #elif defined(VGO_darwin)
2454 MEMCPY(VG_Z_LIBC_SONAME, memcpy)
2455 #endif
2456
2457
2458 /*--------------------------------------------------------------------*/
2459 /*--- end hg_intercepts.c ---*/
2460 /*--------------------------------------------------------------------*/
2461