00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00026 #include "FIFORunner.hh"
00027
00028
00029
00030 #include <signal.h>
00031 #include <time.h>
00032 #include <cassert>
00033 #include <senf/config.hh>
00034 #ifdef SENF_BACKTRACE
00035 #include <execinfo.h>
00036 #endif
00037 #include <stdint.h>
00038 #include <stdio.h>
00039 #include <senf/Utils/Exception.hh>
00040 #include "senf/Utils/IgnoreValue.hh"
00041 #include <senf/Utils/Console/ScopedDirectory.hh>
00042 #include <senf/Utils/Console/ParsedCommand.hh>
00043 #include "ConsoleDir.hh"
00044
00045
00046 #define prefix_
00047
00048
00049 prefix_ senf::scheduler::detail::FIFORunner::FIFORunner()
00050 : tasks_ (), next_ (tasks_.end()), watchdogRunning_ (false), watchdogMs_ (1000),
00051 watchdogAbort_ (false), watchdogCount_(0), hangCount_ (0), yield_ (false)
00052 {
00053 struct sigevent ev;
00054 ::memset(&ev, 0, sizeof(ev));
00055 ev.sigev_notify = SIGEV_SIGNAL;
00056 ev.sigev_signo = SIGURG;
00057 ev.sigev_value.sival_ptr = this;
00058 if (timer_create(CLOCK_MONOTONIC, &ev, &watchdogId_) < 0)
00059 SENF_THROW_SYSTEM_EXCEPTION("timer_create()");
00060
00061 struct sigaction sa;
00062 ::memset(&sa, 0, sizeof(sa));
00063 sa.sa_sigaction = &watchdog;
00064 sa.sa_flags = SA_SIGINFO;
00065 if (sigaction(SIGURG, &sa, 0) < 0)
00066 SENF_THROW_SYSTEM_EXCEPTION("sigaction()");
00067
00068 sigset_t mask;
00069 sigemptyset(&mask);
00070 sigaddset(&mask, SIGURG);
00071 if (sigprocmask(SIG_UNBLOCK, &mask, 0) < 0)
00072 SENF_THROW_SYSTEM_EXCEPTION("sigprocmask()");
00073
00074 tasks_.push_back(highPriorityEnd_);
00075 tasks_.push_back(normalPriorityEnd_);
00076
00077 #ifndef SENF_DISABLE_CONSOLE
00078 namespace fty = console::factory;
00079 consoleDir().add("abortOnWatchdocTimeout", fty::Command(
00080 SENF_MEMBINDFNP( bool, FIFORunner, abortOnTimeout, () const ))
00081 .doc("Get current watchdog abort on event status.") );
00082 consoleDir().add("abortOnWatchdocTimeout", fty::Command(
00083 SENF_MEMBINDFNP( void, FIFORunner, abortOnTimeout, (bool) ))
00084 .doc("Enable/disable abort on watchdog event.") );
00085 consoleDir().add("watchdogTimeout", fty::Command(
00086 SENF_MEMBINDFNP( unsigned, FIFORunner, taskTimeout, () const ))
00087 .doc("Get current watchdog timeout in milliseconds") );
00088 consoleDir().add("watchdogTimeout", fty::Command(
00089 SENF_MEMBINDFNP( void, FIFORunner, taskTimeout, (unsigned) ))
00090 .doc("Set watchdog timeout to in milliseconds\n"
00091 "Setting the watchdog timeout to 0 will disable the watchdog.") );
00092 consoleDir().add("watchdogEvents", fty::Command(membind( &FIFORunner::hangCount, this))
00093 .doc("Get number of occurred watchdog events.\n"
00094 "Calling this method will reset the counter to 0") );
00095 #endif
00096 }
00097
00098 prefix_ senf::scheduler::detail::FIFORunner::~FIFORunner()
00099 {
00100 timer_delete(watchdogId_);
00101 signal(SIGURG, SIG_DFL);
00102
00103 #ifndef SENF_DISABLE_CONSOLE
00104 consoleDir().remove("abortOnWatchdocTimeout");
00105 consoleDir().remove("watchdogTimeout");
00106 consoleDir().remove("watchdogEvents");
00107 #endif
00108 }
00109
00110 prefix_ void senf::scheduler::detail::FIFORunner::startWatchdog()
00111 {
00112 if (watchdogMs_ > 0) {
00113 struct itimerspec timer;
00114 ::memset(&timer, 0, sizeof(timer));
00115
00116 timer.it_interval.tv_sec = watchdogMs_ / 1000;
00117 timer.it_interval.tv_nsec = (watchdogMs_ % 1000) * 1000000ul;
00118 timer.it_value.tv_sec = timer.it_interval.tv_sec;
00119 timer.it_value.tv_nsec = timer.it_interval.tv_nsec;
00120
00121 if (timer_settime(watchdogId_, 0, &timer, 0) < 0)
00122 SENF_THROW_SYSTEM_EXCEPTION("timer_settime()");
00123
00124 watchdogRunning_ = true;
00125 }
00126 else
00127 stopWatchdog();
00128 }
00129
00130 prefix_ void senf::scheduler::detail::FIFORunner::stopWatchdog()
00131 {
00132 struct itimerspec timer;
00133 ::memset(&timer, 0, sizeof(timer));
00134
00135 if (timer_settime(watchdogId_, 0, &timer, 0) < 0)
00136 SENF_THROW_SYSTEM_EXCEPTION("timer_settime()");
00137
00138 watchdogRunning_ = false;
00139 }
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163 prefix_ void senf::scheduler::detail::FIFORunner::dequeue(TaskInfo * task)
00164 {
00165 TaskList::iterator i (TaskList::current(*task));
00166 if (next_ == i)
00167 ++next_;
00168 tasks_.erase(i);
00169 }
00170
00171 prefix_ void senf::scheduler::detail::FIFORunner::run()
00172 {
00173 for (;;) {
00174 TaskList::iterator f (tasks_.begin());
00175 TaskList::iterator l (TaskList::current(highPriorityEnd_));
00176 run(f, l);
00177 if (yield_) {
00178 yield_ = false;
00179 continue;
00180 }
00181
00182 f = l; ++f;
00183 l = TaskList::current(normalPriorityEnd_);
00184 run(f, l);
00185 if (yield_) {
00186 yield_ = false;
00187 continue;
00188 }
00189
00190 f = l; ++f;
00191 l = tasks_.end();
00192 run(f, l);
00193 if (yield_) {
00194 yield_ = false;
00195 continue;
00196 }
00197 break;
00198 }
00199 }
00200
00201 prefix_ void senf::scheduler::detail::FIFORunner::run(TaskList::iterator f, TaskList::iterator l)
00202 {
00203 if (f == l)
00204
00205 return;
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217 NullTask null;
00218 tasks_.insert(l, null);
00219 TaskList::iterator end (TaskList::current(null));
00220 next_ = f;
00221
00222
00223
00224
00225 try {
00226 while (next_ != end) {
00227 TaskInfo & task (*next_);
00228 if (task.runnable_) {
00229 task.runnable_ = false;
00230 runningName_ = task.name();
00231 # ifdef SENF_BACKTRACE
00232 runningBacktrace_ = task.backtrace_;
00233 # endif
00234 TaskList::iterator i (next_);
00235 ++ next_;
00236 tasks_.splice(l, tasks_, i);
00237 watchdogCount_ = 1;
00238 yield_ = false;
00239 task.run();
00240 if (yield_)
00241 return;
00242 }
00243 else
00244 ++ next_;
00245 }
00246 watchdogCount_ = 0;
00247 next_ = l;
00248 }
00249 catch (...) {
00250 watchdogCount_ = 0;
00251 next_ = l;
00252 throw;
00253 }
00254 }
00255
00256 prefix_ senf::scheduler::detail::FIFORunner::TaskList::iterator
00257 senf::scheduler::detail::FIFORunner::priorityEnd(TaskInfo::Priority p)
00258 {
00259 switch (p) {
00260 case TaskInfo::PRIORITY_LOW :
00261 return tasks_.end();
00262 case TaskInfo::PRIORITY_NORMAL :
00263 return TaskList::current(normalPriorityEnd_);
00264 case TaskInfo::PRIORITY_HIGH :
00265 return TaskList::current(highPriorityEnd_);
00266 }
00267 return tasks_.begin();
00268 }
00269
00270 prefix_ void senf::scheduler::detail::FIFORunner::watchdog(int, siginfo_t * si, void *)
00271 {
00272 FIFORunner & runner (*static_cast<FIFORunner *>(si->si_value.sival_ptr));
00273 if (runner.watchdogCount_ > 0) {
00274 ++ runner.watchdogCount_;
00275 if (runner.watchdogCount_ > 2) {
00276 ++ runner.hangCount_;
00277 runner.watchdogError();
00278 }
00279 }
00280 }
00281
00282 prefix_ void senf::scheduler::detail::FIFORunner::watchdogError()
00283 {
00284
00285 senf::IGNORE( write(1, "\n\n*** Scheduler task hanging (pid ",34) );
00286 static char pid[7];
00287 ::snprintf(pid, 7, "%6d", ::getpid());
00288 pid[6] = 0;
00289 senf::IGNORE( write(1, pid, 6) );
00290 senf::IGNORE( write(1, "): ", 3) );
00291 senf::IGNORE( write(1, runningName_.c_str(), runningName_.size()) );
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307 senf::IGNORE( write(1, "\n", 1) );
00308
00309 #ifdef SENF_BACKTRACE
00310 senf::IGNORE( write(1, "Task was initialized at\n", 24) );
00311 senf::IGNORE( write(1, runningBacktrace_.c_str(), runningBacktrace_.size()) );
00312 #endif
00313 senf::IGNORE( write(1, "\n", 1) );
00314 if (watchdogAbort_)
00315 assert(false);
00316 }
00317
00318
00319 #undef prefix_
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331