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