1 2 /*--------------------------------------------------------------------*/ 3 /*--- pthread intercepts for thread checking. ---*/ 4 /*--- hg_intercepts.c ---*/ 5 /*--------------------------------------------------------------------*/ 6 7 /* 8 This file is part of Helgrind, a Valgrind tool for detecting errors 9 in threaded programs. 10 11 Copyright (C) 2007-2015 OpenWorks LLP 12 info (at) open-works.co.uk 13 14 This program is free software; you can redistribute it and/or 15 modify it under the terms of the GNU General Public License as 16 published by the Free Software Foundation; either version 2 of the 17 License, or (at your option) any later version. 18 19 This program is distributed in the hope that it will be useful, but 20 WITHOUT ANY WARRANTY; without even the implied warranty of 21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 General Public License for more details. 23 24 You should have received a copy of the GNU General Public License 25 along with this program; if not, write to the Free Software 26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 27 02111-1307, USA. 28 29 The GNU General Public License is contained in the file COPYING. 30 31 Neither the names of the U.S. Department of Energy nor the 32 University of California nor the names of its contributors may be 33 used to endorse or promote products derived from this software 34 without prior written permission. 35 */ 36 37 /* RUNS ON SIMULATED CPU 38 Interceptors for pthread_* functions, so that tc_main can see 39 significant thread events. 40 41 Important: when adding a function wrapper to this file, remember to 42 add a test case to tc20_verifywrap.c. A common cause of failure is 43 for wrappers to not engage on different distros, and 44 tc20_verifywrap essentially checks that each wrapper is really 45 doing something. 46 */ 47 48 // DDD: for Darwin, need to have non-"@*"-suffixed versions for all pthread 49 // functions that currently have them. 50 // Note also, in the comments and code below, all Darwin symbols start 51 // with a leading underscore, which is not shown either in the comments 52 // nor in the redirect specs. 53 54 55 #include "pub_tool_basics.h" 56 #include "pub_tool_redir.h" 57 #include "pub_tool_clreq.h" 58 #include "helgrind.h" 59 #include "config.h" 60 61 62 #if defined(VGO_solaris) 63 /* See porting comments in drd/drd_pthread_intercepts.c 64 However when a POSIX threads API function (for example pthread_cond_init) 65 is built upon the Solaris one (cond_init), intercept only the bottom one. 66 Helgrind does not contain generic synchronization nesting like DRD 67 and double intercept confuses it. */ 68 #include <synch.h> 69 #include <thread.h> 70 #endif /* VGO_solaris */ 71 72 73 #define TRACE_PTH_FNS 0 74 #define TRACE_QT4_FNS 0 75 #define TRACE_GNAT_FNS 0 76 77 78 /*----------------------------------------------------------------*/ 79 /*--- ---*/ 80 /*----------------------------------------------------------------*/ 81 82 #if defined(VGO_solaris) 83 /* On Solaris, libpthread is just a filter library on top of libc. 84 * Threading and synchronization functions in runtime linker are not 85 * intercepted. 86 */ 87 #define PTH_FUNC(ret_ty, f, args...) \ 88 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)(args); \ 89 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)(args) 90 91 /* pthread_t is typedef'd to 'unsigned int' but in DO_CREQ_* macros 92 sizeof(Word) is expected. */ 93 #define CREQ_PTHREAD_T Word 94 #define SEM_ERROR ret 95 #else 96 #define PTH_FUNC(ret_ty, f, args...) \ 97 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args); \ 98 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args) 99 #define CREQ_PTHREAD_T pthread_t 100 #define SEM_ERROR errno 101 #endif /* VGO_solaris */ 102 103 // Do a client request. These are macros rather than a functions so 104 // as to avoid having an extra frame in stack traces. 105 106 // NB: these duplicate definitions in helgrind.h. But here, we 107 // can have better typing (Word etc) and assertions, whereas 108 // in helgrind.h we can't. Obviously it's important the two 109 // sets of definitions are kept in sync. 110 111 // nuke the previous definitions 112 #undef DO_CREQ_v_W 113 #undef DO_CREQ_v_WW 114 #undef DO_CREQ_W_WW 115 #undef DO_CREQ_v_WWW 116 117 #define DO_CREQ_v_W(_creqF, _ty1F,_arg1F) \ 118 do { \ 119 Word _arg1; \ 120 assert(sizeof(_ty1F) == sizeof(Word)); \ 121 _arg1 = (Word)(_arg1F); \ 122 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \ 123 _arg1, 0,0,0,0); \ 124 } while (0) 125 126 #define DO_CREQ_v_WW(_creqF, _ty1F,_arg1F, _ty2F,_arg2F) \ 127 do { \ 128 Word _arg1, _arg2; \ 129 assert(sizeof(_ty1F) == sizeof(Word)); \ 130 assert(sizeof(_ty2F) == sizeof(Word)); \ 131 _arg1 = (Word)(_arg1F); \ 132 _arg2 = (Word)(_arg2F); \ 133 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \ 134 _arg1,_arg2,0,0,0); \ 135 } while (0) 136 137 #define DO_CREQ_W_WW(_resF, _creqF, _ty1F,_arg1F, \ 138 _ty2F,_arg2F) \ 139 do { \ 140 Word _res, _arg1, _arg2; \ 141 assert(sizeof(_ty1F) == sizeof(Word)); \ 142 assert(sizeof(_ty2F) == sizeof(Word)); \ 143 _arg1 = (Word)(_arg1F); \ 144 _arg2 = (Word)(_arg2F); \ 145 _res = VALGRIND_DO_CLIENT_REQUEST_EXPR(2, \ 146 (_creqF), \ 147 _arg1,_arg2,0,0,0); \ 148 _resF = _res; \ 149 } while (0) 150 151 #define DO_CREQ_v_WWW(_creqF, _ty1F,_arg1F, \ 152 _ty2F,_arg2F, _ty3F, _arg3F) \ 153 do { \ 154 Word _arg1, _arg2, _arg3; \ 155 assert(sizeof(_ty1F) == sizeof(Word)); \ 156 assert(sizeof(_ty2F) == sizeof(Word)); \ 157 assert(sizeof(_ty3F) == sizeof(Word)); \ 158 _arg1 = (Word)(_arg1F); \ 159 _arg2 = (Word)(_arg2F); \ 160 _arg3 = (Word)(_arg3F); \ 161 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \ 162 _arg1,_arg2,_arg3,0,0); \ 163 } while (0) 164 165 #define DO_CREQ_v_WWWW(_creqF, _ty1F,_arg1F, \ 166 _ty2F, _arg2F, _ty3F, _arg3F, \ 167 _ty4F, _arg4F) \ 168 do { \ 169 Word _arg1, _arg2, _arg3, _arg4; \ 170 assert(sizeof(_ty1F) == sizeof(Word)); \ 171 assert(sizeof(_ty2F) == sizeof(Word)); \ 172 assert(sizeof(_ty3F) == sizeof(Word)); \ 173 assert(sizeof(_ty4F) == sizeof(Word)); \ 174 _arg1 = (Word)(_arg1F); \ 175 _arg2 = (Word)(_arg2F); \ 176 _arg3 = (Word)(_arg3F); \ 177 _arg4 = (Word)(_arg4F); \ 178 VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF), \ 179 _arg1,_arg2,_arg3,_arg4,0); \ 180 } while (0) 181 182 #define DO_PthAPIerror(_fnnameF, _errF) \ 183 do { \ 184 const char* _fnname = (_fnnameF); \ 185 long _err = (long)(int)(_errF); \ 186 const char* _errstr = lame_strerror(_err); \ 187 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTH_API_ERROR, \ 188 char*,_fnname, \ 189 long,_err, char*,_errstr); \ 190 } while (0) 191 192 193 /* Needed for older glibcs (2.3 and older, at least) who don't 194 otherwise "know" about pthread_rwlock_anything or about 195 PTHREAD_MUTEX_RECURSIVE (amongst things). */ 196 #define _GNU_SOURCE 1 197 198 #include <stdio.h> 199 #include <assert.h> 200 #include <errno.h> 201 #include <pthread.h> 202 203 /* A standalone memcmp. */ 204 __attribute__((noinline)) 205 static int my_memcmp ( const void* ptr1, const void* ptr2, size_t size) 206 { 207 const unsigned char* uchar_ptr1 = (const unsigned char*) ptr1; 208 const unsigned char* uchar_ptr2 = (const unsigned char*) ptr2; 209 size_t i; 210 for (i = 0; i < size; ++i) { 211 if (uchar_ptr1[i] != uchar_ptr2[i]) 212 return (uchar_ptr1[i] < uchar_ptr2[i]) ? -1 : 1; 213 } 214 return 0; 215 } 216 217 /* A lame version of strerror which doesn't use the real libc 218 strerror_r, since using the latter just generates endless more 219 threading errors (glibc goes off and does tons of crap w.r.t. 220 locales etc) */ 221 static const HChar* lame_strerror ( long err ) 222 { 223 switch (err) { 224 case EPERM: return "EPERM: Operation not permitted"; 225 case ENOENT: return "ENOENT: No such file or directory"; 226 case ESRCH: return "ESRCH: No such process"; 227 case EINTR: return "EINTR: Interrupted system call"; 228 case EBADF: return "EBADF: Bad file number"; 229 case EAGAIN: return "EAGAIN: Try again"; 230 case ENOMEM: return "ENOMEM: Out of memory"; 231 case EACCES: return "EACCES: Permission denied"; 232 case EFAULT: return "EFAULT: Bad address"; 233 case EEXIST: return "EEXIST: File exists"; 234 case EINVAL: return "EINVAL: Invalid argument"; 235 case EMFILE: return "EMFILE: Too many open files"; 236 case ENOSYS: return "ENOSYS: Function not implemented"; 237 case EOVERFLOW: return "EOVERFLOW: Value too large " 238 "for defined data type"; 239 case EBUSY: return "EBUSY: Device or resource busy"; 240 case ETIMEDOUT: return "ETIMEDOUT: Connection timed out"; 241 case EDEADLK: return "EDEADLK: Resource deadlock would occur"; 242 case EOPNOTSUPP: return "EOPNOTSUPP: Operation not supported on " 243 "transport endpoint"; /* honest, guv */ 244 case ETIME: return "ETIME: Timer expired"; 245 default: return "hg_intercepts.c: lame_strerror(): " 246 "unhandled case -- please fix me!"; 247 } 248 } 249 250 #if defined(VGO_solaris) 251 /* 252 * Solaris provides higher throughput, parallelism and scalability than other 253 * operating systems, at the cost of more fine-grained locking activity. 254 * This means for example that when a thread is created under Linux, just one 255 * big lock in glibc is used for all thread setup. Solaris libc uses several 256 * fine-grained locks and the creator thread resumes its activities as soon 257 * as possible, leaving for example stack and TLS setup activities to the 258 * created thread. 259 * 260 * This situation confuses Helgrind as it assumes there is some false ordering 261 * in place between creator and created thread; and therefore many types of 262 * race conditions in the application would not be reported. To prevent such 263 * false ordering, command line option --ignore-thread-creation is set to 264 * 'yes' by default on Solaris. All activity (loads, stores, client requests) 265 * is therefore ignored during: 266 * - pthread_create() call in the creator thread [libc.so] 267 * - thread creation phase (stack and TLS setup) in the created thread [libc.so] 268 * 269 * As explained in the comments for _ti_bind_guard(), whenever the runtime 270 * linker has to perform any activity (such as resolving a symbol), it protects 271 * its data structures by calling into rt_bind_guard() which in turn invokes 272 * _ti_bind_guard() in libc. Pointers to _ti_bind_guard() and _ti_bind_clear() 273 * are passed from libc to runtime linker in _ld_libc() call during libc_init(). 274 * All activity is also ignored during: 275 * - runtime dynamic linker work between rt_bind_guard() and rt_bind_clear() 276 * calls [ld.so] 277 * 278 * This also means that Helgrind does not report race conditions in libc (when 279 * --ignore-thread-creation=yes) and runtime linker itself (unconditionally) 280 * during these ignored sequences. 281 */ 282 283 #include "pub_tool_libcassert.h" 284 #include "pub_tool_vki.h" 285 286 /* 287 * Original function pointers for _ti_bind_guard() and _ti_bind_clear() 288 * from libc. They are intercepted in function wrapper of _ld_libc(). 289 */ 290 typedef int (*hg_rtld_guard_fn)(int flags); 291 static hg_rtld_guard_fn hg_rtld_bind_guard = NULL; 292 static hg_rtld_guard_fn hg_rtld_bind_clear = NULL; 293 294 static void hg_init(void) __attribute__((constructor)); 295 static void hg_init(void) 296 { 297 if ((hg_rtld_bind_guard == NULL) || (hg_rtld_bind_clear == NULL)) { 298 fprintf(stderr, 299 "Bind guard functions for the runtime linker (ld.so.1) were not intercepted.\n" 300 "This means the interface between libc and runtime linker changed\n" 301 "and Helgrind needs to be ported properly. Giving up.\n"); 302 tl_assert(0); 303 } 304 } 305 306 /* 307 * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc. 308 * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD 309 * and CI_BIND_CLEAR, to provide resilience against function renaming. 310 */ 311 static int _ti_bind_guard_intercept_WRK(int flags) 312 { 313 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_RTLD_BIND_GUARD, 314 flags, 0, 0, 0, 0); 315 return hg_rtld_bind_guard(flags); 316 } 317 318 static int _ti_bind_clear_intercept_WRK(int flags) 319 { 320 int ret = hg_rtld_bind_clear(flags); 321 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_RTLD_BIND_CLEAR, 322 flags, 0, 0, 0, 0); 323 return ret; 324 } 325 326 /* 327 * Wrapped _ld_libc() from the runtime linker ld.so.1. 328 */ 329 void I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr); 330 void I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr) 331 { 332 OrigFn fn; 333 int tag; 334 335 VALGRIND_GET_ORIG_FN(fn); 336 337 vki_Lc_interface *funcs = ptr; 338 for (tag = funcs->ci_tag; tag != 0; tag = (++funcs)->ci_tag) { 339 switch (tag) { 340 case VKI_CI_BIND_GUARD: 341 if (funcs->vki_ci_un.ci_func != _ti_bind_guard_intercept_WRK) { 342 hg_rtld_bind_guard = funcs->vki_ci_un.ci_func; 343 funcs->vki_ci_un.ci_func = _ti_bind_guard_intercept_WRK; 344 } 345 break; 346 case VKI_CI_BIND_CLEAR: 347 if (funcs->vki_ci_un.ci_func != _ti_bind_clear_intercept_WRK) { 348 hg_rtld_bind_clear = funcs->vki_ci_un.ci_func; 349 funcs->vki_ci_un.ci_func = _ti_bind_clear_intercept_WRK; 350 } 351 break; 352 } 353 } 354 355 CALL_FN_v_W(fn, ptr); 356 } 357 #endif /* VGO_solaris */ 358 359 360 /*----------------------------------------------------------------*/ 361 /*--- pthread_create, pthread_join, pthread_exit ---*/ 362 /*----------------------------------------------------------------*/ 363 364 static void* mythread_wrapper ( void* xargsV ) 365 { 366 volatile Word* xargs = (volatile Word*) xargsV; 367 void*(*fn)(void*) = (void*(*)(void*))xargs[0]; 368 void* arg = (void*)xargs[1]; 369 pthread_t me = pthread_self(); 370 /* Tell the tool what my pthread_t is. */ 371 DO_CREQ_v_W(_VG_USERREQ__HG_SET_MY_PTHREAD_T, CREQ_PTHREAD_T, me); 372 /* allow the parent to proceed. We can't let it proceed until 373 we're ready because (1) we need to make sure it doesn't exit and 374 hence deallocate xargs[] while we still need it, and (2) we 375 don't want either parent nor child to proceed until the tool has 376 been notified of the child's pthread_t. 377 378 Note that parent and child access args[] without a lock, 379 effectively using args[2] as a spinlock in order to get the 380 parent to wait until the child passes this point. The parent 381 disables checking on xargs[] before creating the child and 382 re-enables it once the child goes past this point, so the user 383 never sees the race. The previous approach (suppressing the 384 resulting error) was flawed, because it could leave shadow 385 memory for args[] in a state in which subsequent use of it by 386 the parent would report further races. */ 387 xargs[2] = 0; 388 /* Now we can no longer safely use xargs[]. */ 389 return (void*) fn( (void*)arg ); 390 } 391 392 //----------------------------------------------------------- 393 // glibc: pthread_create (at) GLIBC_2.0 394 // glibc: pthread_create@@GLIBC_2.1 395 // glibc: pthread_create@@GLIBC_2.2.5 396 // darwin: pthread_create 397 // darwin: pthread_create_suspended_np (trapped) 398 // 399 /* ensure this has its own frame, so as to make it more distinguishable 400 in suppressions */ 401 __attribute__((noinline)) 402 static int pthread_create_WRK(pthread_t *thread, const pthread_attr_t *attr, 403 void *(*start) (void *), void *arg) 404 { 405 int ret; 406 OrigFn fn; 407 volatile Word xargs[3]; 408 409 VALGRIND_GET_ORIG_FN(fn); 410 if (TRACE_PTH_FNS) { 411 fprintf(stderr, "<< pthread_create wrapper"); fflush(stderr); 412 } 413 xargs[0] = (Word)start; 414 xargs[1] = (Word)arg; 415 xargs[2] = 1; /* serves as a spinlock -- sigh */ 416 /* Disable checking on the spinlock and the two words used to 417 convey args to the child. Basically we need to make it appear 418 as if the child never accessed this area, since merely 419 suppressing the resulting races does not address the issue that 420 that piece of the parent's stack winds up in the "wrong" state 421 and therefore may give rise to mysterious races when the parent 422 comes to re-use this piece of stack in some other frame. */ 423 VALGRIND_HG_DISABLE_CHECKING(&xargs, sizeof(xargs)); 424 425 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_BEGIN, 426 0, 0, 0, 0, 0); 427 CALL_FN_W_WWWW(ret, fn, thread,attr,mythread_wrapper,&xargs[0]); 428 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_END, 429 0, 0, 0, 0, 0); 430 431 if (ret == 0) { 432 /* we have to wait for the child to notify the tool of its 433 pthread_t before continuing */ 434 while (xargs[2] != 0) { 435 /* Do nothing. We need to spin until the child writes to 436 xargs[2]. However, that can lead to starvation in the 437 child and very long delays (eg, tc19_shadowmem on 438 ppc64-linux Fedora Core 6). So yield the cpu if we can, 439 to let the child run at the earliest available 440 opportunity. */ 441 sched_yield(); 442 } 443 } else { 444 DO_PthAPIerror( "pthread_create", ret ); 445 } 446 447 /* Reenable checking on the area previously used to communicate 448 with the child. */ 449 VALGRIND_HG_ENABLE_CHECKING(&xargs, sizeof(xargs)); 450 451 if (TRACE_PTH_FNS) { 452 fprintf(stderr, " :: pth_create -> %d >>\n", ret); 453 } 454 return ret; 455 } 456 #if defined(VGO_linux) 457 PTH_FUNC(int, pthreadZucreateZAZa, // pthread_create@* 458 pthread_t *thread, const pthread_attr_t *attr, 459 void *(*start) (void *), void *arg) { 460 return pthread_create_WRK(thread, attr, start, arg); 461 } 462 #elif defined(VGO_darwin) 463 PTH_FUNC(int, pthreadZucreate, // pthread_create 464 pthread_t *thread, const pthread_attr_t *attr, 465 void *(*start) (void *), void *arg) { 466 return pthread_create_WRK(thread, attr, start, arg); 467 } 468 PTH_FUNC(int, pthreadZucreateZuZa, // pthread_create_* 469 pthread_t *thread, const pthread_attr_t *attr, 470 void *(*start) (void *), void *arg) { 471 // trap anything else 472 assert(0); 473 } 474 #elif defined(VGO_solaris) 475 PTH_FUNC(int, pthreadZucreate, // pthread_create 476 pthread_t *thread, const pthread_attr_t *attr, 477 void *(*start) (void *), void *arg) { 478 return pthread_create_WRK(thread, attr, start, arg); 479 } 480 #else 481 # error "Unsupported OS" 482 #endif 483 484 #if defined(VGO_solaris) 485 /* Solaris also provides thr_create() in addition to pthread_create(). 486 * Both pthread_create(3C) and thr_create(3C) are based on private 487 * _thrp_create(). 488 */ 489 __attribute__((noinline)) 490 static int thr_create_WRK(void *stk, size_t stksize, void *(*start)(void *), 491 void *arg, long flags, thread_t *new_thread) 492 { 493 int ret; 494 OrigFn fn; 495 volatile Word xargs[3]; 496 497 VALGRIND_GET_ORIG_FN(fn); 498 if (TRACE_PTH_FNS) { 499 fprintf(stderr, "<< thr_create wrapper"); fflush(stderr); 500 } 501 xargs[0] = (Word)start; 502 xargs[1] = (Word)arg; 503 xargs[2] = 1; /* serves as a spinlock -- sigh */ 504 /* See comments in pthread_create_WRK() */ 505 VALGRIND_HG_DISABLE_CHECKING(&xargs, sizeof(xargs)); 506 507 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_BEGIN, 508 0, 0, 0, 0, 0); 509 CALL_FN_W_6W(ret, fn, stk, stksize, mythread_wrapper, start, flags, 510 new_thread); 511 VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_END, 512 0, 0, 0, 0, 0); 513 514 if (ret == 0) { 515 while (xargs[2] != 0) { 516 /* See comments in pthread_create_WRK(). */ 517 sched_yield(); 518 } 519 } else { 520 DO_PthAPIerror("thr_create", ret); 521 } 522 523 VALGRIND_HG_ENABLE_CHECKING(&xargs, sizeof(xargs)); 524 525 if (TRACE_PTH_FNS) { 526 fprintf(stderr, " :: thr_create -> %d >>\n", ret); 527 } 528 return ret; 529 } 530 PTH_FUNC(int, thrZucreate, // thr_create 531 void *stk, size_t stksize, void *(*start)(void *), 532 void *arg, long flags, thread_t *new_thread) { 533 return thr_create_WRK(stk, stksize, start, arg, flags, new_thread); 534 } 535 #endif /* VGO_solaris */ 536 537 538 //----------------------------------------------------------- 539 // glibc: pthread_join 540 // darwin: pthread_join 541 // darwin: pthread_join$NOCANCEL$UNIX2003 542 // darwin pthread_join$UNIX2003 543 __attribute__((noinline)) 544 static int pthread_join_WRK(pthread_t thread, void** value_pointer) 545 { 546 int ret; 547 OrigFn fn; 548 VALGRIND_GET_ORIG_FN(fn); 549 if (TRACE_PTH_FNS) { 550 fprintf(stderr, "<< pthread_join wrapper"); fflush(stderr); 551 } 552 553 CALL_FN_W_WW(ret, fn, thread,value_pointer); 554 555 /* At least with NPTL as the thread library, this is safe because 556 it is guaranteed (by NPTL) that the joiner will completely gone 557 before pthread_join (the original) returns. See email below.*/ 558 if (ret == 0 /*success*/) { 559 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST, CREQ_PTHREAD_T, thread); 560 } else { 561 DO_PthAPIerror( "pthread_join", ret ); 562 } 563 564 if (TRACE_PTH_FNS) { 565 fprintf(stderr, " :: pth_join -> %d >>\n", ret); 566 } 567 return ret; 568 } 569 #if defined(VGO_linux) 570 PTH_FUNC(int, pthreadZujoin, // pthread_join 571 pthread_t thread, void** value_pointer) { 572 return pthread_join_WRK(thread, value_pointer); 573 } 574 #elif defined(VGO_darwin) 575 PTH_FUNC(int, pthreadZujoinZa, // pthread_join* 576 pthread_t thread, void** value_pointer) { 577 return pthread_join_WRK(thread, value_pointer); 578 } 579 #elif defined(VGO_solaris) 580 PTH_FUNC(int, pthreadZujoin, // pthread_join 581 pthread_t thread, void** value_pointer) { 582 return pthread_join_WRK(thread, value_pointer); 583 } 584 #else 585 # error "Unsupported OS" 586 #endif 587 588 589 /* Behaviour of pthread_join on NPTL: 590 591 Me: 592 I have a question re the NPTL pthread_join implementation. 593 594 Suppose I am the thread 'stayer'. 595 596 If I call pthread_join(quitter), is it guaranteed that the 597 thread 'quitter' has really exited before pthread_join returns? 598 599 IOW, is it guaranteed that 'quitter' will not execute any further 600 instructions after pthread_join returns? 601 602 I believe this is true based on the following analysis of 603 glibc-2.5 sources. However am not 100% sure and would appreciate 604 confirmation. 605 606 'quitter' will be running start_thread() in nptl/pthread_create.c 607 608 The last action of start_thread() is to exit via 609 __exit_thread_inline(0), which simply does sys_exit 610 (nptl/pthread_create.c:403) 611 612 'stayer' meanwhile is waiting for lll_wait_tid (pd->tid) 613 (call at nptl/pthread_join.c:89) 614 615 As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536, 616 lll_wait_tid will not return until kernel notifies via futex 617 wakeup that 'quitter' has terminated. 618 619 Hence pthread_join cannot return until 'quitter' really has 620 completely disappeared. 621 622 Drepper: 623 > As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536, 624 > lll_wait_tid will not return until kernel notifies via futex 625 > wakeup that 'quitter' has terminated. 626 That's the key. The kernel resets the TID field after the thread is 627 done. No way the joiner can return before the thread is gone. 628 */ 629 630 #if defined(VGO_solaris) 631 /* Solaris also provides thr_join() in addition to pthread_join(). 632 * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join(). 633 * 634 * :TODO: No functionality is currently provided for joinee == 0 and departed. 635 * This would require another client request, of course. 636 */ 637 __attribute__((noinline)) 638 static int thr_join_WRK(thread_t joinee, thread_t *departed, void **thread_return) 639 { 640 int ret; 641 OrigFn fn; 642 VALGRIND_GET_ORIG_FN(fn); 643 if (TRACE_PTH_FNS) { 644 fprintf(stderr, "<< thr_join wrapper"); fflush(stderr); 645 } 646 647 CALL_FN_W_WWW(ret, fn, joinee, departed, thread_return); 648 649 if (ret == 0 /*success*/) { 650 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST, CREQ_PTHREAD_T, joinee); 651 } else { 652 DO_PthAPIerror("thr_join", ret); 653 } 654 655 if (TRACE_PTH_FNS) { 656 fprintf(stderr, " :: thr_join -> %d >>\n", ret); 657 } 658 return ret; 659 } 660 PTH_FUNC(int, thrZujoin, // thr_join 661 thread_t joinee, thread_t *departed, void **thread_return) { 662 return thr_join_WRK(joinee, departed, thread_return); 663 } 664 #endif /* VGO_solaris */ 665 666 667 //----------------------------------------------------------- 668 // Ada gcc gnat runtime: 669 // The gnat gcc Ada runtime does not use pthread_join. Instead, it uses 670 // a combination of other pthread primitives to ensure a child thread 671 // is gone. This combination is somewhat functionally equivalent to a 672 // pthread_join. 673 // We wrap two hook procedures called by the gnat gcc Ada runtime 674 // that allows helgrind to understand the semantic of Ada task dependencies 675 // and termination. 676 677 // System.Tasking.Debug.Master_Hook is called by a task Dependent to 678 // indicate that its master is identified by master+master_level. 679 void I_WRAP_SONAME_FNNAME_ZU 680 (Za, 681 system__tasking__debug__master_hook) 682 (void *dependent, void *master, int master_level); 683 void I_WRAP_SONAME_FNNAME_ZU 684 (Za, 685 system__tasking__debug__master_hook) 686 (void *dependent, void *master, int master_level) 687 { 688 OrigFn fn; 689 VALGRIND_GET_ORIG_FN(fn); 690 if (TRACE_GNAT_FNS) { 691 fprintf(stderr, "<< GNAT master_hook wrapper " 692 "dependent %p master %p master_level %d\n", 693 dependent, master, master_level); fflush(stderr); 694 } 695 696 // We call the wrapped function, even if it is a null body. 697 CALL_FN_v_WWW(fn, dependent, master, master_level); 698 699 DO_CREQ_v_WWW(_VG_USERREQ__HG_GNAT_MASTER_HOOK, 700 void*,dependent, void*,master, 701 Word, (Word)master_level); 702 703 if (TRACE_GNAT_FNS) { 704 fprintf(stderr, " :: GNAT master_hook >>\n"); 705 } 706 } 707 708 // System.Tasking.Debug.Master_Completed_Hook is called by a task to 709 // indicate that it has completed a master. 710 // This indicates that all its Dependent tasks (that identified themselves 711 // with the Master_Hook call) are terminated. Helgrind can consider 712 // at this point that the equivalent of a 'pthread_join' has been done 713 // between self_id and all dependent tasks at master_level. 714 void I_WRAP_SONAME_FNNAME_ZU 715 (Za, 716 system__tasking__debug__master_completed_hook) 717 (void *self_id, int master_level); 718 void I_WRAP_SONAME_FNNAME_ZU 719 (Za, 720 system__tasking__debug__master_completed_hook) 721 (void *self_id, int master_level) 722 { 723 OrigFn fn; 724 VALGRIND_GET_ORIG_FN(fn); 725 if (TRACE_GNAT_FNS) { 726 fprintf(stderr, "<< GNAT master_completed_hook wrapper " 727 "self_id %p master_level %d\n", 728 self_id, master_level); fflush(stderr); 729 } 730 731 // We call the wrapped function, even if it is a null body. 732 CALL_FN_v_WW(fn, self_id, master_level); 733 734 DO_CREQ_v_WW(_VG_USERREQ__HG_GNAT_MASTER_COMPLETED_HOOK, 735 void*,self_id, Word,(Word)master_level); 736 737 if (TRACE_GNAT_FNS) { 738 fprintf(stderr, " :: GNAT master_completed_hook >>\n"); 739 } 740 } 741 742 /*----------------------------------------------------------------*/ 743 /*--- pthread_mutex_t functions ---*/ 744 /*----------------------------------------------------------------*/ 745 746 /* Handled: pthread_mutex_init pthread_mutex_destroy 747 pthread_mutex_lock 748 pthread_mutex_trylock pthread_mutex_timedlock 749 pthread_mutex_unlock 750 */ 751 752 //----------------------------------------------------------- 753 #if !defined(VGO_solaris) 754 // glibc: pthread_mutex_init 755 // darwin: pthread_mutex_init 756 PTH_FUNC(int, pthreadZumutexZuinit, // pthread_mutex_init 757 pthread_mutex_t *mutex, 758 pthread_mutexattr_t* attr) 759 { 760 int ret; 761 long mbRec; 762 OrigFn fn; 763 VALGRIND_GET_ORIG_FN(fn); 764 if (TRACE_PTH_FNS) { 765 fprintf(stderr, "<< pthread_mxinit %p", mutex); fflush(stderr); 766 } 767 768 mbRec = 0; 769 if (attr) { 770 int ty, zzz; 771 zzz = pthread_mutexattr_gettype(attr, &ty); 772 if (zzz == 0 && ty == PTHREAD_MUTEX_RECURSIVE) 773 mbRec = 1; 774 } 775 776 CALL_FN_W_WW(ret, fn, mutex,attr); 777 778 if (ret == 0 /*success*/) { 779 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST, 780 pthread_mutex_t*,mutex, long,mbRec); 781 } else { 782 DO_PthAPIerror( "pthread_mutex_init", ret ); 783 } 784 785 if (TRACE_PTH_FNS) { 786 fprintf(stderr, " :: mxinit -> %d >>\n", ret); 787 } 788 return ret; 789 } 790 791 #else /* VGO_solaris */ 792 793 // Solaris: mutex_init (pthread_mutex_init calls here) 794 PTH_FUNC(int, mutexZuinit, // mutex_init 795 mutex_t *mutex, int type, void *arg) 796 { 797 int ret; 798 long mbRec; 799 OrigFn fn; 800 VALGRIND_GET_ORIG_FN(fn); 801 if (TRACE_PTH_FNS) { 802 fprintf(stderr, "<< mxinit %p", mutex); fflush(stderr); 803 } 804 805 mbRec = ((type & LOCK_RECURSIVE) != 0) ? 1 : 0; 806 807 CALL_FN_W_WWW(ret, fn, mutex, type, arg); 808 809 if (ret == 0 /*success*/) { 810 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST, 811 mutex_t *, mutex, long, mbRec); 812 } else { 813 DO_PthAPIerror("mutex_init", ret); 814 } 815 816 if (TRACE_PTH_FNS) { 817 fprintf(stderr, " :: mxinit -> %d >>\n", ret); 818 } 819 return ret; 820 } 821 #endif /* VGO_solaris */ 822 823 824 //----------------------------------------------------------- 825 // glibc: pthread_mutex_destroy 826 // darwin: pthread_mutex_destroy 827 // Solaris: mutex_destroy (pthread_mutex_destroy is a weak alias) 828 __attribute__((noinline)) 829 static int mutex_destroy_WRK(pthread_mutex_t *mutex) 830 { 831 int ret; 832 unsigned long mutex_is_init; 833 OrigFn fn; 834 835 VALGRIND_GET_ORIG_FN(fn); 836 if (TRACE_PTH_FNS) { 837 fprintf(stderr, "<< pthread_mxdestroy %p", mutex); fflush(stderr); 838 } 839 840 if (mutex != NULL) { 841 static const pthread_mutex_t mutex_init = PTHREAD_MUTEX_INITIALIZER; 842 mutex_is_init = my_memcmp(mutex, &mutex_init, sizeof(*mutex)) == 0; 843 } else { 844 mutex_is_init = 0; 845 } 846 847 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE, 848 pthread_mutex_t*, mutex, unsigned long, mutex_is_init); 849 850 CALL_FN_W_W(ret, fn, mutex); 851 852 if (ret != 0) { 853 DO_PthAPIerror( "pthread_mutex_destroy", ret ); 854 } 855 856 if (TRACE_PTH_FNS) { 857 fprintf(stderr, " :: mxdestroy -> %d >>\n", ret); 858 } 859 return ret; 860 } 861 862 #if defined(VGO_linux) || defined(VGO_darwin) 863 PTH_FUNC(int, pthreadZumutexZudestroy, // pthread_mutex_destroy 864 pthread_mutex_t *mutex) { 865 return mutex_destroy_WRK(mutex); 866 } 867 #elif defined(VGO_solaris) 868 PTH_FUNC(int, mutexZudestroy, // mutex_destroy 869 pthread_mutex_t *mutex) { 870 return mutex_destroy_WRK(mutex); 871 } 872 #else 873 # error "Unsupported OS" 874 #endif 875 876 877 //----------------------------------------------------------- 878 // glibc: pthread_mutex_lock 879 // darwin: pthread_mutex_lock 880 // Solaris: mutex_lock (pthread_mutex_lock is a weak alias) 881 __attribute__((noinline)) 882 static int mutex_lock_WRK(pthread_mutex_t *mutex) 883 { 884 int ret; 885 OrigFn fn; 886 VALGRIND_GET_ORIG_FN(fn); 887 if (TRACE_PTH_FNS) { 888 fprintf(stderr, "<< pthread_mxlock %p", mutex); fflush(stderr); 889 } 890 891 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE, 892 pthread_mutex_t*,mutex, long,0/*!isTryLock*/); 893 894 CALL_FN_W_W(ret, fn, mutex); 895 896 /* There's a hole here: libpthread now knows the lock is locked, 897 but the tool doesn't, so some other thread could run and detect 898 that the lock has been acquired by someone (this thread). Does 899 this matter? Not sure, but I don't think so. */ 900 901 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST, 902 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False); 903 904 if (ret != 0) { 905 DO_PthAPIerror( "pthread_mutex_lock", ret ); 906 } 907 908 if (TRACE_PTH_FNS) { 909 fprintf(stderr, " :: mxlock -> %d >>\n", ret); 910 } 911 return ret; 912 } 913 914 #if defined(VGO_linux) || defined(VGO_darwin) 915 PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock 916 pthread_mutex_t *mutex) { 917 return mutex_lock_WRK(mutex); 918 } 919 #elif defined(VGO_solaris) 920 PTH_FUNC(int, mutexZulock, // mutex_lock 921 pthread_mutex_t *mutex) { 922 return mutex_lock_WRK(mutex); 923 } 924 #else 925 # error "Unsupported OS" 926 #endif 927 928 #if defined(VGO_solaris) 929 /* Internal to libc. Mutex is usually initialized only implicitly, 930 * by zeroing mutex_t structure. 931 */ 932 __attribute__((noinline)) 933 PTH_FUNC(void, lmutexZulock, // lmutex_lock 934 mutex_t *mutex) 935 { 936 OrigFn fn; 937 VALGRIND_GET_ORIG_FN(fn); 938 if (TRACE_PTH_FNS) { 939 fprintf(stderr, "<< lmxlock %p", mutex); fflush(stderr); 940 } 941 942 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE, 943 mutex_t *, mutex, long, 0 /*!isTryLock*/); 944 CALL_FN_v_W(fn, mutex); 945 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST, 946 mutex_t *, mutex, long, True); 947 948 if (TRACE_PTH_FNS) { 949 fprintf(stderr, " :: lmxlock >>\n"); 950 } 951 } 952 #endif /* VGO_solaris */ 953 954 955 //----------------------------------------------------------- 956 // glibc: pthread_mutex_trylock 957 // darwin: pthread_mutex_trylock 958 // Solaris: mutex_trylock (pthread_mutex_trylock is a weak alias) 959 // 960 // pthread_mutex_trylock. The handling needed here is very similar 961 // to that for pthread_mutex_lock, except that we need to tell 962 // the pre-lock creq that this is a trylock-style operation, and 963 // therefore not to complain if the lock is nonrecursive and 964 // already locked by this thread -- because then it'll just fail 965 // immediately with EBUSY. 966 __attribute__((noinline)) 967 static int mutex_trylock_WRK(pthread_mutex_t *mutex) 968 { 969 int ret; 970 OrigFn fn; 971 VALGRIND_GET_ORIG_FN(fn); 972 if (TRACE_PTH_FNS) { 973 fprintf(stderr, "<< pthread_mxtrylock %p", mutex); fflush(stderr); 974 } 975 976 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE, 977 pthread_mutex_t*,mutex, long,1/*isTryLock*/); 978 979 CALL_FN_W_W(ret, fn, mutex); 980 981 /* There's a hole here: libpthread now knows the lock is locked, 982 but the tool doesn't, so some other thread could run and detect 983 that the lock has been acquired by someone (this thread). Does 984 this matter? Not sure, but I don't think so. */ 985 986 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST, 987 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False); 988 989 if (ret != 0) { 990 if (ret != EBUSY) 991 DO_PthAPIerror( "pthread_mutex_trylock", ret ); 992 } 993 994 if (TRACE_PTH_FNS) { 995 fprintf(stderr, " :: mxtrylock -> %d >>\n", ret); 996 } 997 return ret; 998 } 999 1000 #if defined(VGO_linux) || defined(VGO_darwin) 1001 PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock 1002 pthread_mutex_t *mutex) { 1003 return mutex_trylock_WRK(mutex); 1004 } 1005 #elif defined(VGO_solaris) 1006 PTH_FUNC(int, mutexZutrylock, // mutex_trylock 1007 pthread_mutex_t *mutex) { 1008 return mutex_trylock_WRK(mutex); 1009 } 1010 #else 1011 # error "Unsupported OS" 1012 #endif 1013 1014 1015 //----------------------------------------------------------- 1016 // glibc: pthread_mutex_timedlock 1017 // darwin: (doesn't appear to exist) 1018 // Solaris: pthread_mutex_timedlock 1019 // 1020 // pthread_mutex_timedlock. Identical logic to pthread_mutex_trylock. 1021 __attribute__((noinline)) 1022 static int mutex_timedlock_WRK(pthread_mutex_t *mutex, 1023 void *timeout) 1024 { 1025 int ret; 1026 OrigFn fn; 1027 VALGRIND_GET_ORIG_FN(fn); 1028 if (TRACE_PTH_FNS) { 1029 fprintf(stderr, "<< pthread_mxtimedlock %p %p", mutex, timeout); 1030 fflush(stderr); 1031 } 1032 1033 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE, 1034 pthread_mutex_t*,mutex, long,1/*isTryLock-ish*/); 1035 1036 CALL_FN_W_WW(ret, fn, mutex,timeout); 1037 1038 /* There's a hole here: libpthread now knows the lock is locked, 1039 but the tool doesn't, so some other thread could run and detect 1040 that the lock has been acquired by someone (this thread). Does 1041 this matter? Not sure, but I don't think so. */ 1042 1043 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST, 1044 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False); 1045 1046 if (ret != 0) { 1047 if (ret != ETIMEDOUT) 1048 DO_PthAPIerror( "pthread_mutex_timedlock", ret ); 1049 } 1050 1051 if (TRACE_PTH_FNS) { 1052 fprintf(stderr, " :: mxtimedlock -> %d >>\n", ret); 1053 } 1054 return ret; 1055 } 1056 1057 PTH_FUNC(int, pthreadZumutexZutimedlock, // pthread_mutex_timedlock 1058 pthread_mutex_t *mutex, 1059 void *timeout) { 1060 return mutex_timedlock_WRK(mutex, timeout); 1061 } 1062 #if defined(VGO_solaris) 1063 PTH_FUNC(int, pthreadZumutexZureltimedlock, // pthread_mutex_reltimedlock 1064 pthread_mutex_t *mutex, 1065 void *timeout) { 1066 return mutex_timedlock_WRK(mutex, timeout); 1067 } 1068 #endif 1069 1070 1071 //----------------------------------------------------------- 1072 // glibc: pthread_mutex_unlock 1073 // darwin: pthread_mutex_unlock 1074 // Solaris: mutex_unlock (pthread_mutex_unlock is a weak alias) 1075 __attribute__((noinline)) 1076 static int mutex_unlock_WRK(pthread_mutex_t *mutex) 1077 { 1078 int ret; 1079 OrigFn fn; 1080 VALGRIND_GET_ORIG_FN(fn); 1081 1082 if (TRACE_PTH_FNS) { 1083 fprintf(stderr, "<< pthread_mxunlk %p", mutex); fflush(stderr); 1084 } 1085 1086 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE, 1087 pthread_mutex_t*,mutex); 1088 1089 CALL_FN_W_W(ret, fn, mutex); 1090 1091 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST, 1092 pthread_mutex_t*,mutex); 1093 1094 if (ret != 0) { 1095 DO_PthAPIerror( "pthread_mutex_unlock", ret ); 1096 } 1097 1098 if (TRACE_PTH_FNS) { 1099 fprintf(stderr, " mxunlk -> %d >>\n", ret); 1100 } 1101 return ret; 1102 } 1103 1104 #if defined(VGO_linux) || defined(VGO_darwin) 1105 PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock 1106 pthread_mutex_t *mutex) { 1107 return mutex_unlock_WRK(mutex); 1108 } 1109 #elif defined(VGO_solaris) 1110 PTH_FUNC(int, mutexZuunlock, // mutex_unlock 1111 pthread_mutex_t *mutex) { 1112 return mutex_unlock_WRK(mutex); 1113 } 1114 #else 1115 # error "Unsupported OS" 1116 #endif 1117 1118 1119 #if defined(VGO_solaris) 1120 /* Internal to libc. */ 1121 __attribute__((noinline)) 1122 PTH_FUNC(void, lmutexZuunlock, // lmutex_unlock 1123 mutex_t *mutex) 1124 { 1125 OrigFn fn; 1126 VALGRIND_GET_ORIG_FN(fn); 1127 1128 if (TRACE_PTH_FNS) { 1129 fprintf(stderr, "<< lmxunlk %p", mutex); fflush(stderr); 1130 } 1131 1132 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE, 1133 mutex_t *, mutex); 1134 CALL_FN_v_W(fn, mutex); 1135 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST, 1136 mutex_t*, mutex); 1137 1138 if (TRACE_PTH_FNS) { 1139 fprintf(stderr, " lmxunlk >>\n"); 1140 } 1141 } 1142 #endif /* VGO_solaris */ 1143 1144 1145 /*----------------------------------------------------------------*/ 1146 /*--- pthread_cond_t functions ---*/ 1147 /*----------------------------------------------------------------*/ 1148 1149 /* Handled: pthread_cond_wait pthread_cond_timedwait 1150 pthread_cond_signal pthread_cond_broadcast 1151 pthread_cond_init 1152 pthread_cond_destroy 1153 */ 1154 1155 //----------------------------------------------------------- 1156 // glibc: pthread_cond_wait (at) GLIBC_2.2.5 1157 // glibc: pthread_cond_wait@@GLIBC_2.3.2 1158 // darwin: pthread_cond_wait 1159 // darwin: pthread_cond_wait$NOCANCEL$UNIX2003 1160 // darwin: pthread_cond_wait$UNIX2003 1161 // Solaris: cond_wait (pthread_cond_wait is built atop of cond_wait) 1162 // 1163 __attribute__((noinline)) 1164 static int pthread_cond_wait_WRK(pthread_cond_t* cond, 1165 pthread_mutex_t* mutex) 1166 { 1167 int ret; 1168 OrigFn fn; 1169 unsigned long mutex_is_valid; 1170 1171 VALGRIND_GET_ORIG_FN(fn); 1172 1173 if (TRACE_PTH_FNS) { 1174 fprintf(stderr, "<< pthread_cond_wait %p %p", cond, mutex); 1175 fflush(stderr); 1176 } 1177 1178 /* Tell the tool a cond-wait is about to happen, so it can check 1179 for bogus argument values. In return it tells us whether it 1180 thinks the mutex is valid or not. */ 1181 DO_CREQ_W_WW(mutex_is_valid, 1182 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE, 1183 pthread_cond_t*,cond, pthread_mutex_t*,mutex); 1184 assert(mutex_is_valid == 1 || mutex_is_valid == 0); 1185 1186 /* Tell the tool we're about to drop the mutex. This reflects the 1187 fact that in a cond_wait, we show up holding the mutex, and the 1188 call atomically drops the mutex and waits for the cv to be 1189 signalled. */ 1190 if (mutex_is_valid) { 1191 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE, 1192 pthread_mutex_t*,mutex); 1193 } 1194 1195 CALL_FN_W_WW(ret, fn, cond,mutex); 1196 1197 /* this conditional look stupid, but compare w/ same logic for 1198 pthread_cond_timedwait below */ 1199 if (mutex_is_valid) { 1200 /* and now we have the mutex again if (ret == 0) */ 1201 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST, 1202 pthread_mutex_t *, mutex, long, (ret == 0) ? True : False); 1203 } 1204 1205 DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST, 1206 pthread_cond_t*,cond, pthread_mutex_t*,mutex, long,0, 1207 long, (ret == 0 && mutex_is_valid) ? True : False); 1208 1209 if (ret != 0) { 1210 DO_PthAPIerror( "pthread_cond_wait", ret ); 1211 } 1212 1213 if (TRACE_PTH_FNS) { 1214 fprintf(stderr, " cowait -> %d >>\n", ret); 1215 } 1216 1217 return ret; 1218 } 1219 #if defined(VGO_linux) 1220 PTH_FUNC(int, pthreadZucondZuwaitZAZa, // pthread_cond_wait@* 1221 pthread_cond_t* cond, pthread_mutex_t* mutex) { 1222 return pthread_cond_wait_WRK(cond, mutex); 1223 } 1224 #elif defined(VGO_darwin) 1225 PTH_FUNC(int, pthreadZucondZuwaitZa, // pthread_cond_wait* 1226 pthread_cond_t* cond, pthread_mutex_t* mutex) { 1227 return pthread_cond_wait_WRK(cond, mutex); 1228 } 1229 #elif defined(VGO_solaris) 1230 PTH_FUNC(int, condZuwait, // cond_wait 1231 pthread_cond_t *cond, pthread_mutex_t *mutex) { 1232 return pthread_cond_wait_WRK(cond, mutex); 1233 } 1234 #else 1235 # error "Unsupported OS" 1236 #endif 1237 1238 1239 //----------------------------------------------------------- 1240 // glibc: pthread_cond_timedwait@@GLIBC_2.3.2 1241 // glibc: pthread_cond_timedwait (at) GLIBC_2.2.5 1242 // glibc: pthread_cond_timedwait (at) GLIBC_2.0 1243 // darwin: pthread_cond_timedwait 1244 // darwin: pthread_cond_timedwait$NOCANCEL$UNIX2003 1245 // darwin: pthread_cond_timedwait$UNIX2003 1246 // darwin: pthread_cond_timedwait_relative_np (trapped) 1247 // Solaris: cond_timedwait (pthread_cond_timedwait is built on cond_timedwait) 1248 // Solaris: cond_reltimedwait (pthread_cond_reltimedwait_np is built on this) 1249 // 1250 __attribute__((noinline)) 1251 static int pthread_cond_timedwait_WRK(pthread_cond_t* cond, 1252 pthread_mutex_t* mutex, 1253 struct timespec* abstime, 1254 int timeout_error) 1255 { 1256 int ret; 1257 OrigFn fn; 1258 unsigned long mutex_is_valid; 1259 Bool abstime_is_valid; 1260 VALGRIND_GET_ORIG_FN(fn); 1261 1262 if (TRACE_PTH_FNS) { 1263 fprintf(stderr, "<< pthread_cond_timedwait %p %p %p", 1264 cond, mutex, abstime); 1265 fflush(stderr); 1266 } 1267 1268 /* Tell the tool a cond-wait is about to happen, so it can check 1269 for bogus argument values. In return it tells us whether it 1270 thinks the mutex is valid or not. */ 1271 DO_CREQ_W_WW(mutex_is_valid, 1272 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE, 1273 pthread_cond_t*,cond, pthread_mutex_t*,mutex); 1274 assert(mutex_is_valid == 1 || mutex_is_valid == 0); 1275 1276 abstime_is_valid = abstime->tv_nsec >= 0 && abstime->tv_nsec < 1000000000; 1277 1278 /* Tell the tool we're about to drop the mutex. This reflects the 1279 fact that in a cond_wait, we show up holding the mutex, and the 1280 call atomically drops the mutex and waits for the cv to be 1281 signalled. */ 1282 if (mutex_is_valid && abstime_is_valid) { 1283 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE, 1284 pthread_mutex_t*,mutex); 1285 } 1286 1287 CALL_FN_W_WWW(ret, fn, cond,mutex,abstime); 1288 1289 if (mutex_is_valid && !abstime_is_valid && ret != EINVAL) { 1290 DO_PthAPIerror("Bug in libpthread: pthread_cond_timedwait " 1291 "invalid abstime did not cause" 1292 " EINVAL", ret); 1293 } 1294 1295 if (mutex_is_valid && abstime_is_valid) { 1296 /* and now we have the mutex again if (ret == 0 || ret == timeout) */ 1297 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST, 1298 pthread_mutex_t *, mutex, 1299 long, (ret == 0 || ret == timeout_error) ? True : False); 1300 } 1301 1302 DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST, 1303 pthread_cond_t*,cond, pthread_mutex_t*,mutex, 1304 long,ret == timeout_error, 1305 long, (ret == 0 || ret == timeout_error) && mutex_is_valid 1306 ? True : False); 1307 1308 if (ret != 0 && ret != timeout_error) { 1309 DO_PthAPIerror( "pthread_cond_timedwait", ret ); 1310 } 1311 1312 if (TRACE_PTH_FNS) { 1313 fprintf(stderr, " cotimedwait -> %d >>\n", ret); 1314 } 1315 1316 return ret; 1317 } 1318 #if defined(VGO_linux) 1319 PTH_FUNC(int, pthreadZucondZutimedwaitZAZa, // pthread_cond_timedwait@* 1320 pthread_cond_t* cond, pthread_mutex_t* mutex, 1321 struct timespec* abstime) { 1322 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT); 1323 } 1324 #elif defined(VGO_darwin) 1325 PTH_FUNC(int, pthreadZucondZutimedwait, // pthread_cond_timedwait 1326 pthread_cond_t* cond, pthread_mutex_t* mutex, 1327 struct timespec* abstime) { 1328 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT); 1329 } 1330 PTH_FUNC(int, pthreadZucondZutimedwaitZDZa, // pthread_cond_timedwait$* 1331 pthread_cond_t* cond, pthread_mutex_t* mutex, 1332 struct timespec* abstime) { 1333 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT); 1334 } 1335 PTH_FUNC(int, pthreadZucondZutimedwaitZuZa, // pthread_cond_timedwait_* 1336 pthread_cond_t* cond, pthread_mutex_t* mutex, 1337 struct timespec* abstime) { 1338 assert(0); 1339 } 1340 #elif defined(VGO_solaris) 1341 PTH_FUNC(int, condZutimedwait, // cond_timedwait 1342 pthread_cond_t *cond, pthread_mutex_t *mutex, 1343 struct timespec *abstime) { 1344 return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIME); 1345 } 1346 PTH_FUNC(int, condZureltimedwait, // cond_reltimedwait 1347 pthread_cond_t *cond, pthread_mutex_t *mutex, 1348 struct timespec *reltime) { 1349 return pthread_cond_timedwait_WRK(cond, mutex, reltime, ETIME); 1350 } 1351 #else 1352 # error "Unsupported OS" 1353 #endif 1354 1355 1356 //----------------------------------------------------------- 1357 // glibc: pthread_cond_signal (at) GLIBC_2.0 1358 // glibc: pthread_cond_signal (at) GLIBC_2.2.5 1359 // glibc: pthread_cond_signal@@GLIBC_2.3.2 1360 // darwin: pthread_cond_signal 1361 // darwin: pthread_cond_signal_thread_np (don't intercept this) 1362 // Solaris: cond_signal (pthread_cond_signal is a weak alias) 1363 // 1364 __attribute__((noinline)) 1365 static int pthread_cond_signal_WRK(pthread_cond_t* cond) 1366 { 1367 int ret; 1368 OrigFn fn; 1369 VALGRIND_GET_ORIG_FN(fn); 1370 1371 if (TRACE_PTH_FNS) { 1372 fprintf(stderr, "<< pthread_cond_signal %p", cond); 1373 fflush(stderr); 1374 } 1375 1376 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE, 1377 pthread_cond_t*,cond); 1378 1379 CALL_FN_W_W(ret, fn, cond); 1380 1381 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_POST, 1382 pthread_cond_t*,cond); 1383 1384 if (ret != 0) { 1385 DO_PthAPIerror( "pthread_cond_signal", ret ); 1386 } 1387 1388 if (TRACE_PTH_FNS) { 1389 fprintf(stderr, " cosig -> %d >>\n", ret); 1390 } 1391 1392 return ret; 1393 } 1394 #if defined(VGO_linux) 1395 PTH_FUNC(int, pthreadZucondZusignalZAZa, // pthread_cond_signal@* 1396 pthread_cond_t* cond) { 1397 return pthread_cond_signal_WRK(cond); 1398 } 1399 #elif defined(VGO_darwin) 1400 PTH_FUNC(int, pthreadZucondZusignal, // pthread_cond_signal 1401 pthread_cond_t* cond) { 1402 return pthread_cond_signal_WRK(cond); 1403 } 1404 #elif defined(VGO_solaris) 1405 PTH_FUNC(int, condZusignal, // cond_signal 1406 pthread_cond_t *cond) { 1407 return pthread_cond_signal_WRK(cond); 1408 } 1409 #else 1410 # error "Unsupported OS" 1411 #endif 1412 1413 1414 //----------------------------------------------------------- 1415 // glibc: pthread_cond_broadcast (at) GLIBC_2.0 1416 // glibc: pthread_cond_broadcast (at) GLIBC_2.2.5 1417 // glibc: pthread_cond_broadcast@@GLIBC_2.3.2 1418 // darwin: pthread_cond_broadcast 1419 // Solaris: cond_broadcast (pthread_cond_broadcast is a weak alias) 1420 // 1421 // Note, this is pretty much identical, from a dependency-graph 1422 // point of view, with cond_signal, so the code is duplicated. 1423 // Maybe it should be commoned up. 1424 // 1425 __attribute__((noinline)) 1426 static int pthread_cond_broadcast_WRK(pthread_cond_t* cond) 1427 { 1428 int ret; 1429 OrigFn fn; 1430 VALGRIND_GET_ORIG_FN(fn); 1431 1432 if (TRACE_PTH_FNS) { 1433 fprintf(stderr, "<< pthread_cond_broadcast %p", cond); 1434 fflush(stderr); 1435 } 1436 1437 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE, 1438 pthread_cond_t*,cond); 1439 1440 CALL_FN_W_W(ret, fn, cond); 1441 1442 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_POST, 1443 pthread_cond_t*,cond); 1444 1445 if (ret != 0) { 1446 DO_PthAPIerror( "pthread_cond_broadcast", ret ); 1447 } 1448 1449 if (TRACE_PTH_FNS) { 1450 fprintf(stderr, " cobro -> %d >>\n", ret); 1451 } 1452 1453 return ret; 1454 } 1455 #if defined(VGO_linux) 1456 PTH_FUNC(int, pthreadZucondZubroadcastZAZa, // pthread_cond_broadcast@* 1457 pthread_cond_t* cond) { 1458 return pthread_cond_broadcast_WRK(cond); 1459 } 1460 #elif defined(VGO_darwin) 1461 PTH_FUNC(int, pthreadZucondZubroadcast, // pthread_cond_broadcast 1462 pthread_cond_t* cond) { 1463 return pthread_cond_broadcast_WRK(cond); 1464 } 1465 #elif defined(VGO_solaris) 1466 PTH_FUNC(int, condZubroadcast, // cond_broadcast 1467 pthread_cond_t *cond) { 1468 return pthread_cond_broadcast_WRK(cond); 1469 } 1470 #else 1471 # error "Unsupported OS" 1472 #endif 1473 1474 // glibc: pthread_cond_init (at) GLIBC_2.0 1475 // glibc: pthread_cond_init (at) GLIBC_2.2.5 1476 // glibc: pthread_cond_init@@GLIBC_2.3.2 1477 // darwin: pthread_cond_init 1478 // Solaris: cond_init (pthread_cond_init is built atop on this function) 1479 // Easy way out: Handling of attr could have been messier. 1480 // It turns out that pthread_cond_init under linux ignores 1481 // all information in cond_attr, so do we. 1482 // FIXME: MacOS X? 1483 #if !defined(VGO_solaris) 1484 __attribute__((noinline)) 1485 static int pthread_cond_init_WRK(pthread_cond_t* cond, pthread_condattr_t *cond_attr) 1486 { 1487 int ret; 1488 OrigFn fn; 1489 VALGRIND_GET_ORIG_FN(fn); 1490 1491 if (TRACE_PTH_FNS) { 1492 fprintf(stderr, "<< pthread_cond_init %p", cond); 1493 fflush(stderr); 1494 } 1495 1496 CALL_FN_W_WW(ret, fn, cond, cond_attr); 1497 1498 if (ret == 0) { 1499 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST, 1500 pthread_cond_t*,cond, pthread_condattr_t*, cond_attr); 1501 } else { 1502 DO_PthAPIerror( "pthread_cond_init", ret ); 1503 } 1504 1505 if (TRACE_PTH_FNS) { 1506 fprintf(stderr, " coinit -> %d >>\n", ret); 1507 } 1508 1509 return ret; 1510 } 1511 #if defined(VGO_linux) 1512 PTH_FUNC(int, pthreadZucondZuinitZAZa, // pthread_cond_init@* 1513 pthread_cond_t* cond, pthread_condattr_t* cond_attr) { 1514 return pthread_cond_init_WRK(cond, cond_attr); 1515 } 1516 #elif defined(VGO_darwin) 1517 PTH_FUNC(int, pthreadZucondZuinit, // pthread_cond_init 1518 pthread_cond_t* cond, pthread_condattr_t * cond_attr) { 1519 return pthread_cond_init_WRK(cond, cond_attr); 1520 } 1521 #else 1522 # error "Unsupported OS" 1523 #endif 1524 1525 #else /* VGO_solaris */ 1526 __attribute__((noinline)) 1527 PTH_FUNC(int, condZuinit, // cond_init 1528 cond_t *cond, int type, void *arg) 1529 { 1530 int ret; 1531 OrigFn fn; 1532 VALGRIND_GET_ORIG_FN(fn); 1533 1534 if (TRACE_PTH_FNS) { 1535 fprintf(stderr, "<< cond_init %p", cond); fflush(stderr); 1536 } 1537 1538 CALL_FN_W_WWW(ret, fn, cond, type, arg); 1539 1540 if (ret == 0) { 1541 /* Luckily evh__HG_PTHREAD_COND_INIT_POST() ignores cond_attr. 1542 See also comment for pthread_cond_init_WRK(). */ 1543 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST, 1544 cond_t *, cond, void *, NULL); 1545 } else { 1546 DO_PthAPIerror("cond_init", ret); 1547 } 1548 1549 if (TRACE_PTH_FNS) { 1550 fprintf(stderr, " cond_init -> %d >>\n", ret); 1551 } 1552 1553 return ret; 1554 } 1555 #endif /* VGO_solaris */ 1556 1557 1558 //----------------------------------------------------------- 1559 // glibc: pthread_cond_destroy@@GLIBC_2.3.2 1560 // glibc: pthread_cond_destroy (at) GLIBC_2.2.5 1561 // glibc: pthread_cond_destroy (at) GLIBC_2.0 1562 // darwin: pthread_cond_destroy 1563 // Solaris: cond_destroy (pthread_cond_destroy is a weak alias) 1564 // 1565 __attribute__((noinline)) 1566 static int pthread_cond_destroy_WRK(pthread_cond_t* cond) 1567 { 1568 int ret; 1569 unsigned long cond_is_init; 1570 OrigFn fn; 1571 1572 VALGRIND_GET_ORIG_FN(fn); 1573 1574 if (TRACE_PTH_FNS) { 1575 fprintf(stderr, "<< pthread_cond_destroy %p", cond); 1576 fflush(stderr); 1577 } 1578 1579 if (cond != NULL) { 1580 const pthread_cond_t cond_init = PTHREAD_COND_INITIALIZER; 1581 cond_is_init = my_memcmp(cond, &cond_init, sizeof(*cond)) == 0; 1582 } else { 1583 cond_is_init = 0; 1584 } 1585 1586 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_DESTROY_PRE, 1587 pthread_cond_t*, cond, unsigned long, cond_is_init); 1588 1589 CALL_FN_W_W(ret, fn, cond); 1590 1591 if (ret != 0) { 1592 DO_PthAPIerror( "pthread_cond_destroy", ret ); 1593 } 1594 1595 if (TRACE_PTH_FNS) { 1596 fprintf(stderr, " codestr -> %d >>\n", ret); 1597 } 1598 1599 return ret; 1600 } 1601 #if defined(VGO_linux) 1602 PTH_FUNC(int, pthreadZucondZudestroyZAZa, // pthread_cond_destroy@* 1603 pthread_cond_t* cond) { 1604 return pthread_cond_destroy_WRK(cond); 1605 } 1606 #elif defined(VGO_darwin) 1607 PTH_FUNC(int, pthreadZucondZudestroy, // pthread_cond_destroy 1608 pthread_cond_t* cond) { 1609 return pthread_cond_destroy_WRK(cond); 1610 } 1611 #elif defined(VGO_solaris) 1612 PTH_FUNC(int, condZudestroy, // cond_destroy 1613 pthread_cond_t *cond) { 1614 return pthread_cond_destroy_WRK(cond); 1615 } 1616 #else 1617 # error "Unsupported OS" 1618 #endif 1619 1620 1621 /*----------------------------------------------------------------*/ 1622 /*--- pthread_barrier_t functions ---*/ 1623 /*----------------------------------------------------------------*/ 1624 1625 #if defined(HAVE_PTHREAD_BARRIER_INIT) 1626 1627 /* Handled: pthread_barrier_init 1628 pthread_barrier_wait 1629 pthread_barrier_destroy 1630 1631 Unhandled: pthread_barrierattr_destroy 1632 pthread_barrierattr_getpshared 1633 pthread_barrierattr_init 1634 pthread_barrierattr_setpshared 1635 -- are these important? 1636 */ 1637 1638 //----------------------------------------------------------- 1639 // glibc: pthread_barrier_init 1640 // darwin: (doesn't appear to exist) 1641 // Solaris: pthread_barrier_init 1642 PTH_FUNC(int, pthreadZubarrierZuinit, // pthread_barrier_init 1643 pthread_barrier_t* bar, 1644 pthread_barrierattr_t* attr, unsigned long count) 1645 { 1646 int ret; 1647 OrigFn fn; 1648 VALGRIND_GET_ORIG_FN(fn); 1649 1650 if (TRACE_PTH_FNS) { 1651 fprintf(stderr, "<< pthread_barrier_init %p %p %lu", 1652 bar, attr, count); 1653 fflush(stderr); 1654 } 1655 1656 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE, 1657 pthread_barrier_t*, bar, 1658 unsigned long, count, 1659 unsigned long, 0/*!resizable*/); 1660 1661 CALL_FN_W_WWW(ret, fn, bar,attr,count); 1662 1663 if (ret != 0) { 1664 DO_PthAPIerror( "pthread_barrier_init", ret ); 1665 } 1666 1667 if (TRACE_PTH_FNS) { 1668 fprintf(stderr, " pthread_barrier_init -> %d >>\n", ret); 1669 } 1670 1671 return ret; 1672 } 1673 1674 1675 //----------------------------------------------------------- 1676 // glibc: pthread_barrier_wait 1677 // darwin: (doesn't appear to exist) 1678 // Solaris: pthread_barrier_wait 1679 PTH_FUNC(int, pthreadZubarrierZuwait, // pthread_barrier_wait 1680 pthread_barrier_t* bar) 1681 { 1682 int ret; 1683 OrigFn fn; 1684 VALGRIND_GET_ORIG_FN(fn); 1685 1686 if (TRACE_PTH_FNS) { 1687 fprintf(stderr, "<< pthread_barrier_wait %p", bar); 1688 fflush(stderr); 1689 } 1690 1691 /* That this works correctly, and doesn't screw up when a thread 1692 leaving the barrier races round to the front and re-enters while 1693 other threads are still leaving it, is quite subtle. See 1694 comments in the handler for PTHREAD_BARRIER_WAIT_PRE in 1695 hg_main.c. */ 1696 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE, 1697 pthread_barrier_t*,bar); 1698 1699 CALL_FN_W_W(ret, fn, bar); 1700 1701 if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) { 1702 DO_PthAPIerror( "pthread_barrier_wait", ret ); 1703 } 1704 1705 if (TRACE_PTH_FNS) { 1706 fprintf(stderr, " pthread_barrier_wait -> %d >>\n", ret); 1707 } 1708 1709 return ret; 1710 } 1711 1712 1713 //----------------------------------------------------------- 1714 // glibc: pthread_barrier_destroy 1715 // darwin: (doesn't appear to exist) 1716 // Solaris: pthread_barrier_destroy 1717 PTH_FUNC(int, pthreadZubarrierZudestroy, // pthread_barrier_destroy 1718 pthread_barrier_t* bar) 1719 { 1720 int ret; 1721 OrigFn fn; 1722 VALGRIND_GET_ORIG_FN(fn); 1723 1724 if (TRACE_PTH_FNS) { 1725 fprintf(stderr, "<< pthread_barrier_destroy %p", bar); 1726 fflush(stderr); 1727 } 1728 1729 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE, 1730 pthread_barrier_t*,bar); 1731 1732 CALL_FN_W_W(ret, fn, bar); 1733 1734 if (ret != 0) { 1735 DO_PthAPIerror( "pthread_barrier_destroy", ret ); 1736 } 1737 1738 if (TRACE_PTH_FNS) { 1739 fprintf(stderr, " pthread_barrier_destroy -> %d >>\n", ret); 1740 } 1741 1742 return ret; 1743 } 1744 1745 #endif // defined(HAVE_PTHREAD_BARRIER_INIT) 1746 1747 1748 /*----------------------------------------------------------------*/ 1749 /*--- pthread_spinlock_t functions ---*/ 1750 /*----------------------------------------------------------------*/ 1751 1752 #if defined(HAVE_PTHREAD_SPIN_LOCK) \ 1753 && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT) 1754 1755 /* Handled: pthread_spin_init pthread_spin_destroy 1756 pthread_spin_lock pthread_spin_trylock 1757 pthread_spin_unlock 1758 1759 Unhandled: 1760 */ 1761 1762 /* This is a nasty kludge, in that glibc "knows" that initialising a 1763 spin lock unlocks it, and pthread_spin_{init,unlock} are names for 1764 the same function. Hence we have to have a wrapper which does both 1765 things, without knowing which the user intended to happen. 1766 Solaris has distinct functions for init/unlock but client requests 1767 are immutable in helgrind.h so follow the glibc lead. */ 1768 1769 //----------------------------------------------------------- 1770 // glibc: pthread_spin_init 1771 // glibc: pthread_spin_unlock 1772 // darwin: (doesn't appear to exist) 1773 // Solaris: pthread_spin_init 1774 // Solaris: pthread_spin_unlock 1775 __attribute__((noinline)) 1776 static int pthread_spin_init_or_unlock_WRK(pthread_spinlock_t* lock, 1777 int pshared) { 1778 int ret; 1779 OrigFn fn; 1780 VALGRIND_GET_ORIG_FN(fn); 1781 if (TRACE_PTH_FNS) { 1782 fprintf(stderr, "<< pthread_spin_iORu %p", lock); fflush(stderr); 1783 } 1784 1785 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE, 1786 pthread_spinlock_t*, lock); 1787 1788 CALL_FN_W_WW(ret, fn, lock,pshared); 1789 1790 if (ret == 0 /*success*/) { 1791 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST, 1792 pthread_spinlock_t*,lock); 1793 } else { 1794 DO_PthAPIerror( "pthread_spinlock_{init,unlock}", ret ); 1795 } 1796 1797 if (TRACE_PTH_FNS) { 1798 fprintf(stderr, " :: spiniORu -> %d >>\n", ret); 1799 } 1800 return ret; 1801 } 1802 #if defined(VGO_linux) 1803 PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init 1804 pthread_spinlock_t* lock, int pshared) { 1805 return pthread_spin_init_or_unlock_WRK(lock, pshared); 1806 } 1807 PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock 1808 pthread_spinlock_t* lock) { 1809 /* this is never actually called */ 1810 return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/); 1811 } 1812 #elif defined(VGO_darwin) 1813 #elif defined(VGO_solaris) 1814 PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init 1815 pthread_spinlock_t *lock, int pshared) { 1816 return pthread_spin_init_or_unlock_WRK(lock, pshared); 1817 } 1818 PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock 1819 pthread_spinlock_t *lock) { 1820 return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/); 1821 } 1822 #else 1823 # error "Unsupported OS" 1824 #endif 1825 1826 1827 //----------------------------------------------------------- 1828 // glibc: pthread_spin_destroy 1829 // darwin: (doesn't appear to exist) 1830 // Solaris: pthread_spin_destroy 1831 __attribute__((noinline)) 1832 static int pthread_spin_destroy_WRK(pthread_spinlock_t *lock) 1833 { 1834 int ret; 1835 OrigFn fn; 1836 VALGRIND_GET_ORIG_FN(fn); 1837 if (TRACE_PTH_FNS) { 1838 fprintf(stderr, "<< pthread_spin_destroy %p", lock); 1839 fflush(stderr); 1840 } 1841 1842 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_DESTROY_PRE, 1843 pthread_spinlock_t*,lock); 1844 1845 CALL_FN_W_W(ret, fn, lock); 1846 1847 if (ret != 0) { 1848 DO_PthAPIerror( "pthread_spin_destroy", ret ); 1849 } 1850 1851 if (TRACE_PTH_FNS) { 1852 fprintf(stderr, " :: spindestroy -> %d >>\n", ret); 1853 } 1854 return ret; 1855 } 1856 #if defined(VGO_linux) 1857 PTH_FUNC(int, pthreadZuspinZusdestroy, // pthread_spin_destroy 1858 pthread_spinlock_t *lock) { 1859 return pthread_spin_destroy_WRK(lock); 1860 } 1861 #elif defined(VGO_darwin) 1862 #elif defined(VGO_solaris) 1863 PTH_FUNC(int, pthreadZuspinZusdestroy, // pthread_spin_destroy 1864 pthread_spinlock_t *lock) { 1865 return pthread_spin_destroy_WRK(lock); 1866 } 1867 #else 1868 # error "Unsupported OS" 1869 #endif 1870 1871 1872 //----------------------------------------------------------- 1873 // glibc: pthread_spin_lock 1874 // darwin: (doesn't appear to exist) 1875 // Solaris: pthread_spin_lock 1876 __attribute__((noinline)) 1877 static int pthread_spin_lock_WRK(pthread_spinlock_t *lock) 1878 { 1879 int ret; 1880 OrigFn fn; 1881 VALGRIND_GET_ORIG_FN(fn); 1882 if (TRACE_PTH_FNS) { 1883 fprintf(stderr, "<< pthread_spinlock %p", lock); 1884 fflush(stderr); 1885 } 1886 1887 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE, 1888 pthread_spinlock_t*,lock, long,0/*!isTryLock*/); 1889 1890 CALL_FN_W_W(ret, fn, lock); 1891 1892 /* There's a hole here: libpthread now knows the lock is locked, 1893 but the tool doesn't, so some other thread could run and detect 1894 that the lock has been acquired by someone (this thread). Does 1895 this matter? Not sure, but I don't think so. */ 1896 1897 if (ret == 0 /*success*/) { 1898 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST, 1899 pthread_spinlock_t*,lock); 1900 } else { 1901 DO_PthAPIerror( "pthread_spin_lock", ret ); 1902 } 1903 1904 if (TRACE_PTH_FNS) { 1905 fprintf(stderr, " :: spinlock -> %d >>\n", ret); 1906 } 1907 return ret; 1908 } 1909 #if defined(VGO_linux) 1910 PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock 1911 pthread_spinlock_t *lock) { 1912 return pthread_spin_lock_WRK(lock); 1913 } 1914 #elif defined(VGO_darwin) 1915 #elif defined(VGO_solaris) 1916 PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock 1917 pthread_spinlock_t *lock) { 1918 return pthread_spin_lock_WRK(lock); 1919 } 1920 #else 1921 # error "Unsupported OS" 1922 #endif 1923 1924 1925 //----------------------------------------------------------- 1926 // glibc: pthread_spin_trylock 1927 // darwin: (doesn't appear to exist) 1928 // Solaris: pthread_spin_trylock 1929 __attribute__((noinline)) 1930 static int pthread_spin_trylock_WRK(pthread_spinlock_t *lock) 1931 { 1932 int ret; 1933 OrigFn fn; 1934 VALGRIND_GET_ORIG_FN(fn); 1935 if (TRACE_PTH_FNS) { 1936 fprintf(stderr, "<< pthread_spin_trylock %p", lock); 1937 fflush(stderr); 1938 } 1939 1940 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE, 1941 pthread_spinlock_t*,lock, long,1/*isTryLock*/); 1942 1943 CALL_FN_W_W(ret, fn, lock); 1944 1945 /* There's a hole here: libpthread now knows the lock is locked, 1946 but the tool doesn't, so some other thread could run and detect 1947 that the lock has been acquired by someone (this thread). Does 1948 this matter? Not sure, but I don't think so. */ 1949 1950 if (ret == 0 /*success*/) { 1951 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST, 1952 pthread_spinlock_t*,lock); 1953 } else { 1954 if (ret != EBUSY) 1955 DO_PthAPIerror( "pthread_spin_trylock", ret ); 1956 } 1957 1958 if (TRACE_PTH_FNS) { 1959 fprintf(stderr, " :: spin_trylock -> %d >>\n", ret); 1960 } 1961 return ret; 1962 } 1963 #if defined(VGO_linux) 1964 PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock 1965 pthread_spinlock_t *lock) { 1966 return pthread_spin_trylock_WRK(lock); 1967 } 1968 #elif defined(VGO_darwin) 1969 #elif defined(VGO_solaris) 1970 PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock 1971 pthread_spinlock_t *lock) { 1972 return pthread_spin_trylock_WRK(lock); 1973 } 1974 #else 1975 # error "Unsupported OS" 1976 #endif 1977 1978 #endif // defined(HAVE_PTHREAD_SPIN_LOCK) 1979 1980 1981 /*----------------------------------------------------------------*/ 1982 /*--- pthread_rwlock_t functions ---*/ 1983 /*----------------------------------------------------------------*/ 1984 1985 /* Android's pthread.h doesn't say anything about rwlocks, hence these 1986 functions have to be conditionally compiled. */ 1987 #if defined(HAVE_PTHREAD_RWLOCK_T) 1988 1989 /* Handled: pthread_rwlock_init pthread_rwlock_destroy 1990 pthread_rwlock_rdlock 1991 pthread_rwlock_wrlock 1992 pthread_rwlock_unlock 1993 pthread_rwlock_tryrdlock 1994 pthread_rwlock_trywrlock 1995 1996 Unhandled: pthread_rwlock_timedrdlock 1997 pthread_rwlock_timedwrlock 1998 */ 1999 2000 //----------------------------------------------------------- 2001 // glibc: pthread_rwlock_init 2002 // darwin: pthread_rwlock_init 2003 // darwin: pthread_rwlock_init$UNIX2003 2004 // Solaris: rwlock_init (pthread_rwlock_init is built atop of rwlock_init) 2005 __attribute__((noinline)) 2006 static int pthread_rwlock_init_WRK(pthread_rwlock_t *rwl, 2007 pthread_rwlockattr_t* attr) 2008 { 2009 int ret; 2010 OrigFn fn; 2011 VALGRIND_GET_ORIG_FN(fn); 2012 if (TRACE_PTH_FNS) { 2013 fprintf(stderr, "<< pthread_rwl_init %p", rwl); fflush(stderr); 2014 } 2015 2016 CALL_FN_W_WW(ret, fn, rwl,attr); 2017 2018 if (ret == 0 /*success*/) { 2019 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST, 2020 pthread_rwlock_t*,rwl); 2021 } else { 2022 DO_PthAPIerror( "pthread_rwlock_init", ret ); 2023 } 2024 2025 if (TRACE_PTH_FNS) { 2026 fprintf(stderr, " :: rwl_init -> %d >>\n", ret); 2027 } 2028 return ret; 2029 } 2030 #if defined(VGO_linux) 2031 PTH_FUNC(int, pthreadZurwlockZuinit, // pthread_rwlock_init 2032 pthread_rwlock_t *rwl, 2033 pthread_rwlockattr_t* attr) { 2034 return pthread_rwlock_init_WRK(rwl, attr); 2035 } 2036 #elif defined(VGO_darwin) 2037 PTH_FUNC(int, pthreadZurwlockZuinitZa, // pthread_rwlock_init* 2038 pthread_rwlock_t *rwl, 2039 pthread_rwlockattr_t* attr) { 2040 return pthread_rwlock_init_WRK(rwl, attr); 2041 } 2042 #elif defined(VGO_solaris) 2043 static int pthread_rwlock_init_WRK(pthread_rwlock_t *rwl, 2044 pthread_rwlockattr_t* attr) 2045 __attribute__((unused)); 2046 #else 2047 # error "Unsupported OS" 2048 #endif 2049 2050 #if defined(VGO_solaris) 2051 PTH_FUNC(int, rwlockZuinit, // rwlock_init 2052 rwlock_t *rwlock, 2053 int type, 2054 void *arg) 2055 { 2056 int ret; 2057 OrigFn fn; 2058 VALGRIND_GET_ORIG_FN(fn); 2059 if (TRACE_PTH_FNS) { 2060 fprintf(stderr, "<< rwl_init %p", rwlock); fflush(stderr); 2061 } 2062 2063 CALL_FN_W_WWW(ret, fn, rwlock, type, arg); 2064 2065 if (ret == 0 /*success*/) { 2066 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST, 2067 rwlock_t *, rwlock); 2068 } else { 2069 DO_PthAPIerror("rwlock_init", ret); 2070 } 2071 2072 if (TRACE_PTH_FNS) { 2073 fprintf(stderr, " :: rwl_init -> %d >>\n", ret); 2074 } 2075 return ret; 2076 } 2077 #endif /* VGO_solaris */ 2078 2079 2080 //----------------------------------------------------------- 2081 // glibc: pthread_rwlock_destroy 2082 // darwin: pthread_rwlock_destroy 2083 // darwin: pthread_rwlock_destroy$UNIX2003 2084 // Solaris: rwlock_destroy (pthread_rwlock_destroy is a weak alias) 2085 // 2086 __attribute__((noinline)) 2087 static int pthread_rwlock_destroy_WRK(pthread_rwlock_t* rwl) 2088 { 2089 int ret; 2090 OrigFn fn; 2091 VALGRIND_GET_ORIG_FN(fn); 2092 if (TRACE_PTH_FNS) { 2093 fprintf(stderr, "<< pthread_rwl_destroy %p", rwl); fflush(stderr); 2094 } 2095 2096 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE, 2097 pthread_rwlock_t*,rwl); 2098 2099 CALL_FN_W_W(ret, fn, rwl); 2100 2101 if (ret != 0) { 2102 DO_PthAPIerror( "pthread_rwlock_destroy", ret ); 2103 } 2104 2105 if (TRACE_PTH_FNS) { 2106 fprintf(stderr, " :: rwl_destroy -> %d >>\n", ret); 2107 } 2108 return ret; 2109 } 2110 #if defined(VGO_linux) 2111 PTH_FUNC(int, pthreadZurwlockZudestroy, // pthread_rwlock_destroy 2112 pthread_rwlock_t *rwl) { 2113 return pthread_rwlock_destroy_WRK(rwl); 2114 } 2115 #elif defined(VGO_darwin) 2116 PTH_FUNC(int, pthreadZurwlockZudestroyZa, // pthread_rwlock_destroy* 2117 pthread_rwlock_t *rwl) { 2118 return pthread_rwlock_destroy_WRK(rwl); 2119 } 2120 #elif defined(VGO_solaris) 2121 PTH_FUNC(int, rwlockZudestroy, // rwlock_destroy 2122 pthread_rwlock_t *rwl) { 2123 return pthread_rwlock_destroy_WRK(rwl); 2124 } 2125 #else 2126 # error "Unsupported OS" 2127 #endif 2128 2129 2130 //----------------------------------------------------------- 2131 // glibc: pthread_rwlock_wrlock 2132 // darwin: pthread_rwlock_wrlock 2133 // darwin: pthread_rwlock_wrlock$UNIX2003 2134 // Solaris: rw_wrlock (pthread_rwlock_wrlock is a weak alias) 2135 // 2136 __attribute__((noinline)) 2137 static int pthread_rwlock_wrlock_WRK(pthread_rwlock_t* rwlock) 2138 { 2139 int ret; 2140 OrigFn fn; 2141 VALGRIND_GET_ORIG_FN(fn); 2142 if (TRACE_PTH_FNS) { 2143 fprintf(stderr, "<< pthread_rwl_wlk %p", rwlock); fflush(stderr); 2144 } 2145 2146 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE, 2147 pthread_rwlock_t*,rwlock, 2148 long,1/*isW*/, long,0/*!isTryLock*/); 2149 2150 CALL_FN_W_W(ret, fn, rwlock); 2151 2152 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST, 2153 pthread_rwlock_t*,rwlock, long,1/*isW*/, 2154 long, (ret == 0) ? True : False); 2155 if (ret != 0) { 2156 DO_PthAPIerror( "pthread_rwlock_wrlock", ret ); 2157 } 2158 2159 if (TRACE_PTH_FNS) { 2160 fprintf(stderr, " :: rwl_wlk -> %d >>\n", ret); 2161 } 2162 return ret; 2163 } 2164 #if defined(VGO_linux) 2165 PTH_FUNC(int, pthreadZurwlockZuwrlock, // pthread_rwlock_wrlock 2166 pthread_rwlock_t* rwlock) { 2167 return pthread_rwlock_wrlock_WRK(rwlock); 2168 } 2169 #elif defined(VGO_darwin) 2170 PTH_FUNC(int, pthreadZurwlockZuwrlockZa, // pthread_rwlock_wrlock* 2171 pthread_rwlock_t* rwlock) { 2172 return pthread_rwlock_wrlock_WRK(rwlock); 2173 } 2174 #elif defined(VGO_solaris) 2175 PTH_FUNC(int, rwZuwrlock, // rw_wrlock 2176 pthread_rwlock_t *rwlock) { 2177 return pthread_rwlock_wrlock_WRK(rwlock); 2178 } 2179 #else 2180 # error "Unsupported OS" 2181 #endif 2182 2183 #if defined(VGO_solaris) 2184 /* Internal to libc. */ 2185 PTH_FUNC(void, lrwZuwrlock, // lrw_wrlock 2186 rwlock_t *rwlock) 2187 { 2188 OrigFn fn; 2189 VALGRIND_GET_ORIG_FN(fn); 2190 if (TRACE_PTH_FNS) { 2191 fprintf(stderr, "<< lrw_wlk %p", rwlock); fflush(stderr); 2192 } 2193 2194 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE, 2195 pthread_rwlock_t *, rwlock, 2196 long, 1/*isW*/, long, 0/*!isTryLock*/); 2197 2198 CALL_FN_v_W(fn, rwlock); 2199 2200 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST, 2201 pthread_rwlock_t *, rwlock, long, 1/*isW*/, long, True); 2202 2203 if (TRACE_PTH_FNS) { 2204 fprintf(stderr, " :: lrw_wlk >>\n"); 2205 } 2206 } 2207 #endif /* VGO_solaris */ 2208 2209 2210 //----------------------------------------------------------- 2211 // glibc: pthread_rwlock_rdlock 2212 // darwin: pthread_rwlock_rdlock 2213 // darwin: pthread_rwlock_rdlock$UNIX2003 2214 // Solaris: rw_rdlock (pthread_rwlock_rdlock is a weak alias) 2215 // 2216 __attribute__((noinline)) 2217 static int pthread_rwlock_rdlock_WRK(pthread_rwlock_t* rwlock) 2218 { 2219 int ret; 2220 OrigFn fn; 2221 VALGRIND_GET_ORIG_FN(fn); 2222 if (TRACE_PTH_FNS) { 2223 fprintf(stderr, "<< pthread_rwl_rlk %p", rwlock); fflush(stderr); 2224 } 2225 2226 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE, 2227 pthread_rwlock_t*,rwlock, 2228 long,0/*!isW*/, long,0/*!isTryLock*/); 2229 2230 CALL_FN_W_W(ret, fn, rwlock); 2231 2232 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST, 2233 pthread_rwlock_t*,rwlock, long,0/*!isW*/, 2234 long, (ret == 0) ? True : False); 2235 if (ret != 0) { 2236 DO_PthAPIerror( "pthread_rwlock_rdlock", ret ); 2237 } 2238 2239 if (TRACE_PTH_FNS) { 2240 fprintf(stderr, " :: rwl_rlk -> %d >>\n", ret); 2241 } 2242 return ret; 2243 } 2244 #if defined(VGO_linux) 2245 PTH_FUNC(int, pthreadZurwlockZurdlock, // pthread_rwlock_rdlock 2246 pthread_rwlock_t* rwlock) { 2247 return pthread_rwlock_rdlock_WRK(rwlock); 2248 } 2249 #elif defined(VGO_darwin) 2250 PTH_FUNC(int, pthreadZurwlockZurdlockZa, // pthread_rwlock_rdlock* 2251 pthread_rwlock_t* rwlock) { 2252 return pthread_rwlock_rdlock_WRK(rwlock); 2253 } 2254 #elif defined(VGO_solaris) 2255 PTH_FUNC(int, rwZurdlock, // rw_rdlock 2256 pthread_rwlock_t *rwlock) { 2257 return pthread_rwlock_rdlock_WRK(rwlock); 2258 } 2259 #else 2260 # error "Unsupported OS" 2261 #endif 2262 2263 #if defined(VGO_solaris) 2264 /* Internal to libc. */ 2265 PTH_FUNC(void, lrwZurdlock, // lrw_rdlock 2266 rwlock_t *rwlock) 2267 { 2268 OrigFn fn; 2269 VALGRIND_GET_ORIG_FN(fn); 2270 if (TRACE_PTH_FNS) { 2271 fprintf(stderr, "<< lrw_rlk %p", rwlock); fflush(stderr); 2272 } 2273 2274 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE, 2275 pthread_rwlock_t *, rwlock, 2276 long, 0/*!isW*/, long, 0/*!isTryLock*/); 2277 2278 CALL_FN_v_W(fn, rwlock); 2279 2280 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST, 2281 pthread_rwlock_t *, rwlock, long, 0/*!isW*/, long, True); 2282 2283 if (TRACE_PTH_FNS) { 2284 fprintf(stderr, " :: lrw_rlk ->>\n"); 2285 } 2286 } 2287 #endif /* VGO_solaris */ 2288 2289 2290 //----------------------------------------------------------- 2291 // glibc: pthread_rwlock_trywrlock 2292 // darwin: pthread_rwlock_trywrlock 2293 // darwin: pthread_rwlock_trywrlock$UNIX2003 2294 // Solaris: rw_trywrlock (pthread_rwlock_trywrlock is a weak alias) 2295 // 2296 __attribute__((noinline)) 2297 static int pthread_rwlock_trywrlock_WRK(pthread_rwlock_t* rwlock) 2298 { 2299 int ret; 2300 OrigFn fn; 2301 VALGRIND_GET_ORIG_FN(fn); 2302 if (TRACE_PTH_FNS) { 2303 fprintf(stderr, "<< pthread_rwl_trywlk %p", rwlock); fflush(stderr); 2304 } 2305 2306 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE, 2307 pthread_rwlock_t*,rwlock, 2308 long,1/*isW*/, long,1/*isTryLock*/); 2309 2310 CALL_FN_W_W(ret, fn, rwlock); 2311 2312 /* There's a hole here: libpthread now knows the lock is locked, 2313 but the tool doesn't, so some other thread could run and detect 2314 that the lock has been acquired by someone (this thread). Does 2315 this matter? Not sure, but I don't think so. */ 2316 2317 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST, 2318 pthread_rwlock_t*,rwlock, long,1/*isW*/, 2319 long, (ret == 0) ? True : False); 2320 if (ret != 0) { 2321 if (ret != EBUSY) 2322 DO_PthAPIerror( "pthread_rwlock_trywrlock", ret ); 2323 } 2324 2325 if (TRACE_PTH_FNS) { 2326 fprintf(stderr, " :: rwl_trywlk -> %d >>\n", ret); 2327 } 2328 return ret; 2329 } 2330 #if defined(VGO_linux) 2331 PTH_FUNC(int, pthreadZurwlockZutrywrlock, // pthread_rwlock_trywrlock 2332 pthread_rwlock_t* rwlock) { 2333 return pthread_rwlock_trywrlock_WRK(rwlock); 2334 } 2335 #elif defined(VGO_darwin) 2336 PTH_FUNC(int, pthreadZurwlockZutrywrlockZa, // pthread_rwlock_trywrlock* 2337 pthread_rwlock_t* rwlock) { 2338 return pthread_rwlock_trywrlock_WRK(rwlock); 2339 } 2340 #elif defined(VGO_solaris) 2341 PTH_FUNC(int, rwZutrywrlock, // rw_trywrlock 2342 pthread_rwlock_t *rwlock) { 2343 return pthread_rwlock_trywrlock_WRK(rwlock); 2344 } 2345 #else 2346 # error "Unsupported OS" 2347 #endif 2348 2349 2350 //----------------------------------------------------------- 2351 // glibc: pthread_rwlock_tryrdlock 2352 // darwin: pthread_rwlock_tryrdlock 2353 // darwin: pthread_rwlock_tryrdlock$UNIX2003 2354 // Solaris: rw_tryrdlock (pthread_rwlock_tryrdlock is a weak alias) 2355 // 2356 __attribute__((noinline)) 2357 static int pthread_rwlock_tryrdlock_WRK(pthread_rwlock_t* rwlock) 2358 { 2359 int ret; 2360 OrigFn fn; 2361 VALGRIND_GET_ORIG_FN(fn); 2362 if (TRACE_PTH_FNS) { 2363 fprintf(stderr, "<< pthread_rwl_tryrlk %p", rwlock); fflush(stderr); 2364 } 2365 2366 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE, 2367 pthread_rwlock_t*,rwlock, 2368 long,0/*!isW*/, long,1/*isTryLock*/); 2369 2370 CALL_FN_W_W(ret, fn, rwlock); 2371 2372 /* There's a hole here: libpthread now knows the lock is locked, 2373 but the tool doesn't, so some other thread could run and detect 2374 that the lock has been acquired by someone (this thread). Does 2375 this matter? Not sure, but I don't think so. */ 2376 2377 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST, 2378 pthread_rwlock_t*,rwlock, long,0/*!isW*/, 2379 long, (ret == 0) ? True : False); 2380 2381 if (ret != 0) { 2382 if (ret != EBUSY) 2383 DO_PthAPIerror( "pthread_rwlock_tryrdlock", ret ); 2384 } 2385 2386 if (TRACE_PTH_FNS) { 2387 fprintf(stderr, " :: rwl_tryrlk -> %d >>\n", ret); 2388 } 2389 return ret; 2390 } 2391 #if defined(VGO_linux) 2392 PTH_FUNC(int, pthreadZurwlockZutryrdlock, // pthread_rwlock_tryrdlock 2393 pthread_rwlock_t* rwlock) { 2394 return pthread_rwlock_tryrdlock_WRK(rwlock); 2395 } 2396 #elif defined(VGO_darwin) 2397 PTH_FUNC(int, pthreadZurwlockZutryrdlockZa, // pthread_rwlock_tryrdlock* 2398 pthread_rwlock_t* rwlock) { 2399 return pthread_rwlock_tryrdlock_WRK(rwlock); 2400 } 2401 #elif defined(VGO_solaris) 2402 PTH_FUNC(int, rwZutryrdlock, // rw_tryrdlock 2403 pthread_rwlock_t *rwlock) { 2404 return pthread_rwlock_tryrdlock_WRK(rwlock); 2405 } 2406 #else 2407 # error "Unsupported OS" 2408 #endif 2409 2410 2411 //----------------------------------------------------------- 2412 // glibc: Unhandled 2413 // darwin: Unhandled 2414 // Solaris: pthread_rwlock_timedrdlock 2415 // Solaris: pthread_rwlock_reltimedrdlock_np 2416 // 2417 __attribute__((noinline)) __attribute__((unused)) 2418 static int pthread_rwlock_timedrdlock_WRK(pthread_rwlock_t *rwlock, 2419 const struct timespec *timeout) 2420 { 2421 int ret; 2422 OrigFn fn; 2423 VALGRIND_GET_ORIG_FN(fn); 2424 if (TRACE_PTH_FNS) { 2425 fprintf(stderr, "<< pthread_rwl_timedrdl %p", rwlock); fflush(stderr); 2426 } 2427 2428 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE, 2429 pthread_rwlock_t *, rwlock, 2430 long, 0/*isW*/, long, 0/*isTryLock*/); 2431 2432 CALL_FN_W_WW(ret, fn, rwlock, timeout); 2433 2434 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST, 2435 pthread_rwlock_t *, rwlock, long, 0/*isW*/, 2436 long, (ret == 0) ? True : False); 2437 if (ret != 0) { 2438 DO_PthAPIerror("pthread_rwlock_timedrdlock", ret); 2439 } 2440 2441 if (TRACE_PTH_FNS) { 2442 fprintf(stderr, " :: rwl_timedrdl -> %d >>\n", ret); 2443 } 2444 return ret; 2445 } 2446 #if defined(VGO_linux) 2447 #elif defined(VGO_darwin) 2448 #elif defined(VGO_solaris) 2449 PTH_FUNC(int, pthreadZurwlockZutimedrdlock, // pthread_rwlock_timedrdlock 2450 pthread_rwlock_t *rwlock, 2451 const struct timespec *timeout) { 2452 return pthread_rwlock_timedrdlock_WRK(rwlock, timeout); 2453 } 2454 PTH_FUNC(int, pthreadZurwlockZureltimedrdlockZunp, // pthread_rwlock_timedrdlock_np 2455 pthread_rwlock_t *rwlock, 2456 const struct timespec *timeout) { 2457 return pthread_rwlock_timedrdlock_WRK(rwlock, timeout); 2458 } 2459 #else 2460 # error "Unsupported OS" 2461 #endif 2462 2463 2464 //----------------------------------------------------------- 2465 // glibc: Unhandled 2466 // darwin: Unhandled 2467 // Solaris: pthread_rwlock_timedwrlock 2468 // Solaris: pthread_rwlock_reltimedwrlock_np 2469 // 2470 __attribute__((noinline)) __attribute__((unused)) 2471 static int pthread_rwlock_timedwrlock_WRK(pthread_rwlock_t *rwlock, 2472 const struct timespec *timeout) 2473 { 2474 int ret; 2475 OrigFn fn; 2476 VALGRIND_GET_ORIG_FN(fn); 2477 if (TRACE_PTH_FNS) { 2478 fprintf(stderr, "<< pthread_rwl_timedwrl %p", rwlock); fflush(stderr); 2479 } 2480 2481 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE, 2482 pthread_rwlock_t *, rwlock, 2483 long, 1/*isW*/, long, 0/*isTryLock*/); 2484 2485 CALL_FN_W_WW(ret, fn, rwlock, timeout); 2486 2487 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST, 2488 pthread_rwlock_t *, rwlock, long, 1/*isW*/, 2489 long, (ret == 0) ? True : False); 2490 if (ret != 0) { 2491 DO_PthAPIerror("pthread_rwlock_timedwrlock", ret); 2492 } 2493 2494 if (TRACE_PTH_FNS) { 2495 fprintf(stderr, " :: rwl_timedwrl -> %d >>\n", ret); 2496 } 2497 return ret; 2498 } 2499 #if defined(VGO_linux) 2500 #elif defined(VGO_darwin) 2501 #elif defined(VGO_solaris) 2502 PTH_FUNC(int, pthreadZurwlockZutimedwrlock, // pthread_rwlock_timedwrlock 2503 pthread_rwlock_t *rwlock, 2504 const struct timespec *timeout) { 2505 return pthread_rwlock_timedwrlock_WRK(rwlock, timeout); 2506 } 2507 PTH_FUNC(int, pthreadZurwlockZureltimedwrlockZunp, // pthread_rwlock_timedwrlock_np 2508 pthread_rwlock_t *rwlock, 2509 const struct timespec *timeout) { 2510 return pthread_rwlock_timedwrlock_WRK(rwlock, timeout); 2511 } 2512 #else 2513 # error "Unsupported OS" 2514 #endif 2515 2516 2517 //----------------------------------------------------------- 2518 // glibc: pthread_rwlock_unlock 2519 // darwin: pthread_rwlock_unlock 2520 // darwin: pthread_rwlock_unlock$UNIX2003 2521 // Solaris: rw_unlock (pthread_rwlock_unlock is a weak alias) 2522 __attribute__((noinline)) 2523 static int pthread_rwlock_unlock_WRK(pthread_rwlock_t* rwlock) 2524 { 2525 int ret; 2526 OrigFn fn; 2527 VALGRIND_GET_ORIG_FN(fn); 2528 if (TRACE_PTH_FNS) { 2529 fprintf(stderr, "<< pthread_rwl_unlk %p", rwlock); fflush(stderr); 2530 } 2531 2532 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE, 2533 pthread_rwlock_t*,rwlock); 2534 2535 CALL_FN_W_W(ret, fn, rwlock); 2536 2537 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST, 2538 pthread_rwlock_t*,rwlock); 2539 if (ret != 0) { 2540 DO_PthAPIerror( "pthread_rwlock_unlock", ret ); 2541 } 2542 2543 if (TRACE_PTH_FNS) { 2544 fprintf(stderr, " :: rwl_unlk -> %d >>\n", ret); 2545 } 2546 return ret; 2547 } 2548 #if defined(VGO_linux) 2549 PTH_FUNC(int, pthreadZurwlockZuunlock, // pthread_rwlock_unlock 2550 pthread_rwlock_t* rwlock) { 2551 return pthread_rwlock_unlock_WRK(rwlock); 2552 } 2553 #elif defined(VGO_darwin) 2554 PTH_FUNC(int, pthreadZurwlockZuunlockZa, // pthread_rwlock_unlock* 2555 pthread_rwlock_t* rwlock) { 2556 return pthread_rwlock_unlock_WRK(rwlock); 2557 } 2558 #elif defined(VGO_solaris) 2559 PTH_FUNC(int, rwZuunlock, // rw_unlock 2560 pthread_rwlock_t *rwlock) { 2561 return pthread_rwlock_unlock_WRK(rwlock); 2562 } 2563 #else 2564 # error "Unsupported OS" 2565 #endif 2566 2567 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */ 2568 2569 2570 /*----------------------------------------------------------------*/ 2571 /*--- POSIX semaphores ---*/ 2572 /*----------------------------------------------------------------*/ 2573 2574 #include <semaphore.h> 2575 #include <fcntl.h> /* O_CREAT */ 2576 2577 #define TRACE_SEM_FNS 0 2578 2579 /* Handled: 2580 int sem_init(sem_t *sem, int pshared, unsigned value); 2581 int sem_destroy(sem_t *sem); 2582 int sem_wait(sem_t *sem); 2583 int sem_post(sem_t *sem); 2584 sem_t* sem_open(const char *name, int oflag, 2585 ... [mode_t mode, unsigned value]); 2586 [complete with its idiotic semantics] 2587 int sem_close(sem_t* sem); 2588 2589 Unhandled: 2590 int sem_trywait(sem_t *sem); 2591 int sem_timedwait(sem_t *restrict sem, 2592 const struct timespec *restrict abs_timeout); 2593 */ 2594 2595 //----------------------------------------------------------- 2596 // glibc: sem_init@@GLIBC_2.2.5 2597 // glibc: sem_init@@GLIBC_2.1 2598 // glibc: sem_init (at) GLIBC_2.0 2599 // darwin: sem_init 2600 // Solaris: sema_init (sem_init is built on top of sem_init) 2601 // 2602 #if !defined(VGO_solaris) 2603 __attribute__((noinline)) 2604 static int sem_init_WRK(sem_t* sem, int pshared, unsigned long value) 2605 { 2606 OrigFn fn; 2607 int ret; 2608 VALGRIND_GET_ORIG_FN(fn); 2609 2610 if (TRACE_SEM_FNS) { 2611 fprintf(stderr, "<< sem_init(%p,%d,%lu) ", sem,pshared,value); 2612 fflush(stderr); 2613 } 2614 2615 CALL_FN_W_WWW(ret, fn, sem,pshared,value); 2616 2617 if (ret == 0) { 2618 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST, 2619 sem_t*, sem, unsigned long, value); 2620 } else { 2621 DO_PthAPIerror( "sem_init", errno ); 2622 } 2623 2624 if (TRACE_SEM_FNS) { 2625 fprintf(stderr, " sem_init -> %d >>\n", ret); 2626 fflush(stderr); 2627 } 2628 2629 return ret; 2630 } 2631 #if defined(VGO_linux) 2632 PTH_FUNC(int, semZuinitZAZa, // sem_init@* 2633 sem_t* sem, int pshared, unsigned long value) { 2634 return sem_init_WRK(sem, pshared, value); 2635 } 2636 #elif defined(VGO_darwin) 2637 PTH_FUNC(int, semZuinit, // sem_init 2638 sem_t* sem, int pshared, unsigned long value) { 2639 return sem_init_WRK(sem, pshared, value); 2640 } 2641 #else 2642 # error "Unsupported OS" 2643 #endif 2644 2645 #else /* VGO_solaris */ 2646 PTH_FUNC(int, semaZuinit, // sema_init 2647 sema_t *sem, 2648 unsigned int value, 2649 int type, 2650 void *arg) 2651 { 2652 OrigFn fn; 2653 int ret; 2654 VALGRIND_GET_ORIG_FN(fn); 2655 2656 if (TRACE_SEM_FNS) { 2657 fprintf(stderr, "<< sema_init(%p, %d, %u) ", sem, type, value); 2658 fflush(stderr); 2659 } 2660 2661 CALL_FN_W_WWWW(ret, fn, sem, value, type, arg); 2662 2663 if (ret == 0) { 2664 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST, 2665 sema_t *, sem, Word, value); 2666 } else { 2667 DO_PthAPIerror("sema_init", ret); 2668 } 2669 2670 if (TRACE_SEM_FNS) { 2671 fprintf(stderr, " sema_init -> %d >>\n", ret); 2672 fflush(stderr); 2673 } 2674 2675 return ret; 2676 } 2677 #endif /* VGO_solaris */ 2678 2679 2680 //----------------------------------------------------------- 2681 // glibc: sem_destroy (at) GLIBC_2.0 2682 // glibc: sem_destroy@@GLIBC_2.1 2683 // glibc: sem_destroy@@GLIBC_2.2.5 2684 // darwin: sem_destroy 2685 // Solaris: sema_destroy (sem_destroy is built on top of sema_destroy) 2686 __attribute__((noinline)) 2687 static int sem_destroy_WRK(sem_t* sem) 2688 { 2689 OrigFn fn; 2690 int ret; 2691 VALGRIND_GET_ORIG_FN(fn); 2692 2693 if (TRACE_SEM_FNS) { 2694 fprintf(stderr, "<< sem_destroy(%p) ", sem); 2695 fflush(stderr); 2696 } 2697 2698 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem); 2699 2700 CALL_FN_W_W(ret, fn, sem); 2701 2702 if (ret != 0) { 2703 DO_PthAPIerror( "sem_destroy", SEM_ERROR ); 2704 } 2705 2706 if (TRACE_SEM_FNS) { 2707 fprintf(stderr, " sem_destroy -> %d >>\n", ret); 2708 fflush(stderr); 2709 } 2710 2711 return ret; 2712 } 2713 #if defined(VGO_linux) 2714 PTH_FUNC(int, semZudestroyZAZa, // sem_destroy* 2715 sem_t* sem) { 2716 return sem_destroy_WRK(sem); 2717 } 2718 #elif defined(VGO_darwin) 2719 PTH_FUNC(int, semZudestroy, // sem_destroy 2720 sem_t* sem) { 2721 return sem_destroy_WRK(sem); 2722 } 2723 #elif defined(VGO_solaris) 2724 PTH_FUNC(int, semaZudestroy, // sema_destroy 2725 sem_t *sem) { 2726 return sem_destroy_WRK(sem); 2727 } 2728 #else 2729 # error "Unsupported OS" 2730 #endif 2731 2732 2733 //----------------------------------------------------------- 2734 // glibc: sem_wait 2735 // glibc: sem_wait (at) GLIBC_2.0 2736 // glibc: sem_wait@@GLIBC_2.1 2737 // darwin: sem_wait 2738 // darwin: sem_wait$NOCANCEL$UNIX2003 2739 // darwin: sem_wait$UNIX2003 2740 // Solaris: sema_wait (sem_wait is built on top of sema_wait) 2741 // 2742 /* wait: decrement semaphore - acquire lockage */ 2743 __attribute__((noinline)) 2744 static int sem_wait_WRK(sem_t* sem) 2745 { 2746 OrigFn fn; 2747 int ret; 2748 VALGRIND_GET_ORIG_FN(fn); 2749 2750 if (TRACE_SEM_FNS) { 2751 fprintf(stderr, "<< sem_wait(%p) ", sem); 2752 fflush(stderr); 2753 } 2754 2755 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_PRE, sem_t*,sem); 2756 2757 CALL_FN_W_W(ret, fn, sem); 2758 2759 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST, sem_t*,sem, 2760 long, (ret == 0) ? True : False); 2761 2762 if (ret != 0) { 2763 DO_PthAPIerror( "sem_wait", SEM_ERROR ); 2764 } 2765 2766 if (TRACE_SEM_FNS) { 2767 fprintf(stderr, " sem_wait -> %d >>\n", ret); 2768 fflush(stderr); 2769 } 2770 2771 return ret; 2772 } 2773 #if defined(VGO_linux) 2774 PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */ 2775 return sem_wait_WRK(sem); 2776 } 2777 PTH_FUNC(int, semZuwaitZAZa, sem_t* sem) { /* sem_wait@* */ 2778 return sem_wait_WRK(sem); 2779 } 2780 #elif defined(VGO_darwin) 2781 PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */ 2782 return sem_wait_WRK(sem); 2783 } 2784 PTH_FUNC(int, semZuwaitZDZa, sem_t* sem) { /* sem_wait$* */ 2785 return sem_wait_WRK(sem); 2786 } 2787 #elif defined(VGO_solaris) 2788 PTH_FUNC(int, semaZuwait, sem_t *sem) { /* sema_wait */ 2789 return sem_wait_WRK(sem); 2790 } 2791 #else 2792 # error "Unsupported OS" 2793 #endif 2794 2795 2796 //----------------------------------------------------------- 2797 // glibc: sem_post 2798 // glibc: sem_post (at) GLIBC_2.0 2799 // glibc: sem_post@@GLIBC_2.1 2800 // darwin: sem_post 2801 // Solaris: sema_post (sem_post is built on top of sema_post) 2802 // 2803 /* post: increment semaphore - release lockage */ 2804 __attribute__((noinline)) 2805 static int sem_post_WRK(sem_t* sem) 2806 { 2807 OrigFn fn; 2808 int ret; 2809 2810 VALGRIND_GET_ORIG_FN(fn); 2811 2812 if (TRACE_SEM_FNS) { 2813 fprintf(stderr, "<< sem_post(%p) ", sem); 2814 fflush(stderr); 2815 } 2816 2817 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_PRE, sem_t*,sem); 2818 2819 CALL_FN_W_W(ret, fn, sem); 2820 2821 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_POST, sem_t*,sem); 2822 2823 if (ret != 0) { 2824 DO_PthAPIerror( "sem_post", SEM_ERROR ); 2825 } 2826 2827 if (TRACE_SEM_FNS) { 2828 fprintf(stderr, " sem_post -> %d >>\n", ret); 2829 fflush(stderr); 2830 } 2831 2832 return ret; 2833 } 2834 #if defined(VGO_linux) 2835 PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */ 2836 return sem_post_WRK(sem); 2837 } 2838 PTH_FUNC(int, semZupostZAZa, sem_t* sem) { /* sem_post@* */ 2839 return sem_post_WRK(sem); 2840 } 2841 #elif defined(VGO_darwin) 2842 PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */ 2843 return sem_post_WRK(sem); 2844 } 2845 #elif defined(VGO_solaris) 2846 PTH_FUNC(int, semaZupost, sem_t *sem) { /* sema_post */ 2847 return sem_post_WRK(sem); 2848 } 2849 #else 2850 # error "Unsupported OS" 2851 #endif 2852 2853 2854 //----------------------------------------------------------- 2855 // glibc: sem_open 2856 // darwin: sem_open 2857 // Solaris: sem_open 2858 // 2859 PTH_FUNC(sem_t*, semZuopen, 2860 const char* name, long oflag, 2861 long mode, unsigned long value) 2862 { 2863 /* A copy of sem_init_WRK (more or less). Is this correct? */ 2864 OrigFn fn; 2865 sem_t* ret; 2866 VALGRIND_GET_ORIG_FN(fn); 2867 2868 if (TRACE_SEM_FNS) { 2869 fprintf(stderr, "<< sem_open(\"%s\",%ld,%lx,%lu) ", 2870 name,oflag,mode,value); 2871 fflush(stderr); 2872 } 2873 2874 CALL_FN_W_WWWW(ret, fn, name,oflag,mode,value); 2875 2876 if (ret != SEM_FAILED && (oflag & O_CREAT)) { 2877 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST, 2878 sem_t*, ret, unsigned long, value); 2879 } 2880 if (ret == SEM_FAILED) { 2881 DO_PthAPIerror( "sem_open", errno ); 2882 } 2883 2884 if (TRACE_SEM_FNS) { 2885 fprintf(stderr, " sem_open -> %p >>\n", ret); 2886 fflush(stderr); 2887 } 2888 2889 return ret; 2890 } 2891 2892 2893 //----------------------------------------------------------- 2894 // glibc: sem_close 2895 // darwin: sem_close 2896 // Solaris: sem_close 2897 PTH_FUNC(int, sem_close, sem_t* sem) 2898 { 2899 OrigFn fn; 2900 int ret; 2901 VALGRIND_GET_ORIG_FN(fn); 2902 2903 if (TRACE_SEM_FNS) { 2904 fprintf(stderr, "<< sem_close(%p) ", sem); 2905 fflush(stderr); 2906 } 2907 2908 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem); 2909 2910 CALL_FN_W_W(ret, fn, sem); 2911 2912 if (ret != 0) { 2913 DO_PthAPIerror( "sem_close", errno ); 2914 } 2915 2916 if (TRACE_SEM_FNS) { 2917 fprintf(stderr, " close -> %d >>\n", ret); 2918 fflush(stderr); 2919 } 2920 2921 return ret; 2922 } 2923 2924 2925 /*----------------------------------------------------------------*/ 2926 /*--- Qt 4 threading functions (w/ GNU name mangling) ---*/ 2927 /*----------------------------------------------------------------*/ 2928 2929 /* Handled: 2930 QMutex::lock() 2931 QMutex::unlock() 2932 QMutex::tryLock() 2933 QMutex::tryLock(int) 2934 2935 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC1ENS_13RecursionModeE 2936 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC2ENS_13RecursionModeE 2937 QMutex::~QMutex() _ZN6QMutexD1Ev 2938 QMutex::~QMutex() _ZN6QMutexD2Ev 2939 2940 Unhandled: 2941 QReadWriteLock::lockForRead() 2942 QReadWriteLock::lockForWrite() 2943 QReadWriteLock::unlock() 2944 QReadWriteLock::tryLockForRead(int) 2945 QReadWriteLock::tryLockForRead() 2946 QReadWriteLock::tryLockForWrite(int) 2947 QReadWriteLock::tryLockForWrite() 2948 2949 QWaitCondition::wait(QMutex*, unsigned long) 2950 QWaitCondition::wakeAll() 2951 QWaitCondition::wakeOne() 2952 2953 QSemaphore::* 2954 */ 2955 /* More comments, 19 Nov 08, based on assessment of qt-4.5.0TP1, 2956 at least on Unix: 2957 2958 It's apparently only necessary to intercept QMutex, since that is 2959 not implemented using pthread_mutex_t; instead Qt4 has its own 2960 implementation based on atomics (to check the non-contended case) 2961 and pthread_cond_wait (to wait in the contended case). 2962 2963 QReadWriteLock is built on top of QMutex, counters, and a wait 2964 queue. So we don't need to handle it specially once QMutex 2965 handling is correct -- presumably the dependencies through QMutex 2966 are sufficient to avoid any false race reports. On the other hand, 2967 it is an open question whether too many dependencies are observed 2968 -- in which case we may miss races (false negatives). I suspect 2969 this is likely to be the case, unfortunately. 2970 2971 QWaitCondition is built on pthread_cond_t, pthread_mutex_t, QMutex 2972 and QReadWriteLock. Same compositional-correctness justificiation 2973 and limitations as fro QReadWriteLock. 2974 2975 Ditto QSemaphore (from cursory examination). 2976 2977 Does it matter that only QMutex is handled directly? Open 2978 question. From testing with drd/tests/qt4_* and with KDE4 apps, it 2979 appears that no false errors are reported; however it is not clear 2980 if this is causing false negatives. 2981 2982 Another problem with Qt4 is thread exiting. Threads are created 2983 with pthread_create (fine); but they detach and simply exit when 2984 done. There is no use of pthread_join, and the provided 2985 wait-for-a-thread-to-exit mechanism (QThread::wait, I believe) 2986 relies on a system of mutexes and flags. I suspect this also 2987 causes too many dependencies to appear. Consequently H sometimes 2988 fails to detect races at exit in some very short-lived racy 2989 programs, because it appears that a thread can exit _and_ have an 2990 observed dependency edge back to the main thread (presumably) 2991 before the main thread reaps the child (that is, calls 2992 QThread::wait). 2993 2994 This theory is supported by the observation that if all threads are 2995 made to wait at a pthread_barrier_t immediately before they exit, 2996 then H's detection of races in such programs becomes reliable; 2997 without the barrier, it is varies from run to run, depending 2998 (according to investigation) on whether aforementioned 2999 exit-before-reaping behaviour happens or not. 3000 3001 Finally, why is it necessary to intercept the QMutex constructors 3002 and destructors? The constructors are intercepted only as a matter 3003 of convenience, so H can print accurate "first observed at" 3004 clauses. However, it is actually necessary to intercept the 3005 destructors (as it is with pthread_mutex_destroy) in order that 3006 locks get removed from LAOG when they are destroyed. 3007 */ 3008 3009 // soname is libQtCore.so.4 ; match against libQtCore.so* 3010 #define QT4_FUNC(ret_ty, f, args...) \ 3011 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args); \ 3012 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args) 3013 3014 // soname is libQt5Core.so.4 ; match against libQt5Core.so* 3015 #define QT5_FUNC(ret_ty, f, args...) \ 3016 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args); \ 3017 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQt5CoreZdsoZa,f)(args) 3018 3019 //----------------------------------------------------------- 3020 // QMutex::lock() 3021 __attribute__((noinline)) 3022 static void QMutex_lock_WRK(void* self) 3023 { 3024 OrigFn fn; 3025 VALGRIND_GET_ORIG_FN(fn); 3026 if (TRACE_QT4_FNS) { 3027 fprintf(stderr, "<< QMutex::lock %p", self); fflush(stderr); 3028 } 3029 3030 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE, 3031 void*,self, long,0/*!isTryLock*/); 3032 3033 CALL_FN_v_W(fn, self); 3034 3035 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST, 3036 void *, self, long, True); 3037 3038 if (TRACE_QT4_FNS) { 3039 fprintf(stderr, " :: Q::lock done >>\n"); 3040 } 3041 } 3042 3043 QT4_FUNC(void, _ZN6QMutex4lockEv, void* self) { 3044 QMutex_lock_WRK(self); 3045 } 3046 QT5_FUNC(void, _ZN6QMutex4lockEv, void* self) { 3047 QMutex_lock_WRK(self); 3048 } 3049 3050 //----------------------------------------------------------- 3051 // QMutex::unlock() 3052 __attribute__((noinline)) 3053 static void QMutex_unlock_WRK(void* self) 3054 { 3055 OrigFn fn; 3056 VALGRIND_GET_ORIG_FN(fn); 3057 3058 if (TRACE_QT4_FNS) { 3059 fprintf(stderr, "<< QMutex::unlock %p", self); fflush(stderr); 3060 } 3061 3062 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE, 3063 void*, self); 3064 3065 CALL_FN_v_W(fn, self); 3066 3067 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST, 3068 void*, self); 3069 3070 if (TRACE_QT4_FNS) { 3071 fprintf(stderr, " Q::unlock done >>\n"); 3072 } 3073 } 3074 3075 QT4_FUNC(void, _ZN6QMutex6unlockEv, void* self) { 3076 QMutex_unlock_WRK(self); 3077 } 3078 QT5_FUNC(void, _ZN6QMutex6unlockEv, void* self) { 3079 QMutex_unlock_WRK(self); 3080 } 3081 3082 //----------------------------------------------------------- 3083 // bool QMutex::tryLock() 3084 // using 'long' to mimic C++ 'bool' 3085 __attribute__((noinline)) 3086 static long QMutex_tryLock_WRK(void* self) 3087 { 3088 OrigFn fn; 3089 long ret; 3090 VALGRIND_GET_ORIG_FN(fn); 3091 if (TRACE_QT4_FNS) { 3092 fprintf(stderr, "<< QMutex::tryLock %p", self); fflush(stderr); 3093 } 3094 3095 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE, 3096 void*,self, long,1/*isTryLock*/); 3097 3098 CALL_FN_W_W(ret, fn, self); 3099 3100 // assumes that only the low 8 bits of the 'bool' are significant 3101 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST, 3102 void *, self, long, (ret & 0xFF) ? True : False); 3103 3104 if (TRACE_QT4_FNS) { 3105 fprintf(stderr, " :: Q::tryLock -> %lu >>\n", ret); 3106 } 3107 3108 return ret; 3109 } 3110 3111 QT4_FUNC(long, _ZN6QMutex7tryLockEv, void* self) { 3112 return QMutex_tryLock_WRK(self); 3113 } 3114 QT5_FUNC(long, _ZN6QMutex7tryLockEv, void* self) { 3115 return QMutex_tryLock_WRK(self); 3116 } 3117 3118 //----------------------------------------------------------- 3119 // bool QMutex::tryLock(int) 3120 // using 'long' to mimic C++ 'bool' 3121 __attribute__((noinline)) 3122 static long QMutex_tryLock_int_WRK(void* self, long arg2) 3123 { 3124 OrigFn fn; 3125 long ret; 3126 VALGRIND_GET_ORIG_FN(fn); 3127 if (TRACE_QT4_FNS) { 3128 fprintf(stderr, "<< QMutex::tryLock(int) %p %d", self, (int)arg2); 3129 fflush(stderr); 3130 } 3131 3132 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE, 3133 void*,self, long,1/*isTryLock*/); 3134 3135 CALL_FN_W_WW(ret, fn, self,arg2); 3136 3137 // assumes that only the low 8 bits of the 'bool' are significant 3138 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST, 3139 void *, self, long, (ret & 0xFF) ? True : False); 3140 3141 if (TRACE_QT4_FNS) { 3142 fprintf(stderr, " :: Q::tryLock(int) -> %lu >>\n", ret); 3143 } 3144 3145 return ret; 3146 } 3147 3148 QT4_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2) { 3149 return QMutex_tryLock_int_WRK(self, arg2); 3150 } 3151 QT5_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2) { 3152 return QMutex_tryLock_int_WRK(self, arg2); 3153 } 3154 3155 //----------------------------------------------------------- 3156 // It's not really very clear what the args are here. But from 3157 // a bit of dataflow analysis of the generated machine code of 3158 // the original function, it appears this takes two args, and 3159 // returns nothing. Nevertheless preserve return value just in 3160 // case. A bit of debug printing indicates that the first arg 3161 // is that of the mutex and the second is either zero or one, 3162 // probably being the recursion mode, therefore. 3163 // QMutex::QMutex(QMutex::RecursionMode) ("C1ENS" variant) 3164 __attribute__((noinline)) 3165 static void* QMutex_constructor_WRK(void* mutex, long recmode) 3166 { 3167 OrigFn fn; 3168 long ret; 3169 VALGRIND_GET_ORIG_FN(fn); 3170 CALL_FN_W_WW(ret, fn, mutex, recmode); 3171 // fprintf(stderr, "QMutex constructor 1: %p <- %p %p\n", ret, arg1, arg2); 3172 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST, 3173 void*,mutex, long,1/*mbRec*/); 3174 return (void*)ret; 3175 } 3176 3177 QT4_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE, void* self, long recmode) { 3178 return QMutex_constructor_WRK(self, recmode); 3179 } 3180 QT5_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE, void* self, long recmode) { 3181 return QMutex_constructor_WRK(self, recmode); 3182 } 3183 3184 //----------------------------------------------------------- 3185 // QMutex::~QMutex() ("D1Ev" variant) 3186 __attribute__((noinline)) 3187 static void* QMutex_destructor_WRK(void* mutex) 3188 { 3189 OrigFn fn; 3190 long ret; 3191 VALGRIND_GET_ORIG_FN(fn); 3192 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE, 3193 void*,mutex); 3194 CALL_FN_W_W(ret, fn, mutex); 3195 return (void*)ret; 3196 } 3197 3198 QT4_FUNC(void*, _ZN6QMutexD1Ev, void* self) { 3199 return QMutex_destructor_WRK(self); 3200 } 3201 QT5_FUNC(void*, _ZN6QMutexD1Ev, void* self) { 3202 return QMutex_destructor_WRK(self); 3203 } 3204 3205 //----------------------------------------------------------- 3206 // QMutex::QMutex(QMutex::RecursionMode) ("C2ENS" variant) 3207 QT4_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE, 3208 void* mutex, 3209 long recmode) 3210 { 3211 assert(0); 3212 /*NOTREACHED*/ 3213 /* Android's gcc behaves like it doesn't know that assert(0) 3214 never returns. Hence: */ 3215 return NULL; 3216 } 3217 3218 QT5_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE, void* self, long recmode) 3219 { 3220 assert(0); 3221 /*NOTREACHED*/ 3222 return NULL; 3223 } 3224 3225 //----------------------------------------------------------- 3226 // QMutex::~QMutex() ("D2Ev" variant) 3227 QT4_FUNC(void*, _ZN6QMutexD2Ev, void* mutex) 3228 { 3229 assert(0); 3230 /* Android's gcc behaves like it doesn't know that assert(0) 3231 never returns. Hence: */ 3232 return NULL; 3233 } 3234 3235 QT5_FUNC(void*, _ZN6QMutexD2Ev, void* self) 3236 { 3237 assert(0); 3238 /*NOTREACHED*/ 3239 return NULL; 3240 } 3241 3242 // QReadWriteLock is not intercepted directly. See comments 3243 // above. 3244 3245 //// QReadWriteLock::lockForRead() 3246 //// _ZN14QReadWriteLock11lockForReadEv == QReadWriteLock::lockForRead() 3247 //QT4_FUNC(void, ZuZZN14QReadWriteLock11lockForReadEv, 3248 // // _ZN14QReadWriteLock11lockForReadEv 3249 // void* self) 3250 //{ 3251 // OrigFn fn; 3252 // VALGRIND_GET_ORIG_FN(fn); 3253 // if (TRACE_QT4_FNS) { 3254 // fprintf(stderr, "<< QReadWriteLock::lockForRead %p", self); 3255 // fflush(stderr); 3256 // } 3257 // 3258 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE, 3259 // void*,self, 3260 // long,0/*!isW*/, long,0/*!isTryLock*/); 3261 // 3262 // CALL_FN_v_W(fn, self); 3263 // 3264 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST, 3265 // void*,self, long,0/*!isW*/, long, True); 3266 // 3267 // if (TRACE_QT4_FNS) { 3268 // fprintf(stderr, " :: Q::lockForRead :: done >>\n"); 3269 // } 3270 //} 3271 // 3272 //// QReadWriteLock::lockForWrite() 3273 //// _ZN14QReadWriteLock12lockForWriteEv == QReadWriteLock::lockForWrite() 3274 //QT4_FUNC(void, ZuZZN14QReadWriteLock12lockForWriteEv, 3275 // // _ZN14QReadWriteLock12lockForWriteEv 3276 // void* self) 3277 //{ 3278 // OrigFn fn; 3279 // VALGRIND_GET_ORIG_FN(fn); 3280 // if (TRACE_QT4_FNS) { 3281 // fprintf(stderr, "<< QReadWriteLock::lockForWrite %p", self); 3282 // fflush(stderr); 3283 // } 3284 // 3285 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE, 3286 // void*,self, 3287 // long,1/*isW*/, long,0/*!isTryLock*/); 3288 // 3289 // CALL_FN_v_W(fn, self); 3290 // 3291 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST, 3292 // void*,self, long,1/*isW*/, long, True); 3293 // 3294 // if (TRACE_QT4_FNS) { 3295 // fprintf(stderr, " :: Q::lockForWrite :: done >>\n"); 3296 // } 3297 //} 3298 // 3299 //// QReadWriteLock::unlock() 3300 //// _ZN14QReadWriteLock6unlockEv == QReadWriteLock::unlock() 3301 //QT4_FUNC(void, ZuZZN14QReadWriteLock6unlockEv, 3302 // // _ZN14QReadWriteLock6unlockEv 3303 // void* self) 3304 //{ 3305 // OrigFn fn; 3306 // VALGRIND_GET_ORIG_FN(fn); 3307 // if (TRACE_QT4_FNS) { 3308 // fprintf(stderr, "<< QReadWriteLock::unlock %p", self); 3309 // fflush(stderr); 3310 // } 3311 // 3312 // DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE, 3313 // void*,self); 3314 // 3315 // CALL_FN_v_W(fn, self); 3316 // 3317 // DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST, 3318 // void*,self); 3319 // 3320 // if (TRACE_QT4_FNS) { 3321 // fprintf(stderr, " :: Q::unlock :: done >>\n"); 3322 // } 3323 //} 3324 3325 3326 /*----------------------------------------------------------------*/ 3327 /*--- Replacements for basic string functions, that don't ---*/ 3328 /*--- overrun the input arrays. ---*/ 3329 /*----------------------------------------------------------------*/ 3330 3331 #include "../shared/vg_replace_strmem.c" 3332 3333 /*--------------------------------------------------------------------*/ 3334 /*--- end hg_intercepts.c ---*/ 3335 /*--------------------------------------------------------------------*/ 3336