1610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov/*
2610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  This file is part of ThreadSanitizer, a dynamic data race detector.
3610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
4610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  Copyright (C) 2008-2009 Google Inc
5610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov     opensource@google.com
6610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
7610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  This program is free software; you can redistribute it and/or
8610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  modify it under the terms of the GNU General Public License as
9610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  published by the Free Software Foundation; either version 2 of the
10610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  License, or (at your option) any later version.
11610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
12610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  This program is distributed in the hope that it will be useful, but
13610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  WITHOUT ANY WARRANTY; without even the implied warranty of
14610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  General Public License for more details.
16610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
17610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  You should have received a copy of the GNU General Public License
18610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  along with this program; if not, write to the Free Software
19610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  02111-1307, USA.
21610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
22610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  The GNU General Public License is contained in the file COPYING.
23610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov*/
24610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
25610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// Author: Konstantin Serebryany <opensource@google.com>
26610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov//
27610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// Here we define a few simple classes that wrap threading primitives.
28610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov//
29610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// We need this to create unit tests for ThreadSanitizer (or similar tools)
30610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// that will work with different threading frameworks.
31610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov//
32610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// Note, that some of the methods defined here are annotated with
33610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// ANNOTATE_* macros defined in dynamic_annotations.h.
34610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov//
35610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// DISCLAIMER: the classes defined in this header file
36610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// are NOT intended for general use -- only for unit tests.
37610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
38610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#ifndef THREAD_WRAPPERS_H
39610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#define THREAD_WRAPPERS_H
40610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
41610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#include <assert.h>
42610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#include <limits.h>   // INT_MAX
43610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#include <queue>
44610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#include <stdio.h>
45610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#include <string>
46610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#include <time.h>
47610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
48610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#include "dynamic_annotations.h"
49610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
50610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovusing namespace std;
51610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
52610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#ifdef NDEBUG
53610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov# error "Pleeease, do not define NDEBUG"
54610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#endif
55610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
56610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#ifdef WIN32
57610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov# define CHECK(x) do { if (!(x)) { \
58610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov   fprintf(stderr, "Assertion failed: %s (%s:%d) %s\n", \
59610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov          __FUNCTION__, __FILE__, __LINE__, #x); \
60610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov   exit(1); }} while (0)
61610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#else
62610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov# define CHECK assert
63610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#endif
64610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
65610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov/// Just a boolean condition. Used by Mutex::LockWhen and similar.
66610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovclass Condition {
67610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov public:
68610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  typedef bool (*func_t)(void*);
69610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
70610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  template <typename T>
71610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  Condition(bool (*func)(T*), T* arg)
72610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  : func_(reinterpret_cast<func_t>(func)), arg_(arg) {}
73610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
74610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  Condition(bool (*func)())
75610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  : func_(reinterpret_cast<func_t>(func)), arg_(NULL) {}
76610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
77610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  bool Eval() { return func_(arg_); }
78610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov private:
79610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  func_t func_;
80610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  void *arg_;
81610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov};
82610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
83610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// Define platform-specific types, constant and functions {{{1
84610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovstatic int AtomicIncrement(volatile int *value, int increment);
85610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovstatic int GetTimeInMs();
86610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
87610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovclass CondVar;
88610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovclass MyThread;
89610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovclass Mutex;
90610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov//}}}
91610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
92610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// Include platform-specific header with declaraions.
93610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#ifndef WIN32
94610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// Include pthread primitives (Linux, Mac)
95610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#include "thread_wrappers_pthread.h"
96610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#else
97610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// Include Windows primitives
98610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#include "thread_wrappers_win.h"
99610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#endif
100610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
101610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// Define cross-platform types synchronization primitives {{{1
102610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov/// Just a message queue.
103610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovclass ProducerConsumerQueue {
104610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov public:
105610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  ProducerConsumerQueue(int unused) {
106610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    //ANNOTATE_PCQ_CREATE(this);
107610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
108610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  ~ProducerConsumerQueue() {
109610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    CHECK(q_.empty());
110610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    //ANNOTATE_PCQ_DESTROY(this);
111610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
112610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
113610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  // Put.
114610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  void Put(void *item) {
115610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    mu_.Lock();
116610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      q_.push(item);
117610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      ANNOTATE_CONDVAR_SIGNAL(&mu_); // LockWhen in Get()
118610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      //ANNOTATE_PCQ_PUT(this);
119610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    mu_.Unlock();
120610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
121610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
122610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  // Get.
123610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  // Blocks if the queue is empty.
124610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  void *Get() {
125610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    mu_.LockWhen(Condition(IsQueueNotEmpty, &q_));
126610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      void * item;
127610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      bool ok = TryGetInternal(&item);
128610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      CHECK(ok);
129610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    mu_.Unlock();
130610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    return item;
131610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
132610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
133610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  // If queue is not empty,
134610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  // remove an element from queue, put it into *res and return true.
135610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  // Otherwise return false.
136610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  bool TryGet(void **res) {
137610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    mu_.Lock();
138610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      bool ok = TryGetInternal(res);
139610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    mu_.Unlock();
140610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    return ok;
141610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
142610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
143610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov private:
144610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  Mutex mu_;
145610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  std::queue<void*> q_; // protected by mu_
146610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
147610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  // Requires mu_
148610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  bool TryGetInternal(void ** item_ptr) {
149610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    if (q_.empty())
150610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      return false;
151610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    *item_ptr = q_.front();
152610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    q_.pop();
153610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    //ANNOTATE_PCQ_GET(this);
154610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    return true;
155610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
156610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
157610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  static bool IsQueueNotEmpty(std::queue<void*> * queue) {
158610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov     return !queue->empty();
159610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
160610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov};
161610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
162610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov/// Function pointer with zero, one or two parameters.
163610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovstruct Closure {
164610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  typedef void (*F0)();
165610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  typedef void (*F1)(void *arg1);
166610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  typedef void (*F2)(void *arg1, void *arg2);
167610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  int  n_params;
168610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  void *f;
169610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  void *param1;
170610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  void *param2;
171610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
172610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  void Execute() {
173610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    if (n_params == 0) {
174610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      (F0(f))();
175610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    } else if (n_params == 1) {
176610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      (F1(f))(param1);
177610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    } else {
178610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      CHECK(n_params == 2);
179610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      (F2(f))(param1, param2);
180610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    }
181610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    delete this;
182610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
183610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov};
184610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
185610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovstatic Closure *NewCallback(void (*f)()) {
186610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  Closure *res = new Closure;
187610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  res->n_params = 0;
188610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  res->f = (void*)(f);
189610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  res->param1 = NULL;
190610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  res->param2 = NULL;
191610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  return res;
192610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov}
193610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
194610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovtemplate <class P1>
195610969f87667a485b9207086b3ff475bab909f95Evgeniy StepanovClosure *NewCallback(void (*f)(P1), P1 p1) {
196610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  CHECK(sizeof(P1) <= sizeof(void*));
197610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  Closure *res = new Closure;
198610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  res->n_params = 1;
199610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  res->f = (void*)(f);
200610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  res->param1 = (void*)(intptr_t)p1;
201610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  res->param2 = NULL;
202610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  return res;
203610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov}
204610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
205610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovtemplate <class P1, class P2>
206610969f87667a485b9207086b3ff475bab909f95Evgeniy StepanovClosure *NewCallback(void (*f)(P1, P2), P1 p1, P2 p2) {
207610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  CHECK(sizeof(P1) <= sizeof(void*));
208610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  CHECK(sizeof(P2) <= sizeof(void*));
209610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  Closure *res = new Closure;
210610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  res->n_params = 2;
211610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  res->f = (void*)(f);
212610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  res->param1 = (void*)p1;
213610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  res->param2 = (void*)p2;
214610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  return res;
215610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov}
216610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
217610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov/*! A thread pool that uses ProducerConsumerQueue.
218610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  Usage:
219610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  {
220610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    ThreadPool pool(n_workers);
221610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    pool.StartWorkers();
222610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    pool.Add(NewCallback(func_with_no_args));
223610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    pool.Add(NewCallback(func_with_one_arg, arg));
224610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    pool.Add(NewCallback(func_with_two_args, arg1, arg2));
225610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    ... // more calls to pool.Add()
226610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
227610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    // the ~ThreadPool() is called: we wait workers to finish
228610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    // and then join all threads in the pool.
229610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
230610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov*/
231610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovclass ThreadPool {
232610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov public:
233610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  //! Create n_threads threads, but do not start.
234610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  explicit ThreadPool(int n_threads)
235610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    : queue_(INT_MAX) {
236610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    for (int i = 0; i < n_threads; i++) {
237610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      MyThread *thread = new MyThread(&ThreadPool::Worker, this);
238610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      workers_.push_back(thread);
239610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    }
240610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
241610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
242610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  //! Start all threads.
243610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  void StartWorkers() {
244610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    for (size_t i = 0; i < workers_.size(); i++) {
245610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      workers_[i]->Start();
246610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    }
247610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
248610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
249610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  //! Add a closure.
250610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  void Add(Closure *closure) {
251610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    queue_.Put(closure);
252610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
253610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
254610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  int num_threads() { return workers_.size();}
255610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
256610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  //! Wait workers to finish, then join all threads.
257610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  ~ThreadPool() {
258610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    for (size_t i = 0; i < workers_.size(); i++) {
259610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      Add(NULL);
260610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    }
261610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    for (size_t i = 0; i < workers_.size(); i++) {
262610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      workers_[i]->Join();
263610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      delete workers_[i];
264610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    }
265610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
266610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov private:
267610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  std::vector<MyThread*>   workers_;
268610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  ProducerConsumerQueue  queue_;
269610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
270610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  static void *Worker(void *p) {
271610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    ThreadPool *pool = reinterpret_cast<ThreadPool*>(p);
272610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    while (true) {
273610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      Closure *closure = reinterpret_cast<Closure*>(pool->queue_.Get());
274610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      if(closure == NULL) {
275610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov        return NULL;
276610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      }
277610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      closure->Execute();
278610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    }
279610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
280610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov};
281610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
282610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovclass MutexLock {  // Scoped Mutex Locker/Unlocker
283610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov public:
284610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  MutexLock(Mutex *mu)
285610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    : mu_(mu) {
286610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    mu_->Lock();
287610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
288610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  ~MutexLock() {
289610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    mu_->Unlock();
290610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
291610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov private:
292610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  Mutex *mu_;
293610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov};
294610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
295610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovclass BlockingCounter {
296610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov public:
297610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  explicit BlockingCounter(int initial_count) :
298610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    count_(initial_count) {}
299610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  bool DecrementCount() {
300610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    MutexLock lock(&mu_);
301610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    count_--;
302610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    return count_ == 0;
303610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
304610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  void Wait() {
305610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    mu_.LockWhen(Condition(&IsZero, &count_));
306610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    mu_.Unlock();
307610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
308610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov private:
309610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  static bool IsZero(int *arg) { return *arg == 0; }
310610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  Mutex mu_;
311610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  int count_;
312610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov};
313610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
314610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov//}}}
315610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
316610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#endif // THREAD_WRAPPERS_H
317610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// vim:shiftwidth=2:softtabstop=2:expandtab:foldmethod=marker
318