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,18 +121,34 @@ static const int errorBufferMax = 512;
static int qt_qprocess_deadChild_pipe[2];
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);
#if defined (QPROCESS_DEBUG)
fprintf(stderr, "*** SIGCHLD\n");
#endif
// load it as volatile
void (*oldAction)(int) = ((volatile struct sigaction *)&qt_sa_old_sigchld_handler)->sa_handler;
// load as volatile
volatile struct sigaction *vsa = &qt_sa_old_sigchld_handler;
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)
{
@ -197,10 +213,16 @@ QProcessManager::QProcessManager()
// set up the SIGCHLD handler, which writes a single byte to the dead
// child pipe every time a child dies.
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_handler = qt_sa_sigchld_handler;
action.sa_flags = SA_NOCLDSTOP;
// use the old handler as template, i.e., preserve the signal mask
// otherwise the original signal handler might be interrupted although it
// 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);
processManagerInstance = this;
@ -225,7 +247,7 @@ QProcessManager::~QProcessManager()
struct sigaction 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);
}