summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Source/kwsys/SystemTools.cxx30
1 files changed, 29 insertions, 1 deletions
diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx
index 291024e..ef5b53d 100644
--- a/Source/kwsys/SystemTools.cxx
+++ b/Source/kwsys/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
}