syswrap openat2 for all linux arches
[valgrind.git] / drd / drd_pthread_intercepts.c
blobb1b4762d633b9d4a1263c83392dce47342259ed1
1 /*--------------------------------------------------------------------*/
2 /*--- Client-space code for DRD. drd_pthread_intercepts.c ---*/
3 /*--------------------------------------------------------------------*/
5 /*
6 This file is part of DRD, a thread error detector.
8 Copyright (C) 2006-2020 Bart Van Assche <bvanassche@acm.org>.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2 of the
13 License, or (at your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, see <http://www.gnu.org/licenses/>.
23 The GNU General Public License is contained in the file COPYING.
26 /* ---------------------------------------------------------------------
27 ALL THE CODE IN THIS FILE RUNS ON THE SIMULATED CPU.
29 These functions are not called directly - they're the targets of code
30 redirection or load notifications (see pub_core_redir.h for info).
31 They're named weirdly so that the intercept code can find them when the
32 shared object is initially loaded.
34 Note that this filename has the "drd_" prefix because it can appear
35 in stack traces, and the "drd_" makes it a little clearer that it
36 originates from Valgrind.
37 ------------------------------------------------------------------ */
40 * Define _GNU_SOURCE to make sure that pthread_spinlock_t is available when
41 * compiling with older glibc versions (2.3 or before).
43 #ifndef _GNU_SOURCE
44 #define _GNU_SOURCE
45 #endif
47 #include <assert.h> /* assert() */
48 #include <errno.h>
49 #include <pthread.h> /* pthread_mutex_t */
50 #include <semaphore.h> /* sem_t */
51 #include <stdint.h> /* uintptr_t */
52 #include <stdio.h> /* fprintf() */
53 #include <stdlib.h> /* malloc(), free() */
54 #include <unistd.h> /* confstr() */
55 #include "config.h" /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP etc. */
56 #include "drd_basics.h" /* DRD_() */
57 #include "drd_clientreq.h"
58 #include "pub_tool_redir.h" /* VG_WRAP_FUNCTION_ZZ() */
60 #if defined(VGO_freebsd)
61 #include <dlfcn.h>
62 #endif
64 #if defined(VGO_solaris)
66 * Solaris usually provides pthread_* functions on top of Solaris threading
67 * and synchronization functions. Usually both need to be intercepted because
68 * pthread_* ones might not call the Solaris ones (see for example sem_wait()).
69 * Such approach is required to correctly report misuse of the POSIX threads
70 * API.
71 * Therefore DRD intercepts and instruments all such functions but due to
72 * DRD_(thread_enter_synchr)() and DRD_(thread_leave_synchr)() guards in
73 * handle_client_request(), only the top-most function is handled.
74 * So the right thing(TM) happens, as expected.
75 * The only exception is when pthread_* function is a weak alias to the Solaris
76 * threading/synchronization function. In such case only one needs to be
77 * intercepted to avoid redirection ambiguity.
79 * Intercepted functions rely on the fact that:
80 * - pthread_mutex_t == mutex_t
81 * - pthread_cond_t == cond_t
82 * - sem_t == sema_t
83 * - pthread_rwlock_t == rwlock_t
85 * It is necessary to intercept also internal libc synchronization functions
86 * for two reasons:
87 * - For read-write locks the unlocking function is shared
88 * - Functions lmutex_lock/lmutex_unlock guard many critical sections in libc
89 * which will be otherwise reported by DRD
91 #include <synch.h>
92 #include <thread.h>
93 #include "pub_tool_vki.h"
96 * Solaris provides higher throughput, parallelism and scalability than other
97 * operating systems, at the cost of more fine-grained locking activity.
98 * This means for example that when a thread is created under Linux, just one
99 * big lock in glibc is used for all thread setup. Solaris libc uses several
100 * fine-grained locks and the creator thread resumes its activities as soon
101 * as possible, leaving for example stack and TLS setup activities to the
102 * created thread.
104 * This situation confuses DRD as it assumes there is some false ordering
105 * in place between creator and created thread; and therefore many types of
106 * race conditions in the application would not be reported. To prevent such
107 * false ordering, command line option --ignore-thread-creation is set to
108 * 'yes' by default on Solaris. All activity (loads, stores, client requests)
109 * is therefore ignored during:
110 * - pthread_create() call in the creator thread [libc.so]
111 * - thread creation phase (stack and TLS setup) in the created thread [libc.so]
113 * As explained in the comments for _ti_bind_guard(), whenever the runtime
114 * linker has to perform any activity (such as resolving a symbol), it protects
115 * its data structures by calling into rt_bind_guard() which in turn invokes
116 * _ti_bind_guard() in libc. Pointers to _ti_bind_guard() and _ti_bind_clear()
117 * are passed from libc to runtime linker in _ld_libc() call during libc_init().
118 * All activity is also ignored during:
119 * - runtime dynamic linker work between rt_bind_guard() and rt_bind_clear()
120 * calls [ld.so]
122 * This also means that DRD does not report race conditions in libc (when
123 * --ignore-thread-creation=yes) and runtime linker itself (unconditionally)
124 * during these ignored sequences.
128 * Original function pointers for _ti_bind_guard() and _ti_bind_clear()
129 * from libc. They are intercepted in function wrapper of _ld_libc().
131 typedef int (*drd_rtld_guard_fn)(int flags);
132 static drd_rtld_guard_fn DRD_(rtld_bind_guard) = NULL;
133 static drd_rtld_guard_fn DRD_(rtld_bind_clear) = NULL;
134 #endif
138 * Notes regarding thread creation:
139 * - sg_init() runs on the context of the created thread and copies the vector
140 * clock of the creator thread. This only works reliably if the creator
141 * thread waits until this copy has been performed.
142 * - DRD_(thread_compute_minimum_vc)() does not take the vector clocks into
143 * account that are involved in thread creation and for which the
144 * corresponding thread has not yet been created. So not waiting until the
145 * created thread has been started would make it possible that segments get
146 * discarded that should not yet be discarded. Or: some data races are not
147 * detected.
151 * Macro for generating a Valgrind interception function.
152 * @param[in] ret_ty Return type of the function to be generated.
153 * @param[in] zf Z-encoded name of the interception function.
154 * @param[in] implf Name of the function that implements the intercept.
155 * @param[in] arg_decl Argument declaration list enclosed in parentheses.
156 * @param[in] argl Argument list enclosed in parentheses.
158 #if defined(VGO_darwin)
160 * Note here VGO_darwin is used rather than VG_WRAP_THREAD_FUNCTION_LIBPTHREAD_ONLY
161 * because of the special-case code adding a function call
163 static int never_true;
164 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
165 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
166 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
168 ret_ty pth_func_result = implf argl; \
169 /* Apparently inserting a function call in wrapper functions */ \
170 /* is sufficient to avoid misaligned stack errors. */ \
171 if (never_true) \
172 fflush(stdout); \
173 return pth_func_result; \
175 #elif defined(VG_WRAP_THREAD_FUNCTION_LIBPTHREAD_ONLY)
176 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
177 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
178 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
179 { return implf argl; }
180 #elif defined(VG_WRAP_THREAD_FUNCTION_LIBC_ONLY)
181 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
182 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl; \
183 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl \
184 { return implf argl; }
185 #elif defined(VG_WRAP_THREAD_FUNCTION_LIBC_AND_LIBPTHREAD)
186 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
187 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl; \
188 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl \
189 { return implf argl; } \
190 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
191 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
192 { return implf argl; }
193 #else
194 # error "Unknown platform/thread wrapping"
195 #endif
197 #if defined(VGO_freebsd)
198 #define LIBC_FUNC(ret_ty, zf, implf, argl_decl, argl) \
199 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl; \
200 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl \
201 { return implf argl; }
202 #endif
205 * Macro for generating three Valgrind interception functions: one with the
206 * Z-encoded name zf, one with ZAZa ("@*") appended to the name zf and one
207 * with ZDZa ("$*") appended to the name zf. The second generated interception
208 * function will intercept versioned symbols on Linux, and the third will
209 * intercept versioned symbols on Darwin.
211 #define PTH_FUNCS(ret_ty, zf, implf, argl_decl, argl) \
212 PTH_FUNC(ret_ty, zf, implf, argl_decl, argl); \
213 PTH_FUNC(ret_ty, zf ## ZAZa, implf, argl_decl, argl); \
214 PTH_FUNC(ret_ty, zf ## ZDZa, implf, argl_decl, argl);
217 * Not inlining one of the intercept functions will cause the regression
218 * tests to fail because this would cause an additional stackfram to appear
219 * in the output. The __always_inline macro guarantees that inlining will
220 * happen, even when compiling with optimization disabled.
222 #undef __always_inline /* since already defined in <cdefs.h> */
223 #if __GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 2
224 #define __always_inline __inline__ __attribute__((always_inline))
225 #else
226 #define __always_inline __inline__
227 #endif
229 /* Local data structures. */
231 typedef struct {
232 pthread_mutex_t mutex;
233 pthread_cond_t cond;
234 int counter;
235 } DrdSema;
237 typedef struct
239 void* (*start)(void*);
240 void* arg;
241 int detachstate;
242 DrdSema* wrapper_started;
243 } DrdPosixThreadArgs;
246 /* Local function declarations. */
248 static void DRD_(init)(void) __attribute__((constructor));
249 static void DRD_(check_threading_library)(void);
250 static void DRD_(set_pthread_id)(void);
251 static void DRD_(sema_init)(DrdSema* sema);
252 static void DRD_(sema_destroy)(DrdSema* sema);
253 static void DRD_(sema_down)(DrdSema* sema);
254 static void DRD_(sema_up)(DrdSema* sema);
257 /* Function definitions. */
260 * Shared library initialization function. The function init() is called after
261 * dlopen() has loaded the shared library with DRD client intercepts because
262 * the constructor attribute was specified in the declaration of this function.
263 * Note: do specify the -nostdlib option to gcc when linking this code into a
264 * shared library because doing so would cancel the effect of the constructor
265 * attribute ! Using the gcc option -nodefaultlibs is fine because this last
266 * option preserves the shared library initialization code that calls
267 * constructor and destructor functions.
269 static void DRD_(init)(void)
271 #if defined(VGO_freebsd)
274 * On FreeBSD, pthead functions are all in libthr.so
275 * However libc.so contains stubs. In this ctor function,
276 * calling DRD_(set_pthread_id)() results in a call to
277 * pthread_self() resolving to the libc.so stub which
278 * returns a junk value for the tid. Subsequent calls
279 * to pthread_create() then also cause calls to
280 * DRD_(set_pthread_id)(), but this time with pthread_self()
281 * resolving to the good libthr.so version (since this is later
282 * and libthr.so has been loaded). That causes an assert
283 * since we expect the tid to either be INVALID_POSIX_THREADID
284 * or the same as the current tid, and the junk value
285 * is neither. So we force loading of libthr.so, which
286 * avoids this junk tid value.
288 dlclose(dlopen("/lib/libthr.so.3", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE));
290 #endif
292 DRD_(check_threading_library)();
293 DRD_(set_pthread_id)();
294 #if defined(VGO_solaris)
295 if ((DRD_(rtld_bind_guard) == NULL) || (DRD_(rtld_bind_clear) == NULL)) {
296 fprintf(stderr,
297 "Bind guard functions for the runtime linker (ld.so.1) were not intercepted.\n"
298 "This means the interface between libc and runtime linker changed and DRD\n"
299 "needs to be ported properly. Giving up.\n");
300 abort();
302 #endif
305 static __always_inline void DRD_(ignore_mutex_ordering)(pthread_mutex_t *mutex)
307 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_IGNORE_MUTEX_ORDERING,
308 mutex, 0, 0, 0, 0);
311 static void DRD_(sema_init)(DrdSema* sema)
313 DRD_IGNORE_VAR(*sema);
314 pthread_mutex_init(&sema->mutex, NULL);
315 DRD_(ignore_mutex_ordering)(&sema->mutex);
316 pthread_cond_init(&sema->cond, NULL);
317 sema->counter = 0;
320 static void DRD_(sema_destroy)(DrdSema* sema)
322 pthread_mutex_destroy(&sema->mutex);
323 pthread_cond_destroy(&sema->cond);
326 static void DRD_(sema_down)(DrdSema* sema)
328 pthread_mutex_lock(&sema->mutex);
329 while (sema->counter == 0)
330 pthread_cond_wait(&sema->cond, &sema->mutex);
331 sema->counter--;
332 pthread_mutex_unlock(&sema->mutex);
335 static void DRD_(sema_up)(DrdSema* sema)
337 pthread_mutex_lock(&sema->mutex);
338 sema->counter++;
339 pthread_cond_signal(&sema->cond);
340 pthread_mutex_unlock(&sema->mutex);
344 * POSIX threads and DRD each have their own mutex type identification.
345 * Convert POSIX threads' mutex type to DRD's mutex type. In the code below
346 * if-statements are used to test the value of 'kind' instead of a switch
347 * statement because some of the PTHREAD_MUTEX_ macro's may have the same
348 * value.
350 static MutexT DRD_(pthread_to_drd_mutex_type)(int kind)
353 * Static checkers don't like this as there are repeated branch
354 * but because there is variation between different platforms
355 * it's messy to make something without repetition.
357 * See also PTHREAD_MUTEX_KIND_MASK_NP in glibc source file
358 * <nptl/pthreadP.h>.
360 kind &= PTHREAD_MUTEX_RECURSIVE | PTHREAD_MUTEX_ERRORCHECK |
361 PTHREAD_MUTEX_NORMAL | PTHREAD_MUTEX_DEFAULT;
363 if (kind == PTHREAD_MUTEX_RECURSIVE)
364 return mutex_type_recursive_mutex;
365 else if (kind == PTHREAD_MUTEX_ERRORCHECK)
366 return mutex_type_errorcheck_mutex;
367 else if (kind == PTHREAD_MUTEX_NORMAL)
368 return mutex_type_default_mutex;
369 else if (kind == PTHREAD_MUTEX_DEFAULT)
370 // @todo PJF what about Solaris?
371 #if defined(VGO_freebsd)
372 return mutex_type_errorcheck_mutex;
373 #else
374 return mutex_type_default_mutex;
375 #endif
376 #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
377 else if (kind == PTHREAD_MUTEX_ADAPTIVE_NP)
378 return mutex_type_default_mutex;
379 #endif
380 else
381 return mutex_type_invalid_mutex;
384 #if defined(VGO_solaris)
386 * Solaris threads and DRD each have their own mutex type identification.
387 * Convert Solaris threads' mutex type to DRD's mutex type.
389 static MutexT DRD_(thread_to_drd_mutex_type)(int type)
391 if (type & LOCK_RECURSIVE) {
392 return mutex_type_recursive_mutex;
393 } else if (type & LOCK_ERRORCHECK) {
394 return mutex_type_errorcheck_mutex;
395 } else {
396 return mutex_type_default_mutex;
399 #endif /* VGO_solaris */
401 #define IS_ALIGNED(p) (((uintptr_t)(p) & (sizeof(*(p)) - 1)) == 0)
404 * Read the mutex type stored in the client memory used for the mutex
405 * implementation.
407 * @note This function depends on the implementation of the POSIX threads
408 * library -- the POSIX standard does not define the name of the member in
409 * which the mutex type is stored.
410 * @note The function mutex_type() has been declared inline in order
411 * to avoid that it shows up in call stacks (drd/tests/...exp* files).
412 * @note glibc stores the mutex type in the lowest two bits, and uses the
413 * higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
414 * PTHREAD_MUTEXATTR_FLAG_PSHARED.
416 static __always_inline MutexT DRD_(mutex_type)(pthread_mutex_t* mutex)
418 MutexT mutex_type = mutex_type_unknown;
420 ANNOTATE_IGNORE_READS_BEGIN();
421 #if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
422 /* glibc + LinuxThreads. */
423 if (IS_ALIGNED(&mutex->__m_kind))
425 const int kind = mutex->__m_kind & 3;
426 mutex_type = DRD_(pthread_to_drd_mutex_type)(kind);
428 #elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
429 /* glibc + NPTL. */
430 if (IS_ALIGNED(&mutex->__data.__kind))
432 const int kind = mutex->__data.__kind & 3;
433 mutex_type = DRD_(pthread_to_drd_mutex_type)(kind);
435 #elif defined(VGO_solaris)
437 const int type = ((mutex_t *) mutex)->vki_mutex_type;
438 mutex_type = DRD_(thread_to_drd_mutex_type)(type);
440 #else
442 * Another POSIX threads implementation. The mutex type won't be printed
443 * when enabling --trace-mutex=yes.
445 #endif
446 ANNOTATE_IGNORE_READS_END();
448 return mutex_type;
452 * Tell DRD whether 'tid' is a joinable thread or a detached thread.
454 static void DRD_(set_joinable)(const pthread_t tid, const int joinable)
456 assert(joinable == 0 || joinable == 1);
457 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_SET_JOINABLE,
458 tid, joinable, 0, 0, 0);
461 /** Tell DRD that the calling thread is about to enter pthread_create(). */
462 static __always_inline void DRD_(entering_pthread_create)(void)
464 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_ENTERING_PTHREAD_CREATE,
465 0, 0, 0, 0, 0);
468 /** Tell DRD that the calling thread has left pthread_create(). */
469 static __always_inline void DRD_(left_pthread_create)(void)
471 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_LEFT_PTHREAD_CREATE,
472 0, 0, 0, 0, 0);
476 * Entry point for newly created threads. This function is called from the
477 * thread created by pthread_create().
479 static void* DRD_(thread_wrapper)(void* arg)
481 DrdPosixThreadArgs* arg_ptr;
482 DrdPosixThreadArgs arg_copy;
484 arg_ptr = (DrdPosixThreadArgs*)arg;
485 arg_copy = *arg_ptr;
487 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_SET_PTHREADID,
488 pthread_self(), 0, 0, 0, 0);
490 DRD_(set_joinable)(pthread_self(),
491 arg_copy.detachstate == PTHREAD_CREATE_JOINABLE);
494 * Only set 'wrapper_started' after VG_USERREQ__SET_PTHREADID and
495 * DRD_(set_joinable)() have been invoked to avoid a race with
496 * a pthread_detach() invocation for this thread from another thread.
498 DRD_(sema_up)(arg_copy.wrapper_started);
500 return (arg_copy.start)(arg_copy.arg);
504 * Return 1 if the LinuxThreads implementation of POSIX Threads has been
505 * detected, and 0 otherwise.
507 * @see For more information about the confstr() function, see also
508 * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
510 static int DRD_(detected_linuxthreads)(void)
512 #if defined(linux)
513 #if defined(_CS_GNU_LIBPTHREAD_VERSION)
514 /* Linux with a recent glibc. */
515 HChar buffer[256];
516 unsigned len;
517 len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
518 assert(len <= sizeof(buffer));
519 return len > 0 && buffer[0] == 'l';
520 #else
521 /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
522 return 1;
523 #endif
524 #else
525 /* Another OS than Linux, hence no LinuxThreads. */
526 return 0;
527 #endif
531 * Stop and print an error message in case a non-supported threading
532 * library implementation (LinuxThreads) has been detected.
534 static void DRD_(check_threading_library)(void)
536 if (DRD_(detected_linuxthreads)())
538 if (getenv("LD_ASSUME_KERNEL"))
540 fprintf(stderr,
541 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
542 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
543 "after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
546 else
548 fprintf(stderr,
549 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
550 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
551 "after having upgraded to a newer version of your Linux distribution.\n"
552 "Giving up.\n"
555 abort();
560 * Update DRD's state information about the current thread.
562 static void DRD_(set_pthread_id)(void)
564 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_SET_PTHREADID,
565 pthread_self(), 0, 0, 0, 0);
569 * Note: as of today there exist three different versions of pthread_create
570 * in Linux:
571 * - pthread_create@GLIBC_2.0
572 * - pthread_create@@GLIBC_2.1
573 * - pthread_create@@GLIBC_2.2.5
574 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
575 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
576 * versions have been implemented. In any glibc version where more than one
577 * pthread_create function has been implemented, older versions call the
578 * newer versions. Or: the pthread_create* wrapper defined below can be
579 * called recursively. Any code in this wrapper should take this in account.
580 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
581 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
582 * See also the implementation of pthread_create@GLIBC_2.0 in
583 * glibc-2.9/nptl/pthread_create.c.
586 static __always_inline
587 int pthread_create_intercept(pthread_t* thread, const pthread_attr_t* attr,
588 void* (*start)(void*), void* arg)
590 int ret;
591 OrigFn fn;
592 DrdSema wrapper_started;
593 DrdPosixThreadArgs thread_args;
595 VALGRIND_GET_ORIG_FN(fn);
597 DRD_(sema_init)(&wrapper_started);
598 thread_args.start = start;
599 thread_args.arg = arg;
600 thread_args.wrapper_started = &wrapper_started;
602 * Find out whether the thread will be started as a joinable thread
603 * or as a detached thread. If no thread attributes have been specified,
604 * this means that the new thread will be started as a joinable thread.
606 thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
607 /* The C11 thrd_create() implementation passes -1 as 'attr' argument. */
608 if (attr && (uintptr_t)attr + 1 != 0)
610 if (pthread_attr_getdetachstate(attr, &thread_args.detachstate) != 0)
611 assert(0);
613 assert(thread_args.detachstate == PTHREAD_CREATE_JOINABLE
614 || thread_args.detachstate == PTHREAD_CREATE_DETACHED);
617 * The DRD_(set_pthread_id)() from DRD_(init)() may encounter that
618 * pthread_self() == 0, e.g. when the main program is not linked with the
619 * pthread library and when a pthread_create() call occurs from within a
620 * shared library. Hence call DRD_(set_pthread_id)() again to ensure that
621 * DRD knows the identity of the current thread. See also B.Z. 356374.
623 DRD_(set_pthread_id)();
624 DRD_(entering_pthread_create)();
625 CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), &thread_args);
626 DRD_(left_pthread_create)();
628 if (ret == 0) {
629 /* Wait until the thread wrapper started. */
630 DRD_(sema_down)(&wrapper_started);
633 DRD_(sema_destroy)(&wrapper_started);
635 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_START_NEW_SEGMENT,
636 pthread_self(), 0, 0, 0, 0);
638 return ret;
641 PTH_FUNCS(int, pthreadZucreate, pthread_create_intercept,
642 (pthread_t *thread, const pthread_attr_t *attr,
643 void *(*start) (void *), void *arg),
644 (thread, attr, start, arg));
646 #if defined(VGO_solaris)
647 /* Solaris also provides thr_create() in addition to pthread_create().
648 * Both pthread_create(3C) and thr_create(3C) are based on private
649 * _thrp_create().
651 static __always_inline
652 int thr_create_intercept(void *stk, size_t stksize, void *(*start)(void *),
653 void *arg, long flags, thread_t *new_thread)
655 int ret;
656 OrigFn fn;
657 DrdSema wrapper_started;
658 DrdPosixThreadArgs thread_args;
660 VALGRIND_GET_ORIG_FN(fn);
662 DRD_(sema_init)(&wrapper_started);
663 thread_args.start = start;
664 thread_args.arg = arg;
665 thread_args.wrapper_started = &wrapper_started;
667 * Find out whether the thread will be started as a joinable thread
668 * or as a detached thread.
670 if (flags & THR_DETACHED)
671 thread_args.detachstate = PTHREAD_CREATE_DETACHED;
672 else
673 thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
675 DRD_(entering_pthread_create)();
676 CALL_FN_W_6W(ret, fn, stk, stksize, DRD_(thread_wrapper), &thread_args,
677 flags, new_thread);
678 DRD_(left_pthread_create)();
680 if (ret == 0) {
681 /* Wait until the thread wrapper started. */
682 DRD_(sema_down)(&wrapper_started);
685 DRD_(sema_destroy)(&wrapper_started);
687 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_START_NEW_SEGMENT,
688 pthread_self(), 0, 0, 0, 0);
690 return ret;
693 PTH_FUNCS(int, thrZucreate, thr_create_intercept,
694 (void *stk, size_t stksize, void *(*start)(void *), void *arg,
695 long flags, thread_t *new_thread),
696 (stk, stksize, start, arg, flags, new_thread));
697 #endif /* VGO_solaris */
699 #if defined(VGO_solaris)
701 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
702 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
703 * and CI_BIND_CLEAR, to provide resilience against function renaming.
705 static __always_inline
706 int DRD_(_ti_bind_guard_intercept)(int flags) {
707 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_RTLD_BIND_GUARD,
708 flags, 0, 0, 0, 0);
709 return DRD_(rtld_bind_guard)(flags);
712 static __always_inline
713 int DRD_(_ti_bind_clear_intercept)(int flags) {
714 int ret = DRD_(rtld_bind_clear)(flags);
715 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_RTLD_BIND_CLEAR,
716 flags, 0, 0, 0, 0);
717 return ret;
721 * Wrapped _ld_libc() from the runtime linker ld.so.1.
723 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr);
724 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr)
726 OrigFn fn;
727 int tag;
729 VALGRIND_GET_ORIG_FN(fn);
731 vki_Lc_interface *funcs = ptr;
732 for (tag = funcs->ci_tag; tag != 0; tag = (++funcs)->ci_tag) {
733 switch (tag) {
734 case VKI_CI_BIND_GUARD:
735 if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_guard_intercept)) {
736 DRD_(rtld_bind_guard) = funcs->vki_ci_un.ci_func;
737 funcs->vki_ci_un.ci_func = DRD_(_ti_bind_guard_intercept);
739 break;
740 case VKI_CI_BIND_CLEAR:
741 if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_clear_intercept)) {
742 DRD_(rtld_bind_clear) = funcs->vki_ci_un.ci_func;
743 funcs->vki_ci_un.ci_func = DRD_(_ti_bind_clear_intercept);
745 break;
749 CALL_FN_v_W(fn, ptr);
751 #endif /* VGO_solaris */
753 static __always_inline
754 int pthread_join_intercept(pthread_t pt_joinee, void **thread_return)
756 int ret;
757 OrigFn fn;
759 VALGRIND_GET_ORIG_FN(fn);
761 * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
762 * implementation triggers a (false positive) race report.
764 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
765 CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
766 if (ret == 0)
768 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_THREAD_JOIN,
769 pt_joinee, 0, 0, 0, 0);
771 ANNOTATE_IGNORE_READS_AND_WRITES_END();
772 return ret;
775 PTH_FUNCS(int, pthreadZujoin, pthread_join_intercept,
776 (pthread_t pt_joinee, void **thread_return),
777 (pt_joinee, thread_return));
779 #if defined(VGO_solaris)
780 /* Solaris also provides thr_join() in addition to pthread_join().
781 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
783 * :TODO: No functionality is currently provided for joinee == 0 and departed.
784 * This would require another client request, of course.
786 static __always_inline
787 int thr_join_intercept(thread_t joinee, thread_t *departed, void **thread_return)
789 int ret;
790 OrigFn fn;
792 VALGRIND_GET_ORIG_FN(fn);
793 CALL_FN_W_WWW(ret, fn, joinee, departed, thread_return);
794 if (ret == 0)
796 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_THREAD_JOIN,
797 joinee, 0, 0, 0, 0);
799 return ret;
802 PTH_FUNCS(int, thrZujoin, thr_join_intercept,
803 (thread_t joinee, thread_t *departed, void **thread_return),
804 (joinee, departed, thread_return));
805 #endif /* VGO_solaris */
807 static __always_inline
808 int pthread_detach_intercept(pthread_t pt_thread)
810 int ret;
811 OrigFn fn;
813 VALGRIND_GET_ORIG_FN(fn);
814 CALL_FN_W_W(ret, fn, pt_thread);
815 DRD_(set_joinable)(pt_thread, 0);
817 return ret;
820 PTH_FUNCS(int, pthreadZudetach, pthread_detach_intercept,
821 (pthread_t thread), (thread));
823 // NOTE: be careful to intercept only pthread_cancel() and not
824 // pthread_cancel_init() on Linux.
826 static __always_inline
827 int pthread_cancel_intercept(pthread_t pt_thread)
829 int ret;
830 OrigFn fn;
831 VALGRIND_GET_ORIG_FN(fn);
832 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_THREAD_CANCEL,
833 pt_thread, 0, 0, 0, 0);
834 CALL_FN_W_W(ret, fn, pt_thread);
835 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_THREAD_CANCEL,
836 pt_thread, ret==0, 0, 0, 0);
837 return ret;
840 PTH_FUNCS(int, pthreadZucancel, pthread_cancel_intercept,
841 (pthread_t thread), (thread))
843 static __always_inline
844 int pthread_once_intercept(pthread_once_t *once_control,
845 void (*init_routine)(void))
847 int ret;
848 OrigFn fn;
849 VALGRIND_GET_ORIG_FN(fn);
851 * Ignore any data races triggered by the implementation of pthread_once().
852 * Necessary for Darwin. This is not necessary for Linux but doesn't have
853 * any known adverse effects.
855 DRD_IGNORE_VAR(*once_control);
856 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
857 CALL_FN_W_WW(ret, fn, once_control, init_routine);
858 ANNOTATE_IGNORE_READS_AND_WRITES_END();
859 DRD_STOP_IGNORING_VAR(*once_control);
860 return ret;
863 PTH_FUNCS(int, pthreadZuonce, pthread_once_intercept,
864 (pthread_once_t *once_control, void (*init_routine)(void)),
865 (once_control, init_routine));
867 static __always_inline
868 int pthread_mutex_init_intercept(pthread_mutex_t *mutex,
869 const pthread_mutexattr_t* attr)
871 int ret;
872 OrigFn fn;
873 int mt;
874 VALGRIND_GET_ORIG_FN(fn);
875 mt = PTHREAD_MUTEX_DEFAULT;
876 if (attr)
877 pthread_mutexattr_gettype(attr, &mt);
878 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_INIT,
879 mutex, DRD_(pthread_to_drd_mutex_type)(mt),
880 0, 0, 0);
881 CALL_FN_W_WW(ret, fn, mutex, attr);
882 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_INIT,
883 mutex, 0, 0, 0, 0);
884 return ret;
887 PTH_FUNCS(int, pthreadZumutexZuinit, pthread_mutex_init_intercept,
888 (pthread_mutex_t *mutex, const pthread_mutexattr_t* attr),
889 (mutex, attr));
891 #if defined(VGO_solaris)
892 static __always_inline
893 int mutex_init_intercept(mutex_t *mutex, int type, void *arg)
895 int ret;
896 OrigFn fn;
897 VALGRIND_GET_ORIG_FN(fn);
899 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_INIT,
900 mutex, DRD_(thread_to_drd_mutex_type)(type),
901 0, 0, 0);
902 CALL_FN_W_WWW(ret, fn, mutex, type, arg);
903 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_INIT,
904 mutex, 0, 0, 0, 0);
905 return ret;
908 PTH_FUNCS(int, mutexZuinit, mutex_init_intercept,
909 (mutex_t *mutex, int type, void *arg),
910 (mutex, type, arg));
911 #endif /* VGO_solaris */
913 static __always_inline
914 int pthread_mutex_destroy_intercept(pthread_mutex_t* mutex)
916 int ret;
917 OrigFn fn;
918 VALGRIND_GET_ORIG_FN(fn);
919 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_DESTROY,
920 mutex, 0, 0, 0, 0);
921 CALL_FN_W_W(ret, fn, mutex);
922 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_DESTROY,
923 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
924 return ret;
927 #if defined(VGO_solaris)
928 /* On Solaris, pthread_mutex_destroy is a weak alias to mutex_destroy. */
929 PTH_FUNCS(int, mutexZudestroy, pthread_mutex_destroy_intercept,
930 (pthread_mutex_t *mutex), (mutex));
931 #else
932 PTH_FUNCS(int, pthreadZumutexZudestroy, pthread_mutex_destroy_intercept,
933 (pthread_mutex_t *mutex), (mutex));
934 #endif /* VGO_solaris */
936 static __always_inline
937 int pthread_mutex_lock_intercept(pthread_mutex_t* mutex)
939 int ret;
940 OrigFn fn;
941 VALGRIND_GET_ORIG_FN(fn);
942 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK,
943 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
944 CALL_FN_W_W(ret, fn, mutex);
945 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK,
946 mutex, ret == 0, 0, 0, 0);
947 return ret;
950 #if defined(VGO_solaris)
951 /* On Solaris, pthread_mutex_lock is a weak alias to mutex_lock. */
952 PTH_FUNCS(int, mutexZulock, pthread_mutex_lock_intercept,
953 (pthread_mutex_t *mutex), (mutex));
954 #else
955 PTH_FUNCS(int, pthreadZumutexZulock, pthread_mutex_lock_intercept,
956 (pthread_mutex_t *mutex), (mutex));
957 #endif /* VGO_solaris */
959 #if defined(VGO_solaris)
960 /* Internal to libc. Mutex is usually initialized only implicitly,
961 * by zeroing mutex_t structure.
963 static __always_inline
964 void lmutex_lock_intercept(mutex_t *mutex)
966 OrigFn fn;
967 VALGRIND_GET_ORIG_FN(fn);
968 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK,
969 mutex,
970 DRD_(mutex_type)((pthread_mutex_t *) mutex),
971 False /* try_lock */, 0, 0);
972 CALL_FN_v_W(fn, mutex);
973 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK,
974 mutex, True /* took_lock */, 0, 0, 0);
977 PTH_FUNCS(void, lmutexZulock, lmutex_lock_intercept,
978 (mutex_t *mutex), (mutex));
979 #endif /* VGO_solaris */
981 static __always_inline
982 int pthread_mutex_trylock_intercept(pthread_mutex_t* mutex)
984 int ret;
985 OrigFn fn;
986 VALGRIND_GET_ORIG_FN(fn);
987 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK,
988 mutex, DRD_(mutex_type)(mutex), 1, 0, 0);
989 CALL_FN_W_W(ret, fn, mutex);
990 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK,
991 mutex, ret == 0, 0, 0, 0);
992 return ret;
995 #if defined(VGO_solaris)
996 /* On Solaris, pthread_mutex_trylock is a weak alias to mutex_trylock. */
997 PTH_FUNCS(int, mutexZutrylock, pthread_mutex_trylock_intercept,
998 (pthread_mutex_t *mutex), (mutex));
999 #else
1000 PTH_FUNCS(int, pthreadZumutexZutrylock, pthread_mutex_trylock_intercept,
1001 (pthread_mutex_t *mutex), (mutex));
1002 #endif /* VGO_solaris */
1004 static __always_inline
1005 int pthread_mutex_timedlock_intercept(pthread_mutex_t *mutex,
1006 const struct timespec *abs_timeout)
1008 int ret;
1009 OrigFn fn;
1010 VALGRIND_GET_ORIG_FN(fn);
1011 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK,
1012 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
1013 CALL_FN_W_WW(ret, fn, mutex, abs_timeout);
1014 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK,
1015 mutex, ret == 0, 0, 0, 0);
1016 return ret;
1019 PTH_FUNCS(int, pthreadZumutexZutimedlock, pthread_mutex_timedlock_intercept,
1020 (pthread_mutex_t *mutex, const struct timespec *abs_timeout),
1021 (mutex, abs_timeout));
1022 #if defined(VGO_solaris)
1023 PTH_FUNCS(int,
1024 pthreadZumutexZureltimedlockZunp, pthread_mutex_timedlock_intercept,
1025 (pthread_mutex_t *mutex, const struct timespec *timeout),
1026 (mutex, timeout));
1027 #endif /* VGO_solaris */
1029 #if defined(HAVE_CLOCKID_T)
1030 static __always_inline
1031 int pthread_mutex_clocklock_intercept(pthread_mutex_t *mutex,
1032 clockid_t clockid,
1033 const struct timespec *abs_timeout)
1035 int ret;
1036 OrigFn fn;
1037 VALGRIND_GET_ORIG_FN(fn);
1038 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK,
1039 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
1040 CALL_FN_W_WWW(ret, fn, mutex, clockid, abs_timeout);
1041 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK,
1042 mutex, ret == 0, 0, 0, 0);
1043 return ret;
1046 PTH_FUNCS(int, pthreadZumutexZuclocklock, pthread_mutex_clocklock_intercept,
1047 (pthread_mutex_t *mutex, clockid_t clockid, const struct timespec *abs_timeout),
1048 (mutex, clockid, abs_timeout));
1049 #endif
1051 static __always_inline
1052 int pthread_mutex_unlock_intercept(pthread_mutex_t *mutex)
1054 int ret;
1055 OrigFn fn;
1056 VALGRIND_GET_ORIG_FN(fn);
1057 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_UNLOCK,
1058 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
1059 CALL_FN_W_W(ret, fn, mutex);
1060 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_UNLOCK,
1061 mutex, 0, 0, 0, 0);
1062 return ret;
1065 #if defined(VGO_solaris)
1066 /* On Solaris, pthread_mutex_unlock is a weak alias to mutex_unlock. */
1067 PTH_FUNCS(int, mutexZuunlock, pthread_mutex_unlock_intercept,
1068 (pthread_mutex_t *mutex), (mutex));
1069 #else
1070 PTH_FUNCS(int, pthreadZumutexZuunlock, pthread_mutex_unlock_intercept,
1071 (pthread_mutex_t *mutex), (mutex));
1072 #endif /* VGO_solaris */
1074 #if defined(VGO_solaris)
1075 /* Internal to libc. */
1076 static __always_inline
1077 void lmutex_unlock_intercept(mutex_t *mutex)
1079 OrigFn fn;
1080 VALGRIND_GET_ORIG_FN(fn);
1081 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_UNLOCK,
1082 mutex,
1083 DRD_(mutex_type)((pthread_mutex_t *) mutex),
1084 0, 0, 0);
1085 CALL_FN_v_W(fn, mutex);
1086 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_UNLOCK,
1087 mutex, 0, 0, 0, 0);
1090 PTH_FUNCS(void, lmutexZuunlock, lmutex_unlock_intercept,
1091 (mutex_t *mutex), (mutex));
1092 #endif /* VGO_solaris */
1094 static __always_inline
1095 int pthread_cond_init_intercept(pthread_cond_t* cond,
1096 const pthread_condattr_t* attr)
1098 int ret;
1099 OrigFn fn;
1100 VALGRIND_GET_ORIG_FN(fn);
1101 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_INIT,
1102 cond, 0, 0, 0, 0);
1103 CALL_FN_W_WW(ret, fn, cond, attr);
1104 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_INIT,
1105 cond, 0, 0, 0, 0);
1106 return ret;
1109 PTH_FUNCS(int, pthreadZucondZuinit, pthread_cond_init_intercept,
1110 (pthread_cond_t* cond, const pthread_condattr_t* attr),
1111 (cond, attr));
1113 #if defined(VGO_solaris)
1114 static __always_inline
1115 int cond_init_intercept(cond_t *cond, int type, void *arg)
1117 int ret;
1118 OrigFn fn;
1119 VALGRIND_GET_ORIG_FN(fn);
1120 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_INIT,
1121 cond, 0, 0, 0, 0);
1122 CALL_FN_W_WWW(ret, fn, cond, type, arg);
1123 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_INIT,
1124 cond, 0, 0, 0, 0);
1125 return ret;
1128 PTH_FUNCS(int, condZuinit, cond_init_intercept,
1129 (cond_t *cond, int type, void *arg),
1130 (cond, type, arg));
1131 #endif /* VGO_solaris */
1133 static __always_inline
1134 int pthread_cond_destroy_intercept(pthread_cond_t* cond)
1136 int ret;
1137 OrigFn fn;
1138 VALGRIND_GET_ORIG_FN(fn);
1139 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_DESTROY,
1140 cond, 0, 0, 0, 0);
1141 CALL_FN_W_W(ret, fn, cond);
1142 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_DESTROY,
1143 cond, ret==0, 0, 0, 0);
1144 return ret;
1147 #if defined(VGO_solaris)
1148 /* On Solaris, pthread_cond_destroy is a weak alias to cond_destroy. */
1149 PTH_FUNCS(int, condZudestroy, pthread_cond_destroy_intercept,
1150 (pthread_cond_t *cond), (cond));
1151 #else
1152 PTH_FUNCS(int, pthreadZucondZudestroy, pthread_cond_destroy_intercept,
1153 (pthread_cond_t* cond), (cond));
1154 #endif /* VGO_solaris */
1156 static __always_inline
1157 int pthread_cond_wait_intercept(pthread_cond_t *cond, pthread_mutex_t *mutex)
1159 int ret;
1160 OrigFn fn;
1161 VALGRIND_GET_ORIG_FN(fn);
1162 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_WAIT,
1163 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1164 CALL_FN_W_WW(ret, fn, cond, mutex);
1165 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_WAIT,
1166 cond, mutex, 1, 0, 0);
1167 return ret;
1170 PTH_FUNCS(int, pthreadZucondZuwait, pthread_cond_wait_intercept,
1171 (pthread_cond_t *cond, pthread_mutex_t *mutex),
1172 (cond, mutex));
1173 #if defined(VGO_solaris)
1174 PTH_FUNCS(int, condZuwait, pthread_cond_wait_intercept,
1175 (pthread_cond_t *cond, pthread_mutex_t *mutex),
1176 (cond, mutex));
1177 #endif /* VGO_solaris */
1179 static __always_inline
1180 int pthread_cond_timedwait_intercept(pthread_cond_t *cond,
1181 pthread_mutex_t *mutex,
1182 const struct timespec* abstime)
1184 int ret;
1185 OrigFn fn;
1186 VALGRIND_GET_ORIG_FN(fn);
1187 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_WAIT,
1188 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1189 CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
1190 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_WAIT,
1191 cond, mutex, 1, 0, 0);
1192 return ret;
1195 PTH_FUNCS(int, pthreadZucondZutimedwait, pthread_cond_timedwait_intercept,
1196 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1197 const struct timespec* abstime),
1198 (cond, mutex, abstime));
1199 #if defined(VGO_solaris)
1200 PTH_FUNCS(int, condZutimedwait, pthread_cond_timedwait_intercept,
1201 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1202 const struct timespec *timeout),
1203 (cond, mutex, timeout));
1204 PTH_FUNCS(int, condZureltimedwait, pthread_cond_timedwait_intercept,
1205 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1206 const struct timespec *timeout),
1207 (cond, mutex, timeout));
1208 #endif /* VGO_solaris */
1211 #if defined(HAVE_CLOCKID_T)
1212 static __always_inline
1213 int pthread_cond_clockwait_intercept(pthread_cond_t *cond,
1214 pthread_mutex_t *mutex,
1215 clockid_t clockid,
1216 const struct timespec* abstime)
1218 int ret;
1219 OrigFn fn;
1220 VALGRIND_GET_ORIG_FN(fn);
1221 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_WAIT,
1222 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1223 CALL_FN_W_WWWW(ret, fn, cond, mutex, clockid, abstime);
1224 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_WAIT,
1225 cond, mutex, 1, 0, 0);
1226 return ret;
1229 PTH_FUNCS(int, pthreadZucondZuclockwait, pthread_cond_clockwait_intercept,
1230 (pthread_cond_t *cond, pthread_mutex_t *mutex,
1231 clockid_t clockid, const struct timespec* abstime),
1232 (cond, mutex, clockid, abstime));
1233 #endif
1236 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
1237 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
1238 // two. Intercepting all pthread_cond_signal* functions will cause only one
1239 // argument to be passed to pthread_cond_signal_np() and hence will cause this
1240 // last function to crash.
1242 static __always_inline
1243 int pthread_cond_signal_intercept(pthread_cond_t* cond)
1245 int ret;
1246 OrigFn fn;
1247 VALGRIND_GET_ORIG_FN(fn);
1248 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_SIGNAL,
1249 cond, 0, 0, 0, 0);
1250 CALL_FN_W_W(ret, fn, cond);
1251 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_SIGNAL,
1252 cond, 0, 0, 0, 0);
1253 return ret;
1256 #if defined(VGO_solaris)
1257 /* On Solaris, pthread_cond_signal is a weak alias to cond_signal. */
1258 PTH_FUNCS(int, condZusignal, pthread_cond_signal_intercept,
1259 (pthread_cond_t *cond), (cond));
1260 #else
1261 PTH_FUNCS(int, pthreadZucondZusignal, pthread_cond_signal_intercept,
1262 (pthread_cond_t* cond), (cond));
1263 #endif /* VGO_solaris */
1265 static __always_inline
1266 int pthread_cond_broadcast_intercept(pthread_cond_t* cond)
1268 int ret;
1269 OrigFn fn;
1270 VALGRIND_GET_ORIG_FN(fn);
1271 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_COND_BROADCAST,
1272 cond, 0, 0, 0, 0);
1273 CALL_FN_W_W(ret, fn, cond);
1274 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_COND_BROADCAST,
1275 cond, 0, 0, 0, 0);
1276 return ret;
1279 #if defined(VGO_solaris)
1280 /* On Solaris, pthread_cond_broadcast is a weak alias to cond_broadcast. */
1281 PTH_FUNCS(int, condZubroadcast, pthread_cond_broadcast_intercept,
1282 (pthread_cond_t *cond), (cond));
1283 #else
1284 PTH_FUNCS(int, pthreadZucondZubroadcast, pthread_cond_broadcast_intercept,
1285 (pthread_cond_t* cond), (cond));
1286 #endif /* VGO_solaris */
1288 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1289 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1290 static __always_inline
1291 int pthread_spin_init_intercept(pthread_spinlock_t *spinlock, int pshared)
1293 int ret;
1294 OrigFn fn;
1295 VALGRIND_GET_ORIG_FN(fn);
1296 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SPIN_INIT_OR_UNLOCK,
1297 spinlock, 0, 0, 0, 0);
1298 CALL_FN_W_WW(ret, fn, spinlock, pshared);
1299 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SPIN_INIT_OR_UNLOCK,
1300 spinlock, 0, 0, 0, 0);
1301 return ret;
1304 PTH_FUNCS(int, pthreadZuspinZuinit, pthread_spin_init_intercept,
1305 (pthread_spinlock_t *spinlock, int pshared), (spinlock, pshared));
1307 static __always_inline
1308 int pthread_spin_destroy_intercept(pthread_spinlock_t *spinlock)
1310 int ret;
1311 OrigFn fn;
1312 VALGRIND_GET_ORIG_FN(fn);
1313 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_DESTROY,
1314 spinlock, 0, 0, 0, 0);
1315 CALL_FN_W_W(ret, fn, spinlock);
1316 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_DESTROY,
1317 spinlock, mutex_type_spinlock, 0, 0, 0);
1318 return ret;
1321 PTH_FUNCS(int, pthreadZuspinZudestroy, pthread_spin_destroy_intercept,
1322 (pthread_spinlock_t *spinlock), (spinlock));
1324 static __always_inline
1325 int pthread_spin_lock_intercept(pthread_spinlock_t *spinlock)
1327 int ret;
1328 OrigFn fn;
1329 VALGRIND_GET_ORIG_FN(fn);
1330 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK,
1331 spinlock, mutex_type_spinlock, 0, 0, 0);
1332 CALL_FN_W_W(ret, fn, spinlock);
1333 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK,
1334 spinlock, ret == 0, 0, 0, 0);
1335 return ret;
1338 PTH_FUNCS(int, pthreadZuspinZulock, pthread_spin_lock_intercept,
1339 (pthread_spinlock_t *spinlock), (spinlock));
1341 static __always_inline
1342 int pthread_spin_trylock_intercept(pthread_spinlock_t *spinlock)
1344 int ret;
1345 OrigFn fn;
1346 VALGRIND_GET_ORIG_FN(fn);
1347 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_MUTEX_LOCK,
1348 spinlock, mutex_type_spinlock, 0, 0, 0);
1349 CALL_FN_W_W(ret, fn, spinlock);
1350 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_MUTEX_LOCK,
1351 spinlock, ret == 0, 0, 0, 0);
1352 return ret;
1355 PTH_FUNCS(int, pthreadZuspinZutrylock, pthread_spin_trylock_intercept,
1356 (pthread_spinlock_t *spinlock), (spinlock));
1358 static __always_inline
1359 int pthread_spin_unlock_intercept(pthread_spinlock_t *spinlock)
1361 int ret;
1362 OrigFn fn;
1363 VALGRIND_GET_ORIG_FN(fn);
1364 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SPIN_INIT_OR_UNLOCK,
1365 spinlock, mutex_type_spinlock, 0, 0, 0);
1366 CALL_FN_W_W(ret, fn, spinlock);
1367 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SPIN_INIT_OR_UNLOCK,
1368 spinlock, 0, 0, 0, 0);
1369 return ret;
1372 PTH_FUNCS(int, pthreadZuspinZuunlock, pthread_spin_unlock_intercept,
1373 (pthread_spinlock_t *spinlock), (spinlock));
1374 #endif // HAVE_PTHREAD_SPIN_LOCK
1377 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1378 static __always_inline
1379 int pthread_barrier_init_intercept(pthread_barrier_t* barrier,
1380 const pthread_barrierattr_t* attr,
1381 unsigned count)
1383 int ret;
1384 OrigFn fn;
1385 VALGRIND_GET_ORIG_FN(fn);
1386 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_BARRIER_INIT,
1387 barrier, pthread_barrier, count, 0, 0);
1388 CALL_FN_W_WWW(ret, fn, barrier, attr, count);
1389 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_BARRIER_INIT,
1390 barrier, pthread_barrier, 0, 0, 0);
1391 return ret;
1394 PTH_FUNCS(int, pthreadZubarrierZuinit, pthread_barrier_init_intercept,
1395 (pthread_barrier_t* barrier, const pthread_barrierattr_t* attr,
1396 unsigned count), (barrier, attr, count));
1398 static __always_inline
1399 int pthread_barrier_destroy_intercept(pthread_barrier_t* barrier)
1401 int ret;
1402 OrigFn fn;
1403 VALGRIND_GET_ORIG_FN(fn);
1404 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_BARRIER_DESTROY,
1405 barrier, pthread_barrier, 0, 0, 0);
1406 CALL_FN_W_W(ret, fn, barrier);
1407 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_BARRIER_DESTROY,
1408 barrier, pthread_barrier, 0, 0, 0);
1409 return ret;
1412 PTH_FUNCS(int, pthreadZubarrierZudestroy, pthread_barrier_destroy_intercept,
1413 (pthread_barrier_t* barrier), (barrier));
1415 static __always_inline
1416 int pthread_barrier_wait_intercept(pthread_barrier_t* barrier)
1418 int ret;
1419 OrigFn fn;
1420 VALGRIND_GET_ORIG_FN(fn);
1421 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_BARRIER_WAIT,
1422 barrier, pthread_barrier, 0, 0, 0);
1423 CALL_FN_W_W(ret, fn, barrier);
1424 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_BARRIER_WAIT,
1425 barrier, pthread_barrier,
1426 ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD,
1427 ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
1428 return ret;
1431 PTH_FUNCS(int, pthreadZubarrierZuwait, pthread_barrier_wait_intercept,
1432 (pthread_barrier_t* barrier), (barrier));
1433 #endif // HAVE_PTHREAD_BARRIER_INIT
1436 static __always_inline
1437 int sem_init_intercept(sem_t *sem, int pshared, unsigned int value)
1439 int ret;
1440 OrigFn fn;
1441 VALGRIND_GET_ORIG_FN(fn);
1442 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_INIT,
1443 sem, pshared, value, 0, 0);
1444 CALL_FN_W_WWW(ret, fn, sem, pshared, value);
1445 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_INIT,
1446 sem, 0, 0, 0, 0);
1447 return ret;
1450 #if defined(VGO_freebsd)
1451 LIBC_FUNC(int, semZuinit, sem_init_intercept,
1452 (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
1453 #else
1454 PTH_FUNCS(int, semZuinit, sem_init_intercept,
1455 (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
1456 #endif
1458 #if defined(VGO_solaris)
1459 static __always_inline
1460 int sema_init_intercept(sema_t *sem, unsigned int value, int type, void *arg)
1462 int ret;
1463 OrigFn fn;
1464 VALGRIND_GET_ORIG_FN(fn);
1465 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_INIT,
1466 sem, type == USYNC_PROCESS ? 1 : 0,
1467 value, 0, 0);
1468 CALL_FN_W_WWWW(ret, fn, sem, value, type, arg);
1469 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_INIT,
1470 sem, 0, 0, 0, 0);
1471 return ret;
1474 PTH_FUNCS(int, semaZuinit, sema_init_intercept,
1475 (sema_t *sem, unsigned int value, int type, void *arg),
1476 (sem, value, type, arg));
1477 #endif /* VGO_solaris */
1479 static __always_inline
1480 int sem_destroy_intercept(sem_t *sem)
1482 int ret;
1483 OrigFn fn;
1484 VALGRIND_GET_ORIG_FN(fn);
1485 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_DESTROY,
1486 sem, 0, 0, 0, 0);
1487 CALL_FN_W_W(ret, fn, sem);
1488 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_DESTROY,
1489 sem, 0, 0, 0, 0);
1490 return ret;
1493 #if defined(VGO_freebsd)
1494 LIBC_FUNC(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1495 #else
1496 PTH_FUNCS(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1497 #endif
1499 #if defined(VGO_solaris)
1500 PTH_FUNCS(int, semaZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1501 #endif /* VGO_solaris */
1503 static __always_inline
1504 sem_t* sem_open_intercept(const char *name, int oflag, mode_t mode,
1505 unsigned int value)
1507 sem_t *ret;
1508 OrigFn fn;
1509 VALGRIND_GET_ORIG_FN(fn);
1510 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_OPEN,
1511 name, oflag, mode, value, 0);
1512 CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value);
1513 // To do: figure out why gcc 9.2.1 miscompiles this function if the printf()
1514 // call below is left out.
1515 printf("");
1516 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_OPEN,
1517 ret != SEM_FAILED ? ret : 0,
1518 name, oflag, mode, value);
1519 return ret;
1522 #if defined(VGO_freebsd)
1523 LIBC_FUNC(sem_t *, semZuopen, sem_open_intercept,
1524 (const char *name, int oflag, mode_t mode, unsigned int value),
1525 (name, oflag, mode, value));
1526 #else
1527 PTH_FUNCS(sem_t *, semZuopen, sem_open_intercept,
1528 (const char *name, int oflag, mode_t mode, unsigned int value),
1529 (name, oflag, mode, value));
1530 #endif
1532 static __always_inline int sem_close_intercept(sem_t *sem)
1534 int ret;
1535 OrigFn fn;
1536 VALGRIND_GET_ORIG_FN(fn);
1537 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_CLOSE,
1538 sem, 0, 0, 0, 0);
1539 CALL_FN_W_W(ret, fn, sem);
1540 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_CLOSE,
1541 sem, 0, 0, 0, 0);
1542 return ret;
1545 #if defined(VGO_freebsd)
1546 LIBC_FUNC(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
1547 #else
1548 PTH_FUNCS(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
1549 #endif
1551 static __always_inline int sem_wait_intercept(sem_t *sem)
1553 int ret;
1554 OrigFn fn;
1555 VALGRIND_GET_ORIG_FN(fn);
1556 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT,
1557 sem, 0, 0, 0, 0);
1558 CALL_FN_W_W(ret, fn, sem);
1559 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT,
1560 sem, ret == 0, 0, 0, 0);
1561 return ret;
1564 #if defined(VGO_freebsd)
1565 LIBC_FUNC(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1566 #else
1567 PTH_FUNCS(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1568 #endif
1570 #if defined(VGO_solaris)
1571 PTH_FUNCS(int, semaZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1572 #endif /* VGO_solaris */
1574 static __always_inline int sem_trywait_intercept(sem_t *sem)
1576 int ret;
1577 OrigFn fn;
1578 VALGRIND_GET_ORIG_FN(fn);
1579 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT,
1580 sem, 0, 0, 0, 0);
1581 CALL_FN_W_W(ret, fn, sem);
1582 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT,
1583 sem, ret == 0, 0, 0, 0);
1584 return ret;
1587 #if defined(VGO_freebsd)
1588 LIBC_FUNC(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1589 #else
1590 PTH_FUNCS(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1591 #endif
1592 #if defined(VGO_solaris)
1593 PTH_FUNCS(int, semaZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1594 #endif /* VGO_solaris */
1596 static __always_inline
1597 int sem_timedwait_intercept(sem_t *sem, const struct timespec *abs_timeout)
1599 int ret;
1600 OrigFn fn;
1601 VALGRIND_GET_ORIG_FN(fn);
1602 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT,
1603 sem, 0, 0, 0, 0);
1604 CALL_FN_W_WW(ret, fn, sem, abs_timeout);
1605 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT,
1606 sem, ret == 0, 0, 0, 0);
1607 return ret;
1610 #if defined(VGO_freebsd)
1611 LIBC_FUNC(int, semZutimedwait, sem_timedwait_intercept,
1612 (sem_t *sem, const struct timespec *abs_timeout),
1613 (sem, abs_timeout));
1614 #else
1615 PTH_FUNCS(int, semZutimedwait, sem_timedwait_intercept,
1616 (sem_t *sem, const struct timespec *abs_timeout),
1617 (sem, abs_timeout));
1618 #endif
1619 #if defined(VGO_solaris)
1620 PTH_FUNCS(int, semaZutimedwait, sem_timedwait_intercept,
1621 (sem_t *sem, const struct timespec *timeout),
1622 (sem, timeout));
1623 PTH_FUNCS(int, semaZureltimedwait, sem_timedwait_intercept,
1624 (sem_t *sem, const struct timespec *timeout),
1625 (sem, timeout));
1626 #endif /* VGO_solaris */
1628 static __always_inline int sem_post_intercept(sem_t *sem)
1630 int ret;
1631 OrigFn fn;
1632 VALGRIND_GET_ORIG_FN(fn);
1633 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_POST,
1634 sem, 0, 0, 0, 0);
1635 CALL_FN_W_W(ret, fn, sem);
1636 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_POST,
1637 sem, ret == 0, 0, 0, 0);
1638 return ret;
1641 #if defined(VGO_freebsd)
1642 LIBC_FUNC(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
1643 #else
1644 PTH_FUNCS(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
1645 #endif
1646 #if defined(VGO_solaris)
1647 PTH_FUNCS(int, semaZupost, sem_post_intercept, (sem_t *sem), (sem));
1648 #endif /* VGO_solaris */
1650 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1651 functions have to be conditionally compiled. */
1652 #if defined(HAVE_PTHREAD_RWLOCK_T)
1654 static __always_inline
1655 int pthread_rwlock_init_intercept(pthread_rwlock_t* rwlock,
1656 const pthread_rwlockattr_t* attr)
1658 int ret;
1659 OrigFn fn;
1660 VALGRIND_GET_ORIG_FN(fn);
1661 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_INIT,
1662 rwlock, 0, 0, 0, 0);
1663 CALL_FN_W_WW(ret, fn, rwlock, attr);
1664 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_INIT,
1665 rwlock, 0, 0, 0, 0);
1666 return ret;
1669 PTH_FUNCS(int,
1670 pthreadZurwlockZuinit, pthread_rwlock_init_intercept,
1671 (pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr),
1672 (rwlock, attr));
1674 #if defined(VGO_solaris)
1675 static __always_inline
1676 int rwlock_init_intercept(rwlock_t *rwlock, int type, void *arg)
1678 int ret;
1679 OrigFn fn;
1680 VALGRIND_GET_ORIG_FN(fn);
1681 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_INIT,
1682 rwlock, 0, 0, 0, 0);
1683 CALL_FN_W_WWW(ret, fn, rwlock, type, arg);
1684 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_INIT,
1685 rwlock, 0, 0, 0, 0);
1686 return ret;
1689 PTH_FUNCS(int, rwlockZuinit, rwlock_init_intercept,
1690 (rwlock_t *rwlock, int type, void *arg),
1691 (rwlock, type, arg));
1692 #endif /* VGO_solaris */
1694 static __always_inline
1695 int pthread_rwlock_destroy_intercept(pthread_rwlock_t* rwlock)
1697 int ret;
1698 OrigFn fn;
1699 VALGRIND_GET_ORIG_FN(fn);
1700 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_DESTROY,
1701 rwlock, 0, 0, 0, 0);
1702 CALL_FN_W_W(ret, fn, rwlock);
1703 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_DESTROY,
1704 rwlock, 0, 0, 0, 0);
1705 return ret;
1708 #if defined(VGO_solaris)
1709 /* On Solaris, pthread_rwlock_destroy is a weak alias to rwlock_destroy. */
1710 PTH_FUNCS(int,
1711 rwlockZudestroy, pthread_rwlock_destroy_intercept,
1712 (pthread_rwlock_t *rwlock), (rwlock));
1713 #else
1714 PTH_FUNCS(int,
1715 pthreadZurwlockZudestroy, pthread_rwlock_destroy_intercept,
1716 (pthread_rwlock_t* rwlock), (rwlock));
1717 #endif /* VGO_solaris */
1719 static __always_inline
1720 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t* rwlock)
1722 int ret;
1723 OrigFn fn;
1724 VALGRIND_GET_ORIG_FN(fn);
1725 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK,
1726 rwlock, 0, 0, 0, 0);
1727 CALL_FN_W_W(ret, fn, rwlock);
1728 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK,
1729 rwlock, ret == 0, 0, 0, 0);
1730 return ret;
1733 #if defined(VGO_solaris)
1734 /* On Solaris, pthread_rwlock_rdlock is a weak alias to rw_rdlock. */
1735 PTH_FUNCS(int,
1736 rwZurdlock, pthread_rwlock_rdlock_intercept,
1737 (pthread_rwlock_t *rwlock), (rwlock));
1738 #else
1739 PTH_FUNCS(int,
1740 pthreadZurwlockZurdlock, pthread_rwlock_rdlock_intercept,
1741 (pthread_rwlock_t* rwlock), (rwlock));
1742 #endif /* VGO_solaris */
1744 #if defined(VGO_solaris)
1745 /* Internal to libc. */
1746 static __always_inline
1747 void lrw_rdlock_intercept(rwlock_t *rwlock)
1749 OrigFn fn;
1750 VALGRIND_GET_ORIG_FN(fn);
1751 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK,
1752 rwlock, 0, 0, 0, 0);
1753 CALL_FN_v_W(fn, rwlock);
1754 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK,
1755 rwlock, True /* took_lock */, 0, 0, 0);
1758 PTH_FUNCS(void, lrwZurdlock, lrw_rdlock_intercept,
1759 (rwlock_t *rwlock), (rwlock));
1760 #endif /* VGO_solaris */
1762 static __always_inline
1763 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t* rwlock)
1765 int ret;
1766 OrigFn fn;
1767 VALGRIND_GET_ORIG_FN(fn);
1768 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK,
1769 rwlock, 0, 0, 0, 0);
1770 CALL_FN_W_W(ret, fn, rwlock);
1771 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK,
1772 rwlock, ret == 0, 0, 0, 0);
1773 return ret;
1776 #if defined(VGO_solaris)
1777 /* On Solaris, pthread_rwlock_wrlock is a weak alias to rw_wrlock. */
1778 PTH_FUNCS(int,
1779 rwZuwrlock, pthread_rwlock_wrlock_intercept,
1780 (pthread_rwlock_t *rwlock), (rwlock));
1781 #else
1782 PTH_FUNCS(int,
1783 pthreadZurwlockZuwrlock, pthread_rwlock_wrlock_intercept,
1784 (pthread_rwlock_t* rwlock), (rwlock));
1785 #endif /* VGO_solaris */
1787 #if defined(VGO_solaris)
1788 /* Internal to libc. */
1789 static __always_inline
1790 void lrw_wrlock_intercept(rwlock_t *rwlock)
1792 OrigFn fn;
1793 VALGRIND_GET_ORIG_FN(fn);
1794 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK,
1795 rwlock, 0, 0, 0, 0);
1796 CALL_FN_v_W(fn, rwlock);
1797 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK,
1798 rwlock, True /* took_lock */, 0, 0, 0);
1801 PTH_FUNCS(void, lrwZuwrlock, lrw_wrlock_intercept,
1802 (rwlock_t *rwlock), (rwlock));
1803 #endif /* VGO_solaris */
1805 static __always_inline
1806 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t* rwlock,
1807 const struct timespec *timeout)
1809 int ret;
1810 OrigFn fn;
1811 VALGRIND_GET_ORIG_FN(fn);
1812 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK,
1813 rwlock, 0, 0, 0, 0);
1814 CALL_FN_W_WW(ret, fn, rwlock, timeout);
1815 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK,
1816 rwlock, ret == 0, 0, 0, 0);
1817 return ret;
1820 PTH_FUNCS(int,
1821 pthreadZurwlockZutimedrdlock, pthread_rwlock_timedrdlock_intercept,
1822 (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1823 (rwlock, timeout));
1824 #if defined(VGO_solaris)
1825 PTH_FUNCS(int, pthreadZurwlockZureltimedrdlockZunp,
1826 pthread_rwlock_timedrdlock_intercept,
1827 (pthread_rwlock_t *rwlock, const struct timespec *timeout),
1828 (rwlock, timeout));
1829 #endif /* VGO_solaris */
1832 #if defined(HAVE_CLOCKID_T)
1833 static __always_inline
1834 int pthread_rwlock_clockrdlock_intercept(pthread_rwlock_t* rwlock,
1835 clockid_t clockid,
1836 const struct timespec *timeout)
1838 int ret;
1839 OrigFn fn;
1840 VALGRIND_GET_ORIG_FN(fn);
1841 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK,
1842 rwlock, 0, 0, 0, 0);
1843 CALL_FN_W_WWW(ret, fn, rwlock, clockid, timeout);
1844 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK,
1845 rwlock, ret == 0, 0, 0, 0);
1846 return ret;
1849 PTH_FUNCS(int,
1850 pthreadZurwlockZuclockrdlock, pthread_rwlock_clockrdlock_intercept,
1851 (pthread_rwlock_t* rwlock, clockid_t clockid, const struct timespec *timeout),
1852 (rwlock, clockid, timeout));
1853 #endif
1855 static __always_inline
1856 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t* rwlock,
1857 const struct timespec *timeout)
1859 int ret;
1860 OrigFn fn;
1861 VALGRIND_GET_ORIG_FN(fn);
1862 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK,
1863 rwlock, 0, 0, 0, 0);
1864 CALL_FN_W_WW(ret, fn, rwlock, timeout);
1865 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK,
1866 rwlock, ret == 0, 0, 0, 0);
1867 return ret;
1870 PTH_FUNCS(int,
1871 pthreadZurwlockZutimedwrlock, pthread_rwlock_timedwrlock_intercept,
1872 (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1873 (rwlock, timeout));
1874 #if defined(VGO_solaris)
1875 PTH_FUNCS(int, pthreadZurwlockZureltimedwrlockZunp,
1876 pthread_rwlock_timedwrlock_intercept,
1877 (pthread_rwlock_t *rwlock, const struct timespec *timeout),
1878 (rwlock, timeout));
1879 #endif /* VGO_solaris */
1882 #if defined(HAVE_CLOCKID_T)
1883 static __always_inline
1884 int pthread_rwlock_clockwrlock_intercept(pthread_rwlock_t* rwlock,
1885 clockid_t clockid,
1886 const struct timespec *timeout)
1888 int ret;
1889 OrigFn fn;
1890 VALGRIND_GET_ORIG_FN(fn);
1891 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK,
1892 rwlock, 0, 0, 0, 0);
1893 CALL_FN_W_WWW(ret, fn, rwlock, clockid, timeout);
1894 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK,
1895 rwlock, ret == 0, 0, 0, 0);
1896 return ret;
1899 PTH_FUNCS(int,
1900 pthreadZurwlockZuclockwrlock, pthread_rwlock_clockwrlock_intercept,
1901 (pthread_rwlock_t* rwlock, clockid_t clockid, const struct timespec *timeout),
1902 (rwlock, clockid, timeout));
1903 #endif
1906 static __always_inline
1907 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t* rwlock)
1909 int ret;
1910 OrigFn fn;
1911 VALGRIND_GET_ORIG_FN(fn);
1912 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK,
1913 rwlock, 0, 0, 0, 0);
1914 CALL_FN_W_W(ret, fn, rwlock);
1915 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_RDLOCK,
1916 rwlock, ret == 0, 0, 0, 0);
1917 return ret;
1920 #if defined(VGO_solaris)
1921 /* On Solaris, pthread_rwlock_tryrdlock is a weak alias to rw_tryrdlock. */
1922 PTH_FUNCS(int,
1923 rwZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1924 (pthread_rwlock_t *rwlock), (rwlock));
1925 #else
1926 PTH_FUNCS(int,
1927 pthreadZurwlockZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1928 (pthread_rwlock_t* rwlock), (rwlock));
1929 #endif /* VGO_solaris */
1931 static __always_inline
1932 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t* rwlock)
1934 int ret;
1935 OrigFn fn;
1936 VALGRIND_GET_ORIG_FN(fn);
1937 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK,
1938 rwlock, 0, 0, 0, 0);
1939 CALL_FN_W_W(ret, fn, rwlock);
1940 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_WRLOCK,
1941 rwlock, ret == 0, 0, 0, 0);
1942 return ret;
1945 #if defined(VGO_solaris)
1946 /* On Solaris, pthread_rwlock_trywrlock is a weak alias to rw_trywrlock. */
1947 PTH_FUNCS(int,
1948 rwZutrywrlock, pthread_rwlock_trywrlock_intercept,
1949 (pthread_rwlock_t *rwlock), (rwlock));
1950 #else
1951 PTH_FUNCS(int,
1952 pthreadZurwlockZutrywrlock, pthread_rwlock_trywrlock_intercept,
1953 (pthread_rwlock_t* rwlock), (rwlock));
1954 #endif /* VGO_solaris */
1956 static __always_inline
1957 int pthread_rwlock_unlock_intercept(pthread_rwlock_t* rwlock)
1959 int ret;
1960 OrigFn fn;
1961 VALGRIND_GET_ORIG_FN(fn);
1962 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_RWLOCK_UNLOCK,
1963 rwlock, 0, 0, 0, 0);
1964 CALL_FN_W_W(ret, fn, rwlock);
1965 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_RWLOCK_UNLOCK,
1966 rwlock, ret == 0, 0, 0, 0);
1967 return ret;
1970 #if defined(VGO_solaris)
1971 /* On Solaris, pthread_rwlock_unlock is a weak alias to rw_unlock. */
1972 PTH_FUNCS(int,
1973 rwZuunlock, pthread_rwlock_unlock_intercept,
1974 (pthread_rwlock_t *rwlock), (rwlock));
1975 #else
1976 PTH_FUNCS(int,
1977 pthreadZurwlockZuunlock, pthread_rwlock_unlock_intercept,
1978 (pthread_rwlock_t* rwlock), (rwlock));
1979 #endif /* VGO_solaris */
1981 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */