Fix sigchld-Handler

Changed the sigchld-Handler such that the SA_SIGINFO flag is handeled
correctly. Furthermore the signal mask is preserved such that the original
signal handler is not interrupted when not allowed.

Task-number: QTBUG-32979
Change-Id: Iec7663e7289ea5d95155f52cf8788ebf646cfabd
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
H. Rittich 2013-09-13 17:28:23 +02:00 committed by The Qt Project
parent ddecbae5e1
commit 97279d0582

View File

@ -121,17 +121,33 @@ static const int errorBufferMax = 512;
static int qt_qprocess_deadChild_pipe[2]; static int qt_qprocess_deadChild_pipe[2];
static struct sigaction qt_sa_old_sigchld_handler; static struct sigaction qt_sa_old_sigchld_handler;
static void qt_sa_sigchld_handler(int signum) static void qt_sa_sigchld_sigaction(int signum, siginfo_t *info, void *context)
{ {
// *Never* use the info or contect variables in this function
// (except for passing them to the next signal in the chain).
// We cannot be sure if another library or if the application
// installed a signal handler for SIGCHLD without SA_SIGINFO
// and fails to pass the arguments to us. If they do that,
// these arguments contain garbage and we'd most likely crash.
qt_safe_write(qt_qprocess_deadChild_pipe[1], "", 1); qt_safe_write(qt_qprocess_deadChild_pipe[1], "", 1);
#if defined (QPROCESS_DEBUG) #if defined (QPROCESS_DEBUG)
fprintf(stderr, "*** SIGCHLD\n"); fprintf(stderr, "*** SIGCHLD\n");
#endif #endif
// load it as volatile // load as volatile
void (*oldAction)(int) = ((volatile struct sigaction *)&qt_sa_old_sigchld_handler)->sa_handler; volatile struct sigaction *vsa = &qt_sa_old_sigchld_handler;
if (oldAction && oldAction != SIG_IGN)
oldAction(signum); if (qt_sa_old_sigchld_handler.sa_flags & SA_SIGINFO) {
void (*oldAction)(int, siginfo_t *, void *) = vsa->sa_sigaction;
oldAction(signum, info, context);
} else {
void (*oldAction)(int) = vsa->sa_handler;
if (oldAction && oldAction != SIG_IGN)
oldAction(signum);
}
} }
static inline void add_fd(int &nfds, int fd, fd_set *fdset) static inline void add_fd(int &nfds, int fd, fd_set *fdset)
@ -197,10 +213,16 @@ QProcessManager::QProcessManager()
// set up the SIGCHLD handler, which writes a single byte to the dead // set up the SIGCHLD handler, which writes a single byte to the dead
// child pipe every time a child dies. // child pipe every time a child dies.
struct sigaction action; struct sigaction action;
memset(&action, 0, sizeof(action)); // use the old handler as template, i.e., preserve the signal mask
action.sa_handler = qt_sa_sigchld_handler; // otherwise the original signal handler might be interrupted although it
action.sa_flags = SA_NOCLDSTOP; // was marked to never be interrupted
::sigaction(SIGCHLD, NULL, &action);
action.sa_sigaction = qt_sa_sigchld_sigaction;
// set the SA_SIGINFO flag such that we can use the three argument handler
// function
action.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
::sigaction(SIGCHLD, &action, &qt_sa_old_sigchld_handler); ::sigaction(SIGCHLD, &action, &qt_sa_old_sigchld_handler);
processManagerInstance = this; processManagerInstance = this;
@ -225,7 +247,7 @@ QProcessManager::~QProcessManager()
struct sigaction currentAction; struct sigaction currentAction;
::sigaction(SIGCHLD, 0, &currentAction); ::sigaction(SIGCHLD, 0, &currentAction);
if (currentAction.sa_handler == qt_sa_sigchld_handler) { if (currentAction.sa_sigaction == qt_sa_sigchld_sigaction) {
::sigaction(SIGCHLD, &qt_sa_old_sigchld_handler, 0); ::sigaction(SIGCHLD, &qt_sa_old_sigchld_handler, 0);
} }