• 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-2015 Bart Van Assche <bvanassche@acm.org>.
9 
10   This program is free software; you can redistribute it and/or
11   modify it under the terms of the GNU General Public License as
12   published by the Free Software Foundation; either version 2 of the
13   License, or (at your option) any later version.
14 
15   This program is distributed in the hope that it will be useful, but
16   WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18   General Public License for more details.
19 
20   You should have received a copy of the GNU General Public License
21   along with this program; if not, write to the Free Software
22   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
23   02111-1307, USA.
24 
25   The GNU General Public License is contained in the file COPYING.
26 */
27 
28 /* ---------------------------------------------------------------------
29    ALL THE CODE IN THIS FILE RUNS ON THE SIMULATED CPU.
30 
31    These functions are not called directly - they're the targets of code
32    redirection or load notifications (see pub_core_redir.h for info).
33    They're named weirdly so that the intercept code can find them when the
34    shared object is initially loaded.
35 
36    Note that this filename has the "drd_" prefix because it can appear
37    in stack traces, and the "drd_" makes it a little clearer that it
38    originates from Valgrind.
39    ------------------------------------------------------------------ */
40 
41 /*
42  * Define _GNU_SOURCE to make sure that pthread_spinlock_t is available when
43  * compiling with older glibc versions (2.3 or before).
44  */
45 #ifndef _GNU_SOURCE
46 #define _GNU_SOURCE
47 #endif
48 
49 #include <assert.h>         /* assert() */
50 #include <errno.h>
51 #include <pthread.h>        /* pthread_mutex_t */
52 #include <semaphore.h>      /* sem_t */
53 #include <stdint.h>         /* uintptr_t */
54 #include <stdio.h>          /* fprintf() */
55 #include <stdlib.h>         /* malloc(), free() */
56 #include <unistd.h>         /* confstr() */
57 #include "config.h"         /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP etc. */
58 #include "drd_basics.h"     /* DRD_() */
59 #include "drd_clientreq.h"
60 #include "pub_tool_redir.h" /* VG_WRAP_FUNCTION_ZZ() */
61 
62 #if defined(VGO_solaris)
63 /*
64  * Solaris usually provides pthread_* functions on top of Solaris threading
65  * and synchronization functions. Usually both need to be intercepted because
66  * pthread_* ones might not call the Solaris ones (see for example sem_wait()).
67  * Such approach is required to correctly report misuse of the POSIX threads
68  * API.
69  * Therefore DRD intercepts and instruments all such functions but due to
70  * DRD_(thread_enter_synchr)() and DRD_(thread_leave_synchr)() guards in
71  * handle_client_request(), only the top-most function is handled.
72  * So the right thing(TM) happens, as expected.
73  * The only exception is when pthread_* function is a weak alias to the Solaris
74  * threading/synchronization function. In such case only one needs to be
75  * intercepted to avoid redirection ambiguity.
76  *
77  * Intercepted functions rely on the fact that:
78  *  - pthread_mutex_t  == mutex_t
79  *  - pthread_cond_t   == cond_t
80  *  - sem_t            == sema_t
81  *  - pthread_rwlock_t == rwlock_t
82  *
83  * It is necessary to intercept also internal libc synchronization functions
84  * for two reasons:
85  *  - For read-write locks the unlocking function is shared
86  *  - Functions lmutex_lock/lmutex_unlock guard many critical sections in libc
87  *    which will be otherwise reported by DRD
88  */
89 #include <synch.h>
90 #include <thread.h>
91 #include "pub_tool_vki.h"
92 
93 /*
94  * Solaris provides higher throughput, parallelism and scalability than other
95  * operating systems, at the cost of more fine-grained locking activity.
96  * This means for example that when a thread is created under Linux, just one
97  * big lock in glibc is used for all thread setup. Solaris libc uses several
98  * fine-grained locks and the creator thread resumes its activities as soon
99  * as possible, leaving for example stack and TLS setup activities to the
100  * created thread.
101  *
102  * This situation confuses DRD as it assumes there is some false ordering
103  * in place between creator and created thread; and therefore many types of
104  * race conditions in the application would not be reported. To prevent such
105  * false ordering, command line option --ignore-thread-creation is set to
106  * 'yes' by default on Solaris. All activity (loads, stores, client requests)
107  * is therefore ignored during:
108  * - pthread_create() call in the creator thread [libc.so]
109  * - thread creation phase (stack and TLS setup) in the created thread [libc.so]
110  *
111  * As explained in the comments for _ti_bind_guard(), whenever the runtime
112  * linker has to perform any activity (such as resolving a symbol), it protects
113  * its data structures by calling into rt_bind_guard() which in turn invokes
114  * _ti_bind_guard() in libc. Pointers to _ti_bind_guard() and _ti_bind_clear()
115  * are passed from libc to runtime linker in _ld_libc() call during libc_init().
116  * All activity is also ignored during:
117  * - runtime dynamic linker work between rt_bind_guard() and rt_bind_clear()
118  *   calls [ld.so]
119  *
120  * This also means that DRD does not report race conditions in libc (when
121  * --ignore-thread-creation=yes) and runtime linker itself (unconditionally)
122  * during these ignored sequences.
123  */
124 
125 /*
126  * Original function pointers for _ti_bind_guard() and _ti_bind_clear()
127  * from libc. They are intercepted in function wrapper of _ld_libc().
128  */
129 typedef int (*drd_rtld_guard_fn)(int flags);
130 static drd_rtld_guard_fn DRD_(rtld_bind_guard) = NULL;
131 static drd_rtld_guard_fn DRD_(rtld_bind_clear) = NULL;
132 #endif
133 
134 
135 /*
136  * Notes regarding thread creation:
137  * - sg_init() runs on the context of the created thread and copies the vector
138  *   clock of the creator thread. This only works reliably if the creator
139  *   thread waits until this copy has been performed.
140  * - DRD_(thread_compute_minimum_vc)() does not take the vector clocks into
141  *   account that are involved in thread creation and for which the
142  *   corresponding thread has not yet been created. So not waiting until the
143  *   created thread has been started would make it possible that segments get
144  *   discarded that should not yet be discarded. Or: some data races are not
145  *   detected.
146  */
147 
148 /**
149  * Macro for generating a Valgrind interception function.
150  * @param[in] ret_ty Return type of the function to be generated.
151  * @param[in] zf Z-encoded name of the interception function.
152  * @param[in] implf Name of the function that implements the intercept.
153  * @param[in] arg_decl Argument declaration list enclosed in parentheses.
154  * @param[in] argl Argument list enclosed in parentheses.
155  */
156 #ifdef VGO_darwin
157 static int never_true;
158 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl)                    \
159    ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl;     \
160    ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl      \
161    {									\
162       ret_ty pth_func_result = implf argl;				\
163       /* Apparently inserting a function call in wrapper functions */   \
164       /* is sufficient to avoid misaligned stack errors.           */	\
165       if (never_true)							\
166 	 fflush(stdout);						\
167       return pth_func_result;						\
168    }
169 #elif defined(VGO_solaris)
170 /* On Solaris, libpthread is just a filter library on top of libc.
171  * Threading and synchronization functions in runtime linker are not
172  * intercepted.
173  */
174 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl)                    \
175    ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl;           \
176    ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl            \
177    { return implf argl; }
178 #else
179 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl)                    \
180    ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl;     \
181    ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl      \
182    { return implf argl; }
183 #endif
184 
185 /**
186  * Macro for generating three Valgrind interception functions: one with the
187  * Z-encoded name zf, one with ZAZa ("@*") appended to the name zf and one
188  * with ZDZa ("$*") appended to the name zf. The second generated interception
189  * function will intercept versioned symbols on Linux, and the third will
190  * intercept versioned symbols on Darwin.
191  */
192 #define PTH_FUNCS(ret_ty, zf, implf, argl_decl, argl)           \
193    PTH_FUNC(ret_ty, zf, implf, argl_decl, argl);                \
194    PTH_FUNC(ret_ty, zf ## ZAZa, implf, argl_decl, argl);        \
195    PTH_FUNC(ret_ty, zf ## ZDZa, implf, argl_decl, argl);
196 
197 /*
198  * Not inlining one of the intercept functions will cause the regression
199  * tests to fail because this would cause an additional stackfram to appear
200  * in the output. The __always_inline macro guarantees that inlining will
201  * happen, even when compiling with optimization disabled.
202  */
203 #undef __always_inline /* since already defined in <cdefs.h> */
204 #if __GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 2
205 #define __always_inline __inline__ __attribute__((always_inline))
206 #else
207 #define __always_inline __inline__
208 #endif
209 
210 /* Local data structures. */
211 
212 typedef struct {
213    pthread_mutex_t mutex;
214    pthread_cond_t cond;
215    int counter;
216 } DrdSema;
217 
218 typedef struct
219 {
220    void* (*start)(void*);
221    void* arg;
222    int   detachstate;
223    DrdSema* wrapper_started;
224 } DrdPosixThreadArgs;
225 
226 
227 /* Local function declarations. */
228 
229 static void DRD_(init)(void) __attribute__((constructor));
230 static void DRD_(check_threading_library)(void);
231 static void DRD_(set_main_thread_state)(void);
232 static void DRD_(sema_init)(DrdSema* sema);
233 static void DRD_(sema_destroy)(DrdSema* sema);
234 static void DRD_(sema_down)(DrdSema* sema);
235 static void DRD_(sema_up)(DrdSema* sema);
236 
237 
238 /* Function definitions. */
239 
240 /**
241  * Shared library initialization function. The function init() is called after
242  * dlopen() has loaded the shared library with DRD client intercepts because
243  * the constructor attribute was specified in the declaration of this function.
244  * Note: do specify the -nostdlib option to gcc when linking this code into a
245  * shared library because doing so would cancel the effect of the constructor
246  * attribute ! Using the gcc option -nodefaultlibs is fine because this last
247  * option preserves the shared library initialization code that calls
248  * constructor and destructor functions.
249  */
DRD_(init)250 static void DRD_(init)(void)
251 {
252    DRD_(check_threading_library)();
253    DRD_(set_main_thread_state)();
254 #if defined(VGO_solaris)
255    if ((DRD_(rtld_bind_guard) == NULL) || (DRD_(rtld_bind_clear) == NULL)) {
256       fprintf(stderr,
257 "Bind guard functions for the runtime linker (ld.so.1) were not intercepted.\n"
258 "This means the interface between libc and runtime linker changed and DRD\n"
259 "needs to be ported properly. Giving up.\n");
260       abort();
261    }
262 #endif
263 }
264 
DRD_(ignore_mutex_ordering)265 static __always_inline void DRD_(ignore_mutex_ordering)(pthread_mutex_t *mutex)
266 {
267    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_IGNORE_MUTEX_ORDERING,
268                                    mutex, 0, 0, 0, 0);
269 }
270 
DRD_(sema_init)271 static void DRD_(sema_init)(DrdSema* sema)
272 {
273    DRD_IGNORE_VAR(*sema);
274    pthread_mutex_init(&sema->mutex, NULL);
275    DRD_(ignore_mutex_ordering)(&sema->mutex);
276    pthread_cond_init(&sema->cond, NULL);
277    sema->counter = 0;
278 }
279 
DRD_(sema_destroy)280 static void DRD_(sema_destroy)(DrdSema* sema)
281 {
282    pthread_mutex_destroy(&sema->mutex);
283    pthread_cond_destroy(&sema->cond);
284 }
285 
DRD_(sema_down)286 static void DRD_(sema_down)(DrdSema* sema)
287 {
288    pthread_mutex_lock(&sema->mutex);
289    while (sema->counter == 0)
290       pthread_cond_wait(&sema->cond, &sema->mutex);
291    sema->counter--;
292    pthread_mutex_unlock(&sema->mutex);
293 }
294 
DRD_(sema_up)295 static void DRD_(sema_up)(DrdSema* sema)
296 {
297    pthread_mutex_lock(&sema->mutex);
298    sema->counter++;
299    pthread_cond_signal(&sema->cond);
300    pthread_mutex_unlock(&sema->mutex);
301 }
302 
303 /**
304  * POSIX threads and DRD each have their own mutex type identification.
305  * Convert POSIX threads' mutex type to DRD's mutex type. In the code below
306  * if-statements are used to test the value of 'kind' instead of a switch
307  * statement because some of the PTHREAD_MUTEX_ macro's may have the same
308  * value.
309  */
DRD_(pthread_to_drd_mutex_type)310 static MutexT DRD_(pthread_to_drd_mutex_type)(int kind)
311 {
312    /*
313     * See also PTHREAD_MUTEX_KIND_MASK_NP in glibc source file
314     * <nptl/pthreadP.h>.
315     */
316    kind &= PTHREAD_MUTEX_RECURSIVE | PTHREAD_MUTEX_ERRORCHECK |
317       PTHREAD_MUTEX_NORMAL | PTHREAD_MUTEX_DEFAULT;
318 
319    if (kind == PTHREAD_MUTEX_RECURSIVE)
320       return mutex_type_recursive_mutex;
321    else if (kind == PTHREAD_MUTEX_ERRORCHECK)
322       return mutex_type_errorcheck_mutex;
323    else if (kind == PTHREAD_MUTEX_NORMAL)
324       return mutex_type_default_mutex;
325    else if (kind == PTHREAD_MUTEX_DEFAULT)
326       return mutex_type_default_mutex;
327 #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
328    else if (kind == PTHREAD_MUTEX_ADAPTIVE_NP)
329       return mutex_type_default_mutex;
330 #endif
331    else
332       return mutex_type_invalid_mutex;
333 }
334 
335 #if defined(VGO_solaris)
336 /**
337  * Solaris threads and DRD each have their own mutex type identification.
338  * Convert Solaris threads' mutex type to DRD's mutex type.
339  */
DRD_(thread_to_drd_mutex_type)340 static MutexT DRD_(thread_to_drd_mutex_type)(int type)
341 {
342    if (type & LOCK_RECURSIVE) {
343       return mutex_type_recursive_mutex;
344    } else if (type & LOCK_ERRORCHECK) {
345       return mutex_type_errorcheck_mutex;
346    } else {
347       return mutex_type_default_mutex;
348    }
349 }
350 #endif /* VGO_solaris */
351 
352 #define IS_ALIGNED(p) (((uintptr_t)(p) & (sizeof(*(p)) - 1)) == 0)
353 
354 /**
355  * Read the mutex type stored in the client memory used for the mutex
356  * implementation.
357  *
358  * @note This function depends on the implementation of the POSIX threads
359  *   library -- the POSIX standard does not define the name of the member in
360  *   which the mutex type is stored.
361  * @note The function mutex_type() has been declared inline in order
362  *   to avoid that it shows up in call stacks (drd/tests/...exp* files).
363  * @note glibc stores the mutex type in the lowest two bits, and uses the
364  *   higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
365  *   PTHREAD_MUTEXATTR_FLAG_PSHARED.
366  */
DRD_(mutex_type)367 static __always_inline MutexT DRD_(mutex_type)(pthread_mutex_t* mutex)
368 {
369 #if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
370    /* glibc + LinuxThreads. */
371    if (IS_ALIGNED(&mutex->__m_kind))
372    {
373       const int kind = mutex->__m_kind & 3;
374       return DRD_(pthread_to_drd_mutex_type)(kind);
375    }
376 #elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
377    /* glibc + NPTL. */
378    if (IS_ALIGNED(&mutex->__data.__kind))
379    {
380       const int kind = mutex->__data.__kind & 3;
381       return DRD_(pthread_to_drd_mutex_type)(kind);
382    }
383 #elif defined(VGO_solaris)
384       const int type = ((mutex_t *) mutex)->vki_mutex_type;
385       return DRD_(thread_to_drd_mutex_type)(type);
386 #else
387    /*
388     * Another POSIX threads implementation. The mutex type won't be printed
389     * when enabling --trace-mutex=yes.
390     */
391 #endif
392    return mutex_type_unknown;
393 }
394 
395 /**
396  * Tell DRD whether 'tid' is a joinable thread or a detached thread.
397  */
DRD_(set_joinable)398 static void DRD_(set_joinable)(const pthread_t tid, const int joinable)
399 {
400    assert(joinable == 0 || joinable == 1);
401    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_JOINABLE,
402                                    tid, joinable, 0, 0, 0);
403 }
404 
405 /** Tell DRD that the calling thread is about to enter pthread_create(). */
DRD_(entering_pthread_create)406 static __always_inline void DRD_(entering_pthread_create)(void)
407 {
408    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__ENTERING_PTHREAD_CREATE,
409                                    0, 0, 0, 0, 0);
410 }
411 
412 /** Tell DRD that the calling thread has left pthread_create(). */
DRD_(left_pthread_create)413 static __always_inline void DRD_(left_pthread_create)(void)
414 {
415    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LEFT_PTHREAD_CREATE,
416                                    0, 0, 0, 0, 0);
417 }
418 
419 /**
420  * Entry point for newly created threads. This function is called from the
421  * thread created by pthread_create().
422  */
DRD_(thread_wrapper)423 static void* DRD_(thread_wrapper)(void* arg)
424 {
425    DrdPosixThreadArgs* arg_ptr;
426    DrdPosixThreadArgs arg_copy;
427 
428    arg_ptr = (DrdPosixThreadArgs*)arg;
429    arg_copy = *arg_ptr;
430 
431    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
432                                    pthread_self(), 0, 0, 0, 0);
433 
434    DRD_(set_joinable)(pthread_self(),
435                       arg_copy.detachstate == PTHREAD_CREATE_JOINABLE);
436 
437    /*
438     * Only set 'wrapper_started' after VG_USERREQ__SET_PTHREADID and
439     * DRD_(set_joinable)() have been invoked to avoid a race with
440     * a pthread_detach() invocation for this thread from another thread.
441     */
442    DRD_(sema_up)(arg_copy.wrapper_started);
443 
444    return (arg_copy.start)(arg_copy.arg);
445 }
446 
447 /**
448  * Return 1 if the LinuxThreads implementation of POSIX Threads has been
449  * detected, and 0 otherwise.
450  *
451  * @see For more information about the confstr() function, see also
452  * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
453  */
DRD_(detected_linuxthreads)454 static int DRD_(detected_linuxthreads)(void)
455 {
456 #if defined(linux)
457 #if defined(_CS_GNU_LIBPTHREAD_VERSION)
458    /* Linux with a recent glibc. */
459    HChar buffer[256];
460    unsigned len;
461    len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
462    assert(len <= sizeof(buffer));
463    return len > 0 && buffer[0] == 'l';
464 #else
465    /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
466    return 1;
467 #endif
468 #else
469    /* Another OS than Linux, hence no LinuxThreads. */
470    return 0;
471 #endif
472 }
473 
474 /**
475  * Stop and print an error message in case a non-supported threading
476  * library implementation (LinuxThreads) has been detected.
477  */
DRD_(check_threading_library)478 static void DRD_(check_threading_library)(void)
479 {
480    if (DRD_(detected_linuxthreads)())
481    {
482       if (getenv("LD_ASSUME_KERNEL"))
483       {
484          fprintf(stderr,
485 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
486 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
487 "after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
488 );
489       }
490       else
491       {
492          fprintf(stderr,
493 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
494 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
495 "after having upgraded to a newer version of your Linux distribution.\n"
496 "Giving up.\n"
497 );
498       }
499       abort();
500    }
501 }
502 
503 /**
504  * The main thread is the only thread not created by pthread_create().
505  * Update DRD's state information about the main thread.
506  */
DRD_(set_main_thread_state)507 static void DRD_(set_main_thread_state)(void)
508 {
509    // Make sure that DRD knows about the main thread's POSIX thread ID.
510    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
511                                    pthread_self(), 0, 0, 0, 0);
512 }
513 
514 /*
515  * Note: as of today there exist three different versions of pthread_create
516  * in Linux:
517  * - pthread_create@GLIBC_2.0
518  * - pthread_create@@GLIBC_2.1
519  * - pthread_create@@GLIBC_2.2.5
520  * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
521  * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
522  * versions have been implemented. In any glibc version where more than one
523  * pthread_create function has been implemented, older versions call the
524  * newer versions. Or: the pthread_create* wrapper defined below can be
525  * called recursively. Any code in this wrapper should take this in account.
526  * As an example, it is not safe to invoke the DRD_STOP_RECORDING
527  * / DRD_START_RECORDING client requests from the pthread_create wrapper.
528  * See also the implementation of pthread_create@GLIBC_2.0 in
529  * glibc-2.9/nptl/pthread_create.c.
530  */
531 
532 static __always_inline
pthread_create_intercept(pthread_t * thread,const pthread_attr_t * attr,void * (* start)(void *),void * arg)533 int pthread_create_intercept(pthread_t* thread, const pthread_attr_t* attr,
534                              void* (*start)(void*), void* arg)
535 {
536    int    ret;
537    OrigFn fn;
538    DrdSema wrapper_started;
539    DrdPosixThreadArgs thread_args;
540 
541    VALGRIND_GET_ORIG_FN(fn);
542 
543    DRD_(sema_init)(&wrapper_started);
544    thread_args.start           = start;
545    thread_args.arg             = arg;
546    thread_args.wrapper_started = &wrapper_started;
547    /*
548     * Find out whether the thread will be started as a joinable thread
549     * or as a detached thread. If no thread attributes have been specified,
550     * this means that the new thread will be started as a joinable thread.
551     */
552    thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
553    if (attr)
554    {
555       if (pthread_attr_getdetachstate(attr, &thread_args.detachstate) != 0)
556          assert(0);
557    }
558    assert(thread_args.detachstate == PTHREAD_CREATE_JOINABLE
559           || thread_args.detachstate == PTHREAD_CREATE_DETACHED);
560 
561    DRD_(entering_pthread_create)();
562    CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), &thread_args);
563    DRD_(left_pthread_create)();
564 
565    if (ret == 0) {
566       /* Wait until the thread wrapper started. */
567       DRD_(sema_down)(&wrapper_started);
568    }
569 
570    DRD_(sema_destroy)(&wrapper_started);
571 
572    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT,
573                                    pthread_self(), 0, 0, 0, 0);
574 
575    return ret;
576 }
577 
578 PTH_FUNCS(int, pthreadZucreate, pthread_create_intercept,
579           (pthread_t *thread, const pthread_attr_t *attr,
580            void *(*start) (void *), void *arg),
581           (thread, attr, start, arg));
582 
583 #if defined(VGO_solaris)
584 /* Solaris also provides thr_create() in addition to pthread_create().
585  * Both pthread_create(3C) and thr_create(3C) are based on private
586  * _thrp_create().
587  */
588 static __always_inline
thr_create_intercept(void * stk,size_t stksize,void * (* start)(void *),void * arg,long flags,thread_t * new_thread)589 int thr_create_intercept(void *stk, size_t stksize, void *(*start)(void *),
590                          void *arg, long flags, thread_t *new_thread)
591 {
592    int                ret;
593    OrigFn             fn;
594    DrdSema            wrapper_started;
595    DrdPosixThreadArgs thread_args;
596 
597    VALGRIND_GET_ORIG_FN(fn);
598 
599    DRD_(sema_init)(&wrapper_started);
600    thread_args.start           = start;
601    thread_args.arg             = arg;
602    thread_args.wrapper_started = &wrapper_started;
603    /*
604     * Find out whether the thread will be started as a joinable thread
605     * or as a detached thread.
606     */
607    if (flags & THR_DETACHED)
608       thread_args.detachstate = PTHREAD_CREATE_DETACHED;
609    else
610       thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
611 
612    DRD_(entering_pthread_create)();
613    CALL_FN_W_6W(ret, fn, stk, stksize, DRD_(thread_wrapper), &thread_args,
614                 flags, new_thread);
615    DRD_(left_pthread_create)();
616 
617    if (ret == 0) {
618       /* Wait until the thread wrapper started. */
619       DRD_(sema_down)(&wrapper_started);
620    }
621 
622    DRD_(sema_destroy)(&wrapper_started);
623 
624    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT,
625                                    pthread_self(), 0, 0, 0, 0);
626 
627    return ret;
628 }
629 
630 PTH_FUNCS(int, thrZucreate, thr_create_intercept,
631           (void *stk, size_t stksize, void *(*start)(void *), void *arg,
632            long flags, thread_t *new_thread),
633           (stk, stksize, start, arg, flags, new_thread));
634 #endif /* VGO_solaris */
635 
636 #if defined(VGO_solaris)
637 /*
638  * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
639  * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
640  * and CI_BIND_CLEAR, to provide resilience against function renaming.
641  */
642 static __always_inline
DRD_(_ti_bind_guard_intercept)643 int DRD_(_ti_bind_guard_intercept)(int flags) {
644    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_GUARD,
645                                    flags, 0, 0, 0, 0);
646    return DRD_(rtld_bind_guard)(flags);
647 }
648 
649 static __always_inline
DRD_(_ti_bind_clear_intercept)650 int DRD_(_ti_bind_clear_intercept)(int flags) {
651    int ret = DRD_(rtld_bind_clear)(flags);
652    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_CLEAR,
653                                    flags, 0, 0, 0, 0);
654    return ret;
655 }
656 
657 /*
658  * Wrapped _ld_libc() from the runtime linker ld.so.1.
659  */
660 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr);
VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1,ZuldZulibc)661 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr)
662 {
663    OrigFn fn;
664    int    tag;
665 
666    VALGRIND_GET_ORIG_FN(fn);
667 
668    vki_Lc_interface *funcs = ptr;
669    for (tag = funcs->ci_tag; tag != 0; tag = (++funcs)->ci_tag) {
670       switch (tag) {
671       case VKI_CI_BIND_GUARD:
672          if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_guard_intercept)) {
673             DRD_(rtld_bind_guard) = funcs->vki_ci_un.ci_func;
674             funcs->vki_ci_un.ci_func = DRD_(_ti_bind_guard_intercept);
675          }
676          break;
677       case VKI_CI_BIND_CLEAR:
678          if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_clear_intercept)) {
679             DRD_(rtld_bind_clear) = funcs->vki_ci_un.ci_func;
680             funcs->vki_ci_un.ci_func = DRD_(_ti_bind_clear_intercept);
681          }
682          break;
683       }
684    }
685 
686    CALL_FN_v_W(fn, ptr);
687 }
688 #endif /* VGO_solaris */
689 
690 static __always_inline
pthread_join_intercept(pthread_t pt_joinee,void ** thread_return)691 int pthread_join_intercept(pthread_t pt_joinee, void **thread_return)
692 {
693    int      ret;
694    OrigFn   fn;
695 
696    VALGRIND_GET_ORIG_FN(fn);
697    /*
698     * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
699     * implementation triggers a (false positive) race report.
700     */
701    ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
702    CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
703    if (ret == 0)
704    {
705       VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN,
706                                       pt_joinee, 0, 0, 0, 0);
707    }
708    ANNOTATE_IGNORE_READS_AND_WRITES_END();
709    return ret;
710 }
711 
712 PTH_FUNCS(int, pthreadZujoin, pthread_join_intercept,
713           (pthread_t pt_joinee, void **thread_return),
714           (pt_joinee, thread_return));
715 
716 #if defined(VGO_solaris)
717 /* Solaris also provides thr_join() in addition to pthread_join().
718  * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
719  *
720  * :TODO: No functionality is currently provided for joinee == 0 and departed.
721  *        This would require another client request, of course.
722  */
723 static __always_inline
thr_join_intercept(thread_t joinee,thread_t * departed,void ** thread_return)724 int thr_join_intercept(thread_t joinee, thread_t *departed, void **thread_return)
725 {
726    int      ret;
727    OrigFn   fn;
728 
729    VALGRIND_GET_ORIG_FN(fn);
730    CALL_FN_W_WWW(ret, fn, joinee, departed, thread_return);
731    if (ret == 0)
732    {
733       VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN,
734                                       joinee, 0, 0, 0, 0);
735    }
736    return ret;
737 }
738 
739 PTH_FUNCS(int, thrZujoin, thr_join_intercept,
740           (thread_t joinee, thread_t *departed, void **thread_return),
741           (joinee, departed, thread_return));
742 #endif /* VGO_solaris */
743 
744 static __always_inline
pthread_detach_intercept(pthread_t pt_thread)745 int pthread_detach_intercept(pthread_t pt_thread)
746 {
747    int ret;
748    OrigFn fn;
749 
750    VALGRIND_GET_ORIG_FN(fn);
751    CALL_FN_W_W(ret, fn, pt_thread);
752    DRD_(set_joinable)(pt_thread, 0);
753 
754    return ret;
755 }
756 
757 PTH_FUNCS(int, pthreadZudetach, pthread_detach_intercept,
758           (pthread_t thread), (thread));
759 
760 // NOTE: be careful to intercept only pthread_cancel() and not
761 // pthread_cancel_init() on Linux.
762 
763 static __always_inline
pthread_cancel_intercept(pthread_t pt_thread)764 int pthread_cancel_intercept(pthread_t pt_thread)
765 {
766    int ret;
767    OrigFn fn;
768    VALGRIND_GET_ORIG_FN(fn);
769    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_THREAD_CANCEL,
770                                    pt_thread, 0, 0, 0, 0);
771    CALL_FN_W_W(ret, fn, pt_thread);
772    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_CANCEL,
773                                    pt_thread, ret==0, 0, 0, 0);
774    return ret;
775 }
776 
777 PTH_FUNCS(int, pthreadZucancel, pthread_cancel_intercept,
778           (pthread_t thread), (thread))
779 
780 static __always_inline
pthread_once_intercept(pthread_once_t * once_control,void (* init_routine)(void))781 int pthread_once_intercept(pthread_once_t *once_control,
782                            void (*init_routine)(void))
783 {
784    int ret;
785    OrigFn fn;
786    VALGRIND_GET_ORIG_FN(fn);
787    /*
788     * Ignore any data races triggered by the implementation of pthread_once().
789     * Necessary for Darwin. This is not necessary for Linux but doesn't have
790     * any known adverse effects.
791     */
792    DRD_IGNORE_VAR(*once_control);
793    ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
794    CALL_FN_W_WW(ret, fn, once_control, init_routine);
795    ANNOTATE_IGNORE_READS_AND_WRITES_END();
796    DRD_STOP_IGNORING_VAR(*once_control);
797    return ret;
798 }
799 
800 PTH_FUNCS(int, pthreadZuonce, pthread_once_intercept,
801           (pthread_once_t *once_control, void (*init_routine)(void)),
802           (once_control, init_routine));
803 
804 static __always_inline
pthread_mutex_init_intercept(pthread_mutex_t * mutex,const pthread_mutexattr_t * attr)805 int pthread_mutex_init_intercept(pthread_mutex_t *mutex,
806                                  const pthread_mutexattr_t* attr)
807 {
808    int ret;
809    OrigFn fn;
810    int mt;
811    VALGRIND_GET_ORIG_FN(fn);
812    mt = PTHREAD_MUTEX_DEFAULT;
813    if (attr)
814       pthread_mutexattr_gettype(attr, &mt);
815    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
816                                    mutex, DRD_(pthread_to_drd_mutex_type)(mt),
817                                    0, 0, 0);
818    CALL_FN_W_WW(ret, fn, mutex, attr);
819    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
820                                    mutex, 0, 0, 0, 0);
821    return ret;
822 }
823 
824 PTH_FUNCS(int, pthreadZumutexZuinit, pthread_mutex_init_intercept,
825           (pthread_mutex_t *mutex, const pthread_mutexattr_t* attr),
826           (mutex, attr));
827 
828 #if defined(VGO_solaris)
829 static __always_inline
mutex_init_intercept(mutex_t * mutex,int type,void * arg)830 int mutex_init_intercept(mutex_t *mutex, int type, void *arg)
831 {
832    int ret;
833    OrigFn fn;
834    VALGRIND_GET_ORIG_FN(fn);
835 
836    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
837                                    mutex, DRD_(thread_to_drd_mutex_type)(type),
838                                    0, 0, 0);
839    CALL_FN_W_WWW(ret, fn, mutex, type, arg);
840    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
841                                    mutex, 0, 0, 0, 0);
842    return ret;
843 }
844 
845 PTH_FUNCS(int, mutexZuinit, mutex_init_intercept,
846           (mutex_t *mutex, int type, void *arg),
847           (mutex, type, arg));
848 #endif /* VGO_solaris */
849 
850 static __always_inline
pthread_mutex_destroy_intercept(pthread_mutex_t * mutex)851 int pthread_mutex_destroy_intercept(pthread_mutex_t* mutex)
852 {
853    int ret;
854    OrigFn fn;
855    VALGRIND_GET_ORIG_FN(fn);
856    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
857                                    mutex, 0, 0, 0, 0);
858    CALL_FN_W_W(ret, fn, mutex);
859    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
860                                    mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
861    return ret;
862 }
863 
864 #if defined(VGO_solaris)
865 /* On Solaris, pthread_mutex_destroy is a weak alias to mutex_destroy. */
866 PTH_FUNCS(int, mutexZudestroy, pthread_mutex_destroy_intercept,
867           (pthread_mutex_t *mutex), (mutex));
868 #else
869 PTH_FUNCS(int, pthreadZumutexZudestroy, pthread_mutex_destroy_intercept,
870           (pthread_mutex_t *mutex), (mutex));
871 #endif /* VGO_solaris */
872 
873 static __always_inline
pthread_mutex_lock_intercept(pthread_mutex_t * mutex)874 int pthread_mutex_lock_intercept(pthread_mutex_t* mutex)
875 {
876    int   ret;
877    OrigFn fn;
878    VALGRIND_GET_ORIG_FN(fn);
879    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
880                                    mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
881    CALL_FN_W_W(ret, fn, mutex);
882    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
883                                    mutex, ret == 0, 0, 0, 0);
884    return ret;
885 }
886 
887 #if defined(VGO_solaris)
888 /* On Solaris, pthread_mutex_lock is a weak alias to mutex_lock. */
889 PTH_FUNCS(int, mutexZulock, pthread_mutex_lock_intercept,
890           (pthread_mutex_t *mutex), (mutex));
891 #else
892 PTH_FUNCS(int, pthreadZumutexZulock, pthread_mutex_lock_intercept,
893           (pthread_mutex_t *mutex), (mutex));
894 #endif /* VGO_solaris */
895 
896 #if defined(VGO_solaris)
897 /* Internal to libc. Mutex is usually initialized only implicitly,
898  * by zeroing mutex_t structure.
899  */
900 static __always_inline
lmutex_lock_intercept(mutex_t * mutex)901 void lmutex_lock_intercept(mutex_t *mutex)
902 {
903    OrigFn fn;
904    VALGRIND_GET_ORIG_FN(fn);
905    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
906                                    mutex,
907                                    DRD_(mutex_type)((pthread_mutex_t *) mutex),
908                                    False /* try_lock */, 0, 0);
909    CALL_FN_v_W(fn, mutex);
910    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
911                                    mutex, True /* took_lock */, 0, 0, 0);
912 }
913 
914 PTH_FUNCS(void, lmutexZulock, lmutex_lock_intercept,
915           (mutex_t *mutex), (mutex));
916 #endif /* VGO_solaris */
917 
918 static __always_inline
pthread_mutex_trylock_intercept(pthread_mutex_t * mutex)919 int pthread_mutex_trylock_intercept(pthread_mutex_t* mutex)
920 {
921    int   ret;
922    OrigFn fn;
923    VALGRIND_GET_ORIG_FN(fn);
924    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
925                                    mutex, DRD_(mutex_type)(mutex), 1, 0, 0);
926    CALL_FN_W_W(ret, fn, mutex);
927    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
928                                    mutex, ret == 0, 0, 0, 0);
929    return ret;
930 }
931 
932 #if defined(VGO_solaris)
933 /* On Solaris, pthread_mutex_trylock is a weak alias to mutex_trylock. */
934 PTH_FUNCS(int, mutexZutrylock, pthread_mutex_trylock_intercept,
935           (pthread_mutex_t *mutex), (mutex));
936 #else
937 PTH_FUNCS(int, pthreadZumutexZutrylock, pthread_mutex_trylock_intercept,
938           (pthread_mutex_t *mutex), (mutex));
939 #endif /* VGO_solaris */
940 
941 static __always_inline
pthread_mutex_timedlock_intercept(pthread_mutex_t * mutex,const struct timespec * abs_timeout)942 int pthread_mutex_timedlock_intercept(pthread_mutex_t *mutex,
943                                       const struct timespec *abs_timeout)
944 {
945    int   ret;
946    OrigFn fn;
947    VALGRIND_GET_ORIG_FN(fn);
948    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
949                                    mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
950    CALL_FN_W_WW(ret, fn, mutex, abs_timeout);
951    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
952                                    mutex, ret == 0, 0, 0, 0);
953    return ret;
954 }
955 
956 PTH_FUNCS(int, pthreadZumutexZutimedlock, pthread_mutex_timedlock_intercept,
957           (pthread_mutex_t *mutex, const struct timespec *abs_timeout),
958           (mutex, abs_timeout));
959 #if defined(VGO_solaris)
960 PTH_FUNCS(int,
961           pthreadZumutexZureltimedlockZunp, pthread_mutex_timedlock_intercept,
962           (pthread_mutex_t *mutex, const struct timespec *timeout),
963           (mutex, timeout));
964 #endif /* VGO_solaris */
965 
966 static __always_inline
pthread_mutex_unlock_intercept(pthread_mutex_t * mutex)967 int pthread_mutex_unlock_intercept(pthread_mutex_t *mutex)
968 {
969    int ret;
970    OrigFn fn;
971    VALGRIND_GET_ORIG_FN(fn);
972    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
973                                    mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
974    CALL_FN_W_W(ret, fn, mutex);
975    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
976                                    mutex, 0, 0, 0, 0);
977    return ret;
978 }
979 
980 #if defined(VGO_solaris)
981 /* On Solaris, pthread_mutex_unlock is a weak alias to mutex_unlock. */
982 PTH_FUNCS(int, mutexZuunlock, pthread_mutex_unlock_intercept,
983           (pthread_mutex_t *mutex), (mutex));
984 #else
985 PTH_FUNCS(int, pthreadZumutexZuunlock, pthread_mutex_unlock_intercept,
986           (pthread_mutex_t *mutex), (mutex));
987 #endif /* VGO_solaris */
988 
989 #if defined(VGO_solaris)
990 /* Internal to libc. */
991 static __always_inline
lmutex_unlock_intercept(mutex_t * mutex)992 void lmutex_unlock_intercept(mutex_t *mutex)
993 {
994    OrigFn fn;
995    VALGRIND_GET_ORIG_FN(fn);
996    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
997                                    mutex,
998                                    DRD_(mutex_type)((pthread_mutex_t *) mutex),
999                                    0, 0, 0);
1000    CALL_FN_v_W(fn, mutex);
1001    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
1002                                    mutex, 0, 0, 0, 0);
1003 }
1004 
1005 PTH_FUNCS(void, lmutexZuunlock, lmutex_unlock_intercept,
1006           (mutex_t *mutex), (mutex));
1007 #endif /* VGO_solaris */
1008 
1009 static __always_inline
pthread_cond_init_intercept(pthread_cond_t * cond,const pthread_condattr_t * attr)1010 int pthread_cond_init_intercept(pthread_cond_t* cond,
1011                                 const pthread_condattr_t* attr)
1012 {
1013    int ret;
1014    OrigFn fn;
1015    VALGRIND_GET_ORIG_FN(fn);
1016    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT,
1017                                    cond, 0, 0, 0, 0);
1018    CALL_FN_W_WW(ret, fn, cond, attr);
1019    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT,
1020                                    cond, 0, 0, 0, 0);
1021    return ret;
1022 }
1023 
1024 PTH_FUNCS(int, pthreadZucondZuinit, pthread_cond_init_intercept,
1025           (pthread_cond_t* cond, const pthread_condattr_t* attr),
1026           (cond, attr));
1027 
1028 #if defined(VGO_solaris)
1029 static __always_inline
cond_init_intercept(cond_t * cond,int type,void * arg)1030 int cond_init_intercept(cond_t *cond, int type, void *arg)
1031 {
1032    int ret;
1033    OrigFn fn;
1034    VALGRIND_GET_ORIG_FN(fn);
1035    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT,
1036                                    cond, 0, 0, 0, 0);
1037    CALL_FN_W_WWW(ret, fn, cond, type, arg);
1038    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT,
1039                                    cond, 0, 0, 0, 0);
1040    return ret;
1041 }
1042 
1043 PTH_FUNCS(int, condZuinit, cond_init_intercept,
1044           (cond_t *cond, int type, void *arg),
1045           (cond, type, arg));
1046 #endif /* VGO_solaris */
1047 
1048 static __always_inline
pthread_cond_destroy_intercept(pthread_cond_t * cond)1049 int pthread_cond_destroy_intercept(pthread_cond_t* cond)
1050 {
1051    int ret;
1052    OrigFn fn;
1053    VALGRIND_GET_ORIG_FN(fn);
1054    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_DESTROY,
1055                                    cond, 0, 0, 0, 0);
1056    CALL_FN_W_W(ret, fn, cond);
1057    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_DESTROY,
1058                                    cond, ret==0, 0, 0, 0);
1059    return ret;
1060 }
1061 
1062 #if defined(VGO_solaris)
1063 /* On Solaris, pthread_cond_destroy is a weak alias to cond_destroy. */
1064 PTH_FUNCS(int, condZudestroy, pthread_cond_destroy_intercept,
1065           (pthread_cond_t *cond), (cond));
1066 #else
1067 PTH_FUNCS(int, pthreadZucondZudestroy, pthread_cond_destroy_intercept,
1068           (pthread_cond_t* cond), (cond));
1069 #endif /* VGO_solaris */
1070 
1071 static __always_inline
pthread_cond_wait_intercept(pthread_cond_t * cond,pthread_mutex_t * mutex)1072 int pthread_cond_wait_intercept(pthread_cond_t *cond, pthread_mutex_t *mutex)
1073 {
1074    int   ret;
1075    OrigFn fn;
1076    VALGRIND_GET_ORIG_FN(fn);
1077    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
1078                                    cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1079    CALL_FN_W_WW(ret, fn, cond, mutex);
1080    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
1081                                    cond, mutex, 1, 0, 0);
1082    return ret;
1083 }
1084 
1085 PTH_FUNCS(int, pthreadZucondZuwait, pthread_cond_wait_intercept,
1086           (pthread_cond_t *cond, pthread_mutex_t *mutex),
1087           (cond, mutex));
1088 #if defined(VGO_solaris)
1089 PTH_FUNCS(int, condZuwait, pthread_cond_wait_intercept,
1090           (pthread_cond_t *cond, pthread_mutex_t *mutex),
1091           (cond, mutex));
1092 #endif /* VGO_solaris */
1093 
1094 static __always_inline
pthread_cond_timedwait_intercept(pthread_cond_t * cond,pthread_mutex_t * mutex,const struct timespec * abstime)1095 int pthread_cond_timedwait_intercept(pthread_cond_t *cond,
1096                                      pthread_mutex_t *mutex,
1097                                      const struct timespec* abstime)
1098 {
1099    int   ret;
1100    OrigFn fn;
1101    VALGRIND_GET_ORIG_FN(fn);
1102    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
1103                                    cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1104    CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
1105    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
1106                                    cond, mutex, 1, 0, 0);
1107    return ret;
1108 }
1109 
1110 PTH_FUNCS(int, pthreadZucondZutimedwait, pthread_cond_timedwait_intercept,
1111           (pthread_cond_t *cond, pthread_mutex_t *mutex,
1112            const struct timespec* abstime),
1113           (cond, mutex, abstime));
1114 #if defined(VGO_solaris)
1115 PTH_FUNCS(int, condZutimedwait, pthread_cond_timedwait_intercept,
1116           (pthread_cond_t *cond, pthread_mutex_t *mutex,
1117            const struct timespec *timeout),
1118           (cond, mutex, timeout));
1119 PTH_FUNCS(int, condZureltimedwait, pthread_cond_timedwait_intercept,
1120           (pthread_cond_t *cond, pthread_mutex_t *mutex,
1121            const struct timespec *timeout),
1122           (cond, mutex, timeout));
1123 #endif /* VGO_solaris */
1124 
1125 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
1126 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
1127 // two. Intercepting all pthread_cond_signal* functions will cause only one
1128 // argument to be passed to pthread_cond_signal_np() and hence will cause this
1129 // last function to crash.
1130 
1131 static __always_inline
pthread_cond_signal_intercept(pthread_cond_t * cond)1132 int pthread_cond_signal_intercept(pthread_cond_t* cond)
1133 {
1134    int   ret;
1135    OrigFn fn;
1136    VALGRIND_GET_ORIG_FN(fn);
1137    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_SIGNAL,
1138                                    cond, 0, 0, 0, 0);
1139    CALL_FN_W_W(ret, fn, cond);
1140    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_SIGNAL,
1141                                    cond, 0, 0, 0, 0);
1142    return ret;
1143 }
1144 
1145 #if defined(VGO_solaris)
1146 /* On Solaris, pthread_cond_signal is a weak alias to cond_signal. */
1147 PTH_FUNCS(int, condZusignal, pthread_cond_signal_intercept,
1148           (pthread_cond_t *cond), (cond));
1149 #else
1150 PTH_FUNCS(int, pthreadZucondZusignal, pthread_cond_signal_intercept,
1151           (pthread_cond_t* cond), (cond));
1152 #endif /* VGO_solaris */
1153 
1154 static __always_inline
pthread_cond_broadcast_intercept(pthread_cond_t * cond)1155 int pthread_cond_broadcast_intercept(pthread_cond_t* cond)
1156 {
1157    int   ret;
1158    OrigFn fn;
1159    VALGRIND_GET_ORIG_FN(fn);
1160    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_BROADCAST,
1161                                    cond, 0, 0, 0, 0);
1162    CALL_FN_W_W(ret, fn, cond);
1163    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_BROADCAST,
1164                                    cond, 0, 0, 0, 0);
1165    return ret;
1166 }
1167 
1168 #if defined(VGO_solaris)
1169 /* On Solaris, pthread_cond_broadcast is a weak alias to cond_broadcast. */
1170 PTH_FUNCS(int, condZubroadcast, pthread_cond_broadcast_intercept,
1171           (pthread_cond_t *cond), (cond));
1172 #else
1173 PTH_FUNCS(int, pthreadZucondZubroadcast, pthread_cond_broadcast_intercept,
1174           (pthread_cond_t* cond), (cond));
1175 #endif /* VGO_solaris */
1176 
1177 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1178     && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1179 static __always_inline
pthread_spin_init_intercept(pthread_spinlock_t * spinlock,int pshared)1180 int pthread_spin_init_intercept(pthread_spinlock_t *spinlock, int pshared)
1181 {
1182    int ret;
1183    OrigFn fn;
1184    VALGRIND_GET_ORIG_FN(fn);
1185    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
1186                                    spinlock, 0, 0, 0, 0);
1187    CALL_FN_W_WW(ret, fn, spinlock, pshared);
1188    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
1189                                    spinlock, 0, 0, 0, 0);
1190    return ret;
1191 }
1192 
1193 PTH_FUNCS(int, pthreadZuspinZuinit, pthread_spin_init_intercept,
1194           (pthread_spinlock_t *spinlock, int pshared), (spinlock, pshared));
1195 
1196 static __always_inline
pthread_spin_destroy_intercept(pthread_spinlock_t * spinlock)1197 int pthread_spin_destroy_intercept(pthread_spinlock_t *spinlock)
1198 {
1199    int ret;
1200    OrigFn fn;
1201    VALGRIND_GET_ORIG_FN(fn);
1202    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
1203                                    spinlock, 0, 0, 0, 0);
1204    CALL_FN_W_W(ret, fn, spinlock);
1205    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
1206                                    spinlock, mutex_type_spinlock, 0, 0, 0);
1207    return ret;
1208 }
1209 
1210 PTH_FUNCS(int, pthreadZuspinZudestroy, pthread_spin_destroy_intercept,
1211           (pthread_spinlock_t *spinlock), (spinlock));
1212 
1213 static __always_inline
pthread_spin_lock_intercept(pthread_spinlock_t * spinlock)1214 int pthread_spin_lock_intercept(pthread_spinlock_t *spinlock)
1215 {
1216    int   ret;
1217    OrigFn fn;
1218    VALGRIND_GET_ORIG_FN(fn);
1219    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
1220                                    spinlock, mutex_type_spinlock, 0, 0, 0);
1221    CALL_FN_W_W(ret, fn, spinlock);
1222    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
1223                                    spinlock, ret == 0, 0, 0, 0);
1224    return ret;
1225 }
1226 
1227 PTH_FUNCS(int, pthreadZuspinZulock, pthread_spin_lock_intercept,
1228           (pthread_spinlock_t *spinlock), (spinlock));
1229 
1230 static __always_inline
pthread_spin_trylock_intercept(pthread_spinlock_t * spinlock)1231 int pthread_spin_trylock_intercept(pthread_spinlock_t *spinlock)
1232 {
1233    int   ret;
1234    OrigFn fn;
1235    VALGRIND_GET_ORIG_FN(fn);
1236    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
1237                                    spinlock, mutex_type_spinlock, 0, 0, 0);
1238    CALL_FN_W_W(ret, fn, spinlock);
1239    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
1240                                    spinlock, ret == 0, 0, 0, 0);
1241    return ret;
1242 }
1243 
1244 PTH_FUNCS(int, pthreadZuspinZutrylock, pthread_spin_trylock_intercept,
1245           (pthread_spinlock_t *spinlock), (spinlock));
1246 
1247 static __always_inline
pthread_spin_unlock_intercept(pthread_spinlock_t * spinlock)1248 int pthread_spin_unlock_intercept(pthread_spinlock_t *spinlock)
1249 {
1250    int   ret;
1251    OrigFn fn;
1252    VALGRIND_GET_ORIG_FN(fn);
1253    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
1254                                    spinlock, mutex_type_spinlock, 0, 0, 0);
1255    CALL_FN_W_W(ret, fn, spinlock);
1256    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
1257                                    spinlock, 0, 0, 0, 0);
1258    return ret;
1259 }
1260 
1261 PTH_FUNCS(int, pthreadZuspinZuunlock, pthread_spin_unlock_intercept,
1262           (pthread_spinlock_t *spinlock), (spinlock));
1263 #endif   // HAVE_PTHREAD_SPIN_LOCK
1264 
1265 
1266 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1267 static __always_inline
pthread_barrier_init_intercept(pthread_barrier_t * barrier,const pthread_barrierattr_t * attr,unsigned count)1268 int pthread_barrier_init_intercept(pthread_barrier_t* barrier,
1269                                    const pthread_barrierattr_t* attr,
1270                                    unsigned count)
1271 {
1272    int   ret;
1273    OrigFn fn;
1274    VALGRIND_GET_ORIG_FN(fn);
1275    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_INIT,
1276                                    barrier, pthread_barrier, count, 0, 0);
1277    CALL_FN_W_WWW(ret, fn, barrier, attr, count);
1278    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_INIT,
1279                                    barrier, pthread_barrier, 0, 0, 0);
1280    return ret;
1281 }
1282 
1283 PTH_FUNCS(int, pthreadZubarrierZuinit, pthread_barrier_init_intercept,
1284           (pthread_barrier_t* barrier, const pthread_barrierattr_t* attr,
1285            unsigned count), (barrier, attr, count));
1286 
1287 static __always_inline
pthread_barrier_destroy_intercept(pthread_barrier_t * barrier)1288 int pthread_barrier_destroy_intercept(pthread_barrier_t* barrier)
1289 {
1290    int   ret;
1291    OrigFn fn;
1292    VALGRIND_GET_ORIG_FN(fn);
1293    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_DESTROY,
1294                                    barrier, pthread_barrier, 0, 0, 0);
1295    CALL_FN_W_W(ret, fn, barrier);
1296    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_DESTROY,
1297                                    barrier, pthread_barrier, 0, 0, 0);
1298    return ret;
1299 }
1300 
1301 PTH_FUNCS(int, pthreadZubarrierZudestroy, pthread_barrier_destroy_intercept,
1302           (pthread_barrier_t* barrier), (barrier));
1303 
1304 static __always_inline
pthread_barrier_wait_intercept(pthread_barrier_t * barrier)1305 int pthread_barrier_wait_intercept(pthread_barrier_t* barrier)
1306 {
1307    int   ret;
1308    OrigFn fn;
1309    VALGRIND_GET_ORIG_FN(fn);
1310    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_WAIT,
1311                                    barrier, pthread_barrier, 0, 0, 0);
1312    CALL_FN_W_W(ret, fn, barrier);
1313    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_WAIT,
1314                               barrier, pthread_barrier,
1315                               ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD,
1316                               ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
1317    return ret;
1318 }
1319 
1320 PTH_FUNCS(int, pthreadZubarrierZuwait, pthread_barrier_wait_intercept,
1321           (pthread_barrier_t* barrier), (barrier));
1322 #endif   // HAVE_PTHREAD_BARRIER_INIT
1323 
1324 
1325 static __always_inline
sem_init_intercept(sem_t * sem,int pshared,unsigned int value)1326 int sem_init_intercept(sem_t *sem, int pshared, unsigned int value)
1327 {
1328    int   ret;
1329    OrigFn fn;
1330    VALGRIND_GET_ORIG_FN(fn);
1331    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT,
1332                                    sem, pshared, value, 0, 0);
1333    CALL_FN_W_WWW(ret, fn, sem, pshared, value);
1334    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT,
1335                                    sem, 0, 0, 0, 0);
1336    return ret;
1337 }
1338 
1339 PTH_FUNCS(int, semZuinit, sem_init_intercept,
1340           (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
1341 
1342 #if defined(VGO_solaris)
1343 static __always_inline
sema_init_intercept(sema_t * sem,unsigned int value,int type,void * arg)1344 int sema_init_intercept(sema_t *sem, unsigned int value, int type, void *arg)
1345 {
1346    int   ret;
1347    OrigFn fn;
1348    VALGRIND_GET_ORIG_FN(fn);
1349    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT,
1350                                    sem, type == USYNC_PROCESS ? 1 : 0,
1351                                    value, 0, 0);
1352    CALL_FN_W_WWWW(ret, fn, sem, value, type, arg);
1353    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT,
1354                                    sem, 0, 0, 0, 0);
1355    return ret;
1356 }
1357 
1358 PTH_FUNCS(int, semaZuinit, sema_init_intercept,
1359           (sema_t *sem, unsigned int value, int type, void *arg),
1360           (sem, value, type, arg));
1361 #endif /* VGO_solaris */
1362 
1363 static __always_inline
sem_destroy_intercept(sem_t * sem)1364 int sem_destroy_intercept(sem_t *sem)
1365 {
1366    int   ret;
1367    OrigFn fn;
1368    VALGRIND_GET_ORIG_FN(fn);
1369    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_DESTROY,
1370                                    sem, 0, 0, 0, 0);
1371    CALL_FN_W_W(ret, fn, sem);
1372    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_DESTROY,
1373                                    sem, 0, 0, 0, 0);
1374    return ret;
1375 }
1376 
1377 PTH_FUNCS(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1378 #if defined(VGO_solaris)
1379 PTH_FUNCS(int, semaZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1380 #endif /* VGO_solaris */
1381 
1382 static __always_inline
sem_open_intercept(const char * name,int oflag,mode_t mode,unsigned int value)1383 sem_t* sem_open_intercept(const char *name, int oflag, mode_t mode,
1384                           unsigned int value)
1385 {
1386    sem_t *ret;
1387    OrigFn fn;
1388    VALGRIND_GET_ORIG_FN(fn);
1389    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_OPEN,
1390                                    name, oflag, mode, value, 0);
1391    CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value);
1392    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_OPEN,
1393                                    ret != SEM_FAILED ? ret : 0,
1394                                    name, oflag, mode, value);
1395    return ret;
1396 }
1397 
1398 PTH_FUNCS(sem_t *, semZuopen, sem_open_intercept,
1399           (const char *name, int oflag, mode_t mode, unsigned int value),
1400           (name, oflag, mode, value));
1401 
sem_close_intercept(sem_t * sem)1402 static __always_inline int sem_close_intercept(sem_t *sem)
1403 {
1404    int   ret;
1405    OrigFn fn;
1406    VALGRIND_GET_ORIG_FN(fn);
1407    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_CLOSE,
1408                                    sem, 0, 0, 0, 0);
1409    CALL_FN_W_W(ret, fn, sem);
1410    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_CLOSE,
1411                                    sem, 0, 0, 0, 0);
1412    return ret;
1413 }
1414 
1415 PTH_FUNCS(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
1416 
sem_wait_intercept(sem_t * sem)1417 static __always_inline int sem_wait_intercept(sem_t *sem)
1418 {
1419    int   ret;
1420    OrigFn fn;
1421    VALGRIND_GET_ORIG_FN(fn);
1422    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1423                                    sem, 0, 0, 0, 0);
1424    CALL_FN_W_W(ret, fn, sem);
1425    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1426                                    sem, ret == 0, 0, 0, 0);
1427    return ret;
1428 }
1429 
1430 PTH_FUNCS(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1431 #if defined(VGO_solaris)
1432 PTH_FUNCS(int, semaZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1433 #endif /* VGO_solaris */
1434 
sem_trywait_intercept(sem_t * sem)1435 static __always_inline int sem_trywait_intercept(sem_t *sem)
1436 {
1437    int   ret;
1438    OrigFn fn;
1439    VALGRIND_GET_ORIG_FN(fn);
1440    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1441                                    sem, 0, 0, 0, 0);
1442    CALL_FN_W_W(ret, fn, sem);
1443    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1444                                    sem, ret == 0, 0, 0, 0);
1445    return ret;
1446 }
1447 
1448 PTH_FUNCS(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1449 #if defined(VGO_solaris)
1450 PTH_FUNCS(int, semaZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1451 #endif /* VGO_solaris */
1452 
1453 static __always_inline
sem_timedwait_intercept(sem_t * sem,const struct timespec * abs_timeout)1454 int sem_timedwait_intercept(sem_t *sem, const struct timespec *abs_timeout)
1455 {
1456    int   ret;
1457    OrigFn fn;
1458    VALGRIND_GET_ORIG_FN(fn);
1459    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1460                                    sem, 0, 0, 0, 0);
1461    CALL_FN_W_WW(ret, fn, sem, abs_timeout);
1462    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1463                                    sem, ret == 0, 0, 0, 0);
1464    return ret;
1465 }
1466 
1467 PTH_FUNCS(int, semZutimedwait, sem_timedwait_intercept,
1468           (sem_t *sem, const struct timespec *abs_timeout),
1469           (sem, abs_timeout));
1470 #if defined(VGO_solaris)
1471 PTH_FUNCS(int, semaZutimedwait, sem_timedwait_intercept,
1472           (sem_t *sem, const struct timespec *timeout),
1473           (sem, timeout));
1474 PTH_FUNCS(int, semaZureltimedwait, sem_timedwait_intercept,
1475           (sem_t *sem, const struct timespec *timeout),
1476           (sem, timeout));
1477 #endif /* VGO_solaris */
1478 
sem_post_intercept(sem_t * sem)1479 static __always_inline int sem_post_intercept(sem_t *sem)
1480 {
1481    int   ret;
1482    OrigFn fn;
1483    VALGRIND_GET_ORIG_FN(fn);
1484    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_POST,
1485                                    sem, 0, 0, 0, 0);
1486    CALL_FN_W_W(ret, fn, sem);
1487    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_POST,
1488                                    sem, ret == 0, 0, 0, 0);
1489    return ret;
1490 }
1491 
1492 PTH_FUNCS(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
1493 #if defined(VGO_solaris)
1494 PTH_FUNCS(int, semaZupost, sem_post_intercept, (sem_t *sem), (sem));
1495 #endif /* VGO_solaris */
1496 
1497 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1498    functions have to be conditionally compiled. */
1499 #if defined(HAVE_PTHREAD_RWLOCK_T)
1500 
1501 static __always_inline
pthread_rwlock_init_intercept(pthread_rwlock_t * rwlock,const pthread_rwlockattr_t * attr)1502 int pthread_rwlock_init_intercept(pthread_rwlock_t* rwlock,
1503                                   const pthread_rwlockattr_t* attr)
1504 {
1505    int   ret;
1506    OrigFn fn;
1507    VALGRIND_GET_ORIG_FN(fn);
1508    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT,
1509                                    rwlock, 0, 0, 0, 0);
1510    CALL_FN_W_WW(ret, fn, rwlock, attr);
1511    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT,
1512                                    rwlock, 0, 0, 0, 0);
1513    return ret;
1514 }
1515 
1516 PTH_FUNCS(int,
1517           pthreadZurwlockZuinit, pthread_rwlock_init_intercept,
1518           (pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr),
1519           (rwlock, attr));
1520 
1521 #if defined(VGO_solaris)
1522 static __always_inline
rwlock_init_intercept(rwlock_t * rwlock,int type,void * arg)1523 int rwlock_init_intercept(rwlock_t *rwlock, int type, void *arg)
1524 {
1525    int   ret;
1526    OrigFn fn;
1527    VALGRIND_GET_ORIG_FN(fn);
1528    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT,
1529                                    rwlock, 0, 0, 0, 0);
1530    CALL_FN_W_WWW(ret, fn, rwlock, type, arg);
1531    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT,
1532                                    rwlock, 0, 0, 0, 0);
1533    return ret;
1534 }
1535 
1536 PTH_FUNCS(int, rwlockZuinit, rwlock_init_intercept,
1537           (rwlock_t *rwlock, int type, void *arg),
1538           (rwlock, type, arg));
1539 #endif /* VGO_solaris */
1540 
1541 static __always_inline
pthread_rwlock_destroy_intercept(pthread_rwlock_t * rwlock)1542 int pthread_rwlock_destroy_intercept(pthread_rwlock_t* rwlock)
1543 {
1544    int   ret;
1545    OrigFn fn;
1546    VALGRIND_GET_ORIG_FN(fn);
1547    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_DESTROY,
1548                                    rwlock, 0, 0, 0, 0);
1549    CALL_FN_W_W(ret, fn, rwlock);
1550    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_DESTROY,
1551                                    rwlock, 0, 0, 0, 0);
1552    return ret;
1553 }
1554 
1555 #if defined(VGO_solaris)
1556 /* On Solaris, pthread_rwlock_destroy is a weak alias to rwlock_destroy. */
1557 PTH_FUNCS(int,
1558           rwlockZudestroy, pthread_rwlock_destroy_intercept,
1559           (pthread_rwlock_t *rwlock), (rwlock));
1560 #else
1561 PTH_FUNCS(int,
1562           pthreadZurwlockZudestroy, pthread_rwlock_destroy_intercept,
1563           (pthread_rwlock_t* rwlock), (rwlock));
1564 #endif /* VGO_solaris */
1565 
1566 static __always_inline
pthread_rwlock_rdlock_intercept(pthread_rwlock_t * rwlock)1567 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t* rwlock)
1568 {
1569    int   ret;
1570    OrigFn fn;
1571    VALGRIND_GET_ORIG_FN(fn);
1572    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1573                                    rwlock, 0, 0, 0, 0);
1574    CALL_FN_W_W(ret, fn, rwlock);
1575    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1576                                    rwlock, ret == 0, 0, 0, 0);
1577    return ret;
1578 }
1579 
1580 #if defined(VGO_solaris)
1581 /* On Solaris, pthread_rwlock_rdlock is a weak alias to rw_rdlock. */
1582 PTH_FUNCS(int,
1583           rwZurdlock, pthread_rwlock_rdlock_intercept,
1584           (pthread_rwlock_t *rwlock), (rwlock));
1585 #else
1586 PTH_FUNCS(int,
1587           pthreadZurwlockZurdlock, pthread_rwlock_rdlock_intercept,
1588           (pthread_rwlock_t* rwlock), (rwlock));
1589 #endif /* VGO_solaris */
1590 
1591 #if defined(VGO_solaris)
1592 /* Internal to libc. */
1593 static __always_inline
lrw_rdlock_intercept(rwlock_t * rwlock)1594 void lrw_rdlock_intercept(rwlock_t *rwlock)
1595 {
1596    OrigFn fn;
1597    VALGRIND_GET_ORIG_FN(fn);
1598    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1599                                    rwlock, 0, 0, 0, 0);
1600    CALL_FN_v_W(fn, rwlock);
1601    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1602                                    rwlock, True /* took_lock */, 0, 0, 0);
1603 }
1604 
1605 PTH_FUNCS(void, lrwZurdlock, lrw_rdlock_intercept,
1606           (rwlock_t *rwlock), (rwlock));
1607 #endif /* VGO_solaris */
1608 
1609 static __always_inline
pthread_rwlock_wrlock_intercept(pthread_rwlock_t * rwlock)1610 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t* rwlock)
1611 {
1612    int   ret;
1613    OrigFn fn;
1614    VALGRIND_GET_ORIG_FN(fn);
1615    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1616                                    rwlock, 0, 0, 0, 0);
1617    CALL_FN_W_W(ret, fn, rwlock);
1618    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1619                                    rwlock, ret == 0, 0, 0, 0);
1620    return ret;
1621 }
1622 
1623 #if defined(VGO_solaris)
1624 /* On Solaris, pthread_rwlock_wrlock is a weak alias to rw_wrlock. */
1625 PTH_FUNCS(int,
1626           rwZuwrlock, pthread_rwlock_wrlock_intercept,
1627           (pthread_rwlock_t *rwlock), (rwlock));
1628 #else
1629 PTH_FUNCS(int,
1630           pthreadZurwlockZuwrlock, pthread_rwlock_wrlock_intercept,
1631           (pthread_rwlock_t* rwlock), (rwlock));
1632 #endif /* VGO_solaris */
1633 
1634 #if defined(VGO_solaris)
1635 /* Internal to libc. */
1636 static __always_inline
lrw_wrlock_intercept(rwlock_t * rwlock)1637 void lrw_wrlock_intercept(rwlock_t *rwlock)
1638 {
1639    OrigFn fn;
1640    VALGRIND_GET_ORIG_FN(fn);
1641    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1642                                    rwlock, 0, 0, 0, 0);
1643    CALL_FN_v_W(fn, rwlock);
1644    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1645                                    rwlock, True /* took_lock */, 0, 0, 0);
1646 }
1647 
1648 PTH_FUNCS(void, lrwZuwrlock, lrw_wrlock_intercept,
1649           (rwlock_t *rwlock), (rwlock));
1650 #endif /* VGO_solaris */
1651 
1652 static __always_inline
pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t * rwlock,const struct timespec * timeout)1653 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t* rwlock,
1654                                          const struct timespec *timeout)
1655 {
1656    int   ret;
1657    OrigFn fn;
1658    VALGRIND_GET_ORIG_FN(fn);
1659    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1660                                    rwlock, 0, 0, 0, 0);
1661    CALL_FN_W_WW(ret, fn, rwlock, timeout);
1662    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1663                                    rwlock, ret == 0, 0, 0, 0);
1664    return ret;
1665 }
1666 
1667 PTH_FUNCS(int,
1668           pthreadZurwlockZutimedrdlock, pthread_rwlock_timedrdlock_intercept,
1669           (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1670           (rwlock, timeout));
1671 #if defined(VGO_solaris)
1672 PTH_FUNCS(int, pthreadZurwlockZureltimedrdlockZunp,
1673           pthread_rwlock_timedrdlock_intercept,
1674           (pthread_rwlock_t *rwlock, const struct timespec *timeout),
1675           (rwlock, timeout));
1676 #endif /* VGO_solaris */
1677 
1678 static __always_inline
pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t * rwlock,const struct timespec * timeout)1679 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t* rwlock,
1680                                          const struct timespec *timeout)
1681 {
1682    int   ret;
1683    OrigFn fn;
1684    VALGRIND_GET_ORIG_FN(fn);
1685    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1686                                    rwlock, 0, 0, 0, 0);
1687    CALL_FN_W_WW(ret, fn, rwlock, timeout);
1688    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1689                                    rwlock, ret == 0, 0, 0, 0);
1690    return ret;
1691 }
1692 
1693 PTH_FUNCS(int,
1694           pthreadZurwlockZutimedwrlock, pthread_rwlock_timedwrlock_intercept,
1695           (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1696           (rwlock, timeout));
1697 #if defined(VGO_solaris)
1698 PTH_FUNCS(int, pthreadZurwlockZureltimedwrlockZunp,
1699           pthread_rwlock_timedwrlock_intercept,
1700           (pthread_rwlock_t *rwlock, const struct timespec *timeout),
1701           (rwlock, timeout));
1702 #endif /* VGO_solaris */
1703 
1704 static __always_inline
pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t * rwlock)1705 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t* rwlock)
1706 {
1707    int   ret;
1708    OrigFn fn;
1709    VALGRIND_GET_ORIG_FN(fn);
1710    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1711                                    rwlock, 0, 0, 0, 0);
1712    CALL_FN_W_W(ret, fn, rwlock);
1713    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1714                                    rwlock, ret == 0, 0, 0, 0);
1715    return ret;
1716 }
1717 
1718 #if defined(VGO_solaris)
1719 /* On Solaris, pthread_rwlock_tryrdlock is a weak alias to rw_tryrdlock. */
1720 PTH_FUNCS(int,
1721           rwZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1722           (pthread_rwlock_t *rwlock), (rwlock));
1723 #else
1724 PTH_FUNCS(int,
1725           pthreadZurwlockZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1726           (pthread_rwlock_t* rwlock), (rwlock));
1727 #endif /* VGO_solaris */
1728 
1729 static __always_inline
pthread_rwlock_trywrlock_intercept(pthread_rwlock_t * rwlock)1730 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t* rwlock)
1731 {
1732    int   ret;
1733    OrigFn fn;
1734    VALGRIND_GET_ORIG_FN(fn);
1735    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1736                                    rwlock, 0, 0, 0, 0);
1737    CALL_FN_W_W(ret, fn, rwlock);
1738    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1739                                    rwlock, ret == 0, 0, 0, 0);
1740    return ret;
1741 }
1742 
1743 #if defined(VGO_solaris)
1744 /* On Solaris, pthread_rwlock_trywrlock is a weak alias to rw_trywrlock. */
1745 PTH_FUNCS(int,
1746           rwZutrywrlock, pthread_rwlock_trywrlock_intercept,
1747           (pthread_rwlock_t *rwlock), (rwlock));
1748 #else
1749 PTH_FUNCS(int,
1750           pthreadZurwlockZutrywrlock, pthread_rwlock_trywrlock_intercept,
1751           (pthread_rwlock_t* rwlock), (rwlock));
1752 #endif /* VGO_solaris */
1753 
1754 static __always_inline
pthread_rwlock_unlock_intercept(pthread_rwlock_t * rwlock)1755 int pthread_rwlock_unlock_intercept(pthread_rwlock_t* rwlock)
1756 {
1757    int   ret;
1758    OrigFn fn;
1759    VALGRIND_GET_ORIG_FN(fn);
1760    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_UNLOCK,
1761                                    rwlock, 0, 0, 0, 0);
1762    CALL_FN_W_W(ret, fn, rwlock);
1763    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_UNLOCK,
1764                                    rwlock, ret == 0, 0, 0, 0);
1765    return ret;
1766 }
1767 
1768 #if defined(VGO_solaris)
1769 /* On Solaris, pthread_rwlock_unlock is a weak alias to rw_unlock. */
1770 PTH_FUNCS(int,
1771           rwZuunlock, pthread_rwlock_unlock_intercept,
1772           (pthread_rwlock_t *rwlock), (rwlock));
1773 #else
1774 PTH_FUNCS(int,
1775           pthreadZurwlockZuunlock, pthread_rwlock_unlock_intercept,
1776           (pthread_rwlock_t* rwlock), (rwlock));
1777 #endif /* VGO_solaris */
1778 
1779 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
1780