1 2 /*--------------------------------------------------------------------*/ 3 /*--- pthread intercepts for thread checking. ---*/ 4 /*--- tc_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-2010 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 "valgrind.h" 58 #include "helgrind.h" 59 #include "config.h" 60 61 #define TRACE_PTH_FNS 0 62 #define TRACE_QT4_FNS 0 63 64 65 /*----------------------------------------------------------------*/ 66 /*--- ---*/ 67 /*----------------------------------------------------------------*/ 68 69 #define PTH_FUNC(ret_ty, f, args...) \ 70 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args); \ 71 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args) 72 73 // Do a client request. These are macros rather than a functions so 74 // as to avoid having an extra frame in stack traces. 75 76 // NB: these duplicate definitions in helgrind.h. But here, we 77 // can have better typing (Word etc) and assertions, whereas 78 // in helgrind.h we can't. Obviously it's important the two 79 // sets of definitions are kept in sync. 80 81 // nuke the previous definitions 82 #undef DO_CREQ_v_W 83 #undef DO_CREQ_v_WW 84 #undef DO_CREQ_W_WW 85 #undef DO_CREQ_v_WWW 86 87 #define DO_CREQ_v_W(_creqF, _ty1F,_arg1F) \ 88 do { \ 89 Word _unused_res, _arg1; \ 90 assert(sizeof(_ty1F) == sizeof(Word)); \ 91 _arg1 = (Word)(_arg1F); \ 92 VALGRIND_DO_CLIENT_REQUEST(_unused_res, 0, \ 93 (_creqF), \ 94 _arg1, 0,0,0,0); \ 95 } while (0) 96 97 #define DO_CREQ_v_WW(_creqF, _ty1F,_arg1F, _ty2F,_arg2F) \ 98 do { \ 99 Word _unused_res, _arg1, _arg2; \ 100 assert(sizeof(_ty1F) == sizeof(Word)); \ 101 assert(sizeof(_ty2F) == sizeof(Word)); \ 102 _arg1 = (Word)(_arg1F); \ 103 _arg2 = (Word)(_arg2F); \ 104 VALGRIND_DO_CLIENT_REQUEST(_unused_res, 0, \ 105 (_creqF), \ 106 _arg1,_arg2,0,0,0); \ 107 } while (0) 108 109 #define DO_CREQ_W_WW(_resF, _creqF, _ty1F,_arg1F, _ty2F,_arg2F) \ 110 do { \ 111 Word _res, _arg1, _arg2; \ 112 assert(sizeof(_ty1F) == sizeof(Word)); \ 113 assert(sizeof(_ty2F) == sizeof(Word)); \ 114 _arg1 = (Word)(_arg1F); \ 115 _arg2 = (Word)(_arg2F); \ 116 VALGRIND_DO_CLIENT_REQUEST(_res, 2, \ 117 (_creqF), \ 118 _arg1,_arg2,0,0,0); \ 119 _resF = _res; \ 120 } while (0) 121 122 #define DO_CREQ_v_WWW(_creqF, _ty1F,_arg1F, \ 123 _ty2F,_arg2F, _ty3F, _arg3F) \ 124 do { \ 125 Word _unused_res, _arg1, _arg2, _arg3; \ 126 assert(sizeof(_ty1F) == sizeof(Word)); \ 127 assert(sizeof(_ty2F) == sizeof(Word)); \ 128 assert(sizeof(_ty3F) == sizeof(Word)); \ 129 _arg1 = (Word)(_arg1F); \ 130 _arg2 = (Word)(_arg2F); \ 131 _arg3 = (Word)(_arg3F); \ 132 VALGRIND_DO_CLIENT_REQUEST(_unused_res, 0, \ 133 (_creqF), \ 134 _arg1,_arg2,_arg3,0,0); \ 135 } while (0) 136 137 138 #define DO_PthAPIerror(_fnnameF, _errF) \ 139 do { \ 140 char* _fnname = (char*)(_fnnameF); \ 141 long _err = (long)(int)(_errF); \ 142 char* _errstr = lame_strerror(_err); \ 143 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTH_API_ERROR, \ 144 char*,_fnname, \ 145 long,_err, char*,_errstr); \ 146 } while (0) 147 148 149 /* Needed for older glibcs (2.3 and older, at least) who don't 150 otherwise "know" about pthread_rwlock_anything or about 151 PTHREAD_MUTEX_RECURSIVE (amongst things). */ 152 #define _GNU_SOURCE 1 153 154 #include <stdio.h> 155 #include <assert.h> 156 #include <errno.h> 157 #include <pthread.h> 158 159 160 /* A lame version of strerror which doesn't use the real libc 161 strerror_r, since using the latter just generates endless more 162 threading errors (glibc goes off and does tons of crap w.r.t. 163 locales etc) */ 164 static char* lame_strerror ( long err ) 165 { switch (err) { 166 case EPERM: return "EPERM: Operation not permitted"; 167 case ENOENT: return "ENOENT: No such file or directory"; 168 case ESRCH: return "ESRCH: No such process"; 169 case EINTR: return "EINTR: Interrupted system call"; 170 case EBADF: return "EBADF: Bad file number"; 171 case EAGAIN: return "EAGAIN: Try again"; 172 case ENOMEM: return "ENOMEM: Out of memory"; 173 case EACCES: return "EACCES: Permission denied"; 174 case EFAULT: return "EFAULT: Bad address"; 175 case EEXIST: return "EEXIST: File exists"; 176 case EINVAL: return "EINVAL: Invalid argument"; 177 case EMFILE: return "EMFILE: Too many open files"; 178 case ENOSYS: return "ENOSYS: Function not implemented"; 179 case EOVERFLOW: return "EOVERFLOW: Value too large " 180 "for defined data type"; 181 case EBUSY: return "EBUSY: Device or resource busy"; 182 case ETIMEDOUT: return "ETIMEDOUT: Connection timed out"; 183 case EDEADLK: return "EDEADLK: Resource deadlock would occur"; 184 case EOPNOTSUPP: return "EOPNOTSUPP: Operation not supported on " 185 "transport endpoint"; /* honest, guv */ 186 default: return "tc_intercepts.c: lame_strerror(): " 187 "unhandled case -- please fix me!"; 188 } 189 } 190 191 192 /*----------------------------------------------------------------*/ 193 /*--- pthread_create, pthread_join, pthread_exit ---*/ 194 /*----------------------------------------------------------------*/ 195 196 static void* mythread_wrapper ( void* xargsV ) 197 { 198 volatile Word* xargs = (volatile Word*) xargsV; 199 void*(*fn)(void*) = (void*(*)(void*))xargs[0]; 200 void* arg = (void*)xargs[1]; 201 pthread_t me = pthread_self(); 202 /* Tell the tool what my pthread_t is. */ 203 DO_CREQ_v_W(_VG_USERREQ__HG_SET_MY_PTHREAD_T, pthread_t,me); 204 /* allow the parent to proceed. We can't let it proceed until 205 we're ready because (1) we need to make sure it doesn't exit and 206 hence deallocate xargs[] while we still need it, and (2) we 207 don't want either parent nor child to proceed until the tool has 208 been notified of the child's pthread_t. 209 210 Note that parent and child access args[] without a lock, 211 effectively using args[2] as a spinlock in order to get the 212 parent to wait until the child passes this point. The parent 213 disables checking on xargs[] before creating the child and 214 re-enables it once the child goes past this point, so the user 215 never sees the race. The previous approach (suppressing the 216 resulting error) was flawed, because it could leave shadow 217 memory for args[] in a state in which subsequent use of it by 218 the parent would report further races. */ 219 xargs[2] = 0; 220 /* Now we can no longer safely use xargs[]. */ 221 return (void*) fn( (void*)arg ); 222 } 223 224 //----------------------------------------------------------- 225 // glibc: pthread_create (at) GLIBC_2.0 226 // glibc: pthread_create@@GLIBC_2.1 227 // glibc: pthread_create@@GLIBC_2.2.5 228 // darwin: pthread_create 229 // darwin: pthread_create_suspended_np (trapped) 230 // 231 /* ensure this has its own frame, so as to make it more distinguishable 232 in suppressions */ 233 __attribute__((noinline)) 234 static int pthread_create_WRK(pthread_t *thread, const pthread_attr_t *attr, 235 void *(*start) (void *), void *arg) 236 { 237 int ret; 238 OrigFn fn; 239 volatile Word xargs[3]; 240 241 VALGRIND_GET_ORIG_FN(fn); 242 if (TRACE_PTH_FNS) { 243 fprintf(stderr, "<< pthread_create wrapper"); fflush(stderr); 244 } 245 xargs[0] = (Word)start; 246 xargs[1] = (Word)arg; 247 xargs[2] = 1; /* serves as a spinlock -- sigh */ 248 /* Disable checking on the spinlock and the two words used to 249 convey args to the child. Basically we need to make it appear 250 as if the child never accessed this area, since merely 251 suppressing the resulting races does not address the issue that 252 that piece of the parent's stack winds up in the "wrong" state 253 and therefore may give rise to mysterious races when the parent 254 comes to re-use this piece of stack in some other frame. */ 255 VALGRIND_HG_DISABLE_CHECKING(&xargs, sizeof(xargs)); 256 257 CALL_FN_W_WWWW(ret, fn, thread,attr,mythread_wrapper,&xargs[0]); 258 259 if (ret == 0) { 260 /* we have to wait for the child to notify the tool of its 261 pthread_t before continuing */ 262 while (xargs[2] != 0) { 263 /* Do nothing. We need to spin until the child writes to 264 xargs[2]. However, that can lead to starvation in the 265 child and very long delays (eg, tc19_shadowmem on 266 ppc64-linux Fedora Core 6). So yield the cpu if we can, 267 to let the child run at the earliest available 268 opportunity. */ 269 sched_yield(); 270 } 271 } else { 272 DO_PthAPIerror( "pthread_create", ret ); 273 } 274 275 /* Reenable checking on the area previously used to communicate 276 with the child. */ 277 VALGRIND_HG_ENABLE_CHECKING(&xargs, sizeof(xargs)); 278 279 if (TRACE_PTH_FNS) { 280 fprintf(stderr, " :: pth_create -> %d >>\n", ret); 281 } 282 return ret; 283 } 284 #if defined(VGO_linux) 285 PTH_FUNC(int, pthreadZucreateZAZa, // pthread_create@* 286 pthread_t *thread, const pthread_attr_t *attr, 287 void *(*start) (void *), void *arg) { 288 return pthread_create_WRK(thread, attr, start, arg); 289 } 290 #elif defined(VGO_darwin) 291 PTH_FUNC(int, pthreadZucreate, // pthread_create 292 pthread_t *thread, const pthread_attr_t *attr, 293 void *(*start) (void *), void *arg) { 294 return pthread_create_WRK(thread, attr, start, arg); 295 } 296 PTH_FUNC(int, pthreadZucreateZuZa, // pthread_create_* 297 pthread_t *thread, const pthread_attr_t *attr, 298 void *(*start) (void *), void *arg) { 299 // trap anything else 300 assert(0); 301 } 302 #else 303 # error "Unsupported OS" 304 #endif 305 306 307 //----------------------------------------------------------- 308 // glibc: pthread_join 309 // darwin: pthread_join 310 // darwin: pthread_join$NOCANCEL$UNIX2003 311 // darwin pthread_join$UNIX2003 312 static int pthread_join_WRK(pthread_t thread, void** value_pointer) 313 { 314 int ret; 315 OrigFn fn; 316 VALGRIND_GET_ORIG_FN(fn); 317 if (TRACE_PTH_FNS) { 318 fprintf(stderr, "<< pthread_join wrapper"); fflush(stderr); 319 } 320 321 CALL_FN_W_WW(ret, fn, thread,value_pointer); 322 323 /* At least with NPTL as the thread library, this is safe because 324 it is guaranteed (by NPTL) that the joiner will completely gone 325 before pthread_join (the original) returns. See email below.*/ 326 if (ret == 0 /*success*/) { 327 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST, pthread_t,thread); 328 } else { 329 DO_PthAPIerror( "pthread_join", ret ); 330 } 331 332 if (TRACE_PTH_FNS) { 333 fprintf(stderr, " :: pth_join -> %d >>\n", ret); 334 } 335 return ret; 336 } 337 #if defined(VGO_linux) 338 PTH_FUNC(int, pthreadZujoin, // pthread_join 339 pthread_t thread, void** value_pointer) { 340 return pthread_join_WRK(thread, value_pointer); 341 } 342 #elif defined(VGO_darwin) 343 PTH_FUNC(int, pthreadZujoinZa, // pthread_join* 344 pthread_t thread, void** value_pointer) { 345 return pthread_join_WRK(thread, value_pointer); 346 } 347 #else 348 # error "Unsupported OS" 349 #endif 350 351 352 /* Behaviour of pthread_join on NPTL: 353 354 Me: 355 I have a question re the NPTL pthread_join implementation. 356 357 Suppose I am the thread 'stayer'. 358 359 If I call pthread_join(quitter), is it guaranteed that the 360 thread 'quitter' has really exited before pthread_join returns? 361 362 IOW, is it guaranteed that 'quitter' will not execute any further 363 instructions after pthread_join returns? 364 365 I believe this is true based on the following analysis of 366 glibc-2.5 sources. However am not 100% sure and would appreciate 367 confirmation. 368 369 'quitter' will be running start_thread() in nptl/pthread_create.c 370 371 The last action of start_thread() is to exit via 372 __exit_thread_inline(0), which simply does sys_exit 373 (nptl/pthread_create.c:403) 374 375 'stayer' meanwhile is waiting for lll_wait_tid (pd->tid) 376 (call at nptl/pthread_join.c:89) 377 378 As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536, 379 lll_wait_tid will not return until kernel notifies via futex 380 wakeup that 'quitter' has terminated. 381 382 Hence pthread_join cannot return until 'quitter' really has 383 completely disappeared. 384 385 Drepper: 386 > As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536, 387 > lll_wait_tid will not return until kernel notifies via futex 388 > wakeup that 'quitter' has terminated. 389 That's the key. The kernel resets the TID field after the thread is 390 done. No way the joiner can return before the thread is gone. 391 */ 392 393 394 /*----------------------------------------------------------------*/ 395 /*--- pthread_mutex_t functions ---*/ 396 /*----------------------------------------------------------------*/ 397 398 /* Handled: pthread_mutex_init pthread_mutex_destroy 399 pthread_mutex_lock 400 pthread_mutex_trylock pthread_mutex_timedlock 401 pthread_mutex_unlock 402 */ 403 404 //----------------------------------------------------------- 405 // glibc: pthread_mutex_init 406 // darwin: pthread_mutex_init 407 PTH_FUNC(int, pthreadZumutexZuinit, // pthread_mutex_init 408 pthread_mutex_t *mutex, 409 pthread_mutexattr_t* attr) 410 { 411 int ret; 412 long mbRec; 413 OrigFn fn; 414 VALGRIND_GET_ORIG_FN(fn); 415 if (TRACE_PTH_FNS) { 416 fprintf(stderr, "<< pthread_mxinit %p", mutex); fflush(stderr); 417 } 418 419 mbRec = 0; 420 if (attr) { 421 int ty, zzz; 422 zzz = pthread_mutexattr_gettype(attr, &ty); 423 if (zzz == 0 && ty == PTHREAD_MUTEX_RECURSIVE) 424 mbRec = 1; 425 } 426 427 CALL_FN_W_WW(ret, fn, mutex,attr); 428 429 if (ret == 0 /*success*/) { 430 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST, 431 pthread_mutex_t*,mutex, long,mbRec); 432 } else { 433 DO_PthAPIerror( "pthread_mutex_init", ret ); 434 } 435 436 if (TRACE_PTH_FNS) { 437 fprintf(stderr, " :: mxinit -> %d >>\n", ret); 438 } 439 return ret; 440 } 441 442 443 //----------------------------------------------------------- 444 // glibc: pthread_mutex_destroy 445 // darwin: pthread_mutex_destroy 446 PTH_FUNC(int, pthreadZumutexZudestroy, // pthread_mutex_destroy 447 pthread_mutex_t *mutex) 448 { 449 int ret; 450 OrigFn fn; 451 VALGRIND_GET_ORIG_FN(fn); 452 if (TRACE_PTH_FNS) { 453 fprintf(stderr, "<< pthread_mxdestroy %p", mutex); fflush(stderr); 454 } 455 456 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE, 457 pthread_mutex_t*,mutex); 458 459 CALL_FN_W_W(ret, fn, mutex); 460 461 if (ret != 0) { 462 DO_PthAPIerror( "pthread_mutex_destroy", ret ); 463 } 464 465 if (TRACE_PTH_FNS) { 466 fprintf(stderr, " :: mxdestroy -> %d >>\n", ret); 467 } 468 return ret; 469 } 470 471 472 //----------------------------------------------------------- 473 // glibc: pthread_mutex_lock 474 // darwin: pthread_mutex_lock 475 PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock 476 pthread_mutex_t *mutex) 477 { 478 int ret; 479 OrigFn fn; 480 VALGRIND_GET_ORIG_FN(fn); 481 if (TRACE_PTH_FNS) { 482 fprintf(stderr, "<< pthread_mxlock %p", mutex); fflush(stderr); 483 } 484 485 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE, 486 pthread_mutex_t*,mutex, long,0/*!isTryLock*/); 487 488 CALL_FN_W_W(ret, fn, mutex); 489 490 /* There's a hole here: libpthread now knows the lock is locked, 491 but the tool doesn't, so some other thread could run and detect 492 that the lock has been acquired by someone (this thread). Does 493 this matter? Not sure, but I don't think so. */ 494 495 if (ret == 0 /*success*/) { 496 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST, 497 pthread_mutex_t*,mutex); 498 } else { 499 DO_PthAPIerror( "pthread_mutex_lock", ret ); 500 } 501 502 if (TRACE_PTH_FNS) { 503 fprintf(stderr, " :: mxlock -> %d >>\n", ret); 504 } 505 return ret; 506 } 507 508 509 //----------------------------------------------------------- 510 // glibc: pthread_mutex_trylock 511 // darwin: pthread_mutex_trylock 512 // 513 // pthread_mutex_trylock. The handling needed here is very similar 514 // to that for pthread_mutex_lock, except that we need to tell 515 // the pre-lock creq that this is a trylock-style operation, and 516 // therefore not to complain if the lock is nonrecursive and 517 // already locked by this thread -- because then it'll just fail 518 // immediately with EBUSY. 519 PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock 520 pthread_mutex_t *mutex) 521 { 522 int ret; 523 OrigFn fn; 524 VALGRIND_GET_ORIG_FN(fn); 525 if (TRACE_PTH_FNS) { 526 fprintf(stderr, "<< pthread_mxtrylock %p", mutex); fflush(stderr); 527 } 528 529 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE, 530 pthread_mutex_t*,mutex, long,1/*isTryLock*/); 531 532 CALL_FN_W_W(ret, fn, mutex); 533 534 /* There's a hole here: libpthread now knows the lock is locked, 535 but the tool doesn't, so some other thread could run and detect 536 that the lock has been acquired by someone (this thread). Does 537 this matter? Not sure, but I don't think so. */ 538 539 if (ret == 0 /*success*/) { 540 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST, 541 pthread_mutex_t*,mutex); 542 } else { 543 if (ret != EBUSY) 544 DO_PthAPIerror( "pthread_mutex_trylock", ret ); 545 } 546 547 if (TRACE_PTH_FNS) { 548 fprintf(stderr, " :: mxtrylock -> %d >>\n", ret); 549 } 550 return ret; 551 } 552 553 554 //----------------------------------------------------------- 555 // glibc: pthread_mutex_timedlock 556 // darwin: (doesn't appear to exist) 557 // 558 // pthread_mutex_timedlock. Identical logic to pthread_mutex_trylock. 559 PTH_FUNC(int, pthreadZumutexZutimedlock, // pthread_mutex_timedlock 560 pthread_mutex_t *mutex, 561 void* timeout) 562 { 563 int ret; 564 OrigFn fn; 565 VALGRIND_GET_ORIG_FN(fn); 566 if (TRACE_PTH_FNS) { 567 fprintf(stderr, "<< pthread_mxtimedlock %p %p", mutex, timeout); 568 fflush(stderr); 569 } 570 571 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE, 572 pthread_mutex_t*,mutex, long,1/*isTryLock-ish*/); 573 574 CALL_FN_W_WW(ret, fn, mutex,timeout); 575 576 /* There's a hole here: libpthread now knows the lock is locked, 577 but the tool doesn't, so some other thread could run and detect 578 that the lock has been acquired by someone (this thread). Does 579 this matter? Not sure, but I don't think so. */ 580 581 if (ret == 0 /*success*/) { 582 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST, 583 pthread_mutex_t*,mutex); 584 } else { 585 if (ret != ETIMEDOUT) 586 DO_PthAPIerror( "pthread_mutex_timedlock", ret ); 587 } 588 589 if (TRACE_PTH_FNS) { 590 fprintf(stderr, " :: mxtimedlock -> %d >>\n", ret); 591 } 592 return ret; 593 } 594 595 596 //----------------------------------------------------------- 597 // glibc: pthread_mutex_unlock 598 // darwin: pthread_mutex_unlock 599 PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock 600 pthread_mutex_t *mutex) 601 { 602 int ret; 603 OrigFn fn; 604 VALGRIND_GET_ORIG_FN(fn); 605 606 if (TRACE_PTH_FNS) { 607 fprintf(stderr, "<< pthread_mxunlk %p", mutex); fflush(stderr); 608 } 609 610 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE, 611 pthread_mutex_t*,mutex); 612 613 CALL_FN_W_W(ret, fn, mutex); 614 615 if (ret == 0 /*success*/) { 616 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST, 617 pthread_mutex_t*,mutex); 618 } else { 619 DO_PthAPIerror( "pthread_mutex_unlock", ret ); 620 } 621 622 if (TRACE_PTH_FNS) { 623 fprintf(stderr, " mxunlk -> %d >>\n", ret); 624 } 625 return ret; 626 } 627 628 629 /*----------------------------------------------------------------*/ 630 /*--- pthread_cond_t functions ---*/ 631 /*----------------------------------------------------------------*/ 632 633 /* Handled: pthread_cond_wait pthread_cond_timedwait 634 pthread_cond_signal pthread_cond_broadcast 635 pthread_cond_destroy 636 637 Unhandled: pthread_cond_init 638 -- is this important? 639 */ 640 641 //----------------------------------------------------------- 642 // glibc: pthread_cond_wait (at) GLIBC_2.2.5 643 // glibc: pthread_cond_wait@@GLIBC_2.3.2 644 // darwin: pthread_cond_wait 645 // darwin: pthread_cond_wait$NOCANCEL$UNIX2003 646 // darwin: pthread_cond_wait$UNIX2003 647 // 648 static int pthread_cond_wait_WRK(pthread_cond_t* cond, 649 pthread_mutex_t* mutex) 650 { 651 int ret; 652 OrigFn fn; 653 unsigned long mutex_is_valid; 654 655 VALGRIND_GET_ORIG_FN(fn); 656 657 if (TRACE_PTH_FNS) { 658 fprintf(stderr, "<< pthread_cond_wait %p %p", cond, mutex); 659 fflush(stderr); 660 } 661 662 /* Tell the tool a cond-wait is about to happen, so it can check 663 for bogus argument values. In return it tells us whether it 664 thinks the mutex is valid or not. */ 665 DO_CREQ_W_WW(mutex_is_valid, 666 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE, 667 pthread_cond_t*,cond, pthread_mutex_t*,mutex); 668 assert(mutex_is_valid == 1 || mutex_is_valid == 0); 669 670 /* Tell the tool we're about to drop the mutex. This reflects the 671 fact that in a cond_wait, we show up holding the mutex, and the 672 call atomically drops the mutex and waits for the cv to be 673 signalled. */ 674 if (mutex_is_valid) { 675 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE, 676 pthread_mutex_t*,mutex); 677 } 678 679 CALL_FN_W_WW(ret, fn, cond,mutex); 680 681 /* these conditionals look stupid, but compare w/ same logic for 682 pthread_cond_timedwait below */ 683 if (ret == 0 && mutex_is_valid) { 684 /* and now we have the mutex again */ 685 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST, 686 pthread_mutex_t*,mutex); 687 } 688 689 if (ret == 0 && mutex_is_valid) { 690 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST, 691 pthread_cond_t*,cond, pthread_mutex_t*,mutex); 692 } 693 694 if (ret != 0) { 695 DO_PthAPIerror( "pthread_cond_wait", ret ); 696 } 697 698 if (TRACE_PTH_FNS) { 699 fprintf(stderr, " cowait -> %d >>\n", ret); 700 } 701 702 return ret; 703 } 704 #if defined(VGO_linux) 705 PTH_FUNC(int, pthreadZucondZuwaitZAZa, // pthread_cond_wait@* 706 pthread_cond_t* cond, pthread_mutex_t* mutex) { 707 return pthread_cond_wait_WRK(cond, mutex); 708 } 709 #elif defined(VGO_darwin) 710 PTH_FUNC(int, pthreadZucondZuwaitZa, // pthread_cond_wait* 711 pthread_cond_t* cond, pthread_mutex_t* mutex) { 712 return pthread_cond_wait_WRK(cond, mutex); 713 } 714 #else 715 # error "Unsupported OS" 716 #endif 717 718 719 //----------------------------------------------------------- 720 // glibc: pthread_cond_timedwait@@GLIBC_2.3.2 721 // glibc: pthread_cond_timedwait (at) GLIBC_2.2.5 722 // glibc: pthread_cond_timedwait (at) GLIBC_2.0 723 // darwin: pthread_cond_timedwait 724 // darwin: pthread_cond_timedwait$NOCANCEL$UNIX2003 725 // darwin: pthread_cond_timedwait$UNIX2003 726 // darwin: pthread_cond_timedwait_relative_np (trapped) 727 // 728 static int pthread_cond_timedwait_WRK(pthread_cond_t* cond, 729 pthread_mutex_t* mutex, 730 struct timespec* abstime) 731 { 732 int ret; 733 OrigFn fn; 734 unsigned long mutex_is_valid; 735 VALGRIND_GET_ORIG_FN(fn); 736 737 if (TRACE_PTH_FNS) { 738 fprintf(stderr, "<< pthread_cond_timedwait %p %p %p", 739 cond, mutex, abstime); 740 fflush(stderr); 741 } 742 743 /* Tell the tool a cond-wait is about to happen, so it can check 744 for bogus argument values. In return it tells us whether it 745 thinks the mutex is valid or not. */ 746 DO_CREQ_W_WW(mutex_is_valid, 747 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE, 748 pthread_cond_t*,cond, pthread_mutex_t*,mutex); 749 assert(mutex_is_valid == 1 || mutex_is_valid == 0); 750 751 /* Tell the tool we're about to drop the mutex. This reflects the 752 fact that in a cond_wait, we show up holding the mutex, and the 753 call atomically drops the mutex and waits for the cv to be 754 signalled. */ 755 if (mutex_is_valid) { 756 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE, 757 pthread_mutex_t*,mutex); 758 } 759 760 CALL_FN_W_WWW(ret, fn, cond,mutex,abstime); 761 762 if ((ret == 0 || ret == ETIMEDOUT) && mutex_is_valid) { 763 /* and now we have the mutex again */ 764 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST, 765 pthread_mutex_t*,mutex); 766 } 767 768 if (ret == 0 && mutex_is_valid) { 769 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST, 770 pthread_cond_t*,cond, pthread_mutex_t*,mutex); 771 } 772 773 if (ret != 0 && ret != ETIMEDOUT) { 774 DO_PthAPIerror( "pthread_cond_timedwait", ret ); 775 } 776 777 if (TRACE_PTH_FNS) { 778 fprintf(stderr, " cotimedwait -> %d >>\n", ret); 779 } 780 781 return ret; 782 } 783 #if defined(VGO_linux) 784 PTH_FUNC(int, pthreadZucondZutimedwaitZAZa, // pthread_cond_timedwait@* 785 pthread_cond_t* cond, pthread_mutex_t* mutex, 786 struct timespec* abstime) { 787 return pthread_cond_timedwait_WRK(cond, mutex, abstime); 788 } 789 #elif defined(VGO_darwin) 790 PTH_FUNC(int, pthreadZucondZutimedwait, // pthread_cond_timedwait 791 pthread_cond_t* cond, pthread_mutex_t* mutex, 792 struct timespec* abstime) { 793 return pthread_cond_timedwait_WRK(cond, mutex, abstime); 794 } 795 PTH_FUNC(int, pthreadZucondZutimedwaitZDZa, // pthread_cond_timedwait$* 796 pthread_cond_t* cond, pthread_mutex_t* mutex, 797 struct timespec* abstime) { 798 return pthread_cond_timedwait_WRK(cond, mutex, abstime); 799 } 800 PTH_FUNC(int, pthreadZucondZutimedwaitZuZa, // pthread_cond_timedwait_* 801 pthread_cond_t* cond, pthread_mutex_t* mutex, 802 struct timespec* abstime) { 803 assert(0); 804 } 805 #else 806 # error "Unsupported OS" 807 #endif 808 809 810 //----------------------------------------------------------- 811 // glibc: pthread_cond_signal (at) GLIBC_2.0 812 // glibc: pthread_cond_signal (at) GLIBC_2.2.5 813 // glibc: pthread_cond_signal@@GLIBC_2.3.2 814 // darwin: pthread_cond_signal 815 // darwin: pthread_cond_signal_thread_np (don't intercept this) 816 // 817 static int pthread_cond_signal_WRK(pthread_cond_t* cond) 818 { 819 int ret; 820 OrigFn fn; 821 VALGRIND_GET_ORIG_FN(fn); 822 823 if (TRACE_PTH_FNS) { 824 fprintf(stderr, "<< pthread_cond_signal %p", cond); 825 fflush(stderr); 826 } 827 828 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE, 829 pthread_cond_t*,cond); 830 831 CALL_FN_W_W(ret, fn, cond); 832 833 if (ret != 0) { 834 DO_PthAPIerror( "pthread_cond_signal", ret ); 835 } 836 837 if (TRACE_PTH_FNS) { 838 fprintf(stderr, " cosig -> %d >>\n", ret); 839 } 840 841 return ret; 842 } 843 #if defined(VGO_linux) 844 PTH_FUNC(int, pthreadZucondZusignalZAZa, // pthread_cond_signal@* 845 pthread_cond_t* cond) { 846 return pthread_cond_signal_WRK(cond); 847 } 848 #elif defined(VGO_darwin) 849 PTH_FUNC(int, pthreadZucondZusignal, // pthread_cond_signal 850 pthread_cond_t* cond) { 851 return pthread_cond_signal_WRK(cond); 852 } 853 #else 854 # error "Unsupported OS" 855 #endif 856 857 858 //----------------------------------------------------------- 859 // glibc: pthread_cond_broadcast (at) GLIBC_2.0 860 // glibc: pthread_cond_broadcast (at) GLIBC_2.2.5 861 // glibc: pthread_cond_broadcast@@GLIBC_2.3.2 862 // darwin: pthread_cond_broadcast 863 // 864 // Note, this is pretty much identical, from a dependency-graph 865 // point of view, with cond_signal, so the code is duplicated. 866 // Maybe it should be commoned up. 867 // 868 static int pthread_cond_broadcast_WRK(pthread_cond_t* cond) 869 { 870 int ret; 871 OrigFn fn; 872 VALGRIND_GET_ORIG_FN(fn); 873 874 if (TRACE_PTH_FNS) { 875 fprintf(stderr, "<< pthread_cond_broadcast %p", cond); 876 fflush(stderr); 877 } 878 879 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE, 880 pthread_cond_t*,cond); 881 882 CALL_FN_W_W(ret, fn, cond); 883 884 if (ret != 0) { 885 DO_PthAPIerror( "pthread_cond_broadcast", ret ); 886 } 887 888 if (TRACE_PTH_FNS) { 889 fprintf(stderr, " cobro -> %d >>\n", ret); 890 } 891 892 return ret; 893 } 894 #if defined(VGO_linux) 895 PTH_FUNC(int, pthreadZucondZubroadcastZAZa, // pthread_cond_broadcast@* 896 pthread_cond_t* cond) { 897 return pthread_cond_broadcast_WRK(cond); 898 } 899 #elif defined(VGO_darwin) 900 PTH_FUNC(int, pthreadZucondZubroadcast, // pthread_cond_broadcast 901 pthread_cond_t* cond) { 902 return pthread_cond_broadcast_WRK(cond); 903 } 904 #else 905 # error "Unsupported OS" 906 #endif 907 908 909 //----------------------------------------------------------- 910 // glibc: pthread_cond_destroy@@GLIBC_2.3.2 911 // glibc: pthread_cond_destroy (at) GLIBC_2.2.5 912 // glibc: pthread_cond_destroy (at) GLIBC_2.0 913 // darwin: pthread_cond_destroy 914 // 915 static int pthread_cond_destroy_WRK(pthread_cond_t* cond) 916 { 917 int ret; 918 OrigFn fn; 919 920 VALGRIND_GET_ORIG_FN(fn); 921 922 if (TRACE_PTH_FNS) { 923 fprintf(stderr, "<< pthread_cond_destroy %p", cond); 924 fflush(stderr); 925 } 926 927 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_DESTROY_PRE, 928 pthread_cond_t*,cond); 929 930 CALL_FN_W_W(ret, fn, cond); 931 932 if (ret != 0) { 933 DO_PthAPIerror( "pthread_cond_destroy", ret ); 934 } 935 936 if (TRACE_PTH_FNS) { 937 fprintf(stderr, " codestr -> %d >>\n", ret); 938 } 939 940 return ret; 941 } 942 #if defined(VGO_linux) 943 PTH_FUNC(int, pthreadZucondZudestroyZAZa, // pthread_cond_destroy@* 944 pthread_cond_t* cond) { 945 return pthread_cond_destroy_WRK(cond); 946 } 947 #elif defined(VGO_darwin) 948 PTH_FUNC(int, pthreadZucondZudestroy, // pthread_cond_destroy 949 pthread_cond_t* cond) { 950 return pthread_cond_destroy_WRK(cond); 951 } 952 #else 953 # error "Unsupported OS" 954 #endif 955 956 957 /*----------------------------------------------------------------*/ 958 /*--- pthread_barrier_t functions ---*/ 959 /*----------------------------------------------------------------*/ 960 961 #if defined(HAVE_PTHREAD_BARRIER_INIT) 962 963 /* Handled: pthread_barrier_init 964 pthread_barrier_wait 965 pthread_barrier_destroy 966 967 Unhandled: pthread_barrierattr_destroy 968 pthread_barrierattr_getpshared 969 pthread_barrierattr_init 970 pthread_barrierattr_setpshared 971 -- are these important? 972 */ 973 974 //----------------------------------------------------------- 975 // glibc: pthread_barrier_init 976 // darwin: (doesn't appear to exist) 977 PTH_FUNC(int, pthreadZubarrierZuinit, // pthread_barrier_init 978 pthread_barrier_t* bar, 979 pthread_barrierattr_t* attr, unsigned long count) 980 { 981 int ret; 982 OrigFn fn; 983 VALGRIND_GET_ORIG_FN(fn); 984 985 if (TRACE_PTH_FNS) { 986 fprintf(stderr, "<< pthread_barrier_init %p %p %lu", 987 bar, attr, count); 988 fflush(stderr); 989 } 990 991 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE, 992 pthread_barrier_t*, bar, 993 unsigned long, count, 994 unsigned long, 0/*!resizable*/); 995 996 CALL_FN_W_WWW(ret, fn, bar,attr,count); 997 998 if (ret != 0) { 999 DO_PthAPIerror( "pthread_barrier_init", ret ); 1000 } 1001 1002 if (TRACE_PTH_FNS) { 1003 fprintf(stderr, " pthread_barrier_init -> %d >>\n", ret); 1004 } 1005 1006 return ret; 1007 } 1008 1009 1010 //----------------------------------------------------------- 1011 // glibc: pthread_barrier_wait 1012 // darwin: (doesn't appear to exist) 1013 PTH_FUNC(int, pthreadZubarrierZuwait, // pthread_barrier_wait 1014 pthread_barrier_t* bar) 1015 { 1016 int ret; 1017 OrigFn fn; 1018 VALGRIND_GET_ORIG_FN(fn); 1019 1020 if (TRACE_PTH_FNS) { 1021 fprintf(stderr, "<< pthread_barrier_wait %p", bar); 1022 fflush(stderr); 1023 } 1024 1025 /* That this works correctly, and doesn't screw up when a thread 1026 leaving the barrier races round to the front and re-enters while 1027 other threads are still leaving it, is quite subtle. See 1028 comments in the handler for PTHREAD_BARRIER_WAIT_PRE in 1029 hg_main.c. */ 1030 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE, 1031 pthread_barrier_t*,bar); 1032 1033 CALL_FN_W_W(ret, fn, bar); 1034 1035 if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) { 1036 DO_PthAPIerror( "pthread_barrier_wait", ret ); 1037 } 1038 1039 if (TRACE_PTH_FNS) { 1040 fprintf(stderr, " pthread_barrier_wait -> %d >>\n", ret); 1041 } 1042 1043 return ret; 1044 } 1045 1046 1047 //----------------------------------------------------------- 1048 // glibc: pthread_barrier_destroy 1049 // darwin: (doesn't appear to exist) 1050 PTH_FUNC(int, pthreadZubarrierZudestroy, // pthread_barrier_destroy 1051 pthread_barrier_t* bar) 1052 { 1053 int ret; 1054 OrigFn fn; 1055 VALGRIND_GET_ORIG_FN(fn); 1056 1057 if (TRACE_PTH_FNS) { 1058 fprintf(stderr, "<< pthread_barrier_destroy %p", bar); 1059 fflush(stderr); 1060 } 1061 1062 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE, 1063 pthread_barrier_t*,bar); 1064 1065 CALL_FN_W_W(ret, fn, bar); 1066 1067 if (ret != 0) { 1068 DO_PthAPIerror( "pthread_barrier_destroy", ret ); 1069 } 1070 1071 if (TRACE_PTH_FNS) { 1072 fprintf(stderr, " pthread_barrier_destroy -> %d >>\n", ret); 1073 } 1074 1075 return ret; 1076 } 1077 1078 #endif // defined(HAVE_PTHREAD_BARRIER_INIT) 1079 1080 1081 /*----------------------------------------------------------------*/ 1082 /*--- pthread_spinlock_t functions ---*/ 1083 /*----------------------------------------------------------------*/ 1084 1085 #if defined(HAVE_PTHREAD_SPIN_LOCK) 1086 1087 /* Handled: pthread_spin_init pthread_spin_destroy 1088 pthread_spin_lock pthread_spin_trylock 1089 pthread_spin_unlock 1090 1091 Unhandled: 1092 */ 1093 1094 /* This is a nasty kludge, in that glibc "knows" that initialising a 1095 spin lock unlocks it, and pthread_spin_{init,unlock} are names for 1096 the same function. Hence we have to have a wrapper which does both 1097 things, without knowing which the user intended to happen. */ 1098 1099 //----------------------------------------------------------- 1100 // glibc: pthread_spin_init 1101 // glibc: pthread_spin_unlock 1102 // darwin: (doesn't appear to exist) 1103 static int pthread_spin_init_or_unlock_WRK(pthread_spinlock_t* lock, 1104 int pshared) { 1105 int ret; 1106 OrigFn fn; 1107 VALGRIND_GET_ORIG_FN(fn); 1108 if (TRACE_PTH_FNS) { 1109 fprintf(stderr, "<< pthread_spin_iORu %p", lock); fflush(stderr); 1110 } 1111 1112 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE, 1113 pthread_spinlock_t*, lock); 1114 1115 CALL_FN_W_WW(ret, fn, lock,pshared); 1116 1117 if (ret == 0 /*success*/) { 1118 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST, 1119 pthread_spinlock_t*,lock); 1120 } else { 1121 DO_PthAPIerror( "pthread_spinlock_{init,unlock}", ret ); 1122 } 1123 1124 if (TRACE_PTH_FNS) { 1125 fprintf(stderr, " :: spiniORu -> %d >>\n", ret); 1126 } 1127 return ret; 1128 } 1129 #if defined(VGO_linux) 1130 PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init 1131 pthread_spinlock_t* lock, int pshared) { 1132 return pthread_spin_init_or_unlock_WRK(lock, pshared); 1133 } 1134 PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock 1135 pthread_spinlock_t* lock) { 1136 /* this is never actually called */ 1137 return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/); 1138 } 1139 #elif defined(VGO_darwin) 1140 #else 1141 # error "Unsupported OS" 1142 #endif 1143 1144 1145 //----------------------------------------------------------- 1146 // glibc: pthread_spin_destroy 1147 // darwin: (doesn't appear to exist) 1148 #if defined(VGO_linux) 1149 1150 PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy 1151 pthread_spinlock_t* lock) 1152 { 1153 int ret; 1154 OrigFn fn; 1155 VALGRIND_GET_ORIG_FN(fn); 1156 if (TRACE_PTH_FNS) { 1157 fprintf(stderr, "<< pthread_spin_destroy %p", lock); 1158 fflush(stderr); 1159 } 1160 1161 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_DESTROY_PRE, 1162 pthread_spinlock_t*,lock); 1163 1164 CALL_FN_W_W(ret, fn, lock); 1165 1166 if (ret != 0) { 1167 DO_PthAPIerror( "pthread_spin_destroy", ret ); 1168 } 1169 1170 if (TRACE_PTH_FNS) { 1171 fprintf(stderr, " :: spindestroy -> %d >>\n", ret); 1172 } 1173 return ret; 1174 } 1175 1176 #elif defined(VGO_darwin) 1177 #else 1178 # error "Unsupported OS" 1179 #endif 1180 1181 1182 //----------------------------------------------------------- 1183 // glibc: pthread_spin_lock 1184 // darwin: (doesn't appear to exist) 1185 #if defined(VGO_linux) 1186 1187 PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock 1188 pthread_spinlock_t* lock) 1189 { 1190 int ret; 1191 OrigFn fn; 1192 VALGRIND_GET_ORIG_FN(fn); 1193 if (TRACE_PTH_FNS) { 1194 fprintf(stderr, "<< pthread_spinlock %p", lock); 1195 fflush(stderr); 1196 } 1197 1198 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE, 1199 pthread_spinlock_t*,lock, long,0/*!isTryLock*/); 1200 1201 CALL_FN_W_W(ret, fn, lock); 1202 1203 /* There's a hole here: libpthread now knows the lock is locked, 1204 but the tool doesn't, so some other thread could run and detect 1205 that the lock has been acquired by someone (this thread). Does 1206 this matter? Not sure, but I don't think so. */ 1207 1208 if (ret == 0 /*success*/) { 1209 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST, 1210 pthread_spinlock_t*,lock); 1211 } else { 1212 DO_PthAPIerror( "pthread_spin_lock", ret ); 1213 } 1214 1215 if (TRACE_PTH_FNS) { 1216 fprintf(stderr, " :: spinlock -> %d >>\n", ret); 1217 } 1218 return ret; 1219 } 1220 1221 #elif defined(VGO_darwin) 1222 #else 1223 # error "Unsupported OS" 1224 #endif 1225 1226 1227 //----------------------------------------------------------- 1228 // glibc: pthread_spin_trylock 1229 // darwin: (doesn't appear to exist) 1230 #if defined(VGO_linux) 1231 1232 PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock 1233 pthread_spinlock_t* lock) 1234 { 1235 int ret; 1236 OrigFn fn; 1237 VALGRIND_GET_ORIG_FN(fn); 1238 if (TRACE_PTH_FNS) { 1239 fprintf(stderr, "<< pthread_spin_trylock %p", lock); 1240 fflush(stderr); 1241 } 1242 1243 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE, 1244 pthread_spinlock_t*,lock, long,1/*isTryLock*/); 1245 1246 CALL_FN_W_W(ret, fn, lock); 1247 1248 /* There's a hole here: libpthread now knows the lock is locked, 1249 but the tool doesn't, so some other thread could run and detect 1250 that the lock has been acquired by someone (this thread). Does 1251 this matter? Not sure, but I don't think so. */ 1252 1253 if (ret == 0 /*success*/) { 1254 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST, 1255 pthread_spinlock_t*,lock); 1256 } else { 1257 if (ret != EBUSY) 1258 DO_PthAPIerror( "pthread_spin_trylock", ret ); 1259 } 1260 1261 if (TRACE_PTH_FNS) { 1262 fprintf(stderr, " :: spin_trylock -> %d >>\n", ret); 1263 } 1264 return ret; 1265 } 1266 1267 #elif defined(VGO_darwin) 1268 #else 1269 # error "Unsupported OS" 1270 #endif 1271 1272 #endif // defined(HAVE_PTHREAD_SPIN_LOCK) 1273 1274 1275 /*----------------------------------------------------------------*/ 1276 /*--- pthread_rwlock_t functions ---*/ 1277 /*----------------------------------------------------------------*/ 1278 1279 /* Handled: pthread_rwlock_init pthread_rwlock_destroy 1280 pthread_rwlock_rdlock 1281 pthread_rwlock_wrlock 1282 pthread_rwlock_unlock 1283 1284 Unhandled: pthread_rwlock_timedrdlock 1285 pthread_rwlock_tryrdlock 1286 1287 pthread_rwlock_timedwrlock 1288 pthread_rwlock_trywrlock 1289 */ 1290 1291 //----------------------------------------------------------- 1292 // glibc: pthread_rwlock_init 1293 // darwin: pthread_rwlock_init 1294 // darwin: pthread_rwlock_init$UNIX2003 1295 static int pthread_rwlock_init_WRK(pthread_rwlock_t *rwl, 1296 pthread_rwlockattr_t* attr) 1297 { 1298 int ret; 1299 OrigFn fn; 1300 VALGRIND_GET_ORIG_FN(fn); 1301 if (TRACE_PTH_FNS) { 1302 fprintf(stderr, "<< pthread_rwl_init %p", rwl); fflush(stderr); 1303 } 1304 1305 CALL_FN_W_WW(ret, fn, rwl,attr); 1306 1307 if (ret == 0 /*success*/) { 1308 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST, 1309 pthread_rwlock_t*,rwl); 1310 } else { 1311 DO_PthAPIerror( "pthread_rwlock_init", ret ); 1312 } 1313 1314 if (TRACE_PTH_FNS) { 1315 fprintf(stderr, " :: rwl_init -> %d >>\n", ret); 1316 } 1317 return ret; 1318 } 1319 #if defined(VGO_linux) 1320 PTH_FUNC(int, pthreadZurwlockZuinit, // pthread_rwlock_init 1321 pthread_rwlock_t *rwl, 1322 pthread_rwlockattr_t* attr) { 1323 return pthread_rwlock_init_WRK(rwl, attr); 1324 } 1325 #elif defined(VGO_darwin) 1326 PTH_FUNC(int, pthreadZurwlockZuinitZa, // pthread_rwlock_init* 1327 pthread_rwlock_t *rwl, 1328 pthread_rwlockattr_t* attr) { 1329 return pthread_rwlock_init_WRK(rwl, attr); 1330 } 1331 #else 1332 # error "Unsupported OS" 1333 #endif 1334 1335 1336 //----------------------------------------------------------- 1337 // glibc: pthread_rwlock_destroy 1338 // darwin: pthread_rwlock_destroy 1339 // darwin: pthread_rwlock_destroy$UNIX2003 1340 // 1341 static int pthread_rwlock_destroy_WRK(pthread_rwlock_t* rwl) 1342 { 1343 int ret; 1344 OrigFn fn; 1345 VALGRIND_GET_ORIG_FN(fn); 1346 if (TRACE_PTH_FNS) { 1347 fprintf(stderr, "<< pthread_rwl_destroy %p", rwl); fflush(stderr); 1348 } 1349 1350 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE, 1351 pthread_rwlock_t*,rwl); 1352 1353 CALL_FN_W_W(ret, fn, rwl); 1354 1355 if (ret != 0) { 1356 DO_PthAPIerror( "pthread_rwlock_destroy", ret ); 1357 } 1358 1359 if (TRACE_PTH_FNS) { 1360 fprintf(stderr, " :: rwl_destroy -> %d >>\n", ret); 1361 } 1362 return ret; 1363 } 1364 #if defined(VGO_linux) 1365 PTH_FUNC(int, pthreadZurwlockZudestroy, // pthread_rwlock_destroy 1366 pthread_rwlock_t *rwl) { 1367 return pthread_rwlock_destroy_WRK(rwl); 1368 } 1369 #elif defined(VGO_darwin) 1370 PTH_FUNC(int, pthreadZurwlockZudestroyZa, // pthread_rwlock_destroy* 1371 pthread_rwlock_t *rwl) { 1372 return pthread_rwlock_destroy_WRK(rwl); 1373 } 1374 #else 1375 # error "Unsupported OS" 1376 #endif 1377 1378 1379 //----------------------------------------------------------- 1380 // glibc: pthread_rwlock_wrlock 1381 // darwin: pthread_rwlock_wrlock 1382 // darwin: pthread_rwlock_wrlock$UNIX2003 1383 // 1384 static int pthread_rwlock_wrlock_WRK(pthread_rwlock_t* rwlock) 1385 { 1386 int ret; 1387 OrigFn fn; 1388 VALGRIND_GET_ORIG_FN(fn); 1389 if (TRACE_PTH_FNS) { 1390 fprintf(stderr, "<< pthread_rwl_wlk %p", rwlock); fflush(stderr); 1391 } 1392 1393 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE, 1394 pthread_rwlock_t*,rwlock, 1395 long,1/*isW*/, long,0/*!isTryLock*/); 1396 1397 CALL_FN_W_W(ret, fn, rwlock); 1398 1399 if (ret == 0 /*success*/) { 1400 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST, 1401 pthread_rwlock_t*,rwlock, long,1/*isW*/); 1402 } else { 1403 DO_PthAPIerror( "pthread_rwlock_wrlock", ret ); 1404 } 1405 1406 if (TRACE_PTH_FNS) { 1407 fprintf(stderr, " :: rwl_wlk -> %d >>\n", ret); 1408 } 1409 return ret; 1410 } 1411 #if defined(VGO_linux) 1412 PTH_FUNC(int, pthreadZurwlockZuwrlock, // pthread_rwlock_wrlock 1413 pthread_rwlock_t* rwlock) { 1414 return pthread_rwlock_wrlock_WRK(rwlock); 1415 } 1416 #elif defined(VGO_darwin) 1417 PTH_FUNC(int, pthreadZurwlockZuwrlockZa, // pthread_rwlock_wrlock* 1418 pthread_rwlock_t* rwlock) { 1419 return pthread_rwlock_wrlock_WRK(rwlock); 1420 } 1421 #else 1422 # error "Unsupported OS" 1423 #endif 1424 1425 1426 //----------------------------------------------------------- 1427 // glibc: pthread_rwlock_rdlock 1428 // darwin: pthread_rwlock_rdlock 1429 // darwin: pthread_rwlock_rdlock$UNIX2003 1430 // 1431 static int pthread_rwlock_rdlock_WRK(pthread_rwlock_t* rwlock) 1432 { 1433 int ret; 1434 OrigFn fn; 1435 VALGRIND_GET_ORIG_FN(fn); 1436 if (TRACE_PTH_FNS) { 1437 fprintf(stderr, "<< pthread_rwl_rlk %p", rwlock); fflush(stderr); 1438 } 1439 1440 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE, 1441 pthread_rwlock_t*,rwlock, 1442 long,0/*!isW*/, long,0/*!isTryLock*/); 1443 1444 CALL_FN_W_W(ret, fn, rwlock); 1445 1446 if (ret == 0 /*success*/) { 1447 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST, 1448 pthread_rwlock_t*,rwlock, long,0/*!isW*/); 1449 } else { 1450 DO_PthAPIerror( "pthread_rwlock_rdlock", ret ); 1451 } 1452 1453 if (TRACE_PTH_FNS) { 1454 fprintf(stderr, " :: rwl_rlk -> %d >>\n", ret); 1455 } 1456 return ret; 1457 } 1458 #if defined(VGO_linux) 1459 PTH_FUNC(int, pthreadZurwlockZurdlock, // pthread_rwlock_rdlock 1460 pthread_rwlock_t* rwlock) { 1461 return pthread_rwlock_rdlock_WRK(rwlock); 1462 } 1463 #elif defined(VGO_darwin) 1464 PTH_FUNC(int, pthreadZurwlockZurdlockZa, // pthread_rwlock_rdlock* 1465 pthread_rwlock_t* rwlock) { 1466 return pthread_rwlock_rdlock_WRK(rwlock); 1467 } 1468 #else 1469 # error "Unsupported OS" 1470 #endif 1471 1472 1473 //----------------------------------------------------------- 1474 // glibc: pthread_rwlock_trywrlock 1475 // darwin: pthread_rwlock_trywrlock 1476 // darwin: pthread_rwlock_trywrlock$UNIX2003 1477 // 1478 static int pthread_rwlock_trywrlock_WRK(pthread_rwlock_t* rwlock) 1479 { 1480 int ret; 1481 OrigFn fn; 1482 VALGRIND_GET_ORIG_FN(fn); 1483 if (TRACE_PTH_FNS) { 1484 fprintf(stderr, "<< pthread_rwl_trywlk %p", rwlock); fflush(stderr); 1485 } 1486 1487 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE, 1488 pthread_rwlock_t*,rwlock, 1489 long,1/*isW*/, long,1/*isTryLock*/); 1490 1491 CALL_FN_W_W(ret, fn, rwlock); 1492 1493 /* There's a hole here: libpthread now knows the lock is locked, 1494 but the tool doesn't, so some other thread could run and detect 1495 that the lock has been acquired by someone (this thread). Does 1496 this matter? Not sure, but I don't think so. */ 1497 1498 if (ret == 0 /*success*/) { 1499 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST, 1500 pthread_rwlock_t*,rwlock, long,1/*isW*/); 1501 } else { 1502 if (ret != EBUSY) 1503 DO_PthAPIerror( "pthread_rwlock_trywrlock", ret ); 1504 } 1505 1506 if (TRACE_PTH_FNS) { 1507 fprintf(stderr, " :: rwl_trywlk -> %d >>\n", ret); 1508 } 1509 return ret; 1510 } 1511 #if defined(VGO_linux) 1512 PTH_FUNC(int, pthreadZurwlockZutrywrlock, // pthread_rwlock_trywrlock 1513 pthread_rwlock_t* rwlock) { 1514 return pthread_rwlock_trywrlock_WRK(rwlock); 1515 } 1516 #elif defined(VGO_darwin) 1517 PTH_FUNC(int, pthreadZurwlockZutrywrlockZa, // pthread_rwlock_trywrlock* 1518 pthread_rwlock_t* rwlock) { 1519 return pthread_rwlock_trywrlock_WRK(rwlock); 1520 } 1521 #else 1522 # error "Unsupported OS" 1523 #endif 1524 1525 1526 //----------------------------------------------------------- 1527 // glibc: pthread_rwlock_tryrdlock 1528 // darwin: pthread_rwlock_trywrlock 1529 // darwin: pthread_rwlock_trywrlock$UNIX2003 1530 // 1531 static int pthread_rwlock_tryrdlock_WRK(pthread_rwlock_t* rwlock) 1532 { 1533 int ret; 1534 OrigFn fn; 1535 VALGRIND_GET_ORIG_FN(fn); 1536 if (TRACE_PTH_FNS) { 1537 fprintf(stderr, "<< pthread_rwl_tryrlk %p", rwlock); fflush(stderr); 1538 } 1539 1540 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE, 1541 pthread_rwlock_t*,rwlock, 1542 long,0/*!isW*/, long,1/*isTryLock*/); 1543 1544 CALL_FN_W_W(ret, fn, rwlock); 1545 1546 /* There's a hole here: libpthread now knows the lock is locked, 1547 but the tool doesn't, so some other thread could run and detect 1548 that the lock has been acquired by someone (this thread). Does 1549 this matter? Not sure, but I don't think so. */ 1550 1551 if (ret == 0 /*success*/) { 1552 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST, 1553 pthread_rwlock_t*,rwlock, long,0/*!isW*/); 1554 } else { 1555 if (ret != EBUSY) 1556 DO_PthAPIerror( "pthread_rwlock_tryrdlock", ret ); 1557 } 1558 1559 if (TRACE_PTH_FNS) { 1560 fprintf(stderr, " :: rwl_tryrlk -> %d >>\n", ret); 1561 } 1562 return ret; 1563 } 1564 #if defined(VGO_linux) 1565 PTH_FUNC(int, pthreadZurwlockZutryrdlock, // pthread_rwlock_tryrdlock 1566 pthread_rwlock_t* rwlock) { 1567 return pthread_rwlock_tryrdlock_WRK(rwlock); 1568 } 1569 #elif defined(VGO_darwin) 1570 PTH_FUNC(int, pthreadZurwlockZutryrdlockZa, // pthread_rwlock_tryrdlock* 1571 pthread_rwlock_t* rwlock) { 1572 return pthread_rwlock_tryrdlock_WRK(rwlock); 1573 } 1574 #else 1575 # error "Unsupported OS" 1576 #endif 1577 1578 1579 //----------------------------------------------------------- 1580 // glibc: pthread_rwlock_unlock 1581 // darwin: pthread_rwlock_unlock 1582 // darwin: pthread_rwlock_unlock$UNIX2003 1583 static int pthread_rwlock_unlock_WRK(pthread_rwlock_t* rwlock) 1584 { 1585 int ret; 1586 OrigFn fn; 1587 VALGRIND_GET_ORIG_FN(fn); 1588 if (TRACE_PTH_FNS) { 1589 fprintf(stderr, "<< pthread_rwl_unlk %p", rwlock); fflush(stderr); 1590 } 1591 1592 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE, 1593 pthread_rwlock_t*,rwlock); 1594 1595 CALL_FN_W_W(ret, fn, rwlock); 1596 1597 if (ret == 0 /*success*/) { 1598 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST, 1599 pthread_rwlock_t*,rwlock); 1600 } else { 1601 DO_PthAPIerror( "pthread_rwlock_unlock", ret ); 1602 } 1603 1604 if (TRACE_PTH_FNS) { 1605 fprintf(stderr, " :: rwl_unlk -> %d >>\n", ret); 1606 } 1607 return ret; 1608 } 1609 #if defined(VGO_linux) 1610 PTH_FUNC(int, pthreadZurwlockZuunlock, // pthread_rwlock_unlock 1611 pthread_rwlock_t* rwlock) { 1612 return pthread_rwlock_unlock_WRK(rwlock); 1613 } 1614 #elif defined(VGO_darwin) 1615 PTH_FUNC(int, pthreadZurwlockZuunlockZa, // pthread_rwlock_unlock* 1616 pthread_rwlock_t* rwlock) { 1617 return pthread_rwlock_unlock_WRK(rwlock); 1618 } 1619 #else 1620 # error "Unsupported OS" 1621 #endif 1622 1623 1624 /*----------------------------------------------------------------*/ 1625 /*--- POSIX semaphores ---*/ 1626 /*----------------------------------------------------------------*/ 1627 1628 #include <semaphore.h> 1629 #include <fcntl.h> /* O_CREAT */ 1630 1631 #define TRACE_SEM_FNS 0 1632 1633 /* Handled: 1634 int sem_init(sem_t *sem, int pshared, unsigned value); 1635 int sem_destroy(sem_t *sem); 1636 int sem_wait(sem_t *sem); 1637 int sem_post(sem_t *sem); 1638 sem_t* sem_open(const char *name, int oflag, 1639 ... [mode_t mode, unsigned value]); 1640 [complete with its idiotic semantics] 1641 int sem_close(sem_t* sem); 1642 1643 Unhandled: 1644 int sem_trywait(sem_t *sem); 1645 int sem_timedwait(sem_t *restrict sem, 1646 const struct timespec *restrict abs_timeout); 1647 */ 1648 1649 //----------------------------------------------------------- 1650 // glibc: sem_init@@GLIBC_2.2.5 1651 // glibc: sem_init@@GLIBC_2.1 1652 // glibc: sem_init (at) GLIBC_2.0 1653 // darwin: sem_init 1654 // 1655 static int sem_init_WRK(sem_t* sem, int pshared, unsigned long value) 1656 { 1657 OrigFn fn; 1658 int ret; 1659 VALGRIND_GET_ORIG_FN(fn); 1660 1661 if (TRACE_SEM_FNS) { 1662 fprintf(stderr, "<< sem_init(%p,%d,%lu) ", sem,pshared,value); 1663 fflush(stderr); 1664 } 1665 1666 CALL_FN_W_WWW(ret, fn, sem,pshared,value); 1667 1668 if (ret == 0) { 1669 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST, 1670 sem_t*, sem, unsigned long, value); 1671 } else { 1672 DO_PthAPIerror( "sem_init", errno ); 1673 } 1674 1675 if (TRACE_SEM_FNS) { 1676 fprintf(stderr, " sem_init -> %d >>\n", ret); 1677 fflush(stderr); 1678 } 1679 1680 return ret; 1681 } 1682 #if defined(VGO_linux) 1683 PTH_FUNC(int, semZuinitZAZa, // sem_init@* 1684 sem_t* sem, int pshared, unsigned long value) { 1685 return sem_init_WRK(sem, pshared, value); 1686 } 1687 #elif defined(VGO_darwin) 1688 PTH_FUNC(int, semZuinit, // sem_init 1689 sem_t* sem, int pshared, unsigned long value) { 1690 return sem_init_WRK(sem, pshared, value); 1691 } 1692 #else 1693 # error "Unsupported OS" 1694 #endif 1695 1696 1697 //----------------------------------------------------------- 1698 // glibc: sem_destroy (at) GLIBC_2.0 1699 // glibc: sem_destroy@@GLIBC_2.1 1700 // glibc: sem_destroy@@GLIBC_2.2.5 1701 // darwin: sem_destroy 1702 static int sem_destroy_WRK(sem_t* sem) 1703 { 1704 OrigFn fn; 1705 int ret; 1706 VALGRIND_GET_ORIG_FN(fn); 1707 1708 if (TRACE_SEM_FNS) { 1709 fprintf(stderr, "<< sem_destroy(%p) ", sem); 1710 fflush(stderr); 1711 } 1712 1713 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem); 1714 1715 CALL_FN_W_W(ret, fn, sem); 1716 1717 if (ret != 0) { 1718 DO_PthAPIerror( "sem_destroy", errno ); 1719 } 1720 1721 if (TRACE_SEM_FNS) { 1722 fprintf(stderr, " sem_destroy -> %d >>\n", ret); 1723 fflush(stderr); 1724 } 1725 1726 return ret; 1727 } 1728 #if defined(VGO_linux) 1729 PTH_FUNC(int, semZudestroyZAZa, // sem_destroy* 1730 sem_t* sem) { 1731 return sem_destroy_WRK(sem); 1732 } 1733 #elif defined(VGO_darwin) 1734 PTH_FUNC(int, semZudestroy, // sem_destroy 1735 sem_t* sem) { 1736 return sem_destroy_WRK(sem); 1737 } 1738 #else 1739 # error "Unsupported OS" 1740 #endif 1741 1742 1743 //----------------------------------------------------------- 1744 // glibc: sem_wait 1745 // glibc: sem_wait (at) GLIBC_2.0 1746 // glibc: sem_wait@@GLIBC_2.1 1747 // darwin: sem_wait 1748 // darwin: sem_wait$NOCANCEL$UNIX2003 1749 // darwin: sem_wait$UNIX2003 1750 // 1751 /* wait: decrement semaphore - acquire lockage */ 1752 static int sem_wait_WRK(sem_t* sem) 1753 { 1754 OrigFn fn; 1755 int ret; 1756 VALGRIND_GET_ORIG_FN(fn); 1757 1758 if (TRACE_SEM_FNS) { 1759 fprintf(stderr, "<< sem_wait(%p) ", sem); 1760 fflush(stderr); 1761 } 1762 1763 CALL_FN_W_W(ret, fn, sem); 1764 1765 if (ret == 0) { 1766 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST, sem_t*,sem); 1767 } else { 1768 DO_PthAPIerror( "sem_wait", errno ); 1769 } 1770 1771 if (TRACE_SEM_FNS) { 1772 fprintf(stderr, " sem_wait -> %d >>\n", ret); 1773 fflush(stderr); 1774 } 1775 1776 return ret; 1777 } 1778 #if defined(VGO_linux) 1779 PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */ 1780 return sem_wait_WRK(sem); 1781 } 1782 PTH_FUNC(int, semZuwaitZAZa, sem_t* sem) { /* sem_wait@* */ 1783 return sem_wait_WRK(sem); 1784 } 1785 #elif defined(VGO_darwin) 1786 PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */ 1787 return sem_wait_WRK(sem); 1788 } 1789 PTH_FUNC(int, semZuwaitZDZa, sem_t* sem) { /* sem_wait$* */ 1790 return sem_wait_WRK(sem); 1791 } 1792 #else 1793 # error "Unsupported OS" 1794 #endif 1795 1796 1797 //----------------------------------------------------------- 1798 // glibc: sem_post 1799 // glibc: sem_post (at) GLIBC_2.0 1800 // glibc: sem_post@@GLIBC_2.1 1801 // darwin: sem_post 1802 // 1803 /* post: increment semaphore - release lockage */ 1804 static int sem_post_WRK(sem_t* sem) 1805 { 1806 OrigFn fn; 1807 int ret; 1808 1809 VALGRIND_GET_ORIG_FN(fn); 1810 1811 if (TRACE_SEM_FNS) { 1812 fprintf(stderr, "<< sem_post(%p) ", sem); 1813 fflush(stderr); 1814 } 1815 1816 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_PRE, sem_t*,sem); 1817 1818 CALL_FN_W_W(ret, fn, sem); 1819 1820 if (ret != 0) { 1821 DO_PthAPIerror( "sem_post", errno ); 1822 } 1823 1824 if (TRACE_SEM_FNS) { 1825 fprintf(stderr, " sem_post -> %d >>\n", ret); 1826 fflush(stderr); 1827 } 1828 1829 return ret; 1830 } 1831 #if defined(VGO_linux) 1832 PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */ 1833 return sem_post_WRK(sem); 1834 } 1835 PTH_FUNC(int, semZupostZAZa, sem_t* sem) { /* sem_post@* */ 1836 return sem_post_WRK(sem); 1837 } 1838 #elif defined(VGO_darwin) 1839 PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */ 1840 return sem_post_WRK(sem); 1841 } 1842 #else 1843 # error "Unsupported OS" 1844 #endif 1845 1846 1847 //----------------------------------------------------------- 1848 // glibc: sem_open 1849 // darwin: sem_open 1850 // 1851 PTH_FUNC(sem_t*, semZuopen, 1852 const char* name, long oflag, 1853 long mode, unsigned long value) 1854 { 1855 /* A copy of sem_init_WRK (more or less). Is this correct? */ 1856 OrigFn fn; 1857 sem_t* ret; 1858 VALGRIND_GET_ORIG_FN(fn); 1859 1860 if (TRACE_SEM_FNS) { 1861 fprintf(stderr, "<< sem_open(\"%s\",%ld,%lx,%lu) ", 1862 name,oflag,mode,value); 1863 fflush(stderr); 1864 } 1865 1866 CALL_FN_W_WWWW(ret, fn, name,oflag,mode,value); 1867 1868 if (ret != SEM_FAILED && (oflag & O_CREAT)) { 1869 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST, 1870 sem_t*, ret, unsigned long, value); 1871 } 1872 if (ret == SEM_FAILED) { 1873 DO_PthAPIerror( "sem_open", errno ); 1874 } 1875 1876 if (TRACE_SEM_FNS) { 1877 fprintf(stderr, " sem_open -> %p >>\n", ret); 1878 fflush(stderr); 1879 } 1880 1881 return ret; 1882 } 1883 1884 1885 //----------------------------------------------------------- 1886 // glibc: sem_close 1887 // darwin: sem_close 1888 PTH_FUNC(int, sem_close, sem_t* sem) 1889 { 1890 OrigFn fn; 1891 int ret; 1892 VALGRIND_GET_ORIG_FN(fn); 1893 1894 if (TRACE_SEM_FNS) { 1895 fprintf(stderr, "<< sem_close(%p) ", sem); 1896 fflush(stderr); 1897 } 1898 1899 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem); 1900 1901 CALL_FN_W_W(ret, fn, sem); 1902 1903 if (ret != 0) { 1904 DO_PthAPIerror( "sem_close", errno ); 1905 } 1906 1907 if (TRACE_SEM_FNS) { 1908 fprintf(stderr, " close -> %d >>\n", ret); 1909 fflush(stderr); 1910 } 1911 1912 return ret; 1913 } 1914 1915 1916 /*----------------------------------------------------------------*/ 1917 /*--- Qt 4 threading functions (w/ GNU name mangling) ---*/ 1918 /*----------------------------------------------------------------*/ 1919 1920 /* Handled: 1921 QMutex::lock() 1922 QMutex::unlock() 1923 QMutex::tryLock() 1924 QMutex::tryLock(int) 1925 1926 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC1ENS_13RecursionModeE 1927 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC2ENS_13RecursionModeE 1928 QMutex::~QMutex() _ZN6QMutexD1Ev 1929 QMutex::~QMutex() _ZN6QMutexD2Ev 1930 1931 Unhandled: 1932 QReadWriteLock::lockForRead() 1933 QReadWriteLock::lockForWrite() 1934 QReadWriteLock::unlock() 1935 QReadWriteLock::tryLockForRead(int) 1936 QReadWriteLock::tryLockForRead() 1937 QReadWriteLock::tryLockForWrite(int) 1938 QReadWriteLock::tryLockForWrite() 1939 1940 QWaitCondition::wait(QMutex*, unsigned long) 1941 QWaitCondition::wakeAll() 1942 QWaitCondition::wakeOne() 1943 1944 QSemaphore::* 1945 */ 1946 /* More comments, 19 Nov 08, based on assessment of qt-4.5.0TP1, 1947 at least on Unix: 1948 1949 It's apparently only necessary to intercept QMutex, since that is 1950 not implemented using pthread_mutex_t; instead Qt4 has its own 1951 implementation based on atomics (to check the non-contended case) 1952 and pthread_cond_wait (to wait in the contended case). 1953 1954 QReadWriteLock is built on top of QMutex, counters, and a wait 1955 queue. So we don't need to handle it specially once QMutex 1956 handling is correct -- presumably the dependencies through QMutex 1957 are sufficient to avoid any false race reports. On the other hand, 1958 it is an open question whether too many dependencies are observed 1959 -- in which case we may miss races (false negatives). I suspect 1960 this is likely to be the case, unfortunately. 1961 1962 QWaitCondition is built on pthread_cond_t, pthread_mutex_t, QMutex 1963 and QReadWriteLock. Same compositional-correctness justificiation 1964 and limitations as fro QReadWriteLock. 1965 1966 Ditto QSemaphore (from cursory examination). 1967 1968 Does it matter that only QMutex is handled directly? Open 1969 question. From testing with drd/tests/qt4_* and with KDE4 apps, it 1970 appears that no false errors are reported; however it is not clear 1971 if this is causing false negatives. 1972 1973 Another problem with Qt4 is thread exiting. Threads are created 1974 with pthread_create (fine); but they detach and simply exit when 1975 done. There is no use of pthread_join, and the provided 1976 wait-for-a-thread-to-exit mechanism (QThread::wait, I believe) 1977 relies on a system of mutexes and flags. I suspect this also 1978 causes too many dependencies to appear. Consequently H sometimes 1979 fails to detect races at exit in some very short-lived racy 1980 programs, because it appears that a thread can exit _and_ have an 1981 observed dependency edge back to the main thread (presumably) 1982 before the main thread reaps the child (that is, calls 1983 QThread::wait). 1984 1985 This theory is supported by the observation that if all threads are 1986 made to wait at a pthread_barrier_t immediately before they exit, 1987 then H's detection of races in such programs becomes reliable; 1988 without the barrier, it is varies from run to run, depending 1989 (according to investigation) on whether aforementioned 1990 exit-before-reaping behaviour happens or not. 1991 1992 Finally, why is it necessary to intercept the QMutex constructors 1993 and destructors? The constructors are intercepted only as a matter 1994 of convenience, so H can print accurate "first observed at" 1995 clauses. However, it is actually necessary to intercept the 1996 destructors (as it is with pthread_mutex_destroy) in order that 1997 locks get removed from LAOG when they are destroyed. 1998 */ 1999 2000 // soname is libQtCore.so.4 ; match against libQtCore.so* 2001 #define QT4_FUNC(ret_ty, f, args...) \ 2002 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args); \ 2003 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args) 2004 2005 //----------------------------------------------------------- 2006 // QMutex::lock() 2007 QT4_FUNC(void, _ZN6QMutex4lockEv, void* self) 2008 { 2009 OrigFn fn; 2010 VALGRIND_GET_ORIG_FN(fn); 2011 if (TRACE_QT4_FNS) { 2012 fprintf(stderr, "<< QMutex::lock %p", self); fflush(stderr); 2013 } 2014 2015 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE, 2016 void*,self, long,0/*!isTryLock*/); 2017 2018 CALL_FN_v_W(fn, self); 2019 2020 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST, 2021 void*, self); 2022 2023 if (TRACE_QT4_FNS) { 2024 fprintf(stderr, " :: Q::lock done >>\n"); 2025 } 2026 } 2027 2028 //----------------------------------------------------------- 2029 // QMutex::unlock() 2030 QT4_FUNC(void, _ZN6QMutex6unlockEv, void* self) 2031 { 2032 OrigFn fn; 2033 VALGRIND_GET_ORIG_FN(fn); 2034 2035 if (TRACE_QT4_FNS) { 2036 fprintf(stderr, "<< QMutex::unlock %p", self); fflush(stderr); 2037 } 2038 2039 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE, 2040 void*, self); 2041 2042 CALL_FN_v_W(fn, self); 2043 2044 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST, 2045 void*, self); 2046 2047 if (TRACE_QT4_FNS) { 2048 fprintf(stderr, " Q::unlock done >>\n"); 2049 } 2050 } 2051 2052 //----------------------------------------------------------- 2053 // bool QMutex::tryLock() 2054 // using 'long' to mimic C++ 'bool' 2055 QT4_FUNC(long, _ZN6QMutex7tryLockEv, void* self) 2056 { 2057 OrigFn fn; 2058 long ret; 2059 VALGRIND_GET_ORIG_FN(fn); 2060 if (TRACE_QT4_FNS) { 2061 fprintf(stderr, "<< QMutex::tryLock %p", self); fflush(stderr); 2062 } 2063 2064 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE, 2065 void*,self, long,1/*isTryLock*/); 2066 2067 CALL_FN_W_W(ret, fn, self); 2068 2069 // assumes that only the low 8 bits of the 'bool' are significant 2070 if (ret & 0xFF) { 2071 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST, 2072 void*, self); 2073 } 2074 2075 if (TRACE_QT4_FNS) { 2076 fprintf(stderr, " :: Q::tryLock -> %lu >>\n", ret); 2077 } 2078 2079 return ret; 2080 } 2081 2082 //----------------------------------------------------------- 2083 // bool QMutex::tryLock(int) 2084 // using 'long' to mimic C++ 'bool' 2085 QT4_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2) 2086 { 2087 OrigFn fn; 2088 long ret; 2089 VALGRIND_GET_ORIG_FN(fn); 2090 if (TRACE_QT4_FNS) { 2091 fprintf(stderr, "<< QMutex::tryLock(int) %p %d", self, (int)arg2); 2092 fflush(stderr); 2093 } 2094 2095 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE, 2096 void*,self, long,1/*isTryLock*/); 2097 2098 CALL_FN_W_WW(ret, fn, self,arg2); 2099 2100 // assumes that only the low 8 bits of the 'bool' are significant 2101 if (ret & 0xFF) { 2102 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST, 2103 void*, self); 2104 } 2105 2106 if (TRACE_QT4_FNS) { 2107 fprintf(stderr, " :: Q::tryLock(int) -> %lu >>\n", ret); 2108 } 2109 2110 return ret; 2111 } 2112 2113 2114 //----------------------------------------------------------- 2115 // It's not really very clear what the args are here. But from 2116 // a bit of dataflow analysis of the generated machine code of 2117 // the original function, it appears this takes two args, and 2118 // returns nothing. Nevertheless preserve return value just in 2119 // case. A bit of debug printing indicates that the first arg 2120 // is that of the mutex and the second is either zero or one, 2121 // probably being the recursion mode, therefore. 2122 // QMutex::QMutex(QMutex::RecursionMode) ("C1ENS" variant) 2123 QT4_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE, 2124 void* mutex, 2125 long recmode) 2126 { 2127 OrigFn fn; 2128 long ret; 2129 VALGRIND_GET_ORIG_FN(fn); 2130 CALL_FN_W_WW(ret, fn, mutex, recmode); 2131 // fprintf(stderr, "QMutex constructor 1: %p <- %p %p\n", ret, arg1, arg2); 2132 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST, 2133 void*,mutex, long,1/*mbRec*/); 2134 return (void*)ret; 2135 } 2136 2137 //----------------------------------------------------------- 2138 // QMutex::~QMutex() ("D1Ev" variant) 2139 QT4_FUNC(void*, _ZN6QMutexD1Ev, void* mutex) 2140 { 2141 OrigFn fn; 2142 long ret; 2143 VALGRIND_GET_ORIG_FN(fn); 2144 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE, 2145 void*,mutex); 2146 CALL_FN_W_W(ret, fn, mutex); 2147 return (void*)ret; 2148 } 2149 2150 2151 //----------------------------------------------------------- 2152 // QMutex::QMutex(QMutex::RecursionMode) ("C2ENS" variant) 2153 QT4_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE, 2154 void* mutex, 2155 long recmode) 2156 { 2157 assert(0); 2158 #ifdef ANDROID // error: control reaches end of non-void function 2159 return 0; 2160 #endif 2161 } 2162 2163 2164 //----------------------------------------------------------- 2165 // QMutex::~QMutex() ("D2Ev" variant) 2166 QT4_FUNC(void*, _ZN6QMutexD2Ev, void* mutex) 2167 { 2168 assert(0); 2169 #ifdef ANDROID // error: control reaches end of non-void function 2170 return 0; 2171 #endif 2172 } 2173 2174 2175 // QReadWriteLock is not intercepted directly. See comments 2176 // above. 2177 2178 //// QReadWriteLock::lockForRead() 2179 //// _ZN14QReadWriteLock11lockForReadEv == QReadWriteLock::lockForRead() 2180 //QT4_FUNC(void, ZuZZN14QReadWriteLock11lockForReadEv, 2181 // // _ZN14QReadWriteLock11lockForReadEv 2182 // void* self) 2183 //{ 2184 // OrigFn fn; 2185 // VALGRIND_GET_ORIG_FN(fn); 2186 // if (TRACE_QT4_FNS) { 2187 // fprintf(stderr, "<< QReadWriteLock::lockForRead %p", self); 2188 // fflush(stderr); 2189 // } 2190 // 2191 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE, 2192 // void*,self, 2193 // long,0/*!isW*/, long,0/*!isTryLock*/); 2194 // 2195 // CALL_FN_v_W(fn, self); 2196 // 2197 // DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST, 2198 // void*,self, long,0/*!isW*/); 2199 // 2200 // if (TRACE_QT4_FNS) { 2201 // fprintf(stderr, " :: Q::lockForRead :: done >>\n"); 2202 // } 2203 //} 2204 // 2205 //// QReadWriteLock::lockForWrite() 2206 //// _ZN14QReadWriteLock12lockForWriteEv == QReadWriteLock::lockForWrite() 2207 //QT4_FUNC(void, ZuZZN14QReadWriteLock12lockForWriteEv, 2208 // // _ZN14QReadWriteLock12lockForWriteEv 2209 // void* self) 2210 //{ 2211 // OrigFn fn; 2212 // VALGRIND_GET_ORIG_FN(fn); 2213 // if (TRACE_QT4_FNS) { 2214 // fprintf(stderr, "<< QReadWriteLock::lockForWrite %p", self); 2215 // fflush(stderr); 2216 // } 2217 // 2218 // DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE, 2219 // void*,self, 2220 // long,1/*isW*/, long,0/*!isTryLock*/); 2221 // 2222 // CALL_FN_v_W(fn, self); 2223 // 2224 // DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST, 2225 // void*,self, long,1/*isW*/); 2226 // 2227 // if (TRACE_QT4_FNS) { 2228 // fprintf(stderr, " :: Q::lockForWrite :: done >>\n"); 2229 // } 2230 //} 2231 // 2232 //// QReadWriteLock::unlock() 2233 //// _ZN14QReadWriteLock6unlockEv == QReadWriteLock::unlock() 2234 //QT4_FUNC(void, ZuZZN14QReadWriteLock6unlockEv, 2235 // // _ZN14QReadWriteLock6unlockEv 2236 // void* self) 2237 //{ 2238 // OrigFn fn; 2239 // VALGRIND_GET_ORIG_FN(fn); 2240 // if (TRACE_QT4_FNS) { 2241 // fprintf(stderr, "<< QReadWriteLock::unlock %p", self); 2242 // fflush(stderr); 2243 // } 2244 // 2245 // DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE, 2246 // void*,self); 2247 // 2248 // CALL_FN_v_W(fn, self); 2249 // 2250 // DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST, 2251 // void*,self); 2252 // 2253 // if (TRACE_QT4_FNS) { 2254 // fprintf(stderr, " :: Q::unlock :: done >>\n"); 2255 // } 2256 //} 2257 2258 2259 /*----------------------------------------------------------------*/ 2260 /*--- Replacements for basic string functions, that don't ---*/ 2261 /*--- overrun the input arrays. ---*/ 2262 /*----------------------------------------------------------------*/ 2263 2264 /* Copied verbatim from memcheck/mc_replace_strmem.c. When copying 2265 new functions, please keep them in the same order as they appear in 2266 mc_replace_strmem.c. */ 2267 2268 2269 #define STRCHR(soname, fnname) \ 2270 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( const char* s, int c ); \ 2271 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( const char* s, int c ) \ 2272 { \ 2273 UChar ch = (UChar)((UInt)c); \ 2274 UChar* p = (UChar*)s; \ 2275 while (True) { \ 2276 if (*p == ch) return p; \ 2277 if (*p == 0) return NULL; \ 2278 p++; \ 2279 } \ 2280 } 2281 2282 // Apparently index() is the same thing as strchr() 2283 STRCHR(VG_Z_LIBC_SONAME, strchr) 2284 STRCHR(VG_Z_LIBC_SONAME, index) 2285 #if defined(VGO_linux) 2286 STRCHR(VG_Z_LD_LINUX_SO_2, strchr) 2287 STRCHR(VG_Z_LD_LINUX_SO_2, index) 2288 STRCHR(VG_Z_LD_LINUX_X86_64_SO_2, strchr) 2289 STRCHR(VG_Z_LD_LINUX_X86_64_SO_2, index) 2290 #endif 2291 2292 2293 // Note that this replacement often doesn't get used because gcc inlines 2294 // calls to strlen() with its own built-in version. This can be very 2295 // confusing if you aren't expecting it. Other small functions in this file 2296 // may also be inline by gcc. 2297 #define STRLEN(soname, fnname) \ 2298 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname)( const char* str ); \ 2299 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname)( const char* str ) \ 2300 { \ 2301 SizeT i = 0; \ 2302 while (str[i] != 0) i++; \ 2303 return i; \ 2304 } 2305 2306 STRLEN(VG_Z_LIBC_SONAME, strlen) 2307 #if defined(VGO_linux) 2308 STRLEN(VG_Z_LD_LINUX_SO_2, strlen) 2309 STRLEN(VG_Z_LD_LINUX_X86_64_SO_2, strlen) 2310 #endif 2311 2312 2313 #define STRCPY(soname, fnname) \ 2314 char* VG_REPLACE_FUNCTION_ZU(soname, fnname) ( char* dst, const char* src ); \ 2315 char* VG_REPLACE_FUNCTION_ZU(soname, fnname) ( char* dst, const char* src ) \ 2316 { \ 2317 const Char* dst_orig = dst; \ 2318 \ 2319 while (*src) *dst++ = *src++; \ 2320 *dst = 0; \ 2321 \ 2322 return (char*)dst_orig; \ 2323 } 2324 2325 STRCPY(VG_Z_LIBC_SONAME, strcpy) 2326 2327 2328 #define STRCMP(soname, fnname) \ 2329 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \ 2330 ( const char* s1, const char* s2 ); \ 2331 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \ 2332 ( const char* s1, const char* s2 ) \ 2333 { \ 2334 register unsigned char c1; \ 2335 register unsigned char c2; \ 2336 while (True) { \ 2337 c1 = *(unsigned char *)s1; \ 2338 c2 = *(unsigned char *)s2; \ 2339 if (c1 != c2) break; \ 2340 if (c1 == 0) break; \ 2341 s1++; s2++; \ 2342 } \ 2343 if ((unsigned char)c1 < (unsigned char)c2) return -1; \ 2344 if ((unsigned char)c1 > (unsigned char)c2) return 1; \ 2345 return 0; \ 2346 } 2347 2348 STRCMP(VG_Z_LIBC_SONAME, strcmp) 2349 #if defined(VGO_linux) 2350 STRCMP(VG_Z_LD_LINUX_X86_64_SO_2, strcmp) 2351 STRCMP(VG_Z_LD64_SO_1, strcmp) 2352 #endif 2353 2354 2355 #define MEMCPY(soname, fnname) \ 2356 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \ 2357 ( void *dst, const void *src, SizeT len ); \ 2358 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \ 2359 ( void *dst, const void *src, SizeT len ) \ 2360 { \ 2361 register char *d; \ 2362 register char *s; \ 2363 \ 2364 if (len == 0) \ 2365 return dst; \ 2366 \ 2367 if ( dst > src ) { \ 2368 d = (char *)dst + len - 1; \ 2369 s = (char *)src + len - 1; \ 2370 while ( len >= 4 ) { \ 2371 *d-- = *s--; \ 2372 *d-- = *s--; \ 2373 *d-- = *s--; \ 2374 *d-- = *s--; \ 2375 len -= 4; \ 2376 } \ 2377 while ( len-- ) { \ 2378 *d-- = *s--; \ 2379 } \ 2380 } else if ( dst < src ) { \ 2381 d = (char *)dst; \ 2382 s = (char *)src; \ 2383 while ( len >= 4 ) { \ 2384 *d++ = *s++; \ 2385 *d++ = *s++; \ 2386 *d++ = *s++; \ 2387 *d++ = *s++; \ 2388 len -= 4; \ 2389 } \ 2390 while ( len-- ) { \ 2391 *d++ = *s++; \ 2392 } \ 2393 } \ 2394 return dst; \ 2395 } 2396 2397 MEMCPY(VG_Z_LIBC_SONAME, memcpy) 2398 #if defined(VGO_linux) 2399 MEMCPY(VG_Z_LD_SO_1, memcpy) /* ld.so.1 */ 2400 MEMCPY(VG_Z_LD64_SO_1, memcpy) /* ld64.so.1 */ 2401 #endif 2402 /* icc9 blats these around all over the place. Not only in the main 2403 executable but various .so's. They are highly tuned and read 2404 memory beyond the source boundary (although work correctly and 2405 never go across page boundaries), so give errors when run natively, 2406 at least for misaligned source arg. Just intercepting in the exe 2407 only until we understand more about the problem. See 2408 http://bugs.kde.org/show_bug.cgi?id=139776 2409 */ 2410 MEMCPY(NONE, _intel_fast_memcpy) 2411 2412 2413 /*--------------------------------------------------------------------*/ 2414 /*--- end tc_intercepts.c ---*/ 2415 /*--------------------------------------------------------------------*/ 2416