#endif // NO_SPINLOCK
/// Just a boolean condition. Used by Mutex::LockWhen and similar.
+template <typename T>
class Condition {
public:
typedef bool (*func_t)(void*);
- template <typename T>
Condition(bool (*func)(T*), T* arg)
- : func_(reinterpret_cast<func_t>(func)), arg_(arg) {}
+ : func1_(func), arg_(arg) {}
Condition(bool (*func)())
- : func_(reinterpret_cast<func_t>(func)), arg_(NULL) {}
+ : func0_(func), arg_(NULL) {}
- bool Eval() { return func_(arg_); }
- private:
- func_t func_;
- void *arg_;
+ bool Eval() const { return func1_ ? func1_(arg_) : func0_(); }
+ private:
+ bool (*func0_)();
+ bool (*func1_)(T*);
+ T *arg_;
};
bool ReaderTryLock() { return TryLock();}
void ReaderUnlock() { Unlock(); }
- void LockWhen(Condition cond) { Lock(); WaitLoop(cond); }
- void ReaderLockWhen(Condition cond) { Lock(); WaitLoop(cond); }
- void Await(Condition cond) { WaitLoop(cond); }
+ template <typename T>
+ void LockWhen(const Condition<T>& cond) { Lock(); WaitLoop(cond); }
+ template <typename T>
+ void ReaderLockWhen(const Condition<T>& cond) { Lock(); WaitLoop(cond); }
+ template <typename T>
+ void Await(const Condition<T>& cond) { WaitLoop(cond); }
- bool ReaderLockWhenWithTimeout(Condition cond, int millis)
+ template <typename T>
+ bool ReaderLockWhenWithTimeout(const Condition<T>& cond, int millis)
{ Lock(); return WaitLoopWithTimeout(cond, millis); }
- bool LockWhenWithTimeout(Condition cond, int millis)
+ template <typename T>
+ bool LockWhenWithTimeout(const Condition<T>& cond, int millis)
{ Lock(); return WaitLoopWithTimeout(cond, millis); }
- bool AwaitWithTimeout(Condition cond, int millis)
+ template <typename T>
+ bool AwaitWithTimeout(const Condition<T>& cond, int millis)
{ return WaitLoopWithTimeout(cond, millis); }
private:
- void WaitLoop(Condition cond) {
+ template <typename T>
+ void WaitLoop(const Condition<T>& cond) {
signal_at_unlock_ = true;
while(cond.Eval() == false) {
pthread_cond_wait(&cv_, &mu_);
ANNOTATE_CONDVAR_LOCK_WAIT(&cv_, &mu_);
}
- bool WaitLoopWithTimeout(Condition cond, int millis) {
+ template <typename T>
+ bool WaitLoopWithTimeout(const Condition<T>& cond, int millis) {
struct timeval now;
struct timespec timeout;
int retcode = 0;
/// Wrapper for pthread_create()/pthread_join().
class MyThread {
public:
- typedef void *(*worker_t)(void*);
-
- 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)
+ :wpvpv_(worker), arg_(arg), name_(name) {}
MyThread(void (*worker)(void), void *arg = NULL, const char *name = NULL)
- :w_(reinterpret_cast<worker_t>(worker)), arg_(arg), name_(name) {}
+ :wvv_(worker), arg_(arg), name_(name) {}
MyThread(void (*worker)(void *), void *arg = NULL, const char *name = NULL)
- :w_(reinterpret_cast<worker_t>(worker)), arg_(arg), name_(name) {}
+ :wvpv_(worker), arg_(arg), name_(name) {}
- ~MyThread(){ w_ = NULL; arg_ = NULL;}
- void Start() { CHECK(0 == pthread_create(&t_, NULL, (worker_t)ThreadBody, this));}
+ void Start() { CHECK(0 == pthread_create(&t_, NULL, ThreadBody, this));}
void Join() { CHECK(0 == pthread_join(t_, NULL));}
pthread_t tid() const { return t_; }
private:
- static void ThreadBody(MyThread *my_thread) {
+ static void *ThreadBody(void *arg) {
+ MyThread *my_thread = reinterpret_cast<MyThread*>(arg);
if (my_thread->name_) {
ANNOTATE_THREAD_NAME(my_thread->name_);
}
- my_thread->w_(my_thread->arg_);
+ if (my_thread->wpvpv_)
+ return my_thread->wpvpv_(my_thread->arg_);
+ if (my_thread->wpvpv_)
+ my_thread->wvpv_(my_thread->arg_);
+ if (my_thread->wvv_)
+ my_thread->wvv_();
+ return NULL;
}
pthread_t t_;
- worker_t w_;
+ void *(*wpvpv_)(void*);
+ void (*wvv_)(void);
+ void (*wvpv_)(void*);
void *arg_;
const char *name_;
};
// Get.
// Blocks if the queue is empty.
void *Get() {
- mu_.LockWhen(Condition(IsQueueNotEmpty, &q_));
+ mu_.LockWhen(Condition<typeof(q_)>(IsQueueNotEmpty, &q_));
void * item = NULL;
bool ok = TryGetInternal(&item);
CHECK(ok);
return count_ == 0;
}
void Wait() {
- mu_.LockWhen(Condition(&IsZero, &count_));
+ mu_.LockWhen(Condition<int>(&IsZero, &count_));
mu_.Unlock();
}
private:
pool.StartWorkers();
COND = 0;
pool.Add(NewCallback(Waker));
- MU.LockWhen(Condition(&ArgIsOne, &COND)); // calls ANNOTATE_CONDVAR_WAIT
+ MU.LockWhen(Condition<int>(&ArgIsOne, &COND)); // calls ANNOTATE_CONDVAR_WAIT
MU.Unlock(); // Waker is done!
GLOB = 2;
t.Start();
usleep(100000); // Make sure the signaller gets there first.
- MU.LockWhen(Condition(&ArgIsTrue, &COND)); // calls ANNOTATE_CONDVAR_WAIT
+ MU.LockWhen(Condition<bool>(&ArgIsTrue, &COND));// calls ANNOTATE_CONDVAR_WAIT
MU.Unlock(); // Signaller is done!
GLOB = 2; // If LockWhen didn't catch the signal, a race may be reported here.
GLOB++;
MU.Unlock();
- MU.LockWhen(Condition(&ArgIsOne, &COND));
+ MU.LockWhen(Condition<int>(&ArgIsOne, &COND));
MU.Unlock();
GLOB++;
}
};
void Waiter() {
- MU.LockWhen(Condition(&ArgIsOne, &COND));
+ MU.LockWhen(Condition<int>(&ArgIsOne, &COND));
MU.Unlock();
CHECK(GLOB != 777);
}
MU2.Lock();
COND--;
ANNOTATE_CONDVAR_SIGNAL(&MU2);
- MU2.Await(Condition(&ArgIsZero, &COND));
+ MU2.Await(Condition<int>(&ArgIsZero, &COND));
MU2.Unlock();
CHECK(GLOB == 2);
MU2.Lock();
COND--;
ANNOTATE_CONDVAR_SIGNAL(&MU2);
- MU2.Await(Condition(&ArgIsZero, &COND));
+ MU2.Await(Condition<int>(&ArgIsZero, &COND));
MU2.Unlock();
CHECK(GLOB == 3);
pool.Add(NewCallback(Waker));
MU.Lock();
- MU.Await(Condition(&ArgIsOne, &COND)); // calls ANNOTATE_CONDVAR_WAIT
+ MU.Await(Condition<int>(&ArgIsOne, &COND)); // calls ANNOTATE_CONDVAR_WAIT
MU.Unlock(); // Waker is done!
GLOB = 2;
pool.Add(NewCallback(Waker));
MU.Lock();
- CHECK(MU.AwaitWithTimeout(Condition(&ArgIsOne, &COND), INT_MAX));
+ CHECK(MU.AwaitWithTimeout(Condition<int>(&ArgIsOne, &COND), INT_MAX));
MU.Unlock();
GLOB = 2;
pool.Add(NewCallback(Waker));
MU.Lock();
- CHECK(!MU.AwaitWithTimeout(Condition(&ArgIsOne, &COND), 100));
+ CHECK(!MU.AwaitWithTimeout(Condition<int>(&ArgIsOne, &COND), 100));
MU.Unlock();
GLOB = 2;
COND = 0;
pool.Add(NewCallback(Waker));
- CHECK(!MU.LockWhenWithTimeout(Condition(&ArgIsOne, &COND), 100));
+ CHECK(!MU.LockWhenWithTimeout(Condition<int>(&ArgIsOne, &COND), 100));
MU.Unlock();
GLOB = 2;
pool.StartWorkers();
COND = 0;
pool.Add(NewCallback(Waker));
- MU.ReaderLockWhen(Condition(&ArgIsOne, &COND));
+ MU.ReaderLockWhen(Condition<int>(&ArgIsOne, &COND));
MU.ReaderUnlock();
GLOB = 2;
pool.StartWorkers();
COND = 0;
pool.Add(NewCallback(Waker));
- CHECK(MU.ReaderLockWhenWithTimeout(Condition(&ArgIsOne, &COND), INT_MAX));
+ CHECK(MU.ReaderLockWhenWithTimeout(Condition<int>(&ArgIsOne, &COND), INT_MAX));
MU.ReaderUnlock();
GLOB = 2;
pool.StartWorkers();
COND = 0;
pool.Add(NewCallback(Waker));
- CHECK(!MU.ReaderLockWhenWithTimeout(Condition(&ArgIsOne, &COND), 100));
+ CHECK(!MU.ReaderLockWhenWithTimeout(Condition<int>(&ArgIsOne, &COND), 100));
MU.ReaderUnlock();
GLOB = 2;
// The race is here. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
printf("B::~B()\n");
// wait until flag_stopped is true.
- mu.LockWhen(Condition(&ArgIsTrue, &flag_stopped));
+ mu.LockWhen(Condition<bool>(&ArgIsTrue, &flag_stopped));
mu.Unlock();
printf("B::~B() done\n");
}
// The race is here. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
printf("B::~B()\n");
// wait until flag_stopped is true.
- mu.LockWhen(Condition(&ArgIsTrue, &flag_stopped));
+ mu.LockWhen(Condition<bool>(&ArgIsTrue, &flag_stopped));
mu.Unlock();
printf("B::~B() done\n");
}
static void Thread1() {
for (int i = 0; i < 100; i++) {
- mu.LockWhenWithTimeout(Condition(&ArgIsTrue, &GLOB), 5);
+ mu.LockWhenWithTimeout(Condition<bool>(&ArgIsTrue, &GLOB), 5);
GLOB = false;
mu.Unlock();
usleep(10000);
void f1() {
char some_stack[N];
write_to_p(some_stack, 1);
- mu.LockWhen(Condition(&ArgIsTrue, &COND));
+ mu.LockWhen(Condition<bool>(&ArgIsTrue, &COND));
mu.Unlock();
}
}
void Waiter() {
int param = 0;
- MU.ReaderLockWhen(Condition(WeirdCondition, ¶m));
+ MU.ReaderLockWhen(Condition<int>(WeirdCondition, ¶m));
MU.ReaderUnlock();
CHECK(GLOB > 0);
CHECK(param > 0);
}
void WaitForAllThreadsToFinish_Good() {
- mu.LockWhen(Condition(NoElementsLeft, vec));
+ mu.LockWhen(Condition<vector<int>>(NoElementsLeft, vec));
mu.Unlock();
// It is now safe to access vec w/o lock.