drd_pthread_intercepts.c revision b3a1e4bffbdbbf38304f216af405009868f43628
1/*--------------------------------------------------------------------*/
2/*--- Client-space code for DRD.          drd_pthread_intercepts.c ---*/
3/*--------------------------------------------------------------------*/
4
5/*
6  This file is part of DRD, a thread error detector.
7
8  Copyright (C) 2006-2015 Bart Van Assche <bvanassche@acm.org>.
9
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.
14
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.
19
20  You should have received a copy of the GNU General Public License
21  along with this program; if not, write to the Free Software
22  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
23  02111-1307, USA.
24
25  The GNU General Public License is contained in the file COPYING.
26*/
27
28/* ---------------------------------------------------------------------
29   ALL THE CODE IN THIS FILE RUNS ON THE SIMULATED CPU.
30
31   These functions are not called directly - they're the targets of code
32   redirection or load notifications (see pub_core_redir.h for info).
33   They're named weirdly so that the intercept code can find them when the
34   shared object is initially loaded.
35
36   Note that this filename has the "drd_" prefix because it can appear
37   in stack traces, and the "drd_" makes it a little clearer that it
38   originates from Valgrind.
39   ------------------------------------------------------------------ */
40
41/*
42 * Define _GNU_SOURCE to make sure that pthread_spinlock_t is available when
43 * compiling with older glibc versions (2.3 or before).
44 */
45#ifndef _GNU_SOURCE
46#define _GNU_SOURCE
47#endif
48
49#include <assert.h>         /* assert() */
50#include <errno.h>
51#include <pthread.h>        /* pthread_mutex_t */
52#include <semaphore.h>      /* sem_t */
53#include <stdint.h>         /* uintptr_t */
54#include <stdio.h>          /* fprintf() */
55#include <stdlib.h>         /* malloc(), free() */
56#include <unistd.h>         /* confstr() */
57#include "config.h"         /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP etc. */
58#ifdef HAVE_USABLE_LINUX_FUTEX_H
59#include <asm/unistd.h>     /* __NR_futex */
60#include <linux/futex.h>    /* FUTEX_WAIT */
61#ifndef FUTEX_PRIVATE_FLAG
62#define FUTEX_PRIVATE_FLAG 0
63#endif
64#endif
65#include "drd_basics.h"     /* DRD_() */
66#include "drd_clientreq.h"
67#include "pub_tool_redir.h" /* VG_WRAP_FUNCTION_ZZ() */
68
69#if defined(VGO_solaris)
70/*
71 * Solaris usually provides pthread_* functions on top of Solaris threading
72 * and synchronization functions. Usually both need to be intercepted because
73 * pthread_* ones might not call the Solaris ones (see for example sem_wait()).
74 * Such approach is required to correctly report misuse of the POSIX threads
75 * API.
76 * Therefore DRD intercepts and instruments all such functions but due to
77 * DRD_(thread_enter_synchr)() and DRD_(thread_leave_synchr)() guards in
78 * handle_client_request(), only the top-most function is handled.
79 * So the right thing(TM) happens, as expected.
80 * The only exception is when pthread_* function is a weak alias to the Solaris
81 * threading/synchronization function. In such case only one needs to be
82 * intercepted to avoid redirection ambiguity.
83 *
84 * Intercepted functions rely on the fact that:
85 *  - pthread_mutex_t  == mutex_t
86 *  - pthread_cond_t   == cond_t
87 *  - sem_t            == sema_t
88 *  - pthread_rwlock_t == rwlock_t
89 *
90 * It is necessary to intercept also internal libc synchronization functions
91 * for two reasons:
92 *  - For read-write locks the unlocking function is shared
93 *  - Functions lmutex_lock/lmutex_unlock guard many critical sections in libc
94 *    which will be otherwise reported by DRD
95 */
96#include <synch.h>
97#include <thread.h>
98#include "pub_tool_vki.h"
99
100/*
101 * Solaris provides higher throughput, parallelism and scalability than other
102 * operating systems, at the cost of more fine-grained locking activity.
103 * This means for example that when a thread is created under Linux, just one
104 * big lock in glibc is used for all thread setup. Solaris libc uses several
105 * fine-grained locks and the creator thread resumes its activities as soon
106 * as possible, leaving for example stack and TLS setup activities to the
107 * created thread.
108 *
109 * This situation confuses DRD as it assumes there is some false ordering
110 * in place between creator and created thread; and therefore many types of
111 * race conditions in the application would not be reported. To prevent such
112 * false ordering, command line option --ignore-thread-creation is set to
113 * 'yes' by default on Solaris. All activity (loads, stores, client requests)
114 * is therefore ignored during:
115 * - pthread_create() call in the creator thread [libc.so]
116 * - thread creation phase (stack and TLS setup) in the created thread [libc.so]
117 *
118 * As explained in the comments for _ti_bind_guard(), whenever the runtime
119 * linker has to perform any activity (such as resolving a symbol), it protects
120 * its data structures by calling into rt_bind_guard() which in turn invokes
121 * _ti_bind_guard() in libc. Pointers to _ti_bind_guard() and _ti_bind_clear()
122 * are passed from libc to runtime linker in _ld_libc() call during libc_init().
123 * All activity is also ignored during:
124 * - runtime dynamic linker work between rt_bind_guard() and rt_bind_clear()
125 *   calls [ld.so]
126 *
127 * This also means that DRD does not report race conditions in libc (when
128 * --ignore-thread-creation=yes) and runtime linker itself (unconditionally)
129 * during these ignored sequences.
130 */
131
132/*
133 * Original function pointers for _ti_bind_guard() and _ti_bind_clear()
134 * from libc. They are intercepted in function wrapper of _ld_libc().
135 */
136typedef int (*drd_rtld_guard_fn)(int flags);
137static drd_rtld_guard_fn DRD_(rtld_bind_guard) = NULL;
138static drd_rtld_guard_fn DRD_(rtld_bind_clear) = NULL;
139#endif
140
141
142/*
143 * Notes regarding thread creation:
144 * - sg_init() runs on the context of the created thread and copies the vector
145 *   clock of the creator thread. This only works reliably if the creator
146 *   thread waits until this copy has been performed.
147 * - DRD_(thread_compute_minimum_vc)() does not take the vector clocks into
148 *   account that are involved in thread creation and for which the
149 *   corresponding thread has not yet been created. So not waiting until the
150 *   created thread has been started would make it possible that segments get
151 *   discarded that should not yet be discarded. Or: some data races are not
152 *   detected.
153 */
154
155/**
156 * Macro for generating a Valgrind interception function.
157 * @param[in] ret_ty Return type of the function to be generated.
158 * @param[in] zf Z-encoded name of the interception function.
159 * @param[in] implf Name of the function that implements the intercept.
160 * @param[in] arg_decl Argument declaration list enclosed in parentheses.
161 * @param[in] argl Argument list enclosed in parentheses.
162 */
163#ifdef VGO_darwin
164static int never_true;
165#define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl)                    \
166   ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl;     \
167   ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl      \
168   {									\
169      ret_ty pth_func_result = implf argl;				\
170      /* Apparently inserting a function call in wrapper functions */   \
171      /* is sufficient to avoid misaligned stack errors.           */	\
172      if (never_true)							\
173	 fflush(stdout);						\
174      return pth_func_result;						\
175   }
176#elif defined(VGO_solaris)
177/* On Solaris, libpthread is just a filter library on top of libc.
178 * Threading and synchronization functions in runtime linker are not
179 * intercepted.
180 */
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#else
186#define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl)                    \
187   ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl;     \
188   ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl      \
189   { return implf argl; }
190#endif
191
192/**
193 * Macro for generating three Valgrind interception functions: one with the
194 * Z-encoded name zf, one with ZAZa ("@*") appended to the name zf and one
195 * with ZDZa ("$*") appended to the name zf. The second generated interception
196 * function will intercept versioned symbols on Linux, and the third will
197 * intercept versioned symbols on Darwin.
198 */
199#define PTH_FUNCS(ret_ty, zf, implf, argl_decl, argl)           \
200   PTH_FUNC(ret_ty, zf, implf, argl_decl, argl);                \
201   PTH_FUNC(ret_ty, zf ## ZAZa, implf, argl_decl, argl);        \
202   PTH_FUNC(ret_ty, zf ## ZDZa, implf, argl_decl, argl);
203
204/*
205 * Not inlining one of the intercept functions will cause the regression
206 * tests to fail because this would cause an additional stackfram to appear
207 * in the output. The __always_inline macro guarantees that inlining will
208 * happen, even when compiling with optimization disabled.
209 */
210#undef __always_inline /* since already defined in <cdefs.h> */
211#if __GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 2
212#define __always_inline __inline__ __attribute__((always_inline))
213#else
214#define __always_inline __inline__
215#endif
216
217/* Local data structures. */
218
219typedef struct {
220   pthread_mutex_t mutex;
221   int counter;
222   int waiters;
223} DrdSema;
224
225typedef struct
226{
227   void* (*start)(void*);
228   void* arg;
229   int   detachstate;
230   DrdSema* wrapper_started;
231} DrdPosixThreadArgs;
232
233
234/* Local function declarations. */
235
236static void DRD_(init)(void) __attribute__((constructor));
237static void DRD_(check_threading_library)(void);
238static void DRD_(set_main_thread_state)(void);
239static void DRD_(sema_init)(DrdSema* sema);
240static void DRD_(sema_destroy)(DrdSema* sema);
241static void DRD_(sema_down)(DrdSema* sema);
242static void DRD_(sema_up)(DrdSema* sema);
243
244
245/* Function definitions. */
246
247/**
248 * Shared library initialization function. The function init() is called after
249 * dlopen() has loaded the shared library with DRD client intercepts because
250 * the constructor attribute was specified in the declaration of this function.
251 * Note: do specify the -nostdlib option to gcc when linking this code into a
252 * shared library because doing so would cancel the effect of the constructor
253 * attribute ! Using the gcc option -nodefaultlibs is fine because this last
254 * option preserves the shared library initialization code that calls
255 * constructor and destructor functions.
256 */
257static void DRD_(init)(void)
258{
259   DRD_(check_threading_library)();
260   DRD_(set_main_thread_state)();
261#if defined(VGO_solaris)
262   if ((DRD_(rtld_bind_guard) == NULL) || (DRD_(rtld_bind_clear) == NULL)) {
263      fprintf(stderr,
264"Bind guard functions for the runtime linker (ld.so.1) were not intercepted.\n"
265"This means the interface between libc and runtime linker changed and DRD\n"
266"needs to be ported properly. Giving up.\n");
267      abort();
268   }
269#endif
270}
271
272static __always_inline void DRD_(ignore_mutex_ordering)(pthread_mutex_t *mutex)
273{
274   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_IGNORE_MUTEX_ORDERING,
275                                   mutex, 0, 0, 0, 0);
276}
277
278static void DRD_(sema_init)(DrdSema* sema)
279{
280   DRD_IGNORE_VAR(*sema);
281   pthread_mutex_init(&sema->mutex, NULL);
282   DRD_(ignore_mutex_ordering)(&sema->mutex);
283   sema->counter = 0;
284   sema->waiters = 0;
285}
286
287static void DRD_(sema_destroy)(DrdSema* sema)
288{
289   pthread_mutex_destroy(&sema->mutex);
290}
291
292static void DRD_(sema_down)(DrdSema* sema)
293{
294   int res = ENOSYS;
295
296   pthread_mutex_lock(&sema->mutex);
297   if (sema->counter == 0) {
298      sema->waiters++;
299      while (sema->counter == 0) {
300         pthread_mutex_unlock(&sema->mutex);
301#ifdef HAVE_USABLE_LINUX_FUTEX_H
302         if (syscall(__NR_futex, (UWord)&sema->counter,
303                     FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0) == 0)
304            res = 0;
305         else
306            res = errno;
307#endif
308         /*
309          * Invoke sched_yield() on non-Linux systems, if the futex syscall has
310          * not been invoked or if this code has been built on a Linux system
311          * where __NR_futex is defined and is run on a Linux system that does
312          * not support the futex syscall.
313          */
314         if (res != 0 && res != EWOULDBLOCK)
315            sched_yield();
316         pthread_mutex_lock(&sema->mutex);
317      }
318      sema->waiters--;
319   }
320   sema->counter--;
321   pthread_mutex_unlock(&sema->mutex);
322}
323
324static void DRD_(sema_up)(DrdSema* sema)
325{
326   pthread_mutex_lock(&sema->mutex);
327   sema->counter++;
328#ifdef HAVE_USABLE_LINUX_FUTEX_H
329   if (sema->waiters > 0)
330      syscall(__NR_futex, (UWord)&sema->counter,
331              FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1);
332#endif
333   pthread_mutex_unlock(&sema->mutex);
334}
335
336/**
337 * POSIX threads and DRD each have their own mutex type identification.
338 * Convert POSIX threads' mutex type to DRD's mutex type. In the code below
339 * if-statements are used to test the value of 'kind' instead of a switch
340 * statement because some of the PTHREAD_MUTEX_ macro's may have the same
341 * value.
342 */
343static MutexT DRD_(pthread_to_drd_mutex_type)(int kind)
344{
345   /*
346    * See also PTHREAD_MUTEX_KIND_MASK_NP in glibc source file
347    * <nptl/pthreadP.h>.
348    */
349   kind &= PTHREAD_MUTEX_RECURSIVE | PTHREAD_MUTEX_ERRORCHECK |
350      PTHREAD_MUTEX_NORMAL | PTHREAD_MUTEX_DEFAULT;
351
352   if (kind == PTHREAD_MUTEX_RECURSIVE)
353      return mutex_type_recursive_mutex;
354   else if (kind == PTHREAD_MUTEX_ERRORCHECK)
355      return mutex_type_errorcheck_mutex;
356   else if (kind == PTHREAD_MUTEX_NORMAL)
357      return mutex_type_default_mutex;
358   else if (kind == PTHREAD_MUTEX_DEFAULT)
359      return mutex_type_default_mutex;
360#if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
361   else if (kind == PTHREAD_MUTEX_ADAPTIVE_NP)
362      return mutex_type_default_mutex;
363#endif
364   else
365      return mutex_type_invalid_mutex;
366}
367
368#if defined(VGO_solaris)
369/**
370 * Solaris threads and DRD each have their own mutex type identification.
371 * Convert Solaris threads' mutex type to DRD's mutex type.
372 */
373static MutexT DRD_(thread_to_drd_mutex_type)(int type)
374{
375   if (type & LOCK_RECURSIVE) {
376      return mutex_type_recursive_mutex;
377   } else if (type & LOCK_ERRORCHECK) {
378      return mutex_type_errorcheck_mutex;
379   } else {
380      return mutex_type_default_mutex;
381   }
382}
383#endif /* VGO_solaris */
384
385#define IS_ALIGNED(p) (((uintptr_t)(p) & (sizeof(*(p)) - 1)) == 0)
386
387/**
388 * Read the mutex type stored in the client memory used for the mutex
389 * implementation.
390 *
391 * @note This function depends on the implementation of the POSIX threads
392 *   library -- the POSIX standard does not define the name of the member in
393 *   which the mutex type is stored.
394 * @note The function mutex_type() has been declared inline in order
395 *   to avoid that it shows up in call stacks (drd/tests/...exp* files).
396 * @note glibc stores the mutex type in the lowest two bits, and uses the
397 *   higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
398 *   PTHREAD_MUTEXATTR_FLAG_PSHARED.
399 */
400static __always_inline MutexT DRD_(mutex_type)(pthread_mutex_t* mutex)
401{
402#if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
403   /* glibc + LinuxThreads. */
404   if (IS_ALIGNED(&mutex->__m_kind))
405   {
406      const int kind = mutex->__m_kind & 3;
407      return DRD_(pthread_to_drd_mutex_type)(kind);
408   }
409#elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
410   /* glibc + NPTL. */
411   if (IS_ALIGNED(&mutex->__data.__kind))
412   {
413      const int kind = mutex->__data.__kind & 3;
414      return DRD_(pthread_to_drd_mutex_type)(kind);
415   }
416#elif defined(VGO_solaris)
417      const int type = ((mutex_t *) mutex)->vki_mutex_type;
418      return DRD_(thread_to_drd_mutex_type)(type);
419#else
420   /*
421    * Another POSIX threads implementation. The mutex type won't be printed
422    * when enabling --trace-mutex=yes.
423    */
424#endif
425   return mutex_type_unknown;
426}
427
428/**
429 * Tell DRD whether 'tid' is a joinable thread or a detached thread.
430 */
431static void DRD_(set_joinable)(const pthread_t tid, const int joinable)
432{
433   assert(joinable == 0 || joinable == 1);
434   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_JOINABLE,
435                                   tid, joinable, 0, 0, 0);
436}
437
438/** Tell DRD that the calling thread is about to enter pthread_create(). */
439static __always_inline void DRD_(entering_pthread_create)(void)
440{
441   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__ENTERING_PTHREAD_CREATE,
442                                   0, 0, 0, 0, 0);
443}
444
445/** Tell DRD that the calling thread has left pthread_create(). */
446static __always_inline void DRD_(left_pthread_create)(void)
447{
448   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LEFT_PTHREAD_CREATE,
449                                   0, 0, 0, 0, 0);
450}
451
452/**
453 * Entry point for newly created threads. This function is called from the
454 * thread created by pthread_create().
455 */
456static void* DRD_(thread_wrapper)(void* arg)
457{
458   DrdPosixThreadArgs* arg_ptr;
459   DrdPosixThreadArgs arg_copy;
460
461   arg_ptr = (DrdPosixThreadArgs*)arg;
462   arg_copy = *arg_ptr;
463
464   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
465                                   pthread_self(), 0, 0, 0, 0);
466
467   DRD_(set_joinable)(pthread_self(),
468                      arg_copy.detachstate == PTHREAD_CREATE_JOINABLE);
469
470   /*
471    * Only set 'wrapper_started' after VG_USERREQ__SET_PTHREADID and
472    * DRD_(set_joinable)() have been invoked to avoid a race with
473    * a pthread_detach() invocation for this thread from another thread.
474    */
475   DRD_(sema_up)(arg_copy.wrapper_started);
476
477   return (arg_copy.start)(arg_copy.arg);
478}
479
480/**
481 * Return 1 if the LinuxThreads implementation of POSIX Threads has been
482 * detected, and 0 otherwise.
483 *
484 * @see For more information about the confstr() function, see also
485 * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
486 */
487static int DRD_(detected_linuxthreads)(void)
488{
489#if defined(linux)
490#if defined(_CS_GNU_LIBPTHREAD_VERSION)
491   /* Linux with a recent glibc. */
492   HChar buffer[256];
493   unsigned len;
494   len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
495   assert(len <= sizeof(buffer));
496   return len > 0 && buffer[0] == 'l';
497#else
498   /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
499   return 1;
500#endif
501#else
502   /* Another OS than Linux, hence no LinuxThreads. */
503   return 0;
504#endif
505}
506
507/**
508 * Stop and print an error message in case a non-supported threading
509 * library implementation (LinuxThreads) has been detected.
510 */
511static void DRD_(check_threading_library)(void)
512{
513   if (DRD_(detected_linuxthreads)())
514   {
515      if (getenv("LD_ASSUME_KERNEL"))
516      {
517         fprintf(stderr,
518"Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
519"the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
520"after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
521);
522      }
523      else
524      {
525         fprintf(stderr,
526"Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
527"the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
528"after having upgraded to a newer version of your Linux distribution.\n"
529"Giving up.\n"
530);
531      }
532      abort();
533   }
534}
535
536/**
537 * The main thread is the only thread not created by pthread_create().
538 * Update DRD's state information about the main thread.
539 */
540static void DRD_(set_main_thread_state)(void)
541{
542   // Make sure that DRD knows about the main thread's POSIX thread ID.
543   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
544                                   pthread_self(), 0, 0, 0, 0);
545}
546
547/*
548 * Note: as of today there exist three different versions of pthread_create
549 * in Linux:
550 * - pthread_create@GLIBC_2.0
551 * - pthread_create@@GLIBC_2.1
552 * - pthread_create@@GLIBC_2.2.5
553 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
554 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
555 * versions have been implemented. In any glibc version where more than one
556 * pthread_create function has been implemented, older versions call the
557 * newer versions. Or: the pthread_create* wrapper defined below can be
558 * called recursively. Any code in this wrapper should take this in account.
559 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
560 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
561 * See also the implementation of pthread_create@GLIBC_2.0 in
562 * glibc-2.9/nptl/pthread_create.c.
563 */
564
565static __always_inline
566int pthread_create_intercept(pthread_t* thread, const pthread_attr_t* attr,
567                             void* (*start)(void*), void* arg)
568{
569   int    ret;
570   OrigFn fn;
571   DrdSema wrapper_started;
572   DrdPosixThreadArgs thread_args;
573
574   VALGRIND_GET_ORIG_FN(fn);
575
576   DRD_(sema_init)(&wrapper_started);
577   thread_args.start           = start;
578   thread_args.arg             = arg;
579   thread_args.wrapper_started = &wrapper_started;
580   /*
581    * Find out whether the thread will be started as a joinable thread
582    * or as a detached thread. If no thread attributes have been specified,
583    * this means that the new thread will be started as a joinable thread.
584    */
585   thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
586   if (attr)
587   {
588      if (pthread_attr_getdetachstate(attr, &thread_args.detachstate) != 0)
589         assert(0);
590   }
591   assert(thread_args.detachstate == PTHREAD_CREATE_JOINABLE
592          || thread_args.detachstate == PTHREAD_CREATE_DETACHED);
593
594   DRD_(entering_pthread_create)();
595   CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), &thread_args);
596   DRD_(left_pthread_create)();
597
598   if (ret == 0) {
599      /* Wait until the thread wrapper started. */
600      DRD_(sema_down)(&wrapper_started);
601   }
602
603   DRD_(sema_destroy)(&wrapper_started);
604
605   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT,
606                                   pthread_self(), 0, 0, 0, 0);
607
608   return ret;
609}
610
611PTH_FUNCS(int, pthreadZucreate, pthread_create_intercept,
612          (pthread_t *thread, const pthread_attr_t *attr,
613           void *(*start) (void *), void *arg),
614          (thread, attr, start, arg));
615
616#if defined(VGO_solaris)
617/* Solaris also provides thr_create() in addition to pthread_create().
618 * Both pthread_create(3C) and thr_create(3C) are based on private
619 * _thrp_create().
620 */
621static __always_inline
622int thr_create_intercept(void *stk, size_t stksize, void *(*start)(void *),
623                         void *arg, long flags, thread_t *new_thread)
624{
625   int                ret;
626   OrigFn             fn;
627   DrdSema            wrapper_started;
628   DrdPosixThreadArgs thread_args;
629
630   VALGRIND_GET_ORIG_FN(fn);
631
632   DRD_(sema_init)(&wrapper_started);
633   thread_args.start           = start;
634   thread_args.arg             = arg;
635   thread_args.wrapper_started = &wrapper_started;
636   /*
637    * Find out whether the thread will be started as a joinable thread
638    * or as a detached thread.
639    */
640   if (flags & THR_DETACHED)
641      thread_args.detachstate = PTHREAD_CREATE_DETACHED;
642   else
643      thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
644
645   DRD_(entering_pthread_create)();
646   CALL_FN_W_6W(ret, fn, stk, stksize, DRD_(thread_wrapper), &thread_args,
647                flags, new_thread);
648   DRD_(left_pthread_create)();
649
650   if (ret == 0) {
651      /* Wait until the thread wrapper started. */
652      DRD_(sema_down)(&wrapper_started);
653   }
654
655   DRD_(sema_destroy)(&wrapper_started);
656
657   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT,
658                                   pthread_self(), 0, 0, 0, 0);
659
660   return ret;
661}
662
663PTH_FUNCS(int, thrZucreate, thr_create_intercept,
664          (void *stk, size_t stksize, void *(*start)(void *), void *arg,
665           long flags, thread_t *new_thread),
666          (stk, stksize, start, arg, flags, new_thread));
667#endif /* VGO_solaris */
668
669#if defined(VGO_solaris)
670/*
671 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
672 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
673 * and CI_BIND_CLEAR, to provide resilience against function renaming.
674 */
675static __always_inline
676int DRD_(_ti_bind_guard_intercept)(int flags) {
677   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_GUARD,
678                                   flags, 0, 0, 0, 0);
679   return DRD_(rtld_bind_guard)(flags);
680}
681
682static __always_inline
683int DRD_(_ti_bind_clear_intercept)(int flags) {
684   int ret = DRD_(rtld_bind_clear)(flags);
685   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_CLEAR,
686                                   flags, 0, 0, 0, 0);
687   return ret;
688}
689
690/*
691 * Wrapped _ld_libc() from the runtime linker ld.so.1.
692 */
693void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr);
694void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr)
695{
696   OrigFn fn;
697   int    tag;
698
699   VALGRIND_GET_ORIG_FN(fn);
700
701   vki_Lc_interface *funcs = ptr;
702   for (tag = funcs->ci_tag; tag != 0; tag = (++funcs)->ci_tag) {
703      switch (tag) {
704      case VKI_CI_BIND_GUARD:
705         if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_guard_intercept)) {
706            DRD_(rtld_bind_guard) = funcs->vki_ci_un.ci_func;
707            funcs->vki_ci_un.ci_func = DRD_(_ti_bind_guard_intercept);
708         }
709         break;
710      case VKI_CI_BIND_CLEAR:
711         if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_clear_intercept)) {
712            DRD_(rtld_bind_clear) = funcs->vki_ci_un.ci_func;
713            funcs->vki_ci_un.ci_func = DRD_(_ti_bind_clear_intercept);
714         }
715         break;
716      }
717   }
718
719   CALL_FN_v_W(fn, ptr);
720}
721#endif /* VGO_solaris */
722
723static __always_inline
724int pthread_join_intercept(pthread_t pt_joinee, void **thread_return)
725{
726   int      ret;
727   OrigFn   fn;
728
729   VALGRIND_GET_ORIG_FN(fn);
730   /*
731    * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
732    * implementation triggers a (false positive) race report.
733    */
734   ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
735   CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
736   if (ret == 0)
737   {
738      VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN,
739                                      pt_joinee, 0, 0, 0, 0);
740   }
741   ANNOTATE_IGNORE_READS_AND_WRITES_END();
742   return ret;
743}
744
745PTH_FUNCS(int, pthreadZujoin, pthread_join_intercept,
746          (pthread_t pt_joinee, void **thread_return),
747          (pt_joinee, thread_return));
748
749#if defined(VGO_solaris)
750/* Solaris also provides thr_join() in addition to pthread_join().
751 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
752 *
753 * :TODO: No functionality is currently provided for joinee == 0 and departed.
754 *        This would require another client request, of course.
755 */
756static __always_inline
757int thr_join_intercept(thread_t joinee, thread_t *departed, void **thread_return)
758{
759   int      ret;
760   OrigFn   fn;
761
762   VALGRIND_GET_ORIG_FN(fn);
763   CALL_FN_W_WWW(ret, fn, joinee, departed, thread_return);
764   if (ret == 0)
765   {
766      VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN,
767                                      joinee, 0, 0, 0, 0);
768   }
769   return ret;
770}
771
772PTH_FUNCS(int, thrZujoin, thr_join_intercept,
773          (thread_t joinee, thread_t *departed, void **thread_return),
774          (joinee, departed, thread_return));
775#endif /* VGO_solaris */
776
777static __always_inline
778int pthread_detach_intercept(pthread_t pt_thread)
779{
780   int ret;
781   OrigFn fn;
782
783   VALGRIND_GET_ORIG_FN(fn);
784   CALL_FN_W_W(ret, fn, pt_thread);
785   DRD_(set_joinable)(pt_thread, 0);
786
787   return ret;
788}
789
790PTH_FUNCS(int, pthreadZudetach, pthread_detach_intercept,
791          (pthread_t thread), (thread));
792
793// NOTE: be careful to intercept only pthread_cancel() and not
794// pthread_cancel_init() on Linux.
795
796static __always_inline
797int pthread_cancel_intercept(pthread_t pt_thread)
798{
799   int ret;
800   OrigFn fn;
801   VALGRIND_GET_ORIG_FN(fn);
802   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_THREAD_CANCEL,
803                                   pt_thread, 0, 0, 0, 0);
804   CALL_FN_W_W(ret, fn, pt_thread);
805   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_CANCEL,
806                                   pt_thread, ret==0, 0, 0, 0);
807   return ret;
808}
809
810PTH_FUNCS(int, pthreadZucancel, pthread_cancel_intercept,
811          (pthread_t thread), (thread))
812
813static __always_inline
814int pthread_once_intercept(pthread_once_t *once_control,
815                           void (*init_routine)(void))
816{
817   int ret;
818   OrigFn fn;
819   VALGRIND_GET_ORIG_FN(fn);
820   /*
821    * Ignore any data races triggered by the implementation of pthread_once().
822    * Necessary for Darwin. This is not necessary for Linux but doesn't have
823    * any known adverse effects.
824    */
825   DRD_IGNORE_VAR(*once_control);
826   ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
827   CALL_FN_W_WW(ret, fn, once_control, init_routine);
828   ANNOTATE_IGNORE_READS_AND_WRITES_END();
829   DRD_STOP_IGNORING_VAR(*once_control);
830   return ret;
831}
832
833PTH_FUNCS(int, pthreadZuonce, pthread_once_intercept,
834          (pthread_once_t *once_control, void (*init_routine)(void)),
835          (once_control, init_routine));
836
837static __always_inline
838int pthread_mutex_init_intercept(pthread_mutex_t *mutex,
839                                 const pthread_mutexattr_t* attr)
840{
841   int ret;
842   OrigFn fn;
843   int mt;
844   VALGRIND_GET_ORIG_FN(fn);
845   mt = PTHREAD_MUTEX_DEFAULT;
846   if (attr)
847      pthread_mutexattr_gettype(attr, &mt);
848   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
849                                   mutex, DRD_(pthread_to_drd_mutex_type)(mt),
850                                   0, 0, 0);
851   CALL_FN_W_WW(ret, fn, mutex, attr);
852   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
853                                   mutex, 0, 0, 0, 0);
854   return ret;
855}
856
857PTH_FUNCS(int, pthreadZumutexZuinit, pthread_mutex_init_intercept,
858          (pthread_mutex_t *mutex, const pthread_mutexattr_t* attr),
859          (mutex, attr));
860
861#if defined(VGO_solaris)
862static __always_inline
863int mutex_init_intercept(mutex_t *mutex, int type, void *arg)
864{
865   int ret;
866   OrigFn fn;
867   VALGRIND_GET_ORIG_FN(fn);
868
869   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
870                                   mutex, DRD_(thread_to_drd_mutex_type)(type),
871                                   0, 0, 0);
872   CALL_FN_W_WWW(ret, fn, mutex, type, arg);
873   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
874                                   mutex, 0, 0, 0, 0);
875   return ret;
876}
877
878PTH_FUNCS(int, mutexZuinit, mutex_init_intercept,
879          (mutex_t *mutex, int type, void *arg),
880          (mutex, type, arg));
881#endif /* VGO_solaris */
882
883static __always_inline
884int pthread_mutex_destroy_intercept(pthread_mutex_t* mutex)
885{
886   int ret;
887   OrigFn fn;
888   VALGRIND_GET_ORIG_FN(fn);
889   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
890                                   mutex, 0, 0, 0, 0);
891   CALL_FN_W_W(ret, fn, mutex);
892   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
893                                   mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
894   return ret;
895}
896
897#if defined(VGO_solaris)
898/* On Solaris, pthread_mutex_destroy is a weak alias to mutex_destroy. */
899PTH_FUNCS(int, mutexZudestroy, pthread_mutex_destroy_intercept,
900          (pthread_mutex_t *mutex), (mutex));
901#else
902PTH_FUNCS(int, pthreadZumutexZudestroy, pthread_mutex_destroy_intercept,
903          (pthread_mutex_t *mutex), (mutex));
904#endif /* VGO_solaris */
905
906static __always_inline
907int pthread_mutex_lock_intercept(pthread_mutex_t* mutex)
908{
909   int   ret;
910   OrigFn fn;
911   VALGRIND_GET_ORIG_FN(fn);
912   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
913                                   mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
914   CALL_FN_W_W(ret, fn, mutex);
915   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
916                                   mutex, ret == 0, 0, 0, 0);
917   return ret;
918}
919
920#if defined(VGO_solaris)
921/* On Solaris, pthread_mutex_lock is a weak alias to mutex_lock. */
922PTH_FUNCS(int, mutexZulock, pthread_mutex_lock_intercept,
923          (pthread_mutex_t *mutex), (mutex));
924#else
925PTH_FUNCS(int, pthreadZumutexZulock, pthread_mutex_lock_intercept,
926          (pthread_mutex_t *mutex), (mutex));
927#endif /* VGO_solaris */
928
929#if defined(VGO_solaris)
930/* Internal to libc. Mutex is usually initialized only implicitly,
931 * by zeroing mutex_t structure.
932 */
933static __always_inline
934void lmutex_lock_intercept(mutex_t *mutex)
935{
936   OrigFn fn;
937   VALGRIND_GET_ORIG_FN(fn);
938   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
939                                   mutex,
940                                   DRD_(mutex_type)((pthread_mutex_t *) mutex),
941                                   False /* try_lock */, 0, 0);
942   CALL_FN_v_W(fn, mutex);
943   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
944                                   mutex, True /* took_lock */, 0, 0, 0);
945}
946
947PTH_FUNCS(void, lmutexZulock, lmutex_lock_intercept,
948          (mutex_t *mutex), (mutex));
949#endif /* VGO_solaris */
950
951static __always_inline
952int pthread_mutex_trylock_intercept(pthread_mutex_t* mutex)
953{
954   int   ret;
955   OrigFn fn;
956   VALGRIND_GET_ORIG_FN(fn);
957   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
958                                   mutex, DRD_(mutex_type)(mutex), 1, 0, 0);
959   CALL_FN_W_W(ret, fn, mutex);
960   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
961                                   mutex, ret == 0, 0, 0, 0);
962   return ret;
963}
964
965#if defined(VGO_solaris)
966/* On Solaris, pthread_mutex_trylock is a weak alias to mutex_trylock. */
967PTH_FUNCS(int, mutexZutrylock, pthread_mutex_trylock_intercept,
968          (pthread_mutex_t *mutex), (mutex));
969#else
970PTH_FUNCS(int, pthreadZumutexZutrylock, pthread_mutex_trylock_intercept,
971          (pthread_mutex_t *mutex), (mutex));
972#endif /* VGO_solaris */
973
974static __always_inline
975int pthread_mutex_timedlock_intercept(pthread_mutex_t *mutex,
976                                      const struct timespec *abs_timeout)
977{
978   int   ret;
979   OrigFn fn;
980   VALGRIND_GET_ORIG_FN(fn);
981   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
982                                   mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
983   CALL_FN_W_WW(ret, fn, mutex, abs_timeout);
984   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
985                                   mutex, ret == 0, 0, 0, 0);
986   return ret;
987}
988
989PTH_FUNCS(int, pthreadZumutexZutimedlock, pthread_mutex_timedlock_intercept,
990          (pthread_mutex_t *mutex, const struct timespec *abs_timeout),
991          (mutex, abs_timeout));
992#if defined(VGO_solaris)
993PTH_FUNCS(int,
994          pthreadZumutexZureltimedlockZunp, pthread_mutex_timedlock_intercept,
995          (pthread_mutex_t *mutex, const struct timespec *timeout),
996          (mutex, timeout));
997#endif /* VGO_solaris */
998
999static __always_inline
1000int pthread_mutex_unlock_intercept(pthread_mutex_t *mutex)
1001{
1002   int ret;
1003   OrigFn fn;
1004   VALGRIND_GET_ORIG_FN(fn);
1005   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
1006                                   mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
1007   CALL_FN_W_W(ret, fn, mutex);
1008   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
1009                                   mutex, 0, 0, 0, 0);
1010   return ret;
1011}
1012
1013#if defined(VGO_solaris)
1014/* On Solaris, pthread_mutex_unlock is a weak alias to mutex_unlock. */
1015PTH_FUNCS(int, mutexZuunlock, pthread_mutex_unlock_intercept,
1016          (pthread_mutex_t *mutex), (mutex));
1017#else
1018PTH_FUNCS(int, pthreadZumutexZuunlock, pthread_mutex_unlock_intercept,
1019          (pthread_mutex_t *mutex), (mutex));
1020#endif /* VGO_solaris */
1021
1022#if defined(VGO_solaris)
1023/* Internal to libc. */
1024static __always_inline
1025void lmutex_unlock_intercept(mutex_t *mutex)
1026{
1027   OrigFn fn;
1028   VALGRIND_GET_ORIG_FN(fn);
1029   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
1030                                   mutex,
1031                                   DRD_(mutex_type)((pthread_mutex_t *) mutex),
1032                                   0, 0, 0);
1033   CALL_FN_v_W(fn, mutex);
1034   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
1035                                   mutex, 0, 0, 0, 0);
1036}
1037
1038PTH_FUNCS(void, lmutexZuunlock, lmutex_unlock_intercept,
1039          (mutex_t *mutex), (mutex));
1040#endif /* VGO_solaris */
1041
1042static __always_inline
1043int pthread_cond_init_intercept(pthread_cond_t* cond,
1044                                const pthread_condattr_t* attr)
1045{
1046   int ret;
1047   OrigFn fn;
1048   VALGRIND_GET_ORIG_FN(fn);
1049   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT,
1050                                   cond, 0, 0, 0, 0);
1051   CALL_FN_W_WW(ret, fn, cond, attr);
1052   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT,
1053                                   cond, 0, 0, 0, 0);
1054   return ret;
1055}
1056
1057PTH_FUNCS(int, pthreadZucondZuinit, pthread_cond_init_intercept,
1058          (pthread_cond_t* cond, const pthread_condattr_t* attr),
1059          (cond, attr));
1060
1061#if defined(VGO_solaris)
1062static __always_inline
1063int cond_init_intercept(cond_t *cond, int type, void *arg)
1064{
1065   int ret;
1066   OrigFn fn;
1067   VALGRIND_GET_ORIG_FN(fn);
1068   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT,
1069                                   cond, 0, 0, 0, 0);
1070   CALL_FN_W_WWW(ret, fn, cond, type, arg);
1071   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT,
1072                                   cond, 0, 0, 0, 0);
1073   return ret;
1074}
1075
1076PTH_FUNCS(int, condZuinit, cond_init_intercept,
1077          (cond_t *cond, int type, void *arg),
1078          (cond, type, arg));
1079#endif /* VGO_solaris */
1080
1081static __always_inline
1082int pthread_cond_destroy_intercept(pthread_cond_t* cond)
1083{
1084   int ret;
1085   OrigFn fn;
1086   VALGRIND_GET_ORIG_FN(fn);
1087   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_DESTROY,
1088                                   cond, 0, 0, 0, 0);
1089   CALL_FN_W_W(ret, fn, cond);
1090   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_DESTROY,
1091                                   cond, ret==0, 0, 0, 0);
1092   return ret;
1093}
1094
1095#if defined(VGO_solaris)
1096/* On Solaris, pthread_cond_destroy is a weak alias to cond_destroy. */
1097PTH_FUNCS(int, condZudestroy, pthread_cond_destroy_intercept,
1098          (pthread_cond_t *cond), (cond));
1099#else
1100PTH_FUNCS(int, pthreadZucondZudestroy, pthread_cond_destroy_intercept,
1101          (pthread_cond_t* cond), (cond));
1102#endif /* VGO_solaris */
1103
1104static __always_inline
1105int pthread_cond_wait_intercept(pthread_cond_t *cond, pthread_mutex_t *mutex)
1106{
1107   int   ret;
1108   OrigFn fn;
1109   VALGRIND_GET_ORIG_FN(fn);
1110   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
1111                                   cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1112   CALL_FN_W_WW(ret, fn, cond, mutex);
1113   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
1114                                   cond, mutex, 1, 0, 0);
1115   return ret;
1116}
1117
1118PTH_FUNCS(int, pthreadZucondZuwait, pthread_cond_wait_intercept,
1119          (pthread_cond_t *cond, pthread_mutex_t *mutex),
1120          (cond, mutex));
1121#if defined(VGO_solaris)
1122PTH_FUNCS(int, condZuwait, pthread_cond_wait_intercept,
1123          (pthread_cond_t *cond, pthread_mutex_t *mutex),
1124          (cond, mutex));
1125#endif /* VGO_solaris */
1126
1127static __always_inline
1128int pthread_cond_timedwait_intercept(pthread_cond_t *cond,
1129                                     pthread_mutex_t *mutex,
1130                                     const struct timespec* abstime)
1131{
1132   int   ret;
1133   OrigFn fn;
1134   VALGRIND_GET_ORIG_FN(fn);
1135   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
1136                                   cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1137   CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
1138   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
1139                                   cond, mutex, 1, 0, 0);
1140   return ret;
1141}
1142
1143PTH_FUNCS(int, pthreadZucondZutimedwait, pthread_cond_timedwait_intercept,
1144          (pthread_cond_t *cond, pthread_mutex_t *mutex,
1145           const struct timespec* abstime),
1146          (cond, mutex, abstime));
1147#if defined(VGO_solaris)
1148PTH_FUNCS(int, condZutimedwait, pthread_cond_timedwait_intercept,
1149          (pthread_cond_t *cond, pthread_mutex_t *mutex,
1150           const struct timespec *timeout),
1151          (cond, mutex, timeout));
1152PTH_FUNCS(int, condZureltimedwait, pthread_cond_timedwait_intercept,
1153          (pthread_cond_t *cond, pthread_mutex_t *mutex,
1154           const struct timespec *timeout),
1155          (cond, mutex, timeout));
1156#endif /* VGO_solaris */
1157
1158// NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
1159// pthread_cond_signal_thread_np(). The former accepts one argument; the latter
1160// two. Intercepting all pthread_cond_signal* functions will cause only one
1161// argument to be passed to pthread_cond_signal_np() and hence will cause this
1162// last function to crash.
1163
1164static __always_inline
1165int pthread_cond_signal_intercept(pthread_cond_t* cond)
1166{
1167   int   ret;
1168   OrigFn fn;
1169   VALGRIND_GET_ORIG_FN(fn);
1170   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_SIGNAL,
1171                                   cond, 0, 0, 0, 0);
1172   CALL_FN_W_W(ret, fn, cond);
1173   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_SIGNAL,
1174                                   cond, 0, 0, 0, 0);
1175   return ret;
1176}
1177
1178#if defined(VGO_solaris)
1179/* On Solaris, pthread_cond_signal is a weak alias to cond_signal. */
1180PTH_FUNCS(int, condZusignal, pthread_cond_signal_intercept,
1181          (pthread_cond_t *cond), (cond));
1182#else
1183PTH_FUNCS(int, pthreadZucondZusignal, pthread_cond_signal_intercept,
1184          (pthread_cond_t* cond), (cond));
1185#endif /* VGO_solaris */
1186
1187static __always_inline
1188int pthread_cond_broadcast_intercept(pthread_cond_t* cond)
1189{
1190   int   ret;
1191   OrigFn fn;
1192   VALGRIND_GET_ORIG_FN(fn);
1193   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_BROADCAST,
1194                                   cond, 0, 0, 0, 0);
1195   CALL_FN_W_W(ret, fn, cond);
1196   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_BROADCAST,
1197                                   cond, 0, 0, 0, 0);
1198   return ret;
1199}
1200
1201#if defined(VGO_solaris)
1202/* On Solaris, pthread_cond_broadcast is a weak alias to cond_broadcast. */
1203PTH_FUNCS(int, condZubroadcast, pthread_cond_broadcast_intercept,
1204          (pthread_cond_t *cond), (cond));
1205#else
1206PTH_FUNCS(int, pthreadZucondZubroadcast, pthread_cond_broadcast_intercept,
1207          (pthread_cond_t* cond), (cond));
1208#endif /* VGO_solaris */
1209
1210#if defined(HAVE_PTHREAD_SPIN_LOCK) \
1211    && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1212static __always_inline
1213int pthread_spin_init_intercept(pthread_spinlock_t *spinlock, int pshared)
1214{
1215   int ret;
1216   OrigFn fn;
1217   VALGRIND_GET_ORIG_FN(fn);
1218   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
1219                                   spinlock, 0, 0, 0, 0);
1220   CALL_FN_W_WW(ret, fn, spinlock, pshared);
1221   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
1222                                   spinlock, 0, 0, 0, 0);
1223   return ret;
1224}
1225
1226PTH_FUNCS(int, pthreadZuspinZuinit, pthread_spin_init_intercept,
1227          (pthread_spinlock_t *spinlock, int pshared), (spinlock, pshared));
1228
1229static __always_inline
1230int pthread_spin_destroy_intercept(pthread_spinlock_t *spinlock)
1231{
1232   int ret;
1233   OrigFn fn;
1234   VALGRIND_GET_ORIG_FN(fn);
1235   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
1236                                   spinlock, 0, 0, 0, 0);
1237   CALL_FN_W_W(ret, fn, spinlock);
1238   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
1239                                   spinlock, mutex_type_spinlock, 0, 0, 0);
1240   return ret;
1241}
1242
1243PTH_FUNCS(int, pthreadZuspinZudestroy, pthread_spin_destroy_intercept,
1244          (pthread_spinlock_t *spinlock), (spinlock));
1245
1246static __always_inline
1247int pthread_spin_lock_intercept(pthread_spinlock_t *spinlock)
1248{
1249   int   ret;
1250   OrigFn fn;
1251   VALGRIND_GET_ORIG_FN(fn);
1252   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
1253                                   spinlock, mutex_type_spinlock, 0, 0, 0);
1254   CALL_FN_W_W(ret, fn, spinlock);
1255   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
1256                                   spinlock, ret == 0, 0, 0, 0);
1257   return ret;
1258}
1259
1260PTH_FUNCS(int, pthreadZuspinZulock, pthread_spin_lock_intercept,
1261          (pthread_spinlock_t *spinlock), (spinlock));
1262
1263static __always_inline
1264int pthread_spin_trylock_intercept(pthread_spinlock_t *spinlock)
1265{
1266   int   ret;
1267   OrigFn fn;
1268   VALGRIND_GET_ORIG_FN(fn);
1269   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
1270                                   spinlock, mutex_type_spinlock, 0, 0, 0);
1271   CALL_FN_W_W(ret, fn, spinlock);
1272   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
1273                                   spinlock, ret == 0, 0, 0, 0);
1274   return ret;
1275}
1276
1277PTH_FUNCS(int, pthreadZuspinZutrylock, pthread_spin_trylock_intercept,
1278          (pthread_spinlock_t *spinlock), (spinlock));
1279
1280static __always_inline
1281int pthread_spin_unlock_intercept(pthread_spinlock_t *spinlock)
1282{
1283   int   ret;
1284   OrigFn fn;
1285   VALGRIND_GET_ORIG_FN(fn);
1286   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
1287                                   spinlock, mutex_type_spinlock, 0, 0, 0);
1288   CALL_FN_W_W(ret, fn, spinlock);
1289   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
1290                                   spinlock, 0, 0, 0, 0);
1291   return ret;
1292}
1293
1294PTH_FUNCS(int, pthreadZuspinZuunlock, pthread_spin_unlock_intercept,
1295          (pthread_spinlock_t *spinlock), (spinlock));
1296#endif   // HAVE_PTHREAD_SPIN_LOCK
1297
1298
1299#if defined(HAVE_PTHREAD_BARRIER_INIT)
1300static __always_inline
1301int pthread_barrier_init_intercept(pthread_barrier_t* barrier,
1302                                   const pthread_barrierattr_t* attr,
1303                                   unsigned count)
1304{
1305   int   ret;
1306   OrigFn fn;
1307   VALGRIND_GET_ORIG_FN(fn);
1308   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_INIT,
1309                                   barrier, pthread_barrier, count, 0, 0);
1310   CALL_FN_W_WWW(ret, fn, barrier, attr, count);
1311   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_INIT,
1312                                   barrier, pthread_barrier, 0, 0, 0);
1313   return ret;
1314}
1315
1316PTH_FUNCS(int, pthreadZubarrierZuinit, pthread_barrier_init_intercept,
1317          (pthread_barrier_t* barrier, const pthread_barrierattr_t* attr,
1318           unsigned count), (barrier, attr, count));
1319
1320static __always_inline
1321int pthread_barrier_destroy_intercept(pthread_barrier_t* barrier)
1322{
1323   int   ret;
1324   OrigFn fn;
1325   VALGRIND_GET_ORIG_FN(fn);
1326   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_DESTROY,
1327                                   barrier, pthread_barrier, 0, 0, 0);
1328   CALL_FN_W_W(ret, fn, barrier);
1329   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_DESTROY,
1330                                   barrier, pthread_barrier, 0, 0, 0);
1331   return ret;
1332}
1333
1334PTH_FUNCS(int, pthreadZubarrierZudestroy, pthread_barrier_destroy_intercept,
1335          (pthread_barrier_t* barrier), (barrier));
1336
1337static __always_inline
1338int pthread_barrier_wait_intercept(pthread_barrier_t* barrier)
1339{
1340   int   ret;
1341   OrigFn fn;
1342   VALGRIND_GET_ORIG_FN(fn);
1343   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_WAIT,
1344                                   barrier, pthread_barrier, 0, 0, 0);
1345   CALL_FN_W_W(ret, fn, barrier);
1346   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_WAIT,
1347                              barrier, pthread_barrier,
1348                              ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD,
1349                              ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
1350   return ret;
1351}
1352
1353PTH_FUNCS(int, pthreadZubarrierZuwait, pthread_barrier_wait_intercept,
1354          (pthread_barrier_t* barrier), (barrier));
1355#endif   // HAVE_PTHREAD_BARRIER_INIT
1356
1357
1358static __always_inline
1359int sem_init_intercept(sem_t *sem, int pshared, unsigned int value)
1360{
1361   int   ret;
1362   OrigFn fn;
1363   VALGRIND_GET_ORIG_FN(fn);
1364   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT,
1365                                   sem, pshared, value, 0, 0);
1366   CALL_FN_W_WWW(ret, fn, sem, pshared, value);
1367   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT,
1368                                   sem, 0, 0, 0, 0);
1369   return ret;
1370}
1371
1372PTH_FUNCS(int, semZuinit, sem_init_intercept,
1373          (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
1374
1375#if defined(VGO_solaris)
1376static __always_inline
1377int sema_init_intercept(sema_t *sem, unsigned int value, int type, void *arg)
1378{
1379   int   ret;
1380   OrigFn fn;
1381   VALGRIND_GET_ORIG_FN(fn);
1382   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT,
1383                                   sem, type == USYNC_PROCESS ? 1 : 0,
1384                                   value, 0, 0);
1385   CALL_FN_W_WWWW(ret, fn, sem, value, type, arg);
1386   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT,
1387                                   sem, 0, 0, 0, 0);
1388   return ret;
1389}
1390
1391PTH_FUNCS(int, semaZuinit, sema_init_intercept,
1392          (sema_t *sem, unsigned int value, int type, void *arg),
1393          (sem, value, type, arg));
1394#endif /* VGO_solaris */
1395
1396static __always_inline
1397int sem_destroy_intercept(sem_t *sem)
1398{
1399   int   ret;
1400   OrigFn fn;
1401   VALGRIND_GET_ORIG_FN(fn);
1402   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_DESTROY,
1403                                   sem, 0, 0, 0, 0);
1404   CALL_FN_W_W(ret, fn, sem);
1405   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_DESTROY,
1406                                   sem, 0, 0, 0, 0);
1407   return ret;
1408}
1409
1410PTH_FUNCS(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1411#if defined(VGO_solaris)
1412PTH_FUNCS(int, semaZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1413#endif /* VGO_solaris */
1414
1415static __always_inline
1416sem_t* sem_open_intercept(const char *name, int oflag, mode_t mode,
1417                          unsigned int value)
1418{
1419   sem_t *ret;
1420   OrigFn fn;
1421   VALGRIND_GET_ORIG_FN(fn);
1422   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_OPEN,
1423                                   name, oflag, mode, value, 0);
1424   CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value);
1425   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_OPEN,
1426                                   ret != SEM_FAILED ? ret : 0,
1427                                   name, oflag, mode, value);
1428   return ret;
1429}
1430
1431PTH_FUNCS(sem_t *, semZuopen, sem_open_intercept,
1432          (const char *name, int oflag, mode_t mode, unsigned int value),
1433          (name, oflag, mode, value));
1434
1435static __always_inline int sem_close_intercept(sem_t *sem)
1436{
1437   int   ret;
1438   OrigFn fn;
1439   VALGRIND_GET_ORIG_FN(fn);
1440   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_CLOSE,
1441                                   sem, 0, 0, 0, 0);
1442   CALL_FN_W_W(ret, fn, sem);
1443   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_CLOSE,
1444                                   sem, 0, 0, 0, 0);
1445   return ret;
1446}
1447
1448PTH_FUNCS(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
1449
1450static __always_inline int sem_wait_intercept(sem_t *sem)
1451{
1452   int   ret;
1453   OrigFn fn;
1454   VALGRIND_GET_ORIG_FN(fn);
1455   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1456                                   sem, 0, 0, 0, 0);
1457   CALL_FN_W_W(ret, fn, sem);
1458   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1459                                   sem, ret == 0, 0, 0, 0);
1460   return ret;
1461}
1462
1463PTH_FUNCS(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1464#if defined(VGO_solaris)
1465PTH_FUNCS(int, semaZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1466#endif /* VGO_solaris */
1467
1468static __always_inline int sem_trywait_intercept(sem_t *sem)
1469{
1470   int   ret;
1471   OrigFn fn;
1472   VALGRIND_GET_ORIG_FN(fn);
1473   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1474                                   sem, 0, 0, 0, 0);
1475   CALL_FN_W_W(ret, fn, sem);
1476   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1477                                   sem, ret == 0, 0, 0, 0);
1478   return ret;
1479}
1480
1481PTH_FUNCS(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1482#if defined(VGO_solaris)
1483PTH_FUNCS(int, semaZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1484#endif /* VGO_solaris */
1485
1486static __always_inline
1487int sem_timedwait_intercept(sem_t *sem, const struct timespec *abs_timeout)
1488{
1489   int   ret;
1490   OrigFn fn;
1491   VALGRIND_GET_ORIG_FN(fn);
1492   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1493                                   sem, 0, 0, 0, 0);
1494   CALL_FN_W_WW(ret, fn, sem, abs_timeout);
1495   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1496                                   sem, ret == 0, 0, 0, 0);
1497   return ret;
1498}
1499
1500PTH_FUNCS(int, semZutimedwait, sem_timedwait_intercept,
1501          (sem_t *sem, const struct timespec *abs_timeout),
1502          (sem, abs_timeout));
1503#if defined(VGO_solaris)
1504PTH_FUNCS(int, semaZutimedwait, sem_timedwait_intercept,
1505          (sem_t *sem, const struct timespec *timeout),
1506          (sem, timeout));
1507PTH_FUNCS(int, semaZureltimedwait, sem_timedwait_intercept,
1508          (sem_t *sem, const struct timespec *timeout),
1509          (sem, timeout));
1510#endif /* VGO_solaris */
1511
1512static __always_inline int sem_post_intercept(sem_t *sem)
1513{
1514   int   ret;
1515   OrigFn fn;
1516   VALGRIND_GET_ORIG_FN(fn);
1517   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_POST,
1518                                   sem, 0, 0, 0, 0);
1519   CALL_FN_W_W(ret, fn, sem);
1520   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_POST,
1521                                   sem, ret == 0, 0, 0, 0);
1522   return ret;
1523}
1524
1525PTH_FUNCS(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
1526#if defined(VGO_solaris)
1527PTH_FUNCS(int, semaZupost, sem_post_intercept, (sem_t *sem), (sem));
1528#endif /* VGO_solaris */
1529
1530/* Android's pthread.h doesn't say anything about rwlocks, hence these
1531   functions have to be conditionally compiled. */
1532#if defined(HAVE_PTHREAD_RWLOCK_T)
1533
1534static __always_inline
1535int pthread_rwlock_init_intercept(pthread_rwlock_t* rwlock,
1536                                  const pthread_rwlockattr_t* attr)
1537{
1538   int   ret;
1539   OrigFn fn;
1540   VALGRIND_GET_ORIG_FN(fn);
1541   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT,
1542                                   rwlock, 0, 0, 0, 0);
1543   CALL_FN_W_WW(ret, fn, rwlock, attr);
1544   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT,
1545                                   rwlock, 0, 0, 0, 0);
1546   return ret;
1547}
1548
1549PTH_FUNCS(int,
1550          pthreadZurwlockZuinit, pthread_rwlock_init_intercept,
1551          (pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr),
1552          (rwlock, attr));
1553
1554#if defined(VGO_solaris)
1555static __always_inline
1556int rwlock_init_intercept(rwlock_t *rwlock, int type, void *arg)
1557{
1558   int   ret;
1559   OrigFn fn;
1560   VALGRIND_GET_ORIG_FN(fn);
1561   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT,
1562                                   rwlock, 0, 0, 0, 0);
1563   CALL_FN_W_WWW(ret, fn, rwlock, type, arg);
1564   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT,
1565                                   rwlock, 0, 0, 0, 0);
1566   return ret;
1567}
1568
1569PTH_FUNCS(int, rwlockZuinit, rwlock_init_intercept,
1570          (rwlock_t *rwlock, int type, void *arg),
1571          (rwlock, type, arg));
1572#endif /* VGO_solaris */
1573
1574static __always_inline
1575int pthread_rwlock_destroy_intercept(pthread_rwlock_t* rwlock)
1576{
1577   int   ret;
1578   OrigFn fn;
1579   VALGRIND_GET_ORIG_FN(fn);
1580   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_DESTROY,
1581                                   rwlock, 0, 0, 0, 0);
1582   CALL_FN_W_W(ret, fn, rwlock);
1583   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_DESTROY,
1584                                   rwlock, 0, 0, 0, 0);
1585   return ret;
1586}
1587
1588#if defined(VGO_solaris)
1589/* On Solaris, pthread_rwlock_destroy is a weak alias to rwlock_destroy. */
1590PTH_FUNCS(int,
1591          rwlockZudestroy, pthread_rwlock_destroy_intercept,
1592          (pthread_rwlock_t *rwlock), (rwlock));
1593#else
1594PTH_FUNCS(int,
1595          pthreadZurwlockZudestroy, pthread_rwlock_destroy_intercept,
1596          (pthread_rwlock_t* rwlock), (rwlock));
1597#endif /* VGO_solaris */
1598
1599static __always_inline
1600int pthread_rwlock_rdlock_intercept(pthread_rwlock_t* rwlock)
1601{
1602   int   ret;
1603   OrigFn fn;
1604   VALGRIND_GET_ORIG_FN(fn);
1605   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1606                                   rwlock, 0, 0, 0, 0);
1607   CALL_FN_W_W(ret, fn, rwlock);
1608   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1609                                   rwlock, ret == 0, 0, 0, 0);
1610   return ret;
1611}
1612
1613#if defined(VGO_solaris)
1614/* On Solaris, pthread_rwlock_rdlock is a weak alias to rw_rdlock. */
1615PTH_FUNCS(int,
1616          rwZurdlock, pthread_rwlock_rdlock_intercept,
1617          (pthread_rwlock_t *rwlock), (rwlock));
1618#else
1619PTH_FUNCS(int,
1620          pthreadZurwlockZurdlock, pthread_rwlock_rdlock_intercept,
1621          (pthread_rwlock_t* rwlock), (rwlock));
1622#endif /* VGO_solaris */
1623
1624#if defined(VGO_solaris)
1625/* Internal to libc. */
1626static __always_inline
1627void lrw_rdlock_intercept(rwlock_t *rwlock)
1628{
1629   OrigFn fn;
1630   VALGRIND_GET_ORIG_FN(fn);
1631   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1632                                   rwlock, 0, 0, 0, 0);
1633   CALL_FN_v_W(fn, rwlock);
1634   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1635                                   rwlock, True /* took_lock */, 0, 0, 0);
1636}
1637
1638PTH_FUNCS(void, lrwZurdlock, lrw_rdlock_intercept,
1639          (rwlock_t *rwlock), (rwlock));
1640#endif /* VGO_solaris */
1641
1642static __always_inline
1643int pthread_rwlock_wrlock_intercept(pthread_rwlock_t* rwlock)
1644{
1645   int   ret;
1646   OrigFn fn;
1647   VALGRIND_GET_ORIG_FN(fn);
1648   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1649                                   rwlock, 0, 0, 0, 0);
1650   CALL_FN_W_W(ret, fn, rwlock);
1651   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1652                                   rwlock, ret == 0, 0, 0, 0);
1653   return ret;
1654}
1655
1656#if defined(VGO_solaris)
1657/* On Solaris, pthread_rwlock_wrlock is a weak alias to rw_wrlock. */
1658PTH_FUNCS(int,
1659          rwZuwrlock, pthread_rwlock_wrlock_intercept,
1660          (pthread_rwlock_t *rwlock), (rwlock));
1661#else
1662PTH_FUNCS(int,
1663          pthreadZurwlockZuwrlock, pthread_rwlock_wrlock_intercept,
1664          (pthread_rwlock_t* rwlock), (rwlock));
1665#endif /* VGO_solaris */
1666
1667#if defined(VGO_solaris)
1668/* Internal to libc. */
1669static __always_inline
1670void lrw_wrlock_intercept(rwlock_t *rwlock)
1671{
1672   OrigFn fn;
1673   VALGRIND_GET_ORIG_FN(fn);
1674   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1675                                   rwlock, 0, 0, 0, 0);
1676   CALL_FN_v_W(fn, rwlock);
1677   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1678                                   rwlock, True /* took_lock */, 0, 0, 0);
1679}
1680
1681PTH_FUNCS(void, lrwZuwrlock, lrw_wrlock_intercept,
1682          (rwlock_t *rwlock), (rwlock));
1683#endif /* VGO_solaris */
1684
1685static __always_inline
1686int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t* rwlock,
1687                                         const struct timespec *timeout)
1688{
1689   int   ret;
1690   OrigFn fn;
1691   VALGRIND_GET_ORIG_FN(fn);
1692   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1693                                   rwlock, 0, 0, 0, 0);
1694   CALL_FN_W_WW(ret, fn, rwlock, timeout);
1695   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1696                                   rwlock, ret == 0, 0, 0, 0);
1697   return ret;
1698}
1699
1700PTH_FUNCS(int,
1701          pthreadZurwlockZutimedrdlock, pthread_rwlock_timedrdlock_intercept,
1702          (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1703          (rwlock, timeout));
1704#if defined(VGO_solaris)
1705PTH_FUNCS(int, pthreadZurwlockZureltimedrdlockZunp,
1706          pthread_rwlock_timedrdlock_intercept,
1707          (pthread_rwlock_t *rwlock, const struct timespec *timeout),
1708          (rwlock, timeout));
1709#endif /* VGO_solaris */
1710
1711static __always_inline
1712int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t* rwlock,
1713                                         const struct timespec *timeout)
1714{
1715   int   ret;
1716   OrigFn fn;
1717   VALGRIND_GET_ORIG_FN(fn);
1718   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1719                                   rwlock, 0, 0, 0, 0);
1720   CALL_FN_W_WW(ret, fn, rwlock, timeout);
1721   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1722                                   rwlock, ret == 0, 0, 0, 0);
1723   return ret;
1724}
1725
1726PTH_FUNCS(int,
1727          pthreadZurwlockZutimedwrlock, pthread_rwlock_timedwrlock_intercept,
1728          (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1729          (rwlock, timeout));
1730#if defined(VGO_solaris)
1731PTH_FUNCS(int, pthreadZurwlockZureltimedwrlockZunp,
1732          pthread_rwlock_timedwrlock_intercept,
1733          (pthread_rwlock_t *rwlock, const struct timespec *timeout),
1734          (rwlock, timeout));
1735#endif /* VGO_solaris */
1736
1737static __always_inline
1738int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t* rwlock)
1739{
1740   int   ret;
1741   OrigFn fn;
1742   VALGRIND_GET_ORIG_FN(fn);
1743   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1744                                   rwlock, 0, 0, 0, 0);
1745   CALL_FN_W_W(ret, fn, rwlock);
1746   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1747                                   rwlock, ret == 0, 0, 0, 0);
1748   return ret;
1749}
1750
1751#if defined(VGO_solaris)
1752/* On Solaris, pthread_rwlock_tryrdlock is a weak alias to rw_tryrdlock. */
1753PTH_FUNCS(int,
1754          rwZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1755          (pthread_rwlock_t *rwlock), (rwlock));
1756#else
1757PTH_FUNCS(int,
1758          pthreadZurwlockZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1759          (pthread_rwlock_t* rwlock), (rwlock));
1760#endif /* VGO_solaris */
1761
1762static __always_inline
1763int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t* rwlock)
1764{
1765   int   ret;
1766   OrigFn fn;
1767   VALGRIND_GET_ORIG_FN(fn);
1768   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__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__POST_RWLOCK_WRLOCK,
1772                                   rwlock, ret == 0, 0, 0, 0);
1773   return ret;
1774}
1775
1776#if defined(VGO_solaris)
1777/* On Solaris, pthread_rwlock_trywrlock is a weak alias to rw_trywrlock. */
1778PTH_FUNCS(int,
1779          rwZutrywrlock, pthread_rwlock_trywrlock_intercept,
1780          (pthread_rwlock_t *rwlock), (rwlock));
1781#else
1782PTH_FUNCS(int,
1783          pthreadZurwlockZutrywrlock, pthread_rwlock_trywrlock_intercept,
1784          (pthread_rwlock_t* rwlock), (rwlock));
1785#endif /* VGO_solaris */
1786
1787static __always_inline
1788int pthread_rwlock_unlock_intercept(pthread_rwlock_t* rwlock)
1789{
1790   int   ret;
1791   OrigFn fn;
1792   VALGRIND_GET_ORIG_FN(fn);
1793   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_UNLOCK,
1794                                   rwlock, 0, 0, 0, 0);
1795   CALL_FN_W_W(ret, fn, rwlock);
1796   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_UNLOCK,
1797                                   rwlock, ret == 0, 0, 0, 0);
1798   return ret;
1799}
1800
1801#if defined(VGO_solaris)
1802/* On Solaris, pthread_rwlock_unlock is a weak alias to rw_unlock. */
1803PTH_FUNCS(int,
1804          rwZuunlock, pthread_rwlock_unlock_intercept,
1805          (pthread_rwlock_t *rwlock), (rwlock));
1806#else
1807PTH_FUNCS(int,
1808          pthreadZurwlockZuunlock, pthread_rwlock_unlock_intercept,
1809          (pthread_rwlock_t* rwlock), (rwlock));
1810#endif /* VGO_solaris */
1811
1812#endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
1813