1 | /* |
2 | * signal.c |
3 | * |
4 | * Copyright (C) 2010-2018 Aerospike, Inc. |
5 | * |
6 | * Portions may be licensed to Aerospike, Inc. under one or more contributor |
7 | * license agreements. |
8 | * |
9 | * This program is free software: you can redistribute it and/or modify it under |
10 | * the terms of the GNU Affero General Public License as published by the Free |
11 | * Software Foundation, either version 3 of the License, or (at your option) any |
12 | * later version. |
13 | * |
14 | * This program is distributed in the hope that it will be useful, but WITHOUT |
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
16 | * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more |
17 | * details. |
18 | * |
19 | * You should have received a copy of the GNU Affero General Public License |
20 | * along with this program. If not, see http://www.gnu.org/licenses/ |
21 | */ |
22 | |
23 | #include <pthread.h> |
24 | #include <signal.h> |
25 | #include <stdbool.h> |
26 | #include <stdlib.h> |
27 | #include <string.h> |
28 | #include <unistd.h> |
29 | |
30 | #include "cf_thread.h" |
31 | #include "fault.h" |
32 | |
33 | |
34 | //========================================================== |
35 | // Typedefs & constants. |
36 | // |
37 | |
38 | typedef void (*action_t)(int sig, siginfo_t *info, void *ctx); |
39 | |
40 | // String constants in version.c, generated by make. |
41 | extern const char aerospike_build_type[]; |
42 | extern const char aerospike_build_id[]; |
43 | extern const char aerospike_build_os[]; |
44 | |
45 | |
46 | //========================================================== |
47 | // Globals. |
48 | // |
49 | |
50 | // The mutex that the main function deadlocks on after starting the service. |
51 | extern pthread_mutex_t g_main_deadlock; |
52 | extern bool g_startup_complete; |
53 | |
54 | |
55 | //========================================================== |
56 | // Local helpers. |
57 | // |
58 | |
59 | static inline void |
60 | set_action(int sig_num, action_t act) |
61 | { |
62 | struct sigaction sa; |
63 | memset(&sa, 0, sizeof(sa)); |
64 | |
65 | sa.sa_sigaction = act; |
66 | sigemptyset(&sa.sa_mask); |
67 | // SA_SIGINFO prefers sa_sigaction over sa_handler. |
68 | sa.sa_flags = SA_RESTART | SA_SIGINFO; |
69 | |
70 | if (sigaction(sig_num, &sa, NULL) < 0) { |
71 | cf_crash(AS_AS, "could not register signal handler for %d" , sig_num); |
72 | } |
73 | } |
74 | |
75 | static inline void |
76 | set_handler(int sig_num, sighandler_t hand) |
77 | { |
78 | struct sigaction sa; |
79 | memset(&sa, 0, sizeof(sa)); |
80 | |
81 | sa.sa_handler = hand; |
82 | sigemptyset(&sa.sa_mask); |
83 | // No SA_SIGINFO; use sa_handler. |
84 | sa.sa_flags = SA_RESTART; |
85 | |
86 | if (sigaction(sig_num, &sa, NULL) < 0) { |
87 | cf_crash(AS_AS, "could not register signal handler for %d" , sig_num); |
88 | } |
89 | } |
90 | |
91 | static inline void |
92 | reraise_signal(int sig_num) |
93 | { |
94 | set_handler(sig_num, SIG_DFL); |
95 | raise(sig_num); |
96 | } |
97 | |
98 | |
99 | //========================================================== |
100 | // Signal handlers. |
101 | // |
102 | |
103 | // We get here on some crashes. |
104 | void |
105 | as_sig_handle_abort(int sig_num, siginfo_t *info, void *ctx) |
106 | { |
107 | cf_warning(AS_AS, "SIGABRT received, aborting %s build %s os %s" , |
108 | aerospike_build_type, aerospike_build_id, aerospike_build_os); |
109 | |
110 | cf_fault_print_signal_context(ctx); |
111 | reraise_signal(sig_num); |
112 | } |
113 | |
114 | void |
115 | as_sig_handle_bus(int sig_num, siginfo_t *info, void *ctx) |
116 | { |
117 | cf_warning(AS_AS, "SIGBUS received, aborting %s build %s os %s" , |
118 | aerospike_build_type, aerospike_build_id, aerospike_build_os); |
119 | |
120 | cf_fault_print_signal_context(ctx); |
121 | reraise_signal(sig_num); |
122 | } |
123 | |
124 | // Floating point exception. |
125 | void |
126 | as_sig_handle_fpe(int sig_num, siginfo_t *info, void *ctx) |
127 | { |
128 | cf_warning(AS_AS, "SIGFPE received, aborting %s build %s os %s" , |
129 | aerospike_build_type, aerospike_build_id, aerospike_build_os); |
130 | |
131 | cf_fault_print_signal_context(ctx); |
132 | reraise_signal(sig_num); |
133 | } |
134 | |
135 | // This signal is our cue to roll the log. |
136 | void |
137 | as_sig_handle_hup(int sig_num, siginfo_t *info, void *ctx) |
138 | { |
139 | cf_info(AS_AS, "SIGHUP received, rolling log" ); |
140 | |
141 | cf_fault_sink_logroll(); |
142 | } |
143 | |
144 | // We get here on some crashes. |
145 | void |
146 | as_sig_handle_ill(int sig_num, siginfo_t *info, void *ctx) |
147 | { |
148 | cf_warning(AS_AS, "SIGILL received, aborting %s build %s os %s" , |
149 | aerospike_build_type, aerospike_build_id, aerospike_build_os); |
150 | |
151 | cf_fault_print_signal_context(ctx); |
152 | reraise_signal(sig_num); |
153 | } |
154 | |
155 | // We get here on cf_crash_nostack(), cf_assert_nostack(), or Ctrl-C when |
156 | // running in foreground. |
157 | void |
158 | as_sig_handle_int(int sig_num, siginfo_t *info, void *ctx) |
159 | { |
160 | cf_warning(AS_AS, "SIGINT received, shutting down %s build %s os %s" , |
161 | aerospike_build_type, aerospike_build_id, aerospike_build_os); |
162 | |
163 | if (! g_startup_complete) { |
164 | cf_warning(AS_AS, "startup was not complete, exiting immediately" ); |
165 | _exit(1); |
166 | } |
167 | |
168 | pthread_mutex_unlock(&g_main_deadlock); |
169 | } |
170 | |
171 | // We get here if we intentionally trigger the signal. |
172 | void |
173 | as_sig_handle_quit(int sig_num, siginfo_t *info, void *ctx) |
174 | { |
175 | cf_warning(AS_AS, "SIGQUIT received, aborting %s build %s os %s" , |
176 | aerospike_build_type, aerospike_build_id, aerospike_build_os); |
177 | |
178 | cf_fault_print_signal_context(ctx); |
179 | reraise_signal(sig_num); |
180 | } |
181 | |
182 | // We get here on some crashes. |
183 | void |
184 | as_sig_handle_segv(int sig_num, siginfo_t *info, void *ctx) |
185 | { |
186 | cf_warning(AS_AS, "SIGSEGV received, aborting %s build %s os %s" , |
187 | aerospike_build_type, aerospike_build_id, aerospike_build_os); |
188 | |
189 | cf_fault_print_signal_context(ctx); |
190 | reraise_signal(sig_num); |
191 | } |
192 | |
193 | // We get here on normal shutdown. |
194 | void |
195 | as_sig_handle_term(int sig_num, siginfo_t *info, void *ctx) |
196 | { |
197 | cf_info(AS_AS, "SIGTERM received, shutting down %s build %s os %s" , |
198 | aerospike_build_type, aerospike_build_id, aerospike_build_os); |
199 | |
200 | if (! g_startup_complete) { |
201 | cf_warning(AS_AS, "startup was not complete, exiting immediately" ); |
202 | _exit(0); |
203 | } |
204 | |
205 | pthread_mutex_unlock(&g_main_deadlock); |
206 | } |
207 | |
208 | // We get here on cf_crash() and cf_assert(). |
209 | void |
210 | as_sig_handle_usr1(int sig_num, siginfo_t *info, void *ctx) |
211 | { |
212 | cf_warning(AS_AS, "SIGUSR1 received, aborting %s build %s os %s" , |
213 | aerospike_build_type, aerospike_build_id, aerospike_build_os); |
214 | |
215 | cf_fault_print_signal_context(ctx); |
216 | reraise_signal(SIGABRT); |
217 | } |
218 | |
219 | |
220 | //========================================================== |
221 | // Public API. |
222 | // |
223 | |
224 | void |
225 | as_signal_setup() |
226 | { |
227 | set_action(SIGABRT, as_sig_handle_abort); |
228 | set_action(SIGBUS, as_sig_handle_bus); |
229 | set_action(SIGFPE, as_sig_handle_fpe); |
230 | set_action(SIGHUP, as_sig_handle_hup); |
231 | set_action(SIGILL, as_sig_handle_ill); |
232 | set_action(SIGINT, as_sig_handle_int); |
233 | set_action(SIGQUIT, as_sig_handle_quit); |
234 | set_action(SIGSEGV, as_sig_handle_segv); |
235 | set_action(SIGTERM, as_sig_handle_term); |
236 | set_action(SIGUSR1, as_sig_handle_usr1); |
237 | set_action(SIGUSR2, cf_thread_traces_action); |
238 | |
239 | // Block SIGPIPE signal when there is some error while writing to pipe. The |
240 | // write() call will return with a normal error which we can handle. |
241 | set_handler(SIGPIPE, SIG_IGN); |
242 | } |
243 | |