• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
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__)
AtomicIncrement(volatile int * value,int increment)72   static int AtomicIncrement(volatile int *value, int increment) {
73     return __sync_add_and_fetch(value, increment);
74   }
75   #else
AtomicIncrement(volatile int * value,int increment)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 
AtomicIncrement(volatile int * value,int increment)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
posix_memalign(void ** out,size_t al,size_t size)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 
GetTimeInMs()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.
timeval2timespec(timeval * const tv,timespec * ts,int64_t offset_milli)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:
Mutex()151   Mutex() {
152     CHECK(0 == pthread_mutex_init(&mu_, NULL));
153     CHECK(0 == pthread_cond_init(&cv_, NULL));
154     signal_at_unlock_ = false;
155   }
~Mutex()156   ~Mutex() {
157     CHECK(0 == pthread_cond_destroy(&cv_));
158     CHECK(0 == pthread_mutex_destroy(&mu_));
159   }
Lock()160   void Lock()          { CHECK(0 == pthread_mutex_lock(&mu_));}
TryLock()161   bool TryLock()       { return (0 == pthread_mutex_trylock(&mu_));}
Unlock()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   }
ReaderLock()169   void ReaderLock()    { Lock(); }
ReaderTryLock()170   bool ReaderTryLock() { return TryLock();}
ReaderUnlock()171   void ReaderUnlock()  { Unlock(); }
172 
LockWhen(Condition cond)173   void LockWhen(Condition cond)            { Lock(); WaitLoop(cond); }
ReaderLockWhen(Condition cond)174   void ReaderLockWhen(Condition cond)      { Lock(); WaitLoop(cond); }
Await(Condition cond)175   void Await(Condition cond)               { WaitLoop(cond); }
176 
ReaderLockWhenWithTimeout(Condition cond,int millis)177   bool ReaderLockWhenWithTimeout(Condition cond, int millis)
178     { Lock(); return WaitLoopWithTimeout(cond, millis); }
LockWhenWithTimeout(Condition cond,int millis)179   bool LockWhenWithTimeout(Condition cond, int millis)
180     { Lock(); return WaitLoopWithTimeout(cond, millis); }
AwaitWithTimeout(Condition cond,int millis)181   bool AwaitWithTimeout(Condition cond, int millis)
182     { return WaitLoopWithTimeout(cond, millis); }
183 
184  private:
185 
WaitLoop(Condition cond)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 
WaitLoopWithTimeout(Condition cond,int millis)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:
CondVar()220   CondVar()   { CHECK(0 == pthread_cond_init(&cv_, NULL)); }
~CondVar()221   ~CondVar()  { CHECK(0 == pthread_cond_destroy(&cv_)); }
Wait(Mutex * mu)222   void Wait(Mutex *mu) { CHECK(0 == pthread_cond_wait(&cv_, &mu->mu_)); }
WaitWithTimeout(Mutex * mu,int millis)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   }
Signal()230   void Signal() { CHECK(0 == pthread_cond_signal(&cv_)); }
SignalAll()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:
RWLock()242   RWLock() { CHECK(0 == pthread_rwlock_init(&mu_, NULL)); }
~RWLock()243   ~RWLock() { CHECK(0 == pthread_rwlock_destroy(&mu_)); }
Lock()244   void Lock() { CHECK(0 == pthread_rwlock_wrlock(&mu_)); }
ReaderLock()245   void ReaderLock() { CHECK(0 == pthread_rwlock_rdlock(&mu_)); }
Unlock()246   void Unlock() { CHECK(0 == pthread_rwlock_unlock(&mu_)); }
ReaderUnlock()247   void ReaderUnlock() { CHECK(0 == pthread_rwlock_unlock(&mu_)); }
TryLock()248   bool TryLock() {
249     int res = pthread_rwlock_trywrlock(&mu_);
250     if (res != 0) {
251       CHECK(EBUSY == res);
252     }
253     return (res == 0);
254   }
ReaderTryLock()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:
ReaderLockScoped(RWLock * mu)268   ReaderLockScoped(RWLock *mu) : mu_(mu) {
269     mu_->ReaderLock();
270   }
~ReaderLockScoped()271   ~ReaderLockScoped() {
272     mu_->ReaderUnlock();
273   }
274  private:
275   RWLock *mu_;
276 };
277 
278 class WriterLockScoped {  // Scoped RWLock Locker/Unlocker
279  public:
WriterLockScoped(RWLock * mu)280   WriterLockScoped(RWLock *mu) : mu_(mu) {
281     mu_->Lock();
282   }
~WriterLockScoped()283   ~WriterLockScoped() {
284     mu_->Unlock();
285   }
286  private:
287   RWLock *mu_;
288 };
289 
290 #if !defined(__APPLE__) && !defined(ANDROID)
291 class SpinLock {
292  public:
SpinLock()293   SpinLock() {
294     CHECK(0 == pthread_spin_init(&mu_, 0));
295   }
~SpinLock()296   ~SpinLock() {
297     CHECK(0 == pthread_spin_destroy(&mu_));
298   }
Lock()299   void Lock() {
300     CHECK(0 == pthread_spin_lock(&mu_));
301   }
Unlock()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.
SpinLock()314   SpinLock() : mu_(OS_SPINLOCK_INIT) {
315     ANNOTATE_RWLOCK_CREATE((void*)&mu_);
316   }
~SpinLock()317   ~SpinLock() {
318     ANNOTATE_RWLOCK_DESTROY((void*)&mu_);
319   }
Lock()320   void Lock() {
321     OSSpinLockLock(&mu_);
322     ANNOTATE_RWLOCK_ACQUIRED((void*)&mu_, 1);
323   }
Unlock()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)
w_(worker)339       :w_(worker), arg_(arg), name_(name) {}
340   MyThread(void (*worker)(void), void *arg = NULL, const char *name = NULL)
w_(reinterpret_cast<worker_t> (worker))341       :w_(reinterpret_cast<worker_t>(worker)), arg_(arg), name_(name) {}
342   MyThread(void (*worker)(void *), void *arg = NULL, const char *name = NULL)
w_(reinterpret_cast<worker_t> (worker))343       :w_(reinterpret_cast<worker_t>(worker)), arg_(arg), name_(name) {}
344 
~MyThread()345   ~MyThread(){ w_ = NULL; arg_ = NULL;}
Start()346   void Start() { CHECK(0 == pthread_create(&t_, NULL, (worker_t)ThreadBody, this));}
Join()347   void Join()  { CHECK(0 == pthread_join(t_, NULL));}
tid()348   pthread_t tid() const { return t_; }
349  private:
ThreadBody(MyThread * my_thread)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:
Barrier(int n_threads)366   explicit Barrier(int n_threads) {CHECK(0 == pthread_barrier_init(&b_, 0, n_threads));}
~Barrier()367   ~Barrier()                      {CHECK(0 == pthread_barrier_destroy(&b_));}
Block()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