#define DRD_STOP_IGNORING_VAR(x) DRDCL_(ignore_range)(&(x), sizeof(x))
/**
- * Tell DRD to trace all memory accesses on the specified variable.
+ * Tell DRD to trace all memory accesses on the specified variable.
* until the memory that was allocated for the variable is freed.
*/
#define DRD_TRACE_VAR(x) DRDCL_(trace_range)(&(x), sizeof(x))
tl_assert(a1 <= b_end && b_end <= a2);
tl_assert(b_start < b_end);
tl_assert(address_lsb(b_start) <= address_lsb(b_end - 1));
-
+
for (b0 = address_lsb(b_start); b0 <= address_lsb(b_end - 1); b0++)
{
if (bm0_is_set(p1->bm0_r, b0))
tl_assert(a1 <= b_end && b_end <= a2);
tl_assert(b_start < b_end);
tl_assert(address_lsb(b_start) <= address_lsb(b_end - 1));
-
+
for (b0 = address_lsb(b_start); b0 <= address_lsb(b_end - 1); b0++)
{
if (bm0_is_set(p1->bm0_w, b0))
tl_assert(a1 <= b_end && b_end <= a2);
tl_assert(b_start < b_end);
tl_assert(address_lsb(b_start) <= address_lsb(b_end - 1));
-
+
for (b0 = address_lsb(b_start); b0 <= address_lsb(b_end - 1); b0++)
{
/*
tl_assert(a1 <= b_end && b_end <= a2);
tl_assert(b_start < b_end);
tl_assert(address_lsb(b_start) <= address_lsb(b_end - 1));
-
+
for (b0 = address_lsb(b_start); b0 <= address_lsb(b_end - 1); b0++)
{
if (access_type == eLoad)
/* Client addresses are split into bitfields as follows:
* ------------------------------------------------------
- * | Address MSB | Address LSB | Ignored bits |
+ * | Address MSB | Address LSB | Ignored bits |
* ------------------------------------------------------
* | Address MSB | UWord MSB | UWord LSB | Ignored bits |
* ------------------------------------------------------
tl_assert(size == 0 || uword_msb(a) == uword_msb(a + size - 1));
#endif
/*
- * Note: although the expression below yields a correct result even if
+ * Note: although the expression below yields a correct result even if
* size == 0, do not touch bm0[] if size == 0 because this might otherwise
* cause an access of memory just past the end of the bm0[] array.
*/
/*
* If szB < sizeof(struct bitmap2) then this function has been called to
* allocate an AVL tree root node. Otherwise it has been called to allocate
- * an AVL tree branch or leaf node.
+ * an AVL tree branch or leaf node.
*/
if (szB < sizeof(struct bitmap2))
return VG_(malloc)(ec, szB);
{
if (a1 <= p->any.a1 && p->any.a1 < a2)
{
- return True;
+ return True;
}
}
return False;
if (DRD_(thread_enter_synchr)(drd_tid) == 0)
DRD_(rwlock_pre_unlock)(arg[1], pthread_rwlock);
break;
-
+
case VG_USERREQ__POST_RWLOCK_UNLOCK:
DRD_(thread_leave_synchr)(drd_tid);
break;
/**
* Compare two error contexts. The core function VG_(maybe_record_error)()
* calls this function to compare error contexts such that errors that occur
- * repeatedly are only printed once. This function is only called by the core
+ * repeatedly are only printed once. This function is only called by the core
* if the error kind of e1 and e2 matches and if the ExeContext's of e1 and
* e2 also match.
*/
} DrdErrorKind;
/* The classification of a faulting address. */
-typedef
-enum {
+typedef
+enum {
//Undescribed, // as-yet unclassified
- eStack,
+ eStack,
eUnknown, // classification yielded nothing useful
//Freed,
- eMallocd,
+ eMallocd,
eSegment, // in a segment (as defined in pub_tool_debuginfo.h)
//UserG, // in a user-defined block
//Mempool, // in a mempool
IRSB* DRD_(instrument)(VgCallbackClosure* const closure,
IRSB* const bb_in,
VexGuestLayout* const layout,
- VexGuestExtents* const vge,
+ VexGuestExtents* const vge,
IRType const gWordTy,
IRType const hWordTy)
{
IRSB* DRD_(instrument)(VgCallbackClosure* const closure,
IRSB* const bb_in,
VexGuestLayout* const layout,
- VexGuestExtents* const vge,
+ VexGuestExtents* const vge,
IRType const gWordTy,
IRType const hWordTy);
void DRD_(trace_mem_access)(const Addr addr, const SizeT size,
}
static void DRD_(print_debug_usage)(void)
-{
+{
VG_(printf)(
" --drd-stats=yes|no Print statistics about DRD activity [no].\n"
" --trace-clientobj=yes|no Trace all client object activity [no].\n"
{
DRD_(trace_mem_access)(a1, len, eStart);
}
-
+
if (UNLIKELY(DRD_(running_thread_inside_pthread_create)()))
{
DRD_(start_suppression)(a1, a1 + len, "pthread_create()");
{
DRD_(thread_set_stack_min)(DRD_(thread_get_running_tid)(),
a - VG_STACK_REDZONE_SZB);
- drd_start_using_mem(a - VG_STACK_REDZONE_SZB,
+ drd_start_using_mem(a - VG_STACK_REDZONE_SZB,
len + VG_STACK_REDZONE_SZB);
}
{
// thread_print_all();
if (VG_(clo_verbosity) == 1 && !VG_(clo_xml)) {
- VG_(message)(Vg_UserMsg,
+ VG_(message)(Vg_UserMsg,
"For counts of detected and suppressed errors, "
"rerun with: -v\n");
}
{
/* Copy from old to new. */
VG_(memcpy)(p_new, p_old, mc->size);
-
+
/* Free old memory. */
VG_(cli_free)(p_old);
if (mc->size > 0)
{
/* Allocation failed -- leave original block untouched. */
}
- }
+ }
return p_new;
}
DRD_Chunk* mc;
SizeT nblocks = 0;
SizeT nbytes = 0;
-
+
if (VG_(clo_verbosity) == 0)
return;
if (VG_(clo_xml))
nbytes += mc->size;
}
- VG_(message)(Vg_DebugMsg,
+ VG_(message)(Vg_DebugMsg,
"malloc/free: in use at exit: %lu bytes in %lu blocks.\n",
nbytes, nblocks);
- VG_(message)(Vg_DebugMsg,
+ VG_(message)(Vg_DebugMsg,
"malloc/free: %lu allocs, %lu frees, %lu bytes allocated.\n",
s_cmalloc_n_mallocs,
s_cmalloc_n_frees, s_cmalloc_bs_mallocd);
*/
/* ---------------------------------------------------------------------
- ALL THE CODE IN THIS FILE RUNS ON THE SIMULATED CPU.
+ ALL THE CODE IN THIS FILE RUNS ON THE SIMULATED CPU.
These functions are not called directly - they're the targets of code
redirection or load notifications (see pub_core_redir.h for info).
*/
/* ---------------------------------------------------------------------
- ALL THE CODE IN THIS FILE RUNS ON THE SIMULATED CPU.
+ ALL THE CODE IN THIS FILE RUNS ON THE SIMULATED CPU.
These functions are not called directly - they're the targets of code
redirection or load notifications (see pub_core_redir.h for info).
/*
- * Segments and segment lists. A segment represents information about
+ * Segments and segment lists. A segment represents information about
* a contiguous group of statements of a specific thread. There is a vector
* clock associated with each segment.
*/
const Bool succeeded)
{
/*
- * Note: it is hard to implement the sem_post() wrapper correctly in
- * case sem_post() returns an error code. This is because handling this
- * case correctly requires restoring the vector clock associated with
+ * Note: it is hard to implement the sem_post() wrapper correctly in
+ * case sem_post() returns an error code. This is because handling this
+ * case correctly requires restoring the vector clock associated with
* the semaphore to its original value here. In order to do that without
- * introducing a race condition, extra locking has to be added around
- * each semaphore call. Such extra locking would have to be added in
+ * introducing a race condition, extra locking has to be added around
+ * each semaphore call. Such extra locking would have to be added in
* drd_pthread_intercepts.c. However, it is hard to implement
* synchronization in drd_pthread_intercepts.c in a portable way without
* calling already redirected functions.
from memchec/mc_replace_strmem.c, which has the following copyright
notice:
- Copyright (C) 2000-2009 Julian Seward
+ Copyright (C) 2000-2009 Julian Seward
jseward@acm.org
This program is free software; you can redistribute it and/or
}
STRNLEN(VG_Z_LIBC_SONAME, strnlen)
-
+
// Note that this replacement often doesn't get used because gcc inlines
// calls to strlen() with its own built-in version. This can be very
{
VG_(message)(Vg_DebugMsg, "finish suppression of 0x%lx sz %ld\n",
a1, a2 - a1);
- VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(), 12);
+ VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(), 12);
}
tl_assert(a1 < a2);
}
/**
- * Clean up thread-specific data structures. Call this just after
+ * Clean up thread-specific data structures. Call this just after
* pthread_join().
*/
void DRD_(thread_delete)(const DrdThreadId tid)
{
tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
&& tid != DRD_INVALID_THREADID);
-
+
if (name == NULL || name[0] == 0)
VG_(snprintf)(DRD_(g_threadinfo)[tid].name,
sizeof(DRD_(g_threadinfo)[tid].name),
{
tl_assert(vg_tid != VG_INVALID_THREADID);
tl_assert(drd_tid != DRD_INVALID_THREADID);
-
+
if (vg_tid != s_vg_running_tid)
{
if (s_trace_context_switches
for (q = DRD_(g_threadinfo)[i].last; q; q = q->prev)
{
/*
- * Since q iterates over the segments of thread i in order of
- * decreasing vector clocks, if q->vc <= p->vc, then
+ * Since q iterates over the segments of thread i in order of
+ * decreasing vector clocks, if q->vc <= p->vc, then
* q->next->vc <= p->vc will also hold. Hence, break out of the
* loop once this condition is met.
*/
}
/**
- * Reports whether or not recording of memory loads is enabled for the
+ * Reports whether or not recording of memory loads is enabled for the
* currently running client thread.
*/
static __inline__
}
/**
- * Reports whether or not recording memory stores is enabled for the
+ * Reports whether or not recording memory stores is enabled for the
* currently running client thread.
*/
static __inline__
* - Vector clocks are compared by comparing all counters of all threads.
* - When a thread synchronization action is performed that guarantees that
* new actions of the current thread are executed after the actions of the
- * other thread, the vector clock of the synchronization object and the
+ * other thread, the vector clock of the synchronization object and the
* current thread are combined (by taking the component-wise maximum).
* - A vector clock is incremented during actions such as
* pthread_create(), pthread_mutex_unlock(), sem_post(). (Actions where
int ign_rw = 1;
int tmp;
pthread_t tid;
-
+
while ((optchar = getopt(argc, argv, "r")) != EOF)
{
switch (optchar)
int optchar;
int ign_rw = 1;
pthread_t tid;
-
+
while ((optchar = getopt(argc, argv, "r")) != EOF)
{
switch (optchar)
if (hp + size2 > hp_lim) {
hp = get_superblock();
hp_lim = hp + SUPERBLOCK_SIZE - 1;
- }
+ }
p = hp + RZ;
hp += size2;
VALGRIND_MALLOCLIKE_BLOCK( p, size, RZ, /*is_zeroed*/1 );
return (void*)p;
-}
+}
static void custom_free(void* p)
{
// unfortunately not identified as being in a free'd
// block because the freeing of the block and shadow
// chunk isn't postponed.
-
+
// leak from make_leak()
}
pthread_mutex_init(&s_mutex, 0);
/*
- * Switch to line-buffered mode, such that timing information can be
+ * Switch to line-buffered mode, such that timing information can be
* obtained for each printf() call with strace.
*/
setlinebuf(stdout);
/** Apply the Gauss-Jordan elimination algorithm on the matrix p->a starting
* at row r0 and up to but not including row r1. It is assumed that as many
- * threads execute this function concurrently as the count barrier p->b was
+ * threads execute this function concurrently as the count barrier p->b was
* initialized with. If the matrix p->a is nonsingular, and if matrix p->a
* has at least as many columns as rows, the result of this algorithm is that
* submatrix p->a[0..p->rows-1,0..p->rows-1] is the identity matrix.
/** Apply the Gauss-Jordan elimination algorithm on the matrix p->a starting
* at row r0 and up to but not including row r1. It is assumed that as many
- * threads execute this function concurrently as the count barrier p->b was
+ * threads execute this function concurrently as the count barrier p->b was
* initialized with. If the matrix p->a is nonsingular, and if matrix p->a
* has at least as many columns as rows, the result of this algorithm is that
* submatrix p->a[0..p->rows-1,0..p->rows-1] is the identity matrix.
-/** Broadcast a (POSIX threads) signal to all running threads, where the
+/** Broadcast a (POSIX threads) signal to all running threads, where the
* number of threads can be specified on the command line. This test program
* is intended not only to test the correctness of drd but also to test
* whether performance does not degrade too much when the number of threads
printf("thread %d [%d] (1)\n", thread_info->m_threadnum, i);
}
csema_v(thread_info->m_sema);
-
+
// Wait until the main thread signals us via pthread_cond_broadcast().
pthread_cond_wait(&s_cond, &s_mutex);
if (s_trace)
thread_arg[i] = i;
pthread_mutex_init(&s_mutex, 0);
-
+
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
assert(pthread_attr_getdetachstate(&attr, &detachstate) == 0);
assert(detachstate == PTHREAD_CREATE_DETACHED);
pthread_attr_setstacksize(&attr, 16384);
- // Create count1 detached threads by setting the "detached" property via
+ // Create count1 detached threads by setting the "detached" property via
// thread attributes.
for (i = 0; i < count1; i++)
{
thread_arg[i] = i;
sem_init(&s_sem, 0, 0);
-
+
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
assert(pthread_attr_getdetachstate(&attr, &detachstate) == 0);
assert(detachstate == PTHREAD_CREATE_DETACHED);
pthread_attr_setstacksize(&attr, 16384);
- // Create count1 detached threads by setting the "detached" property via
+ // Create count1 detached threads by setting the "detached" property via
// thread attributes.
for (i = 0; i < count1; i++)
{
sem_init(&s_sem, 0, 1);
/*
- * Switch to line-buffered mode, such that timing information can be
+ * Switch to line-buffered mode, such that timing information can be
* obtained for each printf() call with strace.
*/
setlinebuf(stdout);
}
/*
- * Switch to line-buffered mode, such that timing information can be
+ * Switch to line-buffered mode, such that timing information can be
* obtained for each printf() call with strace.
*/
setlinebuf(stdout);
framework.
Copyright (C) 2008-2008 Google Inc
- opensource@google.com
+ opensource@google.com
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
The GNU General Public License is contained in the file COPYING.
*/
-// Author: Konstantin Serebryany <opensource@google.com>
+// Author: Konstantin Serebryany <opensource@google.com>
//
-// Here we define few simple classes that wrap pthread primitives.
+// Here we define few simple classes that wrap pthread primitives.
//
-// We need this to create unit tests for helgrind (or similar tool)
-// that will work with different threading frameworks.
+// We need this to create unit tests for helgrind (or similar tool)
+// that will work with different threading frameworks.
//
-// If one needs to test helgrind's support for another threading library,
-// he/she can create a copy of this file and replace pthread_ calls
-// with appropriate calls to his/her library.
+// If one needs to test helgrind's support for another threading library,
+// he/she can create a copy of this file and replace pthread_ calls
+// with appropriate calls to his/her library.
//
-// Note, that some of the methods defined here are annotated with
-// ANNOTATE_* macros defined in dynamic_annotations.h.
+// Note, that some of the methods defined here are annotated with
+// ANNOTATE_* macros defined in dynamic_annotations.h.
//
-// DISCLAIMER: the classes defined in this header file
-// are NOT intended for general use -- only for unit tests.
+// DISCLAIMER: the classes defined in this header file
+// are NOT intended for general use -- only for unit tests.
//
#ifndef THREAD_WRAPPERS_PTHREAD_H
#include <assert.h>
#ifdef NDEBUG
# error "Pleeease, do not define NDEBUG"
-#endif
+#endif
#define CHECK assert
/// Set this to true if malloc() uses mutex on your platform as this may
/// introduce a happens-before arc for a pure happens-before race detector.
const bool kMallocUsesMutex = false;
-/// Current time in milliseconds.
+/// Current time in milliseconds.
static inline int64_t GetCurrentTimeMillis() {
struct timeval now;
gettimeofday(&now, NULL);
return now.tv_sec * 1000 + now.tv_usec / 1000;
}
-/// Copy tv to ts adding offset in milliseconds.
-static inline void timeval2timespec(timeval *const tv,
- timespec *ts,
+/// Copy tv to ts adding offset in milliseconds.
+static inline void timeval2timespec(timeval *const tv,
+ timespec *ts,
int64_t offset_milli) {
const int64_t ten_9 = 1000000000LL;
const int64_t ten_6 = 1000000LL;
#endif // NO_SPINLOCK
-/// Just a boolean condition. Used by Mutex::LockWhen and similar.
+/// Just a boolean condition. Used by Mutex::LockWhen and similar.
class Condition {
public:
typedef bool (*func_t)(void*);
template <typename T>
- Condition(bool (*func)(T*), T* arg)
+ Condition(bool (*func)(T*), T* arg)
: func_(reinterpret_cast<func_t>(func)), arg_(arg) {}
- Condition(bool (*func)())
+ Condition(bool (*func)())
: func_(reinterpret_cast<func_t>(func)), arg_(NULL) {}
bool Eval() { return func_(arg_); }
/// Wrapper for pthread_mutex_t.
///
-/// pthread_mutex_t is *not* a reader-writer lock,
-/// so the methods like ReaderLock() aren't really reader locks.
-/// We can not use pthread_rwlock_t because it
+/// pthread_mutex_t is *not* a reader-writer lock,
+/// so the methods like ReaderLock() aren't really reader locks.
+/// We can not use pthread_rwlock_t because it
/// does not work with pthread_cond_t.
-///
-/// TODO: We still need to test reader locks with this class.
-/// Implement a mode where pthread_rwlock_t will be used
-/// instead of pthread_mutex_t (only when not used with CondVar or LockWhen).
-///
+///
+/// TODO: We still need to test reader locks with this class.
+/// Implement a mode where pthread_rwlock_t will be used
+/// instead of pthread_mutex_t (only when not used with CondVar or LockWhen).
+///
class Mutex {
friend class CondVar;
- public:
+ public:
Mutex() {
CHECK(0 == pthread_mutex_init(&mu_, NULL));
CHECK(0 == pthread_cond_init(&cv_, NULL));
- signal_at_unlock_ = true; // Always signal at Unlock to make
+ signal_at_unlock_ = true; // Always signal at Unlock to make
// Mutex more friendly to hybrid detectors.
}
~Mutex() {
bool TryLock() { return (0 == pthread_mutex_trylock(&mu_));}
void Unlock() {
if (signal_at_unlock_) {
- CHECK(0 == pthread_cond_signal(&cv_));
+ CHECK(0 == pthread_cond_signal(&cv_));
}
CHECK(0 == pthread_mutex_unlock(&mu_));
}
void ReaderLockWhen(Condition cond) { Lock(); WaitLoop(cond); }
void Await(Condition cond) { WaitLoop(cond); }
- bool ReaderLockWhenWithTimeout(Condition cond, int millis)
+ bool ReaderLockWhenWithTimeout(Condition cond, int millis)
{ Lock(); return WaitLoopWithTimeout(cond, millis); }
- bool LockWhenWithTimeout(Condition cond, int millis)
+ bool LockWhenWithTimeout(Condition cond, int millis)
{ Lock(); return WaitLoopWithTimeout(cond, millis); }
- bool AwaitWithTimeout(Condition cond, int millis)
+ bool AwaitWithTimeout(Condition cond, int millis)
{ return WaitLoopWithTimeout(cond, millis); }
private:
return cond.Eval();
}
- // A hack. cv_ should be the first data member so that
- // ANNOTATE_CONDVAR_WAIT(&MU, &MU) and ANNOTATE_CONDVAR_SIGNAL(&MU) works.
+ // A hack. cv_ should be the first data member so that
+ // ANNOTATE_CONDVAR_WAIT(&MU, &MU) and ANNOTATE_CONDVAR_SIGNAL(&MU) works.
// (See also racecheck_unittest.cc)
- pthread_cond_t cv_;
+ pthread_cond_t cv_;
pthread_mutex_t mu_;
bool signal_at_unlock_; // Set to true if Wait was called.
};
class MutexLock { // Scoped Mutex Locker/Unlocker
public:
- MutexLock(Mutex *mu)
+ MutexLock(Mutex *mu)
: mu_(mu) {
mu_->Lock();
}
};
-/// Wrapper for pthread_cond_t.
+/// Wrapper for pthread_cond_t.
class CondVar {
public:
CondVar() { CHECK(0 == pthread_cond_init(&cv_, NULL)); }
~CondVar() { CHECK(0 == pthread_cond_destroy(&cv_)); }
void Wait(Mutex *mu) { CHECK(0 == pthread_cond_wait(&cv_, &mu->mu_)); }
- bool WaitWithTimeout(Mutex *mu, int millis) {
+ bool WaitWithTimeout(Mutex *mu, int millis) {
struct timeval now;
struct timespec timeout;
gettimeofday(&now, NULL);
// pthreads do not allow to use condvar with rwlock so we can't make
// ReaderLock method of Mutex to be the real rw-lock.
-// So, we need a special lock class to test reader locks.
+// So, we need a special lock class to test reader locks.
#define NEEDS_SEPERATE_RW_LOCK
class RWLock {
public:
class ReaderLockScoped { // Scoped RWLock Locker/Unlocker
public:
- ReaderLockScoped(RWLock *mu)
+ ReaderLockScoped(RWLock *mu)
: mu_(mu) {
mu_->ReaderLock();
}
class WriterLockScoped { // Scoped RWLock Locker/Unlocker
public:
- WriterLockScoped(RWLock *mu)
+ WriterLockScoped(RWLock *mu)
: mu_(mu) {
mu_->Lock();
}
/// Wrapper for pthread_create()/pthread_join().
class MyThread {
- public:
+ public:
typedef void *(*worker_t)(void*);
- MyThread(worker_t worker, void *arg = NULL, const char *name = NULL)
+ MyThread(worker_t worker, void *arg = NULL, const char *name = NULL)
:w_(worker), arg_(arg), name_(name) {}
- MyThread(void (*worker)(void), void *arg = NULL, const char *name = NULL)
+ MyThread(void (*worker)(void), void *arg = NULL, const char *name = NULL)
:w_(reinterpret_cast<worker_t>(worker)), arg_(arg), name_(name) {}
- MyThread(void (*worker)(void *), void *arg = NULL, const char *name = NULL)
+ MyThread(void (*worker)(void *), void *arg = NULL, const char *name = NULL)
:w_(reinterpret_cast<worker_t>(worker)), arg_(arg), name_(name) {}
~MyThread(){ w_ = NULL; arg_ = NULL;}
//ANNOTATE_PCQ_DESTROY(this);
}
- // Put.
+ // Put.
void Put(void *item) {
mu_.Lock();
q_.push(item);
mu_.Unlock();
}
- // Get.
- // Blocks if the queue is empty.
- void *Get() {
+ // Get.
+ // Blocks if the queue is empty.
+ void *Get() {
mu_.LockWhen(Condition(IsQueueNotEmpty, &q_));
void * item = NULL;
bool ok = TryGetInternal(&item);
- CHECK(ok);
+ CHECK(ok);
mu_.Unlock();
return item;
}
- // If queue is not empty,
+ // If queue is not empty,
// remove an element from queue, put it into *res and return true.
// Otherwise return false.
bool TryGet(void **res) {
private:
Mutex mu_;
std::queue<void*> q_; // protected by mu_
-
+
// Requires mu_
- bool TryGetInternal(void ** item_ptr) {
+ bool TryGetInternal(void ** item_ptr) {
if (q_.empty())
return false;
*item_ptr = q_.front();
//ANNOTATE_PCQ_GET(this);
return true;
}
-
+
static bool IsQueueNotEmpty(std::queue<void*> * queue) {
return !queue->empty();
}
-/// Function pointer with zero, one or two parameters.
+/// Function pointer with zero, one or two parameters.
struct Closure {
typedef void (*F0)();
typedef void (*F1)(void *arg1);
typedef void (*F2)(void *arg1, void *arg2);
- int n_params;
- void *f;
- void *param1;
- void *param2;
+ int n_params;
+ void *f;
+ void *param1;
+ void *param2;
void Execute() {
if (n_params == 0) {
}
delete this;
}
-};
+};
Closure *NewCallback(void (*f)()) {
Closure *res = new Closure;
return res;
}
-/*! A thread pool that uses ProducerConsumerQueue.
- Usage:
+/*! A thread pool that uses ProducerConsumerQueue.
+ Usage:
{
ThreadPool pool(n_workers);
pool.StartWorkers();
pool.Add(NewCallback(func_with_no_args));
pool.Add(NewCallback(func_with_one_arg, arg));
pool.Add(NewCallback(func_with_two_args, arg1, arg2));
- ... // more calls to pool.Add()
-
- // the ~ThreadPool() is called: we wait workers to finish
- // and then join all threads in the pool.
+ ... // more calls to pool.Add()
+
+ // the ~ThreadPool() is called: we wait workers to finish
+ // and then join all threads in the pool.
}
*/
class ThreadPool {
- public:
- //! Create n_threads threads, but do not start.
- explicit ThreadPool(int n_threads)
+ public:
+ //! Create n_threads threads, but do not start.
+ explicit ThreadPool(int n_threads)
: queue_(INT_MAX) {
for (int i = 0; i < n_threads; i++) {
MyThread *thread = new MyThread(&ThreadPool::Worker, this);
}
}
- //! Start all threads.
+ //! Start all threads.
void StartWorkers() {
for (size_t i = 0; i < workers_.size(); i++) {
workers_[i]->Start();
}
}
- //! Add a closure.
+ //! Add a closure.
void Add(Closure *closure) {
queue_.Put(closure);
}
while (true) {
Closure *closure = reinterpret_cast<Closure*>(pool->queue_.Get());
if(closure == NULL) {
- return NULL;
+ return NULL;
}
- closure->Execute();
+ closure->Execute();
}
}
};
#ifndef NO_BARRIER
-/// Wrapper for pthread_barrier_t.
+/// Wrapper for pthread_barrier_t.
class Barrier{
public:
explicit Barrier(int n_threads) {CHECK(0 == pthread_barrier_init(&b_, 0, n_threads));}
~Barrier() {CHECK(0 == pthread_barrier_destroy(&b_));}
void Block() {
// helgrind 3.3.0 does not have an interceptor for barrier.
- // but our current local version does.
+ // but our current local version does.
// ANNOTATE_CONDVAR_SIGNAL(this);
pthread_barrier_wait(&b_);
// ANNOTATE_CONDVAR_WAIT(this, this);