summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@nokia.com>2011-02-03 19:40:47 (GMT)
committerThiago Macieira <thiago.macieira@nokia.com>2011-04-13 12:06:42 (GMT)
commit4e2d549e8b2e34c5bd4c77a4a6eba99ed0912168 (patch)
treea23b00f5ca7249c199aead8824baedf475220190
parent39aa998e08be078aad5fd45b827c15fc04eb8e51 (diff)
downloadQt-4e2d549e8b2e34c5bd4c77a4a6eba99ed0912168.zip
Qt-4e2d549e8b2e34c5bd4c77a4a6eba99ed0912168.tar.gz
Qt-4e2d549e8b2e34c5bd4c77a4a6eba99ed0912168.tar.bz2
Remove a race condition in SIGCHLD handler.
If the SIGCHLD is delivered *just* as we're installing our handler, there's a race condition in the setting of the old handler. So instead rely on the OS to set it properly before it calls our handler. Reviewed-by: Olivier Goffart
-rw-r--r--src/corelib/io/qprocess_unix.cpp25
1 files changed, 10 insertions, 15 deletions
diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp
index ba61bda..b93fce9 100644
--- a/src/corelib/io/qprocess_unix.cpp
+++ b/src/corelib/io/qprocess_unix.cpp
@@ -120,7 +120,7 @@ static inline char *strdup(const char *data)
#endif
static int qt_qprocess_deadChild_pipe[2];
-static void (*qt_sa_old_sigchld_handler)(int) = 0;
+static struct sigaction qt_sa_old_sigchld_handler;
static void qt_sa_sigchld_handler(int signum)
{
qt_safe_write(qt_qprocess_deadChild_pipe[1], "", 1);
@@ -128,8 +128,10 @@ static void qt_sa_sigchld_handler(int signum)
fprintf(stderr, "*** SIGCHLD\n");
#endif
- if (qt_sa_old_sigchld_handler && qt_sa_old_sigchld_handler != SIG_IGN)
- qt_sa_old_sigchld_handler(signum);
+ // load it as volatile
+ void (*oldAction)(int) = ((volatile struct sigaction *)&qt_sa_old_sigchld_handler)->sa_handler;
+ if (oldAction && oldAction != SIG_IGN)
+ oldAction(signum);
}
static inline void add_fd(int &nfds, int fd, fd_set *fdset)
@@ -190,14 +192,11 @@ QProcessManager::QProcessManager()
// set up the SIGCHLD handler, which writes a single byte to the dead
// child pipe every time a child dies.
- struct sigaction oldAction;
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_handler = qt_sa_sigchld_handler;
action.sa_flags = SA_NOCLDSTOP;
- ::sigaction(SIGCHLD, &action, &oldAction);
- if (oldAction.sa_handler != qt_sa_sigchld_handler)
- qt_sa_old_sigchld_handler = oldAction.sa_handler;
+ ::sigaction(SIGCHLD, &action, &qt_sa_old_sigchld_handler);
}
QProcessManager::~QProcessManager()
@@ -217,14 +216,10 @@ QProcessManager::~QProcessManager()
qDeleteAll(children.values());
children.clear();
- struct sigaction oldAction;
- struct sigaction action;
- memset(&action, 0, sizeof(action));
- action.sa_handler = qt_sa_old_sigchld_handler;
- action.sa_flags = SA_NOCLDSTOP;
- ::sigaction(SIGCHLD, &action, &oldAction);
- if (oldAction.sa_handler != qt_sa_sigchld_handler) {
- ::sigaction(SIGCHLD, &oldAction, 0);
+ struct sigaction currentAction;
+ ::sigaction(SIGCHLD, 0, &currentAction);
+ if (currentAction.sa_handler == qt_sa_sigchld_handler) {
+ ::sigaction(SIGCHLD, &qt_sa_old_sigchld_handler, 0);
}
}