Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

scheduler.hxx

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

Generated on Thu Jul 28 21:21:48 2005 for Qolyester daemon by  doxygen 1.4.1