[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