• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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 
ArgIsOne(int * arg)49 static bool ArgIsOne(int *arg) { return *arg == 1; };
ArgIsZero(int * arg)50 static bool ArgIsZero(int *arg) { return *arg == 0; };
ArgIsTrue(bool * arg)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 
ThreadSanitizerQueryMatch(const char * query,const char * expected_answer)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 
Tsan_PureHappensBefore()75 inline bool Tsan_PureHappensBefore() {
76   static bool ret = ThreadSanitizerQueryMatch("pure_happens_before", "1");
77   return ret;
78 }
79 
Tsan_RaceVerifier()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   }
Start()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 
Join()106   void Join() {
107     for(int i = 0; i < kSize; i++) {
108       if(ar_[i]) {
109         ar_[i]->Join();
110       }
111     }
112   }
113 
~MyThreadArray()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:
StealthNotification()132   StealthNotification() : flag_(0) {}
133 
signal()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 
wait()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