/* This file is part of ThreadSanitizer, a dynamic data race detector. Copyright (C) 2008-2008 Google Inc opensource@google.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. The GNU General Public License is contained in the file COPYING. */ // Author: Konstantin Serebryany <opensource@google.com> // // Here we define few simple classes that wrap pthread primitives. // // We need this to create unit tests for helgrind (or similar tool) // that will work with different threading frameworks. // // If one needs to test helgrind's support for another threading library, // he/she can create a copy of this file and replace pthread_ calls // with appropriate calls to his/her library. // // Note, that some of the methods defined here are annotated with // ANNOTATE_* macros defined in dynamic_annotations.h. // // DISCLAIMER: the classes defined in this header file // are NOT intended for general use -- only for unit tests. // #ifndef THREAD_WRAPPERS_WIN_H #define THREAD_WRAPPERS_WIN_H #define _WIN32_WINNT 0x0500 // Require Windows 2000. #include <windows.h> #include <mmsystem.h> #pragma comment(lib, "winmm.lib") #define NO_BARRIER #define NO_UNNAMED_SEM #define TLS __declspec(thread) #define NO_SPINLOCK // TODO(timurrrr): implement SpinLock #define usleep(x) Sleep((x)/1000) #define sleep(x) Sleep((x)*1000) #define NOINLINE __declspec(noinline) #define ALIGNED(x) __declspec (align(x)) int GetTimeInMs() { return (int)timeGetTime(); } typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; typedef unsigned long long uint64_t; typedef long long int64_t; // This constant is true if malloc() uses mutex on your platform as this may // introduce a happens-before arc for a pure happens-before race detector. static const bool kMallocUsesMutex = false; int AtomicIncrement(volatile int *value, int increment) { return InterlockedExchangeAdd(reinterpret_cast<volatile LONG*>(value), increment) + increment; } class Mutex { friend class CondVar; public: Mutex() { ::InitializeCriticalSection(&cs_); } ~Mutex() { ::DeleteCriticalSection(&cs_); } void Lock() { ::EnterCriticalSection(&cs_);} bool TryLock() { return ::TryEnterCriticalSection(&cs_); } void Unlock() { ANNOTATE_HAPPENS_BEFORE(this); /* // TODO(timurrrr): do we need this? if (signal_at_unlock_) { CHECK(0 == pthread_cond_signal(&cv_)); } */ ::LeaveCriticalSection(&cs_); } void ReaderLock() { Lock(); } bool ReaderTryLock() { return TryLock();} void ReaderUnlock() { Unlock(); } void LockWhen(Condition cond) { Lock(); WaitLoop(cond); } void ReaderLockWhen(Condition cond) { Lock(); WaitLoop(cond); } void Await(Condition cond) { WaitLoop(cond); } bool ReaderLockWhenWithTimeout(Condition cond, int millis) { Lock(); return WaitLoopWithTimeout(cond, millis); } bool LockWhenWithTimeout(Condition cond, int millis) { Lock(); return WaitLoopWithTimeout(cond, millis); } bool AwaitWithTimeout(Condition cond, int millis) { return WaitLoopWithTimeout(cond, millis); } private: void WaitLoop(Condition cond) { while(cond.Eval() == false) { Unlock(); // TODO(timurrrr) Sleep(10); Lock(); } ANNOTATE_HAPPENS_AFTER(this); } bool WaitLoopWithTimeout(Condition cond, int millis) { int start_time = GetTimeInMs(); while (cond.Eval() == false && GetTimeInMs() - start_time < millis) { Unlock(); // TODO(timurrrr) Sleep(10); Lock(); } if (cond.Eval() == 0) { return false; } else { ANNOTATE_HAPPENS_AFTER(this); return true; } } CRITICAL_SECTION cs_; }; class CondVar { public: CondVar() { signaled_ = false; hSignal_ = CreateEvent(NULL, false, false, NULL); CHECK(hSignal_ != NULL); } ~CondVar() { CloseHandle(hSignal_); } void Wait(Mutex *mu) { while (!signaled_) { mu->Unlock(); WaitForSingleObject(hSignal_, INFINITE); mu->Lock(); } signaled_ = false; ANNOTATE_HAPPENS_AFTER(this); } bool WaitWithTimeout(Mutex *mu, int millis) { int start_time = GetTimeInMs(); while (!signaled_ && GetTimeInMs() - start_time < millis) { int curr_time = GetTimeInMs(); if (curr_time - start_time >= millis) break; mu->Unlock(); WaitForSingleObject(hSignal_, start_time + millis - curr_time); mu->Lock(); } if (signaled_) { ANNOTATE_HAPPENS_AFTER(this); signaled_ = false; return true; } return false; } void Signal() { signaled_ = true; ANNOTATE_HAPPENS_BEFORE(this); SetEvent(hSignal_); } // TODO(timurrrr): this isn't used anywhere - do we need these? // void SignalAll(); private: HANDLE hSignal_; bool signaled_; }; class MyThread { public: typedef void *(*worker_t)(void*); MyThread(worker_t worker, void *arg = NULL, const char *name = NULL) :w_(worker), arg_(arg), name_(name), t_(NULL) {} MyThread(void (*worker)(void), void *arg = NULL, const char *name = NULL) :w_(reinterpret_cast<worker_t>(worker)), arg_(arg), name_(name), t_(NULL) {} MyThread(void (*worker)(void *), void *arg = NULL, const char *name = NULL) :w_(reinterpret_cast<worker_t>(worker)), arg_(arg), name_(name), t_(NULL) {} ~MyThread(){ CloseHandle(t_); t_ = NULL; } void Start() { DWORD thr_id; t_ = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadBody, this, 0, &thr_id); CHECK(t_ > 0); } void Join() { CHECK(t_ > 0); CHECK(WAIT_OBJECT_0 == ::WaitForSingleObject(t_, INFINITE)); } HANDLE tid() const { return t_; } private: static DWORD WINAPI ThreadBody(MyThread *my_thread) { if (my_thread->name_) { ANNOTATE_THREAD_NAME(my_thread->name_); } my_thread->w_(my_thread->arg_); return 0; } HANDLE t_; DWORD ret_; worker_t w_; void *arg_; const char *name_; }; #endif // THREAD_WRAPPERS_WIN_H