diff options
Diffstat (limited to 'cpp/src/Ice/Timer.cpp')
-rw-r--r-- | cpp/src/Ice/Timer.cpp | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/cpp/src/Ice/Timer.cpp b/cpp/src/Ice/Timer.cpp new file mode 100644 index 00000000000..2f4d88f7680 --- /dev/null +++ b/cpp/src/Ice/Timer.cpp @@ -0,0 +1,251 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +#include <IceUtil/Timer.h> +#include <IceUtil/Exception.h> + +using namespace std; +using namespace IceUtil; + +Timer::Timer() : + Thread("IceUtil timer thread"), + _destroyed(false) +{ + __setNoDelete(true); + start(); + __setNoDelete(false); +} + +Timer::Timer(int priority) : + Thread("IceUtil timer thread"), + _destroyed(false) +{ + __setNoDelete(true); + start(0, priority); + __setNoDelete(false); +} + +void +Timer::destroy() +{ + { + IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); + if(_destroyed) + { + return; + } + _destroyed = true; + _monitor.notify(); + _tasks.clear(); + _tokens.clear(); + } + + if(getThreadControl() == ThreadControl()) + { + getThreadControl().detach(); + } + else + { + getThreadControl().join(); + } +} + +void +Timer::schedule(const TimerTaskPtr& task, const IceUtil::Time& delay) +{ + IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); + if(_destroyed) + { + throw IllegalArgumentException(__FILE__, __LINE__, "timer destroyed"); + } + + IceUtil::Time now = IceUtil::Time::now(IceUtil::Time::Monotonic); + IceUtil::Time time = now + delay; + if(delay > IceUtil::Time() && time < now) + { + throw IllegalArgumentException(__FILE__, __LINE__, "invalid delay"); + } + + bool inserted = _tasks.insert(make_pair(task, time)).second; + if(!inserted) + { + throw IllegalArgumentException(__FILE__, __LINE__, "task is already schedulded"); + } + _tokens.insert(Token(time, IceUtil::Time(), task)); + + if(_wakeUpTime == IceUtil::Time() || time < _wakeUpTime) + { + _monitor.notify(); + } +} + +void +Timer::scheduleRepeated(const TimerTaskPtr& task, const IceUtil::Time& delay) +{ + IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); + if(_destroyed) + { + throw IllegalArgumentException(__FILE__, __LINE__, "timer destroyed"); + } + + IceUtil::Time now = IceUtil::Time::now(IceUtil::Time::Monotonic); + const Token token(now + delay, delay, task); + if(delay > IceUtil::Time() && token.scheduledTime < now) + { + throw IllegalArgumentException(__FILE__, __LINE__, "invalid delay"); + } + + bool inserted = _tasks.insert(make_pair(task, token.scheduledTime)).second; + if(!inserted) + { + throw IllegalArgumentException(__FILE__, __LINE__, "task is already schedulded"); + } + _tokens.insert(token); + + if(_wakeUpTime == IceUtil::Time() || token.scheduledTime < _wakeUpTime) + { + _monitor.notify(); + } +} + +bool +Timer::cancel(const TimerTaskPtr& task) +{ + IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); + if(_destroyed) + { + return false; + } + + map<TimerTaskPtr, IceUtil::Time, TimerTaskCompare>::iterator p = _tasks.find(task); + if(p == _tasks.end()) + { + return false; + } + + _tokens.erase(Token(p->second, IceUtil::Time(), p->first)); + _tasks.erase(p); + + return true; +} + +void +Timer::run() +{ + Token token(IceUtil::Time(), IceUtil::Time(), 0); + while(true) + { + { + IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); + + if(!_destroyed) + { + // + // If the task we just ran is a repeated task, schedule it + // again for executation if it wasn't canceled. + // + if(token.delay != IceUtil::Time()) + { + map<TimerTaskPtr, IceUtil::Time, TimerTaskCompare>::iterator p = _tasks.find(token.task); + if(p != _tasks.end()) + { + token.scheduledTime = IceUtil::Time::now(IceUtil::Time::Monotonic) + token.delay; + p->second = token.scheduledTime; + _tokens.insert(token); + } + } + token = Token(IceUtil::Time(), IceUtil::Time(), 0); + + if(_tokens.empty()) + { + _wakeUpTime = IceUtil::Time(); + _monitor.wait(); + } + } + + if(_destroyed) + { + break; + } + + while(!_tokens.empty() && !_destroyed) + { + const IceUtil::Time now = IceUtil::Time::now(IceUtil::Time::Monotonic); + const Token& first = *(_tokens.begin()); + if(first.scheduledTime <= now) + { + token = first; + _tokens.erase(_tokens.begin()); + if(token.delay == IceUtil::Time()) + { + _tasks.erase(token.task); + } + break; + } + + _wakeUpTime = first.scheduledTime; + try + { + _monitor.timedWait(first.scheduledTime - now); + } + catch(const IceUtil::InvalidTimeoutException&) + { + IceUtil::Time timeout = (first.scheduledTime - now) / 2; + while(timeout > IceUtil::Time()) + { + try + { + _monitor.timedWait(timeout); + break; + } + catch(const IceUtil::InvalidTimeoutException&) + { + timeout = timeout / 2; + } + } + } + } + + if(_destroyed) + { + break; + } + } + + if(token.task) + { + try + { + runTimerTask(token.task); + } + catch(const IceUtil::Exception& e) + { + cerr << "IceUtil::Timer::run(): uncaught exception:\n" << e.what(); +#ifdef __GNUC__ + cerr << "\n" << e.ice_stackTrace(); +#endif + cerr << endl; + } + catch(const std::exception& e) + { + cerr << "IceUtil::Timer::run(): uncaught exception:\n" << e.what() << endl; + } + catch(...) + { + cerr << "IceUtil::Timer::run(): uncaught exception" << endl; + } + } + } +} + +void +Timer::runTimerTask(const TimerTaskPtr& task) +{ + task->runTimerTask(); +} |