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