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-2013 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
92 static 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 
138 typedef struct {
139    pthread_mutex_t mutex;
140    int counter;
141    int waiters;
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_(ignore_mutex_ordering)182 static __always_inline void DRD_(ignore_mutex_ordering)(pthread_mutex_t *mutex)
183 {
184    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_IGNORE_MUTEX_ORDERING,
185                                    mutex, 0, 0, 0, 0);
186 }
187 
DRD_(sema_init)188 static void DRD_(sema_init)(DrdSema* sema)
189 {
190    DRD_IGNORE_VAR(*sema);
191    pthread_mutex_init(&sema->mutex, NULL);
192    DRD_(ignore_mutex_ordering)(&sema->mutex);
193    sema->counter = 0;
194    sema->waiters = 0;
195 }
196 
DRD_(sema_destroy)197 static void DRD_(sema_destroy)(DrdSema* sema)
198 {
199    pthread_mutex_destroy(&sema->mutex);
200 }
201 
DRD_(sema_down)202 static void DRD_(sema_down)(DrdSema* sema)
203 {
204    int res = ENOSYS;
205 
206    pthread_mutex_lock(&sema->mutex);
207    if (sema->counter == 0) {
208       sema->waiters++;
209       while (sema->counter == 0) {
210          pthread_mutex_unlock(&sema->mutex);
211 #ifdef HAVE_USABLE_LINUX_FUTEX_H
212          if (syscall(__NR_futex, (UWord)&sema->counter,
213                      FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0) == 0)
214             res = 0;
215          else
216             res = errno;
217 #endif
218          /*
219           * Invoke sched_yield() on non-Linux systems, if the futex syscall has
220           * not been invoked or if this code has been built on a Linux system
221           * where __NR_futex is defined and is run on a Linux system that does
222           * not support the futex syscall.
223           */
224          if (res != 0 && res != EWOULDBLOCK)
225             sched_yield();
226          pthread_mutex_lock(&sema->mutex);
227       }
228       sema->waiters--;
229    }
230    sema->counter--;
231    pthread_mutex_unlock(&sema->mutex);
232 }
233 
DRD_(sema_up)234 static void DRD_(sema_up)(DrdSema* sema)
235 {
236    pthread_mutex_lock(&sema->mutex);
237    sema->counter++;
238 #ifdef HAVE_USABLE_LINUX_FUTEX_H
239    if (sema->waiters > 0)
240       syscall(__NR_futex, (UWord)&sema->counter,
241               FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1);
242 #endif
243    pthread_mutex_unlock(&sema->mutex);
244 }
245 
246 /**
247  * POSIX threads and DRD each have their own mutex type identification.
248  * Convert POSIX threads' mutex type to DRD's mutex type. In the code below
249  * if-statements are used to test the value of 'kind' instead of a switch
250  * statement because some of the PTHREAD_MUTEX_ macro's may have the same
251  * value.
252  */
DRD_(pthread_to_drd_mutex_type)253 static MutexT DRD_(pthread_to_drd_mutex_type)(int kind)
254 {
255    /*
256     * See also PTHREAD_MUTEX_KIND_MASK_NP in glibc source file
257     * <nptl/pthreadP.h>.
258     */
259    kind &= PTHREAD_MUTEX_RECURSIVE | PTHREAD_MUTEX_ERRORCHECK |
260       PTHREAD_MUTEX_NORMAL | PTHREAD_MUTEX_DEFAULT;
261 
262    if (kind == PTHREAD_MUTEX_RECURSIVE)
263       return mutex_type_recursive_mutex;
264    else if (kind == PTHREAD_MUTEX_ERRORCHECK)
265       return mutex_type_errorcheck_mutex;
266    else if (kind == PTHREAD_MUTEX_NORMAL)
267       return mutex_type_default_mutex;
268    else if (kind == PTHREAD_MUTEX_DEFAULT)
269       return mutex_type_default_mutex;
270 #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
271    else if (kind == PTHREAD_MUTEX_ADAPTIVE_NP)
272       return mutex_type_default_mutex;
273 #endif
274    else
275       return mutex_type_invalid_mutex;
276 }
277 
278 #define IS_ALIGNED(p) (((uintptr_t)(p) & (sizeof(*(p)) - 1)) == 0)
279 
280 /**
281  * Read the mutex type stored in the client memory used for the mutex
282  * implementation.
283  *
284  * @note This function depends on the implementation of the POSIX threads
285  *   library -- the POSIX standard does not define the name of the member in
286  *   which the mutex type is stored.
287  * @note The function mutex_type() has been declared inline in order
288  *   to avoid that it shows up in call stacks (drd/tests/...exp* files).
289  * @note glibc stores the mutex type in the lowest two bits, and uses the
290  *   higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
291  *   PTHREAD_MUTEXATTR_FLAG_PSHARED.
292  */
DRD_(mutex_type)293 static __always_inline MutexT DRD_(mutex_type)(pthread_mutex_t* mutex)
294 {
295 #if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
296    /* glibc + LinuxThreads. */
297    if (IS_ALIGNED(&mutex->__m_kind))
298    {
299       const int kind = mutex->__m_kind & 3;
300       return DRD_(pthread_to_drd_mutex_type)(kind);
301    }
302 #elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
303    /* glibc + NPTL. */
304    if (IS_ALIGNED(&mutex->__data.__kind))
305    {
306       const int kind = mutex->__data.__kind & 3;
307       return DRD_(pthread_to_drd_mutex_type)(kind);
308    }
309 #else
310    /*
311     * Another POSIX threads implementation. The mutex type won't be printed
312     * when enabling --trace-mutex=yes.
313     */
314 #endif
315    return mutex_type_unknown;
316 }
317 
318 /**
319  * Tell DRD whether 'tid' is a joinable thread or a detached thread.
320  */
DRD_(set_joinable)321 static void DRD_(set_joinable)(const pthread_t tid, const int joinable)
322 {
323    assert(joinable == 0 || joinable == 1);
324    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_JOINABLE,
325                                    tid, joinable, 0, 0, 0);
326 }
327 
328 /** Tell DRD that the calling thread is about to enter pthread_create(). */
DRD_(entering_pthread_create)329 static __always_inline void DRD_(entering_pthread_create)(void)
330 {
331    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__ENTERING_PTHREAD_CREATE,
332                                    0, 0, 0, 0, 0);
333 }
334 
335 /** Tell DRD that the calling thread has left pthread_create(). */
DRD_(left_pthread_create)336 static __always_inline void DRD_(left_pthread_create)(void)
337 {
338    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LEFT_PTHREAD_CREATE,
339                                    0, 0, 0, 0, 0);
340 }
341 
342 /**
343  * Entry point for newly created threads. This function is called from the
344  * thread created by pthread_create().
345  */
DRD_(thread_wrapper)346 static void* DRD_(thread_wrapper)(void* arg)
347 {
348    DrdPosixThreadArgs* arg_ptr;
349    DrdPosixThreadArgs arg_copy;
350 
351    arg_ptr = (DrdPosixThreadArgs*)arg;
352    arg_copy = *arg_ptr;
353 
354    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
355                                    pthread_self(), 0, 0, 0, 0);
356 
357    DRD_(set_joinable)(pthread_self(),
358                       arg_copy.detachstate == PTHREAD_CREATE_JOINABLE);
359 
360    /*
361     * Only set 'wrapper_started' after VG_USERREQ__SET_PTHREADID and
362     * DRD_(set_joinable)() have been invoked to avoid a race with
363     * a pthread_detach() invocation for this thread from another thread.
364     */
365    DRD_(sema_up)(arg_copy.wrapper_started);
366 
367    return (arg_copy.start)(arg_copy.arg);
368 }
369 
370 /**
371  * Return 1 if the LinuxThreads implementation of POSIX Threads has been
372  * detected, and 0 otherwise.
373  *
374  * @see For more information about the confstr() function, see also
375  * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
376  */
DRD_(detected_linuxthreads)377 static int DRD_(detected_linuxthreads)(void)
378 {
379 #if defined(linux)
380 #if defined(_CS_GNU_LIBPTHREAD_VERSION)
381    /* Linux with a recent glibc. */
382    HChar buffer[256];
383    unsigned len;
384    len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
385    assert(len <= sizeof(buffer));
386    return len > 0 && buffer[0] == 'l';
387 #else
388    /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
389    return 1;
390 #endif
391 #else
392    /* Another OS than Linux, hence no LinuxThreads. */
393    return 0;
394 #endif
395 }
396 
397 /**
398  * Stop and print an error message in case a non-supported threading
399  * library implementation (LinuxThreads) has been detected.
400  */
DRD_(check_threading_library)401 static void DRD_(check_threading_library)(void)
402 {
403    if (DRD_(detected_linuxthreads)())
404    {
405       if (getenv("LD_ASSUME_KERNEL"))
406       {
407          fprintf(stderr,
408 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
409 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
410 "after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
411 );
412       }
413       else
414       {
415          fprintf(stderr,
416 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
417 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
418 "after having upgraded to a newer version of your Linux distribution.\n"
419 "Giving up.\n"
420 );
421       }
422       abort();
423    }
424 }
425 
426 /**
427  * The main thread is the only thread not created by pthread_create().
428  * Update DRD's state information about the main thread.
429  */
DRD_(set_main_thread_state)430 static void DRD_(set_main_thread_state)(void)
431 {
432    // Make sure that DRD knows about the main thread's POSIX thread ID.
433    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
434                                    pthread_self(), 0, 0, 0, 0);
435 }
436 
437 /*
438  * Note: as of today there exist three different versions of pthread_create
439  * in Linux:
440  * - pthread_create@GLIBC_2.0
441  * - pthread_create@@GLIBC_2.1
442  * - pthread_create@@GLIBC_2.2.5
443  * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
444  * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
445  * versions have been implemented. In any glibc version where more than one
446  * pthread_create function has been implemented, older versions call the
447  * newer versions. Or: the pthread_create* wrapper defined below can be
448  * called recursively. Any code in this wrapper should take this in account.
449  * As an example, it is not safe to invoke the DRD_STOP_RECORDING
450  * / DRD_START_RECORDING client requests from the pthread_create wrapper.
451  * See also the implementation of pthread_create@GLIBC_2.0 in
452  * glibc-2.9/nptl/pthread_create.c.
453  */
454 
455 static __always_inline
pthread_create_intercept(pthread_t * thread,const pthread_attr_t * attr,void * (* start)(void *),void * arg)456 int pthread_create_intercept(pthread_t* thread, const pthread_attr_t* attr,
457                              void* (*start)(void*), void* arg)
458 {
459    int    ret;
460    OrigFn fn;
461    DrdSema wrapper_started;
462    DrdPosixThreadArgs thread_args;
463 
464    VALGRIND_GET_ORIG_FN(fn);
465 
466    DRD_(sema_init)(&wrapper_started);
467    thread_args.start           = start;
468    thread_args.arg             = arg;
469    thread_args.wrapper_started = &wrapper_started;
470    /*
471     * Find out whether the thread will be started as a joinable thread
472     * or as a detached thread. If no thread attributes have been specified,
473     * this means that the new thread will be started as a joinable thread.
474     */
475    thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
476    if (attr)
477    {
478       if (pthread_attr_getdetachstate(attr, &thread_args.detachstate) != 0)
479          assert(0);
480    }
481    assert(thread_args.detachstate == PTHREAD_CREATE_JOINABLE
482           || thread_args.detachstate == PTHREAD_CREATE_DETACHED);
483 
484    DRD_(entering_pthread_create)();
485    CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), &thread_args);
486    DRD_(left_pthread_create)();
487 
488    if (ret == 0) {
489       /* Wait until the thread wrapper started. */
490       DRD_(sema_down)(&wrapper_started);
491    }
492 
493    DRD_(sema_destroy)(&wrapper_started);
494 
495    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT,
496                                    pthread_self(), 0, 0, 0, 0);
497 
498    return ret;
499 }
500 
501 PTH_FUNCS(int, pthreadZucreate, pthread_create_intercept,
502           (pthread_t *thread, const pthread_attr_t *attr,
503            void *(*start) (void *), void *arg),
504           (thread, attr, start, arg));
505 
506 static __always_inline
pthread_join_intercept(pthread_t pt_joinee,void ** thread_return)507 int pthread_join_intercept(pthread_t pt_joinee, void **thread_return)
508 {
509    int      ret;
510    OrigFn   fn;
511 
512    VALGRIND_GET_ORIG_FN(fn);
513    /*
514     * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
515     * implementation triggers a (false positive) race report.
516     */
517    ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
518    CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
519    if (ret == 0)
520    {
521       VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN,
522                                       pt_joinee, 0, 0, 0, 0);
523    }
524    ANNOTATE_IGNORE_READS_AND_WRITES_END();
525    return ret;
526 }
527 
528 PTH_FUNCS(int, pthreadZujoin, pthread_join_intercept,
529           (pthread_t pt_joinee, void **thread_return),
530           (pt_joinee, thread_return));
531 
532 static __always_inline
pthread_detach_intercept(pthread_t pt_thread)533 int pthread_detach_intercept(pthread_t pt_thread)
534 {
535    int ret;
536    OrigFn fn;
537 
538    VALGRIND_GET_ORIG_FN(fn);
539    CALL_FN_W_W(ret, fn, pt_thread);
540    DRD_(set_joinable)(pt_thread, 0);
541 
542    return ret;
543 }
544 
545 PTH_FUNCS(int, pthreadZudetach, pthread_detach_intercept,
546           (pthread_t thread), (thread));
547 
548 // NOTE: be careful to intercept only pthread_cancel() and not
549 // pthread_cancel_init() on Linux.
550 
551 static __always_inline
pthread_cancel_intercept(pthread_t pt_thread)552 int pthread_cancel_intercept(pthread_t pt_thread)
553 {
554    int ret;
555    OrigFn fn;
556    VALGRIND_GET_ORIG_FN(fn);
557    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_THREAD_CANCEL,
558                                    pt_thread, 0, 0, 0, 0);
559    CALL_FN_W_W(ret, fn, pt_thread);
560    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_CANCEL,
561                                    pt_thread, ret==0, 0, 0, 0);
562    return ret;
563 }
564 
565 PTH_FUNCS(int, pthreadZucancel, pthread_cancel_intercept,
566           (pthread_t thread), (thread))
567 
568 static __always_inline
pthread_once_intercept(pthread_once_t * once_control,void (* init_routine)(void))569 int pthread_once_intercept(pthread_once_t *once_control,
570                            void (*init_routine)(void))
571 {
572    int ret;
573    OrigFn fn;
574    VALGRIND_GET_ORIG_FN(fn);
575    /*
576     * Ignore any data races triggered by the implementation of pthread_once().
577     * Necessary for Darwin. This is not necessary for Linux but doesn't have
578     * any known adverse effects.
579     */
580    DRD_IGNORE_VAR(*once_control);
581    ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
582    CALL_FN_W_WW(ret, fn, once_control, init_routine);
583    ANNOTATE_IGNORE_READS_AND_WRITES_END();
584    DRD_STOP_IGNORING_VAR(*once_control);
585    return ret;
586 }
587 
588 PTH_FUNCS(int, pthreadZuonce, pthread_once_intercept,
589           (pthread_once_t *once_control, void (*init_routine)(void)),
590           (once_control, init_routine));
591 
592 static __always_inline
pthread_mutex_init_intercept(pthread_mutex_t * mutex,const pthread_mutexattr_t * attr)593 int pthread_mutex_init_intercept(pthread_mutex_t *mutex,
594                                  const pthread_mutexattr_t* attr)
595 {
596    int ret;
597    OrigFn fn;
598    int mt;
599    VALGRIND_GET_ORIG_FN(fn);
600    mt = PTHREAD_MUTEX_DEFAULT;
601    if (attr)
602       pthread_mutexattr_gettype(attr, &mt);
603    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
604                                    mutex, DRD_(pthread_to_drd_mutex_type)(mt),
605                                    0, 0, 0);
606    CALL_FN_W_WW(ret, fn, mutex, attr);
607    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
608                                    mutex, 0, 0, 0, 0);
609    return ret;
610 }
611 
612 PTH_FUNCS(int, pthreadZumutexZuinit, pthread_mutex_init_intercept,
613           (pthread_mutex_t *mutex, const pthread_mutexattr_t* attr),
614           (mutex, attr));
615 
616 static __always_inline
pthread_mutex_destroy_intercept(pthread_mutex_t * mutex)617 int pthread_mutex_destroy_intercept(pthread_mutex_t* mutex)
618 {
619    int ret;
620    OrigFn fn;
621    VALGRIND_GET_ORIG_FN(fn);
622    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
623                                    mutex, 0, 0, 0, 0);
624    CALL_FN_W_W(ret, fn, mutex);
625    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
626                                    mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
627    return ret;
628 }
629 
630 PTH_FUNCS(int, pthreadZumutexZudestroy, pthread_mutex_destroy_intercept,
631           (pthread_mutex_t *mutex), (mutex));
632 
633 static __always_inline
pthread_mutex_lock_intercept(pthread_mutex_t * mutex)634 int pthread_mutex_lock_intercept(pthread_mutex_t* mutex)
635 {
636    int   ret;
637    OrigFn fn;
638    VALGRIND_GET_ORIG_FN(fn);
639    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
640                                    mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
641    CALL_FN_W_W(ret, fn, mutex);
642    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
643                                    mutex, ret == 0, 0, 0, 0);
644    return ret;
645 }
646 
647 PTH_FUNCS(int, pthreadZumutexZulock, pthread_mutex_lock_intercept,
648           (pthread_mutex_t *mutex), (mutex));
649 
650 static __always_inline
pthread_mutex_trylock_intercept(pthread_mutex_t * mutex)651 int pthread_mutex_trylock_intercept(pthread_mutex_t* mutex)
652 {
653    int   ret;
654    OrigFn fn;
655    VALGRIND_GET_ORIG_FN(fn);
656    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
657                                    mutex, DRD_(mutex_type)(mutex), 1, 0, 0);
658    CALL_FN_W_W(ret, fn, mutex);
659    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
660                                    mutex, ret == 0, 0, 0, 0);
661    return ret;
662 }
663 
664 PTH_FUNCS(int, pthreadZumutexZutrylock, pthread_mutex_trylock_intercept,
665           (pthread_mutex_t *mutex), (mutex));
666 
667 static __always_inline
pthread_mutex_timedlock_intercept(pthread_mutex_t * mutex,const struct timespec * abs_timeout)668 int pthread_mutex_timedlock_intercept(pthread_mutex_t *mutex,
669                                       const struct timespec *abs_timeout)
670 {
671    int   ret;
672    OrigFn fn;
673    VALGRIND_GET_ORIG_FN(fn);
674    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
675                                    mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
676    CALL_FN_W_WW(ret, fn, mutex, abs_timeout);
677    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
678                                    mutex, ret == 0, 0, 0, 0);
679    return ret;
680 }
681 
682 PTH_FUNCS(int, pthreadZumutexZutimedlock, pthread_mutex_timedlock_intercept,
683           (pthread_mutex_t *mutex, const struct timespec *abs_timeout),
684           (mutex, abs_timeout));
685 
686 static __always_inline
pthread_mutex_unlock_intercept(pthread_mutex_t * mutex)687 int pthread_mutex_unlock_intercept(pthread_mutex_t *mutex)
688 {
689    int ret;
690    OrigFn fn;
691    VALGRIND_GET_ORIG_FN(fn);
692    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
693                                    mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
694    CALL_FN_W_W(ret, fn, mutex);
695    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
696                                    mutex, 0, 0, 0, 0);
697    return ret;
698 }
699 
700 PTH_FUNCS(int, pthreadZumutexZuunlock, pthread_mutex_unlock_intercept,
701           (pthread_mutex_t *mutex), (mutex));
702 
703 static __always_inline
pthread_cond_init_intercept(pthread_cond_t * cond,const pthread_condattr_t * attr)704 int pthread_cond_init_intercept(pthread_cond_t* cond,
705                                 const pthread_condattr_t* attr)
706 {
707    int ret;
708    OrigFn fn;
709    VALGRIND_GET_ORIG_FN(fn);
710    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT,
711                                    cond, 0, 0, 0, 0);
712    CALL_FN_W_WW(ret, fn, cond, attr);
713    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT,
714                                    cond, 0, 0, 0, 0);
715    return ret;
716 }
717 
718 PTH_FUNCS(int, pthreadZucondZuinit, pthread_cond_init_intercept,
719           (pthread_cond_t* cond, const pthread_condattr_t* attr),
720           (cond, attr));
721 
722 static __always_inline
pthread_cond_destroy_intercept(pthread_cond_t * cond)723 int pthread_cond_destroy_intercept(pthread_cond_t* cond)
724 {
725    int ret;
726    OrigFn fn;
727    VALGRIND_GET_ORIG_FN(fn);
728    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_DESTROY,
729                                    cond, 0, 0, 0, 0);
730    CALL_FN_W_W(ret, fn, cond);
731    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_DESTROY,
732                                    cond, ret==0, 0, 0, 0);
733    return ret;
734 }
735 
736 PTH_FUNCS(int, pthreadZucondZudestroy, pthread_cond_destroy_intercept,
737           (pthread_cond_t* cond), (cond));
738 
739 static __always_inline
pthread_cond_wait_intercept(pthread_cond_t * cond,pthread_mutex_t * mutex)740 int pthread_cond_wait_intercept(pthread_cond_t *cond, pthread_mutex_t *mutex)
741 {
742    int   ret;
743    OrigFn fn;
744    VALGRIND_GET_ORIG_FN(fn);
745    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
746                                    cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
747    CALL_FN_W_WW(ret, fn, cond, mutex);
748    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
749                                    cond, mutex, 1, 0, 0);
750    return ret;
751 }
752 
753 PTH_FUNCS(int, pthreadZucondZuwait, pthread_cond_wait_intercept,
754           (pthread_cond_t *cond, pthread_mutex_t *mutex),
755           (cond, mutex));
756 
757 static __always_inline
pthread_cond_timedwait_intercept(pthread_cond_t * cond,pthread_mutex_t * mutex,const struct timespec * abstime)758 int pthread_cond_timedwait_intercept(pthread_cond_t *cond,
759                                      pthread_mutex_t *mutex,
760                                      const struct timespec* abstime)
761 {
762    int   ret;
763    OrigFn fn;
764    VALGRIND_GET_ORIG_FN(fn);
765    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
766                                    cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
767    CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
768    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
769                                    cond, mutex, 1, 0, 0);
770    return ret;
771 }
772 
773 PTH_FUNCS(int, pthreadZucondZutimedwait, pthread_cond_timedwait_intercept,
774           (pthread_cond_t *cond, pthread_mutex_t *mutex,
775            const struct timespec* abstime),
776           (cond, mutex, abstime));
777 
778 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
779 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
780 // two. Intercepting all pthread_cond_signal* functions will cause only one
781 // argument to be passed to pthread_cond_signal_np() and hence will cause this
782 // last function to crash.
783 
784 static __always_inline
pthread_cond_signal_intercept(pthread_cond_t * cond)785 int pthread_cond_signal_intercept(pthread_cond_t* cond)
786 {
787    int   ret;
788    OrigFn fn;
789    VALGRIND_GET_ORIG_FN(fn);
790    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_SIGNAL,
791                                    cond, 0, 0, 0, 0);
792    CALL_FN_W_W(ret, fn, cond);
793    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_SIGNAL,
794                                    cond, 0, 0, 0, 0);
795    return ret;
796 }
797 
798 PTH_FUNCS(int, pthreadZucondZusignal, pthread_cond_signal_intercept,
799           (pthread_cond_t* cond), (cond));
800 
801 static __always_inline
pthread_cond_broadcast_intercept(pthread_cond_t * cond)802 int pthread_cond_broadcast_intercept(pthread_cond_t* cond)
803 {
804    int   ret;
805    OrigFn fn;
806    VALGRIND_GET_ORIG_FN(fn);
807    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_BROADCAST,
808                                    cond, 0, 0, 0, 0);
809    CALL_FN_W_W(ret, fn, cond);
810    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_BROADCAST,
811                                    cond, 0, 0, 0, 0);
812    return ret;
813 }
814 
815 PTH_FUNCS(int, pthreadZucondZubroadcast, pthread_cond_broadcast_intercept,
816           (pthread_cond_t* cond), (cond));
817 
818 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
819     && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
820 static __always_inline
pthread_spin_init_intercept(pthread_spinlock_t * spinlock,int pshared)821 int pthread_spin_init_intercept(pthread_spinlock_t *spinlock, int pshared)
822 {
823    int ret;
824    OrigFn fn;
825    VALGRIND_GET_ORIG_FN(fn);
826    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
827                                    spinlock, 0, 0, 0, 0);
828    CALL_FN_W_WW(ret, fn, spinlock, pshared);
829    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
830                                    spinlock, 0, 0, 0, 0);
831    return ret;
832 }
833 
834 PTH_FUNCS(int, pthreadZuspinZuinit, pthread_spin_init_intercept,
835           (pthread_spinlock_t *spinlock, int pshared), (spinlock, pshared));
836 
837 static __always_inline
pthread_spin_destroy_intercept(pthread_spinlock_t * spinlock)838 int pthread_spin_destroy_intercept(pthread_spinlock_t *spinlock)
839 {
840    int ret;
841    OrigFn fn;
842    VALGRIND_GET_ORIG_FN(fn);
843    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
844                                    spinlock, 0, 0, 0, 0);
845    CALL_FN_W_W(ret, fn, spinlock);
846    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
847                                    spinlock, mutex_type_spinlock, 0, 0, 0);
848    return ret;
849 }
850 
851 PTH_FUNCS(int, pthreadZuspinZudestroy, pthread_spin_destroy_intercept,
852           (pthread_spinlock_t *spinlock), (spinlock));
853 
854 static __always_inline
pthread_spin_lock_intercept(pthread_spinlock_t * spinlock)855 int pthread_spin_lock_intercept(pthread_spinlock_t *spinlock)
856 {
857    int   ret;
858    OrigFn fn;
859    VALGRIND_GET_ORIG_FN(fn);
860    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
861                                    spinlock, mutex_type_spinlock, 0, 0, 0);
862    CALL_FN_W_W(ret, fn, spinlock);
863    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
864                                    spinlock, ret == 0, 0, 0, 0);
865    return ret;
866 }
867 
868 PTH_FUNCS(int, pthreadZuspinZulock, pthread_spin_lock_intercept,
869           (pthread_spinlock_t *spinlock), (spinlock));
870 
871 static __always_inline
pthread_spin_trylock_intercept(pthread_spinlock_t * spinlock)872 int pthread_spin_trylock_intercept(pthread_spinlock_t *spinlock)
873 {
874    int   ret;
875    OrigFn fn;
876    VALGRIND_GET_ORIG_FN(fn);
877    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
878                                    spinlock, mutex_type_spinlock, 0, 0, 0);
879    CALL_FN_W_W(ret, fn, spinlock);
880    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
881                                    spinlock, ret == 0, 0, 0, 0);
882    return ret;
883 }
884 
885 PTH_FUNCS(int, pthreadZuspinZutrylock, pthread_spin_trylock_intercept,
886           (pthread_spinlock_t *spinlock), (spinlock));
887 
888 static __always_inline
pthread_spin_unlock_intercept(pthread_spinlock_t * spinlock)889 int pthread_spin_unlock_intercept(pthread_spinlock_t *spinlock)
890 {
891    int   ret;
892    OrigFn fn;
893    VALGRIND_GET_ORIG_FN(fn);
894    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
895                                    spinlock, mutex_type_spinlock, 0, 0, 0);
896    CALL_FN_W_W(ret, fn, spinlock);
897    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
898                                    spinlock, 0, 0, 0, 0);
899    return ret;
900 }
901 
902 PTH_FUNCS(int, pthreadZuspinZuunlock, pthread_spin_unlock_intercept,
903           (pthread_spinlock_t *spinlock), (spinlock));
904 #endif   // HAVE_PTHREAD_SPIN_LOCK
905 
906 
907 #if defined(HAVE_PTHREAD_BARRIER_INIT)
908 static __always_inline
pthread_barrier_init_intercept(pthread_barrier_t * barrier,const pthread_barrierattr_t * attr,unsigned count)909 int pthread_barrier_init_intercept(pthread_barrier_t* barrier,
910                                    const pthread_barrierattr_t* attr,
911                                    unsigned count)
912 {
913    int   ret;
914    OrigFn fn;
915    VALGRIND_GET_ORIG_FN(fn);
916    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_INIT,
917                                    barrier, pthread_barrier, count, 0, 0);
918    CALL_FN_W_WWW(ret, fn, barrier, attr, count);
919    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_INIT,
920                                    barrier, pthread_barrier, 0, 0, 0);
921    return ret;
922 }
923 
924 PTH_FUNCS(int, pthreadZubarrierZuinit, pthread_barrier_init_intercept,
925           (pthread_barrier_t* barrier, const pthread_barrierattr_t* attr,
926            unsigned count), (barrier, attr, count));
927 
928 static __always_inline
pthread_barrier_destroy_intercept(pthread_barrier_t * barrier)929 int pthread_barrier_destroy_intercept(pthread_barrier_t* barrier)
930 {
931    int   ret;
932    OrigFn fn;
933    VALGRIND_GET_ORIG_FN(fn);
934    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_DESTROY,
935                                    barrier, pthread_barrier, 0, 0, 0);
936    CALL_FN_W_W(ret, fn, barrier);
937    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_DESTROY,
938                                    barrier, pthread_barrier, 0, 0, 0);
939    return ret;
940 }
941 
942 PTH_FUNCS(int, pthreadZubarrierZudestroy, pthread_barrier_destroy_intercept,
943           (pthread_barrier_t* barrier), (barrier));
944 
945 static __always_inline
pthread_barrier_wait_intercept(pthread_barrier_t * barrier)946 int pthread_barrier_wait_intercept(pthread_barrier_t* barrier)
947 {
948    int   ret;
949    OrigFn fn;
950    VALGRIND_GET_ORIG_FN(fn);
951    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_WAIT,
952                                    barrier, pthread_barrier, 0, 0, 0);
953    CALL_FN_W_W(ret, fn, barrier);
954    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_WAIT,
955                               barrier, pthread_barrier,
956                               ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD,
957                               ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
958    return ret;
959 }
960 
961 PTH_FUNCS(int, pthreadZubarrierZuwait, pthread_barrier_wait_intercept,
962           (pthread_barrier_t* barrier), (barrier));
963 #endif   // HAVE_PTHREAD_BARRIER_INIT
964 
965 
966 static __always_inline
sem_init_intercept(sem_t * sem,int pshared,unsigned int value)967 int sem_init_intercept(sem_t *sem, int pshared, unsigned int value)
968 {
969    int   ret;
970    OrigFn fn;
971    VALGRIND_GET_ORIG_FN(fn);
972    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT,
973                                    sem, pshared, value, 0, 0);
974    CALL_FN_W_WWW(ret, fn, sem, pshared, value);
975    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT,
976                                    sem, 0, 0, 0, 0);
977    return ret;
978 }
979 
980 PTH_FUNCS(int, semZuinit, sem_init_intercept,
981           (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
982 
983 static __always_inline
sem_destroy_intercept(sem_t * sem)984 int sem_destroy_intercept(sem_t *sem)
985 {
986    int   ret;
987    OrigFn fn;
988    VALGRIND_GET_ORIG_FN(fn);
989    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_DESTROY,
990                                    sem, 0, 0, 0, 0);
991    CALL_FN_W_W(ret, fn, sem);
992    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_DESTROY,
993                                    sem, 0, 0, 0, 0);
994    return ret;
995 }
996 
997 PTH_FUNCS(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
998 
999 static __always_inline
sem_open_intercept(const char * name,int oflag,mode_t mode,unsigned int value)1000 sem_t* sem_open_intercept(const char *name, int oflag, mode_t mode,
1001                           unsigned int value)
1002 {
1003    sem_t *ret;
1004    OrigFn fn;
1005    VALGRIND_GET_ORIG_FN(fn);
1006    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_OPEN,
1007                                    name, oflag, mode, value, 0);
1008    CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value);
1009    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_OPEN,
1010                                    ret != SEM_FAILED ? ret : 0,
1011                                    name, oflag, mode, value);
1012    return ret;
1013 }
1014 
1015 PTH_FUNCS(sem_t *, semZuopen, sem_open_intercept,
1016           (const char *name, int oflag, mode_t mode, unsigned int value),
1017           (name, oflag, mode, value));
1018 
sem_close_intercept(sem_t * sem)1019 static __always_inline int sem_close_intercept(sem_t *sem)
1020 {
1021    int   ret;
1022    OrigFn fn;
1023    VALGRIND_GET_ORIG_FN(fn);
1024    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_CLOSE,
1025                                    sem, 0, 0, 0, 0);
1026    CALL_FN_W_W(ret, fn, sem);
1027    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_CLOSE,
1028                                    sem, 0, 0, 0, 0);
1029    return ret;
1030 }
1031 
1032 PTH_FUNCS(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
1033 
sem_wait_intercept(sem_t * sem)1034 static __always_inline int sem_wait_intercept(sem_t *sem)
1035 {
1036    int   ret;
1037    OrigFn fn;
1038    VALGRIND_GET_ORIG_FN(fn);
1039    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1040                                    sem, 0, 0, 0, 0);
1041    CALL_FN_W_W(ret, fn, sem);
1042    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1043                                    sem, ret == 0, 0, 0, 0);
1044    return ret;
1045 }
1046 
1047 PTH_FUNCS(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1048 
sem_trywait_intercept(sem_t * sem)1049 static __always_inline int sem_trywait_intercept(sem_t *sem)
1050 {
1051    int   ret;
1052    OrigFn fn;
1053    VALGRIND_GET_ORIG_FN(fn);
1054    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1055                                    sem, 0, 0, 0, 0);
1056    CALL_FN_W_W(ret, fn, sem);
1057    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1058                                    sem, ret == 0, 0, 0, 0);
1059    return ret;
1060 }
1061 
1062 PTH_FUNCS(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1063 
1064 static __always_inline
sem_timedwait_intercept(sem_t * sem,const struct timespec * abs_timeout)1065 int sem_timedwait_intercept(sem_t *sem, const struct timespec *abs_timeout)
1066 {
1067    int   ret;
1068    OrigFn fn;
1069    VALGRIND_GET_ORIG_FN(fn);
1070    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1071                                    sem, 0, 0, 0, 0);
1072    CALL_FN_W_WW(ret, fn, sem, abs_timeout);
1073    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1074                                    sem, ret == 0, 0, 0, 0);
1075    return ret;
1076 }
1077 
1078 PTH_FUNCS(int, semZutimedwait, sem_timedwait_intercept,
1079           (sem_t *sem, const struct timespec *abs_timeout),
1080           (sem, abs_timeout));
1081 
sem_post_intercept(sem_t * sem)1082 static __always_inline int sem_post_intercept(sem_t *sem)
1083 {
1084    int   ret;
1085    OrigFn fn;
1086    VALGRIND_GET_ORIG_FN(fn);
1087    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_POST,
1088                                    sem, 0, 0, 0, 0);
1089    CALL_FN_W_W(ret, fn, sem);
1090    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_POST,
1091                                    sem, ret == 0, 0, 0, 0);
1092    return ret;
1093 }
1094 
1095 PTH_FUNCS(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
1096 
1097 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1098    functions have to be conditionally compiled. */
1099 #if defined(HAVE_PTHREAD_RWLOCK_T)
1100 
1101 static __always_inline
pthread_rwlock_init_intercept(pthread_rwlock_t * rwlock,const pthread_rwlockattr_t * attr)1102 int pthread_rwlock_init_intercept(pthread_rwlock_t* rwlock,
1103                                   const pthread_rwlockattr_t* attr)
1104 {
1105    int   ret;
1106    OrigFn fn;
1107    VALGRIND_GET_ORIG_FN(fn);
1108    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT,
1109                                    rwlock, 0, 0, 0, 0);
1110    CALL_FN_W_WW(ret, fn, rwlock, attr);
1111    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT,
1112                                    rwlock, 0, 0, 0, 0);
1113    return ret;
1114 }
1115 
1116 PTH_FUNCS(int,
1117           pthreadZurwlockZuinit, pthread_rwlock_init_intercept,
1118           (pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr),
1119           (rwlock, attr));
1120 
1121 static __always_inline
pthread_rwlock_destroy_intercept(pthread_rwlock_t * rwlock)1122 int pthread_rwlock_destroy_intercept(pthread_rwlock_t* rwlock)
1123 {
1124    int   ret;
1125    OrigFn fn;
1126    VALGRIND_GET_ORIG_FN(fn);
1127    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_DESTROY,
1128                                    rwlock, 0, 0, 0, 0);
1129    CALL_FN_W_W(ret, fn, rwlock);
1130    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_DESTROY,
1131                                    rwlock, 0, 0, 0, 0);
1132    return ret;
1133 }
1134 
1135 PTH_FUNCS(int,
1136           pthreadZurwlockZudestroy, pthread_rwlock_destroy_intercept,
1137           (pthread_rwlock_t* rwlock), (rwlock));
1138 
1139 static __always_inline
pthread_rwlock_rdlock_intercept(pthread_rwlock_t * rwlock)1140 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t* rwlock)
1141 {
1142    int   ret;
1143    OrigFn fn;
1144    VALGRIND_GET_ORIG_FN(fn);
1145    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1146                                    rwlock, 0, 0, 0, 0);
1147    CALL_FN_W_W(ret, fn, rwlock);
1148    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1149                                    rwlock, ret == 0, 0, 0, 0);
1150    return ret;
1151 }
1152 
1153 PTH_FUNCS(int,
1154           pthreadZurwlockZurdlock, pthread_rwlock_rdlock_intercept,
1155           (pthread_rwlock_t* rwlock), (rwlock));
1156 
1157 static __always_inline
pthread_rwlock_wrlock_intercept(pthread_rwlock_t * rwlock)1158 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t* rwlock)
1159 {
1160    int   ret;
1161    OrigFn fn;
1162    VALGRIND_GET_ORIG_FN(fn);
1163    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1164                                    rwlock, 0, 0, 0, 0);
1165    CALL_FN_W_W(ret, fn, rwlock);
1166    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1167                                    rwlock, ret == 0, 0, 0, 0);
1168    return ret;
1169 }
1170 
1171 PTH_FUNCS(int,
1172           pthreadZurwlockZuwrlock, pthread_rwlock_wrlock_intercept,
1173           (pthread_rwlock_t* rwlock), (rwlock));
1174 
1175 static __always_inline
pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t * rwlock,const struct timespec * timeout)1176 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t* rwlock,
1177                                          const struct timespec *timeout)
1178 {
1179    int   ret;
1180    OrigFn fn;
1181    VALGRIND_GET_ORIG_FN(fn);
1182    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1183                                    rwlock, 0, 0, 0, 0);
1184    CALL_FN_W_WW(ret, fn, rwlock, timeout);
1185    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1186                                    rwlock, ret == 0, 0, 0, 0);
1187    return ret;
1188 }
1189 
1190 PTH_FUNCS(int,
1191           pthreadZurwlockZutimedrdlock, pthread_rwlock_timedrdlock_intercept,
1192           (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1193           (rwlock, timeout));
1194 
1195 static __always_inline
pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t * rwlock,const struct timespec * timeout)1196 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t* rwlock,
1197                                          const struct timespec *timeout)
1198 {
1199    int   ret;
1200    OrigFn fn;
1201    VALGRIND_GET_ORIG_FN(fn);
1202    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1203                                    rwlock, 0, 0, 0, 0);
1204    CALL_FN_W_WW(ret, fn, rwlock, timeout);
1205    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1206                                    rwlock, ret == 0, 0, 0, 0);
1207    return ret;
1208 }
1209 
1210 PTH_FUNCS(int,
1211           pthreadZurwlockZutimedwrlock, pthread_rwlock_timedwrlock_intercept,
1212           (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1213           (rwlock, timeout));
1214 
1215 static __always_inline
pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t * rwlock)1216 int pthread_rwlock_tryrdlock_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_RDLOCK,
1222                                    rwlock, 0, 0, 0, 0);
1223    CALL_FN_W_W(ret, fn, rwlock);
1224    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1225                                    rwlock, ret == 0, 0, 0, 0);
1226    return ret;
1227 }
1228 
1229 PTH_FUNCS(int,
1230           pthreadZurwlockZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1231           (pthread_rwlock_t* rwlock), (rwlock));
1232 
1233 static __always_inline
pthread_rwlock_trywrlock_intercept(pthread_rwlock_t * rwlock)1234 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t* rwlock)
1235 {
1236    int   ret;
1237    OrigFn fn;
1238    VALGRIND_GET_ORIG_FN(fn);
1239    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1240                                    rwlock, 0, 0, 0, 0);
1241    CALL_FN_W_W(ret, fn, rwlock);
1242    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1243                                    rwlock, ret == 0, 0, 0, 0);
1244    return ret;
1245 }
1246 
1247 PTH_FUNCS(int,
1248           pthreadZurwlockZutrywrlock, pthread_rwlock_trywrlock_intercept,
1249           (pthread_rwlock_t* rwlock), (rwlock));
1250 
1251 static __always_inline
pthread_rwlock_unlock_intercept(pthread_rwlock_t * rwlock)1252 int pthread_rwlock_unlock_intercept(pthread_rwlock_t* rwlock)
1253 {
1254    int   ret;
1255    OrigFn fn;
1256    VALGRIND_GET_ORIG_FN(fn);
1257    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_UNLOCK,
1258                                    rwlock, 0, 0, 0, 0);
1259    CALL_FN_W_W(ret, fn, rwlock);
1260    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_UNLOCK,
1261                                    rwlock, ret == 0, 0, 0, 0);
1262    return ret;
1263 }
1264 
1265 PTH_FUNCS(int,
1266           pthreadZurwlockZuunlock, pthread_rwlock_unlock_intercept,
1267           (pthread_rwlock_t* rwlock), (rwlock));
1268 
1269 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
1270