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