blob: 2c97e521e7d57f2bc1c7bb8721f136f80b7eea70 [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
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{
180 volatile Word volatile* xargs = (volatile Word volatile*) xargsV;
181 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
537
538 Unhandled: pthread_cond_init pthread_cond_destroy
539 -- are these important?
540*/
541
542// pthread_cond_wait
543PTH_FUNC(int, pthreadZucondZuwaitZAZa, // pthread_cond_wait@*
544 pthread_cond_t* cond, pthread_mutex_t* mutex)
545{
546 int ret;
547 OrigFn fn;
548 unsigned long mutex_is_valid;
549
550 VALGRIND_GET_ORIG_FN(fn);
551
552 if (TRACE_PTH_FNS) {
553 fprintf(stderr, "<< pthread_cond_wait %p %p", cond, mutex);
554 fflush(stderr);
555 }
556
557 /* Tell the tool a cond-wait is about to happen, so it can check
558 for bogus argument values. In return it tells us whether it
559 thinks the mutex is valid or not. */
560 DO_CREQ_W_WW(mutex_is_valid,
561 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
562 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
563 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
564
565 /* Tell the tool we're about to drop the mutex. This reflects the
566 fact that in a cond_wait, we show up holding the mutex, and the
567 call atomically drops the mutex and waits for the cv to be
568 signalled. */
569 if (mutex_is_valid) {
570 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
571 pthread_mutex_t*,mutex);
572 }
573
574 CALL_FN_W_WW(ret, fn, cond,mutex);
575
576 /* these conditionals look stupid, but compare w/ same logic for
577 pthread_cond_timedwait below */
578 if (ret == 0 && mutex_is_valid) {
579 /* and now we have the mutex again */
580 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
581 pthread_mutex_t*,mutex);
582 }
583
584 if (ret == 0 && mutex_is_valid) {
585 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
586 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
587 }
588
589 if (ret != 0) {
590 DO_PthAPIerror( "pthread_cond_wait", ret );
591 }
592
593 if (TRACE_PTH_FNS) {
594 fprintf(stderr, " cowait -> %d >>\n", ret);
595 }
596
597 return ret;
598}
599
600
601// pthread_cond_timedwait
602PTH_FUNC(int, pthreadZucondZutimedwaitZAZa, // pthread_cond_timedwait@*
603 pthread_cond_t* cond, pthread_mutex_t* mutex,
604 struct timespec* abstime)
605{
606 int ret;
607 OrigFn fn;
608 unsigned long mutex_is_valid;
609 VALGRIND_GET_ORIG_FN(fn);
610
611 if (TRACE_PTH_FNS) {
612 fprintf(stderr, "<< pthread_cond_timedwait %p %p %p",
613 cond, mutex, abstime);
614 fflush(stderr);
615 }
616
617 /* Tell the tool a cond-wait is about to happen, so it can check
618 for bogus argument values. In return it tells us whether it
619 thinks the mutex is valid or not. */
620 DO_CREQ_W_WW(mutex_is_valid,
621 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
622 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
623 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
624
625 /* Tell the tool we're about to drop the mutex. This reflects the
626 fact that in a cond_wait, we show up holding the mutex, and the
627 call atomically drops the mutex and waits for the cv to be
628 signalled. */
629 if (mutex_is_valid) {
630 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
631 pthread_mutex_t*,mutex);
632 }
633
634 CALL_FN_W_WWW(ret, fn, cond,mutex,abstime);
635
636 if ((ret == 0 || ret == ETIMEDOUT) && mutex_is_valid) {
637 /* and now we have the mutex again */
638 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
639 pthread_mutex_t*,mutex);
640 }
641
642 if (ret == 0 && mutex_is_valid) {
643 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
644 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
645 }
646
647 if (ret != 0 && ret != ETIMEDOUT) {
648 DO_PthAPIerror( "pthread_cond_timedwait", ret );
649 }
650
651 if (TRACE_PTH_FNS) {
652 fprintf(stderr, " cotimedwait -> %d >>\n", ret);
653 }
654
655 return ret;
656}
657
658
659// pthread_cond_signal
660PTH_FUNC(int, pthreadZucondZusignalZAZa, // pthread_cond_signal@*
661 pthread_cond_t* cond)
662{
663 int ret;
664 OrigFn fn;
665 VALGRIND_GET_ORIG_FN(fn);
666
667 if (TRACE_PTH_FNS) {
668 fprintf(stderr, "<< pthread_cond_signal %p", cond);
669 fflush(stderr);
670 }
671
672 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE,
673 pthread_cond_t*,cond);
674
675 CALL_FN_W_W(ret, fn, cond);
676
677 if (ret != 0) {
678 DO_PthAPIerror( "pthread_cond_signal", ret );
679 }
680
681 if (TRACE_PTH_FNS) {
682 fprintf(stderr, " cosig -> %d >>\n", ret);
683 }
684
685 return ret;
686}
687
688
689// pthread_cond_broadcast
690// Note, this is pretty much identical, from a dependency-graph
691// point of view, with cond_signal, so the code is duplicated.
692// Maybe it should be commoned up.
693PTH_FUNC(int, pthreadZucondZubroadcastZAZa, // pthread_cond_broadcast@*
694 pthread_cond_t* cond)
695{
696 int ret;
697 OrigFn fn;
698 VALGRIND_GET_ORIG_FN(fn);
699
700 if (TRACE_PTH_FNS) {
701 fprintf(stderr, "<< pthread_broadcast_signal %p", cond);
702 fflush(stderr);
703 }
704
705 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE,
706 pthread_cond_t*,cond);
707
708 CALL_FN_W_W(ret, fn, cond);
709
710 if (ret != 0) {
711 DO_PthAPIerror( "pthread_cond_broadcast", ret );
712 }
713
714 if (TRACE_PTH_FNS) {
715 fprintf(stderr, " cobro -> %d >>\n", ret);
716 }
717
718 return ret;
719}
720
721
722/*----------------------------------------------------------------*/
723/*--- pthread_rwlock_t functions ---*/
724/*----------------------------------------------------------------*/
725
726/* Handled: pthread_rwlock_init pthread_rwlock_destroy
727 pthread_rwlock_rdlock
728 pthread_rwlock_wrlock
729 pthread_rwlock_unlock
730
731 Unhandled: pthread_rwlock_timedrdlock
732 pthread_rwlock_tryrdlock
733
734 pthread_rwlock_timedwrlock
735 pthread_rwlock_trywrlock
736*/
737
738// pthread_rwlock_init
739PTH_FUNC(int, pthreadZurwlockZuinit, // pthread_rwlock_init
740 pthread_rwlock_t *rwl,
741 pthread_rwlockattr_t* attr)
742{
743 int ret;
744 OrigFn fn;
745 VALGRIND_GET_ORIG_FN(fn);
746 if (TRACE_PTH_FNS) {
747 fprintf(stderr, "<< pthread_rwl_init %p", rwl); fflush(stderr);
748 }
749
750 CALL_FN_W_WW(ret, fn, rwl,attr);
751
752 if (ret == 0 /*success*/) {
753 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
754 pthread_rwlock_t*,rwl);
755 } else {
756 DO_PthAPIerror( "pthread_rwlock_init", ret );
757 }
758
759 if (TRACE_PTH_FNS) {
760 fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
761 }
762 return ret;
763}
764
765
766// pthread_rwlock_destroy
767PTH_FUNC(int, pthreadZurwlockZudestroy, // pthread_rwlock_destroy
768 pthread_rwlock_t *rwl)
769{
770 int ret;
771 OrigFn fn;
772 VALGRIND_GET_ORIG_FN(fn);
773 if (TRACE_PTH_FNS) {
774 fprintf(stderr, "<< pthread_rwl_destroy %p", rwl); fflush(stderr);
775 }
776
777 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE,
778 pthread_rwlock_t*,rwl);
779
780 CALL_FN_W_W(ret, fn, rwl);
781
782 if (ret != 0) {
783 DO_PthAPIerror( "pthread_rwlock_destroy", ret );
784 }
785
786 if (TRACE_PTH_FNS) {
787 fprintf(stderr, " :: rwl_destroy -> %d >>\n", ret);
788 }
789 return ret;
790}
791
792
793PTH_FUNC(int, pthreadZurwlockZuwrlock, // pthread_rwlock_wrlock
794 pthread_rwlock_t* rwlock)
795{
796 int ret;
797 OrigFn fn;
798 VALGRIND_GET_ORIG_FN(fn);
799 if (TRACE_PTH_FNS) {
800 fprintf(stderr, "<< pthread_rwl_wlk %p", rwlock); fflush(stderr);
801 }
802
803 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
804 pthread_rwlock_t*,rwlock, long,1/*isW*/);
805
806 CALL_FN_W_W(ret, fn, rwlock);
807
808 if (ret == 0 /*success*/) {
809 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
810 pthread_rwlock_t*,rwlock, long,1/*isW*/);
811 } else {
812 DO_PthAPIerror( "pthread_rwlock_wrlock", ret );
813 }
814
815 if (TRACE_PTH_FNS) {
816 fprintf(stderr, " :: rwl_wlk -> %d >>\n", ret);
817 }
818 return ret;
819}
820
821
822PTH_FUNC(int, pthreadZurwlockZurdlock, // pthread_rwlock_rdlock
823 pthread_rwlock_t* rwlock)
824{
825 int ret;
826 OrigFn fn;
827 VALGRIND_GET_ORIG_FN(fn);
828 if (TRACE_PTH_FNS) {
829 fprintf(stderr, "<< pthread_rwl_rlk %p", rwlock); fflush(stderr);
830 }
831
832 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
833 pthread_rwlock_t*,rwlock, long,0/*!isW*/);
834
835 CALL_FN_W_W(ret, fn, rwlock);
836
837 if (ret == 0 /*success*/) {
838 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
839 pthread_rwlock_t*,rwlock, long,0/*!isW*/);
840 } else {
841 DO_PthAPIerror( "pthread_rwlock_rdlock", ret );
842 }
843
844 if (TRACE_PTH_FNS) {
845 fprintf(stderr, " :: rwl_rlk -> %d >>\n", ret);
846 }
847 return ret;
848}
849
850
851PTH_FUNC(int, pthreadZurwlockZuunlock, // pthread_rwlock_unlock
852 pthread_rwlock_t* rwlock)
853{
854 int ret;
855 OrigFn fn;
856 VALGRIND_GET_ORIG_FN(fn);
857 if (TRACE_PTH_FNS) {
858 fprintf(stderr, "<< pthread_rwl_unlk %p", rwlock); fflush(stderr);
859 }
860
861 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
862 pthread_rwlock_t*,rwlock);
863
864 CALL_FN_W_W(ret, fn, rwlock);
865
866 if (ret == 0 /*success*/) {
867 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
868 pthread_rwlock_t*,rwlock);
869 } else {
870 DO_PthAPIerror( "pthread_rwlock_unlock", ret );
871 }
872
873 if (TRACE_PTH_FNS) {
874 fprintf(stderr, " :: rwl_unlk -> %d >>\n", ret);
875 }
876 return ret;
877}
878
879
880/*----------------------------------------------------------------*/
881/*--- POSIX semaphores ---*/
882/*----------------------------------------------------------------*/
883
884#include <semaphore.h>
885
886#define TRACE_SEM_FNS 0
887
888/* Handled:
889 int sem_init(sem_t *sem, int pshared, unsigned value);
890 int sem_destroy(sem_t *sem);
891 int sem_wait(sem_t *sem);
892 int sem_post(sem_t *sem);
893
894 Unhandled:
895 int sem_trywait(sem_t *sem);
896 int sem_timedwait(sem_t *restrict sem,
897 const struct timespec *restrict abs_timeout);
898*/
899
900/* glibc-2.5 has sem_init@@GLIBC_2.2.5 (amd64-linux)
901 and sem_init@@GLIBC_2.1 (x86-linux): match sem_init@* */
902PTH_FUNC(int, semZuinitZAZa, sem_t* sem, int pshared, unsigned long value)
903{
904 OrigFn fn;
905 int ret;
906 VALGRIND_GET_ORIG_FN(fn);
907
908 if (TRACE_SEM_FNS) {
909 fprintf(stderr, "<< sem_init(%p,%d,%lu) ", sem,pshared,value);
910 fflush(stderr);
911 }
912
913 CALL_FN_W_WWW(ret, fn, sem,pshared,value);
914
915 if (ret == 0) {
sewardj11e352f2007-11-30 11:11:02 +0000916 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
917 sem_t*, sem, unsigned long, value);
sewardjb4112022007-11-09 22:49:28 +0000918 } else {
919 DO_PthAPIerror( "sem_init", errno );
920 }
921
922 if (TRACE_SEM_FNS) {
923 fprintf(stderr, " sem_init -> %d >>\n", ret);
924 fflush(stderr);
925 }
926
927 return ret;
928}
929
930
931/* glibc-2.5 has sem_destroy@@GLIBC_2.2.5 (amd64-linux)
932 and sem_destroy@@GLIBC_2.1 (x86-linux); match sem_destroy@* */
933PTH_FUNC(int, semZudestroyZAZa, sem_t* sem)
934{
935 OrigFn fn;
936 int ret;
937 VALGRIND_GET_ORIG_FN(fn);
938
939 if (TRACE_SEM_FNS) {
940 fprintf(stderr, "<< sem_destroy(%p) ", sem);
941 fflush(stderr);
942 }
943
sewardj11e352f2007-11-30 11:11:02 +0000944 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
sewardjb4112022007-11-09 22:49:28 +0000945
946 CALL_FN_W_W(ret, fn, sem);
947
948 if (ret != 0) {
949 DO_PthAPIerror( "sem_destroy", errno );
950 }
951
952 if (TRACE_SEM_FNS) {
953 fprintf(stderr, " sem_destroy -> %d >>\n", ret);
954 fflush(stderr);
955 }
956
957 return ret;
958}
959
960
961/* glibc-2.5 has sem_wait (amd64-linux); match sem_wait
962 and sem_wait@@GLIBC_2.1 (x86-linux); match sem_wait@* */
963/* wait: decrement semaphore - acquire lockage */
964static int sem_wait_WRK(sem_t* sem)
965{
966 OrigFn fn;
967 int ret;
968 VALGRIND_GET_ORIG_FN(fn);
969
970 if (TRACE_SEM_FNS) {
971 fprintf(stderr, "<< sem_wait(%p) ", sem);
972 fflush(stderr);
973 }
974
975 CALL_FN_W_W(ret, fn, sem);
976
977 if (ret == 0) {
sewardj11e352f2007-11-30 11:11:02 +0000978 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST, sem_t*,sem);
sewardjb4112022007-11-09 22:49:28 +0000979 } else {
980 DO_PthAPIerror( "sem_wait", errno );
981 }
982
983 if (TRACE_SEM_FNS) {
984 fprintf(stderr, " sem_wait -> %d >>\n", ret);
985 fflush(stderr);
986 }
987
988 return ret;
989}
990PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
991 return sem_wait_WRK(sem);
992}
993PTH_FUNC(int, semZuwaitZAZa, sem_t* sem) { /* sem_wait@* */
994 return sem_wait_WRK(sem);
995}
996
997
998/* glibc-2.5 has sem_post (amd64-linux); match sem_post
999 and sem_post@@GLIBC_2.1 (x86-linux); match sem_post@* */
1000/* post: increment semaphore - release lockage */
1001static int sem_post_WRK(sem_t* sem)
1002{
1003 OrigFn fn;
1004 int ret;
1005
1006 VALGRIND_GET_ORIG_FN(fn);
1007
1008 if (TRACE_SEM_FNS) {
1009 fprintf(stderr, "<< sem_post(%p) ", sem);
1010 fflush(stderr);
1011 }
1012
sewardj11e352f2007-11-30 11:11:02 +00001013 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_PRE, sem_t*,sem);
sewardjb4112022007-11-09 22:49:28 +00001014
1015 CALL_FN_W_W(ret, fn, sem);
1016
1017 if (ret != 0) {
1018 DO_PthAPIerror( "sem_post", errno );
1019 }
1020
1021 if (TRACE_SEM_FNS) {
1022 fprintf(stderr, " sem_post -> %d >>\n", ret);
1023 fflush(stderr);
1024 }
1025
1026 return ret;
1027}
1028PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
1029 return sem_post_WRK(sem);
1030}
1031PTH_FUNC(int, semZupostZAZa, sem_t* sem) { /* sem_post@* */
1032 return sem_post_WRK(sem);
1033}
1034
1035
1036
1037/*----------------------------------------------------------------*/
1038/*--- Qt 4 threading functions (w/ GNU name mangling) ---*/
1039/*----------------------------------------------------------------*/
1040
1041/* Handled: QMutex::lock()
1042 QMutex::unlock()
1043 QMutex::tryLock
1044 QReadWriteLock::lockForRead()
1045 QReadWriteLock::lockForWrite()
1046 QReadWriteLock::unlock()
1047
1048 Unhandled: QMutex::tryLock(int)
1049 QReadWriteLock::tryLockForRead(int)
1050 QReadWriteLock::tryLockForRead()
1051 QReadWriteLock::tryLockForWrite(int)
1052 QReadWriteLock::tryLockForWrite()
1053
1054 maybe not the next 3; qt-4.3.1 on Unix merely
1055 implements QWaitCondition using pthread_cond_t
1056 QWaitCondition::wait(QMutex*, unsigned long)
1057 QWaitCondition::wakeAll()
1058 QWaitCondition::wakeOne()
1059*/
1060
1061// soname is libQtCore.so.4 ; match against libQtCore.so*
1062#define QT4_FUNC(ret_ty, f, args...) \
1063 ret_ty I_WRAP_SONAME_FNNAME_ZZ(libQtCoreZdsoZa,f)(args); \
1064 ret_ty I_WRAP_SONAME_FNNAME_ZZ(libQtCoreZdsoZa,f)(args)
1065
1066// QMutex::lock()
1067QT4_FUNC(void, ZuZZN6QMutex4lockEv, // _ZN6QMutex4lockEv == QMutex::lock()
1068 void* self)
1069{
1070 OrigFn fn;
1071 VALGRIND_GET_ORIG_FN(fn);
1072 if (TRACE_QT4_FNS) {
1073 fprintf(stderr, "<< QMutex::lock %p", self); fflush(stderr);
1074 }
1075
1076 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
1077 void*,self, long,0/*!isTryLock*/);
1078
1079 CALL_FN_v_W(fn, self);
1080
1081 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1082 void*, self);
1083
1084 if (TRACE_QT4_FNS) {
1085 fprintf(stderr, " :: Q::lock done >>\n");
1086 }
1087}
1088
1089// QMutex::unlock()
1090QT4_FUNC(void, ZuZZN6QMutex6unlockEv, // _ZN6QMutex6unlockEv == QMutex::unlock()
1091 void* self)
1092{
1093 OrigFn fn;
1094 VALGRIND_GET_ORIG_FN(fn);
1095
1096 if (TRACE_QT4_FNS) {
1097 fprintf(stderr, "<< QMutex::unlock %p", self); fflush(stderr);
1098 }
1099
1100 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1101 void*, self);
1102
1103 CALL_FN_v_W(fn, self);
1104
1105 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
1106 void*, self);
1107
1108 if (TRACE_QT4_FNS) {
1109 fprintf(stderr, " Q::unlock done >>\n");
1110 }
1111}
1112
1113// QMutex::tryLock
1114// _ZN6QMutex7tryLockEv == bool QMutex::tryLock()
1115// using 'long' to mimic C++ 'bool'
1116QT4_FUNC(long, ZuZZN6QMutex7tryLockEv,
1117 void* self)
1118{
1119 OrigFn fn;
1120 long ret;
1121 VALGRIND_GET_ORIG_FN(fn);
1122 if (TRACE_QT4_FNS) {
1123 fprintf(stderr, "<< QMutex::tryLock %p", self); fflush(stderr);
1124 }
1125
1126 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
1127 void*,self, long,1/*isTryLock*/);
1128
1129 CALL_FN_W_W(ret, fn, self);
1130
1131 // assumes that only the low 8 bits of the 'bool' are significant
1132 if (ret & 0xFF) {
1133 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1134 void*, self);
1135 }
1136
1137 if (TRACE_QT4_FNS) {
1138 fprintf(stderr, " :: Q::tryLock -> %lu >>\n", ret);
1139 }
1140
1141 return ret;
1142}
1143
1144
1145// QReadWriteLock::lockForRead()
1146// _ZN14QReadWriteLock11lockForReadEv == QReadWriteLock::lockForRead()
1147QT4_FUNC(void, ZuZZN14QReadWriteLock11lockForReadEv,
1148 // _ZN14QReadWriteLock11lockForReadEv
1149 void* self)
1150{
1151 OrigFn fn;
1152 VALGRIND_GET_ORIG_FN(fn);
1153 if (TRACE_QT4_FNS) {
1154 fprintf(stderr, "<< QReadWriteLock::lockForRead %p", self);
1155 fflush(stderr);
1156 }
1157
1158 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1159 void*,self, long,0/*!isW*/);
1160
1161 CALL_FN_v_W(fn, self);
1162
1163 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1164 void*,self, long,0/*!isW*/);
1165
1166 if (TRACE_QT4_FNS) {
1167 fprintf(stderr, " :: Q::lockForRead :: done >>\n");
1168 }
1169}
1170
1171// QReadWriteLock::lockForWrite()
1172// _ZN14QReadWriteLock12lockForWriteEv == QReadWriteLock::lockForWrite()
1173QT4_FUNC(void, ZuZZN14QReadWriteLock12lockForWriteEv,
1174 // _ZN14QReadWriteLock12lockForWriteEv
1175 void* self)
1176{
1177 OrigFn fn;
1178 VALGRIND_GET_ORIG_FN(fn);
1179 if (TRACE_QT4_FNS) {
1180 fprintf(stderr, "<< QReadWriteLock::lockForWrite %p", self);
1181 fflush(stderr);
1182 }
1183
1184 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1185 void*,self, long,1/*isW*/);
1186
1187 CALL_FN_v_W(fn, self);
1188
1189 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1190 void*,self, long,1/*isW*/);
1191
1192 if (TRACE_QT4_FNS) {
1193 fprintf(stderr, " :: Q::lockForWrite :: done >>\n");
1194 }
1195}
1196
1197// QReadWriteLock::unlock()
1198// _ZN14QReadWriteLock6unlockEv == QReadWriteLock::unlock()
1199QT4_FUNC(void, ZuZZN14QReadWriteLock6unlockEv,
1200 // _ZN14QReadWriteLock6unlockEv
1201 void* self)
1202{
1203 OrigFn fn;
1204 VALGRIND_GET_ORIG_FN(fn);
1205 if (TRACE_QT4_FNS) {
1206 fprintf(stderr, "<< QReadWriteLock::unlock %p", self);
1207 fflush(stderr);
1208 }
1209
1210 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
1211 void*,self);
1212
1213 CALL_FN_v_W(fn, self);
1214
1215 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
1216 void*,self);
1217
1218 if (TRACE_QT4_FNS) {
1219 fprintf(stderr, " :: Q::unlock :: done >>\n");
1220 }
1221}
1222
1223
1224/*--------------------------------------------------------------------*/
1225/*--- end tc_intercepts.c ---*/
1226/*--------------------------------------------------------------------*/