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