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