[PATCH 1 of 3] rust-chg: extract signal handlers from chg/procutil.c

Yuya Nishihara yuya at tcha.org
Sun Oct 7 14:45:28 UTC 2018


# HG changeset patch
# User Yuya Nishihara <yuya at tcha.org>
# Date 1537794297 -32400
#      Mon Sep 24 22:04:57 2018 +0900
# Node ID 60d4ea6eefdc897ccd8f5a9553a7a1ad39de8a7b
# Parent  61cd3abbe6713d4e515e1630a32e8d6f96e41c2c
rust-chg: extract signal handlers from chg/procutil.c

abortmsgerrno() and debugmsg() are removed, and the public interface instead
returns success/error status. Since signal handlers can't propagate errors,
the result of kill() is just ignored.

diff --git a/rust/chg/build.rs b/rust/chg/build.rs
--- a/rust/chg/build.rs
+++ b/rust/chg/build.rs
@@ -4,5 +4,6 @@ fn main() {
     cc::Build::new()
         .warnings(true)
         .file("src/sendfds.c")
+        .file("src/sighandlers.c")
         .compile("procutil");
 }
diff --git a/contrib/chg/procutil.c b/rust/chg/src/sighandlers.c
copy from contrib/chg/procutil.c
copy to rust/chg/src/sighandlers.c
--- a/contrib/chg/procutil.c
+++ b/rust/chg/src/sighandlers.c
@@ -1,7 +1,7 @@
 /*
- * Utilities about process handling - signal and subprocess (ex. pager)
+ * Signal handlers for cHg
  *
- * Copyright (c) 2011 Yuya Nishihara <yuya at tcha.org>
+ * Copyright 2011, 2018 Yuya Nishihara <yuya at tcha.org>
  *
  * This software may be used and distributed according to the terms of the
  * GNU General Public License version 2 or any later version.
@@ -10,13 +10,15 @@
 #include <assert.h>
 #include <errno.h>
 #include <signal.h>
-#include <stdio.h>
 #include <string.h>
 #include <sys/wait.h>
 #include <unistd.h>
 
-#include "procutil.h"
-#include "util.h"
+#ifdef __GNUC__
+#define UNUSED_ __attribute__((unused))
+#else
+#define UNUSED_
+#endif
 
 static pid_t pagerpid = 0;
 static pid_t peerpgid = 0;
@@ -25,18 +27,14 @@ static pid_t peerpid = 0;
 static void forwardsignal(int sig)
 {
 	assert(peerpid > 0);
-	if (kill(peerpid, sig) < 0)
-		abortmsgerrno("cannot kill %d", peerpid);
-	debugmsg("forward signal %d", sig);
+	(void)kill(peerpid, sig);
 }
 
 static void forwardsignaltogroup(int sig)
 {
 	/* prefer kill(-pgid, sig), fallback to pid if pgid is invalid */
 	pid_t killpid = peerpgid > 1 ? -peerpgid : peerpid;
-	if (kill(killpid, sig) < 0)
-		abortmsgerrno("cannot kill %d", killpid);
-	debugmsg("forward signal %d to %d", sig, killpid);
+	(void)kill(killpid, sig);
 }
 
 static void handlestopsignal(int sig)
@@ -44,31 +42,27 @@ static void handlestopsignal(int sig)
 	sigset_t unblockset, oldset;
 	struct sigaction sa, oldsa;
 	if (sigemptyset(&unblockset) < 0)
-		goto error;
+		return;
 	if (sigaddset(&unblockset, sig) < 0)
-		goto error;
+		return;
 	memset(&sa, 0, sizeof(sa));
 	sa.sa_handler = SIG_DFL;
 	sa.sa_flags = SA_RESTART;
 	if (sigemptyset(&sa.sa_mask) < 0)
-		goto error;
+		return;
 
 	forwardsignal(sig);
 	if (raise(sig) < 0) /* resend to self */
-		goto error;
+		return;
 	if (sigaction(sig, &sa, &oldsa) < 0)
-		goto error;
+		return;
 	if (sigprocmask(SIG_UNBLOCK, &unblockset, &oldset) < 0)
-		goto error;
+		return;
 	/* resent signal will be handled before sigprocmask() returns */
 	if (sigprocmask(SIG_SETMASK, &oldset, NULL) < 0)
-		goto error;
+		return;
 	if (sigaction(sig, &oldsa, NULL) < 0)
-		goto error;
-	return;
-
-error:
-	abortmsgerrno("failed to handle stop signal");
+		return;
 }
 
 static void handlechildsignal(int sig UNUSED_)
@@ -82,10 +76,18 @@ static void handlechildsignal(int sig UN
 		kill(peerpid, SIGPIPE);
 }
 
