blob: 440c4beea9233b8bbb0f962ca465ef6e36a3473b [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
sewardj9f569b72008-11-13 13:33:09 +0000758/* Handled: pthread_barrier_init
759 pthread_barrier_wait
760 pthread_barrier_destroy
761
762 Unhandled: pthread_barrierattr_destroy
763 pthread_barrierattr_getpshared
764 pthread_barrierattr_init
765 pthread_barrierattr_setpshared
766 -- are these important?
767*/
768
769PTH_FUNC(int, pthreadZubarrierZuinit, // pthread_barrier_init
770 pthread_barrier_t* bar,
771 pthread_barrierattr_t* attr, unsigned long count)
sewardjf98e1c02008-10-25 16:22:41 +0000772{
773 int ret;
774 OrigFn fn;
775 VALGRIND_GET_ORIG_FN(fn);
776
777 if (TRACE_PTH_FNS) {
sewardj9f569b72008-11-13 13:33:09 +0000778 fprintf(stderr, "<< pthread_barrier_init %p %p %lu",
779 bar, attr, count);
sewardjf98e1c02008-10-25 16:22:41 +0000780 fflush(stderr);
781 }
782
sewardj9f569b72008-11-13 13:33:09 +0000783 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE,
784 pthread_barrier_t*,bar,
785 unsigned long,count);
sewardjf98e1c02008-10-25 16:22:41 +0000786
sewardj9f569b72008-11-13 13:33:09 +0000787 CALL_FN_W_WWW(ret, fn, bar,attr,count);
sewardjf98e1c02008-10-25 16:22:41 +0000788
sewardj9f569b72008-11-13 13:33:09 +0000789 if (ret != 0) {
790 DO_PthAPIerror( "pthread_barrier_init", ret );
791 }
792
793 if (TRACE_PTH_FNS) {
794 fprintf(stderr, " pthread_barrier_init -> %d >>\n", ret);
795 }
796
797 return ret;
798}
799
800
801PTH_FUNC(int, pthreadZubarrierZuwait, // pthread_barrier_wait
802 pthread_barrier_t* bar)
803{
804 int ret;
805 OrigFn fn;
806 VALGRIND_GET_ORIG_FN(fn);
807
808 if (TRACE_PTH_FNS) {
809 fprintf(stderr, "<< pthread_barrier_wait %p", bar);
810 fflush(stderr);
811 }
812
813 /* That this works correctly, and doesn't screw up when a thread
814 leaving the barrier races round to the front and re-enters while
815 other threads are still leaving it, is quite subtle. See
816 comments in the handler for PTHREAD_BARRIER_WAIT_PRE in
817 hg_main.c. */
818 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE,
819 pthread_barrier_t*,bar);
820
821 CALL_FN_W_W(ret, fn, bar);
822
823 if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) {
824 DO_PthAPIerror( "pthread_barrier_wait", ret );
825 }
sewardjf98e1c02008-10-25 16:22:41 +0000826
827 if (TRACE_PTH_FNS) {
828 fprintf(stderr, " pthread_barrier_wait -> %d >>\n", ret);
829 }
830
831 return ret;
832}
833
834
sewardj9f569b72008-11-13 13:33:09 +0000835PTH_FUNC(int, pthreadZubarrierZudestroy, // pthread_barrier_destroy
836 pthread_barrier_t* bar)
837{
838 int ret;
839 OrigFn fn;
840 VALGRIND_GET_ORIG_FN(fn);
841
842 if (TRACE_PTH_FNS) {
843 fprintf(stderr, "<< pthread_barrier_destroy %p", bar);
844 fflush(stderr);
845 }
846
847 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE,
848 pthread_barrier_t*,bar);
849
850 CALL_FN_W_W(ret, fn, bar);
851
852 if (ret != 0) {
853 DO_PthAPIerror( "pthread_barrier_destroy", ret );
854 }
855
856 if (TRACE_PTH_FNS) {
857 fprintf(stderr, " pthread_barrier_destroy -> %d >>\n", ret);
858 }
859
860 return ret;
861}
sewardjf98e1c02008-10-25 16:22:41 +0000862
sewardjb4112022007-11-09 22:49:28 +0000863/*----------------------------------------------------------------*/
864/*--- pthread_rwlock_t functions ---*/
865/*----------------------------------------------------------------*/
866
867/* Handled: pthread_rwlock_init pthread_rwlock_destroy
868 pthread_rwlock_rdlock
869 pthread_rwlock_wrlock
870 pthread_rwlock_unlock
871
872 Unhandled: pthread_rwlock_timedrdlock
873 pthread_rwlock_tryrdlock
874
875 pthread_rwlock_timedwrlock
876 pthread_rwlock_trywrlock
877*/
878
879// pthread_rwlock_init
880PTH_FUNC(int, pthreadZurwlockZuinit, // pthread_rwlock_init
881 pthread_rwlock_t *rwl,
882 pthread_rwlockattr_t* attr)
883{
884 int ret;
885 OrigFn fn;
886 VALGRIND_GET_ORIG_FN(fn);
887 if (TRACE_PTH_FNS) {
888 fprintf(stderr, "<< pthread_rwl_init %p", rwl); fflush(stderr);
889 }
890
891 CALL_FN_W_WW(ret, fn, rwl,attr);
892
893 if (ret == 0 /*success*/) {
894 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
895 pthread_rwlock_t*,rwl);
896 } else {
897 DO_PthAPIerror( "pthread_rwlock_init", ret );
898 }
899
900 if (TRACE_PTH_FNS) {
901 fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
902 }
903 return ret;
904}
905
906
907// pthread_rwlock_destroy
908PTH_FUNC(int, pthreadZurwlockZudestroy, // pthread_rwlock_destroy
909 pthread_rwlock_t *rwl)
910{
911 int ret;
912 OrigFn fn;
913 VALGRIND_GET_ORIG_FN(fn);
914 if (TRACE_PTH_FNS) {
915 fprintf(stderr, "<< pthread_rwl_destroy %p", rwl); fflush(stderr);
916 }
917
918 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE,
919 pthread_rwlock_t*,rwl);
920
921 CALL_FN_W_W(ret, fn, rwl);
922
923 if (ret != 0) {
924 DO_PthAPIerror( "pthread_rwlock_destroy", ret );
925 }
926
927 if (TRACE_PTH_FNS) {
928 fprintf(stderr, " :: rwl_destroy -> %d >>\n", ret);
929 }
930 return ret;
931}
932
933
sewardj789c3c52008-02-25 12:10:07 +0000934// pthread_rwlock_wrlock
sewardjb4112022007-11-09 22:49:28 +0000935PTH_FUNC(int, pthreadZurwlockZuwrlock, // pthread_rwlock_wrlock
936 pthread_rwlock_t* rwlock)
937{
938 int ret;
939 OrigFn fn;
940 VALGRIND_GET_ORIG_FN(fn);
941 if (TRACE_PTH_FNS) {
942 fprintf(stderr, "<< pthread_rwl_wlk %p", rwlock); fflush(stderr);
943 }
944
sewardj789c3c52008-02-25 12:10:07 +0000945 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
946 pthread_rwlock_t*,rwlock,
947 long,1/*isW*/, long,0/*!isTryLock*/);
sewardjb4112022007-11-09 22:49:28 +0000948
949 CALL_FN_W_W(ret, fn, rwlock);
950
951 if (ret == 0 /*success*/) {
952 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
953 pthread_rwlock_t*,rwlock, long,1/*isW*/);
954 } else {
955 DO_PthAPIerror( "pthread_rwlock_wrlock", ret );
956 }
957
958 if (TRACE_PTH_FNS) {
959 fprintf(stderr, " :: rwl_wlk -> %d >>\n", ret);
960 }
961 return ret;
962}
963
964
sewardj789c3c52008-02-25 12:10:07 +0000965// pthread_rwlock_rdlock
sewardjb4112022007-11-09 22:49:28 +0000966PTH_FUNC(int, pthreadZurwlockZurdlock, // pthread_rwlock_rdlock
967 pthread_rwlock_t* rwlock)
968{
969 int ret;
970 OrigFn fn;
971 VALGRIND_GET_ORIG_FN(fn);
972 if (TRACE_PTH_FNS) {
973 fprintf(stderr, "<< pthread_rwl_rlk %p", rwlock); fflush(stderr);
974 }
975
sewardj789c3c52008-02-25 12:10:07 +0000976 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
977 pthread_rwlock_t*,rwlock,
978 long,0/*!isW*/, long,0/*!isTryLock*/);
sewardjb4112022007-11-09 22:49:28 +0000979
980 CALL_FN_W_W(ret, fn, rwlock);
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 DO_PthAPIerror( "pthread_rwlock_rdlock", ret );
987 }
988
989 if (TRACE_PTH_FNS) {
990 fprintf(stderr, " :: rwl_rlk -> %d >>\n", ret);
991 }
992 return ret;
993}
994
995
sewardj789c3c52008-02-25 12:10:07 +0000996// pthread_rwlock_trywrlock
997PTH_FUNC(int, pthreadZurwlockZutrywrlock, // pthread_rwlock_trywrlock
998 pthread_rwlock_t* rwlock)
999{
1000 int ret;
1001 OrigFn fn;
1002 VALGRIND_GET_ORIG_FN(fn);
1003 if (TRACE_PTH_FNS) {
1004 fprintf(stderr, "<< pthread_rwl_trywlk %p", rwlock); fflush(stderr);
1005 }
1006
1007 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1008 pthread_rwlock_t*,rwlock,
1009 long,1/*isW*/, long,1/*isTryLock*/);
1010
1011 CALL_FN_W_W(ret, fn, rwlock);
1012
1013 /* There's a hole here: libpthread now knows the lock is locked,
1014 but the tool doesn't, so some other thread could run and detect
1015 that the lock has been acquired by someone (this thread). Does
1016 this matter? Not sure, but I don't think so. */
1017
1018 if (ret == 0 /*success*/) {
1019 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1020 pthread_rwlock_t*,rwlock, long,1/*isW*/);
1021 } else {
1022 if (ret != EBUSY)
1023 DO_PthAPIerror( "pthread_rwlock_trywrlock", ret );
1024 }
1025
1026 if (TRACE_PTH_FNS) {
1027 fprintf(stderr, " :: rwl_trywlk -> %d >>\n", ret);
1028 }
1029 return ret;
1030}
1031
1032
1033// pthread_rwlock_tryrdlock
1034PTH_FUNC(int, pthreadZurwlockZutryrdlock, // pthread_rwlock_tryrdlock
1035 pthread_rwlock_t* rwlock)
1036{
1037 int ret;
1038 OrigFn fn;
1039 VALGRIND_GET_ORIG_FN(fn);
1040 if (TRACE_PTH_FNS) {
1041 fprintf(stderr, "<< pthread_rwl_tryrlk %p", rwlock); fflush(stderr);
1042 }
1043
1044 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1045 pthread_rwlock_t*,rwlock,
1046 long,0/*!isW*/, long,1/*isTryLock*/);
1047
1048 CALL_FN_W_W(ret, fn, rwlock);
1049
1050 /* There's a hole here: libpthread now knows the lock is locked,
1051 but the tool doesn't, so some other thread could run and detect
1052 that the lock has been acquired by someone (this thread). Does
1053 this matter? Not sure, but I don't think so. */
1054
1055 if (ret == 0 /*success*/) {
1056 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1057 pthread_rwlock_t*,rwlock, long,0/*!isW*/);
1058 } else {
1059 if (ret != EBUSY)
1060 DO_PthAPIerror( "pthread_rwlock_tryrdlock", ret );
1061 }
1062
1063 if (TRACE_PTH_FNS) {
1064 fprintf(stderr, " :: rwl_tryrlk -> %d >>\n", ret);
1065 }
1066 return ret;
1067}
1068
1069
1070// pthread_rwlock_unlock
sewardjb4112022007-11-09 22:49:28 +00001071PTH_FUNC(int, pthreadZurwlockZuunlock, // pthread_rwlock_unlock
1072 pthread_rwlock_t* rwlock)
1073{
1074 int ret;
1075 OrigFn fn;
1076 VALGRIND_GET_ORIG_FN(fn);
1077 if (TRACE_PTH_FNS) {
1078 fprintf(stderr, "<< pthread_rwl_unlk %p", rwlock); fflush(stderr);
1079 }
1080
1081 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
1082 pthread_rwlock_t*,rwlock);
1083
1084 CALL_FN_W_W(ret, fn, rwlock);
1085
1086 if (ret == 0 /*success*/) {
1087 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
1088 pthread_rwlock_t*,rwlock);
1089 } else {
1090 DO_PthAPIerror( "pthread_rwlock_unlock", ret );
1091 }
1092
1093 if (TRACE_PTH_FNS) {
1094 fprintf(stderr, " :: rwl_unlk -> %d >>\n", ret);
1095 }
1096 return ret;
1097}
1098
1099
1100/*----------------------------------------------------------------*/
1101/*--- POSIX semaphores ---*/
1102/*----------------------------------------------------------------*/
1103
1104#include <semaphore.h>
1105
1106#define TRACE_SEM_FNS 0
1107
1108/* Handled:
1109 int sem_init(sem_t *sem, int pshared, unsigned value);
1110 int sem_destroy(sem_t *sem);
1111 int sem_wait(sem_t *sem);
1112 int sem_post(sem_t *sem);
1113
1114 Unhandled:
1115 int sem_trywait(sem_t *sem);
1116 int sem_timedwait(sem_t *restrict sem,
1117 const struct timespec *restrict abs_timeout);
1118*/
1119
1120/* glibc-2.5 has sem_init@@GLIBC_2.2.5 (amd64-linux)
1121 and sem_init@@GLIBC_2.1 (x86-linux): match sem_init@* */
1122PTH_FUNC(int, semZuinitZAZa, sem_t* sem, int pshared, unsigned long value)
1123{
1124 OrigFn fn;
1125 int ret;
1126 VALGRIND_GET_ORIG_FN(fn);
1127
1128 if (TRACE_SEM_FNS) {
1129 fprintf(stderr, "<< sem_init(%p,%d,%lu) ", sem,pshared,value);
1130 fflush(stderr);
1131 }
1132
1133 CALL_FN_W_WWW(ret, fn, sem,pshared,value);
1134
1135 if (ret == 0) {
sewardj11e352f2007-11-30 11:11:02 +00001136 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
1137 sem_t*, sem, unsigned long, value);
sewardjb4112022007-11-09 22:49:28 +00001138 } else {
1139 DO_PthAPIerror( "sem_init", errno );
1140 }
1141
1142 if (TRACE_SEM_FNS) {
1143 fprintf(stderr, " sem_init -> %d >>\n", ret);
1144 fflush(stderr);
1145 }
1146
1147 return ret;
1148}
1149
1150
1151/* glibc-2.5 has sem_destroy@@GLIBC_2.2.5 (amd64-linux)
1152 and sem_destroy@@GLIBC_2.1 (x86-linux); match sem_destroy@* */
1153PTH_FUNC(int, semZudestroyZAZa, sem_t* sem)
1154{
1155 OrigFn fn;
1156 int ret;
1157 VALGRIND_GET_ORIG_FN(fn);
1158
1159 if (TRACE_SEM_FNS) {
1160 fprintf(stderr, "<< sem_destroy(%p) ", sem);
1161 fflush(stderr);
1162 }
1163
sewardj11e352f2007-11-30 11:11:02 +00001164 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
sewardjb4112022007-11-09 22:49:28 +00001165
1166 CALL_FN_W_W(ret, fn, sem);
1167
1168 if (ret != 0) {
1169 DO_PthAPIerror( "sem_destroy", errno );
1170 }
1171
1172 if (TRACE_SEM_FNS) {
1173 fprintf(stderr, " sem_destroy -> %d >>\n", ret);
1174 fflush(stderr);
1175 }
1176
1177 return ret;
1178}
1179
1180
1181/* glibc-2.5 has sem_wait (amd64-linux); match sem_wait
1182 and sem_wait@@GLIBC_2.1 (x86-linux); match sem_wait@* */
1183/* wait: decrement semaphore - acquire lockage */
1184static int sem_wait_WRK(sem_t* sem)
1185{
1186 OrigFn fn;
1187 int ret;
1188 VALGRIND_GET_ORIG_FN(fn);
1189
1190 if (TRACE_SEM_FNS) {
1191 fprintf(stderr, "<< sem_wait(%p) ", sem);
1192 fflush(stderr);
1193 }
1194
1195 CALL_FN_W_W(ret, fn, sem);
1196
1197 if (ret == 0) {
sewardj11e352f2007-11-30 11:11:02 +00001198 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST, sem_t*,sem);
sewardjb4112022007-11-09 22:49:28 +00001199 } else {
1200 DO_PthAPIerror( "sem_wait", errno );
1201 }
1202
1203 if (TRACE_SEM_FNS) {
1204 fprintf(stderr, " sem_wait -> %d >>\n", ret);
1205 fflush(stderr);
1206 }
1207
1208 return ret;
1209}
1210PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
1211 return sem_wait_WRK(sem);
1212}
1213PTH_FUNC(int, semZuwaitZAZa, sem_t* sem) { /* sem_wait@* */
1214 return sem_wait_WRK(sem);
1215}
1216
1217
1218/* glibc-2.5 has sem_post (amd64-linux); match sem_post
1219 and sem_post@@GLIBC_2.1 (x86-linux); match sem_post@* */
1220/* post: increment semaphore - release lockage */
1221static int sem_post_WRK(sem_t* sem)
1222{
1223 OrigFn fn;
1224 int ret;
1225
1226 VALGRIND_GET_ORIG_FN(fn);
1227
1228 if (TRACE_SEM_FNS) {
1229 fprintf(stderr, "<< sem_post(%p) ", sem);
1230 fflush(stderr);
1231 }
1232
sewardj11e352f2007-11-30 11:11:02 +00001233 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_PRE, sem_t*,sem);
sewardjb4112022007-11-09 22:49:28 +00001234
1235 CALL_FN_W_W(ret, fn, sem);
1236
1237 if (ret != 0) {
1238 DO_PthAPIerror( "sem_post", errno );
1239 }
1240
1241 if (TRACE_SEM_FNS) {
1242 fprintf(stderr, " sem_post -> %d >>\n", ret);
1243 fflush(stderr);
1244 }
1245
1246 return ret;
1247}
1248PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
1249 return sem_post_WRK(sem);
1250}
1251PTH_FUNC(int, semZupostZAZa, sem_t* sem) { /* sem_post@* */
1252 return sem_post_WRK(sem);
1253}
1254
1255
1256
1257/*----------------------------------------------------------------*/
1258/*--- Qt 4 threading functions (w/ GNU name mangling) ---*/
1259/*----------------------------------------------------------------*/
1260
1261/* Handled: QMutex::lock()
1262 QMutex::unlock()
1263 QMutex::tryLock
1264 QReadWriteLock::lockForRead()
1265 QReadWriteLock::lockForWrite()
1266 QReadWriteLock::unlock()
1267
1268 Unhandled: QMutex::tryLock(int)
1269 QReadWriteLock::tryLockForRead(int)
1270 QReadWriteLock::tryLockForRead()
1271 QReadWriteLock::tryLockForWrite(int)
1272 QReadWriteLock::tryLockForWrite()
1273
1274 maybe not the next 3; qt-4.3.1 on Unix merely
1275 implements QWaitCondition using pthread_cond_t
1276 QWaitCondition::wait(QMutex*, unsigned long)
1277 QWaitCondition::wakeAll()
1278 QWaitCondition::wakeOne()
1279*/
1280
1281// soname is libQtCore.so.4 ; match against libQtCore.so*
1282#define QT4_FUNC(ret_ty, f, args...) \
1283 ret_ty I_WRAP_SONAME_FNNAME_ZZ(libQtCoreZdsoZa,f)(args); \
1284 ret_ty I_WRAP_SONAME_FNNAME_ZZ(libQtCoreZdsoZa,f)(args)
1285
1286// QMutex::lock()
1287QT4_FUNC(void, ZuZZN6QMutex4lockEv, // _ZN6QMutex4lockEv == QMutex::lock()
1288 void* self)
1289{
1290 OrigFn fn;
1291 VALGRIND_GET_ORIG_FN(fn);
1292 if (TRACE_QT4_FNS) {
1293 fprintf(stderr, "<< QMutex::lock %p", self); fflush(stderr);
1294 }
1295
1296 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
1297 void*,self, long,0/*!isTryLock*/);
1298
1299 CALL_FN_v_W(fn, self);
1300
1301 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1302 void*, self);
1303
1304 if (TRACE_QT4_FNS) {
1305 fprintf(stderr, " :: Q::lock done >>\n");
1306 }
1307}
1308
1309// QMutex::unlock()
1310QT4_FUNC(void, ZuZZN6QMutex6unlockEv, // _ZN6QMutex6unlockEv == QMutex::unlock()
1311 void* self)
1312{
1313 OrigFn fn;
1314 VALGRIND_GET_ORIG_FN(fn);
1315
1316 if (TRACE_QT4_FNS) {
1317 fprintf(stderr, "<< QMutex::unlock %p", self); fflush(stderr);
1318 }
1319
1320 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1321 void*, self);
1322
1323 CALL_FN_v_W(fn, self);
1324
1325 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
1326 void*, self);
1327
1328 if (TRACE_QT4_FNS) {
1329 fprintf(stderr, " Q::unlock done >>\n");
1330 }
1331}
1332
1333// QMutex::tryLock
1334// _ZN6QMutex7tryLockEv == bool QMutex::tryLock()
1335// using 'long' to mimic C++ 'bool'
1336QT4_FUNC(long, ZuZZN6QMutex7tryLockEv,
1337 void* self)
1338{
1339 OrigFn fn;
1340 long ret;
1341 VALGRIND_GET_ORIG_FN(fn);
1342 if (TRACE_QT4_FNS) {
1343 fprintf(stderr, "<< QMutex::tryLock %p", self); fflush(stderr);
1344 }
1345
1346 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
1347 void*,self, long,1/*isTryLock*/);
1348
1349 CALL_FN_W_W(ret, fn, self);
1350
1351 // assumes that only the low 8 bits of the 'bool' are significant
1352 if (ret & 0xFF) {
1353 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1354 void*, self);
1355 }
1356
1357 if (TRACE_QT4_FNS) {
1358 fprintf(stderr, " :: Q::tryLock -> %lu >>\n", ret);
1359 }
1360
1361 return ret;
1362}
1363
1364
1365// QReadWriteLock::lockForRead()
1366// _ZN14QReadWriteLock11lockForReadEv == QReadWriteLock::lockForRead()
1367QT4_FUNC(void, ZuZZN14QReadWriteLock11lockForReadEv,
1368 // _ZN14QReadWriteLock11lockForReadEv
1369 void* self)
1370{
1371 OrigFn fn;
1372 VALGRIND_GET_ORIG_FN(fn);
1373 if (TRACE_QT4_FNS) {
1374 fprintf(stderr, "<< QReadWriteLock::lockForRead %p", self);
1375 fflush(stderr);
1376 }
1377
sewardj789c3c52008-02-25 12:10:07 +00001378 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1379 void*,self,
1380 long,0/*!isW*/, long,0/*!isTryLock*/);
sewardjb4112022007-11-09 22:49:28 +00001381
1382 CALL_FN_v_W(fn, self);
1383
1384 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1385 void*,self, long,0/*!isW*/);
1386
1387 if (TRACE_QT4_FNS) {
1388 fprintf(stderr, " :: Q::lockForRead :: done >>\n");
1389 }
1390}
1391
1392// QReadWriteLock::lockForWrite()
1393// _ZN14QReadWriteLock12lockForWriteEv == QReadWriteLock::lockForWrite()
1394QT4_FUNC(void, ZuZZN14QReadWriteLock12lockForWriteEv,
1395 // _ZN14QReadWriteLock12lockForWriteEv
1396 void* self)
1397{
1398 OrigFn fn;
1399 VALGRIND_GET_ORIG_FN(fn);
1400 if (TRACE_QT4_FNS) {
1401 fprintf(stderr, "<< QReadWriteLock::lockForWrite %p", self);
1402 fflush(stderr);
1403 }
1404
sewardj789c3c52008-02-25 12:10:07 +00001405 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1406 void*,self,
1407 long,1/*isW*/, long,0/*!isTryLock*/);
sewardjb4112022007-11-09 22:49:28 +00001408
1409 CALL_FN_v_W(fn, self);
1410
1411 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1412 void*,self, long,1/*isW*/);
1413
1414 if (TRACE_QT4_FNS) {
1415 fprintf(stderr, " :: Q::lockForWrite :: done >>\n");
1416 }
1417}
1418
1419// QReadWriteLock::unlock()
1420// _ZN14QReadWriteLock6unlockEv == QReadWriteLock::unlock()
1421QT4_FUNC(void, ZuZZN14QReadWriteLock6unlockEv,
1422 // _ZN14QReadWriteLock6unlockEv
1423 void* self)
1424{
1425 OrigFn fn;
1426 VALGRIND_GET_ORIG_FN(fn);
1427 if (TRACE_QT4_FNS) {
1428 fprintf(stderr, "<< QReadWriteLock::unlock %p", self);
1429 fflush(stderr);
1430 }
1431
1432 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
1433 void*,self);
1434
1435 CALL_FN_v_W(fn, self);
1436
1437 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
1438 void*,self);
1439
1440 if (TRACE_QT4_FNS) {
1441 fprintf(stderr, " :: Q::unlock :: done >>\n");
1442 }
1443}
1444
1445
1446/*--------------------------------------------------------------------*/
1447/*--- end tc_intercepts.c ---*/
1448/*--------------------------------------------------------------------*/