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