Search:

SENF Extensible Network Framework

  • Home
  • Download
  • Wiki
  • BerliOS
  • ChangeLog
  • Browse SVN
  • Bug Tracker
  • Overview
  • Examples
  • HowTos
  • Glossary
  • PPI
  • Packets
  • Scheduler
  • Socket
  • Utils
  • Console
  • Daemon
  • Logger
  • Termlib
  • Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

TimerSource.cc

Go to the documentation of this file.
00001 // $Id: TimerSource.cc 1772 2011-03-10 12:45:21Z tho $
00002 //
00003 // Copyright (C) 2009
00004 // Fraunhofer (FOKUS)
00005 // Competence Center NETwork research (NET), St. Augustin, GERMANY
00006 //     Stefan Bund <g0dil@berlios.de>
00007 //
00008 // This program is free software; you can redistribute it and/or modify
00009 // it under the terms of the GNU General Public License as published by
00010 // the Free Software Foundation; either version 2 of the License, or
00011 // (at your option) any later version.
00012 //
00013 // This program is distributed in the hope that it will be useful,
00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 // GNU General Public License for more details.
00017 //
00018 // You should have received a copy of the GNU General Public License
00019 // along with this program; if not, write to the
00020 // Free Software Foundation, Inc.,
00021 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00022 
00026 #include "TimerSource.hh"
00027 //#include "TimerSource.ih"
00028 
00029 // Custom includes
00030 #include "IdleEvent.hh"
00031 #ifdef HAVE_TIMERFD_CREATE
00032 #include TIMERFD_H_PATH
00033 #endif
00034 #include "senf/Utils/IgnoreValue.hh"
00035 
00036 //#include "TimerSource.mpp"
00037 #define prefix_
00038 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00039 
00040 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00041 // senf::scheduler::detail::TimerSource
00042 
00043 prefix_ senf::scheduler::detail::TimerSource::~TimerSource()
00044 {}
00045 
00046 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00047 // senf::scheduler::detail::POSIXTimerSource
00048 
00049 prefix_ senf::scheduler::detail::POSIXTimerSource::POSIXTimerSource()
00050     : timeoutEnabled_ (false), timeout_ (0), signalEnabled_ (false)
00051 {
00052     if (pipe(timerPipe_) < 0)
00053         SENF_THROW_SYSTEM_EXCEPTION("pipe()");
00054     FdManager::instance().set( timerPipe_[0], FdManager::EV_READ, this);
00055 
00056     sigemptyset(&sigSet_);
00057     sigaddset(&sigSet_, SIGALRM);
00058     sigprocmask(SIG_BLOCK, &sigSet_, 0);
00059 
00060     struct sigaction act;
00061     act.sa_sigaction = &sigHandler;
00062     act.sa_mask = sigSet_;
00063     act.sa_flags = SA_SIGINFO | SA_RESTART;
00064     if (sigaction(SIGALRM, &act, 0) < 0)
00065         SENF_THROW_SYSTEM_EXCEPTION("sigaction()");
00066 
00067     struct sigevent ev;
00068     ::memset(&ev, 0, sizeof(ev));
00069     ev.sigev_notify = SIGEV_SIGNAL;
00070     ev.sigev_signo = SIGALRM;
00071     ev.sigev_value.sival_ptr = this;
00072     if (timer_create(CLOCK_MONOTONIC, &ev, &timerId_) < 0)
00073         SENF_THROW_SYSTEM_EXCEPTION("timer_create()");
00074 }
00075 
00076 prefix_ senf::scheduler::detail::POSIXTimerSource::~POSIXTimerSource()
00077 {
00078     timer_delete(timerId_);
00079     ::signal(SIGALRM, SIG_IGN);
00080     sigprocmask(SIG_UNBLOCK, &sigSet_, 0);
00081     FdManager::instance().remove(timerPipe_[0]);
00082     close(timerPipe_[0]);
00083     close(timerPipe_[1]);
00084 }
00085 
00086 prefix_ void
00087 senf::scheduler::detail::POSIXTimerSource::timeout(ClockService::clock_type timeout)
00088 {
00089     if (! timeoutEnabled_ || timeout_ != timeout) {
00090         timeout_ = timeout;
00091         if (timeout_ <= 0)
00092             timeout_ = 1;
00093         timeoutEnabled_ = true;
00094         reschedule();
00095     }
00096 }
00097 
00098 prefix_ void senf::scheduler::detail::POSIXTimerSource::notimeout()
00099 {
00100     if (timeoutEnabled_) {
00101         timeoutEnabled_ = false;
00102         reschedule();
00103     }
00104 }
00105 
00106 prefix_ void senf::scheduler::detail::POSIXTimerSource::enable()
00107 {
00108     if (! signalEnabled_) {
00109         signalEnabled_ = true;
00110         sigprocmask(SIG_UNBLOCK, &sigSet_, 0);
00111     }
00112 }
00113 
00114 prefix_ void senf::scheduler::detail::POSIXTimerSource::disable()
00115 {
00116     if (signalEnabled_) {
00117         signalEnabled_ = false;
00118         sigprocmask(SIG_BLOCK, &sigSet_, 0);
00119     }
00120 }
00121 
00122 prefix_ void senf::scheduler::detail::POSIXTimerSource::sigHandler(int,
00123                                                                    ::siginfo_t * siginfo,
00124                                                                    void *)
00125 {
00126     if (siginfo->si_value.sival_ptr == 0)
00127         return;
00128     static char data = '\xD0';
00129     // If the write fails there's not much we can do anyways ...
00130     senf::IGNORE( write(static_cast<POSIXTimerSource*>(siginfo->si_value.sival_ptr)->timerPipe_[1],
00131                         &data, sizeof(data)) );
00132 }
00133 
00134 prefix_ void senf::scheduler::detail::POSIXTimerSource::signal(int events)
00135 {
00136     char data;
00137     // This should never fail since we are reading a single character from a signaled
00138     // filedescriptor
00139     senf::IGNORE( read(timerPipe_[0], &data, sizeof(data)) );
00140     timeoutEnabled_ = false;
00141 }
00142 
00143 prefix_ void senf::scheduler::detail::POSIXTimerSource::reschedule()
00144 {
00145     struct itimerspec timer;
00146     memset(&timer, 0, sizeof(timer));
00147     if (timeoutEnabled_) {
00148         timer.it_value.tv_sec = ClockService::in_seconds(timeout_);
00149         timer.it_value.tv_nsec = ClockService::in_nanoseconds(
00150             timeout_ - ClockService::seconds(timer.it_value.tv_sec));
00151     }
00152     if (timer_settime(timerId_, TIMER_ABSTIME, &timer, 0)<0)
00153         SENF_THROW_SYSTEM_EXCEPTION("timer_settime()");
00154 }
00155 
00156 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00157 // senf::scheduler::detail::PollTimerSource
00158 
00159 prefix_ void senf::scheduler::detail::PollTimerSource::timeout(ClockService::clock_type timeout)
00160 {
00161     ClockService::clock_type now (ClockService::now());
00162     int delay (ClockService::in_milliseconds(timeout-now)+1);
00163     IdleEventDispatcher::instance().timeout(delay<0?0:delay);
00164 }
00165 
00166 prefix_ void senf::scheduler::detail::PollTimerSource::notimeout()
00167 {
00168     IdleEventDispatcher::instance().timeout(-1);
00169 }
00170 
00171 prefix_ void senf::scheduler::detail::PollTimerSource::enable()
00172 {}
00173 
00174 prefix_ void senf::scheduler::detail::PollTimerSource::disable()
00175 {}
00176 
00177 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00178 // senf::scheduler::detail::TimerFDTimerSource
00179 
00180 #ifdef HAVE_TIMERFD_CREATE
00181 prefix_ senf::scheduler::detail::TimerFDTimerSource::TimerFDTimerSource()
00182     : timerfd_ (-1), timeoutEnabled_ (false), timeout_ (0)
00183 {
00184     timerfd_ = timerfd_create(CLOCK_MONOTONIC, 0);
00185     if (timerfd_ < 0)
00186         SENF_THROW_SYSTEM_EXCEPTION("timerfd_create()");
00187     FdManager::instance().set( timerfd_, FdManager::EV_READ, this);
00188 }
00189 
00190 prefix_ senf::scheduler::detail::TimerFDTimerSource::~TimerFDTimerSource()
00191 {
00192     FdManager::instance().remove(timerfd_);
00193     close(timerfd_);
00194 }
00195 
00196 prefix_ void
00197 senf::scheduler::detail::TimerFDTimerSource::timeout(ClockService::clock_type timeout)
00198 {
00199     if (!timeoutEnabled_ || timeout_ != timeout) {
00200         timeout_ = timeout;
00201         if (timeout_ <= 0)
00202             timeout_ = 1;
00203         timeoutEnabled_ = true;
00204         reschedule();
00205     }
00206 }
00207 
00208 prefix_ void senf::scheduler::detail::TimerFDTimerSource::notimeout()
00209 {
00210     if (timeoutEnabled_) {
00211         timeoutEnabled_ = false;
00212         reschedule();
00213     }
00214 }
00215 
00216 prefix_ void senf::scheduler::detail::TimerFDTimerSource::enable()
00217 {}
00218 
00219 prefix_ void senf::scheduler::detail::TimerFDTimerSource::disable()
00220 {}
00221 
00222 namespace {
00223 
00224     struct TimerFdCheck
00225     {
00226         TimerFdCheck();
00227         bool timerFdOk;
00228     };
00229 
00230     TimerFdCheck::TimerFdCheck()
00231         : timerFdOk (false)
00232     {
00233         int fd (timerfd_create(CLOCK_MONOTONIC, 0));
00234         if (fd == -1) {
00235             if (errno != EINVAL)
00236                 SENF_THROW_SYSTEM_EXCEPTION("timerfd_create()");
00237         }
00238         else {
00239             timerFdOk = true;
00240             close(fd);
00241         }
00242     }
00243 
00244 }
00245 prefix_ bool senf::scheduler::detail::TimerFDTimerSource::haveTimerFD()
00246 {
00247     static TimerFdCheck check;
00248     return check.timerFdOk;
00249 }
00250 
00251 prefix_ void senf::scheduler::detail::TimerFDTimerSource::signal(int events)
00252 {
00253     uint64_t expirations (0);
00254     // We ignore the return value since we ignore the value read anyways
00255     senf::IGNORE( read(timerfd_, &expirations, sizeof(expirations)) );
00256 }
00257 
00258 prefix_ void senf::scheduler::detail::TimerFDTimerSource::reschedule()
00259 {
00260     struct itimerspec timer;
00261     memset(&timer, 0, sizeof(timer));
00262     if (timeoutEnabled_) {
00263         timer.it_value.tv_sec = ClockService::in_seconds(timeout_);
00264         timer.it_value.tv_nsec = ClockService::in_nanoseconds(
00265             timeout_ - ClockService::seconds(timer.it_value.tv_sec));
00266     }
00267     if (timerfd_settime(timerfd_, TFD_TIMER_ABSTIME, &timer, 0)<0)
00268         SENF_THROW_SYSTEM_EXCEPTION("timerfd_settime()");
00269 }
00270 #endif
00271 
00272 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00273 #undef prefix_
00274 //#include "TimerSource.mpp"
00275 
00276 
00277 // Local Variables:
00278 // mode: c++
00279 // fill-column: 100
00280 // comment-column: 40
00281 // c-file-style: "senf"
00282 // indent-tabs-mode: nil
00283 // ispell-local-dictionary: "american"
00284 // compile-command: "scons -u test"
00285 // End:

Contact: senf-dev@lists.berlios.de | © 2006-2010 Fraunhofer Institute for Open Communication Systems, Network Research