scheduler.hxx

Go to the documentation of this file.
00001 // Copyright (C) 2003-2006 Laboratoire de Recherche en Informatique
00002 
00003 // This file is part of Qolyester.
00004 
00005 // Qolyester is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU General Public License
00007 // as published by the Free Software Foundation; either version 2
00008 // of the License, or (at your option) any later version.
00009 
00010 // Qolyester is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 
00015 // You should have received a copy of the GNU General Public License
00016 // along with this program; if not, write to the Free Software
00017 // Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018 // Boston, MA  02110-1301, USA.
00019 
00027 #ifndef QOLYESTER_SCH_SCHEDULER_HXX
00028 #define QOLYESTER_SCH_SCHEDULER_HXX 1
00029 
00030 # include <unistd.h>
00031 # include <signal.h>
00032 # include <sys/times.h>
00033 # include <cassert>
00034 # include <cstring>
00035 # include <cerrno>
00036 # include <map>
00037 # include "scheduler.hh"
00038 # include "utl/mark.hh"
00039 # include "utl/log.hh"
00040 
00041 namespace olsr {
00042 
00043   extern std::ostream           dump_prof;
00044   extern debug_ostream_t        debug;
00045   extern utl::Mark              terminate_now;
00046   extern bool                   do_dump_prof;
00047   extern sched_t                scheduler;
00048 
00049   namespace sch {
00050 
00051     bool
00052     LoopHandler::operator()() const {
00053       if (terminate_now.mark())
00054         return true;
00055       return false;
00056     }
00057 
00058 # ifdef DEBUG
00059     Event::Event(const std::string& name)
00060       : name_(name)
00061     {}
00062 # else // !DEBUG
00063     Event::Event()
00064     {}
00065 # endif
00066 
00067     template <class I>
00068     void
00069     PeriodicEvent_<I>::handle() {
00070       do
00071         increment_(next_, period_);
00072       while (next_.is_past());
00073       scheduler.insert(this);
00074     }
00075 
00076     namespace internal {
00077 
00078       template <class C, class A>
00079       void
00080       PollData::poll(std::multiset<IOEvent*, C, A>& s, int timeout) {
00081         typedef std::multiset<IOEvent*, C, A>   set_t;
00082         ::pollfd                ufds[s.size()];
00083         typename set_t::iterator        ievs[s.size()];
00084 
00085         unsigned        counter = 0;
00086 
00087         for (typename set_t::iterator i = s.begin();
00088              i != s.end(); ++i, ++counter) {
00089           ufds[counter] = (*i)->p().pfd;
00090           ufds[counter].revents = 0;
00091           ievs[counter] = i;
00092         }
00093 
00094         int     ret = ::poll(ufds, s.size(), timeout);
00095 
00096         if (ret < 0 && errno != EINTR)
00097           error << "poll(" << s.size()
00098                 << "): " << strerror(errno) << std::endl;
00099 
00100         assert(ret >= 0 || (ret < 0 && errno == EINTR));
00101 
00102         std::map<int, bool>     input_already;
00103         std::map<int, bool>     output_already;
00104 
00105         if (ret > 0) {
00106           for (unsigned i = 0; i < counter; ++i) {
00107             assert(ufds[i].events == (*ievs[i])->p().pfd.events);
00108             if (ufds[i].events & ufds[i].revents) {
00109               IOEvent*  e = *ievs[i];
00110               s.erase(ievs[i]);
00111               e->p().pfd = ufds[i];
00112               if ((ufds[i].revents & POLLIN) != 0)
00113                 if (input_already[ufds[i].fd])
00114                   e->p().pfd.revents &= ~POLLIN;
00115                 else
00116                   input_already[ufds[i].fd] = true;
00117               if ((ufds[i].revents & POLLOUT) != 0)
00118                 if (output_already[ufds[i].fd])
00119                   e->p().pfd.revents &= ~POLLOUT;
00120                 else
00121                   output_already[ufds[i].fd] = true;
00122               s.insert(e);
00123             }
00124           }
00125         }
00126       }
00127 
00128 
00129       void      (*old_term_handler)(int) = SIG_IGN;
00130       void      (*old_int_handler)(int)  = SIG_IGN;
00131       void      (*old_quit_handler)(int) = SIG_IGN;
00132 
00133       void      install_sighandlers()
00134       {
00135 # define GET_OLD_HANDLER(Signal, SmallSignal) \
00136         do { \
00137           struct sigaction      sa; \
00138           int                   ret; \
00139           while ((ret = ::sigaction(Signal, NULL, &sa)) < 0 && \
00140                  errno == EINTR); \
00141           assert(ret == 0); \
00142           old_ ## SmallSignal ## _handler = sa.sa_handler; \
00143         } while (0)
00144 
00145         GET_OLD_HANDLER(SIGTERM, term);
00146         GET_OLD_HANDLER(SIGINT,  int);
00147         GET_OLD_HANDLER(SIGQUIT, quit);
00148 
00149 # define PUT_NEW_HANDLER(Signal, SmallSignal) \
00150         do { \
00151           if (old_ ## SmallSignal ## _handler != SIG_IGN) { \
00152             struct sigaction    sa; \
00153             memset(&sa, 0, sizeof sa); \
00154             sa.sa_handler = SmallSignal ## _handler; \
00155             sigemptyset(&sa.sa_mask); \
00156             sa.sa_flags = SA_RESTART; \
00157             int                 ret; \
00158             while ((ret = ::sigaction(Signal, &sa, NULL)) < 0 && \
00159                    errno == EINTR); \
00160             assert(ret == 0); \
00161           } \
00162         } while (0)
00163 
00164         PUT_NEW_HANDLER(SIGTERM, term);
00165         PUT_NEW_HANDLER(SIGINT,  int);
00166         PUT_NEW_HANDLER(SIGQUIT, quit);
00167 
00168         {
00169           struct sigaction      sa;
00170           memset(&sa, 0, sizeof sa);
00171           sa.sa_handler = SIG_IGN;
00172           sa.sa_flags = 0;
00173           int                   ret;
00174           while ((ret = ::sigaction(SIGPIPE, &sa, NULL)) < 0 &&
00175                  errno == EINTR);
00176           assert(ret == 0);
00177         }
00178       }
00179 
00180     } // namespace internal
00181 
00182     // The scheduler ctor, which actually sets the signal handlers.  Not
00183     // only do we set the SIGALRM handler, but also termination
00184     // handlers, to clean up the routes before quitting.
00185     Scheduler::Scheduler(LoopHandler& lh)
00186       : loophandler_(lh),
00187         current_event_(0) {
00188       internal::install_sighandlers();
00189     }
00190 
00191     Scheduler::~Scheduler() {
00192       while (!ioevent_set_.empty())
00193         destroy(*ioevent_set_.begin());
00194       while (!tevent_set_.empty())
00195         destroy(*tevent_set_.begin());
00196     }
00197 
00198     // The registering methods.  The event has to be instantiated with
00199     // the new operator, as expired events are deleted.
00200     void
00201     Scheduler::insert(TimedEvent* e) {
00202       assert(e != 0);
00203       tevent_set_.insert(e);
00204       debug << up << "Registering TimedEvent " << e->name()
00205             << ' ' << e << " to " << e->next().diff()
00206             << std::endl << down;
00207     }
00208 
00209     void
00210     Scheduler::erase(TimedEvent* e) {
00211       assert(e != 0);
00212       typedef teventset_t::iterator     iter_t;
00213       std::pair<iter_t, iter_t>         ep = tevent_set_.equal_range(e);
00214 
00215       for (iter_t i = ep.first; i != ep.second;)
00216         if (*i == e) {
00217           debug << up << "Unregistering " << e->name()
00218                 << ' ' << e << " to " << e->next().diff()
00219                 << std::endl << down;
00220           iter_t        tmp = i++;
00221           tevent_set_.erase(tmp);
00222         } else
00223           ++i;
00224     }
00225 
00226     template <class E>
00227     void
00228     Scheduler::destroy(E* e) {
00229       erase(e);
00230       if (current_event_ == e)
00231         delete_ = true;
00232       else
00233         delete e;
00234     }
00235 
00236     // For the moment, we don't need to remove I/O events from the set,
00237     // so we don't delete them at this time.  Nevertheless, avoid
00238     // passing pointers to objects that should not be deleted, as this
00239     // may change in the future.
00240     void
00241     Scheduler::insert(IOEvent* e) {
00242       assert(e != 0);
00243       debug << up << "Registering IOEvent " << e->name()
00244             << ' ' << e << std::endl << down;
00245       ioevent_set_.insert(e);
00246     }
00247 
00248     void
00249     Scheduler::erase(IOEvent* e) {
00250       assert(e != 0);
00251       typedef ioeventset_t::iterator    iter_t;
00252       std::pair<iter_t, iter_t>         ep = ioevent_set_.equal_range(e);
00253 
00254       for (iter_t i = ep.first; i != ep.second;)
00255         if (*i == e) {
00256           iter_t        tmp = i++;
00257           debug << up << "Unregistering IOEvent " << e->name()
00258                 << ' ' << e << std::endl << down;
00259           ioevent_set_.erase(tmp);
00260         } else
00261           ++i;
00262     }
00263 
00264     // This is where the handlers of timed events are called and the
00265     // timer reset.
00266     void
00267     Scheduler::handle_tevents() {
00268 # ifdef DEBUG
00269       debug << up(2) << "TimedEvents before {\n" << indent;
00270       for (teventset_t::iterator i = tevent_set_.begin();
00271            i != tevent_set_.end(); ++i)
00272         debug << (*i)->name() << ' ' << *i << ' ' << (*i)->next().diff()
00273               << ((*i)->next().is_past() ? " A\n" : "\n");
00274       debug << deindent << '}' << std::endl << down(2);
00275 # endif // !DEBUG
00276 
00277       // Iterate on the event set.
00278       while (!tevent_set_.empty()) {
00279         TimedEvent*             e = *tevent_set_.begin();
00280 
00281         if (e->next() > timeval_t::now())
00282           break;
00283 
00284         current_event_ = e;
00285         tevent_set_.erase(tevent_set_.begin());
00286 
00287         delete_ = false;
00288         debug << up << "Handling TimedEvent " << e->name()
00289               << ' ' << e << " with " << e->next().diff()
00290               << std::endl << down;
00291         e->handle();
00292         if (delete_)
00293           delete e;
00294         current_event_ = 0;
00295       }
00296 
00297 # ifdef DEBUG
00298       debug << up(2) << "TimedEvents after {\n" << indent;
00299       for (teventset_t::iterator i = tevent_set_.begin();
00300            i != tevent_set_.end(); ++i)
00301         debug << (*i)->name() << ' ' << *i << ' ' << (*i)->next().diff()
00302               << ((*i)->next().is_past() ? " A\n" : "\n");
00303       debug << deindent << '}' << std::endl << down(2);
00304 # endif // !DEBUG
00305     }
00306 
00307     // This is where I/O event handlers are called.
00308     void
00309     Scheduler::handle_ioevents() {
00310       // Iterate on the event set.
00311 # ifdef DEBUG
00312       debug << up(2) << "IOEvents before {\n" << indent;
00313       for (ioeventset_t::iterator i = ioevent_set_.begin();
00314            i != ioevent_set_.end(); ++i)
00315         debug << (*i)->name() << ' ' << *i << ' '
00316               << ((*i)->p().active() ? " A\n" : "\n");
00317       debug << deindent
00318             << '}' << std::endl << down(2);
00319 # endif // !DEBUG
00320 
00321       while (!ioevent_set_.empty()) {
00322         IOEvent*        e = *ioevent_set_.begin();
00323 
00324         if (!e->p().active())
00325           break;
00326 
00327         current_event_ = e;
00328         ioevent_set_.erase(ioevent_set_.begin());
00329 
00330         delete_ = false;
00331         debug << up << "Handling IOEvent " << e->name()
00332               << ' ' << e << std::endl << down;
00333         e->handle();
00334         if (delete_)
00335           delete e;
00336         current_event_ = 0;
00337       }
00338 
00339 # ifdef DEBUG
00340       debug << up(2) << "IOEvents after {\n" << indent;
00341       for (ioeventset_t::iterator i = ioevent_set_.begin();
00342            i != ioevent_set_.end(); ++i)
00343         debug << (*i)->name() << ' ' << *i << ' '
00344               << ((*i)->p().active() ? " A\n" : "\n");
00345       debug << deindent
00346             << '}' << std::endl << down(2);
00347 # endif // !DEBUG
00348 
00349     }
00350 
00351     // The main scheduler event loop
00352     void
00353     Scheduler::loop() {
00354 
00355 //       sys::InterfaceInfo     info;
00356 
00357       // The loop /per se/
00358       while (true) {
00359 
00360         // Some profiling declarations
00361         ::tms   t;
00362         if (do_dump_prof)
00363           ::times(&t);
00364 
00365         if (tevent_set_.empty())
00366           IOEvent::p_t::poll(ioevent_set_);
00367         else if ((*tevent_set_.begin())->next().is_past())
00368           IOEvent::p_t::poll(ioevent_set_, 0);
00369         else
00370           IOEvent::p_t::poll(ioevent_set_, ((*tevent_set_.begin())->next() -
00371                                             timeval_t::now()).poll_time());
00372 
00373         // Synchronize local clock.
00374         timeval_t::set_now();
00375         // Handle all the events.
00376         handle_ioevents();
00377         handle_tevents();
00378 
00379         if (loophandler_())
00380           break;
00381 
00382         // Spit out profiling info if requested.
00383         if (do_dump_prof) {
00384           ::tms nt;
00385           ::times(&nt);
00386 
00387           dump_prof << "Seconds spent computing: ";
00388           dump_prof.precision(3);
00389           dump_prof.flags(std::ios::fixed);
00390           if (nt.tms_utime >= t.tms_utime)
00391             dump_prof << (float) (nt.tms_utime - t.tms_utime) /
00392               sysconf(_SC_CLK_TCK)
00393                       << std::endl;
00394           else
00395             dump_prof << (float) (LONG_MAX - nt.tms_utime + t.tms_utime) /
00396               sysconf(_SC_CLK_TCK)
00397                       << std::endl;
00398         }
00399       }
00400 
00401     }
00402 
00403     // The sighandler for termination
00404     void term_handler(int)
00405     {
00406       terminate_now.set_mark();
00407     }
00408 
00409     void int_handler(int)
00410     {
00411       terminate_now.set_mark();
00412     }
00413 
00414     void quit_handler(int)
00415     {
00416       ::signal(SIGQUIT, SIG_DFL);
00417       ::raise(SIGQUIT);
00418     }
00419 
00420   } // namespace sch
00421 
00422 } // namespace olsr
00423 
00424 #endif // ! QOLYESTER_SCH_SCHEDULER_HXX

Generated on Mon Sep 4 00:02:16 2006 for Qolyester daemon by  doxygen 1.4.6