1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* 2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown This file is part of Valgrind, a dynamic binary instrumentation 3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown framework. 4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Copyright (C) 2008-2008 Google Inc 6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown opensource@google.com 7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown This program is free software; you can redistribute it and/or 9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown modify it under the terms of the GNU General Public License as 10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown published by the Free Software Foundation; either version 2 of the 11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown License, or (at your option) any later version. 12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown This program is distributed in the hope that it will be useful, but 14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown WITHOUT ANY WARRANTY; without even the implied warranty of 15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown General Public License for more details. 17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown You should have received a copy of the GNU General Public License 19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown along with this program; if not, write to the Free Software 20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 02111-1307, USA. 22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The GNU General Public License is contained in the file COPYING. 24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/ 25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Author: Konstantin Serebryany <opensource@google.com> 27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Here we define few simple classes that wrap pthread primitives. 29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// We need this to create unit tests for helgrind (or similar tool) 31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// that will work with different threading frameworks. 32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// If one needs to test helgrind's support for another threading library, 34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// he/she can create a copy of this file and replace pthread_ calls 35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// with appropriate calls to his/her library. 36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Note, that some of the methods defined here are annotated with 38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// ANNOTATE_* macros defined in dynamic_annotations.h. 39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// DISCLAIMER: the classes defined in this header file 41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// are NOT intended for general use -- only for unit tests. 42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef THREAD_WRAPPERS_PTHREAD_H 45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define THREAD_WRAPPERS_PTHREAD_H 46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <pthread.h> 48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <semaphore.h> 49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <unistd.h> 50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <queue> 51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <stdio.h> 52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <limits.h> // INT_MAX 53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 54b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#ifdef VGO_darwin 55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <libkern/OSAtomic.h> 56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define NO_BARRIER 57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define NO_TLS 58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif 59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <string> 61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownusing namespace std; 62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <sys/time.h> 64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <time.h> 65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "../../drd/drd.h" 67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define ANNOTATE_NO_OP(arg) do { } while(0) 68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define ANNOTATE_EXPECT_RACE(addr, descr) \ 69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ANNOTATE_BENIGN_RACE_SIZED(addr, 4, "expected race") 70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic inline bool RunningOnValgrind() { return RUNNING_ON_VALGRIND; } 71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <assert.h> 73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifdef NDEBUG 74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# error "Pleeease, do not define NDEBUG" 75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif 76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define CHECK assert 77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/// Set this to true if malloc() uses mutex on your platform as this may 79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/// introduce a happens-before arc for a pure happens-before race detector. 80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownconst bool kMallocUsesMutex = false; 81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/// Current time in milliseconds. 83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic inline int64_t GetCurrentTimeMillis() { 84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct timeval now; 85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown gettimeofday(&now, NULL); 86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return now.tv_sec * 1000 + now.tv_usec / 1000; 87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/// Copy tv to ts adding offset in milliseconds. 90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic inline void timeval2timespec(timeval *const tv, 91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown timespec *ts, 92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int64_t offset_milli) { 93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const int64_t ten_9 = 1000000000LL; 94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const int64_t ten_6 = 1000000LL; 95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const int64_t ten_3 = 1000LL; 96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int64_t now_nsec = (int64_t)tv->tv_sec * ten_9; 97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown now_nsec += (int64_t)tv->tv_usec * ten_3; 98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int64_t then_nsec = now_nsec + offset_milli * ten_6; 99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ts->tv_sec = then_nsec / ten_9; 100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ts->tv_nsec = then_nsec % ten_9; 101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass CondVar; 105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef NO_SPINLOCK 107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/// helgrind does not (yet) support spin locks, so we annotate them. 108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 109b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#ifndef VGO_darwin 110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass SpinLock { 111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown public: 112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SpinLock() { 113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown CHECK(0 == pthread_spin_init(&mu_, 0)); 114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ANNOTATE_RWLOCK_CREATE((void*)&mu_); 115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~SpinLock() { 117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ANNOTATE_RWLOCK_DESTROY((void*)&mu_); 118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown CHECK(0 == pthread_spin_destroy(&mu_)); 119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Lock() { 121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown CHECK(0 == pthread_spin_lock(&mu_)); 122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ANNOTATE_RWLOCK_ACQUIRED((void*)&mu_, 1); 123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Unlock() { 125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ANNOTATE_RWLOCK_RELEASED((void*)&mu_, 1); 126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown CHECK(0 == pthread_spin_unlock(&mu_)); 127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown private: 129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_spinlock_t mu_; 130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#else 133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass SpinLock { 135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown public: 136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Mac OS X version. 137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SpinLock() : mu_(OS_SPINLOCK_INIT) { 138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ANNOTATE_RWLOCK_CREATE((void*)&mu_); 139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~SpinLock() { 141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ANNOTATE_RWLOCK_DESTROY((void*)&mu_); 142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Lock() { 144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown OSSpinLockLock(&mu_); 145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ANNOTATE_RWLOCK_ACQUIRED((void*)&mu_, 1); 146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Unlock() { 148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ANNOTATE_RWLOCK_RELEASED((void*)&mu_, 1); 149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown OSSpinLockUnlock(&mu_); 150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown private: 152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown OSSpinLock mu_; 153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 154b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#endif // VGO_darwin 155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif // NO_SPINLOCK 157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/// Just a boolean condition. Used by Mutex::LockWhen and similar. 159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass Condition { 160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown public: 161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown typedef bool (*func_t)(void*); 162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown template <typename T> 164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Condition(bool (*func)(T*), T* arg) 165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown : func_(reinterpret_cast<func_t>(func)), arg_(arg) {} 166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Condition(bool (*func)()) 168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown : func_(reinterpret_cast<func_t>(func)), arg_(NULL) {} 169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown bool Eval() { return func_(arg_); } 171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown private: 172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown func_t func_; 173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void *arg_; 174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/// Wrapper for pthread_mutex_t. 179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/// 180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/// pthread_mutex_t is *not* a reader-writer lock, 181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/// so the methods like ReaderLock() aren't really reader locks. 182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/// We can not use pthread_rwlock_t because it 183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/// does not work with pthread_cond_t. 184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/// 185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/// TODO: We still need to test reader locks with this class. 186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/// Implement a mode where pthread_rwlock_t will be used 187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/// instead of pthread_mutex_t (only when not used with CondVar or LockWhen). 188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/// 189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass Mutex { 190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown friend class CondVar; 191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown public: 192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Mutex() { 193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown CHECK(0 == pthread_mutex_init(&mu_, NULL)); 194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown CHECK(0 == pthread_cond_init(&cv_, NULL)); 195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown signal_at_unlock_ = true; // Always signal at Unlock to make 196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Mutex more friendly to hybrid detectors. 197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~Mutex() { 199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown CHECK(0 == pthread_cond_destroy(&cv_)); 200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown CHECK(0 == pthread_mutex_destroy(&mu_)); 201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Lock() { CHECK(0 == pthread_mutex_lock(&mu_));} 203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown bool TryLock() { return (0 == pthread_mutex_trylock(&mu_));} 204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Unlock() { 205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (signal_at_unlock_) { 206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown CHECK(0 == pthread_cond_signal(&cv_)); 207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown CHECK(0 == pthread_mutex_unlock(&mu_)); 209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void ReaderLock() { Lock(); } 211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown bool ReaderTryLock() { return TryLock();} 212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void ReaderUnlock() { Unlock(); } 213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void LockWhen(Condition cond) { Lock(); WaitLoop(cond); } 215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void ReaderLockWhen(Condition cond) { Lock(); WaitLoop(cond); } 216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Await(Condition cond) { WaitLoop(cond); } 217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown bool ReaderLockWhenWithTimeout(Condition cond, int millis) 219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { Lock(); return WaitLoopWithTimeout(cond, millis); } 220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown bool LockWhenWithTimeout(Condition cond, int millis) 221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { Lock(); return WaitLoopWithTimeout(cond, millis); } 222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown bool AwaitWithTimeout(Condition cond, int millis) 223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { return WaitLoopWithTimeout(cond, millis); } 224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown private: 226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void WaitLoop(Condition cond) { 228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown signal_at_unlock_ = true; 229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown while(cond.Eval() == false) { 230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_cond_wait(&cv_, &mu_); 231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ANNOTATE_CONDVAR_LOCK_WAIT(&cv_, &mu_); 233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown bool WaitLoopWithTimeout(Condition cond, int millis) { 236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct timeval now; 237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct timespec timeout; 238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int retcode = 0; 239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown gettimeofday(&now, NULL); 240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown timeval2timespec(&now, &timeout, millis); 241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown signal_at_unlock_ = true; 243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown while (cond.Eval() == false && retcode == 0) { 244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown retcode = pthread_cond_timedwait(&cv_, &mu_, &timeout); 245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if(retcode == 0) { 247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ANNOTATE_CONDVAR_LOCK_WAIT(&cv_, &mu_); 248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return cond.Eval(); 250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // A hack. cv_ should be the first data member so that 253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // ANNOTATE_CONDVAR_WAIT(&MU, &MU) and ANNOTATE_CONDVAR_SIGNAL(&MU) works. 254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // (See also racecheck_unittest.cc) 255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_cond_t cv_; 256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_mutex_t mu_; 257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown bool signal_at_unlock_; // Set to true if Wait was called. 258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass MutexLock { // Scoped Mutex Locker/Unlocker 262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown public: 263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MutexLock(Mutex *mu) 264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown : mu_(mu) { 265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mu_->Lock(); 266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~MutexLock() { 268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mu_->Unlock(); 269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown private: 271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Mutex *mu_; 272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/// Wrapper for pthread_cond_t. 276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass CondVar { 277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown public: 278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown CondVar() { CHECK(0 == pthread_cond_init(&cv_, NULL)); } 279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~CondVar() { CHECK(0 == pthread_cond_destroy(&cv_)); } 280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Wait(Mutex *mu) { CHECK(0 == pthread_cond_wait(&cv_, &mu->mu_)); } 281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown bool WaitWithTimeout(Mutex *mu, int millis) { 282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct timeval now; 283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct timespec timeout; 284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown gettimeofday(&now, NULL); 285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown timeval2timespec(&now, &timeout, millis); 286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 0 != pthread_cond_timedwait(&cv_, &mu->mu_, &timeout); 287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Signal() { CHECK(0 == pthread_cond_signal(&cv_)); } 289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void SignalAll() { CHECK(0 == pthread_cond_broadcast(&cv_)); } 290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown private: 291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_cond_t cv_; 292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// pthreads do not allow to use condvar with rwlock so we can't make 296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// ReaderLock method of Mutex to be the real rw-lock. 297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// So, we need a special lock class to test reader locks. 298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define NEEDS_SEPERATE_RW_LOCK 299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass RWLock { 300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown public: 301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown RWLock() { CHECK(0 == pthread_rwlock_init(&mu_, NULL)); } 302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~RWLock() { CHECK(0 == pthread_rwlock_destroy(&mu_)); } 303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Lock() { CHECK(0 == pthread_rwlock_wrlock(&mu_)); } 304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void ReaderLock() { CHECK(0 == pthread_rwlock_rdlock(&mu_)); } 305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Unlock() { CHECK(0 == pthread_rwlock_unlock(&mu_)); } 306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void ReaderUnlock() { CHECK(0 == pthread_rwlock_unlock(&mu_)); } 307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown private: 308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_cond_t dummy; // Damn, this requires some redesign... 309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_rwlock_t mu_; 310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass ReaderLockScoped { // Scoped RWLock Locker/Unlocker 313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown public: 314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ReaderLockScoped(RWLock *mu) 315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown : mu_(mu) { 316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mu_->ReaderLock(); 317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~ReaderLockScoped() { 319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mu_->ReaderUnlock(); 320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown private: 322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown RWLock *mu_; 323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass WriterLockScoped { // Scoped RWLock Locker/Unlocker 326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown public: 327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown WriterLockScoped(RWLock *mu) 328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown : mu_(mu) { 329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mu_->Lock(); 330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~WriterLockScoped() { 332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mu_->Unlock(); 333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown private: 335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown RWLock *mu_; 336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/// Wrapper for pthread_create()/pthread_join(). 342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass MyThread { 343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown public: 344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown typedef void *(*worker_t)(void*); 345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MyThread(worker_t worker, void *arg = NULL, const char *name = NULL) 347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown :w_(worker), arg_(arg), name_(name) {} 348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MyThread(void (*worker)(void), void *arg = NULL, const char *name = NULL) 349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown :w_(reinterpret_cast<worker_t>(worker)), arg_(arg), name_(name) {} 350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MyThread(void (*worker)(void *), void *arg = NULL, const char *name = NULL) 351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown :w_(reinterpret_cast<worker_t>(worker)), arg_(arg), name_(name) {} 352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~MyThread(){ w_ = NULL; arg_ = NULL;} 354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Start() { CHECK(0 == pthread_create(&t_, NULL, (worker_t)ThreadBody, this));} 355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Join() { CHECK(0 == pthread_join(t_, NULL));} 356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_t tid() const { return t_; } 357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown private: 358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown static void ThreadBody(MyThread *my_thread) { 359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (my_thread->name_) { 360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ANNOTATE_THREAD_NAME(my_thread->name_); 361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown my_thread->w_(my_thread->arg_); 363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_t t_; 365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown worker_t w_; 366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void *arg_; 367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const char *name_; 368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/// Just a message queue. 372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass ProducerConsumerQueue { 373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown public: 374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ProducerConsumerQueue(int unused) { 375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown //ANNOTATE_PCQ_CREATE(this); 376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~ProducerConsumerQueue() { 378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown CHECK(q_.empty()); 379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown //ANNOTATE_PCQ_DESTROY(this); 380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Put. 383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Put(void *item) { 384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mu_.Lock(); 385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown q_.push(item); 386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ANNOTATE_CONDVAR_SIGNAL(&mu_); // LockWhen in Get() 387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown //ANNOTATE_PCQ_PUT(this); 388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mu_.Unlock(); 389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Get. 392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Blocks if the queue is empty. 393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void *Get() { 394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mu_.LockWhen(Condition(IsQueueNotEmpty, &q_)); 395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void * item = NULL; 396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown bool ok = TryGetInternal(&item); 397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown CHECK(ok); 398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mu_.Unlock(); 399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return item; 400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // If queue is not empty, 403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // remove an element from queue, put it into *res and return true. 404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Otherwise return false. 405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown bool TryGet(void **res) { 406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mu_.Lock(); 407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown bool ok = TryGetInternal(res); 408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mu_.Unlock(); 409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return ok; 410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown private: 413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Mutex mu_; 414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown std::queue<void*> q_; // protected by mu_ 415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Requires mu_ 417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown bool TryGetInternal(void ** item_ptr) { 418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (q_.empty()) 419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return false; 420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *item_ptr = q_.front(); 421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown q_.pop(); 422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown //ANNOTATE_PCQ_GET(this); 423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return true; 424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown static bool IsQueueNotEmpty(std::queue<void*> * queue) { 427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return !queue->empty(); 428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/// Function pointer with zero, one or two parameters. 434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstruct Closure { 435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown typedef void (*F0)(); 436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown typedef void (*F1)(void *arg1); 437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown typedef void (*F2)(void *arg1, void *arg2); 438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int n_params; 439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void *f; 440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void *param1; 441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void *param2; 442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Execute() { 444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (n_params == 0) { 445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (F0(f))(); 446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else if (n_params == 1) { 447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (F1(f))(param1); 448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown CHECK(n_params == 2); 450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (F2(f))(param1, param2); 451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown delete this; 453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownClosure *NewCallback(void (*f)()) { 457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Closure *res = new Closure; 458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown res->n_params = 0; 459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown res->f = (void*)(f); 460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown res->param1 = NULL; 461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown res->param2 = NULL; 462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return res; 463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntemplate <class P1> 466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownClosure *NewCallback(void (*f)(P1), P1 p1) { 467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown CHECK(sizeof(P1) <= sizeof(void*)); 468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Closure *res = new Closure; 469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown res->n_params = 1; 470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown res->f = (void*)(f); 471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown res->param1 = (void*)p1; 472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown res->param2 = NULL; 473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return res; 474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntemplate <class T, class P1, class P2> 477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownClosure *NewCallback(void (*f)(P1, P2), P1 p1, P2 p2) { 478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown CHECK(sizeof(P1) <= sizeof(void*)); 479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Closure *res = new Closure; 480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown res->n_params = 2; 481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown res->f = (void*)(f); 482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown res->param1 = (void*)p1; 483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown res->param2 = (void*)p2; 484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return res; 485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*! A thread pool that uses ProducerConsumerQueue. 488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Usage: 489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ThreadPool pool(n_workers); 491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pool.StartWorkers(); 492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pool.Add(NewCallback(func_with_no_args)); 493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pool.Add(NewCallback(func_with_one_arg, arg)); 494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pool.Add(NewCallback(func_with_two_args, arg1, arg2)); 495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ... // more calls to pool.Add() 496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // the ~ThreadPool() is called: we wait workers to finish 498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // and then join all threads in the pool. 499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/ 501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass ThreadPool { 502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown public: 503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown //! Create n_threads threads, but do not start. 504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown explicit ThreadPool(int n_threads) 505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown : queue_(INT_MAX) { 506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (int i = 0; i < n_threads; i++) { 507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MyThread *thread = new MyThread(&ThreadPool::Worker, this); 508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown workers_.push_back(thread); 509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown //! Start all threads. 513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void StartWorkers() { 514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (size_t i = 0; i < workers_.size(); i++) { 515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown workers_[i]->Start(); 516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown //! Add a closure. 520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Add(Closure *closure) { 521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown queue_.Put(closure); 522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int num_threads() { return workers_.size();} 525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown //! Wait workers to finish, then join all threads. 527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~ThreadPool() { 528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (size_t i = 0; i < workers_.size(); i++) { 529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Add(NULL); 530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (size_t i = 0; i < workers_.size(); i++) { 532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown workers_[i]->Join(); 533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown delete workers_[i]; 534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown private: 537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown std::vector<MyThread*> workers_; 538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ProducerConsumerQueue queue_; 539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown static void *Worker(void *p) { 541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ThreadPool *pool = reinterpret_cast<ThreadPool*>(p); 542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown while (true) { 543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Closure *closure = reinterpret_cast<Closure*>(pool->queue_.Get()); 544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if(closure == NULL) { 545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return NULL; 546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown closure->Execute(); 548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef NO_BARRIER 553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/// Wrapper for pthread_barrier_t. 554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass Barrier{ 555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown public: 556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown explicit Barrier(int n_threads) {CHECK(0 == pthread_barrier_init(&b_, 0, n_threads));} 557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~Barrier() {CHECK(0 == pthread_barrier_destroy(&b_));} 558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Block() { 559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // helgrind 3.3.0 does not have an interceptor for barrier. 560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // but our current local version does. 561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // ANNOTATE_CONDVAR_SIGNAL(this); 562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_barrier_wait(&b_); 563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // ANNOTATE_CONDVAR_WAIT(this, this); 564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown private: 566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_barrier_t b_; 567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif // NO_BARRIER 570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass BlockingCounter { 572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown public: 573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown explicit BlockingCounter(int initial_count) : 574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown count_(initial_count) {} 575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown bool DecrementCount() { 576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MutexLock lock(&mu_); 577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown count_--; 578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return count_ == 0; 579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Wait() { 581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mu_.LockWhen(Condition(&IsZero, &count_)); 582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mu_.Unlock(); 583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown private: 585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown static bool IsZero(int *arg) { return *arg == 0; } 586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Mutex mu_; 587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int count_; 588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownint AtomicIncrement(volatile int *value, int increment); 591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 592b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#ifndef VGO_darwin 593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browninline int AtomicIncrement(volatile int *value, int increment) { 594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return __sync_add_and_fetch(value, increment); 595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#else 598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Mac OS X version. 599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browninline int AtomicIncrement(volatile int *value, int increment) { 600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return OSAtomicAdd32(increment, value); 601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// TODO(timurrrr) this is a hack 604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define memalign(A,B) malloc(B) 605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// TODO(timurrrr) this is a hack 607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownint posix_memalign(void **out, size_t al, size_t size) { 608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *out = memalign(al, size); 609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return (*out == 0); 610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 611b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#endif // VGO_darwin 612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif // THREAD_WRAPPERS_PTHREAD_H 614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// vim:shiftwidth=2:softtabstop=2:expandtab:foldmethod=marker 615