TimerSource.cc
Go to the documentation of this file.
1 //
2 // Copyright (c) 2020 Fraunhofer Institute for Applied Information Technology (FIT)
3 // Network Research Group (NET)
4 // Schloss Birlinghoven, 53754 Sankt Augustin, GERMANY
5 // Contact: support@wiback.org
6 //
7 // This file is part of the SENF code tree.
8 // It is licensed under the 3-clause BSD License (aka New BSD License).
9 // See LICENSE.txt in the top level directory for details or visit
10 // https://opensource.org/licenses/BSD-3-Clause
11 //
12 
13 
17 #include "TimerSource.hh"
18 //#include "TimerSource.ih"
19 
20 // Custom includes
21 #include "IdleEvent.hh"
22 #ifdef HAVE_TIMERFD_CREATE
23 #include TIMERFD_H_PATH
24 #endif
26 
27 //#include "TimerSource.mpp"
28 #define prefix_
29 //-/////////////////////////////////////////////////////////////////////////////////////////////////
30 
31 //-/////////////////////////////////////////////////////////////////////////////////////////////////
32 // senf::scheduler::detail::TimerSource
33 
35 {}
36 
37 //-/////////////////////////////////////////////////////////////////////////////////////////////////
38 // senf::scheduler::detail::POSIXTimerSource
39 
41  : timeoutEnabled_ (false), timeout_ (0), signalEnabled_ (false)
42 {
43  if (pipe(timerPipe_) < 0)
45  FdManager::instance().set( timerPipe_[0], FdManager::EV_READ, this);
46 
47  sigemptyset(&sigSet_);
48  sigaddset(&sigSet_, SIGALRM);
49  sigprocmask(SIG_BLOCK, &sigSet_, 0);
50 
51  struct sigaction act;
52  act.sa_sigaction = &sigHandler;
53  act.sa_mask = sigSet_;
54  act.sa_flags = SA_SIGINFO | SA_RESTART;
55  if (sigaction(SIGALRM, &act, 0) < 0)
56  SENF_THROW_SYSTEM_EXCEPTION("sigaction()");
57 
58  struct sigevent ev;
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()");
65 }
66 
68 {
69  timer_delete(timerId_);
70  ::signal(SIGALRM, SIG_IGN);
71  sigprocmask(SIG_UNBLOCK, &sigSet_, 0);
72  FdManager::instance().remove(timerPipe_[0]);
73  close(timerPipe_[0]);
74  close(timerPipe_[1]);
75 }
76 
77 prefix_ void
79 {
80  if (! timeoutEnabled_ || timeout_ != timeout) {
81  timeout_ = timeout;
82  if (SENF_UNLIKELY(timeout_ <= ClockService::clock_type(0)))
83  timeout_ = ClockService::clock_type(1);
84  timeoutEnabled_ = true;
85  reschedule();
86  }
87 }
88 
90 {
91  if (timeoutEnabled_) {
92  timeoutEnabled_ = false;
93  reschedule();
94  }
95 }
96 
98 {
99  if (! signalEnabled_) {
100  signalEnabled_ = true;
101  sigprocmask(SIG_UNBLOCK, &sigSet_, 0);
102  }
103 }
104 
106 {
107  if (signalEnabled_) {
108  signalEnabled_ = false;
109  sigprocmask(SIG_BLOCK, &sigSet_, 0);
110  }
111 }
112 
113 prefix_ void senf::scheduler::detail::POSIXTimerSource::sigHandler(int,
114  ::siginfo_t * siginfo,
115  void *)
116 {
117  if (siginfo->si_value.sival_ptr == 0)
118  return;
119  static char data = '\xD0';
120  // If the write fails there's not much we can do anyways ...
121  senf::IGNORE( write(static_cast<POSIXTimerSource*>(siginfo->si_value.sival_ptr)->timerPipe_[1],
122  &data, sizeof(data)) );
123 }
124 
125 prefix_ void senf::scheduler::detail::POSIXTimerSource::signal(int events)
126 {
127  char data;
128  // This should never fail since we are reading a single character from a signaled
129  // filedescriptor
130  senf::IGNORE( read(timerPipe_[0], &data, sizeof(data)) );
131  timeoutEnabled_ = false;
132 }
133 
134 prefix_ void senf::scheduler::detail::POSIXTimerSource::reschedule()
135 {
136  struct itimerspec timer;
137  memset(&timer.it_interval, 0, sizeof(timer.it_interval));
138  if (timeoutEnabled_) {
139  timer.it_value.tv_sec = ClockService::in_seconds(timeout_);
140  timer.it_value.tv_nsec = ClockService::in_nanoseconds(timeout_) % 1000000000LL;
141  }
142  if (SENF_UNLIKELY(timer_settime(timerId_, TIMER_ABSTIME, &timer, 0)<0))
143  SENF_THROW_SYSTEM_EXCEPTION("timer_settime()");
144 }
145 
146 //-/////////////////////////////////////////////////////////////////////////////////////////////////
147 // senf::scheduler::detail::PollTimerSource
148 
150 {
152  int delay (ClockService::in_milliseconds(timeout-now)+1);
153  IdleEventDispatcher::instance().timeout(delay<0?0:delay);
154 }
155 
157 {
158  IdleEventDispatcher::instance().timeout(-1);
159 }
160 
162 {}
163 
165 {}
166 
167 //-/////////////////////////////////////////////////////////////////////////////////////////////////
168 // senf::scheduler::detail::TimerFDTimerSource
169 
170 #ifdef HAVE_TIMERFD_CREATE
171 prefix_ senf::scheduler::detail::TimerFDTimerSource::TimerFDTimerSource()
172  : timerfd_ (-1), timeoutEnabled_ (false), timeout_(0)
173 {
174  timerfd_ = timerfd_create(CLOCK_MONOTONIC, 0);
175  if (timerfd_ < 0)
176  SENF_THROW_SYSTEM_EXCEPTION("timerfd_create()");
177  FdManager::instance().set( timerfd_, FdManager::EV_READ, this);
178 }
179 
180 prefix_ senf::scheduler::detail::TimerFDTimerSource::~TimerFDTimerSource()
181 {
182  FdManager::instance().remove(timerfd_);
183  close(timerfd_);
184 }
185 
186 prefix_ void
187 senf::scheduler::detail::TimerFDTimerSource::timeout(ClockService::clock_type const & timeout)
188 {
189  if (!timeoutEnabled_ || timeout_ != timeout) {
190  timeout_ = timeout;
191  if (SENF_UNLIKELY(timeout_ <= ClockService::clock_type(0)))
192  timeout_ = ClockService::clock_type(1);
193  timeoutEnabled_ = true;
194  reschedule();
195  }
196 }
197 
198 prefix_ void senf::scheduler::detail::TimerFDTimerSource::notimeout()
199 {
200  if (timeoutEnabled_) {
201  timeoutEnabled_ = false;
202  reschedule();
203  }
204 }
205 
206 prefix_ void senf::scheduler::detail::TimerFDTimerSource::enable()
207 {}
208 
209 prefix_ void senf::scheduler::detail::TimerFDTimerSource::disable()
210 {}
211 
212 namespace {
213 
214  struct TimerFdCheck
215  {
216  TimerFdCheck();
217  bool timerFdOk;
218  };
219 
220  TimerFdCheck::TimerFdCheck()
221  : timerFdOk (false)
222  {
223  int fd (timerfd_create(CLOCK_MONOTONIC, 0));
224  if (fd == -1) {
225  if (errno != EINVAL)
226  SENF_THROW_SYSTEM_EXCEPTION("timerfd_create()");
227  }
228  else {
229  timerFdOk = true;
230  close(fd);
231  }
232  }
233 
234 }
235 
236 prefix_ bool senf::scheduler::detail::TimerFDTimerSource::haveTimerFD()
237 {
238  static TimerFdCheck check;
239  return check.timerFdOk;
240 }
241 
242 prefix_ void senf::scheduler::detail::TimerFDTimerSource::signal(int events)
243 {
244  uint64_t expirations (0);
245  // We ignore the return value since we ignore the value read anyways
246  senf::IGNORE( read(timerfd_, &expirations, sizeof(expirations)) );
247 }
248 
249 prefix_ void senf::scheduler::detail::TimerFDTimerSource::reschedule()
250 {
251  struct itimerspec timer;
252  memset(&timer.it_interval, 0, sizeof(timer.it_interval));
253  if (timeoutEnabled_) {
254  timer.it_value.tv_sec = ClockService::in_seconds(timeout_);
255  timer.it_value.tv_nsec = ClockService::in_nanoseconds(timeout_) % 1000000000LL;
256  }
257  if (SENF_UNLIKELY(timerfd_settime(timerfd_, TFD_TIMER_ABSTIME, &timer, 0)<0))
258  SENF_THROW_SYSTEM_EXCEPTION("timerfd_settime()");
259 }
260 #endif
261 
262 //-/////////////////////////////////////////////////////////////////////////////////////////////////
263 #undef prefix_
264 //#include "TimerSource.mpp"
265 
266 
267 // Local Variables:
268 // mode: c++
269 // fill-column: 100
270 // comment-column: 40
271 // c-file-style: "senf"
272 // indent-tabs-mode: nil
273 // ispell-local-dictionary: "american"
274 // compile-command: "scons -u test"
275 // End:
config::time_type clock_type
ClockService timer data type.
Definition: ClockService.hh:78
#define SENF_THROW_SYSTEM_EXCEPTION(desc)
static SENF_CLOCKSERVICE_CONSTEXPR int64_type in_milliseconds(clock_type const &v)
Convert v to milliseconds.
TimerSource public header.
u8 data[SPECTRAL_HT20_NUM_BINS]
virtual void timeout(ClockService::clock_type const &timeout)
Definition: TimerSource.cc:149
ClockService::clock_type const & now()
Return (approximate) current time.
static SENF_CLOCKSERVICE_CONSTEXPR int64_type in_nanoseconds(clock_type const &v)
Convert v to nanoseconds.
#define prefix_
Definition: TimerSource.cc:28
virtual void timeout(ClockService::clock_type const &timeout)
Definition: TimerSource.cc:78
IdleEvent public header.
static clock_type now()
Return current clock value.
static SENF_CLOCKSERVICE_CONSTEXPR int64_type in_seconds(clock_type const &v)
Convert v to seconds.
virtual void close()
#define SENF_UNLIKELY(x)