225e608103d9221294babb495d7334632dc64118
[senf.git] / Scheduler / TimerDispatcher.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 "TimerDispatcher.hh"
27 //#include "TimerDispatcher.ih"
28
29 // Custom includes
30
31 //#include "TimerDispatcher.mpp"
32 #define prefix_
33 ///////////////////////////////cc.p////////////////////////////////////////
34
35 unsigned senf::scheduler::TimerDispatcher::useCount_ (0);
36
37 prefix_ senf::scheduler::TimerDispatcher::TimerDispatcher(FdManager & manager,
38                                                           FIFORunner & runner)
39     : manager_ (manager), runner_ (runner), lastId_ (0), blocked_ (true)
40 {
41     if (pipe(timerPipe_) < 0)
42         SENF_THROW_SYSTEM_EXCEPTION("pipe()");
43     manager_.set(timerPipe_[0], FdManager::EV_READ, this);
44
45     sigemptyset(&sigSet_);
46     sigaddset(&sigSet_, SIGALRM);
47     sigprocmask(SIG_BLOCK, &sigSet_, 0);
48
49     if (useCount_ == 0) {
50         struct sigaction act;
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()");
56     }
57
58     struct sigevent ev;
59     ev.sigev_notify = SIGEV_SIGNAL;
60     ev.sigev_signo = SIGALRM;
61     ev.sigev_value.sival_ptr = this;
62     if (timer_create(CLOCK_MONOTONIC, &ev, &timerId_) < 0)
63         SENF_THROW_SYSTEM_EXCEPTION("timer_create()");
64     
65     ++ useCount_;
66 }
67
68 prefix_ senf::scheduler::TimerDispatcher::~TimerDispatcher()
69 {
70     -- useCount_;
71
72     TimerMap::iterator i (timers_.begin());
73     TimerMap::iterator const i_end (timers_.end());
74     for (; i != i_end; ++i)
75         runner_.dequeue(&(i->second));
76
77     timer_delete(timerId_);
78     if (useCount_ == 0)
79         ::signal(SIGALRM, SIG_IGN);
80     sigprocmask(SIG_UNBLOCK, &sigSet_, 0);
81     manager_.remove(timerPipe_[0]);
82     close(timerPipe_[0]);
83     close(timerPipe_[1]);
84 }
85
86 prefix_ senf::scheduler::TimerDispatcher::timer_id
87 senf::scheduler::TimerDispatcher::add(ClockService::clock_type timeout, Callback const & cb)
88 {
89     while (timerIdIndex_.find(++lastId_) != timerIdIndex_.end()) ;
90     TimerMap::iterator i (timers_.insert(std::make_pair(timeout, TimerEvent(lastId_, cb, *this))));
91     timerIdIndex_.insert(std::make_pair(lastId_, i));
92     runner_.enqueue(&(i->second));
93     if (! blocked_)
94         reschedule();
95     return lastId_;
96 }
97
98 prefix_ void senf::scheduler::TimerDispatcher::remove(timer_id id)
99 {
100     TimerIdMap::iterator i (timerIdIndex_.find(id));
101     if (i == timerIdIndex_.end())
102         return;
103     runner_.dequeue(&(i->second->second));
104     timers_.erase(i->second);
105     timerIdIndex_.erase(i);
106     if (! blocked_)
107         reschedule();
108 }
109
110 prefix_ void senf::scheduler::TimerDispatcher::blockSignals()
111 {
112     if (blocked_) 
113         return;
114     sigprocmask(SIG_BLOCK, &sigSet_, 0);
115     blocked_ = true;
116 }
117
118 prefix_ void senf::scheduler::TimerDispatcher::unblockSignals()
119 {
120     if (! blocked_)
121         return;
122     reschedule();
123     sigprocmask(SIG_UNBLOCK, &sigSet_, 0);
124     blocked_ = false;
125 }
126
127 prefix_ void senf::scheduler::TimerDispatcher::signal(int events)
128 {
129     siginfo_t info;
130     if (read(timerPipe_[0], &info, sizeof(info)) < int(sizeof(info)))
131         return;
132
133     TimerMap::iterator i (timers_.begin());
134     TimerMap::iterator const i_end (timers_.end());
135     ClockService::clock_type now (ClockService::now());
136     for (; i != i_end && i->first <= now ; ++i)
137         i->second.runnable = true;
138 }
139
140 prefix_ void senf::scheduler::TimerDispatcher::sigHandler(int signal, ::siginfo_t * siginfo,
141                                                           void *)
142 {
143     // The manpage says, si_signo is unused in linux so we set it here
144     siginfo->si_signo = signal; 
145     // We can't do much on error anyway so we ignore errors here
146     if (siginfo->si_value.sival_ptr == 0)
147         return;
148     write(static_cast<TimerDispatcher*>(siginfo->si_value.sival_ptr)->timerPipe_[1], 
149           siginfo, sizeof(*siginfo));
150 }
151
152 prefix_ void senf::scheduler::TimerDispatcher::reschedule()
153 {
154     struct itimerspec timer;
155     timer.it_interval.tv_sec = 0;
156     timer.it_interval.tv_nsec = 0;
157     if (timers_.empty()) {
158         timer.it_value.tv_sec = 0;
159         timer.it_value.tv_nsec = 0;
160     }
161     else {
162         ClockService::clock_type next (timers_.begin()->first);
163         timer.it_value.tv_sec = ClockService::in_seconds(next);
164         timer.it_value.tv_nsec = ClockService::in_nanoseconds(
165             next - ClockService::seconds(timer.it_value.tv_sec));
166     }
167     if (timer_settime(timerId_, TIMER_ABSTIME, &timer, 0)<0)
168         SENF_THROW_SYSTEM_EXCEPTION("timer_settime()");
169 }
170
171 ///////////////////////////////cc.e////////////////////////////////////////
172 #undef prefix_
173 //#include "TimerDispatcher.mpp"
174
175 \f
176 // Local Variables:
177 // mode: c++
178 // fill-column: 100
179 // comment-column: 40
180 // c-file-style: "senf"
181 // indent-tabs-mode: nil
182 // ispell-local-dictionary: "american"
183 // compile-command: "scons -u test"
184 // End: