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