switch to new MPL based Fraunhofer FOKUS Public License
[senf.git] / senf / Scheduler / SignalEvent.cc
1 // $Id$
2 //
3 // Copyright (C) 2008
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 SignalDispatcher non-inline non-template implementation */
30
31 #include "SignalEvent.hh"
32 #include "SignalEvent.ih"
33
34 // Custom includes
35 #include <senf/Utils/senfassert.hh>
36 #include <senf/Utils/signalnames.hh>
37 #include "senf/Utils/IgnoreValue.hh"
38
39 //#include "SignalEvent.mpp"
40 #define prefix_
41 //-/////////////////////////////////////////////////////////////////////////////////////////////////
42
43 prefix_ senf::scheduler::detail::SignalDispatcher::SignalDispatcher()
44     : blocked_ (true)
45 {
46     if (pipe(sigPipe_) <0)
47         SENF_THROW_SYSTEM_EXCEPTION("pipe()");
48     sigemptyset(&sigSet_);
49     detail::FdManager::instance().set(sigPipe_[0], detail::FdManager::EV_READ, this);
50 }
51
52 prefix_ senf::scheduler::detail::SignalDispatcher::~SignalDispatcher()
53 {
54     for (SignalSet::iterator i (handlers_.begin()); i != handlers_.end(); ++i) {
55         ::signal(i->signal_, SIG_DFL);
56         detail::FIFORunner::instance().dequeue(&(*i));
57     }
58     sigprocmask(SIG_UNBLOCK, &sigSet_, 0);
59     detail::FdManager::instance().remove(sigPipe_[0]);
60     close(sigPipe_[0]);
61     close(sigPipe_[1]);
62 }
63
64 prefix_ void senf::scheduler::detail::SignalDispatcher::add(SignalEvent & event)
65 {
66     SignalSet::iterator i (handlers_.find(event));
67     if (i != handlers_.end())
68         throw DuplicateSignalRegistrationException()
69             << " for signal " << signalName(event.signal_) << " (" << event.signal_ << ")";
70
71     handlers_.insert(event);
72     sigaddset(&sigSet_, event.signal_);
73     detail::FIFORunner::instance().enqueue(&event);
74
75     sigset_t sig;
76     sigemptyset(&sig);
77     sigaddset(&sig, event.signal_);
78     sigprocmask(blocked_ ? SIG_BLOCK : SIG_UNBLOCK, &sig, 0);
79
80     // Need to re-register all handlers to update sa_mask
81     struct sigaction act;
82     act.sa_sigaction = &sigHandler;
83     act.sa_mask = sigSet_;
84     act.sa_flags = SA_SIGINFO | SA_RESTART;
85     for (SignalSet::iterator i (handlers_.begin()); i != handlers_.end(); ++i) {
86         if (i->signal_ == SIGCLD)
87             act.sa_flags |= SA_NOCLDSTOP;
88         else
89             act.sa_flags &= ~SA_NOCLDSTOP;
90         if (sigaction(i->signal_, &act, 0) < 0)
91             SENF_THROW_SYSTEM_EXCEPTION("sigaction()");
92     }
93 }
94
95 prefix_ void senf::scheduler::detail::SignalDispatcher::remove(SignalEvent & event)
96 {
97     ::signal(event.signal_, SIG_DFL);
98     detail::FIFORunner::instance().dequeue(&event);
99     handlers_.erase(event);
100     sigset_t sig;
101     sigemptyset(&sig);
102     sigaddset(&sig, event.signal_);
103     sigprocmask(SIG_UNBLOCK, &sig, 0);
104 }
105
106 prefix_ void senf::scheduler::detail::SignalDispatcher::signal(int events)
107 {
108     siginfo_t info;
109     if (read(sigPipe_[0], &info, sizeof(info)) < int(sizeof(info)))
110         return;
111     SignalSet::iterator i (handlers_.find(info.si_signo, FindNumericSignal()));
112     if (i == handlers_.end())
113         return;
114     i->siginfo_ = info;
115     i->setRunnable();
116 }
117
118 prefix_ void senf::scheduler::detail::SignalDispatcher::sigHandler(int signal,
119                                                                    ::siginfo_t * siginfo,
120                                                                    void *)
121 {
122     SENF_ASSERT( alive(), "Internal failure: Destroyed signal handler called" );
123     // The manpage says, si_signo is unused in linux so we set it here
124     siginfo->si_signo = signal;
125     // We can't do much on error anyway so we ignore errors here
126     senf::IGNORE( write(instance().sigPipe_[1], siginfo, sizeof(*siginfo)) );
127 }
128
129 prefix_ void senf::scheduler::SignalEvent::v_run()
130 {
131     cb_(siginfo_);
132 }
133
134 prefix_ char const * senf::scheduler::SignalEvent::v_type()
135     const
136 {
137     return "si";
138 }
139
140 prefix_ std::string senf::scheduler::SignalEvent::v_info()
141     const
142 {
143     return "";
144 }
145
146 //-/////////////////////////////////////////////////////////////////////////////////////////////////
147 #undef prefix_
148 //#include "SignalEvent.mpp"
149
150
151 // Local Variables:
152 // mode: c++
153 // fill-column: 100
154 // comment-column: 40
155 // c-file-style: "senf"
156 // indent-tabs-mode: nil
157 // ispell-local-dictionary: "american"
158 // compile-command: "scons -u test"
159 // End: