#include <signal.h>
#include <time.h>
#include "../Utils/Exception.hh"
+#include "../Utils/senfassert.hh"
//#include "FIFORunner.mpp"
#define prefix_
///////////////////////////////cc.p////////////////////////////////////////
-prefix_ senf::scheduler::FIFORunner::FIFORunner()
- : tasks_ (), next_ (tasks_.end()), hangCount_ (0)
+prefix_ senf::scheduler::detail::FIFORunner::FIFORunner()
+ : tasks_ (), next_ (tasks_.end()), watchdogMs_ (1000), watchdogCount_(0), hangCount_ (0)
{
struct sigevent ev;
::memset(&ev, 0, sizeof(ev));
SENF_THROW_SYSTEM_EXCEPTION("sigprocmask()");
}
-prefix_ senf::scheduler::FIFORunner::~FIFORunner()
+prefix_ senf::scheduler::detail::FIFORunner::~FIFORunner()
{
timer_delete(watchdogId_);
signal(SIGURG, SIG_DFL);
// will mostly be localized to the end of the queue. only occasionally one of the dormant tasks will
// be runnable. This additional traversal time will be amortized over a larger time.
-prefix_ void senf::scheduler::FIFORunner::dequeue(TaskInfo * task)
+prefix_ void senf::scheduler::detail::FIFORunner::dequeue(TaskInfo * task)
{
TaskList::iterator i (TaskList::current(*task));
if (next_ == i)
namespace {
struct NullTask
- : public senf::scheduler::FIFORunner::TaskInfo
+ : public senf::scheduler::detail::FIFORunner::TaskInfo
{
+ NullTask() : senf::scheduler::detail::FIFORunner::TaskInfo ("<null>") {}
void run() {};
};
}
-prefix_ void senf::scheduler::FIFORunner::run()
+prefix_ void senf::scheduler::detail::FIFORunner::run()
{
// This algorithm is carefully adjusted to make it work even when arbitrary tasks are removed
// from the queue
// - We keep the next to-be-processed node in a class variable which is checked and updated
// whenever a node is removed.
NullTask null;
+ struct itimerspec timer;
+ timer.it_interval.tv_sec = watchdogMs_ / 1000;
+ timer.it_interval.tv_nsec = (watchdogMs_ % 1000) * 1000000ul;
+ timer.it_value.tv_sec = timer.it_interval.tv_sec;
+ timer.it_value.tv_nsec = timer.it_interval.tv_nsec;
tasks_.push_back(null);
TaskList::iterator end (TaskList::current(null));
next_ = tasks_.begin();
- struct itimerspec timer;
- timer.it_interval.tv_sec = 0;
- timer.it_interval.tv_nsec = 0;
- timer.it_value.tv_sec = 1;
- timer.it_value.tv_nsec = 0;
- while (next_ != end) {
- TaskInfo & task (*next_);
- if (task.runnable) {
- task.runnable = false;
- if (timer_settime(watchdogId_, 0, &timer, 0) < 0)
- SENF_THROW_SYSTEM_EXCEPTION("timer_settime()");
- runningName_ = task.name;
-# ifdef SENF_DEBUG
- runningBacktrace_ = task.backtrace;
-# endif
- TaskList::iterator i (next_);
- ++ next_;
- tasks_.splice(tasks_.end(), tasks_, i);
- task.run();
+ try {
+ if (timer_settime(watchdogId_, 0, &timer, 0) < 0)
+ SENF_THROW_SYSTEM_EXCEPTION("timer_settime()");
+ while (next_ != end) {
+ TaskInfo & task (*next_);
+ if (task.runnable_) {
+ task.runnable_ = false;
+ runningName_ = task.name_;
+# ifdef SENF_DEBUG
+ runningBacktrace_ = task.backtrace_;
+# endif
+ TaskList::iterator i (next_);
+ ++ next_;
+ tasks_.splice(tasks_.end(), tasks_, i);
+ watchdogCount_ = 1;
+ task.run();
+ }
+ else
+ ++ next_;
}
- else
- ++ next_;
}
+ catch (...) {
+ watchdogCount_ = 0;
+ timer.it_interval.tv_sec = 0;
+ timer.it_interval.tv_nsec = 0;
+ timer.it_value.tv_sec = 0;
+ timer.it_value.tv_nsec = 0;
+ timer_settime(watchdogId_, 0, &timer, 0);
+ tasks_.erase(end);
+ next_ = tasks_.end();
+ throw;
+ }
+ watchdogCount_ = 0;
+ timer.it_interval.tv_sec = 0;
+ timer.it_interval.tv_nsec = 0;
timer.it_value.tv_sec = 0;
+ timer.it_value.tv_nsec = 0;
if (timer_settime(watchdogId_, 0, &timer, 0) < 0)
SENF_THROW_SYSTEM_EXCEPTION("timer_settime()");
tasks_.erase(end);
next_ = tasks_.end();
}
-prefix_ void senf::scheduler::FIFORunner::watchdog(int, siginfo_t * si, void *)
+prefix_ void senf::scheduler::detail::FIFORunner::watchdog(int, siginfo_t * si, void *)
{
FIFORunner & runner (*static_cast<FIFORunner *>(si->si_value.sival_ptr));
- ++ runner.hangCount_;
- write(1, "\n\n*** Scheduler task hanging: ", 30);
- write(1, runner.runningName_.c_str(), runner.runningName_.size());
- write(1, "\n", 1);
+ if (runner.watchdogCount_ > 0) {
+ ++ runner.watchdogCount_;
+ if (runner.watchdogCount_ > 2) {
+ ++ runner.hangCount_;
+ write(1, "\n\n*** Scheduler task hanging: ", 30);
+ write(1, runner.runningName_.c_str(), runner.runningName_.size());
+ write(1, "\n", 1);
#ifdef SENF_DEBUG
- write(1, "Task was initialized at\n", 24);
- write(1, runner.runningBacktrace_.c_str(), runner.runningBacktrace_.size());
+ write(1, "Task was initialized at\n", 24);
+ write(1, runner.runningBacktrace_.c_str(), runner.runningBacktrace_.size());
#endif
- write(1, "\n", 1);
+ write(1, "\n", 1);
+ }
+ }
}
///////////////////////////////cc.e////////////////////////////////////////