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