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