From 6c07aac2835c5ec4462fedb267f1bba5bb3cadc5 Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Sun, 4 Dec 2011 10:26:30 +0100 Subject: [PATCH] Don't call Lisp in signal handler * emacs.c (Qkill_emacs): Define. (syms_of_emacs): Initialize it. * keyboard.c (interrupt_signal): Don't call Fkill_emacs here, set Qquit_flag to `kill-emacs' instead. (quit_throw_to_read_char): Add parameter `from_signal'. All callers changed. Call Fkill_emacs if requested and safe. * lisp.h (QUIT): Call Fkill_emacs if requested. --- src/ChangeLog | 10 ++++++++++ src/emacs.c | 3 +++ src/keyboard.c | 29 ++++++++++++++++------------- src/lisp.h | 8 +++++++- 4 files changed, 36 insertions(+), 14 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 6a13bd87264..a1d5cc9d5bd 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,13 @@ +2011-12-04 Andreas Schwab + + * emacs.c (Qkill_emacs): Define. + (syms_of_emacs): Initialize it. + * keyboard.c (interrupt_signal): Don't call Fkill_emacs here, set + Qquit_flag to `kill-emacs' instead. + (quit_throw_to_read_char): Add parameter `from_signal'. All + callers changed. Call Fkill_emacs if requested and safe. + * lisp.h (QUIT): Call Fkill_emacs if requested. + 2011-12-03 Jan Djärv * widget.c (update_wm_hints): Return if wmshell is null. diff --git a/src/emacs.c b/src/emacs.c index 529fa35a5bd..6bfc0dc60d0 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -154,6 +154,8 @@ Lisp_Object Qfile_name_handler_alist; Lisp_Object Qrisky_local_variable; +Lisp_Object Qkill_emacs; + /* If non-zero, Emacs should not attempt to use a window-specific code, but instead should use the virtual terminal under which it was started. */ int inhibit_window_system; @@ -2394,6 +2396,7 @@ syms_of_emacs (void) { DEFSYM (Qfile_name_handler_alist, "file-name-handler-alist"); DEFSYM (Qrisky_local_variable, "risky-local-variable"); + DEFSYM (Qkill_emacs, "kill-emacs"); #ifndef CANNOT_DUMP defsubr (&Sdump_emacs); diff --git a/src/keyboard.c b/src/keyboard.c index 7da0348cb25..a114e495cf7 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -464,7 +464,7 @@ static void input_available_signal (int signo); static Lisp_Object (Fcommand_execute) (Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object); static void handle_interrupt (void); -static void quit_throw_to_read_char (void) NO_RETURN; +static void quit_throw_to_read_char (int) NO_RETURN; static void timer_start_idle (void); static void timer_stop_idle (void); static void timer_resume_idle (void); @@ -653,7 +653,7 @@ echo_now (void) echo_kboard = current_kboard; if (waiting_for_input && !NILP (Vquit_flag)) - quit_throw_to_read_char (); + quit_throw_to_read_char (0); } /* Turn off echoing, for the start of a new command. */ @@ -3817,7 +3817,7 @@ kbd_buffer_get_event (KBOARD **kbp, /* If the quit flag is set, then read_char will return quit_char, so that counts as "available input." */ if (!NILP (Vquit_flag)) - quit_throw_to_read_char (); + quit_throw_to_read_char (0); /* One way or another, wait until input is available; then, if interrupt handlers have not read it, read it now. */ @@ -10824,7 +10824,7 @@ set_waiting_for_input (struct timeval *time_to_clear) /* If handle_interrupt was called before and buffered a C-g, make it run again now, to avoid timing error. */ if (!NILP (Vquit_flag)) - quit_throw_to_read_char (); + quit_throw_to_read_char (0); } void @@ -10839,7 +10839,7 @@ clear_waiting_for_input (void) If we have a frame on the controlling tty, we assume that the SIGINT was generated by C-g, so we call handle_interrupt. - Otherwise, the handler kills Emacs. */ + Otherwise, tell QUIT to kill Emacs. */ static void interrupt_signal (int signalnum) /* If we don't have an argument, some */ @@ -10856,12 +10856,10 @@ interrupt_signal (int signalnum) /* If we don't have an argument, some */ if (!terminal) { /* If there are no frames there, let's pretend that we are a - well-behaving UN*X program and quit. We cannot do that while - GC is in progress, though. */ - if (!gc_in_progress && !waiting_for_input) - Fkill_emacs (Qnil); - else - Vquit_flag = Qt; + well-behaving UN*X program and quit. We must not call Lisp + in a signal handler, so tell QUIT to exit when it is + safe. */ + Vquit_flag = Qkill_emacs; } else { @@ -11010,15 +11008,20 @@ handle_interrupt (void) separate event loop thread like W32. */ #ifndef HAVE_NS if (waiting_for_input && !echoing) - quit_throw_to_read_char (); + quit_throw_to_read_char (1); #endif } /* Handle a C-g by making read_char return C-g. */ static void -quit_throw_to_read_char (void) +quit_throw_to_read_char (int from_signal) { + /* When not called from a signal handler it is safe to call + Lisp. */ + if (!from_signal && EQ (Vquit_flag, Qkill_emacs)) + Fkill_emacs (Qnil); + sigfree (); /* Prevent another signal from doing this before we finish. */ clear_waiting_for_input (); diff --git a/src/lisp.h b/src/lisp.h index e645fbd65a5..969923b7cfb 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -2128,7 +2128,10 @@ extern char *stack_bottom; Exception: if you set immediate_quit to nonzero, then the handler that responds to the C-g does the quit itself. This is a good thing to do around a loop that has no side effects - and (in particular) cannot call arbitrary Lisp code. */ + and (in particular) cannot call arbitrary Lisp code. + + If quit-flag is set to `kill-emacs' the SIGINT handler has received + a request to exit Emacs when it is safe to do. */ #ifdef SYNC_INPUT extern void process_pending_signals (void); @@ -2146,6 +2149,8 @@ extern int pending_signals; { \ Lisp_Object flag = Vquit_flag; \ Vquit_flag = Qnil; \ + if (EQ (flag, Qkill_emacs)) \ + Fkill_emacs (Qnil); \ if (EQ (Vthrow_on_input, flag)) \ Fthrow (Vthrow_on_input, Qt); \ Fsignal (Qquit, Qnil); \ @@ -3291,6 +3296,7 @@ extern Lisp_Object Qfile_name_handler_alist; #ifdef FLOAT_CATCH_SIGILL extern void fatal_error_signal (int); #endif +extern Lisp_Object Qkill_emacs; EXFUN (Fkill_emacs, 1) NO_RETURN; #if HAVE_SETLOCALE void fixup_locale (void); -- 2.39.2