diff options
-rw-r--r-- | src/main.c | 9 | ||||
-rw-r--r-- | src/normal.c | 3 | ||||
-rw-r--r-- | src/os/event.c | 105 | ||||
-rw-r--r-- | src/os/event.h | 10 | ||||
-rw-r--r-- | src/os/input.c | 10 | ||||
-rw-r--r-- | src/os/signal.c | 155 | ||||
-rw-r--r-- | src/os/signal.h | 13 | ||||
-rw-r--r-- | src/os_unix.c | 590 | ||||
-rw-r--r-- | src/os_unix.h | 3 | ||||
-rw-r--r-- | src/ui.c | 5 |
10 files changed, 295 insertions, 608 deletions
diff --git a/src/main.c b/src/main.c index a8a2efbc8a..0b1f650827 100644 --- a/src/main.c +++ b/src/main.c @@ -47,6 +47,7 @@ #include "version.h" #include "window.h" #include "os/os.h" +#include "os/signal.h" /* Maximum number of commands from + or -c arguments. */ #define MAX_ARG_CMDS 10 @@ -2167,9 +2168,7 @@ mainerr ( char_u *str /* extra argument or NULL */ ) { -#if defined(UNIX) || defined(__EMX__) || defined(VMS) - reset_signals(); /* kill us with CTRL-C here, if you like */ -#endif + signal_stop(); /* kill us with CTRL-C here, if you like */ mch_errmsg(longVersion); mch_errmsg("\n"); @@ -2214,9 +2213,7 @@ static void usage(void) N_("-q [errorfile] edit file with first error") }; -#if defined(UNIX) || defined(__EMX__) || defined(VMS) - reset_signals(); /* kill us with CTRL-C here, if you like */ -#endif + signal_stop(); /* kill us with CTRL-C here, if you like */ mch_msg(longVersion); mch_msg(_("\n\nusage:")); diff --git a/src/normal.c b/src/normal.c index 0646a62fcf..6319e19203 100644 --- a/src/normal.c +++ b/src/normal.c @@ -7480,9 +7480,6 @@ static void nv_open(cmdarg_T *cap) n_opencmd(cap); } - - - /* * Trigger CursorHold event. * When waiting for a character for 'updatetime' K_CURSORHOLD is put in the diff --git a/src/os/event.c b/src/os/event.c index eb7960c219..943af8c24e 100644 --- a/src/os/event.c +++ b/src/os/event.c @@ -1,13 +1,26 @@ #include <stdint.h> #include <stdbool.h> +#include <stdlib.h> #include <uv.h> #include "os/event.h" #include "os/input.h" +#include "os/signal.h" +#include "vim.h" +#include "misc2.h" +typedef struct EventNode { + Event *event; + struct EventNode *next; +} EventNode; + +static EventNode *head, *tail; static uv_timer_t timer; static uv_prepare_t timer_prepare; +static bool poll_uv_loop(int ms); +static void process_all_events(void); +static bool has_pending_events(void); static void timer_cb(uv_timer_t *handle, int); static void timer_prepare_cb(uv_prepare_t *, int); @@ -17,14 +30,94 @@ void event_init() input_init(); // Timer to wake the event loop if a timeout argument is passed to // `event_poll` + // Signals + signal_init(); uv_timer_init(uv_default_loop(), &timer); // This prepare handle that actually starts the timer uv_prepare_init(uv_default_loop(), &timer_prepare); } -// Wait for some event bool event_poll(int32_t ms) { + int64_t remaining = ms; + uint64_t end; + bool result; + + if (ms > 0) { + // Calculate end time in nanoseconds + end = uv_hrtime() + ms * 1e6; + } + + for (;;) { + result = poll_uv_loop((int32_t)remaining); + // Process queued events + process_all_events(); + + if (ms > 0) { + // Calculate remaining time in milliseconds + remaining = (end - uv_hrtime()) / 1e6; + } + + if (input_ready() || got_int) { + // Bail out if we have pending input + return true; + } + + if (!result || (ms >= 0 && remaining <= 0)) { + // Or if we timed out + return false; + } + } +} + +// Push an event to the queue +void event_push(Event *event) +{ + EventNode *node = (EventNode *)xmalloc(sizeof(EventNode)); + node->event = event; + node->next = NULL; + + if (head == NULL) { + head = node; + } else { + tail->next = node; + } + + tail = node; +} + +// Runs the appropriate action for each queued event +static void process_all_events() +{ + EventNode *next; + Event *event; + + while (has_pending_events()) { + next = head->next; + event = head->event; + free(head); + head = next; + + switch (event->type) { + case kEventSignal: + signal_handle(event); + break; + default: + abort(); + } + + } +} + +// Checks if there are queued events +bool has_pending_events() +{ + return head != NULL; +} + +// Wait for some event +static bool poll_uv_loop(int32_t ms) +{ bool timed_out; uv_run_mode run_mode = UV_RUN_ONCE; @@ -55,9 +148,11 @@ bool event_poll(int32_t ms) uv_run(uv_default_loop(), run_mode); } while ( // Continue running if ... - !input_ready() // ... we have no input - && run_mode != UV_RUN_NOWAIT // ... ms != 0 - && !timed_out); // ... we didn't get a timeout + !input_ready() && // we have no input + !has_pending_events() && // no events are waiting to be processed + run_mode != UV_RUN_NOWAIT && // ms != 0 + !timed_out // we didn't get a timeout + ); input_stop(); @@ -66,7 +161,7 @@ bool event_poll(int32_t ms) uv_timer_stop(&timer); } - return input_ready(); + return input_ready() || has_pending_events(); } // Set a flag in the `event_poll` loop for signaling of a timeout diff --git a/src/os/event.h b/src/os/event.h index d13103373d..fe846695e5 100644 --- a/src/os/event.h +++ b/src/os/event.h @@ -4,8 +4,18 @@ #include <stdint.h> #include <stdbool.h> +typedef enum { + kEventSignal +} EventType; + +typedef struct { + EventType type; + void *data; +} Event; + void event_init(void); bool event_poll(int32_t ms); +void event_push(Event *event); #endif // NEOVIM_OS_EVENT_H diff --git a/src/os/input.c b/src/os/input.c index 1e2d331fc0..14a7088024 100644 --- a/src/os/input.c +++ b/src/os/input.c @@ -1,3 +1,4 @@ +#include <string.h> #include <stdint.h> #include <stdbool.h> @@ -58,7 +59,7 @@ void input_init() } } -// Check if there's a pending input event +// Check if there's pending input bool input_ready() { return rbuffer.rpos < rbuffer.wpos || eof; @@ -126,11 +127,11 @@ int os_inchar(char_u *buf, int maxlen, int32_t ms, int tb_change_cnt) InbufPollResult result; if (ms >= 0) { - if ((result = inbuf_poll(ms)) != kInputAvail) { + if ((result = inbuf_poll(ms)) == kInputNone) { return 0; } } else { - if ((result = inbuf_poll(p_ut)) != kInputAvail) { + if ((result = inbuf_poll(p_ut)) == kInputNone) { if (trigger_cursorhold() && maxlen >= 3 && !typebuf_changed(tb_change_cnt)) { buf[0] = K_SPECIAL; @@ -177,9 +178,10 @@ static InbufPollResult inbuf_poll(int32_t ms) return kInputAvail; if (event_poll(ms)) { - if (rbuffer.rpos == rbuffer.wpos && eof) { + if (!got_int && rbuffer.rpos == rbuffer.wpos && eof) { return kInputEof; } + return kInputAvail; } diff --git a/src/os/signal.c b/src/os/signal.c new file mode 100644 index 0000000000..9c75377062 --- /dev/null +++ b/src/os/signal.c @@ -0,0 +1,155 @@ +#include <stdbool.h> + +#include <uv.h> + +#include "types.h" +#include "vim.h" +#include "globals.h" +#include "memline.h" +#include "eval.h" +#include "term.h" +#include "misc1.h" +#include "misc2.h" +#include "os/event.h" +#include "os/signal.h" + +static uv_signal_t sint, spipe, shup, squit, sterm, swinch; +#ifdef SIGPWR +static uv_signal_t spwr; +#endif + +static bool rejecting_deadly; +static char * signal_name(int signum); +static void deadly_signal(int signum); +static void signal_cb(uv_signal_t *, int signum); + +void signal_init() +{ + uv_signal_init(uv_default_loop(), &sint); + uv_signal_init(uv_default_loop(), &spipe); + uv_signal_init(uv_default_loop(), &shup); + uv_signal_init(uv_default_loop(), &squit); + uv_signal_init(uv_default_loop(), &sterm); + uv_signal_init(uv_default_loop(), &swinch); + uv_signal_start(&sint, signal_cb, SIGINT); + uv_signal_start(&spipe, signal_cb, SIGPIPE); + uv_signal_start(&shup, signal_cb, SIGHUP); + uv_signal_start(&squit, signal_cb, SIGQUIT); + uv_signal_start(&sterm, signal_cb, SIGTERM); + uv_signal_start(&swinch, signal_cb, SIGWINCH); +#ifdef SIGPWR + uv_signal_init(uv_default_loop(), &spwr); + uv_signal_start(&spwr, signal_cb, SIGPWR); +#endif +} + +void signal_stop() +{ + uv_signal_stop(&sint); + uv_signal_stop(&spipe); + uv_signal_stop(&shup); + uv_signal_stop(&squit); + uv_signal_stop(&sterm); + uv_signal_stop(&swinch); +#ifdef SIGPWR + uv_signal_stop(&spwr); +#endif +} + +void signal_reject_deadly() +{ + rejecting_deadly = true; +} + +void signal_accept_deadly() +{ + rejecting_deadly = false; +} + +void signal_handle(Event *event) +{ + int signum = *(int *)event->data; + + free(event->data); + free(event); + + switch (signum) { + case SIGINT: + got_int = TRUE; + break; +#ifdef SIGPWR + case SIGPWR: + // Signal of a power failure(eg batteries low), flush the swap files to + // be safe + ml_sync_all(FALSE, FALSE); + break; +#endif + case SIGPIPE: + // Ignore + break; + case SIGWINCH: + shell_resized(); + break; + case SIGTERM: + case SIGQUIT: + case SIGHUP: + if (!rejecting_deadly) { + deadly_signal(signum); + } + break; + default: + fprintf(stderr, "Invalid signal %d", signum); + break; + } +} + +static char * signal_name(int signum) +{ + switch (signum) { + case SIGINT: + return "SIGINT"; +#ifdef SIGPWR + case SIGPWR: + return "SIGPWR"; +#endif + case SIGPIPE: + return "SIGPIPE"; + case SIGWINCH: + return "SIGWINCH"; + case SIGTERM: + return "SIGTERM"; + case SIGQUIT: + return "SIGQUIT"; + case SIGHUP: + return "SIGHUP"; + default: + return "Unknown"; + } +} + +// 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 void deadly_signal(int signum) +{ + // Set the v:dying variable. + set_vim_var_nr(VV_DYING, 1); + + sprintf((char *)IObuff, "Vim: Caught deadly signal '%s'\n", + signal_name(signum)); + + // Preserve files and exit. This sets the really_exiting flag to prevent + // calling free(). + preserve_exit(); +} + +static void signal_cb(uv_signal_t *handle, int signum) +{ + Event *event = (Event *)xmalloc(sizeof(Event)); + event->type = kEventSignal; + event->data = xmalloc(sizeof(int)); + *(int *)event->data = signum; + event_push(event); +} diff --git a/src/os/signal.h b/src/os/signal.h new file mode 100644 index 0000000000..a5247742db --- /dev/null +++ b/src/os/signal.h @@ -0,0 +1,13 @@ +#ifndef NEOVIM_OS_SIGNAL_H +#define NEOVIM_OS_SIGNAL_H + +#include "os/event.h" + +void signal_init(void); +void signal_stop(void); +void signal_accept_deadly(void); +void signal_reject_deadly(void); +void signal_handle(Event *event); + +#endif + 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; - - diff --git a/src/os_unix.h b/src/os_unix.h index 7a3812dc5b..64b1a62b22 100644 --- a/src/os_unix.h +++ b/src/os_unix.h @@ -5,9 +5,6 @@ /* os_unix.c */ void mch_write(char_u *s, int len); -void mch_startjmp(void); -void mch_endjmp(void); -void mch_didjmp(void); void mch_suspend(void); void mch_init(void); void reset_signals(void); @@ -34,6 +34,7 @@ #include "os_unix.h" #include "os/time.h" #include "os/input.h" +#include "os/signal.h" #include "screen.h" #include "term.h" #include "window.h" @@ -145,7 +146,7 @@ ui_inchar ( /* If we are going to wait for some time or block... */ if (wtime == -1 || wtime > 100L) { /* ... allow signals to kill us. */ - (void)vim_handle_signal(SIGNAL_UNBLOCK); + signal_accept_deadly(); /* ... there is no need for CTRL-C to interrupt something, don't let * it set got_int when it was mapped. */ @@ -161,7 +162,7 @@ ui_inchar ( if (wtime == -1 || wtime > 100L) /* block SIGHUP et al. */ - (void)vim_handle_signal(SIGNAL_BLOCK); + signal_reject_deadly(); ctrl_c_interrupts = TRUE; |