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