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