1610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov/*
2610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  This file is part of Valgrind, a dynamic binary instrumentation
3610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  framework.
4610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
5610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  Copyright (C) 2008-2008 Google Inc
6610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov     opensource@google.com
7610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
8610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  This program is free software; you can redistribute it and/or
9610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  modify it under the terms of the GNU General Public License as
10610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  published by the Free Software Foundation; either version 2 of the
11610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  License, or (at your option) any later version.
12610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
13610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  This program is distributed in the hope that it will be useful, but
14610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  WITHOUT ANY WARRANTY; without even the implied warranty of
15610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  General Public License for more details.
17610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
18610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  You should have received a copy of the GNU General Public License
19610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  along with this program; if not, write to the Free Software
20610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  02111-1307, USA.
22610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
23610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  The GNU General Public License is contained in the file COPYING.
24610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov*/
25610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
26610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov/* Author: Konstantin Serebryany <opensource@google.com>
27610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
28610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov This file contains a few macros useful for implementing
29610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov unit-tests for data race detection tools.
30610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
31610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov*/
32610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
33610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#ifndef TEST_UTILS_H__
34610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#define TEST_UTILS_H__
35610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
36610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// This test must not include any other file specific to threading library,
37610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// everything should be inside THREAD_WRAPPERS.
38610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#ifndef THREAD_WRAPPERS
39610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov# define THREAD_WRAPPERS "thread_wrappers.h"
40610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#endif
41610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#include THREAD_WRAPPERS
42610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
43610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#ifndef NEEDS_SEPERATE_RW_LOCK
44610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#define RWLock Mutex // Mutex does work as an rw-lock.
45610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#define WriterLockScoped MutexLock
46610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#define ReaderLockScoped ReaderMutexLock
47610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#endif // !NEEDS_SEPERATE_RW_LOCK
48610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
49610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovstatic bool ArgIsOne(int *arg) { return *arg == 1; };
50610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovstatic bool ArgIsZero(int *arg) { return *arg == 0; };
51610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovstatic bool ArgIsTrue(bool *arg) { return *arg == true; };
52610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
53610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
54610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// If run under ThreadSanitizerQuery, this function is replaced by the tool
55610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// and a non-NULL string is returned. See the usage below.
56610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovextern "C" const char *ThreadSanitizerQuery(const char *query);
57610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
58610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// Apply ANNOTATE_EXPECT_RACE only if running under ThreadSanitizer.
59610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#define ANNOTATE_EXPECT_RACE_FOR_TSAN(mem, descr) \
60610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    do {\
61610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      if (ThreadSanitizerQuery("") != NULL) {\
62610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov        ANNOTATE_EXPECT_RACE(mem, descr); \
63610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      } \
64610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    } while(0)\
65610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
66610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovinline bool ThreadSanitizerQueryMatch(const char *query, const char *expected_answer) {
67610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  const char *answer = ThreadSanitizerQuery(query);
68610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  if (answer == NULL) {
69610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    // Not running under ThreadSanitizer at all.
70610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    return false;
71610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
72610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  return string(answer) == expected_answer;
73610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov}
74610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
75610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovinline bool Tsan_PureHappensBefore() {
76610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  static bool ret = ThreadSanitizerQueryMatch("pure_happens_before", "1");
77610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  return ret;
78610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov}
79610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
80610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovinline bool Tsan_RaceVerifier() {
81610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  static bool ret = ThreadSanitizerQueryMatch("race_verifier", "1");
82610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  return ret;
83610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov}
84610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
85610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// An array of threads. Create/start/join all elements at once.
86610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovclass MyThreadArray {
87610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov public:
88610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  static const int kSize = 5;
89610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  typedef void (*F) (void);
90610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  MyThreadArray(F f1, F f2 = NULL, F f3 = NULL, F f4 = NULL, F f5 = NULL) {
91610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    ar_[0] = new MyThread(f1);
92610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    ar_[1] = f2 ? new MyThread(f2) : NULL;
93610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    ar_[2] = f3 ? new MyThread(f3) : NULL;
94610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    ar_[3] = f4 ? new MyThread(f4) : NULL;
95610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    ar_[4] = f5 ? new MyThread(f5) : NULL;
96610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
97610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  void Start() {
98610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    for(int i = 0; i < kSize; i++) {
99610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      if(ar_[i]) {
100610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov        ar_[i]->Start();
101610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov        usleep(10);
102610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      }
103610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    }
104610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
105610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
106610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  void Join() {
107610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    for(int i = 0; i < kSize; i++) {
108610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      if(ar_[i]) {
109610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov        ar_[i]->Join();
110610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      }
111610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    }
112610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
113610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
114610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  ~MyThreadArray() {
115610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    for(int i = 0; i < kSize; i++) {
116610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      delete ar_[i];
117610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    }
118610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
119610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov private:
120610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  MyThread *ar_[kSize];
121610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov};
122610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
123610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
124610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// This class does not implement a signal-wait synchronization
125610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// primitive, even if it looks like one. Its purpose is to enforce an
126610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// order of execution of threads in unit tests in a way that is
127610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// invisible to ThreadSanitizer and similar tools. It lacks memory
128610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// barriers, therefore it only works reliably if there is a real
129610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// synchronization primitive before signal() or after wait().
130610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovclass StealthNotification {
131610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov public:
132610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  StealthNotification() : flag_(0) {}
133610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
134610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  void signal() {
135610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
136610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    CHECK(!flag_);
137610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    flag_ = 1;
138610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    ANNOTATE_IGNORE_READS_AND_WRITES_END();
139610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
140610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
141610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  void wait() {
142610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    while (!flag_) {
143610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#ifdef WIN32
144610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      usleep(1000);
145610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#else
146610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      sched_yield();
147610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#endif
148610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    }
149610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
150610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
151610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov private:
152610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  volatile int flag_;
153610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov};
154610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
155610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#endif  // TEST_UTILS_H__
156610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// End {{{1
157610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov // vim:shiftwidth=2:softtabstop=2:expandtab:foldmethod=marker
158