1 /* 2 This file is part of ThreadSanitizer, a dynamic data race detector. 3 4 Copyright (C) 2008-2009 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 // 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. 59 static 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 117 static 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. 124 static 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 /// 148 class 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. 218 class 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 240 class 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 266 class 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 278 class 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) 291 class 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 311 class 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(). 334 class 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. 364 class 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