summary refs log tree commit diff
diff options
context:
space:
mode:
authorLeah Neukirchen <leah@vuxu.org>2022-01-06 17:25:41 +0100
committerLeah Neukirchen <leah@vuxu.org>2022-01-06 17:25:41 +0100
commitfcb0e6cc86da076def79c75d7ac3522ac775ccaa (patch)
tree675bf62862abda3a32b5b35d36cb162a275bc703
parent6975fbcf42eb5a4a68c6871f05ffb3ae332888f0 (diff)
downloadrvnit-fcb0e6cc86da076def79c75d7ac3522ac775ccaa.tar.gz
rvnit-fcb0e6cc86da076def79c75d7ac3522ac775ccaa.tar.xz
rvnit-fcb0e6cc86da076def79c75d7ac3522ac775ccaa.zip
extract timedwait
-rw-r--r--rvnit.c77
1 files changed, 52 insertions, 25 deletions
diff --git a/rvnit.c b/rvnit.c
index b5b798d..5d04251 100644
--- a/rvnit.c
+++ b/rvnit.c
@@ -323,6 +323,40 @@ reap(pid_t pid, int status)
 	return -1;
 }
 
+pid_t
+timedwait(int *wstatus, int secs)
+{
+	struct timespec timeout = {secs, 0};
+	sigset_t childset;
+	sigemptyset(&childset);
+	sigaddset(&childset, SIGCHLD);
+
+	sigprocmask(SIG_BLOCK, &childset, 0);
+
+	pid_t pid;
+
+	while (1) {
+		pid = waitpid(-1, wstatus, WNOHANG);
+		if (pid == 0) { // nothing to reap
+			if (sigtimedwait(&childset, 0, &timeout) == SIGCHLD)
+				continue;
+			if (errno == EAGAIN) // hit timeout, return pid = 0
+				break;
+		} else if (pid < 0) {
+			if (errno == ECHILD)
+				break;
+			if (errno == EINTR)
+				continue;
+		} else {
+			break; // pid > 0
+		}
+	}
+
+	sigprocmask(SIG_UNBLOCK, &childset, 0);
+
+	return pid;
+}
+
 int
 main()
 {
@@ -479,14 +513,6 @@ main()
 
 	LOG("shutting down");
 
-//	sigaction(SIGINT, &(struct sigaction){.sa_handler=SIG_DFL}, 0);
-
-
-	struct timespec timeout = {7, 0};
-	sigset_t childset;
-	sigemptyset(&childset);
-	sigaddset(&childset, SIGCHLD);
-
 	for (level = 99; level >= 0; level--) {
 		/* kill all of level */
 		int oneshot = 0;
@@ -544,27 +570,26 @@ main()
 		if (!daemons)
 			continue;
 
-		sigprocmask(SIG_BLOCK, &childset, 0);
+		int slayed = 0;
 
 		while (daemons) {
 			int status = 0;
-			int pid = waitpid(-1, &status, WNOHANG);
-			if (pid == 0) { // nothing to reap
-				if (sigtimedwait(&childset, 0, &timeout) == SIGCHLD)
-					continue;
-				if (errno == EAGAIN) { // hit timeout
-					printf("need kill\n");
-					for (i = 0; i < MAX_SV; i++) {
-						if (services[i].level != level)
-							continue;
-						if (services[i].name[2] == 'D' &&
-						    services[i].pid > 0)
-							kill(services[i].pid, SIGKILL);
+			int pid = timedwait(&status, 7);
+			if (pid == 0) { // hit timeout
+				if (slayed)
+					break;
+				LOG("slaying level=%d", level);
+				for (i = 0; i < MAX_SV; i++) {
+					if (services[i].level != level)
+						continue;
+					if (services[i].name[2] == 'D' &&
+					    services[i].pid > 0) {
+						kill(services[i].pid, SIGKILL);
+						kill(services[i].pid, SIGCONT);
 					}
-					// XXX ensure this is only run once,
-					// then force next level
-					continue;
 				}
+				slayed = 1;
+				continue;
 			}
 
 			if (pid < 0 && errno == ECHILD)
@@ -589,7 +614,9 @@ main()
 			}
 		}
 
-		sigprocmask(SIG_UNBLOCK, &childset, 0);
+		if (daemons) {
+			LOG("slaying unsuccessful, %d daemons left in level=%d, continuing...", daemons, level);
+		}
 	}
 
 	dprintf(selflogfd[1], "shutdown\n");