blob: e186716627d0e3ec1bf427bb08f72bb7069d6dc2 [file] [log] [blame]
sewardjb4112022007-11-09 22:49:28 +00001
2/*--------------------------------------------------------------------*/
3/*--- pthread intercepts for thread checking. ---*/
sewardj3c944452011-09-05 20:39:57 +00004/*--- hg_intercepts.c ---*/
sewardjb4112022007-11-09 22:49:28 +00005/*--------------------------------------------------------------------*/
6
7/*
8 This file is part of Helgrind, a Valgrind tool for detecting errors
9 in threaded programs.
10
Elliott Hughesed398002017-06-21 14:41:24 -070011 Copyright (C) 2007-2017 OpenWorks LLP
sewardjb4112022007-11-09 22:49:28 +000012 info@open-works.co.uk
13
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
29 The GNU General Public License is contained in the file COPYING.
30
31 Neither the names of the U.S. Department of Energy nor the
32 University of California nor the names of its contributors may be
33 used to endorse or promote products derived from this software
34 without prior written permission.
35*/
36
37/* RUNS ON SIMULATED CPU
38 Interceptors for pthread_* functions, so that tc_main can see
39 significant thread events.
40
41 Important: when adding a function wrapper to this file, remember to
42 add a test case to tc20_verifywrap.c. A common cause of failure is
43 for wrappers to not engage on different distros, and
44 tc20_verifywrap essentially checks that each wrapper is really
45 doing something.
46*/
47
sewardj1c147ff2009-07-26 19:52:06 +000048// DDD: for Darwin, need to have non-"@*"-suffixed versions for all pthread
49// functions that currently have them.
50// Note also, in the comments and code below, all Darwin symbols start
51// with a leading underscore, which is not shown either in the comments
52// nor in the redirect specs.
53
54
sewardjb4112022007-11-09 22:49:28 +000055#include "pub_tool_basics.h"
sewardj38e0cf92008-11-19 10:40:56 +000056#include "pub_tool_redir.h"
florian1a046d52013-09-16 20:56:35 +000057#include "pub_tool_clreq.h"
sewardjb4112022007-11-09 22:49:28 +000058#include "helgrind.h"
bart870f7452009-12-29 16:56:18 +000059#include "config.h"
sewardjb4112022007-11-09 22:49:28 +000060
sewardj8eb8bab2015-07-21 14:44:28 +000061
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
sewardjb4112022007-11-09 22:49:28 +000073#define TRACE_PTH_FNS 0
74#define TRACE_QT4_FNS 0
philipped40aff52014-06-16 20:00:14 +000075#define TRACE_GNAT_FNS 0
sewardjb4112022007-11-09 22:49:28 +000076
77
78/*----------------------------------------------------------------*/
79/*--- ---*/
80/*----------------------------------------------------------------*/
81
sewardj8eb8bab2015-07-21 14:44:28 +000082#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
sewardjb4112022007-11-09 22:49:28 +000096#define PTH_FUNC(ret_ty, f, args...) \
njn5f5ef2a2009-05-11 08:01:09 +000097 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)
sewardj8eb8bab2015-07-21 14:44:28 +000099#define CREQ_PTHREAD_T pthread_t
100#define SEM_ERROR errno
101#endif /* VGO_solaris */
sewardjb4112022007-11-09 22:49:28 +0000102
sewardj406bac82010-03-03 23:03:40 +0000103// 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
sewardjb4112022007-11-09 22:49:28 +0000116
117#define DO_CREQ_v_W(_creqF, _ty1F,_arg1F) \
118 do { \
sewardjc7ffc942011-03-28 16:26:42 +0000119 Word _arg1; \
sewardjb4112022007-11-09 22:49:28 +0000120 assert(sizeof(_ty1F) == sizeof(Word)); \
121 _arg1 = (Word)(_arg1F); \
sewardj4b3a7422011-10-24 13:21:57 +0000122 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
sewardjb4112022007-11-09 22:49:28 +0000123 _arg1, 0,0,0,0); \
124 } while (0)
125
126#define DO_CREQ_v_WW(_creqF, _ty1F,_arg1F, _ty2F,_arg2F) \
127 do { \
sewardjc7ffc942011-03-28 16:26:42 +0000128 Word _arg1, _arg2; \
sewardjb4112022007-11-09 22:49:28 +0000129 assert(sizeof(_ty1F) == sizeof(Word)); \
130 assert(sizeof(_ty2F) == sizeof(Word)); \
131 _arg1 = (Word)(_arg1F); \
132 _arg2 = (Word)(_arg2F); \
sewardj4b3a7422011-10-24 13:21:57 +0000133 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
sewardjb4112022007-11-09 22:49:28 +0000134 _arg1,_arg2,0,0,0); \
135 } while (0)
136
sewardjc7ffc942011-03-28 16:26:42 +0000137#define DO_CREQ_W_WW(_resF, _creqF, _ty1F,_arg1F, \
138 _ty2F,_arg2F) \
sewardjb4112022007-11-09 22:49:28 +0000139 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); \
bart575ce8e2011-05-15 07:04:03 +0000145 _res = VALGRIND_DO_CLIENT_REQUEST_EXPR(2, \
sewardjb4112022007-11-09 22:49:28 +0000146 (_creqF), \
147 _arg1,_arg2,0,0,0); \
148 _resF = _res; \
149 } while (0)
150
151#define DO_CREQ_v_WWW(_creqF, _ty1F,_arg1F, \
sewardj1c147ff2009-07-26 19:52:06 +0000152 _ty2F,_arg2F, _ty3F, _arg3F) \
sewardjb4112022007-11-09 22:49:28 +0000153 do { \
sewardjc7ffc942011-03-28 16:26:42 +0000154 Word _arg1, _arg2, _arg3; \
sewardjb4112022007-11-09 22:49:28 +0000155 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); \
sewardj4b3a7422011-10-24 13:21:57 +0000161 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \
sewardjb4112022007-11-09 22:49:28 +0000162 _arg1,_arg2,_arg3,0,0); \
163 } while (0)
164
sewardj8eb8bab2015-07-21 14:44:28 +0000165#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)
sewardjb4112022007-11-09 22:49:28 +0000181
182#define DO_PthAPIerror(_fnnameF, _errF) \
183 do { \
florian09041e42014-10-21 17:15:14 +0000184 const char* _fnname = (_fnnameF); \
sewardj1c147ff2009-07-26 19:52:06 +0000185 long _err = (long)(int)(_errF); \
florian654b5422012-11-18 00:36:15 +0000186 const char* _errstr = lame_strerror(_err); \
sewardjb4112022007-11-09 22:49:28 +0000187 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
sewardjc02f6c42013-10-14 13:51:25 +0000203/* A standalone memcmp. */
204__attribute__((noinline))
205static int my_memcmp ( const void* ptr1, const void* ptr2, size_t size)
206{
florian8eebf232014-09-18 18:35:47 +0000207 const unsigned char* uchar_ptr1 = (const unsigned char*) ptr1;
208 const unsigned char* uchar_ptr2 = (const unsigned char*) ptr2;
sewardjc02f6c42013-10-14 13:51:25 +0000209 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}
sewardjb4112022007-11-09 22:49:28 +0000216
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) */
florian654b5422012-11-18 00:36:15 +0000221static const HChar* lame_strerror ( long err )
sewardjc02f6c42013-10-14 13:51:25 +0000222{
223 switch (err) {
sewardjb4112022007-11-09 22:49:28 +0000224 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 */
sewardj8eb8bab2015-07-21 14:44:28 +0000244 case ETIME: return "ETIME: Timer expired";
245 default: return "hg_intercepts.c: lame_strerror(): "
sewardjb4112022007-11-09 22:49:28 +0000246 "unhandled case -- please fix me!";
247 }
248}
249
sewardj8eb8bab2015-07-21 14:44:28 +0000250#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 */
290typedef int (*hg_rtld_guard_fn)(int flags);
291static hg_rtld_guard_fn hg_rtld_bind_guard = NULL;
292static hg_rtld_guard_fn hg_rtld_bind_clear = NULL;
293
294static void hg_init(void) __attribute__((constructor));
295static 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 */
311static 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
318static 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 */
329void I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr);
330void 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
sewardjb4112022007-11-09 22:49:28 +0000359
360/*----------------------------------------------------------------*/
361/*--- pthread_create, pthread_join, pthread_exit ---*/
362/*----------------------------------------------------------------*/
363
sewardjb4112022007-11-09 22:49:28 +0000364static void* mythread_wrapper ( void* xargsV )
365{
bart31277bf2008-07-29 17:04:31 +0000366 volatile Word* xargs = (volatile Word*) xargsV;
sewardjb4112022007-11-09 22:49:28 +0000367 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. */
sewardj8eb8bab2015-07-21 14:44:28 +0000371 DO_CREQ_v_W(_VG_USERREQ__HG_SET_MY_PTHREAD_T, CREQ_PTHREAD_T, me);
sewardjb4112022007-11-09 22:49:28 +0000372 /* 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
sewardjf38a74e2010-04-12 19:53:05 +0000376 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. */
sewardjb4112022007-11-09 22:49:28 +0000387 xargs[2] = 0;
388 /* Now we can no longer safely use xargs[]. */
389 return (void*) fn( (void*)arg );
390}
391
sewardj1c147ff2009-07-26 19:52:06 +0000392//-----------------------------------------------------------
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)
njnf76d27a2009-05-28 01:53:07 +0000398//
sewardj28a7f7d2009-07-26 20:15:37 +0000399/* ensure this has its own frame, so as to make it more distinguishable
400 in suppressions */
401__attribute__((noinline))
njnf76d27a2009-05-28 01:53:07 +0000402static int pthread_create_WRK(pthread_t *thread, const pthread_attr_t *attr,
403 void *(*start) (void *), void *arg)
sewardjb4112022007-11-09 22:49:28 +0000404{
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 */
sewardjf38a74e2010-04-12 19:53:05 +0000416 /* 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));
sewardjb4112022007-11-09 22:49:28 +0000424
sewardj8eb8bab2015-07-21 14:44:28 +0000425 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_BEGIN,
426 0, 0, 0, 0, 0);
sewardjb4112022007-11-09 22:49:28 +0000427 CALL_FN_W_WWWW(ret, fn, thread,attr,mythread_wrapper,&xargs[0]);
sewardj8eb8bab2015-07-21 14:44:28 +0000428 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_END,
429 0, 0, 0, 0, 0);
sewardjb4112022007-11-09 22:49:28 +0000430
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) {
sewardjeafad3b2007-11-18 01:16:52 +0000435 /* 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();
sewardjb4112022007-11-09 22:49:28 +0000442 }
443 } else {
444 DO_PthAPIerror( "pthread_create", ret );
445 }
446
sewardjf38a74e2010-04-12 19:53:05 +0000447 /* Reenable checking on the area previously used to communicate
448 with the child. */
449 VALGRIND_HG_ENABLE_CHECKING(&xargs, sizeof(xargs));
450
sewardjb4112022007-11-09 22:49:28 +0000451 if (TRACE_PTH_FNS) {
452 fprintf(stderr, " :: pth_create -> %d >>\n", ret);
453 }
454 return ret;
455}
sewardj1c147ff2009-07-26 19:52:06 +0000456#if defined(VGO_linux)
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)
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 }
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 }
sewardj8eb8bab2015-07-21 14:44:28 +0000474#elif defined(VGO_solaris)
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 }
sewardj1c147ff2009-07-26 19:52:06 +0000480#else
481# error "Unsupported OS"
482#endif
sewardjb4112022007-11-09 22:49:28 +0000483
sewardj8eb8bab2015-07-21 14:44:28 +0000484#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))
490static 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}
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
sewardj1c147ff2009-07-26 19:52:06 +0000537
538//-----------------------------------------------------------
539// glibc: pthread_join
540// darwin: pthread_join
541// darwin: pthread_join$NOCANCEL$UNIX2003
542// darwin pthread_join$UNIX2003
florian31014da2011-09-26 00:29:44 +0000543__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +0000544static int pthread_join_WRK(pthread_t thread, void** value_pointer)
sewardjb4112022007-11-09 22:49:28 +0000545{
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*/) {
sewardj8eb8bab2015-07-21 14:44:28 +0000559 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST, CREQ_PTHREAD_T, thread);
sewardjb4112022007-11-09 22:49:28 +0000560 } 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}
sewardj1c147ff2009-07-26 19:52:06 +0000569#if defined(VGO_linux)
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)
575 PTH_FUNC(int, pthreadZujoinZa, // pthread_join*
576 pthread_t thread, void** value_pointer) {
577 return pthread_join_WRK(thread, value_pointer);
578 }
sewardj8eb8bab2015-07-21 14:44:28 +0000579#elif defined(VGO_solaris)
580 PTH_FUNC(int, pthreadZujoin, // pthread_join
581 pthread_t thread, void** value_pointer) {
582 return pthread_join_WRK(thread, value_pointer);
583 }
sewardj1c147ff2009-07-26 19:52:06 +0000584#else
585# error "Unsupported OS"
586#endif
587
sewardjb4112022007-11-09 22:49:28 +0000588
589/* Behaviour of pthread_join on NPTL:
590
591Me:
592I 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
602I believe this is true based on the following analysis of
603glibc-2.5 sources. However am not 100% sure and would appreciate
604confirmation.
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
622Drepper:
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.
626That's the key. The kernel resets the TID field after the thread is
627done. No way the joiner can return before the thread is gone.
628*/
629
sewardj8eb8bab2015-07-21 14:44:28 +0000630#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))
638static 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}
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
philipped40aff52014-06-16 20:00:14 +0000667//-----------------------------------------------------------
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.
Elliott Hughesed398002017-06-21 14:41:24 -0700676// procedure Master_Hook
677// (Dependent : Task_Id;
678// Parent : Task_Id;
679// Master_Level : Integer);
680// where type Task_Id is access all Ada_Task_Control_Block;
philipped40aff52014-06-16 20:00:14 +0000681// System.Tasking.Debug.Master_Hook is called by a task Dependent to
682// indicate that its master is identified by master+master_level.
683void I_WRAP_SONAME_FNNAME_ZU
684 (Za,
685 system__tasking__debug__master_hook)
686 (void *dependent, void *master, int master_level);
687void I_WRAP_SONAME_FNNAME_ZU
688 (Za,
689 system__tasking__debug__master_hook)
690 (void *dependent, void *master, int master_level)
691{
692 OrigFn fn;
693 VALGRIND_GET_ORIG_FN(fn);
694 if (TRACE_GNAT_FNS) {
695 fprintf(stderr, "<< GNAT master_hook wrapper "
696 "dependent %p master %p master_level %d\n",
697 dependent, master, master_level); fflush(stderr);
698 }
699
700 // We call the wrapped function, even if it is a null body.
701 CALL_FN_v_WWW(fn, dependent, master, master_level);
702
703 DO_CREQ_v_WWW(_VG_USERREQ__HG_GNAT_MASTER_HOOK,
704 void*,dependent, void*,master,
705 Word, (Word)master_level);
706
707 if (TRACE_GNAT_FNS) {
708 fprintf(stderr, " :: GNAT master_hook >>\n");
709 }
710}
711
712// System.Tasking.Debug.Master_Completed_Hook is called by a task to
713// indicate that it has completed a master.
Elliott Hughesed398002017-06-21 14:41:24 -0700714// procedure Master_Completed_Hook
715// (Self_ID : Task_Id;
716// Master_Level : Integer);
717// where type Task_Id is access all Ada_Task_Control_Block;
philipped40aff52014-06-16 20:00:14 +0000718// This indicates that all its Dependent tasks (that identified themselves
719// with the Master_Hook call) are terminated. Helgrind can consider
720// at this point that the equivalent of a 'pthread_join' has been done
721// between self_id and all dependent tasks at master_level.
722void I_WRAP_SONAME_FNNAME_ZU
723 (Za,
724 system__tasking__debug__master_completed_hook)
725 (void *self_id, int master_level);
726void I_WRAP_SONAME_FNNAME_ZU
727 (Za,
728 system__tasking__debug__master_completed_hook)
729 (void *self_id, int master_level)
730{
731 OrigFn fn;
732 VALGRIND_GET_ORIG_FN(fn);
733 if (TRACE_GNAT_FNS) {
734 fprintf(stderr, "<< GNAT master_completed_hook wrapper "
735 "self_id %p master_level %d\n",
736 self_id, master_level); fflush(stderr);
737 }
738
739 // We call the wrapped function, even if it is a null body.
740 CALL_FN_v_WW(fn, self_id, master_level);
741
742 DO_CREQ_v_WW(_VG_USERREQ__HG_GNAT_MASTER_COMPLETED_HOOK,
743 void*,self_id, Word,(Word)master_level);
744
745 if (TRACE_GNAT_FNS) {
746 fprintf(stderr, " :: GNAT master_completed_hook >>\n");
747 }
748}
sewardjb4112022007-11-09 22:49:28 +0000749
750/*----------------------------------------------------------------*/
751/*--- pthread_mutex_t functions ---*/
752/*----------------------------------------------------------------*/
753
754/* Handled: pthread_mutex_init pthread_mutex_destroy
755 pthread_mutex_lock
756 pthread_mutex_trylock pthread_mutex_timedlock
757 pthread_mutex_unlock
sewardjb4112022007-11-09 22:49:28 +0000758*/
759
sewardj1c147ff2009-07-26 19:52:06 +0000760//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +0000761#if !defined(VGO_solaris)
sewardj1c147ff2009-07-26 19:52:06 +0000762// glibc: pthread_mutex_init
763// darwin: pthread_mutex_init
sewardjb4112022007-11-09 22:49:28 +0000764PTH_FUNC(int, pthreadZumutexZuinit, // pthread_mutex_init
765 pthread_mutex_t *mutex,
766 pthread_mutexattr_t* attr)
767{
768 int ret;
769 long mbRec;
770 OrigFn fn;
771 VALGRIND_GET_ORIG_FN(fn);
772 if (TRACE_PTH_FNS) {
773 fprintf(stderr, "<< pthread_mxinit %p", mutex); fflush(stderr);
774 }
775
776 mbRec = 0;
777 if (attr) {
778 int ty, zzz;
779 zzz = pthread_mutexattr_gettype(attr, &ty);
780 if (zzz == 0 && ty == PTHREAD_MUTEX_RECURSIVE)
781 mbRec = 1;
782 }
783
784 CALL_FN_W_WW(ret, fn, mutex,attr);
785
786 if (ret == 0 /*success*/) {
787 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
788 pthread_mutex_t*,mutex, long,mbRec);
789 } else {
790 DO_PthAPIerror( "pthread_mutex_init", ret );
791 }
792
793 if (TRACE_PTH_FNS) {
794 fprintf(stderr, " :: mxinit -> %d >>\n", ret);
795 }
796 return ret;
797}
798
sewardj8eb8bab2015-07-21 14:44:28 +0000799#else /* VGO_solaris */
800
801// Solaris: mutex_init (pthread_mutex_init calls here)
802PTH_FUNC(int, mutexZuinit, // mutex_init
803 mutex_t *mutex, int type, void *arg)
804{
805 int ret;
806 long mbRec;
807 OrigFn fn;
808 VALGRIND_GET_ORIG_FN(fn);
809 if (TRACE_PTH_FNS) {
810 fprintf(stderr, "<< mxinit %p", mutex); fflush(stderr);
811 }
812
813 mbRec = ((type & LOCK_RECURSIVE) != 0) ? 1 : 0;
814
815 CALL_FN_W_WWW(ret, fn, mutex, type, arg);
816
817 if (ret == 0 /*success*/) {
818 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
819 mutex_t *, mutex, long, mbRec);
820 } else {
821 DO_PthAPIerror("mutex_init", ret);
822 }
823
824 if (TRACE_PTH_FNS) {
825 fprintf(stderr, " :: mxinit -> %d >>\n", ret);
826 }
827 return ret;
828}
829#endif /* VGO_solaris */
830
sewardjb4112022007-11-09 22:49:28 +0000831
sewardj1c147ff2009-07-26 19:52:06 +0000832//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +0000833// glibc: pthread_mutex_destroy
834// darwin: pthread_mutex_destroy
835// Solaris: mutex_destroy (pthread_mutex_destroy is a weak alias)
836__attribute__((noinline))
837static int mutex_destroy_WRK(pthread_mutex_t *mutex)
sewardjb4112022007-11-09 22:49:28 +0000838{
839 int ret;
sewardjc02f6c42013-10-14 13:51:25 +0000840 unsigned long mutex_is_init;
sewardjb4112022007-11-09 22:49:28 +0000841 OrigFn fn;
sewardjc02f6c42013-10-14 13:51:25 +0000842
sewardjb4112022007-11-09 22:49:28 +0000843 VALGRIND_GET_ORIG_FN(fn);
844 if (TRACE_PTH_FNS) {
845 fprintf(stderr, "<< pthread_mxdestroy %p", mutex); fflush(stderr);
846 }
847
sewardjc02f6c42013-10-14 13:51:25 +0000848 if (mutex != NULL) {
849 static const pthread_mutex_t mutex_init = PTHREAD_MUTEX_INITIALIZER;
850 mutex_is_init = my_memcmp(mutex, &mutex_init, sizeof(*mutex)) == 0;
851 } else {
852 mutex_is_init = 0;
853 }
854
855 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
856 pthread_mutex_t*, mutex, unsigned long, mutex_is_init);
sewardjb4112022007-11-09 22:49:28 +0000857
858 CALL_FN_W_W(ret, fn, mutex);
859
860 if (ret != 0) {
861 DO_PthAPIerror( "pthread_mutex_destroy", ret );
862 }
863
864 if (TRACE_PTH_FNS) {
865 fprintf(stderr, " :: mxdestroy -> %d >>\n", ret);
866 }
867 return ret;
868}
869
sewardj8eb8bab2015-07-21 14:44:28 +0000870#if defined(VGO_linux) || defined(VGO_darwin)
871 PTH_FUNC(int, pthreadZumutexZudestroy, // pthread_mutex_destroy
872 pthread_mutex_t *mutex) {
873 return mutex_destroy_WRK(mutex);
874 }
875#elif defined(VGO_solaris)
876 PTH_FUNC(int, mutexZudestroy, // mutex_destroy
877 pthread_mutex_t *mutex) {
878 return mutex_destroy_WRK(mutex);
879 }
880#else
881# error "Unsupported OS"
882#endif
883
sewardjb4112022007-11-09 22:49:28 +0000884
sewardj1c147ff2009-07-26 19:52:06 +0000885//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +0000886// glibc: pthread_mutex_lock
887// darwin: pthread_mutex_lock
888// Solaris: mutex_lock (pthread_mutex_lock is a weak alias)
889__attribute__((noinline))
890static int mutex_lock_WRK(pthread_mutex_t *mutex)
sewardjb4112022007-11-09 22:49:28 +0000891{
892 int ret;
893 OrigFn fn;
894 VALGRIND_GET_ORIG_FN(fn);
895 if (TRACE_PTH_FNS) {
896 fprintf(stderr, "<< pthread_mxlock %p", mutex); fflush(stderr);
897 }
898
899 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
900 pthread_mutex_t*,mutex, long,0/*!isTryLock*/);
901
902 CALL_FN_W_W(ret, fn, mutex);
903
904 /* There's a hole here: libpthread now knows the lock is locked,
905 but the tool doesn't, so some other thread could run and detect
906 that the lock has been acquired by someone (this thread). Does
907 this matter? Not sure, but I don't think so. */
908
sewardj8eb8bab2015-07-21 14:44:28 +0000909 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
910 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
911
912 if (ret != 0) {
sewardjb4112022007-11-09 22:49:28 +0000913 DO_PthAPIerror( "pthread_mutex_lock", ret );
914 }
915
916 if (TRACE_PTH_FNS) {
917 fprintf(stderr, " :: mxlock -> %d >>\n", ret);
918 }
919 return ret;
920}
921
sewardj8eb8bab2015-07-21 14:44:28 +0000922#if defined(VGO_linux) || defined(VGO_darwin)
923 PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock
924 pthread_mutex_t *mutex) {
925 return mutex_lock_WRK(mutex);
926 }
927#elif defined(VGO_solaris)
928 PTH_FUNC(int, mutexZulock, // mutex_lock
929 pthread_mutex_t *mutex) {
930 return mutex_lock_WRK(mutex);
931 }
932#else
933# error "Unsupported OS"
934#endif
935
936#if defined(VGO_solaris)
937/* Internal to libc. Mutex is usually initialized only implicitly,
938 * by zeroing mutex_t structure.
939 */
940__attribute__((noinline))
941PTH_FUNC(void, lmutexZulock, // lmutex_lock
942 mutex_t *mutex)
943{
944 OrigFn fn;
945 VALGRIND_GET_ORIG_FN(fn);
946 if (TRACE_PTH_FNS) {
947 fprintf(stderr, "<< lmxlock %p", mutex); fflush(stderr);
948 }
949
950 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
951 mutex_t *, mutex, long, 0 /*!isTryLock*/);
952 CALL_FN_v_W(fn, mutex);
953 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
954 mutex_t *, mutex, long, True);
955
956 if (TRACE_PTH_FNS) {
957 fprintf(stderr, " :: lmxlock >>\n");
958 }
959}
960#endif /* VGO_solaris */
961
sewardjb4112022007-11-09 22:49:28 +0000962
sewardj1c147ff2009-07-26 19:52:06 +0000963//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +0000964// glibc: pthread_mutex_trylock
965// darwin: pthread_mutex_trylock
966// Solaris: mutex_trylock (pthread_mutex_trylock is a weak alias)
sewardj1c147ff2009-07-26 19:52:06 +0000967//
sewardjb4112022007-11-09 22:49:28 +0000968// pthread_mutex_trylock. The handling needed here is very similar
969// to that for pthread_mutex_lock, except that we need to tell
970// the pre-lock creq that this is a trylock-style operation, and
971// therefore not to complain if the lock is nonrecursive and
972// already locked by this thread -- because then it'll just fail
973// immediately with EBUSY.
sewardj8eb8bab2015-07-21 14:44:28 +0000974__attribute__((noinline))
975static int mutex_trylock_WRK(pthread_mutex_t *mutex)
sewardjb4112022007-11-09 22:49:28 +0000976{
977 int ret;
978 OrigFn fn;
979 VALGRIND_GET_ORIG_FN(fn);
980 if (TRACE_PTH_FNS) {
981 fprintf(stderr, "<< pthread_mxtrylock %p", mutex); fflush(stderr);
982 }
983
984 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
985 pthread_mutex_t*,mutex, long,1/*isTryLock*/);
986
987 CALL_FN_W_W(ret, fn, mutex);
988
989 /* There's a hole here: libpthread now knows the lock is locked,
990 but the tool doesn't, so some other thread could run and detect
991 that the lock has been acquired by someone (this thread). Does
992 this matter? Not sure, but I don't think so. */
993
sewardj8eb8bab2015-07-21 14:44:28 +0000994 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
995 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
996
997 if (ret != 0) {
sewardjb4112022007-11-09 22:49:28 +0000998 if (ret != EBUSY)
999 DO_PthAPIerror( "pthread_mutex_trylock", ret );
1000 }
1001
1002 if (TRACE_PTH_FNS) {
1003 fprintf(stderr, " :: mxtrylock -> %d >>\n", ret);
1004 }
1005 return ret;
1006}
1007
sewardj8eb8bab2015-07-21 14:44:28 +00001008#if defined(VGO_linux) || defined(VGO_darwin)
1009 PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock
1010 pthread_mutex_t *mutex) {
1011 return mutex_trylock_WRK(mutex);
1012 }
1013#elif defined(VGO_solaris)
1014 PTH_FUNC(int, mutexZutrylock, // mutex_trylock
1015 pthread_mutex_t *mutex) {
1016 return mutex_trylock_WRK(mutex);
1017 }
1018#else
1019# error "Unsupported OS"
1020#endif
1021
sewardjb4112022007-11-09 22:49:28 +00001022
sewardj1c147ff2009-07-26 19:52:06 +00001023//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00001024// glibc: pthread_mutex_timedlock
1025// darwin: (doesn't appear to exist)
1026// Solaris: pthread_mutex_timedlock
sewardj1c147ff2009-07-26 19:52:06 +00001027//
sewardjb4112022007-11-09 22:49:28 +00001028// pthread_mutex_timedlock. Identical logic to pthread_mutex_trylock.
sewardj8eb8bab2015-07-21 14:44:28 +00001029__attribute__((noinline))
1030static int mutex_timedlock_WRK(pthread_mutex_t *mutex,
1031 void *timeout)
sewardjb4112022007-11-09 22:49:28 +00001032{
1033 int ret;
1034 OrigFn fn;
1035 VALGRIND_GET_ORIG_FN(fn);
1036 if (TRACE_PTH_FNS) {
1037 fprintf(stderr, "<< pthread_mxtimedlock %p %p", mutex, timeout);
1038 fflush(stderr);
1039 }
1040
1041 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
1042 pthread_mutex_t*,mutex, long,1/*isTryLock-ish*/);
1043
1044 CALL_FN_W_WW(ret, fn, mutex,timeout);
1045
1046 /* There's a hole here: libpthread now knows the lock is locked,
1047 but the tool doesn't, so some other thread could run and detect
1048 that the lock has been acquired by someone (this thread). Does
1049 this matter? Not sure, but I don't think so. */
1050
sewardj8eb8bab2015-07-21 14:44:28 +00001051 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1052 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
1053
1054 if (ret != 0) {
sewardjb4112022007-11-09 22:49:28 +00001055 if (ret != ETIMEDOUT)
1056 DO_PthAPIerror( "pthread_mutex_timedlock", ret );
1057 }
1058
1059 if (TRACE_PTH_FNS) {
1060 fprintf(stderr, " :: mxtimedlock -> %d >>\n", ret);
1061 }
1062 return ret;
1063}
1064
sewardj8eb8bab2015-07-21 14:44:28 +00001065PTH_FUNC(int, pthreadZumutexZutimedlock, // pthread_mutex_timedlock
1066 pthread_mutex_t *mutex,
1067 void *timeout) {
1068 return mutex_timedlock_WRK(mutex, timeout);
1069}
1070#if defined(VGO_solaris)
1071PTH_FUNC(int, pthreadZumutexZureltimedlock, // pthread_mutex_reltimedlock
1072 pthread_mutex_t *mutex,
1073 void *timeout) {
1074 return mutex_timedlock_WRK(mutex, timeout);
1075}
1076#endif
1077
sewardjb4112022007-11-09 22:49:28 +00001078
sewardj1c147ff2009-07-26 19:52:06 +00001079//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00001080// glibc: pthread_mutex_unlock
1081// darwin: pthread_mutex_unlock
1082// Solaris: mutex_unlock (pthread_mutex_unlock is a weak alias)
1083__attribute__((noinline))
1084static int mutex_unlock_WRK(pthread_mutex_t *mutex)
sewardjb4112022007-11-09 22:49:28 +00001085{
1086 int ret;
1087 OrigFn fn;
1088 VALGRIND_GET_ORIG_FN(fn);
1089
1090 if (TRACE_PTH_FNS) {
1091 fprintf(stderr, "<< pthread_mxunlk %p", mutex); fflush(stderr);
1092 }
1093
1094 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1095 pthread_mutex_t*,mutex);
1096
1097 CALL_FN_W_W(ret, fn, mutex);
1098
sewardj8eb8bab2015-07-21 14:44:28 +00001099 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
1100 pthread_mutex_t*,mutex);
1101
1102 if (ret != 0) {
sewardjb4112022007-11-09 22:49:28 +00001103 DO_PthAPIerror( "pthread_mutex_unlock", ret );
1104 }
1105
1106 if (TRACE_PTH_FNS) {
1107 fprintf(stderr, " mxunlk -> %d >>\n", ret);
1108 }
1109 return ret;
1110}
1111
sewardj8eb8bab2015-07-21 14:44:28 +00001112#if defined(VGO_linux) || defined(VGO_darwin)
1113 PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock
1114 pthread_mutex_t *mutex) {
1115 return mutex_unlock_WRK(mutex);
1116 }
1117#elif defined(VGO_solaris)
1118 PTH_FUNC(int, mutexZuunlock, // mutex_unlock
1119 pthread_mutex_t *mutex) {
1120 return mutex_unlock_WRK(mutex);
1121 }
1122#else
1123# error "Unsupported OS"
1124#endif
1125
1126
1127#if defined(VGO_solaris)
1128/* Internal to libc. */
1129__attribute__((noinline))
1130PTH_FUNC(void, lmutexZuunlock, // lmutex_unlock
1131 mutex_t *mutex)
1132{
1133 OrigFn fn;
1134 VALGRIND_GET_ORIG_FN(fn);
1135
1136 if (TRACE_PTH_FNS) {
1137 fprintf(stderr, "<< lmxunlk %p", mutex); fflush(stderr);
1138 }
1139
1140 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1141 mutex_t *, mutex);
1142 CALL_FN_v_W(fn, mutex);
1143 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
1144 mutex_t*, mutex);
1145
1146 if (TRACE_PTH_FNS) {
1147 fprintf(stderr, " lmxunlk >>\n");
1148 }
1149}
1150#endif /* VGO_solaris */
1151
sewardjb4112022007-11-09 22:49:28 +00001152
1153/*----------------------------------------------------------------*/
1154/*--- pthread_cond_t functions ---*/
1155/*----------------------------------------------------------------*/
1156
1157/* Handled: pthread_cond_wait pthread_cond_timedwait
1158 pthread_cond_signal pthread_cond_broadcast
philippe19dfe032013-03-24 20:10:23 +00001159 pthread_cond_init
sewardjf98e1c02008-10-25 16:22:41 +00001160 pthread_cond_destroy
sewardjb4112022007-11-09 22:49:28 +00001161*/
1162
sewardj1c147ff2009-07-26 19:52:06 +00001163//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00001164// glibc: pthread_cond_wait@GLIBC_2.2.5
1165// glibc: pthread_cond_wait@@GLIBC_2.3.2
1166// darwin: pthread_cond_wait
1167// darwin: pthread_cond_wait$NOCANCEL$UNIX2003
1168// darwin: pthread_cond_wait$UNIX2003
1169// Solaris: cond_wait (pthread_cond_wait is built atop of cond_wait)
sewardj1c147ff2009-07-26 19:52:06 +00001170//
florian31014da2011-09-26 00:29:44 +00001171__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +00001172static int pthread_cond_wait_WRK(pthread_cond_t* cond,
1173 pthread_mutex_t* mutex)
sewardjb4112022007-11-09 22:49:28 +00001174{
1175 int ret;
1176 OrigFn fn;
1177 unsigned long mutex_is_valid;
1178
1179 VALGRIND_GET_ORIG_FN(fn);
1180
1181 if (TRACE_PTH_FNS) {
1182 fprintf(stderr, "<< pthread_cond_wait %p %p", cond, mutex);
1183 fflush(stderr);
1184 }
1185
1186 /* Tell the tool a cond-wait is about to happen, so it can check
1187 for bogus argument values. In return it tells us whether it
1188 thinks the mutex is valid or not. */
1189 DO_CREQ_W_WW(mutex_is_valid,
1190 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
1191 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
1192 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
1193
1194 /* Tell the tool we're about to drop the mutex. This reflects the
1195 fact that in a cond_wait, we show up holding the mutex, and the
1196 call atomically drops the mutex and waits for the cv to be
1197 signalled. */
1198 if (mutex_is_valid) {
1199 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1200 pthread_mutex_t*,mutex);
1201 }
1202
1203 CALL_FN_W_WW(ret, fn, cond,mutex);
1204
sewardj8eb8bab2015-07-21 14:44:28 +00001205 /* this conditional look stupid, but compare w/ same logic for
sewardjb4112022007-11-09 22:49:28 +00001206 pthread_cond_timedwait below */
sewardj8eb8bab2015-07-21 14:44:28 +00001207 if (mutex_is_valid) {
1208 /* and now we have the mutex again if (ret == 0) */
1209 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1210 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
sewardjb4112022007-11-09 22:49:28 +00001211 }
1212
sewardj8eb8bab2015-07-21 14:44:28 +00001213 DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
1214 pthread_cond_t*,cond, pthread_mutex_t*,mutex, long,0,
1215 long, (ret == 0 && mutex_is_valid) ? True : False);
sewardjb4112022007-11-09 22:49:28 +00001216
1217 if (ret != 0) {
1218 DO_PthAPIerror( "pthread_cond_wait", ret );
1219 }
1220
1221 if (TRACE_PTH_FNS) {
1222 fprintf(stderr, " cowait -> %d >>\n", ret);
1223 }
1224
1225 return ret;
1226}
sewardj1c147ff2009-07-26 19:52:06 +00001227#if defined(VGO_linux)
1228 PTH_FUNC(int, pthreadZucondZuwaitZAZa, // pthread_cond_wait@*
1229 pthread_cond_t* cond, pthread_mutex_t* mutex) {
1230 return pthread_cond_wait_WRK(cond, mutex);
1231 }
1232#elif defined(VGO_darwin)
1233 PTH_FUNC(int, pthreadZucondZuwaitZa, // pthread_cond_wait*
1234 pthread_cond_t* cond, pthread_mutex_t* mutex) {
1235 return pthread_cond_wait_WRK(cond, mutex);
1236 }
sewardj8eb8bab2015-07-21 14:44:28 +00001237#elif defined(VGO_solaris)
1238 PTH_FUNC(int, condZuwait, // cond_wait
1239 pthread_cond_t *cond, pthread_mutex_t *mutex) {
1240 return pthread_cond_wait_WRK(cond, mutex);
1241 }
sewardj1c147ff2009-07-26 19:52:06 +00001242#else
1243# error "Unsupported OS"
1244#endif
sewardjb4112022007-11-09 22:49:28 +00001245
1246
sewardj1c147ff2009-07-26 19:52:06 +00001247//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00001248// glibc: pthread_cond_timedwait@@GLIBC_2.3.2
1249// glibc: pthread_cond_timedwait@GLIBC_2.2.5
1250// glibc: pthread_cond_timedwait@GLIBC_2.0
1251// darwin: pthread_cond_timedwait
1252// darwin: pthread_cond_timedwait$NOCANCEL$UNIX2003
1253// darwin: pthread_cond_timedwait$UNIX2003
1254// darwin: pthread_cond_timedwait_relative_np (trapped)
1255// Solaris: cond_timedwait (pthread_cond_timedwait is built on cond_timedwait)
1256// Solaris: cond_reltimedwait (pthread_cond_reltimedwait_np is built on this)
sewardj1c147ff2009-07-26 19:52:06 +00001257//
florian31014da2011-09-26 00:29:44 +00001258__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +00001259static int pthread_cond_timedwait_WRK(pthread_cond_t* cond,
1260 pthread_mutex_t* mutex,
sewardj8eb8bab2015-07-21 14:44:28 +00001261 struct timespec* abstime,
1262 int timeout_error)
sewardjb4112022007-11-09 22:49:28 +00001263{
1264 int ret;
1265 OrigFn fn;
1266 unsigned long mutex_is_valid;
sewardj6aeadaa2011-10-19 05:41:34 +00001267 Bool abstime_is_valid;
sewardjb4112022007-11-09 22:49:28 +00001268 VALGRIND_GET_ORIG_FN(fn);
1269
1270 if (TRACE_PTH_FNS) {
1271 fprintf(stderr, "<< pthread_cond_timedwait %p %p %p",
1272 cond, mutex, abstime);
1273 fflush(stderr);
1274 }
1275
1276 /* Tell the tool a cond-wait is about to happen, so it can check
1277 for bogus argument values. In return it tells us whether it
1278 thinks the mutex is valid or not. */
1279 DO_CREQ_W_WW(mutex_is_valid,
1280 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
1281 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
1282 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
1283
sewardj6aeadaa2011-10-19 05:41:34 +00001284 abstime_is_valid = abstime->tv_nsec >= 0 && abstime->tv_nsec < 1000000000;
1285
sewardjb4112022007-11-09 22:49:28 +00001286 /* Tell the tool we're about to drop the mutex. This reflects the
1287 fact that in a cond_wait, we show up holding the mutex, and the
1288 call atomically drops the mutex and waits for the cv to be
1289 signalled. */
sewardj6aeadaa2011-10-19 05:41:34 +00001290 if (mutex_is_valid && abstime_is_valid) {
sewardjb4112022007-11-09 22:49:28 +00001291 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1292 pthread_mutex_t*,mutex);
1293 }
1294
1295 CALL_FN_W_WWW(ret, fn, cond,mutex,abstime);
1296
sewardj8eb8bab2015-07-21 14:44:28 +00001297 if (mutex_is_valid && !abstime_is_valid && ret != EINVAL) {
sewardj6aeadaa2011-10-19 05:41:34 +00001298 DO_PthAPIerror("Bug in libpthread: pthread_cond_timedwait "
1299 "invalid abstime did not cause"
1300 " EINVAL", ret);
1301 }
1302
sewardj8eb8bab2015-07-21 14:44:28 +00001303 if (mutex_is_valid && abstime_is_valid) {
1304 /* and now we have the mutex again if (ret == 0 || ret == timeout) */
1305 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1306 pthread_mutex_t *, mutex,
1307 long, (ret == 0 || ret == timeout_error) ? True : False);
sewardjb4112022007-11-09 22:49:28 +00001308 }
1309
sewardj8eb8bab2015-07-21 14:44:28 +00001310 DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
1311 pthread_cond_t*,cond, pthread_mutex_t*,mutex,
1312 long,ret == timeout_error,
1313 long, (ret == 0 || ret == timeout_error) && mutex_is_valid
1314 ? True : False);
sewardjb4112022007-11-09 22:49:28 +00001315
sewardj8eb8bab2015-07-21 14:44:28 +00001316 if (ret != 0 && ret != timeout_error) {
sewardjb4112022007-11-09 22:49:28 +00001317 DO_PthAPIerror( "pthread_cond_timedwait", ret );
1318 }
1319
1320 if (TRACE_PTH_FNS) {
1321 fprintf(stderr, " cotimedwait -> %d >>\n", ret);
1322 }
1323
1324 return ret;
1325}
sewardj1c147ff2009-07-26 19:52:06 +00001326#if defined(VGO_linux)
1327 PTH_FUNC(int, pthreadZucondZutimedwaitZAZa, // pthread_cond_timedwait@*
1328 pthread_cond_t* cond, pthread_mutex_t* mutex,
1329 struct timespec* abstime) {
sewardj8eb8bab2015-07-21 14:44:28 +00001330 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
sewardj1c147ff2009-07-26 19:52:06 +00001331 }
1332#elif defined(VGO_darwin)
1333 PTH_FUNC(int, pthreadZucondZutimedwait, // pthread_cond_timedwait
1334 pthread_cond_t* cond, pthread_mutex_t* mutex,
1335 struct timespec* abstime) {
sewardj8eb8bab2015-07-21 14:44:28 +00001336 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
sewardj1c147ff2009-07-26 19:52:06 +00001337 }
1338 PTH_FUNC(int, pthreadZucondZutimedwaitZDZa, // pthread_cond_timedwait$*
1339 pthread_cond_t* cond, pthread_mutex_t* mutex,
1340 struct timespec* abstime) {
sewardj8eb8bab2015-07-21 14:44:28 +00001341 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
sewardj1c147ff2009-07-26 19:52:06 +00001342 }
1343 PTH_FUNC(int, pthreadZucondZutimedwaitZuZa, // pthread_cond_timedwait_*
1344 pthread_cond_t* cond, pthread_mutex_t* mutex,
1345 struct timespec* abstime) {
1346 assert(0);
1347 }
sewardj8eb8bab2015-07-21 14:44:28 +00001348#elif defined(VGO_solaris)
1349 PTH_FUNC(int, condZutimedwait, // cond_timedwait
1350 pthread_cond_t *cond, pthread_mutex_t *mutex,
1351 struct timespec *abstime) {
1352 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIME);
1353 }
1354 PTH_FUNC(int, condZureltimedwait, // cond_reltimedwait
1355 pthread_cond_t *cond, pthread_mutex_t *mutex,
1356 struct timespec *reltime) {
1357 return pthread_cond_timedwait_WRK(cond, mutex, reltime, ETIME);
1358 }
sewardj1c147ff2009-07-26 19:52:06 +00001359#else
1360# error "Unsupported OS"
1361#endif
sewardjb4112022007-11-09 22:49:28 +00001362
1363
sewardj1c147ff2009-07-26 19:52:06 +00001364//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00001365// glibc: pthread_cond_signal@GLIBC_2.0
1366// glibc: pthread_cond_signal@GLIBC_2.2.5
1367// glibc: pthread_cond_signal@@GLIBC_2.3.2
1368// darwin: pthread_cond_signal
1369// darwin: pthread_cond_signal_thread_np (don't intercept this)
1370// Solaris: cond_signal (pthread_cond_signal is a weak alias)
sewardj1c147ff2009-07-26 19:52:06 +00001371//
florian31014da2011-09-26 00:29:44 +00001372__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +00001373static int pthread_cond_signal_WRK(pthread_cond_t* cond)
sewardjb4112022007-11-09 22:49:28 +00001374{
1375 int ret;
1376 OrigFn fn;
1377 VALGRIND_GET_ORIG_FN(fn);
1378
1379 if (TRACE_PTH_FNS) {
1380 fprintf(stderr, "<< pthread_cond_signal %p", cond);
1381 fflush(stderr);
1382 }
1383
1384 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE,
1385 pthread_cond_t*,cond);
1386
1387 CALL_FN_W_W(ret, fn, cond);
1388
sewardj8eb8bab2015-07-21 14:44:28 +00001389 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_POST,
1390 pthread_cond_t*,cond);
1391
sewardjb4112022007-11-09 22:49:28 +00001392 if (ret != 0) {
1393 DO_PthAPIerror( "pthread_cond_signal", ret );
1394 }
1395
1396 if (TRACE_PTH_FNS) {
1397 fprintf(stderr, " cosig -> %d >>\n", ret);
1398 }
1399
1400 return ret;
1401}
sewardj1c147ff2009-07-26 19:52:06 +00001402#if defined(VGO_linux)
1403 PTH_FUNC(int, pthreadZucondZusignalZAZa, // pthread_cond_signal@*
1404 pthread_cond_t* cond) {
1405 return pthread_cond_signal_WRK(cond);
1406 }
1407#elif defined(VGO_darwin)
1408 PTH_FUNC(int, pthreadZucondZusignal, // pthread_cond_signal
1409 pthread_cond_t* cond) {
1410 return pthread_cond_signal_WRK(cond);
1411 }
sewardj8eb8bab2015-07-21 14:44:28 +00001412#elif defined(VGO_solaris)
1413 PTH_FUNC(int, condZusignal, // cond_signal
1414 pthread_cond_t *cond) {
1415 return pthread_cond_signal_WRK(cond);
1416 }
sewardj1c147ff2009-07-26 19:52:06 +00001417#else
1418# error "Unsupported OS"
1419#endif
sewardjb4112022007-11-09 22:49:28 +00001420
1421
sewardj1c147ff2009-07-26 19:52:06 +00001422//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00001423// glibc: pthread_cond_broadcast@GLIBC_2.0
1424// glibc: pthread_cond_broadcast@GLIBC_2.2.5
1425// glibc: pthread_cond_broadcast@@GLIBC_2.3.2
1426// darwin: pthread_cond_broadcast
1427// Solaris: cond_broadcast (pthread_cond_broadcast is a weak alias)
sewardj1c147ff2009-07-26 19:52:06 +00001428//
sewardjb4112022007-11-09 22:49:28 +00001429// Note, this is pretty much identical, from a dependency-graph
1430// point of view, with cond_signal, so the code is duplicated.
1431// Maybe it should be commoned up.
sewardj1c147ff2009-07-26 19:52:06 +00001432//
florian31014da2011-09-26 00:29:44 +00001433__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +00001434static int pthread_cond_broadcast_WRK(pthread_cond_t* cond)
sewardjb4112022007-11-09 22:49:28 +00001435{
1436 int ret;
1437 OrigFn fn;
1438 VALGRIND_GET_ORIG_FN(fn);
1439
1440 if (TRACE_PTH_FNS) {
sewardj1c147ff2009-07-26 19:52:06 +00001441 fprintf(stderr, "<< pthread_cond_broadcast %p", cond);
sewardjb4112022007-11-09 22:49:28 +00001442 fflush(stderr);
1443 }
1444
1445 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE,
1446 pthread_cond_t*,cond);
1447
1448 CALL_FN_W_W(ret, fn, cond);
1449
sewardj8eb8bab2015-07-21 14:44:28 +00001450 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_POST,
1451 pthread_cond_t*,cond);
1452
sewardjb4112022007-11-09 22:49:28 +00001453 if (ret != 0) {
1454 DO_PthAPIerror( "pthread_cond_broadcast", ret );
1455 }
1456
1457 if (TRACE_PTH_FNS) {
1458 fprintf(stderr, " cobro -> %d >>\n", ret);
1459 }
1460
1461 return ret;
1462}
sewardj1c147ff2009-07-26 19:52:06 +00001463#if defined(VGO_linux)
1464 PTH_FUNC(int, pthreadZucondZubroadcastZAZa, // pthread_cond_broadcast@*
1465 pthread_cond_t* cond) {
1466 return pthread_cond_broadcast_WRK(cond);
1467 }
1468#elif defined(VGO_darwin)
1469 PTH_FUNC(int, pthreadZucondZubroadcast, // pthread_cond_broadcast
1470 pthread_cond_t* cond) {
1471 return pthread_cond_broadcast_WRK(cond);
1472 }
sewardj8eb8bab2015-07-21 14:44:28 +00001473#elif defined(VGO_solaris)
1474 PTH_FUNC(int, condZubroadcast, // cond_broadcast
1475 pthread_cond_t *cond) {
1476 return pthread_cond_broadcast_WRK(cond);
1477 }
sewardj1c147ff2009-07-26 19:52:06 +00001478#else
1479# error "Unsupported OS"
1480#endif
sewardjb4112022007-11-09 22:49:28 +00001481
sewardj8eb8bab2015-07-21 14:44:28 +00001482// glibc: pthread_cond_init@GLIBC_2.0
1483// glibc: pthread_cond_init@GLIBC_2.2.5
1484// glibc: pthread_cond_init@@GLIBC_2.3.2
1485// darwin: pthread_cond_init
1486// Solaris: cond_init (pthread_cond_init is built atop on this function)
philippe19dfe032013-03-24 20:10:23 +00001487// Easy way out: Handling of attr could have been messier.
1488// It turns out that pthread_cond_init under linux ignores
1489// all information in cond_attr, so do we.
1490// FIXME: MacOS X?
sewardj8eb8bab2015-07-21 14:44:28 +00001491#if !defined(VGO_solaris)
philippe19dfe032013-03-24 20:10:23 +00001492__attribute__((noinline))
1493static int pthread_cond_init_WRK(pthread_cond_t* cond, pthread_condattr_t *cond_attr)
1494{
1495 int ret;
1496 OrigFn fn;
1497 VALGRIND_GET_ORIG_FN(fn);
1498
1499 if (TRACE_PTH_FNS) {
1500 fprintf(stderr, "<< pthread_cond_init %p", cond);
1501 fflush(stderr);
1502 }
1503
1504 CALL_FN_W_WW(ret, fn, cond, cond_attr);
1505
1506 if (ret == 0) {
1507 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST,
1508 pthread_cond_t*,cond, pthread_condattr_t*, cond_attr);
1509 } else {
1510 DO_PthAPIerror( "pthread_cond_init", ret );
1511 }
1512
1513 if (TRACE_PTH_FNS) {
1514 fprintf(stderr, " coinit -> %d >>\n", ret);
1515 }
1516
1517 return ret;
1518}
1519#if defined(VGO_linux)
1520 PTH_FUNC(int, pthreadZucondZuinitZAZa, // pthread_cond_init@*
1521 pthread_cond_t* cond, pthread_condattr_t* cond_attr) {
1522 return pthread_cond_init_WRK(cond, cond_attr);
1523 }
1524#elif defined(VGO_darwin)
1525 PTH_FUNC(int, pthreadZucondZuinit, // pthread_cond_init
1526 pthread_cond_t* cond, pthread_condattr_t * cond_attr) {
1527 return pthread_cond_init_WRK(cond, cond_attr);
1528 }
1529#else
1530# error "Unsupported OS"
1531#endif
1532
sewardj8eb8bab2015-07-21 14:44:28 +00001533#else /* VGO_solaris */
1534__attribute__((noinline))
1535PTH_FUNC(int, condZuinit, // cond_init
1536 cond_t *cond, int type, void *arg)
1537{
1538 int ret;
1539 OrigFn fn;
1540 VALGRIND_GET_ORIG_FN(fn);
1541
1542 if (TRACE_PTH_FNS) {
1543 fprintf(stderr, "<< cond_init %p", cond); fflush(stderr);
1544 }
1545
1546 CALL_FN_W_WWW(ret, fn, cond, type, arg);
1547
1548 if (ret == 0) {
1549 /* Luckily evh__HG_PTHREAD_COND_INIT_POST() ignores cond_attr.
1550 See also comment for pthread_cond_init_WRK(). */
1551 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST,
1552 cond_t *, cond, void *, NULL);
1553 } else {
1554 DO_PthAPIerror("cond_init", ret);
1555 }
1556
1557 if (TRACE_PTH_FNS) {
1558 fprintf(stderr, " cond_init -> %d >>\n", ret);
1559 }
1560
1561 return ret;
1562}
1563#endif /* VGO_solaris */
1564
sewardjb4112022007-11-09 22:49:28 +00001565
sewardj1c147ff2009-07-26 19:52:06 +00001566//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00001567// glibc: pthread_cond_destroy@@GLIBC_2.3.2
1568// glibc: pthread_cond_destroy@GLIBC_2.2.5
1569// glibc: pthread_cond_destroy@GLIBC_2.0
1570// darwin: pthread_cond_destroy
1571// Solaris: cond_destroy (pthread_cond_destroy is a weak alias)
sewardj1c147ff2009-07-26 19:52:06 +00001572//
florian31014da2011-09-26 00:29:44 +00001573__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +00001574static int pthread_cond_destroy_WRK(pthread_cond_t* cond)
sewardjf98e1c02008-10-25 16:22:41 +00001575{
1576 int ret;
sewardjc02f6c42013-10-14 13:51:25 +00001577 unsigned long cond_is_init;
sewardjf98e1c02008-10-25 16:22:41 +00001578 OrigFn fn;
1579
1580 VALGRIND_GET_ORIG_FN(fn);
1581
1582 if (TRACE_PTH_FNS) {
1583 fprintf(stderr, "<< pthread_cond_destroy %p", cond);
1584 fflush(stderr);
1585 }
1586
sewardjc02f6c42013-10-14 13:51:25 +00001587 if (cond != NULL) {
1588 const pthread_cond_t cond_init = PTHREAD_COND_INITIALIZER;
1589 cond_is_init = my_memcmp(cond, &cond_init, sizeof(*cond)) == 0;
1590 } else {
1591 cond_is_init = 0;
1592 }
1593
1594 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_DESTROY_PRE,
1595 pthread_cond_t*, cond, unsigned long, cond_is_init);
sewardjf98e1c02008-10-25 16:22:41 +00001596
1597 CALL_FN_W_W(ret, fn, cond);
1598
1599 if (ret != 0) {
1600 DO_PthAPIerror( "pthread_cond_destroy", ret );
1601 }
1602
1603 if (TRACE_PTH_FNS) {
1604 fprintf(stderr, " codestr -> %d >>\n", ret);
1605 }
1606
1607 return ret;
1608}
sewardj1c147ff2009-07-26 19:52:06 +00001609#if defined(VGO_linux)
1610 PTH_FUNC(int, pthreadZucondZudestroyZAZa, // pthread_cond_destroy@*
1611 pthread_cond_t* cond) {
1612 return pthread_cond_destroy_WRK(cond);
1613 }
1614#elif defined(VGO_darwin)
1615 PTH_FUNC(int, pthreadZucondZudestroy, // pthread_cond_destroy
1616 pthread_cond_t* cond) {
1617 return pthread_cond_destroy_WRK(cond);
1618 }
sewardj8eb8bab2015-07-21 14:44:28 +00001619#elif defined(VGO_solaris)
1620 PTH_FUNC(int, condZudestroy, // cond_destroy
1621 pthread_cond_t *cond) {
1622 return pthread_cond_destroy_WRK(cond);
1623 }
sewardj1c147ff2009-07-26 19:52:06 +00001624#else
1625# error "Unsupported OS"
1626#endif
sewardjf98e1c02008-10-25 16:22:41 +00001627
1628
1629/*----------------------------------------------------------------*/
1630/*--- pthread_barrier_t functions ---*/
1631/*----------------------------------------------------------------*/
1632
njnf76d27a2009-05-28 01:53:07 +00001633#if defined(HAVE_PTHREAD_BARRIER_INIT)
1634
sewardj9f569b72008-11-13 13:33:09 +00001635/* Handled: pthread_barrier_init
1636 pthread_barrier_wait
1637 pthread_barrier_destroy
1638
1639 Unhandled: pthread_barrierattr_destroy
1640 pthread_barrierattr_getpshared
1641 pthread_barrierattr_init
1642 pthread_barrierattr_setpshared
1643 -- are these important?
1644*/
1645
sewardj1c147ff2009-07-26 19:52:06 +00001646//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00001647// glibc: pthread_barrier_init
1648// darwin: (doesn't appear to exist)
1649// Solaris: pthread_barrier_init
sewardj9f569b72008-11-13 13:33:09 +00001650PTH_FUNC(int, pthreadZubarrierZuinit, // pthread_barrier_init
1651 pthread_barrier_t* bar,
1652 pthread_barrierattr_t* attr, unsigned long count)
sewardjf98e1c02008-10-25 16:22:41 +00001653{
1654 int ret;
1655 OrigFn fn;
1656 VALGRIND_GET_ORIG_FN(fn);
1657
1658 if (TRACE_PTH_FNS) {
sewardj9f569b72008-11-13 13:33:09 +00001659 fprintf(stderr, "<< pthread_barrier_init %p %p %lu",
1660 bar, attr, count);
sewardjf98e1c02008-10-25 16:22:41 +00001661 fflush(stderr);
1662 }
1663
sewardj406bac82010-03-03 23:03:40 +00001664 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE,
1665 pthread_barrier_t*, bar,
1666 unsigned long, count,
1667 unsigned long, 0/*!resizable*/);
sewardjf98e1c02008-10-25 16:22:41 +00001668
sewardj9f569b72008-11-13 13:33:09 +00001669 CALL_FN_W_WWW(ret, fn, bar,attr,count);
sewardjf98e1c02008-10-25 16:22:41 +00001670
sewardj9f569b72008-11-13 13:33:09 +00001671 if (ret != 0) {
1672 DO_PthAPIerror( "pthread_barrier_init", ret );
1673 }
1674
1675 if (TRACE_PTH_FNS) {
1676 fprintf(stderr, " pthread_barrier_init -> %d >>\n", ret);
1677 }
1678
1679 return ret;
1680}
1681
1682
sewardj1c147ff2009-07-26 19:52:06 +00001683//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00001684// glibc: pthread_barrier_wait
1685// darwin: (doesn't appear to exist)
1686// Solaris: pthread_barrier_wait
sewardj9f569b72008-11-13 13:33:09 +00001687PTH_FUNC(int, pthreadZubarrierZuwait, // pthread_barrier_wait
1688 pthread_barrier_t* bar)
1689{
1690 int ret;
1691 OrigFn fn;
1692 VALGRIND_GET_ORIG_FN(fn);
1693
1694 if (TRACE_PTH_FNS) {
1695 fprintf(stderr, "<< pthread_barrier_wait %p", bar);
1696 fflush(stderr);
1697 }
1698
1699 /* That this works correctly, and doesn't screw up when a thread
1700 leaving the barrier races round to the front and re-enters while
1701 other threads are still leaving it, is quite subtle. See
1702 comments in the handler for PTHREAD_BARRIER_WAIT_PRE in
1703 hg_main.c. */
1704 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE,
1705 pthread_barrier_t*,bar);
1706
1707 CALL_FN_W_W(ret, fn, bar);
1708
1709 if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) {
1710 DO_PthAPIerror( "pthread_barrier_wait", ret );
1711 }
sewardjf98e1c02008-10-25 16:22:41 +00001712
1713 if (TRACE_PTH_FNS) {
1714 fprintf(stderr, " pthread_barrier_wait -> %d >>\n", ret);
1715 }
1716
1717 return ret;
1718}
1719
1720
sewardj1c147ff2009-07-26 19:52:06 +00001721//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00001722// glibc: pthread_barrier_destroy
1723// darwin: (doesn't appear to exist)
1724// Solaris: pthread_barrier_destroy
sewardj9f569b72008-11-13 13:33:09 +00001725PTH_FUNC(int, pthreadZubarrierZudestroy, // pthread_barrier_destroy
1726 pthread_barrier_t* bar)
1727{
1728 int ret;
1729 OrigFn fn;
1730 VALGRIND_GET_ORIG_FN(fn);
1731
1732 if (TRACE_PTH_FNS) {
1733 fprintf(stderr, "<< pthread_barrier_destroy %p", bar);
1734 fflush(stderr);
1735 }
1736
1737 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE,
1738 pthread_barrier_t*,bar);
1739
1740 CALL_FN_W_W(ret, fn, bar);
1741
1742 if (ret != 0) {
1743 DO_PthAPIerror( "pthread_barrier_destroy", ret );
1744 }
1745
1746 if (TRACE_PTH_FNS) {
1747 fprintf(stderr, " pthread_barrier_destroy -> %d >>\n", ret);
1748 }
1749
1750 return ret;
1751}
sewardjf98e1c02008-10-25 16:22:41 +00001752
njnf76d27a2009-05-28 01:53:07 +00001753#endif // defined(HAVE_PTHREAD_BARRIER_INIT)
1754
sewardj5a644da2009-08-11 10:35:58 +00001755
1756/*----------------------------------------------------------------*/
1757/*--- pthread_spinlock_t functions ---*/
1758/*----------------------------------------------------------------*/
1759
petarj6d79b742012-12-20 18:56:57 +00001760#if defined(HAVE_PTHREAD_SPIN_LOCK) \
1761 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
sewardj5a644da2009-08-11 10:35:58 +00001762
1763/* Handled: pthread_spin_init pthread_spin_destroy
1764 pthread_spin_lock pthread_spin_trylock
1765 pthread_spin_unlock
1766
1767 Unhandled:
1768*/
1769
1770/* This is a nasty kludge, in that glibc "knows" that initialising a
1771 spin lock unlocks it, and pthread_spin_{init,unlock} are names for
1772 the same function. Hence we have to have a wrapper which does both
sewardj8eb8bab2015-07-21 14:44:28 +00001773 things, without knowing which the user intended to happen.
1774 Solaris has distinct functions for init/unlock but client requests
1775 are immutable in helgrind.h so follow the glibc lead. */
sewardj5a644da2009-08-11 10:35:58 +00001776
1777//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00001778// glibc: pthread_spin_init
1779// glibc: pthread_spin_unlock
1780// darwin: (doesn't appear to exist)
1781// Solaris: pthread_spin_init
1782// Solaris: pthread_spin_unlock
florian31014da2011-09-26 00:29:44 +00001783__attribute__((noinline))
sewardj5a644da2009-08-11 10:35:58 +00001784static int pthread_spin_init_or_unlock_WRK(pthread_spinlock_t* lock,
1785 int pshared) {
1786 int ret;
1787 OrigFn fn;
1788 VALGRIND_GET_ORIG_FN(fn);
1789 if (TRACE_PTH_FNS) {
1790 fprintf(stderr, "<< pthread_spin_iORu %p", lock); fflush(stderr);
1791 }
1792
1793 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE,
1794 pthread_spinlock_t*, lock);
1795
1796 CALL_FN_W_WW(ret, fn, lock,pshared);
1797
1798 if (ret == 0 /*success*/) {
1799 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST,
1800 pthread_spinlock_t*,lock);
1801 } else {
1802 DO_PthAPIerror( "pthread_spinlock_{init,unlock}", ret );
1803 }
1804
1805 if (TRACE_PTH_FNS) {
1806 fprintf(stderr, " :: spiniORu -> %d >>\n", ret);
1807 }
1808 return ret;
1809}
1810#if defined(VGO_linux)
1811 PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
1812 pthread_spinlock_t* lock, int pshared) {
1813 return pthread_spin_init_or_unlock_WRK(lock, pshared);
1814 }
1815 PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
1816 pthread_spinlock_t* lock) {
1817 /* this is never actually called */
1818 return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/);
1819 }
1820#elif defined(VGO_darwin)
sewardj8eb8bab2015-07-21 14:44:28 +00001821#elif defined(VGO_solaris)
1822 PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
1823 pthread_spinlock_t *lock, int pshared) {
1824 return pthread_spin_init_or_unlock_WRK(lock, pshared);
1825 }
1826 PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
1827 pthread_spinlock_t *lock) {
1828 return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/);
1829 }
sewardj5a644da2009-08-11 10:35:58 +00001830#else
1831# error "Unsupported OS"
1832#endif
1833
1834
1835//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00001836// glibc: pthread_spin_destroy
1837// darwin: (doesn't appear to exist)
1838// Solaris: pthread_spin_destroy
1839__attribute__((noinline))
1840static int pthread_spin_destroy_WRK(pthread_spinlock_t *lock)
sewardj5a644da2009-08-11 10:35:58 +00001841{
1842 int ret;
1843 OrigFn fn;
1844 VALGRIND_GET_ORIG_FN(fn);
1845 if (TRACE_PTH_FNS) {
1846 fprintf(stderr, "<< pthread_spin_destroy %p", lock);
1847 fflush(stderr);
1848 }
1849
1850 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_DESTROY_PRE,
1851 pthread_spinlock_t*,lock);
1852
1853 CALL_FN_W_W(ret, fn, lock);
1854
1855 if (ret != 0) {
1856 DO_PthAPIerror( "pthread_spin_destroy", ret );
1857 }
1858
1859 if (TRACE_PTH_FNS) {
1860 fprintf(stderr, " :: spindestroy -> %d >>\n", ret);
1861 }
1862 return ret;
1863}
sewardj8eb8bab2015-07-21 14:44:28 +00001864#if defined(VGO_linux)
Elliott Hughesa0664b92017-04-18 17:46:52 -07001865 PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy
sewardj8eb8bab2015-07-21 14:44:28 +00001866 pthread_spinlock_t *lock) {
1867 return pthread_spin_destroy_WRK(lock);
1868 }
sewardj5a644da2009-08-11 10:35:58 +00001869#elif defined(VGO_darwin)
sewardj8eb8bab2015-07-21 14:44:28 +00001870#elif defined(VGO_solaris)
Elliott Hughesa0664b92017-04-18 17:46:52 -07001871 PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy
sewardj8eb8bab2015-07-21 14:44:28 +00001872 pthread_spinlock_t *lock) {
1873 return pthread_spin_destroy_WRK(lock);
1874 }
sewardj5a644da2009-08-11 10:35:58 +00001875#else
1876# error "Unsupported OS"
1877#endif
1878
1879
1880//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00001881// glibc: pthread_spin_lock
1882// darwin: (doesn't appear to exist)
1883// Solaris: pthread_spin_lock
1884__attribute__((noinline))
1885static int pthread_spin_lock_WRK(pthread_spinlock_t *lock)
sewardj5a644da2009-08-11 10:35:58 +00001886{
1887 int ret;
1888 OrigFn fn;
1889 VALGRIND_GET_ORIG_FN(fn);
1890 if (TRACE_PTH_FNS) {
1891 fprintf(stderr, "<< pthread_spinlock %p", lock);
1892 fflush(stderr);
1893 }
1894
1895 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE,
1896 pthread_spinlock_t*,lock, long,0/*!isTryLock*/);
1897
1898 CALL_FN_W_W(ret, fn, lock);
1899
1900 /* There's a hole here: libpthread now knows the lock is locked,
1901 but the tool doesn't, so some other thread could run and detect
1902 that the lock has been acquired by someone (this thread). Does
1903 this matter? Not sure, but I don't think so. */
1904
1905 if (ret == 0 /*success*/) {
1906 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST,
1907 pthread_spinlock_t*,lock);
1908 } else {
1909 DO_PthAPIerror( "pthread_spin_lock", ret );
1910 }
1911
1912 if (TRACE_PTH_FNS) {
1913 fprintf(stderr, " :: spinlock -> %d >>\n", ret);
1914 }
1915 return ret;
1916}
sewardj8eb8bab2015-07-21 14:44:28 +00001917#if defined(VGO_linux)
1918 PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
1919 pthread_spinlock_t *lock) {
1920 return pthread_spin_lock_WRK(lock);
1921 }
sewardj5a644da2009-08-11 10:35:58 +00001922#elif defined(VGO_darwin)
sewardj8eb8bab2015-07-21 14:44:28 +00001923#elif defined(VGO_solaris)
1924 PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
1925 pthread_spinlock_t *lock) {
1926 return pthread_spin_lock_WRK(lock);
1927 }
sewardj5a644da2009-08-11 10:35:58 +00001928#else
1929# error "Unsupported OS"
1930#endif
1931
1932
1933//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00001934// glibc: pthread_spin_trylock
1935// darwin: (doesn't appear to exist)
1936// Solaris: pthread_spin_trylock
1937__attribute__((noinline))
1938static int pthread_spin_trylock_WRK(pthread_spinlock_t *lock)
sewardj5a644da2009-08-11 10:35:58 +00001939{
1940 int ret;
1941 OrigFn fn;
1942 VALGRIND_GET_ORIG_FN(fn);
1943 if (TRACE_PTH_FNS) {
1944 fprintf(stderr, "<< pthread_spin_trylock %p", lock);
1945 fflush(stderr);
1946 }
1947
1948 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE,
1949 pthread_spinlock_t*,lock, long,1/*isTryLock*/);
1950
1951 CALL_FN_W_W(ret, fn, lock);
1952
1953 /* There's a hole here: libpthread now knows the lock is locked,
1954 but the tool doesn't, so some other thread could run and detect
1955 that the lock has been acquired by someone (this thread). Does
1956 this matter? Not sure, but I don't think so. */
1957
1958 if (ret == 0 /*success*/) {
1959 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST,
1960 pthread_spinlock_t*,lock);
1961 } else {
1962 if (ret != EBUSY)
1963 DO_PthAPIerror( "pthread_spin_trylock", ret );
1964 }
1965
1966 if (TRACE_PTH_FNS) {
1967 fprintf(stderr, " :: spin_trylock -> %d >>\n", ret);
1968 }
1969 return ret;
1970}
sewardj8eb8bab2015-07-21 14:44:28 +00001971#if defined(VGO_linux)
1972 PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
1973 pthread_spinlock_t *lock) {
1974 return pthread_spin_trylock_WRK(lock);
1975 }
sewardj5a644da2009-08-11 10:35:58 +00001976#elif defined(VGO_darwin)
sewardj8eb8bab2015-07-21 14:44:28 +00001977#elif defined(VGO_solaris)
1978 PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
1979 pthread_spinlock_t *lock) {
1980 return pthread_spin_trylock_WRK(lock);
1981 }
sewardj5a644da2009-08-11 10:35:58 +00001982#else
1983# error "Unsupported OS"
1984#endif
1985
1986#endif // defined(HAVE_PTHREAD_SPIN_LOCK)
1987
1988
sewardjb4112022007-11-09 22:49:28 +00001989/*----------------------------------------------------------------*/
1990/*--- pthread_rwlock_t functions ---*/
1991/*----------------------------------------------------------------*/
1992
sewardj0c09bf02011-07-11 22:11:58 +00001993/* Android's pthread.h doesn't say anything about rwlocks, hence these
1994 functions have to be conditionally compiled. */
1995#if defined(HAVE_PTHREAD_RWLOCK_T)
1996
sewardjb4112022007-11-09 22:49:28 +00001997/* Handled: pthread_rwlock_init pthread_rwlock_destroy
1998 pthread_rwlock_rdlock
1999 pthread_rwlock_wrlock
2000 pthread_rwlock_unlock
sewardj8eb8bab2015-07-21 14:44:28 +00002001 pthread_rwlock_tryrdlock
2002 pthread_rwlock_trywrlock
sewardjb4112022007-11-09 22:49:28 +00002003
2004 Unhandled: pthread_rwlock_timedrdlock
sewardjb4112022007-11-09 22:49:28 +00002005 pthread_rwlock_timedwrlock
sewardjb4112022007-11-09 22:49:28 +00002006*/
2007
sewardj1c147ff2009-07-26 19:52:06 +00002008//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00002009// glibc: pthread_rwlock_init
2010// darwin: pthread_rwlock_init
2011// darwin: pthread_rwlock_init$UNIX2003
2012// Solaris: rwlock_init (pthread_rwlock_init is built atop of rwlock_init)
florian31014da2011-09-26 00:29:44 +00002013__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +00002014static int pthread_rwlock_init_WRK(pthread_rwlock_t *rwl,
2015 pthread_rwlockattr_t* attr)
sewardjb4112022007-11-09 22:49:28 +00002016{
2017 int ret;
2018 OrigFn fn;
2019 VALGRIND_GET_ORIG_FN(fn);
2020 if (TRACE_PTH_FNS) {
2021 fprintf(stderr, "<< pthread_rwl_init %p", rwl); fflush(stderr);
2022 }
2023
2024 CALL_FN_W_WW(ret, fn, rwl,attr);
2025
2026 if (ret == 0 /*success*/) {
2027 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
2028 pthread_rwlock_t*,rwl);
2029 } else {
2030 DO_PthAPIerror( "pthread_rwlock_init", ret );
2031 }
2032
2033 if (TRACE_PTH_FNS) {
2034 fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
2035 }
2036 return ret;
2037}
sewardj1c147ff2009-07-26 19:52:06 +00002038#if defined(VGO_linux)
2039 PTH_FUNC(int, pthreadZurwlockZuinit, // pthread_rwlock_init
2040 pthread_rwlock_t *rwl,
2041 pthread_rwlockattr_t* attr) {
2042 return pthread_rwlock_init_WRK(rwl, attr);
2043 }
2044#elif defined(VGO_darwin)
2045 PTH_FUNC(int, pthreadZurwlockZuinitZa, // pthread_rwlock_init*
2046 pthread_rwlock_t *rwl,
2047 pthread_rwlockattr_t* attr) {
2048 return pthread_rwlock_init_WRK(rwl, attr);
2049 }
sewardj8eb8bab2015-07-21 14:44:28 +00002050#elif defined(VGO_solaris)
2051static int pthread_rwlock_init_WRK(pthread_rwlock_t *rwl,
2052 pthread_rwlockattr_t* attr)
2053 __attribute__((unused));
sewardj1c147ff2009-07-26 19:52:06 +00002054#else
2055# error "Unsupported OS"
2056#endif
sewardjb4112022007-11-09 22:49:28 +00002057
sewardj8eb8bab2015-07-21 14:44:28 +00002058#if defined(VGO_solaris)
2059PTH_FUNC(int, rwlockZuinit, // rwlock_init
2060 rwlock_t *rwlock,
2061 int type,
2062 void *arg)
2063{
2064 int ret;
2065 OrigFn fn;
2066 VALGRIND_GET_ORIG_FN(fn);
2067 if (TRACE_PTH_FNS) {
2068 fprintf(stderr, "<< rwl_init %p", rwlock); fflush(stderr);
2069 }
2070
2071 CALL_FN_W_WWW(ret, fn, rwlock, type, arg);
2072
2073 if (ret == 0 /*success*/) {
2074 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
2075 rwlock_t *, rwlock);
2076 } else {
2077 DO_PthAPIerror("rwlock_init", ret);
2078 }
2079
2080 if (TRACE_PTH_FNS) {
2081 fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
2082 }
2083 return ret;
2084}
2085#endif /* VGO_solaris */
2086
sewardjb4112022007-11-09 22:49:28 +00002087
sewardj1c147ff2009-07-26 19:52:06 +00002088//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00002089// glibc: pthread_rwlock_destroy
2090// darwin: pthread_rwlock_destroy
2091// darwin: pthread_rwlock_destroy$UNIX2003
2092// Solaris: rwlock_destroy (pthread_rwlock_destroy is a weak alias)
sewardj1c147ff2009-07-26 19:52:06 +00002093//
florian31014da2011-09-26 00:29:44 +00002094__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +00002095static int pthread_rwlock_destroy_WRK(pthread_rwlock_t* rwl)
sewardjb4112022007-11-09 22:49:28 +00002096{
2097 int ret;
2098 OrigFn fn;
2099 VALGRIND_GET_ORIG_FN(fn);
2100 if (TRACE_PTH_FNS) {
2101 fprintf(stderr, "<< pthread_rwl_destroy %p", rwl); fflush(stderr);
2102 }
2103
2104 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE,
2105 pthread_rwlock_t*,rwl);
2106
2107 CALL_FN_W_W(ret, fn, rwl);
2108
2109 if (ret != 0) {
2110 DO_PthAPIerror( "pthread_rwlock_destroy", ret );
2111 }
2112
2113 if (TRACE_PTH_FNS) {
2114 fprintf(stderr, " :: rwl_destroy -> %d >>\n", ret);
2115 }
2116 return ret;
2117}
sewardj1c147ff2009-07-26 19:52:06 +00002118#if defined(VGO_linux)
2119 PTH_FUNC(int, pthreadZurwlockZudestroy, // pthread_rwlock_destroy
2120 pthread_rwlock_t *rwl) {
2121 return pthread_rwlock_destroy_WRK(rwl);
2122 }
2123#elif defined(VGO_darwin)
2124 PTH_FUNC(int, pthreadZurwlockZudestroyZa, // pthread_rwlock_destroy*
2125 pthread_rwlock_t *rwl) {
2126 return pthread_rwlock_destroy_WRK(rwl);
2127 }
sewardj8eb8bab2015-07-21 14:44:28 +00002128#elif defined(VGO_solaris)
2129 PTH_FUNC(int, rwlockZudestroy, // rwlock_destroy
2130 pthread_rwlock_t *rwl) {
2131 return pthread_rwlock_destroy_WRK(rwl);
2132 }
sewardj1c147ff2009-07-26 19:52:06 +00002133#else
2134# error "Unsupported OS"
2135#endif
sewardjb4112022007-11-09 22:49:28 +00002136
2137
sewardj1c147ff2009-07-26 19:52:06 +00002138//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00002139// glibc: pthread_rwlock_wrlock
2140// darwin: pthread_rwlock_wrlock
2141// darwin: pthread_rwlock_wrlock$UNIX2003
2142// Solaris: rw_wrlock (pthread_rwlock_wrlock is a weak alias)
sewardj1c147ff2009-07-26 19:52:06 +00002143//
florian31014da2011-09-26 00:29:44 +00002144__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +00002145static int pthread_rwlock_wrlock_WRK(pthread_rwlock_t* rwlock)
sewardjb4112022007-11-09 22:49:28 +00002146{
2147 int ret;
2148 OrigFn fn;
2149 VALGRIND_GET_ORIG_FN(fn);
2150 if (TRACE_PTH_FNS) {
2151 fprintf(stderr, "<< pthread_rwl_wlk %p", rwlock); fflush(stderr);
2152 }
2153
sewardj789c3c52008-02-25 12:10:07 +00002154 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2155 pthread_rwlock_t*,rwlock,
2156 long,1/*isW*/, long,0/*!isTryLock*/);
sewardjb4112022007-11-09 22:49:28 +00002157
2158 CALL_FN_W_W(ret, fn, rwlock);
2159
sewardj8eb8bab2015-07-21 14:44:28 +00002160 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2161 pthread_rwlock_t*,rwlock, long,1/*isW*/,
2162 long, (ret == 0) ? True : False);
2163 if (ret != 0) {
sewardjb4112022007-11-09 22:49:28 +00002164 DO_PthAPIerror( "pthread_rwlock_wrlock", ret );
2165 }
2166
2167 if (TRACE_PTH_FNS) {
2168 fprintf(stderr, " :: rwl_wlk -> %d >>\n", ret);
2169 }
2170 return ret;
2171}
sewardj1c147ff2009-07-26 19:52:06 +00002172#if defined(VGO_linux)
2173 PTH_FUNC(int, pthreadZurwlockZuwrlock, // pthread_rwlock_wrlock
2174 pthread_rwlock_t* rwlock) {
2175 return pthread_rwlock_wrlock_WRK(rwlock);
2176 }
2177#elif defined(VGO_darwin)
2178 PTH_FUNC(int, pthreadZurwlockZuwrlockZa, // pthread_rwlock_wrlock*
2179 pthread_rwlock_t* rwlock) {
2180 return pthread_rwlock_wrlock_WRK(rwlock);
2181 }
sewardj8eb8bab2015-07-21 14:44:28 +00002182#elif defined(VGO_solaris)
2183 PTH_FUNC(int, rwZuwrlock, // rw_wrlock
2184 pthread_rwlock_t *rwlock) {
2185 return pthread_rwlock_wrlock_WRK(rwlock);
2186 }
sewardj1c147ff2009-07-26 19:52:06 +00002187#else
2188# error "Unsupported OS"
2189#endif
sewardjb4112022007-11-09 22:49:28 +00002190
sewardj8eb8bab2015-07-21 14:44:28 +00002191#if defined(VGO_solaris)
2192/* Internal to libc. */
2193PTH_FUNC(void, lrwZuwrlock, // lrw_wrlock
2194 rwlock_t *rwlock)
2195{
2196 OrigFn fn;
2197 VALGRIND_GET_ORIG_FN(fn);
2198 if (TRACE_PTH_FNS) {
2199 fprintf(stderr, "<< lrw_wlk %p", rwlock); fflush(stderr);
2200 }
2201
2202 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2203 pthread_rwlock_t *, rwlock,
2204 long, 1/*isW*/, long, 0/*!isTryLock*/);
2205
2206 CALL_FN_v_W(fn, rwlock);
2207
2208 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2209 pthread_rwlock_t *, rwlock, long, 1/*isW*/, long, True);
2210
2211 if (TRACE_PTH_FNS) {
2212 fprintf(stderr, " :: lrw_wlk >>\n");
2213 }
2214}
2215#endif /* VGO_solaris */
2216
sewardjb4112022007-11-09 22:49:28 +00002217
sewardj1c147ff2009-07-26 19:52:06 +00002218//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00002219// glibc: pthread_rwlock_rdlock
2220// darwin: pthread_rwlock_rdlock
2221// darwin: pthread_rwlock_rdlock$UNIX2003
2222// Solaris: rw_rdlock (pthread_rwlock_rdlock is a weak alias)
sewardj1c147ff2009-07-26 19:52:06 +00002223//
florian31014da2011-09-26 00:29:44 +00002224__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +00002225static int pthread_rwlock_rdlock_WRK(pthread_rwlock_t* rwlock)
sewardjb4112022007-11-09 22:49:28 +00002226{
2227 int ret;
2228 OrigFn fn;
2229 VALGRIND_GET_ORIG_FN(fn);
2230 if (TRACE_PTH_FNS) {
2231 fprintf(stderr, "<< pthread_rwl_rlk %p", rwlock); fflush(stderr);
2232 }
2233
sewardj789c3c52008-02-25 12:10:07 +00002234 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2235 pthread_rwlock_t*,rwlock,
2236 long,0/*!isW*/, long,0/*!isTryLock*/);
sewardjb4112022007-11-09 22:49:28 +00002237
2238 CALL_FN_W_W(ret, fn, rwlock);
2239
sewardj8eb8bab2015-07-21 14:44:28 +00002240 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2241 pthread_rwlock_t*,rwlock, long,0/*!isW*/,
2242 long, (ret == 0) ? True : False);
2243 if (ret != 0) {
sewardjb4112022007-11-09 22:49:28 +00002244 DO_PthAPIerror( "pthread_rwlock_rdlock", ret );
2245 }
2246
2247 if (TRACE_PTH_FNS) {
2248 fprintf(stderr, " :: rwl_rlk -> %d >>\n", ret);
2249 }
2250 return ret;
2251}
sewardj1c147ff2009-07-26 19:52:06 +00002252#if defined(VGO_linux)
2253 PTH_FUNC(int, pthreadZurwlockZurdlock, // pthread_rwlock_rdlock
2254 pthread_rwlock_t* rwlock) {
2255 return pthread_rwlock_rdlock_WRK(rwlock);
2256 }
2257#elif defined(VGO_darwin)
2258 PTH_FUNC(int, pthreadZurwlockZurdlockZa, // pthread_rwlock_rdlock*
2259 pthread_rwlock_t* rwlock) {
2260 return pthread_rwlock_rdlock_WRK(rwlock);
2261 }
sewardj8eb8bab2015-07-21 14:44:28 +00002262#elif defined(VGO_solaris)
2263 PTH_FUNC(int, rwZurdlock, // rw_rdlock
2264 pthread_rwlock_t *rwlock) {
2265 return pthread_rwlock_rdlock_WRK(rwlock);
2266 }
sewardj1c147ff2009-07-26 19:52:06 +00002267#else
2268# error "Unsupported OS"
2269#endif
sewardjb4112022007-11-09 22:49:28 +00002270
sewardj8eb8bab2015-07-21 14:44:28 +00002271#if defined(VGO_solaris)
2272/* Internal to libc. */
2273PTH_FUNC(void, lrwZurdlock, // lrw_rdlock
2274 rwlock_t *rwlock)
2275{
2276 OrigFn fn;
2277 VALGRIND_GET_ORIG_FN(fn);
2278 if (TRACE_PTH_FNS) {
2279 fprintf(stderr, "<< lrw_rlk %p", rwlock); fflush(stderr);
2280 }
2281
2282 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2283 pthread_rwlock_t *, rwlock,
2284 long, 0/*!isW*/, long, 0/*!isTryLock*/);
2285
2286 CALL_FN_v_W(fn, rwlock);
2287
2288 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2289 pthread_rwlock_t *, rwlock, long, 0/*!isW*/, long, True);
2290
2291 if (TRACE_PTH_FNS) {
2292 fprintf(stderr, " :: lrw_rlk ->>\n");
2293 }
2294}
2295#endif /* VGO_solaris */
2296
sewardjb4112022007-11-09 22:49:28 +00002297
sewardj1c147ff2009-07-26 19:52:06 +00002298//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00002299// glibc: pthread_rwlock_trywrlock
2300// darwin: pthread_rwlock_trywrlock
2301// darwin: pthread_rwlock_trywrlock$UNIX2003
2302// Solaris: rw_trywrlock (pthread_rwlock_trywrlock is a weak alias)
sewardj1c147ff2009-07-26 19:52:06 +00002303//
florian31014da2011-09-26 00:29:44 +00002304__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +00002305static int pthread_rwlock_trywrlock_WRK(pthread_rwlock_t* rwlock)
sewardj789c3c52008-02-25 12:10:07 +00002306{
2307 int ret;
2308 OrigFn fn;
2309 VALGRIND_GET_ORIG_FN(fn);
2310 if (TRACE_PTH_FNS) {
2311 fprintf(stderr, "<< pthread_rwl_trywlk %p", rwlock); fflush(stderr);
2312 }
2313
2314 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2315 pthread_rwlock_t*,rwlock,
2316 long,1/*isW*/, long,1/*isTryLock*/);
2317
2318 CALL_FN_W_W(ret, fn, rwlock);
2319
2320 /* There's a hole here: libpthread now knows the lock is locked,
2321 but the tool doesn't, so some other thread could run and detect
2322 that the lock has been acquired by someone (this thread). Does
2323 this matter? Not sure, but I don't think so. */
2324
sewardj8eb8bab2015-07-21 14:44:28 +00002325 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2326 pthread_rwlock_t*,rwlock, long,1/*isW*/,
2327 long, (ret == 0) ? True : False);
2328 if (ret != 0) {
sewardj789c3c52008-02-25 12:10:07 +00002329 if (ret != EBUSY)
2330 DO_PthAPIerror( "pthread_rwlock_trywrlock", ret );
2331 }
2332
2333 if (TRACE_PTH_FNS) {
2334 fprintf(stderr, " :: rwl_trywlk -> %d >>\n", ret);
2335 }
2336 return ret;
2337}
sewardj1c147ff2009-07-26 19:52:06 +00002338#if defined(VGO_linux)
2339 PTH_FUNC(int, pthreadZurwlockZutrywrlock, // pthread_rwlock_trywrlock
2340 pthread_rwlock_t* rwlock) {
2341 return pthread_rwlock_trywrlock_WRK(rwlock);
2342 }
2343#elif defined(VGO_darwin)
2344 PTH_FUNC(int, pthreadZurwlockZutrywrlockZa, // pthread_rwlock_trywrlock*
2345 pthread_rwlock_t* rwlock) {
2346 return pthread_rwlock_trywrlock_WRK(rwlock);
2347 }
sewardj8eb8bab2015-07-21 14:44:28 +00002348#elif defined(VGO_solaris)
2349 PTH_FUNC(int, rwZutrywrlock, // rw_trywrlock
2350 pthread_rwlock_t *rwlock) {
2351 return pthread_rwlock_trywrlock_WRK(rwlock);
2352 }
sewardj1c147ff2009-07-26 19:52:06 +00002353#else
2354# error "Unsupported OS"
2355#endif
sewardj789c3c52008-02-25 12:10:07 +00002356
2357
sewardj1c147ff2009-07-26 19:52:06 +00002358//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00002359// glibc: pthread_rwlock_tryrdlock
2360// darwin: pthread_rwlock_tryrdlock
2361// darwin: pthread_rwlock_tryrdlock$UNIX2003
2362// Solaris: rw_tryrdlock (pthread_rwlock_tryrdlock is a weak alias)
sewardj1c147ff2009-07-26 19:52:06 +00002363//
florian31014da2011-09-26 00:29:44 +00002364__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +00002365static int pthread_rwlock_tryrdlock_WRK(pthread_rwlock_t* rwlock)
sewardj789c3c52008-02-25 12:10:07 +00002366{
2367 int ret;
2368 OrigFn fn;
2369 VALGRIND_GET_ORIG_FN(fn);
2370 if (TRACE_PTH_FNS) {
2371 fprintf(stderr, "<< pthread_rwl_tryrlk %p", rwlock); fflush(stderr);
2372 }
2373
2374 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2375 pthread_rwlock_t*,rwlock,
2376 long,0/*!isW*/, long,1/*isTryLock*/);
2377
2378 CALL_FN_W_W(ret, fn, rwlock);
2379
2380 /* There's a hole here: libpthread now knows the lock is locked,
2381 but the tool doesn't, so some other thread could run and detect
2382 that the lock has been acquired by someone (this thread). Does
2383 this matter? Not sure, but I don't think so. */
2384
sewardj8eb8bab2015-07-21 14:44:28 +00002385 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2386 pthread_rwlock_t*,rwlock, long,0/*!isW*/,
2387 long, (ret == 0) ? True : False);
2388
2389 if (ret != 0) {
sewardj789c3c52008-02-25 12:10:07 +00002390 if (ret != EBUSY)
2391 DO_PthAPIerror( "pthread_rwlock_tryrdlock", ret );
2392 }
2393
2394 if (TRACE_PTH_FNS) {
2395 fprintf(stderr, " :: rwl_tryrlk -> %d >>\n", ret);
2396 }
2397 return ret;
2398}
sewardj1c147ff2009-07-26 19:52:06 +00002399#if defined(VGO_linux)
2400 PTH_FUNC(int, pthreadZurwlockZutryrdlock, // pthread_rwlock_tryrdlock
2401 pthread_rwlock_t* rwlock) {
2402 return pthread_rwlock_tryrdlock_WRK(rwlock);
2403 }
2404#elif defined(VGO_darwin)
2405 PTH_FUNC(int, pthreadZurwlockZutryrdlockZa, // pthread_rwlock_tryrdlock*
2406 pthread_rwlock_t* rwlock) {
2407 return pthread_rwlock_tryrdlock_WRK(rwlock);
2408 }
sewardj8eb8bab2015-07-21 14:44:28 +00002409#elif defined(VGO_solaris)
2410 PTH_FUNC(int, rwZutryrdlock, // rw_tryrdlock
2411 pthread_rwlock_t *rwlock) {
2412 return pthread_rwlock_tryrdlock_WRK(rwlock);
2413 }
sewardj1c147ff2009-07-26 19:52:06 +00002414#else
2415# error "Unsupported OS"
2416#endif
sewardj789c3c52008-02-25 12:10:07 +00002417
2418
sewardj1c147ff2009-07-26 19:52:06 +00002419//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00002420// glibc: Unhandled
2421// darwin: Unhandled
2422// Solaris: pthread_rwlock_timedrdlock
2423// Solaris: pthread_rwlock_reltimedrdlock_np
2424//
2425__attribute__((noinline)) __attribute__((unused))
2426static int pthread_rwlock_timedrdlock_WRK(pthread_rwlock_t *rwlock,
2427 const struct timespec *timeout)
2428{
2429 int ret;
2430 OrigFn fn;
2431 VALGRIND_GET_ORIG_FN(fn);
2432 if (TRACE_PTH_FNS) {
2433 fprintf(stderr, "<< pthread_rwl_timedrdl %p", rwlock); fflush(stderr);
2434 }
2435
2436 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2437 pthread_rwlock_t *, rwlock,
2438 long, 0/*isW*/, long, 0/*isTryLock*/);
2439
2440 CALL_FN_W_WW(ret, fn, rwlock, timeout);
2441
2442 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2443 pthread_rwlock_t *, rwlock, long, 0/*isW*/,
2444 long, (ret == 0) ? True : False);
2445 if (ret != 0) {
2446 DO_PthAPIerror("pthread_rwlock_timedrdlock", ret);
2447 }
2448
2449 if (TRACE_PTH_FNS) {
2450 fprintf(stderr, " :: rwl_timedrdl -> %d >>\n", ret);
2451 }
2452 return ret;
2453}
2454#if defined(VGO_linux)
2455#elif defined(VGO_darwin)
2456#elif defined(VGO_solaris)
2457 PTH_FUNC(int, pthreadZurwlockZutimedrdlock, // pthread_rwlock_timedrdlock
2458 pthread_rwlock_t *rwlock,
2459 const struct timespec *timeout) {
2460 return pthread_rwlock_timedrdlock_WRK(rwlock, timeout);
2461 }
2462 PTH_FUNC(int, pthreadZurwlockZureltimedrdlockZunp, // pthread_rwlock_timedrdlock_np
2463 pthread_rwlock_t *rwlock,
2464 const struct timespec *timeout) {
2465 return pthread_rwlock_timedrdlock_WRK(rwlock, timeout);
2466 }
2467#else
2468# error "Unsupported OS"
2469#endif
2470
2471
2472//-----------------------------------------------------------
2473// glibc: Unhandled
2474// darwin: Unhandled
2475// Solaris: pthread_rwlock_timedwrlock
2476// Solaris: pthread_rwlock_reltimedwrlock_np
2477//
2478__attribute__((noinline)) __attribute__((unused))
2479static int pthread_rwlock_timedwrlock_WRK(pthread_rwlock_t *rwlock,
2480 const struct timespec *timeout)
2481{
2482 int ret;
2483 OrigFn fn;
2484 VALGRIND_GET_ORIG_FN(fn);
2485 if (TRACE_PTH_FNS) {
2486 fprintf(stderr, "<< pthread_rwl_timedwrl %p", rwlock); fflush(stderr);
2487 }
2488
2489 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2490 pthread_rwlock_t *, rwlock,
2491 long, 1/*isW*/, long, 0/*isTryLock*/);
2492
2493 CALL_FN_W_WW(ret, fn, rwlock, timeout);
2494
2495 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2496 pthread_rwlock_t *, rwlock, long, 1/*isW*/,
2497 long, (ret == 0) ? True : False);
2498 if (ret != 0) {
2499 DO_PthAPIerror("pthread_rwlock_timedwrlock", ret);
2500 }
2501
2502 if (TRACE_PTH_FNS) {
2503 fprintf(stderr, " :: rwl_timedwrl -> %d >>\n", ret);
2504 }
2505 return ret;
2506}
2507#if defined(VGO_linux)
2508#elif defined(VGO_darwin)
2509#elif defined(VGO_solaris)
2510 PTH_FUNC(int, pthreadZurwlockZutimedwrlock, // pthread_rwlock_timedwrlock
2511 pthread_rwlock_t *rwlock,
2512 const struct timespec *timeout) {
2513 return pthread_rwlock_timedwrlock_WRK(rwlock, timeout);
2514 }
2515 PTH_FUNC(int, pthreadZurwlockZureltimedwrlockZunp, // pthread_rwlock_timedwrlock_np
2516 pthread_rwlock_t *rwlock,
2517 const struct timespec *timeout) {
2518 return pthread_rwlock_timedwrlock_WRK(rwlock, timeout);
2519 }
2520#else
2521# error "Unsupported OS"
2522#endif
2523
2524
2525//-----------------------------------------------------------
2526// glibc: pthread_rwlock_unlock
2527// darwin: pthread_rwlock_unlock
2528// darwin: pthread_rwlock_unlock$UNIX2003
2529// Solaris: rw_unlock (pthread_rwlock_unlock is a weak alias)
florian31014da2011-09-26 00:29:44 +00002530__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +00002531static int pthread_rwlock_unlock_WRK(pthread_rwlock_t* rwlock)
sewardjb4112022007-11-09 22:49:28 +00002532{
2533 int ret;
2534 OrigFn fn;
2535 VALGRIND_GET_ORIG_FN(fn);
2536 if (TRACE_PTH_FNS) {
2537 fprintf(stderr, "<< pthread_rwl_unlk %p", rwlock); fflush(stderr);
2538 }
2539
2540 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
2541 pthread_rwlock_t*,rwlock);
2542
2543 CALL_FN_W_W(ret, fn, rwlock);
2544
sewardj8eb8bab2015-07-21 14:44:28 +00002545 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
2546 pthread_rwlock_t*,rwlock);
2547 if (ret != 0) {
sewardjb4112022007-11-09 22:49:28 +00002548 DO_PthAPIerror( "pthread_rwlock_unlock", ret );
2549 }
2550
2551 if (TRACE_PTH_FNS) {
2552 fprintf(stderr, " :: rwl_unlk -> %d >>\n", ret);
2553 }
2554 return ret;
2555}
sewardj1c147ff2009-07-26 19:52:06 +00002556#if defined(VGO_linux)
2557 PTH_FUNC(int, pthreadZurwlockZuunlock, // pthread_rwlock_unlock
2558 pthread_rwlock_t* rwlock) {
2559 return pthread_rwlock_unlock_WRK(rwlock);
2560 }
2561#elif defined(VGO_darwin)
2562 PTH_FUNC(int, pthreadZurwlockZuunlockZa, // pthread_rwlock_unlock*
2563 pthread_rwlock_t* rwlock) {
2564 return pthread_rwlock_unlock_WRK(rwlock);
2565 }
sewardj8eb8bab2015-07-21 14:44:28 +00002566#elif defined(VGO_solaris)
2567 PTH_FUNC(int, rwZuunlock, // rw_unlock
2568 pthread_rwlock_t *rwlock) {
2569 return pthread_rwlock_unlock_WRK(rwlock);
2570 }
sewardj1c147ff2009-07-26 19:52:06 +00002571#else
2572# error "Unsupported OS"
2573#endif
sewardjb4112022007-11-09 22:49:28 +00002574
sewardj0c09bf02011-07-11 22:11:58 +00002575#endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
2576
sewardjb4112022007-11-09 22:49:28 +00002577
2578/*----------------------------------------------------------------*/
2579/*--- POSIX semaphores ---*/
2580/*----------------------------------------------------------------*/
2581
2582#include <semaphore.h>
sewardj28a7f7d2009-07-26 20:15:37 +00002583#include <fcntl.h> /* O_CREAT */
sewardjb4112022007-11-09 22:49:28 +00002584
2585#define TRACE_SEM_FNS 0
2586
2587/* Handled:
2588 int sem_init(sem_t *sem, int pshared, unsigned value);
2589 int sem_destroy(sem_t *sem);
2590 int sem_wait(sem_t *sem);
2591 int sem_post(sem_t *sem);
sewardj1c147ff2009-07-26 19:52:06 +00002592 sem_t* sem_open(const char *name, int oflag,
2593 ... [mode_t mode, unsigned value]);
2594 [complete with its idiotic semantics]
2595 int sem_close(sem_t* sem);
sewardjb4112022007-11-09 22:49:28 +00002596
2597 Unhandled:
2598 int sem_trywait(sem_t *sem);
2599 int sem_timedwait(sem_t *restrict sem,
2600 const struct timespec *restrict abs_timeout);
2601*/
2602
sewardj1c147ff2009-07-26 19:52:06 +00002603//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00002604// glibc: sem_init@@GLIBC_2.2.5
2605// glibc: sem_init@@GLIBC_2.1
2606// glibc: sem_init@GLIBC_2.0
2607// darwin: sem_init
2608// Solaris: sema_init (sem_init is built on top of sem_init)
sewardj1c147ff2009-07-26 19:52:06 +00002609//
sewardj8eb8bab2015-07-21 14:44:28 +00002610#if !defined(VGO_solaris)
florian31014da2011-09-26 00:29:44 +00002611__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +00002612static int sem_init_WRK(sem_t* sem, int pshared, unsigned long value)
sewardjb4112022007-11-09 22:49:28 +00002613{
2614 OrigFn fn;
2615 int ret;
2616 VALGRIND_GET_ORIG_FN(fn);
2617
2618 if (TRACE_SEM_FNS) {
2619 fprintf(stderr, "<< sem_init(%p,%d,%lu) ", sem,pshared,value);
2620 fflush(stderr);
2621 }
2622
2623 CALL_FN_W_WWW(ret, fn, sem,pshared,value);
2624
2625 if (ret == 0) {
sewardj11e352f2007-11-30 11:11:02 +00002626 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
2627 sem_t*, sem, unsigned long, value);
sewardjb4112022007-11-09 22:49:28 +00002628 } else {
2629 DO_PthAPIerror( "sem_init", errno );
2630 }
2631
2632 if (TRACE_SEM_FNS) {
2633 fprintf(stderr, " sem_init -> %d >>\n", ret);
2634 fflush(stderr);
2635 }
2636
2637 return ret;
2638}
sewardj1c147ff2009-07-26 19:52:06 +00002639#if defined(VGO_linux)
2640 PTH_FUNC(int, semZuinitZAZa, // sem_init@*
2641 sem_t* sem, int pshared, unsigned long value) {
2642 return sem_init_WRK(sem, pshared, value);
2643 }
2644#elif defined(VGO_darwin)
2645 PTH_FUNC(int, semZuinit, // sem_init
2646 sem_t* sem, int pshared, unsigned long value) {
2647 return sem_init_WRK(sem, pshared, value);
2648 }
2649#else
2650# error "Unsupported OS"
2651#endif
sewardjb4112022007-11-09 22:49:28 +00002652
sewardj8eb8bab2015-07-21 14:44:28 +00002653#else /* VGO_solaris */
2654PTH_FUNC(int, semaZuinit, // sema_init
2655 sema_t *sem,
2656 unsigned int value,
2657 int type,
2658 void *arg)
2659{
2660 OrigFn fn;
2661 int ret;
2662 VALGRIND_GET_ORIG_FN(fn);
2663
2664 if (TRACE_SEM_FNS) {
2665 fprintf(stderr, "<< sema_init(%p, %d, %u) ", sem, type, value);
2666 fflush(stderr);
2667 }
2668
2669 CALL_FN_W_WWWW(ret, fn, sem, value, type, arg);
2670
2671 if (ret == 0) {
2672 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
2673 sema_t *, sem, Word, value);
2674 } else {
2675 DO_PthAPIerror("sema_init", ret);
2676 }
2677
2678 if (TRACE_SEM_FNS) {
2679 fprintf(stderr, " sema_init -> %d >>\n", ret);
2680 fflush(stderr);
2681 }
2682
2683 return ret;
2684}
2685#endif /* VGO_solaris */
2686
sewardjb4112022007-11-09 22:49:28 +00002687
sewardj1c147ff2009-07-26 19:52:06 +00002688//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00002689// glibc: sem_destroy@GLIBC_2.0
2690// glibc: sem_destroy@@GLIBC_2.1
2691// glibc: sem_destroy@@GLIBC_2.2.5
2692// darwin: sem_destroy
2693// Solaris: sema_destroy (sem_destroy is built on top of sema_destroy)
florian31014da2011-09-26 00:29:44 +00002694__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +00002695static int sem_destroy_WRK(sem_t* sem)
sewardjb4112022007-11-09 22:49:28 +00002696{
2697 OrigFn fn;
2698 int ret;
2699 VALGRIND_GET_ORIG_FN(fn);
2700
2701 if (TRACE_SEM_FNS) {
2702 fprintf(stderr, "<< sem_destroy(%p) ", sem);
2703 fflush(stderr);
2704 }
2705
sewardj11e352f2007-11-30 11:11:02 +00002706 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
sewardjb4112022007-11-09 22:49:28 +00002707
2708 CALL_FN_W_W(ret, fn, sem);
2709
2710 if (ret != 0) {
sewardj8eb8bab2015-07-21 14:44:28 +00002711 DO_PthAPIerror( "sem_destroy", SEM_ERROR );
sewardjb4112022007-11-09 22:49:28 +00002712 }
2713
2714 if (TRACE_SEM_FNS) {
2715 fprintf(stderr, " sem_destroy -> %d >>\n", ret);
2716 fflush(stderr);
2717 }
2718
2719 return ret;
2720}
sewardj1c147ff2009-07-26 19:52:06 +00002721#if defined(VGO_linux)
2722 PTH_FUNC(int, semZudestroyZAZa, // sem_destroy*
2723 sem_t* sem) {
2724 return sem_destroy_WRK(sem);
2725 }
2726#elif defined(VGO_darwin)
2727 PTH_FUNC(int, semZudestroy, // sem_destroy
2728 sem_t* sem) {
2729 return sem_destroy_WRK(sem);
2730 }
sewardj8eb8bab2015-07-21 14:44:28 +00002731#elif defined(VGO_solaris)
2732 PTH_FUNC(int, semaZudestroy, // sema_destroy
2733 sem_t *sem) {
2734 return sem_destroy_WRK(sem);
2735 }
sewardj1c147ff2009-07-26 19:52:06 +00002736#else
2737# error "Unsupported OS"
2738#endif
sewardjb4112022007-11-09 22:49:28 +00002739
2740
sewardj1c147ff2009-07-26 19:52:06 +00002741//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00002742// glibc: sem_wait
2743// glibc: sem_wait@GLIBC_2.0
2744// glibc: sem_wait@@GLIBC_2.1
2745// darwin: sem_wait
2746// darwin: sem_wait$NOCANCEL$UNIX2003
2747// darwin: sem_wait$UNIX2003
2748// Solaris: sema_wait (sem_wait is built on top of sema_wait)
sewardj1c147ff2009-07-26 19:52:06 +00002749//
sewardjb4112022007-11-09 22:49:28 +00002750/* wait: decrement semaphore - acquire lockage */
florian31014da2011-09-26 00:29:44 +00002751__attribute__((noinline))
sewardjb4112022007-11-09 22:49:28 +00002752static int sem_wait_WRK(sem_t* sem)
2753{
2754 OrigFn fn;
2755 int ret;
2756 VALGRIND_GET_ORIG_FN(fn);
2757
2758 if (TRACE_SEM_FNS) {
2759 fprintf(stderr, "<< sem_wait(%p) ", sem);
2760 fflush(stderr);
2761 }
2762
sewardj8eb8bab2015-07-21 14:44:28 +00002763 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_PRE, sem_t*,sem);
2764
sewardjb4112022007-11-09 22:49:28 +00002765 CALL_FN_W_W(ret, fn, sem);
2766
sewardj8eb8bab2015-07-21 14:44:28 +00002767 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST, sem_t*,sem,
2768 long, (ret == 0) ? True : False);
2769
2770 if (ret != 0) {
2771 DO_PthAPIerror( "sem_wait", SEM_ERROR );
sewardjb4112022007-11-09 22:49:28 +00002772 }
2773
2774 if (TRACE_SEM_FNS) {
2775 fprintf(stderr, " sem_wait -> %d >>\n", ret);
2776 fflush(stderr);
2777 }
2778
2779 return ret;
2780}
sewardj1c147ff2009-07-26 19:52:06 +00002781#if defined(VGO_linux)
2782 PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
2783 return sem_wait_WRK(sem);
2784 }
2785 PTH_FUNC(int, semZuwaitZAZa, sem_t* sem) { /* sem_wait@* */
2786 return sem_wait_WRK(sem);
2787 }
2788#elif defined(VGO_darwin)
2789 PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
2790 return sem_wait_WRK(sem);
2791 }
2792 PTH_FUNC(int, semZuwaitZDZa, sem_t* sem) { /* sem_wait$* */
2793 return sem_wait_WRK(sem);
2794 }
sewardj8eb8bab2015-07-21 14:44:28 +00002795#elif defined(VGO_solaris)
2796 PTH_FUNC(int, semaZuwait, sem_t *sem) { /* sema_wait */
2797 return sem_wait_WRK(sem);
2798 }
sewardj1c147ff2009-07-26 19:52:06 +00002799#else
2800# error "Unsupported OS"
2801#endif
sewardjb4112022007-11-09 22:49:28 +00002802
2803
sewardj1c147ff2009-07-26 19:52:06 +00002804//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00002805// glibc: sem_post
2806// glibc: sem_post@GLIBC_2.0
2807// glibc: sem_post@@GLIBC_2.1
2808// darwin: sem_post
2809// Solaris: sema_post (sem_post is built on top of sema_post)
sewardj1c147ff2009-07-26 19:52:06 +00002810//
sewardjb4112022007-11-09 22:49:28 +00002811/* post: increment semaphore - release lockage */
florian31014da2011-09-26 00:29:44 +00002812__attribute__((noinline))
sewardjb4112022007-11-09 22:49:28 +00002813static int sem_post_WRK(sem_t* sem)
2814{
2815 OrigFn fn;
2816 int ret;
2817
2818 VALGRIND_GET_ORIG_FN(fn);
2819
2820 if (TRACE_SEM_FNS) {
2821 fprintf(stderr, "<< sem_post(%p) ", sem);
2822 fflush(stderr);
2823 }
2824
sewardj11e352f2007-11-30 11:11:02 +00002825 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_PRE, sem_t*,sem);
sewardjb4112022007-11-09 22:49:28 +00002826
2827 CALL_FN_W_W(ret, fn, sem);
2828
sewardj8eb8bab2015-07-21 14:44:28 +00002829 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_POST, sem_t*,sem);
2830
sewardjb4112022007-11-09 22:49:28 +00002831 if (ret != 0) {
sewardj8eb8bab2015-07-21 14:44:28 +00002832 DO_PthAPIerror( "sem_post", SEM_ERROR );
sewardjb4112022007-11-09 22:49:28 +00002833 }
2834
2835 if (TRACE_SEM_FNS) {
2836 fprintf(stderr, " sem_post -> %d >>\n", ret);
2837 fflush(stderr);
2838 }
2839
2840 return ret;
2841}
sewardj1c147ff2009-07-26 19:52:06 +00002842#if defined(VGO_linux)
2843 PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
2844 return sem_post_WRK(sem);
2845 }
2846 PTH_FUNC(int, semZupostZAZa, sem_t* sem) { /* sem_post@* */
2847 return sem_post_WRK(sem);
2848 }
2849#elif defined(VGO_darwin)
2850 PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
2851 return sem_post_WRK(sem);
2852 }
sewardj8eb8bab2015-07-21 14:44:28 +00002853#elif defined(VGO_solaris)
2854 PTH_FUNC(int, semaZupost, sem_t *sem) { /* sema_post */
2855 return sem_post_WRK(sem);
2856 }
sewardj1c147ff2009-07-26 19:52:06 +00002857#else
2858# error "Unsupported OS"
2859#endif
2860
2861
2862//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00002863// glibc: sem_open
2864// darwin: sem_open
2865// Solaris: sem_open
sewardj1c147ff2009-07-26 19:52:06 +00002866//
2867PTH_FUNC(sem_t*, semZuopen,
2868 const char* name, long oflag,
2869 long mode, unsigned long value)
2870{
2871 /* A copy of sem_init_WRK (more or less). Is this correct? */
2872 OrigFn fn;
2873 sem_t* ret;
2874 VALGRIND_GET_ORIG_FN(fn);
2875
2876 if (TRACE_SEM_FNS) {
2877 fprintf(stderr, "<< sem_open(\"%s\",%ld,%lx,%lu) ",
2878 name,oflag,mode,value);
2879 fflush(stderr);
2880 }
2881
2882 CALL_FN_W_WWWW(ret, fn, name,oflag,mode,value);
2883
2884 if (ret != SEM_FAILED && (oflag & O_CREAT)) {
2885 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
2886 sem_t*, ret, unsigned long, value);
2887 }
2888 if (ret == SEM_FAILED) {
2889 DO_PthAPIerror( "sem_open", errno );
2890 }
2891
2892 if (TRACE_SEM_FNS) {
2893 fprintf(stderr, " sem_open -> %p >>\n", ret);
2894 fflush(stderr);
2895 }
2896
2897 return ret;
sewardjb4112022007-11-09 22:49:28 +00002898}
2899
2900
sewardj1c147ff2009-07-26 19:52:06 +00002901//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00002902// glibc: sem_close
2903// darwin: sem_close
2904// Solaris: sem_close
sewardj1c147ff2009-07-26 19:52:06 +00002905PTH_FUNC(int, sem_close, sem_t* sem)
2906{
2907 OrigFn fn;
2908 int ret;
2909 VALGRIND_GET_ORIG_FN(fn);
2910
2911 if (TRACE_SEM_FNS) {
2912 fprintf(stderr, "<< sem_close(%p) ", sem);
2913 fflush(stderr);
2914 }
2915
2916 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
2917
2918 CALL_FN_W_W(ret, fn, sem);
2919
2920 if (ret != 0) {
2921 DO_PthAPIerror( "sem_close", errno );
2922 }
2923
2924 if (TRACE_SEM_FNS) {
2925 fprintf(stderr, " close -> %d >>\n", ret);
2926 fflush(stderr);
2927 }
2928
2929 return ret;
2930}
2931
sewardjb4112022007-11-09 22:49:28 +00002932
2933/*----------------------------------------------------------------*/
2934/*--- Qt 4 threading functions (w/ GNU name mangling) ---*/
2935/*----------------------------------------------------------------*/
2936
sewardj38e0cf92008-11-19 10:40:56 +00002937/* Handled:
2938 QMutex::lock()
2939 QMutex::unlock()
2940 QMutex::tryLock()
2941 QMutex::tryLock(int)
sewardjb4112022007-11-09 22:49:28 +00002942
sewardj38e0cf92008-11-19 10:40:56 +00002943 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC1ENS_13RecursionModeE
2944 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC2ENS_13RecursionModeE
2945 QMutex::~QMutex() _ZN6QMutexD1Ev
2946 QMutex::~QMutex() _ZN6QMutexD2Ev
sewardjb4112022007-11-09 22:49:28 +00002947
sewardj38e0cf92008-11-19 10:40:56 +00002948 Unhandled:
2949 QReadWriteLock::lockForRead()
2950 QReadWriteLock::lockForWrite()
2951 QReadWriteLock::unlock()
2952 QReadWriteLock::tryLockForRead(int)
2953 QReadWriteLock::tryLockForRead()
2954 QReadWriteLock::tryLockForWrite(int)
2955 QReadWriteLock::tryLockForWrite()
2956
2957 QWaitCondition::wait(QMutex*, unsigned long)
2958 QWaitCondition::wakeAll()
2959 QWaitCondition::wakeOne()
2960
2961 QSemaphore::*
2962*/
2963/* More comments, 19 Nov 08, based on assessment of qt-4.5.0TP1,
2964 at least on Unix:
2965
2966 It's apparently only necessary to intercept QMutex, since that is
2967 not implemented using pthread_mutex_t; instead Qt4 has its own
2968 implementation based on atomics (to check the non-contended case)
2969 and pthread_cond_wait (to wait in the contended case).
2970
2971 QReadWriteLock is built on top of QMutex, counters, and a wait
2972 queue. So we don't need to handle it specially once QMutex
2973 handling is correct -- presumably the dependencies through QMutex
2974 are sufficient to avoid any false race reports. On the other hand,
2975 it is an open question whether too many dependencies are observed
2976 -- in which case we may miss races (false negatives). I suspect
2977 this is likely to be the case, unfortunately.
2978
2979 QWaitCondition is built on pthread_cond_t, pthread_mutex_t, QMutex
2980 and QReadWriteLock. Same compositional-correctness justificiation
2981 and limitations as fro QReadWriteLock.
2982
2983 Ditto QSemaphore (from cursory examination).
2984
2985 Does it matter that only QMutex is handled directly? Open
2986 question. From testing with drd/tests/qt4_* and with KDE4 apps, it
2987 appears that no false errors are reported; however it is not clear
2988 if this is causing false negatives.
2989
2990 Another problem with Qt4 is thread exiting. Threads are created
2991 with pthread_create (fine); but they detach and simply exit when
2992 done. There is no use of pthread_join, and the provided
2993 wait-for-a-thread-to-exit mechanism (QThread::wait, I believe)
2994 relies on a system of mutexes and flags. I suspect this also
2995 causes too many dependencies to appear. Consequently H sometimes
2996 fails to detect races at exit in some very short-lived racy
2997 programs, because it appears that a thread can exit _and_ have an
2998 observed dependency edge back to the main thread (presumably)
2999 before the main thread reaps the child (that is, calls
3000 QThread::wait).
3001
3002 This theory is supported by the observation that if all threads are
3003 made to wait at a pthread_barrier_t immediately before they exit,
3004 then H's detection of races in such programs becomes reliable;
3005 without the barrier, it is varies from run to run, depending
3006 (according to investigation) on whether aforementioned
3007 exit-before-reaping behaviour happens or not.
3008
3009 Finally, why is it necessary to intercept the QMutex constructors
3010 and destructors? The constructors are intercepted only as a matter
3011 of convenience, so H can print accurate "first observed at"
3012 clauses. However, it is actually necessary to intercept the
3013 destructors (as it is with pthread_mutex_destroy) in order that
3014 locks get removed from LAOG when they are destroyed.
sewardjb4112022007-11-09 22:49:28 +00003015*/
3016
3017// soname is libQtCore.so.4 ; match against libQtCore.so*
3018#define QT4_FUNC(ret_ty, f, args...) \
sewardj38e0cf92008-11-19 10:40:56 +00003019 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args); \
3020 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args)
sewardjb4112022007-11-09 22:49:28 +00003021
sewardjd52defb2013-02-07 11:53:36 +00003022// soname is libQt5Core.so.4 ; match against libQt5Core.so*
3023#define QT5_FUNC(ret_ty, f, args...) \
3024 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args); \
3025 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args)
3026
sewardj1c147ff2009-07-26 19:52:06 +00003027//-----------------------------------------------------------
sewardjb4112022007-11-09 22:49:28 +00003028// QMutex::lock()
sewardjd52defb2013-02-07 11:53:36 +00003029__attribute__((noinline))
3030static void QMutex_lock_WRK(void* self)
sewardjb4112022007-11-09 22:49:28 +00003031{
3032 OrigFn fn;
3033 VALGRIND_GET_ORIG_FN(fn);
3034 if (TRACE_QT4_FNS) {
3035 fprintf(stderr, "<< QMutex::lock %p", self); fflush(stderr);
3036 }
3037
3038 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
3039 void*,self, long,0/*!isTryLock*/);
3040
3041 CALL_FN_v_W(fn, self);
3042
sewardj8eb8bab2015-07-21 14:44:28 +00003043 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
3044 void *, self, long, True);
sewardjb4112022007-11-09 22:49:28 +00003045
3046 if (TRACE_QT4_FNS) {
3047 fprintf(stderr, " :: Q::lock done >>\n");
3048 }
3049}
3050
sewardjd52defb2013-02-07 11:53:36 +00003051QT4_FUNC(void, _ZN6QMutex4lockEv, void* self) {
3052 QMutex_lock_WRK(self);
3053}
3054QT5_FUNC(void, _ZN6QMutex4lockEv, void* self) {
3055 QMutex_lock_WRK(self);
3056}
3057
sewardj1c147ff2009-07-26 19:52:06 +00003058//-----------------------------------------------------------
sewardjb4112022007-11-09 22:49:28 +00003059// QMutex::unlock()
sewardjd52defb2013-02-07 11:53:36 +00003060__attribute__((noinline))
3061static void QMutex_unlock_WRK(void* self)
sewardjb4112022007-11-09 22:49:28 +00003062{
3063 OrigFn fn;
3064 VALGRIND_GET_ORIG_FN(fn);
3065
3066 if (TRACE_QT4_FNS) {
3067 fprintf(stderr, "<< QMutex::unlock %p", self); fflush(stderr);
3068 }
3069
3070 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
3071 void*, self);
3072
3073 CALL_FN_v_W(fn, self);
3074
3075 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
3076 void*, self);
3077
3078 if (TRACE_QT4_FNS) {
3079 fprintf(stderr, " Q::unlock done >>\n");
3080 }
3081}
3082
sewardjd52defb2013-02-07 11:53:36 +00003083QT4_FUNC(void, _ZN6QMutex6unlockEv, void* self) {
3084 QMutex_unlock_WRK(self);
3085}
3086QT5_FUNC(void, _ZN6QMutex6unlockEv, void* self) {
3087 QMutex_unlock_WRK(self);
3088}
3089
sewardj1c147ff2009-07-26 19:52:06 +00003090//-----------------------------------------------------------
sewardj38e0cf92008-11-19 10:40:56 +00003091// bool QMutex::tryLock()
sewardjb4112022007-11-09 22:49:28 +00003092// using 'long' to mimic C++ 'bool'
sewardjd52defb2013-02-07 11:53:36 +00003093__attribute__((noinline))
3094static long QMutex_tryLock_WRK(void* self)
sewardjb4112022007-11-09 22:49:28 +00003095{
3096 OrigFn fn;
3097 long ret;
3098 VALGRIND_GET_ORIG_FN(fn);
3099 if (TRACE_QT4_FNS) {
3100 fprintf(stderr, "<< QMutex::tryLock %p", self); fflush(stderr);
3101 }
3102
3103 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
3104 void*,self, long,1/*isTryLock*/);
3105
3106 CALL_FN_W_W(ret, fn, self);
3107
3108 // assumes that only the low 8 bits of the 'bool' are significant
sewardj8eb8bab2015-07-21 14:44:28 +00003109 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
3110 void *, self, long, (ret & 0xFF) ? True : False);
sewardjb4112022007-11-09 22:49:28 +00003111
3112 if (TRACE_QT4_FNS) {
3113 fprintf(stderr, " :: Q::tryLock -> %lu >>\n", ret);
3114 }
3115
3116 return ret;
3117}
3118
sewardjd52defb2013-02-07 11:53:36 +00003119QT4_FUNC(long, _ZN6QMutex7tryLockEv, void* self) {
3120 return QMutex_tryLock_WRK(self);
3121}
3122QT5_FUNC(long, _ZN6QMutex7tryLockEv, void* self) {
3123 return QMutex_tryLock_WRK(self);
3124}
3125
sewardj1c147ff2009-07-26 19:52:06 +00003126//-----------------------------------------------------------
sewardj38e0cf92008-11-19 10:40:56 +00003127// bool QMutex::tryLock(int)
3128// using 'long' to mimic C++ 'bool'
sewardjd52defb2013-02-07 11:53:36 +00003129__attribute__((noinline))
3130static long QMutex_tryLock_int_WRK(void* self, long arg2)
sewardjb4112022007-11-09 22:49:28 +00003131{
3132 OrigFn fn;
sewardj38e0cf92008-11-19 10:40:56 +00003133 long ret;
sewardjb4112022007-11-09 22:49:28 +00003134 VALGRIND_GET_ORIG_FN(fn);
3135 if (TRACE_QT4_FNS) {
sewardj38e0cf92008-11-19 10:40:56 +00003136 fprintf(stderr, "<< QMutex::tryLock(int) %p %d", self, (int)arg2);
sewardjb4112022007-11-09 22:49:28 +00003137 fflush(stderr);
3138 }
3139
sewardj38e0cf92008-11-19 10:40:56 +00003140 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
3141 void*,self, long,1/*isTryLock*/);
sewardjb4112022007-11-09 22:49:28 +00003142
sewardj38e0cf92008-11-19 10:40:56 +00003143 CALL_FN_W_WW(ret, fn, self,arg2);
sewardjb4112022007-11-09 22:49:28 +00003144
sewardj38e0cf92008-11-19 10:40:56 +00003145 // assumes that only the low 8 bits of the 'bool' are significant
sewardj8eb8bab2015-07-21 14:44:28 +00003146 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
3147 void *, self, long, (ret & 0xFF) ? True : False);
sewardjb4112022007-11-09 22:49:28 +00003148
3149 if (TRACE_QT4_FNS) {
sewardj38e0cf92008-11-19 10:40:56 +00003150 fprintf(stderr, " :: Q::tryLock(int) -> %lu >>\n", ret);
sewardjb4112022007-11-09 22:49:28 +00003151 }
sewardj38e0cf92008-11-19 10:40:56 +00003152
3153 return ret;
sewardjb4112022007-11-09 22:49:28 +00003154}
3155
sewardjd52defb2013-02-07 11:53:36 +00003156QT4_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2) {
3157 return QMutex_tryLock_int_WRK(self, arg2);
3158}
3159QT5_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2) {
3160 return QMutex_tryLock_int_WRK(self, arg2);
3161}
sewardj38e0cf92008-11-19 10:40:56 +00003162
sewardj1c147ff2009-07-26 19:52:06 +00003163//-----------------------------------------------------------
sewardj38e0cf92008-11-19 10:40:56 +00003164// It's not really very clear what the args are here. But from
3165// a bit of dataflow analysis of the generated machine code of
3166// the original function, it appears this takes two args, and
3167// returns nothing. Nevertheless preserve return value just in
3168// case. A bit of debug printing indicates that the first arg
3169// is that of the mutex and the second is either zero or one,
3170// probably being the recursion mode, therefore.
3171// QMutex::QMutex(QMutex::RecursionMode) ("C1ENS" variant)
sewardjd52defb2013-02-07 11:53:36 +00003172__attribute__((noinline))
3173static void* QMutex_constructor_WRK(void* mutex, long recmode)
sewardjb4112022007-11-09 22:49:28 +00003174{
3175 OrigFn fn;
sewardj38e0cf92008-11-19 10:40:56 +00003176 long ret;
sewardjb4112022007-11-09 22:49:28 +00003177 VALGRIND_GET_ORIG_FN(fn);
sewardj38e0cf92008-11-19 10:40:56 +00003178 CALL_FN_W_WW(ret, fn, mutex, recmode);
3179 // fprintf(stderr, "QMutex constructor 1: %p <- %p %p\n", ret, arg1, arg2);
3180 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
3181 void*,mutex, long,1/*mbRec*/);
3182 return (void*)ret;
sewardjb4112022007-11-09 22:49:28 +00003183}
3184
sewardjd52defb2013-02-07 11:53:36 +00003185QT4_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE, void* self, long recmode) {
3186 return QMutex_constructor_WRK(self, recmode);
3187}
3188QT5_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE, void* self, long recmode) {
3189 return QMutex_constructor_WRK(self, recmode);
3190}
3191
sewardj1c147ff2009-07-26 19:52:06 +00003192//-----------------------------------------------------------
sewardj38e0cf92008-11-19 10:40:56 +00003193// QMutex::~QMutex() ("D1Ev" variant)
sewardjd52defb2013-02-07 11:53:36 +00003194__attribute__((noinline))
3195static void* QMutex_destructor_WRK(void* mutex)
sewardjb4112022007-11-09 22:49:28 +00003196{
3197 OrigFn fn;
sewardj38e0cf92008-11-19 10:40:56 +00003198 long ret;
sewardjb4112022007-11-09 22:49:28 +00003199 VALGRIND_GET_ORIG_FN(fn);
sewardj38e0cf92008-11-19 10:40:56 +00003200 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
3201 void*,mutex);
3202 CALL_FN_W_W(ret, fn, mutex);
3203 return (void*)ret;
sewardjb4112022007-11-09 22:49:28 +00003204}
3205
sewardjd52defb2013-02-07 11:53:36 +00003206QT4_FUNC(void*, _ZN6QMutexD1Ev, void* self) {
3207 return QMutex_destructor_WRK(self);
3208}
3209QT5_FUNC(void*, _ZN6QMutexD1Ev, void* self) {
3210 return QMutex_destructor_WRK(self);
3211}
sewardjb4112022007-11-09 22:49:28 +00003212
sewardj1c147ff2009-07-26 19:52:06 +00003213//-----------------------------------------------------------
sewardj38e0cf92008-11-19 10:40:56 +00003214// QMutex::QMutex(QMutex::RecursionMode) ("C2ENS" variant)
3215QT4_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE,
3216 void* mutex,
3217 long recmode)
3218{
3219 assert(0);
sewardj211c2532011-07-12 06:13:08 +00003220 /*NOTREACHED*/
3221 /* Android's gcc behaves like it doesn't know that assert(0)
3222 never returns. Hence: */
3223 return NULL;
sewardj38e0cf92008-11-19 10:40:56 +00003224}
3225
sewardjd52defb2013-02-07 11:53:36 +00003226QT5_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE, void* self, long recmode)
3227{
3228 assert(0);
3229 /*NOTREACHED*/
3230 return NULL;
3231}
sewardj1c147ff2009-07-26 19:52:06 +00003232
3233//-----------------------------------------------------------
sewardj38e0cf92008-11-19 10:40:56 +00003234// QMutex::~QMutex() ("D2Ev" variant)
3235QT4_FUNC(void*, _ZN6QMutexD2Ev, void* mutex)
3236{
3237 assert(0);
sewardj211c2532011-07-12 06:13:08 +00003238 /* Android's gcc behaves like it doesn't know that assert(0)
3239 never returns. Hence: */
3240 return NULL;
sewardj38e0cf92008-11-19 10:40:56 +00003241}
3242
sewardjd52defb2013-02-07 11:53:36 +00003243QT5_FUNC(void*, _ZN6QMutexD2Ev, void* self)
3244{
3245 assert(0);
3246 /*NOTREACHED*/
3247 return NULL;
3248}
sewardj38e0cf92008-11-19 10:40:56 +00003249
3250// QReadWriteLock is not intercepted directly. See comments
3251// above.
3252
3253//// QReadWriteLock::lockForRead()
3254//// _ZN14QReadWriteLock11lockForReadEv == QReadWriteLock::lockForRead()
3255//QT4_FUNC(void, ZuZZN14QReadWriteLock11lockForReadEv,
3256// // _ZN14QReadWriteLock11lockForReadEv
3257// void* self)
3258//{
3259// OrigFn fn;
3260// VALGRIND_GET_ORIG_FN(fn);
3261// if (TRACE_QT4_FNS) {
3262// fprintf(stderr, "<< QReadWriteLock::lockForRead %p", self);
3263// fflush(stderr);
3264// }
3265//
3266// DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
3267// void*,self,
3268// long,0/*!isW*/, long,0/*!isTryLock*/);
3269//
3270// CALL_FN_v_W(fn, self);
3271//
sewardj8eb8bab2015-07-21 14:44:28 +00003272// DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
3273// void*,self, long,0/*!isW*/, long, True);
sewardj38e0cf92008-11-19 10:40:56 +00003274//
3275// if (TRACE_QT4_FNS) {
3276// fprintf(stderr, " :: Q::lockForRead :: done >>\n");
3277// }
3278//}
3279//
3280//// QReadWriteLock::lockForWrite()
3281//// _ZN14QReadWriteLock12lockForWriteEv == QReadWriteLock::lockForWrite()
3282//QT4_FUNC(void, ZuZZN14QReadWriteLock12lockForWriteEv,
3283// // _ZN14QReadWriteLock12lockForWriteEv
3284// void* self)
3285//{
3286// OrigFn fn;
3287// VALGRIND_GET_ORIG_FN(fn);
3288// if (TRACE_QT4_FNS) {
3289// fprintf(stderr, "<< QReadWriteLock::lockForWrite %p", self);
3290// fflush(stderr);
3291// }
3292//
3293// DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
3294// void*,self,
3295// long,1/*isW*/, long,0/*!isTryLock*/);
3296//
3297// CALL_FN_v_W(fn, self);
3298//
sewardj8eb8bab2015-07-21 14:44:28 +00003299// DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
3300// void*,self, long,1/*isW*/, long, True);
sewardj38e0cf92008-11-19 10:40:56 +00003301//
3302// if (TRACE_QT4_FNS) {
3303// fprintf(stderr, " :: Q::lockForWrite :: done >>\n");
3304// }
3305//}
3306//
3307//// QReadWriteLock::unlock()
3308//// _ZN14QReadWriteLock6unlockEv == QReadWriteLock::unlock()
3309//QT4_FUNC(void, ZuZZN14QReadWriteLock6unlockEv,
3310// // _ZN14QReadWriteLock6unlockEv
3311// void* self)
3312//{
3313// OrigFn fn;
3314// VALGRIND_GET_ORIG_FN(fn);
3315// if (TRACE_QT4_FNS) {
3316// fprintf(stderr, "<< QReadWriteLock::unlock %p", self);
3317// fflush(stderr);
3318// }
3319//
3320// DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
3321// void*,self);
3322//
3323// CALL_FN_v_W(fn, self);
3324//
3325// DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
3326// void*,self);
3327//
3328// if (TRACE_QT4_FNS) {
3329// fprintf(stderr, " :: Q::unlock :: done >>\n");
3330// }
3331//}
3332
3333
3334/*----------------------------------------------------------------*/
3335/*--- Replacements for basic string functions, that don't ---*/
sewardjb80f0c92008-11-19 16:33:59 +00003336/*--- overrun the input arrays. ---*/
sewardj38e0cf92008-11-19 10:40:56 +00003337/*----------------------------------------------------------------*/
3338
bart9c7779b2013-11-24 17:48:13 +00003339#include "../shared/vg_replace_strmem.c"
sewardj38e0cf92008-11-19 10:40:56 +00003340
sewardjb4112022007-11-09 22:49:28 +00003341/*--------------------------------------------------------------------*/
sewardj3c944452011-09-05 20:39:57 +00003342/*--- end hg_intercepts.c ---*/
sewardjb4112022007-11-09 22:49:28 +00003343/*--------------------------------------------------------------------*/