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