From a9879b9260948c60e1a74f6f7119095f757d7334 Mon Sep 17 00:00:00 2001
From: Gavin Hurlbut <ghurlbut@mythtv.org>
Date: Sat, 22 Sep 2012 01:41:32 -0700
Subject: [PATCH] Add support for real time signal 0 handling
Fixes #11110
Seems that some setups (in particular Ubuntu 12.04) are seeing our applications
getting killed by SIGRTMIN. As I have no clue what is causing this, I am
changing the signal handling to use sigaction's extended handlers that hand
off siginfo_t as well. This gives us the source of the signal.
Additionally, I added a default handler for SIGRTMIN. This should end that
nuisance.
---
mythtv/libs/libmythbase/signalhandling.cpp | 84 +++++++++++++++++++++------
mythtv/libs/libmythbase/signalhandling.h | 12 +++-
mythtv/programs/mythavtest/main.cpp | 2 +-
mythtv/programs/mythbackend/main.cpp | 2 +-
mythtv/programs/mythccextractor/main.cpp | 2 +-
mythtv/programs/mythcommflag/main.cpp | 2 +-
mythtv/programs/mythfilldatabase/main.cpp | 2 +-
mythtv/programs/mythfrontend/main.cpp | 2 +-
mythtv/programs/mythjobqueue/main.cpp | 2 +-
mythtv/programs/mythlcdserver/main.cpp | 2 +-
mythtv/programs/mythlogserver/main.cpp | 2 +-
mythtv/programs/mythmediaserver/main.cpp | 2 +-
mythtv/programs/mythmetadatalookup/main.cpp | 2 +-
mythtv/programs/mythpreviewgen/main.cpp | 2 +-
mythtv/programs/mythshutdown/main.cpp | 2 +-
mythtv/programs/mythtranscode/main.cpp | 2 +-
mythtv/programs/mythtv-setup/main.cpp | 2 +-
mythtv/programs/mythutil/main.cpp | 2 +-
mythtv/programs/mythwelcome/main.cpp | 2 +-
19 files changed, 91 insertions(+), 39 deletions(-)
diff --git a/mythtv/libs/libmythbase/signalhandling.cpp b/mythtv/libs/libmythbase/signalhandling.cpp
index aae4aef..616693d 100644
a
|
b
|
SignalHandler::SignalHandler(QList<int> &signallist, QObject *parent) : |
63 | 63 | s_exit_program = false; // set here due to "C++ static initializer madness" |
64 | 64 | sig_str_init(); |
65 | 65 | |
| 66 | m_sigStack = new char[SIGSTKSZ]; |
| 67 | stack_t stack; |
| 68 | stack.ss_sp = (void *)m_sigStack; |
| 69 | stack.ss_flags = 0; |
| 70 | stack.ss_size = SIGSTKSZ; |
| 71 | |
| 72 | // Carry on without the signal stack if it fails |
| 73 | if (sigaltstack(&stack, NULL) == -1) |
| 74 | { |
| 75 | cerr << "Couldn't create signal stack!" << endl; |
| 76 | delete [] m_sigStack; |
| 77 | m_sigStack = NULL; |
| 78 | } |
| 79 | |
66 | 80 | if (s_defaultHandlerList.isEmpty()) |
67 | 81 | s_defaultHandlerList << SIGINT << SIGTERM << SIGSEGV << SIGABRT |
68 | 82 | #ifndef _WIN32 |
69 | 83 | << SIGBUS |
70 | 84 | #endif |
71 | | << SIGFPE << SIGILL; |
| 85 | << SIGFPE << SIGILL << SIGRTMIN; |
72 | 86 | |
73 | 87 | #ifndef _WIN32 |
74 | 88 | if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigFd)) |
… |
… |
SignalHandler::~SignalHandler() |
107 | 121 | } |
108 | 122 | |
109 | 123 | QMutexLocker locker(&m_sigMapLock); |
110 | | QMap<int, void (*)(void)>::iterator it = m_sigMap.begin(); |
| 124 | QMap<int, SigHandlerFunc>::iterator it = m_sigMap.begin(); |
111 | 125 | for ( ; it != m_sigMap.end(); ++it) |
112 | 126 | { |
113 | 127 | int signum = it.key(); |
… |
… |
void SignalHandler::Done(void) |
133 | 147 | } |
134 | 148 | |
135 | 149 | |
136 | | void SignalHandler::SetHandler(int signum, void (*handler)(void)) |
| 150 | void SignalHandler::SetHandler(int signum, SigHandlerFunc handler) |
137 | 151 | { |
138 | 152 | QMutexLocker locker(&s_singletonLock); |
139 | 153 | if (s_singleton) |
140 | 154 | s_singleton->SetHandlerPrivate(signum, handler); |
141 | 155 | } |
142 | 156 | |
143 | | void SignalHandler::SetHandlerPrivate(int signum, void (*handler)(void)) |
| 157 | void SignalHandler::SetHandlerPrivate(int signum, SigHandlerFunc handler) |
144 | 158 | { |
145 | 159 | #ifndef _WIN32 |
146 | 160 | const char *signame = strsignal(signum); |
… |
… |
void SignalHandler::SetHandlerPrivate(int signum, void (*handler)(void)) |
163 | 177 | if (!sa_handler_already_set) |
164 | 178 | { |
165 | 179 | struct sigaction sa; |
166 | | sa.sa_handler = SignalHandler::signalHandler; |
| 180 | sa.sa_sigaction = SignalHandler::signalHandler; |
167 | 181 | sigemptyset(&sa.sa_mask); |
168 | | sa.sa_flags = SA_RESTART; |
| 182 | sa.sa_flags = SA_RESTART | SA_SIGINFO; |
| 183 | if (m_sigStack) |
| 184 | sa.sa_flags |= SA_ONSTACK; |
169 | 185 | |
170 | 186 | sig_str_init(signum, qPrintable(signal_name)); |
171 | 187 | |
… |
… |
void SignalHandler::SetHandlerPrivate(int signum, void (*handler)(void)) |
176 | 192 | #endif |
177 | 193 | } |
178 | 194 | |
179 | | void SignalHandler::signalHandler(int signum) |
| 195 | typedef struct { |
| 196 | int signum; |
| 197 | int code; |
| 198 | int pid; |
| 199 | int uid; |
| 200 | uint64_t value; |
| 201 | } SignalInfo; |
| 202 | |
| 203 | void SignalHandler::signalHandler(int signum, siginfo_t *info, void *context) |
180 | 204 | { |
181 | | char a = (char)signum; |
| 205 | SignalInfo signalInfo; |
| 206 | |
| 207 | (void)context; |
| 208 | signalInfo.signum = signum; |
| 209 | signalInfo.code = (info ? info->si_code : 0); |
| 210 | signalInfo.pid = (info ? (int)info->si_pid : 0); |
| 211 | signalInfo.uid = (info ? (int)info->si_uid : 0); |
| 212 | signalInfo.value = (info ? (uint64_t)info->si_ptr : 0); |
182 | 213 | |
183 | 214 | // Keep trying if there's no room to write, but stop on error (-1) |
184 | | while (::write(sigFd[0], &a, 1) == 0); |
| 215 | int index = 0; |
| 216 | int size = sizeof(SignalInfo); |
| 217 | char *buffer = (char *)&signalInfo; |
| 218 | do { |
| 219 | int written = ::write(sigFd[0], &buffer[index], size); |
| 220 | // If there's an error, the signal will not be seen be the application, |
| 221 | // but we can't keep trying. |
| 222 | if (written < 0) |
| 223 | break; |
| 224 | index += written; |
| 225 | size -= written; |
| 226 | } while (size > 0); |
185 | 227 | |
186 | 228 | // One must not return from SEGV, ILL, BUS or FPE. When these |
187 | 229 | // are raised by the program itself they will immediately get |
… |
… |
void SignalHandler::handleSignal(void) |
237 | 279 | #ifndef _WIN32 |
238 | 280 | m_notifier->setEnabled(false); |
239 | 281 | |
240 | | char a; |
241 | | int ret = ::read(sigFd[1], &a, sizeof(a)); |
242 | | int signum = (int)a; |
243 | | (void)ret; |
| 282 | SignalInfo signalInfo; |
| 283 | int ret = ::read(sigFd[1], &signalInfo, sizeof(SignalInfo)); |
| 284 | bool infoComplete = (ret == sizeof(SignalInfo)); |
| 285 | int signum = (infoComplete ? signalInfo.signum : 0); |
244 | 286 | |
245 | | const char *signame = strsignal(signum); |
246 | | signame = strdup(signame ? signame : "Unknown"); |
247 | | LOG(VB_GENERAL, LOG_CRIT, QString("Received %1").arg(signame)); |
248 | | free((void *)signame); |
| 287 | if (infoComplete) |
| 288 | { |
| 289 | const char *signame = strsignal(signum); |
| 290 | signame = strdup(signame ? signame : "Unknown Signal"); |
| 291 | LOG(VB_GENERAL, LOG_CRIT, |
| 292 | QString("Received %1: Code %2, PID %3, UID %4, Value 0x%5") |
| 293 | .arg(signame) .arg(signalInfo.code) .arg(signalInfo.pid) |
| 294 | .arg(signalInfo.uid) .arg(signalInfo.value,8,16,QChar('0'))); |
| 295 | free((void *)signame); |
| 296 | } |
249 | 297 | |
250 | | void (*handler)(void) = NULL; |
| 298 | SigHandlerFunc handler = NULL; |
251 | 299 | |
252 | 300 | switch (signum) |
253 | 301 | { |
diff --git a/mythtv/libs/libmythbase/signalhandling.h b/mythtv/libs/libmythbase/signalhandling.h
index 73f96a7..5d39d01 100644
a
|
b
|
|
14 | 14 | #include "mythbaseexp.h" // MBASE_PUBLIC , etc. |
15 | 15 | #include "mthread.h" |
16 | 16 | |
| 17 | typedef void (*SigHandlerFunc)(void); |
| 18 | |
17 | 19 | /// \brief A container object to handle UNIX signals in the Qt space correctly |
18 | 20 | class MBASE_PUBLIC SignalHandler: public QObject |
19 | 21 | { |
… |
… |
class MBASE_PUBLIC SignalHandler: public QObject |
23 | 25 | static void Init(QList<int> &signallist, QObject *parent = NULL); |
24 | 26 | static void Done(void); |
25 | 27 | |
26 | | static void SetHandler(int signal, void (*handler)(void)); |
| 28 | static void SetHandler(int signal, SigHandlerFunc handler); |
27 | 29 | |
28 | 30 | static bool IsExiting(void) { return s_exit_program; } |
29 | 31 | |
30 | 32 | // Unix signal handler. |
31 | | static void signalHandler(int signum); |
| 33 | // context is of type ucontext_t * cast to void * |
| 34 | static void signalHandler(int signum, siginfo_t *info, void *context); |
32 | 35 | |
33 | 36 | public slots: |
34 | 37 | // Qt signal handler. |
… |
… |
class MBASE_PUBLIC SignalHandler: public QObject |
37 | 40 | private: |
38 | 41 | SignalHandler(QList<int> &signallist, QObject *parent); |
39 | 42 | ~SignalHandler(); |
40 | | void SetHandlerPrivate(int signal, void (*handler)(void)); |
| 43 | void SetHandlerPrivate(int signal, SigHandlerFunc handler); |
41 | 44 | |
42 | 45 | static int sigFd[2]; |
43 | 46 | static volatile bool s_exit_program; |
44 | 47 | QSocketNotifier *m_notifier; |
| 48 | char *m_sigStack; |
45 | 49 | |
46 | 50 | QMutex m_sigMapLock; |
47 | | QMap<int, void (*)(void)> m_sigMap; |
| 51 | QMap<int, SigHandlerFunc> m_sigMap; |
48 | 52 | static QList<int> s_defaultHandlerList; |
49 | 53 | |
50 | 54 | static QMutex s_singletonLock; |
diff --git a/mythtv/programs/mythavtest/main.cpp b/mythtv/programs/mythavtest/main.cpp
index 9bf14c5..8ed2ba1 100644
a
|
b
|
int main(int argc, char *argv[]) |
232 | 232 | #ifndef _WIN32 |
233 | 233 | QList<int> signallist; |
234 | 234 | signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE |
235 | | << SIGILL; |
| 235 | << SIGILL << SIGRTMIN; |
236 | 236 | SignalHandler::Init(signallist); |
237 | 237 | signal(SIGHUP, SIG_IGN); |
238 | 238 | #endif |
diff --git a/mythtv/programs/mythbackend/main.cpp b/mythtv/programs/mythbackend/main.cpp
index 3c508ca..22820bf 100644
a
|
b
|
int main(int argc, char **argv) |
103 | 103 | #ifndef _WIN32 |
104 | 104 | QList<int> signallist; |
105 | 105 | signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE |
106 | | << SIGILL; |
| 106 | << SIGILL << SIGRTMIN; |
107 | 107 | SignalHandler::Init(signallist); |
108 | 108 | signal(SIGHUP, SIG_IGN); |
109 | 109 | #endif |
diff --git a/mythtv/programs/mythccextractor/main.cpp b/mythtv/programs/mythccextractor/main.cpp
index a34b904..68272bd 100644
a
|
b
|
int main(int argc, char *argv[]) |
145 | 145 | #ifndef _WIN32 |
146 | 146 | QList<int> signallist; |
147 | 147 | signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE |
148 | | << SIGILL; |
| 148 | << SIGILL << SIGRTMIN; |
149 | 149 | SignalHandler::Init(signallist); |
150 | 150 | signal(SIGHUP, SIG_IGN); |
151 | 151 | #endif |
diff --git a/mythtv/programs/mythcommflag/main.cpp b/mythtv/programs/mythcommflag/main.cpp
index ba12406..5c03c1d 100644
a
|
b
|
int main(int argc, char *argv[]) |
1126 | 1126 | #ifndef _WIN32 |
1127 | 1127 | QList<int> signallist; |
1128 | 1128 | signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE |
1129 | | << SIGILL; |
| 1129 | << SIGILL << SIGRTMIN; |
1130 | 1130 | SignalHandler::Init(signallist); |
1131 | 1131 | signal(SIGHUP, SIG_IGN); |
1132 | 1132 | #endif |
diff --git a/mythtv/programs/mythfilldatabase/main.cpp b/mythtv/programs/mythfilldatabase/main.cpp
index a90381d..30c1352 100644
a
|
b
|
int main(int argc, char *argv[]) |
348 | 348 | #ifndef _WIN32 |
349 | 349 | QList<int> signallist; |
350 | 350 | signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE |
351 | | << SIGILL; |
| 351 | << SIGILL << SIGRTMIN; |
352 | 352 | SignalHandler::Init(signallist); |
353 | 353 | signal(SIGHUP, SIG_IGN); |
354 | 354 | #endif |
diff --git a/mythtv/programs/mythfrontend/main.cpp b/mythtv/programs/mythfrontend/main.cpp
index 0192097..9d91967 100644
a
|
b
|
int main(int argc, char **argv) |
1478 | 1478 | #ifndef _WIN32 |
1479 | 1479 | QList<int> signallist; |
1480 | 1480 | signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE |
1481 | | << SIGILL; |
| 1481 | << SIGILL << SIGRTMIN; |
1482 | 1482 | SignalHandler::Init(signallist); |
1483 | 1483 | SignalHandler::SetHandler(SIGUSR1, handleSIGUSR1); |
1484 | 1484 | SignalHandler::SetHandler(SIGUSR2, handleSIGUSR2); |
diff --git a/mythtv/programs/mythjobqueue/main.cpp b/mythtv/programs/mythjobqueue/main.cpp
index 1718808..bd9c638 100644
a
|
b
|
int main(int argc, char *argv[]) |
113 | 113 | #ifndef _WIN32 |
114 | 114 | QList<int> signallist; |
115 | 115 | signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE |
116 | | << SIGILL; |
| 116 | << SIGILL << SIGRTMIN; |
117 | 117 | SignalHandler::Init(signallist); |
118 | 118 | signal(SIGHUP, SIG_IGN); |
119 | 119 | #endif |
diff --git a/mythtv/programs/mythlcdserver/main.cpp b/mythtv/programs/mythlcdserver/main.cpp
index f9d84e5..a211195 100644
a
|
b
|
int main(int argc, char **argv) |
100 | 100 | #ifndef _WIN32 |
101 | 101 | QList<int> signallist; |
102 | 102 | signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE |
103 | | << SIGILL; |
| 103 | << SIGILL << SIGRTMIN; |
104 | 104 | SignalHandler::Init(signallist); |
105 | 105 | signal(SIGHUP, SIG_IGN); |
106 | 106 | #endif |
diff --git a/mythtv/programs/mythlogserver/main.cpp b/mythtv/programs/mythlogserver/main.cpp
index f327c47..9d9ebca 100644
a
|
b
|
int main(int argc, char *argv[]) |
105 | 105 | #ifndef _WIN32 |
106 | 106 | QList<int> signallist; |
107 | 107 | signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE |
108 | | << SIGILL; |
| 108 | << SIGILL << SIGRTMIN; |
109 | 109 | SignalHandler::Init(signallist); |
110 | 110 | SignalHandler::SetHandler(SIGHUP, logSigHup); |
111 | 111 | #endif |
diff --git a/mythtv/programs/mythmediaserver/main.cpp b/mythtv/programs/mythmediaserver/main.cpp
index 66e744b..756afd6 100644
a
|
b
|
int main(int argc, char *argv[]) |
111 | 111 | #ifndef _WIN32 |
112 | 112 | QList<int> signallist; |
113 | 113 | signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE |
114 | | << SIGILL; |
| 114 | << SIGILL << SIGRTMIN; |
115 | 115 | SignalHandler::Init(signallist); |
116 | 116 | signal(SIGHUP, SIG_IGN); |
117 | 117 | #endif |
diff --git a/mythtv/programs/mythmetadatalookup/main.cpp b/mythtv/programs/mythmetadatalookup/main.cpp
index ed8f737..c18b030 100644
a
|
b
|
int main(int argc, char *argv[]) |
91 | 91 | #ifndef _WIN32 |
92 | 92 | QList<int> signallist; |
93 | 93 | signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE |
94 | | << SIGILL; |
| 94 | << SIGILL << SIGRTMIN; |
95 | 95 | SignalHandler::Init(signallist); |
96 | 96 | signal(SIGHUP, SIG_IGN); |
97 | 97 | #endif |
diff --git a/mythtv/programs/mythpreviewgen/main.cpp b/mythtv/programs/mythpreviewgen/main.cpp
index 388bacb..5c238e2 100644
a
|
b
|
int main(int argc, char **argv) |
206 | 206 | #ifndef _WIN32 |
207 | 207 | QList<int> signallist; |
208 | 208 | signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE |
209 | | << SIGILL; |
| 209 | << SIGILL << SIGRTMIN; |
210 | 210 | SignalHandler::Init(signallist); |
211 | 211 | signal(SIGHUP, SIG_IGN); |
212 | 212 | #endif |
diff --git a/mythtv/programs/mythshutdown/main.cpp b/mythtv/programs/mythshutdown/main.cpp
index 33fd682..1505924 100644
a
|
b
|
int main(int argc, char **argv) |
787 | 787 | #ifndef _WIN32 |
788 | 788 | QList<int> signallist; |
789 | 789 | signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE |
790 | | << SIGILL; |
| 790 | << SIGILL << SIGRTMIN; |
791 | 791 | SignalHandler::Init(signallist); |
792 | 792 | signal(SIGHUP, SIG_IGN); |
793 | 793 | #endif |
diff --git a/mythtv/programs/mythtranscode/main.cpp b/mythtv/programs/mythtranscode/main.cpp
index 0a08d39..49a1a7a 100644
a
|
b
|
int main(int argc, char *argv[]) |
377 | 377 | #ifndef _WIN32 |
378 | 378 | QList<int> signallist; |
379 | 379 | signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE |
380 | | << SIGILL; |
| 380 | << SIGILL << SIGRTMIN; |
381 | 381 | SignalHandler::Init(signallist); |
382 | 382 | signal(SIGHUP, SIG_IGN); |
383 | 383 | #endif |
diff --git a/mythtv/programs/mythtv-setup/main.cpp b/mythtv/programs/mythtv-setup/main.cpp
index 36cd975..6313767 100644
a
|
b
|
int main(int argc, char *argv[]) |
287 | 287 | #ifndef _WIN32 |
288 | 288 | QList<int> signallist; |
289 | 289 | signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE |
290 | | << SIGILL; |
| 290 | << SIGILL << SIGRTMIN; |
291 | 291 | SignalHandler::Init(signallist); |
292 | 292 | signal(SIGHUP, SIG_IGN); |
293 | 293 | #endif |
diff --git a/mythtv/programs/mythutil/main.cpp b/mythtv/programs/mythutil/main.cpp
index 655d39a..1e6c4bb 100644
a
|
b
|
int main(int argc, char *argv[]) |
79 | 79 | #ifndef _WIN32 |
80 | 80 | QList<int> signallist; |
81 | 81 | signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE |
82 | | << SIGILL; |
| 82 | << SIGILL << SIGRTMIN; |
83 | 83 | SignalHandler::Init(signallist); |
84 | 84 | signal(SIGHUP, SIG_IGN); |
85 | 85 | #endif |
diff --git a/mythtv/programs/mythwelcome/main.cpp b/mythtv/programs/mythwelcome/main.cpp
index 8b925be..ee8fdf2 100644
a
|
b
|
int main(int argc, char **argv) |
77 | 77 | #ifndef _WIN32 |
78 | 78 | QList<int> signallist; |
79 | 79 | signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE |
80 | | << SIGILL; |
| 80 | << SIGILL << SIGRTMIN; |
81 | 81 | SignalHandler::Init(signallist); |
82 | 82 | signal(SIGHUP, SIG_IGN); |
83 | 83 | #endif |