mirror of
https://github.com/neovim/neovim.git
synced 2025-09-15 15:58:17 +00:00
Move signal handling to libuv event loop
This removes all signal handling code from os_unix.c to os/signal.c. Now signal handling is done like this: - Watchers for signals are registered with libuv default event loop - `event_poll` continuously calls `poll_uv_loop` to produce events until it receives user input, SIGINT or a timeout - Any signals received in `poll_uv_loop` will push events to a queue that is drained and processed by `event_poll` Signals aren't handled directly in the libuv callback to avoid recursion in the event loop(which isn't supported by libuv). The same principle will apply to other events in the future: Push to a queue from a libuv callback and drain it from `event_poll`
This commit is contained in:
@@ -47,6 +47,7 @@
|
|||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
#include "os/os.h"
|
#include "os/os.h"
|
||||||
|
#include "os/signal.h"
|
||||||
|
|
||||||
/* Maximum number of commands from + or -c arguments. */
|
/* Maximum number of commands from + or -c arguments. */
|
||||||
#define MAX_ARG_CMDS 10
|
#define MAX_ARG_CMDS 10
|
||||||
@@ -2167,9 +2168,7 @@ mainerr (
|
|||||||
char_u *str /* extra argument or NULL */
|
char_u *str /* extra argument or NULL */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
#if defined(UNIX) || defined(__EMX__) || defined(VMS)
|
signal_stop(); /* kill us with CTRL-C here, if you like */
|
||||||
reset_signals(); /* kill us with CTRL-C here, if you like */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
mch_errmsg(longVersion);
|
mch_errmsg(longVersion);
|
||||||
mch_errmsg("\n");
|
mch_errmsg("\n");
|
||||||
@@ -2214,9 +2213,7 @@ static void usage(void)
|
|||||||
N_("-q [errorfile] edit file with first error")
|
N_("-q [errorfile] edit file with first error")
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(UNIX) || defined(__EMX__) || defined(VMS)
|
signal_stop(); /* kill us with CTRL-C here, if you like */
|
||||||
reset_signals(); /* kill us with CTRL-C here, if you like */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
mch_msg(longVersion);
|
mch_msg(longVersion);
|
||||||
mch_msg(_("\n\nusage:"));
|
mch_msg(_("\n\nusage:"));
|
||||||
|
@@ -7480,9 +7480,6 @@ static void nv_open(cmdarg_T *cap)
|
|||||||
n_opencmd(cap);
|
n_opencmd(cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Trigger CursorHold event.
|
* Trigger CursorHold event.
|
||||||
* When waiting for a character for 'updatetime' K_CURSORHOLD is put in the
|
* When waiting for a character for 'updatetime' K_CURSORHOLD is put in the
|
||||||
|
105
src/os/event.c
105
src/os/event.c
@@ -1,13 +1,26 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include <uv.h>
|
#include <uv.h>
|
||||||
|
|
||||||
#include "os/event.h"
|
#include "os/event.h"
|
||||||
#include "os/input.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_timer_t timer;
|
||||||
static uv_prepare_t timer_prepare;
|
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_cb(uv_timer_t *handle, int);
|
||||||
static void timer_prepare_cb(uv_prepare_t *, int);
|
static void timer_prepare_cb(uv_prepare_t *, int);
|
||||||
|
|
||||||
@@ -17,13 +30,93 @@ void event_init()
|
|||||||
input_init();
|
input_init();
|
||||||
// Timer to wake the event loop if a timeout argument is passed to
|
// Timer to wake the event loop if a timeout argument is passed to
|
||||||
// `event_poll`
|
// `event_poll`
|
||||||
|
// Signals
|
||||||
|
signal_init();
|
||||||
uv_timer_init(uv_default_loop(), &timer);
|
uv_timer_init(uv_default_loop(), &timer);
|
||||||
// This prepare handle that actually starts the timer
|
// This prepare handle that actually starts the timer
|
||||||
uv_prepare_init(uv_default_loop(), &timer_prepare);
|
uv_prepare_init(uv_default_loop(), &timer_prepare);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for some event
|
|
||||||
bool event_poll(int32_t ms)
|
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;
|
bool timed_out;
|
||||||
uv_run_mode run_mode = UV_RUN_ONCE;
|
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);
|
uv_run(uv_default_loop(), run_mode);
|
||||||
} while (
|
} while (
|
||||||
// Continue running if ...
|
// Continue running if ...
|
||||||
!input_ready() // ... we have no input
|
!input_ready() && // we have no input
|
||||||
&& run_mode != UV_RUN_NOWAIT // ... ms != 0
|
!has_pending_events() && // no events are waiting to be processed
|
||||||
&& !timed_out); // ... we didn't get a timeout
|
run_mode != UV_RUN_NOWAIT && // ms != 0
|
||||||
|
!timed_out // we didn't get a timeout
|
||||||
|
);
|
||||||
|
|
||||||
input_stop();
|
input_stop();
|
||||||
|
|
||||||
@@ -66,7 +161,7 @@ bool event_poll(int32_t ms)
|
|||||||
uv_timer_stop(&timer);
|
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
|
// Set a flag in the `event_poll` loop for signaling of a timeout
|
||||||
|
@@ -4,8 +4,18 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
kEventSignal
|
||||||
|
} EventType;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
EventType type;
|
||||||
|
void *data;
|
||||||
|
} Event;
|
||||||
|
|
||||||
void event_init(void);
|
void event_init(void);
|
||||||
bool event_poll(int32_t ms);
|
bool event_poll(int32_t ms);
|
||||||
|
void event_push(Event *event);
|
||||||
|
|
||||||
#endif // NEOVIM_OS_EVENT_H
|
#endif // NEOVIM_OS_EVENT_H
|
||||||
|
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
#include <string.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.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()
|
bool input_ready()
|
||||||
{
|
{
|
||||||
return rbuffer.rpos < rbuffer.wpos || eof;
|
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;
|
InbufPollResult result;
|
||||||
|
|
||||||
if (ms >= 0) {
|
if (ms >= 0) {
|
||||||
if ((result = inbuf_poll(ms)) != kInputAvail) {
|
if ((result = inbuf_poll(ms)) == kInputNone) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ((result = inbuf_poll(p_ut)) != kInputAvail) {
|
if ((result = inbuf_poll(p_ut)) == kInputNone) {
|
||||||
if (trigger_cursorhold() && maxlen >= 3
|
if (trigger_cursorhold() && maxlen >= 3
|
||||||
&& !typebuf_changed(tb_change_cnt)) {
|
&& !typebuf_changed(tb_change_cnt)) {
|
||||||
buf[0] = K_SPECIAL;
|
buf[0] = K_SPECIAL;
|
||||||
@@ -177,9 +178,10 @@ static InbufPollResult inbuf_poll(int32_t ms)
|
|||||||
return kInputAvail;
|
return kInputAvail;
|
||||||
|
|
||||||
if (event_poll(ms)) {
|
if (event_poll(ms)) {
|
||||||
if (rbuffer.rpos == rbuffer.wpos && eof) {
|
if (!got_int && rbuffer.rpos == rbuffer.wpos && eof) {
|
||||||
return kInputEof;
|
return kInputEof;
|
||||||
}
|
}
|
||||||
|
|
||||||
return kInputAvail;
|
return kInputAvail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
155
src/os/signal.c
Normal file
155
src/os/signal.c
Normal file
@@ -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);
|
||||||
|
}
|
13
src/os/signal.h
Normal file
13
src/os/signal.h
Normal file
@@ -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
|
||||||
|
|
590
src/os_unix.c
590
src/os_unix.c
@@ -54,6 +54,7 @@
|
|||||||
#include "os/event.h"
|
#include "os/event.h"
|
||||||
#include "os/input.h"
|
#include "os/input.h"
|
||||||
#include "os/shell.h"
|
#include "os/shell.h"
|
||||||
|
#include "os/signal.h"
|
||||||
|
|
||||||
#include "os_unixx.h" /* unix includes for os_unix.c only */
|
#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 *);
|
extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
|
||||||
#endif
|
#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_title(int);
|
||||||
static int get_x11_icon(int);
|
static int get_x11_icon(int);
|
||||||
|
|
||||||
@@ -102,8 +81,6 @@ static int did_set_title = FALSE;
|
|||||||
static char_u *oldicon = NULL;
|
static char_u *oldicon = NULL;
|
||||||
static int did_set_icon = FALSE;
|
static int did_set_icon = FALSE;
|
||||||
|
|
||||||
static void may_core_dump(void);
|
|
||||||
|
|
||||||
#ifdef HAVE_UNION_WAIT
|
#ifdef HAVE_UNION_WAIT
|
||||||
typedef union wait waitstatus;
|
typedef union wait waitstatus;
|
||||||
#else
|
#else
|
||||||
@@ -113,130 +90,12 @@ static pid_t wait4pid(pid_t, waitstatus *);
|
|||||||
|
|
||||||
static int RealWaitForChar(int, long, int *);
|
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_wildcard(int, char_u **);
|
||||||
static int have_dollars(int, char_u **);
|
static int have_dollars(int, char_u **);
|
||||||
|
|
||||||
static int save_patterns(int num_pat, char_u **pat, int *num_file,
|
static int save_patterns(int num_pat, char_u **pat, int *num_file,
|
||||||
char_u ***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.
|
* 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);
|
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.
|
* A simplistic version of setjmp() that only allows one level of using.
|
||||||
* Don't call twice before calling mch_endjmp()!.
|
* Don't call twice before calling mch_endjmp()!.
|
||||||
@@ -363,9 +129,6 @@ catch_sigpwr SIGDEFARG(sigarg) {
|
|||||||
*/
|
*/
|
||||||
void mch_startjmp()
|
void mch_startjmp()
|
||||||
{
|
{
|
||||||
#ifdef SIGHASARG
|
|
||||||
lc_signal = 0;
|
|
||||||
#endif
|
|
||||||
lc_active = TRUE;
|
lc_active = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,165 +137,6 @@ void mch_endjmp()
|
|||||||
lc_active = FALSE;
|
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,
|
* If the machine has job control, use it to suspend the program,
|
||||||
* otherwise fake it by starting a new shell.
|
* otherwise fake it by starting a new shell.
|
||||||
@@ -589,7 +193,6 @@ void mch_init()
|
|||||||
Rows = 24;
|
Rows = 24;
|
||||||
|
|
||||||
out_flush();
|
out_flush();
|
||||||
set_signals();
|
|
||||||
|
|
||||||
#ifdef MACOS_CONVERT
|
#ifdef MACOS_CONVERT
|
||||||
mac_conv_init();
|
mac_conv_init();
|
||||||
@@ -598,159 +201,6 @@ void mch_init()
|
|||||||
event_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.
|
* Check_win checks whether we have an interactive stdout.
|
||||||
*/
|
*/
|
||||||
@@ -1153,26 +603,11 @@ int mch_nodetype(char_u *name)
|
|||||||
|
|
||||||
void mch_early_init()
|
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();
|
time_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(EXITFREE) || defined(PROTO)
|
#if defined(EXITFREE) || defined(PROTO)
|
||||||
void mch_free_mem() {
|
void mch_free_mem() {
|
||||||
# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
|
|
||||||
vim_free(signal_stack);
|
|
||||||
signal_stack = NULL;
|
|
||||||
# endif
|
|
||||||
vim_free(oldtitle);
|
vim_free(oldtitle);
|
||||||
vim_free(oldicon);
|
vim_free(oldicon);
|
||||||
}
|
}
|
||||||
@@ -1239,7 +674,6 @@ void mch_exit(int r)
|
|||||||
}
|
}
|
||||||
out_flush();
|
out_flush();
|
||||||
ml_close_all(TRUE); /* remove all memfiles */
|
ml_close_all(TRUE); /* remove all memfiles */
|
||||||
may_core_dump();
|
|
||||||
|
|
||||||
#ifdef MACOS_CONVERT
|
#ifdef MACOS_CONVERT
|
||||||
mac_conv_cleanup();
|
mac_conv_cleanup();
|
||||||
@@ -1254,14 +688,6 @@ void mch_exit(int r)
|
|||||||
exit(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)
|
void mch_settmode(int tmode)
|
||||||
{
|
{
|
||||||
static int first = TRUE;
|
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 */
|
} else if (pid == 0) { /* child */
|
||||||
reset_signals(); /* handle signals normally */
|
signal_stop(); /* handle signals normally */
|
||||||
|
|
||||||
if (opts & (kShellOptHideMess | kShellOptExpand)) {
|
if (opts & (kShellOptHideMess | kShellOptExpand)) {
|
||||||
int fd;
|
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.
|
* While child is running, ignore terminating signals.
|
||||||
* Do catch CTRL-C, so that "got_int" is set.
|
* Do catch CTRL-C, so that "got_int" is set.
|
||||||
*/
|
*/
|
||||||
catch_signals(SIG_IGN, SIG_ERR);
|
signal_reject_deadly();
|
||||||
catch_int_signal();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For the GUI we redirect stdin, stdout and stderr to our window.
|
* For the GUI we redirect stdin, stdout and stderr to our window.
|
||||||
@@ -2266,7 +1691,7 @@ finished:
|
|||||||
if (tmode == TMODE_RAW)
|
if (tmode == TMODE_RAW)
|
||||||
settmode(TMODE_RAW);
|
settmode(TMODE_RAW);
|
||||||
did_settmode = TRUE;
|
did_settmode = TRUE;
|
||||||
set_signals();
|
signal_accept_deadly();
|
||||||
|
|
||||||
if (WIFEXITED(status)) {
|
if (WIFEXITED(status)) {
|
||||||
/* LINTED avoid "bitwise operation on signed value" */
|
/* LINTED avoid "bitwise operation on signed value" */
|
||||||
@@ -2365,9 +1790,7 @@ select_eintr:
|
|||||||
# ifdef EINTR
|
# ifdef EINTR
|
||||||
if (ret == -1 && errno == EINTR) {
|
if (ret == -1 && errno == EINTR) {
|
||||||
/* Check whether window has been resized, EINTR may be caused by
|
/* Check whether window has been resized, EINTR may be caused by
|
||||||
* SIGWINCH. */
|
* SIGWINCH. FIXME this is broken for now */
|
||||||
if (do_resize)
|
|
||||||
handle_resize();
|
|
||||||
|
|
||||||
/* Interrupted by a signal, need to try again. We ignore msec
|
/* Interrupted by a signal, need to try again. We ignore msec
|
||||||
* here, because we do want to check even after a timeout if
|
* here, because we do want to check even after a timeout if
|
||||||
@@ -3035,7 +2458,6 @@ int *number_result;
|
|||||||
# if defined(USE_DLOPEN)
|
# if defined(USE_DLOPEN)
|
||||||
dlerr = NULL;
|
dlerr = NULL;
|
||||||
# endif
|
# endif
|
||||||
mch_didjmp();
|
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
retval_str = NULL;
|
retval_str = NULL;
|
||||||
@@ -3127,5 +2549,3 @@ int *number_result;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@@ -5,9 +5,6 @@
|
|||||||
|
|
||||||
/* os_unix.c */
|
/* os_unix.c */
|
||||||
void mch_write(char_u *s, int len);
|
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_suspend(void);
|
||||||
void mch_init(void);
|
void mch_init(void);
|
||||||
void reset_signals(void);
|
void reset_signals(void);
|
||||||
|
5
src/ui.c
5
src/ui.c
@@ -34,6 +34,7 @@
|
|||||||
#include "os_unix.h"
|
#include "os_unix.h"
|
||||||
#include "os/time.h"
|
#include "os/time.h"
|
||||||
#include "os/input.h"
|
#include "os/input.h"
|
||||||
|
#include "os/signal.h"
|
||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
#include "term.h"
|
#include "term.h"
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
@@ -145,7 +146,7 @@ ui_inchar (
|
|||||||
/* If we are going to wait for some time or block... */
|
/* If we are going to wait for some time or block... */
|
||||||
if (wtime == -1 || wtime > 100L) {
|
if (wtime == -1 || wtime > 100L) {
|
||||||
/* ... allow signals to kill us. */
|
/* ... 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
|
/* ... there is no need for CTRL-C to interrupt something, don't let
|
||||||
* it set got_int when it was mapped. */
|
* it set got_int when it was mapped. */
|
||||||
@@ -161,7 +162,7 @@ ui_inchar (
|
|||||||
|
|
||||||
if (wtime == -1 || wtime > 100L)
|
if (wtime == -1 || wtime > 100L)
|
||||||
/* block SIGHUP et al. */
|
/* block SIGHUP et al. */
|
||||||
(void)vim_handle_signal(SIGNAL_BLOCK);
|
signal_reject_deadly();
|
||||||
|
|
||||||
ctrl_c_interrupts = TRUE;
|
ctrl_c_interrupts = TRUE;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user