blob: 05461c56f57e725820d0dfcaa8993f32a6479d7d [file] [log] [blame]
bartbd2073c2009-05-30 16:33:10 +00001/*
2 This file is part of Valgrind, a dynamic binary instrumentation
3 framework.
4
5 Copyright (C) 2008-2008 Google Inc
bart31b983d2010-02-21 14:52:59 +00006 opensource@google.com
bartbd2073c2009-05-30 16:33:10 +00007
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the
11 License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 02111-1307, USA.
22
23 The GNU General Public License is contained in the file COPYING.
24*/
25
bart31b983d2010-02-21 14:52:59 +000026// Author: Konstantin Serebryany <opensource@google.com>
bartbd2073c2009-05-30 16:33:10 +000027//
bart31b983d2010-02-21 14:52:59 +000028// Here we define few simple classes that wrap pthread primitives.
bartbd2073c2009-05-30 16:33:10 +000029//
bart31b983d2010-02-21 14:52:59 +000030// We need this to create unit tests for helgrind (or similar tool)
31// that will work with different threading frameworks.
bartbd2073c2009-05-30 16:33:10 +000032//
bart31b983d2010-02-21 14:52:59 +000033// If one needs to test helgrind's support for another threading library,
34// he/she can create a copy of this file and replace pthread_ calls
35// with appropriate calls to his/her library.
bartbd2073c2009-05-30 16:33:10 +000036//
bart31b983d2010-02-21 14:52:59 +000037// Note, that some of the methods defined here are annotated with
38// ANNOTATE_* macros defined in dynamic_annotations.h.
bartbd2073c2009-05-30 16:33:10 +000039//
bart31b983d2010-02-21 14:52:59 +000040// DISCLAIMER: the classes defined in this header file
41// are NOT intended for general use -- only for unit tests.
bartbd2073c2009-05-30 16:33:10 +000042//
43
44#ifndef THREAD_WRAPPERS_PTHREAD_H
45#define THREAD_WRAPPERS_PTHREAD_H
46
47#include <pthread.h>
48#include <semaphore.h>
49#include <unistd.h>
50#include <queue>
51#include <stdio.h>
52#include <limits.h> // INT_MAX
53
barte291d912009-07-21 11:12:59 +000054#ifdef __APPLE__
bartbd2073c2009-05-30 16:33:10 +000055#include <libkern/OSAtomic.h>
bart95c52a12009-06-02 15:11:42 +000056#define NO_BARRIER
57#define NO_TLS
bartbd2073c2009-05-30 16:33:10 +000058#endif
59
60#include <string>
61using namespace std;
62
63#include <sys/time.h>
64#include <time.h>
65
bart263476b2009-05-31 11:53:39 +000066#include "../../drd/drd.h"
67#define ANNOTATE_NO_OP(arg) do { } while(0)
bart031091d2009-08-14 10:19:26 +000068#define ANNOTATE_EXPECT_RACE(addr, descr) DRDCL_(ignore_range)(addr, 4)
bart263476b2009-05-31 11:53:39 +000069static inline bool RunningOnValgrind() { return RUNNING_ON_VALGRIND; }
bartbd2073c2009-05-30 16:33:10 +000070
71#include <assert.h>
72#ifdef NDEBUG
73# error "Pleeease, do not define NDEBUG"
bart31b983d2010-02-21 14:52:59 +000074#endif
bartbd2073c2009-05-30 16:33:10 +000075#define CHECK assert
76
77/// Set this to true if malloc() uses mutex on your platform as this may
78/// introduce a happens-before arc for a pure happens-before race detector.
79const bool kMallocUsesMutex = false;
80
bart31b983d2010-02-21 14:52:59 +000081/// Current time in milliseconds.
bartbd2073c2009-05-30 16:33:10 +000082static inline int64_t GetCurrentTimeMillis() {
83 struct timeval now;
84 gettimeofday(&now, NULL);
85 return now.tv_sec * 1000 + now.tv_usec / 1000;
86}
87
bart31b983d2010-02-21 14:52:59 +000088/// Copy tv to ts adding offset in milliseconds.
89static inline void timeval2timespec(timeval *const tv,
90 timespec *ts,
bartbd2073c2009-05-30 16:33:10 +000091 int64_t offset_milli) {
92 const int64_t ten_9 = 1000000000LL;
93 const int64_t ten_6 = 1000000LL;
94 const int64_t ten_3 = 1000LL;
95 int64_t now_nsec = (int64_t)tv->tv_sec * ten_9;
96 now_nsec += (int64_t)tv->tv_usec * ten_3;
97 int64_t then_nsec = now_nsec + offset_milli * ten_6;
98 ts->tv_sec = then_nsec / ten_9;
99 ts->tv_nsec = then_nsec % ten_9;
100}
101
102
103class CondVar;
104
105#ifndef NO_SPINLOCK
106/// helgrind does not (yet) support spin locks, so we annotate them.
107
barte291d912009-07-21 11:12:59 +0000108#ifndef __APPLE__
bartbd2073c2009-05-30 16:33:10 +0000109class SpinLock {
110 public:
111 SpinLock() {
112 CHECK(0 == pthread_spin_init(&mu_, 0));
113 ANNOTATE_RWLOCK_CREATE((void*)&mu_);
114 }
115 ~SpinLock() {
116 ANNOTATE_RWLOCK_DESTROY((void*)&mu_);
117 CHECK(0 == pthread_spin_destroy(&mu_));
118 }
119 void Lock() {
120 CHECK(0 == pthread_spin_lock(&mu_));
121 ANNOTATE_RWLOCK_ACQUIRED((void*)&mu_, 1);
122 }
123 void Unlock() {
124 ANNOTATE_RWLOCK_RELEASED((void*)&mu_, 1);
125 CHECK(0 == pthread_spin_unlock(&mu_));
126 }
127 private:
128 pthread_spinlock_t mu_;
129};
130
131#else
132
133class SpinLock {
134 public:
135 // Mac OS X version.
136 SpinLock() : mu_(OS_SPINLOCK_INIT) {
137 ANNOTATE_RWLOCK_CREATE((void*)&mu_);
138 }
139 ~SpinLock() {
140 ANNOTATE_RWLOCK_DESTROY((void*)&mu_);
141 }
142 void Lock() {
143 OSSpinLockLock(&mu_);
144 ANNOTATE_RWLOCK_ACQUIRED((void*)&mu_, 1);
145 }
146 void Unlock() {
147 ANNOTATE_RWLOCK_RELEASED((void*)&mu_, 1);
148 OSSpinLockUnlock(&mu_);
149 }
150 private:
151 OSSpinLock mu_;
152};
barte291d912009-07-21 11:12:59 +0000153#endif // __APPLE__
bartbd2073c2009-05-30 16:33:10 +0000154
155#endif // NO_SPINLOCK
156
bart31b983d2010-02-21 14:52:59 +0000157/// Just a boolean condition. Used by Mutex::LockWhen and similar.
bartbd2073c2009-05-30 16:33:10 +0000158class Condition {
159 public:
160 typedef bool (*func_t)(void*);
161
162 template <typename T>
bart31b983d2010-02-21 14:52:59 +0000163 Condition(bool (*func)(T*), T* arg)
bartbd2073c2009-05-30 16:33:10 +0000164 : func_(reinterpret_cast<func_t>(func)), arg_(arg) {}
165
bart31b983d2010-02-21 14:52:59 +0000166 Condition(bool (*func)())
bartbd2073c2009-05-30 16:33:10 +0000167 : func_(reinterpret_cast<func_t>(func)), arg_(NULL) {}
168
169 bool Eval() { return func_(arg_); }
170 private:
171 func_t func_;
172 void *arg_;
173
174};
175
176
177/// Wrapper for pthread_mutex_t.
178///
bart31b983d2010-02-21 14:52:59 +0000179/// pthread_mutex_t is *not* a reader-writer lock,
180/// so the methods like ReaderLock() aren't really reader locks.
181/// We can not use pthread_rwlock_t because it
bartbd2073c2009-05-30 16:33:10 +0000182/// does not work with pthread_cond_t.
bart31b983d2010-02-21 14:52:59 +0000183///
184/// TODO: We still need to test reader locks with this class.
185/// Implement a mode where pthread_rwlock_t will be used
186/// instead of pthread_mutex_t (only when not used with CondVar or LockWhen).
187///
bartbd2073c2009-05-30 16:33:10 +0000188class Mutex {
189 friend class CondVar;
bart31b983d2010-02-21 14:52:59 +0000190 public:
bartbd2073c2009-05-30 16:33:10 +0000191 Mutex() {
192 CHECK(0 == pthread_mutex_init(&mu_, NULL));
193 CHECK(0 == pthread_cond_init(&cv_, NULL));
bart31b983d2010-02-21 14:52:59 +0000194 signal_at_unlock_ = true; // Always signal at Unlock to make
bartbd2073c2009-05-30 16:33:10 +0000195 // Mutex more friendly to hybrid detectors.
196 }
197 ~Mutex() {
198 CHECK(0 == pthread_cond_destroy(&cv_));
199 CHECK(0 == pthread_mutex_destroy(&mu_));
200 }
201 void Lock() { CHECK(0 == pthread_mutex_lock(&mu_));}
202 bool TryLock() { return (0 == pthread_mutex_trylock(&mu_));}
203 void Unlock() {
204 if (signal_at_unlock_) {
bart31b983d2010-02-21 14:52:59 +0000205 CHECK(0 == pthread_cond_signal(&cv_));
bartbd2073c2009-05-30 16:33:10 +0000206 }
207 CHECK(0 == pthread_mutex_unlock(&mu_));
208 }
209 void ReaderLock() { Lock(); }
210 bool ReaderTryLock() { return TryLock();}
211 void ReaderUnlock() { Unlock(); }
212
213 void LockWhen(Condition cond) { Lock(); WaitLoop(cond); }
214 void ReaderLockWhen(Condition cond) { Lock(); WaitLoop(cond); }
215 void Await(Condition cond) { WaitLoop(cond); }
216
bart31b983d2010-02-21 14:52:59 +0000217 bool ReaderLockWhenWithTimeout(Condition cond, int millis)
bartbd2073c2009-05-30 16:33:10 +0000218 { Lock(); return WaitLoopWithTimeout(cond, millis); }
bart31b983d2010-02-21 14:52:59 +0000219 bool LockWhenWithTimeout(Condition cond, int millis)
bartbd2073c2009-05-30 16:33:10 +0000220 { Lock(); return WaitLoopWithTimeout(cond, millis); }
bart31b983d2010-02-21 14:52:59 +0000221 bool AwaitWithTimeout(Condition cond, int millis)
bartbd2073c2009-05-30 16:33:10 +0000222 { return WaitLoopWithTimeout(cond, millis); }
223
224 private:
225
226 void WaitLoop(Condition cond) {
227 signal_at_unlock_ = true;
228 while(cond.Eval() == false) {
229 pthread_cond_wait(&cv_, &mu_);
230 }
231 ANNOTATE_CONDVAR_LOCK_WAIT(&cv_, &mu_);
232 }
233
234 bool WaitLoopWithTimeout(Condition cond, int millis) {
235 struct timeval now;
236 struct timespec timeout;
237 int retcode = 0;
238 gettimeofday(&now, NULL);
239 timeval2timespec(&now, &timeout, millis);
240
241 signal_at_unlock_ = true;
242 while (cond.Eval() == false && retcode == 0) {
243 retcode = pthread_cond_timedwait(&cv_, &mu_, &timeout);
244 }
245 if(retcode == 0) {
246 ANNOTATE_CONDVAR_LOCK_WAIT(&cv_, &mu_);
247 }
248 return cond.Eval();
249 }
250
bart31b983d2010-02-21 14:52:59 +0000251 // A hack. cv_ should be the first data member so that
252 // ANNOTATE_CONDVAR_WAIT(&MU, &MU) and ANNOTATE_CONDVAR_SIGNAL(&MU) works.
bartbd2073c2009-05-30 16:33:10 +0000253 // (See also racecheck_unittest.cc)
bart31b983d2010-02-21 14:52:59 +0000254 pthread_cond_t cv_;
bartbd2073c2009-05-30 16:33:10 +0000255 pthread_mutex_t mu_;
256 bool signal_at_unlock_; // Set to true if Wait was called.
257};
258
259
260class MutexLock { // Scoped Mutex Locker/Unlocker
261 public:
bart31b983d2010-02-21 14:52:59 +0000262 MutexLock(Mutex *mu)
bartbd2073c2009-05-30 16:33:10 +0000263 : mu_(mu) {
264 mu_->Lock();
265 }
266 ~MutexLock() {
267 mu_->Unlock();
268 }
269 private:
270 Mutex *mu_;
271};
272
273
bart31b983d2010-02-21 14:52:59 +0000274/// Wrapper for pthread_cond_t.
bartbd2073c2009-05-30 16:33:10 +0000275class CondVar {
276 public:
277 CondVar() { CHECK(0 == pthread_cond_init(&cv_, NULL)); }
278 ~CondVar() { CHECK(0 == pthread_cond_destroy(&cv_)); }
279 void Wait(Mutex *mu) { CHECK(0 == pthread_cond_wait(&cv_, &mu->mu_)); }
bart31b983d2010-02-21 14:52:59 +0000280 bool WaitWithTimeout(Mutex *mu, int millis) {
bartbd2073c2009-05-30 16:33:10 +0000281 struct timeval now;
282 struct timespec timeout;
283 gettimeofday(&now, NULL);
284 timeval2timespec(&now, &timeout, millis);
285 return 0 != pthread_cond_timedwait(&cv_, &mu->mu_, &timeout);
286 }
287 void Signal() { CHECK(0 == pthread_cond_signal(&cv_)); }
288 void SignalAll() { CHECK(0 == pthread_cond_broadcast(&cv_)); }
289 private:
290 pthread_cond_t cv_;
291};
292
293
294// pthreads do not allow to use condvar with rwlock so we can't make
295// ReaderLock method of Mutex to be the real rw-lock.
bart31b983d2010-02-21 14:52:59 +0000296// So, we need a special lock class to test reader locks.
bartbd2073c2009-05-30 16:33:10 +0000297#define NEEDS_SEPERATE_RW_LOCK
298class RWLock {
299 public:
300 RWLock() { CHECK(0 == pthread_rwlock_init(&mu_, NULL)); }
301 ~RWLock() { CHECK(0 == pthread_rwlock_destroy(&mu_)); }
302 void Lock() { CHECK(0 == pthread_rwlock_wrlock(&mu_)); }
303 void ReaderLock() { CHECK(0 == pthread_rwlock_rdlock(&mu_)); }
304 void Unlock() { CHECK(0 == pthread_rwlock_unlock(&mu_)); }
305 void ReaderUnlock() { CHECK(0 == pthread_rwlock_unlock(&mu_)); }
306 private:
307 pthread_cond_t dummy; // Damn, this requires some redesign...
308 pthread_rwlock_t mu_;
309};
310
311class ReaderLockScoped { // Scoped RWLock Locker/Unlocker
312 public:
bart31b983d2010-02-21 14:52:59 +0000313 ReaderLockScoped(RWLock *mu)
bartbd2073c2009-05-30 16:33:10 +0000314 : mu_(mu) {
315 mu_->ReaderLock();
316 }
317 ~ReaderLockScoped() {
318 mu_->ReaderUnlock();
319 }
320 private:
321 RWLock *mu_;
322};
323
324class WriterLockScoped { // Scoped RWLock Locker/Unlocker
325 public:
bart31b983d2010-02-21 14:52:59 +0000326 WriterLockScoped(RWLock *mu)
bartbd2073c2009-05-30 16:33:10 +0000327 : mu_(mu) {
328 mu_->Lock();
329 }
330 ~WriterLockScoped() {
331 mu_->Unlock();
332 }
333 private:
334 RWLock *mu_;
335};
336
337
338
339
340/// Wrapper for pthread_create()/pthread_join().
341class MyThread {
bart31b983d2010-02-21 14:52:59 +0000342 public:
bartbd2073c2009-05-30 16:33:10 +0000343 typedef void *(*worker_t)(void*);
344
bart31b983d2010-02-21 14:52:59 +0000345 MyThread(worker_t worker, void *arg = NULL, const char *name = NULL)
bartbd2073c2009-05-30 16:33:10 +0000346 :w_(worker), arg_(arg), name_(name) {}
bart31b983d2010-02-21 14:52:59 +0000347 MyThread(void (*worker)(void), void *arg = NULL, const char *name = NULL)
bartbd2073c2009-05-30 16:33:10 +0000348 :w_(reinterpret_cast<worker_t>(worker)), arg_(arg), name_(name) {}
bart31b983d2010-02-21 14:52:59 +0000349 MyThread(void (*worker)(void *), void *arg = NULL, const char *name = NULL)
bartbd2073c2009-05-30 16:33:10 +0000350 :w_(reinterpret_cast<worker_t>(worker)), arg_(arg), name_(name) {}
351
352 ~MyThread(){ w_ = NULL; arg_ = NULL;}
353 void Start() { CHECK(0 == pthread_create(&t_, NULL, (worker_t)ThreadBody, this));}
354 void Join() { CHECK(0 == pthread_join(t_, NULL));}
355 pthread_t tid() const { return t_; }
356 private:
357 static void ThreadBody(MyThread *my_thread) {
358 if (my_thread->name_) {
359 ANNOTATE_THREAD_NAME(my_thread->name_);
360 }
361 my_thread->w_(my_thread->arg_);
362 }
363 pthread_t t_;
364 worker_t w_;
365 void *arg_;
366 const char *name_;
367};
368
369
370/// Just a message queue.
371class ProducerConsumerQueue {
372 public:
373 ProducerConsumerQueue(int unused) {
374 //ANNOTATE_PCQ_CREATE(this);
375 }
376 ~ProducerConsumerQueue() {
377 CHECK(q_.empty());
378 //ANNOTATE_PCQ_DESTROY(this);
379 }
380
bart31b983d2010-02-21 14:52:59 +0000381 // Put.
bartbd2073c2009-05-30 16:33:10 +0000382 void Put(void *item) {
383 mu_.Lock();
384 q_.push(item);
385 ANNOTATE_CONDVAR_SIGNAL(&mu_); // LockWhen in Get()
386 //ANNOTATE_PCQ_PUT(this);
387 mu_.Unlock();
388 }
389
bart31b983d2010-02-21 14:52:59 +0000390 // Get.
391 // Blocks if the queue is empty.
392 void *Get() {
bartbd2073c2009-05-30 16:33:10 +0000393 mu_.LockWhen(Condition(IsQueueNotEmpty, &q_));
bart8b53a132009-07-23 10:50:33 +0000394 void * item = NULL;
bartbd2073c2009-05-30 16:33:10 +0000395 bool ok = TryGetInternal(&item);
bart31b983d2010-02-21 14:52:59 +0000396 CHECK(ok);
bartbd2073c2009-05-30 16:33:10 +0000397 mu_.Unlock();
398 return item;
399 }
400
bart31b983d2010-02-21 14:52:59 +0000401 // If queue is not empty,
bartbd2073c2009-05-30 16:33:10 +0000402 // remove an element from queue, put it into *res and return true.
403 // Otherwise return false.
404 bool TryGet(void **res) {
405 mu_.Lock();
406 bool ok = TryGetInternal(res);
407 mu_.Unlock();
408 return ok;
409 }
410
411 private:
412 Mutex mu_;
413 std::queue<void*> q_; // protected by mu_
bart31b983d2010-02-21 14:52:59 +0000414
bartbd2073c2009-05-30 16:33:10 +0000415 // Requires mu_
bart31b983d2010-02-21 14:52:59 +0000416 bool TryGetInternal(void ** item_ptr) {
bartbd2073c2009-05-30 16:33:10 +0000417 if (q_.empty())
418 return false;
419 *item_ptr = q_.front();
420 q_.pop();
421 //ANNOTATE_PCQ_GET(this);
422 return true;
423 }
bart31b983d2010-02-21 14:52:59 +0000424
bartbd2073c2009-05-30 16:33:10 +0000425 static bool IsQueueNotEmpty(std::queue<void*> * queue) {
426 return !queue->empty();
427 }
428};
429
430
431
bart31b983d2010-02-21 14:52:59 +0000432/// Function pointer with zero, one or two parameters.
bartbd2073c2009-05-30 16:33:10 +0000433struct Closure {
434 typedef void (*F0)();
435 typedef void (*F1)(void *arg1);
436 typedef void (*F2)(void *arg1, void *arg2);
bart31b983d2010-02-21 14:52:59 +0000437 int n_params;
438 void *f;
439 void *param1;
440 void *param2;
bartbd2073c2009-05-30 16:33:10 +0000441
442 void Execute() {
443 if (n_params == 0) {
444 (F0(f))();
445 } else if (n_params == 1) {
446 (F1(f))(param1);
447 } else {
448 CHECK(n_params == 2);
449 (F2(f))(param1, param2);
450 }
451 delete this;
452 }
bart31b983d2010-02-21 14:52:59 +0000453};
bartbd2073c2009-05-30 16:33:10 +0000454
455Closure *NewCallback(void (*f)()) {
456 Closure *res = new Closure;
457 res->n_params = 0;
458 res->f = (void*)(f);
459 res->param1 = NULL;
460 res->param2 = NULL;
461 return res;
462}
463
464template <class P1>
465Closure *NewCallback(void (*f)(P1), P1 p1) {
466 CHECK(sizeof(P1) <= sizeof(void*));
467 Closure *res = new Closure;
468 res->n_params = 1;
469 res->f = (void*)(f);
470 res->param1 = (void*)p1;
471 res->param2 = NULL;
472 return res;
473}
474
475template <class T, class P1, class P2>
476Closure *NewCallback(void (*f)(P1, P2), P1 p1, P2 p2) {
477 CHECK(sizeof(P1) <= sizeof(void*));
478 Closure *res = new Closure;
479 res->n_params = 2;
480 res->f = (void*)(f);
481 res->param1 = (void*)p1;
482 res->param2 = (void*)p2;
483 return res;
484}
485
bart31b983d2010-02-21 14:52:59 +0000486/*! A thread pool that uses ProducerConsumerQueue.
487 Usage:
bartbd2073c2009-05-30 16:33:10 +0000488 {
489 ThreadPool pool(n_workers);
490 pool.StartWorkers();
491 pool.Add(NewCallback(func_with_no_args));
492 pool.Add(NewCallback(func_with_one_arg, arg));
493 pool.Add(NewCallback(func_with_two_args, arg1, arg2));
bart31b983d2010-02-21 14:52:59 +0000494 ... // more calls to pool.Add()
495
496 // the ~ThreadPool() is called: we wait workers to finish
497 // and then join all threads in the pool.
bartbd2073c2009-05-30 16:33:10 +0000498 }
499*/
500class ThreadPool {
bart31b983d2010-02-21 14:52:59 +0000501 public:
502 //! Create n_threads threads, but do not start.
503 explicit ThreadPool(int n_threads)
bartbd2073c2009-05-30 16:33:10 +0000504 : queue_(INT_MAX) {
505 for (int i = 0; i < n_threads; i++) {
506 MyThread *thread = new MyThread(&ThreadPool::Worker, this);
507 workers_.push_back(thread);
508 }
509 }
510
bart31b983d2010-02-21 14:52:59 +0000511 //! Start all threads.
bartbd2073c2009-05-30 16:33:10 +0000512 void StartWorkers() {
bartdf5a1e22009-06-03 08:11:02 +0000513 for (size_t i = 0; i < workers_.size(); i++) {
bartbd2073c2009-05-30 16:33:10 +0000514 workers_[i]->Start();
515 }
516 }
517
bart31b983d2010-02-21 14:52:59 +0000518 //! Add a closure.
bartbd2073c2009-05-30 16:33:10 +0000519 void Add(Closure *closure) {
520 queue_.Put(closure);
521 }
522
523 int num_threads() { return workers_.size();}
524
525 //! Wait workers to finish, then join all threads.
526 ~ThreadPool() {
bartdf5a1e22009-06-03 08:11:02 +0000527 for (size_t i = 0; i < workers_.size(); i++) {
bartbd2073c2009-05-30 16:33:10 +0000528 Add(NULL);
529 }
bartdf5a1e22009-06-03 08:11:02 +0000530 for (size_t i = 0; i < workers_.size(); i++) {
bartbd2073c2009-05-30 16:33:10 +0000531 workers_[i]->Join();
532 delete workers_[i];
533 }
534 }
535 private:
536 std::vector<MyThread*> workers_;
537 ProducerConsumerQueue queue_;
538
539 static void *Worker(void *p) {
540 ThreadPool *pool = reinterpret_cast<ThreadPool*>(p);
541 while (true) {
542 Closure *closure = reinterpret_cast<Closure*>(pool->queue_.Get());
543 if(closure == NULL) {
bart31b983d2010-02-21 14:52:59 +0000544 return NULL;
bartbd2073c2009-05-30 16:33:10 +0000545 }
bart31b983d2010-02-21 14:52:59 +0000546 closure->Execute();
bartbd2073c2009-05-30 16:33:10 +0000547 }
548 }
549};
550
551#ifndef NO_BARRIER
bart31b983d2010-02-21 14:52:59 +0000552/// Wrapper for pthread_barrier_t.
bartbd2073c2009-05-30 16:33:10 +0000553class Barrier{
554 public:
555 explicit Barrier(int n_threads) {CHECK(0 == pthread_barrier_init(&b_, 0, n_threads));}
556 ~Barrier() {CHECK(0 == pthread_barrier_destroy(&b_));}
557 void Block() {
558 // helgrind 3.3.0 does not have an interceptor for barrier.
bart31b983d2010-02-21 14:52:59 +0000559 // but our current local version does.
bartbd2073c2009-05-30 16:33:10 +0000560 // ANNOTATE_CONDVAR_SIGNAL(this);
561 pthread_barrier_wait(&b_);
562 // ANNOTATE_CONDVAR_WAIT(this, this);
563 }
564 private:
565 pthread_barrier_t b_;
566};
567
568#endif // NO_BARRIER
569
570class BlockingCounter {
571 public:
572 explicit BlockingCounter(int initial_count) :
573 count_(initial_count) {}
bartdf5a1e22009-06-03 08:11:02 +0000574 bool DecrementCount() {
bartbd2073c2009-05-30 16:33:10 +0000575 MutexLock lock(&mu_);
576 count_--;
bartdf5a1e22009-06-03 08:11:02 +0000577 return count_ == 0;
bartbd2073c2009-05-30 16:33:10 +0000578 }
579 void Wait() {
580 mu_.LockWhen(Condition(&IsZero, &count_));
581 mu_.Unlock();
582 }
583 private:
584 static bool IsZero(int *arg) { return *arg == 0; }
585 Mutex mu_;
586 int count_;
587};
588
589int AtomicIncrement(volatile int *value, int increment);
590
barte291d912009-07-21 11:12:59 +0000591#ifndef __APPLE__
bartbd2073c2009-05-30 16:33:10 +0000592inline int AtomicIncrement(volatile int *value, int increment) {
593 return __sync_add_and_fetch(value, increment);
594}
595
596#else
597// Mac OS X version.
598inline int AtomicIncrement(volatile int *value, int increment) {
599 return OSAtomicAdd32(increment, value);
600}
601
602// TODO(timurrrr) this is a hack
603#define memalign(A,B) malloc(B)
604
605// TODO(timurrrr) this is a hack
606int posix_memalign(void **out, size_t al, size_t size) {
607 *out = memalign(al, size);
608 return (*out == 0);
609}
barte291d912009-07-21 11:12:59 +0000610#endif // __APPLE__
bartbd2073c2009-05-30 16:33:10 +0000611
612#endif // THREAD_WRAPPERS_PTHREAD_H
613// vim:shiftwidth=2:softtabstop=2:expandtab:foldmethod=marker