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