blob: 10be82b9b01fe5c31301ec2a1aea07f2608d31e7 [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
11 Copyright (C) 2007-2007 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#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
176static void* mythread_wrapper ( void* xargsV )
177{
178 volatile Word volatile* xargs = (volatile Word volatile*) xargsV;
179 void*(*fn)(void*) = (void*(*)(void*))xargs[0];
180 void* arg = (void*)xargs[1];
181 pthread_t me = pthread_self();
182 /* Tell the tool what my pthread_t is. */
183 DO_CREQ_v_W(_VG_USERREQ__HG_SET_MY_PTHREAD_T, pthread_t,me);
184 /* allow the parent to proceed. We can't let it proceed until
185 we're ready because (1) we need to make sure it doesn't exit and
186 hence deallocate xargs[] while we still need it, and (2) we
187 don't want either parent nor child to proceed until the tool has
188 been notified of the child's pthread_t. */
189 xargs[2] = 0;
190 /* Now we can no longer safely use xargs[]. */
191 return (void*) fn( (void*)arg );
192}
193
194// pthread_create
195PTH_FUNC(int, pthreadZucreateZAZa, // pthread_create@*
196 pthread_t *thread, const pthread_attr_t *attr,
197 void *(*start) (void *), void *arg)
198{
199 int ret;
200 OrigFn fn;
201 volatile Word xargs[3];
202
203 VALGRIND_GET_ORIG_FN(fn);
204 if (TRACE_PTH_FNS) {
205 fprintf(stderr, "<< pthread_create wrapper"); fflush(stderr);
206 }
207 xargs[0] = (Word)start;
208 xargs[1] = (Word)arg;
209 xargs[2] = 1; /* serves as a spinlock -- sigh */
210
211 CALL_FN_W_WWWW(ret, fn, thread,attr,mythread_wrapper,&xargs[0]);
212
213 if (ret == 0) {
214 /* we have to wait for the child to notify the tool of its
215 pthread_t before continuing */
216 while (xargs[2] != 0) {
217 // FIXME: add a yield client request
218 /* do nothing */
219 }
220 } else {
221 DO_PthAPIerror( "pthread_create", ret );
222 }
223
224 if (TRACE_PTH_FNS) {
225 fprintf(stderr, " :: pth_create -> %d >>\n", ret);
226 }
227 return ret;
228}
229
230// pthread_join
231PTH_FUNC(int, pthreadZujoin, // pthread_join
232 pthread_t thread, void** value_pointer)
233{
234 int ret;
235 OrigFn fn;
236 VALGRIND_GET_ORIG_FN(fn);
237 if (TRACE_PTH_FNS) {
238 fprintf(stderr, "<< pthread_join wrapper"); fflush(stderr);
239 }
240
241 CALL_FN_W_WW(ret, fn, thread,value_pointer);
242
243 /* At least with NPTL as the thread library, this is safe because
244 it is guaranteed (by NPTL) that the joiner will completely gone
245 before pthread_join (the original) returns. See email below.*/
246 if (ret == 0 /*success*/) {
247 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST, pthread_t,thread);
248 } else {
249 DO_PthAPIerror( "pthread_join", ret );
250 }
251
252 if (TRACE_PTH_FNS) {
253 fprintf(stderr, " :: pth_join -> %d >>\n", ret);
254 }
255 return ret;
256}
257
258/* Behaviour of pthread_join on NPTL:
259
260Me:
261I have a question re the NPTL pthread_join implementation.
262
263 Suppose I am the thread 'stayer'.
264
265 If I call pthread_join(quitter), is it guaranteed that the
266 thread 'quitter' has really exited before pthread_join returns?
267
268 IOW, is it guaranteed that 'quitter' will not execute any further
269 instructions after pthread_join returns?
270
271I believe this is true based on the following analysis of
272glibc-2.5 sources. However am not 100% sure and would appreciate
273confirmation.
274
275 'quitter' will be running start_thread() in nptl/pthread_create.c
276
277 The last action of start_thread() is to exit via
278 __exit_thread_inline(0), which simply does sys_exit
279 (nptl/pthread_create.c:403)
280
281 'stayer' meanwhile is waiting for lll_wait_tid (pd->tid)
282 (call at nptl/pthread_join.c:89)
283
284 As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
285 lll_wait_tid will not return until kernel notifies via futex
286 wakeup that 'quitter' has terminated.
287
288 Hence pthread_join cannot return until 'quitter' really has
289 completely disappeared.
290
291Drepper:
292> As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
293> lll_wait_tid will not return until kernel notifies via futex
294> wakeup that 'quitter' has terminated.
295That's the key. The kernel resets the TID field after the thread is
296done. No way the joiner can return before the thread is gone.
297*/
298
299
300/*----------------------------------------------------------------*/
301/*--- pthread_mutex_t functions ---*/
302/*----------------------------------------------------------------*/
303
304/* Handled: pthread_mutex_init pthread_mutex_destroy
305 pthread_mutex_lock
306 pthread_mutex_trylock pthread_mutex_timedlock
307 pthread_mutex_unlock
308
309 Unhandled: pthread_spin_init pthread_spin_destroy
310 pthread_spin_lock
311 pthread_spin_trylock
312 pthread_spin_unlock
313*/
314
315// pthread_mutex_init
316PTH_FUNC(int, pthreadZumutexZuinit, // pthread_mutex_init
317 pthread_mutex_t *mutex,
318 pthread_mutexattr_t* attr)
319{
320 int ret;
321 long mbRec;
322 OrigFn fn;
323 VALGRIND_GET_ORIG_FN(fn);
324 if (TRACE_PTH_FNS) {
325 fprintf(stderr, "<< pthread_mxinit %p", mutex); fflush(stderr);
326 }
327
328 mbRec = 0;
329 if (attr) {
330 int ty, zzz;
331 zzz = pthread_mutexattr_gettype(attr, &ty);
332 if (zzz == 0 && ty == PTHREAD_MUTEX_RECURSIVE)
333 mbRec = 1;
334 }
335
336 CALL_FN_W_WW(ret, fn, mutex,attr);
337
338 if (ret == 0 /*success*/) {
339 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
340 pthread_mutex_t*,mutex, long,mbRec);
341 } else {
342 DO_PthAPIerror( "pthread_mutex_init", ret );
343 }
344
345 if (TRACE_PTH_FNS) {
346 fprintf(stderr, " :: mxinit -> %d >>\n", ret);
347 }
348 return ret;
349}
350
351
352// pthread_mutex_destroy
353PTH_FUNC(int, pthreadZumutexZudestroy, // pthread_mutex_destroy
354 pthread_mutex_t *mutex)
355{
356 int ret;
357 OrigFn fn;
358 VALGRIND_GET_ORIG_FN(fn);
359 if (TRACE_PTH_FNS) {
360 fprintf(stderr, "<< pthread_mxdestroy %p", mutex); fflush(stderr);
361 }
362
363 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
364 pthread_mutex_t*,mutex);
365
366 CALL_FN_W_W(ret, fn, mutex);
367
368 if (ret != 0) {
369 DO_PthAPIerror( "pthread_mutex_destroy", ret );
370 }
371
372 if (TRACE_PTH_FNS) {
373 fprintf(stderr, " :: mxdestroy -> %d >>\n", ret);
374 }
375 return ret;
376}
377
378
379// pthread_mutex_lock
380PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock
381 pthread_mutex_t *mutex)
382{
383 int ret;
384 OrigFn fn;
385 VALGRIND_GET_ORIG_FN(fn);
386 if (TRACE_PTH_FNS) {
387 fprintf(stderr, "<< pthread_mxlock %p", mutex); fflush(stderr);
388 }
389
390 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
391 pthread_mutex_t*,mutex, long,0/*!isTryLock*/);
392
393 CALL_FN_W_W(ret, fn, mutex);
394
395 /* There's a hole here: libpthread now knows the lock is locked,
396 but the tool doesn't, so some other thread could run and detect
397 that the lock has been acquired by someone (this thread). Does
398 this matter? Not sure, but I don't think so. */
399
400 if (ret == 0 /*success*/) {
401 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
402 pthread_mutex_t*,mutex);
403 } else {
404 DO_PthAPIerror( "pthread_mutex_lock", ret );
405 }
406
407 if (TRACE_PTH_FNS) {
408 fprintf(stderr, " :: mxlock -> %d >>\n", ret);
409 }
410 return ret;
411}
412
413
414// pthread_mutex_trylock. The handling needed here is very similar
415// to that for pthread_mutex_lock, except that we need to tell
416// the pre-lock creq that this is a trylock-style operation, and
417// therefore not to complain if the lock is nonrecursive and
418// already locked by this thread -- because then it'll just fail
419// immediately with EBUSY.
420PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock
421 pthread_mutex_t *mutex)
422{
423 int ret;
424 OrigFn fn;
425 VALGRIND_GET_ORIG_FN(fn);
426 if (TRACE_PTH_FNS) {
427 fprintf(stderr, "<< pthread_mxtrylock %p", mutex); fflush(stderr);
428 }
429
430 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
431 pthread_mutex_t*,mutex, long,1/*isTryLock*/);
432
433 CALL_FN_W_W(ret, fn, mutex);
434
435 /* There's a hole here: libpthread now knows the lock is locked,
436 but the tool doesn't, so some other thread could run and detect
437 that the lock has been acquired by someone (this thread). Does
438 this matter? Not sure, but I don't think so. */
439
440 if (ret == 0 /*success*/) {
441 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
442 pthread_mutex_t*,mutex);
443 } else {
444 if (ret != EBUSY)
445 DO_PthAPIerror( "pthread_mutex_trylock", ret );
446 }
447
448 if (TRACE_PTH_FNS) {
449 fprintf(stderr, " :: mxtrylock -> %d >>\n", ret);
450 }
451 return ret;
452}
453
454
455// pthread_mutex_timedlock. Identical logic to pthread_mutex_trylock.
456PTH_FUNC(int, pthreadZumutexZutimedlock, // pthread_mutex_timedlock
457 pthread_mutex_t *mutex,
458 void* timeout)
459{
460 int ret;
461 OrigFn fn;
462 VALGRIND_GET_ORIG_FN(fn);
463 if (TRACE_PTH_FNS) {
464 fprintf(stderr, "<< pthread_mxtimedlock %p %p", mutex, timeout);
465 fflush(stderr);
466 }
467
468 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
469 pthread_mutex_t*,mutex, long,1/*isTryLock-ish*/);
470
471 CALL_FN_W_WW(ret, fn, mutex,timeout);
472
473 /* There's a hole here: libpthread now knows the lock is locked,
474 but the tool doesn't, so some other thread could run and detect
475 that the lock has been acquired by someone (this thread). Does
476 this matter? Not sure, but I don't think so. */
477
478 if (ret == 0 /*success*/) {
479 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
480 pthread_mutex_t*,mutex);
481 } else {
482 if (ret != ETIMEDOUT)
483 DO_PthAPIerror( "pthread_mutex_timedlock", ret );
484 }
485
486 if (TRACE_PTH_FNS) {
487 fprintf(stderr, " :: mxtimedlock -> %d >>\n", ret);
488 }
489 return ret;
490}
491
492
493// pthread_mutex_unlock
494PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock
495 pthread_mutex_t *mutex)
496{
497 int ret;
498 OrigFn fn;
499 VALGRIND_GET_ORIG_FN(fn);
500
501 if (TRACE_PTH_FNS) {
502 fprintf(stderr, "<< pthread_mxunlk %p", mutex); fflush(stderr);
503 }
504
505 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
506 pthread_mutex_t*,mutex);
507
508 CALL_FN_W_W(ret, fn, mutex);
509
510 if (ret == 0 /*success*/) {
511 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
512 pthread_mutex_t*,mutex);
513 } else {
514 DO_PthAPIerror( "pthread_mutex_unlock", ret );
515 }
516
517 if (TRACE_PTH_FNS) {
518 fprintf(stderr, " mxunlk -> %d >>\n", ret);
519 }
520 return ret;
521}
522
523
524/*----------------------------------------------------------------*/
525/*--- pthread_cond_t functions ---*/
526/*----------------------------------------------------------------*/
527
528/* Handled: pthread_cond_wait pthread_cond_timedwait
529 pthread_cond_signal pthread_cond_broadcast
530
531 Unhandled: pthread_cond_init pthread_cond_destroy
532 -- are these important?
533*/
534
535// pthread_cond_wait
536PTH_FUNC(int, pthreadZucondZuwaitZAZa, // pthread_cond_wait@*
537 pthread_cond_t* cond, pthread_mutex_t* mutex)
538{
539 int ret;
540 OrigFn fn;
541 unsigned long mutex_is_valid;
542
543 VALGRIND_GET_ORIG_FN(fn);
544
545 if (TRACE_PTH_FNS) {
546 fprintf(stderr, "<< pthread_cond_wait %p %p", cond, mutex);
547 fflush(stderr);
548 }
549
550 /* Tell the tool a cond-wait is about to happen, so it can check
551 for bogus argument values. In return it tells us whether it
552 thinks the mutex is valid or not. */
553 DO_CREQ_W_WW(mutex_is_valid,
554 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
555 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
556 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
557
558 /* Tell the tool we're about to drop the mutex. This reflects the
559 fact that in a cond_wait, we show up holding the mutex, and the
560 call atomically drops the mutex and waits for the cv to be
561 signalled. */
562 if (mutex_is_valid) {
563 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
564 pthread_mutex_t*,mutex);
565 }
566
567 CALL_FN_W_WW(ret, fn, cond,mutex);
568
569 /* these conditionals look stupid, but compare w/ same logic for
570 pthread_cond_timedwait below */
571 if (ret == 0 && mutex_is_valid) {
572 /* and now we have the mutex again */
573 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
574 pthread_mutex_t*,mutex);
575 }
576
577 if (ret == 0 && mutex_is_valid) {
578 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
579 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
580 }
581
582 if (ret != 0) {
583 DO_PthAPIerror( "pthread_cond_wait", ret );
584 }
585
586 if (TRACE_PTH_FNS) {
587 fprintf(stderr, " cowait -> %d >>\n", ret);
588 }
589
590 return ret;
591}
592
593
594// pthread_cond_timedwait
595PTH_FUNC(int, pthreadZucondZutimedwaitZAZa, // pthread_cond_timedwait@*
596 pthread_cond_t* cond, pthread_mutex_t* mutex,
597 struct timespec* abstime)
598{
599 int ret;
600 OrigFn fn;
601 unsigned long mutex_is_valid;
602 VALGRIND_GET_ORIG_FN(fn);
603
604 if (TRACE_PTH_FNS) {
605 fprintf(stderr, "<< pthread_cond_timedwait %p %p %p",
606 cond, mutex, abstime);
607 fflush(stderr);
608 }
609
610 /* Tell the tool a cond-wait is about to happen, so it can check
611 for bogus argument values. In return it tells us whether it
612 thinks the mutex is valid or not. */
613 DO_CREQ_W_WW(mutex_is_valid,
614 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
615 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
616 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
617
618 /* Tell the tool we're about to drop the mutex. This reflects the
619 fact that in a cond_wait, we show up holding the mutex, and the
620 call atomically drops the mutex and waits for the cv to be
621 signalled. */
622 if (mutex_is_valid) {
623 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
624 pthread_mutex_t*,mutex);
625 }
626
627 CALL_FN_W_WWW(ret, fn, cond,mutex,abstime);
628
629 if ((ret == 0 || ret == ETIMEDOUT) && mutex_is_valid) {
630 /* and now we have the mutex again */
631 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
632 pthread_mutex_t*,mutex);
633 }
634
635 if (ret == 0 && mutex_is_valid) {
636 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
637 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
638 }
639
640 if (ret != 0 && ret != ETIMEDOUT) {
641 DO_PthAPIerror( "pthread_cond_timedwait", ret );
642 }
643
644 if (TRACE_PTH_FNS) {
645 fprintf(stderr, " cotimedwait -> %d >>\n", ret);
646 }
647
648 return ret;
649}
650
651
652// pthread_cond_signal
653PTH_FUNC(int, pthreadZucondZusignalZAZa, // pthread_cond_signal@*
654 pthread_cond_t* cond)
655{
656 int ret;
657 OrigFn fn;
658 VALGRIND_GET_ORIG_FN(fn);
659
660 if (TRACE_PTH_FNS) {
661 fprintf(stderr, "<< pthread_cond_signal %p", cond);
662 fflush(stderr);
663 }
664
665 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE,
666 pthread_cond_t*,cond);
667
668 CALL_FN_W_W(ret, fn, cond);
669
670 if (ret != 0) {
671 DO_PthAPIerror( "pthread_cond_signal", ret );
672 }
673
674 if (TRACE_PTH_FNS) {
675 fprintf(stderr, " cosig -> %d >>\n", ret);
676 }
677
678 return ret;
679}
680
681
682// pthread_cond_broadcast
683// Note, this is pretty much identical, from a dependency-graph
684// point of view, with cond_signal, so the code is duplicated.
685// Maybe it should be commoned up.
686PTH_FUNC(int, pthreadZucondZubroadcastZAZa, // pthread_cond_broadcast@*
687 pthread_cond_t* cond)
688{
689 int ret;
690 OrigFn fn;
691 VALGRIND_GET_ORIG_FN(fn);
692
693 if (TRACE_PTH_FNS) {
694 fprintf(stderr, "<< pthread_broadcast_signal %p", cond);
695 fflush(stderr);
696 }
697
698 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE,
699 pthread_cond_t*,cond);
700
701 CALL_FN_W_W(ret, fn, cond);
702
703 if (ret != 0) {
704 DO_PthAPIerror( "pthread_cond_broadcast", ret );
705 }
706
707 if (TRACE_PTH_FNS) {
708 fprintf(stderr, " cobro -> %d >>\n", ret);
709 }
710
711 return ret;
712}
713
714
715/*----------------------------------------------------------------*/
716/*--- pthread_rwlock_t functions ---*/
717/*----------------------------------------------------------------*/
718
719/* Handled: pthread_rwlock_init pthread_rwlock_destroy
720 pthread_rwlock_rdlock
721 pthread_rwlock_wrlock
722 pthread_rwlock_unlock
723
724 Unhandled: pthread_rwlock_timedrdlock
725 pthread_rwlock_tryrdlock
726
727 pthread_rwlock_timedwrlock
728 pthread_rwlock_trywrlock
729*/
730
731// pthread_rwlock_init
732PTH_FUNC(int, pthreadZurwlockZuinit, // pthread_rwlock_init
733 pthread_rwlock_t *rwl,
734 pthread_rwlockattr_t* attr)
735{
736 int ret;
737 OrigFn fn;
738 VALGRIND_GET_ORIG_FN(fn);
739 if (TRACE_PTH_FNS) {
740 fprintf(stderr, "<< pthread_rwl_init %p", rwl); fflush(stderr);
741 }
742
743 CALL_FN_W_WW(ret, fn, rwl,attr);
744
745 if (ret == 0 /*success*/) {
746 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
747 pthread_rwlock_t*,rwl);
748 } else {
749 DO_PthAPIerror( "pthread_rwlock_init", ret );
750 }
751
752 if (TRACE_PTH_FNS) {
753 fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
754 }
755 return ret;
756}
757
758
759// pthread_rwlock_destroy
760PTH_FUNC(int, pthreadZurwlockZudestroy, // pthread_rwlock_destroy
761 pthread_rwlock_t *rwl)
762{
763 int ret;
764 OrigFn fn;
765 VALGRIND_GET_ORIG_FN(fn);
766 if (TRACE_PTH_FNS) {
767 fprintf(stderr, "<< pthread_rwl_destroy %p", rwl); fflush(stderr);
768 }
769
770 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE,
771 pthread_rwlock_t*,rwl);
772
773 CALL_FN_W_W(ret, fn, rwl);
774
775 if (ret != 0) {
776 DO_PthAPIerror( "pthread_rwlock_destroy", ret );
777 }
778
779 if (TRACE_PTH_FNS) {
780 fprintf(stderr, " :: rwl_destroy -> %d >>\n", ret);
781 }
782 return ret;
783}
784
785
786PTH_FUNC(int, pthreadZurwlockZuwrlock, // pthread_rwlock_wrlock
787 pthread_rwlock_t* rwlock)
788{
789 int ret;
790 OrigFn fn;
791 VALGRIND_GET_ORIG_FN(fn);
792 if (TRACE_PTH_FNS) {
793 fprintf(stderr, "<< pthread_rwl_wlk %p", rwlock); fflush(stderr);
794 }
795
796 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
797 pthread_rwlock_t*,rwlock, long,1/*isW*/);
798
799 CALL_FN_W_W(ret, fn, rwlock);
800
801 if (ret == 0 /*success*/) {
802 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
803 pthread_rwlock_t*,rwlock, long,1/*isW*/);
804 } else {
805 DO_PthAPIerror( "pthread_rwlock_wrlock", ret );
806 }
807
808 if (TRACE_PTH_FNS) {
809 fprintf(stderr, " :: rwl_wlk -> %d >>\n", ret);
810 }
811 return ret;
812}
813
814
815PTH_FUNC(int, pthreadZurwlockZurdlock, // pthread_rwlock_rdlock
816 pthread_rwlock_t* rwlock)
817{
818 int ret;
819 OrigFn fn;
820 VALGRIND_GET_ORIG_FN(fn);
821 if (TRACE_PTH_FNS) {
822 fprintf(stderr, "<< pthread_rwl_rlk %p", rwlock); fflush(stderr);
823 }
824
825 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
826 pthread_rwlock_t*,rwlock, long,0/*!isW*/);
827
828 CALL_FN_W_W(ret, fn, rwlock);
829
830 if (ret == 0 /*success*/) {
831 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
832 pthread_rwlock_t*,rwlock, long,0/*!isW*/);
833 } else {
834 DO_PthAPIerror( "pthread_rwlock_rdlock", ret );
835 }
836
837 if (TRACE_PTH_FNS) {
838 fprintf(stderr, " :: rwl_rlk -> %d >>\n", ret);
839 }
840 return ret;
841}
842
843
844PTH_FUNC(int, pthreadZurwlockZuunlock, // pthread_rwlock_unlock
845 pthread_rwlock_t* rwlock)
846{
847 int ret;
848 OrigFn fn;
849 VALGRIND_GET_ORIG_FN(fn);
850 if (TRACE_PTH_FNS) {
851 fprintf(stderr, "<< pthread_rwl_unlk %p", rwlock); fflush(stderr);
852 }
853
854 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
855 pthread_rwlock_t*,rwlock);
856
857 CALL_FN_W_W(ret, fn, rwlock);
858
859 if (ret == 0 /*success*/) {
860 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
861 pthread_rwlock_t*,rwlock);
862 } else {
863 DO_PthAPIerror( "pthread_rwlock_unlock", ret );
864 }
865
866 if (TRACE_PTH_FNS) {
867 fprintf(stderr, " :: rwl_unlk -> %d >>\n", ret);
868 }
869 return ret;
870}
871
872
873/*----------------------------------------------------------------*/
874/*--- POSIX semaphores ---*/
875/*----------------------------------------------------------------*/
876
877#include <semaphore.h>
878
879#define TRACE_SEM_FNS 0
880
881/* Handled:
882 int sem_init(sem_t *sem, int pshared, unsigned value);
883 int sem_destroy(sem_t *sem);
884 int sem_wait(sem_t *sem);
885 int sem_post(sem_t *sem);
886
887 Unhandled:
888 int sem_trywait(sem_t *sem);
889 int sem_timedwait(sem_t *restrict sem,
890 const struct timespec *restrict abs_timeout);
891*/
892
893/* glibc-2.5 has sem_init@@GLIBC_2.2.5 (amd64-linux)
894 and sem_init@@GLIBC_2.1 (x86-linux): match sem_init@* */
895PTH_FUNC(int, semZuinitZAZa, sem_t* sem, int pshared, unsigned long value)
896{
897 OrigFn fn;
898 int ret;
899 VALGRIND_GET_ORIG_FN(fn);
900
901 if (TRACE_SEM_FNS) {
902 fprintf(stderr, "<< sem_init(%p,%d,%lu) ", sem,pshared,value);
903 fflush(stderr);
904 }
905
906 CALL_FN_W_WWW(ret, fn, sem,pshared,value);
907
908 if (ret == 0) {
909 /* Probably overly paranoid, but still ... */
910 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_ZAPSTACK, sem_t*,sem);
911 } else {
912 DO_PthAPIerror( "sem_init", errno );
913 }
914
915 if (TRACE_SEM_FNS) {
916 fprintf(stderr, " sem_init -> %d >>\n", ret);
917 fflush(stderr);
918 }
919
920 return ret;
921}
922
923
924/* glibc-2.5 has sem_destroy@@GLIBC_2.2.5 (amd64-linux)
925 and sem_destroy@@GLIBC_2.1 (x86-linux); match sem_destroy@* */
926PTH_FUNC(int, semZudestroyZAZa, sem_t* sem)
927{
928 OrigFn fn;
929 int ret;
930 VALGRIND_GET_ORIG_FN(fn);
931
932 if (TRACE_SEM_FNS) {
933 fprintf(stderr, "<< sem_destroy(%p) ", sem);
934 fflush(stderr);
935 }
936
937 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_ZAPSTACK, sem_t*,sem);
938
939 CALL_FN_W_W(ret, fn, sem);
940
941 if (ret != 0) {
942 DO_PthAPIerror( "sem_destroy", errno );
943 }
944
945 if (TRACE_SEM_FNS) {
946 fprintf(stderr, " sem_destroy -> %d >>\n", ret);
947 fflush(stderr);
948 }
949
950 return ret;
951}
952
953
954/* glibc-2.5 has sem_wait (amd64-linux); match sem_wait
955 and sem_wait@@GLIBC_2.1 (x86-linux); match sem_wait@* */
956/* wait: decrement semaphore - acquire lockage */
957static int sem_wait_WRK(sem_t* sem)
958{
959 OrigFn fn;
960 int ret;
961 VALGRIND_GET_ORIG_FN(fn);
962
963 if (TRACE_SEM_FNS) {
964 fprintf(stderr, "<< sem_wait(%p) ", sem);
965 fflush(stderr);
966 }
967
968 CALL_FN_W_W(ret, fn, sem);
969
970 if (ret == 0) {
971 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEMWAIT_POST, sem_t*,sem);
972 } else {
973 DO_PthAPIerror( "sem_wait", errno );
974 }
975
976 if (TRACE_SEM_FNS) {
977 fprintf(stderr, " sem_wait -> %d >>\n", ret);
978 fflush(stderr);
979 }
980
981 return ret;
982}
983PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
984 return sem_wait_WRK(sem);
985}
986PTH_FUNC(int, semZuwaitZAZa, sem_t* sem) { /* sem_wait@* */
987 return sem_wait_WRK(sem);
988}
989
990
991/* glibc-2.5 has sem_post (amd64-linux); match sem_post
992 and sem_post@@GLIBC_2.1 (x86-linux); match sem_post@* */
993/* post: increment semaphore - release lockage */
994static int sem_post_WRK(sem_t* sem)
995{
996 OrigFn fn;
997 int ret;
998
999 VALGRIND_GET_ORIG_FN(fn);
1000
1001 if (TRACE_SEM_FNS) {
1002 fprintf(stderr, "<< sem_post(%p) ", sem);
1003 fflush(stderr);
1004 }
1005
1006 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEMPOST_PRE, sem_t*,sem);
1007
1008 CALL_FN_W_W(ret, fn, sem);
1009
1010 if (ret != 0) {
1011 DO_PthAPIerror( "sem_post", errno );
1012 }
1013
1014 if (TRACE_SEM_FNS) {
1015 fprintf(stderr, " sem_post -> %d >>\n", ret);
1016 fflush(stderr);
1017 }
1018
1019 return ret;
1020}
1021PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
1022 return sem_post_WRK(sem);
1023}
1024PTH_FUNC(int, semZupostZAZa, sem_t* sem) { /* sem_post@* */
1025 return sem_post_WRK(sem);
1026}
1027
1028
1029
1030/*----------------------------------------------------------------*/
1031/*--- Qt 4 threading functions (w/ GNU name mangling) ---*/
1032/*----------------------------------------------------------------*/
1033
1034/* Handled: QMutex::lock()
1035 QMutex::unlock()
1036 QMutex::tryLock
1037 QReadWriteLock::lockForRead()
1038 QReadWriteLock::lockForWrite()
1039 QReadWriteLock::unlock()
1040
1041 Unhandled: QMutex::tryLock(int)
1042 QReadWriteLock::tryLockForRead(int)
1043 QReadWriteLock::tryLockForRead()
1044 QReadWriteLock::tryLockForWrite(int)
1045 QReadWriteLock::tryLockForWrite()
1046
1047 maybe not the next 3; qt-4.3.1 on Unix merely
1048 implements QWaitCondition using pthread_cond_t
1049 QWaitCondition::wait(QMutex*, unsigned long)
1050 QWaitCondition::wakeAll()
1051 QWaitCondition::wakeOne()
1052*/
1053
1054// soname is libQtCore.so.4 ; match against libQtCore.so*
1055#define QT4_FUNC(ret_ty, f, args...) \
1056 ret_ty I_WRAP_SONAME_FNNAME_ZZ(libQtCoreZdsoZa,f)(args); \
1057 ret_ty I_WRAP_SONAME_FNNAME_ZZ(libQtCoreZdsoZa,f)(args)
1058
1059// QMutex::lock()
1060QT4_FUNC(void, ZuZZN6QMutex4lockEv, // _ZN6QMutex4lockEv == QMutex::lock()
1061 void* self)
1062{
1063 OrigFn fn;
1064 VALGRIND_GET_ORIG_FN(fn);
1065 if (TRACE_QT4_FNS) {
1066 fprintf(stderr, "<< QMutex::lock %p", self); fflush(stderr);
1067 }
1068
1069 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
1070 void*,self, long,0/*!isTryLock*/);
1071
1072 CALL_FN_v_W(fn, self);
1073
1074 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1075 void*, self);
1076
1077 if (TRACE_QT4_FNS) {
1078 fprintf(stderr, " :: Q::lock done >>\n");
1079 }
1080}
1081
1082// QMutex::unlock()
1083QT4_FUNC(void, ZuZZN6QMutex6unlockEv, // _ZN6QMutex6unlockEv == QMutex::unlock()
1084 void* self)
1085{
1086 OrigFn fn;
1087 VALGRIND_GET_ORIG_FN(fn);
1088
1089 if (TRACE_QT4_FNS) {
1090 fprintf(stderr, "<< QMutex::unlock %p", self); fflush(stderr);
1091 }
1092
1093 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1094 void*, self);
1095
1096 CALL_FN_v_W(fn, self);
1097
1098 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
1099 void*, self);
1100
1101 if (TRACE_QT4_FNS) {
1102 fprintf(stderr, " Q::unlock done >>\n");
1103 }
1104}
1105
1106// QMutex::tryLock
1107// _ZN6QMutex7tryLockEv == bool QMutex::tryLock()
1108// using 'long' to mimic C++ 'bool'
1109QT4_FUNC(long, ZuZZN6QMutex7tryLockEv,
1110 void* self)
1111{
1112 OrigFn fn;
1113 long ret;
1114 VALGRIND_GET_ORIG_FN(fn);
1115 if (TRACE_QT4_FNS) {
1116 fprintf(stderr, "<< QMutex::tryLock %p", self); fflush(stderr);
1117 }
1118
1119 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
1120 void*,self, long,1/*isTryLock*/);
1121
1122 CALL_FN_W_W(ret, fn, self);
1123
1124 // assumes that only the low 8 bits of the 'bool' are significant
1125 if (ret & 0xFF) {
1126 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1127 void*, self);
1128 }
1129
1130 if (TRACE_QT4_FNS) {
1131 fprintf(stderr, " :: Q::tryLock -> %lu >>\n", ret);
1132 }
1133
1134 return ret;
1135}
1136
1137
1138// QReadWriteLock::lockForRead()
1139// _ZN14QReadWriteLock11lockForReadEv == QReadWriteLock::lockForRead()
1140QT4_FUNC(void, ZuZZN14QReadWriteLock11lockForReadEv,
1141 // _ZN14QReadWriteLock11lockForReadEv
1142 void* self)
1143{
1144 OrigFn fn;
1145 VALGRIND_GET_ORIG_FN(fn);
1146 if (TRACE_QT4_FNS) {
1147 fprintf(stderr, "<< QReadWriteLock::lockForRead %p", self);
1148 fflush(stderr);
1149 }
1150
1151 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1152 void*,self, long,0/*!isW*/);
1153
1154 CALL_FN_v_W(fn, self);
1155
1156 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1157 void*,self, long,0/*!isW*/);
1158
1159 if (TRACE_QT4_FNS) {
1160 fprintf(stderr, " :: Q::lockForRead :: done >>\n");
1161 }
1162}
1163
1164// QReadWriteLock::lockForWrite()
1165// _ZN14QReadWriteLock12lockForWriteEv == QReadWriteLock::lockForWrite()
1166QT4_FUNC(void, ZuZZN14QReadWriteLock12lockForWriteEv,
1167 // _ZN14QReadWriteLock12lockForWriteEv
1168 void* self)
1169{
1170 OrigFn fn;
1171 VALGRIND_GET_ORIG_FN(fn);
1172 if (TRACE_QT4_FNS) {
1173 fprintf(stderr, "<< QReadWriteLock::lockForWrite %p", self);
1174 fflush(stderr);
1175 }
1176
1177 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1178 void*,self, long,1/*isW*/);
1179
1180 CALL_FN_v_W(fn, self);
1181
1182 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1183 void*,self, long,1/*isW*/);
1184
1185 if (TRACE_QT4_FNS) {
1186 fprintf(stderr, " :: Q::lockForWrite :: done >>\n");
1187 }
1188}
1189
1190// QReadWriteLock::unlock()
1191// _ZN14QReadWriteLock6unlockEv == QReadWriteLock::unlock()
1192QT4_FUNC(void, ZuZZN14QReadWriteLock6unlockEv,
1193 // _ZN14QReadWriteLock6unlockEv
1194 void* self)
1195{
1196 OrigFn fn;
1197 VALGRIND_GET_ORIG_FN(fn);
1198 if (TRACE_QT4_FNS) {
1199 fprintf(stderr, "<< QReadWriteLock::unlock %p", self);
1200 fflush(stderr);
1201 }
1202
1203 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
1204 void*,self);
1205
1206 CALL_FN_v_W(fn, self);
1207
1208 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
1209 void*,self);
1210
1211 if (TRACE_QT4_FNS) {
1212 fprintf(stderr, " :: Q::unlock :: done >>\n");
1213 }
1214}
1215
1216
1217/*--------------------------------------------------------------------*/
1218/*--- end tc_intercepts.c ---*/
1219/*--------------------------------------------------------------------*/