[PATCH xorg-gtest 4/8] process: wait for SIGCHLD instead of busy looping

Peter Hutterer peter.hutterer at who-t.net
Tue Oct 9 22:14:29 PDT 2012


If for some reason we fail to handle the signals, usleep for the timeout
instead. This will slow down the tests, but still behave properly. And if a
test fails with the usleep, the SCOPED_TRACE will print out the warnings.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 src/process.cpp | 47 +++++++++++++++++++++++++++++++----------------
 1 file changed, 31 insertions(+), 16 deletions(-)

diff --git a/src/process.cpp b/src/process.cpp
index 0b0ddc3..7f7d330 100644
--- a/src/process.cpp
+++ b/src/process.cpp
@@ -127,25 +127,40 @@ void xorg::testing::Process::Start(const std::string& program, ...) {
 }
 
 bool xorg::testing::Process::WaitForExit(unsigned int timeout) {
-  for (unsigned int i = 0; i < timeout * 100; i++) {
-    int status;
-    int pid = waitpid(Pid(), &status, WNOHANG);
-
-    if (pid == Pid()) {
-      if (WIFEXITED(status)) {
-        d_->state = WEXITSTATUS(status) ? FINISHED_FAILURE : FINISHED_SUCCESS;
-        return true;
-      } else if (WIFSIGNALED(status)) {
-        d_->state = FINISHED_FAILURE;
-        return true;
-      }
-    } else if (pid == -1)
-      return errno == ECHILD;
+  sigset_t sig_mask, old_mask;
+  sigemptyset(&sig_mask);
+  sigaddset(&sig_mask, SIGCHLD);
+
+  if (sigprocmask(SIG_BLOCK, &sig_mask, &old_mask) == 0) {
+    struct timespec sig_timeout = {timeout / 1000,
+                                   (timeout % 1000) * 1000000L};
+
+    if (sigtimedwait(&sig_mask, NULL, &sig_timeout) != SIGCHLD && errno != EAGAIN) {
+      SCOPED_TRACE("INFO: Failure waiting for SIGCHLD: " +
+                   std::string(strerror(errno)) + ". I slept instead.");
+      usleep(timeout * 1000);
+    }
 
-      usleep(10);
+    if (!sigismember(&sig_mask, SIGCHLD)) {
+      if (sigprocmask(SIG_UNBLOCK, &sig_mask, NULL) == -1)
+        SCOPED_TRACE("WARNING: Failed to unblock SIGCHLD. Tests may behave funny.\n");
+    }
+  } else { /* oops, can't wait for SIGCHLD, sleep instead */
+    SCOPED_TRACE("INFO: Failed to set SIGCHLD mask, sleeping instead.\n");
+    usleep(timeout * 1000);
   }
 
-  return false;
+  int status;
+  int pid = waitpid(Pid(), &status, WNOHANG);
+  if (pid == Pid()) {
+    if (WIFEXITED(status)) {
+      d_->state = WEXITSTATUS(status) ? FINISHED_FAILURE : FINISHED_SUCCESS;
+    } else if (WIFSIGNALED(status)) {
+      d_->state = FINISHED_FAILURE;
+    }
+    return true;
+  } else
+    return (pid == -1 && errno == ECHILD);
 }
 
 bool xorg::testing::Process::KillSelf(int signal, unsigned int timeout) {
-- 
1.7.11.4



More information about the xorg-devel mailing list