mirror of
https://https.git.savannah.gnu.org/git/diffutils.git
synced 2026-01-27 01:44:20 +00:00
diff: refactor and improve signal handling
This is so we can improve sdiff signal handling. * bootstrap.conf: Add stdcountof-h. * src/Makefile.am (diff_SOURCES): Add syncsig.c. (noinst_HEADERS): Add syncsig.h. * src/diff.c, src/util.c: Include syncsig.h. * src/util.c: Move signal-related stuff from here ... * src/syncsig.c: ... to here. (syncsig_install, syncsig_cleanup): Rename from install_signal_handlers, cleanup_signal_handlers. All uses changed. Handle some more signals. Add an option to not handle stop-related signals. (syncsig_poll, syncsig_deliver): New functions, which are like the old process_signals but in two pieces not one. All uses changed. (syncsig_install): New args FUN and ARG. Return int on failure. All callers changed. * src/syncsig.h: New file.
This commit is contained in:
parent
6b9c726076
commit
b4524ba9a6
@ -124,8 +124,9 @@ stat
|
||||
stat-macros
|
||||
stat-size
|
||||
stat-time
|
||||
stdckdint-h
|
||||
stdc_bit_width
|
||||
stdckdint-h
|
||||
stdcountof-h
|
||||
stdint-h
|
||||
stpcpy
|
||||
strcase
|
||||
|
||||
@ -47,8 +47,8 @@ diff3_SOURCES = diff3.c system.c
|
||||
sdiff_SOURCES = sdiff.c system.c
|
||||
diff_SOURCES = \
|
||||
analyze.c context.c diff.c dir.c ed.c ifdef.c io.c \
|
||||
normal.c side.c system.c util.c
|
||||
noinst_HEADERS = diff.h system.h
|
||||
normal.c side.c syncsig.c system.c util.c
|
||||
noinst_HEADERS = diff.h syncsig.h system.h
|
||||
|
||||
MOSTLYCLEANFILES = paths.h paths.ht
|
||||
|
||||
|
||||
350
src/syncsig.c
Normal file
350
src/syncsig.c
Normal file
@ -0,0 +1,350 @@
|
||||
/* Synchronous signal handling
|
||||
|
||||
Copyright 2025 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU DIFF.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "syncsig.h"
|
||||
|
||||
#include "minmax.h"
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdcountof.h>
|
||||
|
||||
/* Use SA_NOCLDSTOP as a proxy for whether the sigaction machinery is
|
||||
present. */
|
||||
#ifndef SA_NOCLDSTOP
|
||||
# define SA_NOCLDSTOP 0
|
||||
# define sigprocmask(how, set, oset) 0
|
||||
# if ! HAVE_SIGINTERRUPT
|
||||
# define siginterrupt(sig, flag) 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef SA_RESTART
|
||||
# define SA_RESTART 0
|
||||
#endif
|
||||
#ifndef SIGSTOP
|
||||
# define SIGSTOP 0
|
||||
#endif
|
||||
|
||||
/* The set of signals that are caught. */
|
||||
static sigset_t caught_signals;
|
||||
|
||||
/* The signals we can catch.
|
||||
This includes all catchable GNU/Linux or POSIX signals that by
|
||||
default are ignored, or that stop or terminate the process.
|
||||
It also includes SIGQUIT since that can come from the terminal.
|
||||
It excludes other signals that normally come from program failure.
|
||||
If you modify this table, also modify signal_count's initializer. */
|
||||
static int const catchable[] =
|
||||
{
|
||||
/* SIGABRT is normally from program failure. */
|
||||
SIGALRM,
|
||||
/* SIGBUS is normally from program failure. */
|
||||
#ifdef SIGCHLD
|
||||
SIGCHLD,
|
||||
#else
|
||||
# define SIGCHLD 0
|
||||
#endif
|
||||
/* SIGCLD (older platforms) is an alias for SIGCHLD. */
|
||||
#ifdef SIGCONT
|
||||
SIGCONT,
|
||||
#else
|
||||
# define SIGCONT 0
|
||||
#endif
|
||||
/* SIGEMT is normally from program failure. */
|
||||
/* SIGFPE is normally from program failure. */
|
||||
SIGHUP,
|
||||
/* SIGILL is normally from program failure. */
|
||||
/* SIGINFO is an alias for SIGPWR on Linux. */
|
||||
SIGINT,
|
||||
/* SIGIO is an alias for SIGPOLL. */
|
||||
/* SIGKILL can't be caught. */
|
||||
#ifdef SIGLOST
|
||||
SIGLOST,
|
||||
#else
|
||||
# define SIGLOST 0
|
||||
#endif
|
||||
SIGPIPE,
|
||||
#ifdef SIGPOLL /* Removed from POSIX.1-2024; still in Linux. */
|
||||
SIGPOLL,
|
||||
#else
|
||||
# define SIGPOLL 0
|
||||
#endif
|
||||
#ifdef SIGPROF /* Removed from POSIX.1-2024; still in Linux. */
|
||||
SIGPROF,
|
||||
#else
|
||||
# define SIGPROF 0
|
||||
#endif
|
||||
#ifdef SIGPWR
|
||||
SIGPWR,
|
||||
#else
|
||||
# define SIGPWR 0
|
||||
#endif
|
||||
SIGQUIT,
|
||||
/* SIGSEGV is normally from program failure. */
|
||||
/* Linux SIGSTKFLT is unused. */
|
||||
/* SIGSTOP can't be caught. */
|
||||
/* SIGSYS is normally from program failure. */
|
||||
SIGTERM,
|
||||
/* SIGTRAP is normally from program failure. */
|
||||
#ifdef SIGTSTP
|
||||
SIGTSTP,
|
||||
#else
|
||||
# define SIGTSTP 0
|
||||
#endif
|
||||
#ifdef SIGTTIN
|
||||
SIGTTIN,
|
||||
#else
|
||||
# define SIGTTIN 0
|
||||
#endif
|
||||
#ifdef SIGTTOU
|
||||
SIGTTOU,
|
||||
#else
|
||||
# define SIGTTOU 0
|
||||
#endif
|
||||
#ifdef SIGURG
|
||||
SIGURG,
|
||||
#else
|
||||
# define SIGURG 0
|
||||
#endif
|
||||
#ifdef SIGUSR1
|
||||
SIGUSR1,
|
||||
#else
|
||||
# define SIGUSR1 0
|
||||
#endif
|
||||
#ifdef SIGUSR2
|
||||
SIGUSR2,
|
||||
#else
|
||||
# define SIGUSR2 0
|
||||
#endif
|
||||
#ifdef SIGVTALRM
|
||||
SIGVTALRM,
|
||||
#else
|
||||
# define SIGVTALRM 0
|
||||
#endif
|
||||
#ifdef SIGWINCH
|
||||
SIGWINCH,
|
||||
#else
|
||||
# define SIGWINCH 0
|
||||
#endif
|
||||
#ifdef SIGXCPU
|
||||
SIGXCPU,
|
||||
#else
|
||||
# define SIGXCPU 0
|
||||
#endif
|
||||
#ifdef SIGXFSZ
|
||||
SIGXFSZ,
|
||||
#else
|
||||
# define SIGXFSZ 0
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Number of pending signals received, for each signal type. */
|
||||
static sig_atomic_t volatile signal_count[] =
|
||||
{
|
||||
/* Explicitly initialize, so that the table is large enough. */
|
||||
[SIGALRM] = 0,
|
||||
[SIGCHLD] = 0,
|
||||
[SIGCONT] = 0,
|
||||
[SIGHUP] = 0,
|
||||
[SIGINT] = 0,
|
||||
[SIGLOST] = 0,
|
||||
[SIGPIPE] = 0,
|
||||
[SIGPOLL] = 0,
|
||||
[SIGPROF] = 0,
|
||||
[SIGPWR] = 0,
|
||||
[SIGQUIT] = 0,
|
||||
[SIGTERM] = 0,
|
||||
[SIGTSTP] = 0,
|
||||
[SIGTTIN] = 0,
|
||||
[SIGTTOU] = 0,
|
||||
[SIGURG] = 0,
|
||||
[SIGUSR1] = 0,
|
||||
[SIGUSR2] = 0,
|
||||
[SIGVTALRM] = 0,
|
||||
[SIGWINCH] = 0,
|
||||
[SIGXCPU] = 0,
|
||||
[SIGXFSZ] = 0,
|
||||
};
|
||||
|
||||
/* This acts as bool though its type is sig_atomic_t.
|
||||
If true, signal_count might contain nonzero entries.
|
||||
If false, signal_count is all zero.
|
||||
This is to speed up syncsig_poll when it returns 0. */
|
||||
static sig_atomic_t volatile possible_signal_count;
|
||||
|
||||
/* Actions before syncsig_install was called. */
|
||||
#if SA_NOCLDSTOP
|
||||
static struct sigaction oldact[countof (signal_count)];
|
||||
#else
|
||||
static void (*oldact[countof (signal_count)]) (int);
|
||||
#endif
|
||||
|
||||
/* Record an asynchronous signal. This function is async-signal-safe. */
|
||||
static void
|
||||
sighandler (int sig)
|
||||
{
|
||||
#if !SA_NOCLDSTOP
|
||||
/* An unavoidable race here: the default action might mistakenly
|
||||
be taken before 'signal' is called. */
|
||||
signal (sig, sighandler);
|
||||
#endif
|
||||
|
||||
possible_signal_count = true;
|
||||
signal_count[sig]++;
|
||||
}
|
||||
|
||||
void
|
||||
syncsig_install (int flags)
|
||||
{
|
||||
for (int i = 0; i < countof (signal_count); i++)
|
||||
signal_count[i] = 0;
|
||||
possible_signal_count = false;
|
||||
|
||||
sigemptyset (&caught_signals);
|
||||
|
||||
for (int i = 0; i < countof (catchable); i++)
|
||||
{
|
||||
int sig = catchable[i];
|
||||
|
||||
if (((sig == SIGTSTP) & !(flags & SYNCSIG_TSTP))
|
||||
| ((sig == SIGTTIN) & !(flags & SYNCSIG_TTIN))
|
||||
| ((sig == SIGTTOU) & !(flags & SYNCSIG_TTOU)))
|
||||
continue;
|
||||
|
||||
#if SA_NOCLDSTOP
|
||||
sigaction (sig, nullptr, &oldact[sig]);
|
||||
bool catching_sig = oldact[sig].sa_handler != SIG_IGN;
|
||||
#else
|
||||
oldact[i] = signal (sig, SIG_IGN);
|
||||
bool catching_sig = oldact[i] != SIG_IGN;
|
||||
if (catching_sig)
|
||||
{
|
||||
/* An unavoidable race here: SIG might be mistakenly ignored
|
||||
before 'signal' is called. */
|
||||
signal (sig, sighandler);
|
||||
siginterrupt (sig, 0);
|
||||
}
|
||||
#endif
|
||||
if (catching_sig)
|
||||
sigaddset (&caught_signals, sig);
|
||||
}
|
||||
|
||||
#if SA_NOCLDSTOP
|
||||
struct sigaction act;
|
||||
act.sa_handler = sighandler;
|
||||
act.sa_mask = caught_signals;
|
||||
act.sa_flags = SA_RESTART;
|
||||
|
||||
for (int i = 0; i < countof (catchable); i++)
|
||||
{
|
||||
int sig = catchable[i];
|
||||
if (sigismember (&caught_signals, sig))
|
||||
sigaction (sig, &act, nullptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
syncsig_uninstall (void)
|
||||
{
|
||||
for (int i = 0; i < countof (catchable); i++)
|
||||
{
|
||||
int sig = catchable[i];
|
||||
if (sigismember (&caught_signals, sig))
|
||||
{
|
||||
#if SA_NOCLDSTOP
|
||||
sigaction (sig, &oldact[sig], nullptr);
|
||||
#else
|
||||
signal (sig, oldact[sig]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
syncsig_poll (void)
|
||||
{
|
||||
int sig = 0;
|
||||
|
||||
if (possible_signal_count)
|
||||
{
|
||||
/* This module uses static rather than thread-local storage,
|
||||
so it is useful only in single-threaded programs,
|
||||
and it uses sigprocmask rather than pthread_sigmask. */
|
||||
sigset_t oldset;
|
||||
sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
|
||||
|
||||
for (int i = 0; ; i++)
|
||||
{
|
||||
if (i == countof (catchable))
|
||||
{
|
||||
possible_signal_count = false;
|
||||
break;
|
||||
}
|
||||
int s = catchable[i];
|
||||
int c = signal_count[s];
|
||||
if (c)
|
||||
{
|
||||
signal_count[s] = c - 1;
|
||||
sig = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sigprocmask (SIG_SETMASK, &oldset, nullptr);
|
||||
}
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
||||
void
|
||||
syncsig_deliver (int sig)
|
||||
{
|
||||
#if SA_NOCLDSTOP
|
||||
struct sigaction act;
|
||||
#else
|
||||
void (*act) (int);
|
||||
#endif
|
||||
|
||||
if (sig == SIGTSTP)
|
||||
sig = SIGSTOP;
|
||||
else
|
||||
{
|
||||
#if SA_NOCLDSTOP
|
||||
sigaction (sig, &oldact[sig], &act);
|
||||
#else
|
||||
act = signal (sig, oldact[sig]);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
raise (sig);
|
||||
|
||||
if (sig != SIGSTOP)
|
||||
{
|
||||
/* The program did not exit due to the raised signal, so continue. */
|
||||
#if SA_NOCLDSTOP
|
||||
sigaction (sig, &act, nullptr);
|
||||
#else
|
||||
signal (sig, act);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
60
src/syncsig.h
Normal file
60
src/syncsig.h
Normal file
@ -0,0 +1,60 @@
|
||||
/* Synchronous signal handling
|
||||
|
||||
Copyright 2025 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU DIFF.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Paul Eggert. */
|
||||
|
||||
/* Flags for syncsig_install. */
|
||||
enum
|
||||
{
|
||||
/* Also catch SIGTSTP, SIGTTIN, SIGTTOU, which by default stop the process.
|
||||
These flags have no effect on platforms lacking these signals. */
|
||||
SYNCSIG_TSTP = (1 << 0),
|
||||
SYNCSIG_TTIN = (1 << 1),
|
||||
SYNCSIG_TTOU = (1 << 2),
|
||||
};
|
||||
|
||||
/* Set up asynchronous signal handling according to FLAGS.
|
||||
syncsig_install fails only on unusual platforms where
|
||||
valid calls to functions like sigaction can fail;
|
||||
if it fails, signal handling is in a weird state
|
||||
and neither syncsig_process nor syncsig_uninstall should be called. */
|
||||
extern void syncsig_install (int flags);
|
||||
|
||||
/* Return a signal number if a signal has arrived, zero otherwise.
|
||||
After syncsig_install, there should not be an unbounded amount of
|
||||
time between calls to this function, and its result should be dealt
|
||||
with promptly. */
|
||||
extern int syncsig_poll (void);
|
||||
|
||||
/* Do the action for SIG that would have been done
|
||||
had syncsig_install not been called.
|
||||
SIG should have recently been returned by syncsig_poll.
|
||||
|
||||
For example, if SIG is SIGTSTP stop the process and return after
|
||||
SIGCONT is delivered. Another example: kill the process if SIG is
|
||||
SIGINT and SIGINT handling is the default.
|
||||
|
||||
This function should be called only after syncsig_install. */
|
||||
extern void syncsig_deliver (int sig);
|
||||
|
||||
/* Stop doing asynchronous signal handling, undoing syncsig_install.
|
||||
This function should be called only after syncsig_install.
|
||||
To deal with signals arriving just before calling this function,
|
||||
call syncsig_poll afterwards. */
|
||||
extern void syncsig_uninstall (void);
|
||||
223
src/util.c
223
src/util.c
@ -27,31 +27,11 @@
|
||||
#include <flexmember.h>
|
||||
#include <mcel.h>
|
||||
#include <quotearg.h>
|
||||
#include <syncsig.h>
|
||||
#include <system-quote.h>
|
||||
#include <xalloc.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <signal.h>
|
||||
|
||||
/* Use SA_NOCLDSTOP as a proxy for whether the sigaction machinery is
|
||||
present. */
|
||||
#ifndef SA_NOCLDSTOP
|
||||
# define SA_NOCLDSTOP 0
|
||||
# define sigprocmask(How, Set, Oset) 0
|
||||
# if ! HAVE_SIGINTERRUPT
|
||||
# define siginterrupt(sig, flag) 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef SA_RESTART
|
||||
# define SA_RESTART 0
|
||||
#endif
|
||||
#ifndef SIGSTOP
|
||||
# define SIGSTOP 0
|
||||
#endif
|
||||
#ifndef SIGTSTP
|
||||
# define SIGTSTP 0
|
||||
#endif
|
||||
|
||||
char const pr_program[] = PR_PROGRAM;
|
||||
|
||||
@ -184,78 +164,9 @@ print_message_queue (void)
|
||||
m = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Signal handling, needed for restoring default colors. */
|
||||
|
||||
static void
|
||||
xsigaddset (sigset_t *set, int sig)
|
||||
{
|
||||
if (sigaddset (set, sig) != 0)
|
||||
pfatal_with_name ("sigaddset");
|
||||
}
|
||||
|
||||
static bool
|
||||
xsigismember (sigset_t const *set, int sig)
|
||||
{
|
||||
int mem = sigismember (set, sig);
|
||||
if (mem < 0)
|
||||
pfatal_with_name ("sigismember");
|
||||
assume (mem <= 1);
|
||||
return mem;
|
||||
}
|
||||
|
||||
typedef void (*signal_handler) (int);
|
||||
static signal_handler
|
||||
xsignal (int sig, signal_handler func)
|
||||
{
|
||||
signal_handler h = signal (sig, func);
|
||||
if (h == SIG_ERR)
|
||||
pfatal_with_name ("signal");
|
||||
return h;
|
||||
}
|
||||
|
||||
static void
|
||||
xsigprocmask (int how, sigset_t const *restrict set, sigset_t *restrict oset)
|
||||
{
|
||||
if (sigprocmask (how, set, oset) != 0)
|
||||
pfatal_with_name ("sigprocmask");
|
||||
}
|
||||
|
||||
/* If true, some signals are caught. This is separate from
|
||||
'caught_signals' because POSIX doesn't require an all-zero sigset_t
|
||||
to be valid. */
|
||||
static bool some_signals_caught;
|
||||
|
||||
/* The set of signals that are caught. */
|
||||
static sigset_t caught_signals;
|
||||
|
||||
/* If nonzero, the value of the pending fatal signal. */
|
||||
static sig_atomic_t volatile interrupt_signal;
|
||||
|
||||
/* A count of the number of pending stop signals that have been received. */
|
||||
static sig_atomic_t volatile stop_signal_count;
|
||||
|
||||
/* An ordinary signal was received; arrange for the program to exit. */
|
||||
|
||||
static void
|
||||
sighandler (int sig)
|
||||
{
|
||||
if (! SA_NOCLDSTOP)
|
||||
signal (sig, SIG_IGN);
|
||||
if (! interrupt_signal)
|
||||
interrupt_signal = sig;
|
||||
}
|
||||
|
||||
/* A SIGTSTP was received; arrange for the program to suspend itself. */
|
||||
|
||||
static void
|
||||
stophandler (int sig)
|
||||
{
|
||||
if (! SA_NOCLDSTOP)
|
||||
signal (sig, stophandler);
|
||||
if (! interrupt_signal)
|
||||
stop_signal_count++;
|
||||
}
|
||||
/* Process any pending signals. If signals are caught, this function
|
||||
should be called periodically. Ideally there should never be an
|
||||
unbounded amount of time when signals are not being processed.
|
||||
@ -265,131 +176,18 @@ stophandler (int sig)
|
||||
static void
|
||||
process_signals (void)
|
||||
{
|
||||
while (interrupt_signal | stop_signal_count)
|
||||
for (int sig; (sig = syncsig_poll ()); )
|
||||
{
|
||||
set_color_context (RESET_CONTEXT);
|
||||
fflush (stdout);
|
||||
|
||||
sigset_t oldset;
|
||||
xsigprocmask (SIG_BLOCK, &caught_signals, &oldset);
|
||||
|
||||
/* Reload stop_signal_count and (if needed) interrupt_signal, in
|
||||
case a new signal was handled before sigprocmask took effect. */
|
||||
int stops = stop_signal_count, sig;
|
||||
|
||||
/* SIGTSTP is special, since the application can receive that signal
|
||||
more than once. In this case, don't set the signal handler to the
|
||||
default. Instead, just raise the uncatchable SIGSTOP. */
|
||||
if (stops)
|
||||
{
|
||||
stop_signal_count = stops - 1;
|
||||
sig = SIGSTOP;
|
||||
}
|
||||
else
|
||||
{
|
||||
sig = interrupt_signal;
|
||||
xsignal (sig, SIG_DFL);
|
||||
}
|
||||
|
||||
/* Exit or suspend the program. */
|
||||
if (raise (sig) != 0)
|
||||
pfatal_with_name ("raise");
|
||||
xsigprocmask (SIG_SETMASK, &oldset, nullptr);
|
||||
|
||||
/* If execution reaches here, then the program has been
|
||||
continued (after being suspended). */
|
||||
syncsig_deliver (sig);
|
||||
}
|
||||
}
|
||||
|
||||
/* The signals that can be caught, the number of such signals,
|
||||
and which of them are actually caught. */
|
||||
static int const sig[] =
|
||||
{
|
||||
#if SIGTSTP
|
||||
/* This one is handled specially; see is_tstp_index. */
|
||||
SIGTSTP,
|
||||
#endif
|
||||
|
||||
/* The usual suspects. */
|
||||
#ifdef SIGALRM
|
||||
SIGALRM,
|
||||
#endif
|
||||
#ifdef SIGHUP
|
||||
SIGHUP,
|
||||
#endif
|
||||
SIGINT,
|
||||
#ifdef SIGPIPE
|
||||
SIGPIPE,
|
||||
#endif
|
||||
#ifdef SIGQUIT
|
||||
SIGQUIT,
|
||||
#endif
|
||||
SIGTERM,
|
||||
#ifdef SIGPOLL
|
||||
SIGPOLL,
|
||||
#endif
|
||||
#ifdef SIGPROF
|
||||
SIGPROF,
|
||||
#endif
|
||||
#ifdef SIGVTALRM
|
||||
SIGVTALRM,
|
||||
#endif
|
||||
#ifdef SIGXCPU
|
||||
SIGXCPU,
|
||||
#endif
|
||||
#ifdef SIGXFSZ
|
||||
SIGXFSZ,
|
||||
#endif
|
||||
};
|
||||
enum { nsigs = sizeof (sig) / sizeof *(sig) };
|
||||
|
||||
/* True if sig[j] == SIGTSTP. */
|
||||
static bool
|
||||
is_tstp_index (int j)
|
||||
{
|
||||
return SIGTSTP && j == 0;
|
||||
}
|
||||
|
||||
static void
|
||||
install_signal_handlers (void)
|
||||
{
|
||||
if (sigemptyset (&caught_signals) != 0)
|
||||
pfatal_with_name ("sigemptyset");
|
||||
|
||||
#if SA_NOCLDSTOP
|
||||
for (int j = 0; j < nsigs; j++)
|
||||
{
|
||||
struct sigaction actj;
|
||||
if (sigaction (sig[j], nullptr, &actj) == 0 && actj.sa_handler != SIG_IGN)
|
||||
xsigaddset (&caught_signals, sig[j]);
|
||||
}
|
||||
|
||||
struct sigaction act;
|
||||
act.sa_mask = caught_signals;
|
||||
act.sa_flags = SA_RESTART;
|
||||
|
||||
for (int j = 0; j < nsigs; j++)
|
||||
if (xsigismember (&caught_signals, sig[j]))
|
||||
{
|
||||
act.sa_handler = is_tstp_index (j) ? stophandler : sighandler;
|
||||
if (sigaction (sig[j], &act, nullptr) != 0)
|
||||
pfatal_with_name ("sigaction");
|
||||
some_signals_caught = true;
|
||||
}
|
||||
#else
|
||||
for (int j = 0; j < nsigs; j++)
|
||||
{
|
||||
signal_handler h = signal (sig[j], SIG_IGN);
|
||||
if (h != SIG_IGN && h != SIG_ERR)
|
||||
{
|
||||
xsigaddset (&caught_signals, sig[j]);
|
||||
xsignal (sig[j], is_tstp_index (j) ? stophandler : sighandler);
|
||||
some_signals_caught = true;
|
||||
if (siginterrupt (sig[j], 0) != 0)
|
||||
pfatal_with_name ("siginterrupt");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
syncsig_install (SYNCSIG_TSTP);
|
||||
}
|
||||
|
||||
/* Clean up signal handlers just before exiting the program. Do this
|
||||
@ -398,14 +196,11 @@ install_signal_handlers (void)
|
||||
void
|
||||
cleanup_signal_handlers (void)
|
||||
{
|
||||
if (some_signals_caught)
|
||||
{
|
||||
for (int j = 0; j < nsigs; j++)
|
||||
if (xsigismember (&caught_signals, sig[j]))
|
||||
xsignal (sig[j], SIG_DFL);
|
||||
process_signals ();
|
||||
}
|
||||
syncsig_uninstall ();
|
||||
process_signals ();
|
||||
}
|
||||
|
||||
/* Color handling. */
|
||||
|
||||
static char const *current_name[2];
|
||||
static bool currently_recursive;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user