| /* |
| This file is part of Valgrind, a dynamic binary instrumentation |
| framework. |
| |
| Copyright (C) 2008-2008 Google Inc |
| opensource@google.com |
| |
| This program is free software; you can redistribute it and/or |
| modify it under the terms of the GNU General Public License as |
| published by the Free Software Foundation; either version 2 of the |
| License, or (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| 02111-1307, USA. |
| |
| The GNU General Public License is contained in the file COPYING. |
| */ |
| |
| /* Author: Konstantin Serebryany <opensource@google.com> |
| |
| This file contains a few macros useful for implementing |
| unit-tests for data race detection tools. |
| |
| */ |
| |
| #ifndef TEST_UTILS_H__ |
| #define TEST_UTILS_H__ |
| |
| // This test must not include any other file specific to threading library, |
| // everything should be inside THREAD_WRAPPERS. |
| #ifndef THREAD_WRAPPERS |
| # define THREAD_WRAPPERS "thread_wrappers.h" |
| #endif |
| #include THREAD_WRAPPERS |
| |
| #ifndef NEEDS_SEPERATE_RW_LOCK |
| #define RWLock Mutex // Mutex does work as an rw-lock. |
| #define WriterLockScoped MutexLock |
| #define ReaderLockScoped ReaderMutexLock |
| #endif // !NEEDS_SEPERATE_RW_LOCK |
| |
| static bool ArgIsOne(int *arg) { return *arg == 1; }; |
| static bool ArgIsZero(int *arg) { return *arg == 0; }; |
| static bool ArgIsTrue(bool *arg) { return *arg == true; }; |
| |
| |
| // If run under ThreadSanitizerQuery, this function is replaced by the tool |
| // and a non-NULL string is returned. See the usage below. |
| extern "C" const char *ThreadSanitizerQuery(const char *query); |
| |
| // Apply ANNOTATE_EXPECT_RACE only if running under ThreadSanitizer. |
| #define ANNOTATE_EXPECT_RACE_FOR_TSAN(mem, descr) \ |
| do {\ |
| if (ThreadSanitizerQuery("") != NULL) {\ |
| ANNOTATE_EXPECT_RACE(mem, descr); \ |
| } \ |
| } while(0)\ |
| |
| inline bool ThreadSanitizerQueryMatch(const char *query, const char *expected_answer) { |
| const char *answer = ThreadSanitizerQuery(query); |
| if (answer == NULL) { |
| // Not running under ThreadSanitizer at all. |
| return false; |
| } |
| return string(answer) == expected_answer; |
| } |
| |
| inline bool Tsan_PureHappensBefore() { |
| static bool ret = ThreadSanitizerQueryMatch("pure_happens_before", "1"); |
| return ret; |
| } |
| |
| inline bool Tsan_RaceVerifier() { |
| static bool ret = ThreadSanitizerQueryMatch("race_verifier", "1"); |
| return ret; |
| } |
| |
| // An array of threads. Create/start/join all elements at once. |
| class MyThreadArray { |
| public: |
| static const int kSize = 5; |
| typedef void (*F) (void); |
| MyThreadArray(F f1, F f2 = NULL, F f3 = NULL, F f4 = NULL, F f5 = NULL) { |
| ar_[0] = new MyThread(f1); |
| ar_[1] = f2 ? new MyThread(f2) : NULL; |
| ar_[2] = f3 ? new MyThread(f3) : NULL; |
| ar_[3] = f4 ? new MyThread(f4) : NULL; |
| ar_[4] = f5 ? new MyThread(f5) : NULL; |
| } |
| void Start() { |
| for(int i = 0; i < kSize; i++) { |
| if(ar_[i]) { |
| ar_[i]->Start(); |
| usleep(10); |
| } |
| } |
| } |
| |
| void Join() { |
| for(int i = 0; i < kSize; i++) { |
| if(ar_[i]) { |
| ar_[i]->Join(); |
| } |
| } |
| } |
| |
| ~MyThreadArray() { |
| for(int i = 0; i < kSize; i++) { |
| delete ar_[i]; |
| } |
| } |
| private: |
| MyThread *ar_[kSize]; |
| }; |
| |
| |
| // This class does not implement a signal-wait synchronization |
| // primitive, even if it looks like one. Its purpose is to enforce an |
| // order of execution of threads in unit tests in a way that is |
| // invisible to ThreadSanitizer and similar tools. It lacks memory |
| // barriers, therefore it only works reliably if there is a real |
| // synchronization primitive before signal() or after wait(). |
| class StealthNotification { |
| public: |
| StealthNotification() : flag_(0) {} |
| |
| void signal() { |
| ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN(); |
| CHECK(!flag_); |
| flag_ = 1; |
| ANNOTATE_IGNORE_READS_AND_WRITES_END(); |
| } |
| |
| void wait() { |
| while (!flag_) { |
| #ifdef WIN32 |
| usleep(1000); |
| #else |
| sched_yield(); |
| #endif |
| } |
| } |
| |
| private: |
| volatile int flag_; |
| }; |
| |
| #endif // TEST_UTILS_H__ |
| // End {{{1 |
| // vim:shiftwidth=2:softtabstop=2:expandtab:foldmethod=marker |