TYPE3
[iec.git] / src / type3_AndroidCloud / anbox-master / external / process-cpp-minimal / src / core / posix / signal.cpp
1 /*
2  * Copyright © 2013 Canonical Ltd.
3  *
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.
7  *
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.
12  *
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/>.
15  *
16  * Authored by: Thomas Voß <thomas.voss@canonical.com>
17  */
18
19 #include <core/posix/signalable.h>
20
21 #include <poll.h>
22 #include <pthread.h>
23 #include <sys/eventfd.h>
24 #include <sys/signalfd.h>
25
26 #include <unistd.h>
27
28 #include <atomic>
29
30 namespace impl
31 {
32 void set_thread_signal_mask(::sigset_t* new_mask, ::sigset_t* old_mask)
33 {
34     ::pthread_sigmask(SIG_BLOCK, new_mask, old_mask);
35 }
36
37 void set_process_signal_mask(::sigset_t* new_mask, ::sigset_t* old_mask)
38 {
39     ::sigprocmask(SIG_BLOCK, new_mask, old_mask);
40 }
41
42 class SignalTrap : public core::posix::SignalTrap
43 {
44 public:
45     enum class Scope
46     {
47         process,
48         thread
49     };
50
51     enum class State
52     {
53         not_running,
54         running
55     };
56
57     SignalTrap(Scope scope, std::initializer_list<core::posix::Signal> blocked_signals)
58         : scope(scope),
59           state(State::not_running),
60           event_fd(::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK))
61     {
62         if (event_fd == -1)
63             throw std::system_error(errno, std::system_category());
64
65         ::sigemptyset(&blocked_signals_mask);
66
67         for(auto signal : blocked_signals)
68             ::sigaddset(&blocked_signals_mask, static_cast<int>(signal));
69
70         switch (scope)
71         {
72         case Scope::process:
73             set_process_signal_mask(&blocked_signals_mask, &old_signals_mask);
74             break;
75         case Scope::thread:
76             set_thread_signal_mask(&blocked_signals_mask, &old_signals_mask);
77             break;
78         default:
79             break;
80         }
81     }
82
83     ~SignalTrap()
84     {
85         switch (scope)
86         {
87         case Scope::process:
88             set_process_signal_mask(&old_signals_mask, nullptr);
89             break;
90         case Scope::thread:
91             set_thread_signal_mask(&old_signals_mask, nullptr);
92             break;
93         default:
94             break;
95         }
96
97         ::close(event_fd);
98     }
99
100     bool has(core::posix::Signal signal) override
101     {
102         return ::sigismember(&blocked_signals_mask, static_cast<int>(signal));
103     }
104
105     void run() override
106     {
107         static constexpr int signal_fd_idx = 0;
108         static constexpr int event_fd_idx = 1;
109
110         static constexpr int signal_info_buffer_size = 5;
111
112         if (state.load() == State::running)
113             throw std::runtime_error("SignalTrap::run can only be run once.");
114
115         state.store(State::running);
116
117         // Make sure we clean up the signal fd whenever
118         // we leave the scope of run.
119         struct Scope
120         {
121             ~Scope()
122             {
123                 if (signal_fd != -1)
124                     ::close(signal_fd);
125             }
126
127             int signal_fd;
128         } scope{::signalfd(-1, &blocked_signals_mask, SFD_CLOEXEC | SFD_NONBLOCK)};
129
130         if (scope.signal_fd == -1)
131             throw std::system_error(errno, std::system_category());
132
133         pollfd fds[2];
134         signalfd_siginfo signal_info[signal_info_buffer_size];
135
136         for (;;)
137         {
138             fds[signal_fd_idx] = {scope.signal_fd, POLLIN, 0};
139             fds[event_fd_idx] = {event_fd, POLLIN, 0};
140
141             auto rc = ::poll(fds, 2, -1);
142
143             if (rc == -1)
144             {
145                 if (errno == EINTR)
146                     continue;
147
148                 break;
149             }
150
151             if (rc == 0)
152                 continue;
153
154             if (fds[signal_fd_idx].revents & POLLIN)
155             {
156                 auto result = ::read(scope.signal_fd, signal_info, sizeof(signal_info));
157
158                 for (unsigned int i = 0; i < result / sizeof(signalfd_siginfo); i++)
159                 {
160                     if (has(static_cast<core::posix::Signal>(signal_info[i].ssi_signo)))
161                     {
162                         on_signal_raised(
163                                     static_cast<core::posix::Signal>(
164                                         signal_info[i].ssi_signo));
165                     }
166                 }
167             }
168
169             if (fds[event_fd_idx].revents & POLLIN)
170             {
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));
175                 (void) result;
176
177                 break;
178             }
179         }
180
181         state.store(State::not_running);
182     }
183
184     void stop() override
185     {
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());
189     }
190
191     core::Signal<core::posix::Signal>& signal_raised() override
192     {
193         return on_signal_raised;
194     }
195
196 private:
197     Scope scope;
198     std::atomic<State> state;
199     int event_fd;
200     core::Signal<core::posix::Signal> on_signal_raised;
201     ::sigset_t old_signals_mask;
202     ::sigset_t blocked_signals_mask;
203 };
204 }
205
206 std::shared_ptr<core::posix::SignalTrap> core::posix::trap_signals_for_process(
207         std::initializer_list<core::posix::Signal> blocked_signals)
208 {
209     return std::make_shared<impl::SignalTrap>(
210                 impl::SignalTrap::Scope::process,
211                 blocked_signals);
212 }
213
214 std::shared_ptr<core::posix::SignalTrap> core::posix::trap_signals_for_all_subsequent_threads(
215         std::initializer_list<core::posix::Signal> blocked_signals)
216 {
217     return std::make_shared<impl::SignalTrap>(
218                 impl::SignalTrap::Scope::thread,
219                 blocked_signals);
220 }
221