aboutsummaryrefslogtreecommitdiff
path: root/src/os_unix.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/os_unix.c')
-rw-r--r--src/os_unix.c590
1 files changed, 5 insertions, 585 deletions
diff --git a/src/os_unix.c b/src/os_unix.c
index 091bf7999e..8da7c4701f 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -54,6 +54,7 @@
#include "os/event.h"
#include "os/input.h"
#include "os/shell.h"
+#include "os/signal.h"
#include "os_unixx.h" /* unix includes for os_unix.c only */
@@ -72,28 +73,6 @@ static int selinux_enabled = -1;
extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
#endif
-
-
-/*
- * end of autoconf section. To be extended...
- */
-
-/* Are the following #ifdefs still required? And why? Is that for X11? */
-
-#if defined(ESIX) || defined(M_UNIX) && !defined(SCO)
-# ifdef SIGWINCH
-# undef SIGWINCH
-# endif
-# ifdef TIOCGWINSZ
-# undef TIOCGWINSZ
-# endif
-#endif
-
-#if defined(SIGWINDOW) && !defined(SIGWINCH) /* hpux 9.01 has it */
-# define SIGWINCH SIGWINDOW
-#endif
-
-
static int get_x11_title(int);
static int get_x11_icon(int);
@@ -102,8 +81,6 @@ static int did_set_title = FALSE;
static char_u *oldicon = NULL;
static int did_set_icon = FALSE;
-static void may_core_dump(void);
-
#ifdef HAVE_UNION_WAIT
typedef union wait waitstatus;
#else
@@ -113,130 +90,12 @@ static pid_t wait4pid(pid_t, waitstatus *);
static int RealWaitForChar(int, long, int *);
-
-static void handle_resize(void);
-
-#if defined(SIGWINCH)
-static RETSIGTYPE sig_winch SIGPROTOARG;
-#endif
-#if defined(SIGINT)
-static RETSIGTYPE catch_sigint SIGPROTOARG;
-#endif
-#if defined(SIGPWR)
-static RETSIGTYPE catch_sigpwr SIGPROTOARG;
-#endif
-static RETSIGTYPE deathtrap SIGPROTOARG;
-
-static void catch_int_signal(void);
-static void set_signals(void);
-static void catch_signals
- (RETSIGTYPE (*func_deadly)(), RETSIGTYPE (*func_other)());
static int have_wildcard(int, char_u **);
static int have_dollars(int, char_u **);
static int save_patterns(int num_pat, char_u **pat, int *num_file,
char_u ***file);
-#ifndef SIG_ERR
-# define SIG_ERR ((RETSIGTYPE (*)())-1)
-#endif
-
-/* volatile because it is used in signal handler sig_winch(). */
-static volatile int do_resize = FALSE;
-/* volatile because it is used in signal handler deathtrap(). */
-static volatile int deadly_signal = 0; /* The signal we caught */
-
-
-#ifdef SYS_SIGLIST_DECLARED
-/*
- * I have seen
- * extern char *_sys_siglist[NSIG];
- * on Irix, Linux, NetBSD and Solaris. It contains a nice list of strings
- * that describe the signals. That is nearly what we want here. But
- * autoconf does only check for sys_siglist (without the underscore), I
- * do not want to change everything today.... jw.
- * This is why AC_DECL_SYS_SIGLIST is commented out in configure.in
- */
-#endif
-
-static struct signalinfo {
- int sig; /* Signal number, eg. SIGSEGV etc */
- char *name; /* Signal name (not char_u!). */
- char deadly; /* Catch as a deadly signal? */
-} signal_info[] =
-{
-#ifdef SIGHUP
- {SIGHUP, "HUP", TRUE},
-#endif
-#ifdef SIGQUIT
- {SIGQUIT, "QUIT", TRUE},
-#endif
-#ifdef SIGILL
- {SIGILL, "ILL", TRUE},
-#endif
-#ifdef SIGTRAP
- {SIGTRAP, "TRAP", TRUE},
-#endif
-#ifdef SIGABRT
- {SIGABRT, "ABRT", TRUE},
-#endif
-#ifdef SIGEMT
- {SIGEMT, "EMT", TRUE},
-#endif
-#ifdef SIGFPE
- {SIGFPE, "FPE", TRUE},
-#endif
-#ifdef SIGBUS
- {SIGBUS, "BUS", TRUE},
-#endif
-#if defined(SIGSEGV)
- /* MzScheme uses SEGV in its garbage collector */
- {SIGSEGV, "SEGV", TRUE},
-#endif
-#ifdef SIGSYS
- {SIGSYS, "SYS", TRUE},
-#endif
-#ifdef SIGALRM
- {SIGALRM, "ALRM", FALSE}, /* Perl's alarm() can trigger it */
-#endif
-#ifdef SIGTERM
- {SIGTERM, "TERM", TRUE},
-#endif
-#if defined(SIGVTALRM)
- {SIGVTALRM, "VTALRM", TRUE},
-#endif
-#if defined(SIGPROF) && !defined(WE_ARE_PROFILING)
- /* MzScheme uses SIGPROF for its own needs; On Linux with profiling
- * this makes Vim exit. WE_ARE_PROFILING is defined in Makefile. */
- {SIGPROF, "PROF", TRUE},
-#endif
-#ifdef SIGXCPU
- {SIGXCPU, "XCPU", TRUE},
-#endif
-#ifdef SIGXFSZ
- {SIGXFSZ, "XFSZ", TRUE},
-#endif
-#ifdef SIGUSR1
- {SIGUSR1, "USR1", TRUE},
-#endif
-#if defined(SIGUSR2) && !defined(FEAT_SYSMOUSE)
- /* Used for sysmouse handling */
- {SIGUSR2, "USR2", TRUE},
-#endif
-#ifdef SIGINT
- {SIGINT, "INT", FALSE},
-#endif
-#ifdef SIGWINCH
- {SIGWINCH, "WINCH", FALSE},
-#endif
-#ifdef SIGTSTP
- {SIGTSTP, "TSTP", FALSE},
-#endif
-#ifdef SIGPIPE
- {SIGPIPE, "PIPE", FALSE},
-#endif
- {-1, "Unknown!", FALSE}
-};
/*
* Write s[len] to the screen.
@@ -248,99 +107,6 @@ void mch_write(char_u *s, int len)
RealWaitForChar(read_cmd_fd, p_wd, NULL);
}
-static void handle_resize()
-{
- do_resize = FALSE;
- shell_resized();
-}
-
-
-#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
-/*
- * Support for using the signal stack.
- * This helps when we run out of stack space, which causes a SIGSEGV. The
- * signal handler then must run on another stack, since the normal stack is
- * completely full.
- */
-
-
-#ifndef SIGSTKSZ
-# define SIGSTKSZ 8000 /* just a guess of how much stack is needed... */
-#endif
-
-# ifdef HAVE_SIGALTSTACK
-static stack_t sigstk; /* for sigaltstack() */
-# else
-static struct sigstack sigstk; /* for sigstack() */
-# endif
-
-static void init_signal_stack(void);
-static char *signal_stack;
-
-static void init_signal_stack()
-{
- if (signal_stack != NULL) {
-# ifdef HAVE_SIGALTSTACK
- sigstk.ss_sp = signal_stack;
- sigstk.ss_size = SIGSTKSZ;
- sigstk.ss_flags = 0;
- (void)sigaltstack(&sigstk, NULL);
-# else
- sigstk.ss_sp = signal_stack;
- if (stack_grows_downwards)
- sigstk.ss_sp += SIGSTKSZ - 1;
- sigstk.ss_onstack = 0;
- (void)sigstack(&sigstk, NULL);
-# endif
- }
-}
-
-#endif
-
-/*
- * We need correct prototypes for a signal function, otherwise mean compilers
- * will barf when the second argument to signal() is ``wrong''.
- * Let me try it with a few tricky defines from my own osdef.h (jw).
- */
-#if defined(SIGWINCH)
-static RETSIGTYPE
-sig_winch SIGDEFARG(sigarg) {
- /* this is not required on all systems, but it doesn't hurt anybody */
- signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
- do_resize = TRUE;
- SIGRETURN;
-}
-
-#endif
-
-#if defined(SIGINT)
-static RETSIGTYPE
-catch_sigint SIGDEFARG(sigarg) {
- /* this is not required on all systems, but it doesn't hurt anybody */
- signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
- got_int = TRUE;
- SIGRETURN;
-}
-
-#endif
-
-#if defined(SIGPWR)
-static RETSIGTYPE
-catch_sigpwr SIGDEFARG(sigarg) {
- /* this is not required on all systems, but it doesn't hurt anybody */
- signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
- /*
- * I'm not sure we get the SIGPWR signal when the system is really going
- * down or when the batteries are almost empty. Just preserve the swap
- * files and don't exit, that can't do any harm.
- */
- ml_sync_all(FALSE, FALSE);
- SIGRETURN;
-}
-
-#endif
-
-#if defined(FEAT_LIBCALL) || defined(PROTO)
/*
* A simplistic version of setjmp() that only allows one level of using.
* Don't call twice before calling mch_endjmp()!.
@@ -363,9 +129,6 @@ catch_sigpwr SIGDEFARG(sigarg) {
*/
void mch_startjmp()
{
-#ifdef SIGHASARG
- lc_signal = 0;
-#endif
lc_active = TRUE;
}
@@ -374,165 +137,6 @@ void mch_endjmp()
lc_active = FALSE;
}
-void mch_didjmp()
-{
-# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
- /* On FreeBSD the signal stack has to be reset after using siglongjmp(),
- * otherwise catching the signal only works once. */
- init_signal_stack();
-# endif
-}
-
-#endif
-
-/*
- * This function handles deadly signals.
- * It tries to preserve any swap files and exit properly.
- * (partly from Elvis).
- * NOTE: Avoid unsafe functions, such as allocating memory, they can result in
- * a deadlock.
- */
-static RETSIGTYPE
-deathtrap SIGDEFARG(sigarg) {
- static int entered = 0; /* count the number of times we got here.
- Note: when memory has been corrupted
- this may get an arbitrary value! */
-#ifdef SIGHASARG
- int i;
-#endif
-
- /*
- * Catch a crash in protected code.
- * Restores the environment saved in lc_jump_env, which looks like
- * SETJMP() returns 1.
- */
- if (lc_active) {
-#if defined(SIGHASARG)
- lc_signal = sigarg;
-#endif
- lc_active = FALSE; /* don't jump again */
- LONGJMP(lc_jump_env, 1);
- /* NOTREACHED */
- }
-
-#ifdef SIGHASARG
-# ifdef SIGQUIT
- /* While in os_delay() we go to cooked mode to allow a CTRL-C to
- * interrupt us. But in cooked mode we may also get SIGQUIT, e.g., when
- * pressing CTRL-\, but we don't want Vim to exit then. */
- if (in_os_delay && sigarg == SIGQUIT)
- SIGRETURN;
-# endif
-
- /* When SIGHUP, SIGQUIT, etc. are blocked: postpone the effect and return
- * here. This avoids that a non-reentrant function is interrupted, e.g.,
- * free(). Calling free() again may then cause a crash. */
- if (entered == 0
- && (0
-# ifdef SIGHUP
- || sigarg == SIGHUP
-# endif
-# ifdef SIGQUIT
- || sigarg == SIGQUIT
-# endif
-# ifdef SIGTERM
- || sigarg == SIGTERM
-# endif
-# ifdef SIGPWR
- || sigarg == SIGPWR
-# endif
-# ifdef SIGUSR1
- || sigarg == SIGUSR1
-# endif
-# ifdef SIGUSR2
- || sigarg == SIGUSR2
-# endif
- )
- && !vim_handle_signal(sigarg))
- SIGRETURN;
-#endif
-
- /* Remember how often we have been called. */
- ++entered;
-
- /* Set the v:dying variable. */
- set_vim_var_nr(VV_DYING, (long)entered);
-
-#ifdef SIGHASARG
- /* try to find the name of this signal */
- for (i = 0; signal_info[i].sig != -1; i++)
- if (sigarg == signal_info[i].sig)
- break;
- deadly_signal = sigarg;
-#endif
-
- full_screen = FALSE; /* don't write message to the GUI, it might be
- * part of the problem... */
- /*
- * If something goes wrong after entering here, we may get here again.
- * When this happens, give a message and try to exit nicely (resetting the
- * terminal mode, etc.)
- * When this happens twice, just exit, don't even try to give a message,
- * stack may be corrupt or something weird.
- * When this still happens again (or memory was corrupted in such a way
- * that "entered" was clobbered) use _exit(), don't try freeing resources.
- */
- if (entered >= 3) {
- reset_signals(); /* don't catch any signals anymore */
- may_core_dump();
- if (entered >= 4)
- _exit(8);
- exit(7);
- }
- if (entered == 2) {
- /* No translation, it may call malloc(). */
- OUT_STR("Vim: Double signal, exiting\n");
- out_flush();
- getout(1);
- }
-
- /* No translation, it may call malloc(). */
-#ifdef SIGHASARG
- sprintf((char *)IObuff, "Vim: Caught deadly signal %s\n",
- signal_info[i].name);
-#else
- sprintf((char *)IObuff, "Vim: Caught deadly signal\n");
-#endif
-
- /* Preserve files and exit. This sets the really_exiting flag to prevent
- * calling free(). */
- preserve_exit();
-
-
- SIGRETURN;
-}
-
-#if defined(_REENTRANT) && defined(SIGCONT)
-/*
- * On Solaris with multi-threading, suspending might not work immediately.
- * Catch the SIGCONT signal, which will be used as an indication whether the
- * suspending has been done or not.
- *
- * On Linux, signal is not always handled immediately either.
- * See https://bugs.launchpad.net/bugs/291373
- *
- * volatile because it is used in signal handler sigcont_handler().
- */
-static volatile int sigcont_received;
-static RETSIGTYPE sigcont_handler SIGPROTOARG;
-
-/*
- * signal handler for SIGCONT
- */
-static RETSIGTYPE
-sigcont_handler SIGDEFARG(sigarg) {
- sigcont_received = TRUE;
- SIGRETURN;
-}
-
-#endif
-
-
/*
* If the machine has job control, use it to suspend the program,
* otherwise fake it by starting a new shell.
@@ -589,7 +193,6 @@ void mch_init()
Rows = 24;
out_flush();
- set_signals();
#ifdef MACOS_CONVERT
mac_conv_init();
@@ -598,159 +201,6 @@ void mch_init()
event_init();
}
-static void set_signals()
-{
-#if defined(SIGWINCH)
- /*
- * WINDOW CHANGE signal is handled with sig_winch().
- */
- signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
-#endif
-
- /*
- * We want the STOP signal to work, to make mch_suspend() work.
- * For "rvim" the STOP signal is ignored.
- */
-#ifdef SIGTSTP
- signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
-#endif
-#if defined(_REENTRANT) && defined(SIGCONT)
- signal(SIGCONT, sigcont_handler);
-#endif
-
- /*
- * We want to ignore breaking of PIPEs.
- */
-#ifdef SIGPIPE
- signal(SIGPIPE, SIG_IGN);
-#endif
-
-#ifdef SIGINT
- catch_int_signal();
-#endif
-
- /*
- * Ignore alarm signals (Perl's alarm() generates it).
- */
-#ifdef SIGALRM
- signal(SIGALRM, SIG_IGN);
-#endif
-
- /*
- * Catch SIGPWR (power failure?) to preserve the swap files, so that no
- * work will be lost.
- */
-#ifdef SIGPWR
- signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
-#endif
-
- /*
- * Arrange for other signals to gracefully shutdown Vim.
- */
- catch_signals(deathtrap, SIG_ERR);
-
-}
-
-#if defined(SIGINT) || defined(PROTO)
-/*
- * Catch CTRL-C (only works while in Cooked mode).
- */
-static void catch_int_signal()
-{
- signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
-}
-
-#endif
-
-void reset_signals()
-{
- catch_signals(SIG_DFL, SIG_DFL);
-#if defined(_REENTRANT) && defined(SIGCONT)
- /* SIGCONT isn't in the list, because its default action is ignore */
- signal(SIGCONT, SIG_DFL);
-#endif
-}
-
-static void catch_signals(
- RETSIGTYPE (*func_deadly)(),
- RETSIGTYPE (*func_other)()
- )
-{
- int i;
-
- for (i = 0; signal_info[i].sig != -1; i++)
- if (signal_info[i].deadly) {
-#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
- struct sigaction sa;
-
- /* Setup to use the alternate stack for the signal function. */
- sa.sa_handler = func_deadly;
- sigemptyset(&sa.sa_mask);
-# if defined(__linux__) && defined(_REENTRANT)
- /* On Linux, with glibc compiled for kernel 2.2, there is a bug in
- * thread handling in combination with using the alternate stack:
- * pthread library functions try to use the stack pointer to
- * identify the current thread, causing a SEGV signal, which
- * recursively calls deathtrap() and hangs. */
- sa.sa_flags = 0;
-# else
- sa.sa_flags = SA_ONSTACK;
-# endif
- sigaction(signal_info[i].sig, &sa, NULL);
-#else
-# if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGVEC)
- struct sigvec sv;
-
- /* Setup to use the alternate stack for the signal function. */
- sv.sv_handler = func_deadly;
- sv.sv_mask = 0;
- sv.sv_flags = SV_ONSTACK;
- sigvec(signal_info[i].sig, &sv, NULL);
-# else
- signal(signal_info[i].sig, func_deadly);
-# endif
-#endif
- } else if (func_other != SIG_ERR)
- signal(signal_info[i].sig, func_other);
-}
-
-/*
- * Handling of SIGHUP, SIGQUIT and SIGTERM:
- * "when" == a signal: when busy, postpone and return FALSE, otherwise
- * return TRUE
- * "when" == SIGNAL_BLOCK: Going to be busy, block signals
- * "when" == SIGNAL_UNBLOCK: Going to wait, unblock signals, use postponed
- * signal
- * Returns TRUE when Vim should exit.
- */
-int vim_handle_signal(int sig)
-{
- static int got_signal = 0;
- static int blocked = TRUE;
-
- switch (sig) {
- case SIGNAL_BLOCK: blocked = TRUE;
- break;
-
- case SIGNAL_UNBLOCK: blocked = FALSE;
- if (got_signal != 0) {
- kill(getpid(), got_signal);
- got_signal = 0;
- }
- break;
-
- default: if (!blocked)
- return TRUE; /* exit! */
- got_signal = sig;
-#ifdef SIGPWR
- if (sig != SIGPWR)
-#endif
- got_int = TRUE; /* break any loops */
- break;
- }
- return FALSE;
-}
-
/*
* Check_win checks whether we have an interactive stdout.
*/
@@ -1153,26 +603,11 @@ int mch_nodetype(char_u *name)
void mch_early_init()
{
- /*
- * Setup an alternative stack for signals. Helps to catch signals when
- * running out of stack space.
- * Use of sigaltstack() is preferred, it's more portable.
- * Ignore any errors.
- */
-#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
- signal_stack = (char *)alloc(SIGSTKSZ);
- init_signal_stack();
-#endif
-
time_init();
}
#if defined(EXITFREE) || defined(PROTO)
void mch_free_mem() {
-# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
- vim_free(signal_stack);
- signal_stack = NULL;
-# endif
vim_free(oldtitle);
vim_free(oldicon);
}
@@ -1239,7 +674,6 @@ void mch_exit(int r)
}
out_flush();
ml_close_all(TRUE); /* remove all memfiles */
- may_core_dump();
#ifdef MACOS_CONVERT
mac_conv_cleanup();
@@ -1254,14 +688,6 @@ void mch_exit(int r)
exit(r);
}
-static void may_core_dump()
-{
- if (deadly_signal != 0) {
- signal(deadly_signal, SIG_DFL);
- kill(getpid(), deadly_signal); /* Die using the signal we caught */
- }
-}
-
void mch_settmode(int tmode)
{
static int first = TRUE;
@@ -1749,7 +1175,7 @@ int mch_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_shell_arg)
}
}
} else if (pid == 0) { /* child */
- reset_signals(); /* handle signals normally */
+ signal_stop(); /* handle signals normally */
if (opts & (kShellOptHideMess | kShellOptExpand)) {
int fd;
@@ -1846,8 +1272,7 @@ int mch_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_shell_arg)
* While child is running, ignore terminating signals.
* Do catch CTRL-C, so that "got_int" is set.
*/
- catch_signals(SIG_IGN, SIG_ERR);
- catch_int_signal();
+ signal_reject_deadly();
/*
* For the GUI we redirect stdin, stdout and stderr to our window.
@@ -2266,7 +1691,7 @@ finished:
if (tmode == TMODE_RAW)
settmode(TMODE_RAW);
did_settmode = TRUE;
- set_signals();
+ signal_accept_deadly();
if (WIFEXITED(status)) {
/* LINTED avoid "bitwise operation on signed value" */
@@ -2365,9 +1790,7 @@ select_eintr:
# ifdef EINTR
if (ret == -1 && errno == EINTR) {
/* Check whether window has been resized, EINTR may be caused by
- * SIGWINCH. */
- if (do_resize)
- handle_resize();
+ * SIGWINCH. FIXME this is broken for now */
/* Interrupted by a signal, need to try again. We ignore msec
* here, because we do want to check even after a timeout if
@@ -3035,7 +2458,6 @@ int *number_result;
# if defined(USE_DLOPEN)
dlerr = NULL;
# endif
- mch_didjmp();
} else
{
retval_str = NULL;
@@ -3127,5 +2549,3 @@ int *number_result;
-
-