summaryrefslogtreecommitdiff
path: root/qpid/cpp/src
diff options
context:
space:
mode:
Diffstat (limited to 'qpid/cpp/src')
-rw-r--r--qpid/cpp/src/qpid/sys/Timer.cpp55
-rw-r--r--qpid/cpp/src/qpid/sys/Timer.h7
2 files changed, 51 insertions, 11 deletions
diff --git a/qpid/cpp/src/qpid/sys/Timer.cpp b/qpid/cpp/src/qpid/sys/Timer.cpp
index 47752e4584..0b3544e7b0 100644
--- a/qpid/cpp/src/qpid/sys/Timer.cpp
+++ b/qpid/cpp/src/qpid/sys/Timer.cpp
@@ -35,7 +35,7 @@ TimerTask::TimerTask(Duration timeout, const std::string& n) :
sortTime(AbsTime::FarFuture()),
period(timeout),
nextFireTime(AbsTime::now(), timeout),
- cancelled(false)
+ state(WAITING)
{}
TimerTask::TimerTask(AbsTime time, const std::string& n) :
@@ -43,7 +43,7 @@ TimerTask::TimerTask(AbsTime time, const std::string& n) :
sortTime(AbsTime::FarFuture()),
period(0),
nextFireTime(time),
- cancelled(false)
+ state(WAITING)
{}
TimerTask::~TimerTask() {}
@@ -52,27 +52,48 @@ bool TimerTask::readyToFire() const {
return !(nextFireTime > AbsTime::now());
}
+bool TimerTask::prepareToFire() {
+ Monitor::ScopedLock l(stateMonitor);
+ if (state != CANCELLED) {
+ state = CALLBACK;
+ return true;
+ } else {
+ return false;
+ }
+}
+
void TimerTask::fireTask() {
- cancelled = true;
fire();
}
+void TimerTask::finishFiring() {
+ Monitor::ScopedLock l(stateMonitor);
+ if (state != CANCELLED) {
+ state = WAITING;
+ stateMonitor.notifyAll();
+ }
+}
+
// This can only be used to setup the next fire time. After the Timer has already fired
void TimerTask::setupNextFire() {
if (period && readyToFire()) {
nextFireTime = max(AbsTime::now(), AbsTime(nextFireTime, period));
- cancelled = false;
} else {
QPID_LOG(error, name << " couldn't setup next timer firing: " << Duration(nextFireTime, AbsTime::now()) << "[" << period << "]");
}
}
// Only allow tasks to be delayed
-void TimerTask::restart() { nextFireTime = max(nextFireTime, AbsTime(AbsTime::now(), period)); }
+void TimerTask::restart() {
+ nextFireTime = max(nextFireTime, AbsTime(AbsTime::now(), period));
+}
void TimerTask::cancel() {
- ScopedLock<Mutex> l(callbackLock);
- cancelled = true;
+ Monitor::ScopedLock l(stateMonitor);
+ while (state == CALLBACK) {
+ stateMonitor.wait();
+ }
+ state = CANCELLED;
}
void TimerTask::setFired() {
@@ -96,6 +117,22 @@ Timer::~Timer()
stop();
}
+class TimerTaskCallbackScope {
+ TimerTask& tt;
+public:
+ explicit TimerTaskCallbackScope(TimerTask& t) :
+ tt(t)
+ {}
+
+ operator bool() {
+ return !tt.prepareToFire();
+ }
+
+ ~TimerTaskCallbackScope() {
+ tt.finishFiring();
+ }
+};
+
// TODO AStitcher 21/08/09 The threshholds for emitting warnings are a little arbitrary
void Timer::run()
{
@@ -112,8 +149,8 @@ void Timer::run()
AbsTime start(AbsTime::now());
Duration delay(t->sortTime, start);
{
- ScopedLock<Mutex> l(t->callbackLock);
- if (t->cancelled) {
+ TimerTaskCallbackScope s(*t);
+ if (s) {
{
Monitor::ScopedUnlock u(monitor);
drop(t);
diff --git a/qpid/cpp/src/qpid/sys/Timer.h b/qpid/cpp/src/qpid/sys/Timer.h
index fccb17dbc2..af0b1b6803 100644
--- a/qpid/cpp/src/qpid/sys/Timer.h
+++ b/qpid/cpp/src/qpid/sys/Timer.h
@@ -40,6 +40,7 @@ class Timer;
class TimerTask : public RefCounted {
friend class Timer;
+ friend class TimerTaskCallbackScope;
friend bool operator<(const boost::intrusive_ptr<TimerTask>&,
const boost::intrusive_ptr<TimerTask>&);
@@ -47,9 +48,11 @@ class TimerTask : public RefCounted {
AbsTime sortTime;
Duration period;
AbsTime nextFireTime;
- Mutex callbackLock;
- volatile bool cancelled;
+ qpid::sys::Monitor stateMonitor;
+ enum {WAITING, CALLBACK, CANCELLED} state;
+ bool prepareToFire();
+ void finishFiring();
bool readyToFire() const;
void fireTask();