Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 4 Oct 2009 01:58:14 -0400 (EDT)
From:      "Mikhail T." <mi@aldan.algebra.com>
To:        FreeBSD-gnats-submit@FreeBSD.org
Subject:   bin/139345: handle SIGINFO in sleep(1), etc. [patch]
Message-ID:  <200910040558.n945wEFg034787@aldan.algebra.com>
Resent-Message-ID: <200910040600.n94606HR060636@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         139345
>Category:       bin
>Synopsis:       handle SIGINFO in sleep(1), etc. [patch]
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Sun Oct 04 06:00:06 UTC 2009
>Closed-Date:
>Last-Modified:
>Originator:     Mikhail T.
>Release:        FreeBSD 7.2-STABLE amd64
>Organization:
Virtual Estates, Inc. (http://libpipe.com/)
>Environment:

>Description:
	The included patch fixes some long-standing problems with sleep(1)
	and adds nice handling of SIGINFO. It will become possible to figure
	out, how much longer it has to sleep, and what was the originally
	requested period:

	mi@aldan:src/bin/sleep (1043) /usr/obj/var/src/bin/sleep/sleep 12
	load: 0.28  cmd: sleep 34753 [running] 0.00u 0.00s 0% 608k
	sleep: about 10 seconds left out of the original 12
	load: 0.28  cmd: sleep 34753 [running] 0.00u 0.00s 0% 680k
	sleep: about 8 seconds left out of the original 12

	this could be very convenient in some situations.

	The minor fixes are:
		* detect non-numeric (or partially non-numeric)
		  time-lengths and treat them as errors, invoking
		  usage(). The current implementation can be invoked
		  as ``sleep meow'' and will simply exit immediately,
		  instead of reporting incorrect usage. The current
		  implementation can also be invoked as ``sleep 11cats''
		  and will simply sleep for 11 seconds, instead of
		  rejecting the invalid argument.
		* whenever exiting due to incorrect usage, exit with
		  the code EX_USAGE (defined as 64 in <sysexits.h>)
		  instead of code 1.
		* warn the user, if sleep is exiting prematurely due
		  to an interruption (other than SIGINFO). Arguably,
		  the program should just go back to sleep for the
		  remainder of the time, but the current implementation
		  does not, so I did not change this aspect...

>How-To-Repeat:
>Fix:

Index: sleep.c
===================================================================
RCS file: /home/ncvs/src/bin/sleep/sleep.c,v
retrieving revision 1.20
diff -U 2 -r1.20 sleep.c
--- sleep.c	7 Aug 2005 09:11:38 -0000	1.20
+++ sleep.c	4 Oct 2009 05:52:09 -0000
@@ -43,7 +43,10 @@
 
 #include <ctype.h>
+#include <err.h>
 #include <limits.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sysexits.h>
 #include <time.h>
 #include <unistd.h>
@@ -51,16 +54,22 @@
 void usage(void);
 
+volatile sig_atomic_t	report_requested = 0;
+
+static void
+report_request(int signum __unused)
+{
+	report_requested = 1;
+}
+
 int
 main(int argc, char *argv[])
 {
 	struct timespec time_to_sleep;
-	long l;
+	long l, original;
 	int neg;
 	char *p;
 
-	if (argc != 2) {
+	if (argc != 2)
 		usage();
-		return(1);
-	}
 
 	p = argv[1];
@@ -86,13 +95,15 @@
 	if (isdigit((unsigned char)*p)) {
 		l = strtol(p, &p, 10);
+		/*
+		 * Avoid overflow when `seconds' is huge.  This assumes
+		 * that the maximum value for a time_t is <= INT_MAX.
+		 */
+
 		if (l > INT_MAX) {
-			/*
-			 * Avoid overflow when `seconds' is huge.  This assumes
-			 * that the maximum value for a time_t is <= INT_MAX.
-			 */
 			l = INT_MAX;
 		}
 	} else
 		l = 0;
+
 	time_to_sleep.tv_sec = (time_t)l;
 
@@ -105,12 +116,40 @@
 			if (isdigit((unsigned char)*++p))
 				time_to_sleep.tv_nsec += (*p - '0') * l;
+			else if(*p != '\0')
+				usage();
 			else
 				break;
 			l /= 10;
 		} while (l);
-	}
+	} else if (*p != '\0')
+		usage();
 
-	if (!neg && (time_to_sleep.tv_sec > 0 || time_to_sleep.tv_nsec > 0))
-		(void)nanosleep(&time_to_sleep, (struct timespec *)NULL);
+	signal(SIGINFO, report_request); /* We don't care if it fails */
+	if (!neg && (time_to_sleep.tv_sec > 0 || time_to_sleep.tv_nsec > 0)) {
+		original = time_to_sleep.tv_sec;
+		while (nanosleep(&time_to_sleep, &time_to_sleep)) {
+			/*
+			 * Reporting does not bother with fractions
+			 * of a second...
+			 */
+			if (report_requested)
+				warnx("about %ld seconds left"
+				    " out of the original %ld",
+				    time_to_sleep.tv_sec, original);
+			else {
+				/*
+				 * The old implementation would exit here, so
+				 * that's what we are doing too. Removing
+				 * the break below would change the behavior
+				 * to "go back to sleep" -- the time_to_sleep
+				 * already contains the proper values.
+				 */
+				warn("exiting prematurely after"
+				    " %ld of the %ld seconds of sleep",
+				    original-time_to_sleep.tv_sec, original);
+				break;
+			}
+		}
+	}
 
 	return(0);
@@ -123,3 +162,4 @@
 
 	write(STDERR_FILENO, msg, sizeof(msg) - 1);
+	exit(EX_USAGE);
 }
>Release-Note:
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200910040558.n945wEFg034787>