From 45d62326a08a1e3f2855e17e657f9eb071361720 Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Tue, 25 Jul 2006 15:18:35 -0400
Subject: [PATCH] BUG: Mask signals during SystemTools::Delay to avoid
 interrupted sleep.

---
 SystemTools.cxx | 30 +++++++++++++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/SystemTools.cxx b/SystemTools.cxx
index b713367..7f1bd24 100644
--- a/SystemTools.cxx
+++ b/SystemTools.cxx
@@ -56,6 +56,7 @@
 #include <sys/ioctl.h>
 #include <unistd.h>
 #include <termios.h>
+#include <signal.h>    /* sigprocmask */
 #endif
 
 // Windows API.  Some parts used even on cygwin.
@@ -3546,7 +3547,34 @@ void SystemTools::Delay(unsigned int msec)
 #ifdef _WIN32
   Sleep(msec);
 #else
-  usleep(msec * 1000);
+  // Block signals to make sure the entire sleep duration occurs.  If
+  // a signal were to arrive the sleep or usleep might return early
+  // and there is no way to accurately know how much time was really
+  // slept without setting up timers.
+  sigset_t newset;
+  sigset_t oldset;
+  sigfillset(&newset);
+  sigprocmask(SIG_BLOCK, &newset, &oldset);
+
+  // The sleep function gives 1 second resolution and the usleep
+  // function gives 1e-6 second resolution but on some platforms has a
+  // maximum sleep time of 1 second.  This could be re-implemented to
+  // use select with masked signals or pselect to mask signals
+  // atomically.  If select is given empty sets and zero as the max
+  // file descriptor but a non-zero timeout it can be used to block
+  // for a precise amount of time.
+  if(msec >= 1000)
+    {
+    sleep(msec / 1000);
+    usleep((msec % 1000) * 1000);
+    }
+  else
+    {
+    usleep(msec * 1000);
+    }
+
+  // Restore the signal mask to the previous setting.
+  sigprocmask(SIG_SETMASK, &oldset, 0);
 #endif
 }
 
-- 
GitLab