timeout: add support for "timeout -k KILL_SECS"

function                                             old     new   delta
timeout_main                                         307     373     +66
timeout_wait                                           -      42     +42
.rodata                                           104201  104203      +2
packed_usage                                       34097   34096      -1
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 2/1 up/down: 110/-1)            Total: 109 bytes

Signed-off-by: Matthew Slowe <foo@mafoo.org.uk>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Matthew Slowe 2021-10-09 12:26:40 +01:00 committed by Denys Vlasenko
parent c1eac153e8
commit 7d49fedc86

View File

@ -39,13 +39,29 @@
//kbuild:lib-$(CONFIG_TIMEOUT) += timeout.o //kbuild:lib-$(CONFIG_TIMEOUT) += timeout.o
//usage:#define timeout_trivial_usage //usage:#define timeout_trivial_usage
//usage: "[-s SIG] SECS PROG ARGS" //usage: "[-s SIG] [-k KILL_SECS] SECS PROG ARGS"
//usage:#define timeout_full_usage "\n\n" //usage:#define timeout_full_usage "\n\n"
//usage: "Run PROG. Send SIG to it if it is not gone in SECS seconds.\n" //usage: "Run PROG. Send SIG to it if it is not gone in SECS seconds.\n"
//usage: "Default SIG: TERM." //usage: "Default SIG: TERM."
//usage: "If it still exists in KILL_SECS seconds, send KILL.\n"
#include "libbb.h" #include "libbb.h"
static NOINLINE int timeout_wait(int timeout, pid_t pid)
{
/* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */
while (1) {
sleep1();
if (--timeout <= 0)
break;
if (kill(pid, 0)) {
/* process is gone */
return EXIT_SUCCESS;
}
}
return EXIT_FAILURE;
}
int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int timeout_main(int argc UNUSED_PARAM, char **argv) int timeout_main(int argc UNUSED_PARAM, char **argv)
{ {
@ -53,23 +69,29 @@ int timeout_main(int argc UNUSED_PARAM, char **argv)
int status; int status;
int parent = 0; int parent = 0;
int timeout; int timeout;
int kill_timeout;
pid_t pid; pid_t pid;
#if !BB_MMU #if !BB_MMU
char *sv1, *sv2; char *sv1, *sv2;
#endif #endif
const char *opt_s = "TERM"; const char *opt_s = "TERM";
char *opt_k = NULL;
/* -p option is not documented, it is needed to support NOMMU. */ /* -p option is not documented, it is needed to support NOMMU. */
/* -t SECONDS; -p PARENT_PID */ /* -t SECONDS; -p PARENT_PID */
/* '+': stop at first non-option */ /* '+': stop at first non-option */
getopt32(argv, "+s:" USE_FOR_NOMMU("p:+"), &opt_s, &parent); getopt32(argv, "+s:k:" USE_FOR_NOMMU("p:+"), &opt_s, &opt_k, &parent);
/*argv += optind; - no, wait for bb_daemonize_or_rexec! */ /*argv += optind; - no, wait for bb_daemonize_or_rexec! */
signo = get_signum(opt_s); signo = get_signum(opt_s);
if (signo < 0) if (signo < 0)
bb_error_msg_and_die("unknown signal '%s'", opt_s); bb_error_msg_and_die("unknown signal '%s'", opt_s);
kill_timeout = 0;
if (opt_k)
kill_timeout = parse_duration_str(opt_k);
if (!argv[optind]) if (!argv[optind])
bb_show_usage(); bb_show_usage();
timeout = parse_duration_str(argv[optind++]); timeout = parse_duration_str(argv[optind++]);
@ -103,17 +125,16 @@ int timeout_main(int argc UNUSED_PARAM, char **argv)
bb_daemonize_or_rexec(0, argv); bb_daemonize_or_rexec(0, argv);
/* Here we are grandchild. Sleep, then kill grandparent */ /* Here we are grandchild. Sleep, then kill grandparent */
grandchild: grandchild:
/* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */ if (timeout_wait(timeout, parent) == EXIT_SUCCESS)
while (1) {
sleep1();
if (--timeout <= 0)
break;
if (kill(parent, 0)) {
/* process is gone */
return EXIT_SUCCESS; return EXIT_SUCCESS;
}
}
kill(parent, signo); kill(parent, signo);
if (kill_timeout > 0) {
if (timeout_wait(kill_timeout, parent) == EXIT_SUCCESS)
return EXIT_SUCCESS;
kill(parent, SIGKILL);
}
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }