2 * Copyright © 2013 Canonical Ltd.
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 * Authored by: Thomas Voß <thomas.voss@canonical.com>
19 #include <core/posix/signalable.h>
23 #include <sys/eventfd.h>
24 #include <sys/signalfd.h>
32 void set_thread_signal_mask(::sigset_t* new_mask, ::sigset_t* old_mask)
34 ::pthread_sigmask(SIG_BLOCK, new_mask, old_mask);
37 void set_process_signal_mask(::sigset_t* new_mask, ::sigset_t* old_mask)
39 ::sigprocmask(SIG_BLOCK, new_mask, old_mask);
42 class SignalTrap : public core::posix::SignalTrap
57 SignalTrap(Scope scope, std::initializer_list<core::posix::Signal> blocked_signals)
59 state(State::not_running),
60 event_fd(::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK))
63 throw std::system_error(errno, std::system_category());
65 ::sigemptyset(&blocked_signals_mask);
67 for(auto signal : blocked_signals)
68 ::sigaddset(&blocked_signals_mask, static_cast<int>(signal));
73 set_process_signal_mask(&blocked_signals_mask, &old_signals_mask);
76 set_thread_signal_mask(&blocked_signals_mask, &old_signals_mask);
88 set_process_signal_mask(&old_signals_mask, nullptr);
91 set_thread_signal_mask(&old_signals_mask, nullptr);
100 bool has(core::posix::Signal signal) override
102 return ::sigismember(&blocked_signals_mask, static_cast<int>(signal));
107 static constexpr int signal_fd_idx = 0;
108 static constexpr int event_fd_idx = 1;
110 static constexpr int signal_info_buffer_size = 5;
112 if (state.load() == State::running)
113 throw std::runtime_error("SignalTrap::run can only be run once.");
115 state.store(State::running);
117 // Make sure we clean up the signal fd whenever
118 // we leave the scope of run.
128 } scope{::signalfd(-1, &blocked_signals_mask, SFD_CLOEXEC | SFD_NONBLOCK)};
130 if (scope.signal_fd == -1)
131 throw std::system_error(errno, std::system_category());
134 signalfd_siginfo signal_info[signal_info_buffer_size];
138 fds[signal_fd_idx] = {scope.signal_fd, POLLIN, 0};
139 fds[event_fd_idx] = {event_fd, POLLIN, 0};
141 auto rc = ::poll(fds, 2, -1);
154 if (fds[signal_fd_idx].revents & POLLIN)
156 auto result = ::read(scope.signal_fd, signal_info, sizeof(signal_info));
158 for (unsigned int i = 0; i < result / sizeof(signalfd_siginfo); i++)
160 if (has(static_cast<core::posix::Signal>(signal_info[i].ssi_signo)))
163 static_cast<core::posix::Signal>(
164 signal_info[i].ssi_signo));
169 if (fds[event_fd_idx].revents & POLLIN)
171 std::int64_t value{1};
172 // Consciously void-ing the return value here.
173 // Not much we can do about an error.
174 auto result = ::read(event_fd, &value, sizeof(value));
181 state.store(State::not_running);
186 static const std::int64_t value = {1};
187 if (sizeof(value) != ::write(event_fd, &value, sizeof(value)))
188 throw std::system_error(errno, std::system_category());
191 core::Signal<core::posix::Signal>& signal_raised() override
193 return on_signal_raised;
198 std::atomic<State> state;
200 core::Signal<core::posix::Signal> on_signal_raised;
201 ::sigset_t old_signals_mask;
202 ::sigset_t blocked_signals_mask;
206 std::shared_ptr<core::posix::SignalTrap> core::posix::trap_signals_for_process(
207 std::initializer_list<core::posix::Signal> blocked_signals)
209 return std::make_shared<impl::SignalTrap>(
210 impl::SignalTrap::Scope::process,
214 std::shared_ptr<core::posix::SignalTrap> core::posix::trap_signals_for_all_subsequent_threads(
215 std::initializer_list<core::posix::Signal> blocked_signals)
217 return std::make_shared<impl::SignalTrap>(
218 impl::SignalTrap::Scope::thread,