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_(ignore_mutex_ordering)182 static __always_inline void DRD_(ignore_mutex_ordering)(pthread_mutex_t *mutex)
183 {
184 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_IGNORE_MUTEX_ORDERING,
185 mutex, 0, 0, 0, 0);
186 }
187
DRD_(sema_init)188 static void DRD_(sema_init)(DrdSema* sema)
189 {
190 DRD_IGNORE_VAR(*sema);
191 pthread_mutex_init(&sema->mutex, NULL);
192 DRD_(ignore_mutex_ordering)(&sema->mutex);
193 sema->counter = 0;
194 sema->waiters = 0;
195 }
196
DRD_(sema_destroy)197 static void DRD_(sema_destroy)(DrdSema* sema)
198 {
199 pthread_mutex_destroy(&sema->mutex);
200 }
201
DRD_(sema_down)202 static void DRD_(sema_down)(DrdSema* sema)
203 {
204 int res = ENOSYS;
205
206 pthread_mutex_lock(&sema->mutex);
207 if (sema->counter == 0) {
208 sema->waiters++;
209 while (sema->counter == 0) {
210 pthread_mutex_unlock(&sema->mutex);
211 #ifdef HAVE_USABLE_LINUX_FUTEX_H
212 if (syscall(__NR_futex, (UWord)&sema->counter,
213 FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0) == 0)
214 res = 0;
215 else
216 res = errno;
217 #endif
218 /*
219 * Invoke sched_yield() on non-Linux systems, if the futex syscall has
220 * not been invoked or if this code has been built on a Linux system
221 * where __NR_futex is defined and is run on a Linux system that does
222 * not support the futex syscall.
223 */
224 if (res != 0 && res != EWOULDBLOCK)
225 sched_yield();
226 pthread_mutex_lock(&sema->mutex);
227 }
228 sema->waiters--;
229 }
230 sema->counter--;
231 pthread_mutex_unlock(&sema->mutex);
232 }
233
DRD_(sema_up)234 static void DRD_(sema_up)(DrdSema* sema)
235 {
236 pthread_mutex_lock(&sema->mutex);
237 sema->counter++;
238 #ifdef HAVE_USABLE_LINUX_FUTEX_H
239 if (sema->waiters > 0)
240 syscall(__NR_futex, (UWord)&sema->counter,
241 FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1);
242 #endif
243 pthread_mutex_unlock(&sema->mutex);
244 }
245
246 /**
247 * POSIX threads and DRD each have their own mutex type identification.
248 * Convert POSIX threads' mutex type to DRD's mutex type. In the code below
249 * if-statements are used to test the value of 'kind' instead of a switch
250 * statement because some of the PTHREAD_MUTEX_ macro's may have the same
251 * value.
252 */
DRD_(pthread_to_drd_mutex_type)253 static MutexT DRD_(pthread_to_drd_mutex_type)(int kind)
254 {
255 /*
256 * See also PTHREAD_MUTEX_KIND_MASK_NP in glibc source file
257 * <nptl/pthreadP.h>.
258 */
259 kind &= PTHREAD_MUTEX_RECURSIVE | PTHREAD_MUTEX_ERRORCHECK |
260 PTHREAD_MUTEX_NORMAL | PTHREAD_MUTEX_DEFAULT;
261
262 if (kind == PTHREAD_MUTEX_RECURSIVE)
263 return mutex_type_recursive_mutex;
264 else if (kind == PTHREAD_MUTEX_ERRORCHECK)
265 return mutex_type_errorcheck_mutex;
266 else if (kind == PTHREAD_MUTEX_NORMAL)
267 return mutex_type_default_mutex;
268 else if (kind == PTHREAD_MUTEX_DEFAULT)
269 return mutex_type_default_mutex;
270 #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
271 else if (kind == PTHREAD_MUTEX_ADAPTIVE_NP)
272 return mutex_type_default_mutex;
273 #endif
274 else
275 return mutex_type_invalid_mutex;
276 }
277
278 #define IS_ALIGNED(p) (((uintptr_t)(p) & (sizeof(*(p)) - 1)) == 0)
279
280 /**
281 * Read the mutex type stored in the client memory used for the mutex
282 * implementation.
283 *
284 * @note This function depends on the implementation of the POSIX threads
285 * library -- the POSIX standard does not define the name of the member in
286 * which the mutex type is stored.
287 * @note The function mutex_type() has been declared inline in order
288 * to avoid that it shows up in call stacks (drd/tests/...exp* files).
289 * @note glibc stores the mutex type in the lowest two bits, and uses the
290 * higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
291 * PTHREAD_MUTEXATTR_FLAG_PSHARED.
292 */
DRD_(mutex_type)293 static __always_inline MutexT DRD_(mutex_type)(pthread_mutex_t* mutex)
294 {
295 #if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
296 /* glibc + LinuxThreads. */
297 if (IS_ALIGNED(&mutex->__m_kind))
298 {
299 const int kind = mutex->__m_kind & 3;
300 return DRD_(pthread_to_drd_mutex_type)(kind);
301 }
302 #elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
303 /* glibc + NPTL. */
304 if (IS_ALIGNED(&mutex->__data.__kind))
305 {
306 const int kind = mutex->__data.__kind & 3;
307 return DRD_(pthread_to_drd_mutex_type)(kind);
308 }
309 #else
310 /*
311 * Another POSIX threads implementation. The mutex type won't be printed
312 * when enabling --trace-mutex=yes.
313 */
314 #endif
315 return mutex_type_unknown;
316 }
317
318 /**
319 * Tell DRD whether 'tid' is a joinable thread or a detached thread.
320 */
DRD_(set_joinable)321 static void DRD_(set_joinable)(const pthread_t tid, const int joinable)
322 {
323 assert(joinable == 0 || joinable == 1);
324 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_JOINABLE,
325 tid, joinable, 0, 0, 0);
326 }
327
328 /** Tell DRD that the calling thread is about to enter pthread_create(). */
DRD_(entering_pthread_create)329 static __always_inline void DRD_(entering_pthread_create)(void)
330 {
331 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__ENTERING_PTHREAD_CREATE,
332 0, 0, 0, 0, 0);
333 }
334
335 /** Tell DRD that the calling thread has left pthread_create(). */
DRD_(left_pthread_create)336 static __always_inline void DRD_(left_pthread_create)(void)
337 {
338 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LEFT_PTHREAD_CREATE,
339 0, 0, 0, 0, 0);
340 }
341
342 /**
343 * Entry point for newly created threads. This function is called from the
344 * thread created by pthread_create().
345 */
DRD_(thread_wrapper)346 static void* DRD_(thread_wrapper)(void* arg)
347 {
348 DrdPosixThreadArgs* arg_ptr;
349 DrdPosixThreadArgs arg_copy;
350
351 arg_ptr = (DrdPosixThreadArgs*)arg;
352 arg_copy = *arg_ptr;
353
354 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
355 pthread_self(), 0, 0, 0, 0);
356
357 DRD_(set_joinable)(pthread_self(),
358 arg_copy.detachstate == PTHREAD_CREATE_JOINABLE);
359
360 /*
361 * Only set 'wrapper_started' after VG_USERREQ__SET_PTHREADID and
362 * DRD_(set_joinable)() have been invoked to avoid a race with
363 * a pthread_detach() invocation for this thread from another thread.
364 */
365 DRD_(sema_up)(arg_copy.wrapper_started);
366
367 return (arg_copy.start)(arg_copy.arg);
368 }
369
370 /**
371 * Return 1 if the LinuxThreads implementation of POSIX Threads has been
372 * detected, and 0 otherwise.
373 *
374 * @see For more information about the confstr() function, see also
375 * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
376 */
DRD_(detected_linuxthreads)377 static int DRD_(detected_linuxthreads)(void)
378 {
379 #if defined(linux)
380 #if defined(_CS_GNU_LIBPTHREAD_VERSION)
381 /* Linux with a recent glibc. */
382 HChar buffer[256];
383 unsigned len;
384 len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
385 assert(len <= sizeof(buffer));
386 return len > 0 && buffer[0] == 'l';
387 #else
388 /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
389 return 1;
390 #endif
391 #else
392 /* Another OS than Linux, hence no LinuxThreads. */
393 return 0;
394 #endif
395 }
396
397 /**
398 * Stop and print an error message in case a non-supported threading
399 * library implementation (LinuxThreads) has been detected.
400 */
DRD_(check_threading_library)401 static void DRD_(check_threading_library)(void)
402 {
403 if (DRD_(detected_linuxthreads)())
404 {
405 if (getenv("LD_ASSUME_KERNEL"))
406 {
407 fprintf(stderr,
408 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
409 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
410 "after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
411 );
412 }
413 else
414 {
415 fprintf(stderr,
416 "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
417 "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
418 "after having upgraded to a newer version of your Linux distribution.\n"
419 "Giving up.\n"
420 );
421 }
422 abort();
423 }
424 }
425
426 /**
427 * The main thread is the only thread not created by pthread_create().
428 * Update DRD's state information about the main thread.
429 */
DRD_(set_main_thread_state)430 static void DRD_(set_main_thread_state)(void)
431 {
432 // Make sure that DRD knows about the main thread's POSIX thread ID.
433 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID,
434 pthread_self(), 0, 0, 0, 0);
435 }
436
437 /*
438 * Note: as of today there exist three different versions of pthread_create
439 * in Linux:
440 * - pthread_create@GLIBC_2.0
441 * - pthread_create@@GLIBC_2.1
442 * - pthread_create@@GLIBC_2.2.5
443 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
444 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
445 * versions have been implemented. In any glibc version where more than one
446 * pthread_create function has been implemented, older versions call the
447 * newer versions. Or: the pthread_create* wrapper defined below can be
448 * called recursively. Any code in this wrapper should take this in account.
449 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
450 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
451 * See also the implementation of pthread_create@GLIBC_2.0 in
452 * glibc-2.9/nptl/pthread_create.c.
453 */
454
455 static __always_inline
pthread_create_intercept(pthread_t * thread,const pthread_attr_t * attr,void * (* start)(void *),void * arg)456 int pthread_create_intercept(pthread_t* thread, const pthread_attr_t* attr,
457 void* (*start)(void*), void* arg)
458 {
459 int ret;
460 OrigFn fn;
461 DrdSema wrapper_started;
462 DrdPosixThreadArgs thread_args;
463
464 VALGRIND_GET_ORIG_FN(fn);
465
466 DRD_(sema_init)(&wrapper_started);
467 thread_args.start = start;
468 thread_args.arg = arg;
469 thread_args.wrapper_started = &wrapper_started;
470 /*
471 * Find out whether the thread will be started as a joinable thread
472 * or as a detached thread. If no thread attributes have been specified,
473 * this means that the new thread will be started as a joinable thread.
474 */
475 thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
476 if (attr)
477 {
478 if (pthread_attr_getdetachstate(attr, &thread_args.detachstate) != 0)
479 assert(0);
480 }
481 assert(thread_args.detachstate == PTHREAD_CREATE_JOINABLE
482 || thread_args.detachstate == PTHREAD_CREATE_DETACHED);
483
484 DRD_(entering_pthread_create)();
485 CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), &thread_args);
486 DRD_(left_pthread_create)();
487
488 if (ret == 0) {
489 /* Wait until the thread wrapper started. */
490 DRD_(sema_down)(&wrapper_started);
491 }
492
493 DRD_(sema_destroy)(&wrapper_started);
494
495 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT,
496 pthread_self(), 0, 0, 0, 0);
497
498 return ret;
499 }
500
501 PTH_FUNCS(int, pthreadZucreate, pthread_create_intercept,
502 (pthread_t *thread, const pthread_attr_t *attr,
503 void *(*start) (void *), void *arg),
504 (thread, attr, start, arg));
505
506 static __always_inline
pthread_join_intercept(pthread_t pt_joinee,void ** thread_return)507 int pthread_join_intercept(pthread_t pt_joinee, void **thread_return)
508 {
509 int ret;
510 OrigFn fn;
511
512 VALGRIND_GET_ORIG_FN(fn);
513 /*
514 * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join()
515 * implementation triggers a (false positive) race report.
516 */
517 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
518 CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
519 if (ret == 0)
520 {
521 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN,
522 pt_joinee, 0, 0, 0, 0);
523 }
524 ANNOTATE_IGNORE_READS_AND_WRITES_END();
525 return ret;
526 }
527
528 PTH_FUNCS(int, pthreadZujoin, pthread_join_intercept,
529 (pthread_t pt_joinee, void **thread_return),
530 (pt_joinee, thread_return));
531
532 static __always_inline
pthread_detach_intercept(pthread_t pt_thread)533 int pthread_detach_intercept(pthread_t pt_thread)
534 {
535 int ret;
536 OrigFn fn;
537
538 VALGRIND_GET_ORIG_FN(fn);
539 CALL_FN_W_W(ret, fn, pt_thread);
540 DRD_(set_joinable)(pt_thread, 0);
541
542 return ret;
543 }
544
545 PTH_FUNCS(int, pthreadZudetach, pthread_detach_intercept,
546 (pthread_t thread), (thread));
547
548 // NOTE: be careful to intercept only pthread_cancel() and not
549 // pthread_cancel_init() on Linux.
550
551 static __always_inline
pthread_cancel_intercept(pthread_t pt_thread)552 int pthread_cancel_intercept(pthread_t pt_thread)
553 {
554 int ret;
555 OrigFn fn;
556 VALGRIND_GET_ORIG_FN(fn);
557 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_THREAD_CANCEL,
558 pt_thread, 0, 0, 0, 0);
559 CALL_FN_W_W(ret, fn, pt_thread);
560 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_CANCEL,
561 pt_thread, ret==0, 0, 0, 0);
562 return ret;
563 }
564
565 PTH_FUNCS(int, pthreadZucancel, pthread_cancel_intercept,
566 (pthread_t thread), (thread))
567
568 static __always_inline
pthread_once_intercept(pthread_once_t * once_control,void (* init_routine)(void))569 int pthread_once_intercept(pthread_once_t *once_control,
570 void (*init_routine)(void))
571 {
572 int ret;
573 OrigFn fn;
574 VALGRIND_GET_ORIG_FN(fn);
575 /*
576 * Ignore any data races triggered by the implementation of pthread_once().
577 * Necessary for Darwin. This is not necessary for Linux but doesn't have
578 * any known adverse effects.
579 */
580 DRD_IGNORE_VAR(*once_control);
581 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
582 CALL_FN_W_WW(ret, fn, once_control, init_routine);
583 ANNOTATE_IGNORE_READS_AND_WRITES_END();
584 DRD_STOP_IGNORING_VAR(*once_control);
585 return ret;
586 }
587
588 PTH_FUNCS(int, pthreadZuonce, pthread_once_intercept,
589 (pthread_once_t *once_control, void (*init_routine)(void)),
590 (once_control, init_routine));
591
592 static __always_inline
pthread_mutex_init_intercept(pthread_mutex_t * mutex,const pthread_mutexattr_t * attr)593 int pthread_mutex_init_intercept(pthread_mutex_t *mutex,
594 const pthread_mutexattr_t* attr)
595 {
596 int ret;
597 OrigFn fn;
598 int mt;
599 VALGRIND_GET_ORIG_FN(fn);
600 mt = PTHREAD_MUTEX_DEFAULT;
601 if (attr)
602 pthread_mutexattr_gettype(attr, &mt);
603 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
604 mutex, DRD_(pthread_to_drd_mutex_type)(mt),
605 0, 0, 0);
606 CALL_FN_W_WW(ret, fn, mutex, attr);
607 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
608 mutex, 0, 0, 0, 0);
609 return ret;
610 }
611
612 PTH_FUNCS(int, pthreadZumutexZuinit, pthread_mutex_init_intercept,
613 (pthread_mutex_t *mutex, const pthread_mutexattr_t* attr),
614 (mutex, attr));
615
616 static __always_inline
pthread_mutex_destroy_intercept(pthread_mutex_t * mutex)617 int pthread_mutex_destroy_intercept(pthread_mutex_t* mutex)
618 {
619 int ret;
620 OrigFn fn;
621 VALGRIND_GET_ORIG_FN(fn);
622 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
623 mutex, 0, 0, 0, 0);
624 CALL_FN_W_W(ret, fn, mutex);
625 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
626 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
627 return ret;
628 }
629
630 PTH_FUNCS(int, pthreadZumutexZudestroy, pthread_mutex_destroy_intercept,
631 (pthread_mutex_t *mutex), (mutex));
632
633 static __always_inline
pthread_mutex_lock_intercept(pthread_mutex_t * mutex)634 int pthread_mutex_lock_intercept(pthread_mutex_t* mutex)
635 {
636 int ret;
637 OrigFn fn;
638 VALGRIND_GET_ORIG_FN(fn);
639 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
640 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
641 CALL_FN_W_W(ret, fn, mutex);
642 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
643 mutex, ret == 0, 0, 0, 0);
644 return ret;
645 }
646
647 PTH_FUNCS(int, pthreadZumutexZulock, pthread_mutex_lock_intercept,
648 (pthread_mutex_t *mutex), (mutex));
649
650 static __always_inline
pthread_mutex_trylock_intercept(pthread_mutex_t * mutex)651 int pthread_mutex_trylock_intercept(pthread_mutex_t* mutex)
652 {
653 int ret;
654 OrigFn fn;
655 VALGRIND_GET_ORIG_FN(fn);
656 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
657 mutex, DRD_(mutex_type)(mutex), 1, 0, 0);
658 CALL_FN_W_W(ret, fn, mutex);
659 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
660 mutex, ret == 0, 0, 0, 0);
661 return ret;
662 }
663
664 PTH_FUNCS(int, pthreadZumutexZutrylock, pthread_mutex_trylock_intercept,
665 (pthread_mutex_t *mutex), (mutex));
666
667 static __always_inline
pthread_mutex_timedlock_intercept(pthread_mutex_t * mutex,const struct timespec * abs_timeout)668 int pthread_mutex_timedlock_intercept(pthread_mutex_t *mutex,
669 const struct timespec *abs_timeout)
670 {
671 int ret;
672 OrigFn fn;
673 VALGRIND_GET_ORIG_FN(fn);
674 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
675 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
676 CALL_FN_W_WW(ret, fn, mutex, abs_timeout);
677 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
678 mutex, ret == 0, 0, 0, 0);
679 return ret;
680 }
681
682 PTH_FUNCS(int, pthreadZumutexZutimedlock, pthread_mutex_timedlock_intercept,
683 (pthread_mutex_t *mutex, const struct timespec *abs_timeout),
684 (mutex, abs_timeout));
685
686 static __always_inline
pthread_mutex_unlock_intercept(pthread_mutex_t * mutex)687 int pthread_mutex_unlock_intercept(pthread_mutex_t *mutex)
688 {
689 int ret;
690 OrigFn fn;
691 VALGRIND_GET_ORIG_FN(fn);
692 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
693 mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
694 CALL_FN_W_W(ret, fn, mutex);
695 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
696 mutex, 0, 0, 0, 0);
697 return ret;
698 }
699
700 PTH_FUNCS(int, pthreadZumutexZuunlock, pthread_mutex_unlock_intercept,
701 (pthread_mutex_t *mutex), (mutex));
702
703 static __always_inline
pthread_cond_init_intercept(pthread_cond_t * cond,const pthread_condattr_t * attr)704 int pthread_cond_init_intercept(pthread_cond_t* cond,
705 const pthread_condattr_t* attr)
706 {
707 int ret;
708 OrigFn fn;
709 VALGRIND_GET_ORIG_FN(fn);
710 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT,
711 cond, 0, 0, 0, 0);
712 CALL_FN_W_WW(ret, fn, cond, attr);
713 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT,
714 cond, 0, 0, 0, 0);
715 return ret;
716 }
717
718 PTH_FUNCS(int, pthreadZucondZuinit, pthread_cond_init_intercept,
719 (pthread_cond_t* cond, const pthread_condattr_t* attr),
720 (cond, attr));
721
722 static __always_inline
pthread_cond_destroy_intercept(pthread_cond_t * cond)723 int pthread_cond_destroy_intercept(pthread_cond_t* cond)
724 {
725 int ret;
726 OrigFn fn;
727 VALGRIND_GET_ORIG_FN(fn);
728 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_DESTROY,
729 cond, 0, 0, 0, 0);
730 CALL_FN_W_W(ret, fn, cond);
731 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_DESTROY,
732 cond, ret==0, 0, 0, 0);
733 return ret;
734 }
735
736 PTH_FUNCS(int, pthreadZucondZudestroy, pthread_cond_destroy_intercept,
737 (pthread_cond_t* cond), (cond));
738
739 static __always_inline
pthread_cond_wait_intercept(pthread_cond_t * cond,pthread_mutex_t * mutex)740 int pthread_cond_wait_intercept(pthread_cond_t *cond, pthread_mutex_t *mutex)
741 {
742 int ret;
743 OrigFn fn;
744 VALGRIND_GET_ORIG_FN(fn);
745 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
746 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
747 CALL_FN_W_WW(ret, fn, cond, mutex);
748 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
749 cond, mutex, 1, 0, 0);
750 return ret;
751 }
752
753 PTH_FUNCS(int, pthreadZucondZuwait, pthread_cond_wait_intercept,
754 (pthread_cond_t *cond, pthread_mutex_t *mutex),
755 (cond, mutex));
756
757 static __always_inline
pthread_cond_timedwait_intercept(pthread_cond_t * cond,pthread_mutex_t * mutex,const struct timespec * abstime)758 int pthread_cond_timedwait_intercept(pthread_cond_t *cond,
759 pthread_mutex_t *mutex,
760 const struct timespec* abstime)
761 {
762 int ret;
763 OrigFn fn;
764 VALGRIND_GET_ORIG_FN(fn);
765 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
766 cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
767 CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
768 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
769 cond, mutex, 1, 0, 0);
770 return ret;
771 }
772
773 PTH_FUNCS(int, pthreadZucondZutimedwait, pthread_cond_timedwait_intercept,
774 (pthread_cond_t *cond, pthread_mutex_t *mutex,
775 const struct timespec* abstime),
776 (cond, mutex, abstime));
777
778 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
779 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
780 // two. Intercepting all pthread_cond_signal* functions will cause only one
781 // argument to be passed to pthread_cond_signal_np() and hence will cause this
782 // last function to crash.
783
784 static __always_inline
pthread_cond_signal_intercept(pthread_cond_t * cond)785 int pthread_cond_signal_intercept(pthread_cond_t* cond)
786 {
787 int ret;
788 OrigFn fn;
789 VALGRIND_GET_ORIG_FN(fn);
790 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_SIGNAL,
791 cond, 0, 0, 0, 0);
792 CALL_FN_W_W(ret, fn, cond);
793 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_SIGNAL,
794 cond, 0, 0, 0, 0);
795 return ret;
796 }
797
798 PTH_FUNCS(int, pthreadZucondZusignal, pthread_cond_signal_intercept,
799 (pthread_cond_t* cond), (cond));
800
801 static __always_inline
pthread_cond_broadcast_intercept(pthread_cond_t * cond)802 int pthread_cond_broadcast_intercept(pthread_cond_t* cond)
803 {
804 int ret;
805 OrigFn fn;
806 VALGRIND_GET_ORIG_FN(fn);
807 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_BROADCAST,
808 cond, 0, 0, 0, 0);
809 CALL_FN_W_W(ret, fn, cond);
810 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_BROADCAST,
811 cond, 0, 0, 0, 0);
812 return ret;
813 }
814
815 PTH_FUNCS(int, pthreadZucondZubroadcast, pthread_cond_broadcast_intercept,
816 (pthread_cond_t* cond), (cond));
817
818 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
819 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
820 static __always_inline
pthread_spin_init_intercept(pthread_spinlock_t * spinlock,int pshared)821 int pthread_spin_init_intercept(pthread_spinlock_t *spinlock, int pshared)
822 {
823 int ret;
824 OrigFn fn;
825 VALGRIND_GET_ORIG_FN(fn);
826 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
827 spinlock, 0, 0, 0, 0);
828 CALL_FN_W_WW(ret, fn, spinlock, pshared);
829 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
830 spinlock, 0, 0, 0, 0);
831 return ret;
832 }
833
834 PTH_FUNCS(int, pthreadZuspinZuinit, pthread_spin_init_intercept,
835 (pthread_spinlock_t *spinlock, int pshared), (spinlock, pshared));
836
837 static __always_inline
pthread_spin_destroy_intercept(pthread_spinlock_t * spinlock)838 int pthread_spin_destroy_intercept(pthread_spinlock_t *spinlock)
839 {
840 int ret;
841 OrigFn fn;
842 VALGRIND_GET_ORIG_FN(fn);
843 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY,
844 spinlock, 0, 0, 0, 0);
845 CALL_FN_W_W(ret, fn, spinlock);
846 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY,
847 spinlock, mutex_type_spinlock, 0, 0, 0);
848 return ret;
849 }
850
851 PTH_FUNCS(int, pthreadZuspinZudestroy, pthread_spin_destroy_intercept,
852 (pthread_spinlock_t *spinlock), (spinlock));
853
854 static __always_inline
pthread_spin_lock_intercept(pthread_spinlock_t * spinlock)855 int pthread_spin_lock_intercept(pthread_spinlock_t *spinlock)
856 {
857 int ret;
858 OrigFn fn;
859 VALGRIND_GET_ORIG_FN(fn);
860 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
861 spinlock, mutex_type_spinlock, 0, 0, 0);
862 CALL_FN_W_W(ret, fn, spinlock);
863 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
864 spinlock, ret == 0, 0, 0, 0);
865 return ret;
866 }
867
868 PTH_FUNCS(int, pthreadZuspinZulock, pthread_spin_lock_intercept,
869 (pthread_spinlock_t *spinlock), (spinlock));
870
871 static __always_inline
pthread_spin_trylock_intercept(pthread_spinlock_t * spinlock)872 int pthread_spin_trylock_intercept(pthread_spinlock_t *spinlock)
873 {
874 int ret;
875 OrigFn fn;
876 VALGRIND_GET_ORIG_FN(fn);
877 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
878 spinlock, mutex_type_spinlock, 0, 0, 0);
879 CALL_FN_W_W(ret, fn, spinlock);
880 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
881 spinlock, ret == 0, 0, 0, 0);
882 return ret;
883 }
884
885 PTH_FUNCS(int, pthreadZuspinZutrylock, pthread_spin_trylock_intercept,
886 (pthread_spinlock_t *spinlock), (spinlock));
887
888 static __always_inline
pthread_spin_unlock_intercept(pthread_spinlock_t * spinlock)889 int pthread_spin_unlock_intercept(pthread_spinlock_t *spinlock)
890 {
891 int ret;
892 OrigFn fn;
893 VALGRIND_GET_ORIG_FN(fn);
894 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
895 spinlock, mutex_type_spinlock, 0, 0, 0);
896 CALL_FN_W_W(ret, fn, spinlock);
897 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
898 spinlock, 0, 0, 0, 0);
899 return ret;
900 }
901
902 PTH_FUNCS(int, pthreadZuspinZuunlock, pthread_spin_unlock_intercept,
903 (pthread_spinlock_t *spinlock), (spinlock));
904 #endif // HAVE_PTHREAD_SPIN_LOCK
905
906
907 #if defined(HAVE_PTHREAD_BARRIER_INIT)
908 static __always_inline
pthread_barrier_init_intercept(pthread_barrier_t * barrier,const pthread_barrierattr_t * attr,unsigned count)909 int pthread_barrier_init_intercept(pthread_barrier_t* barrier,
910 const pthread_barrierattr_t* attr,
911 unsigned count)
912 {
913 int ret;
914 OrigFn fn;
915 VALGRIND_GET_ORIG_FN(fn);
916 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_INIT,
917 barrier, pthread_barrier, count, 0, 0);
918 CALL_FN_W_WWW(ret, fn, barrier, attr, count);
919 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_INIT,
920 barrier, pthread_barrier, 0, 0, 0);
921 return ret;
922 }
923
924 PTH_FUNCS(int, pthreadZubarrierZuinit, pthread_barrier_init_intercept,
925 (pthread_barrier_t* barrier, const pthread_barrierattr_t* attr,
926 unsigned count), (barrier, attr, count));
927
928 static __always_inline
pthread_barrier_destroy_intercept(pthread_barrier_t * barrier)929 int pthread_barrier_destroy_intercept(pthread_barrier_t* barrier)
930 {
931 int ret;
932 OrigFn fn;
933 VALGRIND_GET_ORIG_FN(fn);
934 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_DESTROY,
935 barrier, pthread_barrier, 0, 0, 0);
936 CALL_FN_W_W(ret, fn, barrier);
937 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_DESTROY,
938 barrier, pthread_barrier, 0, 0, 0);
939 return ret;
940 }
941
942 PTH_FUNCS(int, pthreadZubarrierZudestroy, pthread_barrier_destroy_intercept,
943 (pthread_barrier_t* barrier), (barrier));
944
945 static __always_inline
pthread_barrier_wait_intercept(pthread_barrier_t * barrier)946 int pthread_barrier_wait_intercept(pthread_barrier_t* barrier)
947 {
948 int ret;
949 OrigFn fn;
950 VALGRIND_GET_ORIG_FN(fn);
951 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_WAIT,
952 barrier, pthread_barrier, 0, 0, 0);
953 CALL_FN_W_W(ret, fn, barrier);
954 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_WAIT,
955 barrier, pthread_barrier,
956 ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD,
957 ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
958 return ret;
959 }
960
961 PTH_FUNCS(int, pthreadZubarrierZuwait, pthread_barrier_wait_intercept,
962 (pthread_barrier_t* barrier), (barrier));
963 #endif // HAVE_PTHREAD_BARRIER_INIT
964
965
966 static __always_inline
sem_init_intercept(sem_t * sem,int pshared,unsigned int value)967 int sem_init_intercept(sem_t *sem, int pshared, unsigned int value)
968 {
969 int ret;
970 OrigFn fn;
971 VALGRIND_GET_ORIG_FN(fn);
972 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT,
973 sem, pshared, value, 0, 0);
974 CALL_FN_W_WWW(ret, fn, sem, pshared, value);
975 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT,
976 sem, 0, 0, 0, 0);
977 return ret;
978 }
979
980 PTH_FUNCS(int, semZuinit, sem_init_intercept,
981 (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
982
983 static __always_inline
sem_destroy_intercept(sem_t * sem)984 int sem_destroy_intercept(sem_t *sem)
985 {
986 int ret;
987 OrigFn fn;
988 VALGRIND_GET_ORIG_FN(fn);
989 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_DESTROY,
990 sem, 0, 0, 0, 0);
991 CALL_FN_W_W(ret, fn, sem);
992 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_DESTROY,
993 sem, 0, 0, 0, 0);
994 return ret;
995 }
996
997 PTH_FUNCS(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
998
999 static __always_inline
sem_open_intercept(const char * name,int oflag,mode_t mode,unsigned int value)1000 sem_t* sem_open_intercept(const char *name, int oflag, mode_t mode,
1001 unsigned int value)
1002 {
1003 sem_t *ret;
1004 OrigFn fn;
1005 VALGRIND_GET_ORIG_FN(fn);
1006 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_OPEN,
1007 name, oflag, mode, value, 0);
1008 CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value);
1009 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_OPEN,
1010 ret != SEM_FAILED ? ret : 0,
1011 name, oflag, mode, value);
1012 return ret;
1013 }
1014
1015 PTH_FUNCS(sem_t *, semZuopen, sem_open_intercept,
1016 (const char *name, int oflag, mode_t mode, unsigned int value),
1017 (name, oflag, mode, value));
1018
sem_close_intercept(sem_t * sem)1019 static __always_inline int sem_close_intercept(sem_t *sem)
1020 {
1021 int ret;
1022 OrigFn fn;
1023 VALGRIND_GET_ORIG_FN(fn);
1024 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_CLOSE,
1025 sem, 0, 0, 0, 0);
1026 CALL_FN_W_W(ret, fn, sem);
1027 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_CLOSE,
1028 sem, 0, 0, 0, 0);
1029 return ret;
1030 }
1031
1032 PTH_FUNCS(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem));
1033
sem_wait_intercept(sem_t * sem)1034 static __always_inline int sem_wait_intercept(sem_t *sem)
1035 {
1036 int ret;
1037 OrigFn fn;
1038 VALGRIND_GET_ORIG_FN(fn);
1039 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1040 sem, 0, 0, 0, 0);
1041 CALL_FN_W_W(ret, fn, sem);
1042 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1043 sem, ret == 0, 0, 0, 0);
1044 return ret;
1045 }
1046
1047 PTH_FUNCS(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
1048
sem_trywait_intercept(sem_t * sem)1049 static __always_inline int sem_trywait_intercept(sem_t *sem)
1050 {
1051 int ret;
1052 OrigFn fn;
1053 VALGRIND_GET_ORIG_FN(fn);
1054 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1055 sem, 0, 0, 0, 0);
1056 CALL_FN_W_W(ret, fn, sem);
1057 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1058 sem, ret == 0, 0, 0, 0);
1059 return ret;
1060 }
1061
1062 PTH_FUNCS(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
1063
1064 static __always_inline
sem_timedwait_intercept(sem_t * sem,const struct timespec * abs_timeout)1065 int sem_timedwait_intercept(sem_t *sem, const struct timespec *abs_timeout)
1066 {
1067 int ret;
1068 OrigFn fn;
1069 VALGRIND_GET_ORIG_FN(fn);
1070 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT,
1071 sem, 0, 0, 0, 0);
1072 CALL_FN_W_WW(ret, fn, sem, abs_timeout);
1073 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT,
1074 sem, ret == 0, 0, 0, 0);
1075 return ret;
1076 }
1077
1078 PTH_FUNCS(int, semZutimedwait, sem_timedwait_intercept,
1079 (sem_t *sem, const struct timespec *abs_timeout),
1080 (sem, abs_timeout));
1081
sem_post_intercept(sem_t * sem)1082 static __always_inline int sem_post_intercept(sem_t *sem)
1083 {
1084 int ret;
1085 OrigFn fn;
1086 VALGRIND_GET_ORIG_FN(fn);
1087 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_POST,
1088 sem, 0, 0, 0, 0);
1089 CALL_FN_W_W(ret, fn, sem);
1090 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_POST,
1091 sem, ret == 0, 0, 0, 0);
1092 return ret;
1093 }
1094
1095 PTH_FUNCS(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
1096
1097 /* Android's pthread.h doesn't say anything about rwlocks, hence these
1098 functions have to be conditionally compiled. */
1099 #if defined(HAVE_PTHREAD_RWLOCK_T)
1100
1101 static __always_inline
pthread_rwlock_init_intercept(pthread_rwlock_t * rwlock,const pthread_rwlockattr_t * attr)1102 int pthread_rwlock_init_intercept(pthread_rwlock_t* rwlock,
1103 const pthread_rwlockattr_t* attr)
1104 {
1105 int ret;
1106 OrigFn fn;
1107 VALGRIND_GET_ORIG_FN(fn);
1108 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT,
1109 rwlock, 0, 0, 0, 0);
1110 CALL_FN_W_WW(ret, fn, rwlock, attr);
1111 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT,
1112 rwlock, 0, 0, 0, 0);
1113 return ret;
1114 }
1115
1116 PTH_FUNCS(int,
1117 pthreadZurwlockZuinit, pthread_rwlock_init_intercept,
1118 (pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr),
1119 (rwlock, attr));
1120
1121 static __always_inline
pthread_rwlock_destroy_intercept(pthread_rwlock_t * rwlock)1122 int pthread_rwlock_destroy_intercept(pthread_rwlock_t* rwlock)
1123 {
1124 int ret;
1125 OrigFn fn;
1126 VALGRIND_GET_ORIG_FN(fn);
1127 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_DESTROY,
1128 rwlock, 0, 0, 0, 0);
1129 CALL_FN_W_W(ret, fn, rwlock);
1130 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_DESTROY,
1131 rwlock, 0, 0, 0, 0);
1132 return ret;
1133 }
1134
1135 PTH_FUNCS(int,
1136 pthreadZurwlockZudestroy, pthread_rwlock_destroy_intercept,
1137 (pthread_rwlock_t* rwlock), (rwlock));
1138
1139 static __always_inline
pthread_rwlock_rdlock_intercept(pthread_rwlock_t * rwlock)1140 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t* rwlock)
1141 {
1142 int ret;
1143 OrigFn fn;
1144 VALGRIND_GET_ORIG_FN(fn);
1145 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1146 rwlock, 0, 0, 0, 0);
1147 CALL_FN_W_W(ret, fn, rwlock);
1148 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1149 rwlock, ret == 0, 0, 0, 0);
1150 return ret;
1151 }
1152
1153 PTH_FUNCS(int,
1154 pthreadZurwlockZurdlock, pthread_rwlock_rdlock_intercept,
1155 (pthread_rwlock_t* rwlock), (rwlock));
1156
1157 static __always_inline
pthread_rwlock_wrlock_intercept(pthread_rwlock_t * rwlock)1158 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t* rwlock)
1159 {
1160 int ret;
1161 OrigFn fn;
1162 VALGRIND_GET_ORIG_FN(fn);
1163 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1164 rwlock, 0, 0, 0, 0);
1165 CALL_FN_W_W(ret, fn, rwlock);
1166 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1167 rwlock, ret == 0, 0, 0, 0);
1168 return ret;
1169 }
1170
1171 PTH_FUNCS(int,
1172 pthreadZurwlockZuwrlock, pthread_rwlock_wrlock_intercept,
1173 (pthread_rwlock_t* rwlock), (rwlock));
1174
1175 static __always_inline
pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t * rwlock,const struct timespec * timeout)1176 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t* rwlock,
1177 const struct timespec *timeout)
1178 {
1179 int ret;
1180 OrigFn fn;
1181 VALGRIND_GET_ORIG_FN(fn);
1182 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1183 rwlock, 0, 0, 0, 0);
1184 CALL_FN_W_WW(ret, fn, rwlock, timeout);
1185 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1186 rwlock, ret == 0, 0, 0, 0);
1187 return ret;
1188 }
1189
1190 PTH_FUNCS(int,
1191 pthreadZurwlockZutimedrdlock, pthread_rwlock_timedrdlock_intercept,
1192 (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1193 (rwlock, timeout));
1194
1195 static __always_inline
pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t * rwlock,const struct timespec * timeout)1196 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t* rwlock,
1197 const struct timespec *timeout)
1198 {
1199 int ret;
1200 OrigFn fn;
1201 VALGRIND_GET_ORIG_FN(fn);
1202 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1203 rwlock, 0, 0, 0, 0);
1204 CALL_FN_W_WW(ret, fn, rwlock, timeout);
1205 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1206 rwlock, ret == 0, 0, 0, 0);
1207 return ret;
1208 }
1209
1210 PTH_FUNCS(int,
1211 pthreadZurwlockZutimedwrlock, pthread_rwlock_timedwrlock_intercept,
1212 (pthread_rwlock_t* rwlock, const struct timespec *timeout),
1213 (rwlock, timeout));
1214
1215 static __always_inline
pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t * rwlock)1216 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t* rwlock)
1217 {
1218 int ret;
1219 OrigFn fn;
1220 VALGRIND_GET_ORIG_FN(fn);
1221 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
1222 rwlock, 0, 0, 0, 0);
1223 CALL_FN_W_W(ret, fn, rwlock);
1224 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
1225 rwlock, ret == 0, 0, 0, 0);
1226 return ret;
1227 }
1228
1229 PTH_FUNCS(int,
1230 pthreadZurwlockZutryrdlock, pthread_rwlock_tryrdlock_intercept,
1231 (pthread_rwlock_t* rwlock), (rwlock));
1232
1233 static __always_inline
pthread_rwlock_trywrlock_intercept(pthread_rwlock_t * rwlock)1234 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t* rwlock)
1235 {
1236 int ret;
1237 OrigFn fn;
1238 VALGRIND_GET_ORIG_FN(fn);
1239 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
1240 rwlock, 0, 0, 0, 0);
1241 CALL_FN_W_W(ret, fn, rwlock);
1242 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
1243 rwlock, ret == 0, 0, 0, 0);
1244 return ret;
1245 }
1246
1247 PTH_FUNCS(int,
1248 pthreadZurwlockZutrywrlock, pthread_rwlock_trywrlock_intercept,
1249 (pthread_rwlock_t* rwlock), (rwlock));
1250
1251 static __always_inline
pthread_rwlock_unlock_intercept(pthread_rwlock_t * rwlock)1252 int pthread_rwlock_unlock_intercept(pthread_rwlock_t* rwlock)
1253 {
1254 int ret;
1255 OrigFn fn;
1256 VALGRIND_GET_ORIG_FN(fn);
1257 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_UNLOCK,
1258 rwlock, 0, 0, 0, 0);
1259 CALL_FN_W_W(ret, fn, rwlock);
1260 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_UNLOCK,
1261 rwlock, ret == 0, 0, 0, 0);
1262 return ret;
1263 }
1264
1265 PTH_FUNCS(int,
1266 pthreadZurwlockZuunlock, pthread_rwlock_unlock_intercept,
1267 (pthread_rwlock_t* rwlock), (rwlock));
1268
1269 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
1270