• 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-2017 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_pthread_id)(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_pthread_id)();
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  * Update DRD's state information about the current thread.
505  */
DRD_(set_pthread_id)506 static void DRD_(set_pthread_id)(void)
507 {
508    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
509                                    pthread_self(), 0, 0, 0, 0);
510 }
511 
512 /*
513  * Note: as of today there exist three different versions of pthread_create
514  * in Linux:
515  * - pthread_create@GLIBC_2.0
516  * - pthread_create@@GLIBC_2.1
517  * - pthread_create@@GLIBC_2.2.5
518  * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
519  * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
520  * versions have been implemented. In any glibc version where more than one
521  * pthread_create function has been implemented, older versions call the
522  * newer versions. Or: the pthread_create* wrapper defined below can be
523  * called recursively. Any code in this wrapper should take this in account.
524  * As an example, it is not safe to invoke the DRD_STOP_RECORDING
525  * / DRD_START_RECORDING client requests from the pthread_create wrapper.
526  * See also the implementation of pthread_create@GLIBC_2.0 in
527  * glibc-2.9/nptl/pthread_create.c.
528  */
529 
530 static __always_inline
pthread_create_intercept(pthread_t * thread,const pthread_attr_t * attr,void * (* start)(void *),void * arg)531 int pthread_create_intercept(pthread_t* thread, const pthread_attr_t* attr,
532                              void* (*start)(void*), void* arg)
533 {
534    int    ret;
535    OrigFn fn;
536    DrdSema wrapper_started;
537    DrdPosixThreadArgs thread_args;
538 
539    VALGRIND_GET_ORIG_FN(fn);
540 
541    DRD_(sema_init)(&wrapper_started);
542    thread_args.start           = start;
543    thread_args.arg             = arg;
544    thread_args.wrapper_started = &wrapper_started;
545    /*
546     * Find out whether the thread will be started as a joinable thread
547     * or as a detached thread. If no thread attributes have been specified,
548     * this means that the new thread will be started as a joinable thread.
549     */
550    thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
551    if (attr)
552    {
553       if (pthread_attr_getdetachstate(attr, &thread_args.detachstate) != 0)
554          assert(0);
555    }
556    assert(thread_args.detachstate == PTHREAD_CREATE_JOINABLE
557           || thread_args.detachstate == PTHREAD_CREATE_DETACHED);
558 
559    /*
560     * The DRD_(set_pthread_id)() from DRD_(init)() may encounter that
561     * pthread_self() == 0, e.g. when the main program is not linked with the
562     * pthread library and when a pthread_create() call occurs from within a
563     * shared library. Hence call DRD_(set_pthread_id)() again to ensure that
564     * DRD knows the identity of the current thread. See also B.Z. 356374.
565     */
566    DRD_(set_pthread_id)();
567    DRD_(entering_pthread_create)();
568    CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), &thread_args);
569    DRD_(left_pthread_create)();
570 
571    if (ret == 0) {
572       /* Wait until the thread wrapper started. */
573       DRD_(sema_down)(&wrapper_started);
574    }
575 
576    DRD_(sema_destroy)(&wrapper_started);
577 
578    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT,
579                                    pthread_self(), 0, 0, 0, 0);
580 
581    return ret;
582 }
583 
584 PTH_FUNCS(int, pthreadZucreate, pthread_create_intercept,
585           (pthread_t *thread, const pthread_attr_t *attr,
586            void *(*start) (void *), void *arg),
587           (thread, attr, start, arg));
588 
589 #if defined(VGO_solaris)
590 /* Solaris also provides thr_create() in addition to pthread_create().
591  * Both pthread_create(3C) and thr_create(3C) are based on private
592  * _thrp_create().
593  */
594 static __always_inline
thr_create_intercept(void * stk,size_t stksize,void * (* start)(void *),void * arg,long flags,thread_t * new_thread)595 int thr_create_intercept(void *stk, size_t stksize, void *(*start)(void *),
596                          void *arg, long flags, thread_t *new_thread)
597 {
598    int                ret;
599    OrigFn             fn;
600    DrdSema            wrapper_started;
601    DrdPosixThreadArgs thread_args;
602 
603    VALGRIND_GET_ORIG_FN(fn);
604 
605    DRD_(sema_init)(&wrapper_started);
606    thread_args.start           = start;
607    thread_args.arg             = arg;
608    thread_args.wrapper_started = &wrapper_started;
609    /*
610     * Find out whether the thread will be started as a joinable thread
611     * or as a detached thread.
612     */
613    if (flags & THR_DETACHED)
614       thread_args.detachstate = PTHREAD_CREATE_DETACHED;
615    else
616       thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
617 
618    DRD_(entering_pthread_create)();
619    CALL_FN_W_6W(ret, fn, stk, stksize, DRD_(thread_wrapper), &thread_args,
620                 flags, new_thread);
621    DRD_(left_pthread_create)();
622 
623    if (ret == 0) {
624       /* Wait until the thread wrapper started. */
625       DRD_(sema_down)(&wrapper_started);
626    }
627 
628    DRD_(sema_destroy)(&wrapper_started);
629 
630    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT,
631                                    pthread_self(), 0, 0, 0, 0);
632 
633    return ret;
634 }
635 
636 PTH_FUNCS(int, thrZucreate, thr_create_intercept,
637           (void *stk, size_t stksize, void *(*start)(void *), void *arg,
638            long flags, thread_t *new_thread),
639           (stk, stksize, start, arg, flags, new_thread));
640 #endif /* VGO_solaris */
641 
642 #if defined(VGO_solaris)
643 /*
644  * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
645  * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
646  * and CI_BIND_CLEAR, to provide resilience against function renaming.
647  */
648 static __always_inline
DRD_(_ti_bind_guard_intercept)649 int DRD_(_ti_bind_guard_intercept)(int flags) {
650    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_GUARD,
651                                    flags, 0, 0, 0, 0);
652    return DRD_(rtld_bind_guard)(flags);
653 }
654 
655 static __always_inline
DRD_(_ti_bind_clear_intercept)656 int DRD_(_ti_bind_clear_intercept)(int flags) {
657    int ret = DRD_(rtld_bind_clear)(flags);
658    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_CLEAR,
659                                    flags, 0, 0, 0, 0);
660    return ret;
661 }
662 
663 /*
664  * Wrapped _ld_libc() from the runtime linker ld.so.1.
665  */
666 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)667 void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr)
668 {
669    OrigFn fn;
670    int    tag;
671 
672    VALGRIND_GET_ORIG_FN(fn);
673 
674    vki_Lc_interface *funcs = ptr;
675    for (tag = funcs->ci_tag; tag != 0; tag = (++funcs)->ci_tag) {
676       switch (tag) {
677       case VKI_CI_BIND_GUARD:
678          if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_guard_intercept)) {
679             DRD_(rtld_bind_guard) = funcs->vki_ci_un.ci_func;
680             funcs->vki_ci_un.ci_func = DRD_(_ti_bind_guard_intercept);
681          }
682          break;
683       case VKI_CI_BIND_CLEAR:
684          if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_clear_intercept)) {
685             DRD_(rtld_bind_clear) = funcs->vki_ci_un.ci_func;
686             funcs->vki_ci_un.ci_func = DRD_(_ti_bind_clear_intercept);
687          }
688          break;
689       }
690    }
691 
692    CALL_FN_v_W(fn, ptr);
693 }
694 #endif /* VGO_solaris */
695 
696 static __always_inline
pthread_join_intercept(pthread_t pt_joinee,void ** thread_return)697 int pthread_join_intercept(pthread_t pt_joinee, void **thread_return)
698 {
699    int      ret;
700    OrigFn   fn;
701 
702    VALGRIND_GET_ORIG_FN(fn);
703    /*
704     * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
705     * implementation triggers a (false positive) race report.
706     */
707    ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
708    CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
709    if (ret == 0)
710    {
711       VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN,
712                                       pt_joinee, 0, 0, 0, 0);
713    }
714    ANNOTATE_IGNORE_READS_AND_WRITES_END();
715    return ret;
716 }
717 
718 PTH_FUNCS(int, pthreadZujoin, pthread_join_intercept,
719           (pthread_t pt_joinee, void **thread_return),
720           (pt_joinee, thread_return));
721 
722 #if defined(VGO_solaris)
723 /* Solaris also provides thr_join() in addition to pthread_join().
724  * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
725  *
726  * :TODO: No functionality is currently provided for joinee == 0 and departed.
727  *        This would require another client request, of course.
728  */
729 static __always_inline
thr_join_intercept(thread_t joinee,thread_t * departed,void ** thread_return)730 int thr_join_intercept(thread_t joinee, thread_t *departed, void **thread_return)
731 {
732    int      ret;
733    OrigFn   fn;
734 
735    VALGRIND_GET_ORIG_FN(fn);
736    CALL_FN_W_WWW(ret, fn, joinee, departed, thread_return);
737    if (ret == 0)
738    {
739       VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN,
740                                       joinee, 0, 0, 0, 0);
741    }
742    return ret;
743 }
744 
745 PTH_FUNCS(int, thrZujoin, thr_join_intercept,
746           (thread_t joinee, thread_t *departed, void **thread_return),
747           (joinee, departed, thread_return));
748 #endif /* VGO_solaris */
749 
750 static __always_inline
pthread_detach_intercept(pthread_t pt_thread)751 int pthread_detach_intercept(pthread_t pt_thread)
752 {
753    int ret;
754    OrigFn fn;
755 
756    VALGRIND_GET_ORIG_FN(fn);
757    CALL_FN_W_W(ret, fn, pt_thread);
758    DRD_(set_joinable)(pt_thread, 0);
759 
760    return ret;
761 }
762 
763 PTH_FUNCS(int, pthreadZudetach, pthread_detach_intercept,
764           (pthread_t thread), (thread));
765 
766 // NOTE: be careful to intercept only pthread_cancel() and not
767 // pthread_cancel_init() on Linux.
768 
769 static __always_inline
pthread_cancel_intercept(pthread_t pt_thread)770 int pthread_cancel_intercept(pthread_t pt_thread)
771 {
772    int ret;
773    OrigFn fn;
774    VALGRIND_GET_ORIG_FN(fn);
775    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_THREAD_CANCEL,
776                                    pt_thread, 0, 0, 0, 0);
777    CALL_FN_W_W(ret, fn, pt_thread);
778    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_CANCEL,
779                                    pt_thread, ret==0, 0, 0, 0);
780    return ret;
781 }
782 
783 PTH_FUNCS(int, pthreadZucancel, pthread_cancel_intercept,
784           (pthread_t thread), (thread))
785 
786 static __always_inline
pthread_once_intercept(pthread_once_t * once_control,void (* init_routine)(void))787 int pthread_once_intercept(pthread_once_t *once_control,
788                            void (*init_routine)(void))
789 {
790    int ret;
791    OrigFn fn;
792    VALGRIND_GET_ORIG_FN(fn);
793    /*
794     * Ignore any data races triggered by the implementation of pthread_once().
795     * Necessary for Darwin. This is not necessary for Linux but doesn't have
796     * any known adverse effects.
797     */
798    DRD_IGNORE_VAR(*once_control);
799    ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
800    CALL_FN_W_WW(ret, fn, once_control, init_routine);
801    ANNOTATE_IGNORE_READS_AND_WRITES_END();
802    DRD_STOP_IGNORING_VAR(*once_control);
803    return ret;
804 }
805 
806 PTH_FUNCS(int, pthreadZuonce, pthread_once_intercept,
807           (pthread_once_t *once_control, void (*init_routine)(void)),
808           (once_control, init_routine));
809 
810 static __always_inline
pthread_mutex_init_intercept(pthread_mutex_t * mutex,const pthread_mutexattr_t * attr)811 int pthread_mutex_init_intercept(pthread_mutex_t *mutex,
812                                  const pthread_mutexattr_t* attr)
813 {
814    int ret;
815    OrigFn fn;
816    int mt;
817    VALGRIND_GET_ORIG_FN(fn);
818    mt = PTHREAD_MUTEX_DEFAULT;
819    if (attr)
820       pthread_mutexattr_gettype(attr, &mt);
821    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
822                                    mutex, DRD_(pthread_to_drd_mutex_type)(mt),
823                                    0, 0, 0);
824    CALL_FN_W_WW(ret, fn, mutex, attr);
825    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
826                                    mutex, 0, 0, 0, 0);
827    return ret;
828 }
829 
830 PTH_FUNCS(int, pthreadZumutexZuinit, pthread_mutex_init_intercept,
831           (pthread_mutex_t *mutex, const pthread_mutexattr_t* attr),
832           (mutex, attr));
833 
834 #if defined(VGO_solaris)
835 static __always_inline
mutex_init_intercept(mutex_t * mutex,int type,void * arg)836 int mutex_init_intercept(mutex_t *mutex, int type, void *arg)
837 {
838    int ret;
839    OrigFn fn;
840    VALGRIND_GET_ORIG_FN(fn);
841 
842    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
843                                    mutex, DRD_(thread_to_drd_mutex_type)(type),
844                                    0, 0, 0);
845    CALL_FN_W_WWW(ret, fn, mutex, type, arg);
846    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
847                                    mutex, 0, 0, 0, 0);
848    return ret;
849 }
850 
851 PTH_FUNCS(int, mutexZuinit, mutex_init_intercept,
852           (mutex_t *mutex, int type, void *arg),
853           (mutex, type, arg));
854 #endif /* VGO_solaris */
855 
856 static __always_inline
pthread_mutex_destroy_intercept(pthread_mutex_t * mutex)857 int pthread_mutex_destroy_intercept(pthread_mutex_t* mutex)
858 {
859    int ret;
860    OrigFn fn;
861    VALGRIND_GET_ORIG_FN(fn);
862    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
863                                    mutex, 0, 0, 0, 0);
864    CALL_FN_W_W(ret, fn, mutex);
865    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
866                                    mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
867    return ret;
868 }
869 
870 #if defined(VGO_solaris)
871 /* On Solaris, pthread_mutex_destroy is a weak alias to mutex_destroy. */
872 PTH_FUNCS(int, mutexZudestroy, pthread_mutex_destroy_intercept,
873           (pthread_mutex_t *mutex), (mutex));
874 #else
875 PTH_FUNCS(int, pthreadZumutexZudestroy, pthread_mutex_destroy_intercept,
876           (pthread_mutex_t *mutex), (mutex));
877 #endif /* VGO_solaris */
878 
879 static __always_inline
pthread_mutex_lock_intercept(pthread_mutex_t * mutex)880 int pthread_mutex_lock_intercept(pthread_mutex_t* mutex)
881 {
882    int   ret;
883    OrigFn fn;
884    VALGRIND_GET_ORIG_FN(fn);
885    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
886                                    mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
887    CALL_FN_W_W(ret, fn, mutex);
888    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
889                                    mutex, ret == 0, 0, 0, 0);
890    return ret;
891 }
892 
893 #if defined(VGO_solaris)
894 /* On Solaris, pthread_mutex_lock is a weak alias to mutex_lock. */
895 PTH_FUNCS(int, mutexZulock, pthread_mutex_lock_intercept,
896           (pthread_mutex_t *mutex), (mutex));
897 #else
898 PTH_FUNCS(int, pthreadZumutexZulock, pthread_mutex_lock_intercept,
899           (pthread_mutex_t *mutex), (mutex));
900 #endif /* VGO_solaris */
901 
902 #if defined(VGO_solaris)
903 /* Internal to libc. Mutex is usually initialized only implicitly,
904  * by zeroing mutex_t structure.
905  */
906 static __always_inline
lmutex_lock_intercept(mutex_t * mutex)907 void lmutex_lock_intercept(mutex_t *mutex)
908 {
909    OrigFn fn;
910    VALGRIND_GET_ORIG_FN(fn);
911    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
912                                    mutex,
913                                    DRD_(mutex_type)((pthread_mutex_t *) mutex),
914                                    False /* try_lock */, 0, 0);
915    CALL_FN_v_W(fn, mutex);
916    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
917                                    mutex, True /* took_lock */, 0, 0, 0);
918 }
919 
920 PTH_FUNCS(void, lmutexZulock, lmutex_lock_intercept,
921           (mutex_t *mutex), (mutex));
922 #endif /* VGO_solaris */
923 
924 static __always_inline
pthread_mutex_trylock_intercept(pthread_mutex_t * mutex)925 int pthread_mutex_trylock_intercept(pthread_mutex_t* mutex)
926 {
927    int   ret;
928    OrigFn fn;
929    VALGRIND_GET_ORIG_FN(fn);
930    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
931                                    mutex, DRD_(mutex_type)(mutex), 1, 0, 0);
932    CALL_FN_W_W(ret, fn, mutex);
933    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
934                                    mutex, ret == 0, 0, 0, 0);
935    return ret;
936 }
937 
938 #if defined(VGO_solaris)
939 /* On Solaris, pthread_mutex_trylock is a weak alias to mutex_trylock. */
940 PTH_FUNCS(int, mutexZutrylock, pthread_mutex_trylock_intercept,
941           (pthread_mutex_t *mutex), (mutex));
942 #else
943 PTH_FUNCS(int, pthreadZumutexZutrylock, pthread_mutex_trylock_intercept,
944           (pthread_mutex_t *mutex), (mutex));
945 #endif /* VGO_solaris */
946 
947 static __always_inline
pthread_mutex_timedlock_intercept(pthread_mutex_t * mutex,const struct timespec * abs_timeout)948 int pthread_mutex_timedlock_intercept(pthread_mutex_t *mutex,
949                                       const struct timespec *abs_timeout)
950 {
951    int   ret;
952    OrigFn fn;
953    VALGRIND_GET_ORIG_FN(fn);
954    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
955                                    mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
956    CALL_FN_W_WW(ret, fn, mutex, abs_timeout);
957    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
958                                    mutex, ret == 0, 0, 0, 0);
959    return ret;
960 }
961 
962 PTH_FUNCS(int, pthreadZumutexZutimedlock, pthread_mutex_timedlock_intercept,
963           (pthread_mutex_t *mutex, const struct timespec *abs_timeout),
964           (mutex, abs_timeout));
965 #if defined(VGO_solaris)
966 PTH_FUNCS(int,
967           pthreadZumutexZureltimedlockZunp, pthread_mutex_timedlock_intercept,
968           (pthread_mutex_t *mutex, const struct timespec *timeout),
969           (mutex, timeout));
970 #endif /* VGO_solaris */
971 
972 static __always_inline
pthread_mutex_unlock_intercept(pthread_mutex_t * mutex)973 int pthread_mutex_unlock_intercept(pthread_mutex_t *mutex)
974 {
975    int ret;
976    OrigFn fn;
977    VALGRIND_GET_ORIG_FN(fn);
978    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
979                                    mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
980    CALL_FN_W_W(ret, fn, mutex);
981    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
982                                    mutex, 0, 0, 0, 0);
983    return ret;
984 }
985 
986 #if defined(VGO_solaris)
987 /* On Solaris, pthread_mutex_unlock is a weak alias to mutex_unlock. */
988 PTH_FUNCS(int, mutexZuunlock, pthread_mutex_unlock_intercept,
989           (pthread_mutex_t *mutex), (mutex));
990 #else
991 PTH_FUNCS(int, pthreadZumutexZuunlock, pthread_mutex_unlock_intercept,
992           (pthread_mutex_t *mutex), (mutex));
993 #endif /* VGO_solaris */
994 
995 #if defined(VGO_solaris)
996 /* Internal to libc. */
997 static __always_inline
lmutex_unlock_intercept(mutex_t * mutex)998 void lmutex_unlock_intercept(mutex_t *mutex)
999 {
1000    OrigFn fn;
1001    VALGRIND_GET_ORIG_FN(fn);
1002    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
1003                                    mutex,
1004                                    DRD_(mutex_type)((pthread_mutex_t *) mutex),
1005                                    0, 0, 0);
1006    CALL_FN_v_W(fn, mutex);
1007    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
1008                                    mutex, 0, 0, 0, 0);
1009 }
1010 
1011 PTH_FUNCS(void, lmutexZuunlock, lmutex_unlock_intercept,
1012           (mutex_t *mutex), (mutex));
1013 #endif /* VGO_solaris */
1014 
1015 static __always_inline
pthread_cond_init_intercept(pthread_cond_t * cond,const pthread_condattr_t * attr)1016 int pthread_cond_init_intercept(pthread_cond_t* cond,
1017                                 const pthread_condattr_t* attr)
1018 {
1019    int ret;
1020    OrigFn fn;
1021    VALGRIND_GET_ORIG_FN(fn);
1022    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT,
1023                                    cond, 0, 0, 0, 0);
1024    CALL_FN_W_WW(ret, fn, cond, attr);
1025    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT,
1026                                    cond, 0, 0, 0, 0);
1027    return ret;
1028 }
1029 
1030 PTH_FUNCS(int, pthreadZucondZuinit, pthread_cond_init_intercept,
1031           (pthread_cond_t* cond, const pthread_condattr_t* attr),
1032           (cond, attr));
1033 
1034 #if defined(VGO_solaris)
1035 static __always_inline
cond_init_intercept(cond_t * cond,int type,void * arg)1036 int cond_init_intercept(cond_t *cond, int type, void *arg)
1037 {
1038    int ret;
1039    OrigFn fn;
1040    VALGRIND_GET_ORIG_FN(fn);
1041    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT,
1042                                    cond, 0, 0, 0, 0);
1043    CALL_FN_W_WWW(ret, fn, cond, type, arg);
1044    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT,
1045                                    cond, 0, 0, 0, 0);
1046    return ret;
1047 }
1048 
1049 PTH_FUNCS(int, condZuinit, cond_init_intercept,
1050           (cond_t *cond, int type, void *arg),
1051           (cond, type, arg));
1052 #endif /* VGO_solaris */
1053 
1054 static __always_inline
pthread_cond_destroy_intercept(pthread_cond_t * cond)1055 int pthread_cond_destroy_intercept(pthread_cond_t* cond)
1056 {
1057    int ret;
1058    OrigFn fn;
1059    VALGRIND_GET_ORIG_FN(fn);
1060    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_DESTROY,
1061                                    cond, 0, 0, 0, 0);
1062    CALL_FN_W_W(ret, fn, cond);
1063    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_DESTROY,
1064                                    cond, ret==0, 0, 0, 0);
1065    return ret;
1066 }
1067 
1068 #if defined(VGO_solaris)
1069 /* On Solaris, pthread_cond_destroy is a weak alias to cond_destroy. */
1070 PTH_FUNCS(int, condZudestroy, pthread_cond_destroy_intercept,
1071           (pthread_cond_t *cond), (cond));
1072 #else
1073 PTH_FUNCS(int, pthreadZucondZudestroy, pthread_cond_destroy_intercept,
1074           (pthread_cond_t* cond), (cond));
1075 #endif /* VGO_solaris */
1076 
1077 static __always_inline
pthread_cond_wait_intercept(pthread_cond_t * cond,pthread_mutex_t * mutex)1078 int pthread_cond_wait_intercept(pthread_cond_t *cond, pthread_mutex_t *mutex)
1079 {
1080    int   ret;
1081    OrigFn fn;
1082    VALGRIND_GET_ORIG_FN(fn);
1083    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
1084                                    cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1085    CALL_FN_W_WW(ret, fn, cond, mutex);
1086    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
1087                                    cond, mutex, 1, 0, 0);
1088    return ret;
1089 }
1090 
1091 PTH_FUNCS(int, pthreadZucondZuwait, pthread_cond_wait_intercept,
1092           (pthread_cond_t *cond, pthread_mutex_t *mutex),
1093           (cond, mutex));
1094 #if defined(VGO_solaris)
1095 PTH_FUNCS(int, condZuwait, pthread_cond_wait_intercept,
1096           (pthread_cond_t *cond, pthread_mutex_t *mutex),
1097           (cond, mutex));
1098 #endif /* VGO_solaris */
1099 
1100 static __always_inline
pthread_cond_timedwait_intercept(pthread_cond_t * cond,pthread_mutex_t * mutex,const struct timespec * abstime)1101 int pthread_cond_timedwait_intercept(pthread_cond_t *cond,
1102                                      pthread_mutex_t *mutex,
1103                                      const struct timespec* abstime)
1104 {
1105    int   ret;
1106    OrigFn fn;
1107    VALGRIND_GET_ORIG_FN(fn);
1108    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
1109                                    cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
1110    CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
1111    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
1112                                    cond, mutex, 1, 0, 0);
1113    return ret;
1114 }
1115 
1116 PTH_FUNCS(int, pthreadZucondZutimedwait, pthread_cond_timedwait_intercept,
1117           (pthread_cond_t *cond, pthread_mutex_t *mutex,
1118            const struct timespec* abstime),
1119           (cond, mutex, abstime));
1120 #if defined(VGO_solaris)
1121 PTH_FUNCS(int, condZutimedwait, pthread_cond_timedwait_intercept,
1122           (pthread_cond_t *cond, pthread_mutex_t *mutex,
1123            const struct timespec *timeout),
1124           (cond, mutex, timeout));
1125 PTH_FUNCS(int, condZureltimedwait, pthread_cond_timedwait_intercept,
1126           (pthread_cond_t *cond, pthread_mutex_t *mutex,
1127            const struct timespec *timeout),
1128           (cond, mutex, timeout));
1129 #endif /* VGO_solaris */
1130 
1131 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
1132 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
1133 // two. Intercepting all pthread_cond_signal* functions will cause only one
1134 // argument to be passed to pthread_cond_signal_np() and hence will cause this
1135 // last function to crash.
1136 
1137 static __always_inline
pthread_cond_signal_intercept(pthread_cond_t * cond)1138 int pthread_cond_signal_intercept(pthread_cond_t* cond)
1139 {
1140    int   ret;
1141    OrigFn fn;
1142    VALGRIND_GET_ORIG_FN(fn);
1143    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_SIGNAL,
1144                                    cond, 0, 0, 0, 0);
1145    CALL_FN_W_W(ret, fn, cond);
1146    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_SIGNAL,
1147                                    cond, 0, 0, 0, 0);
1148    return ret;
1149 }
1150 
1151 #if defined(VGO_solaris)
1152 /* On Solaris, pthread_cond_signal is a weak alias to cond_signal. */
1153 PTH_FUNCS(int, condZusignal, pthread_cond_signal_intercept,
1154           (pthread_cond_t *cond), (cond));
1155 #else
1156 PTH_FUNCS(int, pthreadZucondZusignal, pthread_cond_signal_intercept,
1157           (pthread_cond_t* cond), (cond));
1158 #endif /* VGO_solaris */
1159 
1160 static __always_inline
pthread_cond_broadcast_intercept(pthread_cond_t * cond)1161 int pthread_cond_broadcast_intercept(pthread_cond_t* cond)
1162 {
1163    int   ret;
1164    OrigFn fn;
1165    VALGRIND_GET_ORIG_FN(fn);
1166    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_BROADCAST,
1167                                    cond, 0, 0, 0, 0);
1168    CALL_FN_W_W(ret, fn, cond);
1169    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_BROADCAST,
1170                                    cond, 0, 0, 0, 0);
1171    return ret;
1172 }
1173 
1174 #if defined(VGO_solaris)
1175 /* On Solaris, pthread_cond_broadcast is a weak alias to cond_broadcast. */
1176 PTH_FUNCS(int, condZubroadcast, pthread_cond_broadcast_intercept,
1177           (pthread_cond_t *cond), (cond));
1178 #else
1179 PTH_FUNCS(int, pthreadZucondZubroadcast, pthread_cond_broadcast_intercept,
1180           (pthread_cond_t* cond), (cond));
1181 #endif /* VGO_solaris */
1182 
1183 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
1184     && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
1185 static __always_inline
pthread_spin_init_intercept(pthread_spinlock_t * spinlock,int pshared)1186 int pthread_spin_init_intercept(pthread_spinlock_t *spinlock, int pshared)
1187 {
1188    int ret;
1189    OrigFn fn;
1190    VALGRIND_GET_ORIG_FN(fn);
1191    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
1192                                    spinlock, 0, 0, 0, 0);
1193    CALL_FN_W_WW(ret, fn, spinlock, pshared);
1194    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
1195                                    spinlock, 0, 0, 0, 0);
1196    return ret;
1197 }
1198 
1199 PTH_FUNCS(int, pthreadZuspinZuinit, pthread_spin_init_intercept,
1200           (pthread_spinlock_t *spinlock, int pshared), (spinlock, pshared));
1201 
1202 static __always_inline
pthread_spin_destroy_intercept(pthread_spinlock_t * spinlock)1203 int pthread_spin_destroy_intercept(pthread_spinlock_t *spinlock)
1204 {
1205    int ret;
1206    OrigFn fn;
1207    VALGRIND_GET_ORIG_FN(fn);
1208    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
1209                                    spinlock, 0, 0, 0, 0);
1210    CALL_FN_W_W(ret, fn, spinlock);
1211    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
1212                                    spinlock, mutex_type_spinlock, 0, 0, 0);
1213    return ret;
1214 }
1215 
1216 PTH_FUNCS(int, pthreadZuspinZudestroy, pthread_spin_destroy_intercept,
1217           (pthread_spinlock_t *spinlock), (spinlock));
1218 
1219 static __always_inline
pthread_spin_lock_intercept(pthread_spinlock_t * spinlock)1220 int pthread_spin_lock_intercept(pthread_spinlock_t *spinlock)
1221 {
1222    int   ret;
1223    OrigFn fn;
1224    VALGRIND_GET_ORIG_FN(fn);
1225    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
1226                                    spinlock, mutex_type_spinlock, 0, 0, 0);
1227    CALL_FN_W_W(ret, fn, spinlock);
1228    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
1229                                    spinlock, ret == 0, 0, 0, 0);
1230    return ret;
1231 }
1232 
1233 PTH_FUNCS(int, pthreadZuspinZulock, pthread_spin_lock_intercept,
1234           (pthread_spinlock_t *spinlock), (spinlock));
1235 
1236 static __always_inline
pthread_spin_trylock_intercept(pthread_spinlock_t * spinlock)1237 int pthread_spin_trylock_intercept(pthread_spinlock_t *spinlock)
1238 {
1239    int   ret;
1240    OrigFn fn;
1241    VALGRIND_GET_ORIG_FN(fn);
1242    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
1243                                    spinlock, mutex_type_spinlock, 0, 0, 0);
1244    CALL_FN_W_W(ret, fn, spinlock);
1245    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
1246                                    spinlock, ret == 0, 0, 0, 0);
1247    return ret;
1248 }
1249 
1250 PTH_FUNCS(int, pthreadZuspinZutrylock, pthread_spin_trylock_intercept,
1251           (pthread_spinlock_t *spinlock), (spinlock));
1252 
1253 static __always_inline
pthread_spin_unlock_intercept(pthread_spinlock_t * spinlock)1254 int pthread_spin_unlock_intercept(pthread_spinlock_t *spinlock)
1255 {
1256    int   ret;
1257    OrigFn fn;
1258    VALGRIND_GET_ORIG_FN(fn);
1259    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
1260                                    spinlock, mutex_type_spinlock, 0, 0, 0);
1261    CALL_FN_W_W(ret, fn, spinlock);
1262    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
1263                                    spinlock, 0, 0, 0, 0);
1264    return ret;
1265 }
1266 
1267 PTH_FUNCS(int, pthreadZuspinZuunlock, pthread_spin_unlock_intercept,
1268           (pthread_spinlock_t *spinlock), (spinlock));
1269 #endif   // HAVE_PTHREAD_SPIN_LOCK
1270 
1271 
1272 #if defined(HAVE_PTHREAD_BARRIER_INIT)
1273 static __always_inline
pthread_barrier_init_intercept(pthread_barrier_t * barrier,const pthread_barrierattr_t * attr,unsigned count)1274 int pthread_barrier_init_intercept(pthread_barrier_t* barrier,
1275                                    const pthread_barrierattr_t* attr,
1276                                    unsigned count)
1277 {
1278    int   ret;
1279    OrigFn fn;
1280    VALGRIND_GET_ORIG_FN(fn);
1281    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_INIT,
1282                                    barrier, pthread_barrier, count, 0, 0);
1283    CALL_FN_W_WWW(ret, fn, barrier, attr, count);
1284    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_INIT,
1285                                    barrier, pthread_barrier, 0, 0, 0);
1286    return ret;
1287 }
1288 
1289 PTH_FUNCS(int, pthreadZubarrierZuinit, pthread_barrier_init_intercept,
1290           (pthread_barrier_t* barrier, const pthread_barrierattr_t* attr,
1291            unsigned count), (barrier, attr, count));
1292 
1293 static __always_inline
pthread_barrier_destroy_intercept(pthread_barrier_t * barrier)1294 int pthread_barrier_destroy_intercept(pthread_barrier_t* barrier)
1295 {
1296    int   ret;
1297    OrigFn fn;
1298    VALGRIND_GET_ORIG_FN(fn);
1299    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_DESTROY,
1300                                    barrier, pthread_barrier, 0, 0, 0);
1301    CALL_FN_W_W(ret, fn, barrier);
1302    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_DESTROY,
1303                                    barrier, pthread_barrier, 0, 0, 0);
1304    return ret;
1305 }
1306 
1307 PTH_FUNCS(int, pthreadZubarrierZudestroy, pthread_barrier_destroy_intercept,
1308           (pthread_barrier_t* barrier), (barrier));
1309 
1310 static __always_inline
pthread_barrier_wait_intercept(pthread_barrier_t * barrier)1311 int pthread_barrier_wait_intercept(pthread_barrier_t* barrier)
1312 {
1313    int   ret;
1314    OrigFn fn;
1315    VALGRIND_GET_ORIG_FN(fn);
1316    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_WAIT,
1317                                    barrier, pthread_barrier, 0, 0, 0);
1318    CALL_FN_W_W(ret, fn, barrier);
1319    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_WAIT,
1320                               barrier, pthread_barrier,
1321                               ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD,
1322                               ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
1323    return ret;
1324 }
1325 
1326 PTH_FUNCS(int, pthreadZubarrierZuwait, pthread_barrier_wait_intercept,
1327           (pthread_barrier_t* barrier), (barrier));
1328 #endif   // HAVE_PTHREAD_BARRIER_INIT
1329 
1330 
1331 static __always_inline
sem_init_intercept(sem_t * sem,int pshared,unsigned int value)1332 int sem_init_intercept(sem_t *sem, int pshared, unsigned int value)
1333 {
1334    int   ret;
1335    OrigFn fn;
1336    VALGRIND_GET_ORIG_FN(fn);
1337    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT,
1338                                    sem, pshared, value, 0, 0);
1339    CALL_FN_W_WWW(ret, fn, sem, pshared, value);
1340    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT,
1341                                    sem, 0, 0, 0, 0);
1342    return ret;
1343 }
1344 
1345 PTH_FUNCS(int, semZuinit, sem_init_intercept,
1346           (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
1347 
1348 #if defined(VGO_solaris)
1349 static __always_inline
sema_init_intercept(sema_t * sem,unsigned int value,int type,void * arg)1350 int sema_init_intercept(sema_t *sem, unsigned int value, int type, void *arg)
1351 {
1352    int   ret;
1353    OrigFn fn;
1354    VALGRIND_GET_ORIG_FN(fn);
1355    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT,
1356                                    sem, type == USYNC_PROCESS ? 1 : 0,
1357                                    value, 0, 0);
1358    CALL_FN_W_WWWW(ret, fn, sem, value, type, arg);
1359    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT,
1360                                    sem, 0, 0, 0, 0);
1361    return ret;
1362 }
1363 
1364 PTH_FUNCS(int, semaZuinit, sema_init_intercept,
1365           (sema_t *sem, unsigned int value, int type, void *arg),
1366           (sem, value, type, arg));
1367 #endif /* VGO_solaris */
1368 
1369 static __always_inline
sem_destroy_intercept(sem_t * sem)1370 int sem_destroy_intercept(sem_t *sem)
1371 {
1372    int   ret;
1373    OrigFn fn;
1374    VALGRIND_GET_ORIG_FN(fn);
1375    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_DESTROY,
1376                                    sem, 0, 0, 0, 0);
1377    CALL_FN_W_W(ret, fn, sem);
1378    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_DESTROY,
1379                                    sem, 0, 0, 0, 0);
1380    return ret;
1381 }
1382 
1383 PTH_FUNCS(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1384 #if defined(VGO_solaris)
1385 PTH_FUNCS(int, semaZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
1386 #endif /* VGO_solaris */
1387 
1388 static __always_inline
sem_open_intercept(const char * name,int oflag,mode_t mode,unsigned int value)1389 sem_t* sem_open_intercept(const char *name, int oflag, mode_t mode,
1390                           unsigned int value)
1391 {
1392    sem_t *ret;
1393    OrigFn fn;
1394    VALGRIND_GET_ORIG_FN(fn);
1395    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_OPEN,
1396                                    name, oflag, mode, value, 0);
1397    CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value);
1398    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_OPEN,
1399                                    ret != SEM_FAILED ? ret : 0,
1400                                    name, oflag, mode, value);
1401    return ret;
1402 }
1403 
1404 PTH_FUNCS(sem_t *, semZuopen, sem_open_intercept,
1405           (const char *name, int oflag, mode_t mode, unsigned int value),
1406           (name, oflag, mode, value));
1407 
sem_close_intercept(sem_t * sem)1408 static __always_inline int sem_close_intercept(sem_t *sem)
1409 {
1410    int   ret;
1411    OrigFn fn;
1412    VALGRIND_GET_ORIG_FN(fn);
1413    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_CLOSE,
1414                                    sem, 0, 0, 0, 0);
1415    CALL_FN_W_W(ret, fn, sem);
1416    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_CLOSE,
1417                                    sem, 0, 0, 0, 0);
1418    return ret;
1419 }
1420 
1421 PTH_FUNCS(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
1422 
sem_wait_intercept(sem_t * sem)1423 static __always_inline int sem_wait_intercept(sem_t *sem)
1424 {
1425    int   ret;
1426    OrigFn fn;
1427    VALGRIND_GET_ORIG_FN(fn);
1428    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1429                                    sem, 0, 0, 0, 0);
1430    CALL_FN_W_W(ret, fn, sem);
1431    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1432                                    sem, ret == 0, 0, 0, 0);
1433    return ret;
1434 }
1435 
1436 PTH_FUNCS(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1437 #if defined(VGO_solaris)
1438 PTH_FUNCS(int, semaZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1439 #endif /* VGO_solaris */
1440 
sem_trywait_intercept(sem_t * sem)1441 static __always_inline int sem_trywait_intercept(sem_t *sem)
1442 {
1443    int   ret;
1444    OrigFn fn;
1445    VALGRIND_GET_ORIG_FN(fn);
1446    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1447                                    sem, 0, 0, 0, 0);
1448    CALL_FN_W_W(ret, fn, sem);
1449    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1450                                    sem, ret == 0, 0, 0, 0);
1451    return ret;
1452 }
1453 
1454 PTH_FUNCS(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1455 #if defined(VGO_solaris)
1456 PTH_FUNCS(int, semaZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1457 #endif /* VGO_solaris */
1458 
1459 static __always_inline
sem_timedwait_intercept(sem_t * sem,const struct timespec * abs_timeout)1460 int sem_timedwait_intercept(sem_t *sem, const struct timespec *abs_timeout)
1461 {
1462    int   ret;
1463    OrigFn fn;
1464    VALGRIND_GET_ORIG_FN(fn);
1465    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1466                                    sem, 0, 0, 0, 0);
1467    CALL_FN_W_WW(ret, fn, sem, abs_timeout);
1468    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1469                                    sem, ret == 0, 0, 0, 0);
1470    return ret;
1471 }
1472 
1473 PTH_FUNCS(int, semZutimedwait, sem_timedwait_intercept,
1474           (sem_t *sem, const struct timespec *abs_timeout),
1475           (sem, abs_timeout));
1476 #if defined(VGO_solaris)
1477 PTH_FUNCS(int, semaZutimedwait, sem_timedwait_intercept,
1478           (sem_t *sem, const struct timespec *timeout),
1479           (sem, timeout));
1480 PTH_FUNCS(int, semaZureltimedwait, sem_timedwait_intercept,
1481           (sem_t *sem, const struct timespec *timeout),
1482           (sem, timeout));
1483 #endif /* VGO_solaris */
1484 
sem_post_intercept(sem_t * sem)1485 static __always_inline int sem_post_intercept(sem_t *sem)
1486 {
1487    int   ret;
1488    OrigFn fn;
1489    VALGRIND_GET_ORIG_FN(fn);
1490    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_POST,
1491                                    sem, 0, 0, 0, 0);
1492    CALL_FN_W_W(ret, fn, sem);
1493    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_POST,
1494                                    sem, ret == 0, 0, 0, 0);
1495    return ret;
1496 }
1497 
1498 PTH_FUNCS(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
1499 #if defined(VGO_solaris)
1500 PTH_FUNCS(int, semaZupost, sem_post_intercept, (sem_t *sem), (sem));
1501 #endif /* VGO_solaris */
1502 
1503 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1504    functions have to be conditionally compiled. */
1505 #if defined(HAVE_PTHREAD_RWLOCK_T)
1506 
1507 static __always_inline
pthread_rwlock_init_intercept(pthread_rwlock_t * rwlock,const pthread_rwlockattr_t * attr)1508 int pthread_rwlock_init_intercept(pthread_rwlock_t* rwlock,
1509                                   const pthread_rwlockattr_t* attr)
1510 {
1511    int   ret;
1512    OrigFn fn;
1513    VALGRIND_GET_ORIG_FN(fn);
1514    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT,
1515                                    rwlock, 0, 0, 0, 0);
1516    CALL_FN_W_WW(ret, fn, rwlock, attr);
1517    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT,
1518                                    rwlock, 0, 0, 0, 0);
1519    return ret;
1520 }
1521 
1522 PTH_FUNCS(int,
1523           pthreadZurwlockZuinit, pthread_rwlock_init_intercept,
1524           (pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr),
1525           (rwlock, attr));
1526 
1527 #if defined(VGO_solaris)
1528 static __always_inline
rwlock_init_intercept(rwlock_t * rwlock,int type,void * arg)1529 int rwlock_init_intercept(rwlock_t *rwlock, int type, void *arg)
1530 {
1531    int   ret;
1532    OrigFn fn;
1533    VALGRIND_GET_ORIG_FN(fn);
1534    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT,
1535                                    rwlock, 0, 0, 0, 0);
1536    CALL_FN_W_WWW(ret, fn, rwlock, type, arg);
1537    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT,
1538                                    rwlock, 0, 0, 0, 0);
1539    return ret;
1540 }
1541 
1542 PTH_FUNCS(int, rwlockZuinit, rwlock_init_intercept,
1543           (rwlock_t *rwlock, int type, void *arg),
1544           (rwlock, type, arg));
1545 #endif /* VGO_solaris */
1546 
1547 static __always_inline
pthread_rwlock_destroy_intercept(pthread_rwlock_t * rwlock)1548 int pthread_rwlock_destroy_intercept(pthread_rwlock_t* rwlock)
1549 {
1550    int   ret;
1551    OrigFn fn;
1552    VALGRIND_GET_ORIG_FN(fn);
1553    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_DESTROY,
1554                                    rwlock, 0, 0, 0, 0);
1555    CALL_FN_W_W(ret, fn, rwlock);
1556    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_DESTROY,
1557                                    rwlock, 0, 0, 0, 0);
1558    return ret;
1559 }
1560 
1561 #if defined(VGO_solaris)
1562 /* On Solaris, pthread_rwlock_destroy is a weak alias to rwlock_destroy. */
1563 PTH_FUNCS(int,
1564           rwlockZudestroy, pthread_rwlock_destroy_intercept,
1565           (pthread_rwlock_t *rwlock), (rwlock));
1566 #else
1567 PTH_FUNCS(int,
1568           pthreadZurwlockZudestroy, pthread_rwlock_destroy_intercept,
1569           (pthread_rwlock_t* rwlock), (rwlock));
1570 #endif /* VGO_solaris */
1571 
1572 static __always_inline
pthread_rwlock_rdlock_intercept(pthread_rwlock_t * rwlock)1573 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t* rwlock)
1574 {
1575    int   ret;
1576    OrigFn fn;
1577    VALGRIND_GET_ORIG_FN(fn);
1578    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1579                                    rwlock, 0, 0, 0, 0);
1580    CALL_FN_W_W(ret, fn, rwlock);
1581    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1582                                    rwlock, ret == 0, 0, 0, 0);
1583    return ret;
1584 }
1585 
1586 #if defined(VGO_solaris)
1587 /* On Solaris, pthread_rwlock_rdlock is a weak alias to rw_rdlock. */
1588 PTH_FUNCS(int,
1589           rwZurdlock, pthread_rwlock_rdlock_intercept,
1590           (pthread_rwlock_t *rwlock), (rwlock));
1591 #else
1592 PTH_FUNCS(int,
1593           pthreadZurwlockZurdlock, pthread_rwlock_rdlock_intercept,
1594           (pthread_rwlock_t* rwlock), (rwlock));
1595 #endif /* VGO_solaris */
1596 
1597 #if defined(VGO_solaris)
1598 /* Internal to libc. */
1599 static __always_inline
lrw_rdlock_intercept(rwlock_t * rwlock)1600 void lrw_rdlock_intercept(rwlock_t *rwlock)
1601 {
1602    OrigFn fn;
1603    VALGRIND_GET_ORIG_FN(fn);
1604    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1605                                    rwlock, 0, 0, 0, 0);
1606    CALL_FN_v_W(fn, rwlock);
1607    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1608                                    rwlock, True /* took_lock */, 0, 0, 0);
1609 }
1610 
1611 PTH_FUNCS(void, lrwZurdlock, lrw_rdlock_intercept,
1612           (rwlock_t *rwlock), (rwlock));
1613 #endif /* VGO_solaris */
1614 
1615 static __always_inline
pthread_rwlock_wrlock_intercept(pthread_rwlock_t * rwlock)1616 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t* rwlock)
1617 {
1618    int   ret;
1619    OrigFn fn;
1620    VALGRIND_GET_ORIG_FN(fn);
1621    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1622                                    rwlock, 0, 0, 0, 0);
1623    CALL_FN_W_W(ret, fn, rwlock);
1624    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1625                                    rwlock, ret == 0, 0, 0, 0);
1626    return ret;
1627 }
1628 
1629 #if defined(VGO_solaris)
1630 /* On Solaris, pthread_rwlock_wrlock is a weak alias to rw_wrlock. */
1631 PTH_FUNCS(int,
1632           rwZuwrlock, pthread_rwlock_wrlock_intercept,
1633           (pthread_rwlock_t *rwlock), (rwlock));
1634 #else
1635 PTH_FUNCS(int,
1636           pthreadZurwlockZuwrlock, pthread_rwlock_wrlock_intercept,
1637           (pthread_rwlock_t* rwlock), (rwlock));
1638 #endif /* VGO_solaris */
1639 
1640 #if defined(VGO_solaris)
1641 /* Internal to libc. */
1642 static __always_inline
lrw_wrlock_intercept(rwlock_t * rwlock)1643 void lrw_wrlock_intercept(rwlock_t *rwlock)
1644 {
1645    OrigFn fn;
1646    VALGRIND_GET_ORIG_FN(fn);
1647    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1648                                    rwlock, 0, 0, 0, 0);
1649    CALL_FN_v_W(fn, rwlock);
1650    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1651                                    rwlock, True /* took_lock */, 0, 0, 0);
1652 }
1653 
1654 PTH_FUNCS(void, lrwZuwrlock, lrw_wrlock_intercept,
1655           (rwlock_t *rwlock), (rwlock));
1656 #endif /* VGO_solaris */
1657 
1658 static __always_inline
pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t * rwlock,const struct timespec * timeout)1659 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t* rwlock,
1660                                          const struct timespec *timeout)
1661 {
1662    int   ret;
1663    OrigFn fn;
1664    VALGRIND_GET_ORIG_FN(fn);
1665    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1666                                    rwlock, 0, 0, 0, 0);
1667    CALL_FN_W_WW(ret, fn, rwlock, timeout);
1668    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1669                                    rwlock, ret == 0, 0, 0, 0);
1670    return ret;
1671 }
1672 
1673 PTH_FUNCS(int,
1674           pthreadZurwlockZutimedrdlock, pthread_rwlock_timedrdlock_intercept,
1675           (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1676           (rwlock, timeout));
1677 #if defined(VGO_solaris)
1678 PTH_FUNCS(int, pthreadZurwlockZureltimedrdlockZunp,
1679           pthread_rwlock_timedrdlock_intercept,
1680           (pthread_rwlock_t *rwlock, const struct timespec *timeout),
1681           (rwlock, timeout));
1682 #endif /* VGO_solaris */
1683 
1684 static __always_inline
pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t * rwlock,const struct timespec * timeout)1685 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t* rwlock,
1686                                          const struct timespec *timeout)
1687 {
1688    int   ret;
1689    OrigFn fn;
1690    VALGRIND_GET_ORIG_FN(fn);
1691    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1692                                    rwlock, 0, 0, 0, 0);
1693    CALL_FN_W_WW(ret, fn, rwlock, timeout);
1694    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1695                                    rwlock, ret == 0, 0, 0, 0);
1696    return ret;
1697 }
1698 
1699 PTH_FUNCS(int,
1700           pthreadZurwlockZutimedwrlock, pthread_rwlock_timedwrlock_intercept,
1701           (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1702           (rwlock, timeout));
1703 #if defined(VGO_solaris)
1704 PTH_FUNCS(int, pthreadZurwlockZureltimedwrlockZunp,
1705           pthread_rwlock_timedwrlock_intercept,
1706           (pthread_rwlock_t *rwlock, const struct timespec *timeout),
1707           (rwlock, timeout));
1708 #endif /* VGO_solaris */
1709 
1710 static __always_inline
pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t * rwlock)1711 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t* rwlock)
1712 {
1713    int   ret;
1714    OrigFn fn;
1715    VALGRIND_GET_ORIG_FN(fn);
1716    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1717                                    rwlock, 0, 0, 0, 0);
1718    CALL_FN_W_W(ret, fn, rwlock);
1719    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1720                                    rwlock, ret == 0, 0, 0, 0);
1721    return ret;
1722 }
1723 
1724 #if defined(VGO_solaris)
1725 /* On Solaris, pthread_rwlock_tryrdlock is a weak alias to rw_tryrdlock. */
1726 PTH_FUNCS(int,
1727           rwZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1728           (pthread_rwlock_t *rwlock), (rwlock));
1729 #else
1730 PTH_FUNCS(int,
1731           pthreadZurwlockZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1732           (pthread_rwlock_t* rwlock), (rwlock));
1733 #endif /* VGO_solaris */
1734 
1735 static __always_inline
pthread_rwlock_trywrlock_intercept(pthread_rwlock_t * rwlock)1736 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t* rwlock)
1737 {
1738    int   ret;
1739    OrigFn fn;
1740    VALGRIND_GET_ORIG_FN(fn);
1741    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1742                                    rwlock, 0, 0, 0, 0);
1743    CALL_FN_W_W(ret, fn, rwlock);
1744    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1745                                    rwlock, ret == 0, 0, 0, 0);
1746    return ret;
1747 }
1748 
1749 #if defined(VGO_solaris)
1750 /* On Solaris, pthread_rwlock_trywrlock is a weak alias to rw_trywrlock. */
1751 PTH_FUNCS(int,
1752           rwZutrywrlock, pthread_rwlock_trywrlock_intercept,
1753           (pthread_rwlock_t *rwlock), (rwlock));
1754 #else
1755 PTH_FUNCS(int,
1756           pthreadZurwlockZutrywrlock, pthread_rwlock_trywrlock_intercept,
1757           (pthread_rwlock_t* rwlock), (rwlock));
1758 #endif /* VGO_solaris */
1759 
1760 static __always_inline
pthread_rwlock_unlock_intercept(pthread_rwlock_t * rwlock)1761 int pthread_rwlock_unlock_intercept(pthread_rwlock_t* rwlock)
1762 {
1763    int   ret;
1764    OrigFn fn;
1765    VALGRIND_GET_ORIG_FN(fn);
1766    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_UNLOCK,
1767                                    rwlock, 0, 0, 0, 0);
1768    CALL_FN_W_W(ret, fn, rwlock);
1769    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_UNLOCK,
1770                                    rwlock, ret == 0, 0, 0, 0);
1771    return ret;
1772 }
1773 
1774 #if defined(VGO_solaris)
1775 /* On Solaris, pthread_rwlock_unlock is a weak alias to rw_unlock. */
1776 PTH_FUNCS(int,
1777           rwZuunlock, pthread_rwlock_unlock_intercept,
1778           (pthread_rwlock_t *rwlock), (rwlock));
1779 #else
1780 PTH_FUNCS(int,
1781           pthreadZurwlockZuunlock, pthread_rwlock_unlock_intercept,
1782           (pthread_rwlock_t* rwlock), (rwlock));
1783 #endif /* VGO_solaris */
1784 
1785 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
1786