The sleep builtin currently doesn't do much in the way of signal
management, so for example it will return on SIGWINCH, which I think most
users will be particularly surprised by the first time they notice a sleep
ending early due to a window resize.

I looked at adding more signal handling to the current select-based
implementation but then realized it would be a lot easier to just use
nanosleep(2).

Both select() and nanosleep() first appear in 1997's XSH Issue 5 so I don't
know if we need to worry much about systems without it. (The patch leaves
the select/pselect code as fallback though).

---
diff --git a/config.h.in b/config.h.in
index c2750a2a..1b6a1853 100644
--- a/config.h.in
+++ b/config.h.in
@@ -771,6 +771,9 @@
 /* Define if you have the mkstemp function.  */
 #undef HAVE_MKSTEMP

+/* Define if you have the nonosleep function.  */
+#undef HAVE_NANOSLEEP
+
 /* Define if you have the pathconf function. */
 #undef HAVE_PATHCONF

diff --git a/configure.ac b/configure.ac
index 29f50438..de7d693c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -850,9 +850,9 @@ AC_REPLACE_FUNCS(rename)
 dnl checks for c library functions
 AC_CHECK_FUNCS(bcopy bzero clock_gettime confstr faccessat fnmatch \
                getaddrinfo gethostbyname getservbyname getservent
inet_aton \
-               imaxdiv memmove pathconf putenv raise random regcomp
regexec \
-               setenv setlinebuf setlocale setvbuf siginterrupt strchr \
-               sysconf syslog tcgetattr times ttyname tzset unsetenv)
+               imaxdiv memmove nanosleep pathconf putenv raise random
regcomp \
+               regexec setenv setlinebuf setlocale setvbuf siginterrupt \
+               strchr sysconf syslog tcgetattr times ttyname tzset
unsetenv)

 AC_CHECK_FUNCS(vasprintf asprintf)
 AC_CHECK_FUNCS(isascii isblank isgraph isprint isspace isxdigit)
diff --git a/lib/sh/ufuncs.c b/lib/sh/ufuncs.c
index 247224d6..b3894450 100644
--- a/lib/sh/ufuncs.c
+++ b/lib/sh/ufuncs.c
@@ -82,7 +82,26 @@ falarm (unsigned int secs, unsigned int usecs)
 /* A version of sleep using fractional seconds and select.  I'd like to use
    `usleep', but it's already taken */

-#if defined (HAVE_TIMEVAL) && (defined (HAVE_SELECT) || defined
(HAVE_PSELECT))
+#if defined (HAVE_NANOSLEEP)
+int
+fsleep(unsigned int sec, unsigned int usec)
+{
+  int r;
+  struct timespec req, rem;
+
+  req.tv_sec = sec;
+  req.tv_nsec = usec * 1000;
+
+  for (;;)
+    {
+      QUIT;
+      r = nanosleep (&req, &rem);
+      if (r == 0 || errno != EINTR)
+        return r;
+      req = rem;
+    }
+}
+#elif defined (HAVE_TIMEVAL) && (defined (HAVE_SELECT) || defined
(HAVE_PSELECT))
 int
 fsleep(unsigned int sec, unsigned int usec)
 {
From a33289b218028b6d72966d8253646d6f174e09a5 Mon Sep 17 00:00:00 2001
From: Grisha Levit <grishalevit@gmail.com>
Date: Thu, 29 Jun 2023 21:55:05 -0400
Subject: [PATCH] fsleep: use nanosleep, handle signals

---
 config.h.in     |  3 +++
 configure.ac    |  6 +++---
 lib/sh/ufuncs.c | 21 ++++++++++++++++++++-
 3 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/config.h.in b/config.h.in
index c2750a2a..1b6a1853 100644
--- a/config.h.in
+++ b/config.h.in
@@ -771,6 +771,9 @@
 /* Define if you have the mkstemp function.  */
 #undef HAVE_MKSTEMP
 
+/* Define if you have the nonosleep function.  */
+#undef HAVE_NANOSLEEP
+
 /* Define if you have the pathconf function. */
 #undef HAVE_PATHCONF
 
diff --git a/configure.ac b/configure.ac
index 29f50438..de7d693c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -850,9 +850,9 @@ AC_REPLACE_FUNCS(rename)
 dnl checks for c library functions
 AC_CHECK_FUNCS(bcopy bzero clock_gettime confstr faccessat fnmatch \
 		getaddrinfo gethostbyname getservbyname getservent inet_aton \
-		imaxdiv memmove pathconf putenv raise random regcomp regexec \
-		setenv setlinebuf setlocale setvbuf siginterrupt strchr \
-		sysconf syslog tcgetattr times ttyname tzset unsetenv)
+		imaxdiv memmove nanosleep pathconf putenv raise random regcomp \
+		regexec setenv setlinebuf setlocale setvbuf siginterrupt \
+		strchr sysconf syslog tcgetattr times ttyname tzset unsetenv)
 
 AC_CHECK_FUNCS(vasprintf asprintf)
 AC_CHECK_FUNCS(isascii isblank isgraph isprint isspace isxdigit)
diff --git a/lib/sh/ufuncs.c b/lib/sh/ufuncs.c
index 247224d6..b3894450 100644
--- a/lib/sh/ufuncs.c
+++ b/lib/sh/ufuncs.c
@@ -82,7 +82,26 @@ falarm (unsigned int secs, unsigned int usecs)
 /* A version of sleep using fractional seconds and select.  I'd like to use
    `usleep', but it's already taken */
 
-#if defined (HAVE_TIMEVAL) && (defined (HAVE_SELECT) || defined (HAVE_PSELECT))
+#if defined (HAVE_NANOSLEEP)
+int
+fsleep(unsigned int sec, unsigned int usec)
+{
+  int r;
+  struct timespec req, rem;
+
+  req.tv_sec = sec;
+  req.tv_nsec = usec * 1000;
+
+  for (;;)
+    {
+      QUIT;
+      r = nanosleep (&req, &rem);
+      if (r == 0 || errno != EINTR)
+        return r;
+      req = rem;
+    }
+}
+#elif defined (HAVE_TIMEVAL) && (defined (HAVE_SELECT) || defined (HAVE_PSELECT))
 int
 fsleep(unsigned int sec, unsigned int usec)
 {
-- 
2.41.0

Reply via email to