Print this page
6805730 some simple changes would make 'init 5' much faster
6809492 startd shouldn't let hung subprocesses impede shutdown
*** 17,27 ****
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
! * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* fork.c - safe forking for svc.startd
--- 17,27 ----
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
! * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* fork.c - safe forking for svc.startd
*** 42,59 ****
--- 42,61 ----
#include <fcntl.h>
#include <libcontract.h>
#include <libcontract_priv.h>
#include <libscf_priv.h>
#include <limits.h>
+ #include <poll.h>
#include <port.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <utmpx.h>
+ #include <spawn.h>
#include "configd_exit.h"
#include "protocol.h"
#include "startd.h"
*** 676,681 ****
--- 678,790 ----
(void) execle(path, path, arg, 0, nenv);
perror("exec");
exit(0);
+ }
+
+ extern char **environ;
+
+ /*
+ * A local variation on system(3c) which accepts a timeout argument. This
+ * allows us to better ensure that the system will actually shut down.
+ *
+ * gracetime specifies an amount of time in seconds which the routine must wait
+ * after the command exits, to allow for asynchronous effects (like sent
+ * signals) to take effect. This can be zero.
+ */
+ void
+ fork_with_timeout(const char *cmd, uint_t gracetime, uint_t timeout)
+ {
+ int err = 0;
+ pid_t pid;
+ char *argv[4];
+ posix_spawnattr_t attr;
+ posix_spawn_file_actions_t factions;
+
+ sigset_t mask, savemask;
+ uint_t msec_timeout;
+ uint_t msec_spent = 0;
+ uint_t msec_gracetime;
+ int status;
+
+ msec_timeout = timeout * 1000;
+ msec_gracetime = gracetime * 1000;
+
+ /*
+ * See also system(3c) in libc. This is very similar, except
+ * that we avoid some unneeded complexity.
+ */
+ err = posix_spawnattr_init(&attr);
+ if (err == 0)
+ err = posix_spawnattr_setflags(&attr,
+ POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF |
+ POSIX_SPAWN_NOSIGCHLD_NP | POSIX_SPAWN_WAITPID_NP |
+ POSIX_SPAWN_NOEXECERR_NP);
+
+ /*
+ * We choose to close fd's above 2, a deviation from system.
+ */
+ if (err == 0)
+ err = posix_spawn_file_actions_init(&factions);
+ if (err == 0)
+ err = posix_spawn_file_actions_addclosefrom_np(&factions,
+ STDERR_FILENO + 1);
+
+ (void) sigemptyset(&mask);
+ (void) sigaddset(&mask, SIGCHLD);
+ (void) thr_sigsetmask(SIG_BLOCK, &mask, &savemask);
+
+ argv[0] = "/bin/sh";
+ argv[1] = "-c";
+ argv[2] = (char *)cmd;
+ argv[3] = NULL;
+
+ if (err == 0)
+ err = posix_spawn(&pid, "/bin/sh", &factions, &attr,
+ (char *const *)argv, (char *const *)environ);
+
+ (void) posix_spawnattr_destroy(&attr);
+ (void) posix_spawn_file_actions_destroy(&factions);
+
+ if (err) {
+ uu_warn("Failed to spawn %s: %s\n", cmd, strerror(err));
+ } else {
+ for (;;) {
+ int w;
+ w = waitpid(pid, &status, WNOHANG);
+ if (w == -1 && errno != EINTR)
+ break;
+ if (w > 0) {
+ /*
+ * Command succeeded, so give it gracetime
+ * seconds for it to have an effect.
+ */
+ if (status == 0 && msec_gracetime != 0)
+ (void) poll(NULL, 0, msec_gracetime);
+ break;
+ }
+
+ (void) poll(NULL, 0, 100);
+ msec_spent += 100;
+ /*
+ * If we timed out, kill off the process, then try to
+ * wait for it-- it's possible that we could accumulate
+ * a zombie here since we don't allow waitpid to hang,
+ * but it's better to let that happen and continue to
+ * make progress.
+ */
+ if (msec_spent >= msec_timeout) {
+ uu_warn("'%s' timed out after %d "
+ "seconds. Killing.\n", cmd,
+ timeout);
+ (void) kill(pid, SIGTERM);
+ (void) poll(NULL, 0, 100);
+ (void) kill(pid, SIGKILL);
+ (void) poll(NULL, 0, 100);
+ (void) waitpid(pid, &status, WNOHANG);
+ break;
+ }
+ }
+ }
+ (void) thr_sigsetmask(SIG_BLOCK, &savemask, NULL);
}