add minimal documentation for DirectoryNode::link()
[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 #include <sstream>
31
32 //#include "TimerEvent.mpp"
33 #define prefix_
34 ///////////////////////////////cc.p////////////////////////////////////////
35
36 prefix_ senf::scheduler::detail::TimerDispatcher::TimerDispatcher()
37     : blocked_ (true)
38 {
39     if (pipe(timerPipe_) < 0)
40         SENF_THROW_SYSTEM_EXCEPTION("pipe()");
41     senf::scheduler::detail::FdManager::instance().set(timerPipe_[0], detail::FdManager::EV_READ, this);
42
43     sigemptyset(&sigSet_);
44     sigaddset(&sigSet_, SIGALRM);
45     sigprocmask(SIG_BLOCK, &sigSet_, 0);
46
47     struct sigaction act;
48     act.sa_sigaction = &sigHandler;
49     act.sa_mask = sigSet_;
50     act.sa_flags = SA_SIGINFO | SA_RESTART;
51     if (sigaction(SIGALRM, &act, 0) < 0)
52         SENF_THROW_SYSTEM_EXCEPTION("sigaction()");
53
54     struct sigevent ev;
55     ::memset(&ev, 0, sizeof(ev));
56     ev.sigev_notify = SIGEV_SIGNAL;
57     ev.sigev_signo = SIGALRM;
58     ev.sigev_value.sival_ptr = this;
59     if (timer_create(CLOCK_MONOTONIC, &ev, &timerId_) < 0)
60         SENF_THROW_SYSTEM_EXCEPTION("timer_create()");
61 }
62
63 prefix_ senf::scheduler::detail::TimerDispatcher::~TimerDispatcher()
64 {
65     TimerSet::iterator i (timers_.begin());
66     TimerSet::iterator const i_end (timers_.end());
67     for (; i != i_end; ++i)
68         senf::scheduler::detail::FIFORunner::instance().dequeue(&(*i));
69
70     timer_delete(timerId_);
71     ::signal(SIGALRM, SIG_IGN);
72     sigprocmask(SIG_UNBLOCK, &sigSet_, 0);
73     senf::scheduler::detail::FdManager::instance().remove(timerPipe_[0]);
74     close(timerPipe_[0]);
75     close(timerPipe_[1]);
76 }
77
78 void senf::scheduler::detail::TimerDispatcher::add(TimerEvent & event)
79 {
80     TimerSet::iterator i (timers_.insert(event));
81     senf::scheduler::detail::FIFORunner::instance().enqueue(&(*i));
82     if (! blocked_)
83         reschedule();
84 }
85
86 prefix_ void senf::scheduler::detail::TimerDispatcher::remove(TimerEvent & event)
87 {
88     TimerSet::iterator i (TimerSet::current(event));
89     if (i == timers_.end())
90         return;
91     senf::scheduler::detail::FIFORunner::instance().dequeue(&(*i));
92     timers_.erase(i);
93     if (! blocked_)
94         reschedule();
95 }
96
97 prefix_ void senf::scheduler::detail::TimerDispatcher::blockSignals()
98 {
99     if (blocked_) 
100         return;
101     sigprocmask(SIG_BLOCK, &sigSet_, 0);
102     blocked_ = true;
103 }
104
105 prefix_ void senf::scheduler::detail::TimerDispatcher::unblockSignals()
106 {
107     if (! blocked_)
108         return;
109     reschedule();
110     sigprocmask(SIG_UNBLOCK, &sigSet_, 0);
111     blocked_ = false;
112 }
113
114 prefix_ void senf::scheduler::detail::TimerDispatcher::signal(int events)
115 {
116     siginfo_t info;
117     if (read(timerPipe_[0], &info, sizeof(info)) < int(sizeof(info)))
118         return;
119     TimerSet::iterator i (timers_.begin());
120     TimerSet::iterator const i_end (timers_.end());
121     ClockService::clock_type now (senf::scheduler::detail::FdManager::instance().eventTime());
122     for (; i != i_end && i->timeout_ <= now ; ++i)
123         i->setRunnable();
124 }
125
126 prefix_ void senf::scheduler::detail::TimerDispatcher::sigHandler(int signal, 
127                                                                   ::siginfo_t * siginfo,
128                                                                   void *)
129 {
130     // The manpage says, si_signo is unused in linux so we set it here
131     siginfo->si_signo = signal; 
132     // We can't do much on error anyway so we ignore errors here
133     if (siginfo->si_value.sival_ptr == 0)
134         return;
135     write(static_cast<TimerDispatcher*>(siginfo->si_value.sival_ptr)->timerPipe_[1], 
136           siginfo, sizeof(*siginfo));
137 }
138
139 prefix_ void senf::scheduler::detail::TimerDispatcher::reschedule()
140 {
141     struct itimerspec timer;
142     memset(&timer, 0, sizeof(timer));
143     timer.it_interval.tv_sec = 0;
144     timer.it_interval.tv_nsec = 0;
145     if (timers_.empty()) {
146         SENF_LOG( (senf::log::VERBOSE)("Timer disabled") );
147         timer.it_value.tv_sec = 0;
148         timer.it_value.tv_nsec = 0;
149     }
150     else {
151         ClockService::clock_type next (timers_.begin()->timeout_);
152         if (next <= 0)
153             next = 1;
154         timer.it_value.tv_sec = ClockService::in_seconds(next);
155         timer.it_value.tv_nsec = ClockService::in_nanoseconds(
156             next - ClockService::seconds(timer.it_value.tv_sec));
157         SENF_LOG( (senf::log::VERBOSE)("Next timeout scheduled @" << timer.it_value.tv_sec << "." 
158                    << std::setw(9) << std::setfill('0') << timer.it_value.tv_nsec) );
159     }
160     if (timer_settime(timerId_, TIMER_ABSTIME, &timer, 0)<0)
161         SENF_THROW_SYSTEM_EXCEPTION("timer_settime()");
162 }
163
164 ///////////////////////////////////////////////////////////////////////////
165 // senf::scheduler::detail::TimerDispatcher::TimerEvent
166
167 prefix_ void senf::scheduler::TimerEvent::v_run()
168 {
169     disable();
170     cb_();
171 }
172
173 prefix_ char const * senf::scheduler::TimerEvent::v_type()
174     const
175 {
176     return "tm";
177 }
178
179 prefix_ std::string senf::scheduler::TimerEvent::v_info()
180     const
181 {
182     std::stringstream ss;
183     ss.imbue( std::locale(ss.getloc(),
184                           new boost::posix_time::time_facet("%Y-%m-%d %H:%M:%S.%f-0000")) );
185     ss << "expire " << ClockService::abstime(timeout_);
186     return ss.str();
187 }
188
189 ///////////////////////////////cc.e////////////////////////////////////////
190 #undef prefix_
191 //#include "TimerEvent.mpp"
192
193 \f
194 // Local Variables:
195 // mode: c++
196 // fill-column: 100
197 // comment-column: 40
198 // c-file-style: "senf"
199 // indent-tabs-mode: nil
200 // ispell-local-dictionary: "american"
201 // compile-command: "scons -u test"
202 // End: