• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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