##// END OF EJS Templates
git: a little pycompat.bytestring() love to make this code work in py3...
git: a little pycompat.bytestring() love to make this code work in py3 Differential Revision: https://phab.mercurial-scm.org/D5765

File last commit:

r41367:763b45bc default
r41619:8e0dd36f default
Show More
procutil.c
275 lines | 5.7 KiB | text/x-c | CLexer
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 /*
* Utilities about process handling - signal and subprocess (ex. pager)
*
* Copyright (c) 2011 Yuya Nishihara <yuya@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.
*/
Jun Wu
chg: add procutil.h...
r30693 #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"
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 static pid_t pagerpid = 0;
static pid_t peerpgid = 0;
static pid_t peerpid = 0;
static void forwardsignal(int sig)
{
assert(peerpid > 0);
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (kill(peerpid, sig) < 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 abortmsgerrno("cannot kill %d", peerpid);
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 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;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (kill(killpid, sig) < 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 abortmsgerrno("cannot kill %d", killpid);
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 debugmsg("forward signal %d to %d", sig, killpid);
}
static void handlestopsignal(int sig)
{
sigset_t unblockset, oldset;
struct sigaction sa, oldsa;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (sigemptyset(&unblockset) < 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 goto error;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
if (sigaddset(&unblockset, sig) < 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 goto error;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 memset(&sa, 0, sizeof(sa));
sa.sa_handler = SIG_DFL;
sa.sa_flags = SA_RESTART;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (sigemptyset(&sa.sa_mask) < 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 goto error;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Jun Wu
chg: move signal and pager handling to a separate file...
r30689
forwardsignal(sig);
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (raise(sig) < 0) { /* resend to self */
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 goto error;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
if (sigaction(sig, &sa, &oldsa) < 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 goto error;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
if (sigprocmask(SIG_UNBLOCK, &unblockset, &oldset) < 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 goto error;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 /* resent signal will be handled before sigprocmask() returns */
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (sigprocmask(SIG_SETMASK, &oldset, NULL) < 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 goto error;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
if (sigaction(sig, &oldsa, NULL) < 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 goto error;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 return;
error:
abortmsgerrno("failed to handle stop signal");
}
static void handlechildsignal(int sig UNUSED_)
{
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (peerpid == 0 || pagerpid == 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 return;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 /* if pager exits, notify the server with SIGPIPE immediately.
* otherwise the server won't get SIGPIPE if it does not write
* anything. (issue5278) */
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (waitpid(pagerpid, NULL, WNOHANG) == pagerpid) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 kill(peerpid, SIGPIPE);
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 }
Jun Wu
chg: add procutil.h...
r30693 void setupsignalhandler(pid_t pid, pid_t pgid)
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 {
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (pid <= 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 return;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 peerpid = pid;
peerpgid = (pgid <= 1 ? 0 : pgid);
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
Jun Wu
chg: document why we send SIGHUP and SIGINT to process group...
r31229
/* deadly signals meant to be sent to a process group:
* - SIGHUP: usually generated by the kernel, when termination of a
* process causes that process group to become orphaned
* - SIGINT: usually generated by the terminal */
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 sa.sa_handler = forwardsignaltogroup;
sa.sa_flags = SA_RESTART;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (sigemptyset(&sa.sa_mask) < 0) {
goto error;
}
if (sigaction(SIGHUP, &sa, NULL) < 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 goto error;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
if (sigaction(SIGINT, &sa, NULL) < 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 goto error;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Jun Wu
chg: move signal and pager handling to a separate file...
r30689
/* terminate frontend by double SIGTERM in case of server freeze */
sa.sa_handler = forwardsignal;
sa.sa_flags |= SA_RESETHAND;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (sigaction(SIGTERM, &sa, NULL) < 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 goto error;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Jun Wu
chg: move signal and pager handling to a separate file...
r30689
/* notify the worker about window resize events */
sa.sa_flags = SA_RESTART;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (sigaction(SIGWINCH, &sa, NULL) < 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 goto error;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Jun Wu
chg: forward user-defined signals...
r31230 /* forward user-defined signals */
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (sigaction(SIGUSR1, &sa, NULL) < 0) {
Jun Wu
chg: forward user-defined signals...
r31230 goto error;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
if (sigaction(SIGUSR2, &sa, NULL) < 0) {
Jun Wu
chg: forward user-defined signals...
r31230 goto error;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 /* propagate job control requests to worker */
sa.sa_handler = forwardsignal;
sa.sa_flags = SA_RESTART;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (sigaction(SIGCONT, &sa, NULL) < 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 goto error;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 sa.sa_handler = handlestopsignal;
sa.sa_flags = SA_RESTART;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (sigaction(SIGTSTP, &sa, NULL) < 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 goto error;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 /* get notified when pager exits */
sa.sa_handler = handlechildsignal;
sa.sa_flags = SA_RESTART;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (sigaction(SIGCHLD, &sa, NULL) < 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 goto error;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Jun Wu
chg: move signal and pager handling to a separate file...
r30689
return;
error:
abortmsgerrno("failed to set up signal handlers");
}
Jun Wu
chg: add procutil.h...
r30693 void restoresignalhandler(void)
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = SIG_DFL;
sa.sa_flags = SA_RESTART;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (sigemptyset(&sa.sa_mask) < 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 goto error;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Jun Wu
chg: move signal and pager handling to a separate file...
r30689
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (sigaction(SIGHUP, &sa, NULL) < 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 goto error;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
if (sigaction(SIGTERM, &sa, NULL) < 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 goto error;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
if (sigaction(SIGWINCH, &sa, NULL) < 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 goto error;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
if (sigaction(SIGCONT, &sa, NULL) < 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 goto error;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
if (sigaction(SIGTSTP, &sa, NULL) < 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 goto error;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
if (sigaction(SIGCHLD, &sa, NULL) < 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 goto error;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Jun Wu
chg: move signal and pager handling to a separate file...
r30689
/* ignore Ctrl+C while shutting down to make pager exits cleanly */
sa.sa_handler = SIG_IGN;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (sigaction(SIGINT, &sa, NULL) < 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 goto error;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Jun Wu
chg: move signal and pager handling to a separate file...
r30689
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 */
Jun Wu
chg: respect environment variables for pager...
r31941 pid_t setuppager(const char *pagercmd, const char *envp[])
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 {
Jun Wu
chg: let procutil maintain its own pagerpid...
r30692 assert(pagerpid == 0);
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (!pagercmd) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 return 0;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Jun Wu
chg: move signal and pager handling to a separate file...
r30689
int pipefds[2];
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (pipe(pipefds) < 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 return 0;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 pid_t pid = fork();
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (pid < 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 goto error;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 if (pid > 0) {
close(pipefds[0]);
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (dup2(pipefds[1], fileno(stdout)) < 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 goto error;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 if (isatty(fileno(stderr))) {
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (dup2(pipefds[1], fileno(stderr)) < 0) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 goto error;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 }
close(pipefds[1]);
Jun Wu
chg: let procutil maintain its own pagerpid...
r30692 pagerpid = pid;
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 return pid;
} else {
dup2(pipefds[0], fileno(stdin));
close(pipefds[0]);
close(pipefds[1]);
Augie Fackler
chg: enable clang-format on all .c and .h files...
r35977 int r =
execle("/bin/sh", "/bin/sh", "-c", pagercmd, NULL, envp);
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 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;
}
Jun Wu
chg: add procutil.h...
r30693 void waitpager(void)
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 {
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (pagerpid == 0) {
Jun Wu
chg: let procutil maintain its own pagerpid...
r30692 return;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Jun Wu
chg: let procutil maintain its own pagerpid...
r30692
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 /* close output streams to notify the pager its input ends */
fclose(stdout);
fclose(stderr);
while (1) {
Jun Wu
chg: let procutil maintain its own pagerpid...
r30692 pid_t ret = waitpid(pagerpid, NULL, 0);
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (ret == -1 && errno == EINTR) {
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 continue;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Jun Wu
chg: move signal and pager handling to a separate file...
r30689 break;
}
}