C++程序  |  233行  |  6.56 KB

/*
  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