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