Home | History | Annotate | Download | only in unittest
      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