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