1/* 2 This file is part of ThreadSanitizer, a dynamic data race detector. 3 4 Copyright (C) 2008-2009 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// If one needs to test ThreadSanitizer's support for another threading library, 30// he/she can create a copy of this file and replace pthread_ calls 31// with appropriate calls to his/her library. 32// 33// Note, that some of the methods defined here are annotated with 34// ANNOTATE_* macros defined in dynamic_annotations.h. 35// 36// DISCLAIMER: the classes defined in this header file 37// are NOT intended for general use -- only for unit tests. 38 39#ifndef THREAD_WRAPPERS_PTHREADS_H_ 40#define THREAD_WRAPPERS_PTHREADS_H_ 41 42#include <dirent.h> 43#include <errno.h> 44#include <pthread.h> 45#include <semaphore.h> 46#include <stdlib.h> 47#include <stdint.h> 48#include <sys/mman.h> // mmap 49#include <sys/time.h> 50#include <sys/types.h> 51#include <sys/stat.h> 52#include <unistd.h> 53 54#define NOINLINE __attribute__ ((noinline)) 55#define ALIGNED(X) __attribute__ ((aligned (X))) 56 57// This constant is true if malloc() uses mutex on your platform as this may 58// introduce a happens-before arc for a pure happens-before race detector. 59static const bool kMallocUsesMutex = false; 60 61#ifndef __APPLE__ 62 // Linux 63 #include <malloc.h> // memalign 64 65 #ifdef ANDROID 66 #define NO_BARRIER 67 #define NO_SPINLOCK 68 #endif 69 70 // Older Android toolchain does not support atomic builtins. 71 #if !defined(ANDROID) || defined(__ANDROID__) 72 static int AtomicIncrement(volatile int *value, int increment) { 73 return __sync_add_and_fetch(value, increment); 74 } 75 #else 76 static int AtomicIncrement(volatile int *value, int increment) { 77 static pthread_mutex_t mu = PTHREAD_MUTEX_INITIALIZER; 78 ANNOTATE_NOT_HAPPENS_BEFORE_MUTEX(&mu); 79 pthread_mutex_lock(&mu); 80 int result = *value += increment; 81 pthread_mutex_unlock(&mu); 82 return result; 83 } 84 #endif 85 86 87 #ifdef ANDROID 88 #undef TLS 89 #else 90 #define TLS __thread 91 #endif 92 93#else 94 // Mac OS X 95 #include <libkern/OSAtomic.h> 96 #define NO_BARRIER 97 #define NO_UNNAMED_SEM 98 #undef TLS 99 #define NO_SPINLOCK 100 101 static int AtomicIncrement(volatile int *value, int increment) { 102 return OSAtomicAdd32(increment, value); 103 } 104 105 // TODO(timurrrr) this is a hack 106 #define memalign(A,B) malloc(B) 107#ifndef OS_darwin_10 108 // TODO(timurrrr) this is a hack 109 static int posix_memalign(void **out, size_t al, size_t size) { 110 *out = memalign(al, size); 111 return (*out == 0); 112 } 113#endif 114#endif 115 116 117static int GetTimeInMs() { 118 struct timeval now; 119 gettimeofday(&now, NULL); 120 return (int)(now.tv_sec * 1000 + now.tv_usec / 1000); 121} 122 123/// Copy tv to ts adding offset in milliseconds. 124static inline void timeval2timespec(timeval *const tv, 125 timespec *ts, 126 int64_t offset_milli) { 127 const int64_t ten_9 = 1000000000LL; 128 const int64_t ten_6 = 1000000LL; 129 const int64_t ten_3 = 1000LL; 130 int64_t now_nsec = (int64_t)tv->tv_sec * ten_9; 131 now_nsec += (int64_t)tv->tv_usec * ten_3; 132 int64_t then_nsec = now_nsec + offset_milli * ten_6; 133 ts->tv_sec = then_nsec / ten_9; 134 ts->tv_nsec = then_nsec % ten_9; 135} 136 137/// Wrapper for pthread_mutex_t. 138/// 139/// pthread_mutex_t is *not* a reader-writer lock, 140/// so the methods like ReaderLock() aren't really reader locks. 141/// We can not use pthread_rwlock_t because it 142/// does not work with pthread_cond_t. 143/// 144/// TODO: We still need to test reader locks with this class. 145/// Implement a mode where pthread_rwlock_t will be used 146/// instead of pthread_mutex_t (only when not used with CondVar or LockWhen). 147/// 148class Mutex { 149 friend class CondVar; 150 public: 151 Mutex() { 152 CHECK(0 == pthread_mutex_init(&mu_, NULL)); 153 CHECK(0 == pthread_cond_init(&cv_, NULL)); 154 signal_at_unlock_ = false; 155 } 156 ~Mutex() { 157 CHECK(0 == pthread_cond_destroy(&cv_)); 158 CHECK(0 == pthread_mutex_destroy(&mu_)); 159 } 160 void Lock() { CHECK(0 == pthread_mutex_lock(&mu_));} 161 bool TryLock() { return (0 == pthread_mutex_trylock(&mu_));} 162 void Unlock() { 163 ANNOTATE_HAPPENS_BEFORE(this); 164 if (signal_at_unlock_) { 165 CHECK(0 == pthread_cond_signal(&cv_)); 166 } 167 CHECK(0 == pthread_mutex_unlock(&mu_)); 168 } 169 void ReaderLock() { Lock(); } 170 bool ReaderTryLock() { return TryLock();} 171 void ReaderUnlock() { Unlock(); } 172 173 void LockWhen(Condition cond) { Lock(); WaitLoop(cond); } 174 void ReaderLockWhen(Condition cond) { Lock(); WaitLoop(cond); } 175 void Await(Condition cond) { WaitLoop(cond); } 176 177 bool ReaderLockWhenWithTimeout(Condition cond, int millis) 178 { Lock(); return WaitLoopWithTimeout(cond, millis); } 179 bool LockWhenWithTimeout(Condition cond, int millis) 180 { Lock(); return WaitLoopWithTimeout(cond, millis); } 181 bool AwaitWithTimeout(Condition cond, int millis) 182 { return WaitLoopWithTimeout(cond, millis); } 183 184 private: 185 186 void WaitLoop(Condition cond) { 187 signal_at_unlock_ = true; 188 while(cond.Eval() == false) { 189 pthread_cond_wait(&cv_, &mu_); 190 } 191 ANNOTATE_HAPPENS_AFTER(this); 192 } 193 194 bool WaitLoopWithTimeout(Condition cond, int millis) { 195 struct timeval now; 196 struct timespec timeout; 197 int retcode = 0; 198 gettimeofday(&now, NULL); 199 timeval2timespec(&now, &timeout, millis); 200 201 signal_at_unlock_ = true; 202 203 while (cond.Eval() == false && retcode == 0) { 204 retcode = pthread_cond_timedwait(&cv_, &mu_, &timeout); 205 } 206 if(retcode == 0) { 207 ANNOTATE_HAPPENS_AFTER(this); 208 } 209 return cond.Eval(); 210 } 211 212 pthread_mutex_t mu_; // Must be the first member. 213 pthread_cond_t cv_; 214 bool signal_at_unlock_; // Set to true if Wait was called. 215}; 216 217/// Wrapper for pthread_cond_t. 218class CondVar { 219 public: 220 CondVar() { CHECK(0 == pthread_cond_init(&cv_, NULL)); } 221 ~CondVar() { CHECK(0 == pthread_cond_destroy(&cv_)); } 222 void Wait(Mutex *mu) { CHECK(0 == pthread_cond_wait(&cv_, &mu->mu_)); } 223 bool WaitWithTimeout(Mutex *mu, int millis) { 224 struct timeval now; 225 struct timespec timeout; 226 gettimeofday(&now, NULL); 227 timeval2timespec(&now, &timeout, millis); 228 return 0 != pthread_cond_timedwait(&cv_, &mu->mu_, &timeout); 229 } 230 void Signal() { CHECK(0 == pthread_cond_signal(&cv_)); } 231 void SignalAll() { CHECK(0 == pthread_cond_broadcast(&cv_)); } 232 private: 233 pthread_cond_t cv_; 234}; 235 236// pthreads do not allow to use condvar with rwlock so we can't make 237// ReaderLock method of Mutex to be the real rw-lock. 238// So, we need a special lock class to test reader locks. 239#define NEEDS_SEPERATE_RW_LOCK 240class RWLock { 241 public: 242 RWLock() { CHECK(0 == pthread_rwlock_init(&mu_, NULL)); } 243 ~RWLock() { CHECK(0 == pthread_rwlock_destroy(&mu_)); } 244 void Lock() { CHECK(0 == pthread_rwlock_wrlock(&mu_)); } 245 void ReaderLock() { CHECK(0 == pthread_rwlock_rdlock(&mu_)); } 246 void Unlock() { CHECK(0 == pthread_rwlock_unlock(&mu_)); } 247 void ReaderUnlock() { CHECK(0 == pthread_rwlock_unlock(&mu_)); } 248 bool TryLock() { 249 int res = pthread_rwlock_trywrlock(&mu_); 250 if (res != 0) { 251 CHECK(EBUSY == res); 252 } 253 return (res == 0); 254 } 255 bool ReaderTryLock() { 256 int res = pthread_rwlock_tryrdlock(&mu_); 257 if (res != 0) { 258 CHECK(EBUSY == res); 259 } 260 return (res == 0); 261 } 262 private: 263 pthread_rwlock_t mu_; 264}; 265 266class ReaderLockScoped { // Scoped RWLock Locker/Unlocker 267 public: 268 ReaderLockScoped(RWLock *mu) : mu_(mu) { 269 mu_->ReaderLock(); 270 } 271 ~ReaderLockScoped() { 272 mu_->ReaderUnlock(); 273 } 274 private: 275 RWLock *mu_; 276}; 277 278class WriterLockScoped { // Scoped RWLock Locker/Unlocker 279 public: 280 WriterLockScoped(RWLock *mu) : mu_(mu) { 281 mu_->Lock(); 282 } 283 ~WriterLockScoped() { 284 mu_->Unlock(); 285 } 286 private: 287 RWLock *mu_; 288}; 289 290#if !defined(__APPLE__) && !defined(ANDROID) 291class SpinLock { 292 public: 293 SpinLock() { 294 CHECK(0 == pthread_spin_init(&mu_, 0)); 295 } 296 ~SpinLock() { 297 CHECK(0 == pthread_spin_destroy(&mu_)); 298 } 299 void Lock() { 300 CHECK(0 == pthread_spin_lock(&mu_)); 301 } 302 void Unlock() { 303 CHECK(0 == pthread_spin_unlock(&mu_)); 304 } 305 private: 306 pthread_spinlock_t mu_; 307}; 308 309#elif defined(__APPLE__) 310 311class SpinLock { 312 public: 313 // Mac OS X version. 314 SpinLock() : mu_(OS_SPINLOCK_INIT) { 315 ANNOTATE_RWLOCK_CREATE((void*)&mu_); 316 } 317 ~SpinLock() { 318 ANNOTATE_RWLOCK_DESTROY((void*)&mu_); 319 } 320 void Lock() { 321 OSSpinLockLock(&mu_); 322 ANNOTATE_RWLOCK_ACQUIRED((void*)&mu_, 1); 323 } 324 void Unlock() { 325 ANNOTATE_RWLOCK_RELEASED((void*)&mu_, 1); 326 OSSpinLockUnlock(&mu_); 327 } 328 private: 329 OSSpinLock mu_; 330}; 331#endif // __APPLE__ 332 333/// Wrapper for pthread_create()/pthread_join(). 334class MyThread { 335 public: 336 typedef void *(*worker_t)(void*); 337 338 MyThread(worker_t worker, void *arg = NULL, const char *name = NULL) 339 :w_(worker), arg_(arg), name_(name) {} 340 MyThread(void (*worker)(void), void *arg = NULL, const char *name = NULL) 341 :w_(reinterpret_cast<worker_t>(worker)), arg_(arg), name_(name) {} 342 MyThread(void (*worker)(void *), void *arg = NULL, const char *name = NULL) 343 :w_(reinterpret_cast<worker_t>(worker)), arg_(arg), name_(name) {} 344 345 ~MyThread(){ w_ = NULL; arg_ = NULL;} 346 void Start() { CHECK(0 == pthread_create(&t_, NULL, (worker_t)ThreadBody, this));} 347 void Join() { CHECK(0 == pthread_join(t_, NULL));} 348 pthread_t tid() const { return t_; } 349 private: 350 static void ThreadBody(MyThread *my_thread) { 351 if (my_thread->name_) { 352 ANNOTATE_THREAD_NAME(my_thread->name_); 353 } 354 my_thread->w_(my_thread->arg_); 355 } 356 pthread_t t_; 357 worker_t w_; 358 void *arg_; 359 const char *name_; 360}; 361 362#ifndef NO_BARRIER 363/// Wrapper for pthread_barrier_t. 364class Barrier{ 365 public: 366 explicit Barrier(int n_threads) {CHECK(0 == pthread_barrier_init(&b_, 0, n_threads));} 367 ~Barrier() {CHECK(0 == pthread_barrier_destroy(&b_));} 368 void Block() { 369 // helgrind 3.3.0 does not have an interceptor for barrier. 370 // but our current local version does. 371 // ANNOTATE_CONDVAR_SIGNAL(this); 372 pthread_barrier_wait(&b_); 373 // ANNOTATE_CONDVAR_WAIT(this, this); 374 } 375 private: 376 pthread_barrier_t b_; 377}; 378 379#endif // NO_BARRIER 380 381#endif // THREAD_WRAPPERS_PTHREADS_H_ 382