1 /* 2 This file is part of ThreadSanitizer, a dynamic data race detector. 3 4 Copyright (C) 2008-2008 Google Inc 5 opensource (at) 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 (at) 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 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 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: 82 Mutex() { ::InitializeCriticalSection(&cs_); } 83 ~Mutex() { ::DeleteCriticalSection(&cs_); } 84 void Lock() { ::EnterCriticalSection(&cs_);} 85 bool TryLock() { return ::TryEnterCriticalSection(&cs_); } 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 } 96 void ReaderLock() { Lock(); } 97 bool ReaderTryLock() { return TryLock();} 98 void ReaderUnlock() { Unlock(); } 99 100 void LockWhen(Condition cond) { Lock(); WaitLoop(cond); } 101 void ReaderLockWhen(Condition cond) { Lock(); WaitLoop(cond); } 102 void Await(Condition cond) { WaitLoop(cond); } 103 104 bool ReaderLockWhenWithTimeout(Condition cond, int millis) 105 { Lock(); return WaitLoopWithTimeout(cond, millis); } 106 bool LockWhenWithTimeout(Condition cond, int millis) 107 { Lock(); return WaitLoopWithTimeout(cond, millis); } 108 bool AwaitWithTimeout(Condition cond, int millis) 109 { return WaitLoopWithTimeout(cond, millis); } 110 111 private: 112 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 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: 146 CondVar() { 147 signaled_ = false; 148 hSignal_ = CreateEvent(NULL, false, false, NULL); 149 CHECK(hSignal_ != NULL); 150 } 151 ~CondVar() { 152 CloseHandle(hSignal_); 153 } 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 } 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 } 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) 198 :w_(worker), arg_(arg), name_(name), t_(NULL) {} 199 MyThread(void (*worker)(void), void *arg = NULL, const char *name = NULL) 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) 202 :w_(reinterpret_cast<worker_t>(worker)), arg_(arg), name_(name), t_(NULL) {} 203 204 ~MyThread(){ 205 CloseHandle(t_); 206 t_ = NULL; 207 } 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 } 213 void Join() { 214 CHECK(t_ > 0); 215 CHECK(WAIT_OBJECT_0 == ::WaitForSingleObject(t_, INFINITE)); 216 } 217 HANDLE tid() const { return t_; } 218 private: 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