blob: ff36e93cba6d6e6ccd2f41074c4fcb1f4c6fb2b5 [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
sewardjb3a1e4b2015-08-21 11:32:26 +000011 Copyright (C) 2007-2015 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.
676
677// System.Tasking.Debug.Master_Hook is called by a task Dependent to
678// indicate that its master is identified by master+master_level.
679void I_WRAP_SONAME_FNNAME_ZU
680 (Za,
681 system__tasking__debug__master_hook)
682 (void *dependent, void *master, int master_level);
683void I_WRAP_SONAME_FNNAME_ZU
684 (Za,
685 system__tasking__debug__master_hook)
686 (void *dependent, void *master, int master_level)
687{
688 OrigFn fn;
689 VALGRIND_GET_ORIG_FN(fn);
690 if (TRACE_GNAT_FNS) {
691 fprintf(stderr, "<< GNAT master_hook wrapper "
692 "dependent %p master %p master_level %d\n",
693 dependent, master, master_level); fflush(stderr);
694 }
695
696 // We call the wrapped function, even if it is a null body.
697 CALL_FN_v_WWW(fn, dependent, master, master_level);
698
699 DO_CREQ_v_WWW(_VG_USERREQ__HG_GNAT_MASTER_HOOK,
700 void*,dependent, void*,master,
701 Word, (Word)master_level);
702
703 if (TRACE_GNAT_FNS) {
704 fprintf(stderr, " :: GNAT master_hook >>\n");
705 }
706}
707
708// System.Tasking.Debug.Master_Completed_Hook is called by a task to
709// indicate that it has completed a master.
710// This indicates that all its Dependent tasks (that identified themselves
711// with the Master_Hook call) are terminated. Helgrind can consider
712// at this point that the equivalent of a 'pthread_join' has been done
713// between self_id and all dependent tasks at master_level.
714void I_WRAP_SONAME_FNNAME_ZU
715 (Za,
716 system__tasking__debug__master_completed_hook)
717 (void *self_id, int master_level);
718void I_WRAP_SONAME_FNNAME_ZU
719 (Za,
720 system__tasking__debug__master_completed_hook)
721 (void *self_id, int master_level)
722{
723 OrigFn fn;
724 VALGRIND_GET_ORIG_FN(fn);
725 if (TRACE_GNAT_FNS) {
726 fprintf(stderr, "<< GNAT master_completed_hook wrapper "
727 "self_id %p master_level %d\n",
728 self_id, master_level); fflush(stderr);
729 }
730
731 // We call the wrapped function, even if it is a null body.
732 CALL_FN_v_WW(fn, self_id, master_level);
733
734 DO_CREQ_v_WW(_VG_USERREQ__HG_GNAT_MASTER_COMPLETED_HOOK,
735 void*,self_id, Word,(Word)master_level);
736
737 if (TRACE_GNAT_FNS) {
738 fprintf(stderr, " :: GNAT master_completed_hook >>\n");
739 }
740}
sewardjb4112022007-11-09 22:49:28 +0000741
742/*----------------------------------------------------------------*/
743/*--- pthread_mutex_t functions ---*/
744/*----------------------------------------------------------------*/
745
746/* Handled: pthread_mutex_init pthread_mutex_destroy
747 pthread_mutex_lock
748 pthread_mutex_trylock pthread_mutex_timedlock
749 pthread_mutex_unlock
sewardjb4112022007-11-09 22:49:28 +0000750*/
751
sewardj1c147ff2009-07-26 19:52:06 +0000752//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +0000753#if !defined(VGO_solaris)
sewardj1c147ff2009-07-26 19:52:06 +0000754// glibc: pthread_mutex_init
755// darwin: pthread_mutex_init
sewardjb4112022007-11-09 22:49:28 +0000756PTH_FUNC(int, pthreadZumutexZuinit, // pthread_mutex_init
757 pthread_mutex_t *mutex,
758 pthread_mutexattr_t* attr)
759{
760 int ret;
761 long mbRec;
762 OrigFn fn;
763 VALGRIND_GET_ORIG_FN(fn);
764 if (TRACE_PTH_FNS) {
765 fprintf(stderr, "<< pthread_mxinit %p", mutex); fflush(stderr);
766 }
767
768 mbRec = 0;
769 if (attr) {
770 int ty, zzz;
771 zzz = pthread_mutexattr_gettype(attr, &ty);
772 if (zzz == 0 && ty == PTHREAD_MUTEX_RECURSIVE)
773 mbRec = 1;
774 }
775
776 CALL_FN_W_WW(ret, fn, mutex,attr);
777
778 if (ret == 0 /*success*/) {
779 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
780 pthread_mutex_t*,mutex, long,mbRec);
781 } else {
782 DO_PthAPIerror( "pthread_mutex_init", ret );
783 }
784
785 if (TRACE_PTH_FNS) {
786 fprintf(stderr, " :: mxinit -> %d >>\n", ret);
787 }
788 return ret;
789}
790
sewardj8eb8bab2015-07-21 14:44:28 +0000791#else /* VGO_solaris */
792
793// Solaris: mutex_init (pthread_mutex_init calls here)
794PTH_FUNC(int, mutexZuinit, // mutex_init
795 mutex_t *mutex, int type, void *arg)
796{
797 int ret;
798 long mbRec;
799 OrigFn fn;
800 VALGRIND_GET_ORIG_FN(fn);
801 if (TRACE_PTH_FNS) {
802 fprintf(stderr, "<< mxinit %p", mutex); fflush(stderr);
803 }
804
805 mbRec = ((type & LOCK_RECURSIVE) != 0) ? 1 : 0;
806
807 CALL_FN_W_WWW(ret, fn, mutex, type, arg);
808
809 if (ret == 0 /*success*/) {
810 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
811 mutex_t *, mutex, long, mbRec);
812 } else {
813 DO_PthAPIerror("mutex_init", ret);
814 }
815
816 if (TRACE_PTH_FNS) {
817 fprintf(stderr, " :: mxinit -> %d >>\n", ret);
818 }
819 return ret;
820}
821#endif /* VGO_solaris */
822
sewardjb4112022007-11-09 22:49:28 +0000823
sewardj1c147ff2009-07-26 19:52:06 +0000824//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +0000825// glibc: pthread_mutex_destroy
826// darwin: pthread_mutex_destroy
827// Solaris: mutex_destroy (pthread_mutex_destroy is a weak alias)
828__attribute__((noinline))
829static int mutex_destroy_WRK(pthread_mutex_t *mutex)
sewardjb4112022007-11-09 22:49:28 +0000830{
831 int ret;
sewardjc02f6c42013-10-14 13:51:25 +0000832 unsigned long mutex_is_init;
sewardjb4112022007-11-09 22:49:28 +0000833 OrigFn fn;
sewardjc02f6c42013-10-14 13:51:25 +0000834
sewardjb4112022007-11-09 22:49:28 +0000835 VALGRIND_GET_ORIG_FN(fn);
836 if (TRACE_PTH_FNS) {
837 fprintf(stderr, "<< pthread_mxdestroy %p", mutex); fflush(stderr);
838 }
839
sewardjc02f6c42013-10-14 13:51:25 +0000840 if (mutex != NULL) {
841 static const pthread_mutex_t mutex_init = PTHREAD_MUTEX_INITIALIZER;
842 mutex_is_init = my_memcmp(mutex, &mutex_init, sizeof(*mutex)) == 0;
843 } else {
844 mutex_is_init = 0;
845 }
846
847 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
848 pthread_mutex_t*, mutex, unsigned long, mutex_is_init);
sewardjb4112022007-11-09 22:49:28 +0000849
850 CALL_FN_W_W(ret, fn, mutex);
851
852 if (ret != 0) {
853 DO_PthAPIerror( "pthread_mutex_destroy", ret );
854 }
855
856 if (TRACE_PTH_FNS) {
857 fprintf(stderr, " :: mxdestroy -> %d >>\n", ret);
858 }
859 return ret;
860}
861
sewardj8eb8bab2015-07-21 14:44:28 +0000862#if defined(VGO_linux) || defined(VGO_darwin)
863 PTH_FUNC(int, pthreadZumutexZudestroy, // pthread_mutex_destroy
864 pthread_mutex_t *mutex) {
865 return mutex_destroy_WRK(mutex);
866 }
867#elif defined(VGO_solaris)
868 PTH_FUNC(int, mutexZudestroy, // mutex_destroy
869 pthread_mutex_t *mutex) {
870 return mutex_destroy_WRK(mutex);
871 }
872#else
873# error "Unsupported OS"
874#endif
875
sewardjb4112022007-11-09 22:49:28 +0000876
sewardj1c147ff2009-07-26 19:52:06 +0000877//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +0000878// glibc: pthread_mutex_lock
879// darwin: pthread_mutex_lock
880// Solaris: mutex_lock (pthread_mutex_lock is a weak alias)
881__attribute__((noinline))
882static int mutex_lock_WRK(pthread_mutex_t *mutex)
sewardjb4112022007-11-09 22:49:28 +0000883{
884 int ret;
885 OrigFn fn;
886 VALGRIND_GET_ORIG_FN(fn);
887 if (TRACE_PTH_FNS) {
888 fprintf(stderr, "<< pthread_mxlock %p", mutex); fflush(stderr);
889 }
890
891 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
892 pthread_mutex_t*,mutex, long,0/*!isTryLock*/);
893
894 CALL_FN_W_W(ret, fn, mutex);
895
896 /* There's a hole here: libpthread now knows the lock is locked,
897 but the tool doesn't, so some other thread could run and detect
898 that the lock has been acquired by someone (this thread). Does
899 this matter? Not sure, but I don't think so. */
900
sewardj8eb8bab2015-07-21 14:44:28 +0000901 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
902 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
903
904 if (ret != 0) {
sewardjb4112022007-11-09 22:49:28 +0000905 DO_PthAPIerror( "pthread_mutex_lock", ret );
906 }
907
908 if (TRACE_PTH_FNS) {
909 fprintf(stderr, " :: mxlock -> %d >>\n", ret);
910 }
911 return ret;
912}
913
sewardj8eb8bab2015-07-21 14:44:28 +0000914#if defined(VGO_linux) || defined(VGO_darwin)
915 PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock
916 pthread_mutex_t *mutex) {
917 return mutex_lock_WRK(mutex);
918 }
919#elif defined(VGO_solaris)
920 PTH_FUNC(int, mutexZulock, // mutex_lock
921 pthread_mutex_t *mutex) {
922 return mutex_lock_WRK(mutex);
923 }
924#else
925# error "Unsupported OS"
926#endif
927
928#if defined(VGO_solaris)
929/* Internal to libc. Mutex is usually initialized only implicitly,
930 * by zeroing mutex_t structure.
931 */
932__attribute__((noinline))
933PTH_FUNC(void, lmutexZulock, // lmutex_lock
934 mutex_t *mutex)
935{
936 OrigFn fn;
937 VALGRIND_GET_ORIG_FN(fn);
938 if (TRACE_PTH_FNS) {
939 fprintf(stderr, "<< lmxlock %p", mutex); fflush(stderr);
940 }
941
942 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
943 mutex_t *, mutex, long, 0 /*!isTryLock*/);
944 CALL_FN_v_W(fn, mutex);
945 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
946 mutex_t *, mutex, long, True);
947
948 if (TRACE_PTH_FNS) {
949 fprintf(stderr, " :: lmxlock >>\n");
950 }
951}
952#endif /* VGO_solaris */
953
sewardjb4112022007-11-09 22:49:28 +0000954
sewardj1c147ff2009-07-26 19:52:06 +0000955//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +0000956// glibc: pthread_mutex_trylock
957// darwin: pthread_mutex_trylock
958// Solaris: mutex_trylock (pthread_mutex_trylock is a weak alias)
sewardj1c147ff2009-07-26 19:52:06 +0000959//
sewardjb4112022007-11-09 22:49:28 +0000960// pthread_mutex_trylock. The handling needed here is very similar
961// to that for pthread_mutex_lock, except that we need to tell
962// the pre-lock creq that this is a trylock-style operation, and
963// therefore not to complain if the lock is nonrecursive and
964// already locked by this thread -- because then it'll just fail
965// immediately with EBUSY.
sewardj8eb8bab2015-07-21 14:44:28 +0000966__attribute__((noinline))
967static int mutex_trylock_WRK(pthread_mutex_t *mutex)
sewardjb4112022007-11-09 22:49:28 +0000968{
969 int ret;
970 OrigFn fn;
971 VALGRIND_GET_ORIG_FN(fn);
972 if (TRACE_PTH_FNS) {
973 fprintf(stderr, "<< pthread_mxtrylock %p", mutex); fflush(stderr);
974 }
975
976 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
977 pthread_mutex_t*,mutex, long,1/*isTryLock*/);
978
979 CALL_FN_W_W(ret, fn, mutex);
980
981 /* There's a hole here: libpthread now knows the lock is locked,
982 but the tool doesn't, so some other thread could run and detect
983 that the lock has been acquired by someone (this thread). Does
984 this matter? Not sure, but I don't think so. */
985
sewardj8eb8bab2015-07-21 14:44:28 +0000986 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
987 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
988
989 if (ret != 0) {
sewardjb4112022007-11-09 22:49:28 +0000990 if (ret != EBUSY)
991 DO_PthAPIerror( "pthread_mutex_trylock", ret );
992 }
993
994 if (TRACE_PTH_FNS) {
995 fprintf(stderr, " :: mxtrylock -> %d >>\n", ret);
996 }
997 return ret;
998}
999
sewardj8eb8bab2015-07-21 14:44:28 +00001000#if defined(VGO_linux) || defined(VGO_darwin)
1001 PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock
1002 pthread_mutex_t *mutex) {
1003 return mutex_trylock_WRK(mutex);
1004 }
1005#elif defined(VGO_solaris)
1006 PTH_FUNC(int, mutexZutrylock, // mutex_trylock
1007 pthread_mutex_t *mutex) {
1008 return mutex_trylock_WRK(mutex);
1009 }
1010#else
1011# error "Unsupported OS"
1012#endif
1013
sewardjb4112022007-11-09 22:49:28 +00001014
sewardj1c147ff2009-07-26 19:52:06 +00001015//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00001016// glibc: pthread_mutex_timedlock
1017// darwin: (doesn't appear to exist)
1018// Solaris: pthread_mutex_timedlock
sewardj1c147ff2009-07-26 19:52:06 +00001019//
sewardjb4112022007-11-09 22:49:28 +00001020// pthread_mutex_timedlock. Identical logic to pthread_mutex_trylock.
sewardj8eb8bab2015-07-21 14:44:28 +00001021__attribute__((noinline))
1022static int mutex_timedlock_WRK(pthread_mutex_t *mutex,
1023 void *timeout)
sewardjb4112022007-11-09 22:49:28 +00001024{
1025 int ret;
1026 OrigFn fn;
1027 VALGRIND_GET_ORIG_FN(fn);
1028 if (TRACE_PTH_FNS) {
1029 fprintf(stderr, "<< pthread_mxtimedlock %p %p", mutex, timeout);
1030 fflush(stderr);
1031 }
1032
1033 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
1034 pthread_mutex_t*,mutex, long,1/*isTryLock-ish*/);
1035
1036 CALL_FN_W_WW(ret, fn, mutex,timeout);
1037
1038 /* There's a hole here: libpthread now knows the lock is locked,
1039 but the tool doesn't, so some other thread could run and detect
1040 that the lock has been acquired by someone (this thread). Does
1041 this matter? Not sure, but I don't think so. */
1042
sewardj8eb8bab2015-07-21 14:44:28 +00001043 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1044 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
1045
1046 if (ret != 0) {
sewardjb4112022007-11-09 22:49:28 +00001047 if (ret != ETIMEDOUT)
1048 DO_PthAPIerror( "pthread_mutex_timedlock", ret );
1049 }
1050
1051 if (TRACE_PTH_FNS) {
1052 fprintf(stderr, " :: mxtimedlock -> %d >>\n", ret);
1053 }
1054 return ret;
1055}
1056
sewardj8eb8bab2015-07-21 14:44:28 +00001057PTH_FUNC(int, pthreadZumutexZutimedlock, // pthread_mutex_timedlock
1058 pthread_mutex_t *mutex,
1059 void *timeout) {
1060 return mutex_timedlock_WRK(mutex, timeout);
1061}
1062#if defined(VGO_solaris)
1063PTH_FUNC(int, pthreadZumutexZureltimedlock, // pthread_mutex_reltimedlock
1064 pthread_mutex_t *mutex,
1065 void *timeout) {
1066 return mutex_timedlock_WRK(mutex, timeout);
1067}
1068#endif
1069
sewardjb4112022007-11-09 22:49:28 +00001070
sewardj1c147ff2009-07-26 19:52:06 +00001071//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00001072// glibc: pthread_mutex_unlock
1073// darwin: pthread_mutex_unlock
1074// Solaris: mutex_unlock (pthread_mutex_unlock is a weak alias)
1075__attribute__((noinline))
1076static int mutex_unlock_WRK(pthread_mutex_t *mutex)
sewardjb4112022007-11-09 22:49:28 +00001077{
1078 int ret;
1079 OrigFn fn;
1080 VALGRIND_GET_ORIG_FN(fn);
1081
1082 if (TRACE_PTH_FNS) {
1083 fprintf(stderr, "<< pthread_mxunlk %p", mutex); fflush(stderr);
1084 }
1085
1086 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1087 pthread_mutex_t*,mutex);
1088
1089 CALL_FN_W_W(ret, fn, mutex);
1090
sewardj8eb8bab2015-07-21 14:44:28 +00001091 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
1092 pthread_mutex_t*,mutex);
1093
1094 if (ret != 0) {
sewardjb4112022007-11-09 22:49:28 +00001095 DO_PthAPIerror( "pthread_mutex_unlock", ret );
1096 }
1097
1098 if (TRACE_PTH_FNS) {
1099 fprintf(stderr, " mxunlk -> %d >>\n", ret);
1100 }
1101 return ret;
1102}
1103
sewardj8eb8bab2015-07-21 14:44:28 +00001104#if defined(VGO_linux) || defined(VGO_darwin)
1105 PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock
1106 pthread_mutex_t *mutex) {
1107 return mutex_unlock_WRK(mutex);
1108 }
1109#elif defined(VGO_solaris)
1110 PTH_FUNC(int, mutexZuunlock, // mutex_unlock
1111 pthread_mutex_t *mutex) {
1112 return mutex_unlock_WRK(mutex);
1113 }
1114#else
1115# error "Unsupported OS"
1116#endif
1117
1118
1119#if defined(VGO_solaris)
1120/* Internal to libc. */
1121__attribute__((noinline))
1122PTH_FUNC(void, lmutexZuunlock, // lmutex_unlock
1123 mutex_t *mutex)
1124{
1125 OrigFn fn;
1126 VALGRIND_GET_ORIG_FN(fn);
1127
1128 if (TRACE_PTH_FNS) {
1129 fprintf(stderr, "<< lmxunlk %p", mutex); fflush(stderr);
1130 }
1131
1132 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1133 mutex_t *, mutex);
1134 CALL_FN_v_W(fn, mutex);
1135 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
1136 mutex_t*, mutex);
1137
1138 if (TRACE_PTH_FNS) {
1139 fprintf(stderr, " lmxunlk >>\n");
1140 }
1141}
1142#endif /* VGO_solaris */
1143
sewardjb4112022007-11-09 22:49:28 +00001144
1145/*----------------------------------------------------------------*/
1146/*--- pthread_cond_t functions ---*/
1147/*----------------------------------------------------------------*/
1148
1149/* Handled: pthread_cond_wait pthread_cond_timedwait
1150 pthread_cond_signal pthread_cond_broadcast
philippe19dfe032013-03-24 20:10:23 +00001151 pthread_cond_init
sewardjf98e1c02008-10-25 16:22:41 +00001152 pthread_cond_destroy
sewardjb4112022007-11-09 22:49:28 +00001153*/
1154
sewardj1c147ff2009-07-26 19:52:06 +00001155//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00001156// glibc: pthread_cond_wait@GLIBC_2.2.5
1157// glibc: pthread_cond_wait@@GLIBC_2.3.2
1158// darwin: pthread_cond_wait
1159// darwin: pthread_cond_wait$NOCANCEL$UNIX2003
1160// darwin: pthread_cond_wait$UNIX2003
1161// Solaris: cond_wait (pthread_cond_wait is built atop of cond_wait)
sewardj1c147ff2009-07-26 19:52:06 +00001162//
florian31014da2011-09-26 00:29:44 +00001163__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +00001164static int pthread_cond_wait_WRK(pthread_cond_t* cond,
1165 pthread_mutex_t* mutex)
sewardjb4112022007-11-09 22:49:28 +00001166{
1167 int ret;
1168 OrigFn fn;
1169 unsigned long mutex_is_valid;
1170
1171 VALGRIND_GET_ORIG_FN(fn);
1172
1173 if (TRACE_PTH_FNS) {
1174 fprintf(stderr, "<< pthread_cond_wait %p %p", cond, mutex);
1175 fflush(stderr);
1176 }
1177
1178 /* Tell the tool a cond-wait is about to happen, so it can check
1179 for bogus argument values. In return it tells us whether it
1180 thinks the mutex is valid or not. */
1181 DO_CREQ_W_WW(mutex_is_valid,
1182 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
1183 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
1184 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
1185
1186 /* Tell the tool we're about to drop the mutex. This reflects the
1187 fact that in a cond_wait, we show up holding the mutex, and the
1188 call atomically drops the mutex and waits for the cv to be
1189 signalled. */
1190 if (mutex_is_valid) {
1191 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1192 pthread_mutex_t*,mutex);
1193 }
1194
1195 CALL_FN_W_WW(ret, fn, cond,mutex);
1196
sewardj8eb8bab2015-07-21 14:44:28 +00001197 /* this conditional look stupid, but compare w/ same logic for
sewardjb4112022007-11-09 22:49:28 +00001198 pthread_cond_timedwait below */
sewardj8eb8bab2015-07-21 14:44:28 +00001199 if (mutex_is_valid) {
1200 /* and now we have the mutex again if (ret == 0) */
1201 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1202 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
sewardjb4112022007-11-09 22:49:28 +00001203 }
1204
sewardj8eb8bab2015-07-21 14:44:28 +00001205 DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
1206 pthread_cond_t*,cond, pthread_mutex_t*,mutex, long,0,
1207 long, (ret == 0 && mutex_is_valid) ? True : False);
sewardjb4112022007-11-09 22:49:28 +00001208
1209 if (ret != 0) {
1210 DO_PthAPIerror( "pthread_cond_wait", ret );
1211 }
1212
1213 if (TRACE_PTH_FNS) {
1214 fprintf(stderr, " cowait -> %d >>\n", ret);
1215 }
1216
1217 return ret;
1218}
sewardj1c147ff2009-07-26 19:52:06 +00001219#if defined(VGO_linux)
1220 PTH_FUNC(int, pthreadZucondZuwaitZAZa, // pthread_cond_wait@*
1221 pthread_cond_t* cond, pthread_mutex_t* mutex) {
1222 return pthread_cond_wait_WRK(cond, mutex);
1223 }
1224#elif defined(VGO_darwin)
1225 PTH_FUNC(int, pthreadZucondZuwaitZa, // pthread_cond_wait*
1226 pthread_cond_t* cond, pthread_mutex_t* mutex) {
1227 return pthread_cond_wait_WRK(cond, mutex);
1228 }
sewardj8eb8bab2015-07-21 14:44:28 +00001229#elif defined(VGO_solaris)
1230 PTH_FUNC(int, condZuwait, // cond_wait
1231 pthread_cond_t *cond, pthread_mutex_t *mutex) {
1232 return pthread_cond_wait_WRK(cond, mutex);
1233 }
sewardj1c147ff2009-07-26 19:52:06 +00001234#else
1235# error "Unsupported OS"
1236#endif
sewardjb4112022007-11-09 22:49:28 +00001237
1238
sewardj1c147ff2009-07-26 19:52:06 +00001239//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00001240// glibc: pthread_cond_timedwait@@GLIBC_2.3.2
1241// glibc: pthread_cond_timedwait@GLIBC_2.2.5
1242// glibc: pthread_cond_timedwait@GLIBC_2.0
1243// darwin: pthread_cond_timedwait
1244// darwin: pthread_cond_timedwait$NOCANCEL$UNIX2003
1245// darwin: pthread_cond_timedwait$UNIX2003
1246// darwin: pthread_cond_timedwait_relative_np (trapped)
1247// Solaris: cond_timedwait (pthread_cond_timedwait is built on cond_timedwait)
1248// Solaris: cond_reltimedwait (pthread_cond_reltimedwait_np is built on this)
sewardj1c147ff2009-07-26 19:52:06 +00001249//
florian31014da2011-09-26 00:29:44 +00001250__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +00001251static int pthread_cond_timedwait_WRK(pthread_cond_t* cond,
1252 pthread_mutex_t* mutex,
sewardj8eb8bab2015-07-21 14:44:28 +00001253 struct timespec* abstime,
1254 int timeout_error)
sewardjb4112022007-11-09 22:49:28 +00001255{
1256 int ret;
1257 OrigFn fn;
1258 unsigned long mutex_is_valid;
sewardj6aeadaa2011-10-19 05:41:34 +00001259 Bool abstime_is_valid;
sewardjb4112022007-11-09 22:49:28 +00001260 VALGRIND_GET_ORIG_FN(fn);
1261
1262 if (TRACE_PTH_FNS) {
1263 fprintf(stderr, "<< pthread_cond_timedwait %p %p %p",
1264 cond, mutex, abstime);
1265 fflush(stderr);
1266 }
1267
1268 /* Tell the tool a cond-wait is about to happen, so it can check
1269 for bogus argument values. In return it tells us whether it
1270 thinks the mutex is valid or not. */
1271 DO_CREQ_W_WW(mutex_is_valid,
1272 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
1273 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
1274 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
1275
sewardj6aeadaa2011-10-19 05:41:34 +00001276 abstime_is_valid = abstime->tv_nsec >= 0 && abstime->tv_nsec < 1000000000;
1277
sewardjb4112022007-11-09 22:49:28 +00001278 /* Tell the tool we're about to drop the mutex. This reflects the
1279 fact that in a cond_wait, we show up holding the mutex, and the
1280 call atomically drops the mutex and waits for the cv to be
1281 signalled. */
sewardj6aeadaa2011-10-19 05:41:34 +00001282 if (mutex_is_valid && abstime_is_valid) {
sewardjb4112022007-11-09 22:49:28 +00001283 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1284 pthread_mutex_t*,mutex);
1285 }
1286
1287 CALL_FN_W_WWW(ret, fn, cond,mutex,abstime);
1288
sewardj8eb8bab2015-07-21 14:44:28 +00001289 if (mutex_is_valid && !abstime_is_valid && ret != EINVAL) {
sewardj6aeadaa2011-10-19 05:41:34 +00001290 DO_PthAPIerror("Bug in libpthread: pthread_cond_timedwait "
1291 "invalid abstime did not cause"
1292 " EINVAL", ret);
1293 }
1294
sewardj8eb8bab2015-07-21 14:44:28 +00001295 if (mutex_is_valid && abstime_is_valid) {
1296 /* and now we have the mutex again if (ret == 0 || ret == timeout) */
1297 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1298 pthread_mutex_t *, mutex,
1299 long, (ret == 0 || ret == timeout_error) ? True : False);
sewardjb4112022007-11-09 22:49:28 +00001300 }
1301
sewardj8eb8bab2015-07-21 14:44:28 +00001302 DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
1303 pthread_cond_t*,cond, pthread_mutex_t*,mutex,
1304 long,ret == timeout_error,
1305 long, (ret == 0 || ret == timeout_error) && mutex_is_valid
1306 ? True : False);
sewardjb4112022007-11-09 22:49:28 +00001307
sewardj8eb8bab2015-07-21 14:44:28 +00001308 if (ret != 0 && ret != timeout_error) {
sewardjb4112022007-11-09 22:49:28 +00001309 DO_PthAPIerror( "pthread_cond_timedwait", ret );
1310 }
1311
1312 if (TRACE_PTH_FNS) {
1313 fprintf(stderr, " cotimedwait -> %d >>\n", ret);
1314 }
1315
1316 return ret;
1317}
sewardj1c147ff2009-07-26 19:52:06 +00001318#if defined(VGO_linux)
1319 PTH_FUNC(int, pthreadZucondZutimedwaitZAZa, // pthread_cond_timedwait@*
1320 pthread_cond_t* cond, pthread_mutex_t* mutex,
1321 struct timespec* abstime) {
sewardj8eb8bab2015-07-21 14:44:28 +00001322 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
sewardj1c147ff2009-07-26 19:52:06 +00001323 }
1324#elif defined(VGO_darwin)
1325 PTH_FUNC(int, pthreadZucondZutimedwait, // pthread_cond_timedwait
1326 pthread_cond_t* cond, pthread_mutex_t* mutex,
1327 struct timespec* abstime) {
sewardj8eb8bab2015-07-21 14:44:28 +00001328 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
sewardj1c147ff2009-07-26 19:52:06 +00001329 }
1330 PTH_FUNC(int, pthreadZucondZutimedwaitZDZa, // pthread_cond_timedwait$*
1331 pthread_cond_t* cond, pthread_mutex_t* mutex,
1332 struct timespec* abstime) {
sewardj8eb8bab2015-07-21 14:44:28 +00001333 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
sewardj1c147ff2009-07-26 19:52:06 +00001334 }
1335 PTH_FUNC(int, pthreadZucondZutimedwaitZuZa, // pthread_cond_timedwait_*
1336 pthread_cond_t* cond, pthread_mutex_t* mutex,
1337 struct timespec* abstime) {
1338 assert(0);
1339 }
sewardj8eb8bab2015-07-21 14:44:28 +00001340#elif defined(VGO_solaris)
1341 PTH_FUNC(int, condZutimedwait, // cond_timedwait
1342 pthread_cond_t *cond, pthread_mutex_t *mutex,
1343 struct timespec *abstime) {
1344 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIME);
1345 }
1346 PTH_FUNC(int, condZureltimedwait, // cond_reltimedwait
1347 pthread_cond_t *cond, pthread_mutex_t *mutex,
1348 struct timespec *reltime) {
1349 return pthread_cond_timedwait_WRK(cond, mutex, reltime, ETIME);
1350 }
sewardj1c147ff2009-07-26 19:52:06 +00001351#else
1352# error "Unsupported OS"
1353#endif
sewardjb4112022007-11-09 22:49:28 +00001354
1355
sewardj1c147ff2009-07-26 19:52:06 +00001356//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00001357// glibc: pthread_cond_signal@GLIBC_2.0
1358// glibc: pthread_cond_signal@GLIBC_2.2.5
1359// glibc: pthread_cond_signal@@GLIBC_2.3.2
1360// darwin: pthread_cond_signal
1361// darwin: pthread_cond_signal_thread_np (don't intercept this)
1362// Solaris: cond_signal (pthread_cond_signal is a weak alias)
sewardj1c147ff2009-07-26 19:52:06 +00001363//
florian31014da2011-09-26 00:29:44 +00001364__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +00001365static int pthread_cond_signal_WRK(pthread_cond_t* cond)
sewardjb4112022007-11-09 22:49:28 +00001366{
1367 int ret;
1368 OrigFn fn;
1369 VALGRIND_GET_ORIG_FN(fn);
1370
1371 if (TRACE_PTH_FNS) {
1372 fprintf(stderr, "<< pthread_cond_signal %p", cond);
1373 fflush(stderr);
1374 }
1375
1376 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE,
1377 pthread_cond_t*,cond);
1378
1379 CALL_FN_W_W(ret, fn, cond);
1380
sewardj8eb8bab2015-07-21 14:44:28 +00001381 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_POST,
1382 pthread_cond_t*,cond);
1383
sewardjb4112022007-11-09 22:49:28 +00001384 if (ret != 0) {
1385 DO_PthAPIerror( "pthread_cond_signal", ret );
1386 }
1387
1388 if (TRACE_PTH_FNS) {
1389 fprintf(stderr, " cosig -> %d >>\n", ret);
1390 }
1391
1392 return ret;
1393}
sewardj1c147ff2009-07-26 19:52:06 +00001394#if defined(VGO_linux)
1395 PTH_FUNC(int, pthreadZucondZusignalZAZa, // pthread_cond_signal@*
1396 pthread_cond_t* cond) {
1397 return pthread_cond_signal_WRK(cond);
1398 }
1399#elif defined(VGO_darwin)
1400 PTH_FUNC(int, pthreadZucondZusignal, // pthread_cond_signal
1401 pthread_cond_t* cond) {
1402 return pthread_cond_signal_WRK(cond);
1403 }
sewardj8eb8bab2015-07-21 14:44:28 +00001404#elif defined(VGO_solaris)
1405 PTH_FUNC(int, condZusignal, // cond_signal
1406 pthread_cond_t *cond) {
1407 return pthread_cond_signal_WRK(cond);
1408 }
sewardj1c147ff2009-07-26 19:52:06 +00001409#else
1410# error "Unsupported OS"
1411#endif
sewardjb4112022007-11-09 22:49:28 +00001412
1413
sewardj1c147ff2009-07-26 19:52:06 +00001414//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00001415// glibc: pthread_cond_broadcast@GLIBC_2.0
1416// glibc: pthread_cond_broadcast@GLIBC_2.2.5
1417// glibc: pthread_cond_broadcast@@GLIBC_2.3.2
1418// darwin: pthread_cond_broadcast
1419// Solaris: cond_broadcast (pthread_cond_broadcast is a weak alias)
sewardj1c147ff2009-07-26 19:52:06 +00001420//
sewardjb4112022007-11-09 22:49:28 +00001421// Note, this is pretty much identical, from a dependency-graph
1422// point of view, with cond_signal, so the code is duplicated.
1423// Maybe it should be commoned up.
sewardj1c147ff2009-07-26 19:52:06 +00001424//
florian31014da2011-09-26 00:29:44 +00001425__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +00001426static int pthread_cond_broadcast_WRK(pthread_cond_t* cond)
sewardjb4112022007-11-09 22:49:28 +00001427{
1428 int ret;
1429 OrigFn fn;
1430 VALGRIND_GET_ORIG_FN(fn);
1431
1432 if (TRACE_PTH_FNS) {
sewardj1c147ff2009-07-26 19:52:06 +00001433 fprintf(stderr, "<< pthread_cond_broadcast %p", cond);
sewardjb4112022007-11-09 22:49:28 +00001434 fflush(stderr);
1435 }
1436
1437 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE,
1438 pthread_cond_t*,cond);
1439
1440 CALL_FN_W_W(ret, fn, cond);
1441
sewardj8eb8bab2015-07-21 14:44:28 +00001442 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_POST,
1443 pthread_cond_t*,cond);
1444
sewardjb4112022007-11-09 22:49:28 +00001445 if (ret != 0) {
1446 DO_PthAPIerror( "pthread_cond_broadcast", ret );
1447 }
1448
1449 if (TRACE_PTH_FNS) {
1450 fprintf(stderr, " cobro -> %d >>\n", ret);
1451 }
1452
1453 return ret;
1454}
sewardj1c147ff2009-07-26 19:52:06 +00001455#if defined(VGO_linux)
1456 PTH_FUNC(int, pthreadZucondZubroadcastZAZa, // pthread_cond_broadcast@*
1457 pthread_cond_t* cond) {
1458 return pthread_cond_broadcast_WRK(cond);
1459 }
1460#elif defined(VGO_darwin)
1461 PTH_FUNC(int, pthreadZucondZubroadcast, // pthread_cond_broadcast
1462 pthread_cond_t* cond) {
1463 return pthread_cond_broadcast_WRK(cond);
1464 }
sewardj8eb8bab2015-07-21 14:44:28 +00001465#elif defined(VGO_solaris)
1466 PTH_FUNC(int, condZubroadcast, // cond_broadcast
1467 pthread_cond_t *cond) {
1468 return pthread_cond_broadcast_WRK(cond);
1469 }
sewardj1c147ff2009-07-26 19:52:06 +00001470#else
1471# error "Unsupported OS"
1472#endif
sewardjb4112022007-11-09 22:49:28 +00001473
sewardj8eb8bab2015-07-21 14:44:28 +00001474// glibc: pthread_cond_init@GLIBC_2.0
1475// glibc: pthread_cond_init@GLIBC_2.2.5
1476// glibc: pthread_cond_init@@GLIBC_2.3.2
1477// darwin: pthread_cond_init
1478// Solaris: cond_init (pthread_cond_init is built atop on this function)
philippe19dfe032013-03-24 20:10:23 +00001479// Easy way out: Handling of attr could have been messier.
1480// It turns out that pthread_cond_init under linux ignores
1481// all information in cond_attr, so do we.
1482// FIXME: MacOS X?
sewardj8eb8bab2015-07-21 14:44:28 +00001483#if !defined(VGO_solaris)
philippe19dfe032013-03-24 20:10:23 +00001484__attribute__((noinline))
1485static int pthread_cond_init_WRK(pthread_cond_t* cond, pthread_condattr_t *cond_attr)
1486{
1487 int ret;
1488 OrigFn fn;
1489 VALGRIND_GET_ORIG_FN(fn);
1490
1491 if (TRACE_PTH_FNS) {
1492 fprintf(stderr, "<< pthread_cond_init %p", cond);
1493 fflush(stderr);
1494 }
1495
1496 CALL_FN_W_WW(ret, fn, cond, cond_attr);
1497
1498 if (ret == 0) {
1499 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST,
1500 pthread_cond_t*,cond, pthread_condattr_t*, cond_attr);
1501 } else {
1502 DO_PthAPIerror( "pthread_cond_init", ret );
1503 }
1504
1505 if (TRACE_PTH_FNS) {
1506 fprintf(stderr, " coinit -> %d >>\n", ret);
1507 }
1508
1509 return ret;
1510}
1511#if defined(VGO_linux)
1512 PTH_FUNC(int, pthreadZucondZuinitZAZa, // pthread_cond_init@*
1513 pthread_cond_t* cond, pthread_condattr_t* cond_attr) {
1514 return pthread_cond_init_WRK(cond, cond_attr);
1515 }
1516#elif defined(VGO_darwin)
1517 PTH_FUNC(int, pthreadZucondZuinit, // pthread_cond_init
1518 pthread_cond_t* cond, pthread_condattr_t * cond_attr) {
1519 return pthread_cond_init_WRK(cond, cond_attr);
1520 }
1521#else
1522# error "Unsupported OS"
1523#endif
1524
sewardj8eb8bab2015-07-21 14:44:28 +00001525#else /* VGO_solaris */
1526__attribute__((noinline))
1527PTH_FUNC(int, condZuinit, // cond_init
1528 cond_t *cond, int type, void *arg)
1529{
1530 int ret;
1531 OrigFn fn;
1532 VALGRIND_GET_ORIG_FN(fn);
1533
1534 if (TRACE_PTH_FNS) {
1535 fprintf(stderr, "<< cond_init %p", cond); fflush(stderr);
1536 }
1537
1538 CALL_FN_W_WWW(ret, fn, cond, type, arg);
1539
1540 if (ret == 0) {
1541 /* Luckily evh__HG_PTHREAD_COND_INIT_POST() ignores cond_attr.
1542 See also comment for pthread_cond_init_WRK(). */
1543 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST,
1544 cond_t *, cond, void *, NULL);
1545 } else {
1546 DO_PthAPIerror("cond_init", ret);
1547 }
1548
1549 if (TRACE_PTH_FNS) {
1550 fprintf(stderr, " cond_init -> %d >>\n", ret);
1551 }
1552
1553 return ret;
1554}
1555#endif /* VGO_solaris */
1556
sewardjb4112022007-11-09 22:49:28 +00001557
sewardj1c147ff2009-07-26 19:52:06 +00001558//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00001559// glibc: pthread_cond_destroy@@GLIBC_2.3.2
1560// glibc: pthread_cond_destroy@GLIBC_2.2.5
1561// glibc: pthread_cond_destroy@GLIBC_2.0
1562// darwin: pthread_cond_destroy
1563// Solaris: cond_destroy (pthread_cond_destroy is a weak alias)
sewardj1c147ff2009-07-26 19:52:06 +00001564//
florian31014da2011-09-26 00:29:44 +00001565__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +00001566static int pthread_cond_destroy_WRK(pthread_cond_t* cond)
sewardjf98e1c02008-10-25 16:22:41 +00001567{
1568 int ret;
sewardjc02f6c42013-10-14 13:51:25 +00001569 unsigned long cond_is_init;
sewardjf98e1c02008-10-25 16:22:41 +00001570 OrigFn fn;
1571
1572 VALGRIND_GET_ORIG_FN(fn);
1573
1574 if (TRACE_PTH_FNS) {
1575 fprintf(stderr, "<< pthread_cond_destroy %p", cond);
1576 fflush(stderr);
1577 }
1578
sewardjc02f6c42013-10-14 13:51:25 +00001579 if (cond != NULL) {
1580 const pthread_cond_t cond_init = PTHREAD_COND_INITIALIZER;
1581 cond_is_init = my_memcmp(cond, &cond_init, sizeof(*cond)) == 0;
1582 } else {
1583 cond_is_init = 0;
1584 }
1585
1586 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_DESTROY_PRE,
1587 pthread_cond_t*, cond, unsigned long, cond_is_init);
sewardjf98e1c02008-10-25 16:22:41 +00001588
1589 CALL_FN_W_W(ret, fn, cond);
1590
1591 if (ret != 0) {
1592 DO_PthAPIerror( "pthread_cond_destroy", ret );
1593 }
1594
1595 if (TRACE_PTH_FNS) {
1596 fprintf(stderr, " codestr -> %d >>\n", ret);
1597 }
1598
1599 return ret;
1600}
sewardj1c147ff2009-07-26 19:52:06 +00001601#if defined(VGO_linux)
1602 PTH_FUNC(int, pthreadZucondZudestroyZAZa, // pthread_cond_destroy@*
1603 pthread_cond_t* cond) {
1604 return pthread_cond_destroy_WRK(cond);
1605 }
1606#elif defined(VGO_darwin)
1607 PTH_FUNC(int, pthreadZucondZudestroy, // pthread_cond_destroy
1608 pthread_cond_t* cond) {
1609 return pthread_cond_destroy_WRK(cond);
1610 }
sewardj8eb8bab2015-07-21 14:44:28 +00001611#elif defined(VGO_solaris)
1612 PTH_FUNC(int, condZudestroy, // cond_destroy
1613 pthread_cond_t *cond) {
1614 return pthread_cond_destroy_WRK(cond);
1615 }
sewardj1c147ff2009-07-26 19:52:06 +00001616#else
1617# error "Unsupported OS"
1618#endif
sewardjf98e1c02008-10-25 16:22:41 +00001619
1620
1621/*----------------------------------------------------------------*/
1622/*--- pthread_barrier_t functions ---*/
1623/*----------------------------------------------------------------*/
1624
njnf76d27a2009-05-28 01:53:07 +00001625#if defined(HAVE_PTHREAD_BARRIER_INIT)
1626
sewardj9f569b72008-11-13 13:33:09 +00001627/* Handled: pthread_barrier_init
1628 pthread_barrier_wait
1629 pthread_barrier_destroy
1630
1631 Unhandled: pthread_barrierattr_destroy
1632 pthread_barrierattr_getpshared
1633 pthread_barrierattr_init
1634 pthread_barrierattr_setpshared
1635 -- are these important?
1636*/
1637
sewardj1c147ff2009-07-26 19:52:06 +00001638//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00001639// glibc: pthread_barrier_init
1640// darwin: (doesn't appear to exist)
1641// Solaris: pthread_barrier_init
sewardj9f569b72008-11-13 13:33:09 +00001642PTH_FUNC(int, pthreadZubarrierZuinit, // pthread_barrier_init
1643 pthread_barrier_t* bar,
1644 pthread_barrierattr_t* attr, unsigned long count)
sewardjf98e1c02008-10-25 16:22:41 +00001645{
1646 int ret;
1647 OrigFn fn;
1648 VALGRIND_GET_ORIG_FN(fn);
1649
1650 if (TRACE_PTH_FNS) {
sewardj9f569b72008-11-13 13:33:09 +00001651 fprintf(stderr, "<< pthread_barrier_init %p %p %lu",
1652 bar, attr, count);
sewardjf98e1c02008-10-25 16:22:41 +00001653 fflush(stderr);
1654 }
1655
sewardj406bac82010-03-03 23:03:40 +00001656 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE,
1657 pthread_barrier_t*, bar,
1658 unsigned long, count,
1659 unsigned long, 0/*!resizable*/);
sewardjf98e1c02008-10-25 16:22:41 +00001660
sewardj9f569b72008-11-13 13:33:09 +00001661 CALL_FN_W_WWW(ret, fn, bar,attr,count);
sewardjf98e1c02008-10-25 16:22:41 +00001662
sewardj9f569b72008-11-13 13:33:09 +00001663 if (ret != 0) {
1664 DO_PthAPIerror( "pthread_barrier_init", ret );
1665 }
1666
1667 if (TRACE_PTH_FNS) {
1668 fprintf(stderr, " pthread_barrier_init -> %d >>\n", ret);
1669 }
1670
1671 return ret;
1672}
1673
1674
sewardj1c147ff2009-07-26 19:52:06 +00001675//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00001676// glibc: pthread_barrier_wait
1677// darwin: (doesn't appear to exist)
1678// Solaris: pthread_barrier_wait
sewardj9f569b72008-11-13 13:33:09 +00001679PTH_FUNC(int, pthreadZubarrierZuwait, // pthread_barrier_wait
1680 pthread_barrier_t* bar)
1681{
1682 int ret;
1683 OrigFn fn;
1684 VALGRIND_GET_ORIG_FN(fn);
1685
1686 if (TRACE_PTH_FNS) {
1687 fprintf(stderr, "<< pthread_barrier_wait %p", bar);
1688 fflush(stderr);
1689 }
1690
1691 /* That this works correctly, and doesn't screw up when a thread
1692 leaving the barrier races round to the front and re-enters while
1693 other threads are still leaving it, is quite subtle. See
1694 comments in the handler for PTHREAD_BARRIER_WAIT_PRE in
1695 hg_main.c. */
1696 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE,
1697 pthread_barrier_t*,bar);
1698
1699 CALL_FN_W_W(ret, fn, bar);
1700
1701 if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) {
1702 DO_PthAPIerror( "pthread_barrier_wait", ret );
1703 }
sewardjf98e1c02008-10-25 16:22:41 +00001704
1705 if (TRACE_PTH_FNS) {
1706 fprintf(stderr, " pthread_barrier_wait -> %d >>\n", ret);
1707 }
1708
1709 return ret;
1710}
1711
1712
sewardj1c147ff2009-07-26 19:52:06 +00001713//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00001714// glibc: pthread_barrier_destroy
1715// darwin: (doesn't appear to exist)
1716// Solaris: pthread_barrier_destroy
sewardj9f569b72008-11-13 13:33:09 +00001717PTH_FUNC(int, pthreadZubarrierZudestroy, // pthread_barrier_destroy
1718 pthread_barrier_t* bar)
1719{
1720 int ret;
1721 OrigFn fn;
1722 VALGRIND_GET_ORIG_FN(fn);
1723
1724 if (TRACE_PTH_FNS) {
1725 fprintf(stderr, "<< pthread_barrier_destroy %p", bar);
1726 fflush(stderr);
1727 }
1728
1729 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE,
1730 pthread_barrier_t*,bar);
1731
1732 CALL_FN_W_W(ret, fn, bar);
1733
1734 if (ret != 0) {
1735 DO_PthAPIerror( "pthread_barrier_destroy", ret );
1736 }
1737
1738 if (TRACE_PTH_FNS) {
1739 fprintf(stderr, " pthread_barrier_destroy -> %d >>\n", ret);
1740 }
1741
1742 return ret;
1743}
sewardjf98e1c02008-10-25 16:22:41 +00001744
njnf76d27a2009-05-28 01:53:07 +00001745#endif // defined(HAVE_PTHREAD_BARRIER_INIT)
1746
sewardj5a644da2009-08-11 10:35:58 +00001747
1748/*----------------------------------------------------------------*/
1749/*--- pthread_spinlock_t functions ---*/
1750/*----------------------------------------------------------------*/
1751
petarj6d79b742012-12-20 18:56:57 +00001752#if defined(HAVE_PTHREAD_SPIN_LOCK) \
1753 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
sewardj5a644da2009-08-11 10:35:58 +00001754
1755/* Handled: pthread_spin_init pthread_spin_destroy
1756 pthread_spin_lock pthread_spin_trylock
1757 pthread_spin_unlock
1758
1759 Unhandled:
1760*/
1761
1762/* This is a nasty kludge, in that glibc "knows" that initialising a
1763 spin lock unlocks it, and pthread_spin_{init,unlock} are names for
1764 the same function. Hence we have to have a wrapper which does both
sewardj8eb8bab2015-07-21 14:44:28 +00001765 things, without knowing which the user intended to happen.
1766 Solaris has distinct functions for init/unlock but client requests
1767 are immutable in helgrind.h so follow the glibc lead. */
sewardj5a644da2009-08-11 10:35:58 +00001768
1769//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00001770// glibc: pthread_spin_init
1771// glibc: pthread_spin_unlock
1772// darwin: (doesn't appear to exist)
1773// Solaris: pthread_spin_init
1774// Solaris: pthread_spin_unlock
florian31014da2011-09-26 00:29:44 +00001775__attribute__((noinline))
sewardj5a644da2009-08-11 10:35:58 +00001776static int pthread_spin_init_or_unlock_WRK(pthread_spinlock_t* lock,
1777 int pshared) {
1778 int ret;
1779 OrigFn fn;
1780 VALGRIND_GET_ORIG_FN(fn);
1781 if (TRACE_PTH_FNS) {
1782 fprintf(stderr, "<< pthread_spin_iORu %p", lock); fflush(stderr);
1783 }
1784
1785 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE,
1786 pthread_spinlock_t*, lock);
1787
1788 CALL_FN_W_WW(ret, fn, lock,pshared);
1789
1790 if (ret == 0 /*success*/) {
1791 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST,
1792 pthread_spinlock_t*,lock);
1793 } else {
1794 DO_PthAPIerror( "pthread_spinlock_{init,unlock}", ret );
1795 }
1796
1797 if (TRACE_PTH_FNS) {
1798 fprintf(stderr, " :: spiniORu -> %d >>\n", ret);
1799 }
1800 return ret;
1801}
1802#if defined(VGO_linux)
1803 PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
1804 pthread_spinlock_t* lock, int pshared) {
1805 return pthread_spin_init_or_unlock_WRK(lock, pshared);
1806 }
1807 PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
1808 pthread_spinlock_t* lock) {
1809 /* this is never actually called */
1810 return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/);
1811 }
1812#elif defined(VGO_darwin)
sewardj8eb8bab2015-07-21 14:44:28 +00001813#elif defined(VGO_solaris)
1814 PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
1815 pthread_spinlock_t *lock, int pshared) {
1816 return pthread_spin_init_or_unlock_WRK(lock, pshared);
1817 }
1818 PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
1819 pthread_spinlock_t *lock) {
1820 return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/);
1821 }
sewardj5a644da2009-08-11 10:35:58 +00001822#else
1823# error "Unsupported OS"
1824#endif
1825
1826
1827//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00001828// glibc: pthread_spin_destroy
1829// darwin: (doesn't appear to exist)
1830// Solaris: pthread_spin_destroy
1831__attribute__((noinline))
1832static int pthread_spin_destroy_WRK(pthread_spinlock_t *lock)
sewardj5a644da2009-08-11 10:35:58 +00001833{
1834 int ret;
1835 OrigFn fn;
1836 VALGRIND_GET_ORIG_FN(fn);
1837 if (TRACE_PTH_FNS) {
1838 fprintf(stderr, "<< pthread_spin_destroy %p", lock);
1839 fflush(stderr);
1840 }
1841
1842 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_DESTROY_PRE,
1843 pthread_spinlock_t*,lock);
1844
1845 CALL_FN_W_W(ret, fn, lock);
1846
1847 if (ret != 0) {
1848 DO_PthAPIerror( "pthread_spin_destroy", ret );
1849 }
1850
1851 if (TRACE_PTH_FNS) {
1852 fprintf(stderr, " :: spindestroy -> %d >>\n", ret);
1853 }
1854 return ret;
1855}
sewardj8eb8bab2015-07-21 14:44:28 +00001856#if defined(VGO_linux)
Elliott Hughesa0664b92017-04-18 17:46:52 -07001857 PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy
sewardj8eb8bab2015-07-21 14:44:28 +00001858 pthread_spinlock_t *lock) {
1859 return pthread_spin_destroy_WRK(lock);
1860 }
sewardj5a644da2009-08-11 10:35:58 +00001861#elif defined(VGO_darwin)
sewardj8eb8bab2015-07-21 14:44:28 +00001862#elif defined(VGO_solaris)
Elliott Hughesa0664b92017-04-18 17:46:52 -07001863 PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy
sewardj8eb8bab2015-07-21 14:44:28 +00001864 pthread_spinlock_t *lock) {
1865 return pthread_spin_destroy_WRK(lock);
1866 }
sewardj5a644da2009-08-11 10:35:58 +00001867#else
1868# error "Unsupported OS"
1869#endif
1870
1871
1872//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00001873// glibc: pthread_spin_lock
1874// darwin: (doesn't appear to exist)
1875// Solaris: pthread_spin_lock
1876__attribute__((noinline))
1877static int pthread_spin_lock_WRK(pthread_spinlock_t *lock)
sewardj5a644da2009-08-11 10:35:58 +00001878{
1879 int ret;
1880 OrigFn fn;
1881 VALGRIND_GET_ORIG_FN(fn);
1882 if (TRACE_PTH_FNS) {
1883 fprintf(stderr, "<< pthread_spinlock %p", lock);
1884 fflush(stderr);
1885 }
1886
1887 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE,
1888 pthread_spinlock_t*,lock, long,0/*!isTryLock*/);
1889
1890 CALL_FN_W_W(ret, fn, lock);
1891
1892 /* There's a hole here: libpthread now knows the lock is locked,
1893 but the tool doesn't, so some other thread could run and detect
1894 that the lock has been acquired by someone (this thread). Does
1895 this matter? Not sure, but I don't think so. */
1896
1897 if (ret == 0 /*success*/) {
1898 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST,
1899 pthread_spinlock_t*,lock);
1900 } else {
1901 DO_PthAPIerror( "pthread_spin_lock", ret );
1902 }
1903
1904 if (TRACE_PTH_FNS) {
1905 fprintf(stderr, " :: spinlock -> %d >>\n", ret);
1906 }
1907 return ret;
1908}
sewardj8eb8bab2015-07-21 14:44:28 +00001909#if defined(VGO_linux)
1910 PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
1911 pthread_spinlock_t *lock) {
1912 return pthread_spin_lock_WRK(lock);
1913 }
sewardj5a644da2009-08-11 10:35:58 +00001914#elif defined(VGO_darwin)
sewardj8eb8bab2015-07-21 14:44:28 +00001915#elif defined(VGO_solaris)
1916 PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
1917 pthread_spinlock_t *lock) {
1918 return pthread_spin_lock_WRK(lock);
1919 }
sewardj5a644da2009-08-11 10:35:58 +00001920#else
1921# error "Unsupported OS"
1922#endif
1923
1924
1925//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00001926// glibc: pthread_spin_trylock
1927// darwin: (doesn't appear to exist)
1928// Solaris: pthread_spin_trylock
1929__attribute__((noinline))
1930static int pthread_spin_trylock_WRK(pthread_spinlock_t *lock)
sewardj5a644da2009-08-11 10:35:58 +00001931{
1932 int ret;
1933 OrigFn fn;
1934 VALGRIND_GET_ORIG_FN(fn);
1935 if (TRACE_PTH_FNS) {
1936 fprintf(stderr, "<< pthread_spin_trylock %p", lock);
1937 fflush(stderr);
1938 }
1939
1940 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE,
1941 pthread_spinlock_t*,lock, long,1/*isTryLock*/);
1942
1943 CALL_FN_W_W(ret, fn, lock);
1944
1945 /* There's a hole here: libpthread now knows the lock is locked,
1946 but the tool doesn't, so some other thread could run and detect
1947 that the lock has been acquired by someone (this thread). Does
1948 this matter? Not sure, but I don't think so. */
1949
1950 if (ret == 0 /*success*/) {
1951 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST,
1952 pthread_spinlock_t*,lock);
1953 } else {
1954 if (ret != EBUSY)
1955 DO_PthAPIerror( "pthread_spin_trylock", ret );
1956 }
1957
1958 if (TRACE_PTH_FNS) {
1959 fprintf(stderr, " :: spin_trylock -> %d >>\n", ret);
1960 }
1961 return ret;
1962}
sewardj8eb8bab2015-07-21 14:44:28 +00001963#if defined(VGO_linux)
1964 PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
1965 pthread_spinlock_t *lock) {
1966 return pthread_spin_trylock_WRK(lock);
1967 }
sewardj5a644da2009-08-11 10:35:58 +00001968#elif defined(VGO_darwin)
sewardj8eb8bab2015-07-21 14:44:28 +00001969#elif defined(VGO_solaris)
1970 PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
1971 pthread_spinlock_t *lock) {
1972 return pthread_spin_trylock_WRK(lock);
1973 }
sewardj5a644da2009-08-11 10:35:58 +00001974#else
1975# error "Unsupported OS"
1976#endif
1977
1978#endif // defined(HAVE_PTHREAD_SPIN_LOCK)
1979
1980
sewardjb4112022007-11-09 22:49:28 +00001981/*----------------------------------------------------------------*/
1982/*--- pthread_rwlock_t functions ---*/
1983/*----------------------------------------------------------------*/
1984
sewardj0c09bf02011-07-11 22:11:58 +00001985/* Android's pthread.h doesn't say anything about rwlocks, hence these
1986 functions have to be conditionally compiled. */
1987#if defined(HAVE_PTHREAD_RWLOCK_T)
1988
sewardjb4112022007-11-09 22:49:28 +00001989/* Handled: pthread_rwlock_init pthread_rwlock_destroy
1990 pthread_rwlock_rdlock
1991 pthread_rwlock_wrlock
1992 pthread_rwlock_unlock
sewardj8eb8bab2015-07-21 14:44:28 +00001993 pthread_rwlock_tryrdlock
1994 pthread_rwlock_trywrlock
sewardjb4112022007-11-09 22:49:28 +00001995
1996 Unhandled: pthread_rwlock_timedrdlock
sewardjb4112022007-11-09 22:49:28 +00001997 pthread_rwlock_timedwrlock
sewardjb4112022007-11-09 22:49:28 +00001998*/
1999
sewardj1c147ff2009-07-26 19:52:06 +00002000//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00002001// glibc: pthread_rwlock_init
2002// darwin: pthread_rwlock_init
2003// darwin: pthread_rwlock_init$UNIX2003
2004// Solaris: rwlock_init (pthread_rwlock_init is built atop of rwlock_init)
florian31014da2011-09-26 00:29:44 +00002005__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +00002006static int pthread_rwlock_init_WRK(pthread_rwlock_t *rwl,
2007 pthread_rwlockattr_t* attr)
sewardjb4112022007-11-09 22:49:28 +00002008{
2009 int ret;
2010 OrigFn fn;
2011 VALGRIND_GET_ORIG_FN(fn);
2012 if (TRACE_PTH_FNS) {
2013 fprintf(stderr, "<< pthread_rwl_init %p", rwl); fflush(stderr);
2014 }
2015
2016 CALL_FN_W_WW(ret, fn, rwl,attr);
2017
2018 if (ret == 0 /*success*/) {
2019 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
2020 pthread_rwlock_t*,rwl);
2021 } else {
2022 DO_PthAPIerror( "pthread_rwlock_init", ret );
2023 }
2024
2025 if (TRACE_PTH_FNS) {
2026 fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
2027 }
2028 return ret;
2029}
sewardj1c147ff2009-07-26 19:52:06 +00002030#if defined(VGO_linux)
2031 PTH_FUNC(int, pthreadZurwlockZuinit, // pthread_rwlock_init
2032 pthread_rwlock_t *rwl,
2033 pthread_rwlockattr_t* attr) {
2034 return pthread_rwlock_init_WRK(rwl, attr);
2035 }
2036#elif defined(VGO_darwin)
2037 PTH_FUNC(int, pthreadZurwlockZuinitZa, // pthread_rwlock_init*
2038 pthread_rwlock_t *rwl,
2039 pthread_rwlockattr_t* attr) {
2040 return pthread_rwlock_init_WRK(rwl, attr);
2041 }
sewardj8eb8bab2015-07-21 14:44:28 +00002042#elif defined(VGO_solaris)
2043static int pthread_rwlock_init_WRK(pthread_rwlock_t *rwl,
2044 pthread_rwlockattr_t* attr)
2045 __attribute__((unused));
sewardj1c147ff2009-07-26 19:52:06 +00002046#else
2047# error "Unsupported OS"
2048#endif
sewardjb4112022007-11-09 22:49:28 +00002049
sewardj8eb8bab2015-07-21 14:44:28 +00002050#if defined(VGO_solaris)
2051PTH_FUNC(int, rwlockZuinit, // rwlock_init
2052 rwlock_t *rwlock,
2053 int type,
2054 void *arg)
2055{
2056 int ret;
2057 OrigFn fn;
2058 VALGRIND_GET_ORIG_FN(fn);
2059 if (TRACE_PTH_FNS) {
2060 fprintf(stderr, "<< rwl_init %p", rwlock); fflush(stderr);
2061 }
2062
2063 CALL_FN_W_WWW(ret, fn, rwlock, type, arg);
2064
2065 if (ret == 0 /*success*/) {
2066 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
2067 rwlock_t *, rwlock);
2068 } else {
2069 DO_PthAPIerror("rwlock_init", ret);
2070 }
2071
2072 if (TRACE_PTH_FNS) {
2073 fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
2074 }
2075 return ret;
2076}
2077#endif /* VGO_solaris */
2078
sewardjb4112022007-11-09 22:49:28 +00002079
sewardj1c147ff2009-07-26 19:52:06 +00002080//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00002081// glibc: pthread_rwlock_destroy
2082// darwin: pthread_rwlock_destroy
2083// darwin: pthread_rwlock_destroy$UNIX2003
2084// Solaris: rwlock_destroy (pthread_rwlock_destroy is a weak alias)
sewardj1c147ff2009-07-26 19:52:06 +00002085//
florian31014da2011-09-26 00:29:44 +00002086__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +00002087static int pthread_rwlock_destroy_WRK(pthread_rwlock_t* rwl)
sewardjb4112022007-11-09 22:49:28 +00002088{
2089 int ret;
2090 OrigFn fn;
2091 VALGRIND_GET_ORIG_FN(fn);
2092 if (TRACE_PTH_FNS) {
2093 fprintf(stderr, "<< pthread_rwl_destroy %p", rwl); fflush(stderr);
2094 }
2095
2096 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE,
2097 pthread_rwlock_t*,rwl);
2098
2099 CALL_FN_W_W(ret, fn, rwl);
2100
2101 if (ret != 0) {
2102 DO_PthAPIerror( "pthread_rwlock_destroy", ret );
2103 }
2104
2105 if (TRACE_PTH_FNS) {
2106 fprintf(stderr, " :: rwl_destroy -> %d >>\n", ret);
2107 }
2108 return ret;
2109}
sewardj1c147ff2009-07-26 19:52:06 +00002110#if defined(VGO_linux)
2111 PTH_FUNC(int, pthreadZurwlockZudestroy, // pthread_rwlock_destroy
2112 pthread_rwlock_t *rwl) {
2113 return pthread_rwlock_destroy_WRK(rwl);
2114 }
2115#elif defined(VGO_darwin)
2116 PTH_FUNC(int, pthreadZurwlockZudestroyZa, // pthread_rwlock_destroy*
2117 pthread_rwlock_t *rwl) {
2118 return pthread_rwlock_destroy_WRK(rwl);
2119 }
sewardj8eb8bab2015-07-21 14:44:28 +00002120#elif defined(VGO_solaris)
2121 PTH_FUNC(int, rwlockZudestroy, // rwlock_destroy
2122 pthread_rwlock_t *rwl) {
2123 return pthread_rwlock_destroy_WRK(rwl);
2124 }
sewardj1c147ff2009-07-26 19:52:06 +00002125#else
2126# error "Unsupported OS"
2127#endif
sewardjb4112022007-11-09 22:49:28 +00002128
2129
sewardj1c147ff2009-07-26 19:52:06 +00002130//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00002131// glibc: pthread_rwlock_wrlock
2132// darwin: pthread_rwlock_wrlock
2133// darwin: pthread_rwlock_wrlock$UNIX2003
2134// Solaris: rw_wrlock (pthread_rwlock_wrlock is a weak alias)
sewardj1c147ff2009-07-26 19:52:06 +00002135//
florian31014da2011-09-26 00:29:44 +00002136__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +00002137static int pthread_rwlock_wrlock_WRK(pthread_rwlock_t* rwlock)
sewardjb4112022007-11-09 22:49:28 +00002138{
2139 int ret;
2140 OrigFn fn;
2141 VALGRIND_GET_ORIG_FN(fn);
2142 if (TRACE_PTH_FNS) {
2143 fprintf(stderr, "<< pthread_rwl_wlk %p", rwlock); fflush(stderr);
2144 }
2145
sewardj789c3c52008-02-25 12:10:07 +00002146 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2147 pthread_rwlock_t*,rwlock,
2148 long,1/*isW*/, long,0/*!isTryLock*/);
sewardjb4112022007-11-09 22:49:28 +00002149
2150 CALL_FN_W_W(ret, fn, rwlock);
2151
sewardj8eb8bab2015-07-21 14:44:28 +00002152 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2153 pthread_rwlock_t*,rwlock, long,1/*isW*/,
2154 long, (ret == 0) ? True : False);
2155 if (ret != 0) {
sewardjb4112022007-11-09 22:49:28 +00002156 DO_PthAPIerror( "pthread_rwlock_wrlock", ret );
2157 }
2158
2159 if (TRACE_PTH_FNS) {
2160 fprintf(stderr, " :: rwl_wlk -> %d >>\n", ret);
2161 }
2162 return ret;
2163}
sewardj1c147ff2009-07-26 19:52:06 +00002164#if defined(VGO_linux)
2165 PTH_FUNC(int, pthreadZurwlockZuwrlock, // pthread_rwlock_wrlock
2166 pthread_rwlock_t* rwlock) {
2167 return pthread_rwlock_wrlock_WRK(rwlock);
2168 }
2169#elif defined(VGO_darwin)
2170 PTH_FUNC(int, pthreadZurwlockZuwrlockZa, // pthread_rwlock_wrlock*
2171 pthread_rwlock_t* rwlock) {
2172 return pthread_rwlock_wrlock_WRK(rwlock);
2173 }
sewardj8eb8bab2015-07-21 14:44:28 +00002174#elif defined(VGO_solaris)
2175 PTH_FUNC(int, rwZuwrlock, // rw_wrlock
2176 pthread_rwlock_t *rwlock) {
2177 return pthread_rwlock_wrlock_WRK(rwlock);
2178 }
sewardj1c147ff2009-07-26 19:52:06 +00002179#else
2180# error "Unsupported OS"
2181#endif
sewardjb4112022007-11-09 22:49:28 +00002182
sewardj8eb8bab2015-07-21 14:44:28 +00002183#if defined(VGO_solaris)
2184/* Internal to libc. */
2185PTH_FUNC(void, lrwZuwrlock, // lrw_wrlock
2186 rwlock_t *rwlock)
2187{
2188 OrigFn fn;
2189 VALGRIND_GET_ORIG_FN(fn);
2190 if (TRACE_PTH_FNS) {
2191 fprintf(stderr, "<< lrw_wlk %p", rwlock); fflush(stderr);
2192 }
2193
2194 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2195 pthread_rwlock_t *, rwlock,
2196 long, 1/*isW*/, long, 0/*!isTryLock*/);
2197
2198 CALL_FN_v_W(fn, rwlock);
2199
2200 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2201 pthread_rwlock_t *, rwlock, long, 1/*isW*/, long, True);
2202
2203 if (TRACE_PTH_FNS) {
2204 fprintf(stderr, " :: lrw_wlk >>\n");
2205 }
2206}
2207#endif /* VGO_solaris */
2208
sewardjb4112022007-11-09 22:49:28 +00002209
sewardj1c147ff2009-07-26 19:52:06 +00002210//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00002211// glibc: pthread_rwlock_rdlock
2212// darwin: pthread_rwlock_rdlock
2213// darwin: pthread_rwlock_rdlock$UNIX2003
2214// Solaris: rw_rdlock (pthread_rwlock_rdlock is a weak alias)
sewardj1c147ff2009-07-26 19:52:06 +00002215//
florian31014da2011-09-26 00:29:44 +00002216__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +00002217static int pthread_rwlock_rdlock_WRK(pthread_rwlock_t* rwlock)
sewardjb4112022007-11-09 22:49:28 +00002218{
2219 int ret;
2220 OrigFn fn;
2221 VALGRIND_GET_ORIG_FN(fn);
2222 if (TRACE_PTH_FNS) {
2223 fprintf(stderr, "<< pthread_rwl_rlk %p", rwlock); fflush(stderr);
2224 }
2225
sewardj789c3c52008-02-25 12:10:07 +00002226 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2227 pthread_rwlock_t*,rwlock,
2228 long,0/*!isW*/, long,0/*!isTryLock*/);
sewardjb4112022007-11-09 22:49:28 +00002229
2230 CALL_FN_W_W(ret, fn, rwlock);
2231
sewardj8eb8bab2015-07-21 14:44:28 +00002232 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2233 pthread_rwlock_t*,rwlock, long,0/*!isW*/,
2234 long, (ret == 0) ? True : False);
2235 if (ret != 0) {
sewardjb4112022007-11-09 22:49:28 +00002236 DO_PthAPIerror( "pthread_rwlock_rdlock", ret );
2237 }
2238
2239 if (TRACE_PTH_FNS) {
2240 fprintf(stderr, " :: rwl_rlk -> %d >>\n", ret);
2241 }
2242 return ret;
2243}
sewardj1c147ff2009-07-26 19:52:06 +00002244#if defined(VGO_linux)
2245 PTH_FUNC(int, pthreadZurwlockZurdlock, // pthread_rwlock_rdlock
2246 pthread_rwlock_t* rwlock) {
2247 return pthread_rwlock_rdlock_WRK(rwlock);
2248 }
2249#elif defined(VGO_darwin)
2250 PTH_FUNC(int, pthreadZurwlockZurdlockZa, // pthread_rwlock_rdlock*
2251 pthread_rwlock_t* rwlock) {
2252 return pthread_rwlock_rdlock_WRK(rwlock);
2253 }
sewardj8eb8bab2015-07-21 14:44:28 +00002254#elif defined(VGO_solaris)
2255 PTH_FUNC(int, rwZurdlock, // rw_rdlock
2256 pthread_rwlock_t *rwlock) {
2257 return pthread_rwlock_rdlock_WRK(rwlock);
2258 }
sewardj1c147ff2009-07-26 19:52:06 +00002259#else
2260# error "Unsupported OS"
2261#endif
sewardjb4112022007-11-09 22:49:28 +00002262
sewardj8eb8bab2015-07-21 14:44:28 +00002263#if defined(VGO_solaris)
2264/* Internal to libc. */
2265PTH_FUNC(void, lrwZurdlock, // lrw_rdlock
2266 rwlock_t *rwlock)
2267{
2268 OrigFn fn;
2269 VALGRIND_GET_ORIG_FN(fn);
2270 if (TRACE_PTH_FNS) {
2271 fprintf(stderr, "<< lrw_rlk %p", rwlock); fflush(stderr);
2272 }
2273
2274 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2275 pthread_rwlock_t *, rwlock,
2276 long, 0/*!isW*/, long, 0/*!isTryLock*/);
2277
2278 CALL_FN_v_W(fn, rwlock);
2279
2280 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2281 pthread_rwlock_t *, rwlock, long, 0/*!isW*/, long, True);
2282
2283 if (TRACE_PTH_FNS) {
2284 fprintf(stderr, " :: lrw_rlk ->>\n");
2285 }
2286}
2287#endif /* VGO_solaris */
2288
sewardjb4112022007-11-09 22:49:28 +00002289
sewardj1c147ff2009-07-26 19:52:06 +00002290//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00002291// glibc: pthread_rwlock_trywrlock
2292// darwin: pthread_rwlock_trywrlock
2293// darwin: pthread_rwlock_trywrlock$UNIX2003
2294// Solaris: rw_trywrlock (pthread_rwlock_trywrlock is a weak alias)
sewardj1c147ff2009-07-26 19:52:06 +00002295//
florian31014da2011-09-26 00:29:44 +00002296__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +00002297static int pthread_rwlock_trywrlock_WRK(pthread_rwlock_t* rwlock)
sewardj789c3c52008-02-25 12:10:07 +00002298{
2299 int ret;
2300 OrigFn fn;
2301 VALGRIND_GET_ORIG_FN(fn);
2302 if (TRACE_PTH_FNS) {
2303 fprintf(stderr, "<< pthread_rwl_trywlk %p", rwlock); fflush(stderr);
2304 }
2305
2306 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2307 pthread_rwlock_t*,rwlock,
2308 long,1/*isW*/, long,1/*isTryLock*/);
2309
2310 CALL_FN_W_W(ret, fn, rwlock);
2311
2312 /* There's a hole here: libpthread now knows the lock is locked,
2313 but the tool doesn't, so some other thread could run and detect
2314 that the lock has been acquired by someone (this thread). Does
2315 this matter? Not sure, but I don't think so. */
2316
sewardj8eb8bab2015-07-21 14:44:28 +00002317 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2318 pthread_rwlock_t*,rwlock, long,1/*isW*/,
2319 long, (ret == 0) ? True : False);
2320 if (ret != 0) {
sewardj789c3c52008-02-25 12:10:07 +00002321 if (ret != EBUSY)
2322 DO_PthAPIerror( "pthread_rwlock_trywrlock", ret );
2323 }
2324
2325 if (TRACE_PTH_FNS) {
2326 fprintf(stderr, " :: rwl_trywlk -> %d >>\n", ret);
2327 }
2328 return ret;
2329}
sewardj1c147ff2009-07-26 19:52:06 +00002330#if defined(VGO_linux)
2331 PTH_FUNC(int, pthreadZurwlockZutrywrlock, // pthread_rwlock_trywrlock
2332 pthread_rwlock_t* rwlock) {
2333 return pthread_rwlock_trywrlock_WRK(rwlock);
2334 }
2335#elif defined(VGO_darwin)
2336 PTH_FUNC(int, pthreadZurwlockZutrywrlockZa, // pthread_rwlock_trywrlock*
2337 pthread_rwlock_t* rwlock) {
2338 return pthread_rwlock_trywrlock_WRK(rwlock);
2339 }
sewardj8eb8bab2015-07-21 14:44:28 +00002340#elif defined(VGO_solaris)
2341 PTH_FUNC(int, rwZutrywrlock, // rw_trywrlock
2342 pthread_rwlock_t *rwlock) {
2343 return pthread_rwlock_trywrlock_WRK(rwlock);
2344 }
sewardj1c147ff2009-07-26 19:52:06 +00002345#else
2346# error "Unsupported OS"
2347#endif
sewardj789c3c52008-02-25 12:10:07 +00002348
2349
sewardj1c147ff2009-07-26 19:52:06 +00002350//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00002351// glibc: pthread_rwlock_tryrdlock
2352// darwin: pthread_rwlock_tryrdlock
2353// darwin: pthread_rwlock_tryrdlock$UNIX2003
2354// Solaris: rw_tryrdlock (pthread_rwlock_tryrdlock is a weak alias)
sewardj1c147ff2009-07-26 19:52:06 +00002355//
florian31014da2011-09-26 00:29:44 +00002356__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +00002357static int pthread_rwlock_tryrdlock_WRK(pthread_rwlock_t* rwlock)
sewardj789c3c52008-02-25 12:10:07 +00002358{
2359 int ret;
2360 OrigFn fn;
2361 VALGRIND_GET_ORIG_FN(fn);
2362 if (TRACE_PTH_FNS) {
2363 fprintf(stderr, "<< pthread_rwl_tryrlk %p", rwlock); fflush(stderr);
2364 }
2365
2366 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2367 pthread_rwlock_t*,rwlock,
2368 long,0/*!isW*/, long,1/*isTryLock*/);
2369
2370 CALL_FN_W_W(ret, fn, rwlock);
2371
2372 /* There's a hole here: libpthread now knows the lock is locked,
2373 but the tool doesn't, so some other thread could run and detect
2374 that the lock has been acquired by someone (this thread). Does
2375 this matter? Not sure, but I don't think so. */
2376
sewardj8eb8bab2015-07-21 14:44:28 +00002377 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2378 pthread_rwlock_t*,rwlock, long,0/*!isW*/,
2379 long, (ret == 0) ? True : False);
2380
2381 if (ret != 0) {
sewardj789c3c52008-02-25 12:10:07 +00002382 if (ret != EBUSY)
2383 DO_PthAPIerror( "pthread_rwlock_tryrdlock", ret );
2384 }
2385
2386 if (TRACE_PTH_FNS) {
2387 fprintf(stderr, " :: rwl_tryrlk -> %d >>\n", ret);
2388 }
2389 return ret;
2390}
sewardj1c147ff2009-07-26 19:52:06 +00002391#if defined(VGO_linux)
2392 PTH_FUNC(int, pthreadZurwlockZutryrdlock, // pthread_rwlock_tryrdlock
2393 pthread_rwlock_t* rwlock) {
2394 return pthread_rwlock_tryrdlock_WRK(rwlock);
2395 }
2396#elif defined(VGO_darwin)
2397 PTH_FUNC(int, pthreadZurwlockZutryrdlockZa, // pthread_rwlock_tryrdlock*
2398 pthread_rwlock_t* rwlock) {
2399 return pthread_rwlock_tryrdlock_WRK(rwlock);
2400 }
sewardj8eb8bab2015-07-21 14:44:28 +00002401#elif defined(VGO_solaris)
2402 PTH_FUNC(int, rwZutryrdlock, // rw_tryrdlock
2403 pthread_rwlock_t *rwlock) {
2404 return pthread_rwlock_tryrdlock_WRK(rwlock);
2405 }
sewardj1c147ff2009-07-26 19:52:06 +00002406#else
2407# error "Unsupported OS"
2408#endif
sewardj789c3c52008-02-25 12:10:07 +00002409
2410
sewardj1c147ff2009-07-26 19:52:06 +00002411//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00002412// glibc: Unhandled
2413// darwin: Unhandled
2414// Solaris: pthread_rwlock_timedrdlock
2415// Solaris: pthread_rwlock_reltimedrdlock_np
2416//
2417__attribute__((noinline)) __attribute__((unused))
2418static int pthread_rwlock_timedrdlock_WRK(pthread_rwlock_t *rwlock,
2419 const struct timespec *timeout)
2420{
2421 int ret;
2422 OrigFn fn;
2423 VALGRIND_GET_ORIG_FN(fn);
2424 if (TRACE_PTH_FNS) {
2425 fprintf(stderr, "<< pthread_rwl_timedrdl %p", rwlock); fflush(stderr);
2426 }
2427
2428 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2429 pthread_rwlock_t *, rwlock,
2430 long, 0/*isW*/, long, 0/*isTryLock*/);
2431
2432 CALL_FN_W_WW(ret, fn, rwlock, timeout);
2433
2434 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2435 pthread_rwlock_t *, rwlock, long, 0/*isW*/,
2436 long, (ret == 0) ? True : False);
2437 if (ret != 0) {
2438 DO_PthAPIerror("pthread_rwlock_timedrdlock", ret);
2439 }
2440
2441 if (TRACE_PTH_FNS) {
2442 fprintf(stderr, " :: rwl_timedrdl -> %d >>\n", ret);
2443 }
2444 return ret;
2445}
2446#if defined(VGO_linux)
2447#elif defined(VGO_darwin)
2448#elif defined(VGO_solaris)
2449 PTH_FUNC(int, pthreadZurwlockZutimedrdlock, // pthread_rwlock_timedrdlock
2450 pthread_rwlock_t *rwlock,
2451 const struct timespec *timeout) {
2452 return pthread_rwlock_timedrdlock_WRK(rwlock, timeout);
2453 }
2454 PTH_FUNC(int, pthreadZurwlockZureltimedrdlockZunp, // pthread_rwlock_timedrdlock_np
2455 pthread_rwlock_t *rwlock,
2456 const struct timespec *timeout) {
2457 return pthread_rwlock_timedrdlock_WRK(rwlock, timeout);
2458 }
2459#else
2460# error "Unsupported OS"
2461#endif
2462
2463
2464//-----------------------------------------------------------
2465// glibc: Unhandled
2466// darwin: Unhandled
2467// Solaris: pthread_rwlock_timedwrlock
2468// Solaris: pthread_rwlock_reltimedwrlock_np
2469//
2470__attribute__((noinline)) __attribute__((unused))
2471static int pthread_rwlock_timedwrlock_WRK(pthread_rwlock_t *rwlock,
2472 const struct timespec *timeout)
2473{
2474 int ret;
2475 OrigFn fn;
2476 VALGRIND_GET_ORIG_FN(fn);
2477 if (TRACE_PTH_FNS) {
2478 fprintf(stderr, "<< pthread_rwl_timedwrl %p", rwlock); fflush(stderr);
2479 }
2480
2481 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
2482 pthread_rwlock_t *, rwlock,
2483 long, 1/*isW*/, long, 0/*isTryLock*/);
2484
2485 CALL_FN_W_WW(ret, fn, rwlock, timeout);
2486
2487 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
2488 pthread_rwlock_t *, rwlock, long, 1/*isW*/,
2489 long, (ret == 0) ? True : False);
2490 if (ret != 0) {
2491 DO_PthAPIerror("pthread_rwlock_timedwrlock", ret);
2492 }
2493
2494 if (TRACE_PTH_FNS) {
2495 fprintf(stderr, " :: rwl_timedwrl -> %d >>\n", ret);
2496 }
2497 return ret;
2498}
2499#if defined(VGO_linux)
2500#elif defined(VGO_darwin)
2501#elif defined(VGO_solaris)
2502 PTH_FUNC(int, pthreadZurwlockZutimedwrlock, // pthread_rwlock_timedwrlock
2503 pthread_rwlock_t *rwlock,
2504 const struct timespec *timeout) {
2505 return pthread_rwlock_timedwrlock_WRK(rwlock, timeout);
2506 }
2507 PTH_FUNC(int, pthreadZurwlockZureltimedwrlockZunp, // pthread_rwlock_timedwrlock_np
2508 pthread_rwlock_t *rwlock,
2509 const struct timespec *timeout) {
2510 return pthread_rwlock_timedwrlock_WRK(rwlock, timeout);
2511 }
2512#else
2513# error "Unsupported OS"
2514#endif
2515
2516
2517//-----------------------------------------------------------
2518// glibc: pthread_rwlock_unlock
2519// darwin: pthread_rwlock_unlock
2520// darwin: pthread_rwlock_unlock$UNIX2003
2521// Solaris: rw_unlock (pthread_rwlock_unlock is a weak alias)
florian31014da2011-09-26 00:29:44 +00002522__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +00002523static int pthread_rwlock_unlock_WRK(pthread_rwlock_t* rwlock)
sewardjb4112022007-11-09 22:49:28 +00002524{
2525 int ret;
2526 OrigFn fn;
2527 VALGRIND_GET_ORIG_FN(fn);
2528 if (TRACE_PTH_FNS) {
2529 fprintf(stderr, "<< pthread_rwl_unlk %p", rwlock); fflush(stderr);
2530 }
2531
2532 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
2533 pthread_rwlock_t*,rwlock);
2534
2535 CALL_FN_W_W(ret, fn, rwlock);
2536
sewardj8eb8bab2015-07-21 14:44:28 +00002537 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
2538 pthread_rwlock_t*,rwlock);
2539 if (ret != 0) {
sewardjb4112022007-11-09 22:49:28 +00002540 DO_PthAPIerror( "pthread_rwlock_unlock", ret );
2541 }
2542
2543 if (TRACE_PTH_FNS) {
2544 fprintf(stderr, " :: rwl_unlk -> %d >>\n", ret);
2545 }
2546 return ret;
2547}
sewardj1c147ff2009-07-26 19:52:06 +00002548#if defined(VGO_linux)
2549 PTH_FUNC(int, pthreadZurwlockZuunlock, // pthread_rwlock_unlock
2550 pthread_rwlock_t* rwlock) {
2551 return pthread_rwlock_unlock_WRK(rwlock);
2552 }
2553#elif defined(VGO_darwin)
2554 PTH_FUNC(int, pthreadZurwlockZuunlockZa, // pthread_rwlock_unlock*
2555 pthread_rwlock_t* rwlock) {
2556 return pthread_rwlock_unlock_WRK(rwlock);
2557 }
sewardj8eb8bab2015-07-21 14:44:28 +00002558#elif defined(VGO_solaris)
2559 PTH_FUNC(int, rwZuunlock, // rw_unlock
2560 pthread_rwlock_t *rwlock) {
2561 return pthread_rwlock_unlock_WRK(rwlock);
2562 }
sewardj1c147ff2009-07-26 19:52:06 +00002563#else
2564# error "Unsupported OS"
2565#endif
sewardjb4112022007-11-09 22:49:28 +00002566
sewardj0c09bf02011-07-11 22:11:58 +00002567#endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
2568
sewardjb4112022007-11-09 22:49:28 +00002569
2570/*----------------------------------------------------------------*/
2571/*--- POSIX semaphores ---*/
2572/*----------------------------------------------------------------*/
2573
2574#include <semaphore.h>
sewardj28a7f7d2009-07-26 20:15:37 +00002575#include <fcntl.h> /* O_CREAT */
sewardjb4112022007-11-09 22:49:28 +00002576
2577#define TRACE_SEM_FNS 0
2578
2579/* Handled:
2580 int sem_init(sem_t *sem, int pshared, unsigned value);
2581 int sem_destroy(sem_t *sem);
2582 int sem_wait(sem_t *sem);
2583 int sem_post(sem_t *sem);
sewardj1c147ff2009-07-26 19:52:06 +00002584 sem_t* sem_open(const char *name, int oflag,
2585 ... [mode_t mode, unsigned value]);
2586 [complete with its idiotic semantics]
2587 int sem_close(sem_t* sem);
sewardjb4112022007-11-09 22:49:28 +00002588
2589 Unhandled:
2590 int sem_trywait(sem_t *sem);
2591 int sem_timedwait(sem_t *restrict sem,
2592 const struct timespec *restrict abs_timeout);
2593*/
2594
sewardj1c147ff2009-07-26 19:52:06 +00002595//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00002596// glibc: sem_init@@GLIBC_2.2.5
2597// glibc: sem_init@@GLIBC_2.1
2598// glibc: sem_init@GLIBC_2.0
2599// darwin: sem_init
2600// Solaris: sema_init (sem_init is built on top of sem_init)
sewardj1c147ff2009-07-26 19:52:06 +00002601//
sewardj8eb8bab2015-07-21 14:44:28 +00002602#if !defined(VGO_solaris)
florian31014da2011-09-26 00:29:44 +00002603__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +00002604static int sem_init_WRK(sem_t* sem, int pshared, unsigned long value)
sewardjb4112022007-11-09 22:49:28 +00002605{
2606 OrigFn fn;
2607 int ret;
2608 VALGRIND_GET_ORIG_FN(fn);
2609
2610 if (TRACE_SEM_FNS) {
2611 fprintf(stderr, "<< sem_init(%p,%d,%lu) ", sem,pshared,value);
2612 fflush(stderr);
2613 }
2614
2615 CALL_FN_W_WWW(ret, fn, sem,pshared,value);
2616
2617 if (ret == 0) {
sewardj11e352f2007-11-30 11:11:02 +00002618 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
2619 sem_t*, sem, unsigned long, value);
sewardjb4112022007-11-09 22:49:28 +00002620 } else {
2621 DO_PthAPIerror( "sem_init", errno );
2622 }
2623
2624 if (TRACE_SEM_FNS) {
2625 fprintf(stderr, " sem_init -> %d >>\n", ret);
2626 fflush(stderr);
2627 }
2628
2629 return ret;
2630}
sewardj1c147ff2009-07-26 19:52:06 +00002631#if defined(VGO_linux)
2632 PTH_FUNC(int, semZuinitZAZa, // sem_init@*
2633 sem_t* sem, int pshared, unsigned long value) {
2634 return sem_init_WRK(sem, pshared, value);
2635 }
2636#elif defined(VGO_darwin)
2637 PTH_FUNC(int, semZuinit, // sem_init
2638 sem_t* sem, int pshared, unsigned long value) {
2639 return sem_init_WRK(sem, pshared, value);
2640 }
2641#else
2642# error "Unsupported OS"
2643#endif
sewardjb4112022007-11-09 22:49:28 +00002644
sewardj8eb8bab2015-07-21 14:44:28 +00002645#else /* VGO_solaris */
2646PTH_FUNC(int, semaZuinit, // sema_init
2647 sema_t *sem,
2648 unsigned int value,
2649 int type,
2650 void *arg)
2651{
2652 OrigFn fn;
2653 int ret;
2654 VALGRIND_GET_ORIG_FN(fn);
2655
2656 if (TRACE_SEM_FNS) {
2657 fprintf(stderr, "<< sema_init(%p, %d, %u) ", sem, type, value);
2658 fflush(stderr);
2659 }
2660
2661 CALL_FN_W_WWWW(ret, fn, sem, value, type, arg);
2662
2663 if (ret == 0) {
2664 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
2665 sema_t *, sem, Word, value);
2666 } else {
2667 DO_PthAPIerror("sema_init", ret);
2668 }
2669
2670 if (TRACE_SEM_FNS) {
2671 fprintf(stderr, " sema_init -> %d >>\n", ret);
2672 fflush(stderr);
2673 }
2674
2675 return ret;
2676}
2677#endif /* VGO_solaris */
2678
sewardjb4112022007-11-09 22:49:28 +00002679
sewardj1c147ff2009-07-26 19:52:06 +00002680//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00002681// glibc: sem_destroy@GLIBC_2.0
2682// glibc: sem_destroy@@GLIBC_2.1
2683// glibc: sem_destroy@@GLIBC_2.2.5
2684// darwin: sem_destroy
2685// Solaris: sema_destroy (sem_destroy is built on top of sema_destroy)
florian31014da2011-09-26 00:29:44 +00002686__attribute__((noinline))
sewardj1c147ff2009-07-26 19:52:06 +00002687static int sem_destroy_WRK(sem_t* sem)
sewardjb4112022007-11-09 22:49:28 +00002688{
2689 OrigFn fn;
2690 int ret;
2691 VALGRIND_GET_ORIG_FN(fn);
2692
2693 if (TRACE_SEM_FNS) {
2694 fprintf(stderr, "<< sem_destroy(%p) ", sem);
2695 fflush(stderr);
2696 }
2697
sewardj11e352f2007-11-30 11:11:02 +00002698 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
sewardjb4112022007-11-09 22:49:28 +00002699
2700 CALL_FN_W_W(ret, fn, sem);
2701
2702 if (ret != 0) {
sewardj8eb8bab2015-07-21 14:44:28 +00002703 DO_PthAPIerror( "sem_destroy", SEM_ERROR );
sewardjb4112022007-11-09 22:49:28 +00002704 }
2705
2706 if (TRACE_SEM_FNS) {
2707 fprintf(stderr, " sem_destroy -> %d >>\n", ret);
2708 fflush(stderr);
2709 }
2710
2711 return ret;
2712}
sewardj1c147ff2009-07-26 19:52:06 +00002713#if defined(VGO_linux)
2714 PTH_FUNC(int, semZudestroyZAZa, // sem_destroy*
2715 sem_t* sem) {
2716 return sem_destroy_WRK(sem);
2717 }
2718#elif defined(VGO_darwin)
2719 PTH_FUNC(int, semZudestroy, // sem_destroy
2720 sem_t* sem) {
2721 return sem_destroy_WRK(sem);
2722 }
sewardj8eb8bab2015-07-21 14:44:28 +00002723#elif defined(VGO_solaris)
2724 PTH_FUNC(int, semaZudestroy, // sema_destroy
2725 sem_t *sem) {
2726 return sem_destroy_WRK(sem);
2727 }
sewardj1c147ff2009-07-26 19:52:06 +00002728#else
2729# error "Unsupported OS"
2730#endif
sewardjb4112022007-11-09 22:49:28 +00002731
2732
sewardj1c147ff2009-07-26 19:52:06 +00002733//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00002734// glibc: sem_wait
2735// glibc: sem_wait@GLIBC_2.0
2736// glibc: sem_wait@@GLIBC_2.1
2737// darwin: sem_wait
2738// darwin: sem_wait$NOCANCEL$UNIX2003
2739// darwin: sem_wait$UNIX2003
2740// Solaris: sema_wait (sem_wait is built on top of sema_wait)
sewardj1c147ff2009-07-26 19:52:06 +00002741//
sewardjb4112022007-11-09 22:49:28 +00002742/* wait: decrement semaphore - acquire lockage */
florian31014da2011-09-26 00:29:44 +00002743__attribute__((noinline))
sewardjb4112022007-11-09 22:49:28 +00002744static int sem_wait_WRK(sem_t* sem)
2745{
2746 OrigFn fn;
2747 int ret;
2748 VALGRIND_GET_ORIG_FN(fn);
2749
2750 if (TRACE_SEM_FNS) {
2751 fprintf(stderr, "<< sem_wait(%p) ", sem);
2752 fflush(stderr);
2753 }
2754
sewardj8eb8bab2015-07-21 14:44:28 +00002755 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_PRE, sem_t*,sem);
2756
sewardjb4112022007-11-09 22:49:28 +00002757 CALL_FN_W_W(ret, fn, sem);
2758
sewardj8eb8bab2015-07-21 14:44:28 +00002759 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST, sem_t*,sem,
2760 long, (ret == 0) ? True : False);
2761
2762 if (ret != 0) {
2763 DO_PthAPIerror( "sem_wait", SEM_ERROR );
sewardjb4112022007-11-09 22:49:28 +00002764 }
2765
2766 if (TRACE_SEM_FNS) {
2767 fprintf(stderr, " sem_wait -> %d >>\n", ret);
2768 fflush(stderr);
2769 }
2770
2771 return ret;
2772}
sewardj1c147ff2009-07-26 19:52:06 +00002773#if defined(VGO_linux)
2774 PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
2775 return sem_wait_WRK(sem);
2776 }
2777 PTH_FUNC(int, semZuwaitZAZa, sem_t* sem) { /* sem_wait@* */
2778 return sem_wait_WRK(sem);
2779 }
2780#elif defined(VGO_darwin)
2781 PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
2782 return sem_wait_WRK(sem);
2783 }
2784 PTH_FUNC(int, semZuwaitZDZa, sem_t* sem) { /* sem_wait$* */
2785 return sem_wait_WRK(sem);
2786 }
sewardj8eb8bab2015-07-21 14:44:28 +00002787#elif defined(VGO_solaris)
2788 PTH_FUNC(int, semaZuwait, sem_t *sem) { /* sema_wait */
2789 return sem_wait_WRK(sem);
2790 }
sewardj1c147ff2009-07-26 19:52:06 +00002791#else
2792# error "Unsupported OS"
2793#endif
sewardjb4112022007-11-09 22:49:28 +00002794
2795
sewardj1c147ff2009-07-26 19:52:06 +00002796//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00002797// glibc: sem_post
2798// glibc: sem_post@GLIBC_2.0
2799// glibc: sem_post@@GLIBC_2.1
2800// darwin: sem_post
2801// Solaris: sema_post (sem_post is built on top of sema_post)
sewardj1c147ff2009-07-26 19:52:06 +00002802//
sewardjb4112022007-11-09 22:49:28 +00002803/* post: increment semaphore - release lockage */
florian31014da2011-09-26 00:29:44 +00002804__attribute__((noinline))
sewardjb4112022007-11-09 22:49:28 +00002805static int sem_post_WRK(sem_t* sem)
2806{
2807 OrigFn fn;
2808 int ret;
2809
2810 VALGRIND_GET_ORIG_FN(fn);
2811
2812 if (TRACE_SEM_FNS) {
2813 fprintf(stderr, "<< sem_post(%p) ", sem);
2814 fflush(stderr);
2815 }
2816
sewardj11e352f2007-11-30 11:11:02 +00002817 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_PRE, sem_t*,sem);
sewardjb4112022007-11-09 22:49:28 +00002818
2819 CALL_FN_W_W(ret, fn, sem);
2820
sewardj8eb8bab2015-07-21 14:44:28 +00002821 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_POST, sem_t*,sem);
2822
sewardjb4112022007-11-09 22:49:28 +00002823 if (ret != 0) {
sewardj8eb8bab2015-07-21 14:44:28 +00002824 DO_PthAPIerror( "sem_post", SEM_ERROR );
sewardjb4112022007-11-09 22:49:28 +00002825 }
2826
2827 if (TRACE_SEM_FNS) {
2828 fprintf(stderr, " sem_post -> %d >>\n", ret);
2829 fflush(stderr);
2830 }
2831
2832 return ret;
2833}
sewardj1c147ff2009-07-26 19:52:06 +00002834#if defined(VGO_linux)
2835 PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
2836 return sem_post_WRK(sem);
2837 }
2838 PTH_FUNC(int, semZupostZAZa, sem_t* sem) { /* sem_post@* */
2839 return sem_post_WRK(sem);
2840 }
2841#elif defined(VGO_darwin)
2842 PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
2843 return sem_post_WRK(sem);
2844 }
sewardj8eb8bab2015-07-21 14:44:28 +00002845#elif defined(VGO_solaris)
2846 PTH_FUNC(int, semaZupost, sem_t *sem) { /* sema_post */
2847 return sem_post_WRK(sem);
2848 }
sewardj1c147ff2009-07-26 19:52:06 +00002849#else
2850# error "Unsupported OS"
2851#endif
2852
2853
2854//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00002855// glibc: sem_open
2856// darwin: sem_open
2857// Solaris: sem_open
sewardj1c147ff2009-07-26 19:52:06 +00002858//
2859PTH_FUNC(sem_t*, semZuopen,
2860 const char* name, long oflag,
2861 long mode, unsigned long value)
2862{
2863 /* A copy of sem_init_WRK (more or less). Is this correct? */
2864 OrigFn fn;
2865 sem_t* ret;
2866 VALGRIND_GET_ORIG_FN(fn);
2867
2868 if (TRACE_SEM_FNS) {
2869 fprintf(stderr, "<< sem_open(\"%s\",%ld,%lx,%lu) ",
2870 name,oflag,mode,value);
2871 fflush(stderr);
2872 }
2873
2874 CALL_FN_W_WWWW(ret, fn, name,oflag,mode,value);
2875
2876 if (ret != SEM_FAILED && (oflag & O_CREAT)) {
2877 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
2878 sem_t*, ret, unsigned long, value);
2879 }
2880 if (ret == SEM_FAILED) {
2881 DO_PthAPIerror( "sem_open", errno );
2882 }
2883
2884 if (TRACE_SEM_FNS) {
2885 fprintf(stderr, " sem_open -> %p >>\n", ret);
2886 fflush(stderr);
2887 }
2888
2889 return ret;
sewardjb4112022007-11-09 22:49:28 +00002890}
2891
2892
sewardj1c147ff2009-07-26 19:52:06 +00002893//-----------------------------------------------------------
sewardj8eb8bab2015-07-21 14:44:28 +00002894// glibc: sem_close
2895// darwin: sem_close
2896// Solaris: sem_close
sewardj1c147ff2009-07-26 19:52:06 +00002897PTH_FUNC(int, sem_close, sem_t* sem)
2898{
2899 OrigFn fn;
2900 int ret;
2901 VALGRIND_GET_ORIG_FN(fn);
2902
2903 if (TRACE_SEM_FNS) {
2904 fprintf(stderr, "<< sem_close(%p) ", sem);
2905 fflush(stderr);
2906 }
2907
2908 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
2909
2910 CALL_FN_W_W(ret, fn, sem);
2911
2912 if (ret != 0) {
2913 DO_PthAPIerror( "sem_close", errno );
2914 }
2915
2916 if (TRACE_SEM_FNS) {
2917 fprintf(stderr, " close -> %d >>\n", ret);
2918 fflush(stderr);
2919 }
2920
2921 return ret;
2922}
2923
sewardjb4112022007-11-09 22:49:28 +00002924
2925/*----------------------------------------------------------------*/
2926/*--- Qt 4 threading functions (w/ GNU name mangling) ---*/
2927/*----------------------------------------------------------------*/
2928
sewardj38e0cf92008-11-19 10:40:56 +00002929/* Handled:
2930 QMutex::lock()
2931 QMutex::unlock()
2932 QMutex::tryLock()
2933 QMutex::tryLock(int)
sewardjb4112022007-11-09 22:49:28 +00002934
sewardj38e0cf92008-11-19 10:40:56 +00002935 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC1ENS_13RecursionModeE
2936 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC2ENS_13RecursionModeE
2937 QMutex::~QMutex() _ZN6QMutexD1Ev
2938 QMutex::~QMutex() _ZN6QMutexD2Ev
sewardjb4112022007-11-09 22:49:28 +00002939
sewardj38e0cf92008-11-19 10:40:56 +00002940 Unhandled:
2941 QReadWriteLock::lockForRead()
2942 QReadWriteLock::lockForWrite()
2943 QReadWriteLock::unlock()
2944 QReadWriteLock::tryLockForRead(int)
2945 QReadWriteLock::tryLockForRead()
2946 QReadWriteLock::tryLockForWrite(int)
2947 QReadWriteLock::tryLockForWrite()
2948
2949 QWaitCondition::wait(QMutex*, unsigned long)
2950 QWaitCondition::wakeAll()
2951 QWaitCondition::wakeOne()
2952
2953 QSemaphore::*
2954*/
2955/* More comments, 19 Nov 08, based on assessment of qt-4.5.0TP1,
2956 at least on Unix:
2957
2958 It's apparently only necessary to intercept QMutex, since that is
2959 not implemented using pthread_mutex_t; instead Qt4 has its own
2960 implementation based on atomics (to check the non-contended case)
2961 and pthread_cond_wait (to wait in the contended case).
2962
2963 QReadWriteLock is built on top of QMutex, counters, and a wait
2964 queue. So we don't need to handle it specially once QMutex
2965 handling is correct -- presumably the dependencies through QMutex
2966 are sufficient to avoid any false race reports. On the other hand,
2967 it is an open question whether too many dependencies are observed
2968 -- in which case we may miss races (false negatives). I suspect
2969 this is likely to be the case, unfortunately.
2970
2971 QWaitCondition is built on pthread_cond_t, pthread_mutex_t, QMutex
2972 and QReadWriteLock. Same compositional-correctness justificiation
2973 and limitations as fro QReadWriteLock.
2974
2975 Ditto QSemaphore (from cursory examination).
2976
2977 Does it matter that only QMutex is handled directly? Open
2978 question. From testing with drd/tests/qt4_* and with KDE4 apps, it
2979 appears that no false errors are reported; however it is not clear
2980 if this is causing false negatives.
2981
2982 Another problem with Qt4 is thread exiting. Threads are created
2983 with pthread_create (fine); but they detach and simply exit when
2984 done. There is no use of pthread_join, and the provided
2985 wait-for-a-thread-to-exit mechanism (QThread::wait, I believe)
2986 relies on a system of mutexes and flags. I suspect this also
2987 causes too many dependencies to appear. Consequently H sometimes
2988 fails to detect races at exit in some very short-lived racy
2989 programs, because it appears that a thread can exit _and_ have an
2990 observed dependency edge back to the main thread (presumably)
2991 before the main thread reaps the child (that is, calls
2992 QThread::wait).
2993
2994 This theory is supported by the observation that if all threads are
2995 made to wait at a pthread_barrier_t immediately before they exit,
2996 then H's detection of races in such programs becomes reliable;
2997 without the barrier, it is varies from run to run, depending
2998 (according to investigation) on whether aforementioned
2999 exit-before-reaping behaviour happens or not.
3000
3001 Finally, why is it necessary to intercept the QMutex constructors
3002 and destructors? The constructors are intercepted only as a matter
3003 of convenience, so H can print accurate "first observed at"
3004 clauses. However, it is actually necessary to intercept the
3005 destructors (as it is with pthread_mutex_destroy) in order that
3006 locks get removed from LAOG when they are destroyed.
sewardjb4112022007-11-09 22:49:28 +00003007*/
3008
3009// soname is libQtCore.so.4 ; match against libQtCore.so*
3010#define QT4_FUNC(ret_ty, f, args...) \
sewardj38e0cf92008-11-19 10:40:56 +00003011 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args); \
3012 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args)
sewardjb4112022007-11-09 22:49:28 +00003013
sewardjd52defb2013-02-07 11:53:36 +00003014// soname is libQt5Core.so.4 ; match against libQt5Core.so*
3015#define QT5_FUNC(ret_ty, f, args...) \
3016 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args); \
3017 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args)
3018
sewardj1c147ff2009-07-26 19:52:06 +00003019//-----------------------------------------------------------
sewardjb4112022007-11-09 22:49:28 +00003020// QMutex::lock()
sewardjd52defb2013-02-07 11:53:36 +00003021__attribute__((noinline))
3022static void QMutex_lock_WRK(void* self)
sewardjb4112022007-11-09 22:49:28 +00003023{
3024 OrigFn fn;
3025 VALGRIND_GET_ORIG_FN(fn);
3026 if (TRACE_QT4_FNS) {
3027 fprintf(stderr, "<< QMutex::lock %p", self); fflush(stderr);
3028 }
3029
3030 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
3031 void*,self, long,0/*!isTryLock*/);
3032
3033 CALL_FN_v_W(fn, self);
3034
sewardj8eb8bab2015-07-21 14:44:28 +00003035 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
3036 void *, self, long, True);
sewardjb4112022007-11-09 22:49:28 +00003037
3038 if (TRACE_QT4_FNS) {
3039 fprintf(stderr, " :: Q::lock done >>\n");
3040 }
3041}
3042
sewardjd52defb2013-02-07 11:53:36 +00003043QT4_FUNC(void, _ZN6QMutex4lockEv, void* self) {
3044 QMutex_lock_WRK(self);
3045}
3046QT5_FUNC(void, _ZN6QMutex4lockEv, void* self) {
3047 QMutex_lock_WRK(self);
3048}
3049
sewardj1c147ff2009-07-26 19:52:06 +00003050//-----------------------------------------------------------
sewardjb4112022007-11-09 22:49:28 +00003051// QMutex::unlock()
sewardjd52defb2013-02-07 11:53:36 +00003052__attribute__((noinline))
3053static void QMutex_unlock_WRK(void* self)
sewardjb4112022007-11-09 22:49:28 +00003054{
3055 OrigFn fn;
3056 VALGRIND_GET_ORIG_FN(fn);
3057
3058 if (TRACE_QT4_FNS) {
3059 fprintf(stderr, "<< QMutex::unlock %p", self); fflush(stderr);
3060 }
3061
3062 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
3063 void*, self);
3064
3065 CALL_FN_v_W(fn, self);
3066
3067 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
3068 void*, self);
3069
3070 if (TRACE_QT4_FNS) {
3071 fprintf(stderr, " Q::unlock done >>\n");
3072 }
3073}
3074
sewardjd52defb2013-02-07 11:53:36 +00003075QT4_FUNC(void, _ZN6QMutex6unlockEv, void* self) {
3076 QMutex_unlock_WRK(self);
3077}
3078QT5_FUNC(void, _ZN6QMutex6unlockEv, void* self) {
3079 QMutex_unlock_WRK(self);
3080}
3081
sewardj1c147ff2009-07-26 19:52:06 +00003082//-----------------------------------------------------------
sewardj38e0cf92008-11-19 10:40:56 +00003083// bool QMutex::tryLock()
sewardjb4112022007-11-09 22:49:28 +00003084// using 'long' to mimic C++ 'bool'
sewardjd52defb2013-02-07 11:53:36 +00003085__attribute__((noinline))
3086static long QMutex_tryLock_WRK(void* self)
sewardjb4112022007-11-09 22:49:28 +00003087{
3088 OrigFn fn;
3089 long ret;
3090 VALGRIND_GET_ORIG_FN(fn);
3091 if (TRACE_QT4_FNS) {
3092 fprintf(stderr, "<< QMutex::tryLock %p", self); fflush(stderr);
3093 }
3094
3095 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
3096 void*,self, long,1/*isTryLock*/);
3097
3098 CALL_FN_W_W(ret, fn, self);
3099
3100 // assumes that only the low 8 bits of the 'bool' are significant
sewardj8eb8bab2015-07-21 14:44:28 +00003101 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
3102 void *, self, long, (ret & 0xFF) ? True : False);
sewardjb4112022007-11-09 22:49:28 +00003103
3104 if (TRACE_QT4_FNS) {
3105 fprintf(stderr, " :: Q::tryLock -> %lu >>\n", ret);
3106 }
3107
3108 return ret;
3109}
3110
sewardjd52defb2013-02-07 11:53:36 +00003111QT4_FUNC(long, _ZN6QMutex7tryLockEv, void* self) {
3112 return QMutex_tryLock_WRK(self);
3113}
3114QT5_FUNC(long, _ZN6QMutex7tryLockEv, void* self) {
3115 return QMutex_tryLock_WRK(self);
3116}
3117
sewardj1c147ff2009-07-26 19:52:06 +00003118//-----------------------------------------------------------
sewardj38e0cf92008-11-19 10:40:56 +00003119// bool QMutex::tryLock(int)
3120// using 'long' to mimic C++ 'bool'
sewardjd52defb2013-02-07 11:53:36 +00003121__attribute__((noinline))
3122static long QMutex_tryLock_int_WRK(void* self, long arg2)
sewardjb4112022007-11-09 22:49:28 +00003123{
3124 OrigFn fn;
sewardj38e0cf92008-11-19 10:40:56 +00003125 long ret;
sewardjb4112022007-11-09 22:49:28 +00003126 VALGRIND_GET_ORIG_FN(fn);
3127 if (TRACE_QT4_FNS) {
sewardj38e0cf92008-11-19 10:40:56 +00003128 fprintf(stderr, "<< QMutex::tryLock(int) %p %d", self, (int)arg2);
sewardjb4112022007-11-09 22:49:28 +00003129 fflush(stderr);
3130 }
3131
sewardj38e0cf92008-11-19 10:40:56 +00003132 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
3133 void*,self, long,1/*isTryLock*/);
sewardjb4112022007-11-09 22:49:28 +00003134
sewardj38e0cf92008-11-19 10:40:56 +00003135 CALL_FN_W_WW(ret, fn, self,arg2);
sewardjb4112022007-11-09 22:49:28 +00003136
sewardj38e0cf92008-11-19 10:40:56 +00003137 // assumes that only the low 8 bits of the 'bool' are significant
sewardj8eb8bab2015-07-21 14:44:28 +00003138 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
3139 void *, self, long, (ret & 0xFF) ? True : False);
sewardjb4112022007-11-09 22:49:28 +00003140
3141 if (TRACE_QT4_FNS) {
sewardj38e0cf92008-11-19 10:40:56 +00003142 fprintf(stderr, " :: Q::tryLock(int) -> %lu >>\n", ret);
sewardjb4112022007-11-09 22:49:28 +00003143 }
sewardj38e0cf92008-11-19 10:40:56 +00003144
3145 return ret;
sewardjb4112022007-11-09 22:49:28 +00003146}
3147
sewardjd52defb2013-02-07 11:53:36 +00003148QT4_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2) {
3149 return QMutex_tryLock_int_WRK(self, arg2);
3150}
3151QT5_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2) {
3152 return QMutex_tryLock_int_WRK(self, arg2);
3153}
sewardj38e0cf92008-11-19 10:40:56 +00003154
sewardj1c147ff2009-07-26 19:52:06 +00003155//-----------------------------------------------------------
sewardj38e0cf92008-11-19 10:40:56 +00003156// It's not really very clear what the args are here. But from
3157// a bit of dataflow analysis of the generated machine code of
3158// the original function, it appears this takes two args, and
3159// returns nothing. Nevertheless preserve return value just in
3160// case. A bit of debug printing indicates that the first arg
3161// is that of the mutex and the second is either zero or one,
3162// probably being the recursion mode, therefore.
3163// QMutex::QMutex(QMutex::RecursionMode) ("C1ENS" variant)
sewardjd52defb2013-02-07 11:53:36 +00003164__attribute__((noinline))
3165static void* QMutex_constructor_WRK(void* mutex, long recmode)
sewardjb4112022007-11-09 22:49:28 +00003166{
3167 OrigFn fn;
sewardj38e0cf92008-11-19 10:40:56 +00003168 long ret;
sewardjb4112022007-11-09 22:49:28 +00003169 VALGRIND_GET_ORIG_FN(fn);
sewardj38e0cf92008-11-19 10:40:56 +00003170 CALL_FN_W_WW(ret, fn, mutex, recmode);
3171 // fprintf(stderr, "QMutex constructor 1: %p <- %p %p\n", ret, arg1, arg2);
3172 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
3173 void*,mutex, long,1/*mbRec*/);
3174 return (void*)ret;
sewardjb4112022007-11-09 22:49:28 +00003175}
3176
sewardjd52defb2013-02-07 11:53:36 +00003177QT4_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE, void* self, long recmode) {
3178 return QMutex_constructor_WRK(self, recmode);
3179}
3180QT5_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE, void* self, long recmode) {
3181 return QMutex_constructor_WRK(self, recmode);
3182}
3183
sewardj1c147ff2009-07-26 19:52:06 +00003184//-----------------------------------------------------------
sewardj38e0cf92008-11-19 10:40:56 +00003185// QMutex::~QMutex() ("D1Ev" variant)
sewardjd52defb2013-02-07 11:53:36 +00003186__attribute__((noinline))
3187static void* QMutex_destructor_WRK(void* mutex)
sewardjb4112022007-11-09 22:49:28 +00003188{
3189 OrigFn fn;
sewardj38e0cf92008-11-19 10:40:56 +00003190 long ret;
sewardjb4112022007-11-09 22:49:28 +00003191 VALGRIND_GET_ORIG_FN(fn);
sewardj38e0cf92008-11-19 10:40:56 +00003192 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
3193 void*,mutex);
3194 CALL_FN_W_W(ret, fn, mutex);
3195 return (void*)ret;
sewardjb4112022007-11-09 22:49:28 +00003196}
3197
sewardjd52defb2013-02-07 11:53:36 +00003198QT4_FUNC(void*, _ZN6QMutexD1Ev, void* self) {
3199 return QMutex_destructor_WRK(self);
3200}
3201QT5_FUNC(void*, _ZN6QMutexD1Ev, void* self) {
3202 return QMutex_destructor_WRK(self);
3203}
sewardjb4112022007-11-09 22:49:28 +00003204
sewardj1c147ff2009-07-26 19:52:06 +00003205//-----------------------------------------------------------
sewardj38e0cf92008-11-19 10:40:56 +00003206// QMutex::QMutex(QMutex::RecursionMode) ("C2ENS" variant)
3207QT4_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE,
3208 void* mutex,
3209 long recmode)
3210{
3211 assert(0);
sewardj211c2532011-07-12 06:13:08 +00003212 /*NOTREACHED*/
3213 /* Android's gcc behaves like it doesn't know that assert(0)
3214 never returns. Hence: */
3215 return NULL;
sewardj38e0cf92008-11-19 10:40:56 +00003216}
3217
sewardjd52defb2013-02-07 11:53:36 +00003218QT5_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE, void* self, long recmode)
3219{
3220 assert(0);
3221 /*NOTREACHED*/
3222 return NULL;
3223}
sewardj1c147ff2009-07-26 19:52:06 +00003224
3225//-----------------------------------------------------------
sewardj38e0cf92008-11-19 10:40:56 +00003226// QMutex::~QMutex() ("D2Ev" variant)
3227QT4_FUNC(void*, _ZN6QMutexD2Ev, void* mutex)
3228{
3229 assert(0);
sewardj211c2532011-07-12 06:13:08 +00003230 /* Android's gcc behaves like it doesn't know that assert(0)
3231 never returns. Hence: */
3232 return NULL;
sewardj38e0cf92008-11-19 10:40:56 +00003233}
3234
sewardjd52defb2013-02-07 11:53:36 +00003235QT5_FUNC(void*, _ZN6QMutexD2Ev, void* self)
3236{
3237 assert(0);
3238 /*NOTREACHED*/
3239 return NULL;
3240}
sewardj38e0cf92008-11-19 10:40:56 +00003241
3242// QReadWriteLock is not intercepted directly. See comments
3243// above.
3244
3245//// QReadWriteLock::lockForRead()
3246//// _ZN14QReadWriteLock11lockForReadEv == QReadWriteLock::lockForRead()
3247//QT4_FUNC(void, ZuZZN14QReadWriteLock11lockForReadEv,
3248// // _ZN14QReadWriteLock11lockForReadEv
3249// void* self)
3250//{
3251// OrigFn fn;
3252// VALGRIND_GET_ORIG_FN(fn);
3253// if (TRACE_QT4_FNS) {
3254// fprintf(stderr, "<< QReadWriteLock::lockForRead %p", self);
3255// fflush(stderr);
3256// }
3257//
3258// DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
3259// void*,self,
3260// long,0/*!isW*/, long,0/*!isTryLock*/);
3261//
3262// CALL_FN_v_W(fn, self);
3263//
sewardj8eb8bab2015-07-21 14:44:28 +00003264// DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
3265// void*,self, long,0/*!isW*/, long, True);
sewardj38e0cf92008-11-19 10:40:56 +00003266//
3267// if (TRACE_QT4_FNS) {
3268// fprintf(stderr, " :: Q::lockForRead :: done >>\n");
3269// }
3270//}
3271//
3272//// QReadWriteLock::lockForWrite()
3273//// _ZN14QReadWriteLock12lockForWriteEv == QReadWriteLock::lockForWrite()
3274//QT4_FUNC(void, ZuZZN14QReadWriteLock12lockForWriteEv,
3275// // _ZN14QReadWriteLock12lockForWriteEv
3276// void* self)
3277//{
3278// OrigFn fn;
3279// VALGRIND_GET_ORIG_FN(fn);
3280// if (TRACE_QT4_FNS) {
3281// fprintf(stderr, "<< QReadWriteLock::lockForWrite %p", self);
3282// fflush(stderr);
3283// }
3284//
3285// DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
3286// void*,self,
3287// long,1/*isW*/, long,0/*!isTryLock*/);
3288//
3289// CALL_FN_v_W(fn, self);
3290//
sewardj8eb8bab2015-07-21 14:44:28 +00003291// DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
3292// void*,self, long,1/*isW*/, long, True);
sewardj38e0cf92008-11-19 10:40:56 +00003293//
3294// if (TRACE_QT4_FNS) {
3295// fprintf(stderr, " :: Q::lockForWrite :: done >>\n");
3296// }
3297//}
3298//
3299//// QReadWriteLock::unlock()
3300//// _ZN14QReadWriteLock6unlockEv == QReadWriteLock::unlock()
3301//QT4_FUNC(void, ZuZZN14QReadWriteLock6unlockEv,
3302// // _ZN14QReadWriteLock6unlockEv
3303// void* self)
3304//{
3305// OrigFn fn;
3306// VALGRIND_GET_ORIG_FN(fn);
3307// if (TRACE_QT4_FNS) {
3308// fprintf(stderr, "<< QReadWriteLock::unlock %p", self);
3309// fflush(stderr);
3310// }
3311//
3312// DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
3313// void*,self);
3314//
3315// CALL_FN_v_W(fn, self);
3316//
3317// DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
3318// void*,self);
3319//
3320// if (TRACE_QT4_FNS) {
3321// fprintf(stderr, " :: Q::unlock :: done >>\n");
3322// }
3323//}
3324
3325
3326/*----------------------------------------------------------------*/
3327/*--- Replacements for basic string functions, that don't ---*/
sewardjb80f0c92008-11-19 16:33:59 +00003328/*--- overrun the input arrays. ---*/
sewardj38e0cf92008-11-19 10:40:56 +00003329/*----------------------------------------------------------------*/
3330
bart9c7779b2013-11-24 17:48:13 +00003331#include "../shared/vg_replace_strmem.c"
sewardj38e0cf92008-11-19 10:40:56 +00003332
sewardjb4112022007-11-09 22:49:28 +00003333/*--------------------------------------------------------------------*/
sewardj3c944452011-09-05 20:39:57 +00003334/*--- end hg_intercepts.c ---*/
sewardjb4112022007-11-09 22:49:28 +00003335/*--------------------------------------------------------------------*/