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