changeset 29608:681fe090d82e stable

chg: forward SIGINT, SIGHUP to process group These signals are meant to send to a process group, instead of a single process: SIGINT is usually emitted by the terminal and sent to the process group. SIGHUP usually happens to a process group if termination of a process causes that process group to become orphaned. Before this patch, chg will only forward these signals to the single server process. This patch changes it to the server process group. This will allow us to properly kill processes started by the forked server process, like a ssh process. The behavior difference can be observed by setting SSH_ASKPASS to a dummy script doing "sleep 100" and then run "chg push ssh://dest-need-password-auth". Before this patch, the first Ctrl+C will kill the hg process while ssh-askpass and ssh will remain alive. This patch will make sure they are killed properly.
author Jun Wu <quark@fb.com>
date Sun, 17 Jul 2016 22:55:47 +0100
parents 02a8fea4289b
children 591c3badff2e
files contrib/chg/chg.c
diffstat 1 files changed, 18 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/contrib/chg/chg.c	Mon Jul 18 23:31:51 2016 -0500
+++ b/contrib/chg/chg.c	Sun Jul 17 22:55:47 2016 +0100
@@ -339,6 +339,7 @@
 }
 
 static pid_t pagerpid = 0;
+static pid_t peerpgid = 0;
 static pid_t peerpid = 0;
 
 static void forwardsignal(int sig)
@@ -349,6 +350,15 @@
 	debugmsg("forward signal %d", 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);
+}
+
 static void handlestopsignal(int sig)
 {
 	sigset_t unblockset, oldset;
@@ -392,15 +402,19 @@
 		kill(peerpid, SIGPIPE);
 }
 
-static void setupsignalhandler(pid_t pid)
+static void setupsignalhandler(const hgclient_t *hgc)
 {
+	pid_t pid = hgc_peerpid(hgc);
 	if (pid <= 0)
 		return;
 	peerpid = pid;
 
+	pid_t pgid = hgc_peerpgid(hgc);
+	peerpgid = (pgid <= 1 ? 0 : pgid);
+
 	struct sigaction sa;
 	memset(&sa, 0, sizeof(sa));
-	sa.sa_handler = forwardsignal;
+	sa.sa_handler = forwardsignaltogroup;
 	sa.sa_flags = SA_RESTART;
 	if (sigemptyset(&sa.sa_mask) < 0)
 		goto error;
@@ -411,6 +425,7 @@
 		goto error;
 
 	/* 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;
@@ -656,7 +671,7 @@
 				 gethgcmd());
 	}
 
-	setupsignalhandler(hgc_peerpid(hgc));
+	setupsignalhandler(hgc);
 	pagerpid = setuppager(hgc, argv + 1, argc - 1);
 	int exitcode = hgc_runcommand(hgc, argv + 1, argc - 1);
 	restoresignalhandler();