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#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_main_thread_state)(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_main_thread_state)(); 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 * The main thread is the only thread not created by pthread_create(). 505 * Update DRD's state information about the main thread. 506 */ 507static void DRD_(set_main_thread_state)(void) 508{ 509 // Make sure that DRD knows about the main thread's POSIX thread ID. 510 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__SET_PTHREADID, 511 pthread_self(), 0, 0, 0, 0); 512} 513 514/* 515 * Note: as of today there exist three different versions of pthread_create 516 * in Linux: 517 * - pthread_create@GLIBC_2.0 518 * - pthread_create@@GLIBC_2.1 519 * - pthread_create@@GLIBC_2.2.5 520 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and 521 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three 522 * versions have been implemented. In any glibc version where more than one 523 * pthread_create function has been implemented, older versions call the 524 * newer versions. Or: the pthread_create* wrapper defined below can be 525 * called recursively. Any code in this wrapper should take this in account. 526 * As an example, it is not safe to invoke the DRD_STOP_RECORDING 527 * / DRD_START_RECORDING client requests from the pthread_create wrapper. 528 * See also the implementation of pthread_create@GLIBC_2.0 in 529 * glibc-2.9/nptl/pthread_create.c. 530 */ 531 532static __always_inline 533int pthread_create_intercept(pthread_t* thread, const pthread_attr_t* attr, 534 void* (*start)(void*), void* arg) 535{ 536 int ret; 537 OrigFn fn; 538 DrdSema wrapper_started; 539 DrdPosixThreadArgs thread_args; 540 541 VALGRIND_GET_ORIG_FN(fn); 542 543 DRD_(sema_init)(&wrapper_started); 544 thread_args.start = start; 545 thread_args.arg = arg; 546 thread_args.wrapper_started = &wrapper_started; 547 /* 548 * Find out whether the thread will be started as a joinable thread 549 * or as a detached thread. If no thread attributes have been specified, 550 * this means that the new thread will be started as a joinable thread. 551 */ 552 thread_args.detachstate = PTHREAD_CREATE_JOINABLE; 553 if (attr) 554 { 555 if (pthread_attr_getdetachstate(attr, &thread_args.detachstate) != 0) 556 assert(0); 557 } 558 assert(thread_args.detachstate == PTHREAD_CREATE_JOINABLE 559 || thread_args.detachstate == PTHREAD_CREATE_DETACHED); 560 561 DRD_(entering_pthread_create)(); 562 CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), &thread_args); 563 DRD_(left_pthread_create)(); 564 565 if (ret == 0) { 566 /* Wait until the thread wrapper started. */ 567 DRD_(sema_down)(&wrapper_started); 568 } 569 570 DRD_(sema_destroy)(&wrapper_started); 571 572 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT, 573 pthread_self(), 0, 0, 0, 0); 574 575 return ret; 576} 577 578PTH_FUNCS(int, pthreadZucreate, pthread_create_intercept, 579 (pthread_t *thread, const pthread_attr_t *attr, 580 void *(*start) (void *), void *arg), 581 (thread, attr, start, arg)); 582 583#if defined(VGO_solaris) 584/* Solaris also provides thr_create() in addition to pthread_create(). 585 * Both pthread_create(3C) and thr_create(3C) are based on private 586 * _thrp_create(). 587 */ 588static __always_inline 589int thr_create_intercept(void *stk, size_t stksize, void *(*start)(void *), 590 void *arg, long flags, thread_t *new_thread) 591{ 592 int ret; 593 OrigFn fn; 594 DrdSema wrapper_started; 595 DrdPosixThreadArgs thread_args; 596 597 VALGRIND_GET_ORIG_FN(fn); 598 599 DRD_(sema_init)(&wrapper_started); 600 thread_args.start = start; 601 thread_args.arg = arg; 602 thread_args.wrapper_started = &wrapper_started; 603 /* 604 * Find out whether the thread will be started as a joinable thread 605 * or as a detached thread. 606 */ 607 if (flags & THR_DETACHED) 608 thread_args.detachstate = PTHREAD_CREATE_DETACHED; 609 else 610 thread_args.detachstate = PTHREAD_CREATE_JOINABLE; 611 612 DRD_(entering_pthread_create)(); 613 CALL_FN_W_6W(ret, fn, stk, stksize, DRD_(thread_wrapper), &thread_args, 614 flags, new_thread); 615 DRD_(left_pthread_create)(); 616 617 if (ret == 0) { 618 /* Wait until the thread wrapper started. */ 619 DRD_(sema_down)(&wrapper_started); 620 } 621 622 DRD_(sema_destroy)(&wrapper_started); 623 624 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT, 625 pthread_self(), 0, 0, 0, 0); 626 627 return ret; 628} 629 630PTH_FUNCS(int, thrZucreate, thr_create_intercept, 631 (void *stk, size_t stksize, void *(*start)(void *), void *arg, 632 long flags, thread_t *new_thread), 633 (stk, stksize, start, arg, flags, new_thread)); 634#endif /* VGO_solaris */ 635 636#if defined(VGO_solaris) 637/* 638 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc. 639 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD 640 * and CI_BIND_CLEAR, to provide resilience against function renaming. 641 */ 642static __always_inline 643int DRD_(_ti_bind_guard_intercept)(int flags) { 644 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_GUARD, 645 flags, 0, 0, 0, 0); 646 return DRD_(rtld_bind_guard)(flags); 647} 648 649static __always_inline 650int DRD_(_ti_bind_clear_intercept)(int flags) { 651 int ret = DRD_(rtld_bind_clear)(flags); 652 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_CLEAR, 653 flags, 0, 0, 0, 0); 654 return ret; 655} 656 657/* 658 * Wrapped _ld_libc() from the runtime linker ld.so.1. 659 */ 660void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr); 661void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr) 662{ 663 OrigFn fn; 664 int tag; 665 666 VALGRIND_GET_ORIG_FN(fn); 667 668 vki_Lc_interface *funcs = ptr; 669 for (tag = funcs->ci_tag; tag != 0; tag = (++funcs)->ci_tag) { 670 switch (tag) { 671 case VKI_CI_BIND_GUARD: 672 if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_guard_intercept)) { 673 DRD_(rtld_bind_guard) = funcs->vki_ci_un.ci_func; 674 funcs->vki_ci_un.ci_func = DRD_(_ti_bind_guard_intercept); 675 } 676 break; 677 case VKI_CI_BIND_CLEAR: 678 if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_clear_intercept)) { 679 DRD_(rtld_bind_clear) = funcs->vki_ci_un.ci_func; 680 funcs->vki_ci_un.ci_func = DRD_(_ti_bind_clear_intercept); 681 } 682 break; 683 } 684 } 685 686 CALL_FN_v_W(fn, ptr); 687} 688#endif /* VGO_solaris */ 689 690static __always_inline 691int pthread_join_intercept(pthread_t pt_joinee, void **thread_return) 692{ 693 int ret; 694 OrigFn fn; 695 696 VALGRIND_GET_ORIG_FN(fn); 697 /* 698 * Avoid that the sys_futex(td->tid) call invoked by the NPTL pthread_join() 699 * implementation triggers a (false positive) race report. 700 */ 701 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN(); 702 CALL_FN_W_WW(ret, fn, pt_joinee, thread_return); 703 if (ret == 0) 704 { 705 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN, 706 pt_joinee, 0, 0, 0, 0); 707 } 708 ANNOTATE_IGNORE_READS_AND_WRITES_END(); 709 return ret; 710} 711 712PTH_FUNCS(int, pthreadZujoin, pthread_join_intercept, 713 (pthread_t pt_joinee, void **thread_return), 714 (pt_joinee, thread_return)); 715 716#if defined(VGO_solaris) 717/* Solaris also provides thr_join() in addition to pthread_join(). 718 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join(). 719 * 720 * :TODO: No functionality is currently provided for joinee == 0 and departed. 721 * This would require another client request, of course. 722 */ 723static __always_inline 724int thr_join_intercept(thread_t joinee, thread_t *departed, void **thread_return) 725{ 726 int ret; 727 OrigFn fn; 728 729 VALGRIND_GET_ORIG_FN(fn); 730 CALL_FN_W_WWW(ret, fn, joinee, departed, thread_return); 731 if (ret == 0) 732 { 733 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN, 734 joinee, 0, 0, 0, 0); 735 } 736 return ret; 737} 738 739PTH_FUNCS(int, thrZujoin, thr_join_intercept, 740 (thread_t joinee, thread_t *departed, void **thread_return), 741 (joinee, departed, thread_return)); 742#endif /* VGO_solaris */ 743 744static __always_inline 745int pthread_detach_intercept(pthread_t pt_thread) 746{ 747 int ret; 748 OrigFn fn; 749 750 VALGRIND_GET_ORIG_FN(fn); 751 CALL_FN_W_W(ret, fn, pt_thread); 752 DRD_(set_joinable)(pt_thread, 0); 753 754 return ret; 755} 756 757PTH_FUNCS(int, pthreadZudetach, pthread_detach_intercept, 758 (pthread_t thread), (thread)); 759 760// NOTE: be careful to intercept only pthread_cancel() and not 761// pthread_cancel_init() on Linux. 762 763static __always_inline 764int pthread_cancel_intercept(pthread_t pt_thread) 765{ 766 int ret; 767 OrigFn fn; 768 VALGRIND_GET_ORIG_FN(fn); 769 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_THREAD_CANCEL, 770 pt_thread, 0, 0, 0, 0); 771 CALL_FN_W_W(ret, fn, pt_thread); 772 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_CANCEL, 773 pt_thread, ret==0, 0, 0, 0); 774 return ret; 775} 776 777PTH_FUNCS(int, pthreadZucancel, pthread_cancel_intercept, 778 (pthread_t thread), (thread)) 779 780static __always_inline 781int pthread_once_intercept(pthread_once_t *once_control, 782 void (*init_routine)(void)) 783{ 784 int ret; 785 OrigFn fn; 786 VALGRIND_GET_ORIG_FN(fn); 787 /* 788 * Ignore any data races triggered by the implementation of pthread_once(). 789 * Necessary for Darwin. This is not necessary for Linux but doesn't have 790 * any known adverse effects. 791 */ 792 DRD_IGNORE_VAR(*once_control); 793 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN(); 794 CALL_FN_W_WW(ret, fn, once_control, init_routine); 795 ANNOTATE_IGNORE_READS_AND_WRITES_END(); 796 DRD_STOP_IGNORING_VAR(*once_control); 797 return ret; 798} 799 800PTH_FUNCS(int, pthreadZuonce, pthread_once_intercept, 801 (pthread_once_t *once_control, void (*init_routine)(void)), 802 (once_control, init_routine)); 803 804static __always_inline 805int pthread_mutex_init_intercept(pthread_mutex_t *mutex, 806 const pthread_mutexattr_t* attr) 807{ 808 int ret; 809 OrigFn fn; 810 int mt; 811 VALGRIND_GET_ORIG_FN(fn); 812 mt = PTHREAD_MUTEX_DEFAULT; 813 if (attr) 814 pthread_mutexattr_gettype(attr, &mt); 815 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT, 816 mutex, DRD_(pthread_to_drd_mutex_type)(mt), 817 0, 0, 0); 818 CALL_FN_W_WW(ret, fn, mutex, attr); 819 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT, 820 mutex, 0, 0, 0, 0); 821 return ret; 822} 823 824PTH_FUNCS(int, pthreadZumutexZuinit, pthread_mutex_init_intercept, 825 (pthread_mutex_t *mutex, const pthread_mutexattr_t* attr), 826 (mutex, attr)); 827 828#if defined(VGO_solaris) 829static __always_inline 830int mutex_init_intercept(mutex_t *mutex, int type, void *arg) 831{ 832 int ret; 833 OrigFn fn; 834 VALGRIND_GET_ORIG_FN(fn); 835 836 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT, 837 mutex, DRD_(thread_to_drd_mutex_type)(type), 838 0, 0, 0); 839 CALL_FN_W_WWW(ret, fn, mutex, type, arg); 840 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT, 841 mutex, 0, 0, 0, 0); 842 return ret; 843} 844 845PTH_FUNCS(int, mutexZuinit, mutex_init_intercept, 846 (mutex_t *mutex, int type, void *arg), 847 (mutex, type, arg)); 848#endif /* VGO_solaris */ 849 850static __always_inline 851int pthread_mutex_destroy_intercept(pthread_mutex_t* mutex) 852{ 853 int ret; 854 OrigFn fn; 855 VALGRIND_GET_ORIG_FN(fn); 856 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY, 857 mutex, 0, 0, 0, 0); 858 CALL_FN_W_W(ret, fn, mutex); 859 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY, 860 mutex, DRD_(mutex_type)(mutex), 0, 0, 0); 861 return ret; 862} 863 864#if defined(VGO_solaris) 865/* On Solaris, pthread_mutex_destroy is a weak alias to mutex_destroy. */ 866PTH_FUNCS(int, mutexZudestroy, pthread_mutex_destroy_intercept, 867 (pthread_mutex_t *mutex), (mutex)); 868#else 869PTH_FUNCS(int, pthreadZumutexZudestroy, pthread_mutex_destroy_intercept, 870 (pthread_mutex_t *mutex), (mutex)); 871#endif /* VGO_solaris */ 872 873static __always_inline 874int pthread_mutex_lock_intercept(pthread_mutex_t* mutex) 875{ 876 int ret; 877 OrigFn fn; 878 VALGRIND_GET_ORIG_FN(fn); 879 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK, 880 mutex, DRD_(mutex_type)(mutex), 0, 0, 0); 881 CALL_FN_W_W(ret, fn, mutex); 882 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK, 883 mutex, ret == 0, 0, 0, 0); 884 return ret; 885} 886 887#if defined(VGO_solaris) 888/* On Solaris, pthread_mutex_lock is a weak alias to mutex_lock. */ 889PTH_FUNCS(int, mutexZulock, pthread_mutex_lock_intercept, 890 (pthread_mutex_t *mutex), (mutex)); 891#else 892PTH_FUNCS(int, pthreadZumutexZulock, pthread_mutex_lock_intercept, 893 (pthread_mutex_t *mutex), (mutex)); 894#endif /* VGO_solaris */ 895 896#if defined(VGO_solaris) 897/* Internal to libc. Mutex is usually initialized only implicitly, 898 * by zeroing mutex_t structure. 899 */ 900static __always_inline 901void lmutex_lock_intercept(mutex_t *mutex) 902{ 903 OrigFn fn; 904 VALGRIND_GET_ORIG_FN(fn); 905 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK, 906 mutex, 907 DRD_(mutex_type)((pthread_mutex_t *) mutex), 908 False /* try_lock */, 0, 0); 909 CALL_FN_v_W(fn, mutex); 910 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK, 911 mutex, True /* took_lock */, 0, 0, 0); 912} 913 914PTH_FUNCS(void, lmutexZulock, lmutex_lock_intercept, 915 (mutex_t *mutex), (mutex)); 916#endif /* VGO_solaris */ 917 918static __always_inline 919int pthread_mutex_trylock_intercept(pthread_mutex_t* mutex) 920{ 921 int ret; 922 OrigFn fn; 923 VALGRIND_GET_ORIG_FN(fn); 924 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK, 925 mutex, DRD_(mutex_type)(mutex), 1, 0, 0); 926 CALL_FN_W_W(ret, fn, mutex); 927 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK, 928 mutex, ret == 0, 0, 0, 0); 929 return ret; 930} 931 932#if defined(VGO_solaris) 933/* On Solaris, pthread_mutex_trylock is a weak alias to mutex_trylock. */ 934PTH_FUNCS(int, mutexZutrylock, pthread_mutex_trylock_intercept, 935 (pthread_mutex_t *mutex), (mutex)); 936#else 937PTH_FUNCS(int, pthreadZumutexZutrylock, pthread_mutex_trylock_intercept, 938 (pthread_mutex_t *mutex), (mutex)); 939#endif /* VGO_solaris */ 940 941static __always_inline 942int pthread_mutex_timedlock_intercept(pthread_mutex_t *mutex, 943 const struct timespec *abs_timeout) 944{ 945 int ret; 946 OrigFn fn; 947 VALGRIND_GET_ORIG_FN(fn); 948 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK, 949 mutex, DRD_(mutex_type)(mutex), 0, 0, 0); 950 CALL_FN_W_WW(ret, fn, mutex, abs_timeout); 951 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK, 952 mutex, ret == 0, 0, 0, 0); 953 return ret; 954} 955 956PTH_FUNCS(int, pthreadZumutexZutimedlock, pthread_mutex_timedlock_intercept, 957 (pthread_mutex_t *mutex, const struct timespec *abs_timeout), 958 (mutex, abs_timeout)); 959#if defined(VGO_solaris) 960PTH_FUNCS(int, 961 pthreadZumutexZureltimedlockZunp, pthread_mutex_timedlock_intercept, 962 (pthread_mutex_t *mutex, const struct timespec *timeout), 963 (mutex, timeout)); 964#endif /* VGO_solaris */ 965 966static __always_inline 967int pthread_mutex_unlock_intercept(pthread_mutex_t *mutex) 968{ 969 int ret; 970 OrigFn fn; 971 VALGRIND_GET_ORIG_FN(fn); 972 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK, 973 mutex, DRD_(mutex_type)(mutex), 0, 0, 0); 974 CALL_FN_W_W(ret, fn, mutex); 975 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK, 976 mutex, 0, 0, 0, 0); 977 return ret; 978} 979 980#if defined(VGO_solaris) 981/* On Solaris, pthread_mutex_unlock is a weak alias to mutex_unlock. */ 982PTH_FUNCS(int, mutexZuunlock, pthread_mutex_unlock_intercept, 983 (pthread_mutex_t *mutex), (mutex)); 984#else 985PTH_FUNCS(int, pthreadZumutexZuunlock, pthread_mutex_unlock_intercept, 986 (pthread_mutex_t *mutex), (mutex)); 987#endif /* VGO_solaris */ 988 989#if defined(VGO_solaris) 990/* Internal to libc. */ 991static __always_inline 992void lmutex_unlock_intercept(mutex_t *mutex) 993{ 994 OrigFn fn; 995 VALGRIND_GET_ORIG_FN(fn); 996 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK, 997 mutex, 998 DRD_(mutex_type)((pthread_mutex_t *) mutex), 999 0, 0, 0); 1000 CALL_FN_v_W(fn, mutex); 1001 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK, 1002 mutex, 0, 0, 0, 0); 1003} 1004 1005PTH_FUNCS(void, lmutexZuunlock, lmutex_unlock_intercept, 1006 (mutex_t *mutex), (mutex)); 1007#endif /* VGO_solaris */ 1008 1009static __always_inline 1010int pthread_cond_init_intercept(pthread_cond_t* cond, 1011 const pthread_condattr_t* attr) 1012{ 1013 int ret; 1014 OrigFn fn; 1015 VALGRIND_GET_ORIG_FN(fn); 1016 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT, 1017 cond, 0, 0, 0, 0); 1018 CALL_FN_W_WW(ret, fn, cond, attr); 1019 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT, 1020 cond, 0, 0, 0, 0); 1021 return ret; 1022} 1023 1024PTH_FUNCS(int, pthreadZucondZuinit, pthread_cond_init_intercept, 1025 (pthread_cond_t* cond, const pthread_condattr_t* attr), 1026 (cond, attr)); 1027 1028#if defined(VGO_solaris) 1029static __always_inline 1030int cond_init_intercept(cond_t *cond, int type, void *arg) 1031{ 1032 int ret; 1033 OrigFn fn; 1034 VALGRIND_GET_ORIG_FN(fn); 1035 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT, 1036 cond, 0, 0, 0, 0); 1037 CALL_FN_W_WWW(ret, fn, cond, type, arg); 1038 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT, 1039 cond, 0, 0, 0, 0); 1040 return ret; 1041} 1042 1043PTH_FUNCS(int, condZuinit, cond_init_intercept, 1044 (cond_t *cond, int type, void *arg), 1045 (cond, type, arg)); 1046#endif /* VGO_solaris */ 1047 1048static __always_inline 1049int pthread_cond_destroy_intercept(pthread_cond_t* cond) 1050{ 1051 int ret; 1052 OrigFn fn; 1053 VALGRIND_GET_ORIG_FN(fn); 1054 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_DESTROY, 1055 cond, 0, 0, 0, 0); 1056 CALL_FN_W_W(ret, fn, cond); 1057 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_DESTROY, 1058 cond, ret==0, 0, 0, 0); 1059 return ret; 1060} 1061 1062#if defined(VGO_solaris) 1063/* On Solaris, pthread_cond_destroy is a weak alias to cond_destroy. */ 1064PTH_FUNCS(int, condZudestroy, pthread_cond_destroy_intercept, 1065 (pthread_cond_t *cond), (cond)); 1066#else 1067PTH_FUNCS(int, pthreadZucondZudestroy, pthread_cond_destroy_intercept, 1068 (pthread_cond_t* cond), (cond)); 1069#endif /* VGO_solaris */ 1070 1071static __always_inline 1072int pthread_cond_wait_intercept(pthread_cond_t *cond, pthread_mutex_t *mutex) 1073{ 1074 int ret; 1075 OrigFn fn; 1076 VALGRIND_GET_ORIG_FN(fn); 1077 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT, 1078 cond, mutex, DRD_(mutex_type)(mutex), 0, 0); 1079 CALL_FN_W_WW(ret, fn, cond, mutex); 1080 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT, 1081 cond, mutex, 1, 0, 0); 1082 return ret; 1083} 1084 1085PTH_FUNCS(int, pthreadZucondZuwait, pthread_cond_wait_intercept, 1086 (pthread_cond_t *cond, pthread_mutex_t *mutex), 1087 (cond, mutex)); 1088#if defined(VGO_solaris) 1089PTH_FUNCS(int, condZuwait, pthread_cond_wait_intercept, 1090 (pthread_cond_t *cond, pthread_mutex_t *mutex), 1091 (cond, mutex)); 1092#endif /* VGO_solaris */ 1093 1094static __always_inline 1095int pthread_cond_timedwait_intercept(pthread_cond_t *cond, 1096 pthread_mutex_t *mutex, 1097 const struct timespec* abstime) 1098{ 1099 int ret; 1100 OrigFn fn; 1101 VALGRIND_GET_ORIG_FN(fn); 1102 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT, 1103 cond, mutex, DRD_(mutex_type)(mutex), 0, 0); 1104 CALL_FN_W_WWW(ret, fn, cond, mutex, abstime); 1105 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT, 1106 cond, mutex, 1, 0, 0); 1107 return ret; 1108} 1109 1110PTH_FUNCS(int, pthreadZucondZutimedwait, pthread_cond_timedwait_intercept, 1111 (pthread_cond_t *cond, pthread_mutex_t *mutex, 1112 const struct timespec* abstime), 1113 (cond, mutex, abstime)); 1114#if defined(VGO_solaris) 1115PTH_FUNCS(int, condZutimedwait, pthread_cond_timedwait_intercept, 1116 (pthread_cond_t *cond, pthread_mutex_t *mutex, 1117 const struct timespec *timeout), 1118 (cond, mutex, timeout)); 1119PTH_FUNCS(int, condZureltimedwait, pthread_cond_timedwait_intercept, 1120 (pthread_cond_t *cond, pthread_mutex_t *mutex, 1121 const struct timespec *timeout), 1122 (cond, mutex, timeout)); 1123#endif /* VGO_solaris */ 1124 1125// NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's 1126// pthread_cond_signal_thread_np(). The former accepts one argument; the latter 1127// two. Intercepting all pthread_cond_signal* functions will cause only one 1128// argument to be passed to pthread_cond_signal_np() and hence will cause this 1129// last function to crash. 1130 1131static __always_inline 1132int pthread_cond_signal_intercept(pthread_cond_t* cond) 1133{ 1134 int ret; 1135 OrigFn fn; 1136 VALGRIND_GET_ORIG_FN(fn); 1137 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_SIGNAL, 1138 cond, 0, 0, 0, 0); 1139 CALL_FN_W_W(ret, fn, cond); 1140 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_SIGNAL, 1141 cond, 0, 0, 0, 0); 1142 return ret; 1143} 1144 1145#if defined(VGO_solaris) 1146/* On Solaris, pthread_cond_signal is a weak alias to cond_signal. */ 1147PTH_FUNCS(int, condZusignal, pthread_cond_signal_intercept, 1148 (pthread_cond_t *cond), (cond)); 1149#else 1150PTH_FUNCS(int, pthreadZucondZusignal, pthread_cond_signal_intercept, 1151 (pthread_cond_t* cond), (cond)); 1152#endif /* VGO_solaris */ 1153 1154static __always_inline 1155int pthread_cond_broadcast_intercept(pthread_cond_t* cond) 1156{ 1157 int ret; 1158 OrigFn fn; 1159 VALGRIND_GET_ORIG_FN(fn); 1160 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_BROADCAST, 1161 cond, 0, 0, 0, 0); 1162 CALL_FN_W_W(ret, fn, cond); 1163 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_BROADCAST, 1164 cond, 0, 0, 0, 0); 1165 return ret; 1166} 1167 1168#if defined(VGO_solaris) 1169/* On Solaris, pthread_cond_broadcast is a weak alias to cond_broadcast. */ 1170PTH_FUNCS(int, condZubroadcast, pthread_cond_broadcast_intercept, 1171 (pthread_cond_t *cond), (cond)); 1172#else 1173PTH_FUNCS(int, pthreadZucondZubroadcast, pthread_cond_broadcast_intercept, 1174 (pthread_cond_t* cond), (cond)); 1175#endif /* VGO_solaris */ 1176 1177#if defined(HAVE_PTHREAD_SPIN_LOCK) \ 1178 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT) 1179static __always_inline 1180int pthread_spin_init_intercept(pthread_spinlock_t *spinlock, int pshared) 1181{ 1182 int ret; 1183 OrigFn fn; 1184 VALGRIND_GET_ORIG_FN(fn); 1185 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK, 1186 spinlock, 0, 0, 0, 0); 1187 CALL_FN_W_WW(ret, fn, spinlock, pshared); 1188 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK, 1189 spinlock, 0, 0, 0, 0); 1190 return ret; 1191} 1192 1193PTH_FUNCS(int, pthreadZuspinZuinit, pthread_spin_init_intercept, 1194 (pthread_spinlock_t *spinlock, int pshared), (spinlock, pshared)); 1195 1196static __always_inline 1197int pthread_spin_destroy_intercept(pthread_spinlock_t *spinlock) 1198{ 1199 int ret; 1200 OrigFn fn; 1201 VALGRIND_GET_ORIG_FN(fn); 1202 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_DESTROY, 1203 spinlock, 0, 0, 0, 0); 1204 CALL_FN_W_W(ret, fn, spinlock); 1205 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_DESTROY, 1206 spinlock, mutex_type_spinlock, 0, 0, 0); 1207 return ret; 1208} 1209 1210PTH_FUNCS(int, pthreadZuspinZudestroy, pthread_spin_destroy_intercept, 1211 (pthread_spinlock_t *spinlock), (spinlock)); 1212 1213static __always_inline 1214int pthread_spin_lock_intercept(pthread_spinlock_t *spinlock) 1215{ 1216 int ret; 1217 OrigFn fn; 1218 VALGRIND_GET_ORIG_FN(fn); 1219 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK, 1220 spinlock, mutex_type_spinlock, 0, 0, 0); 1221 CALL_FN_W_W(ret, fn, spinlock); 1222 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK, 1223 spinlock, ret == 0, 0, 0, 0); 1224 return ret; 1225} 1226 1227PTH_FUNCS(int, pthreadZuspinZulock, pthread_spin_lock_intercept, 1228 (pthread_spinlock_t *spinlock), (spinlock)); 1229 1230static __always_inline 1231int pthread_spin_trylock_intercept(pthread_spinlock_t *spinlock) 1232{ 1233 int ret; 1234 OrigFn fn; 1235 VALGRIND_GET_ORIG_FN(fn); 1236 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK, 1237 spinlock, mutex_type_spinlock, 0, 0, 0); 1238 CALL_FN_W_W(ret, fn, spinlock); 1239 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK, 1240 spinlock, ret == 0, 0, 0, 0); 1241 return ret; 1242} 1243 1244PTH_FUNCS(int, pthreadZuspinZutrylock, pthread_spin_trylock_intercept, 1245 (pthread_spinlock_t *spinlock), (spinlock)); 1246 1247static __always_inline 1248int pthread_spin_unlock_intercept(pthread_spinlock_t *spinlock) 1249{ 1250 int ret; 1251 OrigFn fn; 1252 VALGRIND_GET_ORIG_FN(fn); 1253 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK, 1254 spinlock, mutex_type_spinlock, 0, 0, 0); 1255 CALL_FN_W_W(ret, fn, spinlock); 1256 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK, 1257 spinlock, 0, 0, 0, 0); 1258 return ret; 1259} 1260 1261PTH_FUNCS(int, pthreadZuspinZuunlock, pthread_spin_unlock_intercept, 1262 (pthread_spinlock_t *spinlock), (spinlock)); 1263#endif // HAVE_PTHREAD_SPIN_LOCK 1264 1265 1266#if defined(HAVE_PTHREAD_BARRIER_INIT) 1267static __always_inline 1268int pthread_barrier_init_intercept(pthread_barrier_t* barrier, 1269 const pthread_barrierattr_t* attr, 1270 unsigned count) 1271{ 1272 int ret; 1273 OrigFn fn; 1274 VALGRIND_GET_ORIG_FN(fn); 1275 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_INIT, 1276 barrier, pthread_barrier, count, 0, 0); 1277 CALL_FN_W_WWW(ret, fn, barrier, attr, count); 1278 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_INIT, 1279 barrier, pthread_barrier, 0, 0, 0); 1280 return ret; 1281} 1282 1283PTH_FUNCS(int, pthreadZubarrierZuinit, pthread_barrier_init_intercept, 1284 (pthread_barrier_t* barrier, const pthread_barrierattr_t* attr, 1285 unsigned count), (barrier, attr, count)); 1286 1287static __always_inline 1288int pthread_barrier_destroy_intercept(pthread_barrier_t* barrier) 1289{ 1290 int ret; 1291 OrigFn fn; 1292 VALGRIND_GET_ORIG_FN(fn); 1293 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_DESTROY, 1294 barrier, pthread_barrier, 0, 0, 0); 1295 CALL_FN_W_W(ret, fn, barrier); 1296 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_DESTROY, 1297 barrier, pthread_barrier, 0, 0, 0); 1298 return ret; 1299} 1300 1301PTH_FUNCS(int, pthreadZubarrierZudestroy, pthread_barrier_destroy_intercept, 1302 (pthread_barrier_t* barrier), (barrier)); 1303 1304static __always_inline 1305int pthread_barrier_wait_intercept(pthread_barrier_t* barrier) 1306{ 1307 int ret; 1308 OrigFn fn; 1309 VALGRIND_GET_ORIG_FN(fn); 1310 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_WAIT, 1311 barrier, pthread_barrier, 0, 0, 0); 1312 CALL_FN_W_W(ret, fn, barrier); 1313 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_WAIT, 1314 barrier, pthread_barrier, 1315 ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD, 1316 ret == PTHREAD_BARRIER_SERIAL_THREAD, 0); 1317 return ret; 1318} 1319 1320PTH_FUNCS(int, pthreadZubarrierZuwait, pthread_barrier_wait_intercept, 1321 (pthread_barrier_t* barrier), (barrier)); 1322#endif // HAVE_PTHREAD_BARRIER_INIT 1323 1324 1325static __always_inline 1326int sem_init_intercept(sem_t *sem, int pshared, unsigned int value) 1327{ 1328 int ret; 1329 OrigFn fn; 1330 VALGRIND_GET_ORIG_FN(fn); 1331 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT, 1332 sem, pshared, value, 0, 0); 1333 CALL_FN_W_WWW(ret, fn, sem, pshared, value); 1334 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT, 1335 sem, 0, 0, 0, 0); 1336 return ret; 1337} 1338 1339PTH_FUNCS(int, semZuinit, sem_init_intercept, 1340 (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value)); 1341 1342#if defined(VGO_solaris) 1343static __always_inline 1344int sema_init_intercept(sema_t *sem, unsigned int value, int type, void *arg) 1345{ 1346 int ret; 1347 OrigFn fn; 1348 VALGRIND_GET_ORIG_FN(fn); 1349 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT, 1350 sem, type == USYNC_PROCESS ? 1 : 0, 1351 value, 0, 0); 1352 CALL_FN_W_WWWW(ret, fn, sem, value, type, arg); 1353 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT, 1354 sem, 0, 0, 0, 0); 1355 return ret; 1356} 1357 1358PTH_FUNCS(int, semaZuinit, sema_init_intercept, 1359 (sema_t *sem, unsigned int value, int type, void *arg), 1360 (sem, value, type, arg)); 1361#endif /* VGO_solaris */ 1362 1363static __always_inline 1364int sem_destroy_intercept(sem_t *sem) 1365{ 1366 int ret; 1367 OrigFn fn; 1368 VALGRIND_GET_ORIG_FN(fn); 1369 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_DESTROY, 1370 sem, 0, 0, 0, 0); 1371 CALL_FN_W_W(ret, fn, sem); 1372 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_DESTROY, 1373 sem, 0, 0, 0, 0); 1374 return ret; 1375} 1376 1377PTH_FUNCS(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem)); 1378#if defined(VGO_solaris) 1379PTH_FUNCS(int, semaZudestroy, sem_destroy_intercept, (sem_t *sem), (sem)); 1380#endif /* VGO_solaris */ 1381 1382static __always_inline 1383sem_t* sem_open_intercept(const char *name, int oflag, mode_t mode, 1384 unsigned int value) 1385{ 1386 sem_t *ret; 1387 OrigFn fn; 1388 VALGRIND_GET_ORIG_FN(fn); 1389 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_OPEN, 1390 name, oflag, mode, value, 0); 1391 CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value); 1392 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_OPEN, 1393 ret != SEM_FAILED ? ret : 0, 1394 name, oflag, mode, value); 1395 return ret; 1396} 1397 1398PTH_FUNCS(sem_t *, semZuopen, sem_open_intercept, 1399 (const char *name, int oflag, mode_t mode, unsigned int value), 1400 (name, oflag, mode, value)); 1401 1402static __always_inline int sem_close_intercept(sem_t *sem) 1403{ 1404 int ret; 1405 OrigFn fn; 1406 VALGRIND_GET_ORIG_FN(fn); 1407 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_CLOSE, 1408 sem, 0, 0, 0, 0); 1409 CALL_FN_W_W(ret, fn, sem); 1410 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_CLOSE, 1411 sem, 0, 0, 0, 0); 1412 return ret; 1413} 1414 1415PTH_FUNCS(int, semZuclose, sem_close_intercept, (sem_t *sem), (sem)); 1416 1417static __always_inline int sem_wait_intercept(sem_t *sem) 1418{ 1419 int ret; 1420 OrigFn fn; 1421 VALGRIND_GET_ORIG_FN(fn); 1422 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT, 1423 sem, 0, 0, 0, 0); 1424 CALL_FN_W_W(ret, fn, sem); 1425 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT, 1426 sem, ret == 0, 0, 0, 0); 1427 return ret; 1428} 1429 1430PTH_FUNCS(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem)); 1431#if defined(VGO_solaris) 1432PTH_FUNCS(int, semaZuwait, sem_wait_intercept, (sem_t *sem), (sem)); 1433#endif /* VGO_solaris */ 1434 1435static __always_inline int sem_trywait_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_WAIT, 1441 sem, 0, 0, 0, 0); 1442 CALL_FN_W_W(ret, fn, sem); 1443 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT, 1444 sem, ret == 0, 0, 0, 0); 1445 return ret; 1446} 1447 1448PTH_FUNCS(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem)); 1449#if defined(VGO_solaris) 1450PTH_FUNCS(int, semaZutrywait, sem_trywait_intercept, (sem_t *sem), (sem)); 1451#endif /* VGO_solaris */ 1452 1453static __always_inline 1454int sem_timedwait_intercept(sem_t *sem, const struct timespec *abs_timeout) 1455{ 1456 int ret; 1457 OrigFn fn; 1458 VALGRIND_GET_ORIG_FN(fn); 1459 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_WAIT, 1460 sem, 0, 0, 0, 0); 1461 CALL_FN_W_WW(ret, fn, sem, abs_timeout); 1462 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_WAIT, 1463 sem, ret == 0, 0, 0, 0); 1464 return ret; 1465} 1466 1467PTH_FUNCS(int, semZutimedwait, sem_timedwait_intercept, 1468 (sem_t *sem, const struct timespec *abs_timeout), 1469 (sem, abs_timeout)); 1470#if defined(VGO_solaris) 1471PTH_FUNCS(int, semaZutimedwait, sem_timedwait_intercept, 1472 (sem_t *sem, const struct timespec *timeout), 1473 (sem, timeout)); 1474PTH_FUNCS(int, semaZureltimedwait, sem_timedwait_intercept, 1475 (sem_t *sem, const struct timespec *timeout), 1476 (sem, timeout)); 1477#endif /* VGO_solaris */ 1478 1479static __always_inline int sem_post_intercept(sem_t *sem) 1480{ 1481 int ret; 1482 OrigFn fn; 1483 VALGRIND_GET_ORIG_FN(fn); 1484 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_POST, 1485 sem, 0, 0, 0, 0); 1486 CALL_FN_W_W(ret, fn, sem); 1487 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_POST, 1488 sem, ret == 0, 0, 0, 0); 1489 return ret; 1490} 1491 1492PTH_FUNCS(int, semZupost, sem_post_intercept, (sem_t *sem), (sem)); 1493#if defined(VGO_solaris) 1494PTH_FUNCS(int, semaZupost, sem_post_intercept, (sem_t *sem), (sem)); 1495#endif /* VGO_solaris */ 1496 1497/* Android's pthread.h doesn't say anything about rwlocks, hence these 1498 functions have to be conditionally compiled. */ 1499#if defined(HAVE_PTHREAD_RWLOCK_T) 1500 1501static __always_inline 1502int pthread_rwlock_init_intercept(pthread_rwlock_t* rwlock, 1503 const pthread_rwlockattr_t* attr) 1504{ 1505 int ret; 1506 OrigFn fn; 1507 VALGRIND_GET_ORIG_FN(fn); 1508 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT, 1509 rwlock, 0, 0, 0, 0); 1510 CALL_FN_W_WW(ret, fn, rwlock, attr); 1511 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT, 1512 rwlock, 0, 0, 0, 0); 1513 return ret; 1514} 1515 1516PTH_FUNCS(int, 1517 pthreadZurwlockZuinit, pthread_rwlock_init_intercept, 1518 (pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr), 1519 (rwlock, attr)); 1520 1521#if defined(VGO_solaris) 1522static __always_inline 1523int rwlock_init_intercept(rwlock_t *rwlock, int type, void *arg) 1524{ 1525 int ret; 1526 OrigFn fn; 1527 VALGRIND_GET_ORIG_FN(fn); 1528 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT, 1529 rwlock, 0, 0, 0, 0); 1530 CALL_FN_W_WWW(ret, fn, rwlock, type, arg); 1531 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT, 1532 rwlock, 0, 0, 0, 0); 1533 return ret; 1534} 1535 1536PTH_FUNCS(int, rwlockZuinit, rwlock_init_intercept, 1537 (rwlock_t *rwlock, int type, void *arg), 1538 (rwlock, type, arg)); 1539#endif /* VGO_solaris */ 1540 1541static __always_inline 1542int pthread_rwlock_destroy_intercept(pthread_rwlock_t* rwlock) 1543{ 1544 int ret; 1545 OrigFn fn; 1546 VALGRIND_GET_ORIG_FN(fn); 1547 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_DESTROY, 1548 rwlock, 0, 0, 0, 0); 1549 CALL_FN_W_W(ret, fn, rwlock); 1550 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_DESTROY, 1551 rwlock, 0, 0, 0, 0); 1552 return ret; 1553} 1554 1555#if defined(VGO_solaris) 1556/* On Solaris, pthread_rwlock_destroy is a weak alias to rwlock_destroy. */ 1557PTH_FUNCS(int, 1558 rwlockZudestroy, pthread_rwlock_destroy_intercept, 1559 (pthread_rwlock_t *rwlock), (rwlock)); 1560#else 1561PTH_FUNCS(int, 1562 pthreadZurwlockZudestroy, pthread_rwlock_destroy_intercept, 1563 (pthread_rwlock_t* rwlock), (rwlock)); 1564#endif /* VGO_solaris */ 1565 1566static __always_inline 1567int pthread_rwlock_rdlock_intercept(pthread_rwlock_t* rwlock) 1568{ 1569 int ret; 1570 OrigFn fn; 1571 VALGRIND_GET_ORIG_FN(fn); 1572 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK, 1573 rwlock, 0, 0, 0, 0); 1574 CALL_FN_W_W(ret, fn, rwlock); 1575 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK, 1576 rwlock, ret == 0, 0, 0, 0); 1577 return ret; 1578} 1579 1580#if defined(VGO_solaris) 1581/* On Solaris, pthread_rwlock_rdlock is a weak alias to rw_rdlock. */ 1582PTH_FUNCS(int, 1583 rwZurdlock, pthread_rwlock_rdlock_intercept, 1584 (pthread_rwlock_t *rwlock), (rwlock)); 1585#else 1586PTH_FUNCS(int, 1587 pthreadZurwlockZurdlock, pthread_rwlock_rdlock_intercept, 1588 (pthread_rwlock_t* rwlock), (rwlock)); 1589#endif /* VGO_solaris */ 1590 1591#if defined(VGO_solaris) 1592/* Internal to libc. */ 1593static __always_inline 1594void lrw_rdlock_intercept(rwlock_t *rwlock) 1595{ 1596 OrigFn fn; 1597 VALGRIND_GET_ORIG_FN(fn); 1598 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK, 1599 rwlock, 0, 0, 0, 0); 1600 CALL_FN_v_W(fn, rwlock); 1601 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK, 1602 rwlock, True /* took_lock */, 0, 0, 0); 1603} 1604 1605PTH_FUNCS(void, lrwZurdlock, lrw_rdlock_intercept, 1606 (rwlock_t *rwlock), (rwlock)); 1607#endif /* VGO_solaris */ 1608 1609static __always_inline 1610int pthread_rwlock_wrlock_intercept(pthread_rwlock_t* rwlock) 1611{ 1612 int ret; 1613 OrigFn fn; 1614 VALGRIND_GET_ORIG_FN(fn); 1615 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK, 1616 rwlock, 0, 0, 0, 0); 1617 CALL_FN_W_W(ret, fn, rwlock); 1618 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK, 1619 rwlock, ret == 0, 0, 0, 0); 1620 return ret; 1621} 1622 1623#if defined(VGO_solaris) 1624/* On Solaris, pthread_rwlock_wrlock is a weak alias to rw_wrlock. */ 1625PTH_FUNCS(int, 1626 rwZuwrlock, pthread_rwlock_wrlock_intercept, 1627 (pthread_rwlock_t *rwlock), (rwlock)); 1628#else 1629PTH_FUNCS(int, 1630 pthreadZurwlockZuwrlock, pthread_rwlock_wrlock_intercept, 1631 (pthread_rwlock_t* rwlock), (rwlock)); 1632#endif /* VGO_solaris */ 1633 1634#if defined(VGO_solaris) 1635/* Internal to libc. */ 1636static __always_inline 1637void lrw_wrlock_intercept(rwlock_t *rwlock) 1638{ 1639 OrigFn fn; 1640 VALGRIND_GET_ORIG_FN(fn); 1641 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK, 1642 rwlock, 0, 0, 0, 0); 1643 CALL_FN_v_W(fn, rwlock); 1644 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK, 1645 rwlock, True /* took_lock */, 0, 0, 0); 1646} 1647 1648PTH_FUNCS(void, lrwZuwrlock, lrw_wrlock_intercept, 1649 (rwlock_t *rwlock), (rwlock)); 1650#endif /* VGO_solaris */ 1651 1652static __always_inline 1653int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t* rwlock, 1654 const struct timespec *timeout) 1655{ 1656 int ret; 1657 OrigFn fn; 1658 VALGRIND_GET_ORIG_FN(fn); 1659 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK, 1660 rwlock, 0, 0, 0, 0); 1661 CALL_FN_W_WW(ret, fn, rwlock, timeout); 1662 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK, 1663 rwlock, ret == 0, 0, 0, 0); 1664 return ret; 1665} 1666 1667PTH_FUNCS(int, 1668 pthreadZurwlockZutimedrdlock, pthread_rwlock_timedrdlock_intercept, 1669 (pthread_rwlock_t* rwlock, const struct timespec *timeout), 1670 (rwlock, timeout)); 1671#if defined(VGO_solaris) 1672PTH_FUNCS(int, pthreadZurwlockZureltimedrdlockZunp, 1673 pthread_rwlock_timedrdlock_intercept, 1674 (pthread_rwlock_t *rwlock, const struct timespec *timeout), 1675 (rwlock, timeout)); 1676#endif /* VGO_solaris */ 1677 1678static __always_inline 1679int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t* rwlock, 1680 const struct timespec *timeout) 1681{ 1682 int ret; 1683 OrigFn fn; 1684 VALGRIND_GET_ORIG_FN(fn); 1685 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK, 1686 rwlock, 0, 0, 0, 0); 1687 CALL_FN_W_WW(ret, fn, rwlock, timeout); 1688 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK, 1689 rwlock, ret == 0, 0, 0, 0); 1690 return ret; 1691} 1692 1693PTH_FUNCS(int, 1694 pthreadZurwlockZutimedwrlock, pthread_rwlock_timedwrlock_intercept, 1695 (pthread_rwlock_t* rwlock, const struct timespec *timeout), 1696 (rwlock, timeout)); 1697#if defined(VGO_solaris) 1698PTH_FUNCS(int, pthreadZurwlockZureltimedwrlockZunp, 1699 pthread_rwlock_timedwrlock_intercept, 1700 (pthread_rwlock_t *rwlock, const struct timespec *timeout), 1701 (rwlock, timeout)); 1702#endif /* VGO_solaris */ 1703 1704static __always_inline 1705int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t* rwlock) 1706{ 1707 int ret; 1708 OrigFn fn; 1709 VALGRIND_GET_ORIG_FN(fn); 1710 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK, 1711 rwlock, 0, 0, 0, 0); 1712 CALL_FN_W_W(ret, fn, rwlock); 1713 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK, 1714 rwlock, ret == 0, 0, 0, 0); 1715 return ret; 1716} 1717 1718#if defined(VGO_solaris) 1719/* On Solaris, pthread_rwlock_tryrdlock is a weak alias to rw_tryrdlock. */ 1720PTH_FUNCS(int, 1721 rwZutryrdlock, pthread_rwlock_tryrdlock_intercept, 1722 (pthread_rwlock_t *rwlock), (rwlock)); 1723#else 1724PTH_FUNCS(int, 1725 pthreadZurwlockZutryrdlock, pthread_rwlock_tryrdlock_intercept, 1726 (pthread_rwlock_t* rwlock), (rwlock)); 1727#endif /* VGO_solaris */ 1728 1729static __always_inline 1730int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t* rwlock) 1731{ 1732 int ret; 1733 OrigFn fn; 1734 VALGRIND_GET_ORIG_FN(fn); 1735 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK, 1736 rwlock, 0, 0, 0, 0); 1737 CALL_FN_W_W(ret, fn, rwlock); 1738 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK, 1739 rwlock, ret == 0, 0, 0, 0); 1740 return ret; 1741} 1742 1743#if defined(VGO_solaris) 1744/* On Solaris, pthread_rwlock_trywrlock is a weak alias to rw_trywrlock. */ 1745PTH_FUNCS(int, 1746 rwZutrywrlock, pthread_rwlock_trywrlock_intercept, 1747 (pthread_rwlock_t *rwlock), (rwlock)); 1748#else 1749PTH_FUNCS(int, 1750 pthreadZurwlockZutrywrlock, pthread_rwlock_trywrlock_intercept, 1751 (pthread_rwlock_t* rwlock), (rwlock)); 1752#endif /* VGO_solaris */ 1753 1754static __always_inline 1755int pthread_rwlock_unlock_intercept(pthread_rwlock_t* rwlock) 1756{ 1757 int ret; 1758 OrigFn fn; 1759 VALGRIND_GET_ORIG_FN(fn); 1760 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_UNLOCK, 1761 rwlock, 0, 0, 0, 0); 1762 CALL_FN_W_W(ret, fn, rwlock); 1763 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_UNLOCK, 1764 rwlock, ret == 0, 0, 0, 0); 1765 return ret; 1766} 1767 1768#if defined(VGO_solaris) 1769/* On Solaris, pthread_rwlock_unlock is a weak alias to rw_unlock. */ 1770PTH_FUNCS(int, 1771 rwZuunlock, pthread_rwlock_unlock_intercept, 1772 (pthread_rwlock_t *rwlock), (rwlock)); 1773#else 1774PTH_FUNCS(int, 1775 pthreadZurwlockZuunlock, pthread_rwlock_unlock_intercept, 1776 (pthread_rwlock_t* rwlock), (rwlock)); 1777#endif /* VGO_solaris */ 1778 1779#endif /* defined(HAVE_PTHREAD_RWLOCK_T) */ 1780