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