chg: forward job control signals to worker process (
issue5051)
This is necessary to suspend/resume long pulls, interactive curses session,
etc.
The implementation is based on emacsclient, but our version doesn't test if
chg process is foreground or not before propagating SIGCONT. This is because
chg isn't always an interactive session. If we copy the SIGTTIN/SIGTTOU
emulation from emacsclient, non-interactive session can't be moved to a
background job.
$ chg pull
^Z
suspended
$ bg %1
[1] continued
[1] suspended (tty input) # wrong
https://github.com/emacs-mirror/emacs/blob/0e96320/lib-src/emacsclient.c#L1094
--- a/contrib/chg/chg.c Fri Jan 29 22:52:16 2016 +0900
+++ b/contrib/chg/chg.c Tue Jan 19 22:31:59 2016 +0900
@@ -231,6 +231,38 @@
debugmsg("forward signal %d", sig);
}
+static void handlestopsignal(int sig)
+{
+ sigset_t unblockset, oldset;
+ struct sigaction sa, oldsa;
+ if (sigemptyset(&unblockset) < 0)
+ goto error;
+ if (sigaddset(&unblockset, sig) < 0)
+ goto error;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_DFL;
+ sa.sa_flags = SA_RESTART;
+ if (sigemptyset(&sa.sa_mask) < 0)
+ goto error;
+
+ forwardsignal(sig);
+ if (raise(sig) < 0) /* resend to self */
+ goto error;
+ if (sigaction(sig, &sa, &oldsa) < 0)
+ goto error;
+ if (sigprocmask(SIG_UNBLOCK, &unblockset, &oldset) < 0)
+ goto error;
+ /* resent signal will be handled before sigprocmask() returns */
+ if (sigprocmask(SIG_SETMASK, &oldset, NULL) < 0)
+ goto error;
+ if (sigaction(sig, &oldsa, NULL) < 0)
+ goto error;
+ return;
+
+error:
+ abortmsg("failed to handle stop signal (errno = %d)", errno);
+}
+
static void setupsignalhandler(pid_t pid)
{
if (pid <= 0)
@@ -253,6 +285,17 @@
sa.sa_flags |= SA_RESETHAND;
if (sigaction(SIGTERM, &sa, NULL) < 0)
goto error;
+
+ /* propagate job control requests to worker */
+ sa.sa_handler = forwardsignal;
+ sa.sa_flags = SA_RESTART;
+ if (sigaction(SIGCONT, &sa, NULL) < 0)
+ goto error;
+ sa.sa_handler = handlestopsignal;
+ sa.sa_flags = SA_RESTART;
+ if (sigaction(SIGTSTP, &sa, NULL) < 0)
+ goto error;
+
return;
error: