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