X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Scheduler%2FScheduler.cc;h=c758ea9ca30658542562c5aa6509c3460ccaad4c;hb=53a3d02e7fde841badf42555eba87ccef4566073;hp=816e663d17da7b4494ed213220ed6e78d2a253ad;hpb=dd9cab12c8a33e57da1dd1104b530e8ea1591c53;p=senf.git diff --git a/Scheduler/Scheduler.cc b/Scheduler/Scheduler.cc index 816e663..c758ea9 100644 --- a/Scheduler/Scheduler.cc +++ b/Scheduler/Scheduler.cc @@ -85,19 +85,9 @@ static const int EPollInitialSize = 16; #define prefix_ ///////////////////////////////cc.p//////////////////////////////////////// -prefix_ senf::Scheduler::Scheduler & senf::Scheduler::instance() -{ - static Scheduler instance; - return instance; -} - -prefix_ void senf::Scheduler::timeout(ClockService::clock_type timeout, TimerCallback const & cb) -{ - timerQueue_.push(TimerSpec(ClockService::now()+timeout,cb)); -} - prefix_ senf::Scheduler::Scheduler() - : epollFd_ (epoll_create(EPollInitialSize)) + : timerIdCounter_(0), epollFd_ (epoll_create(EPollInitialSize)), terminate_(false), + eventTime_(0) { if (epollFd_<0) throw SystemException(errno); @@ -164,31 +154,58 @@ prefix_ int senf::Scheduler::EventSpec::epollMask() prefix_ void senf::Scheduler::process() { terminate_ = false; + eventTime_ = ClockService::now(); while (! terminate_) { - ClockService::clock_type timeNow = ClockService::now(); - while ( ! timerQueue_.empty() && timerQueue_.top().timeout <= timeNow ) { - timerQueue_.top().cb(); + // Since a callback may have disabled further timers, we need to check for canceled timeouts + // again. + + while (! timerQueue_.empty()) { + TimerMap::iterator i (timerQueue_.top()); + if (! i->second.canceled) + break; + timerMap_.erase(i); timerQueue_.pop(); } - if (terminate_) - return; - - int timeout (MinTimeout); - if (! timerQueue_.empty()) { - ClockService::clock_type delta ((timerQueue_.top().timeout - timeNow)/1000000UL); - if (deltasecond.timeout - eventTime_)/1000000UL); + timeout = delta < 0 ? 0 : delta; } + ///\todo Handle more than one epoll_event per call struct epoll_event ev; int events = epoll_wait(epollFd_, &ev, 1, timeout); if (events<0) - // 'man epoll' says, epoll will not return with EINTR. - throw SystemException(errno); - if (events==0) - // Timeout .. the handler will be run when going back to the loop top + if (errno != EINTR) + throw SystemException(errno); + + eventTime_ = ClockService::now(); + + // We always run event handlers. This is important, even if a file-descriptor is signaled + // since some descriptors (e.g. real files) will *always* be ready and we still may want to + // handle timers. + // Time handlers are run before file events to not delay them unnecessarily. + + while (! timerQueue_.empty()) { + TimerMap::iterator i (timerQueue_.top()); + if (i->second.canceled) + ; + else if (i->second.timeout <= eventTime_) + i->second.cb(); + else + break; + timerMap_.erase(i); + timerQueue_.pop(); + } + + if (events <= 0) continue; FdTable::iterator i = fdTable_.find(ev.data.fd);