1 /** @file
2
3 A brief file description
4
5 @section license License
6
7 Licensed to the Apache Software Foundation (ASF) under one
8 or more contributor license agreements. See the NOTICE file
9 distributed with this work for additional information
10 regarding copyright ownership. The ASF licenses this file
11 to you under the Apache License, Version 2.0 (the
12 "License"); you may not use this file except in compliance
13 with the License. You may obtain a copy of the License at
14
15 http://www.apache.org/licenses/LICENSE-2.0
16
17 Unless required by applicable law or agreed to in writing, software
18 distributed under the License is distributed on an "AS IS" BASIS,
19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 See the License for the specific language governing permissions and
21 limitations under the License.
22 */
23
24 /**************************************************************************
25 Signal functions and handlers.
26
27 **************************************************************************/
28
29 #include "tscore/ink_platform.h"
30 #include "tscore/signals.h"
31 #include "tscore/ink_stack_trace.h"
32 #include "tscore/ink_assert.h"
33 #include "tscore/ink_thread.h"
34 #include "tscore/Diags.h"
35
36 bool
signal_check_handler(int signal,signal_handler_t handler)37 signal_check_handler(int signal, signal_handler_t handler)
38 {
39 struct sigaction oact;
40 void *sigact;
41
42 ink_release_assert(sigaction(signal, nullptr, &oact) == 0);
43 if (handler == reinterpret_cast<signal_handler_t>(SIG_DFL) || handler == reinterpret_cast<signal_handler_t>(SIG_IGN)) {
44 sigact = reinterpret_cast<void *>(oact.sa_handler);
45 } else {
46 sigact = reinterpret_cast<void *>(oact.sa_sigaction);
47 }
48
49 if (sigact != reinterpret_cast<void *>(handler)) {
50 Warning("handler for signal %d was %p, not %p as expected", signal, sigact, handler);
51 return false;
52 }
53
54 return true;
55 }
56
57 //
58 // This is used during debugging to insure that the signals
59 // don't change from under us, as they did on the DEC alpha
60 // with a specific version of pthreads.
61 //
62
63 void
check_signals(signal_handler_t handler)64 check_signals(signal_handler_t handler)
65 {
66 signal_check_handler(SIGPIPE, reinterpret_cast<signal_handler_t>(SIG_IGN));
67 signal_check_handler(SIGQUIT, handler);
68 signal_check_handler(SIGHUP, handler);
69 signal_check_handler(SIGTERM, handler);
70 signal_check_handler(SIGINT, handler);
71 signal_check_handler(SIGUSR1, handler);
72 signal_check_handler(SIGUSR2, handler);
73 }
74
75 static void
set_signal(int signo,signal_handler_t handler)76 set_signal(int signo, signal_handler_t handler)
77 {
78 struct sigaction act;
79
80 act.sa_handler = nullptr;
81 act.sa_sigaction = handler;
82 act.sa_flags = SA_SIGINFO;
83 sigemptyset(&(act.sa_mask));
84
85 ink_release_assert(sigaction(signo, &act, nullptr) == 0);
86 }
87
88 // Reset a signal handler to the default handler.
89 static void
signal_reset_default(int signo)90 signal_reset_default(int signo)
91 {
92 struct sigaction act;
93
94 act.sa_handler = SIG_DFL;
95 act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND;
96 sigemptyset(&(act.sa_mask));
97
98 ink_release_assert(sigaction(signo, &act, nullptr) == 0);
99 }
100
101 //
102 // This thread checks the signals every 2 seconds to make
103 // certain the DEC pthreads SIGPIPE bug isn't back..
104 //
105 static void *
check_signal_thread(void * ptr)106 check_signal_thread(void *ptr)
107 {
108 signal_handler_t handler = reinterpret_cast<signal_handler_t>(ptr);
109 for (;;) {
110 check_signals(handler);
111 sleep(2);
112 }
113 return nullptr;
114 }
115
116 void
signal_start_check_thread(signal_handler_t handler)117 signal_start_check_thread(signal_handler_t handler)
118 {
119 ink_thread_create(nullptr, check_signal_thread, reinterpret_cast<void *>(handler), 0, 0, nullptr);
120 }
121
122 bool
signal_is_masked(int signo)123 signal_is_masked(int signo)
124 {
125 sigset_t current;
126
127 sigemptyset(¤t);
128 if (ink_thread_sigsetmask(SIG_SETMASK, nullptr /* oldset */, ¤t) == 0) {
129 return sigismember(¤t, signo) == 1;
130 }
131
132 return false;
133 }
134
135 bool
signal_is_crash(int signo)136 signal_is_crash(int signo)
137 {
138 switch (signo) {
139 case SIGILL:
140 case SIGTRAP:
141 #if defined(SIGEMT)
142 case SIGEMT:
143 #endif
144 #if defined(SIGSYS)
145 case SIGSYS:
146 #endif
147 case SIGFPE:
148 case SIGBUS:
149 case SIGXCPU:
150 case SIGXFSZ:
151 case SIGSEGV:
152 case SIGABRT:
153 return true;
154 default:
155 return false;
156 }
157 }
158
159 void
signal_format_siginfo(int signo,siginfo_t * info,const char * msg)160 signal_format_siginfo(int signo, siginfo_t *info, const char *msg)
161 {
162 (void)info;
163 (void)signo;
164
165 char buf[64];
166
167 #if HAVE_STRSIGNAL
168 snprintf(buf, sizeof(buf), "%s: received signal %d (%s)\n", msg, signo, strsignal(signo));
169 #else
170 snprintf(buf, sizeof(buf), "%s: received signal %d\n", msg, signo);
171 #endif
172
173 ssize_t ignored = write(STDERR_FILENO, buf, strlen(buf));
174 (void)ignored; // because gcc and glibc are stupid, "(void)write(...)" doesn't suffice.
175 }
176
177 void
signal_crash_handler(int signo,siginfo_t *,void *)178 signal_crash_handler(int signo, siginfo_t *, void *)
179 {
180 ink_stack_trace_dump();
181
182 // Make sure to drop a core for signals that normally would do so.
183 signal_reset_default(signo);
184 raise(signo);
185 }
186
187 void
signal_register_crash_handler(signal_handler_t handler)188 signal_register_crash_handler(signal_handler_t handler)
189 {
190 set_signal(SIGBUS, handler);
191 set_signal(SIGSEGV, handler);
192 set_signal(SIGILL, handler);
193 set_signal(SIGTRAP, handler);
194 set_signal(SIGFPE, handler);
195 set_signal(SIGABRT, handler);
196 }
197
198 void
signal_register_default_handler(signal_handler_t handler)199 signal_register_default_handler(signal_handler_t handler)
200 {
201 sigset_t sigsToBlock;
202
203 sigemptyset(&sigsToBlock);
204 ink_thread_sigsetmask(SIG_SETMASK, &sigsToBlock, nullptr);
205
206 // SIGPIPE is just annoying to handle,we never care about it
207 signal(SIGPIPE, SIG_IGN);
208
209 // SIGHUP ought to reconfigure, but it's surprisingly complex to figure out
210 // how to do that. so leave that to libmgmt.
211 signal(SIGHUP, SIG_IGN);
212
213 set_signal(SIGQUIT, handler);
214 set_signal(SIGTERM, handler);
215 set_signal(SIGINT, handler);
216 set_signal(SIGUSR1, handler);
217 set_signal(SIGUSR2, handler);
218 }
219