-void setupsignalhandler(pid_t pid, pid_t pgid)
+/*
+ * Installs signal handlers.
+ *
+ * Returns 0 on success, -1 on error and errno is set appropriately.
+ * Installed handlers wouldn't be cleaned up on error.
+ */
+int setupsignalhandler(pid_t pid, pid_t pgid)
 {
-	if (pid <= 0)
-		return;
+	if (pid <= 0) {
+		errno = EINVAL;
+		return -1;
+	}
 	peerpid = pid;
 	peerpgid = (pgid <= 1 ? 0 : pgid);
 
@@ -99,139 +101,77 @@ void setupsignalhandler(pid_t pid, pid_t
 	sa.sa_handler = forwardsignaltogroup;
 	sa.sa_flags = SA_RESTART;
 	if (sigemptyset(&sa.sa_mask) < 0)
-		goto error;
+		return -1;
 	if (sigaction(SIGHUP, &sa, NULL) < 0)
-		goto error;
+		return -1;
 	if (sigaction(SIGINT, &sa, NULL) < 0)
-		goto error;
+		return -1;
 
 	/* terminate frontend by double SIGTERM in case of server freeze */
 	sa.sa_handler = forwardsignal;
 	sa.sa_flags |= SA_RESETHAND;
 	if (sigaction(SIGTERM, &sa, NULL) < 0)
-		goto error;
+		return -1;
 
 	/* notify the worker about window resize events */
 	sa.sa_flags = SA_RESTART;
 	if (sigaction(SIGWINCH, &sa, NULL) < 0)
-		goto error;
+		return -1;
 	/* forward user-defined signals */
 	if (sigaction(SIGUSR1, &sa, NULL) < 0)
-		goto error;
+		return -1;
 	if (sigaction(SIGUSR2, &sa, NULL) < 0)
-		goto error;
+		return -1;
 	/* propagate job control requests to worker */
 	sa.sa_handler = forwardsignal;
 	sa.sa_flags = SA_RESTART;
 	if (sigaction(SIGCONT, &sa, NULL) < 0)
-		goto error;
+		return -1;
 	sa.sa_handler = handlestopsignal;
 	sa.sa_flags = SA_RESTART;
 	if (sigaction(SIGTSTP, &sa, NULL) < 0)
-		goto error;
+		return -1;
 	/* get notified when pager exits */
 	sa.sa_handler = handlechildsignal;
 	sa.sa_flags = SA_RESTART;
 	if (sigaction(SIGCHLD, &sa, NULL) < 0)
-		goto error;
+		return -1;
 
-	return;
-
-error:
-	abortmsgerrno("failed to set up signal handlers");
+	return 0;
 }
 
-void restoresignalhandler(void)
+/*
+ * Restores signal handlers to the default, and masks SIGINT.
+ *
+ * Returns 0 on success, -1 on error and errno is set appropriately.
+ */
+int restoresignalhandler(void)
 {
 	struct sigaction sa;
 	memset(&sa, 0, sizeof(sa));
 	sa.sa_handler = SIG_DFL;
 	sa.sa_flags = SA_RESTART;
 	if (sigemptyset(&sa.sa_mask) < 0)
-		goto error;
+		return -1;
 
 	if (sigaction(SIGHUP, &sa, NULL) < 0)
-		goto error;
+		return -1;
 	if (sigaction(SIGTERM, &sa, NULL) < 0)
-		goto error;
+		return -1;
 	if (sigaction(SIGWINCH, &sa, NULL) < 0)
-		goto error;
+		return -1;
 	if (sigaction(SIGCONT, &sa, NULL) < 0)
-		goto error;
+		return -1;
 	if (sigaction(SIGTSTP, &sa, NULL) < 0)
-		goto error;
+		return -1;
 	if (sigaction(SIGCHLD, &sa, NULL) < 0)
-		goto error;
+		return -1;
 
 	/* ignore Ctrl+C while shutting down to make pager exits cleanly */
 	sa.sa_handler = SIG_IGN;
 	if (sigaction(SIGINT, &sa, NULL) < 0)
-		goto error;
+		return -1;
 
 	peerpid = 0;
-	return;
-
-error:
-	abortmsgerrno("failed to restore signal handlers");
-}
-
-/* This implementation is based on hgext/pager.py (post 369741ef7253)
- * Return 0 if pager is not started, or pid of the pager */
-pid_t setuppager(const char *pagercmd, const char *envp[])
-{
-	assert(pagerpid == 0);
-	if (!pagercmd)
-		return 0;
-
-	int pipefds[2];
-	if (pipe(pipefds) < 0)
-		return 0;
-	pid_t pid = fork();
-	if (pid < 0)
-		goto error;
-	if (pid > 0) {
-		close(pipefds[0]);
-		if (dup2(pipefds[1], fileno(stdout)) < 0)
-			goto error;
-		if (isatty(fileno(stderr))) {
-			if (dup2(pipefds[1], fileno(stderr)) < 0)
-				goto error;
-		}
-		close(pipefds[1]);
-		pagerpid = pid;
-		return pid;
-	} else {
-		dup2(pipefds[0], fileno(stdin));
-		close(pipefds[0]);
-		close(pipefds[1]);
-
-		int r =
-		    execle("/bin/sh", "/bin/sh", "-c", pagercmd, NULL, envp);
-		if (r < 0) {
-			abortmsgerrno("cannot start pager '%s'", pagercmd);
-		}
-		return 0;
-	}
-
-error:
-	close(pipefds[0]);
-	close(pipefds[1]);
-	abortmsgerrno("failed to prepare pager");
 	return 0;
 }
-
-void waitpager(void)
-{
-	if (pagerpid == 0)
-		return;
-
-	/* close output streams to notify the pager its input ends */
-	fclose(stdout);
-	fclose(stderr);
-	while (1) {
-		pid_t ret = waitpid(pagerpid, NULL, 0);
-		if (ret == -1 && errno == EINTR)
-			continue;
-		break;
-	}
-}


More information about the Mercurial-devel mailing list