xref: /trafficserver/src/tscore/signals.cc (revision 85622c7e)
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(&current);
128   if (ink_thread_sigsetmask(SIG_SETMASK, nullptr /* oldset */, &current) == 0) {
129     return sigismember(&current, 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