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 |