1 /* 2 This file is part of Valgrind, a dynamic binary instrumentation 3 framework. 4 5 Copyright (C) 2008-2008 Google Inc 6 opensource (at) 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 (at) google.com> 27 28 This file contains a few macros useful for implementing 29 unit-tests for data race detection tools. 30 31 */ 32 33 #ifndef TEST_UTILS_H__ 34 #define TEST_UTILS_H__ 35 36 // This test must not include any other file specific to threading library, 37 // everything should be inside THREAD_WRAPPERS. 38 #ifndef THREAD_WRAPPERS 39 # define THREAD_WRAPPERS "thread_wrappers.h" 40 #endif 41 #include THREAD_WRAPPERS 42 43 #ifndef NEEDS_SEPERATE_RW_LOCK 44 #define RWLock Mutex // Mutex does work as an rw-lock. 45 #define WriterLockScoped MutexLock 46 #define ReaderLockScoped ReaderMutexLock 47 #endif // !NEEDS_SEPERATE_RW_LOCK 48 49 static bool ArgIsOne(int *arg) { return *arg == 1; }; 50 static bool ArgIsZero(int *arg) { return *arg == 0; }; 51 static bool ArgIsTrue(bool *arg) { return *arg == true; }; 52 53 54 // If run under ThreadSanitizerQuery, this function is replaced by the tool 55 // and a non-NULL string is returned. See the usage below. 56 extern "C" const char *ThreadSanitizerQuery(const char *query); 57 58 // Apply ANNOTATE_EXPECT_RACE only if running under ThreadSanitizer. 59 #define ANNOTATE_EXPECT_RACE_FOR_TSAN(mem, descr) \ 60 do {\ 61 if (ThreadSanitizerQuery("") != NULL) {\ 62 ANNOTATE_EXPECT_RACE(mem, descr); \ 63 } \ 64 } while(0)\ 65 66 inline bool ThreadSanitizerQueryMatch(const char *query, const char *expected_answer) { 67 const char *answer = ThreadSanitizerQuery(query); 68 if (answer == NULL) { 69 // Not running under ThreadSanitizer at all. 70 return false; 71 } 72 return string(answer) == expected_answer; 73 } 74 75 inline bool Tsan_PureHappensBefore() { 76 static bool ret = ThreadSanitizerQueryMatch("pure_happens_before", "1"); 77 return ret; 78 } 79 80 inline bool Tsan_RaceVerifier() { 81 static bool ret = ThreadSanitizerQueryMatch("race_verifier", "1"); 82 return ret; 83 } 84 85 // An array of threads. Create/start/join all elements at once. 86 class MyThreadArray { 87 public: 88 static const int kSize = 5; 89 typedef void (*F) (void); 90 MyThreadArray(F f1, F f2 = NULL, F f3 = NULL, F f4 = NULL, F f5 = NULL) { 91 ar_[0] = new MyThread(f1); 92 ar_[1] = f2 ? new MyThread(f2) : NULL; 93 ar_[2] = f3 ? new MyThread(f3) : NULL; 94 ar_[3] = f4 ? new MyThread(f4) : NULL; 95 ar_[4] = f5 ? new MyThread(f5) : NULL; 96 } 97 void Start() { 98 for(int i = 0; i < kSize; i++) { 99 if(ar_[i]) { 100 ar_[i]->Start(); 101 usleep(10); 102 } 103 } 104 } 105 106 void Join() { 107 for(int i = 0; i < kSize; i++) { 108 if(ar_[i]) { 109 ar_[i]->Join(); 110 } 111 } 112 } 113 114 ~MyThreadArray() { 115 for(int i = 0; i < kSize; i++) { 116 delete ar_[i]; 117 } 118 } 119 private: 120 MyThread *ar_[kSize]; 121 }; 122 123 124 // This class does not implement a signal-wait synchronization 125 // primitive, even if it looks like one. Its purpose is to enforce an 126 // order of execution of threads in unit tests in a way that is 127 // invisible to ThreadSanitizer and similar tools. It lacks memory 128 // barriers, therefore it only works reliably if there is a real 129 // synchronization primitive before signal() or after wait(). 130 class StealthNotification { 131 public: 132 StealthNotification() : flag_(0) {} 133 134 void signal() { 135 ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN(); 136 CHECK(!flag_); 137 flag_ = 1; 138 ANNOTATE_IGNORE_READS_AND_WRITES_END(); 139 } 140 141 void wait() { 142 while (!flag_) { 143 #ifdef WIN32 144 usleep(1000); 145 #else 146 sched_yield(); 147 #endif 148 } 149 } 150 151 private: 152 volatile int flag_; 153 }; 154 155 #endif // TEST_UTILS_H__ 156 // End {{{1 157 // vim:shiftwidth=2:softtabstop=2:expandtab:foldmethod=marker 158