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