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