aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/os/signal.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/os/signal.c')
-rw-r--r--src/nvim/os/signal.c163
1 files changed, 163 insertions, 0 deletions
diff --git a/src/nvim/os/signal.c b/src/nvim/os/signal.c
new file mode 100644
index 0000000000..d3bedad09c
--- /dev/null
+++ b/src/nvim/os/signal.c
@@ -0,0 +1,163 @@
+#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 "memory.h"
+#include "misc1.h"
+#include "misc2.h"
+#include "os/event_defs.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 = event.data.signum;
+
+ 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);
+
+ snprintf((char *)IObuff, sizeof(IObuff), "Vim: Caught deadly signal '%s'\n",
+ signal_name(signum));
+
+ // Preserve files and exit.
+ preserve_exit();
+}
+
+static void signal_cb(uv_signal_t *handle, int signum)
+{
+ if (rejecting_deadly) {
+ if (signum == SIGINT) {
+ got_int = true;
+ }
+
+ return;
+ }
+
+ Event event = {
+ .type = kEventSignal,
+ .data = {
+ .signum = signum
+ }
+ };
+ event_push(event);
+}