4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 // Stefan Bund <g0dil@berlios.de>
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 \brief TimerDispatcher non-inline non-template implementation */
26 #include "TimerDispatcher.hh"
27 //#include "TimerDispatcher.ih"
31 //#include "TimerDispatcher.mpp"
33 ///////////////////////////////cc.p////////////////////////////////////////
35 unsigned senf::scheduler::TimerDispatcher::useCount_ (0);
37 prefix_ senf::scheduler::TimerDispatcher::TimerDispatcher(FdManager & manager,
39 : manager_ (manager), runner_ (runner), lastId_ (0), blocked_ (true)
41 if (pipe(timerPipe_) < 0)
42 SENF_THROW_SYSTEM_EXCEPTION("pipe()");
43 manager_.set(timerPipe_[0], FdManager::EV_READ, this);
45 sigemptyset(&sigSet_);
46 sigaddset(&sigSet_, SIGALRM);
47 sigprocmask(SIG_BLOCK, &sigSet_, 0);
51 act.sa_sigaction = &sigHandler;
52 act.sa_mask = sigSet_;
53 act.sa_flags = SA_SIGINFO | SA_RESTART;
54 if (sigaction(SIGALRM, &act, 0) < 0)
55 SENF_THROW_SYSTEM_EXCEPTION("sigaction()");
59 ::memset(&ev, 0, sizeof(ev));
60 ev.sigev_notify = SIGEV_SIGNAL;
61 ev.sigev_signo = SIGALRM;
62 ev.sigev_value.sival_ptr = this;
63 if (timer_create(CLOCK_MONOTONIC, &ev, &timerId_) < 0)
64 SENF_THROW_SYSTEM_EXCEPTION("timer_create()");
69 prefix_ senf::scheduler::TimerDispatcher::~TimerDispatcher()
73 TimerMap::iterator i (timers_.begin());
74 TimerMap::iterator const i_end (timers_.end());
75 for (; i != i_end; ++i)
76 runner_.dequeue(&(i->second));
78 timer_delete(timerId_);
80 ::signal(SIGALRM, SIG_IGN);
81 sigprocmask(SIG_UNBLOCK, &sigSet_, 0);
82 manager_.remove(timerPipe_[0]);
87 prefix_ senf::scheduler::TimerDispatcher::timer_id
88 senf::scheduler::TimerDispatcher::add(std::string const & name,
89 ClockService::clock_type timeout, Callback const & cb)
91 while (timerIdIndex_.find(++lastId_) != timerIdIndex_.end()) ;
92 TimerMap::iterator i (
93 timers_.insert(std::make_pair(timeout, TimerEvent(lastId_, cb, *this, name))));
94 timerIdIndex_.insert(std::make_pair(lastId_, i));
95 runner_.enqueue(&(i->second));
101 prefix_ void senf::scheduler::TimerDispatcher::remove(timer_id id)
103 TimerIdMap::iterator i (timerIdIndex_.find(id));
104 if (i == timerIdIndex_.end())
106 runner_.dequeue(&(i->second->second));
107 timers_.erase(i->second);
108 timerIdIndex_.erase(i);
113 prefix_ void senf::scheduler::TimerDispatcher::blockSignals()
117 sigprocmask(SIG_BLOCK, &sigSet_, 0);
121 prefix_ void senf::scheduler::TimerDispatcher::unblockSignals()
126 sigprocmask(SIG_UNBLOCK, &sigSet_, 0);
130 prefix_ void senf::scheduler::TimerDispatcher::signal(int events)
133 if (read(timerPipe_[0], &info, sizeof(info)) < int(sizeof(info)))
136 TimerMap::iterator i (timers_.begin());
137 TimerMap::iterator const i_end (timers_.end());
138 ClockService::clock_type now (manager_.eventTime());
139 for (; i != i_end && i->first <= now ; ++i)
140 i->second.runnable = true;
143 prefix_ void senf::scheduler::TimerDispatcher::sigHandler(int signal, ::siginfo_t * siginfo,
146 // The manpage says, si_signo is unused in linux so we set it here
147 siginfo->si_signo = signal;
148 // We can't do much on error anyway so we ignore errors here
149 if (siginfo->si_value.sival_ptr == 0)
151 write(static_cast<TimerDispatcher*>(siginfo->si_value.sival_ptr)->timerPipe_[1],
152 siginfo, sizeof(*siginfo));
155 prefix_ void senf::scheduler::TimerDispatcher::reschedule()
157 struct itimerspec timer;
158 memset(&timer, 0, sizeof(timer));
159 timer.it_interval.tv_sec = 0;
160 timer.it_interval.tv_nsec = 0;
161 if (timers_.empty()) {
162 SENF_LOG( (senf::log::VERBOSE)("Timer disabled") );
163 timer.it_value.tv_sec = 0;
164 timer.it_value.tv_nsec = 0;
167 ClockService::clock_type next (timers_.begin()->first);
170 timer.it_value.tv_sec = ClockService::in_seconds(next);
171 timer.it_value.tv_nsec = ClockService::in_nanoseconds(
172 next - ClockService::seconds(timer.it_value.tv_sec));
173 SENF_LOG( (senf::log::VERBOSE)("Next timeout scheduled @" << timer.it_value.tv_sec << "."
174 << std::setw(9) << std::setfill('0') << timer.it_value.tv_nsec) );
176 if (timer_settime(timerId_, TIMER_ABSTIME, &timer, 0)<0)
177 SENF_THROW_SYSTEM_EXCEPTION("timer_settime()");
180 ///////////////////////////////////////////////////////////////////////////
181 // senf::scheduler::TimerDispatcher::TimerEvent
183 prefix_ void senf::scheduler::TimerDispatcher::TimerEvent::run()
185 Callback savedCb (cb);
186 dispatcher.remove(id);
187 // The member is now running WITHOUT AN OBJECT ... that has been destroyed above !!!!!! On the
188 // other hand, if we do things the other way round, we have no idea, whether the callback might
189 // explicitly remove us and we have the same problem then ...
193 ///////////////////////////////cc.e////////////////////////////////////////
195 //#include "TimerDispatcher.mpp"
201 // comment-column: 40
202 // c-file-style: "senf"
203 // indent-tabs-mode: nil
204 // ispell-local-dictionary: "american"
205 // compile-command: "scons -u test"