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