1 /*
2 This file is part of ThreadSanitizer, a dynamic data race detector.
3
4 Copyright (C) 2008-2008 Google Inc
5 opensource@google.com
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 02111-1307, USA.
21
22 The GNU General Public License is contained in the file COPYING.
23 */
24
25 // Author: Konstantin Serebryany <opensource@google.com>
26 //
27 // Here we define few simple classes that wrap pthread primitives.
28 //
29 // We need this to create unit tests for helgrind (or similar tool)
30 // that will work with different threading frameworks.
31 //
32 // If one needs to test helgrind's support for another threading library,
33 // he/she can create a copy of this file and replace pthread_ calls
34 // with appropriate calls to his/her library.
35 //
36 // Note, that some of the methods defined here are annotated with
37 // ANNOTATE_* macros defined in dynamic_annotations.h.
38 //
39 // DISCLAIMER: the classes defined in this header file
40 // are NOT intended for general use -- only for unit tests.
41 //
42 #ifndef THREAD_WRAPPERS_WIN_H
43 #define THREAD_WRAPPERS_WIN_H
44
45 #define _WIN32_WINNT 0x0500 // Require Windows 2000.
46 #include <windows.h>
47 #include <mmsystem.h>
48
49 #pragma comment(lib, "winmm.lib")
50
51 #define NO_BARRIER
52 #define NO_UNNAMED_SEM
53 #define TLS __declspec(thread)
54 #define NO_SPINLOCK // TODO(timurrrr): implement SpinLock
55 #define usleep(x) Sleep((x)/1000)
56 #define sleep(x) Sleep((x)*1000)
57 #define NOINLINE __declspec(noinline)
58 #define ALIGNED(x) __declspec (align(x))
59
GetTimeInMs()60 int GetTimeInMs() {
61 return (int)timeGetTime();
62 }
63
64 typedef unsigned char uint8_t;
65 typedef unsigned short uint16_t;
66 typedef unsigned int uint32_t;
67 typedef unsigned long long uint64_t;
68 typedef long long int64_t;
69
70 // This constant is true if malloc() uses mutex on your platform as this may
71 // introduce a happens-before arc for a pure happens-before race detector.
72 static const bool kMallocUsesMutex = false;
73
AtomicIncrement(volatile int * value,int increment)74 int AtomicIncrement(volatile int *value, int increment) {
75 return InterlockedExchangeAdd(reinterpret_cast<volatile LONG*>(value),
76 increment) + increment;
77 }
78
79 class Mutex {
80 friend class CondVar;
81 public:
Mutex()82 Mutex() { ::InitializeCriticalSection(&cs_); }
~Mutex()83 ~Mutex() { ::DeleteCriticalSection(&cs_); }
Lock()84 void Lock() { ::EnterCriticalSection(&cs_);}
TryLock()85 bool TryLock() { return ::TryEnterCriticalSection(&cs_); }
Unlock()86 void Unlock() {
87 ANNOTATE_HAPPENS_BEFORE(this);
88 /*
89 // TODO(timurrrr): do we need this?
90 if (signal_at_unlock_) {
91 CHECK(0 == pthread_cond_signal(&cv_));
92 }
93 */
94 ::LeaveCriticalSection(&cs_);
95 }
ReaderLock()96 void ReaderLock() { Lock(); }
ReaderTryLock()97 bool ReaderTryLock() { return TryLock();}
ReaderUnlock()98 void ReaderUnlock() { Unlock(); }
99
LockWhen(Condition cond)100 void LockWhen(Condition cond) { Lock(); WaitLoop(cond); }
ReaderLockWhen(Condition cond)101 void ReaderLockWhen(Condition cond) { Lock(); WaitLoop(cond); }
Await(Condition cond)102 void Await(Condition cond) { WaitLoop(cond); }
103
ReaderLockWhenWithTimeout(Condition cond,int millis)104 bool ReaderLockWhenWithTimeout(Condition cond, int millis)
105 { Lock(); return WaitLoopWithTimeout(cond, millis); }
LockWhenWithTimeout(Condition cond,int millis)106 bool LockWhenWithTimeout(Condition cond, int millis)
107 { Lock(); return WaitLoopWithTimeout(cond, millis); }
AwaitWithTimeout(Condition cond,int millis)108 bool AwaitWithTimeout(Condition cond, int millis)
109 { return WaitLoopWithTimeout(cond, millis); }
110
111 private:
112
WaitLoop(Condition cond)113 void WaitLoop(Condition cond) {
114 while(cond.Eval() == false) {
115 Unlock();
116 // TODO(timurrrr)
117 Sleep(10);
118 Lock();
119 }
120 ANNOTATE_HAPPENS_AFTER(this);
121 }
122
WaitLoopWithTimeout(Condition cond,int millis)123 bool WaitLoopWithTimeout(Condition cond, int millis) {
124 int start_time = GetTimeInMs();
125
126 while (cond.Eval() == false && GetTimeInMs() - start_time < millis) {
127 Unlock();
128 // TODO(timurrrr)
129 Sleep(10);
130 Lock();
131 }
132
133 if (cond.Eval() == 0) {
134 return false;
135 } else {
136 ANNOTATE_HAPPENS_AFTER(this);
137 return true;
138 }
139 }
140
141 CRITICAL_SECTION cs_;
142 };
143
144 class CondVar {
145 public:
CondVar()146 CondVar() {
147 signaled_ = false;
148 hSignal_ = CreateEvent(NULL, false, false, NULL);
149 CHECK(hSignal_ != NULL);
150 }
~CondVar()151 ~CondVar() {
152 CloseHandle(hSignal_);
153 }
Wait(Mutex * mu)154 void Wait(Mutex *mu) {
155 while (!signaled_) {
156 mu->Unlock();
157 WaitForSingleObject(hSignal_, INFINITE);
158 mu->Lock();
159 }
160 signaled_ = false;
161 ANNOTATE_HAPPENS_AFTER(this);
162 }
WaitWithTimeout(Mutex * mu,int millis)163 bool WaitWithTimeout(Mutex *mu, int millis) {
164 int start_time = GetTimeInMs();
165
166 while (!signaled_ && GetTimeInMs() - start_time < millis) {
167 int curr_time = GetTimeInMs();
168 if (curr_time - start_time >= millis)
169 break;
170 mu->Unlock();
171 WaitForSingleObject(hSignal_, start_time + millis - curr_time);
172 mu->Lock();
173 }
174 if (signaled_) {
175 ANNOTATE_HAPPENS_AFTER(this);
176 signaled_ = false;
177 return true;
178 }
179 return false;
180 }
Signal()181 void Signal() {
182 signaled_ = true;
183 ANNOTATE_HAPPENS_BEFORE(this);
184 SetEvent(hSignal_);
185 }
186 // TODO(timurrrr): this isn't used anywhere - do we need these?
187 // void SignalAll();
188 private:
189 HANDLE hSignal_;
190 bool signaled_;
191 };
192
193 class MyThread {
194 public:
195 typedef void *(*worker_t)(void*);
196
197 MyThread(worker_t worker, void *arg = NULL, const char *name = NULL)
w_(worker)198 :w_(worker), arg_(arg), name_(name), t_(NULL) {}
199 MyThread(void (*worker)(void), void *arg = NULL, const char *name = NULL)
w_(reinterpret_cast<worker_t> (worker))200 :w_(reinterpret_cast<worker_t>(worker)), arg_(arg), name_(name), t_(NULL) {}
201 MyThread(void (*worker)(void *), void *arg = NULL, const char *name = NULL)
w_(reinterpret_cast<worker_t> (worker))202 :w_(reinterpret_cast<worker_t>(worker)), arg_(arg), name_(name), t_(NULL) {}
203
~MyThread()204 ~MyThread(){
205 CloseHandle(t_);
206 t_ = NULL;
207 }
Start()208 void Start() {
209 DWORD thr_id;
210 t_ = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadBody, this, 0, &thr_id);
211 CHECK(t_ > 0);
212 }
Join()213 void Join() {
214 CHECK(t_ > 0);
215 CHECK(WAIT_OBJECT_0 == ::WaitForSingleObject(t_, INFINITE));
216 }
tid()217 HANDLE tid() const { return t_; }
218 private:
ThreadBody(MyThread * my_thread)219 static DWORD WINAPI ThreadBody(MyThread *my_thread) {
220 if (my_thread->name_) {
221 ANNOTATE_THREAD_NAME(my_thread->name_);
222 }
223 my_thread->w_(my_thread->arg_);
224 return 0;
225 }
226 HANDLE t_;
227 DWORD ret_;
228 worker_t w_;
229 void *arg_;
230 const char *name_;
231 };
232 #endif // THREAD_WRAPPERS_WIN_H
233