1
2 /*--------------------------------------------------------------------*/
3 /*--- pthread intercepts for thread checking. ---*/
4 /*--- hg_intercepts.c ---*/
5 /*--------------------------------------------------------------------*/
6
7 /*
8 This file is part of Helgrind, a Valgrind tool for detecting errors
9 in threaded programs.
10
11 Copyright (C) 2007-2017 OpenWorks LLP
12 info@open-works.co.uk
13
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
29 The GNU General Public License is contained in the file COPYING.
30
31 Neither the names of the U.S. Department of Energy nor the
32 University of California nor the names of its contributors may be
33 used to endorse or promote products derived from this software
34 without prior written permission.
35 */
36
37 /* RUNS ON SIMULATED CPU
38 Interceptors for pthread_* functions, so that tc_main can see
39 significant thread events.
40
41 Important: when adding a function wrapper to this file, remember to
42 add a test case to tc20_verifywrap.c. A common cause of failure is
43 for wrappers to not engage on different distros, and
44 tc20_verifywrap essentially checks that each wrapper is really
45 doing something.
46 */
47
48 // 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
55 #include "pub_tool_basics.h"
56 #include "pub_tool_redir.h"
57 #include "pub_tool_clreq.h"
58 #include "helgrind.h"
59 #include "config.h"
60
61
62 #if defined(VGO_solaris)
63 /* See porting comments in drd/drd_pthread_intercepts.c
64 However when a POSIX threads API function (for example pthread_cond_init)
65 is built upon the Solaris one (cond_init), intercept only the bottom one.
66 Helgrind does not contain generic synchronization nesting like DRD
67 and double intercept confuses it. */
68 #include <synch.h>
69 #include <thread.h>
70 #endif /* VGO_solaris */
71
72
73 #define TRACE_PTH_FNS 0
74 #define TRACE_QT4_FNS 0
75 #define TRACE_GNAT_FNS 0
76
77
78 /*----------------------------------------------------------------*/
79 /*--- ---*/
80 /*----------------------------------------------------------------*/
81
82 #if defined(VGO_solaris)
83 /* On Solaris, libpthread is just a filter library on top of libc.
84 * Threading and synchronization functions in runtime linker are not
85 * intercepted.
86 */
87 #define PTH_FUNC(ret_ty, f, args...) \
88 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)(args); \
89 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)(args)
90
91 /* pthread_t is typedef'd to 'unsigned int' but in DO_CREQ_* macros
92 sizeof(Word) is expected. */
93 #define CREQ_PTHREAD_T Word
94 #define SEM_ERROR ret
95 #else
96 #define PTH_FUNC(ret_ty, f, args...) \
97 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args); \
98 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args)
99 #define CREQ_PTHREAD_T pthread_t
100 #define SEM_ERROR errno
101 #endif /* VGO_solaris */
102
103 // Do a client request. These are macros rather than a functions so
104 // as to avoid having an extra frame in stack traces.
105
106 // NB: these duplicate definitions in helgrind.h. But here, we
107 // can have better typing (Word etc) and assertions, whereas
108 // in helgrind.h we can't. Obviously it's important the two
109 // sets of definitions are kept in sync.
110
111 // nuke the previous definitions
112 #undef DO_CREQ_v_W
113 #undef DO_CREQ_v_WW
114 #undef DO_CREQ_W_WW
115 #undef DO_CREQ_v_WWW
116
117 #define DO_CREQ_v_W(_creqF, _ty1F,_arg1F) \
118 do { \
119 Word _arg1; \
120 assert(sizeof(_ty1F) == sizeof(Word)); \
121 _arg1 = (Word)(_arg1F); \
122 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
123 _arg1, 0,0,0,0); \
124 } while (0)
125
126 #define DO_CREQ_v_WW(_creqF, _ty1F,_arg1F, _ty2F,_arg2F) \
127 do { \
128 Word _arg1, _arg2; \
129 assert(sizeof(_ty1F) == sizeof(Word)); \
130 assert(sizeof(_ty2F) == sizeof(Word)); \
131 _arg1 = (Word)(_arg1F); \
132 _arg2 = (Word)(_arg2F); \
133 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
134 _arg1,_arg2,0,0,0); \
135 } while (0)
136
137 #define DO_CREQ_W_WW(_resF, _creqF, _ty1F,_arg1F, \
138 _ty2F,_arg2F) \
139 do { \
140 Word _res, _arg1, _arg2; \
141 assert(sizeof(_ty1F) == sizeof(Word)); \
142 assert(sizeof(_ty2F) == sizeof(Word)); \
143 _arg1 = (Word)(_arg1F); \
144 _arg2 = (Word)(_arg2F); \
145 _res = VALGRIND_DO_CLIENT_REQUEST_EXPR(2, \
146 (_creqF), \
147 _arg1,_arg2,0,0,0); \
148 _resF = _res; \
149 } while (0)
150
151 #define DO_CREQ_v_WWW(_creqF, _ty1F,_arg1F, \
152 _ty2F,_arg2F, _ty3F, _arg3F) \
153 do { \
154 Word _arg1, _arg2, _arg3; \
155 assert(sizeof(_ty1F) == sizeof(Word)); \
156 assert(sizeof(_ty2F) == sizeof(Word)); \
157 assert(sizeof(_ty3F) == sizeof(Word)); \
158 _arg1 = (Word)(_arg1F); \
159 _arg2 = (Word)(_arg2F); \
160 _arg3 = (Word)(_arg3F); \
161 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
162 _arg1,_arg2,_arg3,0,0); \
163 } while (0)
164
165 #define DO_CREQ_v_WWWW(_creqF, _ty1F,_arg1F, \
166 _ty2F, _arg2F, _ty3F, _arg3F, \
167 _ty4F, _arg4F) \
168 do { \
169 Word _arg1, _arg2, _arg3, _arg4; \
170 assert(sizeof(_ty1F) == sizeof(Word)); \
171 assert(sizeof(_ty2F) == sizeof(Word)); \
172 assert(sizeof(_ty3F) == sizeof(Word)); \
173 assert(sizeof(_ty4F) == sizeof(Word)); \
174 _arg1 = (Word)(_arg1F); \
175 _arg2 = (Word)(_arg2F); \
176 _arg3 = (Word)(_arg3F); \
177 _arg4 = (Word)(_arg4F); \
178 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
179 _arg1,_arg2,_arg3,_arg4,0); \
180 } while (0)
181
182 #define DO_PthAPIerror(_fnnameF, _errF) \
183 do { \
184 const char* _fnname = (_fnnameF); \
185 long _err = (long)(int)(_errF); \
186 const char* _errstr = lame_strerror(_err); \
187 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTH_API_ERROR, \
188 char*,_fnname, \
189 long,_err, char*,_errstr); \
190 } while (0)
191
192
193 /* Needed for older glibcs (2.3 and older, at least) who don't
194 otherwise "know" about pthread_rwlock_anything or about
195 PTHREAD_MUTEX_RECURSIVE (amongst things). */
196 #define _GNU_SOURCE 1
197
198 #include <stdio.h>
199 #include <assert.h>
200 #include <errno.h>
201 #include <pthread.h>
202
203 /* A standalone memcmp. */
204 __attribute__((noinline))
my_memcmp(const void * ptr1,const void * ptr2,size_t size)205 static int my_memcmp ( const void* ptr1, const void* ptr2, size_t size)
206 {
207 const unsigned char* uchar_ptr1 = (const unsigned char*) ptr1;
208 const unsigned char* uchar_ptr2 = (const unsigned char*) ptr2;
209 size_t i;
210 for (i = 0; i < size; ++i) {
211 if (uchar_ptr1[i] != uchar_ptr2[i])
212 return (uchar_ptr1[i] < uchar_ptr2[i]) ? -1 : 1;
213 }
214 return 0;
215 }
216
217 /* A lame version of strerror which doesn't use the real libc
218 strerror_r, since using the latter just generates endless more
219 threading errors (glibc goes off and does tons of crap w.r.t.
220 locales etc) */
lame_strerror(long err)221 static const HChar* lame_strerror ( long err )
222 {
223 switch (err) {
224 case EPERM: return "EPERM: Operation not permitted";
225 case ENOENT: return "ENOENT: No such file or directory";
226 case ESRCH: return "ESRCH: No such process";
227 case EINTR: return "EINTR: Interrupted system call";
228 case EBADF: return "EBADF: Bad file number";
229 case EAGAIN: return "EAGAIN: Try again";
230 case ENOMEM: return "ENOMEM: Out of memory";
231 case EACCES: return "EACCES: Permission denied";
232 case EFAULT: return "EFAULT: Bad address";
233 case EEXIST: return "EEXIST: File exists";
234 case EINVAL: return "EINVAL: Invalid argument";
235 case EMFILE: return "EMFILE: Too many open files";
236 case ENOSYS: return "ENOSYS: Function not implemented";
237 case EOVERFLOW: return "EOVERFLOW: Value too large "
238 "for defined data type";
239 case EBUSY: return "EBUSY: Device or resource busy";
240 case ETIMEDOUT: return "ETIMEDOUT: Connection timed out";
241 case EDEADLK: return "EDEADLK: Resource deadlock would occur";
242 case EOPNOTSUPP: return "EOPNOTSUPP: Operation not supported on "
243 "transport endpoint"; /* honest, guv */
244 #if !defined(VGO_dragonfly)
245 case ETIME: return "ETIME: Timer expired";
246 #endif
247 default: return "hg_intercepts.c: lame_strerror(): "
248 "unhandled case -- please fix me!";
249 }
250 }
251
252 #if defined(VGO_solaris)
253 /*
254 * Solaris provides higher throughput, parallelism and scalability than other
255 * operating systems, at the cost of more fine-grained locking activity.
256 * This means for example that when a thread is created under Linux, just one
257 * big lock in glibc is used for all thread setup. Solaris libc uses several
258 * fine-grained locks and the creator thread resumes its activities as soon
259 * as possible, leaving for example stack and TLS setup activities to the
260 * created thread.
261 *
262 * This situation confuses Helgrind as it assumes there is some false ordering
263 * in place between creator and created thread; and therefore many types of
264 * race conditions in the application would not be reported. To prevent such
265 * false ordering, command line option --ignore-thread-creation is set to
266 * 'yes' by default on Solaris. All activity (loads, stores, client requests)
267 * is therefore ignored during:
268 * - pthread_create() call in the creator thread [libc.so]
269 * - thread creation phase (stack and TLS setup) in the created thread [libc.so]
270 *
271 * As explained in the comments for _ti_bind_guard(), whenever the runtime
272 * linker has to perform any activity (such as resolving a symbol), it protects
273 * its data structures by calling into rt_bind_guard() which in turn invokes
274 * _ti_bind_guard() in libc. Pointers to _ti_bind_guard() and _ti_bind_clear()
275 * are passed from libc to runtime linker in _ld_libc() call during libc_init().
276 * All activity is also ignored during:
277 * - runtime dynamic linker work between rt_bind_guard() and rt_bind_clear()
278 * calls [ld.so]
279 *
280 * This also means that Helgrind does not report race conditions in libc (when
281 * --ignore-thread-creation=yes) and runtime linker itself (unconditionally)
282 * during these ignored sequences.
283 */
284
285 #include "pub_tool_libcassert.h"
286 #include "pub_tool_vki.h"
287
288 /*
289 * Original function pointers for _ti_bind_guard() and _ti_bind_clear()
290 * from libc. They are intercepted in function wrapper of _ld_libc().
291 */
292 typedef int (*hg_rtld_guard_fn)(int flags);
293 static hg_rtld_guard_fn hg_rtld_bind_guard = NULL;
294 static hg_rtld_guard_fn hg_rtld_bind_clear = NULL;
295
296 static void hg_init(void) __attribute__((constructor));
hg_init(void)297 static void hg_init(void)
298 {
299 if ((hg_rtld_bind_guard == NULL) || (hg_rtld_bind_clear == NULL)) {
300 fprintf(stderr,
301 "Bind guard functions for the runtime linker (ld.so.1) were not intercepted.\n"
302 "This means the interface between libc and runtime linker changed\n"
303 "and Helgrind needs to be ported properly. Giving up.\n");
304 tl_assert(0);
305 }
306 }
307
308 /*
309 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
310 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
311 * and CI_BIND_CLEAR, to provide resilience against function renaming.
312 */
_ti_bind_guard_intercept_WRK(int flags)313 static int _ti_bind_guard_intercept_WRK(int flags)
314 {
315 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_RTLD_BIND_GUARD,
316 flags, 0, 0, 0, 0);
317 return hg_rtld_bind_guard(flags);
318 }
319
_ti_bind_clear_intercept_WRK(int flags)320 static int _ti_bind_clear_intercept_WRK(int flags)
321 {
322 int ret = hg_rtld_bind_clear(flags);
323 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_RTLD_BIND_CLEAR,
324 flags, 0, 0, 0, 0);
325 return ret;
326 }
327
328 /*
329 * Wrapped _ld_libc() from the runtime linker ld.so.1.
330 */
331 void I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr);
I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LD_SO_1,ZuldZulibc)332 void I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr)
333 {
334 OrigFn fn;
335 int tag;
336
337 VALGRIND_GET_ORIG_FN(fn);
338
339 vki_Lc_interface *funcs = ptr;
340 for (tag = funcs->ci_tag; tag != 0; tag = (++funcs)->ci_tag) {
341 switch (tag) {
342 case VKI_CI_BIND_GUARD:
343 if (funcs->vki_ci_un.ci_func != _ti_bind_guard_intercept_WRK) {
344 hg_rtld_bind_guard = funcs->vki_ci_un.ci_func;
345 funcs->vki_ci_un.ci_func = _ti_bind_guard_intercept_WRK;
346 }
347 break;
348 case VKI_CI_BIND_CLEAR:
349 if (funcs->vki_ci_un.ci_func != _ti_bind_clear_intercept_WRK) {
350 hg_rtld_bind_clear = funcs->vki_ci_un.ci_func;
351 funcs->vki_ci_un.ci_func = _ti_bind_clear_intercept_WRK;
352 }
353 break;
354 }
355 }
356
357 CALL_FN_v_W(fn, ptr);
358 }
359 #endif /* VGO_solaris */
360
361
362 /*----------------------------------------------------------------*/
363 /*--- pthread_create, pthread_join, pthread_exit ---*/
364 /*----------------------------------------------------------------*/
365
mythread_wrapper(void * xargsV)366 static void* mythread_wrapper ( void* xargsV )
367 {
368 volatile Word* xargs = (volatile Word*) xargsV;
369 void*(*fn)(void*) = (void*(*)(void*))xargs[0];
370 void* arg = (void*)xargs[1];
371 pthread_t me = pthread_self();
372 /* Tell the tool what my pthread_t is. */
373 DO_CREQ_v_W(_VG_USERREQ__HG_SET_MY_PTHREAD_T, CREQ_PTHREAD_T, me);
374 /* allow the parent to proceed. We can't let it proceed until
375 we're ready because (1) we need to make sure it doesn't exit and
376 hence deallocate xargs[] while we still need it, and (2) we
377 don't want either parent nor child to proceed until the tool has
378 been notified of the child's pthread_t.
379
380 Note that parent and child access args[] without a lock,
381 effectively using args[2] as a spinlock in order to get the
382 parent to wait until the child passes this point. The parent
383 disables checking on xargs[] before creating the child and
384 re-enables it once the child goes past this point, so the user
385 never sees the race. The previous approach (suppressing the
386 resulting error) was flawed, because it could leave shadow
387 memory for args[] in a state in which subsequent use of it by
388 the parent would report further races. */
389 xargs[2] = 0;
390 /* Now we can no longer safely use xargs[]. */
391 return (void*) fn( (void*)arg );
392 }
393
394 //-----------------------------------------------------------
395 // glibc: pthread_create@GLIBC_2.0
396 // glibc: pthread_create@@GLIBC_2.1
397 // glibc: pthread_create@@GLIBC_2.2.5
398 // darwin: pthread_create
399 // darwin: pthread_create_suspended_np (trapped)
400 //
401 /* ensure this has its own frame, so as to make it more distinguishable
402 in suppressions */
403 __attribute__((noinline))
pthread_create_WRK(pthread_t * thread,const pthread_attr_t * attr,void * (* start)(void *),void * arg)404 static int pthread_create_WRK(pthread_t *thread, const pthread_attr_t *attr,
405 void *(*start) (void *), void *arg)
406 {
407 int ret;
408 OrigFn fn;
409 volatile Word xargs[3];
410
411 VALGRIND_GET_ORIG_FN(fn);
412 if (TRACE_PTH_FNS) {
413 fprintf(stderr, "<< pthread_create wrapper"); fflush(stderr);
414 }
415 xargs[0] = (Word)start;
416 xargs[1] = (Word)arg;
417 xargs[2] = 1; /* serves as a spinlock -- sigh */
418 /* Disable checking on the spinlock and the two words used to
419 convey args to the child. Basically we need to make it appear
420 as if the child never accessed this area, since merely
421 suppressing the resulting races does not address the issue that
422 that piece of the parent's stack winds up in the "wrong" state
423 and therefore may give rise to mysterious races when the parent
424 comes to re-use this piece of stack in some other frame. */
425 VALGRIND_HG_DISABLE_CHECKING(&xargs, sizeof(xargs));
426
427 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_BEGIN,
428 0, 0, 0, 0, 0);
429 CALL_FN_W_WWWW(ret, fn, thread,attr,mythread_wrapper,&xargs[0]);
430 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_END,
431 0, 0, 0, 0, 0);
432
433 if (ret == 0) {
434 /* we have to wait for the child to notify the tool of its
435 pthread_t before continuing */
436 while (xargs[2] != 0) {
437 /* Do nothing. We need to spin until the child writes to
438 xargs[2]. However, that can lead to starvation in the
439 child and very long delays (eg, tc19_shadowmem on
440 ppc64-linux Fedora Core 6). So yield the cpu if we can,
441 to let the child run at the earliest available
442 opportunity. */
443 sched_yield();
444 }
445 } else {
446 DO_PthAPIerror( "pthread_create", ret );
447 }
448
449 /* Reenable checking on the area previously used to communicate
450 with the child. */
451 VALGRIND_HG_ENABLE_CHECKING(&xargs, sizeof(xargs));
452
453 if (TRACE_PTH_FNS) {
454 fprintf(stderr, " :: pth_create -> %d >>\n", ret);
455 }
456 return ret;
457 }
458 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZucreateZAZa,pthread_t * thread,const pthread_attr_t * attr,void * (* start)(void *),void * arg)459 PTH_FUNC(int, pthreadZucreateZAZa, // pthread_create@*
460 pthread_t *thread, const pthread_attr_t *attr,
461 void *(*start) (void *), void *arg) {
462 return pthread_create_WRK(thread, attr, start, arg);
463 }
464 #elif defined(VGO_dragonfly)
PTH_FUNC(int,pthreadZucreate,pthread_t * thread,const pthread_attr_t * attr,void * (* start)(void *),void * arg)465 PTH_FUNC(int, pthreadZucreate, // pthread_create
466 pthread_t *thread, const pthread_attr_t *attr,
467 void *(*start) (void *), void *arg) {
468 return pthread_create_WRK(thread, attr, start, arg);
469 }
470 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZucreate,pthread_t * thread,const pthread_attr_t * attr,void * (* start)(void *),void * arg)471 PTH_FUNC(int, pthreadZucreate, // pthread_create
472 pthread_t *thread, const pthread_attr_t *attr,
473 void *(*start) (void *), void *arg) {
474 return pthread_create_WRK(thread, attr, start, arg);
475 }
PTH_FUNC(int,pthreadZucreateZuZa,pthread_t * thread,const pthread_attr_t * attr,void * (* start)(void *),void * arg)476 PTH_FUNC(int, pthreadZucreateZuZa, // pthread_create_*
477 pthread_t *thread, const pthread_attr_t *attr,
478 void *(*start) (void *), void *arg) {
479 // trap anything else
480 assert(0);
481 }
482 #elif defined(VGO_solaris)
PTH_FUNC(int,pthreadZucreate,pthread_t * thread,const pthread_attr_t * attr,void * (* start)(void *),void * arg)483 PTH_FUNC(int, pthreadZucreate, // pthread_create
484 pthread_t *thread, const pthread_attr_t *attr,
485 void *(*start) (void *), void *arg) {
486 return pthread_create_WRK(thread, attr, start, arg);
487 }
488 #else
489 # error "Unsupported OS"
490 #endif
491
492 #if defined(VGO_solaris)
493 /* Solaris also provides thr_create() in addition to pthread_create().
494 * Both pthread_create(3C) and thr_create(3C) are based on private
495 * _thrp_create().
496 */
497 __attribute__((noinline))
thr_create_WRK(void * stk,size_t stksize,void * (* start)(void *),void * arg,long flags,thread_t * new_thread)498 static int thr_create_WRK(void *stk, size_t stksize, void *(*start)(void *),
499 void *arg, long flags, thread_t *new_thread)
500 {
501 int ret;
502 OrigFn fn;
503 volatile Word xargs[3];
504
505 VALGRIND_GET_ORIG_FN(fn);
506 if (TRACE_PTH_FNS) {
507 fprintf(stderr, "<< thr_create wrapper"); fflush(stderr);
508 }
509 xargs[0] = (Word)start;
510 xargs[1] = (Word)arg;
511 xargs[2] = 1; /* serves as a spinlock -- sigh */
512 /* See comments in pthread_create_WRK() */
513 VALGRIND_HG_DISABLE_CHECKING(&xargs, sizeof(xargs));
514
515 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_BEGIN,
516 0, 0, 0, 0, 0);
517 CALL_FN_W_6W(ret, fn, stk, stksize, mythread_wrapper, start, flags,
518 new_thread);
519 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_END,
520 0, 0, 0, 0, 0);
521
522 if (ret == 0) {
523 while (xargs[2] != 0) {
524 /* See comments in pthread_create_WRK(). */
525 sched_yield();
526 }
527 } else {
528 DO_PthAPIerror("thr_create", ret);
529 }
530
531 VALGRIND_HG_ENABLE_CHECKING(&xargs, sizeof(xargs));
532
533 if (TRACE_PTH_FNS) {
534 fprintf(stderr, " :: thr_create -> %d >>\n", ret);
535 }
536 return ret;
537 }
PTH_FUNC(int,thrZucreate,void * stk,size_t stksize,void * (* start)(void *),void * arg,long flags,thread_t * new_thread)538 PTH_FUNC(int, thrZucreate, // thr_create
539 void *stk, size_t stksize, void *(*start)(void *),
540 void *arg, long flags, thread_t *new_thread) {
541 return thr_create_WRK(stk, stksize, start, arg, flags, new_thread);
542 }
543 #endif /* VGO_solaris */
544
545
546 //-----------------------------------------------------------
547 // glibc: pthread_join
548 // darwin: pthread_join
549 // darwin: pthread_join$NOCANCEL$UNIX2003
550 // darwin pthread_join$UNIX2003
551 __attribute__((noinline))
pthread_join_WRK(pthread_t thread,void ** value_pointer)552 static int pthread_join_WRK(pthread_t thread, void** value_pointer)
553 {
554 int ret;
555 OrigFn fn;
556 VALGRIND_GET_ORIG_FN(fn);
557 if (TRACE_PTH_FNS) {
558 fprintf(stderr, "<< pthread_join wrapper"); fflush(stderr);
559 }
560
561 CALL_FN_W_WW(ret, fn, thread,value_pointer);
562
563 /* At least with NPTL as the thread library, this is safe because
564 it is guaranteed (by NPTL) that the joiner will completely gone
565 before pthread_join (the original) returns. See email below.*/
566 if (ret == 0 /*success*/) {
567 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST, CREQ_PTHREAD_T, thread);
568 } else {
569 DO_PthAPIerror( "pthread_join", ret );
570 }
571
572 if (TRACE_PTH_FNS) {
573 fprintf(stderr, " :: pth_join -> %d >>\n", ret);
574 }
575 return ret;
576 }
577 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZujoin,pthread_t thread,void ** value_pointer)578 PTH_FUNC(int, pthreadZujoin, // pthread_join
579 pthread_t thread, void** value_pointer) {
580 return pthread_join_WRK(thread, value_pointer);
581 }
582 #elif defined(VGO_dragonfly)
PTH_FUNC(int,pthreadZujoin,pthread_t thread,void ** value_pointer)583 PTH_FUNC(int, pthreadZujoin, // pthread_join
584 pthread_t thread, void** value_pointer) {
585 return pthread_join_WRK(thread, value_pointer);
586 }
587 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZujoinZa,pthread_t thread,void ** value_pointer)588 PTH_FUNC(int, pthreadZujoinZa, // pthread_join*
589 pthread_t thread, void** value_pointer) {
590 return pthread_join_WRK(thread, value_pointer);
591 }
592 #elif defined(VGO_solaris)
PTH_FUNC(int,pthreadZujoin,pthread_t thread,void ** value_pointer)593 PTH_FUNC(int, pthreadZujoin, // pthread_join
594 pthread_t thread, void** value_pointer) {
595 return pthread_join_WRK(thread, value_pointer);
596 }
597 #else
598 # error "Unsupported OS"
599 #endif
600
601
602 /* Behaviour of pthread_join on NPTL:
603
604 Me:
605 I have a question re the NPTL pthread_join implementation.
606
607 Suppose I am the thread 'stayer'.
608
609 If I call pthread_join(quitter), is it guaranteed that the
610 thread 'quitter' has really exited before pthread_join returns?
611
612 IOW, is it guaranteed that 'quitter' will not execute any further
613 instructions after pthread_join returns?
614
615 I believe this is true based on the following analysis of
616 glibc-2.5 sources. However am not 100% sure and would appreciate
617 confirmation.
618
619 'quitter' will be running start_thread() in nptl/pthread_create.c
620
621 The last action of start_thread() is to exit via
622 __exit_thread_inline(0), which simply does sys_exit
623 (nptl/pthread_create.c:403)
624
625 'stayer' meanwhile is waiting for lll_wait_tid (pd->tid)
626 (call at nptl/pthread_join.c:89)
627
628 As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
629 lll_wait_tid will not return until kernel notifies via futex
630 wakeup that 'quitter' has terminated.
631
632 Hence pthread_join cannot return until 'quitter' really has
633 completely disappeared.
634
635 Drepper:
636 > As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
637 > lll_wait_tid will not return until kernel notifies via futex
638 > wakeup that 'quitter' has terminated.
639 That's the key. The kernel resets the TID field after the thread is
640 done. No way the joiner can return before the thread is gone.
641 */
642
643 #if defined(VGO_solaris)
644 /* Solaris also provides thr_join() in addition to pthread_join().
645 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
646 *
647 * :TODO: No functionality is currently provided for joinee == 0 and departed.
648 * This would require another client request, of course.
649 */
650 __attribute__((noinline))
thr_join_WRK(thread_t joinee,thread_t * departed,void ** thread_return)651 static int thr_join_WRK(thread_t joinee, thread_t *departed, void **thread_return)
652 {
653 int ret;
654 OrigFn fn;
655 VALGRIND_GET_ORIG_FN(fn);
656 if (TRACE_PTH_FNS) {
657 fprintf(stderr, "<< thr_join wrapper"); fflush(stderr);
658 }
659
660 CALL_FN_W_WWW(ret, fn, joinee, departed, thread_return);
661
662 if (ret == 0 /*success*/) {
663 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST, CREQ_PTHREAD_T, joinee);
664 } else {
665 DO_PthAPIerror("thr_join", ret);
666 }
667
668 if (TRACE_PTH_FNS) {
669 fprintf(stderr, " :: thr_join -> %d >>\n", ret);
670 }
671 return ret;
672 }
PTH_FUNC(int,thrZujoin,thread_t joinee,thread_t * departed,void ** thread_return)673 PTH_FUNC(int, thrZujoin, // thr_join
674 thread_t joinee, thread_t *departed, void **thread_return) {
675 return thr_join_WRK(joinee, departed, thread_return);
676 }
677 #endif /* VGO_solaris */
678
679
680 //-----------------------------------------------------------
681 // Ada gcc gnat runtime:
682 // The gnat gcc Ada runtime does not use pthread_join. Instead, it uses
683 // a combination of other pthread primitives to ensure a child thread
684 // is gone. This combination is somewhat functionally equivalent to a
685 // pthread_join.
686 // We wrap two hook procedures called by the gnat gcc Ada runtime
687 // that allows helgrind to understand the semantic of Ada task dependencies
688 // and termination.
689 // procedure Master_Hook
690 // (Dependent : Task_Id;
691 // Parent : Task_Id;
692 // Master_Level : Integer);
693 // where type Task_Id is access all Ada_Task_Control_Block;
694 // System.Tasking.Debug.Master_Hook is called by a task Dependent to
695 // indicate that its master is identified by master+master_level.
696 void I_WRAP_SONAME_FNNAME_ZU
697 (Za,
698 system__tasking__debug__master_hook)
699 (void *dependent, void *master, int master_level);
I_WRAP_SONAME_FNNAME_ZU(Za,system__tasking__debug__master_hook)700 void I_WRAP_SONAME_FNNAME_ZU
701 (Za,
702 system__tasking__debug__master_hook)
703 (void *dependent, void *master, int master_level)
704 {
705 OrigFn fn;
706 VALGRIND_GET_ORIG_FN(fn);
707 if (TRACE_GNAT_FNS) {
708 fprintf(stderr, "<< GNAT master_hook wrapper "
709 "dependent %p master %p master_level %d\n",
710 dependent, master, master_level); fflush(stderr);
711 }
712
713 // We call the wrapped function, even if it is a null body.
714 CALL_FN_v_WWW(fn, dependent, master, master_level);
715
716 DO_CREQ_v_WWW(_VG_USERREQ__HG_GNAT_MASTER_HOOK,
717 void*,dependent, void*,master,
718 Word, (Word)master_level);
719
720 if (TRACE_GNAT_FNS) {
721 fprintf(stderr, " :: GNAT master_hook >>\n");
722 }
723 }
724
725 // System.Tasking.Debug.Master_Completed_Hook is called by a task to
726 // indicate that it has completed a master.
727 // procedure Master_Completed_Hook
728 // (Self_ID : Task_Id;
729 // Master_Level : Integer);
730 // where type Task_Id is access all Ada_Task_Control_Block;
731 // This indicates that all its Dependent tasks (that identified themselves
732 // with the Master_Hook call) are terminated. Helgrind can consider
733 // at this point that the equivalent of a 'pthread_join' has been done
734 // between self_id and all dependent tasks at master_level.
735 void I_WRAP_SONAME_FNNAME_ZU
736 (Za,
737 system__tasking__debug__master_completed_hook)
738 (void *self_id, int master_level);
I_WRAP_SONAME_FNNAME_ZU(Za,system__tasking__debug__master_completed_hook)739 void I_WRAP_SONAME_FNNAME_ZU
740 (Za,
741 system__tasking__debug__master_completed_hook)
742 (void *self_id, int master_level)
743 {
744 OrigFn fn;
745 VALGRIND_GET_ORIG_FN(fn);
746 if (TRACE_GNAT_FNS) {
747 fprintf(stderr, "<< GNAT master_completed_hook wrapper "
748 "self_id %p master_level %d\n",
749 self_id, master_level); fflush(stderr);
750 }
751
752 // We call the wrapped function, even if it is a null body.
753 CALL_FN_v_WW(fn, self_id, master_level);
754
755 DO_CREQ_v_WW(_VG_USERREQ__HG_GNAT_MASTER_COMPLETED_HOOK,
756 void*,self_id, Word,(Word)master_level);
757
758 if (TRACE_GNAT_FNS) {
759 fprintf(stderr, " :: GNAT master_completed_hook >>\n");
760 }
761 }
762
763 /*----------------------------------------------------------------*/
764 /*--- pthread_mutex_t functions ---*/
765 /*----------------------------------------------------------------*/
766
767 /* Handled: pthread_mutex_init pthread_mutex_destroy
768 pthread_mutex_lock
769 pthread_mutex_trylock pthread_mutex_timedlock
770 pthread_mutex_unlock
771 */
772
773 //-----------------------------------------------------------
774 #if !defined(VGO_solaris)
775 // glibc: pthread_mutex_init
776 // darwin: pthread_mutex_init
PTH_FUNC(int,pthreadZumutexZuinit,pthread_mutex_t * mutex,pthread_mutexattr_t * attr)777 PTH_FUNC(int, pthreadZumutexZuinit, // pthread_mutex_init
778 pthread_mutex_t *mutex,
779 pthread_mutexattr_t* attr)
780 {
781 int ret;
782 long mbRec;
783 OrigFn fn;
784 VALGRIND_GET_ORIG_FN(fn);
785 if (TRACE_PTH_FNS) {
786 fprintf(stderr, "<< pthread_mxinit %p", mutex); fflush(stderr);
787 }
788
789 mbRec = 0;
790 if (attr) {
791 int ty, zzz;
792 zzz = pthread_mutexattr_gettype(attr, &ty);
793 if (zzz == 0 && ty == PTHREAD_MUTEX_RECURSIVE)
794 mbRec = 1;
795 }
796
797 CALL_FN_W_WW(ret, fn, mutex,attr);
798
799 if (ret == 0 /*success*/) {
800 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
801 pthread_mutex_t*,mutex, long,mbRec);
802 } else {
803 DO_PthAPIerror( "pthread_mutex_init", ret );
804 }
805
806 if (TRACE_PTH_FNS) {
807 fprintf(stderr, " :: mxinit -> %d >>\n", ret);
808 }
809 return ret;
810 }
811
812 #else /* VGO_solaris */
813
814 // Solaris: mutex_init (pthread_mutex_init calls here)
PTH_FUNC(int,mutexZuinit,mutex_t * mutex,int type,void * arg)815 PTH_FUNC(int, mutexZuinit, // mutex_init
816 mutex_t *mutex, int type, void *arg)
817 {
818 int ret;
819 long mbRec;
820 OrigFn fn;
821 VALGRIND_GET_ORIG_FN(fn);
822 if (TRACE_PTH_FNS) {
823 fprintf(stderr, "<< mxinit %p", mutex); fflush(stderr);
824 }
825
826 mbRec = ((type & LOCK_RECURSIVE) != 0) ? 1 : 0;
827
828 CALL_FN_W_WWW(ret, fn, mutex, type, arg);
829
830 if (ret == 0 /*success*/) {
831 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
832 mutex_t *, mutex, long, mbRec);
833 } else {
834 DO_PthAPIerror("mutex_init", ret);
835 }
836
837 if (TRACE_PTH_FNS) {
838 fprintf(stderr, " :: mxinit -> %d >>\n", ret);
839 }
840 return ret;
841 }
842 #endif /* VGO_solaris */
843
844
845 //-----------------------------------------------------------
846 // glibc: pthread_mutex_destroy
847 // darwin: pthread_mutex_destroy
848 // Solaris: mutex_destroy (pthread_mutex_destroy is a weak alias)
849 __attribute__((noinline))
mutex_destroy_WRK(pthread_mutex_t * mutex)850 static int mutex_destroy_WRK(pthread_mutex_t *mutex)
851 {
852 int ret;
853 unsigned long mutex_is_init;
854 OrigFn fn;
855
856 VALGRIND_GET_ORIG_FN(fn);
857 if (TRACE_PTH_FNS) {
858 fprintf(stderr, "<< pthread_mxdestroy %p", mutex); fflush(stderr);
859 }
860
861 if (mutex != NULL) {
862 static const pthread_mutex_t mutex_init = PTHREAD_MUTEX_INITIALIZER;
863 mutex_is_init = my_memcmp(mutex, &mutex_init, sizeof(*mutex)) == 0;
864 } else {
865 mutex_is_init = 0;
866 }
867
868 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
869 pthread_mutex_t*, mutex, unsigned long, mutex_is_init);
870
871 CALL_FN_W_W(ret, fn, mutex);
872
873 if (ret != 0) {
874 DO_PthAPIerror( "pthread_mutex_destroy", ret );
875 }
876
877 if (TRACE_PTH_FNS) {
878 fprintf(stderr, " :: mxdestroy -> %d >>\n", ret);
879 }
880 return ret;
881 }
882
883 #if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_dragonfly)
PTH_FUNC(int,pthreadZumutexZudestroy,pthread_mutex_t * mutex)884 PTH_FUNC(int, pthreadZumutexZudestroy, // pthread_mutex_destroy
885 pthread_mutex_t *mutex) {
886 return mutex_destroy_WRK(mutex);
887 }
888 #elif defined(VGO_solaris)
PTH_FUNC(int,mutexZudestroy,pthread_mutex_t * mutex)889 PTH_FUNC(int, mutexZudestroy, // mutex_destroy
890 pthread_mutex_t *mutex) {
891 return mutex_destroy_WRK(mutex);
892 }
893 #else
894 # error "Unsupported OS"
895 #endif
896
897
898 //-----------------------------------------------------------
899 // glibc: pthread_mutex_lock
900 // darwin: pthread_mutex_lock
901 // Solaris: mutex_lock (pthread_mutex_lock is a weak alias)
902 __attribute__((noinline))
mutex_lock_WRK(pthread_mutex_t * mutex)903 static int mutex_lock_WRK(pthread_mutex_t *mutex)
904 {
905 int ret;
906 OrigFn fn;
907 VALGRIND_GET_ORIG_FN(fn);
908 if (TRACE_PTH_FNS) {
909 fprintf(stderr, "<< pthread_mxlock %p", mutex); fflush(stderr);
910 }
911
912 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
913 pthread_mutex_t*,mutex, long,0/*!isTryLock*/);
914
915 CALL_FN_W_W(ret, fn, mutex);
916
917 /* There's a hole here: libpthread now knows the lock is locked,
918 but the tool doesn't, so some other thread could run and detect
919 that the lock has been acquired by someone (this thread). Does
920 this matter? Not sure, but I don't think so. */
921
922 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
923 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
924
925 if (ret != 0) {
926 DO_PthAPIerror( "pthread_mutex_lock", ret );
927 }
928
929 if (TRACE_PTH_FNS) {
930 fprintf(stderr, " :: mxlock -> %d >>\n", ret);
931 }
932 return ret;
933 }
934
935 #if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_dragonfly)
PTH_FUNC(int,pthreadZumutexZulock,pthread_mutex_t * mutex)936 PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock
937 pthread_mutex_t *mutex) {
938 return mutex_lock_WRK(mutex);
939 }
940 #elif defined(VGO_solaris)
PTH_FUNC(int,mutexZulock,pthread_mutex_t * mutex)941 PTH_FUNC(int, mutexZulock, // mutex_lock
942 pthread_mutex_t *mutex) {
943 return mutex_lock_WRK(mutex);
944 }
945 #else
946 # error "Unsupported OS"
947 #endif
948
949 #if defined(VGO_solaris)
950 /* Internal to libc. Mutex is usually initialized only implicitly,
951 * by zeroing mutex_t structure.
952 */
953 __attribute__((noinline))
PTH_FUNC(void,lmutexZulock,mutex_t * mutex)954 PTH_FUNC(void, lmutexZulock, // lmutex_lock
955 mutex_t *mutex)
956 {
957 OrigFn fn;
958 VALGRIND_GET_ORIG_FN(fn);
959 if (TRACE_PTH_FNS) {
960 fprintf(stderr, "<< lmxlock %p", mutex); fflush(stderr);
961 }
962
963 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
964 mutex_t *, mutex, long, 0 /*!isTryLock*/);
965 CALL_FN_v_W(fn, mutex);
966 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
967 mutex_t *, mutex, long, True);
968
969 if (TRACE_PTH_FNS) {
970 fprintf(stderr, " :: lmxlock >>\n");
971 }
972 }
973 #endif /* VGO_solaris */
974
975
976 //-----------------------------------------------------------
977 // glibc: pthread_mutex_trylock
978 // darwin: pthread_mutex_trylock
979 // Solaris: mutex_trylock (pthread_mutex_trylock is a weak alias)
980 //
981 // pthread_mutex_trylock. The handling needed here is very similar
982 // to that for pthread_mutex_lock, except that we need to tell
983 // the pre-lock creq that this is a trylock-style operation, and
984 // therefore not to complain if the lock is nonrecursive and
985 // already locked by this thread -- because then it'll just fail
986 // immediately with EBUSY.
987 __attribute__((noinline))
mutex_trylock_WRK(pthread_mutex_t * mutex)988 static int mutex_trylock_WRK(pthread_mutex_t *mutex)
989 {
990 int ret;
991 OrigFn fn;
992 VALGRIND_GET_ORIG_FN(fn);
993 if (TRACE_PTH_FNS) {
994 fprintf(stderr, "<< pthread_mxtrylock %p", mutex); fflush(stderr);
995 }
996
997 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
998 pthread_mutex_t*,mutex, long,1/*isTryLock*/);
999
1000 CALL_FN_W_W(ret, fn, mutex);
1001
1002 /* There's a hole here: libpthread now knows the lock is locked,
1003 but the tool doesn't, so some other thread could run and detect
1004 that the lock has been acquired by someone (this thread). Does
1005 this matter? Not sure, but I don't think so. */
1006
1007 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1008 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
1009
1010 if (ret != 0) {
1011 if (ret != EBUSY)
1012 DO_PthAPIerror( "pthread_mutex_trylock", ret );
1013 }
1014
1015 if (TRACE_PTH_FNS) {
1016 fprintf(stderr, " :: mxtrylock -> %d >>\n", ret);
1017 }
1018 return ret;
1019 }
1020
1021 #if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_dragonfly)
PTH_FUNC(int,pthreadZumutexZutrylock,pthread_mutex_t * mutex)1022 PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock
1023 pthread_mutex_t *mutex) {
1024 return mutex_trylock_WRK(mutex);
1025 }
1026 #elif defined(VGO_solaris)
PTH_FUNC(int,mutexZutrylock,pthread_mutex_t * mutex)1027 PTH_FUNC(int, mutexZutrylock, // mutex_trylock
1028 pthread_mutex_t *mutex) {
1029 return mutex_trylock_WRK(mutex);
1030 }
1031 #else
1032 # error "Unsupported OS"
1033 #endif
1034
1035
1036 //-----------------------------------------------------------
1037 // glibc: pthread_mutex_timedlock
1038 // darwin: (doesn't appear to exist)
1039 // Solaris: pthread_mutex_timedlock
1040 //
1041 // pthread_mutex_timedlock. Identical logic to pthread_mutex_trylock.
1042 __attribute__((noinline))
mutex_timedlock_WRK(pthread_mutex_t * mutex,void * timeout)1043 static int mutex_timedlock_WRK(pthread_mutex_t *mutex,
1044 void *timeout)
1045 {
1046 int ret;
1047 OrigFn fn;
1048 VALGRIND_GET_ORIG_FN(fn);
1049 if (TRACE_PTH_FNS) {
1050 fprintf(stderr, "<< pthread_mxtimedlock %p %p", mutex, timeout);
1051 fflush(stderr);
1052 }
1053
1054 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
1055 pthread_mutex_t*,mutex, long,1/*isTryLock-ish*/);
1056
1057 CALL_FN_W_WW(ret, fn, mutex,timeout);
1058
1059 /* There's a hole here: libpthread now knows the lock is locked,
1060 but the tool doesn't, so some other thread could run and detect
1061 that the lock has been acquired by someone (this thread). Does
1062 this matter? Not sure, but I don't think so. */
1063
1064 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1065 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
1066
1067 if (ret != 0) {
1068 if (ret != ETIMEDOUT)
1069 DO_PthAPIerror( "pthread_mutex_timedlock", ret );
1070 }
1071
1072 if (TRACE_PTH_FNS) {
1073 fprintf(stderr, " :: mxtimedlock -> %d >>\n", ret);
1074 }
1075 return ret;
1076 }
1077
PTH_FUNC(int,pthreadZumutexZutimedlock,pthread_mutex_t * mutex,void * timeout)1078 PTH_FUNC(int, pthreadZumutexZutimedlock, // pthread_mutex_timedlock
1079 pthread_mutex_t *mutex,
1080 void *timeout) {
1081 return mutex_timedlock_WRK(mutex, timeout);
1082 }
1083 #if defined(VGO_solaris)
PTH_FUNC(int,pthreadZumutexZureltimedlock,pthread_mutex_t * mutex,void * timeout)1084 PTH_FUNC(int, pthreadZumutexZureltimedlock, // pthread_mutex_reltimedlock
1085 pthread_mutex_t *mutex,
1086 void *timeout) {
1087 return mutex_timedlock_WRK(mutex, timeout);
1088 }
1089 #endif
1090
1091
1092 //-----------------------------------------------------------
1093 // glibc: pthread_mutex_unlock
1094 // darwin: pthread_mutex_unlock
1095 // Solaris: mutex_unlock (pthread_mutex_unlock is a weak alias)
1096 __attribute__((noinline))
mutex_unlock_WRK(pthread_mutex_t * mutex)1097 static int mutex_unlock_WRK(pthread_mutex_t *mutex)
1098 {
1099 int ret;
1100 OrigFn fn;
1101 VALGRIND_GET_ORIG_FN(fn);
1102
1103 if (TRACE_PTH_FNS) {
1104 fprintf(stderr, "<< pthread_mxunlk %p", mutex); fflush(stderr);
1105 }
1106
1107 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1108 pthread_mutex_t*,mutex);
1109
1110 CALL_FN_W_W(ret, fn, mutex);
1111
1112 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
1113 pthread_mutex_t*,mutex);
1114
1115 if (ret != 0) {
1116 DO_PthAPIerror( "pthread_mutex_unlock", ret );
1117 }
1118
1119 if (TRACE_PTH_FNS) {
1120 fprintf(stderr, " mxunlk -> %d >>\n", ret);
1121 }
1122 return ret;
1123 }
1124
1125 #if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_dragonfly)
PTH_FUNC(int,pthreadZumutexZuunlock,pthread_mutex_t * mutex)1126 PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock
1127 pthread_mutex_t *mutex) {
1128 return mutex_unlock_WRK(mutex);
1129 }
1130 #elif defined(VGO_solaris)
PTH_FUNC(int,mutexZuunlock,pthread_mutex_t * mutex)1131 PTH_FUNC(int, mutexZuunlock, // mutex_unlock
1132 pthread_mutex_t *mutex) {
1133 return mutex_unlock_WRK(mutex);
1134 }
1135 #else
1136 # error "Unsupported OS"
1137 #endif
1138
1139
1140 #if defined(VGO_solaris)
1141 /* Internal to libc. */
1142 __attribute__((noinline))
PTH_FUNC(void,lmutexZuunlock,mutex_t * mutex)1143 PTH_FUNC(void, lmutexZuunlock, // lmutex_unlock
1144 mutex_t *mutex)
1145 {
1146 OrigFn fn;
1147 VALGRIND_GET_ORIG_FN(fn);
1148
1149 if (TRACE_PTH_FNS) {
1150 fprintf(stderr, "<< lmxunlk %p", mutex); fflush(stderr);
1151 }
1152
1153 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1154 mutex_t *, mutex);
1155 CALL_FN_v_W(fn, mutex);
1156 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
1157 mutex_t*, mutex);
1158
1159 if (TRACE_PTH_FNS) {
1160 fprintf(stderr, " lmxunlk >>\n");
1161 }
1162 }
1163 #endif /* VGO_solaris */
1164
1165
1166 /*----------------------------------------------------------------*/
1167 /*--- pthread_cond_t functions ---*/
1168 /*----------------------------------------------------------------*/
1169
1170 /* Handled: pthread_cond_wait pthread_cond_timedwait
1171 pthread_cond_signal pthread_cond_broadcast
1172 pthread_cond_init
1173 pthread_cond_destroy
1174 */
1175
1176 //-----------------------------------------------------------
1177 // glibc: pthread_cond_wait@GLIBC_2.2.5
1178 // glibc: pthread_cond_wait@@GLIBC_2.3.2
1179 // darwin: pthread_cond_wait
1180 // darwin: pthread_cond_wait$NOCANCEL$UNIX2003
1181 // darwin: pthread_cond_wait$UNIX2003
1182 // Solaris: cond_wait (pthread_cond_wait is built atop of cond_wait)
1183 //
1184 __attribute__((noinline))
pthread_cond_wait_WRK(pthread_cond_t * cond,pthread_mutex_t * mutex)1185 static int pthread_cond_wait_WRK(pthread_cond_t* cond,
1186 pthread_mutex_t* mutex)
1187 {
1188 int ret;
1189 OrigFn fn;
1190 unsigned long mutex_is_valid;
1191
1192 VALGRIND_GET_ORIG_FN(fn);
1193
1194 if (TRACE_PTH_FNS) {
1195 fprintf(stderr, "<< pthread_cond_wait %p %p", cond, mutex);
1196 fflush(stderr);
1197 }
1198
1199 /* Tell the tool a cond-wait is about to happen, so it can check
1200 for bogus argument values. In return it tells us whether it
1201 thinks the mutex is valid or not. */
1202 DO_CREQ_W_WW(mutex_is_valid,
1203 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
1204 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
1205 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
1206
1207 /* Tell the tool we're about to drop the mutex. This reflects the
1208 fact that in a cond_wait, we show up holding the mutex, and the
1209 call atomically drops the mutex and waits for the cv to be
1210 signalled. */
1211 if (mutex_is_valid) {
1212 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1213 pthread_mutex_t*,mutex);
1214 }
1215
1216 CALL_FN_W_WW(ret, fn, cond,mutex);
1217
1218 /* this conditional look stupid, but compare w/ same logic for
1219 pthread_cond_timedwait below */
1220 if (mutex_is_valid) {
1221 /* and now we have the mutex again if (ret == 0) */
1222 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1223 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
1224 }
1225
1226 DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
1227 pthread_cond_t*,cond, pthread_mutex_t*,mutex, long,0,
1228 long, (ret == 0 && mutex_is_valid) ? True : False);
1229
1230 if (ret != 0) {
1231 DO_PthAPIerror( "pthread_cond_wait", ret );
1232 }
1233
1234 if (TRACE_PTH_FNS) {
1235 fprintf(stderr, " cowait -> %d >>\n", ret);
1236 }
1237
1238 return ret;
1239 }
1240 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZucondZuwaitZAZa,pthread_cond_t * cond,pthread_mutex_t * mutex)1241 PTH_FUNC(int, pthreadZucondZuwaitZAZa, // pthread_cond_wait@*
1242 pthread_cond_t* cond, pthread_mutex_t* mutex) {
1243 return pthread_cond_wait_WRK(cond, mutex);
1244 }
1245 #elif defined(VGO_dragonfly)
PTH_FUNC(int,pthreadZucondZuwait,pthread_cond_t * cond,pthread_mutex_t * mutex)1246 PTH_FUNC(int, pthreadZucondZuwait, // pthread_cond_wait
1247 pthread_cond_t* cond, pthread_mutex_t* mutex) {
1248 return pthread_cond_wait_WRK(cond, mutex);
1249 }
1250 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZucondZuwaitZa,pthread_cond_t * cond,pthread_mutex_t * mutex)1251 PTH_FUNC(int, pthreadZucondZuwaitZa, // pthread_cond_wait*
1252 pthread_cond_t* cond, pthread_mutex_t* mutex) {
1253 return pthread_cond_wait_WRK(cond, mutex);
1254 }
1255 #elif defined(VGO_solaris)
PTH_FUNC(int,condZuwait,pthread_cond_t * cond,pthread_mutex_t * mutex)1256 PTH_FUNC(int, condZuwait, // cond_wait
1257 pthread_cond_t *cond, pthread_mutex_t *mutex) {
1258 return pthread_cond_wait_WRK(cond, mutex);
1259 }
1260 #else
1261 # error "Unsupported OS"
1262 #endif
1263
1264
1265 //-----------------------------------------------------------
1266 // glibc: pthread_cond_timedwait@@GLIBC_2.3.2
1267 // glibc: pthread_cond_timedwait@GLIBC_2.2.5
1268 // glibc: pthread_cond_timedwait@GLIBC_2.0
1269 // darwin: pthread_cond_timedwait
1270 // darwin: pthread_cond_timedwait$NOCANCEL$UNIX2003
1271 // darwin: pthread_cond_timedwait$UNIX2003
1272 // darwin: pthread_cond_timedwait_relative_np (trapped)
1273 // Solaris: cond_timedwait (pthread_cond_timedwait is built on cond_timedwait)
1274 // Solaris: cond_reltimedwait (pthread_cond_reltimedwait_np is built on this)
1275 //
1276 __attribute__((noinline))
pthread_cond_timedwait_WRK(pthread_cond_t * cond,pthread_mutex_t * mutex,struct timespec * abstime,int timeout_error)1277 static int pthread_cond_timedwait_WRK(pthread_cond_t* cond,
1278 pthread_mutex_t* mutex,
1279 struct timespec* abstime,
1280 int timeout_error)
1281 {
1282 int ret;
1283 OrigFn fn;
1284 unsigned long mutex_is_valid;
1285 Bool abstime_is_valid;
1286 VALGRIND_GET_ORIG_FN(fn);
1287
1288 if (TRACE_PTH_FNS) {
1289 fprintf(stderr, "<< pthread_cond_timedwait %p %p %p",
1290 cond, mutex, abstime);
1291 fflush(stderr);
1292 }
1293
1294 /* Tell the tool a cond-wait is about to happen, so it can check
1295 for bogus argument values. In return it tells us whether it
1296 thinks the mutex is valid or not. */
1297 DO_CREQ_W_WW(mutex_is_valid,
1298 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
1299 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
1300 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
1301
1302 abstime_is_valid = abstime->tv_nsec >= 0 && abstime->tv_nsec < 1000000000;
1303
1304 /* Tell the tool we're about to drop the mutex. This reflects the
1305 fact that in a cond_wait, we show up holding the mutex, and the
1306 call atomically drops the mutex and waits for the cv to be
1307 signalled. */
1308 if (mutex_is_valid && abstime_is_valid) {
1309 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1310 pthread_mutex_t*,mutex);
1311 }
1312
1313 CALL_FN_W_WWW(ret, fn, cond,mutex,abstime);
1314
1315 if (mutex_is_valid && !abstime_is_valid && ret != EINVAL) {
1316 DO_PthAPIerror("Bug in libpthread: pthread_cond_timedwait "
1317 "invalid abstime did not cause"
1318 " EINVAL", ret);
1319 }
1320
1321 if (mutex_is_valid && abstime_is_valid) {
1322 /* and now we have the mutex again if (ret == 0 || ret == timeout) */
1323 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1324 pthread_mutex_t *, mutex,
1325 long, (ret == 0 || ret == timeout_error) ? True : False);
1326 }
1327
1328 DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
1329 pthread_cond_t*,cond, pthread_mutex_t*,mutex,
1330 long,ret == timeout_error,
1331 long, (ret == 0 || ret == timeout_error) && mutex_is_valid
1332 ? True : False);
1333
1334 if (ret != 0 && ret != timeout_error) {
1335 DO_PthAPIerror( "pthread_cond_timedwait", ret );
1336 }
1337
1338 if (TRACE_PTH_FNS) {
1339 fprintf(stderr, " cotimedwait -> %d >>\n", ret);
1340 }
1341
1342 return ret;
1343 }
1344 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZucondZutimedwaitZAZa,pthread_cond_t * cond,pthread_mutex_t * mutex,struct timespec * abstime)1345 PTH_FUNC(int, pthreadZucondZutimedwaitZAZa, // pthread_cond_timedwait@*
1346 pthread_cond_t* cond, pthread_mutex_t* mutex,
1347 struct timespec* abstime) {
1348 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
1349 }
1350 #elif defined(VGO_dragonfly)
PTH_FUNC(int,pthreadZucondZutimedwait,pthread_cond_t * cond,pthread_mutex_t * mutex,struct timespec * abstime)1351 PTH_FUNC(int, pthreadZucondZutimedwait, // pthread_cond_timedwait
1352 pthread_cond_t* cond, pthread_mutex_t* mutex,
1353 struct timespec* abstime) {
1354 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
1355 }
1356 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZucondZutimedwait,pthread_cond_t * cond,pthread_mutex_t * mutex,struct timespec * abstime)1357 PTH_FUNC(int, pthreadZucondZutimedwait, // pthread_cond_timedwait
1358 pthread_cond_t* cond, pthread_mutex_t* mutex,
1359 struct timespec* abstime) {
1360 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
1361 }
PTH_FUNC(int,pthreadZucondZutimedwaitZDZa,pthread_cond_t * cond,pthread_mutex_t * mutex,struct timespec * abstime)1362 PTH_FUNC(int, pthreadZucondZutimedwaitZDZa, // pthread_cond_timedwait$*
1363 pthread_cond_t* cond, pthread_mutex_t* mutex,
1364 struct timespec* abstime) {
1365 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
1366 }
PTH_FUNC(int,pthreadZucondZutimedwaitZuZa,pthread_cond_t * cond,pthread_mutex_t * mutex,struct timespec * abstime)1367 PTH_FUNC(int, pthreadZucondZutimedwaitZuZa, // pthread_cond_timedwait_*
1368 pthread_cond_t* cond, pthread_mutex_t* mutex,
1369 struct timespec* abstime) {
1370 assert(0);
1371 }
1372 #elif defined(VGO_solaris)
PTH_FUNC(int,condZutimedwait,pthread_cond_t * cond,pthread_mutex_t * mutex,struct timespec * abstime)1373 PTH_FUNC(int, condZutimedwait, // cond_timedwait
1374 pthread_cond_t *cond, pthread_mutex_t *mutex,
1375 struct timespec *abstime) {
1376 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIME);
1377 }
PTH_FUNC(int,condZureltimedwait,pthread_cond_t * cond,pthread_mutex_t * mutex,struct timespec * reltime)1378 PTH_FUNC(int, condZureltimedwait, // cond_reltimedwait
1379 pthread_cond_t *cond, pthread_mutex_t *mutex,
1380 struct timespec *reltime) {
1381 return pthread_cond_timedwait_WRK(cond, mutex, reltime, ETIME);
1382 }
1383 #else
1384 # error "Unsupported OS"
1385 #endif
1386
1387
1388 //-----------------------------------------------------------
1389 // glibc: pthread_cond_signal@GLIBC_2.0
1390 // glibc: pthread_cond_signal@GLIBC_2.2.5
1391 // glibc: pthread_cond_signal@@GLIBC_2.3.2
1392 // darwin: pthread_cond_signal
1393 // darwin: pthread_cond_signal_thread_np (don't intercept this)
1394 // Solaris: cond_signal (pthread_cond_signal is a weak alias)
1395 //
1396 __attribute__((noinline))
pthread_cond_signal_WRK(pthread_cond_t * cond)1397 static int pthread_cond_signal_WRK(pthread_cond_t* cond)
1398 {
1399 int ret;
1400 OrigFn fn;
1401 VALGRIND_GET_ORIG_FN(fn);
1402
1403 if (TRACE_PTH_FNS) {
1404 fprintf(stderr, "<< pthread_cond_signal %p", cond);
1405 fflush(stderr);
1406 }
1407
1408 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE,
1409 pthread_cond_t*,cond);
1410
1411 CALL_FN_W_W(ret, fn, cond);
1412
1413 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_POST,
1414 pthread_cond_t*,cond);
1415
1416 if (ret != 0) {
1417 DO_PthAPIerror( "pthread_cond_signal", ret );
1418 }
1419
1420 if (TRACE_PTH_FNS) {
1421 fprintf(stderr, " cosig -> %d >>\n", ret);
1422 }
1423
1424 return ret;
1425 }
1426 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZucondZusignalZAZa,pthread_cond_t * cond)1427 PTH_FUNC(int, pthreadZucondZusignalZAZa, // pthread_cond_signal@*
1428 pthread_cond_t* cond) {
1429 return pthread_cond_signal_WRK(cond);
1430 }
1431 #elif defined(VGO_dragonfly)
PTH_FUNC(int,pthreadZucondZusignal,pthread_cond_t * cond)1432 PTH_FUNC(int, pthreadZucondZusignal, // pthread_cond_signal
1433 pthread_cond_t* cond) {
1434 return pthread_cond_signal_WRK(cond);
1435 }
1436 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZucondZusignal,pthread_cond_t * cond)1437 PTH_FUNC(int, pthreadZucondZusignal, // pthread_cond_signal
1438 pthread_cond_t* cond) {
1439 return pthread_cond_signal_WRK(cond);
1440 }
1441 #elif defined(VGO_solaris)
PTH_FUNC(int,condZusignal,pthread_cond_t * cond)1442 PTH_FUNC(int, condZusignal, // cond_signal
1443 pthread_cond_t *cond) {
1444 return pthread_cond_signal_WRK(cond);
1445 }
1446 #else
1447 # error "Unsupported OS"
1448 #endif
1449
1450
1451 //-----------------------------------------------------------
1452 // glibc: pthread_cond_broadcast@GLIBC_2.0
1453 // glibc: pthread_cond_broadcast@GLIBC_2.2.5
1454 // glibc: pthread_cond_broadcast@@GLIBC_2.3.2
1455 // darwin: pthread_cond_broadcast
1456 // Solaris: cond_broadcast (pthread_cond_broadcast is a weak alias)
1457 //
1458 // Note, this is pretty much identical, from a dependency-graph
1459 // point of view, with cond_signal, so the code is duplicated.
1460 // Maybe it should be commoned up.
1461 //
1462 __attribute__((noinline))
pthread_cond_broadcast_WRK(pthread_cond_t * cond)1463 static int pthread_cond_broadcast_WRK(pthread_cond_t* cond)
1464 {
1465 int ret;
1466 OrigFn fn;
1467 VALGRIND_GET_ORIG_FN(fn);
1468
1469 if (TRACE_PTH_FNS) {
1470 fprintf(stderr, "<< pthread_cond_broadcast %p", cond);
1471 fflush(stderr);
1472 }
1473
1474 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE,
1475 pthread_cond_t*,cond);
1476
1477 CALL_FN_W_W(ret, fn, cond);
1478
1479 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_POST,
1480 pthread_cond_t*,cond);
1481
1482 if (ret != 0) {
1483 DO_PthAPIerror( "pthread_cond_broadcast", ret );
1484 }
1485
1486 if (TRACE_PTH_FNS) {
1487 fprintf(stderr, " cobro -> %d >>\n", ret);
1488 }
1489
1490 return ret;
1491 }
1492 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZucondZubroadcastZAZa,pthread_cond_t * cond)1493 PTH_FUNC(int, pthreadZucondZubroadcastZAZa, // pthread_cond_broadcast@*
1494 pthread_cond_t* cond) {
1495 return pthread_cond_broadcast_WRK(cond);
1496 }
1497 #elif defined(VGO_dragonfly)
PTH_FUNC(int,pthreadZucondZubroadcast,pthread_cond_t * cond)1498 PTH_FUNC(int, pthreadZucondZubroadcast, // pthread_cond_broadcast
1499 pthread_cond_t* cond) {
1500 return pthread_cond_broadcast_WRK(cond);
1501 }
1502 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZucondZubroadcast,pthread_cond_t * cond)1503 PTH_FUNC(int, pthreadZucondZubroadcast, // pthread_cond_broadcast
1504 pthread_cond_t* cond) {
1505 return pthread_cond_broadcast_WRK(cond);
1506 }
1507 #elif defined(VGO_solaris)
PTH_FUNC(int,condZubroadcast,pthread_cond_t * cond)1508 PTH_FUNC(int, condZubroadcast, // cond_broadcast
1509 pthread_cond_t *cond) {
1510 return pthread_cond_broadcast_WRK(cond);
1511 }
1512 #else
1513 # error "Unsupported OS"
1514 #endif
1515
1516 // glibc: pthread_cond_init@GLIBC_2.0
1517 // glibc: pthread_cond_init@GLIBC_2.2.5
1518 // glibc: pthread_cond_init@@GLIBC_2.3.2
1519 // darwin: pthread_cond_init
1520 // Solaris: cond_init (pthread_cond_init is built atop on this function)
1521 // Easy way out: Handling of attr could have been messier.
1522 // It turns out that pthread_cond_init under linux ignores
1523 // all information in cond_attr, so do we.
1524 // FIXME: MacOS X?
1525 #if !defined(VGO_solaris)
1526 __attribute__((noinline))
pthread_cond_init_WRK(pthread_cond_t * cond,pthread_condattr_t * cond_attr)1527 static int pthread_cond_init_WRK(pthread_cond_t* cond, pthread_condattr_t *cond_attr)
1528 {
1529 int ret;
1530 OrigFn fn;
1531 VALGRIND_GET_ORIG_FN(fn);
1532
1533 if (TRACE_PTH_FNS) {
1534 fprintf(stderr, "<< pthread_cond_init %p", cond);
1535 fflush(stderr);
1536 }
1537
1538 CALL_FN_W_WW(ret, fn, cond, cond_attr);
1539
1540 if (ret == 0) {
1541 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST,
1542 pthread_cond_t*,cond, pthread_condattr_t*, cond_attr);
1543 } else {
1544 DO_PthAPIerror( "pthread_cond_init", ret );
1545 }
1546
1547 if (TRACE_PTH_FNS) {
1548 fprintf(stderr, " coinit -> %d >>\n", ret);
1549 }
1550
1551 return ret;
1552 }
1553 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZucondZuinitZAZa,pthread_cond_t * cond,pthread_condattr_t * cond_attr)1554 PTH_FUNC(int, pthreadZucondZuinitZAZa, // pthread_cond_init@*
1555 pthread_cond_t* cond, pthread_condattr_t* cond_attr) {
1556 return pthread_cond_init_WRK(cond, cond_attr);
1557 }
1558 #elif defined(VGO_dragonfly)
PTH_FUNC(int,pthreadZucondZuinitZAZa,pthread_cond_t * cond,pthread_condattr_t * cond_attr)1559 PTH_FUNC(int, pthreadZucondZuinitZAZa, // pthread_cond_init@*
1560 pthread_cond_t* cond, pthread_condattr_t* cond_attr) {
1561 return pthread_cond_init_WRK(cond, cond_attr);
1562 }
1563 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZucondZuinit,pthread_cond_t * cond,pthread_condattr_t * cond_attr)1564 PTH_FUNC(int, pthreadZucondZuinit, // pthread_cond_init
1565 pthread_cond_t* cond, pthread_condattr_t * cond_attr) {
1566 return pthread_cond_init_WRK(cond, cond_attr);
1567 }
1568 #else
1569 # error "Unsupported OS"
1570 #endif
1571
1572 #else /* VGO_solaris */
1573 __attribute__((noinline))
PTH_FUNC(int,condZuinit,cond_t * cond,int type,void * arg)1574 PTH_FUNC(int, condZuinit, // cond_init
1575 cond_t *cond, int type, void *arg)
1576 {
1577 int ret;
1578 OrigFn fn;
1579 VALGRIND_GET_ORIG_FN(fn);
1580
1581 if (TRACE_PTH_FNS) {
1582 fprintf(stderr, "<< cond_init %p", cond); fflush(stderr);
1583 }
1584
1585 CALL_FN_W_WWW(ret, fn, cond, type, arg);
1586
1587 if (ret == 0) {
1588 /* Luckily evh__HG_PTHREAD_COND_INIT_POST() ignores cond_attr.
1589 See also comment for pthread_cond_init_WRK(). */
1590 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST,
1591 cond_t *, cond, void *, NULL);
1592 } else {
1593 DO_PthAPIerror("cond_init", ret);
1594 }
1595
1596 if (TRACE_PTH_FNS) {
1597 fprintf(stderr, " cond_init -> %d >>\n", ret);
1598 }
1599
1600 return ret;
1601 }
1602 #endif /* VGO_solaris */
1603
1604
1605 //-----------------------------------------------------------
1606 // glibc: pthread_cond_destroy@@GLIBC_2.3.2
1607 // glibc: pthread_cond_destroy@GLIBC_2.2.5
1608 // glibc: pthread_cond_destroy@GLIBC_2.0
1609 // darwin: pthread_cond_destroy
1610 // Solaris: cond_destroy (pthread_cond_destroy is a weak alias)
1611 //
1612 __attribute__((noinline))
pthread_cond_destroy_WRK(pthread_cond_t * cond)1613 static int pthread_cond_destroy_WRK(pthread_cond_t* cond)
1614 {
1615 int ret;
1616 unsigned long cond_is_init;
1617 OrigFn fn;
1618
1619 VALGRIND_GET_ORIG_FN(fn);
1620
1621 if (TRACE_PTH_FNS) {
1622 fprintf(stderr, "<< pthread_cond_destroy %p", cond);
1623 fflush(stderr);
1624 }
1625
1626 if (cond != NULL) {
1627 const pthread_cond_t cond_init = PTHREAD_COND_INITIALIZER;
1628 cond_is_init = my_memcmp(cond, &cond_init, sizeof(*cond)) == 0;
1629 } else {
1630 cond_is_init = 0;
1631 }
1632
1633 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_DESTROY_PRE,
1634 pthread_cond_t*, cond, unsigned long, cond_is_init);
1635
1636 CALL_FN_W_W(ret, fn, cond);
1637
1638 if (ret != 0) {
1639 DO_PthAPIerror( "pthread_cond_destroy", ret );
1640 }
1641
1642 if (TRACE_PTH_FNS) {
1643 fprintf(stderr, " codestr -> %d >>\n", ret);
1644 }
1645
1646 return ret;
1647 }
1648 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZucondZudestroyZAZa,pthread_cond_t * cond)1649 PTH_FUNC(int, pthreadZucondZudestroyZAZa, // pthread_cond_destroy@*
1650 pthread_cond_t* cond) {
1651 return pthread_cond_destroy_WRK(cond);
1652 }
1653 #elif defined(VGO_dragonfly)
PTH_FUNC(int,pthreadZucondZudestroy,pthread_cond_t * cond)1654 PTH_FUNC(int, pthreadZucondZudestroy, // pthread_cond_destroy
1655 pthread_cond_t* cond) {
1656 return pthread_cond_destroy_WRK(cond);
1657 }
1658 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZucondZudestroy,pthread_cond_t * cond)1659 PTH_FUNC(int, pthreadZucondZudestroy, // pthread_cond_destroy
1660 pthread_cond_t* cond) {
1661 return pthread_cond_destroy_WRK(cond);
1662 }
1663 #elif defined(VGO_solaris)
PTH_FUNC(int,condZudestroy,pthread_cond_t * cond)1664 PTH_FUNC(int, condZudestroy, // cond_destroy
1665 pthread_cond_t *cond) {
1666 return pthread_cond_destroy_WRK(cond);
1667 }
1668 #else
1669 # error "Unsupported OS"
1670 #endif
1671
1672
1673 /*----------------------------------------------------------------*/
1674 /*--- pthread_barrier_t functions ---*/
1675 /*----------------------------------------------------------------*/
1676
1677 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1678
1679 /* Handled: pthread_barrier_init
1680 pthread_barrier_wait
1681 pthread_barrier_destroy
1682
1683 Unhandled: pthread_barrierattr_destroy
1684 pthread_barrierattr_getpshared
1685 pthread_barrierattr_init
1686 pthread_barrierattr_setpshared
1687 -- are these important?
1688 */
1689
1690 //-----------------------------------------------------------
1691 // glibc: pthread_barrier_init
1692 // darwin: (doesn't appear to exist)
1693 // Solaris: pthread_barrier_init
PTH_FUNC(int,pthreadZubarrierZuinit,pthread_barrier_t * bar,pthread_barrierattr_t * attr,unsigned long count)1694 PTH_FUNC(int, pthreadZubarrierZuinit, // pthread_barrier_init
1695 pthread_barrier_t* bar,
1696 pthread_barrierattr_t* attr, unsigned long count)
1697 {
1698 int ret;
1699 OrigFn fn;
1700 VALGRIND_GET_ORIG_FN(fn);
1701
1702 if (TRACE_PTH_FNS) {
1703 fprintf(stderr, "<< pthread_barrier_init %p %p %lu",
1704 bar, attr, count);
1705 fflush(stderr);
1706 }
1707
1708 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE,
1709 pthread_barrier_t*, bar,
1710 unsigned long, count,
1711 unsigned long, 0/*!resizable*/);
1712
1713 CALL_FN_W_WWW(ret, fn, bar,attr,count);
1714
1715 if (ret != 0) {
1716 DO_PthAPIerror( "pthread_barrier_init", ret );
1717 }
1718
1719 if (TRACE_PTH_FNS) {
1720 fprintf(stderr, " pthread_barrier_init -> %d >>\n", ret);
1721 }
1722
1723 return ret;
1724 }
1725
1726
1727 //-----------------------------------------------------------
1728 // glibc: pthread_barrier_wait
1729 // darwin: (doesn't appear to exist)
1730 // Solaris: pthread_barrier_wait
PTH_FUNC(int,pthreadZubarrierZuwait,pthread_barrier_t * bar)1731 PTH_FUNC(int, pthreadZubarrierZuwait, // pthread_barrier_wait
1732 pthread_barrier_t* bar)
1733 {
1734 int ret;
1735 OrigFn fn;
1736 VALGRIND_GET_ORIG_FN(fn);
1737
1738 if (TRACE_PTH_FNS) {
1739 fprintf(stderr, "<< pthread_barrier_wait %p", bar);
1740 fflush(stderr);
1741 }
1742
1743 /* That this works correctly, and doesn't screw up when a thread
1744 leaving the barrier races round to the front and re-enters while
1745 other threads are still leaving it, is quite subtle. See
1746 comments in the handler for PTHREAD_BARRIER_WAIT_PRE in
1747 hg_main.c. */
1748 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE,
1749 pthread_barrier_t*,bar);
1750
1751 CALL_FN_W_W(ret, fn, bar);
1752
1753 if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) {
1754 DO_PthAPIerror( "pthread_barrier_wait", ret );
1755 }
1756
1757 if (TRACE_PTH_FNS) {
1758 fprintf(stderr, " pthread_barrier_wait -> %d >>\n", ret);
1759 }
1760
1761 return ret;
1762 }
1763
1764
1765 //-----------------------------------------------------------
1766 // glibc: pthread_barrier_destroy
1767 // darwin: (doesn't appear to exist)
1768 // Solaris: pthread_barrier_destroy
PTH_FUNC(int,pthreadZubarrierZudestroy,pthread_barrier_t * bar)1769 PTH_FUNC(int, pthreadZubarrierZudestroy, // pthread_barrier_destroy
1770 pthread_barrier_t* bar)
1771 {
1772 int ret;
1773 OrigFn fn;
1774 VALGRIND_GET_ORIG_FN(fn);
1775
1776 if (TRACE_PTH_FNS) {
1777 fprintf(stderr, "<< pthread_barrier_destroy %p", bar);
1778 fflush(stderr);
1779 }
1780
1781 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE,
1782 pthread_barrier_t*,bar);
1783
1784 CALL_FN_W_W(ret, fn, bar);
1785
1786 if (ret != 0) {
1787 DO_PthAPIerror( "pthread_barrier_destroy", ret );
1788 }
1789
1790 if (TRACE_PTH_FNS) {
1791 fprintf(stderr, " pthread_barrier_destroy -> %d >>\n", ret);
1792 }
1793
1794 return ret;
1795 }
1796
1797 #endif // defined(HAVE_PTHREAD_BARRIER_INIT)
1798
1799
1800 /*----------------------------------------------------------------*/
1801 /*--- pthread_spinlock_t functions ---*/
1802 /*----------------------------------------------------------------*/
1803
1804 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1805 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1806
1807 /* Handled: pthread_spin_init pthread_spin_destroy
1808 pthread_spin_lock pthread_spin_trylock
1809 pthread_spin_unlock
1810
1811 Unhandled:
1812 */
1813
1814 /* This is a nasty kludge, in that glibc "knows" that initialising a
1815 spin lock unlocks it, and pthread_spin_{init,unlock} are names for
1816 the same function. Hence we have to have a wrapper which does both
1817 things, without knowing which the user intended to happen.
1818 Solaris has distinct functions for init/unlock but client requests
1819 are immutable in helgrind.h so follow the glibc lead. */
1820
1821 //-----------------------------------------------------------
1822 // glibc: pthread_spin_init
1823 // glibc: pthread_spin_unlock
1824 // darwin: (doesn't appear to exist)
1825 // Solaris: pthread_spin_init
1826 // Solaris: pthread_spin_unlock
1827 __attribute__((noinline))
pthread_spin_init_or_unlock_WRK(pthread_spinlock_t * lock,int pshared)1828 static int pthread_spin_init_or_unlock_WRK(pthread_spinlock_t* lock,
1829 int pshared) {
1830 int ret;
1831 OrigFn fn;
1832 VALGRIND_GET_ORIG_FN(fn);
1833 if (TRACE_PTH_FNS) {
1834 fprintf(stderr, "<< pthread_spin_iORu %p", lock); fflush(stderr);
1835 }
1836
1837 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE,
1838 pthread_spinlock_t*, lock);
1839
1840 CALL_FN_W_WW(ret, fn, lock,pshared);
1841
1842 if (ret == 0 /*success*/) {
1843 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST,
1844 pthread_spinlock_t*,lock);
1845 } else {
1846 DO_PthAPIerror( "pthread_spinlock_{init,unlock}", ret );
1847 }
1848
1849 if (TRACE_PTH_FNS) {
1850 fprintf(stderr, " :: spiniORu -> %d >>\n", ret);
1851 }
1852 return ret;
1853 }
1854 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZuspinZuinit,pthread_spinlock_t * lock,int pshared)1855 PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
1856 pthread_spinlock_t* lock, int pshared) {
1857 return pthread_spin_init_or_unlock_WRK(lock, pshared);
1858 }
PTH_FUNC(int,pthreadZuspinZuunlock,pthread_spinlock_t * lock)1859 PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
1860 pthread_spinlock_t* lock) {
1861 /* this is never actually called */
1862 return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/);
1863 }
1864 #elif defined(VGO_dragonfly)
PTH_FUNC(int,pthreadZuspinZuinit,pthread_spinlock_t * lock,int pshared)1865 PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
1866 pthread_spinlock_t* lock, int pshared) {
1867 return pthread_spin_init_or_unlock_WRK(lock, pshared);
1868 }
PTH_FUNC(int,pthreadZuspinZuunlockZAZa,pthread_spinlock_t * lock)1869 PTH_FUNC(int, pthreadZuspinZuunlockZAZa, // pthread_spin_unlock@*
1870 pthread_spinlock_t* lock) {
1871 /* this is never actually called */
1872 return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/);
1873 }
1874 #elif defined(VGO_darwin)
1875 #elif defined(VGO_solaris)
PTH_FUNC(int,pthreadZuspinZuinit,pthread_spinlock_t * lock,int pshared)1876 PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
1877 pthread_spinlock_t *lock, int pshared) {
1878 return pthread_spin_init_or_unlock_WRK(lock, pshared);
1879 }
PTH_FUNC(int,pthreadZuspinZuunlock,pthread_spinlock_t * lock)1880 PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
1881 pthread_spinlock_t *lock) {
1882 return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/);
1883 }
1884 #else
1885 # error "Unsupported OS"
1886 #endif
1887
1888
1889 //-----------------------------------------------------------
1890 // glibc: pthread_spin_destroy
1891 // darwin: (doesn't appear to exist)
1892 // Solaris: pthread_spin_destroy
1893 __attribute__((noinline))
pthread_spin_destroy_WRK(pthread_spinlock_t * lock)1894 static int pthread_spin_destroy_WRK(pthread_spinlock_t *lock)
1895 {
1896 int ret;
1897 OrigFn fn;
1898 VALGRIND_GET_ORIG_FN(fn);
1899 if (TRACE_PTH_FNS) {
1900 fprintf(stderr, "<< pthread_spin_destroy %p", lock);
1901 fflush(stderr);
1902 }
1903
1904 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_DESTROY_PRE,
1905 pthread_spinlock_t*,lock);
1906
1907 CALL_FN_W_W(ret, fn, lock);
1908
1909 if (ret != 0) {
1910 DO_PthAPIerror( "pthread_spin_destroy", ret );
1911 }
1912
1913 if (TRACE_PTH_FNS) {
1914 fprintf(stderr, " :: spindestroy -> %d >>\n", ret);
1915 }
1916 return ret;
1917 }
1918 #if defined(VGO_linux) || defined(VGO_dragonfly)
PTH_FUNC(int,pthreadZuspinZudestroy,pthread_spinlock_t * lock)1919 PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy
1920 pthread_spinlock_t *lock) {
1921 return pthread_spin_destroy_WRK(lock);
1922 }
1923 #elif defined(VGO_darwin)
1924 #elif defined(VGO_solaris)
PTH_FUNC(int,pthreadZuspinZudestroy,pthread_spinlock_t * lock)1925 PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy
1926 pthread_spinlock_t *lock) {
1927 return pthread_spin_destroy_WRK(lock);
1928 }
1929 #else
1930 # error "Unsupported OS"
1931 #endif
1932
1933
1934 //-----------------------------------------------------------
1935 // glibc: pthread_spin_lock
1936 // darwin: (doesn't appear to exist)
1937 // Solaris: pthread_spin_lock
1938 __attribute__((noinline))
pthread_spin_lock_WRK(pthread_spinlock_t * lock)1939 static int pthread_spin_lock_WRK(pthread_spinlock_t *lock)
1940 {
1941 int ret;
1942 OrigFn fn;
1943 VALGRIND_GET_ORIG_FN(fn);
1944 if (TRACE_PTH_FNS) {
1945 fprintf(stderr, "<< pthread_spinlock %p", lock);
1946 fflush(stderr);
1947 }
1948
1949 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE,
1950 pthread_spinlock_t*,lock, long,0/*!isTryLock*/);
1951
1952 CALL_FN_W_W(ret, fn, lock);
1953
1954 /* There's a hole here: libpthread now knows the lock is locked,
1955 but the tool doesn't, so some other thread could run and detect
1956 that the lock has been acquired by someone (this thread). Does
1957 this matter? Not sure, but I don't think so. */
1958
1959 if (ret == 0 /*success*/) {
1960 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST,
1961 pthread_spinlock_t*,lock);
1962 } else {
1963 DO_PthAPIerror( "pthread_spin_lock", ret );
1964 }
1965
1966 if (TRACE_PTH_FNS) {
1967 fprintf(stderr, " :: spinlock -> %d >>\n", ret);
1968 }
1969 return ret;
1970 }
1971 #if defined(VGO_linux) || defined(VGO_dragonfly)
PTH_FUNC(int,pthreadZuspinZulock,pthread_spinlock_t * lock)1972 PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
1973 pthread_spinlock_t *lock) {
1974 return pthread_spin_lock_WRK(lock);
1975 }
1976 #elif defined(VGO_darwin)
1977 #elif defined(VGO_solaris)
PTH_FUNC(int,pthreadZuspinZulock,pthread_spinlock_t * lock)1978 PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
1979 pthread_spinlock_t *lock) {
1980 return pthread_spin_lock_WRK(lock);
1981 }
1982 #else
1983 # error "Unsupported OS"
1984 #endif
1985
1986
1987 //-----------------------------------------------------------
1988 // glibc: pthread_spin_trylock
1989 // darwin: (doesn't appear to exist)
1990 // Solaris: pthread_spin_trylock
1991 __attribute__((noinline))
pthread_spin_trylock_WRK(pthread_spinlock_t * lock)1992 static int pthread_spin_trylock_WRK(pthread_spinlock_t *lock)
1993 {
1994 int ret;
1995 OrigFn fn;
1996 VALGRIND_GET_ORIG_FN(fn);
1997 if (TRACE_PTH_FNS) {
1998 fprintf(stderr, "<< pthread_spin_trylock %p", lock);
1999 fflush(stderr);
2000 }
2001
2002 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE,
2003 pthread_spinlock_t*,lock, long,1/*isTryLock*/);
2004
2005 CALL_FN_W_W(ret, fn, lock);
2006
2007 /* There's a hole here: libpthread now knows the lock is locked,
2008 but the tool doesn't, so some other thread could run and detect
2009 that the lock has been acquired by someone (this thread). Does
2010 this matter? Not sure, but I don't think so. */
2011
2012 if (ret == 0 /*success*/) {
2013 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST,
2014 pthread_spinlock_t*,lock);
2015 } else {
2016 if (ret != EBUSY)
2017 DO_PthAPIerror( "pthread_spin_trylock", ret );
2018 }
2019
2020 if (TRACE_PTH_FNS) {
2021 fprintf(stderr, " :: spin_trylock -> %d >>\n", ret);
2022 }
2023 return ret;
2024 }
2025 #if defined(VGO_linux) || defined(VGO_dragonfly)
PTH_FUNC(int,pthreadZuspinZutrylock,pthread_spinlock_t * lock)2026 PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
2027 pthread_spinlock_t *lock) {
2028 return pthread_spin_trylock_WRK(lock);
2029 }
2030 #elif defined(VGO_darwin)
2031 #elif defined(VGO_solaris)
PTH_FUNC(int,pthreadZuspinZutrylock,pthread_spinlock_t * lock)2032 PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
2033 pthread_spinlock_t *lock) {
2034 return pthread_spin_trylock_WRK(lock);
2035 }
2036 #else
2037 # error "Unsupported OS"
2038 #endif
2039
2040 #endif // defined(HAVE_PTHREAD_SPIN_LOCK)
2041
2042
2043 /*----------------------------------------------------------------*/
2044 /*--- pthread_rwlock_t functions ---*/
2045 /*----------------------------------------------------------------*/
2046
2047 /* Android's pthread.h doesn't say anything about rwlocks, hence these
2048 functions have to be conditionally compiled. */
2049 #if defined(HAVE_PTHREAD_RWLOCK_T)
2050
2051 /* Handled: pthread_rwlock_init pthread_rwlock_destroy
2052 pthread_rwlock_rdlock
2053 pthread_rwlock_wrlock
2054 pthread_rwlock_unlock
2055 pthread_rwlock_tryrdlock
2056 pthread_rwlock_trywrlock
2057
2058 Unhandled: pthread_rwlock_timedrdlock
2059 pthread_rwlock_timedwrlock
2060 */
2061
2062 //-----------------------------------------------------------
2063 // glibc: pthread_rwlock_init
2064 // darwin: pthread_rwlock_init
2065 // darwin: pthread_rwlock_init$UNIX2003
2066 // Solaris: rwlock_init (pthread_rwlock_init is built atop of rwlock_init)
2067 __attribute__((noinline))
pthread_rwlock_init_WRK(pthread_rwlock_t * rwl,pthread_rwlockattr_t * attr)2068 static int pthread_rwlock_init_WRK(pthread_rwlock_t *rwl,
2069 pthread_rwlockattr_t* attr)
2070 {
2071 int ret;
2072 OrigFn fn;
2073 VALGRIND_GET_ORIG_FN(fn);
2074 if (TRACE_PTH_FNS) {
2075 fprintf(stderr, "<< pthread_rwl_init %p", rwl); fflush(stderr);
2076 }
2077
2078 CALL_FN_W_WW(ret, fn, rwl,attr);
2079
2080 if (ret == 0 /*success*/) {
2081 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
2082 pthread_rwlock_t*,rwl);
2083 } else {
2084 DO_PthAPIerror( "pthread_rwlock_init", ret );
2085 }
2086
2087 if (TRACE_PTH_FNS) {
2088 fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
2089 }
2090 return ret;
2091 }
2092 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZurwlockZuinit,pthread_rwlock_t * rwl,pthread_rwlockattr_t * attr)2093 PTH_FUNC(int, pthreadZurwlockZuinit, // pthread_rwlock_init
2094 pthread_rwlock_t *rwl,
2095 pthread_rwlockattr_t* attr) {
2096 return pthread_rwlock_init_WRK(rwl, attr);
2097 }
2098 #elif defined(VGO_dragonfly)
PTH_FUNC(int,pthreadZurwlockZuinit,pthread_rwlock_t * rwl,pthread_rwlockattr_t * attr)2099 PTH_FUNC(int, pthreadZurwlockZuinit, // pthread_rwlock_init
2100 pthread_rwlock_t *rwl,
2101 pthread_rwlockattr_t* attr) {
2102 return pthread_rwlock_init_WRK(rwl, attr);
2103 }
2104 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZurwlockZuinitZa,pthread_rwlock_t * rwl,pthread_rwlockattr_t * attr)2105 PTH_FUNC(int, pthreadZurwlockZuinitZa, // pthread_rwlock_init*
2106 pthread_rwlock_t *rwl,
2107 pthread_rwlockattr_t* attr) {
2108 return pthread_rwlock_init_WRK(rwl, attr);
2109 }
2110 #elif defined(VGO_solaris)
2111 static int pthread_rwlock_init_WRK(pthread_rwlock_t *rwl,
2112 pthread_rwlockattr_t* attr)
2113 __attribute__((unused));
2114 #else
2115 # error "Unsupported OS"
2116 #endif
2117
2118 #if defined(VGO_solaris)
PTH_FUNC(int,rwlockZuinit,rwlock_t * rwlock,int type,void * arg)2119 PTH_FUNC(int, rwlockZuinit, // rwlock_init
2120 rwlock_t *rwlock,
2121 int type,
2122 void *arg)
2123 {
2124 int ret;
2125 OrigFn fn;
2126 VALGRIND_GET_ORIG_FN(fn);
2127 if (TRACE_PTH_FNS) {
2128 fprintf(stderr, "<< rwl_init %p", rwlock); fflush(stderr);
2129 }
2130
2131 CALL_FN_W_WWW(ret, fn, rwlock, type, arg);
2132
2133 if (ret == 0 /*success*/) {
2134 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
2135 rwlock_t *, rwlock);
2136 } else {
2137 DO_PthAPIerror("rwlock_init", ret);
2138 }
2139
2140 if (TRACE_PTH_FNS) {
2141 fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
2142 }
2143 return ret;
2144 }
2145 #endif /* VGO_solaris */
2146
2147
2148 //-----------------------------------------------------------
2149 // glibc: pthread_rwlock_destroy
2150 // darwin: pthread_rwlock_destroy
2151 // darwin: pthread_rwlock_destroy$UNIX2003
2152 // Solaris: rwlock_destroy (pthread_rwlock_destroy is a weak alias)
2153 //
2154 __attribute__((noinline))
pthread_rwlock_destroy_WRK(pthread_rwlock_t * rwl)2155 static int pthread_rwlock_destroy_WRK(pthread_rwlock_t* rwl)
2156 {
2157 int ret;
2158 OrigFn fn;
2159 VALGRIND_GET_ORIG_FN(fn);
2160 if (TRACE_PTH_FNS) {
2161 fprintf(stderr, "<< pthread_rwl_destroy %p", rwl); fflush(stderr);
2162 }
2163
2164 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE,
2165 pthread_rwlock_t*,rwl);
2166
2167 CALL_FN_W_W(ret, fn, rwl);
2168
2169 if (ret != 0) {
2170 DO_PthAPIerror( "pthread_rwlock_destroy", ret );
2171 }
2172
2173 if (TRACE_PTH_FNS) {
2174 fprintf(stderr, " :: rwl_destroy -> %d >>\n", ret);
2175 }
2176 return ret;
2177 }
2178 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZurwlockZudestroy,pthread_rwlock_t * rwl)2179 PTH_FUNC(int, pthreadZurwlockZudestroy, // pthread_rwlock_destroy
2180 pthread_rwlock_t *rwl) {
2181 return pthread_rwlock_destroy_WRK(rwl);
2182 }
2183 #elif defined(VGO_dragonfly)
PTH_FUNC(int,pthreadZurwlockZudestroy,pthread_rwlock_t * rwl)2184 PTH_FUNC(int, pthreadZurwlockZudestroy, // pthread_rwlock_destroy
2185 pthread_rwlock_t *rwl) {
2186 return pthread_rwlock_destroy_WRK(rwl);
2187 }
2188 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZurwlockZudestroyZa,pthread_rwlock_t * rwl)2189 PTH_FUNC(int, pthreadZurwlockZudestroyZa, // pthread_rwlock_destroy*
2190 pthread_rwlock_t *rwl) {
2191 return pthread_rwlock_destroy_WRK(rwl);
2192 }
2193 #elif defined(VGO_solaris)
PTH_FUNC(int,rwlockZudestroy,pthread_rwlock_t * rwl)2194 PTH_FUNC(int, rwlockZudestroy, // rwlock_destroy
2195 pthread_rwlock_t *rwl) {
2196 return pthread_rwlock_destroy_WRK(rwl);
2197 }
2198 #else
2199 # error "Unsupported OS"
2200 #endif
2201
2202
2203 //-----------------------------------------------------------
2204 // glibc: pthread_rwlock_wrlock
2205 // darwin: pthread_rwlock_wrlock
2206 // darwin: pthread_rwlock_wrlock$UNIX2003
2207 // Solaris: rw_wrlock (pthread_rwlock_wrlock is a weak alias)
2208 //
2209 __attribute__((noinline))
pthread_rwlock_wrlock_WRK(pthread_rwlock_t * rwlock)2210 static int pthread_rwlock_wrlock_WRK(pthread_rwlock_t* rwlock)
2211 {
2212 int ret;
2213 OrigFn fn;
2214 VALGRIND_GET_ORIG_FN(fn);
2215 if (TRACE_PTH_FNS) {
2216 fprintf(stderr, "<< pthread_rwl_wlk %p", rwlock); fflush(stderr);
2217 }
2218
2219 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2220 pthread_rwlock_t*,rwlock,
2221 long,1/*isW*/, long,0/*!isTryLock*/);
2222
2223 CALL_FN_W_W(ret, fn, rwlock);
2224
2225 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2226 pthread_rwlock_t*,rwlock, long,1/*isW*/,
2227 long, (ret == 0) ? True : False);
2228 if (ret != 0) {
2229 DO_PthAPIerror( "pthread_rwlock_wrlock", ret );
2230 }
2231
2232 if (TRACE_PTH_FNS) {
2233 fprintf(stderr, " :: rwl_wlk -> %d >>\n", ret);
2234 }
2235 return ret;
2236 }
2237 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZurwlockZuwrlock,pthread_rwlock_t * rwlock)2238 PTH_FUNC(int, pthreadZurwlockZuwrlock, // pthread_rwlock_wrlock
2239 pthread_rwlock_t* rwlock) {
2240 return pthread_rwlock_wrlock_WRK(rwlock);
2241 }
2242 #elif defined(VGO_dragonfly)
PTH_FUNC(int,pthreadZurwlockZuwrlock,pthread_rwlock_t * rwlock)2243 PTH_FUNC(int, pthreadZurwlockZuwrlock, // pthread_rwlock_wrlock
2244 pthread_rwlock_t* rwlock) {
2245 return pthread_rwlock_wrlock_WRK(rwlock);
2246 }
2247 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZurwlockZuwrlockZa,pthread_rwlock_t * rwlock)2248 PTH_FUNC(int, pthreadZurwlockZuwrlockZa, // pthread_rwlock_wrlock*
2249 pthread_rwlock_t* rwlock) {
2250 return pthread_rwlock_wrlock_WRK(rwlock);
2251 }
2252 #elif defined(VGO_solaris)
PTH_FUNC(int,rwZuwrlock,pthread_rwlock_t * rwlock)2253 PTH_FUNC(int, rwZuwrlock, // rw_wrlock
2254 pthread_rwlock_t *rwlock) {
2255 return pthread_rwlock_wrlock_WRK(rwlock);
2256 }
2257 #else
2258 # error "Unsupported OS"
2259 #endif
2260
2261 #if defined(VGO_solaris)
2262 /* Internal to libc. */
PTH_FUNC(void,lrwZuwrlock,rwlock_t * rwlock)2263 PTH_FUNC(void, lrwZuwrlock, // lrw_wrlock
2264 rwlock_t *rwlock)
2265 {
2266 OrigFn fn;
2267 VALGRIND_GET_ORIG_FN(fn);
2268 if (TRACE_PTH_FNS) {
2269 fprintf(stderr, "<< lrw_wlk %p", rwlock); fflush(stderr);
2270 }
2271
2272 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2273 pthread_rwlock_t *, rwlock,
2274 long, 1/*isW*/, long, 0/*!isTryLock*/);
2275
2276 CALL_FN_v_W(fn, rwlock);
2277
2278 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2279 pthread_rwlock_t *, rwlock, long, 1/*isW*/, long, True);
2280
2281 if (TRACE_PTH_FNS) {
2282 fprintf(stderr, " :: lrw_wlk >>\n");
2283 }
2284 }
2285 #endif /* VGO_solaris */
2286
2287
2288 //-----------------------------------------------------------
2289 // glibc: pthread_rwlock_rdlock
2290 // darwin: pthread_rwlock_rdlock
2291 // darwin: pthread_rwlock_rdlock$UNIX2003
2292 // Solaris: rw_rdlock (pthread_rwlock_rdlock is a weak alias)
2293 //
2294 __attribute__((noinline))
pthread_rwlock_rdlock_WRK(pthread_rwlock_t * rwlock)2295 static int pthread_rwlock_rdlock_WRK(pthread_rwlock_t* rwlock)
2296 {
2297 int ret;
2298 OrigFn fn;
2299 VALGRIND_GET_ORIG_FN(fn);
2300 if (TRACE_PTH_FNS) {
2301 fprintf(stderr, "<< pthread_rwl_rlk %p", rwlock); fflush(stderr);
2302 }
2303
2304 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2305 pthread_rwlock_t*,rwlock,
2306 long,0/*!isW*/, long,0/*!isTryLock*/);
2307
2308 CALL_FN_W_W(ret, fn, rwlock);
2309
2310 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2311 pthread_rwlock_t*,rwlock, long,0/*!isW*/,
2312 long, (ret == 0) ? True : False);
2313 if (ret != 0) {
2314 DO_PthAPIerror( "pthread_rwlock_rdlock", ret );
2315 }
2316
2317 if (TRACE_PTH_FNS) {
2318 fprintf(stderr, " :: rwl_rlk -> %d >>\n", ret);
2319 }
2320 return ret;
2321 }
2322 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZurwlockZurdlock,pthread_rwlock_t * rwlock)2323 PTH_FUNC(int, pthreadZurwlockZurdlock, // pthread_rwlock_rdlock
2324 pthread_rwlock_t* rwlock) {
2325 return pthread_rwlock_rdlock_WRK(rwlock);
2326 }
2327 #elif defined(VGO_dragonfly)
PTH_FUNC(int,pthreadZurwlockZurdlock,pthread_rwlock_t * rwlock)2328 PTH_FUNC(int, pthreadZurwlockZurdlock, // pthread_rwlock_rdlock
2329 pthread_rwlock_t* rwlock) {
2330 return pthread_rwlock_rdlock_WRK(rwlock);
2331 }
2332 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZurwlockZurdlockZa,pthread_rwlock_t * rwlock)2333 PTH_FUNC(int, pthreadZurwlockZurdlockZa, // pthread_rwlock_rdlock*
2334 pthread_rwlock_t* rwlock) {
2335 return pthread_rwlock_rdlock_WRK(rwlock);
2336 }
2337 #elif defined(VGO_solaris)
PTH_FUNC(int,rwZurdlock,pthread_rwlock_t * rwlock)2338 PTH_FUNC(int, rwZurdlock, // rw_rdlock
2339 pthread_rwlock_t *rwlock) {
2340 return pthread_rwlock_rdlock_WRK(rwlock);
2341 }
2342 #else
2343 # error "Unsupported OS"
2344 #endif
2345
2346 #if defined(VGO_solaris)
2347 /* Internal to libc. */
PTH_FUNC(void,lrwZurdlock,rwlock_t * rwlock)2348 PTH_FUNC(void, lrwZurdlock, // lrw_rdlock
2349 rwlock_t *rwlock)
2350 {
2351 OrigFn fn;
2352 VALGRIND_GET_ORIG_FN(fn);
2353 if (TRACE_PTH_FNS) {
2354 fprintf(stderr, "<< lrw_rlk %p", rwlock); fflush(stderr);
2355 }
2356
2357 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2358 pthread_rwlock_t *, rwlock,
2359 long, 0/*!isW*/, long, 0/*!isTryLock*/);
2360
2361 CALL_FN_v_W(fn, rwlock);
2362
2363 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2364 pthread_rwlock_t *, rwlock, long, 0/*!isW*/, long, True);
2365
2366 if (TRACE_PTH_FNS) {
2367 fprintf(stderr, " :: lrw_rlk ->>\n");
2368 }
2369 }
2370 #endif /* VGO_solaris */
2371
2372
2373 //-----------------------------------------------------------
2374 // glibc: pthread_rwlock_trywrlock
2375 // darwin: pthread_rwlock_trywrlock
2376 // darwin: pthread_rwlock_trywrlock$UNIX2003
2377 // Solaris: rw_trywrlock (pthread_rwlock_trywrlock is a weak alias)
2378 //
2379 __attribute__((noinline))
pthread_rwlock_trywrlock_WRK(pthread_rwlock_t * rwlock)2380 static int pthread_rwlock_trywrlock_WRK(pthread_rwlock_t* rwlock)
2381 {
2382 int ret;
2383 OrigFn fn;
2384 VALGRIND_GET_ORIG_FN(fn);
2385 if (TRACE_PTH_FNS) {
2386 fprintf(stderr, "<< pthread_rwl_trywlk %p", rwlock); fflush(stderr);
2387 }
2388
2389 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2390 pthread_rwlock_t*,rwlock,
2391 long,1/*isW*/, long,1/*isTryLock*/);
2392
2393 CALL_FN_W_W(ret, fn, rwlock);
2394
2395 /* There's a hole here: libpthread now knows the lock is locked,
2396 but the tool doesn't, so some other thread could run and detect
2397 that the lock has been acquired by someone (this thread). Does
2398 this matter? Not sure, but I don't think so. */
2399
2400 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2401 pthread_rwlock_t*,rwlock, long,1/*isW*/,
2402 long, (ret == 0) ? True : False);
2403 if (ret != 0) {
2404 if (ret != EBUSY)
2405 DO_PthAPIerror( "pthread_rwlock_trywrlock", ret );
2406 }
2407
2408 if (TRACE_PTH_FNS) {
2409 fprintf(stderr, " :: rwl_trywlk -> %d >>\n", ret);
2410 }
2411 return ret;
2412 }
2413 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZurwlockZutrywrlock,pthread_rwlock_t * rwlock)2414 PTH_FUNC(int, pthreadZurwlockZutrywrlock, // pthread_rwlock_trywrlock
2415 pthread_rwlock_t* rwlock) {
2416 return pthread_rwlock_trywrlock_WRK(rwlock);
2417 }
2418 #elif defined(VGO_dragonfly)
PTH_FUNC(int,pthreadZurwlockZutrywrlock,pthread_rwlock_t * rwlock)2419 PTH_FUNC(int, pthreadZurwlockZutrywrlock, // pthread_rwlock_trywrlock
2420 pthread_rwlock_t* rwlock) {
2421 return pthread_rwlock_trywrlock_WRK(rwlock);
2422 }
2423 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZurwlockZutrywrlockZa,pthread_rwlock_t * rwlock)2424 PTH_FUNC(int, pthreadZurwlockZutrywrlockZa, // pthread_rwlock_trywrlock*
2425 pthread_rwlock_t* rwlock) {
2426 return pthread_rwlock_trywrlock_WRK(rwlock);
2427 }
2428 #elif defined(VGO_solaris)
PTH_FUNC(int,rwZutrywrlock,pthread_rwlock_t * rwlock)2429 PTH_FUNC(int, rwZutrywrlock, // rw_trywrlock
2430 pthread_rwlock_t *rwlock) {
2431 return pthread_rwlock_trywrlock_WRK(rwlock);
2432 }
2433 #else
2434 # error "Unsupported OS"
2435 #endif
2436
2437
2438 //-----------------------------------------------------------
2439 // glibc: pthread_rwlock_tryrdlock
2440 // darwin: pthread_rwlock_tryrdlock
2441 // darwin: pthread_rwlock_tryrdlock$UNIX2003
2442 // Solaris: rw_tryrdlock (pthread_rwlock_tryrdlock is a weak alias)
2443 //
2444 __attribute__((noinline))
pthread_rwlock_tryrdlock_WRK(pthread_rwlock_t * rwlock)2445 static int pthread_rwlock_tryrdlock_WRK(pthread_rwlock_t* rwlock)
2446 {
2447 int ret;
2448 OrigFn fn;
2449 VALGRIND_GET_ORIG_FN(fn);
2450 if (TRACE_PTH_FNS) {
2451 fprintf(stderr, "<< pthread_rwl_tryrlk %p", rwlock); fflush(stderr);
2452 }
2453
2454 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2455 pthread_rwlock_t*,rwlock,
2456 long,0/*!isW*/, long,1/*isTryLock*/);
2457
2458 CALL_FN_W_W(ret, fn, rwlock);
2459
2460 /* There's a hole here: libpthread now knows the lock is locked,
2461 but the tool doesn't, so some other thread could run and detect
2462 that the lock has been acquired by someone (this thread). Does
2463 this matter? Not sure, but I don't think so. */
2464
2465 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2466 pthread_rwlock_t*,rwlock, long,0/*!isW*/,
2467 long, (ret == 0) ? True : False);
2468
2469 if (ret != 0) {
2470 if (ret != EBUSY)
2471 DO_PthAPIerror( "pthread_rwlock_tryrdlock", ret );
2472 }
2473
2474 if (TRACE_PTH_FNS) {
2475 fprintf(stderr, " :: rwl_tryrlk -> %d >>\n", ret);
2476 }
2477 return ret;
2478 }
2479 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZurwlockZutryrdlock,pthread_rwlock_t * rwlock)2480 PTH_FUNC(int, pthreadZurwlockZutryrdlock, // pthread_rwlock_tryrdlock
2481 pthread_rwlock_t* rwlock) {
2482 return pthread_rwlock_tryrdlock_WRK(rwlock);
2483 }
2484 #elif defined(VGO_dragonfly)
PTH_FUNC(int,pthreadZurwlockZutryrdlock,pthread_rwlock_t * rwlock)2485 PTH_FUNC(int, pthreadZurwlockZutryrdlock, // pthread_rwlock_tryrdlock
2486 pthread_rwlock_t* rwlock) {
2487 return pthread_rwlock_tryrdlock_WRK(rwlock);
2488 }
2489 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZurwlockZutryrdlockZa,pthread_rwlock_t * rwlock)2490 PTH_FUNC(int, pthreadZurwlockZutryrdlockZa, // pthread_rwlock_tryrdlock*
2491 pthread_rwlock_t* rwlock) {
2492 return pthread_rwlock_tryrdlock_WRK(rwlock);
2493 }
2494 #elif defined(VGO_solaris)
PTH_FUNC(int,rwZutryrdlock,pthread_rwlock_t * rwlock)2495 PTH_FUNC(int, rwZutryrdlock, // rw_tryrdlock
2496 pthread_rwlock_t *rwlock) {
2497 return pthread_rwlock_tryrdlock_WRK(rwlock);
2498 }
2499 #else
2500 # error "Unsupported OS"
2501 #endif
2502
2503
2504 //-----------------------------------------------------------
2505 // glibc: Unhandled
2506 // darwin: Unhandled
2507 // Solaris: pthread_rwlock_timedrdlock
2508 // Solaris: pthread_rwlock_reltimedrdlock_np
2509 //
2510 __attribute__((noinline)) __attribute__((unused))
pthread_rwlock_timedrdlock_WRK(pthread_rwlock_t * rwlock,const struct timespec * timeout)2511 static int pthread_rwlock_timedrdlock_WRK(pthread_rwlock_t *rwlock,
2512 const struct timespec *timeout)
2513 {
2514 int ret;
2515 OrigFn fn;
2516 VALGRIND_GET_ORIG_FN(fn);
2517 if (TRACE_PTH_FNS) {
2518 fprintf(stderr, "<< pthread_rwl_timedrdl %p", rwlock); fflush(stderr);
2519 }
2520
2521 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2522 pthread_rwlock_t *, rwlock,
2523 long, 0/*isW*/, long, 0/*isTryLock*/);
2524
2525 CALL_FN_W_WW(ret, fn, rwlock, timeout);
2526
2527 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2528 pthread_rwlock_t *, rwlock, long, 0/*isW*/,
2529 long, (ret == 0) ? True : False);
2530 if (ret != 0) {
2531 DO_PthAPIerror("pthread_rwlock_timedrdlock", ret);
2532 }
2533
2534 if (TRACE_PTH_FNS) {
2535 fprintf(stderr, " :: rwl_timedrdl -> %d >>\n", ret);
2536 }
2537 return ret;
2538 }
2539 #if defined(VGO_linux)
2540 #elif defined(VGO_darwin)
2541 #elif defined(VGO_dragonfly)
2542 #elif defined(VGO_solaris)
PTH_FUNC(int,pthreadZurwlockZutimedrdlock,pthread_rwlock_t * rwlock,const struct timespec * timeout)2543 PTH_FUNC(int, pthreadZurwlockZutimedrdlock, // pthread_rwlock_timedrdlock
2544 pthread_rwlock_t *rwlock,
2545 const struct timespec *timeout) {
2546 return pthread_rwlock_timedrdlock_WRK(rwlock, timeout);
2547 }
PTH_FUNC(int,pthreadZurwlockZureltimedrdlockZunp,pthread_rwlock_t * rwlock,const struct timespec * timeout)2548 PTH_FUNC(int, pthreadZurwlockZureltimedrdlockZunp, // pthread_rwlock_timedrdlock_np
2549 pthread_rwlock_t *rwlock,
2550 const struct timespec *timeout) {
2551 return pthread_rwlock_timedrdlock_WRK(rwlock, timeout);
2552 }
2553 #else
2554 # error "Unsupported OS"
2555 #endif
2556
2557
2558 //-----------------------------------------------------------
2559 // glibc: Unhandled
2560 // darwin: Unhandled
2561 // Solaris: pthread_rwlock_timedwrlock
2562 // Solaris: pthread_rwlock_reltimedwrlock_np
2563 //
2564 __attribute__((noinline)) __attribute__((unused))
pthread_rwlock_timedwrlock_WRK(pthread_rwlock_t * rwlock,const struct timespec * timeout)2565 static int pthread_rwlock_timedwrlock_WRK(pthread_rwlock_t *rwlock,
2566 const struct timespec *timeout)
2567 {
2568 int ret;
2569 OrigFn fn;
2570 VALGRIND_GET_ORIG_FN(fn);
2571 if (TRACE_PTH_FNS) {
2572 fprintf(stderr, "<< pthread_rwl_timedwrl %p", rwlock); fflush(stderr);
2573 }
2574
2575 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2576 pthread_rwlock_t *, rwlock,
2577 long, 1/*isW*/, long, 0/*isTryLock*/);
2578
2579 CALL_FN_W_WW(ret, fn, rwlock, timeout);
2580
2581 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2582 pthread_rwlock_t *, rwlock, long, 1/*isW*/,
2583 long, (ret == 0) ? True : False);
2584 if (ret != 0) {
2585 DO_PthAPIerror("pthread_rwlock_timedwrlock", ret);
2586 }
2587
2588 if (TRACE_PTH_FNS) {
2589 fprintf(stderr, " :: rwl_timedwrl -> %d >>\n", ret);
2590 }
2591 return ret;
2592 }
2593 #if defined(VGO_linux)
2594 #elif defined(VGO_darwin)
2595 #elif defined(VGO_dragonfly)
2596 #elif defined(VGO_solaris)
PTH_FUNC(int,pthreadZurwlockZutimedwrlock,pthread_rwlock_t * rwlock,const struct timespec * timeout)2597 PTH_FUNC(int, pthreadZurwlockZutimedwrlock, // pthread_rwlock_timedwrlock
2598 pthread_rwlock_t *rwlock,
2599 const struct timespec *timeout) {
2600 return pthread_rwlock_timedwrlock_WRK(rwlock, timeout);
2601 }
PTH_FUNC(int,pthreadZurwlockZureltimedwrlockZunp,pthread_rwlock_t * rwlock,const struct timespec * timeout)2602 PTH_FUNC(int, pthreadZurwlockZureltimedwrlockZunp, // pthread_rwlock_timedwrlock_np
2603 pthread_rwlock_t *rwlock,
2604 const struct timespec *timeout) {
2605 return pthread_rwlock_timedwrlock_WRK(rwlock, timeout);
2606 }
2607 #else
2608 # error "Unsupported OS"
2609 #endif
2610
2611
2612 //-----------------------------------------------------------
2613 // glibc: pthread_rwlock_unlock
2614 // darwin: pthread_rwlock_unlock
2615 // darwin: pthread_rwlock_unlock$UNIX2003
2616 // Solaris: rw_unlock (pthread_rwlock_unlock is a weak alias)
2617 __attribute__((noinline))
pthread_rwlock_unlock_WRK(pthread_rwlock_t * rwlock)2618 static int pthread_rwlock_unlock_WRK(pthread_rwlock_t* rwlock)
2619 {
2620 int ret;
2621 OrigFn fn;
2622 VALGRIND_GET_ORIG_FN(fn);
2623 if (TRACE_PTH_FNS) {
2624 fprintf(stderr, "<< pthread_rwl_unlk %p", rwlock); fflush(stderr);
2625 }
2626
2627 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
2628 pthread_rwlock_t*,rwlock);
2629
2630 CALL_FN_W_W(ret, fn, rwlock);
2631
2632 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
2633 pthread_rwlock_t*,rwlock);
2634 if (ret != 0) {
2635 DO_PthAPIerror( "pthread_rwlock_unlock", ret );
2636 }
2637
2638 if (TRACE_PTH_FNS) {
2639 fprintf(stderr, " :: rwl_unlk -> %d >>\n", ret);
2640 }
2641 return ret;
2642 }
2643 #if defined(VGO_linux)
PTH_FUNC(int,pthreadZurwlockZuunlock,pthread_rwlock_t * rwlock)2644 PTH_FUNC(int, pthreadZurwlockZuunlock, // pthread_rwlock_unlock
2645 pthread_rwlock_t* rwlock) {
2646 return pthread_rwlock_unlock_WRK(rwlock);
2647 }
2648 #elif defined(VGO_dragonfly)
PTH_FUNC(int,pthreadZurwlockZuunlock,pthread_rwlock_t * rwlock)2649 PTH_FUNC(int, pthreadZurwlockZuunlock, // pthread_rwlock_unlock
2650 pthread_rwlock_t* rwlock) {
2651 return pthread_rwlock_unlock_WRK(rwlock);
2652 }
2653 #elif defined(VGO_darwin)
PTH_FUNC(int,pthreadZurwlockZuunlockZa,pthread_rwlock_t * rwlock)2654 PTH_FUNC(int, pthreadZurwlockZuunlockZa, // pthread_rwlock_unlock*
2655 pthread_rwlock_t* rwlock) {
2656 return pthread_rwlock_unlock_WRK(rwlock);
2657 }
2658 #elif defined(VGO_solaris)
PTH_FUNC(int,rwZuunlock,pthread_rwlock_t * rwlock)2659 PTH_FUNC(int, rwZuunlock, // rw_unlock
2660 pthread_rwlock_t *rwlock) {
2661 return pthread_rwlock_unlock_WRK(rwlock);
2662 }
2663 #else
2664 # error "Unsupported OS"
2665 #endif
2666
2667 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
2668
2669
2670 /*----------------------------------------------------------------*/
2671 /*--- POSIX semaphores ---*/
2672 /*----------------------------------------------------------------*/
2673
2674 #include <semaphore.h>
2675 #include <fcntl.h> /* O_CREAT */
2676
2677 #define TRACE_SEM_FNS 0
2678
2679 /* Handled:
2680 int sem_init(sem_t *sem, int pshared, unsigned value);
2681 int sem_destroy(sem_t *sem);
2682 int sem_wait(sem_t *sem);
2683 int sem_post(sem_t *sem);
2684 sem_t* sem_open(const char *name, int oflag,
2685 ... [mode_t mode, unsigned value]);
2686 [complete with its idiotic semantics]
2687 int sem_close(sem_t* sem);
2688
2689 Unhandled:
2690 int sem_trywait(sem_t *sem);
2691 int sem_timedwait(sem_t *restrict sem,
2692 const struct timespec *restrict abs_timeout);
2693 */
2694
2695 //-----------------------------------------------------------
2696 // glibc: sem_init@@GLIBC_2.2.5
2697 // glibc: sem_init@@GLIBC_2.1
2698 // glibc: sem_init@GLIBC_2.0
2699 // darwin: sem_init
2700 // Solaris: sema_init (sem_init is built on top of sem_init)
2701 //
2702 #if !defined(VGO_solaris)
2703 __attribute__((noinline))
sem_init_WRK(sem_t * sem,int pshared,unsigned long value)2704 static int sem_init_WRK(sem_t* sem, int pshared, unsigned long value)
2705 {
2706 OrigFn fn;
2707 int ret;
2708 VALGRIND_GET_ORIG_FN(fn);
2709
2710 if (TRACE_SEM_FNS) {
2711 fprintf(stderr, "<< sem_init(%p,%d,%lu) ", sem,pshared,value);
2712 fflush(stderr);
2713 }
2714
2715 CALL_FN_W_WWW(ret, fn, sem,pshared,value);
2716
2717 if (ret == 0) {
2718 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
2719 sem_t*, sem, unsigned long, value);
2720 } else {
2721 DO_PthAPIerror( "sem_init", errno );
2722 }
2723
2724 if (TRACE_SEM_FNS) {
2725 fprintf(stderr, " sem_init -> %d >>\n", ret);
2726 fflush(stderr);
2727 }
2728
2729 return ret;
2730 }
2731 #if defined(VGO_linux)
PTH_FUNC(int,semZuinitZAZa,sem_t * sem,int pshared,unsigned long value)2732 PTH_FUNC(int, semZuinitZAZa, // sem_init@*
2733 sem_t* sem, int pshared, unsigned long value) {
2734 return sem_init_WRK(sem, pshared, value);
2735 }
2736 #elif defined(VGO_dragonfly)
PTH_FUNC(int,semZuinit,sem_t * sem,int pshared,unsigned long value)2737 PTH_FUNC(int, semZuinit, // sem_init
2738 sem_t* sem, int pshared, unsigned long value) {
2739 return sem_init_WRK(sem, pshared, value);
2740 }
2741 #elif defined(VGO_darwin)
PTH_FUNC(int,semZuinit,sem_t * sem,int pshared,unsigned long value)2742 PTH_FUNC(int, semZuinit, // sem_init
2743 sem_t* sem, int pshared, unsigned long value) {
2744 return sem_init_WRK(sem, pshared, value);
2745 }
2746 #else
2747 # error "Unsupported OS"
2748 #endif
2749
2750 #else /* VGO_solaris */
PTH_FUNC(int,semaZuinit,sema_t * sem,unsigned int value,int type,void * arg)2751 PTH_FUNC(int, semaZuinit, // sema_init
2752 sema_t *sem,
2753 unsigned int value,
2754 int type,
2755 void *arg)
2756 {
2757 OrigFn fn;
2758 int ret;
2759 VALGRIND_GET_ORIG_FN(fn);
2760
2761 if (TRACE_SEM_FNS) {
2762 fprintf(stderr, "<< sema_init(%p, %d, %u) ", sem, type, value);
2763 fflush(stderr);
2764 }
2765
2766 CALL_FN_W_WWWW(ret, fn, sem, value, type, arg);
2767
2768 if (ret == 0) {
2769 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
2770 sema_t *, sem, Word, value);
2771 } else {
2772 DO_PthAPIerror("sema_init", ret);
2773 }
2774
2775 if (TRACE_SEM_FNS) {
2776 fprintf(stderr, " sema_init -> %d >>\n", ret);
2777 fflush(stderr);
2778 }
2779
2780 return ret;
2781 }
2782 #endif /* VGO_solaris */
2783
2784
2785 //-----------------------------------------------------------
2786 // glibc: sem_destroy@GLIBC_2.0
2787 // glibc: sem_destroy@@GLIBC_2.1
2788 // glibc: sem_destroy@@GLIBC_2.2.5
2789 // darwin: sem_destroy
2790 // Solaris: sema_destroy (sem_destroy is built on top of sema_destroy)
2791 __attribute__((noinline))
sem_destroy_WRK(sem_t * sem)2792 static int sem_destroy_WRK(sem_t* sem)
2793 {
2794 OrigFn fn;
2795 int ret;
2796 VALGRIND_GET_ORIG_FN(fn);
2797
2798 if (TRACE_SEM_FNS) {
2799 fprintf(stderr, "<< sem_destroy(%p) ", sem);
2800 fflush(stderr);
2801 }
2802
2803 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
2804
2805 CALL_FN_W_W(ret, fn, sem);
2806
2807 if (ret != 0) {
2808 DO_PthAPIerror( "sem_destroy", SEM_ERROR );
2809 }
2810
2811 if (TRACE_SEM_FNS) {
2812 fprintf(stderr, " sem_destroy -> %d >>\n", ret);
2813 fflush(stderr);
2814 }
2815
2816 return ret;
2817 }
2818 #if defined(VGO_linux)
PTH_FUNC(int,semZudestroyZAZa,sem_t * sem)2819 PTH_FUNC(int, semZudestroyZAZa, // sem_destroy*
2820 sem_t* sem) {
2821 return sem_destroy_WRK(sem);
2822 }
2823 #elif defined(VGO_dragonfly)
PTH_FUNC(int,semZudestroy,sem_t * sem)2824 PTH_FUNC(int, semZudestroy, // sem_destroy
2825 sem_t* sem) {
2826 return sem_destroy_WRK(sem);
2827 }
2828 #elif defined(VGO_darwin)
PTH_FUNC(int,semZudestroy,sem_t * sem)2829 PTH_FUNC(int, semZudestroy, // sem_destroy
2830 sem_t* sem) {
2831 return sem_destroy_WRK(sem);
2832 }
2833 #elif defined(VGO_solaris)
PTH_FUNC(int,semaZudestroy,sem_t * sem)2834 PTH_FUNC(int, semaZudestroy, // sema_destroy
2835 sem_t *sem) {
2836 return sem_destroy_WRK(sem);
2837 }
2838 #else
2839 # error "Unsupported OS"
2840 #endif
2841
2842
2843 //-----------------------------------------------------------
2844 // glibc: sem_wait
2845 // glibc: sem_wait@GLIBC_2.0
2846 // glibc: sem_wait@@GLIBC_2.1
2847 // darwin: sem_wait
2848 // darwin: sem_wait$NOCANCEL$UNIX2003
2849 // darwin: sem_wait$UNIX2003
2850 // Solaris: sema_wait (sem_wait is built on top of sema_wait)
2851 //
2852 /* wait: decrement semaphore - acquire lockage */
2853 __attribute__((noinline))
sem_wait_WRK(sem_t * sem)2854 static int sem_wait_WRK(sem_t* sem)
2855 {
2856 OrigFn fn;
2857 int ret;
2858 VALGRIND_GET_ORIG_FN(fn);
2859
2860 if (TRACE_SEM_FNS) {
2861 fprintf(stderr, "<< sem_wait(%p) ", sem);
2862 fflush(stderr);
2863 }
2864
2865 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_PRE, sem_t*,sem);
2866
2867 CALL_FN_W_W(ret, fn, sem);
2868
2869 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST, sem_t*,sem,
2870 long, (ret == 0) ? True : False);
2871
2872 if (ret != 0) {
2873 DO_PthAPIerror( "sem_wait", SEM_ERROR );
2874 }
2875
2876 if (TRACE_SEM_FNS) {
2877 fprintf(stderr, " sem_wait -> %d >>\n", ret);
2878 fflush(stderr);
2879 }
2880
2881 return ret;
2882 }
2883 #if defined(VGO_linux)
PTH_FUNC(int,semZuwait,sem_t * sem)2884 PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
2885 return sem_wait_WRK(sem);
2886 }
PTH_FUNC(int,semZuwaitZAZa,sem_t * sem)2887 PTH_FUNC(int, semZuwaitZAZa, sem_t* sem) { /* sem_wait@* */
2888 return sem_wait_WRK(sem);
2889 }
2890 #elif defined(VGO_dragonfly)
PTH_FUNC(int,semZuwait,sem_t * sem)2891 PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
2892 return sem_wait_WRK(sem);
2893 }
2894 #elif defined(VGO_darwin)
PTH_FUNC(int,semZuwait,sem_t * sem)2895 PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
2896 return sem_wait_WRK(sem);
2897 }
PTH_FUNC(int,semZuwaitZDZa,sem_t * sem)2898 PTH_FUNC(int, semZuwaitZDZa, sem_t* sem) { /* sem_wait$* */
2899 return sem_wait_WRK(sem);
2900 }
2901 #elif defined(VGO_solaris)
PTH_FUNC(int,semaZuwait,sem_t * sem)2902 PTH_FUNC(int, semaZuwait, sem_t *sem) { /* sema_wait */
2903 return sem_wait_WRK(sem);
2904 }
2905 #else
2906 # error "Unsupported OS"
2907 #endif
2908
2909
2910 //-----------------------------------------------------------
2911 // glibc: sem_post
2912 // glibc: sem_post@GLIBC_2.0
2913 // glibc: sem_post@@GLIBC_2.1
2914 // darwin: sem_post
2915 // Solaris: sema_post (sem_post is built on top of sema_post)
2916 //
2917 /* post: increment semaphore - release lockage */
2918 __attribute__((noinline))
sem_post_WRK(sem_t * sem)2919 static int sem_post_WRK(sem_t* sem)
2920 {
2921 OrigFn fn;
2922 int ret;
2923
2924 VALGRIND_GET_ORIG_FN(fn);
2925
2926 if (TRACE_SEM_FNS) {
2927 fprintf(stderr, "<< sem_post(%p) ", sem);
2928 fflush(stderr);
2929 }
2930
2931 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_PRE, sem_t*,sem);
2932
2933 CALL_FN_W_W(ret, fn, sem);
2934
2935 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_POST, sem_t*,sem);
2936
2937 if (ret != 0) {
2938 DO_PthAPIerror( "sem_post", SEM_ERROR );
2939 }
2940
2941 if (TRACE_SEM_FNS) {
2942 fprintf(stderr, " sem_post -> %d >>\n", ret);
2943 fflush(stderr);
2944 }
2945
2946 return ret;
2947 }
2948 #if defined(VGO_linux)
PTH_FUNC(int,semZupost,sem_t * sem)2949 PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
2950 return sem_post_WRK(sem);
2951 }
PTH_FUNC(int,semZupostZAZa,sem_t * sem)2952 PTH_FUNC(int, semZupostZAZa, sem_t* sem) { /* sem_post@* */
2953 return sem_post_WRK(sem);
2954 }
2955 #elif defined(VGO_dragonfly)
PTH_FUNC(int,semZupost,sem_t * sem)2956 PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
2957 return sem_post_WRK(sem);
2958 }
2959 #elif defined(VGO_darwin)
PTH_FUNC(int,semZupost,sem_t * sem)2960 PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
2961 return sem_post_WRK(sem);
2962 }
2963 #elif defined(VGO_solaris)
PTH_FUNC(int,semaZupost,sem_t * sem)2964 PTH_FUNC(int, semaZupost, sem_t *sem) { /* sema_post */
2965 return sem_post_WRK(sem);
2966 }
2967 #else
2968 # error "Unsupported OS"
2969 #endif
2970
2971
2972 //-----------------------------------------------------------
2973 // glibc: sem_open
2974 // darwin: sem_open
2975 // Solaris: sem_open
2976 //
PTH_FUNC(sem_t *,semZuopen,const char * name,long oflag,long mode,unsigned long value)2977 PTH_FUNC(sem_t*, semZuopen,
2978 const char* name, long oflag,
2979 long mode, unsigned long value)
2980 {
2981 /* A copy of sem_init_WRK (more or less). Is this correct? */
2982 OrigFn fn;
2983 sem_t* ret;
2984 VALGRIND_GET_ORIG_FN(fn);
2985
2986 if (TRACE_SEM_FNS) {
2987 fprintf(stderr, "<< sem_open(\"%s\",%ld,%lx,%lu) ",
2988 name,oflag,mode,value);
2989 fflush(stderr);
2990 }
2991
2992 CALL_FN_W_WWWW(ret, fn, name,oflag,mode,value);
2993
2994 if (ret != SEM_FAILED && (oflag & O_CREAT)) {
2995 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
2996 sem_t*, ret, unsigned long, value);
2997 }
2998 if (ret == SEM_FAILED) {
2999 DO_PthAPIerror( "sem_open", errno );
3000 }
3001
3002 if (TRACE_SEM_FNS) {
3003 fprintf(stderr, " sem_open -> %p >>\n", ret);
3004 fflush(stderr);
3005 }
3006
3007 return ret;
3008 }
3009
3010
3011 //-----------------------------------------------------------
3012 // glibc: sem_close
3013 // darwin: sem_close
3014 // Solaris: sem_close
PTH_FUNC(int,sem_close,sem_t * sem)3015 PTH_FUNC(int, sem_close, sem_t* sem)
3016 {
3017 OrigFn fn;
3018 int ret;
3019 VALGRIND_GET_ORIG_FN(fn);
3020
3021 if (TRACE_SEM_FNS) {
3022 fprintf(stderr, "<< sem_close(%p) ", sem);
3023 fflush(stderr);
3024 }
3025
3026 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
3027
3028 CALL_FN_W_W(ret, fn, sem);
3029
3030 if (ret != 0) {
3031 DO_PthAPIerror( "sem_close", errno );
3032 }
3033
3034 if (TRACE_SEM_FNS) {
3035 fprintf(stderr, " close -> %d >>\n", ret);
3036 fflush(stderr);
3037 }
3038
3039 return ret;
3040 }
3041
3042
3043 /*----------------------------------------------------------------*/
3044 /*--- Qt 4 threading functions (w/ GNU name mangling) ---*/
3045 /*----------------------------------------------------------------*/
3046
3047 /* Handled:
3048 QMutex::lock()
3049 QMutex::unlock()
3050 QMutex::tryLock()
3051 QMutex::tryLock(int)
3052
3053 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC1ENS_13RecursionModeE
3054 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC2ENS_13RecursionModeE
3055 QMutex::~QMutex() _ZN6QMutexD1Ev
3056 QMutex::~QMutex() _ZN6QMutexD2Ev
3057
3058 Unhandled:
3059 QReadWriteLock::lockForRead()
3060 QReadWriteLock::lockForWrite()
3061 QReadWriteLock::unlock()
3062 QReadWriteLock::tryLockForRead(int)
3063 QReadWriteLock::tryLockForRead()
3064 QReadWriteLock::tryLockForWrite(int)
3065 QReadWriteLock::tryLockForWrite()
3066
3067 QWaitCondition::wait(QMutex*, unsigned long)
3068 QWaitCondition::wakeAll()
3069 QWaitCondition::wakeOne()
3070
3071 QSemaphore::*
3072 */
3073 /* More comments, 19 Nov 08, based on assessment of qt-4.5.0TP1,
3074 at least on Unix:
3075
3076 It's apparently only necessary to intercept QMutex, since that is
3077 not implemented using pthread_mutex_t; instead Qt4 has its own
3078 implementation based on atomics (to check the non-contended case)
3079 and pthread_cond_wait (to wait in the contended case).
3080
3081 QReadWriteLock is built on top of QMutex, counters, and a wait
3082 queue. So we don't need to handle it specially once QMutex
3083 handling is correct -- presumably the dependencies through QMutex
3084 are sufficient to avoid any false race reports. On the other hand,
3085 it is an open question whether too many dependencies are observed
3086 -- in which case we may miss races (false negatives). I suspect
3087 this is likely to be the case, unfortunately.
3088
3089 QWaitCondition is built on pthread_cond_t, pthread_mutex_t, QMutex
3090 and QReadWriteLock. Same compositional-correctness justificiation
3091 and limitations as fro QReadWriteLock.
3092
3093 Ditto QSemaphore (from cursory examination).
3094
3095 Does it matter that only QMutex is handled directly? Open
3096 question. From testing with drd/tests/qt4_* and with KDE4 apps, it
3097 appears that no false errors are reported; however it is not clear
3098 if this is causing false negatives.
3099
3100 Another problem with Qt4 is thread exiting. Threads are created
3101 with pthread_create (fine); but they detach and simply exit when
3102 done. There is no use of pthread_join, and the provided
3103 wait-for-a-thread-to-exit mechanism (QThread::wait, I believe)
3104 relies on a system of mutexes and flags. I suspect this also
3105 causes too many dependencies to appear. Consequently H sometimes
3106 fails to detect races at exit in some very short-lived racy
3107 programs, because it appears that a thread can exit _and_ have an
3108 observed dependency edge back to the main thread (presumably)
3109 before the main thread reaps the child (that is, calls
3110 QThread::wait).
3111
3112 This theory is supported by the observation that if all threads are
3113 made to wait at a pthread_barrier_t immediately before they exit,
3114 then H's detection of races in such programs becomes reliable;
3115 without the barrier, it is varies from run to run, depending
3116 (according to investigation) on whether aforementioned
3117 exit-before-reaping behaviour happens or not.
3118
3119 Finally, why is it necessary to intercept the QMutex constructors
3120 and destructors? The constructors are intercepted only as a matter
3121 of convenience, so H can print accurate "first observed at"
3122 clauses. However, it is actually necessary to intercept the
3123 destructors (as it is with pthread_mutex_destroy) in order that
3124 locks get removed from LAOG when they are destroyed.
3125 */
3126
3127 // soname is libQtCore.so.4 ; match against libQtCore.so*
3128 #define QT4_FUNC(ret_ty, f, args...) \
3129 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args); \
3130 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args)
3131
3132 // soname is libQt5Core.so.4 ; match against libQt5Core.so*
3133 #define QT5_FUNC(ret_ty, f, args...) \
3134 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args); \
3135 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args)
3136
3137 //-----------------------------------------------------------
3138 // QMutex::lock()
3139 __attribute__((noinline))
QMutex_lock_WRK(void * self)3140 static void QMutex_lock_WRK(void* self)
3141 {
3142 OrigFn fn;
3143 VALGRIND_GET_ORIG_FN(fn);
3144 if (TRACE_QT4_FNS) {
3145 fprintf(stderr, "<< QMutex::lock %p", self); fflush(stderr);
3146 }
3147
3148 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
3149 void*,self, long,0/*!isTryLock*/);
3150
3151 CALL_FN_v_W(fn, self);
3152
3153 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
3154 void *, self, long, True);
3155
3156 if (TRACE_QT4_FNS) {
3157 fprintf(stderr, " :: Q::lock done >>\n");
3158 }
3159 }
3160
QT4_FUNC(void,_ZN6QMutex4lockEv,void * self)3161 QT4_FUNC(void, _ZN6QMutex4lockEv, void* self) {
3162 QMutex_lock_WRK(self);
3163 }
QT5_FUNC(void,_ZN6QMutex4lockEv,void * self)3164 QT5_FUNC(void, _ZN6QMutex4lockEv, void* self) {
3165 QMutex_lock_WRK(self);
3166 }
3167
3168 //-----------------------------------------------------------
3169 // QMutex::unlock()
3170 __attribute__((noinline))
QMutex_unlock_WRK(void * self)3171 static void QMutex_unlock_WRK(void* self)
3172 {
3173 OrigFn fn;
3174 VALGRIND_GET_ORIG_FN(fn);
3175
3176 if (TRACE_QT4_FNS) {
3177 fprintf(stderr, "<< QMutex::unlock %p", self); fflush(stderr);
3178 }
3179
3180 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
3181 void*, self);
3182
3183 CALL_FN_v_W(fn, self);
3184
3185 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
3186 void*, self);
3187
3188 if (TRACE_QT4_FNS) {
3189 fprintf(stderr, " Q::unlock done >>\n");
3190 }
3191 }
3192
QT4_FUNC(void,_ZN6QMutex6unlockEv,void * self)3193 QT4_FUNC(void, _ZN6QMutex6unlockEv, void* self) {
3194 QMutex_unlock_WRK(self);
3195 }
QT5_FUNC(void,_ZN6QMutex6unlockEv,void * self)3196 QT5_FUNC(void, _ZN6QMutex6unlockEv, void* self) {
3197 QMutex_unlock_WRK(self);
3198 }
3199
3200 //-----------------------------------------------------------
3201 // bool QMutex::tryLock()
3202 // using 'long' to mimic C++ 'bool'
3203 __attribute__((noinline))
QMutex_tryLock_WRK(void * self)3204 static long QMutex_tryLock_WRK(void* self)
3205 {
3206 OrigFn fn;
3207 long ret;
3208 VALGRIND_GET_ORIG_FN(fn);
3209 if (TRACE_QT4_FNS) {
3210 fprintf(stderr, "<< QMutex::tryLock %p", self); fflush(stderr);
3211 }
3212
3213 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
3214 void*,self, long,1/*isTryLock*/);
3215
3216 CALL_FN_W_W(ret, fn, self);
3217
3218 // assumes that only the low 8 bits of the 'bool' are significant
3219 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
3220 void *, self, long, (ret & 0xFF) ? True : False);
3221
3222 if (TRACE_QT4_FNS) {
3223 fprintf(stderr, " :: Q::tryLock -> %lu >>\n", ret);
3224 }
3225
3226 return ret;
3227 }
3228
QT4_FUNC(long,_ZN6QMutex7tryLockEv,void * self)3229 QT4_FUNC(long, _ZN6QMutex7tryLockEv, void* self) {
3230 return QMutex_tryLock_WRK(self);
3231 }
QT5_FUNC(long,_ZN6QMutex7tryLockEv,void * self)3232 QT5_FUNC(long, _ZN6QMutex7tryLockEv, void* self) {
3233 return QMutex_tryLock_WRK(self);
3234 }
3235
3236 //-----------------------------------------------------------
3237 // bool QMutex::tryLock(int)
3238 // using 'long' to mimic C++ 'bool'
3239 __attribute__((noinline))
QMutex_tryLock_int_WRK(void * self,long arg2)3240 static long QMutex_tryLock_int_WRK(void* self, long arg2)
3241 {
3242 OrigFn fn;
3243 long ret;
3244 VALGRIND_GET_ORIG_FN(fn);
3245 if (TRACE_QT4_FNS) {
3246 fprintf(stderr, "<< QMutex::tryLock(int) %p %d", self, (int)arg2);
3247 fflush(stderr);
3248 }
3249
3250 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
3251 void*,self, long,1/*isTryLock*/);
3252
3253 CALL_FN_W_WW(ret, fn, self,arg2);
3254
3255 // assumes that only the low 8 bits of the 'bool' are significant
3256 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
3257 void *, self, long, (ret & 0xFF) ? True : False);
3258
3259 if (TRACE_QT4_FNS) {
3260 fprintf(stderr, " :: Q::tryLock(int) -> %lu >>\n", ret);
3261 }
3262
3263 return ret;
3264 }
3265
QT4_FUNC(long,_ZN6QMutex7tryLockEi,void * self,long arg2)3266 QT4_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2) {
3267 return QMutex_tryLock_int_WRK(self, arg2);
3268 }
QT5_FUNC(long,_ZN6QMutex7tryLockEi,void * self,long arg2)3269 QT5_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2) {
3270 return QMutex_tryLock_int_WRK(self, arg2);
3271 }
3272
3273 //-----------------------------------------------------------
3274 // It's not really very clear what the args are here. But from
3275 // a bit of dataflow analysis of the generated machine code of
3276 // the original function, it appears this takes two args, and
3277 // returns nothing. Nevertheless preserve return value just in
3278 // case. A bit of debug printing indicates that the first arg
3279 // is that of the mutex and the second is either zero or one,
3280 // probably being the recursion mode, therefore.
3281 // QMutex::QMutex(QMutex::RecursionMode) ("C1ENS" variant)
3282 __attribute__((noinline))
QMutex_constructor_WRK(void * mutex,long recmode)3283 static void* QMutex_constructor_WRK(void* mutex, long recmode)
3284 {
3285 OrigFn fn;
3286 long ret;
3287 VALGRIND_GET_ORIG_FN(fn);
3288 CALL_FN_W_WW(ret, fn, mutex, recmode);
3289 // fprintf(stderr, "QMutex constructor 1: %p <- %p %p\n", ret, arg1, arg2);
3290 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
3291 void*,mutex, long,1/*mbRec*/);
3292 return (void*)ret;
3293 }
3294
QT4_FUNC(void *,_ZN6QMutexC1ENS_13RecursionModeE,void * self,long recmode)3295 QT4_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE, void* self, long recmode) {
3296 return QMutex_constructor_WRK(self, recmode);
3297 }
QT5_FUNC(void *,_ZN6QMutexC1ENS_13RecursionModeE,void * self,long recmode)3298 QT5_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE, void* self, long recmode) {
3299 return QMutex_constructor_WRK(self, recmode);
3300 }
3301
3302 //-----------------------------------------------------------
3303 // QMutex::~QMutex() ("D1Ev" variant)
3304 __attribute__((noinline))
QMutex_destructor_WRK(void * mutex)3305 static void* QMutex_destructor_WRK(void* mutex)
3306 {
3307 OrigFn fn;
3308 long ret;
3309 VALGRIND_GET_ORIG_FN(fn);
3310 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
3311 void*,mutex);
3312 CALL_FN_W_W(ret, fn, mutex);
3313 return (void*)ret;
3314 }
3315
QT4_FUNC(void *,_ZN6QMutexD1Ev,void * self)3316 QT4_FUNC(void*, _ZN6QMutexD1Ev, void* self) {
3317 return QMutex_destructor_WRK(self);
3318 }
QT5_FUNC(void *,_ZN6QMutexD1Ev,void * self)3319 QT5_FUNC(void*, _ZN6QMutexD1Ev, void* self) {
3320 return QMutex_destructor_WRK(self);
3321 }
3322
3323 //-----------------------------------------------------------
3324 // QMutex::QMutex(QMutex::RecursionMode) ("C2ENS" variant)
QT4_FUNC(void *,_ZN6QMutexC2ENS_13RecursionModeE,void * mutex,long recmode)3325 QT4_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE,
3326 void* mutex,
3327 long recmode)
3328 {
3329 assert(0);
3330 /*NOTREACHED*/
3331 /* Android's gcc behaves like it doesn't know that assert(0)
3332 never returns. Hence: */
3333 return NULL;
3334 }
3335
QT5_FUNC(void *,_ZN6QMutexC2ENS_13RecursionModeE,void * self,long recmode)3336 QT5_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE, void* self, long recmode)
3337 {
3338 assert(0);
3339 /*NOTREACHED*/
3340 return NULL;
3341 }
3342
3343 //-----------------------------------------------------------
3344 // QMutex::~QMutex() ("D2Ev" variant)
QT4_FUNC(void *,_ZN6QMutexD2Ev,void * mutex)3345 QT4_FUNC(void*, _ZN6QMutexD2Ev, void* mutex)
3346 {
3347 assert(0);
3348 /* Android's gcc behaves like it doesn't know that assert(0)
3349 never returns. Hence: */
3350 return NULL;
3351 }
3352
QT5_FUNC(void *,_ZN6QMutexD2Ev,void * self)3353 QT5_FUNC(void*, _ZN6QMutexD2Ev, void* self)
3354 {
3355 assert(0);
3356 /*NOTREACHED*/
3357 return NULL;
3358 }
3359
3360 // QReadWriteLock is not intercepted directly. See comments
3361 // above.
3362
3363 //// QReadWriteLock::lockForRead()
3364 //// _ZN14QReadWriteLock11lockForReadEv == QReadWriteLock::lockForRead()
3365 //QT4_FUNC(void, ZuZZN14QReadWriteLock11lockForReadEv,
3366 // // _ZN14QReadWriteLock11lockForReadEv
3367 // void* self)
3368 //{
3369 // OrigFn fn;
3370 // VALGRIND_GET_ORIG_FN(fn);
3371 // if (TRACE_QT4_FNS) {
3372 // fprintf(stderr, "<< QReadWriteLock::lockForRead %p", self);
3373 // fflush(stderr);
3374 // }
3375 //
3376 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
3377 // void*,self,
3378 // long,0/*!isW*/, long,0/*!isTryLock*/);
3379 //
3380 // CALL_FN_v_W(fn, self);
3381 //
3382 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
3383 // void*,self, long,0/*!isW*/, long, True);
3384 //
3385 // if (TRACE_QT4_FNS) {
3386 // fprintf(stderr, " :: Q::lockForRead :: done >>\n");
3387 // }
3388 //}
3389 //
3390 //// QReadWriteLock::lockForWrite()
3391 //// _ZN14QReadWriteLock12lockForWriteEv == QReadWriteLock::lockForWrite()
3392 //QT4_FUNC(void, ZuZZN14QReadWriteLock12lockForWriteEv,
3393 // // _ZN14QReadWriteLock12lockForWriteEv
3394 // void* self)
3395 //{
3396 // OrigFn fn;
3397 // VALGRIND_GET_ORIG_FN(fn);
3398 // if (TRACE_QT4_FNS) {
3399 // fprintf(stderr, "<< QReadWriteLock::lockForWrite %p", self);
3400 // fflush(stderr);
3401 // }
3402 //
3403 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
3404 // void*,self,
3405 // long,1/*isW*/, long,0/*!isTryLock*/);
3406 //
3407 // CALL_FN_v_W(fn, self);
3408 //
3409 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
3410 // void*,self, long,1/*isW*/, long, True);
3411 //
3412 // if (TRACE_QT4_FNS) {
3413 // fprintf(stderr, " :: Q::lockForWrite :: done >>\n");
3414 // }
3415 //}
3416 //
3417 //// QReadWriteLock::unlock()
3418 //// _ZN14QReadWriteLock6unlockEv == QReadWriteLock::unlock()
3419 //QT4_FUNC(void, ZuZZN14QReadWriteLock6unlockEv,
3420 // // _ZN14QReadWriteLock6unlockEv
3421 // void* self)
3422 //{
3423 // OrigFn fn;
3424 // VALGRIND_GET_ORIG_FN(fn);
3425 // if (TRACE_QT4_FNS) {
3426 // fprintf(stderr, "<< QReadWriteLock::unlock %p", self);
3427 // fflush(stderr);
3428 // }
3429 //
3430 // DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
3431 // void*,self);
3432 //
3433 // CALL_FN_v_W(fn, self);
3434 //
3435 // DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
3436 // void*,self);
3437 //
3438 // if (TRACE_QT4_FNS) {
3439 // fprintf(stderr, " :: Q::unlock :: done >>\n");
3440 // }
3441 //}
3442
3443
3444 /*----------------------------------------------------------------*/
3445 /*--- Replacements for basic string functions, that don't ---*/
3446 /*--- overrun the input arrays. ---*/
3447 /*----------------------------------------------------------------*/
3448
3449 #include "../shared/vg_replace_strmem.c"
3450
3451 /*--------------------------------------------------------------------*/
3452 /*--- end hg_intercepts.c ---*/
3453 /*--------------------------------------------------------------------*/
3454