[PATCH 1 of 2 V2] chg: forward SIGINT, SIGHUP to process group

Jun Wu quark at fb.com
Mon Jul 18 11:04:47 EDT 2016


# HG changeset patch
# User Jun Wu <quark at fb.com>
# Date 1468792547 -3600
#      Sun Jul 17 22:55:47 2016 +0100
# Node ID c782f543300c7cf3b52d64dfbf4f5b9e3878e1c7
# Parent  953839de96ab574caa40557c542c262286c6287c
# Available At https://bitbucket.org/quark-zju/hg-draft
#              hg pull https://bitbucket.org/quark-zju/hg-draft -r c782f543300c
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.

diff --git a/contrib/chg/chg.c b/contrib/chg/chg.c
--- a/contrib/chg/chg.c
+++ b/contrib/chg/chg.c
@@ -339,6 +339,7 @@ static void killcmdserver(const struct c
 }
 
 static pid_t pagerpid = 0;
+static pid_t peerpgid = 0;
 static pid_t peerpid = 0;
 
 static void forwardsignal(int sig)
@@ -349,6 +350,15 @@ static void forwardsignal(int sig)
 	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 @@ static void handlechildsignal(int sig UN
 		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 @@ static void setupsignalhandler(pid_t pid
 		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 @@ int main(int argc, const char *argv[], c
 				 gethgcmd());
 	}
 
-	setupsignalhandler(hgc_peerpid(hgc));
+	setupsignalhandler(hgc);
 	pagerpid = setuppager(hgc, argv + 1, argc - 1);
 	int exitcode = hgc_runcommand(hgc, argv + 1, argc - 1);
 	restoresignalhandler();


More information about the Mercurial-devel mailing list