Home | History | Annotate | Download | only in unittest
      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