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