X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Scheduler%2FScheduler.cc;h=f7509bcb28f4999f1a4b7dd5ff0de250a4048751;hb=3e42ecb22121f2e6df86b27bea73f890384a4ee4;hp=4f39c4ba7e2429cfdf843d0828651a08127ee3f8;hpb=2654c3b13a187f38dc026e04c76ea5c885b34787;p=senf.git diff --git a/Scheduler/Scheduler.cc b/Scheduler/Scheduler.cc index 4f39c4b..f7509bc 100644 --- a/Scheduler/Scheduler.cc +++ b/Scheduler/Scheduler.cc @@ -20,7 +20,20 @@ // Free Software Foundation, Inc., // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// TODO: Implement signal handling +/** \file + \brief Scheduler non-inline non-template implementation + + \idea Implement signal handling (See source for more discussion + about this) + + \idea Multithreading support: To support multithreading, the + static member Scheduler::instance() must return a thread-local + value (that is Scheduler::instance() must allocate one Scheduler + instance per thread). Another possibility would be to distribute + the async load unto several threads (one scheduler for multiple + threads) + */ + // Here a basic concept of how to add signal support to the scheduler: // // Every signal to be reported by the scheduler will be asigned a @@ -52,17 +65,12 @@ // You should use sigaction to register the signal handlers and define // a sa_mask so all Scheduler-registered signals are automatically // *blocked* whenever one of the signals is called (including the -// called signal!). This ensures, that no two signals can be delivered -// on top of each other. And of course any signal registered with the -// scheduler must be blocked as soon as it is registered with the -// scheduler. - -// TODO: Multithreading support -// To support multithreading, the static member Scheduler::instance() -// must return a thread-local value (that is Scheduler::instance() -// must allocate one Scheduler instance per thread) - -// Definition of non-inline non-template functions +// called signal!) (This also means, we will have to re-register all +// signals if we change the registration of some signal since the +// sa_mask changes). This ensures, that no two signals can be +// delivered on top of each other. And of course any signal registered +// with the scheduler must be blocked as soon as it is registered with +// the scheduler. #include "Scheduler.hh" //#include "Scheduler.ih" @@ -78,25 +86,25 @@ static const int EPollInitialSize = 16; #define prefix_ ///////////////////////////////cc.p//////////////////////////////////////// -prefix_ satcom::lib::Scheduler::Scheduler & satcom::lib::Scheduler::instance() +prefix_ senf::Scheduler::Scheduler & senf::Scheduler::instance() { static Scheduler instance; return instance; } -prefix_ void satcom::lib::Scheduler::timeout(unsigned long timeout, TimerCallback const & cb) +prefix_ void senf::Scheduler::timeout(unsigned long timeout, TimerCallback const & cb) { timerQueue_.push(TimerSpec(now()+1000*timeout,cb)); } -prefix_ satcom::lib::Scheduler::Scheduler() +prefix_ senf::Scheduler::Scheduler() : epollFd_(epoll_create(EPollInitialSize)) { if (epollFd_<0) throw SystemException(errno); } -prefix_ void satcom::lib::Scheduler::do_add(int fd, SimpleCallback const & cb, EventId eventMask) +prefix_ void senf::Scheduler::do_add(int fd, SimpleCallback const & cb, int eventMask) { FdTable::iterator i (fdTable_.find(fd)); int action (EPOLL_CTL_MOD); @@ -120,7 +128,7 @@ prefix_ void satcom::lib::Scheduler::do_add(int fd, SimpleCallback const & cb, E throw SystemException(errno); } -prefix_ void satcom::lib::Scheduler::do_remove(int fd, EventId eventMask) +prefix_ void senf::Scheduler::do_remove(int fd, int eventMask) { FdTable::iterator i (fdTable_.find(fd)); if (i == fdTable_.end()) @@ -136,7 +144,7 @@ prefix_ void satcom::lib::Scheduler::do_remove(int fd, EventId eventMask) memset(&ev,0,sizeof(ev)); ev.events = i->second.epollMask(); ev.data.fd = fd; - + int action (EPOLL_CTL_MOD); if (ev.events==0) { action = EPOLL_CTL_DEL; @@ -148,7 +156,7 @@ prefix_ void satcom::lib::Scheduler::do_remove(int fd, EventId eventMask) } -prefix_ int satcom::lib::Scheduler::EventSpec::epollMask() +prefix_ int senf::Scheduler::EventSpec::epollMask() const { int mask (0); @@ -160,11 +168,11 @@ prefix_ int satcom::lib::Scheduler::EventSpec::epollMask() return mask; } -prefix_ void satcom::lib::Scheduler::process() +prefix_ void senf::Scheduler::process() { terminate_ = false; while (! terminate_) { - struct epoll_event ev; + MicroTime timeNow = now(); while ( ! timerQueue_.empty() && timerQueue_.top().timeout <= timeNow ) { timerQueue_.top().cb(); @@ -174,6 +182,7 @@ prefix_ void satcom::lib::Scheduler::process() return; int timeout = timerQueue_.empty() ? -1 : int((timerQueue_.top().timeout - timeNow)/1000); + struct epoll_event ev; int events = epoll_wait(epollFd_, &ev, 1, timeout); if (events<0) // Hmm ... man epoll says, it will NOT return with EINTR ?? @@ -200,13 +209,26 @@ prefix_ void satcom::lib::Scheduler::process() } else if (ev.events & EPOLLHUP) { - BOOST_ASSERT(spec.cb_hup); - spec.cb_hup(EV_HUP); + if (spec.cb_hup) + spec.cb_hup(EV_HUP); + else if (ev.events & EPOLLERR) { + /** \fixme This is stupid, if cb_write and cb_read are + the same. The same below. We really have to + exactly define sane semantics of what to do on + EPOLLHUP and EPOLLERR. */ + if (spec.cb_write) spec.cb_write(EV_HUP); + if (spec.cb_read) spec.cb_read(EV_HUP); + } } - else if (ev.events & EPOLLERR) { - BOOST_ASSERT(spec.cb_err); - spec.cb_err(EV_ERR); + else if (ev.events & EPOLLERR && ! ev.events & EPOLLHUP) { + if (spec.cb_err) + spec.cb_err(EV_ERR); + else { + if (spec.cb_write) spec.cb_write(EV_ERR); + if (spec.cb_read) spec.cb_read(EV_ERR); + } } + } } @@ -216,5 +238,5 @@ prefix_ void satcom::lib::Scheduler::process() // Local Variables: // mode: c++ -// c-file-style: "satcom" +// c-file-style: "senf" // End: