Added additional operators to RestrictedInt and made
[senf.git] / senf / Scheduler / TimerSource.cc
1 // $Id$
2 //
3 // Copyright (C) 2009
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 //
6 // The contents of this file are subject to the Fraunhofer FOKUS Public License
7 // Version 1.0 (the "License"); you may not use this file except in compliance
8 // with the License. You may obtain a copy of the License at 
9 // http://senf.berlios.de/license.html
10 //
11 // The Fraunhofer FOKUS Public License Version 1.0 is based on, 
12 // but modifies the Mozilla Public License Version 1.1.
13 // See the full license text for the amendments.
14 //
15 // Software distributed under the License is distributed on an "AS IS" basis, 
16 // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
17 // for the specific language governing rights and limitations under the License.
18 //
19 // The Original Code is Fraunhofer FOKUS code.
20 //
21 // The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V. 
22 // (registered association), Hansastraße 27 c, 80686 Munich, Germany.
23 // All Rights Reserved.
24 //
25 // Contributor(s):
26 //   Stefan Bund <g0dil@berlios.de>
27
28 /** \file
29     \brief TimerSource non-inline non-template implementation */
30
31 #include "TimerSource.hh"
32 //#include "TimerSource.ih"
33
34 // Custom includes
35 #include "IdleEvent.hh"
36 #ifdef HAVE_TIMERFD_CREATE
37 #include TIMERFD_H_PATH
38 #endif
39 #include "senf/Utils/IgnoreValue.hh"
40 #include <senf/Utils/ClockTypeMacros.hh>
41
42 //#include "TimerSource.mpp"
43 #define prefix_
44 //-/////////////////////////////////////////////////////////////////////////////////////////////////
45
46 //-/////////////////////////////////////////////////////////////////////////////////////////////////
47 // senf::scheduler::detail::TimerSource
48
49 prefix_ senf::scheduler::detail::TimerSource::~TimerSource()
50 {}
51
52 //-/////////////////////////////////////////////////////////////////////////////////////////////////
53 // senf::scheduler::detail::POSIXTimerSource
54
55 prefix_ senf::scheduler::detail::POSIXTimerSource::POSIXTimerSource()
56     : timeoutEnabled_ (false), timeout_ (0), signalEnabled_ (false)
57 {
58     if (pipe(timerPipe_) < 0)
59         SENF_THROW_SYSTEM_EXCEPTION("pipe()");
60     FdManager::instance().set( timerPipe_[0], FdManager::EV_READ, this);
61
62     sigemptyset(&sigSet_);
63     sigaddset(&sigSet_, SIGALRM);
64     sigprocmask(SIG_BLOCK, &sigSet_, 0);
65
66     struct sigaction act;
67     act.sa_sigaction = &sigHandler;
68     act.sa_mask = sigSet_;
69     act.sa_flags = SA_SIGINFO | SA_RESTART;
70     if (sigaction(SIGALRM, &act, 0) < 0)
71         SENF_THROW_SYSTEM_EXCEPTION("sigaction()");
72
73     struct sigevent ev;
74     ::memset(&ev, 0, sizeof(ev));
75     ev.sigev_notify = SIGEV_SIGNAL;
76     ev.sigev_signo = SIGALRM;
77     ev.sigev_value.sival_ptr = this;
78     if (timer_create(CLOCK_MONOTONIC, &ev, &timerId_) < 0)
79         SENF_THROW_SYSTEM_EXCEPTION("timer_create()");
80 }
81
82 prefix_ senf::scheduler::detail::POSIXTimerSource::~POSIXTimerSource()
83 {
84     timer_delete(timerId_);
85     ::signal(SIGALRM, SIG_IGN);
86     sigprocmask(SIG_UNBLOCK, &sigSet_, 0);
87     FdManager::instance().remove(timerPipe_[0]);
88     close(timerPipe_[0]);
89     close(timerPipe_[1]);
90 }
91
92 prefix_ void
93 senf::scheduler::detail::POSIXTimerSource::timeout(ClockService::clock_type timeout)
94 {
95     if (! timeoutEnabled_ || timeout_ != timeout) {
96         timeout_ = timeout;
97         if (SENF_CLOCKTYPEVAL(timeout_) <= 0)
98             timeout_ = SENF_INT2CLOCKTYPE(1);
99         timeoutEnabled_ = true;
100         reschedule();
101     }
102 }
103
104 prefix_ void senf::scheduler::detail::POSIXTimerSource::notimeout()
105 {
106     if (timeoutEnabled_) {
107         timeoutEnabled_ = false;
108         reschedule();
109     }
110 }
111
112 prefix_ void senf::scheduler::detail::POSIXTimerSource::enable()
113 {
114     if (! signalEnabled_) {
115         signalEnabled_ = true;
116         sigprocmask(SIG_UNBLOCK, &sigSet_, 0);
117     }
118 }
119
120 prefix_ void senf::scheduler::detail::POSIXTimerSource::disable()
121 {
122     if (signalEnabled_) {
123         signalEnabled_ = false;
124         sigprocmask(SIG_BLOCK, &sigSet_, 0);
125     }
126 }
127
128 prefix_ void senf::scheduler::detail::POSIXTimerSource::sigHandler(int,
129                                                                    ::siginfo_t * siginfo,
130                                                                    void *)
131 {
132     if (siginfo->si_value.sival_ptr == 0)
133         return;
134     static char data = '\xD0';
135     // If the write fails there's not much we can do anyways ...
136     senf::IGNORE( write(static_cast<POSIXTimerSource*>(siginfo->si_value.sival_ptr)->timerPipe_[1],
137                         &data, sizeof(data)) );
138 }
139
140 prefix_ void senf::scheduler::detail::POSIXTimerSource::signal(int events)
141 {
142     char data;
143     // This should never fail since we are reading a single character from a signaled
144     // filedescriptor
145     senf::IGNORE( read(timerPipe_[0], &data, sizeof(data)) );
146     timeoutEnabled_ = false;
147 }
148
149 prefix_ void senf::scheduler::detail::POSIXTimerSource::reschedule()
150 {
151     struct itimerspec timer;
152     memset(&timer, 0, sizeof(timer));
153     if (timeoutEnabled_) {
154         timer.it_value.tv_sec = ClockService::in_seconds(timeout_);
155         timer.it_value.tv_nsec = ClockService::in_nanoseconds(
156             timeout_ - ClockService::seconds(timer.it_value.tv_sec));
157     }
158     if (timer_settime(timerId_, TIMER_ABSTIME, &timer, 0)<0)
159         SENF_THROW_SYSTEM_EXCEPTION("timer_settime()");
160 }
161
162 //-/////////////////////////////////////////////////////////////////////////////////////////////////
163 // senf::scheduler::detail::PollTimerSource
164
165 prefix_ void senf::scheduler::detail::PollTimerSource::timeout(ClockService::clock_type timeout)
166 {
167     ClockService::clock_type now (ClockService::now());
168     int delay (ClockService::in_milliseconds(timeout-now)+1);
169     IdleEventDispatcher::instance().timeout(delay<0?0:delay);
170 }
171
172 prefix_ void senf::scheduler::detail::PollTimerSource::notimeout()
173 {
174     IdleEventDispatcher::instance().timeout(-1);
175 }
176
177 prefix_ void senf::scheduler::detail::PollTimerSource::enable()
178 {}
179
180 prefix_ void senf::scheduler::detail::PollTimerSource::disable()
181 {}
182
183 //-/////////////////////////////////////////////////////////////////////////////////////////////////
184 // senf::scheduler::detail::TimerFDTimerSource
185
186 #ifdef HAVE_TIMERFD_CREATE
187 prefix_ senf::scheduler::detail::TimerFDTimerSource::TimerFDTimerSource()
188     : timerfd_ (-1), timeoutEnabled_ (false), timeout_ (0)
189 {
190     timerfd_ = timerfd_create(CLOCK_MONOTONIC, 0);
191     if (timerfd_ < 0)
192         SENF_THROW_SYSTEM_EXCEPTION("timerfd_create()");
193     FdManager::instance().set( timerfd_, FdManager::EV_READ, this);
194 }
195
196 prefix_ senf::scheduler::detail::TimerFDTimerSource::~TimerFDTimerSource()
197 {
198     FdManager::instance().remove(timerfd_);
199     close(timerfd_);
200 }
201
202 prefix_ void
203 senf::scheduler::detail::TimerFDTimerSource::timeout(ClockService::clock_type timeout)
204 {
205     if (!timeoutEnabled_ || timeout_ != timeout) {
206         timeout_ = timeout;
207         if (SENF_CLOCKTYPEVAL(timeout_) <= 0)
208             timeout_ = SENF_INT2CLOCKTYPE(1);
209         timeoutEnabled_ = true;
210         reschedule();
211     }
212 }
213
214 prefix_ void senf::scheduler::detail::TimerFDTimerSource::notimeout()
215 {
216     if (timeoutEnabled_) {
217         timeoutEnabled_ = false;
218         reschedule();
219     }
220 }
221
222 prefix_ void senf::scheduler::detail::TimerFDTimerSource::enable()
223 {}
224
225 prefix_ void senf::scheduler::detail::TimerFDTimerSource::disable()
226 {}
227
228 namespace {
229
230     struct TimerFdCheck
231     {
232         TimerFdCheck();
233         bool timerFdOk;
234     };
235
236     TimerFdCheck::TimerFdCheck()
237         : timerFdOk (false)
238     {
239         int fd (timerfd_create(CLOCK_MONOTONIC, 0));
240         if (fd == -1) {
241             if (errno != EINVAL)
242                 SENF_THROW_SYSTEM_EXCEPTION("timerfd_create()");
243         }
244         else {
245             timerFdOk = true;
246             close(fd);
247         }
248     }
249
250 }
251 prefix_ bool senf::scheduler::detail::TimerFDTimerSource::haveTimerFD()
252 {
253     static TimerFdCheck check;
254     return check.timerFdOk;
255 }
256
257 prefix_ void senf::scheduler::detail::TimerFDTimerSource::signal(int events)
258 {
259     uint64_t expirations (0);
260     // We ignore the return value since we ignore the value read anyways
261     senf::IGNORE( read(timerfd_, &expirations, sizeof(expirations)) );
262 }
263
264 prefix_ void senf::scheduler::detail::TimerFDTimerSource::reschedule()
265 {
266     struct itimerspec timer;
267     memset(&timer, 0, sizeof(timer));
268     if (timeoutEnabled_) {
269         timer.it_value.tv_sec = ClockService::in_seconds(timeout_);
270         timer.it_value.tv_nsec = ClockService::in_nanoseconds(
271             timeout_ - ClockService::seconds(timer.it_value.tv_sec));
272     }
273     if (timerfd_settime(timerfd_, TFD_TIMER_ABSTIME, &timer, 0)<0)
274         SENF_THROW_SYSTEM_EXCEPTION("timerfd_settime()");
275 }
276 #endif
277
278 //-/////////////////////////////////////////////////////////////////////////////////////////////////
279 #undef prefix_
280 //#include "TimerSource.mpp"
281
282
283 // Local Variables:
284 // mode: c++
285 // fill-column: 100
286 // comment-column: 40
287 // c-file-style: "senf"
288 // indent-tabs-mode: nil
289 // ispell-local-dictionary: "american"
290 // compile-command: "scons -u test"
291 // End: