1 /*--------------------------------------------------------------------*/
2 /*--- Client-space code for DRD. drd_pthread_intercepts.c ---*/
3 /*--------------------------------------------------------------------*/
4
5 /*
6 This file is part of DRD, a thread error detector.
7
8 Copyright (C) 2006-2013 Bart Van Assche <bvanassche@acm.org>.
9
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2 of the
13 License, or (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
23 02111-1307, USA.
24
25 The GNU General Public License is contained in the file COPYING.
26 */
27
28 /* ---------------------------------------------------------------------
29 ALL THE CODE IN THIS FILE RUNS ON THE SIMULATED CPU.
30
31 These functions are not called directly - they're the targets of code
32 redirection or load notifications (see pub_core_redir.h for info).
33 They're named weirdly so that the intercept code can find them when the
34 shared object is initially loaded.
35
36 Note that this filename has the "drd_" prefix because it can appear
37 in stack traces, and the "drd_" makes it a little clearer that it
38 originates from Valgrind.
39 ------------------------------------------------------------------ */
40
41 /*
42 * Define _GNU_SOURCE to make sure that pthread_spinlock_t is available when
43 * compiling with older glibc versions (2.3 or before).
44 */
45 #ifndef _GNU_SOURCE
46 #define _GNU_SOURCE
47 #endif
48
49 #include <assert.h> /* assert() */
50 #include <errno.h>
51 #include <pthread.h> /* pthread_mutex_t */
52 #include <semaphore.h> /* sem_t */
53 #include <stdint.h> /* uintptr_t */
54 #include <stdio.h> /* fprintf() */
55 #include <stdlib.h> /* malloc(), free() */
56 #include <unistd.h> /* confstr() */
57 #include "config.h" /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP etc. */
58 #ifdef HAVE_USABLE_LINUX_FUTEX_H
59 #include <asm/unistd.h> /* __NR_futex */
60 #include <linux/futex.h> /* FUTEX_WAIT */
61 #ifndef FUTEX_PRIVATE_FLAG
62 #define FUTEX_PRIVATE_FLAG 0
63 #endif
64 #endif
65 #include "drd_basics.h" /* DRD_() */
66 #include "drd_clientreq.h"
67 #include "pub_tool_redir.h" /* VG_WRAP_FUNCTION_ZZ() */
68
69
70 /*
71 * Notes regarding thread creation:
72 * - sg_init() runs on the context of the created thread and copies the vector
73 * clock of the creator thread. This only works reliably if the creator
74 * thread waits until this copy has been performed.
75 * - DRD_(thread_compute_minimum_vc)() does not take the vector clocks into
76 * account that are involved in thread creation and for which the
77 * corresponding thread has not yet been created. So not waiting until the
78 * created thread has been started would make it possible that segments get
79 * discarded that should not yet be discarded. Or: some data races are not
80 * detected.
81 */
82
83 /**
84 * Macro for generating a Valgrind interception function.
85 * @param[in] ret_ty Return type of the function to be generated.
86 * @param[in] zf Z-encoded name of the interception function.
87 * @param[in] implf Name of the function that implements the intercept.
88 * @param[in] arg_decl Argument declaration list enclosed in parentheses.
89 * @param[in] argl Argument list enclosed in parentheses.
90 */
91 #ifdef VGO_darwin
92 static int never_true;
93 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
94 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
95 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
96 { \
97 ret_ty pth_func_result = implf argl; \
98 /* Apparently inserting a function call in wrapper functions */ \
99 /* is sufficient to avoid misaligned stack errors. */ \
100 if (never_true) \
101 fflush(stdout); \
102 return pth_func_result; \
103 }
104 #else
105 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl) \
106 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl; \
107 ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl \
108 { return implf argl; }
109 #endif
110
111 /**
112 * Macro for generating three Valgrind interception functions: one with the
113 * Z-encoded name zf, one with ZAZa ("@*") appended to the name zf and one
114 * with ZDZa ("$*") appended to the name zf. The second generated interception
115 * function will intercept versioned symbols on Linux, and the third will
116 * intercept versioned symbols on Darwin.
117 */
118 #define PTH_FUNCS(ret_ty, zf, implf, argl_decl, argl) \
119 PTH_FUNC(ret_ty, zf, implf, argl_decl, argl); \
120 PTH_FUNC(ret_ty, zf ## ZAZa, implf, argl_decl, argl); \
121 PTH_FUNC(ret_ty, zf ## ZDZa, implf, argl_decl, argl);
122
123 /*
124 * Not inlining one of the intercept functions will cause the regression
125 * tests to fail because this would cause an additional stackfram to appear
126 * in the output. The __always_inline macro guarantees that inlining will
127 * happen, even when compiling with optimization disabled.
128 */
129 #undef __always_inline /* since already defined in <cdefs.h> */
130 #if __GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 2
131 #define __always_inline __inline__ __attribute__((always_inline))
132 #else
133 #define __always_inline __inline__
134 #endif
135
136 /* Local data structures. */
137
138 typedef struct {
139 pthread_mutex_t mutex;
140 int counter;
141 int waiters;
142 } DrdSema;
143
144 typedef struct
145 {
146 void* (*start)(void*);
147 void* arg;
148 int detachstate;
149 DrdSema* wrapper_started;
150 } DrdPosixThreadArgs;
151
152
153 /* Local function declarations. */
154
155 static void DRD_(init)(void) __attribute__((constructor));
156 static void DRD_(check_threading_library)(void);
157 static void DRD_(set_main_thread_state)(void);
158 static void DRD_(sema_init)(DrdSema* sema);
159 static void DRD_(sema_destroy)(DrdSema* sema);
160 static void DRD_(sema_down)(DrdSema* sema);
161 static void DRD_(sema_up)(DrdSema* sema);
162
163
164 /* Function definitions. */
165
166 /**
167 * Shared library initialization function. The function init() is called after
168 * dlopen() has loaded the shared library with DRD client intercepts because
169 * the constructor attribute was specified in the declaration of this function.
170 * Note: do specify the -nostdlib option to gcc when linking this code into a
171 * shared library because doing so would cancel the effect of the constructor
172 * attribute ! Using the gcc option -nodefaultlibs is fine because this last
173 * option preserves the shared library initialization code that calls
174 * constructor and destructor functions.
175 */
DRD_(init)176 static void DRD_(init)(void)
177 {
178 DRD_(check_threading_library)();
179 DRD_(set_main_thread_state)();
180 }
181
DRD_(sema_init)182 static void DRD_(sema_init)(DrdSema* sema)
183 {
184 DRD_IGNORE_VAR(sema->counter);
185 pthread_mutex_init(&sema->mutex, NULL);
186 sema->counter = 0;
187 sema->waiters = 0;
188 }
189
DRD_(sema_destroy)190 static void DRD_(sema_destroy)(DrdSema* sema)
191 {
192 pthread_mutex_destroy(&sema->mutex);
193 }
194
DRD_(sema_down)195 static void DRD_(sema_down)(DrdSema* sema)
196 {
197 int res = ENOSYS;
198
199 pthread_mutex_lock(&sema->mutex);
200 if (sema->counter == 0) {
201 sema->waiters++;
202 while (sema->counter == 0) {
203 pthread_mutex_unlock(&sema->mutex);
204 #ifdef HAVE_USABLE_LINUX_FUTEX_H
205 if (syscall(__NR_futex, (UWord)&sema->counter,
206 FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0) == 0)
207 res = 0;
208 else
209 res = errno;
210 #endif
211 /*
212 * Invoke sched_yield() on non-Linux systems, if the futex syscall has
213 * not been invoked or if this code has been built on a Linux system
214 * where __NR_futex is defined and is run on a Linux system that does
215 * not support the futex syscall.
216 */
217 if (res != 0 && res != EWOULDBLOCK)
218 sched_yield();
219 pthread_mutex_lock(&sema->mutex);
220 }
221 sema->waiters--;
222 }
223 sema->counter--;
224 pthread_mutex_unlock(&sema->mutex);
225 }
226
DRD_(sema_up)227 static void DRD_(sema_up)(DrdSema* sema)
228 {
229 pthread_mutex_lock(&sema->mutex);
230 sema->counter++;
231 #ifdef HAVE_USABLE_LINUX_FUTEX_H
232 if (sema->waiters > 0)
233 syscall(__NR_futex, (UWord)&sema->counter,
234 FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1);
235 #endif
236 pthread_mutex_unlock(&sema->mutex);
237 }
238
239 /**
240 * POSIX threads and DRD each have their own mutex type identification.
241 * Convert POSIX threads' mutex type to DRD's mutex type. In the code below
242 * if-statements are used to test the value of 'kind' instead of a switch
243 * statement because some of the PTHREAD_MUTEX_ macro's may have the same
244 * value.
245 */
DRD_(pthread_to_drd_mutex_type)246 static MutexT DRD_(pthread_to_drd_mutex_type)(int kind)
247 {
248 /*
249 * See also PTHREAD_MUTEX_KIND_MASK_NP in glibc source file
250 * <nptl/pthreadP.h>.
251 */
252 kind &= PTHREAD_MUTEX_RECURSIVE | PTHREAD_MUTEX_ERRORCHECK |
253 PTHREAD_MUTEX_NORMAL | PTHREAD_MUTEX_DEFAULT;
254
255 if (kind == PTHREAD_MUTEX_RECURSIVE)
256 return mutex_type_recursive_mutex;
257 else if (kind == PTHREAD_MUTEX_ERRORCHECK)
258 return mutex_type_errorcheck_mutex;
259 else if (kind == PTHREAD_MUTEX_NORMAL)
260 return mutex_type_default_mutex;
261 else if (kind == PTHREAD_MUTEX_DEFAULT)
262 return mutex_type_default_mutex;
263 #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
264 else if (kind == PTHREAD_MUTEX_ADAPTIVE_NP)
265 return mutex_type_default_mutex;
266 #endif
267 else
268 return mutex_type_invalid_mutex;
269 }
270
271 #define IS_ALIGNED(p) (((uintptr_t)(p) & (sizeof(*(p)) - 1)) == 0)
272
273 /**
274 * Read the mutex type stored in the client memory used for the mutex
275 * implementation.
276 *
277 * @note This function depends on the implementation of the POSIX threads
278 * library -- the POSIX standard does not define the name of the member in
279 * which the mutex type is stored.
280 * @note The function mutex_type() has been declared inline in order
281 * to avoid that it shows up in call stacks (drd/tests/...exp* files).
282 * @note glibc stores the mutex type in the lowest two bits, and uses the
283 * higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
284 * PTHREAD_MUTEXATTR_FLAG_PSHARED.
285 */
DRD_(mutex_type)286 static __always_inline MutexT DRD_(mutex_type)(pthread_mutex_t* mutex)
287 {
288 #if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
289 /* glibc + LinuxThreads. */
290 if (IS_ALIGNED(&mutex->__m_kind))
291 {
292 const int kind = mutex->__m_kind & 3;
293 return DRD_(pthread_to_drd_mutex_type)(kind);
294 }
295 #elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
296 /* glibc + NPTL. */
297 if (IS_ALIGNED(&mutex->__data.__kind))
298 {
299 const int kind = mutex->__data.__kind & 3;
300 return DRD_(pthread_to_drd_mutex_type)(kind);
301 }
302 #else
303 /*
304 * Another POSIX threads implementation. The mutex type won't be printed
305 * when enabling --trace-mutex=yes.
306 */
307 #endif
308 return mutex_type_unknown;
309 }
310
311 /**
312 * Tell DRD whether 'tid' is a joinable thread or a detached thread.
313 */
DRD_(set_joinable)314 static void DRD_(set_joinable)(const pthread_t tid, const int joinable)
315 {
316 assert(joinable == 0 || joinable == 1);
317 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_JOINABLE,
318 tid, joinable, 0, 0, 0);
319 }
320
321 /** Tell DRD that the calling thread is about to enter pthread_create(). */
DRD_(entering_pthread_create)322 static __always_inline void DRD_(entering_pthread_create)(void)
323 {
324 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__ENTERING_PTHREAD_CREATE,
325 0, 0, 0, 0, 0);
326 }
327
328 /** Tell DRD that the calling thread has left pthread_create(). */
DRD_(left_pthread_create)329 static __always_inline void DRD_(left_pthread_create)(void)
330 {
331 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LEFT_PTHREAD_CREATE,
332 0, 0, 0, 0, 0);
333 }
334
335 /**
336 * Entry point for newly created threads. This function is called from the
337 * thread created by pthread_create().
338 */
DRD_(thread_wrapper)339 static void* DRD_(thread_wrapper)(void* arg)
340 {
341 DrdPosixThreadArgs* arg_ptr;
342 DrdPosixThreadArgs arg_copy;
343
344 arg_ptr = (DrdPosixThreadArgs*)arg;
345 arg_copy = *arg_ptr;
346
347 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
348 pthread_self(), 0, 0, 0, 0);
349
350 DRD_(set_joinable)(pthread_self(),
351 arg_copy.detachstate == PTHREAD_CREATE_JOINABLE);
352
353 /*
354 * Only set 'wrapper_started' after VG_USERREQ__SET_PTHREADID and
355 * DRD_(set_joinable)() have been invoked to avoid a race with
356 * a pthread_detach() invocation for this thread from another thread.
357 */
358 DRD_(sema_up)(arg_copy.wrapper_started);
359
360 return (arg_copy.start)(arg_copy.arg);
361 }
362
363 /**
364 * Return 1 if the LinuxThreads implementation of POSIX Threads has been
365 * detected, and 0 otherwise.
366 *
367 * @see For more information about the confstr() function, see also
368 * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
369 */
DRD_(detected_linuxthreads)370 static int DRD_(detected_linuxthreads)(void)
371 {
372 #if defined(linux)
373 #if defined(_CS_GNU_LIBPTHREAD_VERSION)
374 /* Linux with a recent glibc. */
375 HChar buffer[256];
376 unsigned len;
377 len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
378 assert(len <= sizeof(buffer));
379 return len > 0 && buffer[0] == 'l';
380 #else
381 /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
382 return 1;
383 #endif
384 #else
385 /* Another OS than Linux, hence no LinuxThreads. */
386 return 0;
387 #endif
388 }
389
390 /**
391 * Stop and print an error message in case a non-supported threading
392 * library implementation (LinuxThreads) has been detected.
393 */
DRD_(check_threading_library)394 static void DRD_(check_threading_library)(void)
395 {
396 if (DRD_(detected_linuxthreads)())
397 {
398 if (getenv("LD_ASSUME_KERNEL"))
399 {
400 fprintf(stderr,
401 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
402 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
403 "after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
404 );
405 }
406 else
407 {
408 fprintf(stderr,
409 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
410 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
411 "after having upgraded to a newer version of your Linux distribution.\n"
412 "Giving up.\n"
413 );
414 }
415 abort();
416 }
417 }
418
419 /**
420 * The main thread is the only thread not created by pthread_create().
421 * Update DRD's state information about the main thread.
422 */
DRD_(set_main_thread_state)423 static void DRD_(set_main_thread_state)(void)
424 {
425 // Make sure that DRD knows about the main thread's POSIX thread ID.
426 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
427 pthread_self(), 0, 0, 0, 0);
428 }
429
430 /*
431 * Note: as of today there exist three different versions of pthread_create
432 * in Linux:
433 * - pthread_create@GLIBC_2.0
434 * - pthread_create@@GLIBC_2.1
435 * - pthread_create@@GLIBC_2.2.5
436 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
437 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
438 * versions have been implemented. In any glibc version where more than one
439 * pthread_create function has been implemented, older versions call the
440 * newer versions. Or: the pthread_create* wrapper defined below can be
441 * called recursively. Any code in this wrapper should take this in account.
442 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
443 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
444 * See also the implementation of pthread_create@GLIBC_2.0 in
445 * glibc-2.9/nptl/pthread_create.c.
446 */
447
448 static __always_inline
pthread_create_intercept(pthread_t * thread,const pthread_attr_t * attr,void * (* start)(void *),void * arg)449 int pthread_create_intercept(pthread_t* thread, const pthread_attr_t* attr,
450 void* (*start)(void*), void* arg)
451 {
452 int ret;
453 OrigFn fn;
454 DrdSema wrapper_started;
455 DrdPosixThreadArgs thread_args;
456
457 VALGRIND_GET_ORIG_FN(fn);
458
459 DRD_(sema_init)(&wrapper_started);
460 thread_args.start = start;
461 thread_args.arg = arg;
462 thread_args.wrapper_started = &wrapper_started;
463 /*
464 * Find out whether the thread will be started as a joinable thread
465 * or as a detached thread. If no thread attributes have been specified,
466 * this means that the new thread will be started as a joinable thread.
467 */
468 thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
469 if (attr)
470 {
471 if (pthread_attr_getdetachstate(attr, &thread_args.detachstate) != 0)
472 assert(0);
473 }
474 assert(thread_args.detachstate == PTHREAD_CREATE_JOINABLE
475 || thread_args.detachstate == PTHREAD_CREATE_DETACHED);
476
477 DRD_(entering_pthread_create)();
478 CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), &thread_args);
479 DRD_(left_pthread_create)();
480
481 if (ret == 0) {
482 /* Wait until the thread wrapper started. */
483 DRD_(sema_down)(&wrapper_started);
484 }
485
486 DRD_(sema_destroy)(&wrapper_started);
487
488 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT,
489 pthread_self(), 0, 0, 0, 0);
490
491 return ret;
492 }
493
494 PTH_FUNCS(int, pthreadZucreate, pthread_create_intercept,
495 (pthread_t *thread, const pthread_attr_t *attr,
496 void *(*start) (void *), void *arg),
497 (thread, attr, start, arg));
498
499 static __always_inline
pthread_join_intercept(pthread_t pt_joinee,void ** thread_return)500 int pthread_join_intercept(pthread_t pt_joinee, void **thread_return)
501 {
502 int ret;
503 OrigFn fn;
504
505 VALGRIND_GET_ORIG_FN(fn);
506 /*
507 * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
508 * implementation triggers a (false positive) race report.
509 */
510 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
511 CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
512 if (ret == 0)
513 {
514 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN,
515 pt_joinee, 0, 0, 0, 0);
516 }
517 ANNOTATE_IGNORE_READS_AND_WRITES_END();
518 return ret;
519 }
520
521 PTH_FUNCS(int, pthreadZujoin, pthread_join_intercept,
522 (pthread_t pt_joinee, void **thread_return),
523 (pt_joinee, thread_return));
524
525 static __always_inline
pthread_detach_intercept(pthread_t pt_thread)526 int pthread_detach_intercept(pthread_t pt_thread)
527 {
528 int ret;
529 OrigFn fn;
530
531 VALGRIND_GET_ORIG_FN(fn);
532 CALL_FN_W_W(ret, fn, pt_thread);
533 DRD_(set_joinable)(pt_thread, 0);
534
535 return ret;
536 }
537
538 PTH_FUNCS(int, pthreadZudetach, pthread_detach_intercept,
539 (pthread_t thread), (thread));
540
541 // NOTE: be careful to intercept only pthread_cancel() and not
542 // pthread_cancel_init() on Linux.
543
544 static __always_inline
pthread_cancel_intercept(pthread_t pt_thread)545 int pthread_cancel_intercept(pthread_t pt_thread)
546 {
547 int ret;
548 OrigFn fn;
549 VALGRIND_GET_ORIG_FN(fn);
550 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_THREAD_CANCEL,
551 pt_thread, 0, 0, 0, 0);
552 CALL_FN_W_W(ret, fn, pt_thread);
553 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_CANCEL,
554 pt_thread, ret==0, 0, 0, 0);
555 return ret;
556 }
557
558 PTH_FUNCS(int, pthreadZucancel, pthread_cancel_intercept,
559 (pthread_t thread), (thread))
560
561 static __always_inline
pthread_once_intercept(pthread_once_t * once_control,void (* init_routine)(void))562 int pthread_once_intercept(pthread_once_t *once_control,
563 void (*init_routine)(void))
564 {
565 int ret;
566 OrigFn fn;
567 VALGRIND_GET_ORIG_FN(fn);
568 /*
569 * Ignore any data races triggered by the implementation of pthread_once().
570 * Necessary for Darwin. This is not necessary for Linux but doesn't have
571 * any known adverse effects.
572 */
573 DRD_IGNORE_VAR(*once_control);
574 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
575 CALL_FN_W_WW(ret, fn, once_control, init_routine);
576 ANNOTATE_IGNORE_READS_AND_WRITES_END();
577 DRD_STOP_IGNORING_VAR(*once_control);
578 return ret;
579 }
580
581 PTH_FUNCS(int, pthreadZuonce, pthread_once_intercept,
582 (pthread_once_t *once_control, void (*init_routine)(void)),
583 (once_control, init_routine));
584
585 static __always_inline
pthread_mutex_init_intercept(pthread_mutex_t * mutex,const pthread_mutexattr_t * attr)586 int pthread_mutex_init_intercept(pthread_mutex_t *mutex,
587 const pthread_mutexattr_t* attr)
588 {
589 int ret;
590 OrigFn fn;
591 int mt;
592 VALGRIND_GET_ORIG_FN(fn);
593 mt = PTHREAD_MUTEX_DEFAULT;
594 if (attr)
595 pthread_mutexattr_gettype(attr, &mt);
596 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
597 mutex, DRD_(pthread_to_drd_mutex_type)(mt),
598 0, 0, 0);
599 CALL_FN_W_WW(ret, fn, mutex, attr);
600 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
601 mutex, 0, 0, 0, 0);
602 return ret;
603 }
604
605 PTH_FUNCS(int, pthreadZumutexZuinit, pthread_mutex_init_intercept,
606 (pthread_mutex_t *mutex, const pthread_mutexattr_t* attr),
607 (mutex, attr));
608
609 static __always_inline
pthread_mutex_destroy_intercept(pthread_mutex_t * mutex)610 int pthread_mutex_destroy_intercept(pthread_mutex_t* mutex)
611 {
612 int ret;
613 OrigFn fn;
614 VALGRIND_GET_ORIG_FN(fn);
615 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
616 mutex, 0, 0, 0, 0);
617 CALL_FN_W_W(ret, fn, mutex);
618 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
619 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
620 return ret;
621 }
622
623 PTH_FUNCS(int, pthreadZumutexZudestroy, pthread_mutex_destroy_intercept,
624 (pthread_mutex_t *mutex), (mutex));
625
626 static __always_inline
pthread_mutex_lock_intercept(pthread_mutex_t * mutex)627 int pthread_mutex_lock_intercept(pthread_mutex_t* mutex)
628 {
629 int ret;
630 OrigFn fn;
631 VALGRIND_GET_ORIG_FN(fn);
632 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
633 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
634 CALL_FN_W_W(ret, fn, mutex);
635 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
636 mutex, ret == 0, 0, 0, 0);
637 return ret;
638 }
639
640 PTH_FUNCS(int, pthreadZumutexZulock, pthread_mutex_lock_intercept,
641 (pthread_mutex_t *mutex), (mutex));
642
643 static __always_inline
pthread_mutex_trylock_intercept(pthread_mutex_t * mutex)644 int pthread_mutex_trylock_intercept(pthread_mutex_t* mutex)
645 {
646 int ret;
647 OrigFn fn;
648 VALGRIND_GET_ORIG_FN(fn);
649 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
650 mutex, DRD_(mutex_type)(mutex), 1, 0, 0);
651 CALL_FN_W_W(ret, fn, mutex);
652 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
653 mutex, ret == 0, 0, 0, 0);
654 return ret;
655 }
656
657 PTH_FUNCS(int, pthreadZumutexZutrylock, pthread_mutex_trylock_intercept,
658 (pthread_mutex_t *mutex), (mutex));
659
660 static __always_inline
pthread_mutex_timedlock_intercept(pthread_mutex_t * mutex,const struct timespec * abs_timeout)661 int pthread_mutex_timedlock_intercept(pthread_mutex_t *mutex,
662 const struct timespec *abs_timeout)
663 {
664 int ret;
665 OrigFn fn;
666 VALGRIND_GET_ORIG_FN(fn);
667 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
668 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
669 CALL_FN_W_WW(ret, fn, mutex, abs_timeout);
670 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
671 mutex, ret == 0, 0, 0, 0);
672 return ret;
673 }
674
675 PTH_FUNCS(int, pthreadZumutexZutimedlock, pthread_mutex_timedlock_intercept,
676 (pthread_mutex_t *mutex, const struct timespec *abs_timeout),
677 (mutex, abs_timeout));
678
679 static __always_inline
pthread_mutex_unlock_intercept(pthread_mutex_t * mutex)680 int pthread_mutex_unlock_intercept(pthread_mutex_t *mutex)
681 {
682 int ret;
683 OrigFn fn;
684 VALGRIND_GET_ORIG_FN(fn);
685 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
686 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
687 CALL_FN_W_W(ret, fn, mutex);
688 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
689 mutex, 0, 0, 0, 0);
690 return ret;
691 }
692
693 PTH_FUNCS(int, pthreadZumutexZuunlock, pthread_mutex_unlock_intercept,
694 (pthread_mutex_t *mutex), (mutex));
695
696 static __always_inline
pthread_cond_init_intercept(pthread_cond_t * cond,const pthread_condattr_t * attr)697 int pthread_cond_init_intercept(pthread_cond_t* cond,
698 const pthread_condattr_t* attr)
699 {
700 int ret;
701 OrigFn fn;
702 VALGRIND_GET_ORIG_FN(fn);
703 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT,
704 cond, 0, 0, 0, 0);
705 CALL_FN_W_WW(ret, fn, cond, attr);
706 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT,
707 cond, 0, 0, 0, 0);
708 return ret;
709 }
710
711 PTH_FUNCS(int, pthreadZucondZuinit, pthread_cond_init_intercept,
712 (pthread_cond_t* cond, const pthread_condattr_t* attr),
713 (cond, attr));
714
715 static __always_inline
pthread_cond_destroy_intercept(pthread_cond_t * cond)716 int pthread_cond_destroy_intercept(pthread_cond_t* cond)
717 {
718 int ret;
719 OrigFn fn;
720 VALGRIND_GET_ORIG_FN(fn);
721 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_DESTROY,
722 cond, 0, 0, 0, 0);
723 CALL_FN_W_W(ret, fn, cond);
724 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_DESTROY,
725 cond, ret==0, 0, 0, 0);
726 return ret;
727 }
728
729 PTH_FUNCS(int, pthreadZucondZudestroy, pthread_cond_destroy_intercept,
730 (pthread_cond_t* cond), (cond));
731
732 static __always_inline
pthread_cond_wait_intercept(pthread_cond_t * cond,pthread_mutex_t * mutex)733 int pthread_cond_wait_intercept(pthread_cond_t *cond, pthread_mutex_t *mutex)
734 {
735 int ret;
736 OrigFn fn;
737 VALGRIND_GET_ORIG_FN(fn);
738 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
739 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
740 CALL_FN_W_WW(ret, fn, cond, mutex);
741 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
742 cond, mutex, 1, 0, 0);
743 return ret;
744 }
745
746 PTH_FUNCS(int, pthreadZucondZuwait, pthread_cond_wait_intercept,
747 (pthread_cond_t *cond, pthread_mutex_t *mutex),
748 (cond, mutex));
749
750 static __always_inline
pthread_cond_timedwait_intercept(pthread_cond_t * cond,pthread_mutex_t * mutex,const struct timespec * abstime)751 int pthread_cond_timedwait_intercept(pthread_cond_t *cond,
752 pthread_mutex_t *mutex,
753 const struct timespec* abstime)
754 {
755 int ret;
756 OrigFn fn;
757 VALGRIND_GET_ORIG_FN(fn);
758 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
759 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
760 CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
761 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
762 cond, mutex, 1, 0, 0);
763 return ret;
764 }
765
766 PTH_FUNCS(int, pthreadZucondZutimedwait, pthread_cond_timedwait_intercept,
767 (pthread_cond_t *cond, pthread_mutex_t *mutex,
768 const struct timespec* abstime),
769 (cond, mutex, abstime));
770
771 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
772 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
773 // two. Intercepting all pthread_cond_signal* functions will cause only one
774 // argument to be passed to pthread_cond_signal_np() and hence will cause this
775 // last function to crash.
776
777 static __always_inline
pthread_cond_signal_intercept(pthread_cond_t * cond)778 int pthread_cond_signal_intercept(pthread_cond_t* cond)
779 {
780 int ret;
781 OrigFn fn;
782 VALGRIND_GET_ORIG_FN(fn);
783 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_SIGNAL,
784 cond, 0, 0, 0, 0);
785 CALL_FN_W_W(ret, fn, cond);
786 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_SIGNAL,
787 cond, 0, 0, 0, 0);
788 return ret;
789 }
790
791 PTH_FUNCS(int, pthreadZucondZusignal, pthread_cond_signal_intercept,
792 (pthread_cond_t* cond), (cond));
793
794 static __always_inline
pthread_cond_broadcast_intercept(pthread_cond_t * cond)795 int pthread_cond_broadcast_intercept(pthread_cond_t* cond)
796 {
797 int ret;
798 OrigFn fn;
799 VALGRIND_GET_ORIG_FN(fn);
800 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_BROADCAST,
801 cond, 0, 0, 0, 0);
802 CALL_FN_W_W(ret, fn, cond);
803 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_BROADCAST,
804 cond, 0, 0, 0, 0);
805 return ret;
806 }
807
808 PTH_FUNCS(int, pthreadZucondZubroadcast, pthread_cond_broadcast_intercept,
809 (pthread_cond_t* cond), (cond));
810
811 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
812 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
813 static __always_inline
pthread_spin_init_intercept(pthread_spinlock_t * spinlock,int pshared)814 int pthread_spin_init_intercept(pthread_spinlock_t *spinlock, int pshared)
815 {
816 int ret;
817 OrigFn fn;
818 VALGRIND_GET_ORIG_FN(fn);
819 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
820 spinlock, 0, 0, 0, 0);
821 CALL_FN_W_WW(ret, fn, spinlock, pshared);
822 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
823 spinlock, 0, 0, 0, 0);
824 return ret;
825 }
826
827 PTH_FUNCS(int, pthreadZuspinZuinit, pthread_spin_init_intercept,
828 (pthread_spinlock_t *spinlock, int pshared), (spinlock, pshared));
829
830 static __always_inline
pthread_spin_destroy_intercept(pthread_spinlock_t * spinlock)831 int pthread_spin_destroy_intercept(pthread_spinlock_t *spinlock)
832 {
833 int ret;
834 OrigFn fn;
835 VALGRIND_GET_ORIG_FN(fn);
836 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
837 spinlock, 0, 0, 0, 0);
838 CALL_FN_W_W(ret, fn, spinlock);
839 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
840 spinlock, mutex_type_spinlock, 0, 0, 0);
841 return ret;
842 }
843
844 PTH_FUNCS(int, pthreadZuspinZudestroy, pthread_spin_destroy_intercept,
845 (pthread_spinlock_t *spinlock), (spinlock));
846
847 static __always_inline
pthread_spin_lock_intercept(pthread_spinlock_t * spinlock)848 int pthread_spin_lock_intercept(pthread_spinlock_t *spinlock)
849 {
850 int ret;
851 OrigFn fn;
852 VALGRIND_GET_ORIG_FN(fn);
853 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
854 spinlock, mutex_type_spinlock, 0, 0, 0);
855 CALL_FN_W_W(ret, fn, spinlock);
856 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
857 spinlock, ret == 0, 0, 0, 0);
858 return ret;
859 }
860
861 PTH_FUNCS(int, pthreadZuspinZulock, pthread_spin_lock_intercept,
862 (pthread_spinlock_t *spinlock), (spinlock));
863
864 static __always_inline
pthread_spin_trylock_intercept(pthread_spinlock_t * spinlock)865 int pthread_spin_trylock_intercept(pthread_spinlock_t *spinlock)
866 {
867 int ret;
868 OrigFn fn;
869 VALGRIND_GET_ORIG_FN(fn);
870 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
871 spinlock, mutex_type_spinlock, 0, 0, 0);
872 CALL_FN_W_W(ret, fn, spinlock);
873 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
874 spinlock, ret == 0, 0, 0, 0);
875 return ret;
876 }
877
878 PTH_FUNCS(int, pthreadZuspinZutrylock, pthread_spin_trylock_intercept,
879 (pthread_spinlock_t *spinlock), (spinlock));
880
881 static __always_inline
pthread_spin_unlock_intercept(pthread_spinlock_t * spinlock)882 int pthread_spin_unlock_intercept(pthread_spinlock_t *spinlock)
883 {
884 int ret;
885 OrigFn fn;
886 VALGRIND_GET_ORIG_FN(fn);
887 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
888 spinlock, mutex_type_spinlock, 0, 0, 0);
889 CALL_FN_W_W(ret, fn, spinlock);
890 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
891 spinlock, 0, 0, 0, 0);
892 return ret;
893 }
894
895 PTH_FUNCS(int, pthreadZuspinZuunlock, pthread_spin_unlock_intercept,
896 (pthread_spinlock_t *spinlock), (spinlock));
897 #endif // HAVE_PTHREAD_SPIN_LOCK
898
899
900 #if defined(HAVE_PTHREAD_BARRIER_INIT)
901 static __always_inline
pthread_barrier_init_intercept(pthread_barrier_t * barrier,const pthread_barrierattr_t * attr,unsigned count)902 int pthread_barrier_init_intercept(pthread_barrier_t* barrier,
903 const pthread_barrierattr_t* attr,
904 unsigned count)
905 {
906 int ret;
907 OrigFn fn;
908 VALGRIND_GET_ORIG_FN(fn);
909 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_INIT,
910 barrier, pthread_barrier, count, 0, 0);
911 CALL_FN_W_WWW(ret, fn, barrier, attr, count);
912 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_INIT,
913 barrier, pthread_barrier, 0, 0, 0);
914 return ret;
915 }
916
917 PTH_FUNCS(int, pthreadZubarrierZuinit, pthread_barrier_init_intercept,
918 (pthread_barrier_t* barrier, const pthread_barrierattr_t* attr,
919 unsigned count), (barrier, attr, count));
920
921 static __always_inline
pthread_barrier_destroy_intercept(pthread_barrier_t * barrier)922 int pthread_barrier_destroy_intercept(pthread_barrier_t* barrier)
923 {
924 int ret;
925 OrigFn fn;
926 VALGRIND_GET_ORIG_FN(fn);
927 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_DESTROY,
928 barrier, pthread_barrier, 0, 0, 0);
929 CALL_FN_W_W(ret, fn, barrier);
930 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_DESTROY,
931 barrier, pthread_barrier, 0, 0, 0);
932 return ret;
933 }
934
935 PTH_FUNCS(int, pthreadZubarrierZudestroy, pthread_barrier_destroy_intercept,
936 (pthread_barrier_t* barrier), (barrier));
937
938 static __always_inline
pthread_barrier_wait_intercept(pthread_barrier_t * barrier)939 int pthread_barrier_wait_intercept(pthread_barrier_t* barrier)
940 {
941 int ret;
942 OrigFn fn;
943 VALGRIND_GET_ORIG_FN(fn);
944 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_WAIT,
945 barrier, pthread_barrier, 0, 0, 0);
946 CALL_FN_W_W(ret, fn, barrier);
947 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_WAIT,
948 barrier, pthread_barrier,
949 ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD,
950 ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
951 return ret;
952 }
953
954 PTH_FUNCS(int, pthreadZubarrierZuwait, pthread_barrier_wait_intercept,
955 (pthread_barrier_t* barrier), (barrier));
956 #endif // HAVE_PTHREAD_BARRIER_INIT
957
958
959 static __always_inline
sem_init_intercept(sem_t * sem,int pshared,unsigned int value)960 int sem_init_intercept(sem_t *sem, int pshared, unsigned int value)
961 {
962 int ret;
963 OrigFn fn;
964 VALGRIND_GET_ORIG_FN(fn);
965 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT,
966 sem, pshared, value, 0, 0);
967 CALL_FN_W_WWW(ret, fn, sem, pshared, value);
968 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT,
969 sem, 0, 0, 0, 0);
970 return ret;
971 }
972
973 PTH_FUNCS(int, semZuinit, sem_init_intercept,
974 (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
975
976 static __always_inline
sem_destroy_intercept(sem_t * sem)977 int sem_destroy_intercept(sem_t *sem)
978 {
979 int ret;
980 OrigFn fn;
981 VALGRIND_GET_ORIG_FN(fn);
982 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_DESTROY,
983 sem, 0, 0, 0, 0);
984 CALL_FN_W_W(ret, fn, sem);
985 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_DESTROY,
986 sem, 0, 0, 0, 0);
987 return ret;
988 }
989
990 PTH_FUNCS(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
991
992 static __always_inline
sem_open_intercept(const char * name,int oflag,mode_t mode,unsigned int value)993 sem_t* sem_open_intercept(const char *name, int oflag, mode_t mode,
994 unsigned int value)
995 {
996 sem_t *ret;
997 OrigFn fn;
998 VALGRIND_GET_ORIG_FN(fn);
999 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_OPEN,
1000 name, oflag, mode, value, 0);
1001 CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value);
1002 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_OPEN,
1003 ret != SEM_FAILED ? ret : 0,
1004 name, oflag, mode, value);
1005 return ret;
1006 }
1007
1008 PTH_FUNCS(sem_t *, semZuopen, sem_open_intercept,
1009 (const char *name, int oflag, mode_t mode, unsigned int value),
1010 (name, oflag, mode, value));
1011
sem_close_intercept(sem_t * sem)1012 static __always_inline int sem_close_intercept(sem_t *sem)
1013 {
1014 int ret;
1015 OrigFn fn;
1016 VALGRIND_GET_ORIG_FN(fn);
1017 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_CLOSE,
1018 sem, 0, 0, 0, 0);
1019 CALL_FN_W_W(ret, fn, sem);
1020 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_CLOSE,
1021 sem, 0, 0, 0, 0);
1022 return ret;
1023 }
1024
1025 PTH_FUNCS(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
1026
sem_wait_intercept(sem_t * sem)1027 static __always_inline int sem_wait_intercept(sem_t *sem)
1028 {
1029 int ret;
1030 OrigFn fn;
1031 VALGRIND_GET_ORIG_FN(fn);
1032 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1033 sem, 0, 0, 0, 0);
1034 CALL_FN_W_W(ret, fn, sem);
1035 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1036 sem, ret == 0, 0, 0, 0);
1037 return ret;
1038 }
1039
1040 PTH_FUNCS(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1041
sem_trywait_intercept(sem_t * sem)1042 static __always_inline int sem_trywait_intercept(sem_t *sem)
1043 {
1044 int ret;
1045 OrigFn fn;
1046 VALGRIND_GET_ORIG_FN(fn);
1047 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1048 sem, 0, 0, 0, 0);
1049 CALL_FN_W_W(ret, fn, sem);
1050 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1051 sem, ret == 0, 0, 0, 0);
1052 return ret;
1053 }
1054
1055 PTH_FUNCS(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1056
1057 static __always_inline
sem_timedwait_intercept(sem_t * sem,const struct timespec * abs_timeout)1058 int sem_timedwait_intercept(sem_t *sem, const struct timespec *abs_timeout)
1059 {
1060 int ret;
1061 OrigFn fn;
1062 VALGRIND_GET_ORIG_FN(fn);
1063 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1064 sem, 0, 0, 0, 0);
1065 CALL_FN_W_WW(ret, fn, sem, abs_timeout);
1066 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1067 sem, ret == 0, 0, 0, 0);
1068 return ret;
1069 }
1070
1071 PTH_FUNCS(int, semZutimedwait, sem_timedwait_intercept,
1072 (sem_t *sem, const struct timespec *abs_timeout),
1073 (sem, abs_timeout));
1074
sem_post_intercept(sem_t * sem)1075 static __always_inline int sem_post_intercept(sem_t *sem)
1076 {
1077 int ret;
1078 OrigFn fn;
1079 VALGRIND_GET_ORIG_FN(fn);
1080 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_POST,
1081 sem, 0, 0, 0, 0);
1082 CALL_FN_W_W(ret, fn, sem);
1083 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_POST,
1084 sem, ret == 0, 0, 0, 0);
1085 return ret;
1086 }
1087
1088 PTH_FUNCS(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
1089
1090 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1091 functions have to be conditionally compiled. */
1092 #if defined(HAVE_PTHREAD_RWLOCK_T)
1093
1094 static __always_inline
pthread_rwlock_init_intercept(pthread_rwlock_t * rwlock,const pthread_rwlockattr_t * attr)1095 int pthread_rwlock_init_intercept(pthread_rwlock_t* rwlock,
1096 const pthread_rwlockattr_t* attr)
1097 {
1098 int ret;
1099 OrigFn fn;
1100 VALGRIND_GET_ORIG_FN(fn);
1101 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT,
1102 rwlock, 0, 0, 0, 0);
1103 CALL_FN_W_WW(ret, fn, rwlock, attr);
1104 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT,
1105 rwlock, 0, 0, 0, 0);
1106 return ret;
1107 }
1108
1109 PTH_FUNCS(int,
1110 pthreadZurwlockZuinit, pthread_rwlock_init_intercept,
1111 (pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr),
1112 (rwlock, attr));
1113
1114 static __always_inline
pthread_rwlock_destroy_intercept(pthread_rwlock_t * rwlock)1115 int pthread_rwlock_destroy_intercept(pthread_rwlock_t* rwlock)
1116 {
1117 int ret;
1118 OrigFn fn;
1119 VALGRIND_GET_ORIG_FN(fn);
1120 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_DESTROY,
1121 rwlock, 0, 0, 0, 0);
1122 CALL_FN_W_W(ret, fn, rwlock);
1123 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_DESTROY,
1124 rwlock, 0, 0, 0, 0);
1125 return ret;
1126 }
1127
1128 PTH_FUNCS(int,
1129 pthreadZurwlockZudestroy, pthread_rwlock_destroy_intercept,
1130 (pthread_rwlock_t* rwlock), (rwlock));
1131
1132 static __always_inline
pthread_rwlock_rdlock_intercept(pthread_rwlock_t * rwlock)1133 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t* rwlock)
1134 {
1135 int ret;
1136 OrigFn fn;
1137 VALGRIND_GET_ORIG_FN(fn);
1138 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1139 rwlock, 0, 0, 0, 0);
1140 CALL_FN_W_W(ret, fn, rwlock);
1141 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1142 rwlock, ret == 0, 0, 0, 0);
1143 return ret;
1144 }
1145
1146 PTH_FUNCS(int,
1147 pthreadZurwlockZurdlock, pthread_rwlock_rdlock_intercept,
1148 (pthread_rwlock_t* rwlock), (rwlock));
1149
1150 static __always_inline
pthread_rwlock_wrlock_intercept(pthread_rwlock_t * rwlock)1151 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t* rwlock)
1152 {
1153 int ret;
1154 OrigFn fn;
1155 VALGRIND_GET_ORIG_FN(fn);
1156 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1157 rwlock, 0, 0, 0, 0);
1158 CALL_FN_W_W(ret, fn, rwlock);
1159 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1160 rwlock, ret == 0, 0, 0, 0);
1161 return ret;
1162 }
1163
1164 PTH_FUNCS(int,
1165 pthreadZurwlockZuwrlock, pthread_rwlock_wrlock_intercept,
1166 (pthread_rwlock_t* rwlock), (rwlock));
1167
1168 static __always_inline
pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t * rwlock,const struct timespec * timeout)1169 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t* rwlock,
1170 const struct timespec *timeout)
1171 {
1172 int ret;
1173 OrigFn fn;
1174 VALGRIND_GET_ORIG_FN(fn);
1175 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1176 rwlock, 0, 0, 0, 0);
1177 CALL_FN_W_WW(ret, fn, rwlock, timeout);
1178 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1179 rwlock, ret == 0, 0, 0, 0);
1180 return ret;
1181 }
1182
1183 PTH_FUNCS(int,
1184 pthreadZurwlockZutimedrdlock, pthread_rwlock_timedrdlock_intercept,
1185 (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1186 (rwlock, timeout));
1187
1188 static __always_inline
pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t * rwlock,const struct timespec * timeout)1189 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t* rwlock,
1190 const struct timespec *timeout)
1191 {
1192 int ret;
1193 OrigFn fn;
1194 VALGRIND_GET_ORIG_FN(fn);
1195 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1196 rwlock, 0, 0, 0, 0);
1197 CALL_FN_W_WW(ret, fn, rwlock, timeout);
1198 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1199 rwlock, ret == 0, 0, 0, 0);
1200 return ret;
1201 }
1202
1203 PTH_FUNCS(int,
1204 pthreadZurwlockZutimedwrlock, pthread_rwlock_timedwrlock_intercept,
1205 (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1206 (rwlock, timeout));
1207
1208 static __always_inline
pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t * rwlock)1209 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t* rwlock)
1210 {
1211 int ret;
1212 OrigFn fn;
1213 VALGRIND_GET_ORIG_FN(fn);
1214 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1215 rwlock, 0, 0, 0, 0);
1216 CALL_FN_W_W(ret, fn, rwlock);
1217 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1218 rwlock, ret == 0, 0, 0, 0);
1219 return ret;
1220 }
1221
1222 PTH_FUNCS(int,
1223 pthreadZurwlockZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1224 (pthread_rwlock_t* rwlock), (rwlock));
1225
1226 static __always_inline
pthread_rwlock_trywrlock_intercept(pthread_rwlock_t * rwlock)1227 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t* rwlock)
1228 {
1229 int ret;
1230 OrigFn fn;
1231 VALGRIND_GET_ORIG_FN(fn);
1232 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1233 rwlock, 0, 0, 0, 0);
1234 CALL_FN_W_W(ret, fn, rwlock);
1235 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1236 rwlock, ret == 0, 0, 0, 0);
1237 return ret;
1238 }
1239
1240 PTH_FUNCS(int,
1241 pthreadZurwlockZutrywrlock, pthread_rwlock_trywrlock_intercept,
1242 (pthread_rwlock_t* rwlock), (rwlock));
1243
1244 static __always_inline
pthread_rwlock_unlock_intercept(pthread_rwlock_t * rwlock)1245 int pthread_rwlock_unlock_intercept(pthread_rwlock_t* rwlock)
1246 {
1247 int ret;
1248 OrigFn fn;
1249 VALGRIND_GET_ORIG_FN(fn);
1250 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_UNLOCK,
1251 rwlock, 0, 0, 0, 0);
1252 CALL_FN_W_W(ret, fn, rwlock);
1253 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_UNLOCK,
1254 rwlock, ret == 0, 0, 0, 0);
1255 return ret;
1256 }
1257
1258 PTH_FUNCS(int,
1259 pthreadZurwlockZuunlock, pthread_rwlock_unlock_intercept,
1260 (pthread_rwlock_t* rwlock), (rwlock));
1261
1262 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
1263