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