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-2017 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_pthread_id)(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_pthread_id)();
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 * Update DRD's state information about the current thread.
505 */
506static void DRD_(set_pthread_id)(void)
507{
508   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
509                                   pthread_self(), 0, 0, 0, 0);
510}
511
512/*
513 * Note: as of today there exist three different versions of pthread_create
514 * in Linux:
515 * - pthread_create@GLIBC_2.0
516 * - pthread_create@@GLIBC_2.1
517 * - pthread_create@@GLIBC_2.2.5
518 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
519 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
520 * versions have been implemented. In any glibc version where more than one
521 * pthread_create function has been implemented, older versions call the
522 * newer versions. Or: the pthread_create* wrapper defined below can be
523 * called recursively. Any code in this wrapper should take this in account.
524 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
525 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
526 * See also the implementation of pthread_create@GLIBC_2.0 in
527 * glibc-2.9/nptl/pthread_create.c.
528 */
529
530static __always_inline
531int pthread_create_intercept(pthread_t* thread, const pthread_attr_t* attr,
532                             void* (*start)(void*), void* arg)
533{
534   int    ret;
535   OrigFn fn;
536   DrdSema wrapper_started;
537   DrdPosixThreadArgs thread_args;
538
539   VALGRIND_GET_ORIG_FN(fn);
540
541   DRD_(sema_init)(&wrapper_started);
542   thread_args.start           = start;
543   thread_args.arg             = arg;
544   thread_args.wrapper_started = &wrapper_started;
545   /*
546    * Find out whether the thread will be started as a joinable thread
547    * or as a detached thread. If no thread attributes have been specified,
548    * this means that the new thread will be started as a joinable thread.
549    */
550   thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
551   if (attr)
552   {
553      if (pthread_attr_getdetachstate(attr, &thread_args.detachstate) != 0)
554         assert(0);
555   }
556   assert(thread_args.detachstate == PTHREAD_CREATE_JOINABLE
557          || thread_args.detachstate == PTHREAD_CREATE_DETACHED);
558
559   /*
560    * The DRD_(set_pthread_id)() from DRD_(init)() may encounter that
561    * pthread_self() == 0, e.g. when the main program is not linked with the
562    * pthread library and when a pthread_create() call occurs from within a
563    * shared library. Hence call DRD_(set_pthread_id)() again to ensure that
564    * DRD knows the identity of the current thread. See also B.Z. 356374.
565    */
566   DRD_(set_pthread_id)();
567   DRD_(entering_pthread_create)();
568   CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), &thread_args);
569   DRD_(left_pthread_create)();
570
571   if (ret == 0) {
572      /* Wait until the thread wrapper started. */
573      DRD_(sema_down)(&wrapper_started);
574   }
575
576   DRD_(sema_destroy)(&wrapper_started);
577
578   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT,
579                                   pthread_self(), 0, 0, 0, 0);
580
581   return ret;
582}
583
584PTH_FUNCS(int, pthreadZucreate, pthread_create_intercept,
585          (pthread_t *thread, const pthread_attr_t *attr,
586           void *(*start) (void *), void *arg),
587          (thread, attr, start, arg));
588
589#if defined(VGO_solaris)
590/* Solaris also provides thr_create() in addition to pthread_create().
591 * Both pthread_create(3C) and thr_create(3C) are based on private
592 * _thrp_create().
593 */
594static __always_inline
595int thr_create_intercept(void *stk, size_t stksize, void *(*start)(void *),
596                         void *arg, long flags, thread_t *new_thread)
597{
598   int                ret;
599   OrigFn             fn;
600   DrdSema            wrapper_started;
601   DrdPosixThreadArgs thread_args;
602
603   VALGRIND_GET_ORIG_FN(fn);
604
605   DRD_(sema_init)(&wrapper_started);
606   thread_args.start           = start;
607   thread_args.arg             = arg;
608   thread_args.wrapper_started = &wrapper_started;
609   /*
610    * Find out whether the thread will be started as a joinable thread
611    * or as a detached thread.
612    */
613   if (flags & THR_DETACHED)
614      thread_args.detachstate = PTHREAD_CREATE_DETACHED;
615   else
616      thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
617
618   DRD_(entering_pthread_create)();
619   CALL_FN_W_6W(ret, fn, stk, stksize, DRD_(thread_wrapper), &thread_args,
620                flags, new_thread);
621   DRD_(left_pthread_create)();
622
623   if (ret == 0) {
624      /* Wait until the thread wrapper started. */
625      DRD_(sema_down)(&wrapper_started);
626   }
627
628   DRD_(sema_destroy)(&wrapper_started);
629
630   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT,
631                                   pthread_self(), 0, 0, 0, 0);
632
633   return ret;
634}
635
636PTH_FUNCS(int, thrZucreate, thr_create_intercept,
637          (void *stk, size_t stksize, void *(*start)(void *), void *arg,
638           long flags, thread_t *new_thread),
639          (stk, stksize, start, arg, flags, new_thread));
640#endif /* VGO_solaris */
641
642#if defined(VGO_solaris)
643/*
644 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
645 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
646 * and CI_BIND_CLEAR, to provide resilience against function renaming.
647 */
648static __always_inline
649int DRD_(_ti_bind_guard_intercept)(int flags) {
650   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_GUARD,
651                                   flags, 0, 0, 0, 0);
652   return DRD_(rtld_bind_guard)(flags);
653}
654
655static __always_inline
656int DRD_(_ti_bind_clear_intercept)(int flags) {
657   int ret = DRD_(rtld_bind_clear)(flags);
658   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_CLEAR,
659                                   flags, 0, 0, 0, 0);
660   return ret;
661}
662
663/*
664 * Wrapped _ld_libc() from the runtime linker ld.so.1.
665 */
666void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr);
667void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr)
668{
669   OrigFn fn;
670   int    tag;
671
672   VALGRIND_GET_ORIG_FN(fn);
673
674   vki_Lc_interface *funcs = ptr;
675   for (tag = funcs->ci_tag; tag != 0; tag = (++funcs)->ci_tag) {
676      switch (tag) {
677      case VKI_CI_BIND_GUARD:
678         if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_guard_intercept)) {
679            DRD_(rtld_bind_guard) = funcs->vki_ci_un.ci_func;
680            funcs->vki_ci_un.ci_func = DRD_(_ti_bind_guard_intercept);
681         }
682         break;
683      case VKI_CI_BIND_CLEAR:
684         if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_clear_intercept)) {
685            DRD_(rtld_bind_clear) = funcs->vki_ci_un.ci_func;
686            funcs->vki_ci_un.ci_func = DRD_(_ti_bind_clear_intercept);
687         }
688         break;
689      }
690   }
691
692   CALL_FN_v_W(fn, ptr);
693}
694#endif /* VGO_solaris */
695
696static __always_inline
697int pthread_join_intercept(pthread_t pt_joinee, void **thread_return)
698{
699   int      ret;
700   OrigFn   fn;
701
702   VALGRIND_GET_ORIG_FN(fn);
703   /*
704    * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
705    * implementation triggers a (false positive) race report.
706    */
707   ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
708   CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
709   if (ret == 0)
710   {
711      VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN,
712                                      pt_joinee, 0, 0, 0, 0);
713   }
714   ANNOTATE_IGNORE_READS_AND_WRITES_END();
715   return ret;
716}
717
718PTH_FUNCS(int, pthreadZujoin, pthread_join_intercept,
719          (pthread_t pt_joinee, void **thread_return),
720          (pt_joinee, thread_return));
721
722#if defined(VGO_solaris)
723/* Solaris also provides thr_join() in addition to pthread_join().
724 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
725 *
726 * :TODO: No functionality is currently provided for joinee == 0 and departed.
727 *        This would require another client request, of course.
728 */
729static __always_inline
730int thr_join_intercept(thread_t joinee, thread_t *departed, void **thread_return)
731{
732   int      ret;
733   OrigFn   fn;
734
735   VALGRIND_GET_ORIG_FN(fn);
736   CALL_FN_W_WWW(ret, fn, joinee, departed, thread_return);
737   if (ret == 0)
738   {
739      VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN,
740                                      joinee, 0, 0, 0, 0);
741   }
742   return ret;
743}
744
745PTH_FUNCS(int, thrZujoin, thr_join_intercept,
746          (thread_t joinee, thread_t *departed, void **thread_return),
747          (joinee, departed, thread_return));
748#endif /* VGO_solaris */
749
750static __always_inline
751int pthread_detach_intercept(pthread_t pt_thread)
752{
753   int ret;
754   OrigFn fn;
755
756   VALGRIND_GET_ORIG_FN(fn);
757   CALL_FN_W_W(ret, fn, pt_thread);
758   DRD_(set_joinable)(pt_thread, 0);
759
760   return ret;
761}
762
763PTH_FUNCS(int, pthreadZudetach, pthread_detach_intercept,
764          (pthread_t thread), (thread));
765
766// NOTE: be careful to intercept only pthread_cancel() and not
767// pthread_cancel_init() on Linux.
768
769static __always_inline
770int pthread_cancel_intercept(pthread_t pt_thread)
771{
772   int ret;
773   OrigFn fn;
774   VALGRIND_GET_ORIG_FN(fn);
775   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_THREAD_CANCEL,
776                                   pt_thread, 0, 0, 0, 0);
777   CALL_FN_W_W(ret, fn, pt_thread);
778   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_CANCEL,
779                                   pt_thread, ret==0, 0, 0, 0);
780   return ret;
781}
782
783PTH_FUNCS(int, pthreadZucancel, pthread_cancel_intercept,
784          (pthread_t thread), (thread))
785
786static __always_inline
787int pthread_once_intercept(pthread_once_t *once_control,
788                           void (*init_routine)(void))
789{
790   int ret;
791   OrigFn fn;
792   VALGRIND_GET_ORIG_FN(fn);
793   /*
794    * Ignore any data races triggered by the implementation of pthread_once().
795    * Necessary for Darwin. This is not necessary for Linux but doesn't have
796    * any known adverse effects.
797    */
798   DRD_IGNORE_VAR(*once_control);
799   ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
800   CALL_FN_W_WW(ret, fn, once_control, init_routine);
801   ANNOTATE_IGNORE_READS_AND_WRITES_END();
802   DRD_STOP_IGNORING_VAR(*once_control);
803   return ret;
804}
805
806PTH_FUNCS(int, pthreadZuonce, pthread_once_intercept,
807          (pthread_once_t *once_control, void (*init_routine)(void)),
808          (once_control, init_routine));
809
810static __always_inline
811int pthread_mutex_init_intercept(pthread_mutex_t *mutex,
812                                 const pthread_mutexattr_t* attr)
813{
814   int ret;
815   OrigFn fn;
816   int mt;
817   VALGRIND_GET_ORIG_FN(fn);
818   mt = PTHREAD_MUTEX_DEFAULT;
819   if (attr)
820      pthread_mutexattr_gettype(attr, &mt);
821   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
822                                   mutex, DRD_(pthread_to_drd_mutex_type)(mt),
823                                   0, 0, 0);
824   CALL_FN_W_WW(ret, fn, mutex, attr);
825   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
826                                   mutex, 0, 0, 0, 0);
827   return ret;
828}
829
830PTH_FUNCS(int, pthreadZumutexZuinit, pthread_mutex_init_intercept,
831          (pthread_mutex_t *mutex, const pthread_mutexattr_t* attr),
832          (mutex, attr));
833
834#if defined(VGO_solaris)
835static __always_inline
836int mutex_init_intercept(mutex_t *mutex, int type, void *arg)
837{
838   int ret;
839   OrigFn fn;
840   VALGRIND_GET_ORIG_FN(fn);
841
842   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
843                                   mutex, DRD_(thread_to_drd_mutex_type)(type),
844                                   0, 0, 0);
845   CALL_FN_W_WWW(ret, fn, mutex, type, arg);
846   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
847                                   mutex, 0, 0, 0, 0);
848   return ret;
849}
850
851PTH_FUNCS(int, mutexZuinit, mutex_init_intercept,
852          (mutex_t *mutex, int type, void *arg),
853          (mutex, type, arg));
854#endif /* VGO_solaris */
855
856static __always_inline
857int pthread_mutex_destroy_intercept(pthread_mutex_t* mutex)
858{
859   int ret;
860   OrigFn fn;
861   VALGRIND_GET_ORIG_FN(fn);
862   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
863                                   mutex, 0, 0, 0, 0);
864   CALL_FN_W_W(ret, fn, mutex);
865   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
866                                   mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
867   return ret;
868}
869
870#if defined(VGO_solaris)
871/* On Solaris, pthread_mutex_destroy is a weak alias to mutex_destroy. */
872PTH_FUNCS(int, mutexZudestroy, pthread_mutex_destroy_intercept,
873          (pthread_mutex_t *mutex), (mutex));
874#else
875PTH_FUNCS(int, pthreadZumutexZudestroy, pthread_mutex_destroy_intercept,
876          (pthread_mutex_t *mutex), (mutex));
877#endif /* VGO_solaris */
878
879static __always_inline
880int pthread_mutex_lock_intercept(pthread_mutex_t* mutex)
881{
882   int   ret;
883   OrigFn fn;
884   VALGRIND_GET_ORIG_FN(fn);
885   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
886                                   mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
887   CALL_FN_W_W(ret, fn, mutex);
888   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
889                                   mutex, ret == 0, 0, 0, 0);
890   return ret;
891}
892
893#if defined(VGO_solaris)
894/* On Solaris, pthread_mutex_lock is a weak alias to mutex_lock. */
895PTH_FUNCS(int, mutexZulock, pthread_mutex_lock_intercept,
896          (pthread_mutex_t *mutex), (mutex));
897#else
898PTH_FUNCS(int, pthreadZumutexZulock, pthread_mutex_lock_intercept,
899          (pthread_mutex_t *mutex), (mutex));
900#endif /* VGO_solaris */
901
902#if defined(VGO_solaris)
903/* Internal to libc. Mutex is usually initialized only implicitly,
904 * by zeroing mutex_t structure.
905 */
906static __always_inline
907void lmutex_lock_intercept(mutex_t *mutex)
908{
909   OrigFn fn;
910   VALGRIND_GET_ORIG_FN(fn);
911   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
912                                   mutex,
913                                   DRD_(mutex_type)((pthread_mutex_t *) mutex),
914                                   False /* try_lock */, 0, 0);
915   CALL_FN_v_W(fn, mutex);
916   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
917                                   mutex, True /* took_lock */, 0, 0, 0);
918}
919
920PTH_FUNCS(void, lmutexZulock, lmutex_lock_intercept,
921          (mutex_t *mutex), (mutex));
922#endif /* VGO_solaris */
923
924static __always_inline
925int pthread_mutex_trylock_intercept(pthread_mutex_t* mutex)
926{
927   int   ret;
928   OrigFn fn;
929   VALGRIND_GET_ORIG_FN(fn);
930   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
931                                   mutex, DRD_(mutex_type)(mutex), 1, 0, 0);
932   CALL_FN_W_W(ret, fn, mutex);
933   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
934                                   mutex, ret == 0, 0, 0, 0);
935   return ret;
936}
937
938#if defined(VGO_solaris)
939/* On Solaris, pthread_mutex_trylock is a weak alias to mutex_trylock. */
940PTH_FUNCS(int, mutexZutrylock, pthread_mutex_trylock_intercept,
941          (pthread_mutex_t *mutex), (mutex));
942#else
943PTH_FUNCS(int, pthreadZumutexZutrylock, pthread_mutex_trylock_intercept,
944          (pthread_mutex_t *mutex), (mutex));
945#endif /* VGO_solaris */
946
947static __always_inline
948int pthread_mutex_timedlock_intercept(pthread_mutex_t *mutex,
949                                      const struct timespec *abs_timeout)
950{
951   int   ret;
952   OrigFn fn;
953   VALGRIND_GET_ORIG_FN(fn);
954   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
955                                   mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
956   CALL_FN_W_WW(ret, fn, mutex, abs_timeout);
957   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
958                                   mutex, ret == 0, 0, 0, 0);
959   return ret;
960}
961
962PTH_FUNCS(int, pthreadZumutexZutimedlock, pthread_mutex_timedlock_intercept,
963          (pthread_mutex_t *mutex, const struct timespec *abs_timeout),
964          (mutex, abs_timeout));
965#if defined(VGO_solaris)
966PTH_FUNCS(int,
967          pthreadZumutexZureltimedlockZunp, pthread_mutex_timedlock_intercept,
968          (pthread_mutex_t *mutex, const struct timespec *timeout),
969          (mutex, timeout));
970#endif /* VGO_solaris */
971
972static __always_inline
973int pthread_mutex_unlock_intercept(pthread_mutex_t *mutex)
974{
975   int ret;
976   OrigFn fn;
977   VALGRIND_GET_ORIG_FN(fn);
978   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
979                                   mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
980   CALL_FN_W_W(ret, fn, mutex);
981   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
982                                   mutex, 0, 0, 0, 0);
983   return ret;
984}
985
986#if defined(VGO_solaris)
987/* On Solaris, pthread_mutex_unlock is a weak alias to mutex_unlock. */
988PTH_FUNCS(int, mutexZuunlock, pthread_mutex_unlock_intercept,
989          (pthread_mutex_t *mutex), (mutex));
990#else
991PTH_FUNCS(int, pthreadZumutexZuunlock, pthread_mutex_unlock_intercept,
992          (pthread_mutex_t *mutex), (mutex));
993#endif /* VGO_solaris */
994
995#if defined(VGO_solaris)
996/* Internal to libc. */
997static __always_inline
998void lmutex_unlock_intercept(mutex_t *mutex)
999{
1000   OrigFn fn;
1001   VALGRIND_GET_ORIG_FN(fn);
1002   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
1003                                   mutex,
1004                                   DRD_(mutex_type)((pthread_mutex_t *) mutex),
1005                                   0, 0, 0);
1006   CALL_FN_v_W(fn, mutex);
1007   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
1008                                   mutex, 0, 0, 0, 0);
1009}
1010
1011PTH_FUNCS(void, lmutexZuunlock, lmutex_unlock_intercept,
1012          (mutex_t *mutex), (mutex));
1013#endif /* VGO_solaris */
1014
1015static __always_inline
1016int pthread_cond_init_intercept(pthread_cond_t* cond,
1017                                const pthread_condattr_t* attr)
1018{
1019   int ret;
1020   OrigFn fn;
1021   VALGRIND_GET_ORIG_FN(fn);
1022   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT,
1023                                   cond, 0, 0, 0, 0);
1024   CALL_FN_W_WW(ret, fn, cond, attr);
1025   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT,
1026                                   cond, 0, 0, 0, 0);
1027   return ret;
1028}
1029
1030PTH_FUNCS(int, pthreadZucondZuinit, pthread_cond_init_intercept,
1031          (pthread_cond_t* cond, const pthread_condattr_t* attr),
1032          (cond, attr));
1033
1034#if defined(VGO_solaris)
1035static __always_inline
1036int cond_init_intercept(cond_t *cond, int type, void *arg)
1037{
1038   int ret;
1039   OrigFn fn;
1040   VALGRIND_GET_ORIG_FN(fn);
1041   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT,
1042                                   cond, 0, 0, 0, 0);
1043   CALL_FN_W_WWW(ret, fn, cond, type, arg);
1044   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT,
1045                                   cond, 0, 0, 0, 0);
1046   return ret;
1047}
1048
1049PTH_FUNCS(int, condZuinit, cond_init_intercept,
1050          (cond_t *cond, int type, void *arg),
1051          (cond, type, arg));
1052#endif /* VGO_solaris */
1053
1054static __always_inline
1055int pthread_cond_destroy_intercept(pthread_cond_t* cond)
1056{
1057   int ret;
1058   OrigFn fn;
1059   VALGRIND_GET_ORIG_FN(fn);
1060   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_DESTROY,
1061                                   cond, 0, 0, 0, 0);
1062   CALL_FN_W_W(ret, fn, cond);
1063   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_DESTROY,
1064                                   cond, ret==0, 0, 0, 0);
1065   return ret;
1066}
1067
1068#if defined(VGO_solaris)
1069/* On Solaris, pthread_cond_destroy is a weak alias to cond_destroy. */
1070PTH_FUNCS(int, condZudestroy, pthread_cond_destroy_intercept,
1071          (pthread_cond_t *cond), (cond));
1072#else
1073PTH_FUNCS(int, pthreadZucondZudestroy, pthread_cond_destroy_intercept,
1074          (pthread_cond_t* cond), (cond));
1075#endif /* VGO_solaris */
1076
1077static __always_inline
1078int pthread_cond_wait_intercept(pthread_cond_t *cond, pthread_mutex_t *mutex)
1079{
1080   int   ret;
1081   OrigFn fn;
1082   VALGRIND_GET_ORIG_FN(fn);
1083   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
1084                                   cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1085   CALL_FN_W_WW(ret, fn, cond, mutex);
1086   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
1087                                   cond, mutex, 1, 0, 0);
1088   return ret;
1089}
1090
1091PTH_FUNCS(int, pthreadZucondZuwait, pthread_cond_wait_intercept,
1092          (pthread_cond_t *cond, pthread_mutex_t *mutex),
1093          (cond, mutex));
1094#if defined(VGO_solaris)
1095PTH_FUNCS(int, condZuwait, pthread_cond_wait_intercept,
1096          (pthread_cond_t *cond, pthread_mutex_t *mutex),
1097          (cond, mutex));
1098#endif /* VGO_solaris */
1099
1100static __always_inline
1101int pthread_cond_timedwait_intercept(pthread_cond_t *cond,
1102                                     pthread_mutex_t *mutex,
1103                                     const struct timespec* abstime)
1104{
1105   int   ret;
1106   OrigFn fn;
1107   VALGRIND_GET_ORIG_FN(fn);
1108   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
1109                                   cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1110   CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
1111   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
1112                                   cond, mutex, 1, 0, 0);
1113   return ret;
1114}
1115
1116PTH_FUNCS(int, pthreadZucondZutimedwait, pthread_cond_timedwait_intercept,
1117          (pthread_cond_t *cond, pthread_mutex_t *mutex,
1118           const struct timespec* abstime),
1119          (cond, mutex, abstime));
1120#if defined(VGO_solaris)
1121PTH_FUNCS(int, condZutimedwait, pthread_cond_timedwait_intercept,
1122          (pthread_cond_t *cond, pthread_mutex_t *mutex,
1123           const struct timespec *timeout),
1124          (cond, mutex, timeout));
1125PTH_FUNCS(int, condZureltimedwait, pthread_cond_timedwait_intercept,
1126          (pthread_cond_t *cond, pthread_mutex_t *mutex,
1127           const struct timespec *timeout),
1128          (cond, mutex, timeout));
1129#endif /* VGO_solaris */
1130
1131// NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
1132// pthread_cond_signal_thread_np(). The former accepts one argument; the latter
1133// two. Intercepting all pthread_cond_signal* functions will cause only one
1134// argument to be passed to pthread_cond_signal_np() and hence will cause this
1135// last function to crash.
1136
1137static __always_inline
1138int pthread_cond_signal_intercept(pthread_cond_t* cond)
1139{
1140   int   ret;
1141   OrigFn fn;
1142   VALGRIND_GET_ORIG_FN(fn);
1143   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_SIGNAL,
1144                                   cond, 0, 0, 0, 0);
1145   CALL_FN_W_W(ret, fn, cond);
1146   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_SIGNAL,
1147                                   cond, 0, 0, 0, 0);
1148   return ret;
1149}
1150
1151#if defined(VGO_solaris)
1152/* On Solaris, pthread_cond_signal is a weak alias to cond_signal. */
1153PTH_FUNCS(int, condZusignal, pthread_cond_signal_intercept,
1154          (pthread_cond_t *cond), (cond));
1155#else
1156PTH_FUNCS(int, pthreadZucondZusignal, pthread_cond_signal_intercept,
1157          (pthread_cond_t* cond), (cond));
1158#endif /* VGO_solaris */
1159
1160static __always_inline
1161int pthread_cond_broadcast_intercept(pthread_cond_t* cond)
1162{
1163   int   ret;
1164   OrigFn fn;
1165   VALGRIND_GET_ORIG_FN(fn);
1166   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_BROADCAST,
1167                                   cond, 0, 0, 0, 0);
1168   CALL_FN_W_W(ret, fn, cond);
1169   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_BROADCAST,
1170                                   cond, 0, 0, 0, 0);
1171   return ret;
1172}
1173
1174#if defined(VGO_solaris)
1175/* On Solaris, pthread_cond_broadcast is a weak alias to cond_broadcast. */
1176PTH_FUNCS(int, condZubroadcast, pthread_cond_broadcast_intercept,
1177          (pthread_cond_t *cond), (cond));
1178#else
1179PTH_FUNCS(int, pthreadZucondZubroadcast, pthread_cond_broadcast_intercept,
1180          (pthread_cond_t* cond), (cond));
1181#endif /* VGO_solaris */
1182
1183#if defined(HAVE_PTHREAD_SPIN_LOCK) \
1184    && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1185static __always_inline
1186int pthread_spin_init_intercept(pthread_spinlock_t *spinlock, int pshared)
1187{
1188   int ret;
1189   OrigFn fn;
1190   VALGRIND_GET_ORIG_FN(fn);
1191   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
1192                                   spinlock, 0, 0, 0, 0);
1193   CALL_FN_W_WW(ret, fn, spinlock, pshared);
1194   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
1195                                   spinlock, 0, 0, 0, 0);
1196   return ret;
1197}
1198
1199PTH_FUNCS(int, pthreadZuspinZuinit, pthread_spin_init_intercept,
1200          (pthread_spinlock_t *spinlock, int pshared), (spinlock, pshared));
1201
1202static __always_inline
1203int pthread_spin_destroy_intercept(pthread_spinlock_t *spinlock)
1204{
1205   int ret;
1206   OrigFn fn;
1207   VALGRIND_GET_ORIG_FN(fn);
1208   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
1209                                   spinlock, 0, 0, 0, 0);
1210   CALL_FN_W_W(ret, fn, spinlock);
1211   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
1212                                   spinlock, mutex_type_spinlock, 0, 0, 0);
1213   return ret;
1214}
1215
1216PTH_FUNCS(int, pthreadZuspinZudestroy, pthread_spin_destroy_intercept,
1217          (pthread_spinlock_t *spinlock), (spinlock));
1218
1219static __always_inline
1220int pthread_spin_lock_intercept(pthread_spinlock_t *spinlock)
1221{
1222   int   ret;
1223   OrigFn fn;
1224   VALGRIND_GET_ORIG_FN(fn);
1225   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
1226                                   spinlock, mutex_type_spinlock, 0, 0, 0);
1227   CALL_FN_W_W(ret, fn, spinlock);
1228   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
1229                                   spinlock, ret == 0, 0, 0, 0);
1230   return ret;
1231}
1232
1233PTH_FUNCS(int, pthreadZuspinZulock, pthread_spin_lock_intercept,
1234          (pthread_spinlock_t *spinlock), (spinlock));
1235
1236static __always_inline
1237int pthread_spin_trylock_intercept(pthread_spinlock_t *spinlock)
1238{
1239   int   ret;
1240   OrigFn fn;
1241   VALGRIND_GET_ORIG_FN(fn);
1242   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
1243                                   spinlock, mutex_type_spinlock, 0, 0, 0);
1244   CALL_FN_W_W(ret, fn, spinlock);
1245   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
1246                                   spinlock, ret == 0, 0, 0, 0);
1247   return ret;
1248}
1249
1250PTH_FUNCS(int, pthreadZuspinZutrylock, pthread_spin_trylock_intercept,
1251          (pthread_spinlock_t *spinlock), (spinlock));
1252
1253static __always_inline
1254int pthread_spin_unlock_intercept(pthread_spinlock_t *spinlock)
1255{
1256   int   ret;
1257   OrigFn fn;
1258   VALGRIND_GET_ORIG_FN(fn);
1259   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
1260                                   spinlock, mutex_type_spinlock, 0, 0, 0);
1261   CALL_FN_W_W(ret, fn, spinlock);
1262   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
1263                                   spinlock, 0, 0, 0, 0);
1264   return ret;
1265}
1266
1267PTH_FUNCS(int, pthreadZuspinZuunlock, pthread_spin_unlock_intercept,
1268          (pthread_spinlock_t *spinlock), (spinlock));
1269#endif   // HAVE_PTHREAD_SPIN_LOCK
1270
1271
1272#if defined(HAVE_PTHREAD_BARRIER_INIT)
1273static __always_inline
1274int pthread_barrier_init_intercept(pthread_barrier_t* barrier,
1275                                   const pthread_barrierattr_t* attr,
1276                                   unsigned count)
1277{
1278   int   ret;
1279   OrigFn fn;
1280   VALGRIND_GET_ORIG_FN(fn);
1281   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_INIT,
1282                                   barrier, pthread_barrier, count, 0, 0);
1283   CALL_FN_W_WWW(ret, fn, barrier, attr, count);
1284   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_INIT,
1285                                   barrier, pthread_barrier, 0, 0, 0);
1286   return ret;
1287}
1288
1289PTH_FUNCS(int, pthreadZubarrierZuinit, pthread_barrier_init_intercept,
1290          (pthread_barrier_t* barrier, const pthread_barrierattr_t* attr,
1291           unsigned count), (barrier, attr, count));
1292
1293static __always_inline
1294int pthread_barrier_destroy_intercept(pthread_barrier_t* barrier)
1295{
1296   int   ret;
1297   OrigFn fn;
1298   VALGRIND_GET_ORIG_FN(fn);
1299   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_DESTROY,
1300                                   barrier, pthread_barrier, 0, 0, 0);
1301   CALL_FN_W_W(ret, fn, barrier);
1302   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_DESTROY,
1303                                   barrier, pthread_barrier, 0, 0, 0);
1304   return ret;
1305}
1306
1307PTH_FUNCS(int, pthreadZubarrierZudestroy, pthread_barrier_destroy_intercept,
1308          (pthread_barrier_t* barrier), (barrier));
1309
1310static __always_inline
1311int pthread_barrier_wait_intercept(pthread_barrier_t* barrier)
1312{
1313   int   ret;
1314   OrigFn fn;
1315   VALGRIND_GET_ORIG_FN(fn);
1316   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_WAIT,
1317                                   barrier, pthread_barrier, 0, 0, 0);
1318   CALL_FN_W_W(ret, fn, barrier);
1319   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_WAIT,
1320                              barrier, pthread_barrier,
1321                              ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD,
1322                              ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
1323   return ret;
1324}
1325
1326PTH_FUNCS(int, pthreadZubarrierZuwait, pthread_barrier_wait_intercept,
1327          (pthread_barrier_t* barrier), (barrier));
1328#endif   // HAVE_PTHREAD_BARRIER_INIT
1329
1330
1331static __always_inline
1332int sem_init_intercept(sem_t *sem, int pshared, unsigned int value)
1333{
1334   int   ret;
1335   OrigFn fn;
1336   VALGRIND_GET_ORIG_FN(fn);
1337   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT,
1338                                   sem, pshared, value, 0, 0);
1339   CALL_FN_W_WWW(ret, fn, sem, pshared, value);
1340   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT,
1341                                   sem, 0, 0, 0, 0);
1342   return ret;
1343}
1344
1345PTH_FUNCS(int, semZuinit, sem_init_intercept,
1346          (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
1347
1348#if defined(VGO_solaris)
1349static __always_inline
1350int sema_init_intercept(sema_t *sem, unsigned int value, int type, void *arg)
1351{
1352   int   ret;
1353   OrigFn fn;
1354   VALGRIND_GET_ORIG_FN(fn);
1355   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT,
1356                                   sem, type == USYNC_PROCESS ? 1 : 0,
1357                                   value, 0, 0);
1358   CALL_FN_W_WWWW(ret, fn, sem, value, type, arg);
1359   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT,
1360                                   sem, 0, 0, 0, 0);
1361   return ret;
1362}
1363
1364PTH_FUNCS(int, semaZuinit, sema_init_intercept,
1365          (sema_t *sem, unsigned int value, int type, void *arg),
1366          (sem, value, type, arg));
1367#endif /* VGO_solaris */
1368
1369static __always_inline
1370int sem_destroy_intercept(sem_t *sem)
1371{
1372   int   ret;
1373   OrigFn fn;
1374   VALGRIND_GET_ORIG_FN(fn);
1375   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_DESTROY,
1376                                   sem, 0, 0, 0, 0);
1377   CALL_FN_W_W(ret, fn, sem);
1378   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_DESTROY,
1379                                   sem, 0, 0, 0, 0);
1380   return ret;
1381}
1382
1383PTH_FUNCS(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1384#if defined(VGO_solaris)
1385PTH_FUNCS(int, semaZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1386#endif /* VGO_solaris */
1387
1388static __always_inline
1389sem_t* sem_open_intercept(const char *name, int oflag, mode_t mode,
1390                          unsigned int value)
1391{
1392   sem_t *ret;
1393   OrigFn fn;
1394   VALGRIND_GET_ORIG_FN(fn);
1395   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_OPEN,
1396                                   name, oflag, mode, value, 0);
1397   CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value);
1398   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_OPEN,
1399                                   ret != SEM_FAILED ? ret : 0,
1400                                   name, oflag, mode, value);
1401   return ret;
1402}
1403
1404PTH_FUNCS(sem_t *, semZuopen, sem_open_intercept,
1405          (const char *name, int oflag, mode_t mode, unsigned int value),
1406          (name, oflag, mode, value));
1407
1408static __always_inline int sem_close_intercept(sem_t *sem)
1409{
1410   int   ret;
1411   OrigFn fn;
1412   VALGRIND_GET_ORIG_FN(fn);
1413   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_CLOSE,
1414                                   sem, 0, 0, 0, 0);
1415   CALL_FN_W_W(ret, fn, sem);
1416   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_CLOSE,
1417                                   sem, 0, 0, 0, 0);
1418   return ret;
1419}
1420
1421PTH_FUNCS(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
1422
1423static __always_inline int sem_wait_intercept(sem_t *sem)
1424{
1425   int   ret;
1426   OrigFn fn;
1427   VALGRIND_GET_ORIG_FN(fn);
1428   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1429                                   sem, 0, 0, 0, 0);
1430   CALL_FN_W_W(ret, fn, sem);
1431   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1432                                   sem, ret == 0, 0, 0, 0);
1433   return ret;
1434}
1435
1436PTH_FUNCS(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1437#if defined(VGO_solaris)
1438PTH_FUNCS(int, semaZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1439#endif /* VGO_solaris */
1440
1441static __always_inline int sem_trywait_intercept(sem_t *sem)
1442{
1443   int   ret;
1444   OrigFn fn;
1445   VALGRIND_GET_ORIG_FN(fn);
1446   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1447                                   sem, 0, 0, 0, 0);
1448   CALL_FN_W_W(ret, fn, sem);
1449   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1450                                   sem, ret == 0, 0, 0, 0);
1451   return ret;
1452}
1453
1454PTH_FUNCS(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1455#if defined(VGO_solaris)
1456PTH_FUNCS(int, semaZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1457#endif /* VGO_solaris */
1458
1459static __always_inline
1460int sem_timedwait_intercept(sem_t *sem, const struct timespec *abs_timeout)
1461{
1462   int   ret;
1463   OrigFn fn;
1464   VALGRIND_GET_ORIG_FN(fn);
1465   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1466                                   sem, 0, 0, 0, 0);
1467   CALL_FN_W_WW(ret, fn, sem, abs_timeout);
1468   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1469                                   sem, ret == 0, 0, 0, 0);
1470   return ret;
1471}
1472
1473PTH_FUNCS(int, semZutimedwait, sem_timedwait_intercept,
1474          (sem_t *sem, const struct timespec *abs_timeout),
1475          (sem, abs_timeout));
1476#if defined(VGO_solaris)
1477PTH_FUNCS(int, semaZutimedwait, sem_timedwait_intercept,
1478          (sem_t *sem, const struct timespec *timeout),
1479          (sem, timeout));
1480PTH_FUNCS(int, semaZureltimedwait, sem_timedwait_intercept,
1481          (sem_t *sem, const struct timespec *timeout),
1482          (sem, timeout));
1483#endif /* VGO_solaris */
1484
1485static __always_inline int sem_post_intercept(sem_t *sem)
1486{
1487   int   ret;
1488   OrigFn fn;
1489   VALGRIND_GET_ORIG_FN(fn);
1490   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_POST,
1491                                   sem, 0, 0, 0, 0);
1492   CALL_FN_W_W(ret, fn, sem);
1493   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_POST,
1494                                   sem, ret == 0, 0, 0, 0);
1495   return ret;
1496}
1497
1498PTH_FUNCS(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
1499#if defined(VGO_solaris)
1500PTH_FUNCS(int, semaZupost, sem_post_intercept, (sem_t *sem), (sem));
1501#endif /* VGO_solaris */
1502
1503/* Android's pthread.h doesn't say anything about rwlocks, hence these
1504   functions have to be conditionally compiled. */
1505#if defined(HAVE_PTHREAD_RWLOCK_T)
1506
1507static __always_inline
1508int pthread_rwlock_init_intercept(pthread_rwlock_t* rwlock,
1509                                  const pthread_rwlockattr_t* attr)
1510{
1511   int   ret;
1512   OrigFn fn;
1513   VALGRIND_GET_ORIG_FN(fn);
1514   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT,
1515                                   rwlock, 0, 0, 0, 0);
1516   CALL_FN_W_WW(ret, fn, rwlock, attr);
1517   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT,
1518                                   rwlock, 0, 0, 0, 0);
1519   return ret;
1520}
1521
1522PTH_FUNCS(int,
1523          pthreadZurwlockZuinit, pthread_rwlock_init_intercept,
1524          (pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr),
1525          (rwlock, attr));
1526
1527#if defined(VGO_solaris)
1528static __always_inline
1529int rwlock_init_intercept(rwlock_t *rwlock, int type, void *arg)
1530{
1531   int   ret;
1532   OrigFn fn;
1533   VALGRIND_GET_ORIG_FN(fn);
1534   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT,
1535                                   rwlock, 0, 0, 0, 0);
1536   CALL_FN_W_WWW(ret, fn, rwlock, type, arg);
1537   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT,
1538                                   rwlock, 0, 0, 0, 0);
1539   return ret;
1540}
1541
1542PTH_FUNCS(int, rwlockZuinit, rwlock_init_intercept,
1543          (rwlock_t *rwlock, int type, void *arg),
1544          (rwlock, type, arg));
1545#endif /* VGO_solaris */
1546
1547static __always_inline
1548int pthread_rwlock_destroy_intercept(pthread_rwlock_t* rwlock)
1549{
1550   int   ret;
1551   OrigFn fn;
1552   VALGRIND_GET_ORIG_FN(fn);
1553   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_DESTROY,
1554                                   rwlock, 0, 0, 0, 0);
1555   CALL_FN_W_W(ret, fn, rwlock);
1556   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_DESTROY,
1557                                   rwlock, 0, 0, 0, 0);
1558   return ret;
1559}
1560
1561#if defined(VGO_solaris)
1562/* On Solaris, pthread_rwlock_destroy is a weak alias to rwlock_destroy. */
1563PTH_FUNCS(int,
1564          rwlockZudestroy, pthread_rwlock_destroy_intercept,
1565          (pthread_rwlock_t *rwlock), (rwlock));
1566#else
1567PTH_FUNCS(int,
1568          pthreadZurwlockZudestroy, pthread_rwlock_destroy_intercept,
1569          (pthread_rwlock_t* rwlock), (rwlock));
1570#endif /* VGO_solaris */
1571
1572static __always_inline
1573int pthread_rwlock_rdlock_intercept(pthread_rwlock_t* rwlock)
1574{
1575   int   ret;
1576   OrigFn fn;
1577   VALGRIND_GET_ORIG_FN(fn);
1578   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1579                                   rwlock, 0, 0, 0, 0);
1580   CALL_FN_W_W(ret, fn, rwlock);
1581   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1582                                   rwlock, ret == 0, 0, 0, 0);
1583   return ret;
1584}
1585
1586#if defined(VGO_solaris)
1587/* On Solaris, pthread_rwlock_rdlock is a weak alias to rw_rdlock. */
1588PTH_FUNCS(int,
1589          rwZurdlock, pthread_rwlock_rdlock_intercept,
1590          (pthread_rwlock_t *rwlock), (rwlock));
1591#else
1592PTH_FUNCS(int,
1593          pthreadZurwlockZurdlock, pthread_rwlock_rdlock_intercept,
1594          (pthread_rwlock_t* rwlock), (rwlock));
1595#endif /* VGO_solaris */
1596
1597#if defined(VGO_solaris)
1598/* Internal to libc. */
1599static __always_inline
1600void lrw_rdlock_intercept(rwlock_t *rwlock)
1601{
1602   OrigFn fn;
1603   VALGRIND_GET_ORIG_FN(fn);
1604   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1605                                   rwlock, 0, 0, 0, 0);
1606   CALL_FN_v_W(fn, rwlock);
1607   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1608                                   rwlock, True /* took_lock */, 0, 0, 0);
1609}
1610
1611PTH_FUNCS(void, lrwZurdlock, lrw_rdlock_intercept,
1612          (rwlock_t *rwlock), (rwlock));
1613#endif /* VGO_solaris */
1614
1615static __always_inline
1616int pthread_rwlock_wrlock_intercept(pthread_rwlock_t* rwlock)
1617{
1618   int   ret;
1619   OrigFn fn;
1620   VALGRIND_GET_ORIG_FN(fn);
1621   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1622                                   rwlock, 0, 0, 0, 0);
1623   CALL_FN_W_W(ret, fn, rwlock);
1624   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1625                                   rwlock, ret == 0, 0, 0, 0);
1626   return ret;
1627}
1628
1629#if defined(VGO_solaris)
1630/* On Solaris, pthread_rwlock_wrlock is a weak alias to rw_wrlock. */
1631PTH_FUNCS(int,
1632          rwZuwrlock, pthread_rwlock_wrlock_intercept,
1633          (pthread_rwlock_t *rwlock), (rwlock));
1634#else
1635PTH_FUNCS(int,
1636          pthreadZurwlockZuwrlock, pthread_rwlock_wrlock_intercept,
1637          (pthread_rwlock_t* rwlock), (rwlock));
1638#endif /* VGO_solaris */
1639
1640#if defined(VGO_solaris)
1641/* Internal to libc. */
1642static __always_inline
1643void lrw_wrlock_intercept(rwlock_t *rwlock)
1644{
1645   OrigFn fn;
1646   VALGRIND_GET_ORIG_FN(fn);
1647   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1648                                   rwlock, 0, 0, 0, 0);
1649   CALL_FN_v_W(fn, rwlock);
1650   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1651                                   rwlock, True /* took_lock */, 0, 0, 0);
1652}
1653
1654PTH_FUNCS(void, lrwZuwrlock, lrw_wrlock_intercept,
1655          (rwlock_t *rwlock), (rwlock));
1656#endif /* VGO_solaris */
1657
1658static __always_inline
1659int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t* rwlock,
1660                                         const struct timespec *timeout)
1661{
1662   int   ret;
1663   OrigFn fn;
1664   VALGRIND_GET_ORIG_FN(fn);
1665   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1666                                   rwlock, 0, 0, 0, 0);
1667   CALL_FN_W_WW(ret, fn, rwlock, timeout);
1668   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1669                                   rwlock, ret == 0, 0, 0, 0);
1670   return ret;
1671}
1672
1673PTH_FUNCS(int,
1674          pthreadZurwlockZutimedrdlock, pthread_rwlock_timedrdlock_intercept,
1675          (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1676          (rwlock, timeout));
1677#if defined(VGO_solaris)
1678PTH_FUNCS(int, pthreadZurwlockZureltimedrdlockZunp,
1679          pthread_rwlock_timedrdlock_intercept,
1680          (pthread_rwlock_t *rwlock, const struct timespec *timeout),
1681          (rwlock, timeout));
1682#endif /* VGO_solaris */
1683
1684static __always_inline
1685int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t* rwlock,
1686                                         const struct timespec *timeout)
1687{
1688   int   ret;
1689   OrigFn fn;
1690   VALGRIND_GET_ORIG_FN(fn);
1691   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1692                                   rwlock, 0, 0, 0, 0);
1693   CALL_FN_W_WW(ret, fn, rwlock, timeout);
1694   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1695                                   rwlock, ret == 0, 0, 0, 0);
1696   return ret;
1697}
1698
1699PTH_FUNCS(int,
1700          pthreadZurwlockZutimedwrlock, pthread_rwlock_timedwrlock_intercept,
1701          (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1702          (rwlock, timeout));
1703#if defined(VGO_solaris)
1704PTH_FUNCS(int, pthreadZurwlockZureltimedwrlockZunp,
1705          pthread_rwlock_timedwrlock_intercept,
1706          (pthread_rwlock_t *rwlock, const struct timespec *timeout),
1707          (rwlock, timeout));
1708#endif /* VGO_solaris */
1709
1710static __always_inline
1711int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t* rwlock)
1712{
1713   int   ret;
1714   OrigFn fn;
1715   VALGRIND_GET_ORIG_FN(fn);
1716   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1717                                   rwlock, 0, 0, 0, 0);
1718   CALL_FN_W_W(ret, fn, rwlock);
1719   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1720                                   rwlock, ret == 0, 0, 0, 0);
1721   return ret;
1722}
1723
1724#if defined(VGO_solaris)
1725/* On Solaris, pthread_rwlock_tryrdlock is a weak alias to rw_tryrdlock. */
1726PTH_FUNCS(int,
1727          rwZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1728          (pthread_rwlock_t *rwlock), (rwlock));
1729#else
1730PTH_FUNCS(int,
1731          pthreadZurwlockZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1732          (pthread_rwlock_t* rwlock), (rwlock));
1733#endif /* VGO_solaris */
1734
1735static __always_inline
1736int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t* rwlock)
1737{
1738   int   ret;
1739   OrigFn fn;
1740   VALGRIND_GET_ORIG_FN(fn);
1741   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1742                                   rwlock, 0, 0, 0, 0);
1743   CALL_FN_W_W(ret, fn, rwlock);
1744   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1745                                   rwlock, ret == 0, 0, 0, 0);
1746   return ret;
1747}
1748
1749#if defined(VGO_solaris)
1750/* On Solaris, pthread_rwlock_trywrlock is a weak alias to rw_trywrlock. */
1751PTH_FUNCS(int,
1752          rwZutrywrlock, pthread_rwlock_trywrlock_intercept,
1753          (pthread_rwlock_t *rwlock), (rwlock));
1754#else
1755PTH_FUNCS(int,
1756          pthreadZurwlockZutrywrlock, pthread_rwlock_trywrlock_intercept,
1757          (pthread_rwlock_t* rwlock), (rwlock));
1758#endif /* VGO_solaris */
1759
1760static __always_inline
1761int pthread_rwlock_unlock_intercept(pthread_rwlock_t* rwlock)
1762{
1763   int   ret;
1764   OrigFn fn;
1765   VALGRIND_GET_ORIG_FN(fn);
1766   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_UNLOCK,
1767                                   rwlock, 0, 0, 0, 0);
1768   CALL_FN_W_W(ret, fn, rwlock);
1769   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_UNLOCK,
1770                                   rwlock, ret == 0, 0, 0, 0);
1771   return ret;
1772}
1773
1774#if defined(VGO_solaris)
1775/* On Solaris, pthread_rwlock_unlock is a weak alias to rw_unlock. */
1776PTH_FUNCS(int,
1777          rwZuunlock, pthread_rwlock_unlock_intercept,
1778          (pthread_rwlock_t *rwlock), (rwlock));
1779#else
1780PTH_FUNCS(int,
1781          pthreadZurwlockZuunlock, pthread_rwlock_unlock_intercept,
1782          (pthread_rwlock_t* rwlock), (rwlock));
1783#endif /* VGO_solaris */
1784
1785#endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
1786