1 /*
2 +----------------------------------------------------------------------+
3 | Swoole |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 2.0 of the Apache license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | http://www.apache.org/licenses/LICENSE-2.0.html |
9 | If you did not receive a copy of the Apache2.0 license and are unable|
10 | to obtain it through the world-wide-web, please send a note to |
11 | license@swoole.com so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Author: Tianfeng Han <mikan.tenny@gmail.com> |
14 +----------------------------------------------------------------------+
15 */
16
17 #include "swoole.h"
18 #include "swoole_api.h"
19 #include "swoole_signal.h"
20 #include "swoole_socket.h"
21 #include "swoole_reactor.h"
22
23 #ifdef HAVE_SIGNALFD
24 #include <sys/signalfd.h>
25 #endif
26
27 #ifdef HAVE_KQUEUE
28 #ifdef USE_KQUEUE_IDE_HELPER
29 #include "helper/kqueue.h"
30 #else
31 #include <sys/event.h>
32 #endif
33 #endif
34
35 using swoole::Event;
36 using swoole::Reactor;
37 using swoole::Signal;
38 using swoole::SignalHandler;
39 using swoole::network::Socket;
40
41 #ifdef HAVE_SIGNALFD
42 static SignalHandler swoole_signalfd_set(int signo, SignalHandler handler);
43 static bool swoole_signalfd_create();
44 static void swoole_signalfd_clear();
45 static int swoole_signalfd_event_callback(Reactor *reactor, Event *event);
46 #endif
47
48 #ifdef HAVE_KQUEUE
49 static SignalHandler swoole_signal_kqueue_set(int signo, SignalHandler handler);
50 #endif
51
52 static void swoole_signal_async_handler(int signo);
53
54 #ifdef HAVE_SIGNALFD
55 static sigset_t signalfd_mask;
56 static int signal_fd = 0;
57 static pid_t signalfd_create_pid;
58 static Socket *signal_socket = nullptr;
59 #endif
60 static Signal signals[SW_SIGNO_MAX];
61 static int _lock = 0;
62
swoole_signal_to_str(int sig)63 char *swoole_signal_to_str(int sig) {
64 static char buf[64];
65 snprintf(buf, sizeof(buf), "%s", strsignal(sig));
66 if (strchr(buf, ':') == 0) {
67 size_t len = strlen(buf);
68 snprintf(buf + len, sizeof(buf) - len, ": %d", sig);
69 }
70 return buf;
71 }
72
73 /**
74 * block all singal
75 */
swoole_signal_block_all(void)76 void swoole_signal_block_all(void) {
77 sigset_t mask;
78 sigfillset(&mask);
79 int ret = pthread_sigmask(SIG_BLOCK, &mask, nullptr);
80 if (ret < 0) {
81 swoole_sys_warning("pthread_sigmask() failed");
82 }
83 }
84
85 /**
86 * set new signal handler and return origin signal handler
87 */
swoole_signal_set(int signo,SignalHandler func,int restart,int mask)88 SignalHandler swoole_signal_set(int signo, SignalHandler func, int restart, int mask) {
89 // ignore
90 if (func == nullptr) {
91 func = SIG_IGN;
92 }
93 // clear
94 else if ((long) func == -1) {
95 func = SIG_DFL;
96 }
97
98 struct sigaction act {
99 }, oact{};
100 act.sa_handler = func;
101 if (mask) {
102 sigfillset(&act.sa_mask);
103 } else {
104 sigemptyset(&act.sa_mask);
105 }
106 act.sa_flags = 0;
107 if (sigaction(signo, &act, &oact) < 0) {
108 return nullptr;
109 }
110 return oact.sa_handler;
111 }
112
113 /**
114 * set new signal handler and return origin signal handler
115 */
swoole_signal_set(int signo,SignalHandler handler)116 SignalHandler swoole_signal_set(int signo, SignalHandler handler) {
117 #ifdef HAVE_SIGNALFD
118 if (SwooleG.use_signalfd) {
119 return swoole_signalfd_set(signo, handler);
120 } else
121 #endif
122 {
123 #ifdef HAVE_KQUEUE
124 // SIGCHLD can not be monitored by kqueue, if blocked by SIG_IGN
125 // see https://www.freebsd.org/cgi/man.cgi?kqueue
126 // if there's no main reactor, signals cannot be monitored either
127 if (signo != SIGCHLD && sw_reactor()) {
128 return swoole_signal_kqueue_set(signo, handler);
129 } else
130 #endif
131 {
132 signals[signo].handler = handler;
133 signals[signo].activated = true;
134 signals[signo].signo = signo;
135 return swoole_signal_set(signo, swoole_signal_async_handler, 1, 0);
136 }
137 }
138 }
139
swoole_signal_async_handler(int signo)140 static void swoole_signal_async_handler(int signo) {
141 if (sw_reactor()) {
142 sw_reactor()->singal_no = signo;
143 } else {
144 // discard signal
145 if (_lock) {
146 return;
147 }
148 _lock = 1;
149 swoole_signal_callback(signo);
150 _lock = 0;
151 }
152 }
153
swoole_signal_callback(int signo)154 void swoole_signal_callback(int signo) {
155 if (signo >= SW_SIGNO_MAX) {
156 swoole_warning("signal[%d] numberis invalid", signo);
157 return;
158 }
159 SignalHandler callback = signals[signo].handler;
160 if (!callback) {
161 swoole_error_log(
162 SW_LOG_WARNING, SW_ERROR_UNREGISTERED_SIGNAL, SW_UNREGISTERED_SIGNAL_FMT, swoole_signal_to_str(signo));
163 return;
164 }
165 callback(signo);
166 }
167
swoole_signal_get_handler(int signo)168 SignalHandler swoole_signal_get_handler(int signo) {
169 if (signo >= SW_SIGNO_MAX) {
170 swoole_warning("signal[%d] numberis invalid", signo);
171 return nullptr;
172 } else {
173 return signals[signo].handler;
174 }
175 }
176
swoole_signal_clear(void)177 void swoole_signal_clear(void) {
178 #ifdef HAVE_SIGNALFD
179 if (SwooleG.use_signalfd) {
180 swoole_signalfd_clear();
181 } else
182 #endif
183 {
184 int i;
185 for (i = 0; i < SW_SIGNO_MAX; i++) {
186 if (signals[i].activated) {
187 #ifdef HAVE_KQUEUE
188 if (signals[i].signo != SIGCHLD && sw_reactor()) {
189 swoole_signal_kqueue_set(signals[i].signo, nullptr);
190 } else
191 #endif
192 {
193 swoole_signal_set(signals[i].signo, (SignalHandler) -1, 1, 0);
194 }
195 }
196 }
197 }
198 sw_memset_zero(&signals, sizeof(signals));
199 }
200
201 #ifdef HAVE_SIGNALFD
swoole_signalfd_init()202 void swoole_signalfd_init() {
203 sigemptyset(&signalfd_mask);
204 sw_memset_zero(&signals, sizeof(signals));
205 }
206
207 /**
208 * set new signal handler and return origin signal handler
209 */
swoole_signalfd_set(int signo,SignalHandler handler)210 static SignalHandler swoole_signalfd_set(int signo, SignalHandler handler) {
211 SignalHandler origin_handler = nullptr;
212
213 if (handler == nullptr && signals[signo].activated) {
214 sigdelset(&signalfd_mask, signo);
215 sw_memset_zero(&signals[signo], sizeof(Signal));
216 } else {
217 sigaddset(&signalfd_mask, signo);
218 origin_handler = signals[signo].handler;
219 signals[signo].handler = handler;
220 signals[signo].signo = signo;
221 signals[signo].activated = true;
222 }
223
224 if (sw_reactor()) {
225 if (signal_fd == 0) {
226 swoole_signalfd_create();
227 } else {
228 sigprocmask(SIG_SETMASK, &signalfd_mask, nullptr);
229 signalfd(signal_fd, &signalfd_mask, SFD_NONBLOCK | SFD_CLOEXEC);
230 }
231 swoole_signalfd_setup(sw_reactor());
232 }
233
234 return origin_handler;
235 }
236
swoole_signalfd_create()237 static bool swoole_signalfd_create() {
238 if (signal_fd != 0) {
239 return false;
240 }
241
242 signal_fd = signalfd(-1, &signalfd_mask, SFD_NONBLOCK | SFD_CLOEXEC);
243 if (signal_fd < 0) {
244 swoole_sys_warning("signalfd() failed");
245 signal_fd = 0;
246 return false;
247 }
248 signal_socket = swoole::make_socket(signal_fd, SW_FD_SIGNAL);
249 if (sigprocmask(SIG_BLOCK, &signalfd_mask, nullptr) == -1) {
250 swoole_sys_warning("sigprocmask() failed");
251 signal_socket->fd = -1;
252 signal_socket->free();
253 close(signal_fd);
254 signal_socket = nullptr;
255 signal_fd = 0;
256 return false;
257 }
258 signalfd_create_pid = getpid();
259 SwooleG.signal_fd = signal_fd;
260
261 return true;
262 }
263
swoole_signalfd_setup(Reactor * reactor)264 bool swoole_signalfd_setup(Reactor *reactor) {
265 if (signal_fd == 0 && !swoole_signalfd_create()) {
266 return false;
267 }
268 if (!swoole_event_isset_handler(SW_FD_SIGNAL)) {
269 swoole_event_set_handler(SW_FD_SIGNAL, swoole_signalfd_event_callback);
270 reactor->set_exit_condition(Reactor::EXIT_CONDITION_SIGNALFD, [](Reactor *reactor, size_t &event_num) -> bool {
271 event_num--;
272 return true;
273 });
274 reactor->add_destroy_callback([](void *) {
275 // child process removes signal socket, parent process will not be able to trigger signal
276 if (signal_socket && signalfd_create_pid == getpid()) {
277 swoole_event_del(signal_socket);
278 }
279 });
280 }
281 if (!(signal_socket->events & SW_EVENT_READ) && swoole_event_add(signal_socket, SW_EVENT_READ) < 0) {
282 return false;
283 }
284 return true;
285 }
286
swoole_signalfd_clear()287 static void swoole_signalfd_clear() {
288 if (signal_fd) {
289 if (sigprocmask(SIG_UNBLOCK, &signalfd_mask, nullptr) < 0) {
290 swoole_sys_warning("sigprocmask(SIG_UNBLOCK) failed");
291 }
292 if (signal_socket) {
293 signal_socket->free();
294 signal_socket = nullptr;
295 }
296 sw_memset_zero(&signalfd_mask, sizeof(signalfd_mask));
297 }
298 SwooleG.signal_fd = signal_fd = 0;
299 }
300
swoole_signalfd_event_callback(Reactor * reactor,Event * event)301 static int swoole_signalfd_event_callback(Reactor *reactor, Event *event) {
302 struct signalfd_siginfo siginfo;
303 ssize_t n = read(event->fd, &siginfo, sizeof(siginfo));
304 if (n < 0) {
305 swoole_sys_warning("read from signalfd failed");
306 return SW_OK;
307 }
308 if (siginfo.ssi_signo >= SW_SIGNO_MAX) {
309 swoole_warning("unknown signal[%d]", siginfo.ssi_signo);
310 return SW_OK;
311 }
312 if (signals[siginfo.ssi_signo].activated) {
313 SignalHandler handler = signals[siginfo.ssi_signo].handler;
314 if (handler == SIG_IGN) {
315 return SW_OK;
316 } else if (handler) {
317 handler(siginfo.ssi_signo);
318 } else {
319 swoole_error_log(SW_LOG_WARNING,
320 SW_ERROR_UNREGISTERED_SIGNAL,
321 SW_UNREGISTERED_SIGNAL_FMT,
322 swoole_signal_to_str(siginfo.ssi_signo));
323 }
324 }
325
326 return SW_OK;
327 }
328 #endif
329
330 #ifdef HAVE_KQUEUE
331 /**
332 * set new signal handler and return origin signal handler
333 */
swoole_signal_kqueue_set(int signo,SignalHandler handler)334 static SignalHandler swoole_signal_kqueue_set(int signo, SignalHandler handler) {
335 struct kevent ev;
336 SignalHandler origin_handler = nullptr;
337 Reactor *reactor = sw_reactor();
338
339 // clear signal
340 if (handler == nullptr) {
341 signal(signo, SIG_DFL);
342 sw_memset_zero(&signals[signo], sizeof(Signal));
343 EV_SET(&ev, signo, EVFILT_SIGNAL, EV_DELETE, 0, 0, NULL);
344 }
345 // add/update signal
346 else {
347 signal(signo, SIG_IGN);
348 origin_handler = signals[signo].handler;
349 signals[signo].handler = handler;
350 signals[signo].signo = signo;
351 signals[signo].activated = true;
352 #ifndef __NetBSD__
353 auto sigptr = &signals[signo];
354 #else
355 auto sigptr = reinterpret_cast<intptr_t>(&signals[signo]);
356 #endif
357 // save swSignal* as udata
358 EV_SET(&ev, signo, EVFILT_SIGNAL, EV_ADD, 0, 0, sigptr);
359 }
360 int n = kevent(reactor->native_handle, &ev, 1, nullptr, 0, nullptr);
361 if (n < 0 && sw_unlikely(handler)) {
362 swoole_sys_warning("kevent set signal[%d] error", signo);
363 }
364
365 return origin_handler;
366 }
367 #endif
368