blob: 172edfe9ac87bbda390377e33e037a4e38c485a6 [file] [log] [blame]
sewardjb4112022007-11-09 22:49:28 +00001
2/*--------------------------------------------------------------------*/
3/*--- pthread intercepts for thread checking. ---*/
4/*--- tc_intercepts.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
8 This file is part of Helgrind, a Valgrind tool for detecting errors
9 in threaded programs.
10
sewardj4d474d02008-02-11 11:34:59 +000011 Copyright (C) 2007-2008 OpenWorks LLP
sewardjb4112022007-11-09 22:49:28 +000012 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#include "pub_tool_basics.h"
49#include "valgrind.h"
50#include "helgrind.h"
51
52#define TRACE_PTH_FNS 0
53#define TRACE_QT4_FNS 0
54
55
56/*----------------------------------------------------------------*/
57/*--- ---*/
58/*----------------------------------------------------------------*/
59
60#define PTH_FUNC(ret_ty, f, args...) \
61 ret_ty I_WRAP_SONAME_FNNAME_ZZ(libpthreadZdsoZd0,f)(args); \
62 ret_ty I_WRAP_SONAME_FNNAME_ZZ(libpthreadZdsoZd0,f)(args)
63
64// Do a client request. This is a macro rather than a function
65// so as to avoid having an extra function in the stack trace.
66
67#define DO_CREQ_v_W(_creqF, _ty1F,_arg1F) \
68 do { \
69 Word _unused_res, _arg1; \
70 assert(sizeof(_ty1F) == sizeof(Word)); \
71 _arg1 = (Word)(_arg1F); \
72 VALGRIND_DO_CLIENT_REQUEST(_unused_res, 0, \
73 (_creqF), \
74 _arg1, 0,0,0,0); \
75 } while (0)
76
77#define DO_CREQ_v_WW(_creqF, _ty1F,_arg1F, _ty2F,_arg2F) \
78 do { \
79 Word _unused_res, _arg1, _arg2; \
80 assert(sizeof(_ty1F) == sizeof(Word)); \
81 assert(sizeof(_ty2F) == sizeof(Word)); \
82 _arg1 = (Word)(_arg1F); \
83 _arg2 = (Word)(_arg2F); \
84 VALGRIND_DO_CLIENT_REQUEST(_unused_res, 0, \
85 (_creqF), \
86 _arg1,_arg2,0,0,0); \
87 } while (0)
88
89#define DO_CREQ_W_WW(_resF, _creqF, _ty1F,_arg1F, _ty2F,_arg2F) \
90 do { \
91 Word _res, _arg1, _arg2; \
92 assert(sizeof(_ty1F) == sizeof(Word)); \
93 assert(sizeof(_ty2F) == sizeof(Word)); \
94 _arg1 = (Word)(_arg1F); \
95 _arg2 = (Word)(_arg2F); \
96 VALGRIND_DO_CLIENT_REQUEST(_res, 2, \
97 (_creqF), \
98 _arg1,_arg2,0,0,0); \
99 _resF = _res; \
100 } while (0)
101
102#define DO_CREQ_v_WWW(_creqF, _ty1F,_arg1F, \
103 _ty2F,_arg2F, _ty3F, _arg3F) \
104 do { \
105 Word _unused_res, _arg1, _arg2, _arg3; \
106 assert(sizeof(_ty1F) == sizeof(Word)); \
107 assert(sizeof(_ty2F) == sizeof(Word)); \
108 assert(sizeof(_ty3F) == sizeof(Word)); \
109 _arg1 = (Word)(_arg1F); \
110 _arg2 = (Word)(_arg2F); \
111 _arg3 = (Word)(_arg3F); \
112 VALGRIND_DO_CLIENT_REQUEST(_unused_res, 0, \
113 (_creqF), \
114 _arg1,_arg2,_arg3,0,0); \
115 } while (0)
116
117
118#define DO_PthAPIerror(_fnnameF, _errF) \
119 do { \
120 char* _fnname = (char*)(_fnnameF); \
121 long _err = (long)(int)(_errF); \
122 char* _errstr = lame_strerror(_err); \
123 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTH_API_ERROR, \
124 char*,_fnname, \
125 long,_err, char*,_errstr); \
126 } while (0)
127
128
129/* Needed for older glibcs (2.3 and older, at least) who don't
130 otherwise "know" about pthread_rwlock_anything or about
131 PTHREAD_MUTEX_RECURSIVE (amongst things). */
132#define _GNU_SOURCE 1
133
134#include <stdio.h>
135#include <assert.h>
136#include <errno.h>
137#include <pthread.h>
138
139
140/* A lame version of strerror which doesn't use the real libc
141 strerror_r, since using the latter just generates endless more
142 threading errors (glibc goes off and does tons of crap w.r.t.
143 locales etc) */
144static char* lame_strerror ( long err )
145{ switch (err) {
146 case EPERM: return "EPERM: Operation not permitted";
147 case ENOENT: return "ENOENT: No such file or directory";
148 case ESRCH: return "ESRCH: No such process";
149 case EINTR: return "EINTR: Interrupted system call";
150 case EBADF: return "EBADF: Bad file number";
151 case EAGAIN: return "EAGAIN: Try again";
152 case ENOMEM: return "ENOMEM: Out of memory";
153 case EACCES: return "EACCES: Permission denied";
154 case EFAULT: return "EFAULT: Bad address";
155 case EEXIST: return "EEXIST: File exists";
156 case EINVAL: return "EINVAL: Invalid argument";
157 case EMFILE: return "EMFILE: Too many open files";
158 case ENOSYS: return "ENOSYS: Function not implemented";
159 case EOVERFLOW: return "EOVERFLOW: Value too large "
160 "for defined data type";
161 case EBUSY: return "EBUSY: Device or resource busy";
162 case ETIMEDOUT: return "ETIMEDOUT: Connection timed out";
163 case EDEADLK: return "EDEADLK: Resource deadlock would occur";
164 case EOPNOTSUPP: return "EOPNOTSUPP: Operation not supported on "
165 "transport endpoint"; /* honest, guv */
166 default: return "tc_intercepts.c: lame_strerror(): "
167 "unhandled case -- please fix me!";
168 }
169}
170
171
172/*----------------------------------------------------------------*/
173/*--- pthread_create, pthread_join, pthread_exit ---*/
174/*----------------------------------------------------------------*/
175
sewardj0d2a2c12007-11-11 05:58:41 +0000176/* Do not rename this function. It contains an unavoidable race and
177 so is mentioned by name in glibc-*helgrind*.supp. */
sewardjb4112022007-11-09 22:49:28 +0000178static void* mythread_wrapper ( void* xargsV )
179{
bart31277bf2008-07-29 17:04:31 +0000180 volatile Word* xargs = (volatile Word*) xargsV;
sewardjb4112022007-11-09 22:49:28 +0000181 void*(*fn)(void*) = (void*(*)(void*))xargs[0];
182 void* arg = (void*)xargs[1];
183 pthread_t me = pthread_self();
184 /* Tell the tool what my pthread_t is. */
185 DO_CREQ_v_W(_VG_USERREQ__HG_SET_MY_PTHREAD_T, pthread_t,me);
186 /* allow the parent to proceed. We can't let it proceed until
187 we're ready because (1) we need to make sure it doesn't exit and
188 hence deallocate xargs[] while we still need it, and (2) we
189 don't want either parent nor child to proceed until the tool has
190 been notified of the child's pthread_t. */
191 xargs[2] = 0;
192 /* Now we can no longer safely use xargs[]. */
193 return (void*) fn( (void*)arg );
194}
195
196// pthread_create
197PTH_FUNC(int, pthreadZucreateZAZa, // pthread_create@*
198 pthread_t *thread, const pthread_attr_t *attr,
199 void *(*start) (void *), void *arg)
200{
201 int ret;
202 OrigFn fn;
203 volatile Word xargs[3];
204
205 VALGRIND_GET_ORIG_FN(fn);
206 if (TRACE_PTH_FNS) {
207 fprintf(stderr, "<< pthread_create wrapper"); fflush(stderr);
208 }
209 xargs[0] = (Word)start;
210 xargs[1] = (Word)arg;
211 xargs[2] = 1; /* serves as a spinlock -- sigh */
212
213 CALL_FN_W_WWWW(ret, fn, thread,attr,mythread_wrapper,&xargs[0]);
214
215 if (ret == 0) {
216 /* we have to wait for the child to notify the tool of its
217 pthread_t before continuing */
218 while (xargs[2] != 0) {
sewardjeafad3b2007-11-18 01:16:52 +0000219 /* Do nothing. We need to spin until the child writes to
220 xargs[2]. However, that can lead to starvation in the
221 child and very long delays (eg, tc19_shadowmem on
222 ppc64-linux Fedora Core 6). So yield the cpu if we can,
223 to let the child run at the earliest available
224 opportunity. */
225 sched_yield();
sewardjb4112022007-11-09 22:49:28 +0000226 }
227 } else {
228 DO_PthAPIerror( "pthread_create", ret );
229 }
230
231 if (TRACE_PTH_FNS) {
232 fprintf(stderr, " :: pth_create -> %d >>\n", ret);
233 }
234 return ret;
235}
236
237// pthread_join
238PTH_FUNC(int, pthreadZujoin, // pthread_join
239 pthread_t thread, void** value_pointer)
240{
241 int ret;
242 OrigFn fn;
243 VALGRIND_GET_ORIG_FN(fn);
244 if (TRACE_PTH_FNS) {
245 fprintf(stderr, "<< pthread_join wrapper"); fflush(stderr);
246 }
247
248 CALL_FN_W_WW(ret, fn, thread,value_pointer);
249
250 /* At least with NPTL as the thread library, this is safe because
251 it is guaranteed (by NPTL) that the joiner will completely gone
252 before pthread_join (the original) returns. See email below.*/
253 if (ret == 0 /*success*/) {
254 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST, pthread_t,thread);
255 } else {
256 DO_PthAPIerror( "pthread_join", ret );
257 }
258
259 if (TRACE_PTH_FNS) {
260 fprintf(stderr, " :: pth_join -> %d >>\n", ret);
261 }
262 return ret;
263}
264
265/* Behaviour of pthread_join on NPTL:
266
267Me:
268I have a question re the NPTL pthread_join implementation.
269
270 Suppose I am the thread 'stayer'.
271
272 If I call pthread_join(quitter), is it guaranteed that the
273 thread 'quitter' has really exited before pthread_join returns?
274
275 IOW, is it guaranteed that 'quitter' will not execute any further
276 instructions after pthread_join returns?
277
278I believe this is true based on the following analysis of
279glibc-2.5 sources. However am not 100% sure and would appreciate
280confirmation.
281
282 'quitter' will be running start_thread() in nptl/pthread_create.c
283
284 The last action of start_thread() is to exit via
285 __exit_thread_inline(0), which simply does sys_exit
286 (nptl/pthread_create.c:403)
287
288 'stayer' meanwhile is waiting for lll_wait_tid (pd->tid)
289 (call at nptl/pthread_join.c:89)
290
291 As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
292 lll_wait_tid will not return until kernel notifies via futex
293 wakeup that 'quitter' has terminated.
294
295 Hence pthread_join cannot return until 'quitter' really has
296 completely disappeared.
297
298Drepper:
299> As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
300> lll_wait_tid will not return until kernel notifies via futex
301> wakeup that 'quitter' has terminated.
302That's the key. The kernel resets the TID field after the thread is
303done. No way the joiner can return before the thread is gone.
304*/
305
306
307/*----------------------------------------------------------------*/
308/*--- pthread_mutex_t functions ---*/
309/*----------------------------------------------------------------*/
310
311/* Handled: pthread_mutex_init pthread_mutex_destroy
312 pthread_mutex_lock
313 pthread_mutex_trylock pthread_mutex_timedlock
314 pthread_mutex_unlock
315
316 Unhandled: pthread_spin_init pthread_spin_destroy
317 pthread_spin_lock
318 pthread_spin_trylock
319 pthread_spin_unlock
320*/
321
322// pthread_mutex_init
323PTH_FUNC(int, pthreadZumutexZuinit, // pthread_mutex_init
324 pthread_mutex_t *mutex,
325 pthread_mutexattr_t* attr)
326{
327 int ret;
328 long mbRec;
329 OrigFn fn;
330 VALGRIND_GET_ORIG_FN(fn);
331 if (TRACE_PTH_FNS) {
332 fprintf(stderr, "<< pthread_mxinit %p", mutex); fflush(stderr);
333 }
334
335 mbRec = 0;
336 if (attr) {
337 int ty, zzz;
338 zzz = pthread_mutexattr_gettype(attr, &ty);
339 if (zzz == 0 && ty == PTHREAD_MUTEX_RECURSIVE)
340 mbRec = 1;
341 }
342
343 CALL_FN_W_WW(ret, fn, mutex,attr);
344
345 if (ret == 0 /*success*/) {
346 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
347 pthread_mutex_t*,mutex, long,mbRec);
348 } else {
349 DO_PthAPIerror( "pthread_mutex_init", ret );
350 }
351
352 if (TRACE_PTH_FNS) {
353 fprintf(stderr, " :: mxinit -> %d >>\n", ret);
354 }
355 return ret;
356}
357
358
359// pthread_mutex_destroy
360PTH_FUNC(int, pthreadZumutexZudestroy, // pthread_mutex_destroy
361 pthread_mutex_t *mutex)
362{
363 int ret;
364 OrigFn fn;
365 VALGRIND_GET_ORIG_FN(fn);
366 if (TRACE_PTH_FNS) {
367 fprintf(stderr, "<< pthread_mxdestroy %p", mutex); fflush(stderr);
368 }
369
370 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
371 pthread_mutex_t*,mutex);
372
373 CALL_FN_W_W(ret, fn, mutex);
374
375 if (ret != 0) {
376 DO_PthAPIerror( "pthread_mutex_destroy", ret );
377 }
378
379 if (TRACE_PTH_FNS) {
380 fprintf(stderr, " :: mxdestroy -> %d >>\n", ret);
381 }
382 return ret;
383}
384
385
386// pthread_mutex_lock
387PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock
388 pthread_mutex_t *mutex)
389{
390 int ret;
391 OrigFn fn;
392 VALGRIND_GET_ORIG_FN(fn);
393 if (TRACE_PTH_FNS) {
394 fprintf(stderr, "<< pthread_mxlock %p", mutex); fflush(stderr);
395 }
396
397 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
398 pthread_mutex_t*,mutex, long,0/*!isTryLock*/);
399
400 CALL_FN_W_W(ret, fn, mutex);
401
402 /* There's a hole here: libpthread now knows the lock is locked,
403 but the tool doesn't, so some other thread could run and detect
404 that the lock has been acquired by someone (this thread). Does
405 this matter? Not sure, but I don't think so. */
406
407 if (ret == 0 /*success*/) {
408 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
409 pthread_mutex_t*,mutex);
410 } else {
411 DO_PthAPIerror( "pthread_mutex_lock", ret );
412 }
413
414 if (TRACE_PTH_FNS) {
415 fprintf(stderr, " :: mxlock -> %d >>\n", ret);
416 }
417 return ret;
418}
419
420
421// pthread_mutex_trylock. The handling needed here is very similar
422// to that for pthread_mutex_lock, except that we need to tell
423// the pre-lock creq that this is a trylock-style operation, and
424// therefore not to complain if the lock is nonrecursive and
425// already locked by this thread -- because then it'll just fail
426// immediately with EBUSY.
427PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock
428 pthread_mutex_t *mutex)
429{
430 int ret;
431 OrigFn fn;
432 VALGRIND_GET_ORIG_FN(fn);
433 if (TRACE_PTH_FNS) {
434 fprintf(stderr, "<< pthread_mxtrylock %p", mutex); fflush(stderr);
435 }
436
437 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
438 pthread_mutex_t*,mutex, long,1/*isTryLock*/);
439
440 CALL_FN_W_W(ret, fn, mutex);
441
442 /* There's a hole here: libpthread now knows the lock is locked,
443 but the tool doesn't, so some other thread could run and detect
444 that the lock has been acquired by someone (this thread). Does
445 this matter? Not sure, but I don't think so. */
446
447 if (ret == 0 /*success*/) {
448 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
449 pthread_mutex_t*,mutex);
450 } else {
451 if (ret != EBUSY)
452 DO_PthAPIerror( "pthread_mutex_trylock", ret );
453 }
454
455 if (TRACE_PTH_FNS) {
456 fprintf(stderr, " :: mxtrylock -> %d >>\n", ret);
457 }
458 return ret;
459}
460
461
462// pthread_mutex_timedlock. Identical logic to pthread_mutex_trylock.
463PTH_FUNC(int, pthreadZumutexZutimedlock, // pthread_mutex_timedlock
464 pthread_mutex_t *mutex,
465 void* timeout)
466{
467 int ret;
468 OrigFn fn;
469 VALGRIND_GET_ORIG_FN(fn);
470 if (TRACE_PTH_FNS) {
471 fprintf(stderr, "<< pthread_mxtimedlock %p %p", mutex, timeout);
472 fflush(stderr);
473 }
474
475 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
476 pthread_mutex_t*,mutex, long,1/*isTryLock-ish*/);
477
478 CALL_FN_W_WW(ret, fn, mutex,timeout);
479
480 /* There's a hole here: libpthread now knows the lock is locked,
481 but the tool doesn't, so some other thread could run and detect
482 that the lock has been acquired by someone (this thread). Does
483 this matter? Not sure, but I don't think so. */
484
485 if (ret == 0 /*success*/) {
486 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
487 pthread_mutex_t*,mutex);
488 } else {
489 if (ret != ETIMEDOUT)
490 DO_PthAPIerror( "pthread_mutex_timedlock", ret );
491 }
492
493 if (TRACE_PTH_FNS) {
494 fprintf(stderr, " :: mxtimedlock -> %d >>\n", ret);
495 }
496 return ret;
497}
498
499
500// pthread_mutex_unlock
501PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock
502 pthread_mutex_t *mutex)
503{
504 int ret;
505 OrigFn fn;
506 VALGRIND_GET_ORIG_FN(fn);
507
508 if (TRACE_PTH_FNS) {
509 fprintf(stderr, "<< pthread_mxunlk %p", mutex); fflush(stderr);
510 }
511
512 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
513 pthread_mutex_t*,mutex);
514
515 CALL_FN_W_W(ret, fn, mutex);
516
517 if (ret == 0 /*success*/) {
518 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
519 pthread_mutex_t*,mutex);
520 } else {
521 DO_PthAPIerror( "pthread_mutex_unlock", ret );
522 }
523
524 if (TRACE_PTH_FNS) {
525 fprintf(stderr, " mxunlk -> %d >>\n", ret);
526 }
527 return ret;
528}
529
530
531/*----------------------------------------------------------------*/
532/*--- pthread_cond_t functions ---*/
533/*----------------------------------------------------------------*/
534
535/* Handled: pthread_cond_wait pthread_cond_timedwait
536 pthread_cond_signal pthread_cond_broadcast
sewardjf98e1c02008-10-25 16:22:41 +0000537 pthread_cond_destroy
sewardjb4112022007-11-09 22:49:28 +0000538
sewardjf98e1c02008-10-25 16:22:41 +0000539 Unhandled: pthread_cond_init
540 -- is this important?
sewardjb4112022007-11-09 22:49:28 +0000541*/
542
543// pthread_cond_wait
544PTH_FUNC(int, pthreadZucondZuwaitZAZa, // pthread_cond_wait@*
545 pthread_cond_t* cond, pthread_mutex_t* mutex)
546{
547 int ret;
548 OrigFn fn;
549 unsigned long mutex_is_valid;
550
551 VALGRIND_GET_ORIG_FN(fn);
552
553 if (TRACE_PTH_FNS) {
554 fprintf(stderr, "<< pthread_cond_wait %p %p", cond, mutex);
555 fflush(stderr);
556 }
557
558 /* Tell the tool a cond-wait is about to happen, so it can check
559 for bogus argument values. In return it tells us whether it
560 thinks the mutex is valid or not. */
561 DO_CREQ_W_WW(mutex_is_valid,
562 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
563 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
564 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
565
566 /* Tell the tool we're about to drop the mutex. This reflects the
567 fact that in a cond_wait, we show up holding the mutex, and the
568 call atomically drops the mutex and waits for the cv to be
569 signalled. */
570 if (mutex_is_valid) {
571 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
572 pthread_mutex_t*,mutex);
573 }
574
575 CALL_FN_W_WW(ret, fn, cond,mutex);
576
577 /* these conditionals look stupid, but compare w/ same logic for
578 pthread_cond_timedwait below */
579 if (ret == 0 && mutex_is_valid) {
580 /* and now we have the mutex again */
581 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
582 pthread_mutex_t*,mutex);
583 }
584
585 if (ret == 0 && mutex_is_valid) {
586 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
587 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
588 }
589
590 if (ret != 0) {
591 DO_PthAPIerror( "pthread_cond_wait", ret );
592 }
593
594 if (TRACE_PTH_FNS) {
595 fprintf(stderr, " cowait -> %d >>\n", ret);
596 }
597
598 return ret;
599}
600
601
602// pthread_cond_timedwait
603PTH_FUNC(int, pthreadZucondZutimedwaitZAZa, // pthread_cond_timedwait@*
604 pthread_cond_t* cond, pthread_mutex_t* mutex,
605 struct timespec* abstime)
606{
607 int ret;
608 OrigFn fn;
609 unsigned long mutex_is_valid;
610 VALGRIND_GET_ORIG_FN(fn);
611
612 if (TRACE_PTH_FNS) {
613 fprintf(stderr, "<< pthread_cond_timedwait %p %p %p",
614 cond, mutex, abstime);
615 fflush(stderr);
616 }
617
618 /* Tell the tool a cond-wait is about to happen, so it can check
619 for bogus argument values. In return it tells us whether it
620 thinks the mutex is valid or not. */
621 DO_CREQ_W_WW(mutex_is_valid,
622 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
623 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
624 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
625
626 /* Tell the tool we're about to drop the mutex. This reflects the
627 fact that in a cond_wait, we show up holding the mutex, and the
628 call atomically drops the mutex and waits for the cv to be
629 signalled. */
630 if (mutex_is_valid) {
631 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
632 pthread_mutex_t*,mutex);
633 }
634
635 CALL_FN_W_WWW(ret, fn, cond,mutex,abstime);
636
637 if ((ret == 0 || ret == ETIMEDOUT) && mutex_is_valid) {
638 /* and now we have the mutex again */
639 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
640 pthread_mutex_t*,mutex);
641 }
642
643 if (ret == 0 && mutex_is_valid) {
644 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
645 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
646 }
647
648 if (ret != 0 && ret != ETIMEDOUT) {
649 DO_PthAPIerror( "pthread_cond_timedwait", ret );
650 }
651
652 if (TRACE_PTH_FNS) {
653 fprintf(stderr, " cotimedwait -> %d >>\n", ret);
654 }
655
656 return ret;
657}
658
659
660// pthread_cond_signal
661PTH_FUNC(int, pthreadZucondZusignalZAZa, // pthread_cond_signal@*
662 pthread_cond_t* cond)
663{
664 int ret;
665 OrigFn fn;
666 VALGRIND_GET_ORIG_FN(fn);
667
668 if (TRACE_PTH_FNS) {
669 fprintf(stderr, "<< pthread_cond_signal %p", cond);
670 fflush(stderr);
671 }
672
673 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE,
674 pthread_cond_t*,cond);
675
676 CALL_FN_W_W(ret, fn, cond);
677
678 if (ret != 0) {
679 DO_PthAPIerror( "pthread_cond_signal", ret );
680 }
681
682 if (TRACE_PTH_FNS) {
683 fprintf(stderr, " cosig -> %d >>\n", ret);
684 }
685
686 return ret;
687}
688
689
690// pthread_cond_broadcast
691// Note, this is pretty much identical, from a dependency-graph
692// point of view, with cond_signal, so the code is duplicated.
693// Maybe it should be commoned up.
694PTH_FUNC(int, pthreadZucondZubroadcastZAZa, // pthread_cond_broadcast@*
695 pthread_cond_t* cond)
696{
697 int ret;
698 OrigFn fn;
699 VALGRIND_GET_ORIG_FN(fn);
700
701 if (TRACE_PTH_FNS) {
702 fprintf(stderr, "<< pthread_broadcast_signal %p", cond);
703 fflush(stderr);
704 }
705
706 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE,
707 pthread_cond_t*,cond);
708
709 CALL_FN_W_W(ret, fn, cond);
710
711 if (ret != 0) {
712 DO_PthAPIerror( "pthread_cond_broadcast", ret );
713 }
714
715 if (TRACE_PTH_FNS) {
716 fprintf(stderr, " cobro -> %d >>\n", ret);
717 }
718
719 return ret;
720}
721
722
sewardjf98e1c02008-10-25 16:22:41 +0000723// pthread_cond_destroy
724PTH_FUNC(int, pthreadZucondZudestroyZAZa, // pthread_cond_destroy@*
725 pthread_cond_t* cond)
726{
727 int ret;
728 OrigFn fn;
729
730 VALGRIND_GET_ORIG_FN(fn);
731
732 if (TRACE_PTH_FNS) {
733 fprintf(stderr, "<< pthread_cond_destroy %p", cond);
734 fflush(stderr);
735 }
736
737 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_DESTROY_PRE,
738 pthread_cond_t*,cond);
739
740 CALL_FN_W_W(ret, fn, cond);
741
742 if (ret != 0) {
743 DO_PthAPIerror( "pthread_cond_destroy", ret );
744 }
745
746 if (TRACE_PTH_FNS) {
747 fprintf(stderr, " codestr -> %d >>\n", ret);
748 }
749
750 return ret;
751}
752
753
754/*----------------------------------------------------------------*/
755/*--- pthread_barrier_t functions ---*/
756/*----------------------------------------------------------------*/
757
758PTH_FUNC(int, pthreadZubarrierZuwait, // pthread_barrier_wait.
759 pthread_barrier_t* b)
760{
761 int ret;
762 OrigFn fn;
763 VALGRIND_GET_ORIG_FN(fn);
764
765 if (TRACE_PTH_FNS) {
766 fprintf(stderr, "<< pthread_barrier_wait %p", b);
767 fflush(stderr);
768 }
769
770 // We blocked, signal.
771 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE,
772 void*,b);
773 CALL_FN_W_W(ret, fn, b);
774
775 // FIXME: handle ret
776
777 // We unblocked, finish wait.
778 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
779 void *, b, void *, b);
780
781 if (TRACE_PTH_FNS) {
782 fprintf(stderr, " pthread_barrier_wait -> %d >>\n", ret);
783 }
784
785 return ret;
786}
787
788
789
sewardjb4112022007-11-09 22:49:28 +0000790/*----------------------------------------------------------------*/
791/*--- pthread_rwlock_t functions ---*/
792/*----------------------------------------------------------------*/
793
794/* Handled: pthread_rwlock_init pthread_rwlock_destroy
795 pthread_rwlock_rdlock
796 pthread_rwlock_wrlock
797 pthread_rwlock_unlock
798
799 Unhandled: pthread_rwlock_timedrdlock
800 pthread_rwlock_tryrdlock
801
802 pthread_rwlock_timedwrlock
803 pthread_rwlock_trywrlock
804*/
805
806// pthread_rwlock_init
807PTH_FUNC(int, pthreadZurwlockZuinit, // pthread_rwlock_init
808 pthread_rwlock_t *rwl,
809 pthread_rwlockattr_t* attr)
810{
811 int ret;
812 OrigFn fn;
813 VALGRIND_GET_ORIG_FN(fn);
814 if (TRACE_PTH_FNS) {
815 fprintf(stderr, "<< pthread_rwl_init %p", rwl); fflush(stderr);
816 }
817
818 CALL_FN_W_WW(ret, fn, rwl,attr);
819
820 if (ret == 0 /*success*/) {
821 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
822 pthread_rwlock_t*,rwl);
823 } else {
824 DO_PthAPIerror( "pthread_rwlock_init", ret );
825 }
826
827 if (TRACE_PTH_FNS) {
828 fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
829 }
830 return ret;
831}
832
833
834// pthread_rwlock_destroy
835PTH_FUNC(int, pthreadZurwlockZudestroy, // pthread_rwlock_destroy
836 pthread_rwlock_t *rwl)
837{
838 int ret;
839 OrigFn fn;
840 VALGRIND_GET_ORIG_FN(fn);
841 if (TRACE_PTH_FNS) {
842 fprintf(stderr, "<< pthread_rwl_destroy %p", rwl); fflush(stderr);
843 }
844
845 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE,
846 pthread_rwlock_t*,rwl);
847
848 CALL_FN_W_W(ret, fn, rwl);
849
850 if (ret != 0) {
851 DO_PthAPIerror( "pthread_rwlock_destroy", ret );
852 }
853
854 if (TRACE_PTH_FNS) {
855 fprintf(stderr, " :: rwl_destroy -> %d >>\n", ret);
856 }
857 return ret;
858}
859
860
sewardj789c3c52008-02-25 12:10:07 +0000861// pthread_rwlock_wrlock
sewardjb4112022007-11-09 22:49:28 +0000862PTH_FUNC(int, pthreadZurwlockZuwrlock, // pthread_rwlock_wrlock
863 pthread_rwlock_t* rwlock)
864{
865 int ret;
866 OrigFn fn;
867 VALGRIND_GET_ORIG_FN(fn);
868 if (TRACE_PTH_FNS) {
869 fprintf(stderr, "<< pthread_rwl_wlk %p", rwlock); fflush(stderr);
870 }
871
sewardj789c3c52008-02-25 12:10:07 +0000872 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
873 pthread_rwlock_t*,rwlock,
874 long,1/*isW*/, long,0/*!isTryLock*/);
sewardjb4112022007-11-09 22:49:28 +0000875
876 CALL_FN_W_W(ret, fn, rwlock);
877
878 if (ret == 0 /*success*/) {
879 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
880 pthread_rwlock_t*,rwlock, long,1/*isW*/);
881 } else {
882 DO_PthAPIerror( "pthread_rwlock_wrlock", ret );
883 }
884
885 if (TRACE_PTH_FNS) {
886 fprintf(stderr, " :: rwl_wlk -> %d >>\n", ret);
887 }
888 return ret;
889}
890
891
sewardj789c3c52008-02-25 12:10:07 +0000892// pthread_rwlock_rdlock
sewardjb4112022007-11-09 22:49:28 +0000893PTH_FUNC(int, pthreadZurwlockZurdlock, // pthread_rwlock_rdlock
894 pthread_rwlock_t* rwlock)
895{
896 int ret;
897 OrigFn fn;
898 VALGRIND_GET_ORIG_FN(fn);
899 if (TRACE_PTH_FNS) {
900 fprintf(stderr, "<< pthread_rwl_rlk %p", rwlock); fflush(stderr);
901 }
902
sewardj789c3c52008-02-25 12:10:07 +0000903 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
904 pthread_rwlock_t*,rwlock,
905 long,0/*!isW*/, long,0/*!isTryLock*/);
sewardjb4112022007-11-09 22:49:28 +0000906
907 CALL_FN_W_W(ret, fn, rwlock);
908
909 if (ret == 0 /*success*/) {
910 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
911 pthread_rwlock_t*,rwlock, long,0/*!isW*/);
912 } else {
913 DO_PthAPIerror( "pthread_rwlock_rdlock", ret );
914 }
915
916 if (TRACE_PTH_FNS) {
917 fprintf(stderr, " :: rwl_rlk -> %d >>\n", ret);
918 }
919 return ret;
920}
921
922
sewardj789c3c52008-02-25 12:10:07 +0000923// pthread_rwlock_trywrlock
924PTH_FUNC(int, pthreadZurwlockZutrywrlock, // pthread_rwlock_trywrlock
925 pthread_rwlock_t* rwlock)
926{
927 int ret;
928 OrigFn fn;
929 VALGRIND_GET_ORIG_FN(fn);
930 if (TRACE_PTH_FNS) {
931 fprintf(stderr, "<< pthread_rwl_trywlk %p", rwlock); fflush(stderr);
932 }
933
934 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
935 pthread_rwlock_t*,rwlock,
936 long,1/*isW*/, long,1/*isTryLock*/);
937
938 CALL_FN_W_W(ret, fn, rwlock);
939
940 /* There's a hole here: libpthread now knows the lock is locked,
941 but the tool doesn't, so some other thread could run and detect
942 that the lock has been acquired by someone (this thread). Does
943 this matter? Not sure, but I don't think so. */
944
945 if (ret == 0 /*success*/) {
946 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
947 pthread_rwlock_t*,rwlock, long,1/*isW*/);
948 } else {
949 if (ret != EBUSY)
950 DO_PthAPIerror( "pthread_rwlock_trywrlock", ret );
951 }
952
953 if (TRACE_PTH_FNS) {
954 fprintf(stderr, " :: rwl_trywlk -> %d >>\n", ret);
955 }
956 return ret;
957}
958
959
960// pthread_rwlock_tryrdlock
961PTH_FUNC(int, pthreadZurwlockZutryrdlock, // pthread_rwlock_tryrdlock
962 pthread_rwlock_t* rwlock)
963{
964 int ret;
965 OrigFn fn;
966 VALGRIND_GET_ORIG_FN(fn);
967 if (TRACE_PTH_FNS) {
968 fprintf(stderr, "<< pthread_rwl_tryrlk %p", rwlock); fflush(stderr);
969 }
970
971 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
972 pthread_rwlock_t*,rwlock,
973 long,0/*!isW*/, long,1/*isTryLock*/);
974
975 CALL_FN_W_W(ret, fn, rwlock);
976
977 /* There's a hole here: libpthread now knows the lock is locked,
978 but the tool doesn't, so some other thread could run and detect
979 that the lock has been acquired by someone (this thread). Does
980 this matter? Not sure, but I don't think so. */
981
982 if (ret == 0 /*success*/) {
983 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
984 pthread_rwlock_t*,rwlock, long,0/*!isW*/);
985 } else {
986 if (ret != EBUSY)
987 DO_PthAPIerror( "pthread_rwlock_tryrdlock", ret );
988 }
989
990 if (TRACE_PTH_FNS) {
991 fprintf(stderr, " :: rwl_tryrlk -> %d >>\n", ret);
992 }
993 return ret;
994}
995
996
997// pthread_rwlock_unlock
sewardjb4112022007-11-09 22:49:28 +0000998PTH_FUNC(int, pthreadZurwlockZuunlock, // pthread_rwlock_unlock
999 pthread_rwlock_t* rwlock)
1000{
1001 int ret;
1002 OrigFn fn;
1003 VALGRIND_GET_ORIG_FN(fn);
1004 if (TRACE_PTH_FNS) {
1005 fprintf(stderr, "<< pthread_rwl_unlk %p", rwlock); fflush(stderr);
1006 }
1007
1008 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
1009 pthread_rwlock_t*,rwlock);
1010
1011 CALL_FN_W_W(ret, fn, rwlock);
1012
1013 if (ret == 0 /*success*/) {
1014 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
1015 pthread_rwlock_t*,rwlock);
1016 } else {
1017 DO_PthAPIerror( "pthread_rwlock_unlock", ret );
1018 }
1019
1020 if (TRACE_PTH_FNS) {
1021 fprintf(stderr, " :: rwl_unlk -> %d >>\n", ret);
1022 }
1023 return ret;
1024}
1025
1026
1027/*----------------------------------------------------------------*/
1028/*--- POSIX semaphores ---*/
1029/*----------------------------------------------------------------*/
1030
1031#include <semaphore.h>
1032
1033#define TRACE_SEM_FNS 0
1034
1035/* Handled:
1036 int sem_init(sem_t *sem, int pshared, unsigned value);
1037 int sem_destroy(sem_t *sem);
1038 int sem_wait(sem_t *sem);
1039 int sem_post(sem_t *sem);
1040
1041 Unhandled:
1042 int sem_trywait(sem_t *sem);
1043 int sem_timedwait(sem_t *restrict sem,
1044 const struct timespec *restrict abs_timeout);
1045*/
1046
1047/* glibc-2.5 has sem_init@@GLIBC_2.2.5 (amd64-linux)
1048 and sem_init@@GLIBC_2.1 (x86-linux): match sem_init@* */
1049PTH_FUNC(int, semZuinitZAZa, sem_t* sem, int pshared, unsigned long value)
1050{
1051 OrigFn fn;
1052 int ret;
1053 VALGRIND_GET_ORIG_FN(fn);
1054
1055 if (TRACE_SEM_FNS) {
1056 fprintf(stderr, "<< sem_init(%p,%d,%lu) ", sem,pshared,value);
1057 fflush(stderr);
1058 }
1059
1060 CALL_FN_W_WWW(ret, fn, sem,pshared,value);
1061
1062 if (ret == 0) {
sewardj11e352f2007-11-30 11:11:02 +00001063 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
1064 sem_t*, sem, unsigned long, value);
sewardjb4112022007-11-09 22:49:28 +00001065 } else {
1066 DO_PthAPIerror( "sem_init", errno );
1067 }
1068
1069 if (TRACE_SEM_FNS) {
1070 fprintf(stderr, " sem_init -> %d >>\n", ret);
1071 fflush(stderr);
1072 }
1073
1074 return ret;
1075}
1076
1077
1078/* glibc-2.5 has sem_destroy@@GLIBC_2.2.5 (amd64-linux)
1079 and sem_destroy@@GLIBC_2.1 (x86-linux); match sem_destroy@* */
1080PTH_FUNC(int, semZudestroyZAZa, sem_t* sem)
1081{
1082 OrigFn fn;
1083 int ret;
1084 VALGRIND_GET_ORIG_FN(fn);
1085
1086 if (TRACE_SEM_FNS) {
1087 fprintf(stderr, "<< sem_destroy(%p) ", sem);
1088 fflush(stderr);
1089 }
1090
sewardj11e352f2007-11-30 11:11:02 +00001091 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
sewardjb4112022007-11-09 22:49:28 +00001092
1093 CALL_FN_W_W(ret, fn, sem);
1094
1095 if (ret != 0) {
1096 DO_PthAPIerror( "sem_destroy", errno );
1097 }
1098
1099 if (TRACE_SEM_FNS) {
1100 fprintf(stderr, " sem_destroy -> %d >>\n", ret);
1101 fflush(stderr);
1102 }
1103
1104 return ret;
1105}
1106
1107
1108/* glibc-2.5 has sem_wait (amd64-linux); match sem_wait
1109 and sem_wait@@GLIBC_2.1 (x86-linux); match sem_wait@* */
1110/* wait: decrement semaphore - acquire lockage */
1111static int sem_wait_WRK(sem_t* sem)
1112{
1113 OrigFn fn;
1114 int ret;
1115 VALGRIND_GET_ORIG_FN(fn);
1116
1117 if (TRACE_SEM_FNS) {
1118 fprintf(stderr, "<< sem_wait(%p) ", sem);
1119 fflush(stderr);
1120 }
1121
1122 CALL_FN_W_W(ret, fn, sem);
1123
1124 if (ret == 0) {
sewardj11e352f2007-11-30 11:11:02 +00001125 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST, sem_t*,sem);
sewardjb4112022007-11-09 22:49:28 +00001126 } else {
1127 DO_PthAPIerror( "sem_wait", errno );
1128 }
1129
1130 if (TRACE_SEM_FNS) {
1131 fprintf(stderr, " sem_wait -> %d >>\n", ret);
1132 fflush(stderr);
1133 }
1134
1135 return ret;
1136}
1137PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
1138 return sem_wait_WRK(sem);
1139}
1140PTH_FUNC(int, semZuwaitZAZa, sem_t* sem) { /* sem_wait@* */
1141 return sem_wait_WRK(sem);
1142}
1143
1144
1145/* glibc-2.5 has sem_post (amd64-linux); match sem_post
1146 and sem_post@@GLIBC_2.1 (x86-linux); match sem_post@* */
1147/* post: increment semaphore - release lockage */
1148static int sem_post_WRK(sem_t* sem)
1149{
1150 OrigFn fn;
1151 int ret;
1152
1153 VALGRIND_GET_ORIG_FN(fn);
1154
1155 if (TRACE_SEM_FNS) {
1156 fprintf(stderr, "<< sem_post(%p) ", sem);
1157 fflush(stderr);
1158 }
1159
sewardj11e352f2007-11-30 11:11:02 +00001160 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_PRE, sem_t*,sem);
sewardjb4112022007-11-09 22:49:28 +00001161
1162 CALL_FN_W_W(ret, fn, sem);
1163
1164 if (ret != 0) {
1165 DO_PthAPIerror( "sem_post", errno );
1166 }
1167
1168 if (TRACE_SEM_FNS) {
1169 fprintf(stderr, " sem_post -> %d >>\n", ret);
1170 fflush(stderr);
1171 }
1172
1173 return ret;
1174}
1175PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
1176 return sem_post_WRK(sem);
1177}
1178PTH_FUNC(int, semZupostZAZa, sem_t* sem) { /* sem_post@* */
1179 return sem_post_WRK(sem);
1180}
1181
1182
1183
1184/*----------------------------------------------------------------*/
1185/*--- Qt 4 threading functions (w/ GNU name mangling) ---*/
1186/*----------------------------------------------------------------*/
1187
1188/* Handled: QMutex::lock()
1189 QMutex::unlock()
1190 QMutex::tryLock
1191 QReadWriteLock::lockForRead()
1192 QReadWriteLock::lockForWrite()
1193 QReadWriteLock::unlock()
1194
1195 Unhandled: QMutex::tryLock(int)
1196 QReadWriteLock::tryLockForRead(int)
1197 QReadWriteLock::tryLockForRead()
1198 QReadWriteLock::tryLockForWrite(int)
1199 QReadWriteLock::tryLockForWrite()
1200
1201 maybe not the next 3; qt-4.3.1 on Unix merely
1202 implements QWaitCondition using pthread_cond_t
1203 QWaitCondition::wait(QMutex*, unsigned long)
1204 QWaitCondition::wakeAll()
1205 QWaitCondition::wakeOne()
1206*/
1207
1208// soname is libQtCore.so.4 ; match against libQtCore.so*
1209#define QT4_FUNC(ret_ty, f, args...) \
1210 ret_ty I_WRAP_SONAME_FNNAME_ZZ(libQtCoreZdsoZa,f)(args); \
1211 ret_ty I_WRAP_SONAME_FNNAME_ZZ(libQtCoreZdsoZa,f)(args)
1212
1213// QMutex::lock()
1214QT4_FUNC(void, ZuZZN6QMutex4lockEv, // _ZN6QMutex4lockEv == QMutex::lock()
1215 void* self)
1216{
1217 OrigFn fn;
1218 VALGRIND_GET_ORIG_FN(fn);
1219 if (TRACE_QT4_FNS) {
1220 fprintf(stderr, "<< QMutex::lock %p", self); fflush(stderr);
1221 }
1222
1223 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
1224 void*,self, long,0/*!isTryLock*/);
1225
1226 CALL_FN_v_W(fn, self);
1227
1228 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1229 void*, self);
1230
1231 if (TRACE_QT4_FNS) {
1232 fprintf(stderr, " :: Q::lock done >>\n");
1233 }
1234}
1235
1236// QMutex::unlock()
1237QT4_FUNC(void, ZuZZN6QMutex6unlockEv, // _ZN6QMutex6unlockEv == QMutex::unlock()
1238 void* self)
1239{
1240 OrigFn fn;
1241 VALGRIND_GET_ORIG_FN(fn);
1242
1243 if (TRACE_QT4_FNS) {
1244 fprintf(stderr, "<< QMutex::unlock %p", self); fflush(stderr);
1245 }
1246
1247 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1248 void*, self);
1249
1250 CALL_FN_v_W(fn, self);
1251
1252 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
1253 void*, self);
1254
1255 if (TRACE_QT4_FNS) {
1256 fprintf(stderr, " Q::unlock done >>\n");
1257 }
1258}
1259
1260// QMutex::tryLock
1261// _ZN6QMutex7tryLockEv == bool QMutex::tryLock()
1262// using 'long' to mimic C++ 'bool'
1263QT4_FUNC(long, ZuZZN6QMutex7tryLockEv,
1264 void* self)
1265{
1266 OrigFn fn;
1267 long ret;
1268 VALGRIND_GET_ORIG_FN(fn);
1269 if (TRACE_QT4_FNS) {
1270 fprintf(stderr, "<< QMutex::tryLock %p", self); fflush(stderr);
1271 }
1272
1273 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
1274 void*,self, long,1/*isTryLock*/);
1275
1276 CALL_FN_W_W(ret, fn, self);
1277
1278 // assumes that only the low 8 bits of the 'bool' are significant
1279 if (ret & 0xFF) {
1280 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1281 void*, self);
1282 }
1283
1284 if (TRACE_QT4_FNS) {
1285 fprintf(stderr, " :: Q::tryLock -> %lu >>\n", ret);
1286 }
1287
1288 return ret;
1289}
1290
1291
1292// QReadWriteLock::lockForRead()
1293// _ZN14QReadWriteLock11lockForReadEv == QReadWriteLock::lockForRead()
1294QT4_FUNC(void, ZuZZN14QReadWriteLock11lockForReadEv,
1295 // _ZN14QReadWriteLock11lockForReadEv
1296 void* self)
1297{
1298 OrigFn fn;
1299 VALGRIND_GET_ORIG_FN(fn);
1300 if (TRACE_QT4_FNS) {
1301 fprintf(stderr, "<< QReadWriteLock::lockForRead %p", self);
1302 fflush(stderr);
1303 }
1304
sewardj789c3c52008-02-25 12:10:07 +00001305 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1306 void*,self,
1307 long,0/*!isW*/, long,0/*!isTryLock*/);
sewardjb4112022007-11-09 22:49:28 +00001308
1309 CALL_FN_v_W(fn, self);
1310
1311 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1312 void*,self, long,0/*!isW*/);
1313
1314 if (TRACE_QT4_FNS) {
1315 fprintf(stderr, " :: Q::lockForRead :: done >>\n");
1316 }
1317}
1318
1319// QReadWriteLock::lockForWrite()
1320// _ZN14QReadWriteLock12lockForWriteEv == QReadWriteLock::lockForWrite()
1321QT4_FUNC(void, ZuZZN14QReadWriteLock12lockForWriteEv,
1322 // _ZN14QReadWriteLock12lockForWriteEv
1323 void* self)
1324{
1325 OrigFn fn;
1326 VALGRIND_GET_ORIG_FN(fn);
1327 if (TRACE_QT4_FNS) {
1328 fprintf(stderr, "<< QReadWriteLock::lockForWrite %p", self);
1329 fflush(stderr);
1330 }
1331
sewardj789c3c52008-02-25 12:10:07 +00001332 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1333 void*,self,
1334 long,1/*isW*/, long,0/*!isTryLock*/);
sewardjb4112022007-11-09 22:49:28 +00001335
1336 CALL_FN_v_W(fn, self);
1337
1338 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1339 void*,self, long,1/*isW*/);
1340
1341 if (TRACE_QT4_FNS) {
1342 fprintf(stderr, " :: Q::lockForWrite :: done >>\n");
1343 }
1344}
1345
1346// QReadWriteLock::unlock()
1347// _ZN14QReadWriteLock6unlockEv == QReadWriteLock::unlock()
1348QT4_FUNC(void, ZuZZN14QReadWriteLock6unlockEv,
1349 // _ZN14QReadWriteLock6unlockEv
1350 void* self)
1351{
1352 OrigFn fn;
1353 VALGRIND_GET_ORIG_FN(fn);
1354 if (TRACE_QT4_FNS) {
1355 fprintf(stderr, "<< QReadWriteLock::unlock %p", self);
1356 fflush(stderr);
1357 }
1358
1359 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
1360 void*,self);
1361
1362 CALL_FN_v_W(fn, self);
1363
1364 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
1365 void*,self);
1366
1367 if (TRACE_QT4_FNS) {
1368 fprintf(stderr, " :: Q::unlock :: done >>\n");
1369 }
1370}
1371
1372
1373/*--------------------------------------------------------------------*/
1374/*--- end tc_intercepts.c ---*/
1375/*--------------------------------------------------------------------*/