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
49static bool ArgIsOne(int *arg) { return *arg == 1; };
50static bool ArgIsZero(int *arg) { return *arg == 0; };
51static 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.
56extern "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
66inline 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
75inline bool Tsan_PureHappensBefore() {
76  static bool ret = ThreadSanitizerQueryMatch("pure_happens_before", "1");
77  return ret;
78}
79
80inline 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.
86class 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().
130class 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