tsan_unittest.cpp revision 4b1a65eab75499b553e57e6710dcd4b2da0f0574
1/* 2 This file is part of Valgrind, a dynamic binary instrumentation 3 framework. 4 5 Copyright (C) 2008-2008 Google Inc 6 opensource@google.com 7 8 This program is free software; you can redistribute it and/or 9 modify it under the terms of the GNU General Public License as 10 published by the Free Software Foundation; either version 2 of the 11 License, or (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, but 14 WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 21 02111-1307, USA. 22 23 The GNU General Public License is contained in the file COPYING. 24*/ 25 26// Author: Konstantin Serebryany <opensource@google.com> 27// 28// This file contains a set of unit tests for a data race detection tool. 29// 30// 31// 32// This test can be compiled with pthreads (default) or 33// with any other library that supports threads, locks, cond vars, etc. 34// 35// To compile with pthreads: 36// g++ racecheck_unittest.cc dynamic_annotations.cc 37// -lpthread -g -DDYNAMIC_ANNOTATIONS=1 38// 39// To compile with different library: 40// 1. cp thread_wrappers_pthread.h thread_wrappers_yourlib.h 41// 2. edit thread_wrappers_yourlib.h 42// 3. add '-DTHREAD_WRAPPERS="thread_wrappers_yourlib.h"' to your compilation. 43// 44// 45 46// This test must not include any other file specific to threading library, 47// everything should be inside THREAD_WRAPPERS. 48#ifndef THREAD_WRAPPERS 49# define THREAD_WRAPPERS "thread_wrappers_pthread.h" 50#endif 51#include THREAD_WRAPPERS 52 53#ifndef NEEDS_SEPERATE_RW_LOCK 54#define RWLock Mutex // Mutex does work as an rw-lock. 55#define WriterLockScoped MutexLock 56#define ReaderLockScoped ReaderMutexLock 57#endif // !NEEDS_SEPERATE_RW_LOCK 58 59 60// Helgrind memory usage testing stuff 61// If not present in dynamic_annotations.h/.cc - ignore 62#ifndef ANNOTATE_RESET_STATS 63#define ANNOTATE_RESET_STATS() do { } while(0) 64#endif 65#ifndef ANNOTATE_PRINT_STATS 66#define ANNOTATE_PRINT_STATS() do { } while(0) 67#endif 68#ifndef ANNOTATE_PRINT_MEMORY_USAGE 69#define ANNOTATE_PRINT_MEMORY_USAGE(a) do { } while(0) 70#endif 71// 72 73#include <vector> 74#include <string> 75#include <map> 76#include <queue> 77#include <algorithm> 78#include <cstring> // strlen(), index(), rindex() 79#include <ctime> 80#include <sys/time.h> 81#include <sys/types.h> 82#include <sys/stat.h> 83#include <fcntl.h> 84#include <sys/mman.h> // mmap 85#include <errno.h> 86#include <stdlib.h> 87#include <dirent.h> 88 89#ifndef _APPLE_ 90#include <malloc.h> 91#endif 92 93// The tests are 94// - Stability tests (marked STAB) 95// - Performance tests (marked PERF) 96// - Feature tests 97// - TN (true negative) : no race exists and the tool is silent. 98// - TP (true positive) : a race exists and reported. 99// - FN (false negative): a race exists but not reported. 100// - FP (false positive): no race exists but the tool reports it. 101// 102// The feature tests are marked according to the behavior of helgrind 3.3.0. 103// 104// TP and FP tests are annotated with ANNOTATE_EXPECT_RACE, 105// so, no error reports should be seen when running under helgrind. 106// 107// When some of the FP cases are fixed in helgrind we'll need 108// to update this test. 109// 110// Each test resides in its own namespace. 111// Namespaces are named test01, test02, ... 112// Please, *DO NOT* change the logic of existing tests nor rename them. 113// Create a new test instead. 114// 115// Some tests use sleep()/usleep(). 116// This is not a synchronization, but a simple way to trigger 117// some specific behaviour of the race detector's scheduler. 118 119// Globals and utilities used by several tests. {{{1 120CondVar CV; 121int COND = 0; 122 123 124typedef void (*void_func_void_t)(void); 125enum TEST_FLAG { 126 FEATURE = 1 << 0, 127 STABILITY = 1 << 1, 128 PERFORMANCE = 1 << 2, 129 EXCLUDE_FROM_ALL = 1 << 3, 130 NEEDS_ANNOTATIONS = 1 << 4, 131 RACE_DEMO = 1 << 5, 132 MEMORY_USAGE = 1 << 6, 133 PRINT_STATS = 1 << 7 134}; 135 136// Put everything into stderr. 137Mutex printf_mu; 138#define printf(args...) \ 139 do{ \ 140 printf_mu.Lock();\ 141 fprintf(stderr, args);\ 142 printf_mu.Unlock(); \ 143 }while(0) 144 145long GetTimeInMs() { 146 struct timeval tv; 147 gettimeofday(&tv, NULL); 148 return (tv.tv_sec * 1000L) + (tv.tv_usec / 1000L); 149} 150 151struct Test{ 152 void_func_void_t f_; 153 int flags_; 154 Test(void_func_void_t f, int flags) 155 : f_(f) 156 , flags_(flags) 157 {} 158 Test() : f_(0), flags_(0) {} 159 void Run() { 160 ANNOTATE_RESET_STATS(); 161 if (flags_ & PERFORMANCE) { 162 long start = GetTimeInMs(); 163 f_(); 164 long end = GetTimeInMs(); 165 printf ("Time: %4ldms\n", end-start); 166 } else 167 f_(); 168 if (flags_ & PRINT_STATS) 169 ANNOTATE_PRINT_STATS(); 170 if (flags_ & MEMORY_USAGE) 171 ANNOTATE_PRINT_MEMORY_USAGE(0); 172 } 173}; 174std::map<int, Test> TheMapOfTests; 175 176#define NOINLINE __attribute__ ((noinline)) 177extern "C" void NOINLINE AnnotateSetVerbosity(const char *, int, int) {}; 178 179 180struct TestAdder { 181 TestAdder(void_func_void_t f, int id, int flags = FEATURE) { 182 // AnnotateSetVerbosity(__FILE__, __LINE__, 0); 183 CHECK(TheMapOfTests.count(id) == 0); 184 TheMapOfTests[id] = Test(f, flags); 185 } 186}; 187 188#define REGISTER_TEST(f, id) TestAdder add_test_##id (f, id); 189#define REGISTER_TEST2(f, id, flags) TestAdder add_test_##id (f, id, flags); 190 191static bool ArgIsOne(int *arg) { return *arg == 1; }; 192static bool ArgIsZero(int *arg) { return *arg == 0; }; 193static bool ArgIsTrue(bool *arg) { return *arg == true; }; 194 195// Call ANNOTATE_EXPECT_RACE only if 'machine' env variable is defined. 196// Useful to test against several different machines. 197// Supported machines so far: 198// MSM_HYBRID1 -- aka MSMProp1 199// MSM_HYBRID1_INIT_STATE -- aka MSMProp1 with --initialization-state=yes 200// MSM_THREAD_SANITIZER -- ThreadSanitizer's state machine 201#define ANNOTATE_EXPECT_RACE_FOR_MACHINE(mem, descr, machine) \ 202 while(getenv(machine)) {\ 203 ANNOTATE_EXPECT_RACE(mem, descr); \ 204 break;\ 205 }\ 206 207#define ANNOTATE_EXPECT_RACE_FOR_TSAN(mem, descr) \ 208 ANNOTATE_EXPECT_RACE_FOR_MACHINE(mem, descr, "MSM_THREAD_SANITIZER") 209 210inline bool Tsan_PureHappensBefore() { 211 return true; 212} 213 214inline bool Tsan_FastMode() { 215 return getenv("TSAN_FAST_MODE") != NULL; 216} 217 218// Initialize *(mem) to 0 if Tsan_FastMode. 219#define FAST_MODE_INIT(mem) do { if (Tsan_FastMode()) { *(mem) = 0; } } while(0) 220 221#ifndef MAIN_INIT_ACTION 222#define MAIN_INIT_ACTION 223#endif 224 225 226 227int main(int argc, char** argv) { // {{{1 228 MAIN_INIT_ACTION; 229 printf("FLAGS [phb=%i, fm=%i]\n", Tsan_PureHappensBefore(), Tsan_FastMode()); 230 if (argc == 2 && !strcmp(argv[1], "benchmark")) { 231 for (std::map<int,Test>::iterator it = TheMapOfTests.begin(); 232 it != TheMapOfTests.end(); ++it) { 233 if(!(it->second.flags_ & PERFORMANCE)) continue; 234 it->second.Run(); 235 } 236 } else if (argc == 2 && !strcmp(argv[1], "demo")) { 237 for (std::map<int,Test>::iterator it = TheMapOfTests.begin(); 238 it != TheMapOfTests.end(); ++it) { 239 if(!(it->second.flags_ & RACE_DEMO)) continue; 240 it->second.Run(); 241 } 242 } else if (argc > 1) { 243 // the tests are listed in command line flags 244 for (int i = 1; i < argc; i++) { 245 int f_num = atoi(argv[i]); 246 CHECK(TheMapOfTests.count(f_num)); 247 TheMapOfTests[f_num].Run(); 248 } 249 } else { 250 bool run_tests_with_annotations = false; 251 if (getenv("DRT_ALLOW_ANNOTATIONS")) { 252 run_tests_with_annotations = true; 253 } 254 for (std::map<int,Test>::iterator it = TheMapOfTests.begin(); 255 it != TheMapOfTests.end(); 256 ++it) { 257 if(it->second.flags_ & EXCLUDE_FROM_ALL) continue; 258 if(it->second.flags_ & RACE_DEMO) continue; 259 if((it->second.flags_ & NEEDS_ANNOTATIONS) 260 && run_tests_with_annotations == false) continue; 261 it->second.Run(); 262 } 263 } 264} 265 266#ifdef THREAD_WRAPPERS_PTHREAD_H 267#endif 268 269 270// An array of threads. Create/start/join all elements at once. {{{1 271class MyThreadArray { 272 public: 273 static const int kSize = 5; 274 typedef void (*F) (void); 275 MyThreadArray(F f1, F f2 = NULL, F f3 = NULL, F f4 = NULL, F f5 = NULL) { 276 ar_[0] = new MyThread(f1); 277 ar_[1] = f2 ? new MyThread(f2) : NULL; 278 ar_[2] = f3 ? new MyThread(f3) : NULL; 279 ar_[3] = f4 ? new MyThread(f4) : NULL; 280 ar_[4] = f5 ? new MyThread(f5) : NULL; 281 } 282 void Start() { 283 for(int i = 0; i < kSize; i++) { 284 if(ar_[i]) { 285 ar_[i]->Start(); 286 usleep(10); 287 } 288 } 289 } 290 291 void Join() { 292 for(int i = 0; i < kSize; i++) { 293 if(ar_[i]) { 294 ar_[i]->Join(); 295 } 296 } 297 } 298 299 ~MyThreadArray() { 300 for(int i = 0; i < kSize; i++) { 301 delete ar_[i]; 302 } 303 } 304 private: 305 MyThread *ar_[kSize]; 306}; 307 308 309 310// test00: {{{1 311namespace test00 { 312int GLOB = 0; 313void Run() { 314 printf("test00: negative\n"); 315 printf("\tGLOB=%d\n", GLOB); 316} 317REGISTER_TEST(Run, 00) 318} // namespace test00 319 320 321// test01: TP. Simple race (write vs write). {{{1 322namespace test01 { 323int GLOB = 0; 324void Worker() { 325 GLOB = 1; 326} 327 328void Parent() { 329 MyThread t(Worker); 330 t.Start(); 331 GLOB = 2; 332 t.Join(); 333} 334void Run() { 335 FAST_MODE_INIT(&GLOB); 336 ANNOTATE_EXPECT_RACE_FOR_TSAN(&GLOB, "test01. TP."); 337 ANNOTATE_TRACE_MEMORY(&GLOB); 338 printf("test01: positive\n"); 339 Parent(); 340 const int tmp = GLOB; 341 printf("\tGLOB=%d\n", tmp); 342} 343REGISTER_TEST(Run, 1); 344} // namespace test01 345 346 347// test02: TN. Synchronization via CondVar. {{{1 348namespace test02 { 349int GLOB = 0; 350// Two write accesses to GLOB are synchronized because 351// the pair of CV.Signal() and CV.Wait() establish happens-before relation. 352// 353// Waiter: Waker: 354// 1. COND = 0 355// 2. Start(Waker) 356// 3. MU.Lock() a. write(GLOB) 357// b. MU.Lock() 358// c. COND = 1 359// /--- d. CV.Signal() 360// 4. while(COND) / e. MU.Unlock() 361// CV.Wait(MU) <---/ 362// 5. MU.Unlock() 363// 6. write(GLOB) 364Mutex MU; 365 366void Waker() { 367 usleep(100000); // Make sure the waiter blocks. 368 GLOB = 1; 369 370 MU.Lock(); 371 COND = 1; 372 CV.Signal(); 373 MU.Unlock(); 374} 375 376void Waiter() { 377 ThreadPool pool(1); 378 pool.StartWorkers(); 379 COND = 0; 380 pool.Add(NewCallback(Waker)); 381 MU.Lock(); 382 while(COND != 1) 383 CV.Wait(&MU); 384 MU.Unlock(); 385 GLOB = 2; 386} 387void Run() { 388 printf("test02: negative\n"); 389 Waiter(); 390 printf("\tGLOB=%d\n", GLOB); 391} 392REGISTER_TEST(Run, 2); 393} // namespace test02 394 395 396// test03: TN. Synchronization via LockWhen, signaller gets there first. {{{1 397namespace test03 { 398int GLOB = 0; 399// Two write accesses to GLOB are synchronized via conditional critical section. 400// Note that LockWhen() happens first (we use sleep(1) to make sure)! 401// 402// Waiter: Waker: 403// 1. COND = 0 404// 2. Start(Waker) 405// a. write(GLOB) 406// b. MU.Lock() 407// c. COND = 1 408// /--- d. MU.Unlock() 409// 3. MU.LockWhen(COND==1) <---/ 410// 4. MU.Unlock() 411// 5. write(GLOB) 412Mutex MU; 413 414void Waker() { 415 usleep(100000); // Make sure the waiter blocks. 416 GLOB = 1; 417 418 MU.Lock(); 419 COND = 1; // We are done! Tell the Waiter. 420 MU.Unlock(); // calls ANNOTATE_CONDVAR_SIGNAL; 421} 422void Waiter() { 423 ThreadPool pool(1); 424 pool.StartWorkers(); 425 COND = 0; 426 pool.Add(NewCallback(Waker)); 427 MU.LockWhen(Condition(&ArgIsOne, &COND)); // calls ANNOTATE_CONDVAR_WAIT 428 MU.Unlock(); // Waker is done! 429 430 GLOB = 2; 431} 432void Run() { 433 printf("test03: negative\n"); 434 Waiter(); 435 printf("\tGLOB=%d\n", GLOB); 436} 437REGISTER_TEST2(Run, 3, FEATURE|NEEDS_ANNOTATIONS); 438} // namespace test03 439 440// test04: TN. Synchronization via PCQ. {{{1 441namespace test04 { 442int GLOB = 0; 443ProducerConsumerQueue Q(INT_MAX); 444// Two write accesses to GLOB are separated by PCQ Put/Get. 445// 446// Putter: Getter: 447// 1. write(GLOB) 448// 2. Q.Put() ---------\ . 449// \-------> a. Q.Get() 450// b. write(GLOB) 451 452 453void Putter() { 454 GLOB = 1; 455 Q.Put(NULL); 456} 457 458void Getter() { 459 Q.Get(); 460 GLOB = 2; 461} 462 463void Run() { 464 printf("test04: negative\n"); 465 MyThreadArray t(Putter, Getter); 466 t.Start(); 467 t.Join(); 468 printf("\tGLOB=%d\n", GLOB); 469} 470REGISTER_TEST(Run, 4); 471} // namespace test04 472 473 474// test05: FP. Synchronization via CondVar, but waiter does not block. {{{1 475// Since CondVar::Wait() is not called, we get a false positive. 476namespace test05 { 477int GLOB = 0; 478// Two write accesses to GLOB are synchronized via CondVar. 479// But race detector can not see it. 480// See this for details: 481// http://www.valgrind.org/docs/manual/hg-manual.html#hg-manual.effective-use. 482// 483// Waiter: Waker: 484// 1. COND = 0 485// 2. Start(Waker) 486// 3. MU.Lock() a. write(GLOB) 487// b. MU.Lock() 488// c. COND = 1 489// d. CV.Signal() 490// 4. while(COND) e. MU.Unlock() 491// CV.Wait(MU) <<< not called 492// 5. MU.Unlock() 493// 6. write(GLOB) 494Mutex MU; 495 496void Waker() { 497 GLOB = 1; 498 MU.Lock(); 499 COND = 1; 500 CV.Signal(); 501 MU.Unlock(); 502} 503 504void Waiter() { 505 ThreadPool pool(1); 506 pool.StartWorkers(); 507 COND = 0; 508 pool.Add(NewCallback(Waker)); 509 usleep(100000); // Make sure the signaller gets first. 510 MU.Lock(); 511 while(COND != 1) 512 CV.Wait(&MU); 513 MU.Unlock(); 514 GLOB = 2; 515} 516void Run() { 517 FAST_MODE_INIT(&GLOB); 518 if (!Tsan_PureHappensBefore()) 519 ANNOTATE_EXPECT_RACE_FOR_TSAN(&GLOB, "test05. FP. Unavoidable in hybrid scheme."); 520 printf("test05: unavoidable false positive\n"); 521 Waiter(); 522 printf("\tGLOB=%d\n", GLOB); 523} 524REGISTER_TEST(Run, 5); 525} // namespace test05 526 527 528// test06: TN. Synchronization via CondVar, but Waker gets there first. {{{1 529namespace test06 { 530int GLOB = 0; 531// Same as test05 but we annotated the Wait() loop. 532// 533// Waiter: Waker: 534// 1. COND = 0 535// 2. Start(Waker) 536// 3. MU.Lock() a. write(GLOB) 537// b. MU.Lock() 538// c. COND = 1 539// /------- d. CV.Signal() 540// 4. while(COND) / e. MU.Unlock() 541// CV.Wait(MU) <<< not called / 542// 6. ANNOTATE_CONDVAR_WAIT(CV, MU) <----/ 543// 5. MU.Unlock() 544// 6. write(GLOB) 545 546Mutex MU; 547 548void Waker() { 549 GLOB = 1; 550 MU.Lock(); 551 COND = 1; 552 CV.Signal(); 553 MU.Unlock(); 554} 555 556void Waiter() { 557 ThreadPool pool(1); 558 pool.StartWorkers(); 559 COND = 0; 560 pool.Add(NewCallback(Waker)); 561 usleep(100000); // Make sure the signaller gets first. 562 MU.Lock(); 563 while(COND != 1) 564 CV.Wait(&MU); 565 ANNOTATE_CONDVAR_LOCK_WAIT(&CV, &MU); 566 567 MU.Unlock(); 568 GLOB = 2; 569} 570void Run() { 571 printf("test06: negative\n"); 572 Waiter(); 573 printf("\tGLOB=%d\n", GLOB); 574} 575REGISTER_TEST2(Run, 6, FEATURE|NEEDS_ANNOTATIONS); 576} // namespace test06 577 578 579// test07: TN. Synchronization via LockWhen(), Signaller is observed first. {{{1 580namespace test07 { 581int GLOB = 0; 582bool COND = 0; 583// Two write accesses to GLOB are synchronized via conditional critical section. 584// LockWhen() is observed after COND has been set (due to sleep). 585// Unlock() calls ANNOTATE_CONDVAR_SIGNAL(). 586// 587// Waiter: Signaller: 588// 1. COND = 0 589// 2. Start(Signaller) 590// a. write(GLOB) 591// b. MU.Lock() 592// c. COND = 1 593// /--- d. MU.Unlock calls ANNOTATE_CONDVAR_SIGNAL 594// 3. MU.LockWhen(COND==1) <---/ 595// 4. MU.Unlock() 596// 5. write(GLOB) 597 598Mutex MU; 599void Signaller() { 600 GLOB = 1; 601 MU.Lock(); 602 COND = true; // We are done! Tell the Waiter. 603 MU.Unlock(); // calls ANNOTATE_CONDVAR_SIGNAL; 604} 605void Waiter() { 606 COND = false; 607 MyThread t(Signaller); 608 t.Start(); 609 usleep(100000); // Make sure the signaller gets there first. 610 611 MU.LockWhen(Condition(&ArgIsTrue, &COND)); // calls ANNOTATE_CONDVAR_WAIT 612 MU.Unlock(); // Signaller is done! 613 614 GLOB = 2; // If LockWhen didn't catch the signal, a race may be reported here. 615 t.Join(); 616} 617void Run() { 618 printf("test07: negative\n"); 619 Waiter(); 620 printf("\tGLOB=%d\n", GLOB); 621} 622REGISTER_TEST2(Run, 7, FEATURE|NEEDS_ANNOTATIONS); 623} // namespace test07 624 625// test08: TN. Synchronization via thread start/join. {{{1 626namespace test08 { 627int GLOB = 0; 628// Three accesses to GLOB are separated by thread start/join. 629// 630// Parent: Worker: 631// 1. write(GLOB) 632// 2. Start(Worker) ------------> 633// a. write(GLOB) 634// 3. Join(Worker) <------------ 635// 4. write(GLOB) 636void Worker() { 637 GLOB = 2; 638} 639 640void Parent() { 641 MyThread t(Worker); 642 GLOB = 1; 643 t.Start(); 644 t.Join(); 645 GLOB = 3; 646} 647void Run() { 648 printf("test08: negative\n"); 649 Parent(); 650 printf("\tGLOB=%d\n", GLOB); 651} 652REGISTER_TEST(Run, 8); 653} // namespace test08 654 655 656// test09: TP. Simple race (read vs write). {{{1 657namespace test09 { 658int GLOB = 0; 659// A simple data race between writer and reader. 660// Write happens after read (enforced by sleep). 661// Usually, easily detectable by a race detector. 662void Writer() { 663 usleep(100000); 664 GLOB = 3; 665} 666void Reader() { 667 CHECK(GLOB != -777); 668} 669 670void Run() { 671 ANNOTATE_TRACE_MEMORY(&GLOB); 672 FAST_MODE_INIT(&GLOB); 673 ANNOTATE_EXPECT_RACE_FOR_TSAN(&GLOB, "test09. TP."); 674 printf("test09: positive\n"); 675 MyThreadArray t(Writer, Reader); 676 t.Start(); 677 t.Join(); 678 printf("\tGLOB=%d\n", GLOB); 679} 680REGISTER_TEST(Run, 9); 681} // namespace test09 682 683 684// test10: FN. Simple race (write vs read). {{{1 685namespace test10 { 686int GLOB = 0; 687// A simple data race between writer and reader. 688// Write happens before Read (enforced by sleep), 689// otherwise this test is the same as test09. 690// 691// Writer: Reader: 692// 1. write(GLOB) a. sleep(long enough so that GLOB 693// is most likely initialized by Writer) 694// b. read(GLOB) 695// 696// 697// Eraser algorithm does not detect the race here, 698// see Section 2.2 of http://citeseer.ist.psu.edu/savage97eraser.html. 699// 700void Writer() { 701 GLOB = 3; 702} 703void Reader() { 704 usleep(100000); 705 CHECK(GLOB != -777); 706} 707 708void Run() { 709 FAST_MODE_INIT(&GLOB); 710 ANNOTATE_EXPECT_RACE_FOR_TSAN(&GLOB, "test10. TP. FN in MSMHelgrind."); 711 printf("test10: positive\n"); 712 MyThreadArray t(Writer, Reader); 713 t.Start(); 714 t.Join(); 715 printf("\tGLOB=%d\n", GLOB); 716} 717REGISTER_TEST(Run, 10); 718} // namespace test10 719 720 721// test11: FP. Synchronization via CondVar, 2 workers. {{{1 722// This test is properly synchronized, but currently (Dec 2007) 723// helgrind reports a false positive. 724// 725// Parent: Worker1, Worker2: 726// 1. Start(workers) a. read(GLOB) 727// 2. MU.Lock() b. MU.Lock() 728// 3. while(COND != 2) /-------- c. CV.Signal() 729// CV.Wait(&MU) <-------/ d. MU.Unlock() 730// 4. MU.Unlock() 731// 5. write(GLOB) 732// 733namespace test11 { 734int GLOB = 0; 735Mutex MU; 736void Worker() { 737 usleep(200000); 738 CHECK(GLOB != 777); 739 740 MU.Lock(); 741 COND++; 742 CV.Signal(); 743 MU.Unlock(); 744} 745 746void Parent() { 747 COND = 0; 748 749 MyThreadArray t(Worker, Worker); 750 t.Start(); 751 752 MU.Lock(); 753 while(COND != 2) { 754 CV.Wait(&MU); 755 } 756 MU.Unlock(); 757 758 GLOB = 2; 759 760 t.Join(); 761} 762 763void Run() { 764// ANNOTATE_EXPECT_RACE(&GLOB, "test11. FP. Fixed by MSMProp1."); 765 printf("test11: negative\n"); 766 Parent(); 767 printf("\tGLOB=%d\n", GLOB); 768} 769REGISTER_TEST(Run, 11); 770} // namespace test11 771 772 773// test12: FP. Synchronization via Mutex, then via PCQ. {{{1 774namespace test12 { 775int GLOB = 0; 776// This test is properly synchronized, but currently (Dec 2007) 777// helgrind reports a false positive. 778// 779// First, we write to GLOB under MU, then we synchronize via PCQ, 780// which is essentially a semaphore. 781// 782// Putter: Getter: 783// 1. MU.Lock() a. MU.Lock() 784// 2. write(GLOB) <---- MU ----> b. write(GLOB) 785// 3. MU.Unlock() c. MU.Unlock() 786// 4. Q.Put() ---------------> d. Q.Get() 787// e. write(GLOB) 788 789ProducerConsumerQueue Q(INT_MAX); 790Mutex MU; 791 792void Putter() { 793 MU.Lock(); 794 GLOB++; 795 MU.Unlock(); 796 797 Q.Put(NULL); 798} 799 800void Getter() { 801 MU.Lock(); 802 GLOB++; 803 MU.Unlock(); 804 805 Q.Get(); 806 GLOB++; 807} 808 809void Run() { 810// ANNOTATE_EXPECT_RACE(&GLOB, "test12. FP. Fixed by MSMProp1."); 811 printf("test12: negative\n"); 812 MyThreadArray t(Putter, Getter); 813 t.Start(); 814 t.Join(); 815 printf("\tGLOB=%d\n", GLOB); 816} 817REGISTER_TEST(Run, 12); 818} // namespace test12 819 820 821// test13: FP. Synchronization via Mutex, then via LockWhen. {{{1 822namespace test13 { 823int GLOB = 0; 824// This test is essentially the same as test12, but uses LockWhen 825// instead of PCQ. 826// 827// Waker: Waiter: 828// 1. MU.Lock() a. MU.Lock() 829// 2. write(GLOB) <---------- MU ----------> b. write(GLOB) 830// 3. MU.Unlock() c. MU.Unlock() 831// 4. MU.Lock() . 832// 5. COND = 1 . 833// 6. ANNOTATE_CONDVAR_SIGNAL -------\ . 834// 7. MU.Unlock() \ . 835// \----> d. MU.LockWhen(COND == 1) 836// e. MU.Unlock() 837// f. write(GLOB) 838Mutex MU; 839 840void Waker() { 841 MU.Lock(); 842 GLOB++; 843 MU.Unlock(); 844 845 MU.Lock(); 846 COND = 1; 847 ANNOTATE_CONDVAR_SIGNAL(&MU); 848 MU.Unlock(); 849} 850 851void Waiter() { 852 MU.Lock(); 853 GLOB++; 854 MU.Unlock(); 855 856 MU.LockWhen(Condition(&ArgIsOne, &COND)); 857 MU.Unlock(); 858 GLOB++; 859} 860 861void Run() { 862// ANNOTATE_EXPECT_RACE(&GLOB, "test13. FP. Fixed by MSMProp1."); 863 printf("test13: negative\n"); 864 COND = 0; 865 866 MyThreadArray t(Waker, Waiter); 867 t.Start(); 868 t.Join(); 869 870 printf("\tGLOB=%d\n", GLOB); 871} 872REGISTER_TEST2(Run, 13, FEATURE|NEEDS_ANNOTATIONS); 873} // namespace test13 874 875 876// test14: FP. Synchronization via PCQ, reads, 2 workers. {{{1 877namespace test14 { 878int GLOB = 0; 879// This test is properly synchronized, but currently (Dec 2007) 880// helgrind reports a false positive. 881// 882// This test is similar to test11, but uses PCQ (semaphore). 883// 884// Putter2: Putter1: Getter: 885// 1. read(GLOB) a. read(GLOB) 886// 2. Q2.Put() ----\ b. Q1.Put() -----\ . 887// \ \--------> A. Q1.Get() 888// \----------------------------------> B. Q2.Get() 889// C. write(GLOB) 890ProducerConsumerQueue Q1(INT_MAX), Q2(INT_MAX); 891 892void Putter1() { 893 CHECK(GLOB != 777); 894 Q1.Put(NULL); 895} 896void Putter2() { 897 CHECK(GLOB != 777); 898 Q2.Put(NULL); 899} 900void Getter() { 901 Q1.Get(); 902 Q2.Get(); 903 GLOB++; 904} 905void Run() { 906// ANNOTATE_EXPECT_RACE(&GLOB, "test14. FP. Fixed by MSMProp1."); 907 printf("test14: negative\n"); 908 MyThreadArray t(Getter, Putter1, Putter2); 909 t.Start(); 910 t.Join(); 911 printf("\tGLOB=%d\n", GLOB); 912} 913REGISTER_TEST(Run, 14); 914} // namespace test14 915 916 917// test15: TN. Synchronization via LockWhen. One waker and 2 waiters. {{{1 918namespace test15 { 919// Waker: Waiter1, Waiter2: 920// 1. write(GLOB) 921// 2. MU.Lock() 922// 3. COND = 1 923// 4. ANNOTATE_CONDVAR_SIGNAL ------------> a. MU.LockWhen(COND == 1) 924// 5. MU.Unlock() b. MU.Unlock() 925// c. read(GLOB) 926 927int GLOB = 0; 928Mutex MU; 929 930void Waker() { 931 GLOB = 2; 932 933 MU.Lock(); 934 COND = 1; 935 ANNOTATE_CONDVAR_SIGNAL(&MU); 936 MU.Unlock(); 937}; 938 939void Waiter() { 940 MU.LockWhen(Condition(&ArgIsOne, &COND)); 941 MU.Unlock(); 942 CHECK(GLOB != 777); 943} 944 945 946void Run() { 947 COND = 0; 948 printf("test15: negative\n"); 949 MyThreadArray t(Waker, Waiter, Waiter); 950 t.Start(); 951 t.Join(); 952 printf("\tGLOB=%d\n", GLOB); 953} 954REGISTER_TEST(Run, 15); 955} // namespace test15 956 957 958// test16: FP. Barrier (emulated by CV), 2 threads. {{{1 959namespace test16 { 960// Worker1: Worker2: 961// 1. MU.Lock() a. MU.Lock() 962// 2. write(GLOB) <------------ MU ----------> b. write(GLOB) 963// 3. MU.Unlock() c. MU.Unlock() 964// 4. MU2.Lock() d. MU2.Lock() 965// 5. COND-- e. COND-- 966// 6. ANNOTATE_CONDVAR_SIGNAL(MU2) ---->V . 967// 7. MU2.Await(COND == 0) <------------+------ f. ANNOTATE_CONDVAR_SIGNAL(MU2) 968// 8. MU2.Unlock() V-----> g. MU2.Await(COND == 0) 969// 9. read(GLOB) h. MU2.Unlock() 970// i. read(GLOB) 971// 972// 973// TODO: This way we may create too many edges in happens-before graph. 974// Arndt Mühlenfeld in his PhD (TODO: link) suggests creating special nodes in 975// happens-before graph to reduce the total number of edges. 976// See figure 3.14. 977// 978// 979int GLOB = 0; 980Mutex MU; 981Mutex MU2; 982 983void Worker() { 984 MU.Lock(); 985 GLOB++; 986 MU.Unlock(); 987 988 MU2.Lock(); 989 COND--; 990 ANNOTATE_CONDVAR_SIGNAL(&MU2); 991 MU2.Await(Condition(&ArgIsZero, &COND)); 992 MU2.Unlock(); 993 994 CHECK(GLOB == 2); 995} 996 997void Run() { 998// ANNOTATE_EXPECT_RACE(&GLOB, "test16. FP. Fixed by MSMProp1 + Barrier support."); 999 COND = 2; 1000 printf("test16: negative\n"); 1001 MyThreadArray t(Worker, Worker); 1002 t.Start(); 1003 t.Join(); 1004 printf("\tGLOB=%d\n", GLOB); 1005} 1006REGISTER_TEST2(Run, 16, FEATURE|NEEDS_ANNOTATIONS); 1007} // namespace test16 1008 1009 1010// test17: FP. Barrier (emulated by CV), 3 threads. {{{1 1011namespace test17 { 1012// Same as test16, but with 3 threads. 1013int GLOB = 0; 1014Mutex MU; 1015Mutex MU2; 1016 1017void Worker() { 1018 MU.Lock(); 1019 GLOB++; 1020 MU.Unlock(); 1021 1022 MU2.Lock(); 1023 COND--; 1024 ANNOTATE_CONDVAR_SIGNAL(&MU2); 1025 MU2.Await(Condition(&ArgIsZero, &COND)); 1026 MU2.Unlock(); 1027 1028 CHECK(GLOB == 3); 1029} 1030 1031void Run() { 1032// ANNOTATE_EXPECT_RACE(&GLOB, "test17. FP. Fixed by MSMProp1 + Barrier support."); 1033 COND = 3; 1034 printf("test17: negative\n"); 1035 MyThreadArray t(Worker, Worker, Worker); 1036 t.Start(); 1037 t.Join(); 1038 printf("\tGLOB=%d\n", GLOB); 1039} 1040REGISTER_TEST2(Run, 17, FEATURE|NEEDS_ANNOTATIONS); 1041} // namespace test17 1042 1043 1044// test18: TN. Synchronization via Await(), signaller gets there first. {{{1 1045namespace test18 { 1046int GLOB = 0; 1047Mutex MU; 1048// Same as test03, but uses Mutex::Await() instead of Mutex::LockWhen(). 1049 1050void Waker() { 1051 usleep(100000); // Make sure the waiter blocks. 1052 GLOB = 1; 1053 1054 MU.Lock(); 1055 COND = 1; // We are done! Tell the Waiter. 1056 MU.Unlock(); // calls ANNOTATE_CONDVAR_SIGNAL; 1057} 1058void Waiter() { 1059 ThreadPool pool(1); 1060 pool.StartWorkers(); 1061 COND = 0; 1062 pool.Add(NewCallback(Waker)); 1063 1064 MU.Lock(); 1065 MU.Await(Condition(&ArgIsOne, &COND)); // calls ANNOTATE_CONDVAR_WAIT 1066 MU.Unlock(); // Waker is done! 1067 1068 GLOB = 2; 1069} 1070void Run() { 1071 printf("test18: negative\n"); 1072 Waiter(); 1073 printf("\tGLOB=%d\n", GLOB); 1074} 1075REGISTER_TEST2(Run, 18, FEATURE|NEEDS_ANNOTATIONS); 1076} // namespace test18 1077 1078// test19: TN. Synchronization via AwaitWithTimeout(). {{{1 1079namespace test19 { 1080int GLOB = 0; 1081// Same as test18, but with AwaitWithTimeout. Do not timeout. 1082Mutex MU; 1083void Waker() { 1084 usleep(100000); // Make sure the waiter blocks. 1085 GLOB = 1; 1086 1087 MU.Lock(); 1088 COND = 1; // We are done! Tell the Waiter. 1089 MU.Unlock(); // calls ANNOTATE_CONDVAR_SIGNAL; 1090} 1091void Waiter() { 1092 ThreadPool pool(1); 1093 pool.StartWorkers(); 1094 COND = 0; 1095 pool.Add(NewCallback(Waker)); 1096 1097 MU.Lock(); 1098 CHECK(MU.AwaitWithTimeout(Condition(&ArgIsOne, &COND), INT_MAX)); 1099 MU.Unlock(); 1100 1101 GLOB = 2; 1102} 1103void Run() { 1104 printf("test19: negative\n"); 1105 Waiter(); 1106 printf("\tGLOB=%d\n", GLOB); 1107} 1108REGISTER_TEST2(Run, 19, FEATURE|NEEDS_ANNOTATIONS); 1109} // namespace test19 1110 1111// test20: TP. Incorrect synchronization via AwaitWhen(), timeout. {{{1 1112namespace test20 { 1113int GLOB = 0; 1114Mutex MU; 1115// True race. We timeout in AwaitWhen. 1116void Waker() { 1117 GLOB = 1; 1118 usleep(100 * 1000); 1119} 1120void Waiter() { 1121 ThreadPool pool(1); 1122 pool.StartWorkers(); 1123 COND = 0; 1124 pool.Add(NewCallback(Waker)); 1125 1126 MU.Lock(); 1127 CHECK(!MU.AwaitWithTimeout(Condition(&ArgIsOne, &COND), 100)); 1128 MU.Unlock(); 1129 1130 GLOB = 2; 1131} 1132void Run() { 1133 FAST_MODE_INIT(&GLOB); 1134 ANNOTATE_EXPECT_RACE_FOR_TSAN(&GLOB, "test20. TP."); 1135 printf("test20: positive\n"); 1136 Waiter(); 1137 printf("\tGLOB=%d\n", GLOB); 1138} 1139REGISTER_TEST2(Run, 20, FEATURE|NEEDS_ANNOTATIONS); 1140} // namespace test20 1141 1142// test21: TP. Incorrect synchronization via LockWhenWithTimeout(). {{{1 1143namespace test21 { 1144int GLOB = 0; 1145// True race. We timeout in LockWhenWithTimeout(). 1146Mutex MU; 1147void Waker() { 1148 GLOB = 1; 1149 usleep(100 * 1000); 1150} 1151void Waiter() { 1152 ThreadPool pool(1); 1153 pool.StartWorkers(); 1154 COND = 0; 1155 pool.Add(NewCallback(Waker)); 1156 1157 CHECK(!MU.LockWhenWithTimeout(Condition(&ArgIsOne, &COND), 100)); 1158 MU.Unlock(); 1159 1160 GLOB = 2; 1161} 1162void Run() { 1163 FAST_MODE_INIT(&GLOB); 1164 ANNOTATE_EXPECT_RACE_FOR_TSAN(&GLOB, "test21. TP."); 1165 printf("test21: positive\n"); 1166 Waiter(); 1167 printf("\tGLOB=%d\n", GLOB); 1168} 1169REGISTER_TEST2(Run, 21, FEATURE|NEEDS_ANNOTATIONS); 1170} // namespace test21 1171 1172// test22: TP. Incorrect synchronization via CondVar::WaitWithTimeout(). {{{1 1173namespace test22 { 1174int GLOB = 0; 1175Mutex MU; 1176// True race. We timeout in CondVar::WaitWithTimeout(). 1177void Waker() { 1178 GLOB = 1; 1179 usleep(100 * 1000); 1180} 1181void Waiter() { 1182 ThreadPool pool(1); 1183 pool.StartWorkers(); 1184 COND = 0; 1185 pool.Add(NewCallback(Waker)); 1186 1187 int64_t ms_left_to_wait = 100; 1188 int64_t deadline_ms = GetCurrentTimeMillis() + ms_left_to_wait; 1189 MU.Lock(); 1190 while(COND != 1 && ms_left_to_wait > 0) { 1191 CV.WaitWithTimeout(&MU, ms_left_to_wait); 1192 ms_left_to_wait = deadline_ms - GetCurrentTimeMillis(); 1193 } 1194 MU.Unlock(); 1195 1196 GLOB = 2; 1197} 1198void Run() { 1199 FAST_MODE_INIT(&GLOB); 1200 ANNOTATE_EXPECT_RACE_FOR_TSAN(&GLOB, "test22. TP."); 1201 printf("test22: positive\n"); 1202 Waiter(); 1203 printf("\tGLOB=%d\n", GLOB); 1204} 1205REGISTER_TEST(Run, 22); 1206} // namespace test22 1207 1208// test23: TN. TryLock, ReaderLock, ReaderTryLock. {{{1 1209namespace test23 { 1210// Correct synchronization with TryLock, Lock, ReaderTryLock, ReaderLock. 1211int GLOB = 0; 1212Mutex MU; 1213void Worker_TryLock() { 1214 for (int i = 0; i < 20; i++) { 1215 while (true) { 1216 if (MU.TryLock()) { 1217 GLOB++; 1218 MU.Unlock(); 1219 break; 1220 } 1221 usleep(1000); 1222 } 1223 } 1224} 1225 1226void Worker_ReaderTryLock() { 1227 for (int i = 0; i < 20; i++) { 1228 while (true) { 1229 if (MU.ReaderTryLock()) { 1230 CHECK(GLOB != 777); 1231 MU.ReaderUnlock(); 1232 break; 1233 } 1234 usleep(1000); 1235 } 1236 } 1237} 1238 1239void Worker_ReaderLock() { 1240 for (int i = 0; i < 20; i++) { 1241 MU.ReaderLock(); 1242 CHECK(GLOB != 777); 1243 MU.ReaderUnlock(); 1244 usleep(1000); 1245 } 1246} 1247 1248void Worker_Lock() { 1249 for (int i = 0; i < 20; i++) { 1250 MU.Lock(); 1251 GLOB++; 1252 MU.Unlock(); 1253 usleep(1000); 1254 } 1255} 1256 1257void Run() { 1258 printf("test23: negative\n"); 1259 MyThreadArray t(Worker_TryLock, 1260 Worker_ReaderTryLock, 1261 Worker_ReaderLock, 1262 Worker_Lock 1263 ); 1264 t.Start(); 1265 t.Join(); 1266 printf("\tGLOB=%d\n", GLOB); 1267} 1268REGISTER_TEST(Run, 23); 1269} // namespace test23 1270 1271// test24: TN. Synchronization via ReaderLockWhen(). {{{1 1272namespace test24 { 1273int GLOB = 0; 1274Mutex MU; 1275// Same as test03, but uses ReaderLockWhen(). 1276 1277void Waker() { 1278 usleep(100000); // Make sure the waiter blocks. 1279 GLOB = 1; 1280 1281 MU.Lock(); 1282 COND = 1; // We are done! Tell the Waiter. 1283 MU.Unlock(); // calls ANNOTATE_CONDVAR_SIGNAL; 1284} 1285void Waiter() { 1286 ThreadPool pool(1); 1287 pool.StartWorkers(); 1288 COND = 0; 1289 pool.Add(NewCallback(Waker)); 1290 MU.ReaderLockWhen(Condition(&ArgIsOne, &COND)); 1291 MU.ReaderUnlock(); 1292 1293 GLOB = 2; 1294} 1295void Run() { 1296 printf("test24: negative\n"); 1297 Waiter(); 1298 printf("\tGLOB=%d\n", GLOB); 1299} 1300REGISTER_TEST2(Run, 24, FEATURE|NEEDS_ANNOTATIONS); 1301} // namespace test24 1302 1303// test25: TN. Synchronization via ReaderLockWhenWithTimeout(). {{{1 1304namespace test25 { 1305int GLOB = 0; 1306Mutex MU; 1307// Same as test24, but uses ReaderLockWhenWithTimeout(). 1308// We do not timeout. 1309 1310void Waker() { 1311 usleep(100000); // Make sure the waiter blocks. 1312 GLOB = 1; 1313 1314 MU.Lock(); 1315 COND = 1; // We are done! Tell the Waiter. 1316 MU.Unlock(); // calls ANNOTATE_CONDVAR_SIGNAL; 1317} 1318void Waiter() { 1319 ThreadPool pool(1); 1320 pool.StartWorkers(); 1321 COND = 0; 1322 pool.Add(NewCallback(Waker)); 1323 CHECK(MU.ReaderLockWhenWithTimeout(Condition(&ArgIsOne, &COND), INT_MAX)); 1324 MU.ReaderUnlock(); 1325 1326 GLOB = 2; 1327} 1328void Run() { 1329 printf("test25: negative\n"); 1330 Waiter(); 1331 printf("\tGLOB=%d\n", GLOB); 1332} 1333REGISTER_TEST2(Run, 25, FEATURE|NEEDS_ANNOTATIONS); 1334} // namespace test25 1335 1336// test26: TP. Incorrect synchronization via ReaderLockWhenWithTimeout(). {{{1 1337namespace test26 { 1338int GLOB = 0; 1339Mutex MU; 1340// Same as test25, but we timeout and incorrectly assume happens-before. 1341 1342void Waker() { 1343 GLOB = 1; 1344 usleep(10000); 1345} 1346void Waiter() { 1347 ThreadPool pool(1); 1348 pool.StartWorkers(); 1349 COND = 0; 1350 pool.Add(NewCallback(Waker)); 1351 CHECK(!MU.ReaderLockWhenWithTimeout(Condition(&ArgIsOne, &COND), 100)); 1352 MU.ReaderUnlock(); 1353 1354 GLOB = 2; 1355} 1356void Run() { 1357 FAST_MODE_INIT(&GLOB); 1358 ANNOTATE_EXPECT_RACE_FOR_TSAN(&GLOB, "test26. TP"); 1359 printf("test26: positive\n"); 1360 Waiter(); 1361 printf("\tGLOB=%d\n", GLOB); 1362} 1363REGISTER_TEST2(Run, 26, FEATURE|NEEDS_ANNOTATIONS); 1364} // namespace test26 1365 1366 1367// test27: TN. Simple synchronization via SpinLock. {{{1 1368namespace test27 { 1369#ifndef NO_SPINLOCK 1370int GLOB = 0; 1371SpinLock MU; 1372void Worker() { 1373 MU.Lock(); 1374 GLOB++; 1375 MU.Unlock(); 1376 usleep(10000); 1377} 1378 1379void Run() { 1380 printf("test27: negative\n"); 1381 MyThreadArray t(Worker, Worker, Worker, Worker); 1382 t.Start(); 1383 t.Join(); 1384 printf("\tGLOB=%d\n", GLOB); 1385} 1386REGISTER_TEST2(Run, 27, FEATURE|NEEDS_ANNOTATIONS); 1387#endif // NO_SPINLOCK 1388} // namespace test27 1389 1390 1391// test28: TN. Synchronization via Mutex, then PCQ. 3 threads {{{1 1392namespace test28 { 1393// Putter1: Getter: Putter2: 1394// 1. MU.Lock() A. MU.Lock() 1395// 2. write(GLOB) B. write(GLOB) 1396// 3. MU.Unlock() C. MU.Unlock() 1397// 4. Q.Put() ---------\ /------- D. Q.Put() 1398// 5. MU.Lock() \-------> a. Q.Get() / E. MU.Lock() 1399// 6. read(GLOB) b. Q.Get() <---------/ F. read(GLOB) 1400// 7. MU.Unlock() (sleep) G. MU.Unlock() 1401// c. read(GLOB) 1402ProducerConsumerQueue Q(INT_MAX); 1403int GLOB = 0; 1404Mutex MU; 1405 1406void Putter() { 1407 MU.Lock(); 1408 GLOB++; 1409 MU.Unlock(); 1410 1411 Q.Put(NULL); 1412 1413 MU.Lock(); 1414 CHECK(GLOB != 777); 1415 MU.Unlock(); 1416} 1417 1418void Getter() { 1419 Q.Get(); 1420 Q.Get(); 1421 usleep(100000); 1422 CHECK(GLOB == 2); 1423} 1424 1425void Run() { 1426 printf("test28: negative\n"); 1427 MyThreadArray t(Getter, Putter, Putter); 1428 t.Start(); 1429 t.Join(); 1430 printf("\tGLOB=%d\n", GLOB); 1431} 1432REGISTER_TEST(Run, 28); 1433} // namespace test28 1434 1435 1436// test29: TN. Synchronization via Mutex, then PCQ. 4 threads. {{{1 1437namespace test29 { 1438// Similar to test28, but has two Getters and two PCQs. 1439ProducerConsumerQueue *Q1, *Q2; 1440Mutex MU; 1441int GLOB = 0; 1442 1443void Putter(ProducerConsumerQueue *q) { 1444 MU.Lock(); 1445 GLOB++; 1446 MU.Unlock(); 1447 1448 q->Put(NULL); 1449 q->Put(NULL); 1450 1451 MU.Lock(); 1452 CHECK(GLOB != 777); 1453 MU.Unlock(); 1454 1455} 1456 1457void Putter1() { Putter(Q1); } 1458void Putter2() { Putter(Q2); } 1459 1460void Getter() { 1461 Q1->Get(); 1462 Q2->Get(); 1463 usleep(100000); 1464 CHECK(GLOB == 2); 1465 usleep(48000); // TODO: remove this when FP in test32 is fixed. 1466} 1467 1468void Run() { 1469 printf("test29: negative\n"); 1470 Q1 = new ProducerConsumerQueue(INT_MAX); 1471 Q2 = new ProducerConsumerQueue(INT_MAX); 1472 MyThreadArray t(Getter, Getter, Putter1, Putter2); 1473 t.Start(); 1474 t.Join(); 1475 printf("\tGLOB=%d\n", GLOB); 1476 delete Q1; 1477 delete Q2; 1478} 1479REGISTER_TEST(Run, 29); 1480} // namespace test29 1481 1482 1483// test30: TN. Synchronization via 'safe' race. Writer vs multiple Readers. {{{1 1484namespace test30 { 1485// This test shows a very risky kind of synchronization which is very easy 1486// to get wrong. Actually, I am not sure I've got it right. 1487// 1488// Writer: Reader1, Reader2, ..., ReaderN: 1489// 1. write(GLOB[i]: i >= BOUNDARY) a. n = BOUNDARY 1490// 2. HAPPENS_BEFORE(BOUNDARY+1) -------> b. HAPPENS_AFTER(n) 1491// 3. BOUNDARY++; c. read(GLOB[i]: i < n) 1492// 1493// Here we have a 'safe' race on accesses to BOUNDARY and 1494// no actual races on accesses to GLOB[]: 1495// Writer writes to GLOB[i] where i>=BOUNDARY and then increments BOUNDARY. 1496// Readers read BOUNDARY and read GLOB[i] where i<BOUNDARY. 1497// 1498// I am not completely sure that this scheme guaranties no race between 1499// accesses to GLOB since compilers and CPUs 1500// are free to rearrange memory operations. 1501// I am actually sure that this scheme is wrong unless we use 1502// some smart memory fencing... 1503 1504 1505const int N = 48; 1506static int GLOB[N]; 1507volatile int BOUNDARY = 0; 1508 1509void Writer() { 1510 for (int i = 0; i < N; i++) { 1511 CHECK(BOUNDARY == i); 1512 for (int j = i; j < N; j++) { 1513 GLOB[j] = j; 1514 } 1515 ANNOTATE_HAPPENS_BEFORE(reinterpret_cast<void*>(BOUNDARY+1)); 1516 BOUNDARY++; 1517 usleep(1000); 1518 } 1519} 1520 1521void Reader() { 1522 int n; 1523 do { 1524 n = BOUNDARY; 1525 if (n == 0) continue; 1526 ANNOTATE_HAPPENS_AFTER(reinterpret_cast<void*>(n)); 1527 for (int i = 0; i < n; i++) { 1528 CHECK(GLOB[i] == i); 1529 } 1530 usleep(100); 1531 } while(n < N); 1532} 1533 1534void Run() { 1535 FAST_MODE_INIT(&BOUNDARY); 1536 ANNOTATE_EXPECT_RACE((void*)(&BOUNDARY), "test30. Sync via 'safe' race."); 1537 printf("test30: negative\n"); 1538 MyThreadArray t(Writer, Reader, Reader, Reader); 1539 t.Start(); 1540 t.Join(); 1541 printf("\tGLOB=%d\n", GLOB[N-1]); 1542} 1543REGISTER_TEST2(Run, 30, FEATURE|NEEDS_ANNOTATIONS); 1544} // namespace test30 1545 1546 1547// test31: TN. Synchronization via 'safe' race. Writer vs Writer. {{{1 1548namespace test31 { 1549// This test is similar to test30, but 1550// it has one Writer instead of mulitple Readers. 1551// 1552// Writer1: Writer2 1553// 1. write(GLOB[i]: i >= BOUNDARY) a. n = BOUNDARY 1554// 2. HAPPENS_BEFORE(BOUNDARY+1) -------> b. HAPPENS_AFTER(n) 1555// 3. BOUNDARY++; c. write(GLOB[i]: i < n) 1556// 1557 1558const int N = 48; 1559static int GLOB[N]; 1560volatile int BOUNDARY = 0; 1561 1562void Writer1() { 1563 for (int i = 0; i < N; i++) { 1564 CHECK(BOUNDARY == i); 1565 for (int j = i; j < N; j++) { 1566 GLOB[j] = j; 1567 } 1568 ANNOTATE_HAPPENS_BEFORE(reinterpret_cast<void*>(BOUNDARY+1)); 1569 BOUNDARY++; 1570 usleep(1000); 1571 } 1572} 1573 1574void Writer2() { 1575 int n; 1576 do { 1577 n = BOUNDARY; 1578 if (n == 0) continue; 1579 ANNOTATE_HAPPENS_AFTER(reinterpret_cast<void*>(n)); 1580 for (int i = 0; i < n; i++) { 1581 if(GLOB[i] == i) { 1582 GLOB[i]++; 1583 } 1584 } 1585 usleep(100); 1586 } while(n < N); 1587} 1588 1589void Run() { 1590 FAST_MODE_INIT(&BOUNDARY); 1591 ANNOTATE_EXPECT_RACE((void*)(&BOUNDARY), "test31. Sync via 'safe' race."); 1592 printf("test31: negative\n"); 1593 MyThreadArray t(Writer1, Writer2); 1594 t.Start(); 1595 t.Join(); 1596 printf("\tGLOB=%d\n", GLOB[N-1]); 1597} 1598REGISTER_TEST2(Run, 31, FEATURE|NEEDS_ANNOTATIONS); 1599} // namespace test31 1600 1601 1602// test32: FP. Synchronization via thread create/join. W/R. {{{1 1603namespace test32 { 1604// This test is well synchronized but helgrind 3.3.0 reports a race. 1605// 1606// Parent: Writer: Reader: 1607// 1. Start(Reader) -----------------------\ . 1608// \ . 1609// 2. Start(Writer) ---\ \ . 1610// \---> a. MU.Lock() \--> A. sleep(long enough) 1611// b. write(GLOB) 1612// /---- c. MU.Unlock() 1613// 3. Join(Writer) <---/ 1614// B. MU.Lock() 1615// C. read(GLOB) 1616// /------------ D. MU.Unlock() 1617// 4. Join(Reader) <----------------/ 1618// 5. write(GLOB) 1619// 1620// 1621// The call to sleep() in Reader is not part of synchronization, 1622// it is required to trigger the false positive in helgrind 3.3.0. 1623// 1624int GLOB = 0; 1625Mutex MU; 1626 1627void Writer() { 1628 MU.Lock(); 1629 GLOB = 1; 1630 MU.Unlock(); 1631} 1632 1633void Reader() { 1634 usleep(480000); 1635 MU.Lock(); 1636 CHECK(GLOB != 777); 1637 MU.Unlock(); 1638} 1639 1640void Parent() { 1641 MyThread r(Reader); 1642 MyThread w(Writer); 1643 r.Start(); 1644 w.Start(); 1645 1646 w.Join(); // 'w' joins first. 1647 r.Join(); 1648 1649 GLOB = 2; 1650} 1651 1652void Run() { 1653// ANNOTATE_EXPECT_RACE(&GLOB, "test32. FP. Fixed by MSMProp1."); 1654 printf("test32: negative\n"); 1655 Parent(); 1656 printf("\tGLOB=%d\n", GLOB); 1657} 1658 1659REGISTER_TEST(Run, 32); 1660} // namespace test32 1661 1662 1663// test33: STAB. Stress test for the number of thread sets (TSETs). {{{1 1664namespace test33 { 1665int GLOB = 0; 1666// Here we access N memory locations from within log(N) threads. 1667// We do it in such a way that helgrind creates nearly all possible TSETs. 1668// Then we join all threads and start again (N_iter times). 1669const int N_iter = 48; 1670const int Nlog = 15; 1671const int N = 1 << Nlog; 1672static int ARR[N]; 1673Mutex MU; 1674 1675void Worker() { 1676 MU.Lock(); 1677 int n = ++GLOB; 1678 MU.Unlock(); 1679 1680 n %= Nlog; 1681 for (int i = 0; i < N; i++) { 1682 // ARR[i] is accessed by threads from i-th subset 1683 if (i & (1 << n)) { 1684 CHECK(ARR[i] == 0); 1685 } 1686 } 1687} 1688 1689void Run() { 1690 printf("test33:\n"); 1691 1692 std::vector<MyThread*> vec(Nlog); 1693 1694 for (int i = 0; i < N_iter; i++) { 1695 // Create and start Nlog threads 1696 for (int i = 0; i < Nlog; i++) { 1697 vec[i] = new MyThread(Worker); 1698 } 1699 for (int i = 0; i < Nlog; i++) { 1700 vec[i]->Start(); 1701 } 1702 // Join all threads. 1703 for (int i = 0; i < Nlog; i++) { 1704 vec[i]->Join(); 1705 delete vec[i]; 1706 } 1707 printf("------------------\n"); 1708 } 1709 1710 printf("\tGLOB=%d; ARR[1]=%d; ARR[7]=%d; ARR[N-1]=%d\n", 1711 GLOB, ARR[1], ARR[7], ARR[N-1]); 1712} 1713REGISTER_TEST2(Run, 33, STABILITY|EXCLUDE_FROM_ALL); 1714} // namespace test33 1715 1716 1717// test34: STAB. Stress test for the number of locks sets (LSETs). {{{1 1718namespace test34 { 1719// Similar to test33, but for lock sets. 1720int GLOB = 0; 1721const int N_iter = 48; 1722const int Nlog = 10; 1723const int N = 1 << Nlog; 1724static int ARR[N]; 1725static Mutex *MUs[Nlog]; 1726 1727void Worker() { 1728 for (int i = 0; i < N; i++) { 1729 // ARR[i] is protected by MUs from i-th subset of all MUs 1730 for (int j = 0; j < Nlog; j++) if (i & (1 << j)) MUs[j]->Lock(); 1731 CHECK(ARR[i] == 0); 1732 for (int j = 0; j < Nlog; j++) if (i & (1 << j)) MUs[j]->Unlock(); 1733 } 1734} 1735 1736void Run() { 1737 printf("test34:\n"); 1738 for (int iter = 0; iter < N_iter; iter++) { 1739 for (int i = 0; i < Nlog; i++) { 1740 MUs[i] = new Mutex; 1741 } 1742 MyThreadArray t(Worker, Worker); 1743 t.Start(); 1744 t.Join(); 1745 for (int i = 0; i < Nlog; i++) { 1746 delete MUs[i]; 1747 } 1748 printf("------------------\n"); 1749 } 1750 printf("\tGLOB=%d\n", GLOB); 1751} 1752REGISTER_TEST2(Run, 34, STABILITY|EXCLUDE_FROM_ALL); 1753} // namespace test34 1754 1755 1756// test35: PERF. Lots of mutexes and lots of call to free(). {{{1 1757namespace test35 { 1758// Helgrind 3.3.0 has very slow in shadow_mem_make_NoAccess(). Fixed locally. 1759// With the fix helgrind runs this test about a minute. 1760// Without the fix -- about 5 minutes. (on c2d 2.4GHz). 1761// 1762// TODO: need to figure out the best way for performance testing. 1763int **ARR; 1764const int N_mu = 25000; 1765const int N_free = 48000; 1766 1767void Worker() { 1768 for (int i = 0; i < N_free; i++) 1769 CHECK(777 == *ARR[i]); 1770} 1771 1772void Run() { 1773 printf("test35:\n"); 1774 std::vector<Mutex*> mus; 1775 1776 ARR = new int *[N_free]; 1777 for (int i = 0; i < N_free; i++) { 1778 const int c = N_free / N_mu; 1779 if ((i % c) == 0) { 1780 mus.push_back(new Mutex); 1781 mus.back()->Lock(); 1782 mus.back()->Unlock(); 1783 } 1784 ARR[i] = new int(777); 1785 } 1786 1787 // Need to put all ARR[i] into shared state in order 1788 // to trigger the performance bug. 1789 MyThreadArray t(Worker, Worker); 1790 t.Start(); 1791 t.Join(); 1792 1793 for (int i = 0; i < N_free; i++) delete ARR[i]; 1794 delete [] ARR; 1795 1796 for (size_t i = 0; i < mus.size(); i++) { 1797 delete mus[i]; 1798 } 1799} 1800REGISTER_TEST2(Run, 35, PERFORMANCE|EXCLUDE_FROM_ALL); 1801} // namespace test35 1802 1803 1804// test36: TN. Synchronization via Mutex, then PCQ. 3 threads. W/W {{{1 1805namespace test36 { 1806// variation of test28 (W/W instead of W/R) 1807 1808// Putter1: Getter: Putter2: 1809// 1. MU.Lock(); A. MU.Lock() 1810// 2. write(GLOB) B. write(GLOB) 1811// 3. MU.Unlock() C. MU.Unlock() 1812// 4. Q.Put() ---------\ /------- D. Q.Put() 1813// 5. MU1.Lock() \-------> a. Q.Get() / E. MU1.Lock() 1814// 6. MU.Lock() b. Q.Get() <---------/ F. MU.Lock() 1815// 7. write(GLOB) G. write(GLOB) 1816// 8. MU.Unlock() H. MU.Unlock() 1817// 9. MU1.Unlock() (sleep) I. MU1.Unlock() 1818// c. MU1.Lock() 1819// d. write(GLOB) 1820// e. MU1.Unlock() 1821ProducerConsumerQueue Q(INT_MAX); 1822int GLOB = 0; 1823Mutex MU, MU1; 1824 1825void Putter() { 1826 MU.Lock(); 1827 GLOB++; 1828 MU.Unlock(); 1829 1830 Q.Put(NULL); 1831 1832 MU1.Lock(); 1833 MU.Lock(); 1834 GLOB++; 1835 MU.Unlock(); 1836 MU1.Unlock(); 1837} 1838 1839void Getter() { 1840 Q.Get(); 1841 Q.Get(); 1842 usleep(100000); 1843 MU1.Lock(); 1844 GLOB++; 1845 MU1.Unlock(); 1846} 1847 1848void Run() { 1849 printf("test36: negative \n"); 1850 MyThreadArray t(Getter, Putter, Putter); 1851 t.Start(); 1852 t.Join(); 1853 printf("\tGLOB=%d\n", GLOB); 1854} 1855REGISTER_TEST(Run, 36); 1856} // namespace test36 1857 1858 1859// test37: TN. Simple synchronization (write vs read). {{{1 1860namespace test37 { 1861int GLOB = 0; 1862Mutex MU; 1863// Similar to test10, but properly locked. 1864// Writer: Reader: 1865// 1. MU.Lock() 1866// 2. write 1867// 3. MU.Unlock() 1868// a. MU.Lock() 1869// b. read 1870// c. MU.Unlock(); 1871 1872void Writer() { 1873 MU.Lock(); 1874 GLOB = 3; 1875 MU.Unlock(); 1876} 1877void Reader() { 1878 usleep(100000); 1879 MU.Lock(); 1880 CHECK(GLOB != -777); 1881 MU.Unlock(); 1882} 1883 1884void Run() { 1885 printf("test37: negative\n"); 1886 MyThreadArray t(Writer, Reader); 1887 t.Start(); 1888 t.Join(); 1889 printf("\tGLOB=%d\n", GLOB); 1890} 1891REGISTER_TEST(Run, 37); 1892} // namespace test37 1893 1894 1895// test38: TN. Synchronization via Mutexes and PCQ. 4 threads. W/W {{{1 1896namespace test38 { 1897// Fusion of test29 and test36. 1898 1899// Putter1: Putter2: Getter1: Getter2: 1900// MU1.Lock() MU1.Lock() 1901// write(GLOB) write(GLOB) 1902// MU1.Unlock() MU1.Unlock() 1903// Q1.Put() Q2.Put() 1904// Q1.Put() Q2.Put() 1905// MU1.Lock() MU1.Lock() 1906// MU2.Lock() MU2.Lock() 1907// write(GLOB) write(GLOB) 1908// MU2.Unlock() MU2.Unlock() 1909// MU1.Unlock() MU1.Unlock() sleep sleep 1910// Q1.Get() Q1.Get() 1911// Q2.Get() Q2.Get() 1912// MU2.Lock() MU2.Lock() 1913// write(GLOB) write(GLOB) 1914// MU2.Unlock() MU2.Unlock() 1915// 1916 1917 1918ProducerConsumerQueue *Q1, *Q2; 1919int GLOB = 0; 1920Mutex MU, MU1, MU2; 1921 1922void Putter(ProducerConsumerQueue *q) { 1923 MU1.Lock(); 1924 GLOB++; 1925 MU1.Unlock(); 1926 1927 q->Put(NULL); 1928 q->Put(NULL); 1929 1930 MU1.Lock(); 1931 MU2.Lock(); 1932 GLOB++; 1933 MU2.Unlock(); 1934 MU1.Unlock(); 1935 1936} 1937 1938void Putter1() { Putter(Q1); } 1939void Putter2() { Putter(Q2); } 1940 1941void Getter() { 1942 usleep(100000); 1943 Q1->Get(); 1944 Q2->Get(); 1945 1946 MU2.Lock(); 1947 GLOB++; 1948 MU2.Unlock(); 1949 1950 usleep(48000); // TODO: remove this when FP in test32 is fixed. 1951} 1952 1953void Run() { 1954 printf("test38: negative\n"); 1955 Q1 = new ProducerConsumerQueue(INT_MAX); 1956 Q2 = new ProducerConsumerQueue(INT_MAX); 1957 MyThreadArray t(Getter, Getter, Putter1, Putter2); 1958 t.Start(); 1959 t.Join(); 1960 printf("\tGLOB=%d\n", GLOB); 1961 delete Q1; 1962 delete Q2; 1963} 1964REGISTER_TEST(Run, 38); 1965} // namespace test38 1966 1967// test39: FP. Barrier. {{{1 1968namespace test39 { 1969#ifndef NO_BARRIER 1970// Same as test17 but uses Barrier class (pthread_barrier_t). 1971int GLOB = 0; 1972const int N_threads = 3; 1973Barrier barrier(N_threads); 1974Mutex MU; 1975 1976void Worker() { 1977 MU.Lock(); 1978 GLOB++; 1979 MU.Unlock(); 1980 barrier.Block(); 1981 CHECK(GLOB == N_threads); 1982} 1983void Run() { 1984 ANNOTATE_TRACE_MEMORY(&GLOB); 1985// ANNOTATE_EXPECT_RACE(&GLOB, "test39. FP. Fixed by MSMProp1. Barrier."); 1986 printf("test39: negative\n"); 1987 { 1988 ThreadPool pool(N_threads); 1989 pool.StartWorkers(); 1990 for (int i = 0; i < N_threads; i++) { 1991 pool.Add(NewCallback(Worker)); 1992 } 1993 } // all folks are joined here. 1994 printf("\tGLOB=%d\n", GLOB); 1995} 1996REGISTER_TEST(Run, 39); 1997#endif // NO_BARRIER 1998} // namespace test39 1999 2000 2001// test40: FP. Synchronization via Mutexes and PCQ. 4 threads. W/W {{{1 2002namespace test40 { 2003// Similar to test38 but with different order of events (due to sleep). 2004 2005// Putter1: Putter2: Getter1: Getter2: 2006// MU1.Lock() MU1.Lock() 2007// write(GLOB) write(GLOB) 2008// MU1.Unlock() MU1.Unlock() 2009// Q1.Put() Q2.Put() 2010// Q1.Put() Q2.Put() 2011// Q1.Get() Q1.Get() 2012// Q2.Get() Q2.Get() 2013// MU2.Lock() MU2.Lock() 2014// write(GLOB) write(GLOB) 2015// MU2.Unlock() MU2.Unlock() 2016// 2017// MU1.Lock() MU1.Lock() 2018// MU2.Lock() MU2.Lock() 2019// write(GLOB) write(GLOB) 2020// MU2.Unlock() MU2.Unlock() 2021// MU1.Unlock() MU1.Unlock() 2022 2023 2024ProducerConsumerQueue *Q1, *Q2; 2025int GLOB = 0; 2026Mutex MU, MU1, MU2; 2027 2028void Putter(ProducerConsumerQueue *q) { 2029 MU1.Lock(); 2030 GLOB++; 2031 MU1.Unlock(); 2032 2033 q->Put(NULL); 2034 q->Put(NULL); 2035 usleep(100000); 2036 2037 MU1.Lock(); 2038 MU2.Lock(); 2039 GLOB++; 2040 MU2.Unlock(); 2041 MU1.Unlock(); 2042 2043} 2044 2045void Putter1() { Putter(Q1); } 2046void Putter2() { Putter(Q2); } 2047 2048void Getter() { 2049 Q1->Get(); 2050 Q2->Get(); 2051 2052 MU2.Lock(); 2053 GLOB++; 2054 MU2.Unlock(); 2055 2056 usleep(48000); // TODO: remove this when FP in test32 is fixed. 2057} 2058 2059void Run() { 2060// ANNOTATE_EXPECT_RACE(&GLOB, "test40. FP. Fixed by MSMProp1. Complex Stuff."); 2061 printf("test40: negative\n"); 2062 Q1 = new ProducerConsumerQueue(INT_MAX); 2063 Q2 = new ProducerConsumerQueue(INT_MAX); 2064 MyThreadArray t(Getter, Getter, Putter1, Putter2); 2065 t.Start(); 2066 t.Join(); 2067 printf("\tGLOB=%d\n", GLOB); 2068 delete Q1; 2069 delete Q2; 2070} 2071REGISTER_TEST(Run, 40); 2072} // namespace test40 2073 2074// test41: TN. Test for race that appears when loading a dynamic symbol. {{{1 2075namespace test41 { 2076void Worker() { 2077 ANNOTATE_NO_OP(NULL); // An empty function, loaded from dll. 2078} 2079void Run() { 2080 printf("test41: negative\n"); 2081 MyThreadArray t(Worker, Worker, Worker); 2082 t.Start(); 2083 t.Join(); 2084} 2085REGISTER_TEST2(Run, 41, FEATURE|NEEDS_ANNOTATIONS); 2086} // namespace test41 2087 2088 2089// test42: TN. Using the same cond var several times. {{{1 2090namespace test42 { 2091int GLOB = 0; 2092int COND = 0; 2093int N_threads = 3; 2094Mutex MU; 2095 2096void Worker1() { 2097 GLOB=1; 2098 2099 MU.Lock(); 2100 COND = 1; 2101 CV.Signal(); 2102 MU.Unlock(); 2103 2104 MU.Lock(); 2105 while (COND != 0) 2106 CV.Wait(&MU); 2107 ANNOTATE_CONDVAR_LOCK_WAIT(&CV, &MU); 2108 MU.Unlock(); 2109 2110 GLOB=3; 2111 2112} 2113 2114void Worker2() { 2115 2116 MU.Lock(); 2117 while (COND != 1) 2118 CV.Wait(&MU); 2119 ANNOTATE_CONDVAR_LOCK_WAIT(&CV, &MU); 2120 MU.Unlock(); 2121 2122 GLOB=2; 2123 2124 MU.Lock(); 2125 COND = 0; 2126 CV.Signal(); 2127 MU.Unlock(); 2128 2129} 2130 2131void Run() { 2132// ANNOTATE_EXPECT_RACE(&GLOB, "test42. TN. debugging."); 2133 printf("test42: negative\n"); 2134 MyThreadArray t(Worker1, Worker2); 2135 t.Start(); 2136 t.Join(); 2137 printf("\tGLOB=%d\n", GLOB); 2138} 2139REGISTER_TEST2(Run, 42, FEATURE|NEEDS_ANNOTATIONS); 2140} // namespace test42 2141 2142 2143 2144// test43: TN. {{{1 2145namespace test43 { 2146// 2147// Putter: Getter: 2148// 1. write 2149// 2. Q.Put() --\ . 2150// 3. read \--> a. Q.Get() 2151// b. read 2152int GLOB = 0; 2153ProducerConsumerQueue Q(INT_MAX); 2154void Putter() { 2155 GLOB = 1; 2156 Q.Put(NULL); 2157 CHECK(GLOB == 1); 2158} 2159void Getter() { 2160 Q.Get(); 2161 usleep(100000); 2162 CHECK(GLOB == 1); 2163} 2164void Run() { 2165 printf("test43: negative\n"); 2166 MyThreadArray t(Putter, Getter); 2167 t.Start(); 2168 t.Join(); 2169 printf("\tGLOB=%d\n", GLOB); 2170} 2171REGISTER_TEST(Run, 43) 2172} // namespace test43 2173 2174 2175// test44: FP. {{{1 2176namespace test44 { 2177// 2178// Putter: Getter: 2179// 1. read 2180// 2. Q.Put() --\ . 2181// 3. MU.Lock() \--> a. Q.Get() 2182// 4. write 2183// 5. MU.Unlock() 2184// b. MU.Lock() 2185// c. write 2186// d. MU.Unlock(); 2187int GLOB = 0; 2188Mutex MU; 2189ProducerConsumerQueue Q(INT_MAX); 2190void Putter() { 2191 CHECK(GLOB == 0); 2192 Q.Put(NULL); 2193 MU.Lock(); 2194 GLOB = 1; 2195 MU.Unlock(); 2196} 2197void Getter() { 2198 Q.Get(); 2199 usleep(100000); 2200 MU.Lock(); 2201 GLOB = 1; 2202 MU.Unlock(); 2203} 2204void Run() { 2205// ANNOTATE_EXPECT_RACE(&GLOB, "test44. FP. Fixed by MSMProp1."); 2206 printf("test44: negative\n"); 2207 MyThreadArray t(Putter, Getter); 2208 t.Start(); 2209 t.Join(); 2210 printf("\tGLOB=%d\n", GLOB); 2211} 2212REGISTER_TEST(Run, 44) 2213} // namespace test44 2214 2215 2216// test45: TN. {{{1 2217namespace test45 { 2218// 2219// Putter: Getter: 2220// 1. read 2221// 2. Q.Put() --\ . 2222// 3. MU.Lock() \--> a. Q.Get() 2223// 4. write 2224// 5. MU.Unlock() 2225// b. MU.Lock() 2226// c. read 2227// d. MU.Unlock(); 2228int GLOB = 0; 2229Mutex MU; 2230ProducerConsumerQueue Q(INT_MAX); 2231void Putter() { 2232 CHECK(GLOB == 0); 2233 Q.Put(NULL); 2234 MU.Lock(); 2235 GLOB++; 2236 MU.Unlock(); 2237} 2238void Getter() { 2239 Q.Get(); 2240 usleep(100000); 2241 MU.Lock(); 2242 CHECK(GLOB <= 1); 2243 MU.Unlock(); 2244} 2245void Run() { 2246 printf("test45: negative\n"); 2247 MyThreadArray t(Putter, Getter); 2248 t.Start(); 2249 t.Join(); 2250 printf("\tGLOB=%d\n", GLOB); 2251} 2252REGISTER_TEST(Run, 45) 2253} // namespace test45 2254 2255 2256// test46: FN. {{{1 2257namespace test46 { 2258// 2259// First: Second: 2260// 1. write 2261// 2. MU.Lock() 2262// 3. write 2263// 4. MU.Unlock() (sleep) 2264// a. MU.Lock() 2265// b. write 2266// c. MU.Unlock(); 2267int GLOB = 0; 2268Mutex MU; 2269void First() { 2270 GLOB++; 2271 MU.Lock(); 2272 GLOB++; 2273 MU.Unlock(); 2274} 2275void Second() { 2276 usleep(480000); 2277 MU.Lock(); 2278 GLOB++; 2279 MU.Unlock(); 2280 2281 // just a print. 2282 // If we move it to Run() we will get report in MSMHelgrind 2283 // due to its false positive (test32). 2284 MU.Lock(); 2285 printf("\tGLOB=%d\n", GLOB); 2286 MU.Unlock(); 2287} 2288void Run() { 2289 ANNOTATE_TRACE_MEMORY(&GLOB); 2290 MyThreadArray t(First, Second); 2291 t.Start(); 2292 t.Join(); 2293} 2294REGISTER_TEST(Run, 46) 2295} // namespace test46 2296 2297 2298// test47: TP. Not detected by pure happens-before detectors. {{{1 2299namespace test47 { 2300// A true race that can not be detected by a pure happens-before 2301// race detector. 2302// 2303// First: Second: 2304// 1. write 2305// 2. MU.Lock() 2306// 3. MU.Unlock() (sleep) 2307// a. MU.Lock() 2308// b. MU.Unlock(); 2309// c. write 2310int GLOB = 0; 2311Mutex MU; 2312void First() { 2313 GLOB=1; 2314 MU.Lock(); 2315 MU.Unlock(); 2316} 2317void Second() { 2318 usleep(480000); 2319 MU.Lock(); 2320 MU.Unlock(); 2321 GLOB++; 2322} 2323void Run() { 2324 FAST_MODE_INIT(&GLOB); 2325 if (!Tsan_PureHappensBefore()) 2326 ANNOTATE_EXPECT_RACE_FOR_TSAN(&GLOB, "test47. TP. Not detected by pure HB."); 2327 printf("test47: positive\n"); 2328 MyThreadArray t(First, Second); 2329 t.Start(); 2330 t.Join(); 2331 printf("\tGLOB=%d\n", GLOB); 2332} 2333REGISTER_TEST(Run, 47) 2334} // namespace test47 2335 2336 2337// test48: FN. Simple race (single write vs multiple reads). {{{1 2338namespace test48 { 2339int GLOB = 0; 2340// same as test10 but with single writer and multiple readers 2341// A simple data race between single writer and multiple readers. 2342// Write happens before Reads (enforced by sleep(1)), 2343 2344// 2345// Writer: Readers: 2346// 1. write(GLOB) a. sleep(long enough so that GLOB 2347// is most likely initialized by Writer) 2348// b. read(GLOB) 2349// 2350// 2351// Eraser algorithm does not detect the race here, 2352// see Section 2.2 of http://citeseer.ist.psu.edu/savage97eraser.html. 2353// 2354void Writer() { 2355 GLOB = 3; 2356} 2357void Reader() { 2358 usleep(100000); 2359 CHECK(GLOB != -777); 2360} 2361 2362void Run() { 2363 FAST_MODE_INIT(&GLOB); 2364 ANNOTATE_EXPECT_RACE_FOR_TSAN(&GLOB, "test48. TP. FN in MSMHelgrind."); 2365 printf("test48: positive\n"); 2366 MyThreadArray t(Writer, Reader,Reader,Reader); 2367 t.Start(); 2368 t.Join(); 2369 printf("\tGLOB=%d\n", GLOB); 2370} 2371REGISTER_TEST(Run, 48) 2372} // namespace test48 2373 2374 2375// test49: FN. Simple race (single write vs multiple reads). {{{1 2376namespace test49 { 2377int GLOB = 0; 2378// same as test10 but with multiple read operations done by a single reader 2379// A simple data race between writer and readers. 2380// Write happens before Read (enforced by sleep(1)), 2381// 2382// Writer: Reader: 2383// 1. write(GLOB) a. sleep(long enough so that GLOB 2384// is most likely initialized by Writer) 2385// b. read(GLOB) 2386// c. read(GLOB) 2387// d. read(GLOB) 2388// e. read(GLOB) 2389// 2390// 2391// Eraser algorithm does not detect the race here, 2392// see Section 2.2 of http://citeseer.ist.psu.edu/savage97eraser.html. 2393// 2394void Writer() { 2395 GLOB = 3; 2396} 2397void Reader() { 2398 usleep(100000); 2399 CHECK(GLOB != -777); 2400 CHECK(GLOB != -777); 2401 CHECK(GLOB != -777); 2402 CHECK(GLOB != -777); 2403} 2404 2405void Run() { 2406 FAST_MODE_INIT(&GLOB); 2407 ANNOTATE_EXPECT_RACE_FOR_TSAN(&GLOB, "test49. TP. FN in MSMHelgrind."); 2408 printf("test49: positive\n"); 2409 MyThreadArray t(Writer, Reader); 2410 t.Start(); 2411 t.Join(); 2412 printf("\tGLOB=%d\n", GLOB); 2413} 2414REGISTER_TEST(Run, 49); 2415} // namespace test49 2416 2417 2418// test50: TP. Synchronization via CondVar. {{{1 2419namespace test50 { 2420int GLOB = 0; 2421Mutex MU; 2422// Two last write accesses to GLOB are not synchronized 2423// 2424// Waiter: Waker: 2425// 1. COND = 0 2426// 2. Start(Waker) 2427// 3. MU.Lock() a. write(GLOB) 2428// b. MU.Lock() 2429// c. COND = 1 2430// /--- d. CV.Signal() 2431// 4. while(COND != 1) / e. MU.Unlock() 2432// CV.Wait(MU) <---/ 2433// 5. MU.Unlock() 2434// 6. write(GLOB) f. MU.Lock() 2435// g. write(GLOB) 2436// h. MU.Unlock() 2437 2438 2439void Waker() { 2440 usleep(100000); // Make sure the waiter blocks. 2441 2442 GLOB = 1; 2443 2444 MU.Lock(); 2445 COND = 1; 2446 CV.Signal(); 2447 MU.Unlock(); 2448 2449 usleep(100000); 2450 MU.Lock(); 2451 GLOB = 3; 2452 MU.Unlock(); 2453} 2454 2455void Waiter() { 2456 ThreadPool pool(1); 2457 pool.StartWorkers(); 2458 COND = 0; 2459 pool.Add(NewCallback(Waker)); 2460 2461 MU.Lock(); 2462 while(COND != 1) 2463 CV.Wait(&MU); 2464 ANNOTATE_CONDVAR_LOCK_WAIT(&CV, &MU); 2465 MU.Unlock(); 2466 2467 GLOB = 2; 2468} 2469void Run() { 2470 FAST_MODE_INIT(&GLOB); 2471 ANNOTATE_EXPECT_RACE_FOR_TSAN(&GLOB, "test50. TP."); 2472 printf("test50: positive\n"); 2473 Waiter(); 2474 printf("\tGLOB=%d\n", GLOB); 2475} 2476REGISTER_TEST2(Run, 50, FEATURE|NEEDS_ANNOTATIONS); 2477} // namespace test50 2478 2479 2480// test51: TP. Synchronization via CondVar: problem with several signals. {{{1 2481namespace test51 { 2482int GLOB = 0; 2483int COND = 0; 2484Mutex MU; 2485 2486 2487// scheduler dependent results because of several signals 2488// second signal will be lost 2489// 2490// Waiter: Waker: 2491// 1. Start(Waker) 2492// 2. MU.Lock() 2493// 3. while(COND) 2494// CV.Wait(MU)<-\ . 2495// 4. MU.Unlock() \ . 2496// 5. write(GLOB) \ a. write(GLOB) 2497// \ b. MU.Lock() 2498// \ c. COND = 1 2499// \--- d. CV.Signal() 2500// e. MU.Unlock() 2501// 2502// f. write(GLOB) 2503// 2504// g. MU.Lock() 2505// h. COND = 1 2506// LOST<---- i. CV.Signal() 2507// j. MU.Unlock() 2508 2509void Waker() { 2510 2511 usleep(10000); // Make sure the waiter blocks. 2512 2513 GLOB = 1; 2514 2515 MU.Lock(); 2516 COND = 1; 2517 CV.Signal(); 2518 MU.Unlock(); 2519 2520 usleep(10000); // Make sure the waiter is signalled. 2521 2522 GLOB = 2; 2523 2524 MU.Lock(); 2525 COND = 1; 2526 CV.Signal(); //Lost Signal 2527 MU.Unlock(); 2528} 2529 2530void Waiter() { 2531 2532 ThreadPool pool(1); 2533 pool.StartWorkers(); 2534 pool.Add(NewCallback(Waker)); 2535 2536 MU.Lock(); 2537 while(COND != 1) 2538 CV.Wait(&MU); 2539 MU.Unlock(); 2540 2541 2542 GLOB = 3; 2543} 2544void Run() { 2545 FAST_MODE_INIT(&GLOB); 2546 ANNOTATE_EXPECT_RACE(&GLOB, "test51. TP."); 2547 printf("test51: positive\n"); 2548 Waiter(); 2549 printf("\tGLOB=%d\n", GLOB); 2550} 2551REGISTER_TEST(Run, 51); 2552} // namespace test51 2553 2554 2555// test52: TP. Synchronization via CondVar: problem with several signals. {{{1 2556namespace test52 { 2557int GLOB = 0; 2558int COND = 0; 2559Mutex MU; 2560 2561// same as test51 but the first signal will be lost 2562// scheduler dependent results because of several signals 2563// 2564// Waiter: Waker: 2565// 1. Start(Waker) 2566// a. write(GLOB) 2567// b. MU.Lock() 2568// c. COND = 1 2569// LOST<---- d. CV.Signal() 2570// e. MU.Unlock() 2571// 2572// 2. MU.Lock() 2573// 3. while(COND) 2574// CV.Wait(MU)<-\ . 2575// 4. MU.Unlock() \ f. write(GLOB) 2576// 5. write(GLOB) \ . 2577// \ g. MU.Lock() 2578// \ h. COND = 1 2579// \--- i. CV.Signal() 2580// j. MU.Unlock() 2581 2582void Waker() { 2583 2584 GLOB = 1; 2585 2586 MU.Lock(); 2587 COND = 1; 2588 CV.Signal(); //lost signal 2589 MU.Unlock(); 2590 2591 usleep(20000); // Make sure the waiter blocks 2592 2593 GLOB = 2; 2594 2595 MU.Lock(); 2596 COND = 1; 2597 CV.Signal(); 2598 MU.Unlock(); 2599} 2600 2601void Waiter() { 2602 ThreadPool pool(1); 2603 pool.StartWorkers(); 2604 pool.Add(NewCallback(Waker)); 2605 2606 usleep(10000); // Make sure the first signal will be lost 2607 2608 MU.Lock(); 2609 while(COND != 1) 2610 CV.Wait(&MU); 2611 MU.Unlock(); 2612 2613 GLOB = 3; 2614} 2615void Run() { 2616 FAST_MODE_INIT(&GLOB); 2617 ANNOTATE_EXPECT_RACE(&GLOB, "test52. TP."); 2618 printf("test52: positive\n"); 2619 Waiter(); 2620 printf("\tGLOB=%d\n", GLOB); 2621} 2622REGISTER_TEST(Run, 52); 2623} // namespace test52 2624 2625 2626// test53: FP. Synchronization via implicit semaphore. {{{1 2627namespace test53 { 2628// Correctly synchronized test, but the common lockset is empty. 2629// The variable FLAG works as an implicit semaphore. 2630// MSMHelgrind still does not complain since it does not maintain the lockset 2631// at the exclusive state. But MSMProp1 does complain. 2632// See also test54. 2633// 2634// 2635// Initializer: Users 2636// 1. MU1.Lock() 2637// 2. write(GLOB) 2638// 3. FLAG = true 2639// 4. MU1.Unlock() 2640// a. MU1.Lock() 2641// b. f = FLAG; 2642// c. MU1.Unlock() 2643// d. if (!f) goto a. 2644// e. MU2.Lock() 2645// f. write(GLOB) 2646// g. MU2.Unlock() 2647// 2648 2649int GLOB = 0; 2650bool FLAG = false; 2651Mutex MU1, MU2; 2652 2653void Initializer() { 2654 MU1.Lock(); 2655 GLOB = 1000; 2656 FLAG = true; 2657 MU1.Unlock(); 2658 usleep(100000); // just in case 2659} 2660 2661void User() { 2662 bool f = false; 2663 while(!f) { 2664 MU1.Lock(); 2665 f = FLAG; 2666 MU1.Unlock(); 2667 usleep(10000); 2668 } 2669 // at this point Initializer will not access GLOB again 2670 MU2.Lock(); 2671 CHECK(GLOB >= 1000); 2672 GLOB++; 2673 MU2.Unlock(); 2674} 2675 2676void Run() { 2677 FAST_MODE_INIT(&GLOB); 2678 if (!Tsan_PureHappensBefore()) 2679 ANNOTATE_EXPECT_RACE_FOR_TSAN(&GLOB, "test53. FP. Implicit semaphore"); 2680 printf("test53: FP. false positive, Implicit semaphore\n"); 2681 MyThreadArray t(Initializer, User, User); 2682 t.Start(); 2683 t.Join(); 2684 printf("\tGLOB=%d\n", GLOB); 2685} 2686REGISTER_TEST(Run, 53) 2687} // namespace test53 2688 2689 2690// test54: TN. Synchronization via implicit semaphore. Annotated {{{1 2691namespace test54 { 2692// Same as test53, but annotated. 2693int GLOB = 0; 2694bool FLAG = false; 2695Mutex MU1, MU2; 2696 2697void Initializer() { 2698 MU1.Lock(); 2699 GLOB = 1000; 2700 FLAG = true; 2701 ANNOTATE_CONDVAR_SIGNAL(&GLOB); 2702 MU1.Unlock(); 2703 usleep(100000); // just in case 2704} 2705 2706void User() { 2707 bool f = false; 2708 while(!f) { 2709 MU1.Lock(); 2710 f = FLAG; 2711 MU1.Unlock(); 2712 usleep(10000); 2713 } 2714 // at this point Initializer will not access GLOB again 2715 ANNOTATE_CONDVAR_WAIT(&GLOB); 2716 MU2.Lock(); 2717 CHECK(GLOB >= 1000); 2718 GLOB++; 2719 MU2.Unlock(); 2720} 2721 2722void Run() { 2723 printf("test54: negative\n"); 2724 MyThreadArray t(Initializer, User, User); 2725 t.Start(); 2726 t.Join(); 2727 printf("\tGLOB=%d\n", GLOB); 2728} 2729REGISTER_TEST2(Run, 54, FEATURE|NEEDS_ANNOTATIONS) 2730} // namespace test54 2731 2732 2733// test55: FP. Synchronization with TryLock. Not easy for race detectors {{{1 2734namespace test55 { 2735// "Correct" synchronization with TryLock and Lock. 2736// 2737// This scheme is actually very risky. 2738// It is covered in detail in this video: 2739// http://youtube.com/watch?v=mrvAqvtWYb4 (slide 36, near 50-th minute). 2740int GLOB = 0; 2741Mutex MU; 2742 2743void Worker_Lock() { 2744 GLOB = 1; 2745 MU.Lock(); 2746} 2747 2748void Worker_TryLock() { 2749 while (true) { 2750 if (!MU.TryLock()) { 2751 MU.Unlock(); 2752 break; 2753 } 2754 else 2755 MU.Unlock(); 2756 usleep(100); 2757 } 2758 GLOB = 2; 2759} 2760 2761void Run() { 2762 printf("test55:\n"); 2763 MyThreadArray t(Worker_Lock, Worker_TryLock); 2764 t.Start(); 2765 t.Join(); 2766 printf("\tGLOB=%d\n", GLOB); 2767} 2768REGISTER_TEST2(Run, 55, FEATURE|EXCLUDE_FROM_ALL); 2769} // namespace test55 2770 2771 2772 2773// test56: TP. Use of ANNOTATE_BENIGN_RACE. {{{1 2774namespace test56 { 2775// For whatever reason the user wants to treat 2776// a race on GLOB as a benign race. 2777int GLOB = 0; 2778int GLOB2 = 0; 2779 2780void Worker() { 2781 GLOB++; 2782} 2783 2784void Run() { 2785 ANNOTATE_BENIGN_RACE(&GLOB, "test56. Use of ANNOTATE_BENIGN_RACE."); 2786 ANNOTATE_BENIGN_RACE(&GLOB2, "No race. The tool should be silent"); 2787 printf("test56: positive\n"); 2788 MyThreadArray t(Worker, Worker, Worker, Worker); 2789 t.Start(); 2790 t.Join(); 2791 printf("\tGLOB=%d\n", GLOB); 2792} 2793REGISTER_TEST2(Run, 56, FEATURE|NEEDS_ANNOTATIONS) 2794} // namespace test56 2795 2796 2797// test57: TN: Correct use of atomics. {{{1 2798namespace test57 { 2799int GLOB = 0; 2800void Writer() { 2801 for (int i = 0; i < 10; i++) { 2802 AtomicIncrement(&GLOB, 1); 2803 usleep(1000); 2804 } 2805} 2806void Reader() { 2807 while (GLOB < 20) usleep(1000); 2808} 2809void Run() { 2810 printf("test57: negative\n"); 2811 MyThreadArray t(Writer, Writer, Reader, Reader); 2812 t.Start(); 2813 t.Join(); 2814 CHECK(GLOB == 20); 2815 printf("\tGLOB=%d\n", GLOB); 2816} 2817REGISTER_TEST(Run, 57) 2818} // namespace test57 2819 2820 2821// test58: TN. User defined synchronization. {{{1 2822namespace test58 { 2823int GLOB1 = 1; 2824int GLOB2 = 2; 2825int FLAG1 = 0; 2826int FLAG2 = 0; 2827 2828// Correctly synchronized test, but the common lockset is empty. 2829// The variables FLAG1 and FLAG2 used for synchronization and as 2830// temporary variables for swapping two global values. 2831// Such kind of synchronization is rarely used (Excluded from all tests??). 2832 2833void Worker2() { 2834 FLAG1=GLOB2; 2835 2836 while(!FLAG2) 2837 ; 2838 GLOB2=FLAG2; 2839} 2840 2841void Worker1() { 2842 FLAG2=GLOB1; 2843 2844 while(!FLAG1) 2845 ; 2846 GLOB1=FLAG1; 2847} 2848 2849void Run() { 2850 printf("test58:\n"); 2851 MyThreadArray t(Worker1, Worker2); 2852 t.Start(); 2853 t.Join(); 2854 printf("\tGLOB1=%d\n", GLOB1); 2855 printf("\tGLOB2=%d\n", GLOB2); 2856} 2857REGISTER_TEST2(Run, 58, FEATURE|EXCLUDE_FROM_ALL) 2858} // namespace test58 2859 2860 2861 2862// test59: TN. User defined synchronization. Annotated {{{1 2863namespace test59 { 2864int COND1 = 0; 2865int COND2 = 0; 2866int GLOB1 = 1; 2867int GLOB2 = 2; 2868int FLAG1 = 0; 2869int FLAG2 = 0; 2870// same as test 58 but annotated 2871 2872void Worker2() { 2873 FLAG1=GLOB2; 2874 ANNOTATE_CONDVAR_SIGNAL(&COND2); 2875 while(!FLAG2) usleep(1); 2876 ANNOTATE_CONDVAR_WAIT(&COND1); 2877 GLOB2=FLAG2; 2878} 2879 2880void Worker1() { 2881 FLAG2=GLOB1; 2882 ANNOTATE_CONDVAR_SIGNAL(&COND1); 2883 while(!FLAG1) usleep(1); 2884 ANNOTATE_CONDVAR_WAIT(&COND2); 2885 GLOB1=FLAG1; 2886} 2887 2888void Run() { 2889 printf("test59: negative\n"); 2890 ANNOTATE_BENIGN_RACE(&FLAG1, "synchronization via 'safe' race"); 2891 ANNOTATE_BENIGN_RACE(&FLAG2, "synchronization via 'safe' race"); 2892 MyThreadArray t(Worker1, Worker2); 2893 t.Start(); 2894 t.Join(); 2895 printf("\tGLOB1=%d\n", GLOB1); 2896 printf("\tGLOB2=%d\n", GLOB2); 2897} 2898REGISTER_TEST2(Run, 59, FEATURE|NEEDS_ANNOTATIONS) 2899} // namespace test59 2900 2901 2902// test60: TN. Correct synchronization using signal-wait {{{1 2903namespace test60 { 2904int COND1 = 0; 2905int COND2 = 0; 2906int GLOB1 = 1; 2907int GLOB2 = 2; 2908int FLAG2 = 0; 2909int FLAG1 = 0; 2910Mutex MU; 2911// same as test 59 but synchronized with signal-wait. 2912 2913void Worker2() { 2914 FLAG1=GLOB2; 2915 2916 MU.Lock(); 2917 COND1 = 1; 2918 CV.Signal(); 2919 MU.Unlock(); 2920 2921 MU.Lock(); 2922 while(COND2 != 1) 2923 CV.Wait(&MU); 2924 ANNOTATE_CONDVAR_LOCK_WAIT(&CV, &MU); 2925 MU.Unlock(); 2926 2927 GLOB2=FLAG2; 2928} 2929 2930void Worker1() { 2931 FLAG2=GLOB1; 2932 2933 MU.Lock(); 2934 COND2 = 1; 2935 CV.Signal(); 2936 MU.Unlock(); 2937 2938 MU.Lock(); 2939 while(COND1 != 1) 2940 CV.Wait(&MU); 2941 ANNOTATE_CONDVAR_LOCK_WAIT(&CV, &MU); 2942 MU.Unlock(); 2943 2944 GLOB1=FLAG1; 2945} 2946 2947void Run() { 2948 printf("test60: negative\n"); 2949 MyThreadArray t(Worker1, Worker2); 2950 t.Start(); 2951 t.Join(); 2952 printf("\tGLOB1=%d\n", GLOB1); 2953 printf("\tGLOB2=%d\n", GLOB2); 2954} 2955REGISTER_TEST2(Run, 60, FEATURE|NEEDS_ANNOTATIONS) 2956} // namespace test60 2957 2958 2959// test61: TN. Synchronization via Mutex as in happens-before, annotated. {{{1 2960namespace test61 { 2961Mutex MU; 2962int GLOB = 0; 2963int *P1 = NULL, *P2 = NULL; 2964 2965// In this test Mutex lock/unlock operations introduce happens-before relation. 2966// We annotate the code so that MU is treated as in pure happens-before detector. 2967 2968 2969void Putter() { 2970 ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(&MU); 2971 MU.Lock(); 2972 if (P1 == NULL) { 2973 P1 = &GLOB; 2974 *P1 = 1; 2975 } 2976 MU.Unlock(); 2977} 2978 2979void Getter() { 2980 bool done = false; 2981 while (!done) { 2982 MU.Lock(); 2983 if (P1) { 2984 done = true; 2985 P2 = P1; 2986 P1 = NULL; 2987 } 2988 MU.Unlock(); 2989 } 2990 *P2 = 2; 2991} 2992 2993 2994void Run() { 2995 printf("test61: negative\n"); 2996 MyThreadArray t(Putter, Getter); 2997 t.Start(); 2998 t.Join(); 2999 printf("\tGLOB=%d\n", GLOB); 3000} 3001REGISTER_TEST2(Run, 61, FEATURE|NEEDS_ANNOTATIONS) 3002} // namespace test61 3003 3004 3005// test62: STAB. Create as many segments as possible. {{{1 3006namespace test62 { 3007// Helgrind 3.3.0 will fail as it has a hard limit of < 2^24 segments. 3008// A better scheme is to implement garbage collection for segments. 3009ProducerConsumerQueue Q(INT_MAX); 3010const int N = 1 << 22; 3011 3012void Putter() { 3013 for (int i = 0; i < N; i++){ 3014 if ((i % (N / 8)) == 0) { 3015 printf("i=%d\n", i); 3016 } 3017 Q.Put(NULL); 3018 } 3019} 3020 3021void Getter() { 3022 for (int i = 0; i < N; i++) 3023 Q.Get(); 3024} 3025 3026void Run() { 3027 printf("test62:\n"); 3028 MyThreadArray t(Putter, Getter); 3029 t.Start(); 3030 t.Join(); 3031} 3032REGISTER_TEST2(Run, 62, STABILITY|EXCLUDE_FROM_ALL) 3033} // namespace test62 3034 3035 3036// test63: STAB. Create as many segments as possible and do it fast. {{{1 3037namespace test63 { 3038// Helgrind 3.3.0 will fail as it has a hard limit of < 2^24 segments. 3039// A better scheme is to implement garbage collection for segments. 3040const int N = 1 << 24; 3041int C = 0; 3042 3043void Putter() { 3044 for (int i = 0; i < N; i++){ 3045 if ((i % (N / 8)) == 0) { 3046 printf("i=%d\n", i); 3047 } 3048 ANNOTATE_CONDVAR_SIGNAL(&C); 3049 } 3050} 3051 3052void Getter() { 3053} 3054 3055void Run() { 3056 printf("test63:\n"); 3057 MyThreadArray t(Putter, Getter); 3058 t.Start(); 3059 t.Join(); 3060} 3061REGISTER_TEST2(Run, 63, STABILITY|EXCLUDE_FROM_ALL) 3062} // namespace test63 3063 3064 3065// test64: TP. T2 happens-before T3, but T1 is independent. Reads in T1/T2. {{{1 3066namespace test64 { 3067// True race between T1 and T3: 3068// 3069// T1: T2: T3: 3070// 1. read(GLOB) (sleep) 3071// a. read(GLOB) 3072// b. Q.Put() -----> A. Q.Get() 3073// B. write(GLOB) 3074// 3075// 3076 3077int GLOB = 0; 3078ProducerConsumerQueue Q(INT_MAX); 3079 3080void T1() { 3081 CHECK(GLOB == 0); 3082} 3083 3084void T2() { 3085 usleep(100000); 3086 CHECK(GLOB == 0); 3087 Q.Put(NULL); 3088} 3089 3090void T3() { 3091 Q.Get(); 3092 GLOB = 1; 3093} 3094 3095 3096void Run() { 3097 FAST_MODE_INIT(&GLOB); 3098 ANNOTATE_EXPECT_RACE_FOR_TSAN(&GLOB, "test64: TP."); 3099 printf("test64: positive\n"); 3100 MyThreadArray t(T1, T2, T3); 3101 t.Start(); 3102 t.Join(); 3103 printf("\tGLOB=%d\n", GLOB); 3104} 3105REGISTER_TEST(Run, 64) 3106} // namespace test64 3107 3108 3109// test65: TP. T2 happens-before T3, but T1 is independent. Writes in T1/T2. {{{1 3110namespace test65 { 3111// Similar to test64. 3112// True race between T1 and T3: 3113// 3114// T1: T2: T3: 3115// 1. MU.Lock() 3116// 2. write(GLOB) 3117// 3. MU.Unlock() (sleep) 3118// a. MU.Lock() 3119// b. write(GLOB) 3120// c. MU.Unlock() 3121// d. Q.Put() -----> A. Q.Get() 3122// B. write(GLOB) 3123// 3124// 3125 3126int GLOB = 0; 3127Mutex MU; 3128ProducerConsumerQueue Q(INT_MAX); 3129 3130void T1() { 3131 MU.Lock(); 3132 GLOB++; 3133 MU.Unlock(); 3134} 3135 3136void T2() { 3137 usleep(100000); 3138 MU.Lock(); 3139 GLOB++; 3140 MU.Unlock(); 3141 Q.Put(NULL); 3142} 3143 3144void T3() { 3145 Q.Get(); 3146 GLOB = 1; 3147} 3148 3149 3150void Run() { 3151 FAST_MODE_INIT(&GLOB); 3152 if (!Tsan_PureHappensBefore()) 3153 ANNOTATE_EXPECT_RACE_FOR_TSAN(&GLOB, "test65. TP."); 3154 printf("test65: positive\n"); 3155 MyThreadArray t(T1, T2, T3); 3156 t.Start(); 3157 t.Join(); 3158 printf("\tGLOB=%d\n", GLOB); 3159} 3160REGISTER_TEST(Run, 65) 3161} // namespace test65 3162 3163 3164// test66: TN. Two separate pairs of signaller/waiter using the same CV. {{{1 3165namespace test66 { 3166int GLOB1 = 0; 3167int GLOB2 = 0; 3168int C1 = 0; 3169int C2 = 0; 3170Mutex MU; 3171 3172void Signaller1() { 3173 GLOB1 = 1; 3174 MU.Lock(); 3175 C1 = 1; 3176 CV.Signal(); 3177 MU.Unlock(); 3178} 3179 3180void Signaller2() { 3181 GLOB2 = 1; 3182 usleep(100000); 3183 MU.Lock(); 3184 C2 = 1; 3185 CV.Signal(); 3186 MU.Unlock(); 3187} 3188 3189void Waiter1() { 3190 MU.Lock(); 3191 while (C1 != 1) CV.Wait(&MU); 3192 ANNOTATE_CONDVAR_WAIT(&CV); 3193 MU.Unlock(); 3194 GLOB1 = 2; 3195} 3196 3197void Waiter2() { 3198 MU.Lock(); 3199 while (C2 != 1) CV.Wait(&MU); 3200 ANNOTATE_CONDVAR_WAIT(&CV); 3201 MU.Unlock(); 3202 GLOB2 = 2; 3203} 3204 3205void Run() { 3206 printf("test66: negative\n"); 3207 MyThreadArray t(Signaller1, Signaller2, Waiter1, Waiter2); 3208 t.Start(); 3209 t.Join(); 3210 printf("\tGLOB=%d/%d\n", GLOB1, GLOB2); 3211} 3212REGISTER_TEST2(Run, 66, FEATURE|NEEDS_ANNOTATIONS) 3213} // namespace test66 3214 3215 3216// test67: FN. Race between Signaller1 and Waiter2 {{{1 3217namespace test67 { 3218// Similar to test66, but there is a real race here. 3219// 3220// Here we create a happens-before arc between Signaller1 and Waiter2 3221// even though there should be no such arc. 3222// However, it's probably improssible (or just very hard) to avoid it. 3223int GLOB = 0; 3224int C1 = 0; 3225int C2 = 0; 3226Mutex MU; 3227 3228void Signaller1() { 3229 GLOB = 1; 3230 MU.Lock(); 3231 C1 = 1; 3232 CV.Signal(); 3233 MU.Unlock(); 3234} 3235 3236void Signaller2() { 3237 usleep(100000); 3238 MU.Lock(); 3239 C2 = 1; 3240 CV.Signal(); 3241 MU.Unlock(); 3242} 3243 3244void Waiter1() { 3245 MU.Lock(); 3246 while (C1 != 1) CV.Wait(&MU); 3247 ANNOTATE_CONDVAR_WAIT(&CV); 3248 MU.Unlock(); 3249} 3250 3251void Waiter2() { 3252 MU.Lock(); 3253 while (C2 != 1) CV.Wait(&MU); 3254 ANNOTATE_CONDVAR_WAIT(&CV); 3255 MU.Unlock(); 3256 GLOB = 2; 3257} 3258 3259void Run() { 3260 FAST_MODE_INIT(&GLOB); 3261 ANNOTATE_EXPECT_RACE(&GLOB, "test67. FN. Race between Signaller1 and Waiter2"); 3262 printf("test67: positive\n"); 3263 MyThreadArray t(Signaller1, Signaller2, Waiter1, Waiter2); 3264 t.Start(); 3265 t.Join(); 3266 printf("\tGLOB=%d\n", GLOB); 3267} 3268REGISTER_TEST2(Run, 67, FEATURE|NEEDS_ANNOTATIONS|EXCLUDE_FROM_ALL) 3269} // namespace test67 3270 3271 3272// test68: TP. Writes are protected by MU, reads are not. {{{1 3273namespace test68 { 3274// In this test, all writes to GLOB are protected by a mutex 3275// but some reads go unprotected. 3276// This is certainly a race, but in some cases such code could occur in 3277// a correct program. For example, the unprotected reads may be used 3278// for showing statistics and are not required to be precise. 3279int GLOB = 0; 3280int COND = 0; 3281const int N_writers = 3; 3282Mutex MU, MU1; 3283 3284void Writer() { 3285 for (int i = 0; i < 100; i++) { 3286 MU.Lock(); 3287 GLOB++; 3288 MU.Unlock(); 3289 } 3290 3291 // we are done 3292 MU1.Lock(); 3293 COND++; 3294 MU1.Unlock(); 3295} 3296 3297void Reader() { 3298 bool cont = true; 3299 while (cont) { 3300 CHECK(GLOB >= 0); 3301 3302 // are we done? 3303 MU1.Lock(); 3304 if (COND == N_writers) 3305 cont = false; 3306 MU1.Unlock(); 3307 usleep(100); 3308 } 3309} 3310 3311void Run() { 3312 FAST_MODE_INIT(&GLOB); 3313 ANNOTATE_EXPECT_RACE(&GLOB, "TP. Writes are protected, reads are not."); 3314 printf("test68: positive\n"); 3315 MyThreadArray t(Reader, Writer, Writer, Writer); 3316 t.Start(); 3317 t.Join(); 3318 printf("\tGLOB=%d\n", GLOB); 3319} 3320REGISTER_TEST(Run, 68) 3321} // namespace test68 3322 3323 3324// test69: {{{1 3325namespace test69 { 3326// This is the same as test68, but annotated. 3327// We do not want to annotate GLOB as a benign race 3328// because we want to allow racy reads only in certain places. 3329// 3330// TODO: 3331int GLOB = 0; 3332int COND = 0; 3333const int N_writers = 3; 3334int FAKE_MU = 0; 3335Mutex MU, MU1; 3336 3337void Writer() { 3338 for (int i = 0; i < 10; i++) { 3339 MU.Lock(); 3340 GLOB++; 3341 MU.Unlock(); 3342 } 3343 3344 // we are done 3345 MU1.Lock(); 3346 COND++; 3347 MU1.Unlock(); 3348} 3349 3350void Reader() { 3351 bool cont = true; 3352 while (cont) { 3353 ANNOTATE_IGNORE_READS_BEGIN(); 3354 CHECK(GLOB >= 0); 3355 ANNOTATE_IGNORE_READS_END(); 3356 3357 // are we done? 3358 MU1.Lock(); 3359 if (COND == N_writers) 3360 cont = false; 3361 MU1.Unlock(); 3362 usleep(100); 3363 } 3364} 3365 3366void Run() { 3367 printf("test69: negative\n"); 3368 MyThreadArray t(Reader, Writer, Writer, Writer); 3369 t.Start(); 3370 t.Join(); 3371 printf("\tGLOB=%d\n", GLOB); 3372} 3373REGISTER_TEST(Run, 69) 3374} // namespace test69 3375 3376// test70: STAB. Check that TRACE_MEMORY works. {{{1 3377namespace test70 { 3378int GLOB = 0; 3379void Run() { 3380 printf("test70: negative\n"); 3381 ANNOTATE_TRACE_MEMORY(&GLOB); 3382 GLOB = 1; 3383 printf("\tGLOB=%d\n", GLOB); 3384} 3385REGISTER_TEST(Run, 70) 3386} // namespace test70 3387 3388 3389 3390// test71: TN. strlen, index. {{{1 3391namespace test71 { 3392// This test is a reproducer for a benign race in strlen (as well as index, etc). 3393// Some implementations of strlen may read up to 7 bytes past the end of the string 3394// thus touching memory which may not belong to this string. 3395// Such race is benign because the data read past the end of the string is not used. 3396// 3397// Here, we allocate a 8-byte aligned string str and initialize first 5 bytes. 3398// Then one thread calls strlen(str) (as well as index & rindex) 3399// and another thread initializes str[5]..str[7]. 3400// 3401// This can be fixed in Helgrind by intercepting strlen and replacing it 3402// with a simpler implementation. 3403 3404char *str; 3405void WorkerX() { 3406 usleep(100000); 3407 CHECK(strlen(str) == 4); 3408 CHECK(index(str, 'X') == str); 3409 CHECK(index(str, 'x') == str+1); 3410 CHECK(index(str, 'Y') == NULL); 3411 CHECK(rindex(str, 'X') == str+2); 3412 CHECK(rindex(str, 'x') == str+3); 3413 CHECK(rindex(str, 'Y') == NULL); 3414} 3415void WorkerY() { 3416 str[5] = 'Y'; 3417 str[6] = 'Y'; 3418 str[7] = '\0'; 3419} 3420 3421void Run() { 3422 str = new char[8]; 3423 str[0] = 'X'; 3424 str[1] = 'x'; 3425 str[2] = 'X'; 3426 str[3] = 'x'; 3427 str[4] = '\0'; 3428 3429 printf("test71: negative (strlen & index)\n"); 3430 MyThread t1(WorkerY); 3431 MyThread t2(WorkerX); 3432 t1.Start(); 3433 t2.Start(); 3434 t1.Join(); 3435 t2.Join(); 3436 printf("\tstrX=%s; strY=%s\n", str, str+5); 3437} 3438REGISTER_TEST(Run, 71) 3439} // namespace test71 3440 3441 3442// test72: STAB. Stress test for the number of segment sets (SSETs). {{{1 3443namespace test72 { 3444#ifndef NO_BARRIER 3445// Variation of test33. 3446// Instead of creating Nlog*N_iter threads, 3447// we create Nlog threads and do N_iter barriers. 3448int GLOB = 0; 3449const int N_iter = 30; 3450const int Nlog = 16; 3451const int N = 1 << Nlog; 3452static int64_t ARR1[N]; 3453static int64_t ARR2[N]; 3454Barrier *barriers[N_iter]; 3455Mutex MU; 3456 3457void Worker() { 3458 MU.Lock(); 3459 int n = ++GLOB; 3460 MU.Unlock(); 3461 3462 n %= Nlog; 3463 3464 long t0 = clock(); 3465 long t = t0; 3466 3467 for (int it = 0; it < N_iter; it++) { 3468 if(n == 0) { 3469 //printf("Iter: %d; %ld %ld\n", it, clock() - t, clock() - t0); 3470 t = clock(); 3471 } 3472 // Iterate N_iter times, block on barrier after each iteration. 3473 // This way Helgrind will create new segments after each barrier. 3474 3475 for (int x = 0; x < 2; x++) { 3476 // run the inner loop twice. 3477 // When a memory location is accessed second time it is likely 3478 // that the state (SVal) will be unchanged. 3479 // The memory machine may optimize this case. 3480 for (int i = 0; i < N; i++) { 3481 // ARR1[i] and ARR2[N-1-i] are accessed by threads from i-th subset 3482 if (i & (1 << n)) { 3483 CHECK(ARR1[i] == 0); 3484 CHECK(ARR2[N-1-i] == 0); 3485 } 3486 } 3487 } 3488 barriers[it]->Block(); 3489 } 3490} 3491 3492 3493void Run() { 3494 printf("test72:\n"); 3495 3496 std::vector<MyThread*> vec(Nlog); 3497 3498 for (int i = 0; i < N_iter; i++) 3499 barriers[i] = new Barrier(Nlog); 3500 3501 // Create and start Nlog threads 3502 for (int i = 0; i < Nlog; i++) { 3503 vec[i] = new MyThread(Worker); 3504 vec[i]->Start(); 3505 } 3506 3507 // Join all threads. 3508 for (int i = 0; i < Nlog; i++) { 3509 vec[i]->Join(); 3510 delete vec[i]; 3511 } 3512 for (int i = 0; i < N_iter; i++) 3513 delete barriers[i]; 3514 3515 /*printf("\tGLOB=%d; ARR[1]=%d; ARR[7]=%d; ARR[N-1]=%d\n", 3516 GLOB, (int)ARR1[1], (int)ARR1[7], (int)ARR1[N-1]);*/ 3517} 3518REGISTER_TEST2(Run, 72, STABILITY|PERFORMANCE|EXCLUDE_FROM_ALL); 3519#endif // NO_BARRIER 3520} // namespace test72 3521 3522 3523// test73: STAB. Stress test for the number of (SSETs), different access sizes. {{{1 3524namespace test73 { 3525#ifndef NO_BARRIER 3526// Variation of test72. 3527// We perform accesses of different sizes to the same location. 3528int GLOB = 0; 3529const int N_iter = 2; 3530const int Nlog = 16; 3531const int N = 1 << Nlog; 3532static int64_t ARR1[N]; 3533static int ARR2[N]; 3534Barrier *barriers[N_iter]; 3535Mutex MU; 3536 3537void Worker() { 3538 MU.Lock(); 3539 int n = ++GLOB; 3540 MU.Unlock(); 3541 3542 n %= Nlog; 3543 3544 for (int it = 0; it < N_iter; it++) { 3545 // Iterate N_iter times, block on barrier after each iteration. 3546 // This way Helgrind will create new segments after each barrier. 3547 3548 for (int x = 0; x < 4; x++) { 3549 for (int i = 0; i < N; i++) { 3550 // ARR1[i] are accessed by threads from i-th subset 3551 if (i & (1 << n)) { 3552 for (int off = 0; off < (1 << x); off++) { 3553 switch(x) { 3554 case 0: CHECK( ARR1 [i * (1<<x) + off] == 0); break; 3555 case 1: CHECK(((int*) (ARR1))[i * (1<<x) + off] == 0); break; 3556 case 2: CHECK(((short*)(ARR1))[i * (1<<x) + off] == 0); break; 3557 case 3: CHECK(((char*) (ARR1))[i * (1<<x) + off] == 0); break; 3558 } 3559 switch(x) { 3560 case 1: CHECK(((int*) (ARR2))[i * (1<<x) + off] == 0); break; 3561 case 2: CHECK(((short*)(ARR2))[i * (1<<x) + off] == 0); break; 3562 case 3: CHECK(((char*) (ARR2))[i * (1<<x) + off] == 0); break; 3563 } 3564 } 3565 } 3566 } 3567 } 3568 barriers[it]->Block(); 3569 } 3570} 3571 3572 3573 3574void Run() { 3575 printf("test73:\n"); 3576 3577 std::vector<MyThread*> vec(Nlog); 3578 3579 for (int i = 0; i < N_iter; i++) 3580 barriers[i] = new Barrier(Nlog); 3581 3582 // Create and start Nlog threads 3583 for (int i = 0; i < Nlog; i++) { 3584 vec[i] = new MyThread(Worker); 3585 vec[i]->Start(); 3586 } 3587 3588 // Join all threads. 3589 for (int i = 0; i < Nlog; i++) { 3590 vec[i]->Join(); 3591 delete vec[i]; 3592 } 3593 for (int i = 0; i < N_iter; i++) 3594 delete barriers[i]; 3595 3596 /*printf("\tGLOB=%d; ARR[1]=%d; ARR[7]=%d; ARR[N-1]=%d\n", 3597 GLOB, (int)ARR1[1], (int)ARR1[7], (int)ARR1[N-1]);*/ 3598} 3599REGISTER_TEST2(Run, 73, STABILITY|PERFORMANCE|EXCLUDE_FROM_ALL); 3600#endif // NO_BARRIER 3601} // namespace test73 3602 3603 3604// test74: PERF. A lot of lock/unlock calls. {{{1 3605namespace test74 { 3606const int N = 100000; 3607Mutex MU; 3608void Run() { 3609 printf("test74: perf\n"); 3610 for (int i = 0; i < N; i++ ) { 3611 MU.Lock(); 3612 MU.Unlock(); 3613 } 3614} 3615REGISTER_TEST(Run, 74) 3616} // namespace test74 3617 3618 3619// test75: TN. Test for sem_post, sem_wait, sem_trywait. {{{1 3620namespace test75 { 3621int GLOB = 0; 3622sem_t sem[2]; 3623 3624void Poster() { 3625 GLOB = 1; 3626 sem_post(&sem[0]); 3627 sem_post(&sem[1]); 3628} 3629 3630void Waiter() { 3631 sem_wait(&sem[0]); 3632 CHECK(GLOB==1); 3633} 3634void TryWaiter() { 3635 usleep(500000); 3636 sem_trywait(&sem[1]); 3637 CHECK(GLOB==1); 3638} 3639 3640void Run() { 3641#ifndef DRT_NO_SEM 3642 sem_init(&sem[0], 0, 0); 3643 sem_init(&sem[1], 0, 0); 3644 3645 printf("test75: negative\n"); 3646 { 3647 MyThreadArray t(Poster, Waiter); 3648 t.Start(); 3649 t.Join(); 3650 } 3651 GLOB = 2; 3652 { 3653 MyThreadArray t(Poster, TryWaiter); 3654 t.Start(); 3655 t.Join(); 3656 } 3657 printf("\tGLOB=%d\n", GLOB); 3658 3659 sem_destroy(&sem[0]); 3660 sem_destroy(&sem[1]); 3661#endif 3662} 3663REGISTER_TEST(Run, 75) 3664} // namespace test75 3665 3666// RefCountedClass {{{1 3667struct RefCountedClass { 3668 public: 3669 RefCountedClass() { 3670 annotate_unref_ = false; 3671 ref_ = 0; 3672 data_ = 0; 3673 } 3674 3675 ~RefCountedClass() { 3676 CHECK(ref_ == 0); // race may be reported here 3677 int data_val = data_; // and here 3678 // if MU is not annotated 3679 data_ = 0; 3680 ref_ = -1; 3681 printf("\tRefCountedClass::data_ = %d\n", data_val); 3682 } 3683 3684 void AccessData() { 3685 this->mu_.Lock(); 3686 this->data_++; 3687 this->mu_.Unlock(); 3688 } 3689 3690 void Ref() { 3691 MU.Lock(); 3692 CHECK(ref_ >= 0); 3693 ref_++; 3694 MU.Unlock(); 3695 } 3696 3697 void Unref() { 3698 MU.Lock(); 3699 CHECK(ref_ > 0); 3700 ref_--; 3701 bool do_delete = ref_ == 0; 3702 if (annotate_unref_) { 3703 ANNOTATE_CONDVAR_SIGNAL(this); 3704 } 3705 MU.Unlock(); 3706 if (do_delete) { 3707 if (annotate_unref_) { 3708 ANNOTATE_CONDVAR_WAIT(this); 3709 } 3710 delete this; 3711 } 3712 } 3713 3714 static void Annotate_MU() { 3715 ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(&MU); 3716 } 3717 void AnnotateUnref() { 3718 annotate_unref_ = true; 3719 } 3720 void Annotate_Race() { 3721 ANNOTATE_BENIGN_RACE(&this->data_, "needs annotation"); 3722 ANNOTATE_BENIGN_RACE(&this->ref_, "needs annotation"); 3723 } 3724 private: 3725 bool annotate_unref_; 3726 3727 int data_; 3728 Mutex mu_; // protects data_ 3729 3730 int ref_; 3731 static Mutex MU; // protects ref_ 3732}; 3733 3734Mutex RefCountedClass::MU; 3735 3736// test76: FP. Ref counting, no annotations. {{{1 3737namespace test76 { 3738#ifndef NO_BARRIER 3739int GLOB = 0; 3740Barrier barrier(4); 3741RefCountedClass *object = NULL; 3742void Worker() { 3743 object->Ref(); 3744 barrier.Block(); 3745 object->AccessData(); 3746 object->Unref(); 3747} 3748void Run() { 3749 printf("test76: false positive (ref counting)\n"); 3750 object = new RefCountedClass; 3751 object->Annotate_Race(); 3752 MyThreadArray t(Worker, Worker, Worker, Worker); 3753 t.Start(); 3754 t.Join(); 3755} 3756REGISTER_TEST2(Run, 76, FEATURE) 3757#endif // NO_BARRIER 3758} // namespace test76 3759 3760 3761 3762// test77: TN. Ref counting, MU is annotated. {{{1 3763namespace test77 { 3764#ifndef NO_BARRIER 3765// same as test76, but RefCountedClass::MU is annotated. 3766int GLOB = 0; 3767Barrier barrier(4); 3768RefCountedClass *object = NULL; 3769void Worker() { 3770 object->Ref(); 3771 barrier.Block(); 3772 object->AccessData(); 3773 object->Unref(); 3774} 3775void Run() { 3776 printf("test77: true negative (ref counting), mutex is annotated\n"); 3777 RefCountedClass::Annotate_MU(); 3778 object = new RefCountedClass; 3779 MyThreadArray t(Worker, Worker, Worker, Worker); 3780 t.Start(); 3781 t.Join(); 3782} 3783REGISTER_TEST(Run, 77) 3784#endif // NO_BARRIER 3785} // namespace test77 3786 3787 3788 3789// test78: TN. Ref counting, Unref is annotated. {{{1 3790namespace test78 { 3791#ifndef NO_BARRIER 3792// same as test76, but RefCountedClass::Unref is annotated. 3793int GLOB = 0; 3794Barrier barrier(4); 3795RefCountedClass *object = NULL; 3796void Worker() { 3797 object->Ref(); 3798 barrier.Block(); 3799 object->AccessData(); 3800 object->Unref(); 3801} 3802void Run() { 3803 printf("test78: true negative (ref counting), Unref is annotated\n"); 3804 RefCountedClass::Annotate_MU(); 3805 object = new RefCountedClass; 3806 MyThreadArray t(Worker, Worker, Worker, Worker); 3807 t.Start(); 3808 t.Join(); 3809} 3810REGISTER_TEST(Run, 78) 3811#endif // NO_BARRIER 3812} // namespace test78 3813 3814 3815 3816// test79 TN. Swap. {{{1 3817namespace test79 { 3818#if 0 3819typedef __gnu_cxx::hash_map<int, int> map_t; 3820#else 3821typedef std::map<int, int> map_t; 3822#endif 3823map_t MAP; 3824Mutex MU; 3825 3826// Here we use swap to pass MAP between threads. 3827// The synchronization is correct, but w/o ANNOTATE_MUTEX_IS_USED_AS_CONDVAR 3828// Helgrind will complain. 3829 3830void Worker1() { 3831 map_t tmp; 3832 MU.Lock(); 3833 // We swap the new empty map 'tmp' with 'MAP'. 3834 MAP.swap(tmp); 3835 MU.Unlock(); 3836 // tmp (which is the old version of MAP) is destroyed here. 3837} 3838 3839void Worker2() { 3840 MU.Lock(); 3841 MAP[1]++; // Just update MAP under MU. 3842 MU.Unlock(); 3843} 3844 3845void Worker3() { Worker1(); } 3846void Worker4() { Worker2(); } 3847 3848void Run() { 3849 ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(&MU); 3850 printf("test79: negative\n"); 3851 MyThreadArray t(Worker1, Worker2, Worker3, Worker4); 3852 t.Start(); 3853 t.Join(); 3854} 3855REGISTER_TEST(Run, 79) 3856} // namespace test79 3857 3858 3859// AtomicRefCountedClass. {{{1 3860// Same as RefCountedClass, but using atomic ops instead of mutex. 3861struct AtomicRefCountedClass { 3862 public: 3863 AtomicRefCountedClass() { 3864 annotate_unref_ = false; 3865 ref_ = 0; 3866 data_ = 0; 3867 } 3868 3869 ~AtomicRefCountedClass() { 3870 CHECK(ref_ == 0); // race may be reported here 3871 int data_val = data_; // and here 3872 data_ = 0; 3873 ref_ = -1; 3874 printf("\tRefCountedClass::data_ = %d\n", data_val); 3875 } 3876 3877 void AccessData() { 3878 this->mu_.Lock(); 3879 this->data_++; 3880 this->mu_.Unlock(); 3881 } 3882 3883 void Ref() { 3884 AtomicIncrement(&ref_, 1); 3885 } 3886 3887 void Unref() { 3888 // DISCLAIMER: I am not sure I've implemented this correctly 3889 // (might require some memory barrier, etc). 3890 // But this implementation of reference counting is enough for 3891 // the purpose of Helgrind demonstration. 3892 AtomicIncrement(&ref_, -1); 3893 if (annotate_unref_) { ANNOTATE_CONDVAR_SIGNAL(this); } 3894 if (ref_ == 0) { 3895 if (annotate_unref_) { ANNOTATE_CONDVAR_WAIT(this); } 3896 delete this; 3897 } 3898 } 3899 3900 void AnnotateUnref() { 3901 annotate_unref_ = true; 3902 } 3903 void Annotate_Race() { 3904 ANNOTATE_BENIGN_RACE(&this->data_, "needs annotation"); 3905 } 3906 private: 3907 bool annotate_unref_; 3908 3909 Mutex mu_; 3910 int data_; // under mu_ 3911 3912 int ref_; // used in atomic ops. 3913}; 3914 3915// test80: FP. Ref counting with atomics, no annotations. {{{1 3916namespace test80 { 3917#ifndef NO_BARRIER 3918int GLOB = 0; 3919Barrier barrier(4); 3920AtomicRefCountedClass *object = NULL; 3921void Worker() { 3922 object->Ref(); 3923 barrier.Block(); 3924 object->AccessData(); 3925 object->Unref(); // All the tricky stuff is here. 3926} 3927void Run() { 3928 printf("test80: false positive (ref counting)\n"); 3929 object = new AtomicRefCountedClass; 3930 object->Annotate_Race(); 3931 MyThreadArray t(Worker, Worker, Worker, Worker); 3932 t.Start(); 3933 t.Join(); 3934} 3935REGISTER_TEST2(Run, 80, FEATURE|EXCLUDE_FROM_ALL) 3936#endif // NO_BARRIER 3937} // namespace test80 3938 3939 3940// test81: TN. Ref counting with atomics, Unref is annotated. {{{1 3941namespace test81 { 3942#ifndef NO_BARRIER 3943// same as test80, but Unref is annotated. 3944int GLOB = 0; 3945Barrier barrier(4); 3946AtomicRefCountedClass *object = NULL; 3947void Worker() { 3948 object->Ref(); 3949 barrier.Block(); 3950 object->AccessData(); 3951 object->Unref(); // All the tricky stuff is here. 3952} 3953void Run() { 3954 printf("test81: negative (annotated ref counting)\n"); 3955 object = new AtomicRefCountedClass; 3956 object->AnnotateUnref(); 3957 MyThreadArray t(Worker, Worker, Worker, Worker); 3958 t.Start(); 3959 t.Join(); 3960} 3961REGISTER_TEST2(Run, 81, FEATURE|EXCLUDE_FROM_ALL) 3962#endif // NO_BARRIER 3963} // namespace test81 3964 3965 3966// test82: Object published w/o synchronization. {{{1 3967namespace test82 { 3968 3969// Writer creates a new object and makes the pointer visible to the Reader. 3970// Reader waits until the object pointer is non-null and reads the object. 3971// 3972// On Core 2 Duo this test will sometimes (quite rarely) fail in 3973// the CHECK below, at least if compiled with -O2. 3974// 3975// The sequence of events:: 3976// Thread1: Thread2: 3977// a. arr_[...] = ... 3978// b. foo[i] = ... 3979// A. ... = foo[i]; // non NULL 3980// B. ... = arr_[...]; 3981// 3982// Since there is no proper synchronization, during the even (B) 3983// Thread2 may not see the result of the event (a). 3984// On x86 and x86_64 this happens due to compiler reordering instructions. 3985// On other arcitectures it may also happen due to cashe inconsistency. 3986 3987class FOO { 3988 public: 3989 FOO() { 3990 idx_ = rand() % 1024; 3991 arr_[idx_] = 77777; 3992 // __asm__ __volatile__("" : : : "memory"); // this fixes! 3993 } 3994 static void check(volatile FOO *foo) { 3995 CHECK(foo->arr_[foo->idx_] == 77777); 3996 } 3997 private: 3998 int idx_; 3999 int arr_[1024]; 4000}; 4001 4002const int N = 100000; 4003static volatile FOO *foo[N]; 4004Mutex MU; 4005 4006void Writer() { 4007 for (int i = 0; i < N; i++) { 4008 foo[i] = new FOO; 4009 usleep(100); 4010 } 4011} 4012 4013void Reader() { 4014 for (int i = 0; i < N; i++) { 4015 while (!foo[i]) { 4016 MU.Lock(); // this is NOT a synchronization, 4017 MU.Unlock(); // it just helps foo[i] to become visible in Reader. 4018 } 4019 if ((i % 100) == 0) { 4020 printf("rd %d\n", i); 4021 } 4022 // At this point Reader() sees the new value of foo[i] 4023 // but in very rare cases will not see the new value of foo[i]->arr_. 4024 // Thus this CHECK will sometimes fail. 4025 FOO::check(foo[i]); 4026 } 4027} 4028 4029void Run() { 4030 printf("test82: positive\n"); 4031 MyThreadArray t(Writer, Reader); 4032 t.Start(); 4033 t.Join(); 4034} 4035REGISTER_TEST2(Run, 82, FEATURE|EXCLUDE_FROM_ALL) 4036} // namespace test82 4037 4038 4039// test83: Object published w/o synchronization (simple version){{{1 4040namespace test83 { 4041// A simplified version of test83 (example of a wrong code). 4042// This test, though incorrect, will almost never fail. 4043volatile static int *ptr = NULL; 4044Mutex MU; 4045 4046void Writer() { 4047 usleep(100); 4048 ptr = new int(777); 4049} 4050 4051void Reader() { 4052 while(!ptr) { 4053 MU.Lock(); // Not a synchronization! 4054 MU.Unlock(); 4055 } 4056 CHECK(*ptr == 777); 4057} 4058 4059void Run() { 4060// printf("test83: positive\n"); 4061 MyThreadArray t(Writer, Reader); 4062 t.Start(); 4063 t.Join(); 4064} 4065REGISTER_TEST2(Run, 83, FEATURE|EXCLUDE_FROM_ALL) 4066} // namespace test83 4067 4068 4069// test84: TP. True race (regression test for a bug related to atomics){{{1 4070namespace test84 { 4071// Helgrind should not create HB arcs for the bus lock even when 4072// --pure-happens-before=yes is used. 4073// Bug found in by Bart Van Assche, the test is taken from 4074// valgrind file drd/tests/atomic_var.c. 4075static int s_x = 0; 4076/* s_dummy[] ensures that s_x and s_y are not in the same cache line. */ 4077static char s_dummy[512] = {0}; 4078static int s_y; 4079 4080void thread_func_1() 4081{ 4082 s_y = 1; 4083 AtomicIncrement(&s_x, 1); 4084} 4085 4086void thread_func_2() 4087{ 4088 while (AtomicIncrement(&s_x, 0) == 0) 4089 ; 4090 printf("y = %d\n", s_y); 4091} 4092 4093 4094void Run() { 4095 CHECK(s_dummy[0] == 0); // Avoid compiler warning about 's_dummy unused'. 4096 printf("test84: positive\n"); 4097 FAST_MODE_INIT(&s_y); 4098 ANNOTATE_EXPECT_RACE_FOR_TSAN(&s_y, "test84: TP. true race."); 4099 MyThreadArray t(thread_func_1, thread_func_2); 4100 t.Start(); 4101 t.Join(); 4102} 4103REGISTER_TEST(Run, 84) 4104} // namespace test84 4105 4106 4107// test85: Test for RunningOnValgrind(). {{{1 4108namespace test85 { 4109int GLOB = 0; 4110void Run() { 4111 printf("test85: RunningOnValgrind() = %d\n", RunningOnValgrind()); 4112} 4113REGISTER_TEST(Run, 85) 4114} // namespace test85 4115 4116 4117// test86: Test for race inside DTOR: racey write to vptr. Benign. {{{1 4118namespace test86 { 4119// This test shows a racey access to vptr (the pointer to vtbl). 4120// We have class A and class B derived from A. 4121// Both classes have a virtual function f() and a virtual DTOR. 4122// We create an object 'A *a = new B' 4123// and pass this object from Thread1 to Thread2. 4124// Thread2 calls a->f(). This call reads a->vtpr. 4125// Thread1 deletes the object. B::~B waits untill the object can be destroyed 4126// (flag_stopped == true) but at the very beginning of B::~B 4127// a->vptr is written to. 4128// So, we have a race on a->vptr. 4129// On this particular test this race is benign, but test87 shows 4130// how such race could harm. 4131// 4132// 4133// 4134// Threa1: Thread2: 4135// 1. A a* = new B; 4136// 2. Q.Put(a); ------------\ . 4137// \--------------------> a. a = Q.Get(); 4138// b. a->f(); 4139// /--------- c. flag_stopped = true; 4140// 3. delete a; / 4141// waits untill flag_stopped <------/ 4142// inside the dtor 4143// 4144 4145bool flag_stopped = false; 4146Mutex mu; 4147 4148ProducerConsumerQueue Q(INT_MAX); // Used to pass A* between threads. 4149 4150struct A { 4151 A() { printf("A::A()\n"); } 4152 virtual ~A() { printf("A::~A()\n"); } 4153 virtual void f() { } 4154 4155 uintptr_t padding[15]; 4156} __attribute__ ((aligned (64))); 4157 4158struct B: A { 4159 B() { printf("B::B()\n"); } 4160 virtual ~B() { 4161 // The race is here. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 4162 printf("B::~B()\n"); 4163 // wait until flag_stopped is true. 4164 mu.LockWhen(Condition(&ArgIsTrue, &flag_stopped)); 4165 mu.Unlock(); 4166 printf("B::~B() done\n"); 4167 } 4168 virtual void f() { } 4169}; 4170 4171void Waiter() { 4172 A *a = new B; 4173 if (!Tsan_FastMode()) 4174 ANNOTATE_EXPECT_RACE(a, "test86: expected race on a->vptr"); 4175 printf("Waiter: B created\n"); 4176 Q.Put(a); 4177 usleep(100000); // so that Worker calls a->f() first. 4178 printf("Waiter: deleting B\n"); 4179 delete a; 4180 printf("Waiter: B deleted\n"); 4181 usleep(100000); 4182 printf("Waiter: done\n"); 4183} 4184 4185void Worker() { 4186 A *a = reinterpret_cast<A*>(Q.Get()); 4187 printf("Worker: got A\n"); 4188 a->f(); 4189 4190 mu.Lock(); 4191 flag_stopped = true; 4192 mu.Unlock(); 4193 usleep(200000); 4194 printf("Worker: done\n"); 4195} 4196 4197void Run() { 4198 printf("test86: positive, race inside DTOR\n"); 4199 MyThreadArray t(Waiter, Worker); 4200 t.Start(); 4201 t.Join(); 4202} 4203REGISTER_TEST(Run, 86) 4204} // namespace test86 4205 4206 4207// test87: Test for race inside DTOR: racey write to vptr. Harmful.{{{1 4208namespace test87 { 4209// A variation of test86 where the race is harmful. 4210// Here we have class C derived from B. 4211// We create an object 'A *a = new C' in Thread1 and pass it to Thread2. 4212// Thread2 calls a->f(). 4213// Thread1 calls 'delete a'. 4214// It first calls C::~C, then B::~B where it rewrites the vptr to point 4215// to B::vtbl. This is a problem because Thread2 might not have called a->f() 4216// and now it will call B::f instead of C::f. 4217// 4218bool flag_stopped = false; 4219Mutex mu; 4220 4221ProducerConsumerQueue Q(INT_MAX); // Used to pass A* between threads. 4222 4223struct A { 4224 A() { printf("A::A()\n"); } 4225 virtual ~A() { printf("A::~A()\n"); } 4226 virtual void f() = 0; // pure virtual. 4227}; 4228 4229struct B: A { 4230 B() { printf("B::B()\n"); } 4231 virtual ~B() { 4232 // The race is here. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 4233 printf("B::~B()\n"); 4234 // wait until flag_stopped is true. 4235 mu.LockWhen(Condition(&ArgIsTrue, &flag_stopped)); 4236 mu.Unlock(); 4237 printf("B::~B() done\n"); 4238 } 4239 virtual void f() = 0; // pure virtual. 4240}; 4241 4242struct C: B { 4243 C() { printf("C::C()\n"); } 4244 virtual ~C() { printf("C::~C()\n"); } 4245 virtual void f() { } 4246}; 4247 4248void Waiter() { 4249 A *a = new C; 4250 Q.Put(a); 4251 delete a; 4252} 4253 4254void Worker() { 4255 A *a = reinterpret_cast<A*>(Q.Get()); 4256 a->f(); 4257 4258 mu.Lock(); 4259 flag_stopped = true; 4260 ANNOTATE_CONDVAR_SIGNAL(&mu); 4261 mu.Unlock(); 4262} 4263 4264void Run() { 4265 printf("test87: positive, race inside DTOR\n"); 4266 MyThreadArray t(Waiter, Worker); 4267 t.Start(); 4268 t.Join(); 4269} 4270REGISTER_TEST2(Run, 87, FEATURE|EXCLUDE_FROM_ALL) 4271} // namespace test87 4272 4273 4274// test88: Test for ANNOTATE_IGNORE_WRITES_*{{{1 4275namespace test88 { 4276// a recey write annotated with ANNOTATE_IGNORE_WRITES_BEGIN/END. 4277int GLOB = 0; 4278void Worker() { 4279 ANNOTATE_IGNORE_WRITES_BEGIN(); 4280 GLOB = 1; 4281 ANNOTATE_IGNORE_WRITES_END(); 4282} 4283void Run() { 4284 printf("test88: negative, test for ANNOTATE_IGNORE_WRITES_*\n"); 4285 MyThread t(Worker); 4286 t.Start(); 4287 GLOB = 1; 4288 t.Join(); 4289 printf("\tGLOB=%d\n", GLOB); 4290} 4291REGISTER_TEST(Run, 88) 4292} // namespace test88 4293 4294 4295// test89: Test for debug info. {{{1 4296namespace test89 { 4297// Simlpe races with different objects (stack, heap globals; scalars, structs). 4298// Also, if run with --trace-level=2 this test will show a sequence of 4299// CTOR and DTOR calls. 4300struct STRUCT { 4301 int a, b, c; 4302}; 4303 4304struct A { 4305 int a; 4306 A() { 4307 ANNOTATE_TRACE_MEMORY(&a); 4308 a = 1; 4309 } 4310 virtual ~A() { 4311 a = 4; 4312 } 4313}; 4314 4315struct B : A { 4316 B() { CHECK(a == 1); } 4317 virtual ~B() { CHECK(a == 3); } 4318}; 4319struct C : B { 4320 C() { a = 2; } 4321 virtual ~C() { a = 3; } 4322}; 4323 4324int GLOBAL = 0; 4325int *STACK = 0; 4326STRUCT GLOB_STRUCT; 4327STRUCT *STACK_STRUCT; 4328STRUCT *HEAP_STRUCT; 4329 4330void Worker() { 4331 GLOBAL = 1; 4332 *STACK = 1; 4333 GLOB_STRUCT.b = 1; 4334 STACK_STRUCT->b = 1; 4335 HEAP_STRUCT->b = 1; 4336} 4337 4338void Run() { 4339 int stack_var = 0; 4340 STACK = &stack_var; 4341 4342 STRUCT stack_struct; 4343 STACK_STRUCT = &stack_struct; 4344 4345 HEAP_STRUCT = new STRUCT; 4346 4347 printf("test89: negative\n"); 4348 MyThreadArray t(Worker, Worker); 4349 t.Start(); 4350 t.Join(); 4351 4352 delete HEAP_STRUCT; 4353 4354 A *a = new C; 4355 printf("Using 'a->a': %d\n", a->a); 4356 delete a; 4357} 4358REGISTER_TEST2(Run, 89, FEATURE|EXCLUDE_FROM_ALL) 4359} // namespace test89 4360 4361 4362// test90: FP. Test for a safely-published pointer (read-only). {{{1 4363namespace test90 { 4364// The Publisher creates an object and safely publishes it under a mutex. 4365// Readers access the object read-only. 4366// See also test91. 4367// 4368// Without annotations Helgrind will issue a false positive in Reader(). 4369// 4370// Choices for annotations: 4371// -- ANNOTATE_CONDVAR_SIGNAL/ANNOTATE_CONDVAR_WAIT 4372// -- ANNOTATE_MUTEX_IS_USED_AS_CONDVAR 4373// -- ANNOTATE_PUBLISH_MEMORY_RANGE. 4374 4375int *GLOB = 0; 4376Mutex MU; 4377 4378void Publisher() { 4379 MU.Lock(); 4380 GLOB = (int*)memalign(64, sizeof(int)); 4381 *GLOB = 777; 4382 if (!Tsan_PureHappensBefore() && !Tsan_FastMode()) 4383 ANNOTATE_EXPECT_RACE_FOR_TSAN(GLOB, "test90. FP. This is a false positve"); 4384 MU.Unlock(); 4385 usleep(200000); 4386} 4387 4388void Reader() { 4389 usleep(10000); 4390 while (true) { 4391 MU.Lock(); 4392 int *p = GLOB; 4393 MU.Unlock(); 4394 if (p) { 4395 CHECK(*p == 777); // Race is reported here. 4396 break; 4397 } 4398 } 4399} 4400 4401void Run() { 4402 printf("test90: false positive (safely published pointer).\n"); 4403 MyThreadArray t(Publisher, Reader, Reader, Reader); 4404 t.Start(); 4405 t.Join(); 4406 printf("\t*GLOB=%d\n", *GLOB); 4407 free(GLOB); 4408} 4409REGISTER_TEST(Run, 90) 4410} // namespace test90 4411 4412 4413// test91: FP. Test for a safely-published pointer (read-write). {{{1 4414namespace test91 { 4415// Similar to test90. 4416// The Publisher creates an object and safely publishes it under a mutex MU1. 4417// Accessors get the object under MU1 and access it (read/write) under MU2. 4418// 4419// Without annotations Helgrind will issue a false positive in Accessor(). 4420// 4421 4422int *GLOB = 0; 4423Mutex MU, MU1, MU2; 4424 4425void Publisher() { 4426 MU1.Lock(); 4427 GLOB = (int*)memalign(64, sizeof(int)); 4428 *GLOB = 777; 4429 if (!Tsan_PureHappensBefore() && !Tsan_FastMode()) 4430 ANNOTATE_EXPECT_RACE_FOR_TSAN(GLOB, "test91. FP. This is a false positve"); 4431 MU1.Unlock(); 4432} 4433 4434void Accessor() { 4435 usleep(10000); 4436 while (true) { 4437 MU1.Lock(); 4438 int *p = GLOB; 4439 MU1.Unlock(); 4440 if (p) { 4441 MU2.Lock(); 4442 (*p)++; // Race is reported here. 4443 CHECK(*p > 777); 4444 MU2.Unlock(); 4445 break; 4446 } 4447 } 4448} 4449 4450void Run() { 4451 printf("test91: false positive (safely published pointer, read/write).\n"); 4452 MyThreadArray t(Publisher, Accessor, Accessor, Accessor); 4453 t.Start(); 4454 t.Join(); 4455 printf("\t*GLOB=%d\n", *GLOB); 4456 free(GLOB); 4457} 4458REGISTER_TEST(Run, 91) 4459} // namespace test91 4460 4461 4462// test92: TN. Test for a safely-published pointer (read-write), annotated. {{{1 4463namespace test92 { 4464// Similar to test91, but annotated with ANNOTATE_PUBLISH_MEMORY_RANGE. 4465// 4466// 4467// Publisher: Accessors: 4468// 4469// 1. MU1.Lock() 4470// 2. Create GLOB. 4471// 3. ANNOTATE_PUBLISH_...(GLOB) -------\ . 4472// 4. MU1.Unlock() \ . 4473// \ a. MU1.Lock() 4474// \ b. Get GLOB 4475// \ c. MU1.Unlock() 4476// \--> d. Access GLOB 4477// 4478// A happens-before arc is created between ANNOTATE_PUBLISH_MEMORY_RANGE and 4479// accesses to GLOB. 4480 4481struct ObjType { 4482 int arr[10]; 4483}; 4484 4485ObjType *GLOB = 0; 4486Mutex MU, MU1, MU2; 4487 4488void Publisher() { 4489 MU1.Lock(); 4490 GLOB = new ObjType; 4491 for (int i = 0; i < 10; i++) { 4492 GLOB->arr[i] = 777; 4493 } 4494 // This annotation should go right before the object is published. 4495 ANNOTATE_PUBLISH_MEMORY_RANGE(GLOB, sizeof(*GLOB)); 4496 MU1.Unlock(); 4497} 4498 4499void Accessor(int index) { 4500 while (true) { 4501 MU1.Lock(); 4502 ObjType *p = GLOB; 4503 MU1.Unlock(); 4504 if (p) { 4505 MU2.Lock(); 4506 p->arr[index]++; // W/o the annotations the race will be reported here. 4507 CHECK(p->arr[index] == 778); 4508 MU2.Unlock(); 4509 break; 4510 } 4511 } 4512} 4513 4514void Accessor0() { Accessor(0); } 4515void Accessor5() { Accessor(5); } 4516void Accessor9() { Accessor(9); } 4517 4518void Run() { 4519 printf("test92: safely published pointer, read/write, annotated.\n"); 4520 MyThreadArray t(Publisher, Accessor0, Accessor5, Accessor9); 4521 t.Start(); 4522 t.Join(); 4523 printf("\t*GLOB=%d\n", GLOB->arr[0]); 4524} 4525REGISTER_TEST(Run, 92) 4526} // namespace test92 4527 4528 4529// test93: TP. Test for incorrect usage of ANNOTATE_PUBLISH_MEMORY_RANGE. {{{1 4530namespace test93 { 4531int GLOB = 0; 4532 4533void Reader() { 4534 CHECK(GLOB == 0); 4535} 4536 4537void Publisher() { 4538 usleep(10000); 4539 // Incorrect, used after the memory has been accessed in another thread. 4540 ANNOTATE_PUBLISH_MEMORY_RANGE(&GLOB, sizeof(GLOB)); 4541} 4542 4543void Run() { 4544 printf("test93: positive, misuse of ANNOTATE_PUBLISH_MEMORY_RANGE\n"); 4545 MyThreadArray t(Reader, Publisher); 4546 t.Start(); 4547 t.Join(); 4548 printf("\tGLOB=%d\n", GLOB); 4549} 4550REGISTER_TEST2(Run, 93, FEATURE|EXCLUDE_FROM_ALL) 4551} // namespace test93 4552 4553 4554// test94: TP. Check do_cv_signal/fake segment logic {{{1 4555namespace test94 { 4556int GLOB; 4557 4558int COND = 0; 4559int COND2 = 0; 4560Mutex MU, MU2; 4561CondVar CV, CV2; 4562 4563void Thr1() { 4564 usleep(10000); // Make sure the waiter blocks. 4565 4566 GLOB = 1; // WRITE 4567 4568 MU.Lock(); 4569 COND = 1; 4570 CV.Signal(); 4571 MU.Unlock(); 4572} 4573void Thr2() { 4574 usleep(1000*1000); // Make sure CV2.Signal() "happens after" CV.Signal() 4575 usleep(10000); // Make sure the waiter blocks. 4576 4577 MU2.Lock(); 4578 COND2 = 1; 4579 CV2.Signal(); 4580 MU2.Unlock(); 4581} 4582void Thr3() { 4583 MU.Lock(); 4584 while(COND != 1) 4585 CV.Wait(&MU); 4586 MU.Unlock(); 4587} 4588void Thr4() { 4589 MU2.Lock(); 4590 while(COND2 != 1) 4591 CV2.Wait(&MU2); 4592 MU2.Unlock(); 4593 GLOB = 2; // READ: no HB-relation between CV.Signal and CV2.Wait ! 4594} 4595void Run() { 4596 FAST_MODE_INIT(&GLOB); 4597 ANNOTATE_EXPECT_RACE_FOR_TSAN(&GLOB, "test94: TP."); 4598 printf("test94: TP. Check do_cv_signal/fake segment logic\n"); 4599 MyThreadArray mta(Thr1, Thr2, Thr3, Thr4); 4600 mta.Start(); 4601 mta.Join(); 4602 printf("\tGLOB=%d\n", GLOB); 4603} 4604REGISTER_TEST(Run, 94); 4605} // namespace test94 4606 4607// test95: TP. Check do_cv_signal/fake segment logic {{{1 4608namespace test95 { 4609int GLOB = 0; 4610 4611int COND = 0; 4612int COND2 = 0; 4613Mutex MU, MU2; 4614CondVar CV, CV2; 4615 4616void Thr1() { 4617 usleep(1000*1000); // Make sure CV2.Signal() "happens before" CV.Signal() 4618 usleep(10000); // Make sure the waiter blocks. 4619 4620 GLOB = 1; // WRITE 4621 4622 MU.Lock(); 4623 COND = 1; 4624 CV.Signal(); 4625 MU.Unlock(); 4626} 4627void Thr2() { 4628 usleep(10000); // Make sure the waiter blocks. 4629 4630 MU2.Lock(); 4631 COND2 = 1; 4632 CV2.Signal(); 4633 MU2.Unlock(); 4634} 4635void Thr3() { 4636 MU.Lock(); 4637 while(COND != 1) 4638 CV.Wait(&MU); 4639 MU.Unlock(); 4640} 4641void Thr4() { 4642 MU2.Lock(); 4643 while(COND2 != 1) 4644 CV2.Wait(&MU2); 4645 MU2.Unlock(); 4646 GLOB = 2; // READ: no HB-relation between CV.Signal and CV2.Wait ! 4647} 4648void Run() { 4649 FAST_MODE_INIT(&GLOB); 4650 ANNOTATE_EXPECT_RACE_FOR_TSAN(&GLOB, "test95: TP."); 4651 printf("test95: TP. Check do_cv_signal/fake segment logic\n"); 4652 MyThreadArray mta(Thr1, Thr2, Thr3, Thr4); 4653 mta.Start(); 4654 mta.Join(); 4655 printf("\tGLOB=%d\n", GLOB); 4656} 4657REGISTER_TEST(Run, 95); 4658} // namespace test95 4659 4660// test96: TN. tricky LockSet behaviour {{{1 4661// 3 threads access the same memory with three different 4662// locksets: {A, B}, {B, C}, {C, A}. 4663// These locksets have empty intersection 4664namespace test96 { 4665int GLOB = 0; 4666 4667Mutex A, B, C; 4668 4669void Thread1() { 4670 MutexLock a(&A); 4671 MutexLock b(&B); 4672 GLOB++; 4673} 4674 4675void Thread2() { 4676 MutexLock b(&B); 4677 MutexLock c(&C); 4678 GLOB++; 4679} 4680 4681void Thread3() { 4682 MutexLock a(&A); 4683 MutexLock c(&C); 4684 GLOB++; 4685} 4686 4687void Run() { 4688 printf("test96: FP. tricky LockSet behaviour\n"); 4689 ANNOTATE_TRACE_MEMORY(&GLOB); 4690 MyThreadArray mta(Thread1, Thread2, Thread3); 4691 mta.Start(); 4692 mta.Join(); 4693 CHECK(GLOB == 3); 4694 printf("\tGLOB=%d\n", GLOB); 4695} 4696REGISTER_TEST(Run, 96); 4697} // namespace test96 4698 4699// test97: This test shows false negative with --fast-mode=yes {{{1 4700namespace test97 { 4701const int HG_CACHELINE_SIZE = 64; 4702 4703Mutex MU; 4704 4705const int ARRAY_SIZE = HG_CACHELINE_SIZE * 4 / sizeof(int); 4706int array[ARRAY_SIZE]; 4707int * GLOB = &array[ARRAY_SIZE/2]; 4708/* 4709 We use sizeof(array) == 4 * HG_CACHELINE_SIZE to be sure that GLOB points 4710 to a memory inside a CacheLineZ which is inside array's memory range 4711 */ 4712 4713void Reader() { 4714 usleep(500000); 4715 CHECK(777 == *GLOB); 4716} 4717 4718void Run() { 4719 MyThreadArray t(Reader); 4720 if (!Tsan_FastMode()) 4721 ANNOTATE_EXPECT_RACE_FOR_TSAN(GLOB, "test97: TP. FN with --fast-mode=yes"); 4722 printf("test97: This test shows false negative with --fast-mode=yes\n"); 4723 4724 t.Start(); 4725 *GLOB = 777; 4726 t.Join(); 4727} 4728 4729REGISTER_TEST2(Run, 97, FEATURE) 4730} // namespace test97 4731 4732// test98: Synchronization via read/write (or send/recv). {{{1 4733namespace test98 { 4734// The synchronization here is done by a pair of read/write calls 4735// that create a happens-before arc. Same may be done with send/recv. 4736// Such synchronization is quite unusual in real programs 4737// (why would one synchronizae via a file or socket?), but 4738// quite possible in unittests where one threads runs for producer 4739// and one for consumer. 4740// 4741// A race detector has to create a happens-before arcs for 4742// {read,send}->{write,recv} even if the file descriptors are different. 4743// 4744int GLOB = 0; 4745int fd_out = -1; 4746int fd_in = -1; 4747 4748void Writer() { 4749 usleep(1000); 4750 GLOB = 1; 4751 const char *str = "Hey there!\n"; 4752 write(fd_out, str, strlen(str) + 1); 4753} 4754 4755void Reader() { 4756 char buff[100]; 4757 while (read(fd_in, buff, 100) == 0) 4758 sleep(1); 4759 printf("read: %s\n", buff); 4760 GLOB = 2; 4761} 4762 4763void Run() { 4764 printf("test98: negative, synchronization via I/O\n"); 4765 char in_name[100]; 4766 char out_name[100]; 4767 // we open two files, on for reading and one for writing, 4768 // but the files are actually the same (symlinked). 4769 sprintf(in_name, "/tmp/racecheck_unittest_in.%d", getpid()); 4770 sprintf(out_name, "/tmp/racecheck_unittest_out.%d", getpid()); 4771 fd_out = creat(out_name, O_WRONLY | S_IRWXU); 4772 symlink(out_name, in_name); 4773 fd_in = open(in_name, 0, O_RDONLY); 4774 CHECK(fd_out >= 0); 4775 CHECK(fd_in >= 0); 4776 MyThreadArray t(Writer, Reader); 4777 t.Start(); 4778 t.Join(); 4779 printf("\tGLOB=%d\n", GLOB); 4780 // cleanup 4781 close(fd_in); 4782 close(fd_out); 4783 unlink(in_name); 4784 unlink(out_name); 4785} 4786REGISTER_TEST(Run, 98) 4787} // namespace test98 4788 4789 4790// test99: TP. Unit test for a bug in LockWhen*. {{{1 4791namespace test99 { 4792 4793 4794bool GLOB = false; 4795Mutex mu; 4796 4797static void Thread1() { 4798 for (int i = 0; i < 100; i++) { 4799 mu.LockWhenWithTimeout(Condition(&ArgIsTrue, &GLOB), 5); 4800 GLOB = false; 4801 mu.Unlock(); 4802 usleep(10000); 4803 } 4804} 4805 4806static void Thread2() { 4807 for (int i = 0; i < 100; i++) { 4808 mu.Lock(); 4809 mu.Unlock(); 4810 usleep(10000); 4811 } 4812} 4813 4814void Run() { 4815 printf("test99: regression test for LockWhen*\n"); 4816 MyThreadArray t(Thread1, Thread2); 4817 t.Start(); 4818 t.Join(); 4819} 4820REGISTER_TEST(Run, 99); 4821} // namespace test99 4822 4823 4824// test100: Test for initialization bit. {{{1 4825namespace test100 { 4826int G1 = 0; 4827int G2 = 0; 4828int G3 = 0; 4829int G4 = 0; 4830 4831void Creator() { 4832 G1 = 1; CHECK(G1); 4833 G2 = 1; 4834 G3 = 1; CHECK(G3); 4835 G4 = 1; 4836} 4837 4838void Worker1() { 4839 usleep(100000); 4840 CHECK(G1); 4841 CHECK(G2); 4842 G3 = 3; 4843 G4 = 3; 4844} 4845 4846void Worker2() { 4847 4848} 4849 4850 4851void Run() { 4852 printf("test100: test for initialization bit. \n"); 4853 MyThreadArray t(Creator, Worker1, Worker2); 4854 ANNOTATE_TRACE_MEMORY(&G1); 4855 ANNOTATE_TRACE_MEMORY(&G2); 4856 ANNOTATE_TRACE_MEMORY(&G3); 4857 ANNOTATE_TRACE_MEMORY(&G4); 4858 t.Start(); 4859 t.Join(); 4860} 4861REGISTER_TEST2(Run, 100, FEATURE|EXCLUDE_FROM_ALL) 4862} // namespace test100 4863 4864 4865// test101: TN. Two signals and two waits. {{{1 4866namespace test101 { 4867Mutex MU; 4868CondVar CV; 4869int GLOB = 0; 4870 4871int C1 = 0, C2 = 0; 4872 4873void Signaller() { 4874 usleep(100000); 4875 MU.Lock(); 4876 C1 = 1; 4877 CV.Signal(); 4878 printf("signal\n"); 4879 MU.Unlock(); 4880 4881 GLOB = 1; 4882 4883 usleep(500000); 4884 MU.Lock(); 4885 C2 = 1; 4886 CV.Signal(); 4887 printf("signal\n"); 4888 MU.Unlock(); 4889} 4890 4891void Waiter() { 4892 MU.Lock(); 4893 while(!C1) 4894 CV.Wait(&MU); 4895 printf("wait\n"); 4896 MU.Unlock(); 4897 4898 MU.Lock(); 4899 while(!C2) 4900 CV.Wait(&MU); 4901 printf("wait\n"); 4902 MU.Unlock(); 4903 4904 GLOB = 2; 4905 4906} 4907 4908void Run() { 4909 printf("test101: negative\n"); 4910 MyThreadArray t(Waiter, Signaller); 4911 t.Start(); 4912 t.Join(); 4913 printf("\tGLOB=%d\n", GLOB); 4914} 4915REGISTER_TEST(Run, 101) 4916} // namespace test101 4917 4918// test102: --fast-mode=yes vs. --initialization-bit=yes {{{1 4919namespace test102 { 4920const int HG_CACHELINE_SIZE = 64; 4921 4922Mutex MU; 4923 4924const int ARRAY_SIZE = HG_CACHELINE_SIZE * 4 / sizeof(int); 4925int array[ARRAY_SIZE + 1]; 4926int * GLOB = &array[ARRAY_SIZE/2]; 4927/* 4928 We use sizeof(array) == 4 * HG_CACHELINE_SIZE to be sure that GLOB points 4929 to a memory inside a CacheLineZ which is inside array's memory range 4930*/ 4931 4932void Reader() { 4933 usleep(200000); 4934 CHECK(777 == GLOB[0]); 4935 usleep(400000); 4936 CHECK(777 == GLOB[1]); 4937} 4938 4939void Run() { 4940 MyThreadArray t(Reader); 4941 if (!Tsan_FastMode()) 4942 ANNOTATE_EXPECT_RACE_FOR_TSAN(GLOB+0, "test102: TP. FN with --fast-mode=yes"); 4943 ANNOTATE_EXPECT_RACE_FOR_TSAN(GLOB+1, "test102: TP"); 4944 printf("test102: --fast-mode=yes vs. --initialization-bit=yes\n"); 4945 4946 t.Start(); 4947 GLOB[0] = 777; 4948 usleep(400000); 4949 GLOB[1] = 777; 4950 t.Join(); 4951} 4952 4953REGISTER_TEST2(Run, 102, FEATURE) 4954} // namespace test102 4955 4956// test103: Access different memory locations with different LockSets {{{1 4957namespace test103 { 4958const int N_MUTEXES = 6; 4959const int LOCKSET_INTERSECTION_SIZE = 3; 4960 4961int data[1 << LOCKSET_INTERSECTION_SIZE] = {0}; 4962Mutex MU[N_MUTEXES]; 4963 4964inline int LS_to_idx (int ls) { 4965 return (ls >> (N_MUTEXES - LOCKSET_INTERSECTION_SIZE)) 4966 & ((1 << LOCKSET_INTERSECTION_SIZE) - 1); 4967} 4968 4969void Worker() { 4970 for (int ls = 0; ls < (1 << N_MUTEXES); ls++) { 4971 if (LS_to_idx(ls) == 0) 4972 continue; 4973 for (int m = 0; m < N_MUTEXES; m++) 4974 if (ls & (1 << m)) 4975 MU[m].Lock(); 4976 4977 data[LS_to_idx(ls)]++; 4978 4979 for (int m = N_MUTEXES - 1; m >= 0; m--) 4980 if (ls & (1 << m)) 4981 MU[m].Unlock(); 4982 } 4983} 4984 4985void Run() { 4986 printf("test103: Access different memory locations with different LockSets\n"); 4987 MyThreadArray t(Worker, Worker, Worker, Worker); 4988 t.Start(); 4989 t.Join(); 4990} 4991REGISTER_TEST2(Run, 103, FEATURE) 4992} // namespace test103 4993 4994// test104: TP. Simple race (write vs write). Heap mem. {{{1 4995namespace test104 { 4996int *GLOB = NULL; 4997void Worker() { 4998 *GLOB = 1; 4999} 5000 5001void Parent() { 5002 MyThread t(Worker); 5003 t.Start(); 5004 usleep(100000); 5005 *GLOB = 2; 5006 t.Join(); 5007} 5008void Run() { 5009 GLOB = (int*)memalign(64, sizeof(int)); 5010 *GLOB = 0; 5011 ANNOTATE_EXPECT_RACE(GLOB, "test104. TP."); 5012 ANNOTATE_TRACE_MEMORY(GLOB); 5013 printf("test104: positive\n"); 5014 Parent(); 5015 printf("\tGLOB=%d\n", *GLOB); 5016 free(GLOB); 5017} 5018REGISTER_TEST(Run, 104); 5019} // namespace test104 5020 5021 5022// test105: Checks how stack grows. {{{1 5023namespace test105 { 5024int GLOB = 0; 5025 5026void F1() { 5027 int ar[32]; 5028// ANNOTATE_TRACE_MEMORY(&ar[0]); 5029// ANNOTATE_TRACE_MEMORY(&ar[31]); 5030 ar[0] = 1; 5031 ar[31] = 1; 5032} 5033 5034void Worker() { 5035 int ar[32]; 5036// ANNOTATE_TRACE_MEMORY(&ar[0]); 5037// ANNOTATE_TRACE_MEMORY(&ar[31]); 5038 ar[0] = 1; 5039 ar[31] = 1; 5040 F1(); 5041} 5042 5043void Run() { 5044 printf("test105: negative\n"); 5045 Worker(); 5046 MyThread t(Worker); 5047 t.Start(); 5048 t.Join(); 5049 printf("\tGLOB=%d\n", GLOB); 5050} 5051REGISTER_TEST(Run, 105) 5052} // namespace test105 5053 5054 5055// test106: TN. pthread_once. {{{1 5056namespace test106 { 5057int *GLOB = NULL; 5058static pthread_once_t once = PTHREAD_ONCE_INIT; 5059void Init() { 5060 GLOB = new int; 5061 ANNOTATE_TRACE_MEMORY(GLOB); 5062 *GLOB = 777; 5063} 5064 5065void Worker0() { 5066 pthread_once(&once, Init); 5067} 5068void Worker1() { 5069 usleep(100000); 5070 pthread_once(&once, Init); 5071 CHECK(*GLOB == 777); 5072} 5073 5074 5075void Run() { 5076 printf("test106: negative\n"); 5077 MyThreadArray t(Worker0, Worker1, Worker1, Worker1); 5078 t.Start(); 5079 t.Join(); 5080 printf("\tGLOB=%d\n", *GLOB); 5081} 5082REGISTER_TEST2(Run, 106, FEATURE) 5083} // namespace test106 5084 5085 5086// test107: Test for ANNOTATE_EXPECT_RACE {{{1 5087namespace test107 { 5088int GLOB = 0; 5089void Run() { 5090 printf("test107: negative\n"); 5091 ANNOTATE_EXPECT_RACE(&GLOB, "No race in fact. Just checking the tool."); 5092 printf("\tGLOB=%d\n", GLOB); 5093} 5094REGISTER_TEST2(Run, 107, FEATURE|EXCLUDE_FROM_ALL) 5095} // namespace test107 5096 5097 5098// test108: TN. initialization of static object. {{{1 5099namespace test108 { 5100// Here we have a function-level static object. 5101// Starting from gcc 4 this is therad safe, 5102// but is is not thread safe with many other compilers. 5103// 5104// Helgrind supports this kind of initialization by 5105// intercepting __cxa_guard_acquire/__cxa_guard_release 5106// and ignoring all accesses between them. 5107// Helgrind also intercepts pthread_once in the same manner. 5108class Foo { 5109 public: 5110 Foo() { 5111 ANNOTATE_TRACE_MEMORY(&a_); 5112 a_ = 42; 5113 } 5114 void Check() const { CHECK(a_ == 42); } 5115 private: 5116 int a_; 5117}; 5118 5119const Foo *GetFoo() { 5120 static const Foo *foo = new Foo(); 5121 return foo; 5122} 5123void Worker0() { 5124 GetFoo(); 5125} 5126 5127void Worker() { 5128 usleep(200000); 5129 const Foo *foo = GetFoo(); 5130 foo->Check(); 5131} 5132 5133 5134void Run() { 5135 printf("test108: negative, initialization of static object\n"); 5136 MyThreadArray t(Worker0, Worker, Worker); 5137 t.Start(); 5138 t.Join(); 5139} 5140REGISTER_TEST2(Run, 108, FEATURE) 5141} // namespace test108 5142 5143 5144// test109: TN. Checking happens before between parent and child threads. {{{1 5145namespace test109 { 5146// Check that the detector correctly connects 5147// pthread_create with the new thread 5148// and 5149// thread exit with pthread_join 5150const int N = 32; 5151static int GLOB[N]; 5152 5153void Worker(void *a) { 5154 usleep(10000); 5155// printf("--Worker : %ld %p\n", (int*)a - GLOB, (void*)pthread_self()); 5156 int *arg = (int*)a; 5157 (*arg)++; 5158} 5159 5160void Run() { 5161 printf("test109: negative\n"); 5162 MyThread *t[N]; 5163 for (int i = 0; i < N; i++) { 5164 t[i] = new MyThread(Worker, &GLOB[i]); 5165 } 5166 for (int i = 0; i < N; i++) { 5167 ANNOTATE_TRACE_MEMORY(&GLOB[i]); 5168 GLOB[i] = 1; 5169 t[i]->Start(); 5170// printf("--Started: %p\n", (void*)t[i]->tid()); 5171 } 5172 for (int i = 0; i < N; i++) { 5173// printf("--Joining: %p\n", (void*)t[i]->tid()); 5174 t[i]->Join(); 5175// printf("--Joined : %p\n", (void*)t[i]->tid()); 5176 GLOB[i]++; 5177 } 5178 for (int i = 0; i < N; i++) delete t[i]; 5179 5180 printf("\tGLOB=%d\n", GLOB[13]); 5181} 5182REGISTER_TEST(Run, 109) 5183} // namespace test109 5184 5185 5186// test110: TP. Simple races with stack, global and heap objects. {{{1 5187namespace test110 { 5188int GLOB = 0; 5189static int STATIC; 5190 5191int *STACK = 0; 5192 5193int *MALLOC; 5194int *CALLOC; 5195int *REALLOC; 5196int *VALLOC; 5197int *PVALLOC; 5198int *MEMALIGN; 5199int *POSIX_MEMALIGN; 5200int *MMAP; 5201 5202int *NEW; 5203int *NEW_ARR; 5204 5205void Worker() { 5206 GLOB++; 5207 STATIC++; 5208 5209 (*STACK)++; 5210 5211 (*MALLOC)++; 5212 (*CALLOC)++; 5213 (*REALLOC)++; 5214 (*VALLOC)++; 5215 (*PVALLOC)++; 5216 (*MEMALIGN)++; 5217 (*POSIX_MEMALIGN)++; 5218 (*MMAP)++; 5219 5220 (*NEW)++; 5221 (*NEW_ARR)++; 5222} 5223void Run() { 5224 int x = 0; 5225 STACK = &x; 5226 5227 MALLOC = (int*)malloc(sizeof(int)); 5228 CALLOC = (int*)calloc(1, sizeof(int)); 5229 REALLOC = (int*)realloc(NULL, sizeof(int)); 5230 VALLOC = (int*)valloc(sizeof(int)); 5231 PVALLOC = (int*)valloc(sizeof(int)); // TODO: pvalloc breaks helgrind. 5232 MEMALIGN = (int*)memalign(64, sizeof(int)); 5233 CHECK(0 == posix_memalign((void**)&POSIX_MEMALIGN, 64, sizeof(int))); 5234 MMAP = (int*)mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, 5235 MAP_PRIVATE | MAP_ANON, -1, 0); 5236 5237 NEW = new int; 5238 NEW_ARR = new int[10]; 5239 5240 5241 FAST_MODE_INIT(STACK); 5242 ANNOTATE_EXPECT_RACE(STACK, "real race on stack object"); 5243 FAST_MODE_INIT(&GLOB); 5244 ANNOTATE_EXPECT_RACE(&GLOB, "real race on global object"); 5245 FAST_MODE_INIT(&STATIC); 5246 ANNOTATE_EXPECT_RACE(&STATIC, "real race on a static global object"); 5247 FAST_MODE_INIT(MALLOC); 5248 ANNOTATE_EXPECT_RACE(MALLOC, "real race on a malloc-ed object"); 5249 FAST_MODE_INIT(CALLOC); 5250 ANNOTATE_EXPECT_RACE(CALLOC, "real race on a calloc-ed object"); 5251 FAST_MODE_INIT(REALLOC); 5252 ANNOTATE_EXPECT_RACE(REALLOC, "real race on a realloc-ed object"); 5253 FAST_MODE_INIT(VALLOC); 5254 ANNOTATE_EXPECT_RACE(VALLOC, "real race on a valloc-ed object"); 5255 FAST_MODE_INIT(PVALLOC); 5256 ANNOTATE_EXPECT_RACE(PVALLOC, "real race on a pvalloc-ed object"); 5257 FAST_MODE_INIT(MEMALIGN); 5258 ANNOTATE_EXPECT_RACE(MEMALIGN, "real race on a memalign-ed object"); 5259 FAST_MODE_INIT(POSIX_MEMALIGN); 5260 ANNOTATE_EXPECT_RACE(POSIX_MEMALIGN, "real race on a posix_memalign-ed object"); 5261 FAST_MODE_INIT(MMAP); 5262 ANNOTATE_EXPECT_RACE(MMAP, "real race on a mmap-ed object"); 5263 5264 FAST_MODE_INIT(NEW); 5265 ANNOTATE_EXPECT_RACE(NEW, "real race on a new-ed object"); 5266 FAST_MODE_INIT(NEW_ARR); 5267 ANNOTATE_EXPECT_RACE(NEW_ARR, "real race on a new[]-ed object"); 5268 5269 MyThreadArray t(Worker, Worker, Worker); 5270 t.Start(); 5271 t.Join(); 5272 printf("test110: positive (race on a stack object)\n"); 5273 printf("\tSTACK=%d\n", *STACK); 5274 CHECK(GLOB <= 3); 5275 CHECK(STATIC <= 3); 5276 5277 free(MALLOC); 5278 free(CALLOC); 5279 free(REALLOC); 5280 free(VALLOC); 5281 free(PVALLOC); 5282 free(MEMALIGN); 5283 free(POSIX_MEMALIGN); 5284 munmap(MMAP, sizeof(int)); 5285 delete NEW; 5286 delete [] NEW_ARR; 5287} 5288REGISTER_TEST(Run, 110) 5289} // namespace test110 5290 5291 5292// test111: TN. Unit test for a bug related to stack handling. {{{1 5293namespace test111 { 5294char *GLOB = 0; 5295bool COND = false; 5296Mutex mu; 5297const int N = 3000; 5298 5299void write_to_p(char *p, int val) { 5300 for (int i = 0; i < N; i++) 5301 p[i] = val; 5302} 5303 5304static bool ArgIsTrue(bool *arg) { 5305// printf("ArgIsTrue: %d tid=%d\n", *arg, (int)pthread_self()); 5306 return *arg == true; 5307} 5308 5309void f1() { 5310 char some_stack[N]; 5311 write_to_p(some_stack, 1); 5312 mu.LockWhen(Condition(&ArgIsTrue, &COND)); 5313 mu.Unlock(); 5314} 5315 5316void f2() { 5317 char some_stack[N]; 5318 char some_more_stack[N]; 5319 write_to_p(some_stack, 2); 5320 write_to_p(some_more_stack, 2); 5321} 5322 5323void f0() { f2(); } 5324 5325void Worker1() { 5326 f0(); 5327 f1(); 5328 f2(); 5329} 5330 5331void Worker2() { 5332 usleep(100000); 5333 mu.Lock(); 5334 COND = true; 5335 mu.Unlock(); 5336} 5337 5338void Run() { 5339 printf("test111: regression test\n"); 5340 MyThreadArray t(Worker1, Worker1, Worker2); 5341// AnnotateSetVerbosity(__FILE__, __LINE__, 3); 5342 t.Start(); 5343 t.Join(); 5344// AnnotateSetVerbosity(__FILE__, __LINE__, 1); 5345} 5346REGISTER_TEST2(Run, 111, FEATURE) 5347} // namespace test111 5348 5349// test112: STAB. Test for ANNOTATE_PUBLISH_MEMORY_RANGE{{{1 5350namespace test112 { 5351char *GLOB = 0; 5352const int N = 64 * 5; 5353Mutex mu; 5354bool ready = false; // under mu 5355int beg, end; // under mu 5356 5357Mutex mu1; 5358 5359void Worker() { 5360 5361 bool is_ready = false; 5362 int b, e; 5363 while (!is_ready) { 5364 mu.Lock(); 5365 is_ready = ready; 5366 b = beg; 5367 e = end; 5368 mu.Unlock(); 5369 usleep(1000); 5370 } 5371 5372 mu1.Lock(); 5373 for (int i = b; i < e; i++) { 5374 GLOB[i]++; 5375 } 5376 mu1.Unlock(); 5377} 5378 5379void PublishRange(int b, int e) { 5380 MyThreadArray t(Worker, Worker); 5381 ready = false; // runs before other threads 5382 t.Start(); 5383 5384 ANNOTATE_NEW_MEMORY(GLOB + b, e - b); 5385 ANNOTATE_TRACE_MEMORY(GLOB + b); 5386 for (int j = b; j < e; j++) { 5387 GLOB[j] = 0; 5388 } 5389 ANNOTATE_PUBLISH_MEMORY_RANGE(GLOB + b, e - b); 5390 5391 // hand off 5392 mu.Lock(); 5393 ready = true; 5394 beg = b; 5395 end = e; 5396 mu.Unlock(); 5397 5398 t.Join(); 5399} 5400 5401void Run() { 5402 printf("test112: stability (ANNOTATE_PUBLISH_MEMORY_RANGE)\n"); 5403 GLOB = new char [N]; 5404 5405 PublishRange(0, 10); 5406 PublishRange(3, 5); 5407 5408 PublishRange(12, 13); 5409 PublishRange(10, 14); 5410 5411 PublishRange(15, 17); 5412 PublishRange(16, 18); 5413 5414 // do few more random publishes. 5415 for (int i = 0; i < 20; i++) { 5416 int beg = rand() % N; 5417 int size = (rand() % (N - beg)) + 1; 5418 CHECK(size > 0); 5419 CHECK(beg + size <= N); 5420 PublishRange(beg, beg + size); 5421 } 5422 5423 printf("GLOB = %d\n", (int)GLOB[0]); 5424} 5425REGISTER_TEST2(Run, 112, STABILITY) 5426} // namespace test112 5427 5428 5429// test113: PERF. A lot of lock/unlock calls. Many locks {{{1 5430namespace test113 { 5431const int kNumIter = 100000; 5432const int kNumLocks = 7; 5433Mutex MU[kNumLocks]; 5434void Run() { 5435 printf("test113: perf\n"); 5436 for (int i = 0; i < kNumIter; i++ ) { 5437 for (int j = 0; j < kNumLocks; j++) { 5438 if (i & (1 << j)) MU[j].Lock(); 5439 } 5440 for (int j = kNumLocks - 1; j >= 0; j--) { 5441 if (i & (1 << j)) MU[j].Unlock(); 5442 } 5443 } 5444} 5445REGISTER_TEST(Run, 113) 5446} // namespace test113 5447 5448 5449// test114: STAB. Recursive lock. {{{1 5450namespace test114 { 5451int Bar() { 5452 static int bar = 1; 5453 return bar; 5454} 5455int Foo() { 5456 static int foo = Bar(); 5457 return foo; 5458} 5459void Worker() { 5460 static int x = Foo(); 5461 CHECK(x == 1); 5462} 5463void Run() { 5464 printf("test114: stab\n"); 5465 MyThreadArray t(Worker, Worker); 5466 t.Start(); 5467 t.Join(); 5468} 5469REGISTER_TEST(Run, 114) 5470} // namespace test114 5471 5472 5473// test115: TN. sem_open. {{{1 5474namespace test115 { 5475int tid = 0; 5476Mutex mu; 5477const char *kSemName = "drt-test-sem"; 5478 5479int GLOB = 0; 5480 5481sem_t *DoSemOpen() { 5482 // TODO: there is some race report inside sem_open 5483 // for which suppressions do not work... (???) 5484 ANNOTATE_IGNORE_WRITES_BEGIN(); 5485 sem_t *sem = sem_open(kSemName, O_CREAT, 0600, 3); 5486 ANNOTATE_IGNORE_WRITES_END(); 5487 return sem; 5488} 5489 5490void Worker() { 5491 mu.Lock(); 5492 int my_tid = tid++; 5493 mu.Unlock(); 5494 5495 if (my_tid == 0) { 5496 GLOB = 1; 5497 } 5498 5499 // if the detector observes a happens-before arc between 5500 // sem_open and sem_wait, it will be silent. 5501 sem_t *sem = DoSemOpen(); 5502 usleep(100000); 5503 CHECK(sem != SEM_FAILED); 5504 CHECK(sem_wait(sem) == 0); 5505 5506 if (my_tid > 0) { 5507 CHECK(GLOB == 1); 5508 } 5509} 5510 5511void Run() { 5512 printf("test115: stab (sem_open())\n"); 5513 5514 // just check that sem_open is not completely broken 5515 sem_unlink(kSemName); 5516 sem_t* sem = DoSemOpen(); 5517 CHECK(sem != SEM_FAILED); 5518 CHECK(sem_wait(sem) == 0); 5519 sem_unlink(kSemName); 5520 5521 // check that sem_open and sem_wait create a happens-before arc. 5522 MyThreadArray t(Worker, Worker, Worker); 5523 t.Start(); 5524 t.Join(); 5525 // clean up 5526 sem_unlink(kSemName); 5527} 5528REGISTER_TEST(Run, 115) 5529} // namespace test115 5530 5531 5532// test116: TN. some operations with string<> objects. {{{1 5533namespace test116 { 5534 5535void Worker() { 5536 string A[10], B[10], C[10]; 5537 for (int i = 0; i < 1000; i++) { 5538 for (int j = 0; j < 10; j++) { 5539 string &a = A[j]; 5540 string &b = B[j]; 5541 string &c = C[j]; 5542 a = "sdl;fkjhasdflksj df"; 5543 b = "sdf sdf;ljsd "; 5544 c = "'sfdf df"; 5545 c = b; 5546 a = c; 5547 b = a; 5548 swap(a,b); 5549 swap(b,c); 5550 } 5551 for (int j = 0; j < 10; j++) { 5552 string &a = A[j]; 5553 string &b = B[j]; 5554 string &c = C[j]; 5555 a.clear(); 5556 b.clear(); 5557 c.clear(); 5558 } 5559 } 5560} 5561 5562void Run() { 5563 printf("test116: negative (strings)\n"); 5564 MyThreadArray t(Worker, Worker, Worker); 5565 t.Start(); 5566 t.Join(); 5567} 5568REGISTER_TEST2(Run, 116, FEATURE|EXCLUDE_FROM_ALL) 5569} // namespace test116 5570 5571// test117: TN. Many calls to function-scope static init. {{{1 5572namespace test117 { 5573const int N = 50; 5574 5575int Foo() { 5576 usleep(20000); 5577 return 1; 5578} 5579 5580void Worker(void *a) { 5581 static int foo = Foo(); 5582 CHECK(foo == 1); 5583} 5584 5585void Run() { 5586 printf("test117: negative\n"); 5587 MyThread *t[N]; 5588 for (int i = 0; i < N; i++) { 5589 t[i] = new MyThread(Worker); 5590 } 5591 for (int i = 0; i < N; i++) { 5592 t[i]->Start(); 5593 } 5594 for (int i = 0; i < N; i++) { 5595 t[i]->Join(); 5596 } 5597 for (int i = 0; i < N; i++) delete t[i]; 5598} 5599REGISTER_TEST(Run, 117) 5600} // namespace test117 5601 5602 5603 5604// test118 PERF: One signal, multiple waits. {{{1 5605namespace test118 { 5606int GLOB = 0; 5607const int kNumIter = 2000000; 5608void Signaller() { 5609 usleep(50000); 5610 ANNOTATE_CONDVAR_SIGNAL(&GLOB); 5611} 5612void Waiter() { 5613 for (int i = 0; i < kNumIter; i++) { 5614 ANNOTATE_CONDVAR_WAIT(&GLOB); 5615 if (i == kNumIter / 2) 5616 usleep(100000); 5617 } 5618} 5619void Run() { 5620 printf("test118: perf\n"); 5621 MyThreadArray t(Signaller, Waiter, Signaller, Waiter); 5622 t.Start(); 5623 t.Join(); 5624 printf("\tGLOB=%d\n", GLOB); 5625} 5626REGISTER_TEST(Run, 118) 5627} // namespace test118 5628 5629 5630// test119: TP. Testing that malloc does not introduce any HB arc. {{{1 5631namespace test119 { 5632int GLOB = 0; 5633void Worker1() { 5634 GLOB = 1; 5635 free(malloc(123)); 5636} 5637void Worker2() { 5638 usleep(100000); 5639 free(malloc(345)); 5640 GLOB = 2; 5641} 5642void Run() { 5643 printf("test119: positive (checking if malloc creates HB arcs)\n"); 5644 FAST_MODE_INIT(&GLOB); 5645 if (!(Tsan_PureHappensBefore() && kMallocUsesMutex)) 5646 ANNOTATE_EXPECT_RACE_FOR_TSAN(&GLOB, "true race"); 5647 MyThreadArray t(Worker1, Worker2); 5648 t.Start(); 5649 t.Join(); 5650 printf("\tGLOB=%d\n", GLOB); 5651} 5652REGISTER_TEST(Run, 119) 5653} // namespace test119 5654 5655 5656// test120: TP. Thread1: write then read. Thread2: read. {{{1 5657namespace test120 { 5658int GLOB = 0; 5659 5660void Thread1() { 5661 GLOB = 1; // write 5662 CHECK(GLOB); // read 5663} 5664 5665void Thread2() { 5666 usleep(100000); 5667 CHECK(GLOB >= 0); // read 5668} 5669 5670void Run() { 5671 FAST_MODE_INIT(&GLOB); 5672 ANNOTATE_EXPECT_RACE_FOR_TSAN(&GLOB, "TP (T1: write then read, T2: read)"); 5673 printf("test120: positive\n"); 5674 MyThreadArray t(Thread1, Thread2); 5675 GLOB = 1; 5676 t.Start(); 5677 t.Join(); 5678 printf("\tGLOB=%d\n", GLOB); 5679} 5680REGISTER_TEST(Run, 120) 5681} // namespace test120 5682 5683 5684// test121: TP. Example of double-checked-locking {{{1 5685namespace test121 { 5686struct Foo { 5687 uintptr_t a, b[15]; 5688} __attribute__ ((aligned (64))); 5689 5690static Mutex mu; 5691static Foo *foo; 5692 5693void InitMe() { 5694 if (!foo) { 5695 MutexLock lock(&mu); 5696 if (!foo) { 5697 ANNOTATE_EXPECT_RACE_FOR_TSAN(&foo, "test121. Double-checked locking (ptr)"); 5698 foo = new Foo; 5699 if (!Tsan_FastMode()) 5700 ANNOTATE_EXPECT_RACE_FOR_TSAN(&foo->a, "test121. Double-checked locking (obj)"); 5701 foo->a = 42; 5702 } 5703 } 5704} 5705 5706void UseMe() { 5707 InitMe(); 5708 CHECK(foo && foo->a == 42); 5709} 5710 5711void Worker1() { UseMe(); } 5712void Worker2() { UseMe(); } 5713void Worker3() { UseMe(); } 5714 5715 5716void Run() { 5717 FAST_MODE_INIT(&foo); 5718 printf("test121: TP. Example of double-checked-locking\n"); 5719 MyThreadArray t1(Worker1, Worker2, Worker3); 5720 t1.Start(); 5721 t1.Join(); 5722 delete foo; 5723} 5724REGISTER_TEST(Run, 121) 5725} // namespace test121 5726 5727// test122 TP: Simple test with RWLock {{{1 5728namespace test122 { 5729int VAR1 = 0; 5730int VAR2 = 0; 5731RWLock mu; 5732 5733void WriteWhileHoldingReaderLock(int *p) { 5734 usleep(100000); 5735 ReaderLockScoped lock(&mu); // Reader lock for writing. -- bug. 5736 (*p)++; 5737} 5738 5739void CorrectWrite(int *p) { 5740 WriterLockScoped lock(&mu); 5741 (*p)++; 5742} 5743 5744void Thread1() { WriteWhileHoldingReaderLock(&VAR1); } 5745void Thread2() { CorrectWrite(&VAR1); } 5746void Thread3() { CorrectWrite(&VAR2); } 5747void Thread4() { WriteWhileHoldingReaderLock(&VAR2); } 5748 5749 5750void Run() { 5751 printf("test122: positive (rw-lock)\n"); 5752 VAR1 = 0; 5753 VAR2 = 0; 5754 ANNOTATE_TRACE_MEMORY(&VAR1); 5755 ANNOTATE_TRACE_MEMORY(&VAR2); 5756 if (!Tsan_PureHappensBefore()) { 5757 ANNOTATE_EXPECT_RACE_FOR_TSAN(&VAR1, "test122. TP. ReaderLock-ed while writing"); 5758 ANNOTATE_EXPECT_RACE_FOR_TSAN(&VAR2, "test122. TP. ReaderLock-ed while writing"); 5759 } 5760 MyThreadArray t(Thread1, Thread2, Thread3, Thread4); 5761 t.Start(); 5762 t.Join(); 5763} 5764REGISTER_TEST(Run, 122) 5765} // namespace test122 5766 5767 5768// test123 TP: accesses of different sizes. {{{1 5769namespace test123 { 5770 5771uint64_t MEM[8]; 5772 5773#define GenericWrite(p,size,off) { \ 5774 if (size == 64) {\ 5775 CHECK(off == 0);\ 5776 (p)[off] = 1;\ 5777 } else if (size == 32) {\ 5778 CHECK(off <= 2);\ 5779 uint32_t *x = (uint32_t*)(p);\ 5780 x[off] = 1;\ 5781 } else if (size == 16) {\ 5782 CHECK(off <= 4);\ 5783 uint16_t *x = (uint16_t*)(p);\ 5784 x[off] = 1;\ 5785 } else if (size == 8) {\ 5786 CHECK(off <= 8);\ 5787 uint8_t *x = (uint8_t*)(p);\ 5788 x[off] = 1;\ 5789 } else {\ 5790 CHECK(0);\ 5791 }\ 5792}\ 5793 5794// Q. Hey dude, why so many functions? 5795// A. I need different stack traces for different accesses. 5796 5797void Wr64_0() { GenericWrite(&MEM[0], 64, 0); } 5798void Wr64_1() { GenericWrite(&MEM[1], 64, 0); } 5799void Wr64_2() { GenericWrite(&MEM[2], 64, 0); } 5800void Wr64_3() { GenericWrite(&MEM[3], 64, 0); } 5801void Wr64_4() { GenericWrite(&MEM[4], 64, 0); } 5802void Wr64_5() { GenericWrite(&MEM[5], 64, 0); } 5803void Wr64_6() { GenericWrite(&MEM[6], 64, 0); } 5804void Wr64_7() { GenericWrite(&MEM[7], 64, 0); } 5805 5806void Wr32_0() { GenericWrite(&MEM[0], 32, 0); } 5807void Wr32_1() { GenericWrite(&MEM[1], 32, 1); } 5808void Wr32_2() { GenericWrite(&MEM[2], 32, 0); } 5809void Wr32_3() { GenericWrite(&MEM[3], 32, 1); } 5810void Wr32_4() { GenericWrite(&MEM[4], 32, 0); } 5811void Wr32_5() { GenericWrite(&MEM[5], 32, 1); } 5812void Wr32_6() { GenericWrite(&MEM[6], 32, 0); } 5813void Wr32_7() { GenericWrite(&MEM[7], 32, 1); } 5814 5815void Wr16_0() { GenericWrite(&MEM[0], 16, 0); } 5816void Wr16_1() { GenericWrite(&MEM[1], 16, 1); } 5817void Wr16_2() { GenericWrite(&MEM[2], 16, 2); } 5818void Wr16_3() { GenericWrite(&MEM[3], 16, 3); } 5819void Wr16_4() { GenericWrite(&MEM[4], 16, 0); } 5820void Wr16_5() { GenericWrite(&MEM[5], 16, 1); } 5821void Wr16_6() { GenericWrite(&MEM[6], 16, 2); } 5822void Wr16_7() { GenericWrite(&MEM[7], 16, 3); } 5823 5824void Wr8_0() { GenericWrite(&MEM[0], 8, 0); } 5825void Wr8_1() { GenericWrite(&MEM[1], 8, 1); } 5826void Wr8_2() { GenericWrite(&MEM[2], 8, 2); } 5827void Wr8_3() { GenericWrite(&MEM[3], 8, 3); } 5828void Wr8_4() { GenericWrite(&MEM[4], 8, 4); } 5829void Wr8_5() { GenericWrite(&MEM[5], 8, 5); } 5830void Wr8_6() { GenericWrite(&MEM[6], 8, 6); } 5831void Wr8_7() { GenericWrite(&MEM[7], 8, 7); } 5832 5833void WriteAll64() { 5834 Wr64_0(); 5835 Wr64_1(); 5836 Wr64_2(); 5837 Wr64_3(); 5838 Wr64_4(); 5839 Wr64_5(); 5840 Wr64_6(); 5841 Wr64_7(); 5842} 5843 5844void WriteAll32() { 5845 Wr32_0(); 5846 Wr32_1(); 5847 Wr32_2(); 5848 Wr32_3(); 5849 Wr32_4(); 5850 Wr32_5(); 5851 Wr32_6(); 5852 Wr32_7(); 5853} 5854 5855void WriteAll16() { 5856 Wr16_0(); 5857 Wr16_1(); 5858 Wr16_2(); 5859 Wr16_3(); 5860 Wr16_4(); 5861 Wr16_5(); 5862 Wr16_6(); 5863 Wr16_7(); 5864} 5865 5866void WriteAll8() { 5867 Wr8_0(); 5868 Wr8_1(); 5869 Wr8_2(); 5870 Wr8_3(); 5871 Wr8_4(); 5872 Wr8_5(); 5873 Wr8_6(); 5874 Wr8_7(); 5875} 5876 5877void W00() { WriteAll64(); } 5878void W01() { WriteAll64(); } 5879void W02() { WriteAll64(); } 5880 5881void W10() { WriteAll32(); } 5882void W11() { WriteAll32(); } 5883void W12() { WriteAll32(); } 5884 5885void W20() { WriteAll16(); } 5886void W21() { WriteAll16(); } 5887void W22() { WriteAll16(); } 5888 5889void W30() { WriteAll8(); } 5890void W31() { WriteAll8(); } 5891void W32() { WriteAll8(); } 5892 5893typedef void (*F)(void); 5894 5895void TestTwoSizes(F f1, F f2) { 5896 // first f1, then f2 5897 ANNOTATE_NEW_MEMORY(MEM, sizeof(MEM)); 5898 memset(MEM, 0, sizeof(MEM)); 5899 MyThreadArray t1(f1, f2); 5900 t1.Start(); 5901 t1.Join(); 5902 // reverse order 5903 ANNOTATE_NEW_MEMORY(MEM, sizeof(MEM)); 5904 memset(MEM, 0, sizeof(MEM)); 5905 MyThreadArray t2(f2, f1); 5906 t2.Start(); 5907 t2.Join(); 5908} 5909 5910void Run() { 5911 printf("test123: positive (different sizes)\n"); 5912 TestTwoSizes(W00, W10); 5913// TestTwoSizes(W01, W20); 5914// TestTwoSizes(W02, W30); 5915// TestTwoSizes(W11, W21); 5916// TestTwoSizes(W12, W31); 5917// TestTwoSizes(W22, W32); 5918 5919} 5920REGISTER_TEST2(Run, 123, FEATURE|EXCLUDE_FROM_ALL) 5921} // namespace test123 5922 5923 5924// test124: What happens if we delete an unlocked lock? {{{1 5925namespace test124 { 5926// This test does not worg with pthreads (you can't call 5927// pthread_mutex_destroy on a locked lock). 5928int GLOB = 0; 5929const int N = 1000; 5930void Worker() { 5931 Mutex *a_large_local_array_of_mutexes; 5932 a_large_local_array_of_mutexes = new Mutex[N]; 5933 for (int i = 0; i < N; i++) { 5934 a_large_local_array_of_mutexes[i].Lock(); 5935 } 5936 delete []a_large_local_array_of_mutexes; 5937 GLOB = 1; 5938} 5939 5940void Run() { 5941 printf("test124: negative\n"); 5942 MyThreadArray t(Worker, Worker, Worker); 5943 t.Start(); 5944 t.Join(); 5945 printf("\tGLOB=%d\n", GLOB); 5946} 5947REGISTER_TEST2(Run, 124, FEATURE|EXCLUDE_FROM_ALL) 5948} // namespace test124 5949 5950 5951// test125 TN: Backwards lock (annotated). {{{1 5952namespace test125 { 5953// This test uses "Backwards mutex" locking protocol. 5954// We take a *reader* lock when writing to a per-thread data 5955// (GLOB[thread_num]) and we take a *writer* lock when we 5956// are reading from the entire array at once. 5957// 5958// Such locking protocol is not understood by ThreadSanitizer's 5959// hybrid state machine. So, you either have to use a pure-happens-before 5960// detector ("tsan --pure-happens-before") or apply pure happens-before mode 5961// to this particular lock by using ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(&mu). 5962 5963const int n_threads = 3; 5964RWLock mu; 5965int GLOB[n_threads]; 5966 5967int adder_num; // updated atomically. 5968 5969void Adder() { 5970 int my_num = AtomicIncrement(&adder_num, 1); 5971 5972 ReaderLockScoped lock(&mu); 5973 GLOB[my_num]++; 5974} 5975 5976void Aggregator() { 5977 int sum = 0; 5978 { 5979 WriterLockScoped lock(&mu); 5980 for (int i = 0; i < n_threads; i++) { 5981 sum += GLOB[i]; 5982 } 5983 } 5984 printf("sum=%d\n", sum); 5985} 5986 5987void Run() { 5988 printf("test125: negative\n"); 5989 5990 ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(&mu); 5991 5992 // run Adders, then Aggregator 5993 { 5994 MyThreadArray t(Adder, Adder, Adder, Aggregator); 5995 t.Start(); 5996 t.Join(); 5997 } 5998 5999 // Run Aggregator first. 6000 adder_num = 0; 6001 { 6002 MyThreadArray t(Aggregator, Adder, Adder, Adder); 6003 t.Start(); 6004 t.Join(); 6005 } 6006 6007} 6008REGISTER_TEST(Run, 125) 6009} // namespace test125 6010 6011// test126 TN: test for BlockingCounter {{{1 6012namespace test126 { 6013BlockingCounter *blocking_counter; 6014int GLOB = 0; 6015void Worker() { 6016 CHECK(blocking_counter); 6017 CHECK(GLOB == 0); 6018 blocking_counter->DecrementCount(); 6019} 6020void Run() { 6021 printf("test126: negative\n"); 6022 MyThreadArray t(Worker, Worker, Worker); 6023 blocking_counter = new BlockingCounter(3); 6024 t.Start(); 6025 blocking_counter->Wait(); 6026 GLOB = 1; 6027 t.Join(); 6028 printf("\tGLOB=%d\n", GLOB); 6029} 6030REGISTER_TEST(Run, 126) 6031} // namespace test126 6032 6033 6034// test127. Bad code: unlocking a mutex locked by another thread. {{{1 6035namespace test127 { 6036Mutex mu; 6037void Thread1() { 6038 mu.Lock(); 6039} 6040void Thread2() { 6041 usleep(100000); 6042 mu.Unlock(); 6043} 6044void Run() { 6045 printf("test127: unlocking a mutex locked by another thread.\n"); 6046 MyThreadArray t(Thread1, Thread2); 6047 t.Start(); 6048 t.Join(); 6049} 6050REGISTER_TEST(Run, 127) 6051} // namespace test127 6052 6053// test128. Suppressed code in concurrent accesses {{{1 6054// Please use --suppressions=unittest.supp flag when running this test. 6055namespace test128 { 6056Mutex mu; 6057int GLOB = 0; 6058void Worker() { 6059 usleep(100000); 6060 mu.Lock(); 6061 GLOB++; 6062 mu.Unlock(); 6063} 6064void ThisFunctionShouldBeSuppressed() { 6065 GLOB++; 6066} 6067void Run() { 6068 printf("test128: Suppressed code in concurrent accesses.\n"); 6069 MyThreadArray t(Worker, ThisFunctionShouldBeSuppressed); 6070 t.Start(); 6071 t.Join(); 6072} 6073REGISTER_TEST2(Run, 128, FEATURE | EXCLUDE_FROM_ALL) 6074} // namespace test128 6075 6076// test129: TN. Synchronization via ReaderLockWhen(). {{{1 6077namespace test129 { 6078int GLOB = 0; 6079Mutex MU; 6080bool WeirdCondition(int* param) { 6081 *param = GLOB; // a write into Waiter's memory 6082 return GLOB > 0; 6083} 6084void Waiter() { 6085 int param = 0; 6086 MU.ReaderLockWhen(Condition(WeirdCondition, ¶m)); 6087 MU.ReaderUnlock(); 6088 CHECK(GLOB > 0); 6089 CHECK(param > 0); 6090} 6091void Waker() { 6092 usleep(100000); // Make sure the waiter blocks. 6093 MU.Lock(); 6094 GLOB++; 6095 MU.Unlock(); // calls ANNOTATE_CONDVAR_SIGNAL; 6096} 6097void Run() { 6098 printf("test129: Synchronization via ReaderLockWhen()\n"); 6099 MyThread mt(Waiter, NULL, "Waiter Thread"); 6100 mt.Start(); 6101 Waker(); 6102 mt.Join(); 6103 printf("\tGLOB=%d\n", GLOB); 6104} 6105REGISTER_TEST2(Run, 129, FEATURE); 6106} // namespace test129 6107 6108// test130: TN. Per-thread. {{{1 6109namespace test130 { 6110#ifndef NO_TLS 6111// This test verifies that the race detector handles 6112// thread-local storage (TLS) correctly. 6113// As of 09-03-30 ThreadSanitizer has a bug: 6114// - Thread1 starts 6115// - Thread1 touches per_thread_global 6116// - Thread1 ends 6117// - Thread2 starts (and there is no happens-before relation between it and 6118// Thread1) 6119// - Thread2 touches per_thread_global 6120// It may happen so that Thread2 will have per_thread_global in the same address 6121// as Thread1. Since there is no happens-before relation between threads, 6122// ThreadSanitizer reports a race. 6123// 6124// test131 does the same for stack. 6125 6126static __thread int per_thread_global[10] = {0}; 6127 6128void RealWorker() { // Touch per_thread_global. 6129 per_thread_global[1]++; 6130 errno++; 6131} 6132 6133void Worker() { // Spawn few threads that touch per_thread_global. 6134 MyThreadArray t(RealWorker, RealWorker); 6135 t.Start(); 6136 t.Join(); 6137} 6138void Worker0() { sleep(0); Worker(); } 6139void Worker1() { sleep(1); Worker(); } 6140void Worker2() { sleep(2); Worker(); } 6141void Worker3() { sleep(3); Worker(); } 6142 6143void Run() { 6144 printf("test130: Per-thread\n"); 6145 MyThreadArray t1(Worker0, Worker1, Worker2, Worker3); 6146 t1.Start(); 6147 t1.Join(); 6148 printf("\tper_thread_global=%d\n", per_thread_global[1]); 6149} 6150REGISTER_TEST(Run, 130) 6151#endif // NO_TLS 6152} // namespace test130 6153 6154 6155// test131: TN. Stack. {{{1 6156namespace test131 { 6157// Same as test130, but for stack. 6158 6159void RealWorker() { // Touch stack. 6160 int stack_var = 0; 6161 stack_var++; 6162} 6163 6164void Worker() { // Spawn few threads that touch stack. 6165 MyThreadArray t(RealWorker, RealWorker); 6166 t.Start(); 6167 t.Join(); 6168} 6169void Worker0() { sleep(0); Worker(); } 6170void Worker1() { sleep(1); Worker(); } 6171void Worker2() { sleep(2); Worker(); } 6172void Worker3() { sleep(3); Worker(); } 6173 6174void Run() { 6175 printf("test131: stack\n"); 6176 MyThreadArray t(Worker0, Worker1, Worker2, Worker3); 6177 t.Start(); 6178 t.Join(); 6179} 6180REGISTER_TEST(Run, 131) 6181} // namespace test131 6182 6183 6184// test132: TP. Simple race (write vs write). Works in fast-mode. {{{1 6185namespace test132 { 6186int GLOB = 0; 6187void Worker() { GLOB = 1; } 6188 6189void Run1() { 6190 FAST_MODE_INIT(&GLOB); 6191 ANNOTATE_EXPECT_RACE_FOR_TSAN(&GLOB, "test132"); 6192 printf("test132: positive; &GLOB=%p\n", &GLOB); 6193 ANNOTATE_TRACE_MEMORY(&GLOB); 6194 GLOB = 7; 6195 MyThreadArray t(Worker, Worker); 6196 t.Start(); 6197 t.Join(); 6198} 6199 6200void Run() { 6201 Run1(); 6202} 6203REGISTER_TEST(Run, 132); 6204} // namespace test132 6205 6206 6207// test133: TP. Simple race (write vs write). Works in fast mode. {{{1 6208namespace test133 { 6209// Same as test132, but everything is run from a separate thread spawned from 6210// the main thread. 6211int GLOB = 0; 6212void Worker() { GLOB = 1; } 6213 6214void Run1() { 6215 FAST_MODE_INIT(&GLOB); 6216 ANNOTATE_EXPECT_RACE_FOR_TSAN(&GLOB, "test133"); 6217 printf("test133: positive; &GLOB=%p\n", &GLOB); 6218 ANNOTATE_TRACE_MEMORY(&GLOB); 6219 GLOB = 7; 6220 MyThreadArray t(Worker, Worker); 6221 t.Start(); 6222 t.Join(); 6223} 6224void Run() { 6225 MyThread t(Run1); 6226 t.Start(); 6227 t.Join(); 6228} 6229REGISTER_TEST(Run, 133); 6230} // namespace test133 6231 6232 6233// test134 TN. Swap. Variant of test79. {{{1 6234namespace test134 { 6235#if 0 6236typedef __gnu_cxx::hash_map<int, int> map_t; 6237#else 6238typedef std::map<int, int> map_t; 6239#endif 6240map_t map; 6241Mutex mu; 6242// Here we use swap to pass map between threads. 6243// The synchronization is correct, but w/o the annotation 6244// any hybrid detector will complain. 6245 6246// Swap is very unfriendly to the lock-set (and hybrid) race detectors. 6247// Since tmp is destructed outside the mutex, we need to have a happens-before 6248// arc between any prior access to map and here. 6249// Since the internals of tmp are created ouside the mutex and are passed to 6250// other thread, we need to have a h-b arc between here and any future access. 6251// These arcs can be created by HAPPENS_{BEFORE,AFTER} annotations, but it is 6252// much simpler to apply pure-happens-before mode to the mutex mu. 6253void Swapper() { 6254 map_t tmp; 6255 MutexLock lock(&mu); 6256 ANNOTATE_HAPPENS_AFTER(&map); 6257 // We swap the new empty map 'tmp' with 'map'. 6258 map.swap(tmp); 6259 ANNOTATE_HAPPENS_BEFORE(&map); 6260 // tmp (which is the old version of map) is destroyed here. 6261} 6262 6263void Worker() { 6264 MutexLock lock(&mu); 6265 ANNOTATE_HAPPENS_AFTER(&map); 6266 map[1]++; 6267 ANNOTATE_HAPPENS_BEFORE(&map); 6268} 6269 6270void Run() { 6271 printf("test134: negative (swap)\n"); 6272 // ********************** Shorter way: *********************** 6273 // ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(&mu); 6274 MyThreadArray t(Worker, Worker, Swapper, Worker, Worker); 6275 t.Start(); 6276 t.Join(); 6277} 6278REGISTER_TEST(Run, 134) 6279} // namespace test134 6280 6281// test135 TN. Swap. Variant of test79. {{{1 6282namespace test135 { 6283 6284void SubWorker() { 6285 const long SIZE = 65536; 6286 for (int i = 0; i < 32; i++) { 6287 int *ptr = (int*)mmap(NULL, SIZE, PROT_READ | PROT_WRITE, 6288 MAP_PRIVATE | MAP_ANON, -1, 0); 6289 *ptr = 42; 6290 munmap(ptr, SIZE); 6291 } 6292} 6293 6294void Worker() { 6295 MyThreadArray t(SubWorker, SubWorker, SubWorker, SubWorker); 6296 t.Start(); 6297 t.Join(); 6298} 6299 6300void Run() { 6301 printf("test135: negative (mmap)\n"); 6302 MyThreadArray t(Worker, Worker, Worker, Worker); 6303 t.Start(); 6304 t.Join(); 6305} 6306REGISTER_TEST(Run, 135) 6307} // namespace test135 6308 6309// test136. Unlock twice. {{{1 6310namespace test136 { 6311void Run() { 6312 printf("test136: unlock twice\n"); 6313 pthread_mutexattr_t attr; 6314 CHECK(0 == pthread_mutexattr_init(&attr)); 6315 CHECK(0 == pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK)); 6316 6317 pthread_mutex_t mu; 6318 CHECK(0 == pthread_mutex_init(&mu, &attr)); 6319 CHECK(0 == pthread_mutex_lock(&mu)); 6320 CHECK(0 == pthread_mutex_unlock(&mu)); 6321 int ret_unlock = pthread_mutex_unlock(&mu); // unlocking twice. 6322 int ret_destroy = pthread_mutex_destroy(&mu); 6323 printf(" pthread_mutex_unlock returned %d\n", ret_unlock); 6324 printf(" pthread_mutex_destroy returned %d\n", ret_destroy); 6325 6326} 6327 6328REGISTER_TEST(Run, 136) 6329} // namespace test136 6330 6331// test137 TP. Races on stack variables. {{{1 6332namespace test137 { 6333int GLOB = 0; 6334ProducerConsumerQueue q(10); 6335 6336void Worker() { 6337 int stack; 6338 int *tmp = (int*)q.Get(); 6339 (*tmp)++; 6340 int *racey = &stack; 6341 q.Put(racey); 6342 (*racey)++; 6343 usleep(150000); 6344 // We may miss the races if we sleep less due to die_memory events... 6345} 6346 6347void Run() { 6348 int tmp = 0; 6349 printf("test137: TP. Races on stack variables.\n"); 6350 q.Put(&tmp); 6351 MyThreadArray t(Worker, Worker, Worker, Worker); 6352 t.Start(); 6353 t.Join(); 6354 q.Get(); 6355} 6356 6357REGISTER_TEST2(Run, 137, FEATURE | EXCLUDE_FROM_ALL) 6358} // namespace test137 6359 6360// test138 FN. Two closures hit the same thread in ThreadPool. {{{1 6361namespace test138 { 6362int GLOB = 0; 6363 6364void Worker() { 6365 usleep(100000); 6366 GLOB++; 6367} 6368 6369void Run() { 6370 FAST_MODE_INIT(&GLOB); 6371 printf("test138: FN. Two closures hit the same thread in ThreadPool.\n"); 6372 6373 // When using thread pools, two concurrent callbacks might be scheduled 6374 // onto the same executor thread. As a result, unnecessary happens-before 6375 // relation may be introduced between callbacks. 6376 // If we set the number of executor threads to 1, any known data 6377 // race detector will be silent. However, the same situation may happen 6378 // with any number of executor threads (with some probability). 6379 ThreadPool tp(1); 6380 tp.StartWorkers(); 6381 tp.Add(NewCallback(Worker)); 6382 tp.Add(NewCallback(Worker)); 6383} 6384 6385REGISTER_TEST2(Run, 138, FEATURE) 6386} // namespace test138 6387 6388// test139: FN. A true race hidden by reference counting annotation. {{{1 6389namespace test139 { 6390int GLOB = 0; 6391RefCountedClass *obj; 6392 6393void Worker1() { 6394 GLOB++; // First access. 6395 obj->Unref(); 6396} 6397 6398void Worker2() { 6399 usleep(100000); 6400 obj->Unref(); 6401 GLOB++; // Second access. 6402} 6403 6404void Run() { 6405 FAST_MODE_INIT(&GLOB); 6406 printf("test139: FN. A true race hidden by reference counting annotation.\n"); 6407 6408 obj = new RefCountedClass; 6409 obj->AnnotateUnref(); 6410 obj->Ref(); 6411 obj->Ref(); 6412 MyThreadArray mt(Worker1, Worker2); 6413 mt.Start(); 6414 mt.Join(); 6415} 6416 6417REGISTER_TEST2(Run, 139, FEATURE) 6418} // namespace test139 6419 6420// test140 TN. Swap. Variant of test79 and test134. {{{1 6421namespace test140 { 6422#if 0 6423typedef __gnu_cxx::hash_map<int, int> Container; 6424#else 6425typedef std::map<int,int> Container; 6426#endif 6427Mutex mu; 6428static Container container; 6429 6430// Here we use swap to pass a Container between threads. 6431// The synchronization is correct, but w/o the annotation 6432// any hybrid detector will complain. 6433// 6434// Unlike the test134, we try to have a minimal set of annotations 6435// so that extra h-b arcs do not hide other races. 6436 6437// Swap is very unfriendly to the lock-set (and hybrid) race detectors. 6438// Since tmp is destructed outside the mutex, we need to have a happens-before 6439// arc between any prior access to map and here. 6440// Since the internals of tmp are created ouside the mutex and are passed to 6441// other thread, we need to have a h-b arc between here and any future access. 6442// 6443// We want to be able to annotate swapper so that we don't need to annotate 6444// anything else. 6445void Swapper() { 6446 Container tmp; 6447 tmp[1] = tmp[2] = tmp[3] = 0; 6448 { 6449 MutexLock lock(&mu); 6450 container.swap(tmp); 6451 // we are unpublishing the old container. 6452 ANNOTATE_UNPUBLISH_MEMORY_RANGE(&container, sizeof(container)); 6453 // we are publishing the new container. 6454 ANNOTATE_PUBLISH_MEMORY_RANGE(&container, sizeof(container)); 6455 } 6456 tmp[1]++; 6457 tmp[2]++; 6458 // tmp (which is the old version of container) is destroyed here. 6459} 6460 6461void Worker() { 6462 MutexLock lock(&mu); 6463 container[1]++; 6464 int *v = &container[2]; 6465 for (int i = 0; i < 10; i++) { 6466 // if uncommented, this will break ANNOTATE_UNPUBLISH_MEMORY_RANGE(): 6467 // ANNOTATE_HAPPENS_BEFORE(v); 6468 if (i % 3) { 6469 (*v)++; 6470 } 6471 } 6472} 6473 6474void Run() { 6475 printf("test140: negative (swap) %p\n", &container); 6476 MyThreadArray t(Worker, Worker, Swapper, Worker, Worker); 6477 t.Start(); 6478 t.Join(); 6479} 6480REGISTER_TEST(Run, 140) 6481} // namespace test140 6482 6483// test141 FP. unlink/fopen, rmdir/opendir. {{{1 6484namespace test141 { 6485int GLOB1 = 0, 6486 GLOB2 = 0; 6487char *dir_name = NULL, 6488 *filename = NULL; 6489 6490void Waker1() { 6491 usleep(100000); 6492 GLOB1 = 1; // Write 6493 // unlink deletes a file 'filename' 6494 // which exits spin-loop in Waiter1(). 6495 printf(" Deleting file...\n"); 6496 CHECK(unlink(filename) == 0); 6497} 6498 6499void Waiter1() { 6500 FILE *tmp; 6501 while ((tmp = fopen(filename, "r")) != NULL) { 6502 fclose(tmp); 6503 usleep(10000); 6504 } 6505 printf(" ...file has been deleted\n"); 6506 GLOB1 = 2; // Write 6507} 6508 6509void Waker2() { 6510 usleep(100000); 6511 GLOB2 = 1; // Write 6512 // rmdir deletes a directory 'dir_name' 6513 // which exit spin-loop in Waker(). 6514 printf(" Deleting directory...\n"); 6515 CHECK(rmdir(dir_name) == 0); 6516} 6517 6518void Waiter2() { 6519 DIR *tmp; 6520 while ((tmp = opendir(dir_name)) != NULL) { 6521 closedir(tmp); 6522 usleep(10000); 6523 } 6524 printf(" ...directory has been deleted\n"); 6525 GLOB2 = 2; 6526} 6527 6528void Run() { 6529 FAST_MODE_INIT(&GLOB1); 6530 FAST_MODE_INIT(&GLOB2); 6531 printf("test141: FP. unlink/fopen, rmdir/opendir.\n"); 6532 6533 dir_name = strdup("/tmp/tsan-XXXXXX"); 6534 mkdtemp(dir_name); 6535 6536 filename = strdup((std::string() + dir_name + "/XXXXXX").c_str()); 6537 const int fd = mkstemp(filename); 6538 CHECK(fd >= 0); 6539 close(fd); 6540 6541 MyThreadArray mta1(Waker1, Waiter1); 6542 mta1.Start(); 6543 mta1.Join(); 6544 6545 MyThreadArray mta2(Waker2, Waiter2); 6546 mta2.Start(); 6547 mta2.Join(); 6548 free(filename); 6549 filename = 0; 6550 free(dir_name); 6551 dir_name = 0; 6552} 6553REGISTER_TEST(Run, 141) 6554} // namespace test141 6555 6556 6557// Simple FIFO queue annotated with PCQ annotations. {{{1 6558class FifoMessageQueue { 6559 public: 6560 FifoMessageQueue() { ANNOTATE_PCQ_CREATE(this); } 6561 ~FifoMessageQueue() { ANNOTATE_PCQ_DESTROY(this); } 6562 // Send a message. 'message' should be positive. 6563 void Put(int message) { 6564 CHECK(message); 6565 MutexLock lock(&mu_); 6566 ANNOTATE_PCQ_PUT(this); 6567 q_.push(message); 6568 } 6569 // Return the message from the queue and pop it 6570 // or return 0 if there are no messages. 6571 int Get() { 6572 MutexLock lock(&mu_); 6573 if (q_.empty()) return 0; 6574 int res = q_.front(); 6575 q_.pop(); 6576 ANNOTATE_PCQ_GET(this); 6577 return res; 6578 } 6579 private: 6580 Mutex mu_; 6581 queue<int> q_; 6582}; 6583 6584 6585// test142: TN. Check PCQ_* annotations. {{{1 6586namespace test142 { 6587// Putter writes to array[i] and sends a message 'i'. 6588// Getters receive messages and read array[message]. 6589// PCQ_* annotations calm down the hybrid detectors. 6590 6591const int N = 1000; 6592int array[N+1]; 6593 6594FifoMessageQueue q; 6595 6596void Putter() { 6597 for (int i = 1; i <= N; i++) { 6598 array[i] = i*i; 6599 q.Put(i); 6600 usleep(1000); 6601 } 6602} 6603 6604void Getter() { 6605 int non_zero_received = 0; 6606 for (int i = 1; i <= N; i++) { 6607 int res = q.Get(); 6608 if (res > 0) { 6609 CHECK(array[res] = res * res); 6610 non_zero_received++; 6611 } 6612 usleep(1000); 6613 } 6614 printf("T=%d: non_zero_received=%d\n", 6615 (int)pthread_self(), non_zero_received); 6616} 6617 6618void Run() { 6619 printf("test142: tests PCQ annotations\n"); 6620 MyThreadArray t(Putter, Getter, Getter); 6621 t.Start(); 6622 t.Join(); 6623} 6624REGISTER_TEST(Run, 142) 6625} // namespace test142 6626 6627 6628// test143: TP. Check PCQ_* annotations. {{{1 6629namespace test143 { 6630// True positive. 6631// We have a race on GLOB between Putter and one of the Getters. 6632// Pure h-b will not see it. 6633// If FifoMessageQueue was annotated using HAPPENS_BEFORE/AFTER, the race would 6634// be missed too. 6635// PCQ_* annotations do not hide this race. 6636int GLOB = 0; 6637 6638FifoMessageQueue q; 6639 6640void Putter() { 6641 GLOB = 1; 6642 q.Put(1); 6643} 6644 6645void Getter() { 6646 usleep(10000); 6647 q.Get(); 6648 CHECK(GLOB == 1); // Race here 6649} 6650 6651void Run() { 6652 q.Put(1); 6653 if (!Tsan_PureHappensBefore()) { 6654 ANNOTATE_EXPECT_RACE_FOR_TSAN(&GLOB, "true races"); 6655 } 6656 printf("test143: tests PCQ annotations (true positive)\n"); 6657 MyThreadArray t(Putter, Getter, Getter); 6658 t.Start(); 6659 t.Join(); 6660} 6661REGISTER_TEST(Run, 143); 6662} // namespace test143 6663 6664 6665 6666 6667// test300: {{{1 6668namespace test300 { 6669int GLOB = 0; 6670void Run() { 6671} 6672REGISTER_TEST2(Run, 300, RACE_DEMO) 6673} // namespace test300 6674 6675// test301: Simple race. {{{1 6676namespace test301 { 6677Mutex mu1; // This Mutex guards var. 6678Mutex mu2; // This Mutex is not related to var. 6679int var; // GUARDED_BY(mu1) 6680 6681void Thread1() { // Runs in thread named 'test-thread-1'. 6682 MutexLock lock(&mu1); // Correct Mutex. 6683 var = 1; 6684} 6685 6686void Thread2() { // Runs in thread named 'test-thread-2'. 6687 MutexLock lock(&mu2); // Wrong Mutex. 6688 var = 2; 6689} 6690 6691void Run() { 6692 var = 0; 6693 printf("test301: simple race.\n"); 6694 MyThread t1(Thread1, NULL, "test-thread-1"); 6695 MyThread t2(Thread2, NULL, "test-thread-2"); 6696 t1.Start(); 6697 t2.Start(); 6698 t1.Join(); 6699 t2.Join(); 6700} 6701REGISTER_TEST2(Run, 301, RACE_DEMO) 6702} // namespace test301 6703 6704// test302: Complex race which happens at least twice. {{{1 6705namespace test302 { 6706// In this test we have many different accesses to GLOB and only one access 6707// is not synchronized properly. 6708int GLOB = 0; 6709 6710Mutex MU1; 6711Mutex MU2; 6712void Worker() { 6713 for(int i = 0; i < 100; i++) { 6714 switch(i % 4) { 6715 case 0: 6716 // This read is protected correctly. 6717 MU1.Lock(); CHECK(GLOB >= 0); MU1.Unlock(); 6718 break; 6719 case 1: 6720 // Here we used the wrong lock! The reason of the race is here. 6721 MU2.Lock(); CHECK(GLOB >= 0); MU2.Unlock(); 6722 break; 6723 case 2: 6724 // This read is protected correctly. 6725 MU1.Lock(); CHECK(GLOB >= 0); MU1.Unlock(); 6726 break; 6727 case 3: 6728 // This write is protected correctly. 6729 MU1.Lock(); GLOB++; MU1.Unlock(); 6730 break; 6731 } 6732 // sleep a bit so that the threads interleave 6733 // and the race happens at least twice. 6734 usleep(100); 6735 } 6736} 6737 6738void Run() { 6739 printf("test302: Complex race that happens twice.\n"); 6740 MyThread t1(Worker), t2(Worker); 6741 t1.Start(); 6742 t2.Start(); 6743 t1.Join(); t2.Join(); 6744} 6745REGISTER_TEST2(Run, 302, RACE_DEMO) 6746} // namespace test302 6747 6748 6749// test303: Need to trace the memory to understand the report. {{{1 6750namespace test303 { 6751int GLOB = 0; 6752 6753Mutex MU; 6754void Worker1() { CHECK(GLOB >= 0); } 6755void Worker2() { MU.Lock(); GLOB=1; MU.Unlock();} 6756 6757void Run() { 6758 printf("test303: a race that needs annotations.\n"); 6759 ANNOTATE_TRACE_MEMORY(&GLOB); 6760 MyThreadArray t(Worker1, Worker2); 6761 t.Start(); 6762 t.Join(); 6763} 6764REGISTER_TEST2(Run, 303, RACE_DEMO) 6765} // namespace test303 6766 6767 6768 6769// test304: Can not trace the memory, since it is a library object. {{{1 6770namespace test304 { 6771string *STR; 6772Mutex MU; 6773 6774void Worker1() { 6775 sleep(0); 6776 ANNOTATE_CONDVAR_SIGNAL((void*)0xDEADBEAF); 6777 MU.Lock(); CHECK(STR->length() >= 4); MU.Unlock(); 6778} 6779void Worker2() { 6780 sleep(1); 6781 ANNOTATE_CONDVAR_SIGNAL((void*)0xDEADBEAF); 6782 CHECK(STR->length() >= 4); // Unprotected! 6783} 6784void Worker3() { 6785 sleep(2); 6786 ANNOTATE_CONDVAR_SIGNAL((void*)0xDEADBEAF); 6787 MU.Lock(); CHECK(STR->length() >= 4); MU.Unlock(); 6788} 6789void Worker4() { 6790 sleep(3); 6791 ANNOTATE_CONDVAR_SIGNAL((void*)0xDEADBEAF); 6792 MU.Lock(); *STR += " + a very very long string"; MU.Unlock(); 6793} 6794 6795void Run() { 6796 STR = new string ("The String"); 6797 printf("test304: a race where memory tracing does not work.\n"); 6798 MyThreadArray t(Worker1, Worker2, Worker3, Worker4); 6799 t.Start(); 6800 t.Join(); 6801 6802 printf("%s\n", STR->c_str()); 6803 delete STR; 6804} 6805REGISTER_TEST2(Run, 304, RACE_DEMO) 6806} // namespace test304 6807 6808 6809 6810// test305: A bit more tricky: two locks used inconsistenly. {{{1 6811namespace test305 { 6812int GLOB = 0; 6813 6814// In this test GLOB is protected by MU1 and MU2, but inconsistently. 6815// The TRACES observed by helgrind are: 6816// TRACE[1]: Access{T2/S2 wr} -> new State{Mod; #LS=2; #SS=1; T2/S2} 6817// TRACE[2]: Access{T4/S9 wr} -> new State{Mod; #LS=1; #SS=2; T2/S2, T4/S9} 6818// TRACE[3]: Access{T5/S13 wr} -> new State{Mod; #LS=1; #SS=3; T2/S2, T4/S9, T5/S13} 6819// TRACE[4]: Access{T6/S19 wr} -> new State{Mod; #LS=0; #SS=4; T2/S2, T4/S9, T5/S13, T6/S19} 6820// 6821// The guilty access is either Worker2() or Worker4(), depending on 6822// which mutex is supposed to protect GLOB. 6823Mutex MU1; 6824Mutex MU2; 6825void Worker1() { MU1.Lock(); MU2.Lock(); GLOB=1; MU2.Unlock(); MU1.Unlock(); } 6826void Worker2() { MU1.Lock(); GLOB=2; MU1.Unlock(); } 6827void Worker3() { MU1.Lock(); MU2.Lock(); GLOB=3; MU2.Unlock(); MU1.Unlock(); } 6828void Worker4() { MU2.Lock(); GLOB=4; MU2.Unlock(); } 6829 6830void Run() { 6831 ANNOTATE_TRACE_MEMORY(&GLOB); 6832 printf("test305: simple race.\n"); 6833 MyThread t1(Worker1), t2(Worker2), t3(Worker3), t4(Worker4); 6834 t1.Start(); usleep(100); 6835 t2.Start(); usleep(100); 6836 t3.Start(); usleep(100); 6837 t4.Start(); usleep(100); 6838 t1.Join(); t2.Join(); t3.Join(); t4.Join(); 6839} 6840REGISTER_TEST2(Run, 305, RACE_DEMO) 6841} // namespace test305 6842 6843// test306: Two locks are used to protect a var. {{{1 6844namespace test306 { 6845int GLOB = 0; 6846// Thread1 and Thread2 access the var under two locks. 6847// Thread3 uses no locks. 6848 6849Mutex MU1; 6850Mutex MU2; 6851void Worker1() { MU1.Lock(); MU2.Lock(); GLOB=1; MU2.Unlock(); MU1.Unlock(); } 6852void Worker2() { MU1.Lock(); MU2.Lock(); GLOB=3; MU2.Unlock(); MU1.Unlock(); } 6853void Worker3() { GLOB=4; } 6854 6855void Run() { 6856 ANNOTATE_TRACE_MEMORY(&GLOB); 6857 printf("test306: simple race.\n"); 6858 MyThread t1(Worker1), t2(Worker2), t3(Worker3); 6859 t1.Start(); usleep(100); 6860 t2.Start(); usleep(100); 6861 t3.Start(); usleep(100); 6862 t1.Join(); t2.Join(); t3.Join(); 6863} 6864REGISTER_TEST2(Run, 306, RACE_DEMO) 6865} // namespace test306 6866 6867// test307: Simple race, code with control flow {{{1 6868namespace test307 { 6869int *GLOB = 0; 6870volatile /*to fake the compiler*/ bool some_condition = true; 6871 6872 6873void SomeFunc() { } 6874 6875int FunctionWithControlFlow() { 6876 int unrelated_stuff = 0; 6877 unrelated_stuff++; 6878 SomeFunc(); // "--keep-history=1" will point somewhere here. 6879 if (some_condition) { // Or here 6880 if (some_condition) { 6881 unrelated_stuff++; // Or here. 6882 unrelated_stuff++; 6883 (*GLOB)++; // "--keep-history=2" will point here (experimental). 6884 } 6885 } 6886 usleep(100000); 6887 return unrelated_stuff; 6888} 6889 6890void Worker1() { FunctionWithControlFlow(); } 6891void Worker2() { Worker1(); } 6892void Worker3() { Worker2(); } 6893void Worker4() { Worker3(); } 6894 6895void Run() { 6896 GLOB = new int; 6897 *GLOB = 1; 6898 printf("test307: simple race, code with control flow\n"); 6899 MyThreadArray t1(Worker1, Worker2, Worker3, Worker4); 6900 t1.Start(); 6901 t1.Join(); 6902} 6903REGISTER_TEST2(Run, 307, RACE_DEMO) 6904} // namespace test307 6905 6906// test308: Example of double-checked-locking {{{1 6907namespace test308 { 6908struct Foo { 6909 int a; 6910}; 6911 6912static int is_inited = 0; 6913static Mutex lock; 6914static Foo *foo; 6915 6916void InitMe() { 6917 if (!is_inited) { 6918 lock.Lock(); 6919 if (!is_inited) { 6920 foo = new Foo; 6921 foo->a = 42; 6922 is_inited = 1; 6923 } 6924 lock.Unlock(); 6925 } 6926} 6927 6928void UseMe() { 6929 InitMe(); 6930 CHECK(foo && foo->a == 42); 6931} 6932 6933void Worker1() { UseMe(); } 6934void Worker2() { UseMe(); } 6935void Worker3() { UseMe(); } 6936 6937 6938void Run() { 6939 ANNOTATE_TRACE_MEMORY(&is_inited); 6940 printf("test308: Example of double-checked-locking\n"); 6941 MyThreadArray t1(Worker1, Worker2, Worker3); 6942 t1.Start(); 6943 t1.Join(); 6944} 6945REGISTER_TEST2(Run, 308, RACE_DEMO) 6946} // namespace test308 6947 6948// test309: Simple race on an STL object. {{{1 6949namespace test309 { 6950string GLOB; 6951 6952void Worker1() { 6953 GLOB="Thread1"; 6954} 6955void Worker2() { 6956 usleep(100000); 6957 GLOB="Booooooooooo"; 6958} 6959 6960void Run() { 6961 printf("test309: simple race on an STL object.\n"); 6962 MyThread t1(Worker1), t2(Worker2); 6963 t1.Start(); 6964 t2.Start(); 6965 t1.Join(); t2.Join(); 6966} 6967REGISTER_TEST2(Run, 309, RACE_DEMO) 6968} // namespace test309 6969 6970// test310: One more simple race. {{{1 6971namespace test310 { 6972int *PTR = NULL; // GUARDED_BY(mu1) 6973 6974Mutex mu1; // Protects PTR. 6975Mutex mu2; // Unrelated to PTR. 6976Mutex mu3; // Unrelated to PTR. 6977 6978void Writer1() { 6979 MutexLock lock3(&mu3); // This lock is unrelated to PTR. 6980 MutexLock lock1(&mu1); // Protect PTR. 6981 *PTR = 1; 6982} 6983 6984void Writer2() { 6985 MutexLock lock2(&mu2); // This lock is unrelated to PTR. 6986 MutexLock lock1(&mu1); // Protect PTR. 6987 int some_unrelated_stuff = 0; 6988 if (some_unrelated_stuff == 0) 6989 some_unrelated_stuff++; 6990 *PTR = 2; 6991} 6992 6993 6994void Reader() { 6995 MutexLock lock2(&mu2); // Oh, gosh, this is a wrong mutex! 6996 CHECK(*PTR <= 2); 6997} 6998 6999// Some functions to make the stack trace non-trivial. 7000void DoWrite1() { Writer1(); } 7001void Thread1() { DoWrite1(); } 7002 7003void DoWrite2() { Writer2(); } 7004void Thread2() { DoWrite2(); } 7005 7006void DoRead() { Reader(); } 7007void Thread3() { DoRead(); } 7008 7009void Run() { 7010 printf("test310: simple race.\n"); 7011 PTR = new int; 7012 ANNOTATE_TRACE_MEMORY(PTR); 7013 *PTR = 0; 7014 MyThread t1(Thread1, NULL, "writer1"), 7015 t2(Thread2, NULL, "writer2"), 7016 t3(Thread3, NULL, "buggy reader"); 7017 t1.Start(); 7018 t2.Start(); 7019 usleep(100000); // Let the writers go first. 7020 t3.Start(); 7021 7022 t1.Join(); 7023 t2.Join(); 7024 t3.Join(); 7025} 7026REGISTER_TEST2(Run, 310, RACE_DEMO) 7027} // namespace test310 7028 7029// test311: Yet another simple race. {{{1 7030namespace test311 { 7031int *PTR = NULL; // GUARDED_BY(mu1) 7032 7033Mutex mu1; // Protects PTR. 7034Mutex mu2; // Unrelated to PTR. 7035Mutex mu3; // Unrelated to PTR. 7036 7037void GoodWriter1() { 7038 MutexLock lock3(&mu3); // This lock is unrelated to PTR. 7039 MutexLock lock1(&mu1); // Protect PTR. 7040 *PTR = 1; 7041} 7042 7043void GoodWriter2() { 7044 MutexLock lock2(&mu2); // This lock is unrelated to PTR. 7045 MutexLock lock1(&mu1); // Protect PTR. 7046 *PTR = 2; 7047} 7048 7049void GoodReader() { 7050 MutexLock lock1(&mu1); // Protect PTR. 7051 CHECK(*PTR >= 0); 7052} 7053 7054void BuggyWriter() { 7055 MutexLock lock2(&mu2); // Wrong mutex! 7056 *PTR = 3; 7057} 7058 7059// Some functions to make the stack trace non-trivial. 7060void DoWrite1() { GoodWriter1(); } 7061void Thread1() { DoWrite1(); } 7062 7063void DoWrite2() { GoodWriter2(); } 7064void Thread2() { DoWrite2(); } 7065 7066void DoGoodRead() { GoodReader(); } 7067void Thread3() { DoGoodRead(); } 7068 7069void DoBadWrite() { BuggyWriter(); } 7070void Thread4() { DoBadWrite(); } 7071 7072void Run() { 7073 printf("test311: simple race.\n"); 7074 PTR = new int; 7075 ANNOTATE_TRACE_MEMORY(PTR); 7076 *PTR = 0; 7077 MyThread t1(Thread1, NULL, "good writer1"), 7078 t2(Thread2, NULL, "good writer2"), 7079 t3(Thread3, NULL, "good reader"), 7080 t4(Thread4, NULL, "buggy writer"); 7081 t1.Start(); 7082 t3.Start(); 7083 // t2 goes after t3. This way a pure happens-before detector has no chance. 7084 usleep(10000); 7085 t2.Start(); 7086 usleep(100000); // Let the good folks go first. 7087 t4.Start(); 7088 7089 t1.Join(); 7090 t2.Join(); 7091 t3.Join(); 7092 t4.Join(); 7093} 7094REGISTER_TEST2(Run, 311, RACE_DEMO) 7095} // namespace test311 7096 7097// test312: A test with a very deep stack. {{{1 7098namespace test312 { 7099int GLOB = 0; 7100void RaceyWrite() { GLOB++; } 7101void Func1() { RaceyWrite(); } 7102void Func2() { Func1(); } 7103void Func3() { Func2(); } 7104void Func4() { Func3(); } 7105void Func5() { Func4(); } 7106void Func6() { Func5(); } 7107void Func7() { Func6(); } 7108void Func8() { Func7(); } 7109void Func9() { Func8(); } 7110void Func10() { Func9(); } 7111void Func11() { Func10(); } 7112void Func12() { Func11(); } 7113void Func13() { Func12(); } 7114void Func14() { Func13(); } 7115void Func15() { Func14(); } 7116void Func16() { Func15(); } 7117void Func17() { Func16(); } 7118void Func18() { Func17(); } 7119void Func19() { Func18(); } 7120void Worker() { Func19(); } 7121void Run() { 7122 printf("test312: simple race with deep stack.\n"); 7123 MyThreadArray t(Worker, Worker, Worker); 7124 t.Start(); 7125 t.Join(); 7126} 7127REGISTER_TEST2(Run, 312, RACE_DEMO) 7128} // namespace test312 7129 7130// test313 TP: test for thread graph output {{{1 7131namespace test313 { 7132BlockingCounter *blocking_counter; 7133int GLOB = 0; 7134 7135// Worker(N) will do 2^N increments of GLOB, each increment in a separate thread 7136void Worker(int depth) { 7137 CHECK(depth >= 0); 7138 if (depth > 0) { 7139 ThreadPool pool(2); 7140 pool.StartWorkers(); 7141 pool.Add(NewCallback(Worker, depth-1)); 7142 pool.Add(NewCallback(Worker, depth-1)); 7143 } else { 7144 GLOB++; // Race here 7145 } 7146} 7147void Run() { 7148 printf("test313: positive\n"); 7149 Worker(4); 7150 printf("\tGLOB=%d\n", GLOB); 7151} 7152REGISTER_TEST2(Run, 313, RACE_DEMO) 7153} // namespace test313 7154 7155 7156 7157// test400: Demo of a simple false positive. {{{1 7158namespace test400 { 7159static Mutex mu; 7160static vector<int> *vec; // GUARDED_BY(mu); 7161 7162void InitAllBeforeStartingThreads() { 7163 vec = new vector<int>; 7164 vec->push_back(1); 7165 vec->push_back(2); 7166} 7167 7168void Thread1() { 7169 MutexLock lock(&mu); 7170 vec->pop_back(); 7171} 7172 7173void Thread2() { 7174 MutexLock lock(&mu); 7175 vec->pop_back(); 7176} 7177 7178//---- Sub-optimal code --------- 7179size_t NumberOfElementsLeft() { 7180 MutexLock lock(&mu); 7181 return vec->size(); 7182} 7183 7184void WaitForAllThreadsToFinish_InefficientAndTsanUnfriendly() { 7185 while(NumberOfElementsLeft()) { 7186 ; // sleep or print or do nothing. 7187 } 7188 // It is now safe to access vec w/o lock. 7189 // But a hybrid detector (like ThreadSanitizer) can't see it. 7190 // Solutions: 7191 // 1. Use pure happens-before detector (e.g. "tsan --pure-happens-before") 7192 // 2. Call ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(&mu) 7193 // in InitAllBeforeStartingThreads() 7194 // 3. (preferred) Use WaitForAllThreadsToFinish_Good() (see below). 7195 CHECK(vec->empty()); 7196 delete vec; 7197} 7198 7199//----- Better code ----------- 7200 7201bool NoElementsLeft(vector<int> *v) { 7202 return v->empty(); 7203} 7204 7205void WaitForAllThreadsToFinish_Good() { 7206 mu.LockWhen(Condition(NoElementsLeft, vec)); 7207 mu.Unlock(); 7208 7209 // It is now safe to access vec w/o lock. 7210 CHECK(vec->empty()); 7211 delete vec; 7212} 7213 7214 7215void Run() { 7216 MyThreadArray t(Thread1, Thread2); 7217 InitAllBeforeStartingThreads(); 7218 t.Start(); 7219 WaitForAllThreadsToFinish_InefficientAndTsanUnfriendly(); 7220// WaitForAllThreadsToFinish_Good(); 7221 t.Join(); 7222} 7223REGISTER_TEST2(Run, 400, RACE_DEMO) 7224} // namespace test400 7225 7226// test401: Demo of false positive caused by reference counting. {{{1 7227namespace test401 { 7228// A simplified example of reference counting. 7229// DecRef() does ref count increment in a way unfriendly to race detectors. 7230// DecRefAnnotated() does the same in a friendly way. 7231 7232static vector<int> *vec; 7233static int ref_count; 7234 7235void InitAllBeforeStartingThreads(int number_of_threads) { 7236 vec = new vector<int>; 7237 vec->push_back(1); 7238 ref_count = number_of_threads; 7239} 7240 7241// Correct, but unfriendly to race detectors. 7242int DecRef() { 7243 return AtomicIncrement(&ref_count, -1); 7244} 7245 7246// Correct and friendly to race detectors. 7247int DecRefAnnotated() { 7248 ANNOTATE_CONDVAR_SIGNAL(&ref_count); 7249 int res = AtomicIncrement(&ref_count, -1); 7250 if (res == 0) { 7251 ANNOTATE_CONDVAR_WAIT(&ref_count); 7252 } 7253 return res; 7254} 7255 7256void ThreadWorker() { 7257 CHECK(ref_count > 0); 7258 CHECK(vec->size() == 1); 7259 if (DecRef() == 0) { // Use DecRefAnnotated() instead! 7260 // No one uses vec now ==> delete it. 7261 delete vec; // A false race may be reported here. 7262 vec = NULL; 7263 } 7264} 7265 7266void Run() { 7267 MyThreadArray t(ThreadWorker, ThreadWorker, ThreadWorker); 7268 InitAllBeforeStartingThreads(3 /*number of threads*/); 7269 t.Start(); 7270 t.Join(); 7271 CHECK(vec == 0); 7272} 7273REGISTER_TEST2(Run, 401, RACE_DEMO) 7274} // namespace test401 7275 7276// test501: Manually call PRINT_* annotations {{{1 7277namespace test501 { 7278int COUNTER = 0; 7279int GLOB = 0; 7280Mutex muCounter, muGlob[65]; 7281 7282void Worker() { 7283 muCounter.Lock(); 7284 int myId = ++COUNTER; 7285 muCounter.Unlock(); 7286 7287 usleep(100); 7288 7289 muGlob[myId].Lock(); 7290 muGlob[0].Lock(); 7291 GLOB++; 7292 muGlob[0].Unlock(); 7293 muGlob[myId].Unlock(); 7294} 7295 7296void Worker_1() { 7297 MyThreadArray ta (Worker, Worker, Worker, Worker); 7298 ta.Start(); 7299 usleep(500000); 7300 ta.Join (); 7301} 7302 7303void Worker_2() { 7304 MyThreadArray ta (Worker_1, Worker_1, Worker_1, Worker_1); 7305 ta.Start(); 7306 usleep(300000); 7307 ta.Join (); 7308} 7309 7310void Run() { 7311 ANNOTATE_RESET_STATS(); 7312 printf("test501: Manually call PRINT_* annotations.\n"); 7313 MyThreadArray ta (Worker_2, Worker_2, Worker_2, Worker_2); 7314 ta.Start(); 7315 usleep(100000); 7316 ta.Join (); 7317 ANNOTATE_PRINT_MEMORY_USAGE(0); 7318 ANNOTATE_PRINT_STATS(); 7319} 7320 7321REGISTER_TEST2(Run, 501, FEATURE | EXCLUDE_FROM_ALL) 7322} // namespace test501 7323 7324// test502: produce lots of segments without cross-thread relations {{{1 7325namespace test502 { 7326 7327/* 7328 * This test produces ~1Gb of memory usage when run with the following options: 7329 * 7330 * --tool=helgrind 7331 * --trace-after-race=0 7332 * --num-callers=2 7333 * --more-context=no 7334 */ 7335 7336Mutex MU; 7337int GLOB = 0; 7338 7339void TP() { 7340 for (int i = 0; i < 750000; i++) { 7341 MU.Lock(); 7342 GLOB++; 7343 MU.Unlock(); 7344 } 7345} 7346 7347void Run() { 7348 MyThreadArray t(TP, TP); 7349 printf("test502: produce lots of segments without cross-thread relations\n"); 7350 7351 t.Start(); 7352 t.Join(); 7353} 7354 7355REGISTER_TEST2(Run, 502, MEMORY_USAGE | PRINT_STATS | EXCLUDE_FROM_ALL 7356 | PERFORMANCE) 7357} // namespace test502 7358 7359// test503: produce lots of segments with simple HB-relations {{{1 7360// HB cache-miss rate is ~55% 7361namespace test503 { 7362 7363// |- | | | | | 7364// | \| | | | | 7365// | |- | | | | 7366// | | \| | | | 7367// | | |- | | | 7368// | | | \| | | 7369// | | | |- | | 7370// | | | | \| | 7371// | | | | |- | 7372// | | | | | \| 7373// | | | | | |---- 7374//->| | | | | | 7375// |- | | | | | 7376// | \| | | | | 7377// ... 7378 7379const int N_threads = 32; 7380const int ARRAY_SIZE = 128; 7381int GLOB[ARRAY_SIZE]; 7382ProducerConsumerQueue *Q[N_threads]; 7383int GLOB_limit = 100000; 7384int count = -1; 7385 7386void Worker(){ 7387 int myId = AtomicIncrement(&count, 1); 7388 7389 ProducerConsumerQueue &myQ = *Q[myId], &nextQ = *Q[(myId+1) % N_threads]; 7390 7391 // this code produces a new SS with each new segment 7392 while (myQ.Get() != NULL) { 7393 for (int i = 0; i < ARRAY_SIZE; i++) 7394 GLOB[i]++; 7395 7396 if (myId == 0 && GLOB[0] > GLOB_limit) { 7397 // Stop all threads 7398 for (int i = 0; i < N_threads; i++) 7399 Q[i]->Put(NULL); 7400 } else 7401 nextQ.Put(GLOB); 7402 } 7403} 7404 7405void Run() { 7406 printf("test503: produce lots of segments with simple HB-relations\n"); 7407 for (int i = 0; i < N_threads; i++) 7408 Q[i] = new ProducerConsumerQueue(1); 7409 Q[0]->Put(GLOB); 7410 7411 { 7412 ThreadPool pool(N_threads); 7413 pool.StartWorkers(); 7414 for (int i = 0; i < N_threads; i++) { 7415 pool.Add(NewCallback(Worker)); 7416 } 7417 } // all folks are joined here. 7418 7419 for (int i = 0; i < N_threads; i++) 7420 delete Q[i]; 7421} 7422 7423REGISTER_TEST2(Run, 503, MEMORY_USAGE | PRINT_STATS 7424 | PERFORMANCE | EXCLUDE_FROM_ALL) 7425} // namespace test503 7426 7427// test504: force massive cache fetch-wback (50% misses, mostly CacheLineZ) {{{1 7428namespace test504 { 7429 7430const int N_THREADS = 2, 7431 HG_CACHELINE_COUNT = 1 << 16, 7432 HG_CACHELINE_SIZE = 1 << 6, 7433 HG_CACHE_SIZE = HG_CACHELINE_COUNT * HG_CACHELINE_SIZE; 7434 7435// int gives us ~4x speed of the byte test 7436// 4x array size gives us 7437// total multiplier of 16x over the cachesize 7438// so we can neglect the cached-at-the-end memory 7439const int ARRAY_SIZE = 4 * HG_CACHE_SIZE, 7440 ITERATIONS = 30; 7441int array[ARRAY_SIZE]; 7442 7443int count = 0; 7444Mutex count_mu; 7445 7446void Worker() { 7447 count_mu.Lock(); 7448 int myId = ++count; 7449 count_mu.Unlock(); 7450 7451 // all threads write to different memory locations, 7452 // so no synchronization mechanisms are needed 7453 int lower_bound = ARRAY_SIZE * (myId-1) / N_THREADS, 7454 upper_bound = ARRAY_SIZE * ( myId ) / N_THREADS; 7455 for (int j = 0; j < ITERATIONS; j++) 7456 for (int i = lower_bound; i < upper_bound; 7457 i += HG_CACHELINE_SIZE / sizeof(array[0])) { 7458 array[i] = i; // each array-write generates a cache miss 7459 } 7460} 7461 7462void Run() { 7463 printf("test504: force massive CacheLineZ fetch-wback\n"); 7464 MyThreadArray t(Worker, Worker); 7465 t.Start(); 7466 t.Join(); 7467} 7468 7469REGISTER_TEST2(Run, 504, PERFORMANCE | PRINT_STATS | EXCLUDE_FROM_ALL) 7470} // namespace test504 7471 7472// test505: force massive cache fetch-wback (60% misses) {{{1 7473// modification of test504 - more threads, byte accesses and lots of mutexes 7474// so it produces lots of CacheLineF misses (30-50% of CacheLineZ misses) 7475namespace test505 { 7476 7477const int N_THREADS = 2, 7478 HG_CACHELINE_COUNT = 1 << 16, 7479 HG_CACHELINE_SIZE = 1 << 6, 7480 HG_CACHE_SIZE = HG_CACHELINE_COUNT * HG_CACHELINE_SIZE; 7481 7482const int ARRAY_SIZE = 4 * HG_CACHE_SIZE, 7483 ITERATIONS = 3; 7484int64_t array[ARRAY_SIZE]; 7485 7486int count = 0; 7487Mutex count_mu; 7488 7489void Worker() { 7490 const int N_MUTEXES = 5; 7491 Mutex mu[N_MUTEXES]; 7492 count_mu.Lock(); 7493 int myId = ++count; 7494 count_mu.Unlock(); 7495 7496 // all threads write to different memory locations, 7497 // so no synchronization mechanisms are needed 7498 int lower_bound = ARRAY_SIZE * (myId-1) / N_THREADS, 7499 upper_bound = ARRAY_SIZE * ( myId ) / N_THREADS; 7500 for (int j = 0; j < ITERATIONS; j++) 7501 for (int mutex_id = 0; mutex_id < N_MUTEXES; mutex_id++) { 7502 Mutex *m = & mu[mutex_id]; 7503 m->Lock(); 7504 for (int i = lower_bound + mutex_id, cnt = 0; 7505 i < upper_bound; 7506 i += HG_CACHELINE_SIZE / sizeof(array[0]), cnt++) { 7507 array[i] = i; // each array-write generates a cache miss 7508 } 7509 m->Unlock(); 7510 } 7511} 7512 7513void Run() { 7514 printf("test505: force massive CacheLineF fetch-wback\n"); 7515 MyThreadArray t(Worker, Worker); 7516 t.Start(); 7517 t.Join(); 7518} 7519 7520REGISTER_TEST2(Run, 505, PERFORMANCE | PRINT_STATS | EXCLUDE_FROM_ALL) 7521} // namespace test505 7522 7523// test506: massive HB's using Barriers {{{1 7524// HB cache miss is ~40% 7525// segments consume 10x more memory than SSs 7526// modification of test39 7527namespace test506 { 7528#ifndef NO_BARRIER 7529// Same as test17 but uses Barrier class (pthread_barrier_t). 7530int GLOB = 0; 7531const int N_threads = 64, 7532 ITERATIONS = 1000; 7533Barrier *barrier[ITERATIONS]; 7534Mutex MU; 7535 7536void Worker() { 7537 for (int i = 0; i < ITERATIONS; i++) { 7538 MU.Lock(); 7539 GLOB++; 7540 MU.Unlock(); 7541 barrier[i]->Block(); 7542 } 7543} 7544void Run() { 7545 printf("test506: massive HB's using Barriers\n"); 7546 for (int i = 0; i < ITERATIONS; i++) { 7547 barrier[i] = new Barrier(N_threads); 7548 } 7549 { 7550 ThreadPool pool(N_threads); 7551 pool.StartWorkers(); 7552 for (int i = 0; i < N_threads; i++) { 7553 pool.Add(NewCallback(Worker)); 7554 } 7555 } // all folks are joined here. 7556 CHECK(GLOB == N_threads * ITERATIONS); 7557 for (int i = 0; i < ITERATIONS; i++) { 7558 delete barrier[i]; 7559 } 7560} 7561REGISTER_TEST2(Run, 506, PERFORMANCE | PRINT_STATS | EXCLUDE_FROM_ALL); 7562#endif // NO_BARRIER 7563} // namespace test506 7564 7565// test507: vgHelgrind_initIterAtFM/stackClear benchmark {{{1 7566// vgHelgrind_initIterAtFM/stackClear consume ~8.5%/5.5% CPU 7567namespace test507 { 7568const int N_THREADS = 1, 7569 BUFFER_SIZE = 1, 7570 ITERATIONS = 1 << 20; 7571 7572void Foo() { 7573 struct T { 7574 char temp; 7575 T() { 7576 ANNOTATE_RWLOCK_CREATE(&temp); 7577 } 7578 ~T() { 7579 ANNOTATE_RWLOCK_DESTROY(&temp); 7580 } 7581 } s[BUFFER_SIZE]; 7582 s->temp = '\0'; 7583} 7584 7585void Worker() { 7586 for (int j = 0; j < ITERATIONS; j++) { 7587 Foo(); 7588 } 7589} 7590 7591void Run() { 7592 printf("test507: vgHelgrind_initIterAtFM/stackClear benchmark\n"); 7593 { 7594 ThreadPool pool(N_THREADS); 7595 pool.StartWorkers(); 7596 for (int i = 0; i < N_THREADS; i++) { 7597 pool.Add(NewCallback(Worker)); 7598 } 7599 } // all folks are joined here. 7600} 7601REGISTER_TEST2(Run, 507, EXCLUDE_FROM_ALL); 7602} // namespace test507 7603 7604// test508: cmp_WordVecs_for_FM benchmark {{{1 7605// 50+% of CPU consumption by cmp_WordVecs_for_FM 7606namespace test508 { 7607const int N_THREADS = 1, 7608 BUFFER_SIZE = 1 << 10, 7609 ITERATIONS = 1 << 9; 7610 7611void Foo() { 7612 struct T { 7613 char temp; 7614 T() { 7615 ANNOTATE_RWLOCK_CREATE(&temp); 7616 } 7617 ~T() { 7618 ANNOTATE_RWLOCK_DESTROY(&temp); 7619 } 7620 } s[BUFFER_SIZE]; 7621 s->temp = '\0'; 7622} 7623 7624void Worker() { 7625 for (int j = 0; j < ITERATIONS; j++) { 7626 Foo(); 7627 } 7628} 7629 7630void Run() { 7631 printf("test508: cmp_WordVecs_for_FM benchmark\n"); 7632 { 7633 ThreadPool pool(N_THREADS); 7634 pool.StartWorkers(); 7635 for (int i = 0; i < N_THREADS; i++) { 7636 pool.Add(NewCallback(Worker)); 7637 } 7638 } // all folks are joined here. 7639} 7640REGISTER_TEST2(Run, 508, EXCLUDE_FROM_ALL); 7641} // namespace test508 7642 7643// test509: avl_find_node benchmark {{{1 7644// 10+% of CPU consumption by avl_find_node 7645namespace test509 { 7646const int N_THREADS = 16, 7647 ITERATIONS = 1 << 8; 7648 7649void Worker() { 7650 std::vector<Mutex*> mu_list; 7651 for (int i = 0; i < ITERATIONS; i++) { 7652 Mutex * mu = new Mutex(); 7653 mu_list.push_back(mu); 7654 mu->Lock(); 7655 } 7656 for (int i = ITERATIONS - 1; i >= 0; i--) { 7657 Mutex * mu = mu_list[i]; 7658 mu->Unlock(); 7659 delete mu; 7660 } 7661} 7662 7663void Run() { 7664 printf("test509: avl_find_node benchmark\n"); 7665 { 7666 ThreadPool pool(N_THREADS); 7667 pool.StartWorkers(); 7668 for (int i = 0; i < N_THREADS; i++) { 7669 pool.Add(NewCallback(Worker)); 7670 } 7671 } // all folks are joined here. 7672} 7673REGISTER_TEST2(Run, 509, EXCLUDE_FROM_ALL); 7674} // namespace test509 7675 7676// test510: SS-recycle test {{{1 7677// this tests shows the case where only ~1% of SS are recycled 7678namespace test510 { 7679const int N_THREADS = 16, 7680 ITERATIONS = 1 << 10; 7681int GLOB = 0; 7682 7683void Worker() { 7684 usleep(100000); 7685 for (int i = 0; i < ITERATIONS; i++) { 7686 ANNOTATE_CONDVAR_SIGNAL((void*)0xDeadBeef); 7687 GLOB++; 7688 usleep(10); 7689 } 7690} 7691 7692void Run() { 7693 //ANNOTATE_BENIGN_RACE(&GLOB, "Test"); 7694 printf("test510: SS-recycle test\n"); 7695 { 7696 ThreadPool pool(N_THREADS); 7697 pool.StartWorkers(); 7698 for (int i = 0; i < N_THREADS; i++) { 7699 pool.Add(NewCallback(Worker)); 7700 } 7701 } // all folks are joined here. 7702} 7703REGISTER_TEST2(Run, 510, MEMORY_USAGE | PRINT_STATS | EXCLUDE_FROM_ALL); 7704} // namespace test510 7705 7706// test511: Segment refcounting test ('1' refcounting) {{{1 7707namespace test511 { 7708int GLOB = 0; 7709 7710void Run () { 7711 for (int i = 0; i < 300; i++) { 7712 ANNOTATE_CONDVAR_SIGNAL(&GLOB); 7713 usleep(1000); 7714 GLOB++; 7715 ANNOTATE_CONDVAR_WAIT(&GLOB); 7716 if (i % 100 == 0) 7717 ANNOTATE_PRINT_MEMORY_USAGE(0); 7718 } 7719} 7720REGISTER_TEST2(Run, 511, MEMORY_USAGE | PRINT_STATS | EXCLUDE_FROM_ALL); 7721} // namespace test511 7722 7723// test512: Segment refcounting test ('S' refcounting) {{{1 7724namespace test512 { 7725int GLOB = 0; 7726sem_t SEM; 7727 7728void Run () { 7729 sem_init(&SEM, 0, 0); 7730 for (int i = 0; i < 300; i++) { 7731 sem_post(&SEM); 7732 usleep(1000); 7733 GLOB++; 7734 sem_wait(&SEM); 7735 /*if (i % 100 == 0) 7736 ANNOTATE_PRINT_MEMORY_USAGE(0);*/ 7737 } 7738 sem_destroy(&SEM); 7739} 7740REGISTER_TEST2(Run, 512, MEMORY_USAGE | PRINT_STATS | EXCLUDE_FROM_ALL); 7741} // namespace test512 7742 7743// test513: --fast-mode benchmark {{{1 7744namespace test513 { 7745 7746const int N_THREADS = 2, 7747 HG_CACHELINE_SIZE = 1 << 6, 7748 ARRAY_SIZE = HG_CACHELINE_SIZE * 512, 7749 MUTEX_ID_BITS = 8, 7750 MUTEX_ID_MASK = (1 << MUTEX_ID_BITS) - 1; 7751 7752// Each thread has its own cacheline and tackles with it intensively 7753const int ITERATIONS = 1024; 7754int array[N_THREADS][ARRAY_SIZE]; 7755 7756int count = 0; 7757Mutex count_mu; 7758Mutex mutex_arr[N_THREADS][MUTEX_ID_BITS]; 7759 7760void Worker() { 7761 count_mu.Lock(); 7762 int myId = count++; 7763 count_mu.Unlock(); 7764 7765 // all threads write to different memory locations 7766 for (int j = 0; j < ITERATIONS; j++) { 7767 int mutex_mask = j & MUTEX_ID_BITS; 7768 for (int m = 0; m < MUTEX_ID_BITS; m++) 7769 if (mutex_mask & (1 << m)) 7770 mutex_arr[myId][m].Lock(); 7771 7772 for (int i = 0; i < ARRAY_SIZE; i++) { 7773 array[myId][i] = i; 7774 } 7775 7776 for (int m = 0; m < MUTEX_ID_BITS; m++) 7777 if (mutex_mask & (1 << m)) 7778 mutex_arr[myId][m].Unlock(); 7779 } 7780} 7781 7782void Run() { 7783 printf("test513: --fast-mode benchmark\n"); 7784 { 7785 ThreadPool pool(N_THREADS); 7786 pool.StartWorkers(); 7787 for (int i = 0; i < N_THREADS; i++) { 7788 pool.Add(NewCallback(Worker)); 7789 } 7790 } // all folks are joined here. 7791} 7792 7793REGISTER_TEST2(Run, 513, PERFORMANCE | PRINT_STATS | EXCLUDE_FROM_ALL) 7794} // namespace test513 7795 7796// End {{{1 7797// vim:shiftwidth=2:softtabstop=2:expandtab:foldmethod=marker 7798