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-2012 Bart Van Assche <bvanassche@acm.org>.
9
10  This program is free software; you can redistribute it and/or
11  modify it under the terms of the GNU General Public License as
12  published by the Free Software Foundation; either version 2 of the
13  License, or (at your option) any later version.
14
15  This program is distributed in the hope that it will be useful, but
16  WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  General Public License for more details.
19
20  You should have received a copy of the GNU General Public License
21  along with this program; if not, write to the Free Software
22  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
23  02111-1307, USA.
24
25  The GNU General Public License is contained in the file COPYING.
26*/
27
28/* ---------------------------------------------------------------------
29   ALL THE CODE IN THIS FILE RUNS ON THE SIMULATED CPU.
30
31   These functions are not called directly - they're the targets of code
32   redirection or load notifications (see pub_core_redir.h for info).
33   They're named weirdly so that the intercept code can find them when the
34   shared object is initially loaded.
35
36   Note that this filename has the "drd_" prefix because it can appear
37   in stack traces, and the "drd_" makes it a little clearer that it
38   originates from Valgrind.
39   ------------------------------------------------------------------ */
40
41/*
42 * Define _GNU_SOURCE to make sure that pthread_spinlock_t is available when
43 * compiling with older glibc versions (2.3 or before).
44 */
45#ifndef _GNU_SOURCE
46#define _GNU_SOURCE
47#endif
48
49#include <assert.h>         /* assert() */
50#include <errno.h>
51#include <pthread.h>        /* pthread_mutex_t */
52#include <semaphore.h>      /* sem_t */
53#include <stdint.h>         /* uintptr_t */
54#include <stdio.h>          /* fprintf() */
55#include <stdlib.h>         /* malloc(), free() */
56#include <unistd.h>         /* confstr() */
57#include "config.h"         /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP etc. */
58#ifdef HAVE_USABLE_LINUX_FUTEX_H
59#include <asm/unistd.h>     /* __NR_futex */
60#include <linux/futex.h>    /* FUTEX_WAIT */
61#ifndef FUTEX_PRIVATE_FLAG
62#define FUTEX_PRIVATE_FLAG 0
63#endif
64#endif
65#include "drd_basics.h"     /* DRD_() */
66#include "drd_clientreq.h"
67#include "pub_tool_redir.h" /* VG_WRAP_FUNCTION_ZZ() */
68
69
70/*
71 * Notes regarding thread creation:
72 * - sg_init() runs on the context of the created thread and copies the vector
73 *   clock of the creator thread. This only works reliably if the creator
74 *   thread waits until this copy has been performed.
75 * - DRD_(thread_compute_minimum_vc)() does not take the vector clocks into
76 *   account that are involved in thread creation and for which the
77 *   corresponding thread has not yet been created. So not waiting until the
78 *   created thread has been started would make it possible that segments get
79 *   discarded that should not yet be discarded. Or: some data races are not
80 *   detected.
81 */
82
83/**
84 * Macro for generating a Valgrind interception function.
85 * @param[in] ret_ty Return type of the function to be generated.
86 * @param[in] zf Z-encoded name of the interception function.
87 * @param[in] implf Name of the function that implements the intercept.
88 * @param[in] arg_decl Argument declaration list enclosed in parentheses.
89 * @param[in] argl Argument list enclosed in parentheses.
90 */
91#ifdef VGO_darwin
92static int never_true;
93#define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl)                    \
94   ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl;     \
95   ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl      \
96   {									\
97      ret_ty pth_func_result = implf argl;				\
98      /* Apparently inserting a function call in wrapper functions */   \
99      /* is sufficient to avoid misaligned stack errors.           */	\
100      if (never_true)							\
101	 fflush(stdout);						\
102      return pth_func_result;						\
103   }
104#else
105#define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl)                    \
106   ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl;     \
107   ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl      \
108   { return implf argl; }
109#endif
110
111/**
112 * Macro for generating three Valgrind interception functions: one with the
113 * Z-encoded name zf, one with ZAZa ("@*") appended to the name zf and one
114 * with ZDZa ("$*") appended to the name zf. The second generated interception
115 * function will intercept versioned symbols on Linux, and the third will
116 * intercept versioned symbols on Darwin.
117 */
118#define PTH_FUNCS(ret_ty, zf, implf, argl_decl, argl)           \
119   PTH_FUNC(ret_ty, zf, implf, argl_decl, argl);                \
120   PTH_FUNC(ret_ty, zf ## ZAZa, implf, argl_decl, argl);        \
121   PTH_FUNC(ret_ty, zf ## ZDZa, implf, argl_decl, argl);
122
123/*
124 * Not inlining one of the intercept functions will cause the regression
125 * tests to fail because this would cause an additional stackfram to appear
126 * in the output. The __always_inline macro guarantees that inlining will
127 * happen, even when compiling with optimization disabled.
128 */
129#undef __always_inline /* since already defined in <cdefs.h> */
130#if __GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 2
131#define __always_inline __inline__ __attribute__((always_inline))
132#else
133#define __always_inline __inline__
134#endif
135
136/* Local data structures. */
137
138typedef struct {
139   pthread_mutex_t mutex;
140   int counter;
141   int waiters;
142} DrdSema;
143
144typedef struct
145{
146   void* (*start)(void*);
147   void* arg;
148   int   detachstate;
149   DrdSema* wrapper_started;
150} DrdPosixThreadArgs;
151
152
153/* Local function declarations. */
154
155static void DRD_(init)(void) __attribute__((constructor));
156static void DRD_(check_threading_library)(void);
157static void DRD_(set_main_thread_state)(void);
158static void DRD_(sema_init)(DrdSema* sema);
159static void DRD_(sema_destroy)(DrdSema* sema);
160static void DRD_(sema_down)(DrdSema* sema);
161static void DRD_(sema_up)(DrdSema* sema);
162
163
164/* Function definitions. */
165
166/**
167 * Shared library initialization function. The function init() is called after
168 * dlopen() has loaded the shared library with DRD client intercepts because
169 * the constructor attribute was specified in the declaration of this function.
170 * Note: do specify the -nostdlib option to gcc when linking this code into a
171 * shared library because doing so would cancel the effect of the constructor
172 * attribute ! Using the gcc option -nodefaultlibs is fine because this last
173 * option preserves the shared library initialization code that calls
174 * constructor and destructor functions.
175 */
176static void DRD_(init)(void)
177{
178   DRD_(check_threading_library)();
179   DRD_(set_main_thread_state)();
180}
181
182static void DRD_(sema_init)(DrdSema* sema)
183{
184   DRD_IGNORE_VAR(sema->counter);
185   pthread_mutex_init(&sema->mutex, NULL);
186   sema->counter = 0;
187   sema->waiters = 0;
188}
189
190static void DRD_(sema_destroy)(DrdSema* sema)
191{
192   pthread_mutex_destroy(&sema->mutex);
193}
194
195static void DRD_(sema_down)(DrdSema* sema)
196{
197   int res = ENOSYS;
198
199   pthread_mutex_lock(&sema->mutex);
200   if (sema->counter == 0) {
201      sema->waiters++;
202      while (sema->counter == 0) {
203         pthread_mutex_unlock(&sema->mutex);
204#ifdef HAVE_USABLE_LINUX_FUTEX_H
205         if (syscall(__NR_futex, (UWord)&sema->counter,
206                     FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0) == 0)
207            res = 0;
208         else
209            res = errno;
210#endif
211         /*
212          * Invoke sched_yield() on non-Linux systems, if the futex syscall has
213          * not been invoked or if this code has been built on a Linux system
214          * where __NR_futex is defined and is run on a Linux system that does
215          * not support the futex syscall.
216          */
217         if (res != 0 && res != EWOULDBLOCK)
218            sched_yield();
219         pthread_mutex_lock(&sema->mutex);
220      }
221      sema->waiters--;
222   }
223   sema->counter--;
224   pthread_mutex_unlock(&sema->mutex);
225}
226
227static void DRD_(sema_up)(DrdSema* sema)
228{
229   pthread_mutex_lock(&sema->mutex);
230   sema->counter++;
231#ifdef HAVE_USABLE_LINUX_FUTEX_H
232   if (sema->waiters > 0)
233      syscall(__NR_futex, (UWord)&sema->counter,
234              FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1);
235#endif
236   pthread_mutex_unlock(&sema->mutex);
237}
238
239/**
240 * POSIX threads and DRD each have their own mutex type identification.
241 * Convert POSIX threads' mutex type to DRD's mutex type. In the code below
242 * if-statements are used to test the value of 'kind' instead of a switch
243 * statement because some of the PTHREAD_MUTEX_ macro's may have the same
244 * value.
245 */
246static MutexT DRD_(pthread_to_drd_mutex_type)(const int kind)
247{
248   if (kind == PTHREAD_MUTEX_RECURSIVE)
249      return mutex_type_recursive_mutex;
250   else if (kind == PTHREAD_MUTEX_ERRORCHECK)
251      return mutex_type_errorcheck_mutex;
252   else if (kind == PTHREAD_MUTEX_NORMAL)
253      return mutex_type_default_mutex;
254   else if (kind == PTHREAD_MUTEX_DEFAULT)
255      return mutex_type_default_mutex;
256#if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
257   else if (kind == PTHREAD_MUTEX_ADAPTIVE_NP)
258      return mutex_type_default_mutex;
259#endif
260   else
261   {
262      return mutex_type_invalid_mutex;
263   }
264}
265
266#define IS_ALIGNED(p) (((uintptr_t)(p) & (sizeof(*(p)) - 1)) == 0)
267
268/**
269 * Read the mutex type stored in the client memory used for the mutex
270 * implementation.
271 *
272 * @note This function depends on the implementation of the POSIX threads
273 *   library -- the POSIX standard does not define the name of the member in
274 *   which the mutex type is stored.
275 * @note The function mutex_type() has been declared inline in order
276 *   to avoid that it shows up in call stacks (drd/tests/...exp* files).
277 * @note glibc stores the mutex type in the lowest two bits, and uses the
278 *   higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
279 *   PTHREAD_MUTEXATTR_FLAG_PSHARED.
280 */
281static __always_inline MutexT DRD_(mutex_type)(pthread_mutex_t* mutex)
282{
283#if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
284   /* glibc + LinuxThreads. */
285   if (IS_ALIGNED(&mutex->__m_kind))
286   {
287      const int kind = mutex->__m_kind & 3;
288      return DRD_(pthread_to_drd_mutex_type)(kind);
289   }
290#elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
291   /* glibc + NPTL. */
292   if (IS_ALIGNED(&mutex->__data.__kind))
293   {
294      const int kind = mutex->__data.__kind & 3;
295      return DRD_(pthread_to_drd_mutex_type)(kind);
296   }
297#else
298   /*
299    * Another POSIX threads implementation. The mutex type won't be printed
300    * when enabling --trace-mutex=yes.
301    */
302#endif
303   return mutex_type_unknown;
304}
305
306/**
307 * Tell DRD whether 'tid' is a joinable thread or a detached thread.
308 */
309static void DRD_(set_joinable)(const pthread_t tid, const int joinable)
310{
311   assert(joinable == 0 || joinable == 1);
312   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_JOINABLE,
313                                   tid, joinable, 0, 0, 0);
314}
315
316/** Tell DRD that the calling thread is about to enter pthread_create(). */
317static __always_inline void DRD_(entering_pthread_create)(void)
318{
319   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__ENTERING_PTHREAD_CREATE,
320                                   0, 0, 0, 0, 0);
321}
322
323/** Tell DRD that the calling thread has left pthread_create(). */
324static __always_inline void DRD_(left_pthread_create)(void)
325{
326   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LEFT_PTHREAD_CREATE,
327                                   0, 0, 0, 0, 0);
328}
329
330/**
331 * Entry point for newly created threads. This function is called from the
332 * thread created by pthread_create().
333 */
334static void* DRD_(thread_wrapper)(void* arg)
335{
336   DrdPosixThreadArgs* arg_ptr;
337   DrdPosixThreadArgs arg_copy;
338
339   arg_ptr = (DrdPosixThreadArgs*)arg;
340   arg_copy = *arg_ptr;
341
342   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
343                                   pthread_self(), 0, 0, 0, 0);
344
345   DRD_(set_joinable)(pthread_self(),
346                      arg_copy.detachstate == PTHREAD_CREATE_JOINABLE);
347
348   /*
349    * Only set 'wrapper_started' after VG_USERREQ__SET_PTHREADID and
350    * DRD_(set_joinable)() have been invoked to avoid a race with
351    * a pthread_detach() invocation for this thread from another thread.
352    */
353   DRD_(sema_up)(arg_copy.wrapper_started);
354
355   return (arg_copy.start)(arg_copy.arg);
356}
357
358/**
359 * Return 1 if the LinuxThreads implementation of POSIX Threads has been
360 * detected, and 0 otherwise.
361 *
362 * @see For more information about the confstr() function, see also
363 * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
364 */
365static int DRD_(detected_linuxthreads)(void)
366{
367#if defined(linux)
368#if defined(_CS_GNU_LIBPTHREAD_VERSION)
369   /* Linux with a recent glibc. */
370   char buffer[256];
371   unsigned len;
372   len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
373   assert(len <= sizeof(buffer));
374   return len > 0 && buffer[0] == 'l';
375#else
376   /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
377   return 1;
378#endif
379#else
380   /* Another OS than Linux, hence no LinuxThreads. */
381   return 0;
382#endif
383}
384
385/**
386 * Stop and print an error message in case a non-supported threading
387 * library implementation (LinuxThreads) has been detected.
388 */
389static void DRD_(check_threading_library)(void)
390{
391   if (DRD_(detected_linuxthreads)())
392   {
393      if (getenv("LD_ASSUME_KERNEL"))
394      {
395         fprintf(stderr,
396"Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
397"the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
398"after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
399);
400      }
401      else
402      {
403         fprintf(stderr,
404"Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
405"the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
406"after having upgraded to a newer version of your Linux distribution.\n"
407"Giving up.\n"
408);
409      }
410      abort();
411   }
412}
413
414/**
415 * The main thread is the only thread not created by pthread_create().
416 * Update DRD's state information about the main thread.
417 */
418static void DRD_(set_main_thread_state)(void)
419{
420   // Make sure that DRD knows about the main thread's POSIX thread ID.
421   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
422                                   pthread_self(), 0, 0, 0, 0);
423}
424
425/*
426 * Note: as of today there exist three different versions of pthread_create
427 * in Linux:
428 * - pthread_create@GLIBC_2.0
429 * - pthread_create@@GLIBC_2.1
430 * - pthread_create@@GLIBC_2.2.5
431 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
432 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
433 * versions have been implemented. In any glibc version where more than one
434 * pthread_create function has been implemented, older versions call the
435 * newer versions. Or: the pthread_create* wrapper defined below can be
436 * called recursively. Any code in this wrapper should take this in account.
437 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
438 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
439 * See also the implementation of pthread_create@GLIBC_2.0 in
440 * glibc-2.9/nptl/pthread_create.c.
441 */
442
443static __always_inline
444int pthread_create_intercept(pthread_t* thread, const pthread_attr_t* attr,
445                             void* (*start)(void*), void* arg)
446{
447   int    ret;
448   OrigFn fn;
449   DrdSema wrapper_started;
450   DrdPosixThreadArgs thread_args;
451
452   VALGRIND_GET_ORIG_FN(fn);
453
454   DRD_(sema_init)(&wrapper_started);
455   thread_args.start           = start;
456   thread_args.arg             = arg;
457   thread_args.wrapper_started = &wrapper_started;
458   /*
459    * Find out whether the thread will be started as a joinable thread
460    * or as a detached thread. If no thread attributes have been specified,
461    * this means that the new thread will be started as a joinable thread.
462    */
463   thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
464   if (attr)
465   {
466      if (pthread_attr_getdetachstate(attr, &thread_args.detachstate) != 0)
467         assert(0);
468   }
469   assert(thread_args.detachstate == PTHREAD_CREATE_JOINABLE
470          || thread_args.detachstate == PTHREAD_CREATE_DETACHED);
471
472   DRD_(entering_pthread_create)();
473   CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), &thread_args);
474   DRD_(left_pthread_create)();
475
476   if (ret == 0) {
477      /* Wait until the thread wrapper started. */
478      DRD_(sema_down)(&wrapper_started);
479   }
480
481   DRD_(sema_destroy)(&wrapper_started);
482
483   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT,
484                                   pthread_self(), 0, 0, 0, 0);
485
486   return ret;
487}
488
489PTH_FUNCS(int, pthreadZucreate, pthread_create_intercept,
490          (pthread_t *thread, const pthread_attr_t *attr,
491           void *(*start) (void *), void *arg),
492          (thread, attr, start, arg));
493
494static __always_inline
495int pthread_join_intercept(pthread_t pt_joinee, void **thread_return)
496{
497   int      ret;
498   OrigFn   fn;
499
500   VALGRIND_GET_ORIG_FN(fn);
501   /*
502    * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
503    * implementation triggers a (false positive) race report.
504    */
505   ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
506   CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
507   if (ret == 0)
508   {
509      VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN,
510                                      pt_joinee, 0, 0, 0, 0);
511   }
512   ANNOTATE_IGNORE_READS_AND_WRITES_END();
513   return ret;
514}
515
516PTH_FUNCS(int, pthreadZujoin, pthread_join_intercept,
517          (pthread_t pt_joinee, void **thread_return),
518          (pt_joinee, thread_return));
519
520static __always_inline
521int pthread_detach_intercept(pthread_t pt_thread)
522{
523   int ret;
524   OrigFn fn;
525
526   VALGRIND_GET_ORIG_FN(fn);
527   CALL_FN_W_W(ret, fn, pt_thread);
528   DRD_(set_joinable)(pt_thread, 0);
529
530   return ret;
531}
532
533PTH_FUNCS(int, pthreadZudetach, pthread_detach_intercept,
534          (pthread_t thread), (thread));
535
536// Don't intercept pthread_cancel() because pthread_cancel_init() loads
537// libgcc.so. That library is loaded by calling _dl_open(). The function
538// dl_open_worker() looks up from which object the caller is calling in
539// GL(dn_ns)[]. Since the DRD intercepts are linked into vgpreload_drd-*.so
540// and since that object file is not loaded through glibc, glibc does not
541// have any information about that object. That results in the following
542// segmentation fault on at least Fedora 17 x86_64:
543//   Process terminating with default action of signal 11 (SIGSEGV)
544//    General Protection Fault
545//      at 0x4006B75: _dl_map_object_from_fd (dl-load.c:1580)
546//      by 0x4008312: _dl_map_object (dl-load.c:2355)
547//      by 0x4012FFB: dl_open_worker (dl-open.c:226)
548//      by 0x400ECB5: _dl_catch_error (dl-error.c:178)
549//      by 0x4012B2B: _dl_open (dl-open.c:652)
550//      by 0x5184511: do_dlopen (dl-libc.c:89)
551//      by 0x400ECB5: _dl_catch_error (dl-error.c:178)
552//      by 0x51845D1: __libc_dlopen_mode (dl-libc.c:48)
553//      by 0x4E4A703: pthread_cancel_init (unwind-forcedunwind.c:53)
554//      by 0x4E476F2: pthread_cancel (pthread_cancel.c:40)
555//      by 0x4C2C050: pthread_cancel (drd_pthread_intercepts.c:547)
556//      by 0x400B3A: main (bar_bad.c:83)
557#if 0
558// NOTE: be careful to intercept only pthread_cancel() and not
559// pthread_cancel_init() on Linux.
560
561static __always_inline
562int pthread_cancel_intercept(pthread_t pt_thread)
563{
564   int ret;
565   OrigFn fn;
566   VALGRIND_GET_ORIG_FN(fn);
567   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_THREAD_CANCEL,
568                                   pt_thread, 0, 0, 0, 0);
569   CALL_FN_W_W(ret, fn, pt_thread);
570   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_CANCEL,
571                                   pt_thread, ret==0, 0, 0, 0);
572   return ret;
573}
574
575PTH_FUNCS(int, pthreadZucancel, pthread_cancel_intercept,
576          (pthread_t thread), (thread))
577#endif
578
579static __always_inline
580int pthread_once_intercept(pthread_once_t *once_control,
581                           void (*init_routine)(void))
582{
583   int ret;
584   OrigFn fn;
585   VALGRIND_GET_ORIG_FN(fn);
586   /*
587    * Ignore any data races triggered by the implementation of pthread_once().
588    * Necessary for Darwin. This is not necessary for Linux but doesn't have
589    * any known adverse effects.
590    */
591   DRD_IGNORE_VAR(*once_control);
592   ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
593   CALL_FN_W_WW(ret, fn, once_control, init_routine);
594   ANNOTATE_IGNORE_READS_AND_WRITES_END();
595   DRD_STOP_IGNORING_VAR(*once_control);
596   return ret;
597}
598
599PTH_FUNCS(int, pthreadZuonce, pthread_once_intercept,
600          (pthread_once_t *once_control, void (*init_routine)(void)),
601          (once_control, init_routine));
602
603static __always_inline
604int pthread_mutex_init_intercept(pthread_mutex_t *mutex,
605                                 const pthread_mutexattr_t* attr)
606{
607   int ret;
608   OrigFn fn;
609   int mt;
610   VALGRIND_GET_ORIG_FN(fn);
611   mt = PTHREAD_MUTEX_DEFAULT;
612   if (attr)
613      pthread_mutexattr_gettype(attr, &mt);
614   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
615                                   mutex, DRD_(pthread_to_drd_mutex_type)(mt),
616                                   0, 0, 0);
617   CALL_FN_W_WW(ret, fn, mutex, attr);
618   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
619                                   mutex, 0, 0, 0, 0);
620   return ret;
621}
622
623PTH_FUNCS(int, pthreadZumutexZuinit, pthread_mutex_init_intercept,
624          (pthread_mutex_t *mutex, const pthread_mutexattr_t* attr),
625          (mutex, attr));
626
627static __always_inline
628int pthread_mutex_destroy_intercept(pthread_mutex_t* mutex)
629{
630   int ret;
631   OrigFn fn;
632   VALGRIND_GET_ORIG_FN(fn);
633   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
634                                   mutex, 0, 0, 0, 0);
635   CALL_FN_W_W(ret, fn, mutex);
636   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
637                                   mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
638   return ret;
639}
640
641PTH_FUNCS(int, pthreadZumutexZudestroy, pthread_mutex_destroy_intercept,
642          (pthread_mutex_t *mutex), (mutex));
643
644static __always_inline
645int pthread_mutex_lock_intercept(pthread_mutex_t* mutex)
646{
647   int   ret;
648   OrigFn fn;
649   VALGRIND_GET_ORIG_FN(fn);
650   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
651                                   mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
652   CALL_FN_W_W(ret, fn, mutex);
653   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
654                                   mutex, ret == 0, 0, 0, 0);
655   return ret;
656}
657
658PTH_FUNCS(int, pthreadZumutexZulock, pthread_mutex_lock_intercept,
659          (pthread_mutex_t *mutex), (mutex));
660
661static __always_inline
662int pthread_mutex_trylock_intercept(pthread_mutex_t* mutex)
663{
664   int   ret;
665   OrigFn fn;
666   VALGRIND_GET_ORIG_FN(fn);
667   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
668                                   mutex, DRD_(mutex_type)(mutex), 1, 0, 0);
669   CALL_FN_W_W(ret, fn, mutex);
670   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
671                                   mutex, ret == 0, 0, 0, 0);
672   return ret;
673}
674
675PTH_FUNCS(int, pthreadZumutexZutrylock, pthread_mutex_trylock_intercept,
676          (pthread_mutex_t *mutex), (mutex));
677
678static __always_inline
679int pthread_mutex_timedlock_intercept(pthread_mutex_t *mutex,
680                                      const struct timespec *abs_timeout)
681{
682   int   ret;
683   OrigFn fn;
684   VALGRIND_GET_ORIG_FN(fn);
685   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
686                                   mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
687   CALL_FN_W_WW(ret, fn, mutex, abs_timeout);
688   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
689                                   mutex, ret == 0, 0, 0, 0);
690   return ret;
691}
692
693PTH_FUNCS(int, pthreadZumutexZutimedlock, pthread_mutex_timedlock_intercept,
694          (pthread_mutex_t *mutex, const struct timespec *abs_timeout),
695          (mutex, abs_timeout));
696
697static __always_inline
698int pthread_mutex_unlock_intercept(pthread_mutex_t *mutex)
699{
700   int ret;
701   OrigFn fn;
702   VALGRIND_GET_ORIG_FN(fn);
703   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
704                                   mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
705   CALL_FN_W_W(ret, fn, mutex);
706   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
707                                   mutex, 0, 0, 0, 0);
708   return ret;
709}
710
711PTH_FUNCS(int, pthreadZumutexZuunlock, pthread_mutex_unlock_intercept,
712          (pthread_mutex_t *mutex), (mutex));
713
714static __always_inline
715int pthread_cond_init_intercept(pthread_cond_t* cond,
716                                const pthread_condattr_t* attr)
717{
718   int ret;
719   OrigFn fn;
720   VALGRIND_GET_ORIG_FN(fn);
721   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT,
722                                   cond, 0, 0, 0, 0);
723   CALL_FN_W_WW(ret, fn, cond, attr);
724   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT,
725                                   cond, 0, 0, 0, 0);
726   return ret;
727}
728
729PTH_FUNCS(int, pthreadZucondZuinit, pthread_cond_init_intercept,
730          (pthread_cond_t* cond, const pthread_condattr_t* attr),
731          (cond, attr));
732
733static __always_inline
734int pthread_cond_destroy_intercept(pthread_cond_t* cond)
735{
736   int ret;
737   OrigFn fn;
738   VALGRIND_GET_ORIG_FN(fn);
739   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_DESTROY,
740                                   cond, 0, 0, 0, 0);
741   CALL_FN_W_W(ret, fn, cond);
742   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_DESTROY,
743                                   cond, 0, 0, 0, 0);
744   return ret;
745}
746
747PTH_FUNCS(int, pthreadZucondZudestroy, pthread_cond_destroy_intercept,
748          (pthread_cond_t* cond), (cond));
749
750static __always_inline
751int pthread_cond_wait_intercept(pthread_cond_t *cond, pthread_mutex_t *mutex)
752{
753   int   ret;
754   OrigFn fn;
755   VALGRIND_GET_ORIG_FN(fn);
756   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
757                                   cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
758   CALL_FN_W_WW(ret, fn, cond, mutex);
759   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
760                                   cond, mutex, 1, 0, 0);
761   return ret;
762}
763
764PTH_FUNCS(int, pthreadZucondZuwait, pthread_cond_wait_intercept,
765          (pthread_cond_t *cond, pthread_mutex_t *mutex),
766          (cond, mutex));
767
768static __always_inline
769int pthread_cond_timedwait_intercept(pthread_cond_t *cond,
770                                     pthread_mutex_t *mutex,
771                                     const struct timespec* abstime)
772{
773   int   ret;
774   OrigFn fn;
775   VALGRIND_GET_ORIG_FN(fn);
776   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
777                                   cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
778   CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
779   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
780                                   cond, mutex, 1, 0, 0);
781   return ret;
782}
783
784PTH_FUNCS(int, pthreadZucondZutimedwait, pthread_cond_timedwait_intercept,
785          (pthread_cond_t *cond, pthread_mutex_t *mutex,
786           const struct timespec* abstime),
787          (cond, mutex, abstime));
788
789// NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
790// pthread_cond_signal_thread_np(). The former accepts one argument; the latter
791// two. Intercepting all pthread_cond_signal* functions will cause only one
792// argument to be passed to pthread_cond_signal_np() and hence will cause this
793// last function to crash.
794
795static __always_inline
796int pthread_cond_signal_intercept(pthread_cond_t* cond)
797{
798   int   ret;
799   OrigFn fn;
800   VALGRIND_GET_ORIG_FN(fn);
801   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_SIGNAL,
802                                   cond, 0, 0, 0, 0);
803   CALL_FN_W_W(ret, fn, cond);
804   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_SIGNAL,
805                                   cond, 0, 0, 0, 0);
806   return ret;
807}
808
809PTH_FUNCS(int, pthreadZucondZusignal, pthread_cond_signal_intercept,
810          (pthread_cond_t* cond), (cond));
811
812static __always_inline
813int pthread_cond_broadcast_intercept(pthread_cond_t* cond)
814{
815   int   ret;
816   OrigFn fn;
817   VALGRIND_GET_ORIG_FN(fn);
818   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_BROADCAST,
819                                   cond, 0, 0, 0, 0);
820   CALL_FN_W_W(ret, fn, cond);
821   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_BROADCAST,
822                                   cond, 0, 0, 0, 0);
823   return ret;
824}
825
826PTH_FUNCS(int, pthreadZucondZubroadcast, pthread_cond_broadcast_intercept,
827          (pthread_cond_t* cond), (cond));
828
829#if defined(HAVE_PTHREAD_SPIN_LOCK)
830static __always_inline
831int pthread_spin_init_intercept(pthread_spinlock_t *spinlock, int pshared)
832{
833   int ret;
834   OrigFn fn;
835   VALGRIND_GET_ORIG_FN(fn);
836   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
837                                   spinlock, 0, 0, 0, 0);
838   CALL_FN_W_WW(ret, fn, spinlock, pshared);
839   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
840                                   spinlock, 0, 0, 0, 0);
841   return ret;
842}
843
844PTH_FUNCS(int, pthreadZuspinZuinit, pthread_spin_init_intercept,
845          (pthread_spinlock_t *spinlock, int pshared), (spinlock, pshared));
846
847static __always_inline
848int pthread_spin_destroy_intercept(pthread_spinlock_t *spinlock)
849{
850   int ret;
851   OrigFn fn;
852   VALGRIND_GET_ORIG_FN(fn);
853   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
854                                   spinlock, 0, 0, 0, 0);
855   CALL_FN_W_W(ret, fn, spinlock);
856   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
857                                   spinlock, mutex_type_spinlock, 0, 0, 0);
858   return ret;
859}
860
861PTH_FUNCS(int, pthreadZuspinZudestroy, pthread_spin_destroy_intercept,
862          (pthread_spinlock_t *spinlock), (spinlock));
863
864static __always_inline
865int pthread_spin_lock_intercept(pthread_spinlock_t *spinlock)
866{
867   int   ret;
868   OrigFn fn;
869   VALGRIND_GET_ORIG_FN(fn);
870   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
871                                   spinlock, mutex_type_spinlock, 0, 0, 0);
872   CALL_FN_W_W(ret, fn, spinlock);
873   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
874                                   spinlock, ret == 0, 0, 0, 0);
875   return ret;
876}
877
878PTH_FUNCS(int, pthreadZuspinZulock, pthread_spin_lock_intercept,
879          (pthread_spinlock_t *spinlock), (spinlock));
880
881static __always_inline
882int pthread_spin_trylock_intercept(pthread_spinlock_t *spinlock)
883{
884   int   ret;
885   OrigFn fn;
886   VALGRIND_GET_ORIG_FN(fn);
887   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
888                                   spinlock, mutex_type_spinlock, 0, 0, 0);
889   CALL_FN_W_W(ret, fn, spinlock);
890   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
891                                   spinlock, ret == 0, 0, 0, 0);
892   return ret;
893}
894
895PTH_FUNCS(int, pthreadZuspinZutrylock, pthread_spin_trylock_intercept,
896          (pthread_spinlock_t *spinlock), (spinlock));
897
898static __always_inline
899int pthread_spin_unlock_intercept(pthread_spinlock_t *spinlock)
900{
901   int   ret;
902   OrigFn fn;
903   VALGRIND_GET_ORIG_FN(fn);
904   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
905                                   spinlock, mutex_type_spinlock, 0, 0, 0);
906   CALL_FN_W_W(ret, fn, spinlock);
907   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
908                                   spinlock, 0, 0, 0, 0);
909   return ret;
910}
911
912PTH_FUNCS(int, pthreadZuspinZuunlock, pthread_spin_unlock_intercept,
913          (pthread_spinlock_t *spinlock), (spinlock));
914#endif   // HAVE_PTHREAD_SPIN_LOCK
915
916
917#if defined(HAVE_PTHREAD_BARRIER_INIT)
918static __always_inline
919int pthread_barrier_init_intercept(pthread_barrier_t* barrier,
920                                   const pthread_barrierattr_t* attr,
921                                   unsigned count)
922{
923   int   ret;
924   OrigFn fn;
925   VALGRIND_GET_ORIG_FN(fn);
926   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_INIT,
927                                   barrier, pthread_barrier, count, 0, 0);
928   CALL_FN_W_WWW(ret, fn, barrier, attr, count);
929   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_INIT,
930                                   barrier, pthread_barrier, 0, 0, 0);
931   return ret;
932}
933
934PTH_FUNCS(int, pthreadZubarrierZuinit, pthread_barrier_init_intercept,
935          (pthread_barrier_t* barrier, const pthread_barrierattr_t* attr,
936           unsigned count), (barrier, attr, count));
937
938static __always_inline
939int pthread_barrier_destroy_intercept(pthread_barrier_t* barrier)
940{
941   int   ret;
942   OrigFn fn;
943   VALGRIND_GET_ORIG_FN(fn);
944   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_DESTROY,
945                                   barrier, pthread_barrier, 0, 0, 0);
946   CALL_FN_W_W(ret, fn, barrier);
947   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_DESTROY,
948                                   barrier, pthread_barrier, 0, 0, 0);
949   return ret;
950}
951
952PTH_FUNCS(int, pthreadZubarrierZudestroy, pthread_barrier_destroy_intercept,
953          (pthread_barrier_t* barrier), (barrier));
954
955static __always_inline
956int pthread_barrier_wait_intercept(pthread_barrier_t* barrier)
957{
958   int   ret;
959   OrigFn fn;
960   VALGRIND_GET_ORIG_FN(fn);
961   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_WAIT,
962                                   barrier, pthread_barrier, 0, 0, 0);
963   CALL_FN_W_W(ret, fn, barrier);
964   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_WAIT,
965                              barrier, pthread_barrier,
966                              ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD,
967                              ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
968   return ret;
969}
970
971PTH_FUNCS(int, pthreadZubarrierZuwait, pthread_barrier_wait_intercept,
972          (pthread_barrier_t* barrier), (barrier));
973#endif   // HAVE_PTHREAD_BARRIER_INIT
974
975
976static __always_inline
977int sem_init_intercept(sem_t *sem, int pshared, unsigned int value)
978{
979   int   ret;
980   OrigFn fn;
981   VALGRIND_GET_ORIG_FN(fn);
982   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT,
983                                   sem, pshared, value, 0, 0);
984   CALL_FN_W_WWW(ret, fn, sem, pshared, value);
985   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT,
986                                   sem, 0, 0, 0, 0);
987   return ret;
988}
989
990PTH_FUNCS(int, semZuinit, sem_init_intercept,
991          (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
992
993static __always_inline
994int sem_destroy_intercept(sem_t *sem)
995{
996   int   ret;
997   OrigFn fn;
998   VALGRIND_GET_ORIG_FN(fn);
999   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_DESTROY,
1000                                   sem, 0, 0, 0, 0);
1001   CALL_FN_W_W(ret, fn, sem);
1002   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_DESTROY,
1003                                   sem, 0, 0, 0, 0);
1004   return ret;
1005}
1006
1007PTH_FUNCS(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1008
1009static __always_inline
1010sem_t* sem_open_intercept(const char *name, int oflag, mode_t mode,
1011                          unsigned int value)
1012{
1013   sem_t *ret;
1014   OrigFn fn;
1015   VALGRIND_GET_ORIG_FN(fn);
1016   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_OPEN,
1017                                   name, oflag, mode, value, 0);
1018   CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value);
1019   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_OPEN,
1020                                   ret != SEM_FAILED ? ret : 0,
1021                                   name, oflag, mode, value);
1022   return ret;
1023}
1024
1025PTH_FUNCS(sem_t *, semZuopen, sem_open_intercept,
1026          (const char *name, int oflag, mode_t mode, unsigned int value),
1027          (name, oflag, mode, value));
1028
1029static __always_inline int sem_close_intercept(sem_t *sem)
1030{
1031   int   ret;
1032   OrigFn fn;
1033   VALGRIND_GET_ORIG_FN(fn);
1034   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_CLOSE,
1035                                   sem, 0, 0, 0, 0);
1036   CALL_FN_W_W(ret, fn, sem);
1037   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_CLOSE,
1038                                   sem, 0, 0, 0, 0);
1039   return ret;
1040}
1041
1042PTH_FUNCS(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
1043
1044static __always_inline int sem_wait_intercept(sem_t *sem)
1045{
1046   int   ret;
1047   OrigFn fn;
1048   VALGRIND_GET_ORIG_FN(fn);
1049   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1050                                   sem, 0, 0, 0, 0);
1051   CALL_FN_W_W(ret, fn, sem);
1052   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1053                                   sem, ret == 0, 0, 0, 0);
1054   return ret;
1055}
1056
1057PTH_FUNCS(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1058
1059static __always_inline int sem_trywait_intercept(sem_t *sem)
1060{
1061   int   ret;
1062   OrigFn fn;
1063   VALGRIND_GET_ORIG_FN(fn);
1064   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1065                                   sem, 0, 0, 0, 0);
1066   CALL_FN_W_W(ret, fn, sem);
1067   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1068                                   sem, ret == 0, 0, 0, 0);
1069   return ret;
1070}
1071
1072PTH_FUNCS(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1073
1074static __always_inline
1075int sem_timedwait_intercept(sem_t *sem, const struct timespec *abs_timeout)
1076{
1077   int   ret;
1078   OrigFn fn;
1079   VALGRIND_GET_ORIG_FN(fn);
1080   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1081                                   sem, 0, 0, 0, 0);
1082   CALL_FN_W_WW(ret, fn, sem, abs_timeout);
1083   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1084                                   sem, ret == 0, 0, 0, 0);
1085   return ret;
1086}
1087
1088PTH_FUNCS(int, semZutimedwait, sem_timedwait_intercept,
1089          (sem_t *sem, const struct timespec *abs_timeout),
1090          (sem, abs_timeout));
1091
1092static __always_inline int sem_post_intercept(sem_t *sem)
1093{
1094   int   ret;
1095   OrigFn fn;
1096   VALGRIND_GET_ORIG_FN(fn);
1097   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_POST,
1098                                   sem, 0, 0, 0, 0);
1099   CALL_FN_W_W(ret, fn, sem);
1100   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_POST,
1101                                   sem, ret == 0, 0, 0, 0);
1102   return ret;
1103}
1104
1105PTH_FUNCS(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
1106
1107/* Android's pthread.h doesn't say anything about rwlocks, hence these
1108   functions have to be conditionally compiled. */
1109#if defined(HAVE_PTHREAD_RWLOCK_T)
1110
1111static __always_inline
1112int pthread_rwlock_init_intercept(pthread_rwlock_t* rwlock,
1113                                  const pthread_rwlockattr_t* attr)
1114{
1115   int   ret;
1116   OrigFn fn;
1117   VALGRIND_GET_ORIG_FN(fn);
1118   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT,
1119                                   rwlock, 0, 0, 0, 0);
1120   CALL_FN_W_WW(ret, fn, rwlock, attr);
1121   return ret;
1122}
1123
1124PTH_FUNCS(int,
1125          pthreadZurwlockZuinit, pthread_rwlock_init_intercept,
1126          (pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr),
1127          (rwlock, attr));
1128
1129static __always_inline
1130int pthread_rwlock_destroy_intercept(pthread_rwlock_t* rwlock)
1131{
1132   int   ret;
1133   OrigFn fn;
1134   VALGRIND_GET_ORIG_FN(fn);
1135   CALL_FN_W_W(ret, fn, rwlock);
1136   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_DESTROY,
1137                                   rwlock, 0, 0, 0, 0);
1138   return ret;
1139}
1140
1141PTH_FUNCS(int,
1142          pthreadZurwlockZudestroy, pthread_rwlock_destroy_intercept,
1143          (pthread_rwlock_t* rwlock), (rwlock));
1144
1145static __always_inline
1146int pthread_rwlock_rdlock_intercept(pthread_rwlock_t* rwlock)
1147{
1148   int   ret;
1149   OrigFn fn;
1150   VALGRIND_GET_ORIG_FN(fn);
1151   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1152                                   rwlock, 0, 0, 0, 0);
1153   CALL_FN_W_W(ret, fn, rwlock);
1154   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1155                                   rwlock, ret == 0, 0, 0, 0);
1156   return ret;
1157}
1158
1159PTH_FUNCS(int,
1160          pthreadZurwlockZurdlock, pthread_rwlock_rdlock_intercept,
1161          (pthread_rwlock_t* rwlock), (rwlock));
1162
1163static __always_inline
1164int pthread_rwlock_wrlock_intercept(pthread_rwlock_t* rwlock)
1165{
1166   int   ret;
1167   OrigFn fn;
1168   VALGRIND_GET_ORIG_FN(fn);
1169   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1170                                   rwlock, 0, 0, 0, 0);
1171   CALL_FN_W_W(ret, fn, rwlock);
1172   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1173                                   rwlock, ret == 0, 0, 0, 0);
1174   return ret;
1175}
1176
1177PTH_FUNCS(int,
1178          pthreadZurwlockZuwrlock, pthread_rwlock_wrlock_intercept,
1179          (pthread_rwlock_t* rwlock), (rwlock));
1180
1181static __always_inline
1182int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t* rwlock)
1183{
1184   int   ret;
1185   OrigFn fn;
1186   VALGRIND_GET_ORIG_FN(fn);
1187   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1188                                   rwlock, 0, 0, 0, 0);
1189   CALL_FN_W_W(ret, fn, rwlock);
1190   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1191                                   rwlock, ret == 0, 0, 0, 0);
1192   return ret;
1193}
1194
1195PTH_FUNCS(int,
1196          pthreadZurwlockZutimedrdlock, pthread_rwlock_timedrdlock_intercept,
1197          (pthread_rwlock_t* rwlock), (rwlock));
1198
1199static __always_inline
1200int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t* rwlock)
1201{
1202   int   ret;
1203   OrigFn fn;
1204   VALGRIND_GET_ORIG_FN(fn);
1205   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1206                                   rwlock, 0, 0, 0, 0);
1207   CALL_FN_W_W(ret, fn, rwlock);
1208   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1209                                   rwlock, ret == 0, 0, 0, 0);
1210   return ret;
1211}
1212
1213PTH_FUNCS(int,
1214          pthreadZurwlockZutimedwrlock, pthread_rwlock_timedwrlock_intercept,
1215          (pthread_rwlock_t* rwlock), (rwlock));
1216
1217static __always_inline
1218int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t* rwlock)
1219{
1220   int   ret;
1221   OrigFn fn;
1222   VALGRIND_GET_ORIG_FN(fn);
1223   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1224                                   rwlock, 0, 0, 0, 0);
1225   CALL_FN_W_W(ret, fn, rwlock);
1226   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1227                                   rwlock, ret == 0, 0, 0, 0);
1228   return ret;
1229}
1230
1231PTH_FUNCS(int,
1232          pthreadZurwlockZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1233          (pthread_rwlock_t* rwlock), (rwlock));
1234
1235static __always_inline
1236int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t* rwlock)
1237{
1238   int   ret;
1239   OrigFn fn;
1240   VALGRIND_GET_ORIG_FN(fn);
1241   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1242                                   rwlock, 0, 0, 0, 0);
1243   CALL_FN_W_W(ret, fn, rwlock);
1244   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1245                                   rwlock, ret == 0, 0, 0, 0);
1246   return ret;
1247}
1248
1249PTH_FUNCS(int,
1250          pthreadZurwlockZutrywrlock, pthread_rwlock_trywrlock_intercept,
1251          (pthread_rwlock_t* rwlock), (rwlock));
1252
1253static __always_inline
1254int pthread_rwlock_unlock_intercept(pthread_rwlock_t* rwlock)
1255{
1256   int   ret;
1257   OrigFn fn;
1258   VALGRIND_GET_ORIG_FN(fn);
1259   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_UNLOCK,
1260                                   rwlock, 0, 0, 0, 0);
1261   CALL_FN_W_W(ret, fn, rwlock);
1262   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_UNLOCK,
1263                                   rwlock, ret == 0, 0, 0, 0);
1264   return ret;
1265}
1266
1267PTH_FUNCS(int,
1268          pthreadZurwlockZuunlock, pthread_rwlock_unlock_intercept,
1269          (pthread_rwlock_t* rwlock), (rwlock));
1270
1271#endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
1272