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.
75 template <typename T>
IGNORE_RETURN_VALUE(T v)76 static 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
131 CondVar CV;
132 int COND = 0;
133
134
135 typedef void (*void_func_void_t)(void);
136 enum 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.
148 Mutex printf_mu;
149 #define printf(args...) \
150 do{ \
151 printf_mu.Lock();\
152 fprintf(stderr, args);\
153 printf_mu.Unlock(); \
154 }while(0)
155
GetTimeInMs()156 long GetTimeInMs() {
157 struct timeval tv;
158 gettimeofday(&tv, NULL);
159 return (tv.tv_sec * 1000L) + (tv.tv_usec / 1000L);
160 }
161
162 struct Test{
163 void_func_void_t f_;
164 int flags_;
TestTest165 Test(void_func_void_t f, int flags)
166 : f_(f)
167 , flags_(flags)
168 {}
TestTest169 Test() : f_(0), flags_(0) {}
RunTest170 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 };
185 std::map<int, Test> TheMapOfTests;
186
187 #define NOINLINE __attribute__ ((noinline))
AnnotateSetVerbosity(const char *,int,int)188 extern "C" void NOINLINE AnnotateSetVerbosity(const char *, int, int) {};
189
190
191 struct TestAdder {
TestAdderTestAdder192 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
ArgIsOne(int * arg)202 static bool ArgIsOne(int *arg) { return *arg == 1; };
ArgIsZero(int * arg)203 static bool ArgIsZero(int *arg) { return *arg == 0; };
ArgIsTrue(bool * arg)204 static 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
Tsan_PureHappensBefore()221 inline bool Tsan_PureHappensBefore() {
222 return true;
223 }
224
Tsan_FastMode()225 inline 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
main(int argc,char ** argv)238 int 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
282 class MyThreadArray {
283 public:
284 static const int kSize = 5;
285 typedef void (*F) (void);
MyThreadArray(F f1,F f2=NULL,F f3=NULL,F f4=NULL,F f5=NULL)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 }
Start()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
Join()302 void Join() {
303 for(int i = 0; i < kSize; i++) {
304 if(ar_[i]) {
305 ar_[i]->Join();
306 }
307 }
308 }
309
~MyThreadArray()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
322 namespace test00 {
323 int GLOB = 0;
Run()324 void Run() {
325 printf("test00: negative\n");
326 printf("\tGLOB=%d\n", GLOB);
327 }
328 REGISTER_TEST(Run, 00)
329 } // namespace test00
330
331
332 // test01: TP. Simple race (write vs write). {{{1
333 namespace test01 {
334 int GLOB = 0;
Worker()335 void Worker() {
336 GLOB = 1;
337 }
338
Parent()339 void 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 }
Run()347 void 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 }
356 REGISTER_TEST(Run, 1);
357 } // namespace test01
358
359
360 // test02: TN. Synchronization via CondVar. {{{1
361 namespace test02 {
362 int 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)
377 Mutex MU;
378
Waker()379 void 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
Waiter()389 void 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 }
Run()400 void Run() {
401 printf("test02: negative\n");
402 Waiter();
403 printf("\tGLOB=%d\n", GLOB);
404 }
405 REGISTER_TEST(Run, 2);
406 } // namespace test02
407
408
409 // test03: TN. Synchronization via LockWhen, signaller gets there first. {{{1
410 namespace test03 {
411 int 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)
425 Mutex MU;
426
Waker()427 void 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 }
Waiter()435 void 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 }
Run()445 void Run() {
446 printf("test03: negative\n");
447 Waiter();
448 printf("\tGLOB=%d\n", GLOB);
449 }
450 REGISTER_TEST2(Run, 3, FEATURE|NEEDS_ANNOTATIONS);
451 } // namespace test03
452
453 // test04: TN. Synchronization via PCQ. {{{1
454 namespace test04 {
455 int GLOB = 0;
456 ProducerConsumerQueue 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
Putter()466 void Putter() {
467 GLOB = 1;
468 Q.Put(NULL);
469 }
470
Getter()471 void Getter() {
472 Q.Get();
473 GLOB = 2;
474 }
475
Run()476 void Run() {
477 printf("test04: negative\n");
478 MyThreadArray t(Putter, Getter);
479 t.Start();
480 t.Join();
481 printf("\tGLOB=%d\n", GLOB);
482 }
483 REGISTER_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.
489 namespace test05 {
490 int 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)
507 Mutex MU;
508
Waker()509 void Waker() {
510 GLOB = 1;
511 MU.Lock();
512 COND = 1;
513 CV.Signal();
514 MU.Unlock();
515 }
516
Waiter()517 void 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 }
Run()529 void 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 }
537 REGISTER_TEST(Run, 5);
538 } // namespace test05
539
540
541 // test06: TN. Synchronization via CondVar, but Waker gets there first. {{{1
542 namespace test06 {
543 int 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
559 Mutex MU;
560
Waker()561 void Waker() {
562 GLOB = 1;
563 MU.Lock();
564 COND = 1;
565 CV.Signal();
566 MU.Unlock();
567 }
568
Waiter()569 void 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 }
Run()583 void Run() {
584 printf("test06: negative\n");
585 Waiter();
586 printf("\tGLOB=%d\n", GLOB);
587 }
588 REGISTER_TEST2(Run, 6, FEATURE|NEEDS_ANNOTATIONS);
589 } // namespace test06
590
591
592 // test07: TN. Synchronization via LockWhen(), Signaller is observed first. {{{1
593 namespace test07 {
594 int GLOB = 0;
595 bool 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
611 Mutex MU;
Signaller()612 void Signaller() {
613 GLOB = 1;
614 MU.Lock();
615 COND = true; // We are done! Tell the Waiter.
616 MU.Unlock(); // calls ANNOTATE_CONDVAR_SIGNAL;
617 }
Waiter()618 void 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 }
Run()630 void Run() {
631 printf("test07: negative\n");
632 Waiter();
633 printf("\tGLOB=%d\n", GLOB);
634 }
635 REGISTER_TEST2(Run, 7, FEATURE|NEEDS_ANNOTATIONS);
636 } // namespace test07
637
638 // test08: TN. Synchronization via thread start/join. {{{1
639 namespace test08 {
640 int 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)
Worker()649 void Worker() {
650 GLOB = 2;
651 }
652
Parent()653 void Parent() {
654 MyThread t(Worker);
655 GLOB = 1;
656 t.Start();
657 t.Join();
658 GLOB = 3;
659 }
Run()660 void Run() {
661 printf("test08: negative\n");
662 Parent();
663 printf("\tGLOB=%d\n", GLOB);
664 }
665 REGISTER_TEST(Run, 8);
666 } // namespace test08
667
668
669 // test09: TP. Simple race (read vs write). {{{1
670 namespace test09 {
671 int 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.
Writer()675 void Writer() {
676 usleep(100000);
677 GLOB = 3;
678 }
Reader()679 void Reader() {
680 CHECK(GLOB != -777);
681 }
682
Run()683 void 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 }
693 REGISTER_TEST(Run, 9);
694 } // namespace test09
695
696
697 // test10: FN. Simple race (write vs read). {{{1
698 namespace test10 {
699 int 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 //
Writer()713 void Writer() {
714 GLOB = 3;
715 }
Reader()716 void Reader() {
717 usleep(100000);
718 CHECK(GLOB != -777);
719 }
720
Run()721 void 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 }
730 REGISTER_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 //
746 namespace test11 {
747 int GLOB = 0;
748 Mutex MU;
Worker()749 void Worker() {
750 usleep(200000);
751 CHECK(GLOB != 777);
752
753 MU.Lock();
754 COND++;
755 CV.Signal();
756 MU.Unlock();
757 }
758
Parent()759 void 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
Run()776 void 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 }
782 REGISTER_TEST(Run, 11);
783 } // namespace test11
784
785
786 // test12: FP. Synchronization via Mutex, then via PCQ. {{{1
787 namespace test12 {
788 int 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
802 ProducerConsumerQueue Q(INT_MAX);
803 Mutex MU;
804
Putter()805 void Putter() {
806 MU.Lock();
807 GLOB++;
808 MU.Unlock();
809
810 Q.Put(NULL);
811 }
812
Getter()813 void Getter() {
814 MU.Lock();
815 GLOB++;
816 MU.Unlock();
817
818 Q.Get();
819 GLOB++;
820 }
821
Run()822 void 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 }
830 REGISTER_TEST(Run, 12);
831 } // namespace test12
832
833
834 // test13: FP. Synchronization via Mutex, then via LockWhen. {{{1
835 namespace test13 {
836 int 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)
851 Mutex MU;
852
Waker()853 void 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
Waiter()864 void Waiter() {
865 MU.Lock();
866 GLOB++;
867 MU.Unlock();
868
869 MU.LockWhen(Condition(&ArgIsOne, &COND));
870 MU.Unlock();
871 GLOB++;
872 }
873
Run()874 void 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 }
885 REGISTER_TEST2(Run, 13, FEATURE|NEEDS_ANNOTATIONS);
886 } // namespace test13
887
888
889 // test14: FP. Synchronization via PCQ, reads, 2 workers. {{{1
890 namespace test14 {
891 int 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)
903 ProducerConsumerQueue Q1(INT_MAX), Q2(INT_MAX);
904
Putter1()905 void Putter1() {
906 CHECK(GLOB != 777);
907 Q1.Put(NULL);
908 }
Putter2()909 void Putter2() {
910 CHECK(GLOB != 777);
911 Q2.Put(NULL);
912 }
Getter()913 void Getter() {
914 Q1.Get();
915 Q2.Get();
916 GLOB++;
917 }
Run()918 void 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 }
926 REGISTER_TEST(Run, 14);
927 } // namespace test14
928
929
930 // test15: TN. Synchronization via LockWhen. One waker and 2 waiters. {{{1
931 namespace 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
940 int GLOB = 0;
941 Mutex MU;
942
Waker()943 void Waker() {
944 GLOB = 2;
945
946 MU.Lock();
947 COND = 1;
948 ANNOTATE_CONDVAR_SIGNAL(&MU);
949 MU.Unlock();
950 };
951
Waiter()952 void Waiter() {
953 MU.LockWhen(Condition(&ArgIsOne, &COND));
954 MU.Unlock();
955 CHECK(GLOB != 777);
956 }
957
958
Run()959 void 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 }
967 REGISTER_TEST(Run, 15);
968 } // namespace test15
969
970
971 // test16: FP. Barrier (emulated by CV), 2 threads. {{{1
972 namespace 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 //
992 int GLOB = 0;
993 Mutex MU;
994 Mutex MU2;
995
Worker()996 void 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
Run()1010 void 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 }
1019 REGISTER_TEST2(Run, 16, FEATURE|NEEDS_ANNOTATIONS);
1020 } // namespace test16
1021
1022
1023 // test17: FP. Barrier (emulated by CV), 3 threads. {{{1
1024 namespace test17 {
1025 // Same as test16, but with 3 threads.
1026 int GLOB = 0;
1027 Mutex MU;
1028 Mutex MU2;
1029
Worker()1030 void 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
Run()1044 void 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 }
1053 REGISTER_TEST2(Run, 17, FEATURE|NEEDS_ANNOTATIONS);
1054 } // namespace test17
1055
1056
1057 // test18: TN. Synchronization via Await(), signaller gets there first. {{{1
1058 namespace test18 {
1059 int GLOB = 0;
1060 Mutex MU;
1061 // Same as test03, but uses Mutex::Await() instead of Mutex::LockWhen().
1062
Waker()1063 void 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 }
Waiter()1071 void 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 }
Run()1083 void Run() {
1084 printf("test18: negative\n");
1085 Waiter();
1086 printf("\tGLOB=%d\n", GLOB);
1087 }
1088 REGISTER_TEST2(Run, 18, FEATURE|NEEDS_ANNOTATIONS);
1089 } // namespace test18
1090
1091 // test19: TN. Synchronization via AwaitWithTimeout(). {{{1
1092 namespace test19 {
1093 int GLOB = 0;
1094 // Same as test18, but with AwaitWithTimeout. Do not timeout.
1095 Mutex MU;
Waker()1096 void 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 }
Waiter()1104 void 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 }
Run()1116 void Run() {
1117 printf("test19: negative\n");
1118 Waiter();
1119 printf("\tGLOB=%d\n", GLOB);
1120 }
1121 REGISTER_TEST2(Run, 19, FEATURE|NEEDS_ANNOTATIONS);
1122 } // namespace test19
1123
1124 // test20: TP. Incorrect synchronization via AwaitWhen(), timeout. {{{1
1125 namespace test20 {
1126 int GLOB = 0;
1127 Mutex MU;
1128 // True race. We timeout in AwaitWhen.
Waker()1129 void Waker() {
1130 GLOB = 1;
1131 usleep(100 * 1000);
1132 }
Waiter()1133 void 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 }
Run()1145 void 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 }
1152 REGISTER_TEST2(Run, 20, FEATURE|NEEDS_ANNOTATIONS);
1153 } // namespace test20
1154
1155 // test21: TP. Incorrect synchronization via LockWhenWithTimeout(). {{{1
1156 namespace test21 {
1157 int GLOB = 0;
1158 // True race. We timeout in LockWhenWithTimeout().
1159 Mutex MU;
Waker()1160 void Waker() {
1161 GLOB = 1;
1162 usleep(100 * 1000);
1163 }
Waiter()1164 void 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 }
Run()1175 void 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 }
1182 REGISTER_TEST2(Run, 21, FEATURE|NEEDS_ANNOTATIONS);
1183 } // namespace test21
1184
1185 // test22: TP. Incorrect synchronization via CondVar::WaitWithTimeout(). {{{1
1186 namespace test22 {
1187 int GLOB = 0;
1188 Mutex MU;
1189 // True race. We timeout in CondVar::WaitWithTimeout().
Waker()1190 void Waker() {
1191 GLOB = 1;
1192 usleep(100 * 1000);
1193 }
Waiter()1194 void 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 }
Run()1211 void 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 }
1218 REGISTER_TEST(Run, 22);
1219 } // namespace test22
1220
1221 // test23: TN. TryLock, ReaderLock, ReaderTryLock. {{{1
1222 namespace test23 {
1223 // Correct synchronization with TryLock, Lock, ReaderTryLock, ReaderLock.
1224 int GLOB = 0;
1225 Mutex MU;
Worker_TryLock()1226 void 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
Worker_ReaderTryLock()1239 void 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
Worker_ReaderLock()1252 void 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
Worker_Lock()1261 void Worker_Lock() {
1262 for (int i = 0; i < 20; i++) {
1263 MU.Lock();
1264 GLOB++;
1265 MU.Unlock();
1266 usleep(1000);
1267 }
1268 }
1269
Run()1270 void 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 }
1281 REGISTER_TEST(Run, 23);
1282 } // namespace test23
1283
1284 // test24: TN. Synchronization via ReaderLockWhen(). {{{1
1285 namespace test24 {
1286 int GLOB = 0;
1287 Mutex MU;
1288 // Same as test03, but uses ReaderLockWhen().
1289
Waker()1290 void 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 }
Waiter()1298 void 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 }
Run()1308 void Run() {
1309 printf("test24: negative\n");
1310 Waiter();
1311 printf("\tGLOB=%d\n", GLOB);
1312 }
1313 REGISTER_TEST2(Run, 24, FEATURE|NEEDS_ANNOTATIONS);
1314 } // namespace test24
1315
1316 // test25: TN. Synchronization via ReaderLockWhenWithTimeout(). {{{1
1317 namespace test25 {
1318 int GLOB = 0;
1319 Mutex MU;
1320 // Same as test24, but uses ReaderLockWhenWithTimeout().
1321 // We do not timeout.
1322
Waker()1323 void 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 }
Waiter()1331 void 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 }
Run()1341 void Run() {
1342 printf("test25: negative\n");
1343 Waiter();
1344 printf("\tGLOB=%d\n", GLOB);
1345 }
1346 REGISTER_TEST2(Run, 25, FEATURE|NEEDS_ANNOTATIONS);
1347 } // namespace test25
1348
1349 // test26: TP. Incorrect synchronization via ReaderLockWhenWithTimeout(). {{{1
1350 namespace test26 {
1351 int GLOB = 0;
1352 Mutex MU;
1353 // Same as test25, but we timeout and incorrectly assume happens-before.
1354
Waker()1355 void Waker() {
1356 GLOB = 1;
1357 usleep(10000);
1358 }
Waiter()1359 void 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 }
Run()1369 void 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 }
1376 REGISTER_TEST2(Run, 26, FEATURE|NEEDS_ANNOTATIONS);
1377 } // namespace test26
1378
1379
1380 // test27: TN. Simple synchronization via SpinLock. {{{1
1381 namespace test27 {
1382 #ifndef NO_SPINLOCK
1383 int GLOB = 0;
1384 SpinLock MU;
Worker()1385 void Worker() {
1386 MU.Lock();
1387 GLOB++;
1388 MU.Unlock();
1389 usleep(10000);
1390 }
1391
Run()1392 void 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 }
1399 REGISTER_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
1405 namespace 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)
1415 ProducerConsumerQueue Q(INT_MAX);
1416 int GLOB = 0;
1417 Mutex MU;
1418
Putter()1419 void 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
Getter()1431 void Getter() {
1432 Q.Get();
1433 Q.Get();
1434 usleep(100000);
1435 CHECK(GLOB == 2);
1436 }
1437
Run()1438 void 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 }
1445 REGISTER_TEST(Run, 28);
1446 } // namespace test28
1447
1448
1449 // test29: TN. Synchronization via Mutex, then PCQ. 4 threads. {{{1
1450 namespace test29 {
1451 // Similar to test28, but has two Getters and two PCQs.
1452 ProducerConsumerQueue *Q1, *Q2;
1453 Mutex MU;
1454 int GLOB = 0;
1455
Putter(ProducerConsumerQueue * q)1456 void 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
Putter1()1470 void Putter1() { Putter(Q1); }
Putter2()1471 void Putter2() { Putter(Q2); }
1472
Getter()1473 void 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
Run()1481 void 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 }
1492 REGISTER_TEST(Run, 29);
1493 } // namespace test29
1494
1495
1496 // test30: TN. Synchronization via 'safe' race. Writer vs multiple Readers. {{{1
1497 namespace 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
1518 const int N = 48;
1519 static int GLOB[N];
1520 volatile int BOUNDARY = 0;
1521
Writer()1522 void 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
Reader()1534 void 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
Run()1547 void 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 }
1556 REGISTER_TEST2(Run, 30, FEATURE|NEEDS_ANNOTATIONS);
1557 } // namespace test30
1558
1559
1560 // test31: TN. Synchronization via 'safe' race. Writer vs Writer. {{{1
1561 namespace 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
1571 const int N = 48;
1572 static int GLOB[N];
1573 volatile int BOUNDARY = 0;
1574
Writer1()1575 void 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
Writer2()1587 void 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
Run()1602 void 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 }
1611 REGISTER_TEST2(Run, 31, FEATURE|NEEDS_ANNOTATIONS);
1612 } // namespace test31
1613
1614
1615 // test32: FP. Synchronization via thread create/join. W/R. {{{1
1616 namespace 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 //
1637 int GLOB = 0;
1638 Mutex MU;
1639
Writer()1640 void Writer() {
1641 MU.Lock();
1642 GLOB = 1;
1643 MU.Unlock();
1644 }
1645
Reader()1646 void Reader() {
1647 usleep(480000);
1648 MU.Lock();
1649 CHECK(GLOB != 777);
1650 MU.Unlock();
1651 }
1652
Parent()1653 void 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
Run()1665 void 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
1672 REGISTER_TEST(Run, 32);
1673 } // namespace test32
1674
1675
1676 // test33: STAB. Stress test for the number of thread sets (TSETs). {{{1
1677 namespace test33 {
1678 int 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).
1682 const int N_iter = 48;
1683 const int Nlog = 15;
1684 const int N = 1 << Nlog;
1685 static int ARR[N];
1686 Mutex MU;
1687
Worker()1688 void 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
Run()1702 void 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 }
1726 REGISTER_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
1731 namespace test34 {
1732 // Similar to test33, but for lock sets.
1733 int GLOB = 0;
1734 const int N_iter = 48;
1735 const int Nlog = 10;
1736 const int N = 1 << Nlog;
1737 static int ARR[N];
1738 static Mutex *MUs[Nlog];
1739
Worker()1740 void 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
Run()1749 void 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 }
1765 REGISTER_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
1770 namespace 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.
1776 int **ARR;
1777 const int N_mu = 25000;
1778 const int N_free = 48000;
1779
Worker()1780 void Worker() {
1781 for (int i = 0; i < N_free; i++)
1782 CHECK(777 == *ARR[i]);
1783 }
1784
Run()1785 void 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 }
1813 REGISTER_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
1818 namespace 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()
1834 ProducerConsumerQueue Q(INT_MAX);
1835 int GLOB = 0;
1836 Mutex MU, MU1;
1837
Putter()1838 void 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
Getter()1852 void Getter() {
1853 Q.Get();
1854 Q.Get();
1855 usleep(100000);
1856 MU1.Lock();
1857 GLOB++;
1858 MU1.Unlock();
1859 }
1860
Run()1861 void 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 }
1868 REGISTER_TEST(Run, 36);
1869 } // namespace test36
1870
1871
1872 // test37: TN. Simple synchronization (write vs read). {{{1
1873 namespace test37 {
1874 int GLOB = 0;
1875 Mutex 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
Writer()1885 void Writer() {
1886 MU.Lock();
1887 GLOB = 3;
1888 MU.Unlock();
1889 }
Reader()1890 void Reader() {
1891 usleep(100000);
1892 MU.Lock();
1893 CHECK(GLOB != -777);
1894 MU.Unlock();
1895 }
1896
Run()1897 void Run() {
1898 printf("test37: negative\n");
1899 MyThreadArray t(Writer, Reader);
1900 t.Start();
1901 t.Join();
1902 printf("\tGLOB=%d\n", GLOB);
1903 }
1904 REGISTER_TEST(Run, 37);
1905 } // namespace test37
1906
1907
1908 // test38: TN. Synchronization via Mutexes and PCQ. 4 threads. W/W {{{1
1909 namespace 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
1931 ProducerConsumerQueue *Q1, *Q2;
1932 int GLOB = 0;
1933 Mutex MU, MU1, MU2;
1934
Putter(ProducerConsumerQueue * q)1935 void 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
Putter1()1951 void Putter1() { Putter(Q1); }
Putter2()1952 void Putter2() { Putter(Q2); }
1953
Getter()1954 void 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
Run()1966 void 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 }
1977 REGISTER_TEST(Run, 38);
1978 } // namespace test38
1979
1980 // test39: FP. Barrier. {{{1
1981 namespace test39 {
1982 #ifndef NO_BARRIER
1983 // Same as test17 but uses Barrier class (pthread_barrier_t).
1984 int GLOB = 0;
1985 const int N_threads = 3;
1986 Barrier barrier(N_threads);
1987 Mutex MU;
1988
Worker()1989 void Worker() {
1990 MU.Lock();
1991 GLOB++;
1992 MU.Unlock();
1993 barrier.Block();
1994 CHECK(GLOB == N_threads);
1995 }
Run()1996 void 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 }
2009 REGISTER_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
2015 namespace 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
2037 ProducerConsumerQueue *Q1, *Q2;
2038 int GLOB = 0;
2039 Mutex MU, MU1, MU2;
2040
Putter(ProducerConsumerQueue * q)2041 void 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
Putter1()2058 void Putter1() { Putter(Q1); }
Putter2()2059 void Putter2() { Putter(Q2); }
2060
Getter()2061 void 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
Run()2072 void 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 }
2084 REGISTER_TEST(Run, 40);
2085 } // namespace test40
2086
2087 // test41: TN. Test for race that appears when loading a dynamic symbol. {{{1
2088 namespace test41 {
Worker()2089 void Worker() {
2090 ANNOTATE_NO_OP(NULL); // An empty function, loaded from dll.
2091 }
Run()2092 void Run() {
2093 printf("test41: negative\n");
2094 MyThreadArray t(Worker, Worker, Worker);
2095 t.Start();
2096 t.Join();
2097 }
2098 REGISTER_TEST2(Run, 41, FEATURE|NEEDS_ANNOTATIONS);
2099 } // namespace test41
2100
2101
2102 // test42: TN. Using the same cond var several times. {{{1
2103 namespace test42 {
2104 int GLOB = 0;
2105 int COND = 0;
2106 int N_threads = 3;
2107 Mutex MU;
2108
Worker1()2109 void 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
Worker2()2127 void 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
Run()2144 void 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 }
2152 REGISTER_TEST2(Run, 42, FEATURE|NEEDS_ANNOTATIONS);
2153 } // namespace test42
2154
2155
2156
2157 // test43: TN. {{{1
2158 namespace test43 {
2159 //
2160 // Putter: Getter:
2161 // 1. write
2162 // 2. Q.Put() --\ .
2163 // 3. read \--> a. Q.Get()
2164 // b. read
2165 int GLOB = 0;
2166 ProducerConsumerQueue Q(INT_MAX);
Putter()2167 void Putter() {
2168 GLOB = 1;
2169 Q.Put(NULL);
2170 CHECK(GLOB == 1);
2171 }
Getter()2172 void Getter() {
2173 Q.Get();
2174 usleep(100000);
2175 CHECK(GLOB == 1);
2176 }
Run()2177 void Run() {
2178 printf("test43: negative\n");
2179 MyThreadArray t(Putter, Getter);
2180 t.Start();
2181 t.Join();
2182 printf("\tGLOB=%d\n", GLOB);
2183 }
2184 REGISTER_TEST(Run, 43)
2185 } // namespace test43
2186
2187
2188 // test44: FP. {{{1
2189 namespace 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();
2200 int GLOB = 0;
2201 Mutex MU;
2202 ProducerConsumerQueue Q(INT_MAX);
Putter()2203 void Putter() {
2204 CHECK(GLOB == 0);
2205 Q.Put(NULL);
2206 MU.Lock();
2207 GLOB = 1;
2208 MU.Unlock();
2209 }
Getter()2210 void Getter() {
2211 Q.Get();
2212 usleep(100000);
2213 MU.Lock();
2214 GLOB = 1;
2215 MU.Unlock();
2216 }
Run()2217 void 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 }
2225 REGISTER_TEST(Run, 44)
2226 } // namespace test44
2227
2228
2229 // test45: TN. {{{1
2230 namespace 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();
2241 int GLOB = 0;
2242 Mutex MU;
2243 ProducerConsumerQueue Q(INT_MAX);
Putter()2244 void Putter() {
2245 CHECK(GLOB == 0);
2246 Q.Put(NULL);
2247 MU.Lock();
2248 GLOB++;
2249 MU.Unlock();
2250 }
Getter()2251 void Getter() {
2252 Q.Get();
2253 usleep(100000);
2254 MU.Lock();
2255 CHECK(GLOB <= 1);
2256 MU.Unlock();
2257 }
Run()2258 void Run() {
2259 printf("test45: negative\n");
2260 MyThreadArray t(Putter, Getter);
2261 t.Start();
2262 t.Join();
2263 printf("\tGLOB=%d\n", GLOB);
2264 }
2265 REGISTER_TEST(Run, 45)
2266 } // namespace test45
2267
2268
2269 // test46: FN. {{{1
2270 namespace 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();
2280 int GLOB = 0;
2281 Mutex MU;
First()2282 void First() {
2283 GLOB++;
2284 MU.Lock();
2285 GLOB++;
2286 MU.Unlock();
2287 }
Second()2288 void 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 }
Run()2301 void Run() {
2302 ANNOTATE_TRACE_MEMORY(&GLOB);
2303 MyThreadArray t(First, Second);
2304 t.Start();
2305 t.Join();
2306 }
2307 REGISTER_TEST(Run, 46)
2308 } // namespace test46
2309
2310
2311 // test47: TP. Not detected by pure happens-before detectors. {{{1
2312 namespace 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
2323 int GLOB = 0;
2324 Mutex MU;
First()2325 void First() {
2326 GLOB=1;
2327 MU.Lock();
2328 MU.Unlock();
2329 }
Second()2330 void Second() {
2331 usleep(480000);
2332 MU.Lock();
2333 MU.Unlock();
2334 GLOB++;
2335 }
Run()2336 void 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 }
2346 REGISTER_TEST(Run, 47)
2347 } // namespace test47
2348
2349
2350 // test48: FN. Simple race (single write vs multiple reads). {{{1
2351 namespace test48 {
2352 int 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 //
Writer()2367 void Writer() {
2368 GLOB = 3;
2369 }
Reader()2370 void Reader() {
2371 usleep(100000);
2372 CHECK(GLOB != -777);
2373 }
2374
Run()2375 void 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 }
2384 REGISTER_TEST(Run, 48)
2385 } // namespace test48
2386
2387
2388 // test49: FN. Simple race (single write vs multiple reads). {{{1
2389 namespace test49 {
2390 int 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 //
Writer()2407 void Writer() {
2408 GLOB = 3;
2409 }
Reader()2410 void Reader() {
2411 usleep(100000);
2412 CHECK(GLOB != -777);
2413 CHECK(GLOB != -777);
2414 CHECK(GLOB != -777);
2415 CHECK(GLOB != -777);
2416 }
2417
Run()2418 void 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 }
2427 REGISTER_TEST(Run, 49);
2428 } // namespace test49
2429
2430
2431 // test50: TP. Synchronization via CondVar. {{{1
2432 namespace test50 {
2433 int GLOB = 0;
2434 Mutex 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
Waker()2452 void 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
Waiter()2468 void 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 }
Run()2482 void 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 }
2489 REGISTER_TEST2(Run, 50, FEATURE|NEEDS_ANNOTATIONS);
2490 } // namespace test50
2491
2492
2493 // test51: TP. Synchronization via CondVar: problem with several signals. {{{1
2494 namespace test51 {
2495 int GLOB = 0;
2496 int COND = 0;
2497 Mutex 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
Waker()2522 void 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
Waiter()2543 void 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 }
Run()2557 void 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 }
2564 REGISTER_TEST(Run, 51);
2565 } // namespace test51
2566
2567
2568 // test52: TP. Synchronization via CondVar: problem with several signals. {{{1
2569 namespace test52 {
2570 int GLOB = 0;
2571 int COND = 0;
2572 Mutex 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
Waker()2595 void 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
Waiter()2614 void 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 }
Run()2628 void 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 }
2635 REGISTER_TEST(Run, 52);
2636 } // namespace test52
2637
2638
2639 // test53: FP. Synchronization via implicit semaphore. {{{1
2640 namespace 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
2662 int GLOB = 0;
2663 bool FLAG = false;
2664 Mutex MU1, MU2;
2665
Initializer()2666 void Initializer() {
2667 MU1.Lock();
2668 GLOB = 1000;
2669 FLAG = true;
2670 MU1.Unlock();
2671 usleep(100000); // just in case
2672 }
2673
User()2674 void 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
Run()2689 void 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 }
2699 REGISTER_TEST(Run, 53)
2700 } // namespace test53
2701
2702
2703 // test54: TN. Synchronization via implicit semaphore. Annotated {{{1
2704 namespace test54 {
2705 // Same as test53, but annotated.
2706 int GLOB = 0;
2707 bool FLAG = false;
2708 Mutex MU1, MU2;
2709
Initializer()2710 void 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
User()2719 void 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
Run()2735 void 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 }
2742 REGISTER_TEST2(Run, 54, FEATURE|NEEDS_ANNOTATIONS)
2743 } // namespace test54
2744
2745
2746 // test55: FP. Synchronization with TryLock. Not easy for race detectors {{{1
2747 namespace 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).
2753 int GLOB = 0;
2754 Mutex MU;
2755
Worker_Lock()2756 void Worker_Lock() {
2757 GLOB = 1;
2758 MU.Lock();
2759 }
2760
Worker_TryLock()2761 void 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
Run()2774 void 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 }
2781 REGISTER_TEST2(Run, 55, FEATURE|EXCLUDE_FROM_ALL);
2782 } // namespace test55
2783
2784
2785
2786 // test56: TP. Use of ANNOTATE_BENIGN_RACE. {{{1
2787 namespace test56 {
2788 // For whatever reason the user wants to treat
2789 // a race on GLOB as a benign race.
2790 int GLOB = 0;
2791 int GLOB2 = 0;
2792
Worker()2793 void Worker() {
2794 GLOB++;
2795 }
2796
Run()2797 void 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 }
2806 REGISTER_TEST2(Run, 56, FEATURE|NEEDS_ANNOTATIONS)
2807 } // namespace test56
2808
2809
2810 // test57: TN: Correct use of atomics. {{{1
2811 namespace test57 {
2812 int GLOB = 0;
Writer()2813 void Writer() {
2814 for (int i = 0; i < 10; i++) {
2815 AtomicIncrement(&GLOB, 1);
2816 usleep(1000);
2817 }
2818 }
Reader()2819 void Reader() {
2820 while (GLOB < 20) usleep(1000);
2821 }
Run()2822 void 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 }
2830 REGISTER_TEST(Run, 57)
2831 } // namespace test57
2832
2833
2834 // test58: TN. User defined synchronization. {{{1
2835 namespace test58 {
2836 int GLOB1 = 1;
2837 int GLOB2 = 2;
2838 int FLAG1 = 0;
2839 int 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
Worker2()2846 void Worker2() {
2847 FLAG1=GLOB2;
2848
2849 while(!FLAG2)
2850 ;
2851 GLOB2=FLAG2;
2852 }
2853
Worker1()2854 void Worker1() {
2855 FLAG2=GLOB1;
2856
2857 while(!FLAG1)
2858 ;
2859 GLOB1=FLAG1;
2860 }
2861
Run()2862 void 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 }
2870 REGISTER_TEST2(Run, 58, FEATURE|EXCLUDE_FROM_ALL)
2871 } // namespace test58
2872
2873
2874
2875 // test59: TN. User defined synchronization. Annotated {{{1
2876 namespace test59 {
2877 int COND1 = 0;
2878 int COND2 = 0;
2879 int GLOB1 = 1;
2880 int GLOB2 = 2;
2881 int FLAG1 = 0;
2882 int FLAG2 = 0;
2883 // same as test 58 but annotated
2884
Worker2()2885 void Worker2() {
2886 FLAG1=GLOB2;
2887 ANNOTATE_CONDVAR_SIGNAL(&COND2);
2888 while(!FLAG2) usleep(1);
2889 ANNOTATE_CONDVAR_WAIT(&COND1);
2890 GLOB2=FLAG2;
2891 }
2892
Worker1()2893 void Worker1() {
2894 FLAG2=GLOB1;
2895 ANNOTATE_CONDVAR_SIGNAL(&COND1);
2896 while(!FLAG1) usleep(1);
2897 ANNOTATE_CONDVAR_WAIT(&COND2);
2898 GLOB1=FLAG1;
2899 }
2900
Run()2901 void 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 }
2911 REGISTER_TEST2(Run, 59, FEATURE|NEEDS_ANNOTATIONS)
2912 } // namespace test59
2913
2914
2915 // test60: TN. Correct synchronization using signal-wait {{{1
2916 namespace test60 {
2917 int COND1 = 0;
2918 int COND2 = 0;
2919 int GLOB1 = 1;
2920 int GLOB2 = 2;
2921 int FLAG2 = 0;
2922 int FLAG1 = 0;
2923 Mutex MU;
2924 // same as test 59 but synchronized with signal-wait.
2925
Worker2()2926 void 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
Worker1()2943 void 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
Run()2960 void 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 }
2968 REGISTER_TEST2(Run, 60, FEATURE|NEEDS_ANNOTATIONS)
2969 } // namespace test60
2970
2971
2972 // test61: TN. Synchronization via Mutex as in happens-before, annotated. {{{1
2973 namespace test61 {
2974 Mutex MU;
2975 int GLOB = 0;
2976 int *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
Putter()2982 void 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
Getter()2992 void 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
Run()3007 void Run() {
3008 printf("test61: negative\n");
3009 MyThreadArray t(Putter, Getter);
3010 t.Start();
3011 t.Join();
3012 printf("\tGLOB=%d\n", GLOB);
3013 }
3014 REGISTER_TEST2(Run, 61, FEATURE|NEEDS_ANNOTATIONS)
3015 } // namespace test61
3016
3017
3018 // test62: STAB. Create as many segments as possible. {{{1
3019 namespace 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.
3022 ProducerConsumerQueue Q(INT_MAX);
3023 const int N = 1 << 22;
3024
Putter()3025 void 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
Getter()3034 void Getter() {
3035 for (int i = 0; i < N; i++)
3036 Q.Get();
3037 }
3038
Run()3039 void Run() {
3040 printf("test62:\n");
3041 MyThreadArray t(Putter, Getter);
3042 t.Start();
3043 t.Join();
3044 }
3045 REGISTER_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
3050 namespace 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.
3053 const int N = 1 << 24;
3054 int C = 0;
3055
Putter()3056 void 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
Getter()3065 void Getter() {
3066 }
3067
Run()3068 void Run() {
3069 printf("test63:\n");
3070 MyThreadArray t(Putter, Getter);
3071 t.Start();
3072 t.Join();
3073 }
3074 REGISTER_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
3079 namespace 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
3090 int GLOB = 0;
3091 ProducerConsumerQueue Q(INT_MAX);
3092
T1()3093 void T1() {
3094 CHECK(GLOB == 0);
3095 }
3096
T2()3097 void T2() {
3098 usleep(100000);
3099 CHECK(GLOB == 0);
3100 Q.Put(NULL);
3101 }
3102
T3()3103 void T3() {
3104 Q.Get();
3105 GLOB = 1;
3106 }
3107
3108
Run()3109 void 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 }
3118 REGISTER_TEST(Run, 64)
3119 } // namespace test64
3120
3121
3122 // test65: TP. T2 happens-before T3, but T1 is independent. Writes in T1/T2. {{{1
3123 namespace 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
3139 int GLOB = 0;
3140 Mutex MU;
3141 ProducerConsumerQueue Q(INT_MAX);
3142
T1()3143 void T1() {
3144 MU.Lock();
3145 GLOB++;
3146 MU.Unlock();
3147 }
3148
T2()3149 void T2() {
3150 usleep(100000);
3151 MU.Lock();
3152 GLOB++;
3153 MU.Unlock();
3154 Q.Put(NULL);
3155 }
3156
T3()3157 void T3() {
3158 Q.Get();
3159 GLOB = 1;
3160 }
3161
3162
Run()3163 void 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 }
3173 REGISTER_TEST(Run, 65)
3174 } // namespace test65
3175
3176
3177 // test66: TN. Two separate pairs of signaller/waiter using the same CV. {{{1
3178 namespace test66 {
3179 int GLOB1 = 0;
3180 int GLOB2 = 0;
3181 int C1 = 0;
3182 int C2 = 0;
3183 Mutex MU;
3184
Signaller1()3185 void Signaller1() {
3186 GLOB1 = 1;
3187 MU.Lock();
3188 C1 = 1;
3189 CV.Signal();
3190 MU.Unlock();
3191 }
3192
Signaller2()3193 void Signaller2() {
3194 GLOB2 = 1;
3195 usleep(100000);
3196 MU.Lock();
3197 C2 = 1;
3198 CV.Signal();
3199 MU.Unlock();
3200 }
3201
Waiter1()3202 void Waiter1() {
3203 MU.Lock();
3204 while (C1 != 1) CV.Wait(&MU);
3205 ANNOTATE_CONDVAR_WAIT(&CV);
3206 MU.Unlock();
3207 GLOB1 = 2;
3208 }
3209
Waiter2()3210 void Waiter2() {
3211 MU.Lock();
3212 while (C2 != 1) CV.Wait(&MU);
3213 ANNOTATE_CONDVAR_WAIT(&CV);
3214 MU.Unlock();
3215 GLOB2 = 2;
3216 }
3217
Run()3218 void 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 }
3225 REGISTER_TEST2(Run, 66, FEATURE|NEEDS_ANNOTATIONS)
3226 } // namespace test66
3227
3228
3229 // test67: FN. Race between Signaller1 and Waiter2 {{{1
3230 namespace 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.
3236 int GLOB = 0;
3237 int C1 = 0;
3238 int C2 = 0;
3239 Mutex MU;
3240
Signaller1()3241 void Signaller1() {
3242 GLOB = 1;
3243 MU.Lock();
3244 C1 = 1;
3245 CV.Signal();
3246 MU.Unlock();
3247 }
3248
Signaller2()3249 void Signaller2() {
3250 usleep(100000);
3251 MU.Lock();
3252 C2 = 1;
3253 CV.Signal();
3254 MU.Unlock();
3255 }
3256
Waiter1()3257 void Waiter1() {
3258 MU.Lock();
3259 while (C1 != 1) CV.Wait(&MU);
3260 ANNOTATE_CONDVAR_WAIT(&CV);
3261 MU.Unlock();
3262 }
3263
Waiter2()3264 void Waiter2() {
3265 MU.Lock();
3266 while (C2 != 1) CV.Wait(&MU);
3267 ANNOTATE_CONDVAR_WAIT(&CV);
3268 MU.Unlock();
3269 GLOB = 2;
3270 }
3271
Run()3272 void 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 }
3281 REGISTER_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
3286 namespace 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.
3292 int GLOB = 0;
3293 int COND = 0;
3294 const int N_writers = 3;
3295 Mutex MU, MU1;
3296
Writer()3297 void 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
Reader()3310 void 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
Run()3324 void 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 }
3333 REGISTER_TEST(Run, 68)
3334 } // namespace test68
3335
3336
3337 // test69: {{{1
3338 namespace 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:
3344 int GLOB = 0;
3345 int COND = 0;
3346 const int N_writers = 3;
3347 int FAKE_MU = 0;
3348 Mutex MU, MU1;
3349
Writer()3350 void 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
Reader()3363 void 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
Run()3379 void 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 }
3386 REGISTER_TEST(Run, 69)
3387 } // namespace test69
3388
3389 // test70: STAB. Check that TRACE_MEMORY works. {{{1
3390 namespace test70 {
3391 int GLOB = 0;
Run()3392 void Run() {
3393 printf("test70: negative\n");
3394 ANNOTATE_TRACE_MEMORY(&GLOB);
3395 GLOB = 1;
3396 printf("\tGLOB=%d\n", GLOB);
3397 }
3398 REGISTER_TEST(Run, 70)
3399 } // namespace test70
3400
3401
3402
3403 // test71: TN. strlen, index. {{{1
3404 namespace 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
3417 char *str;
WorkerX()3418 void 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 }
WorkerY()3428 void WorkerY() {
3429 str[5] = 'Y';
3430 str[6] = 'Y';
3431 str[7] = '\0';
3432 }
3433
Run()3434 void 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 }
3451 REGISTER_TEST(Run, 71)
3452 } // namespace test71
3453
3454
3455 // test72: STAB. Stress test for the number of segment sets (SSETs). {{{1
3456 namespace 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.
3461 int GLOB = 0;
3462 const int N_iter = 30;
3463 const int Nlog = 16;
3464 const int N = 1 << Nlog;
3465 static int64_t ARR1[N];
3466 static int64_t ARR2[N];
3467 Barrier *barriers[N_iter];
3468 Mutex MU;
3469
Worker()3470 void 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
Run()3506 void 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 }
3531 REGISTER_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
3537 namespace test73 {
3538 #ifndef NO_BARRIER
3539 // Variation of test72.
3540 // We perform accesses of different sizes to the same location.
3541 int GLOB = 0;
3542 const int N_iter = 2;
3543 const int Nlog = 16;
3544 const int N = 1 << Nlog;
3545 union uint64_union {
3546 uint64_t u64[1];
3547 uint32_t u32[2];
3548 uint16_t u16[4];
3549 uint8_t u8 [8];
3550 };
3551 static uint64_union ARR1[N];
3552 union uint32_union {
3553 uint32_t u32[1];
3554 uint16_t u16[2];
3555 uint8_t u8 [4];
3556 };
3557 static uint32_union ARR2[N];
3558 Barrier *barriers[N_iter];
3559 Mutex MU;
3560
Worker()3561 void 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
Run()3598 void 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 }
3623 REGISTER_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
3629 namespace test74 {
3630 const int N = 100000;
3631 Mutex MU;
Run()3632 void Run() {
3633 printf("test74: perf\n");
3634 for (int i = 0; i < N; i++ ) {
3635 MU.Lock();
3636 MU.Unlock();
3637 }
3638 }
3639 REGISTER_TEST(Run, 74)
3640 } // namespace test74
3641
3642
3643 // test75: TN. Test for sem_post, sem_wait, sem_trywait. {{{1
3644 namespace test75 {
3645 int GLOB = 0;
3646 sem_t sem[2];
3647
Poster()3648 void Poster() {
3649 GLOB = 1;
3650 sem_post(&sem[0]);
3651 sem_post(&sem[1]);
3652 }
3653
Waiter()3654 void Waiter() {
3655 sem_wait(&sem[0]);
3656 CHECK(GLOB==1);
3657 }
TryWaiter()3658 void TryWaiter() {
3659 usleep(500000);
3660 sem_trywait(&sem[1]);
3661 CHECK(GLOB==1);
3662 }
3663
Run()3664 void 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 }
3687 REGISTER_TEST(Run, 75)
3688 } // namespace test75
3689
3690 // RefCountedClass {{{1
3691 struct RefCountedClass {
3692 public:
RefCountedClassRefCountedClass3693 RefCountedClass() {
3694 annotate_unref_ = false;
3695 ref_ = 0;
3696 data_ = 0;
3697 }
3698
~RefCountedClassRefCountedClass3699 ~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
AccessDataRefCountedClass3708 void AccessData() {
3709 this->mu_.Lock();
3710 this->data_++;
3711 this->mu_.Unlock();
3712 }
3713
RefRefCountedClass3714 void Ref() {
3715 MU.Lock();
3716 CHECK(ref_ >= 0);
3717 ref_++;
3718 MU.Unlock();
3719 }
3720
UnrefRefCountedClass3721 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
Annotate_MURefCountedClass3738 static void Annotate_MU() {
3739 ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(&MU);
3740 }
AnnotateUnrefRefCountedClass3741 void AnnotateUnref() {
3742 annotate_unref_ = true;
3743 }
Annotate_RaceRefCountedClass3744 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
3758 Mutex RefCountedClass::MU;
3759
3760 // test76: FP. Ref counting, no annotations. {{{1
3761 namespace test76 {
3762 #ifndef NO_BARRIER
3763 int GLOB = 0;
3764 Barrier barrier(4);
3765 RefCountedClass *object = NULL;
Worker()3766 void Worker() {
3767 object->Ref();
3768 barrier.Block();
3769 object->AccessData();
3770 object->Unref();
3771 }
Run()3772 void 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 }
3780 REGISTER_TEST2(Run, 76, FEATURE)
3781 #endif // NO_BARRIER
3782 } // namespace test76
3783
3784
3785
3786 // test77: TN. Ref counting, MU is annotated. {{{1
3787 namespace test77 {
3788 #ifndef NO_BARRIER
3789 // same as test76, but RefCountedClass::MU is annotated.
3790 int GLOB = 0;
3791 Barrier barrier(4);
3792 RefCountedClass *object = NULL;
Worker()3793 void Worker() {
3794 object->Ref();
3795 barrier.Block();
3796 object->AccessData();
3797 object->Unref();
3798 }
Run()3799 void 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 }
3807 REGISTER_TEST(Run, 77)
3808 #endif // NO_BARRIER
3809 } // namespace test77
3810
3811
3812
3813 // test78: TN. Ref counting, Unref is annotated. {{{1
3814 namespace test78 {
3815 #ifndef NO_BARRIER
3816 // same as test76, but RefCountedClass::Unref is annotated.
3817 int GLOB = 0;
3818 Barrier barrier(4);
3819 RefCountedClass *object = NULL;
Worker()3820 void Worker() {
3821 object->Ref();
3822 barrier.Block();
3823 object->AccessData();
3824 object->Unref();
3825 }
Run()3826 void 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 }
3834 REGISTER_TEST(Run, 78)
3835 #endif // NO_BARRIER
3836 } // namespace test78
3837
3838
3839
3840 // test79 TN. Swap. {{{1
3841 namespace test79 {
3842 #if 0
3843 typedef __gnu_cxx::hash_map<int, int> map_t;
3844 #else
3845 typedef std::map<int, int> map_t;
3846 #endif
3847 map_t MAP;
3848 Mutex 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
Worker1()3854 void 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
Worker2()3863 void Worker2() {
3864 MU.Lock();
3865 MAP[1]++; // Just update MAP under MU.
3866 MU.Unlock();
3867 }
3868
Worker3()3869 void Worker3() { Worker1(); }
Worker4()3870 void Worker4() { Worker2(); }
3871
Run()3872 void 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 }
3879 REGISTER_TEST(Run, 79)
3880 } // namespace test79
3881
3882
3883 // AtomicRefCountedClass. {{{1
3884 // Same as RefCountedClass, but using atomic ops instead of mutex.
3885 struct AtomicRefCountedClass {
3886 public:
AtomicRefCountedClassAtomicRefCountedClass3887 AtomicRefCountedClass() {
3888 annotate_unref_ = false;
3889 ref_ = 0;
3890 data_ = 0;
3891 }
3892
~AtomicRefCountedClassAtomicRefCountedClass3893 ~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
AccessDataAtomicRefCountedClass3901 void AccessData() {
3902 this->mu_.Lock();
3903 this->data_++;
3904 this->mu_.Unlock();
3905 }
3906
RefAtomicRefCountedClass3907 void Ref() {
3908 AtomicIncrement(&ref_, 1);
3909 }
3910
UnrefAtomicRefCountedClass3911 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
AnnotateUnrefAtomicRefCountedClass3924 void AnnotateUnref() {
3925 annotate_unref_ = true;
3926 }
Annotate_RaceAtomicRefCountedClass3927 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
3940 namespace test80 {
3941 #ifndef NO_BARRIER
3942 int GLOB = 0;
3943 Barrier barrier(4);
3944 AtomicRefCountedClass *object = NULL;
Worker()3945 void Worker() {
3946 object->Ref();
3947 barrier.Block();
3948 object->AccessData();
3949 object->Unref(); // All the tricky stuff is here.
3950 }
Run()3951 void 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 }
3959 REGISTER_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
3965 namespace test81 {
3966 #ifndef NO_BARRIER
3967 // same as test80, but Unref is annotated.
3968 int GLOB = 0;
3969 Barrier barrier(4);
3970 AtomicRefCountedClass *object = NULL;
Worker()3971 void Worker() {
3972 object->Ref();
3973 barrier.Block();
3974 object->AccessData();
3975 object->Unref(); // All the tricky stuff is here.
3976 }
Run()3977 void 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 }
3985 REGISTER_TEST2(Run, 81, FEATURE|EXCLUDE_FROM_ALL)
3986 #endif // NO_BARRIER
3987 } // namespace test81
3988
3989
3990 // test82: Object published w/o synchronization. {{{1
3991 namespace 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
4011 class FOO {
4012 public:
FOO()4013 FOO() {
4014 idx_ = rand() % 1024;
4015 arr_[idx_] = 77777;
4016 // __asm__ __volatile__("" : : : "memory"); // this fixes!
4017 }
check(volatile FOO * foo)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
4026 const int N = 100000;
4027 static volatile FOO *foo[N];
4028 Mutex MU;
4029
Writer()4030 void Writer() {
4031 for (int i = 0; i < N; i++) {
4032 foo[i] = new FOO;
4033 usleep(100);
4034 }
4035 }
4036
Reader()4037 void 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
Run()4053 void Run() {
4054 printf("test82: positive\n");
4055 MyThreadArray t(Writer, Reader);
4056 t.Start();
4057 t.Join();
4058 }
4059 REGISTER_TEST2(Run, 82, FEATURE|EXCLUDE_FROM_ALL)
4060 } // namespace test82
4061
4062
4063 // test83: Object published w/o synchronization (simple version){{{1
4064 namespace test83 {
4065 // A simplified version of test83 (example of a wrong code).
4066 // This test, though incorrect, will almost never fail.
4067 volatile static int *ptr = NULL;
4068 Mutex MU;
4069
Writer()4070 void Writer() {
4071 usleep(100);
4072 ptr = new int(777);
4073 }
4074
Reader()4075 void Reader() {
4076 while(!ptr) {
4077 MU.Lock(); // Not a synchronization!
4078 MU.Unlock();
4079 }
4080 CHECK(*ptr == 777);
4081 }
4082
Run()4083 void Run() {
4084 // printf("test83: positive\n");
4085 MyThreadArray t(Writer, Reader);
4086 t.Start();
4087 t.Join();
4088 }
4089 REGISTER_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
4094 namespace 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.
4099 static int s_x = 0;
4100 /* s_dummy[] ensures that s_x and s_y are not in the same cache line. */
4101 static char s_dummy[512] = {0};
4102 static int s_y;
4103
thread_func_1()4104 void thread_func_1()
4105 {
4106 s_y = 1;
4107 AtomicIncrement(&s_x, 1);
4108 }
4109
thread_func_2()4110 void thread_func_2()
4111 {
4112 while (AtomicIncrement(&s_x, 0) == 0)
4113 ;
4114 printf("y = %d\n", s_y);
4115 }
4116
4117
Run()4118 void 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 }
4127 REGISTER_TEST(Run, 84)
4128 } // namespace test84
4129
4130
4131 // test85: Test for RunningOnValgrind(). {{{1
4132 namespace test85 {
4133 int GLOB = 0;
Run()4134 void Run() {
4135 printf("test85: RunningOnValgrind() = %d\n", RunningOnValgrind());
4136 }
4137 REGISTER_TEST(Run, 85)
4138 } // namespace test85
4139
4140
4141 // test86: Test for race inside DTOR: racey write to vptr. Benign. {{{1
4142 namespace 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
4169 bool flag_stopped = false;
4170 Mutex mu;
4171
4172 ProducerConsumerQueue Q(INT_MAX); // Used to pass A* between threads.
4173
4174 struct A {
Atest86::A4175 A() { printf("A::A()\n"); }
~Atest86::A4176 virtual ~A() { printf("A::~A()\n"); }
ftest86::A4177 virtual void f() { }
4178
4179 uintptr_t padding[15];
4180 } __attribute__ ((aligned (64)));
4181
4182 struct B: A {
Btest86::B4183 B() { printf("B::B()\n"); }
~Btest86::B4184 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 }
ftest86::B4192 virtual void f() { }
4193 };
4194
Waiter()4195 void 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
Worker()4209 void 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
Run()4221 void Run() {
4222 printf("test86: positive, race inside DTOR\n");
4223 MyThreadArray t(Waiter, Worker);
4224 t.Start();
4225 t.Join();
4226 }
4227 REGISTER_TEST(Run, 86)
4228 } // namespace test86
4229
4230
4231 // test87: Test for race inside DTOR: racey write to vptr. Harmful.{{{1
4232 namespace 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 //
4242 bool flag_stopped = false;
4243 Mutex mu;
4244
4245 ProducerConsumerQueue Q(INT_MAX); // Used to pass A* between threads.
4246
4247 struct A {
Atest87::A4248 A() { printf("A::A()\n"); }
~Atest87::A4249 virtual ~A() { printf("A::~A()\n"); }
4250 virtual void f() = 0; // pure virtual.
4251 };
4252
4253 struct B: A {
Btest87::B4254 B() { printf("B::B()\n"); }
~Btest87::B4255 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
4266 struct C: B {
Ctest87::C4267 C() { printf("C::C()\n"); }
~Ctest87::C4268 virtual ~C() { printf("C::~C()\n"); }
ftest87::C4269 virtual void f() { }
4270 };
4271
Waiter()4272 void Waiter() {
4273 A *a = new C;
4274 Q.Put(a);
4275 delete a;
4276 }
4277
Worker()4278 void 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
Run()4288 void Run() {
4289 printf("test87: positive, race inside DTOR\n");
4290 MyThreadArray t(Waiter, Worker);
4291 t.Start();
4292 t.Join();
4293 }
4294 REGISTER_TEST2(Run, 87, FEATURE|EXCLUDE_FROM_ALL)
4295 } // namespace test87
4296
4297
4298 // test88: Test for ANNOTATE_IGNORE_WRITES_*{{{1
4299 namespace test88 {
4300 // a recey write annotated with ANNOTATE_IGNORE_WRITES_BEGIN/END.
4301 int GLOB = 0;
Worker()4302 void Worker() {
4303 ANNOTATE_IGNORE_WRITES_BEGIN();
4304 GLOB = 1;
4305 ANNOTATE_IGNORE_WRITES_END();
4306 }
Run()4307 void 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 }
4315 REGISTER_TEST(Run, 88)
4316 } // namespace test88
4317
4318
4319 // test89: Test for debug info. {{{1
4320 namespace 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.
4324 struct STRUCT {
4325 int a, b, c;
4326 };
4327
4328 struct A {
4329 int a;
Atest89::A4330 A() {
4331 ANNOTATE_TRACE_MEMORY(&a);
4332 a = 1;
4333 }
~Atest89::A4334 virtual ~A() {
4335 a = 4;
4336 }
4337 };
4338
4339 struct B : A {
Btest89::B4340 B() { CHECK(a == 1); }
~Btest89::B4341 virtual ~B() { CHECK(a == 3); }
4342 };
4343 struct C : B {
Ctest89::C4344 C() { a = 2; }
~Ctest89::C4345 virtual ~C() { a = 3; }
4346 };
4347
4348 int GLOBAL = 0;
4349 int *STACK = 0;
4350 STRUCT GLOB_STRUCT;
4351 STRUCT *STACK_STRUCT;
4352 STRUCT *HEAP_STRUCT;
4353
Worker()4354 void Worker() {
4355 GLOBAL = 1;
4356 *STACK = 1;
4357 GLOB_STRUCT.b = 1;
4358 STACK_STRUCT->b = 1;
4359 HEAP_STRUCT->b = 1;
4360 }
4361
Run()4362 void 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 }
4382 REGISTER_TEST2(Run, 89, FEATURE|EXCLUDE_FROM_ALL)
4383 } // namespace test89
4384
4385
4386 // test90: FP. Test for a safely-published pointer (read-only). {{{1
4387 namespace 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
4399 int *GLOB = 0;
4400 Mutex MU;
4401
Publisher()4402 void 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
Reader()4412 void 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
Run()4425 void 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 }
4433 REGISTER_TEST(Run, 90)
4434 } // namespace test90
4435
4436
4437 // test91: FP. Test for a safely-published pointer (read-write). {{{1
4438 namespace 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
4446 int *GLOB = 0;
4447 Mutex MU, MU1, MU2;
4448
Publisher()4449 void 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
Accessor()4458 void 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
Run()4474 void 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 }
4482 REGISTER_TEST(Run, 91)
4483 } // namespace test91
4484
4485
4486 // test92: TN. Test for a safely-published pointer (read-write), annotated. {{{1
4487 namespace 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
4505 struct ObjType {
4506 int arr[10];
4507 };
4508
4509 ObjType *GLOB = 0;
4510 Mutex MU, MU1, MU2;
4511
Publisher()4512 void 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
Accessor(int index)4523 void 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
Accessor0()4538 void Accessor0() { Accessor(0); }
Accessor5()4539 void Accessor5() { Accessor(5); }
Accessor9()4540 void Accessor9() { Accessor(9); }
4541
Run()4542 void 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 }
4549 REGISTER_TEST(Run, 92)
4550 } // namespace test92
4551
4552
4553 // test93: TP. Test for incorrect usage of ANNOTATE_PUBLISH_MEMORY_RANGE. {{{1
4554 namespace test93 {
4555 int GLOB = 0;
4556
Reader()4557 void Reader() {
4558 CHECK(GLOB == 0);
4559 }
4560
Publisher()4561 void 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
Run()4567 void 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 }
4574 REGISTER_TEST2(Run, 93, FEATURE|EXCLUDE_FROM_ALL)
4575 } // namespace test93
4576
4577
4578 // test94: TP. Check do_cv_signal/fake segment logic {{{1
4579 namespace test94 {
4580 int GLOB;
4581
4582 int COND = 0;
4583 int COND2 = 0;
4584 Mutex MU, MU2;
4585 CondVar CV, CV2;
4586
Thr1()4587 void 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 }
Thr2()4597 void 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 }
Thr3()4606 void Thr3() {
4607 MU.Lock();
4608 while(COND != 1)
4609 CV.Wait(&MU);
4610 MU.Unlock();
4611 }
Thr4()4612 void 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 }
Run()4619 void 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 }
4628 REGISTER_TEST(Run, 94);
4629 } // namespace test94
4630
4631 // test95: TP. Check do_cv_signal/fake segment logic {{{1
4632 namespace test95 {
4633 int GLOB = 0;
4634
4635 int COND = 0;
4636 int COND2 = 0;
4637 Mutex MU, MU2;
4638 CondVar CV, CV2;
4639
Thr1()4640 void 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 }
Thr2()4651 void Thr2() {
4652 usleep(10000); // Make sure the waiter blocks.
4653
4654 MU2.Lock();
4655 COND2 = 1;
4656 CV2.Signal();
4657 MU2.Unlock();
4658 }
Thr3()4659 void Thr3() {
4660 MU.Lock();
4661 while(COND != 1)
4662 CV.Wait(&MU);
4663 MU.Unlock();
4664 }
Thr4()4665 void 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 }
Run()4672 void 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 }
4681 REGISTER_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
4688 namespace test96 {
4689 int GLOB = 0;
4690
4691 Mutex A, B, C;
4692
Thread1()4693 void Thread1() {
4694 MutexLock a(&A);
4695 MutexLock b(&B);
4696 GLOB++;
4697 }
4698
Thread2()4699 void Thread2() {
4700 MutexLock b(&B);
4701 MutexLock c(&C);
4702 GLOB++;
4703 }
4704
Thread3()4705 void Thread3() {
4706 MutexLock a(&A);
4707 MutexLock c(&C);
4708 GLOB++;
4709 }
4710
Run()4711 void 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 }
4720 REGISTER_TEST(Run, 96);
4721 } // namespace test96
4722
4723 // test97: This test shows false negative with --fast-mode=yes {{{1
4724 namespace test97 {
4725 const int HG_CACHELINE_SIZE = 64;
4726
4727 Mutex MU;
4728
4729 const int ARRAY_SIZE = HG_CACHELINE_SIZE * 4 / sizeof(int);
4730 int array[ARRAY_SIZE];
4731 int * 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
Reader()4737 void Reader() {
4738 usleep(500000);
4739 CHECK(777 == *GLOB);
4740 }
4741
Run()4742 void 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
4753 REGISTER_TEST2(Run, 97, FEATURE)
4754 } // namespace test97
4755
4756 // test98: Synchronization via read/write (or send/recv). {{{1
4757 namespace 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 //
4768 int GLOB = 0;
4769 int fd_out = -1;
4770 int fd_in = -1;
4771
Writer()4772 void 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
Reader()4779 void 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
Run()4787 void 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 }
4815 REGISTER_TEST(Run, 98)
4816 } // namespace test98
4817
4818
4819 // test99: TP. Unit test for a bug in LockWhen*. {{{1
4820 namespace test99 {
4821
4822
4823 bool GLOB = false;
4824 Mutex mu;
4825
Thread1()4826 static 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
Thread2()4835 static void Thread2() {
4836 for (int i = 0; i < 100; i++) {
4837 mu.Lock();
4838 mu.Unlock();
4839 usleep(10000);
4840 }
4841 }
4842
Run()4843 void Run() {
4844 printf("test99: regression test for LockWhen*\n");
4845 MyThreadArray t(Thread1, Thread2);
4846 t.Start();
4847 t.Join();
4848 }
4849 REGISTER_TEST(Run, 99);
4850 } // namespace test99
4851
4852
4853 // test100: Test for initialization bit. {{{1
4854 namespace test100 {
4855 int G1 = 0;
4856 int G2 = 0;
4857 int G3 = 0;
4858 int G4 = 0;
4859
Creator()4860 void Creator() {
4861 G1 = 1; CHECK(G1);
4862 G2 = 1;
4863 G3 = 1; CHECK(G3);
4864 G4 = 1;
4865 }
4866
Worker1()4867 void Worker1() {
4868 usleep(100000);
4869 CHECK(G1);
4870 CHECK(G2);
4871 G3 = 3;
4872 G4 = 3;
4873 }
4874
Worker2()4875 void Worker2() {
4876
4877 }
4878
4879
Run()4880 void 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 }
4890 REGISTER_TEST2(Run, 100, FEATURE|EXCLUDE_FROM_ALL)
4891 } // namespace test100
4892
4893
4894 // test101: TN. Two signals and two waits. {{{1
4895 namespace test101 {
4896 Mutex MU;
4897 CondVar CV;
4898 int GLOB = 0;
4899
4900 int C1 = 0, C2 = 0;
4901
Signaller()4902 void 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
Waiter()4920 void 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
Run()4937 void Run() {
4938 printf("test101: negative\n");
4939 MyThreadArray t(Waiter, Signaller);
4940 t.Start();
4941 t.Join();
4942 printf("\tGLOB=%d\n", GLOB);
4943 }
4944 REGISTER_TEST(Run, 101)
4945 } // namespace test101
4946
4947 // test102: --fast-mode=yes vs. --initialization-bit=yes {{{1
4948 namespace test102 {
4949 const int HG_CACHELINE_SIZE = 64;
4950
4951 Mutex MU;
4952
4953 const int ARRAY_SIZE = HG_CACHELINE_SIZE * 4 / sizeof(int);
4954 int array[ARRAY_SIZE + 1];
4955 int * 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
Reader()4961 void Reader() {
4962 usleep(200000);
4963 CHECK(777 == GLOB[0]);
4964 usleep(400000);
4965 CHECK(777 == GLOB[1]);
4966 }
4967
Run()4968 void 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
4982 REGISTER_TEST2(Run, 102, FEATURE)
4983 } // namespace test102
4984
4985 // test103: Access different memory locations with different LockSets {{{1
4986 namespace test103 {
4987 const int N_MUTEXES = 6;
4988 const int LOCKSET_INTERSECTION_SIZE = 3;
4989
4990 int data[1 << LOCKSET_INTERSECTION_SIZE] = {0};
4991 Mutex MU[N_MUTEXES];
4992
LS_to_idx(int ls)4993 inline int LS_to_idx (int ls) {
4994 return (ls >> (N_MUTEXES - LOCKSET_INTERSECTION_SIZE))
4995 & ((1 << LOCKSET_INTERSECTION_SIZE) - 1);
4996 }
4997
Worker()4998 void 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
Run()5014 void 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 }
5020 REGISTER_TEST2(Run, 103, FEATURE)
5021 } // namespace test103
5022
5023 // test104: TP. Simple race (write vs write). Heap mem. {{{1
5024 namespace test104 {
5025 int *GLOB = NULL;
Worker()5026 void Worker() {
5027 *GLOB = 1;
5028 }
5029
Parent()5030 void Parent() {
5031 MyThread t(Worker);
5032 t.Start();
5033 usleep(100000);
5034 *GLOB = 2;
5035 t.Join();
5036 }
Run()5037 void 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 }
5047 REGISTER_TEST(Run, 104);
5048 } // namespace test104
5049
5050
5051 // test105: Checks how stack grows. {{{1
5052 namespace test105 {
5053 int GLOB = 0;
5054
F1()5055 void 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
Worker()5063 void 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
Run()5072 void 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 }
5080 REGISTER_TEST(Run, 105)
5081 } // namespace test105
5082
5083
5084 // test106: TN. pthread_once. {{{1
5085 namespace test106 {
5086 int *GLOB = NULL;
5087 static pthread_once_t once = PTHREAD_ONCE_INIT;
Init()5088 void Init() {
5089 GLOB = new int;
5090 ANNOTATE_TRACE_MEMORY(GLOB);
5091 *GLOB = 777;
5092 }
5093
Worker0()5094 void Worker0() {
5095 pthread_once(&once, Init);
5096 }
Worker1()5097 void Worker1() {
5098 usleep(100000);
5099 pthread_once(&once, Init);
5100 CHECK(*GLOB == 777);
5101 }
5102
5103
Run()5104 void 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 }
5111 REGISTER_TEST2(Run, 106, FEATURE)
5112 } // namespace test106
5113
5114
5115 // test107: Test for ANNOTATE_EXPECT_RACE {{{1
5116 namespace test107 {
5117 int GLOB = 0;
Run()5118 void 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 }
5123 REGISTER_TEST2(Run, 107, FEATURE|EXCLUDE_FROM_ALL)
5124 } // namespace test107
5125
5126
5127 // test108: TN. initialization of static object. {{{1
5128 namespace 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.
5137 class Foo {
5138 public:
Foo()5139 Foo() {
5140 ANNOTATE_TRACE_MEMORY(&a_);
5141 a_ = 42;
5142 }
Check() const5143 void Check() const { CHECK(a_ == 42); }
5144 private:
5145 int a_;
5146 };
5147
GetFoo()5148 const Foo *GetFoo() {
5149 static const Foo *foo = new Foo();
5150 return foo;
5151 }
Worker0()5152 void Worker0() {
5153 GetFoo();
5154 }
5155
Worker()5156 void Worker() {
5157 usleep(200000);
5158 const Foo *foo = GetFoo();
5159 foo->Check();
5160 }
5161
5162
Run()5163 void Run() {
5164 printf("test108: negative, initialization of static object\n");
5165 MyThreadArray t(Worker0, Worker, Worker);
5166 t.Start();
5167 t.Join();
5168 }
5169 REGISTER_TEST2(Run, 108, FEATURE)
5170 } // namespace test108
5171
5172
5173 // test109: TN. Checking happens before between parent and child threads. {{{1
5174 namespace test109 {
5175 // Check that the detector correctly connects
5176 // pthread_create with the new thread
5177 // and
5178 // thread exit with pthread_join
5179 const int N = 32;
5180 static int GLOB[N];
5181
Worker(void * a)5182 void 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
Run()5189 void 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 }
5211 REGISTER_TEST(Run, 109)
5212 } // namespace test109
5213
5214
5215 // test110: TP. Simple races with stack, global and heap objects. {{{1
5216 namespace test110 {
5217 int GLOB = 0;
5218 static int STATIC;
5219
5220 int *STACK = 0;
5221
5222 int *MALLOC;
5223 int *CALLOC;
5224 int *REALLOC;
5225 int *VALLOC;
5226 int *PVALLOC;
5227 int *MEMALIGN;
5228 union pi_pv_union { int* pi; void* pv; } POSIX_MEMALIGN;
5229 int *MMAP;
5230
5231 int *NEW;
5232 int *NEW_ARR;
5233
Worker()5234 void 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 }
Run()5252 void 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 }
5317 REGISTER_TEST(Run, 110)
5318 } // namespace test110
5319
5320
5321 // test111: TN. Unit test for a bug related to stack handling. {{{1
5322 namespace test111 {
5323 char *GLOB = 0;
5324 bool COND = false;
5325 Mutex mu;
5326 const int N = 3000;
5327
write_to_p(char * p,int val)5328 void write_to_p(char *p, int val) {
5329 for (int i = 0; i < N; i++)
5330 p[i] = val;
5331 }
5332
ArgIsTrue(bool * arg)5333 static bool ArgIsTrue(bool *arg) {
5334 // printf("ArgIsTrue: %d tid=%d\n", *arg, (int)pthread_self());
5335 return *arg == true;
5336 }
5337
f1()5338 void f1() {
5339 char some_stack[N];
5340 write_to_p(some_stack, 1);
5341 mu.LockWhen(Condition(&ArgIsTrue, &COND));
5342 mu.Unlock();
5343 }
5344
f2()5345 void 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
f0()5352 void f0() { f2(); }
5353
Worker1()5354 void Worker1() {
5355 f0();
5356 f1();
5357 f2();
5358 }
5359
Worker2()5360 void Worker2() {
5361 usleep(100000);
5362 mu.Lock();
5363 COND = true;
5364 mu.Unlock();
5365 }
5366
Run()5367 void 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 }
5375 REGISTER_TEST2(Run, 111, FEATURE)
5376 } // namespace test111
5377
5378 // test112: STAB. Test for ANNOTATE_PUBLISH_MEMORY_RANGE{{{1
5379 namespace test112 {
5380 char *GLOB = 0;
5381 const int N = 64 * 5;
5382 Mutex mu;
5383 bool ready = false; // under mu
5384 int beg, end; // under mu
5385
5386 Mutex mu1;
5387
Worker()5388 void 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
PublishRange(int b,int e)5408 void 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
Run()5430 void 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 }
5454 REGISTER_TEST2(Run, 112, STABILITY)
5455 } // namespace test112
5456
5457
5458 // test113: PERF. A lot of lock/unlock calls. Many locks {{{1
5459 namespace test113 {
5460 const int kNumIter = 100000;
5461 const int kNumLocks = 7;
5462 Mutex MU[kNumLocks];
Run()5463 void 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 }
5474 REGISTER_TEST(Run, 113)
5475 } // namespace test113
5476
5477
5478 // test114: STAB. Recursive lock. {{{1
5479 namespace test114 {
Bar()5480 int Bar() {
5481 static int bar = 1;
5482 return bar;
5483 }
Foo()5484 int Foo() {
5485 static int foo = Bar();
5486 return foo;
5487 }
Worker()5488 void Worker() {
5489 static int x = Foo();
5490 CHECK(x == 1);
5491 }
Run()5492 void Run() {
5493 printf("test114: stab\n");
5494 MyThreadArray t(Worker, Worker);
5495 t.Start();
5496 t.Join();
5497 }
5498 REGISTER_TEST(Run, 114)
5499 } // namespace test114
5500
5501
5502 // test115: TN. sem_open. {{{1
5503 namespace test115 {
5504 int tid = 0;
5505 Mutex mu;
5506 const char *kSemName = "drt-test-sem";
5507
5508 int GLOB = 0;
5509
DoSemOpen()5510 sem_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
Worker()5519 void 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
Run()5540 void 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 }
5557 REGISTER_TEST(Run, 115)
5558 } // namespace test115
5559
5560
5561 // test116: TN. some operations with string<> objects. {{{1
5562 namespace test116 {
5563
Worker()5564 void 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
Run()5591 void Run() {
5592 printf("test116: negative (strings)\n");
5593 MyThreadArray t(Worker, Worker, Worker);
5594 t.Start();
5595 t.Join();
5596 }
5597 REGISTER_TEST2(Run, 116, FEATURE|EXCLUDE_FROM_ALL)
5598 } // namespace test116
5599
5600 // test117: TN. Many calls to function-scope static init. {{{1
5601 namespace test117 {
5602 const int N = 50;
5603
Foo()5604 int Foo() {
5605 usleep(20000);
5606 return 1;
5607 }
5608
Worker(void * a)5609 void Worker(void *a) {
5610 static int foo = Foo();
5611 CHECK(foo == 1);
5612 }
5613
Run()5614 void 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 }
5628 REGISTER_TEST(Run, 117)
5629 } // namespace test117
5630
5631
5632
5633 // test118 PERF: One signal, multiple waits. {{{1
5634 namespace test118 {
5635 int GLOB = 0;
5636 const int kNumIter = 2000000;
Signaller()5637 void Signaller() {
5638 usleep(50000);
5639 ANNOTATE_CONDVAR_SIGNAL(&GLOB);
5640 }
Waiter()5641 void Waiter() {
5642 for (int i = 0; i < kNumIter; i++) {
5643 ANNOTATE_CONDVAR_WAIT(&GLOB);
5644 if (i == kNumIter / 2)
5645 usleep(100000);
5646 }
5647 }
Run()5648 void 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 }
5655 REGISTER_TEST(Run, 118)
5656 } // namespace test118
5657
5658
5659 // test119: TP. Testing that malloc does not introduce any HB arc. {{{1
5660 namespace test119 {
5661 int GLOB = 0;
Worker1()5662 void Worker1() {
5663 GLOB = 1;
5664 free(malloc(123));
5665 }
Worker2()5666 void Worker2() {
5667 usleep(100000);
5668 free(malloc(345));
5669 GLOB = 2;
5670 }
Run()5671 void 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 }
5681 REGISTER_TEST(Run, 119)
5682 } // namespace test119
5683
5684
5685 // test120: TP. Thread1: write then read. Thread2: read. {{{1
5686 namespace test120 {
5687 int GLOB = 0;
5688
Thread1()5689 void Thread1() {
5690 GLOB = 1; // write
5691 CHECK(GLOB); // read
5692 }
5693
Thread2()5694 void Thread2() {
5695 usleep(100000);
5696 CHECK(GLOB >= 0); // read
5697 }
5698
Run()5699 void 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 }
5709 REGISTER_TEST(Run, 120)
5710 } // namespace test120
5711
5712
5713 // test121: TP. Example of double-checked-locking {{{1
5714 namespace test121 {
5715 struct Foo {
5716 uintptr_t a, b[15];
5717 } __attribute__ ((aligned (64)));
5718
5719 static Mutex mu;
5720 static Foo *foo;
5721
InitMe()5722 void 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
UseMe()5735 void UseMe() {
5736 InitMe();
5737 CHECK(foo && foo->a == 42);
5738 }
5739
Worker1()5740 void Worker1() { UseMe(); }
Worker2()5741 void Worker2() { UseMe(); }
Worker3()5742 void Worker3() { UseMe(); }
5743
5744
Run()5745 void 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 }
5753 REGISTER_TEST(Run, 121)
5754 } // namespace test121
5755
5756 // test122 TP: Simple test with RWLock {{{1
5757 namespace test122 {
5758 int VAR1 = 0;
5759 int VAR2 = 0;
5760 RWLock mu;
5761
WriteWhileHoldingReaderLock(int * p)5762 void WriteWhileHoldingReaderLock(int *p) {
5763 usleep(100000);
5764 ReaderLockScoped lock(&mu); // Reader lock for writing. -- bug.
5765 (*p)++;
5766 }
5767
CorrectWrite(int * p)5768 void CorrectWrite(int *p) {
5769 WriterLockScoped lock(&mu);
5770 (*p)++;
5771 }
5772
Thread1()5773 void Thread1() { WriteWhileHoldingReaderLock(&VAR1); }
Thread2()5774 void Thread2() { CorrectWrite(&VAR1); }
Thread3()5775 void Thread3() { CorrectWrite(&VAR2); }
Thread4()5776 void Thread4() { WriteWhileHoldingReaderLock(&VAR2); }
5777
5778
Run()5779 void 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 }
5793 REGISTER_TEST(Run, 122)
5794 } // namespace test122
5795
5796
5797 // test123 TP: accesses of different sizes. {{{1
5798 namespace test123 {
5799
5800 union uint_union {
5801 uint64_t u64[1];
5802 uint32_t u32[2];
5803 uint16_t u16[4];
5804 uint8_t u8[8];
5805 };
5806
5807 uint_union MEM[8];
5808
5809 // Q. Hey dude, why so many functions?
5810 // A. I need different stack traces for different accesses.
5811
Wr64_0()5812 void Wr64_0() { MEM[0].u64[0] = 1; }
Wr64_1()5813 void Wr64_1() { MEM[1].u64[0] = 1; }
Wr64_2()5814 void Wr64_2() { MEM[2].u64[0] = 1; }
Wr64_3()5815 void Wr64_3() { MEM[3].u64[0] = 1; }
Wr64_4()5816 void Wr64_4() { MEM[4].u64[0] = 1; }
Wr64_5()5817 void Wr64_5() { MEM[5].u64[0] = 1; }
Wr64_6()5818 void Wr64_6() { MEM[6].u64[0] = 1; }
Wr64_7()5819 void Wr64_7() { MEM[7].u64[0] = 1; }
5820
Wr32_0()5821 void Wr32_0() { MEM[0].u32[0] = 1; }
Wr32_1()5822 void Wr32_1() { MEM[1].u32[1] = 1; }
Wr32_2()5823 void Wr32_2() { MEM[2].u32[0] = 1; }
Wr32_3()5824 void Wr32_3() { MEM[3].u32[1] = 1; }
Wr32_4()5825 void Wr32_4() { MEM[4].u32[0] = 1; }
Wr32_5()5826 void Wr32_5() { MEM[5].u32[1] = 1; }
Wr32_6()5827 void Wr32_6() { MEM[6].u32[0] = 1; }
Wr32_7()5828 void Wr32_7() { MEM[7].u32[1] = 1; }
5829
Wr16_0()5830 void Wr16_0() { MEM[0].u16[0] = 1; }
Wr16_1()5831 void Wr16_1() { MEM[1].u16[1] = 1; }
Wr16_2()5832 void Wr16_2() { MEM[2].u16[2] = 1; }
Wr16_3()5833 void Wr16_3() { MEM[3].u16[3] = 1; }
Wr16_4()5834 void Wr16_4() { MEM[4].u16[0] = 1; }
Wr16_5()5835 void Wr16_5() { MEM[5].u16[1] = 1; }
Wr16_6()5836 void Wr16_6() { MEM[6].u16[2] = 1; }
Wr16_7()5837 void Wr16_7() { MEM[7].u16[3] = 1; }
5838
Wr8_0()5839 void Wr8_0() { MEM[0].u8[0] = 1; }
Wr8_1()5840 void Wr8_1() { MEM[1].u8[1] = 1; }
Wr8_2()5841 void Wr8_2() { MEM[2].u8[2] = 1; }
Wr8_3()5842 void Wr8_3() { MEM[3].u8[3] = 1; }
Wr8_4()5843 void Wr8_4() { MEM[4].u8[4] = 1; }
Wr8_5()5844 void Wr8_5() { MEM[5].u8[5] = 1; }
Wr8_6()5845 void Wr8_6() { MEM[6].u8[6] = 1; }
Wr8_7()5846 void Wr8_7() { MEM[7].u8[7] = 1; }
5847
WriteAll64()5848 void 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
WriteAll32()5859 void 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
WriteAll16()5870 void 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
WriteAll8()5881 void 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
W00()5892 void W00() { WriteAll64(); }
W01()5893 void W01() { WriteAll64(); }
W02()5894 void W02() { WriteAll64(); }
5895
W10()5896 void W10() { WriteAll32(); }
W11()5897 void W11() { WriteAll32(); }
W12()5898 void W12() { WriteAll32(); }
5899
W20()5900 void W20() { WriteAll16(); }
W21()5901 void W21() { WriteAll16(); }
W22()5902 void W22() { WriteAll16(); }
5903
W30()5904 void W30() { WriteAll8(); }
W31()5905 void W31() { WriteAll8(); }
W32()5906 void W32() { WriteAll8(); }
5907
5908 typedef void (*F)(void);
5909
TestTwoSizes(F f1,F f2)5910 void 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
Run()5925 void 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 }
5935 REGISTER_TEST2(Run, 123, FEATURE|EXCLUDE_FROM_ALL)
5936 } // namespace test123
5937
5938
5939 // test124: What happens if we delete an unlocked lock? {{{1
5940 namespace test124 {
5941 // This test does not worg with pthreads (you can't call
5942 // pthread_mutex_destroy on a locked lock).
5943 int GLOB = 0;
5944 const int N = 1000;
Worker()5945 void 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
Run()5955 void 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 }
5962 REGISTER_TEST2(Run, 124, FEATURE|EXCLUDE_FROM_ALL)
5963 } // namespace test124
5964
5965
5966 // test125 TN: Backwards lock (annotated). {{{1
5967 namespace 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
5978 const int n_threads = 3;
5979 RWLock mu;
5980 int GLOB[n_threads];
5981
5982 int adder_num; // updated atomically.
5983
Adder()5984 void Adder() {
5985 int my_num = AtomicIncrement(&adder_num, 1);
5986
5987 ReaderLockScoped lock(&mu);
5988 GLOB[my_num]++;
5989 }
5990
Aggregator()5991 void 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
Run()6002 void 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 }
6023 REGISTER_TEST(Run, 125)
6024 } // namespace test125
6025
6026 // test126 TN: test for BlockingCounter {{{1
6027 namespace test126 {
6028 BlockingCounter *blocking_counter;
6029 int GLOB = 0;
Worker()6030 void Worker() {
6031 CHECK(blocking_counter);
6032 CHECK(GLOB == 0);
6033 blocking_counter->DecrementCount();
6034 }
Run()6035 void 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 }
6045 REGISTER_TEST(Run, 126)
6046 } // namespace test126
6047
6048
6049 // test127. Bad code: unlocking a mutex locked by another thread. {{{1
6050 namespace test127 {
6051 Mutex mu;
Thread1()6052 void Thread1() {
6053 mu.Lock();
6054 }
Thread2()6055 void Thread2() {
6056 usleep(100000);
6057 mu.Unlock();
6058 }
Run()6059 void Run() {
6060 printf("test127: unlocking a mutex locked by another thread.\n");
6061 MyThreadArray t(Thread1, Thread2);
6062 t.Start();
6063 t.Join();
6064 }
6065 REGISTER_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.
6070 namespace test128 {
6071 Mutex mu;
6072 int GLOB = 0;
Worker()6073 void Worker() {
6074 usleep(100000);
6075 mu.Lock();
6076 GLOB++;
6077 mu.Unlock();
6078 }
ThisFunctionShouldBeSuppressed()6079 void ThisFunctionShouldBeSuppressed() {
6080 GLOB++;
6081 }
Run()6082 void Run() {
6083 printf("test128: Suppressed code in concurrent accesses.\n");
6084 MyThreadArray t(Worker, ThisFunctionShouldBeSuppressed);
6085 t.Start();
6086 t.Join();
6087 }
6088 REGISTER_TEST2(Run, 128, FEATURE | EXCLUDE_FROM_ALL)
6089 } // namespace test128
6090
6091 // test129: TN. Synchronization via ReaderLockWhen(). {{{1
6092 namespace test129 {
6093 int GLOB = 0;
6094 Mutex MU;
WeirdCondition(int * param)6095 bool WeirdCondition(int* param) {
6096 *param = GLOB; // a write into Waiter's memory
6097 return GLOB > 0;
6098 }
Waiter()6099 void Waiter() {
6100 int param = 0;
6101 MU.ReaderLockWhen(Condition(WeirdCondition, ¶m));
6102 MU.ReaderUnlock();
6103 CHECK(GLOB > 0);
6104 CHECK(param > 0);
6105 }
Waker()6106 void Waker() {
6107 usleep(100000); // Make sure the waiter blocks.
6108 MU.Lock();
6109 GLOB++;
6110 MU.Unlock(); // calls ANNOTATE_CONDVAR_SIGNAL;
6111 }
Run()6112 void 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 }
6120 REGISTER_TEST2(Run, 129, FEATURE);
6121 } // namespace test129
6122
6123 // test130: TN. Per-thread. {{{1
6124 namespace 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
6141 static __thread int per_thread_global[10] = {0};
6142
RealWorker()6143 void RealWorker() { // Touch per_thread_global.
6144 per_thread_global[1]++;
6145 errno++;
6146 }
6147
Worker()6148 void Worker() { // Spawn few threads that touch per_thread_global.
6149 MyThreadArray t(RealWorker, RealWorker);
6150 t.Start();
6151 t.Join();
6152 }
Worker0()6153 void Worker0() { sleep(0); Worker(); }
Worker1()6154 void Worker1() { sleep(1); Worker(); }
Worker2()6155 void Worker2() { sleep(2); Worker(); }
Worker3()6156 void Worker3() { sleep(3); Worker(); }
6157
Run()6158 void 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 }
6165 REGISTER_TEST(Run, 130)
6166 #endif // NO_TLS
6167 } // namespace test130
6168
6169
6170 // test131: TN. Stack. {{{1
6171 namespace test131 {
6172 // Same as test130, but for stack.
6173
RealWorker()6174 void RealWorker() { // Touch stack.
6175 int stack_var = 0;
6176 stack_var++;
6177 }
6178
Worker()6179 void Worker() { // Spawn few threads that touch stack.
6180 MyThreadArray t(RealWorker, RealWorker);
6181 t.Start();
6182 t.Join();
6183 }
Worker0()6184 void Worker0() { sleep(0); Worker(); }
Worker1()6185 void Worker1() { sleep(1); Worker(); }
Worker2()6186 void Worker2() { sleep(2); Worker(); }
Worker3()6187 void Worker3() { sleep(3); Worker(); }
6188
Run()6189 void Run() {
6190 printf("test131: stack\n");
6191 MyThreadArray t(Worker0, Worker1, Worker2, Worker3);
6192 t.Start();
6193 t.Join();
6194 }
6195 REGISTER_TEST(Run, 131)
6196 } // namespace test131
6197
6198
6199 // test132: TP. Simple race (write vs write). Works in fast-mode. {{{1
6200 namespace test132 {
6201 int GLOB = 0;
Worker()6202 void Worker() { GLOB = 1; }
6203
Run1()6204 void 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
Run()6215 void Run() {
6216 Run1();
6217 }
6218 REGISTER_TEST(Run, 132);
6219 } // namespace test132
6220
6221
6222 // test133: TP. Simple race (write vs write). Works in fast mode. {{{1
6223 namespace test133 {
6224 // Same as test132, but everything is run from a separate thread spawned from
6225 // the main thread.
6226 int GLOB = 0;
Worker()6227 void Worker() { GLOB = 1; }
6228
Run1()6229 void 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 }
Run()6239 void Run() {
6240 MyThread t(Run1);
6241 t.Start();
6242 t.Join();
6243 }
6244 REGISTER_TEST(Run, 133);
6245 } // namespace test133
6246
6247
6248 // test134 TN. Swap. Variant of test79. {{{1
6249 namespace test134 {
6250 #if 0
6251 typedef __gnu_cxx::hash_map<int, int> map_t;
6252 #else
6253 typedef std::map<int, int> map_t;
6254 #endif
6255 map_t map;
6256 Mutex 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.
Swapper()6268 void 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
Worker()6278 void Worker() {
6279 MutexLock lock(&mu);
6280 ANNOTATE_HAPPENS_AFTER(&map);
6281 map[1]++;
6282 ANNOTATE_HAPPENS_BEFORE(&map);
6283 }
6284
Run()6285 void 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 }
6293 REGISTER_TEST(Run, 134)
6294 } // namespace test134
6295
6296 // test135 TN. Swap. Variant of test79. {{{1
6297 namespace test135 {
6298
SubWorker()6299 void 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
Worker()6309 void Worker() {
6310 MyThreadArray t(SubWorker, SubWorker, SubWorker, SubWorker);
6311 t.Start();
6312 t.Join();
6313 }
6314
Run()6315 void Run() {
6316 printf("test135: negative (mmap)\n");
6317 MyThreadArray t(Worker, Worker, Worker, Worker);
6318 t.Start();
6319 t.Join();
6320 }
6321 REGISTER_TEST(Run, 135)
6322 } // namespace test135
6323
6324 // test136. Unlock twice. {{{1
6325 namespace test136 {
Run()6326 void 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
6343 REGISTER_TEST(Run, 136)
6344 } // namespace test136
6345
6346 // test137 TP. Races on stack variables. {{{1
6347 namespace test137 {
6348 int GLOB = 0;
6349 ProducerConsumerQueue q(10);
6350
Worker()6351 void 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
Run()6362 void 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
6372 REGISTER_TEST2(Run, 137, FEATURE | EXCLUDE_FROM_ALL)
6373 } // namespace test137
6374
6375 // test138 FN. Two closures hit the same thread in ThreadPool. {{{1
6376 namespace test138 {
6377 int GLOB = 0;
6378
Worker()6379 void Worker() {
6380 usleep(100000);
6381 GLOB++;
6382 }
6383
Run()6384 void 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
6400 REGISTER_TEST2(Run, 138, FEATURE)
6401 } // namespace test138
6402
6403 // test139: FN. A true race hidden by reference counting annotation. {{{1
6404 namespace test139 {
6405 int GLOB = 0;
6406 RefCountedClass *obj;
6407
Worker1()6408 void Worker1() {
6409 GLOB++; // First access.
6410 obj->Unref();
6411 }
6412
Worker2()6413 void Worker2() {
6414 usleep(100000);
6415 obj->Unref();
6416 GLOB++; // Second access.
6417 }
6418
Run()6419 void 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
6432 REGISTER_TEST2(Run, 139, FEATURE)
6433 } // namespace test139
6434
6435 // test140 TN. Swap. Variant of test79 and test134. {{{1
6436 namespace test140 {
6437 #if 0
6438 typedef __gnu_cxx::hash_map<int, int> Container;
6439 #else
6440 typedef std::map<int,int> Container;
6441 #endif
6442 Mutex mu;
6443 static 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.
Swapper()6460 void 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
Worker()6476 void 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
Run()6489 void Run() {
6490 printf("test140: negative (swap) %p\n", &container);
6491 MyThreadArray t(Worker, Worker, Swapper, Worker, Worker);
6492 t.Start();
6493 t.Join();
6494 }
6495 REGISTER_TEST(Run, 140)
6496 } // namespace test140
6497
6498 // test141 FP. unlink/fopen, rmdir/opendir. {{{1
6499 namespace test141 {
6500 int GLOB1 = 0,
6501 GLOB2 = 0;
6502 char *dir_name = NULL,
6503 *filename = NULL;
6504
Waker1()6505 void 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
Waiter1()6514 void 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
Waker2()6524 void 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
Waiter2()6533 void 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
Run()6543 void 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 }
6568 REGISTER_TEST(Run, 141)
6569 } // namespace test141
6570
6571
6572 // Simple FIFO queue annotated with PCQ annotations. {{{1
6573 class FifoMessageQueue {
6574 public:
FifoMessageQueue()6575 FifoMessageQueue() { ANNOTATE_PCQ_CREATE(this); }
~FifoMessageQueue()6576 ~FifoMessageQueue() { ANNOTATE_PCQ_DESTROY(this); }
6577 // Send a message. 'message' should be positive.
Put(int message)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.
Get()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
6601 namespace 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
6606 const int N = 1000;
6607 int array[N+1];
6608
6609 FifoMessageQueue q;
6610
Putter()6611 void Putter() {
6612 for (int i = 1; i <= N; i++) {
6613 array[i] = i*i;
6614 q.Put(i);
6615 usleep(1000);
6616 }
6617 }
6618
Getter()6619 void 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
Run()6633 void Run() {
6634 printf("test142: tests PCQ annotations\n");
6635 MyThreadArray t(Putter, Getter, Getter);
6636 t.Start();
6637 t.Join();
6638 }
6639 REGISTER_TEST(Run, 142)
6640 } // namespace test142
6641
6642
6643 // test143: TP. Check PCQ_* annotations. {{{1
6644 namespace 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.
6651 int GLOB = 0;
6652
6653 FifoMessageQueue q;
6654
Putter()6655 void Putter() {
6656 GLOB = 1;
6657 q.Put(1);
6658 }
6659
Getter()6660 void Getter() {
6661 usleep(10000);
6662 q.Get();
6663 CHECK(GLOB == 1); // Race here
6664 }
6665
Run()6666 void 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 }
6676 REGISTER_TEST(Run, 143);
6677 } // namespace test143
6678
6679
6680
6681
6682 // test300: {{{1
6683 namespace test300 {
6684 int GLOB = 0;
Run()6685 void Run() {
6686 }
6687 REGISTER_TEST2(Run, 300, RACE_DEMO)
6688 } // namespace test300
6689
6690 // test301: Simple race. {{{1
6691 namespace test301 {
6692 Mutex mu1; // This Mutex guards var.
6693 Mutex mu2; // This Mutex is not related to var.
6694 int var; // GUARDED_BY(mu1)
6695
Thread1()6696 void Thread1() { // Runs in thread named 'test-thread-1'.
6697 MutexLock lock(&mu1); // Correct Mutex.
6698 var = 1;
6699 }
6700
Thread2()6701 void Thread2() { // Runs in thread named 'test-thread-2'.
6702 MutexLock lock(&mu2); // Wrong Mutex.
6703 var = 2;
6704 }
6705
Run()6706 void 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 }
6716 REGISTER_TEST2(Run, 301, RACE_DEMO)
6717 } // namespace test301
6718
6719 // test302: Complex race which happens at least twice. {{{1
6720 namespace test302 {
6721 // In this test we have many different accesses to GLOB and only one access
6722 // is not synchronized properly.
6723 int GLOB = 0;
6724
6725 Mutex MU1;
6726 Mutex MU2;
Worker()6727 void 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
Run()6753 void 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 }
6760 REGISTER_TEST2(Run, 302, RACE_DEMO)
6761 } // namespace test302
6762
6763
6764 // test303: Need to trace the memory to understand the report. {{{1
6765 namespace test303 {
6766 int GLOB = 0;
6767
6768 Mutex MU;
Worker1()6769 void Worker1() { CHECK(GLOB >= 0); }
Worker2()6770 void Worker2() { MU.Lock(); GLOB=1; MU.Unlock();}
6771
Run()6772 void 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 }
6779 REGISTER_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
6785 namespace test304 {
6786 string *STR;
6787 Mutex MU;
6788
Worker1()6789 void Worker1() {
6790 sleep(0);
6791 ANNOTATE_CONDVAR_SIGNAL((void*)0xDEADBEAF);
6792 MU.Lock(); CHECK(STR->length() >= 4); MU.Unlock();
6793 }
Worker2()6794 void Worker2() {
6795 sleep(1);
6796 ANNOTATE_CONDVAR_SIGNAL((void*)0xDEADBEAF);
6797 CHECK(STR->length() >= 4); // Unprotected!
6798 }
Worker3()6799 void Worker3() {
6800 sleep(2);
6801 ANNOTATE_CONDVAR_SIGNAL((void*)0xDEADBEAF);
6802 MU.Lock(); CHECK(STR->length() >= 4); MU.Unlock();
6803 }
Worker4()6804 void Worker4() {
6805 sleep(3);
6806 ANNOTATE_CONDVAR_SIGNAL((void*)0xDEADBEAF);
6807 MU.Lock(); *STR += " + a very very long string"; MU.Unlock();
6808 }
6809
Run()6810 void 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 }
6820 REGISTER_TEST2(Run, 304, RACE_DEMO)
6821 } // namespace test304
6822
6823
6824
6825 // test305: A bit more tricky: two locks used inconsistenly. {{{1
6826 namespace test305 {
6827 int 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.
6838 Mutex MU1;
6839 Mutex MU2;
Worker1()6840 void Worker1() { MU1.Lock(); MU2.Lock(); GLOB=1; MU2.Unlock(); MU1.Unlock(); }
Worker2()6841 void Worker2() { MU1.Lock(); GLOB=2; MU1.Unlock(); }
Worker3()6842 void Worker3() { MU1.Lock(); MU2.Lock(); GLOB=3; MU2.Unlock(); MU1.Unlock(); }
Worker4()6843 void Worker4() { MU2.Lock(); GLOB=4; MU2.Unlock(); }
6844
Run()6845 void 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 }
6855 REGISTER_TEST2(Run, 305, RACE_DEMO)
6856 } // namespace test305
6857
6858 // test306: Two locks are used to protect a var. {{{1
6859 namespace test306 {
6860 int GLOB = 0;
6861 // Thread1 and Thread2 access the var under two locks.
6862 // Thread3 uses no locks.
6863
6864 Mutex MU1;
6865 Mutex MU2;
Worker1()6866 void Worker1() { MU1.Lock(); MU2.Lock(); GLOB=1; MU2.Unlock(); MU1.Unlock(); }
Worker2()6867 void Worker2() { MU1.Lock(); MU2.Lock(); GLOB=3; MU2.Unlock(); MU1.Unlock(); }
Worker3()6868 void Worker3() { GLOB=4; }
6869
Run()6870 void 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 }
6879 REGISTER_TEST2(Run, 306, RACE_DEMO)
6880 } // namespace test306
6881
6882 // test307: Simple race, code with control flow {{{1
6883 namespace test307 {
6884 int *GLOB = 0;
6885 volatile /*to fake the compiler*/ bool some_condition = true;
6886
6887
SomeFunc()6888 void SomeFunc() { }
6889
FunctionWithControlFlow()6890 int 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
Worker1()6905 void Worker1() { FunctionWithControlFlow(); }
Worker2()6906 void Worker2() { Worker1(); }
Worker3()6907 void Worker3() { Worker2(); }
Worker4()6908 void Worker4() { Worker3(); }
6909
Run()6910 void 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 }
6918 REGISTER_TEST2(Run, 307, RACE_DEMO)
6919 } // namespace test307
6920
6921 // test308: Example of double-checked-locking {{{1
6922 namespace test308 {
6923 struct Foo {
6924 int a;
6925 };
6926
6927 static int is_inited = 0;
6928 static Mutex lock;
6929 static Foo *foo;
6930
InitMe()6931 void 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
UseMe()6943 void UseMe() {
6944 InitMe();
6945 CHECK(foo && foo->a == 42);
6946 }
6947
Worker1()6948 void Worker1() { UseMe(); }
Worker2()6949 void Worker2() { UseMe(); }
Worker3()6950 void Worker3() { UseMe(); }
6951
6952
Run()6953 void 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 }
6960 REGISTER_TEST2(Run, 308, RACE_DEMO)
6961 } // namespace test308
6962
6963 // test309: Simple race on an STL object. {{{1
6964 namespace test309 {
6965 string GLOB;
6966
Worker1()6967 void Worker1() {
6968 GLOB="Thread1";
6969 }
Worker2()6970 void Worker2() {
6971 usleep(100000);
6972 GLOB="Booooooooooo";
6973 }
6974
Run()6975 void 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 }
6982 REGISTER_TEST2(Run, 309, RACE_DEMO)
6983 } // namespace test309
6984
6985 // test310: One more simple race. {{{1
6986 namespace test310 {
6987 int *PTR = NULL; // GUARDED_BY(mu1)
6988
6989 Mutex mu1; // Protects PTR.
6990 Mutex mu2; // Unrelated to PTR.
6991 Mutex mu3; // Unrelated to PTR.
6992
Writer1()6993 void Writer1() {
6994 MutexLock lock3(&mu3); // This lock is unrelated to PTR.
6995 MutexLock lock1(&mu1); // Protect PTR.
6996 *PTR = 1;
6997 }
6998
Writer2()6999 void 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
Reader()7009 void 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.
DoWrite1()7015 void DoWrite1() { Writer1(); }
Thread1()7016 void Thread1() { DoWrite1(); }
7017
DoWrite2()7018 void DoWrite2() { Writer2(); }
Thread2()7019 void Thread2() { DoWrite2(); }
7020
DoRead()7021 void DoRead() { Reader(); }
Thread3()7022 void Thread3() { DoRead(); }
7023
Run()7024 void 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 }
7041 REGISTER_TEST2(Run, 310, RACE_DEMO)
7042 } // namespace test310
7043
7044 // test311: Yet another simple race. {{{1
7045 namespace test311 {
7046 int *PTR = NULL; // GUARDED_BY(mu1)
7047
7048 Mutex mu1; // Protects PTR.
7049 Mutex mu2; // Unrelated to PTR.
7050 Mutex mu3; // Unrelated to PTR.
7051
GoodWriter1()7052 void GoodWriter1() {
7053 MutexLock lock3(&mu3); // This lock is unrelated to PTR.
7054 MutexLock lock1(&mu1); // Protect PTR.
7055 *PTR = 1;
7056 }
7057
GoodWriter2()7058 void GoodWriter2() {
7059 MutexLock lock2(&mu2); // This lock is unrelated to PTR.
7060 MutexLock lock1(&mu1); // Protect PTR.
7061 *PTR = 2;
7062 }
7063
GoodReader()7064 void GoodReader() {
7065 MutexLock lock1(&mu1); // Protect PTR.
7066 CHECK(*PTR >= 0);
7067 }
7068
BuggyWriter()7069 void BuggyWriter() {
7070 MutexLock lock2(&mu2); // Wrong mutex!
7071 *PTR = 3;
7072 }
7073
7074 // Some functions to make the stack trace non-trivial.
DoWrite1()7075 void DoWrite1() { GoodWriter1(); }
Thread1()7076 void Thread1() { DoWrite1(); }
7077
DoWrite2()7078 void DoWrite2() { GoodWriter2(); }
Thread2()7079 void Thread2() { DoWrite2(); }
7080
DoGoodRead()7081 void DoGoodRead() { GoodReader(); }
Thread3()7082 void Thread3() { DoGoodRead(); }
7083
DoBadWrite()7084 void DoBadWrite() { BuggyWriter(); }
Thread4()7085 void Thread4() { DoBadWrite(); }
7086
Run()7087 void 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 }
7109 REGISTER_TEST2(Run, 311, RACE_DEMO)
7110 } // namespace test311
7111
7112 // test312: A test with a very deep stack. {{{1
7113 namespace test312 {
7114 int GLOB = 0;
RaceyWrite()7115 void RaceyWrite() { GLOB++; }
Func1()7116 void Func1() { RaceyWrite(); }
Func2()7117 void Func2() { Func1(); }
Func3()7118 void Func3() { Func2(); }
Func4()7119 void Func4() { Func3(); }
Func5()7120 void Func5() { Func4(); }
Func6()7121 void Func6() { Func5(); }
Func7()7122 void Func7() { Func6(); }
Func8()7123 void Func8() { Func7(); }
Func9()7124 void Func9() { Func8(); }
Func10()7125 void Func10() { Func9(); }
Func11()7126 void Func11() { Func10(); }
Func12()7127 void Func12() { Func11(); }
Func13()7128 void Func13() { Func12(); }
Func14()7129 void Func14() { Func13(); }
Func15()7130 void Func15() { Func14(); }
Func16()7131 void Func16() { Func15(); }
Func17()7132 void Func17() { Func16(); }
Func18()7133 void Func18() { Func17(); }
Func19()7134 void Func19() { Func18(); }
Worker()7135 void Worker() { Func19(); }
Run()7136 void Run() {
7137 printf("test312: simple race with deep stack.\n");
7138 MyThreadArray t(Worker, Worker, Worker);
7139 t.Start();
7140 t.Join();
7141 }
7142 REGISTER_TEST2(Run, 312, RACE_DEMO)
7143 } // namespace test312
7144
7145 // test313 TP: test for thread graph output {{{1
7146 namespace test313 {
7147 BlockingCounter *blocking_counter;
7148 int GLOB = 0;
7149
7150 // Worker(N) will do 2^N increments of GLOB, each increment in a separate thread
Worker(long depth)7151 void 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 }
Run()7162 void Run() {
7163 printf("test313: positive\n");
7164 Worker(4);
7165 printf("\tGLOB=%d\n", GLOB);
7166 }
7167 REGISTER_TEST2(Run, 313, RACE_DEMO)
7168 } // namespace test313
7169
7170
7171
7172 // test400: Demo of a simple false positive. {{{1
7173 namespace test400 {
7174 static Mutex mu;
7175 static vector<int> *vec; // GUARDED_BY(mu);
7176
InitAllBeforeStartingThreads()7177 void InitAllBeforeStartingThreads() {
7178 vec = new vector<int>;
7179 vec->push_back(1);
7180 vec->push_back(2);
7181 }
7182
Thread1()7183 void Thread1() {
7184 MutexLock lock(&mu);
7185 vec->pop_back();
7186 }
7187
Thread2()7188 void Thread2() {
7189 MutexLock lock(&mu);
7190 vec->pop_back();
7191 }
7192
7193 //---- Sub-optimal code ---------
NumberOfElementsLeft()7194 size_t NumberOfElementsLeft() {
7195 MutexLock lock(&mu);
7196 return vec->size();
7197 }
7198
WaitForAllThreadsToFinish_InefficientAndTsanUnfriendly()7199 void 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
NoElementsLeft(vector<int> * v)7216 bool NoElementsLeft(vector<int> *v) {
7217 return v->empty();
7218 }
7219
WaitForAllThreadsToFinish_Good()7220 void 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
Run()7230 void Run() {
7231 MyThreadArray t(Thread1, Thread2);
7232 InitAllBeforeStartingThreads();
7233 t.Start();
7234 WaitForAllThreadsToFinish_InefficientAndTsanUnfriendly();
7235 // WaitForAllThreadsToFinish_Good();
7236 t.Join();
7237 }
7238 REGISTER_TEST2(Run, 400, RACE_DEMO)
7239 } // namespace test400
7240
7241 // test401: Demo of false positive caused by reference counting. {{{1
7242 namespace 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
7247 static vector<int> *vec;
7248 static int ref_count;
7249
InitAllBeforeStartingThreads(int number_of_threads)7250 void 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.
DecRef()7257 int DecRef() {
7258 return AtomicIncrement(&ref_count, -1);
7259 }
7260
7261 // Correct and friendly to race detectors.
DecRefAnnotated()7262 int 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
ThreadWorker()7271 void 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
Run()7281 void Run() {
7282 MyThreadArray t(ThreadWorker, ThreadWorker, ThreadWorker);
7283 InitAllBeforeStartingThreads(3 /*number of threads*/);
7284 t.Start();
7285 t.Join();
7286 CHECK(vec == 0);
7287 }
7288 REGISTER_TEST2(Run, 401, RACE_DEMO)
7289 } // namespace test401
7290
7291 // test501: Manually call PRINT_* annotations {{{1
7292 namespace test501 {
7293 int COUNTER = 0;
7294 int GLOB = 0;
7295 Mutex muCounter, muGlob[65];
7296
Worker()7297 void 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
Worker_1()7311 void Worker_1() {
7312 MyThreadArray ta (Worker, Worker, Worker, Worker);
7313 ta.Start();
7314 usleep(500000);
7315 ta.Join ();
7316 }
7317
Worker_2()7318 void Worker_2() {
7319 MyThreadArray ta (Worker_1, Worker_1, Worker_1, Worker_1);
7320 ta.Start();
7321 usleep(300000);
7322 ta.Join ();
7323 }
7324
Run()7325 void 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
7336 REGISTER_TEST2(Run, 501, FEATURE | EXCLUDE_FROM_ALL)
7337 } // namespace test501
7338
7339 // test502: produce lots of segments without cross-thread relations {{{1
7340 namespace 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
7351 Mutex MU;
7352 int GLOB = 0;
7353
TP()7354 void TP() {
7355 for (int i = 0; i < 750000; i++) {
7356 MU.Lock();
7357 GLOB++;
7358 MU.Unlock();
7359 }
7360 }
7361
Run()7362 void 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
7370 REGISTER_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%
7376 namespace test503 {
7377
7378 // |- | | | | |
7379 // | \| | | | |
7380 // | |- | | | |
7381 // | | \| | | |
7382 // | | |- | | |
7383 // | | | \| | |
7384 // | | | |- | |
7385 // | | | | \| |
7386 // | | | | |- |
7387 // | | | | | \|
7388 // | | | | | |----
7389 //->| | | | | |
7390 // |- | | | | |
7391 // | \| | | | |
7392 // ...
7393
7394 const int N_threads = 32;
7395 const int ARRAY_SIZE = 128;
7396 int GLOB[ARRAY_SIZE];
7397 ProducerConsumerQueue *Q[N_threads];
7398 int GLOB_limit = 100000;
7399 int count = -1;
7400
Worker()7401 void 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
Run()7420 void 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
7438 REGISTER_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
7443 namespace test504 {
7444
7445 const 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
7454 const int ARRAY_SIZE = 4 * HG_CACHE_SIZE,
7455 ITERATIONS = 30;
7456 int array[ARRAY_SIZE];
7457
7458 int count = 0;
7459 Mutex count_mu;
7460
Worker()7461 void 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
Run()7477 void Run() {
7478 printf("test504: force massive CacheLineZ fetch-wback\n");
7479 MyThreadArray t(Worker, Worker);
7480 t.Start();
7481 t.Join();
7482 }
7483
7484 REGISTER_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)
7490 namespace test505 {
7491
7492 const 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
7497 const int ARRAY_SIZE = 4 * HG_CACHE_SIZE,
7498 ITERATIONS = 3;
7499 int64_t array[ARRAY_SIZE];
7500
7501 int count = 0;
7502 Mutex count_mu;
7503
Worker()7504 void 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
Run()7528 void Run() {
7529 printf("test505: force massive CacheLineF fetch-wback\n");
7530 MyThreadArray t(Worker, Worker);
7531 t.Start();
7532 t.Join();
7533 }
7534
7535 REGISTER_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
7542 namespace test506 {
7543 #ifndef NO_BARRIER
7544 // Same as test17 but uses Barrier class (pthread_barrier_t).
7545 int GLOB = 0;
7546 const int N_threads = 64,
7547 ITERATIONS = 1000;
7548 Barrier *barrier[ITERATIONS];
7549 Mutex MU;
7550
Worker()7551 void Worker() {
7552 for (int i = 0; i < ITERATIONS; i++) {
7553 MU.Lock();
7554 GLOB++;
7555 MU.Unlock();
7556 barrier[i]->Block();
7557 }
7558 }
Run()7559 void 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 }
7576 REGISTER_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
7582 namespace test507 {
7583 const int N_THREADS = 1,
7584 BUFFER_SIZE = 1,
7585 ITERATIONS = 1 << 20;
7586
Foo()7587 void 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
Worker()7600 void Worker() {
7601 for (int j = 0; j < ITERATIONS; j++) {
7602 Foo();
7603 }
7604 }
7605
Run()7606 void 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 }
7616 REGISTER_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
7621 namespace test508 {
7622 const int N_THREADS = 1,
7623 BUFFER_SIZE = 1 << 10,
7624 ITERATIONS = 1 << 9;
7625
Foo()7626 void 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
Worker()7639 void Worker() {
7640 for (int j = 0; j < ITERATIONS; j++) {
7641 Foo();
7642 }
7643 }
7644
Run()7645 void 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 }
7655 REGISTER_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
7660 namespace test509 {
7661 const int N_THREADS = 16,
7662 ITERATIONS = 1 << 8;
7663
Worker()7664 void 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
Run()7678 void 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 }
7688 REGISTER_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
7693 namespace test510 {
7694 const int N_THREADS = 16,
7695 ITERATIONS = 1 << 10;
7696 int GLOB = 0;
7697
Worker()7698 void 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
Run()7707 void 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 }
7718 REGISTER_TEST2(Run, 510, MEMORY_USAGE | PRINT_STATS | EXCLUDE_FROM_ALL);
7719 } // namespace test510
7720
7721 // test511: Segment refcounting test ('1' refcounting) {{{1
7722 namespace test511 {
7723 int GLOB = 0;
7724
Run()7725 void 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 }
7735 REGISTER_TEST2(Run, 511, MEMORY_USAGE | PRINT_STATS | EXCLUDE_FROM_ALL);
7736 } // namespace test511
7737
7738 // test512: Segment refcounting test ('S' refcounting) {{{1
7739 namespace test512 {
7740 int GLOB = 0;
7741 sem_t SEM;
7742
Run()7743 void 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 }
7755 REGISTER_TEST2(Run, 512, MEMORY_USAGE | PRINT_STATS | EXCLUDE_FROM_ALL);
7756 } // namespace test512
7757
7758 // test513: --fast-mode benchmark {{{1
7759 namespace test513 {
7760
7761 const 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
7768 const int ITERATIONS = 1024;
7769 int array[N_THREADS][ARRAY_SIZE];
7770
7771 int count = 0;
7772 Mutex count_mu;
7773 Mutex mutex_arr[N_THREADS][MUTEX_ID_BITS];
7774
Worker()7775 void 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
Run()7797 void 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
7808 REGISTER_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