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