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>