7c3278bd85632ee409e05ed4feb1c0b5418a21fb
[senf.git] / Scheduler / TimerEvent.cc
1 // $Id$
2 //
3 // Copyright (C) 2008 
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 //     Stefan Bund <g0dil@berlios.de>
7 //
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.
12 //
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.
17 //
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.
22
23 /** \file
24     \brief TimerDispatcher non-inline non-template implementation */
25
26 #include "TimerEvent.hh"
27 #include "TimerEvent.ih"
28
29 // Custom includes
30
31 //#include "TimerEvent.mpp"
32 #define prefix_
33 ///////////////////////////////cc.p////////////////////////////////////////
34
35 prefix_ senf::scheduler::detail::TimerDispatcher::TimerDispatcher()
36     : blocked_ (true)
37 {
38     if (pipe(timerPipe_) < 0)
39         SENF_THROW_SYSTEM_EXCEPTION("pipe()");
40     senf::scheduler::FdManager::instance().set(timerPipe_[0], FdManager::EV_READ, this);
41
42     sigemptyset(&sigSet_);
43     sigaddset(&sigSet_, SIGALRM);
44     sigprocmask(SIG_BLOCK, &sigSet_, 0);
45
46     struct sigaction act;
47     act.sa_sigaction = &sigHandler;
48     act.sa_mask = sigSet_;
49     act.sa_flags = SA_SIGINFO | SA_RESTART;
50     if (sigaction(SIGALRM, &act, 0) < 0)
51         SENF_THROW_SYSTEM_EXCEPTION("sigaction()");
52
53     struct sigevent ev;
54     ::memset(&ev, 0, sizeof(ev));
55     ev.sigev_notify = SIGEV_SIGNAL;
56     ev.sigev_signo = SIGALRM;
57     ev.sigev_value.sival_ptr = this;
58     if (timer_create(CLOCK_MONOTONIC, &ev, &timerId_) < 0)
59         SENF_THROW_SYSTEM_EXCEPTION("timer_create()");
60 }
61
62 prefix_ senf::scheduler::detail::TimerDispatcher::~TimerDispatcher()
63 {
64     TimerSet::iterator i (timers_.begin());
65     TimerSet::iterator const i_end (timers_.end());
66     for (; i != i_end; ++i)
67         senf::scheduler::FIFORunner::instance().dequeue(&(*i));
68
69     timer_delete(timerId_);
70     ::signal(SIGALRM, SIG_IGN);
71     sigprocmask(SIG_UNBLOCK, &sigSet_, 0);
72     senf::scheduler::FdManager::instance().remove(timerPipe_[0]);
73     close(timerPipe_[0]);
74     close(timerPipe_[1]);
75 }
76
77 void senf::scheduler::detail::TimerDispatcher::add(TimerEvent & event)
78 {
79     TimerSet::iterator i (timers_.insert(event));
80     senf::scheduler::FIFORunner::instance().enqueue(&(*i));
81     if (! blocked_)
82         reschedule();
83 }
84
85 prefix_ void senf::scheduler::detail::TimerDispatcher::remove(TimerEvent & event)
86 {
87     TimerSet::iterator i (TimerSet::current(event));
88     if (i == timers_.end())
89         return;
90     senf::scheduler::FIFORunner::instance().dequeue(&(*i));
91     timers_.erase(i);
92     if (! blocked_)
93         reschedule();
94 }
95
96 prefix_ void senf::scheduler::detail::TimerDispatcher::blockSignals()
97 {
98     if (blocked_) 
99         return;
100     sigprocmask(SIG_BLOCK, &sigSet_, 0);
101     blocked_ = true;
102 }
103
104 prefix_ void senf::scheduler::detail::TimerDispatcher::unblockSignals()
105 {
106     if (! blocked_)
107         return;
108     reschedule();
109     sigprocmask(SIG_UNBLOCK, &sigSet_, 0);
110     blocked_ = false;
111 }
112
113 prefix_ void senf::scheduler::detail::TimerDispatcher::signal(int events)
114 {
115     siginfo_t info;
116     if (read(timerPipe_[0], &info, sizeof(info)) < int(sizeof(info)))
117         return;
118     TimerSet::iterator i (timers_.begin());
119     TimerSet::iterator const i_end (timers_.end());
120     ClockService::clock_type now (senf::scheduler::FdManager::instance().eventTime());
121     for (; i != i_end && i->timeout_ <= now ; ++i)
122         i->setRunnable();
123 }
124
125 prefix_ void senf::scheduler::detail::TimerDispatcher::sigHandler(int signal, 
126                                                                   ::siginfo_t * siginfo,
127                                                                   void *)
128 {
129     // The manpage says, si_signo is unused in linux so we set it here
130     siginfo->si_signo = signal; 
131     // We can't do much on error anyway so we ignore errors here
132     if (siginfo->si_value.sival_ptr == 0)
133         return;
134     write(static_cast<TimerDispatcher*>(siginfo->si_value.sival_ptr)->timerPipe_[1], 
135           siginfo, sizeof(*siginfo));
136 }
137
138 prefix_ void senf::scheduler::detail::TimerDispatcher::reschedule()
139 {
140     struct itimerspec timer;
141     memset(&timer, 0, sizeof(timer));
142     timer.it_interval.tv_sec = 0;
143     timer.it_interval.tv_nsec = 0;
144     if (timers_.empty()) {
145         SENF_LOG( (senf::log::VERBOSE)("Timer disabled") );
146         timer.it_value.tv_sec = 0;
147         timer.it_value.tv_nsec = 0;
148     }
149     else {
150         ClockService::clock_type next (timers_.begin()->timeout_);
151         if (next <= 0)
152             next = 1;
153         timer.it_value.tv_sec = ClockService::in_seconds(next);
154         timer.it_value.tv_nsec = ClockService::in_nanoseconds(
155             next - ClockService::seconds(timer.it_value.tv_sec));
156         SENF_LOG( (senf::log::VERBOSE)("Next timeout scheduled @" << timer.it_value.tv_sec << "." 
157                    << std::setw(9) << std::setfill('0') << timer.it_value.tv_nsec) );
158     }
159     if (timer_settime(timerId_, TIMER_ABSTIME, &timer, 0)<0)
160         SENF_THROW_SYSTEM_EXCEPTION("timer_settime()");
161 }
162
163 ///////////////////////////////////////////////////////////////////////////
164 // senf::scheduler::detail::TimerDispatcher::TimerEvent
165
166 prefix_ void senf::scheduler::TimerEvent::run()
167 {
168     disable();
169     cb_();
170 }
171
172 ///////////////////////////////cc.e////////////////////////////////////////
173 #undef prefix_
174 //#include "TimerEvent.mpp"
175
176 \f
177 // Local Variables:
178 // mode: c++
179 // fill-column: 100
180 // comment-column: 40
181 // c-file-style: "senf"
182 // indent-tabs-mode: nil
183 // ispell-local-dictionary: "american"
184 // compile-command: "scons -u test"
185 // End: