]> code.delx.au - gnu-emacs/blobdiff - src/keyboard.c
Merge from trunk
[gnu-emacs] / src / keyboard.c
index 451ffd9d600b9ccc1e30b2e2c9383c510d287a5c..05b9a9dde0133ec725650fcc582ea4a9ec6f687a 100644 (file)
@@ -19,6 +19,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 
+#define BLOCKINPUT_INLINE EXTERN_INLINE
 #define KEYBOARD_INLINE EXTERN_INLINE
 
 #include <stdio.h>
@@ -72,19 +73,12 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 /* Variables for blockinput.h: */
 
-/* Non-zero if interrupt input is blocked right now.  */
+/* Positive if interrupt input is blocked right now.  */
 volatile int interrupt_input_blocked;
 
-/* Nonzero means an input interrupt has arrived
-   during the current critical section.  */
-int interrupt_input_pending;
-
-/* This var should be (interrupt_input_pending || pending_atimers).
-   The QUIT macro checks this instead of interrupt_input_pending and
-   pending_atimers separately, to reduce code size.  So, any code that
-   changes interrupt_input_pending or pending_atimers should update
-   this too.  */
-int pending_signals;
+/* True means an input interrupt or alarm signal has arrived.
+   The QUIT macro checks this.  */
+volatile bool pending_signals;
 
 #define KBD_BUFFER_SIZE 4096
 
@@ -225,7 +219,11 @@ static Lisp_Object last_point_position_window;
    last event came from a macro.  We use this to determine when to
    generate switch-frame events.  This may be cleared by functions
    like Fselect_frame, to make sure that a switch-frame event is
-   generated by the next character.  */
+   generated by the next character.
+
+   FIXME: This is modified by a signal handler so it should be volatile.
+   It's exported to Lisp, though, so it can't simply be marked
+   'volatile' here.  */
 Lisp_Object internal_last_event_frame;
 
 /* The timestamp of the last input event we received from the X server.
@@ -389,7 +387,7 @@ int interrupts_deferred;
 
 /* If we support a window system, turn on the code to poll periodically
    to detect C-g.  It isn't actually used when doing interrupt input.  */
-#if defined (HAVE_WINDOW_SYSTEM) && !defined (USE_ASYNC_EVENTS)
+#ifdef HAVE_WINDOW_SYSTEM
 #define POLL_FOR_INPUT
 #endif
 
@@ -413,7 +411,6 @@ static EMACS_TIME timer_last_idleness_start_time;
 /* Function for init_keyboard to call with no args (if nonzero).  */
 static void (*keyboard_init_hook) (void);
 
-static int read_avail_input (int);
 static void get_input_pending (int *, int);
 static int readable_events (int);
 static Lisp_Object read_char_x_menu_prompt (ptrdiff_t, Lisp_Object *,
@@ -440,7 +437,7 @@ static Lisp_Object restore_kboard_configuration (Lisp_Object);
 #ifdef USABLE_SIGIO
 static void deliver_input_available_signal (int signo);
 #endif
-static void handle_interrupt (void);
+static void handle_interrupt (bool);
 static _Noreturn void quit_throw_to_read_char (int);
 static void process_special_events (void);
 static void timer_start_idle (void);
@@ -448,50 +445,50 @@ static void timer_stop_idle (void);
 static void timer_resume_idle (void);
 static void deliver_user_signal (int);
 static char *find_user_signal_name (int);
-static int store_user_signal_events (void);
+static void store_user_signal_events (void);
 
 /* These setters are used only in this file, so they can be private.  */
-static inline void
+static void
 kset_echo_string (struct kboard *kb, Lisp_Object val)
 {
   kb->INTERNAL_FIELD (echo_string) = val;
 }
-static inline void
+static void
 kset_kbd_queue (struct kboard *kb, Lisp_Object val)
 {
   kb->INTERNAL_FIELD (kbd_queue) = val;
 }
-static inline void
+static void
 kset_keyboard_translate_table (struct kboard *kb, Lisp_Object val)
 {
   kb->INTERNAL_FIELD (Vkeyboard_translate_table) = val;
 }
-static inline void
+static void
 kset_last_prefix_arg (struct kboard *kb, Lisp_Object val)
 {
   kb->INTERNAL_FIELD (Vlast_prefix_arg) = val;
 }
-static inline void
+static void
 kset_last_repeatable_command (struct kboard *kb, Lisp_Object val)
 {
   kb->INTERNAL_FIELD (Vlast_repeatable_command) = val;
 }
-static inline void
+static void
 kset_local_function_key_map (struct kboard *kb, Lisp_Object val)
 {
   kb->INTERNAL_FIELD (Vlocal_function_key_map) = val;
 }
-static inline void
+static void
 kset_overriding_terminal_local_map (struct kboard *kb, Lisp_Object val)
 {
   kb->INTERNAL_FIELD (Voverriding_terminal_local_map) = val;
 }
-static inline void
+static void
 kset_real_last_command (struct kboard *kb, Lisp_Object val)
 {
   kb->INTERNAL_FIELD (Vreal_last_command) = val;
 }
-static inline void
+static void
 kset_system_key_syms (struct kboard *kb, Lisp_Object val)
 {
   kb->INTERNAL_FIELD (system_key_syms) = val;
@@ -823,7 +820,7 @@ This function is called by the editor initialization to begin editing.  */)
 
   /* If we enter while input is blocked, don't lock up here.
      This may happen through the debugger during redisplay.  */
-  if (INPUT_BLOCKED_P)
+  if (input_blocked_p ())
     return Qnil;
 
   command_loop_level++;
@@ -1216,8 +1213,7 @@ This also exits all active minibuffers.  */)
 
   /* Unblock input if we enter with input blocked.  This may happen if
      redisplay traps e.g. during tool-bar update with input blocked.  */
-  while (INPUT_BLOCKED_P)
-    UNBLOCK_INPUT;
+  totally_unblock_input ();
 
   Fthrow (Qtop_level, Qnil);
 }
@@ -1460,15 +1456,6 @@ command_loop_1 (void)
            }
        }
 
-#if 0
-      /* Select the frame that the last event came from.  Usually,
-        switch-frame events will take care of this, but if some lisp
-        code swallows a switch-frame event, we'll fix things up here.
-        Is this a good idea?  */
-      if (FRAMEP (internal_last_event_frame)
-         && !EQ (internal_last_event_frame, selected_frame))
-       Fselect_frame (internal_last_event_frame, Qnil);
-#endif
       /* If it has changed current-menubar from previous value,
         really recompute the menubar from the value.  */
       if (! NILP (Vlucid_menu_bar_dirty_flag)
@@ -2008,9 +1995,9 @@ static struct atimer *poll_timer;
 void
 poll_for_input_1 (void)
 {
-  if (interrupt_input_blocked == 0
+  if (! input_blocked_p ()
       && !waiting_for_input)
-    read_avail_input (0);
+    gobble_input ();
 }
 
 /* Timer callback function for poll_timer.  TIMER is equal to
@@ -2020,10 +2007,7 @@ static void
 poll_for_input (struct atimer *timer)
 {
   if (poll_suppress_count == 0)
-    {
-      interrupt_input_pending = 1;
-      pending_signals = 1;
-    }
+    pending_signals = 1;
 }
 
 #endif /* POLL_FOR_INPUT */
@@ -2299,11 +2283,10 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
           Lisp_Object prev_event,
           int *used_mouse_menu, EMACS_TIME *end_time)
 {
-  volatile Lisp_Object c;
+  Lisp_Object c;
   ptrdiff_t jmpcount;
   sys_jmp_buf local_getcjmp;
   sys_jmp_buf save_jump;
-  volatile int key_already_recorded = 0;
   Lisp_Object tem, save;
   volatile Lisp_Object previous_echo_area_message;
   volatile Lisp_Object also_record;
@@ -2535,10 +2518,7 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
         return c;               /* wrong_kboard_jmpbuf */
 
       if (! NILP (c))
-       {
-         key_already_recorded = 1;
-         goto non_reread_1;
-       }
+       goto exit;
     }
 
   /* Make a longjmp point for quits to use, but don't alter getcjmp just yet.
@@ -2866,12 +2846,10 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
       goto wrong_kboard;
     }
 
- non_reread_1:
-
   /* Buffer switch events are only for internal wakeups
      so don't show them to the user.
      Also, don't record a key if we already did.  */
-  if (BUFFERP (c) || key_already_recorded)
+  if (BUFFERP (c))
     goto exit;
 
   /* Process special events within read_char
@@ -3344,7 +3322,7 @@ record_char (Lisp_Object c)
      If you, dear reader, have a better idea, you've got the source.  :-) */
   if (dribble)
     {
-      BLOCK_INPUT;
+      block_input ();
       if (INTEGERP (c))
        {
          if (XUINT (c) < 0x100)
@@ -3370,7 +3348,7 @@ record_char (Lisp_Object c)
        }
 
       fflush (dribble);
-      UNBLOCK_INPUT;
+      unblock_input ();
     }
 }
 
@@ -3514,10 +3492,8 @@ kbd_buffer_store_event (register struct input_event *event)
    Else, if EVENT is a quit event, store the quit event
    in HOLD_QUIT, and return (thus ignoring further events).
 
-   This is used in read_avail_input to postpone the processing
-   of the quit event until all subsequent input events have been
-   parsed (and discarded).
- */
+   This is used to postpone the processing of the quit event until all
+   subsequent input events have been parsed (and discarded).  */
 
 void
 kbd_buffer_store_event_hold (register struct input_event *event,
@@ -3587,7 +3563,8 @@ kbd_buffer_store_event_hold (register struct input_event *event,
          }
 
          last_event_timestamp = event->timestamp;
-         handle_interrupt ();
+
+         handle_interrupt (0);
          return;
        }
 
@@ -3643,7 +3620,6 @@ kbd_buffer_store_event_hold (register struct input_event *event,
       if (immediate_quit && NILP (Vinhibit_quit))
        {
          immediate_quit = 0;
-         pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
          QUIT;
        }
     }
@@ -3767,7 +3743,7 @@ kbd_buffer_events_waiting (int discard)
 \f
 /* Clear input event EVENT.  */
 
-static inline void
+static void
 clear_event (struct input_event *event)
 {
   event->kind = NO_EVENT;
@@ -3793,14 +3769,6 @@ kbd_buffer_get_event (KBOARD **kbp,
       /* Start reading input again because we have processed enough to
          be able to accept new events again.  */
       unhold_keyboard_input ();
-#ifdef USABLE_SIGIO
-      if (!noninteractive)
-       {
-         struct sigaction action;
-         emacs_sigaction_init (&action, deliver_input_available_signal);
-         sigaction (SIGIO, &action, 0);
-       }
-#endif
       start_polling ();
     }
 #endif /* subprocesses */
@@ -3843,7 +3811,7 @@ kbd_buffer_get_event (KBOARD **kbp,
         interrupt handlers have not read it, read it now.  */
 
 #ifdef USABLE_SIGIO
-      gobble_input (0);
+      gobble_input ();
 #endif
       if (kbd_fetch_ptr != kbd_store_ptr)
        break;
@@ -3869,8 +3837,7 @@ kbd_buffer_get_event (KBOARD **kbp,
        wait_reading_process_output (0, 0, -1, 1, Qnil, NULL, 0);
 
       if (!interrupt_input && kbd_fetch_ptr == kbd_store_ptr)
-       /* Pass 1 for EXPECT since we just waited to have input.  */
-       read_avail_input (1);
+       gobble_input ();
     }
 
   if (CONSP (Vunread_command_events))
@@ -4334,25 +4301,18 @@ decode_timer (Lisp_Object timer, EMACS_TIME *result)
    should be done.  */
 
 static EMACS_TIME
-timer_check_2 (void)
+timer_check_2 (Lisp_Object timers, Lisp_Object idle_timers)
 {
   EMACS_TIME nexttime;
   EMACS_TIME now;
   EMACS_TIME idleness_now;
-  Lisp_Object timers, idle_timers, chosen_timer;
-  struct gcpro gcpro1, gcpro2, gcpro3;
+  Lisp_Object chosen_timer;
+  struct gcpro gcpro1;
 
   nexttime = invalid_emacs_time ();
 
-  /* Always consider the ordinary timers.  */
-  timers = Vtimer_list;
-  /* Consider the idle timers only if Emacs is idle.  */
-  if (EMACS_TIME_VALID_P (timer_idleness_start_time))
-    idle_timers = Vtimer_idle_list;
-  else
-    idle_timers = Qnil;
   chosen_timer = Qnil;
-  GCPRO3 (timers, idle_timers, chosen_timer);
+  GCPRO1 (chosen_timer);
 
   /* First run the code that was delayed.  */
   while (CONSP (pending_funcalls))
@@ -4501,13 +4461,35 @@ EMACS_TIME
 timer_check (void)
 {
   EMACS_TIME nexttime;
+  Lisp_Object timers, idle_timers;
+  struct gcpro gcpro1, gcpro2;
+
+  Lisp_Object tem = Vinhibit_quit;
+  Vinhibit_quit = Qt;
+
+  /* We use copies of the timers' lists to allow a timer to add itself
+     again, without locking up Emacs if the newly added timer is
+     already ripe when added.  */
+
+  /* Always consider the ordinary timers.  */
+  timers = Fcopy_sequence (Vtimer_list);
+  /* Consider the idle timers only if Emacs is idle.  */
+  if (EMACS_TIME_VALID_P (timer_idleness_start_time))
+    idle_timers = Fcopy_sequence (Vtimer_idle_list);
+  else
+    idle_timers = Qnil;
+
+  Vinhibit_quit = tem;
+
+  GCPRO2 (timers, idle_timers);
 
   do
     {
-      nexttime = timer_check_2 ();
+      nexttime = timer_check_2 (timers, idle_timers);
     }
   while (EMACS_SECS (nexttime) == 0 && EMACS_NSECS (nexttime) == 0);
 
+  UNGCPRO;
   return nexttime;
 }
 
@@ -6734,45 +6716,10 @@ get_input_pending (int *addr, int flags)
     return;
 
   /* Try to read some input and see how much we get.  */
-  gobble_input (0);
+  gobble_input ();
   *addr = (!NILP (Vquit_flag) || readable_events (flags));
 }
 
-/* Interface to read_avail_input, blocking SIGIO or SIGALRM if necessary.  */
-
-void
-gobble_input (int expected)
-{
-#ifdef USABLE_SIGIO
-  if (interrupt_input)
-    {
-      sigset_t blocked, procmask;
-      sigemptyset (&blocked);
-      sigaddset (&blocked, SIGIO);
-      pthread_sigmask (SIG_BLOCK, &blocked, &procmask);
-      read_avail_input (expected);
-      pthread_sigmask (SIG_SETMASK, &procmask, 0);
-    }
-  else
-#ifdef POLL_FOR_INPUT
-  /* XXX This condition was (read_socket_hook && !interrupt_input),
-     but read_socket_hook is not global anymore.  Let's pretend that
-     it's always set.  */
-  if (!interrupt_input && poll_suppress_count == 0)
-    {
-      sigset_t blocked, procmask;
-      sigemptyset (&blocked);
-      sigaddset (&blocked, SIGALRM);
-      pthread_sigmask (SIG_BLOCK, &blocked, &procmask);
-      read_avail_input (expected);
-      pthread_sigmask (SIG_SETMASK, &procmask, 0);
-    }
-  else
-#endif
-#endif
-    read_avail_input (expected);
-}
-
 /* Put a BUFFER_SWITCH_EVENT in the buffer
    so that read_key_sequence will notice the new current buffer.  */
 
@@ -6800,14 +6747,7 @@ record_asynch_buffer_change (void)
   /* Make sure no interrupt happens while storing the event.  */
 #ifdef USABLE_SIGIO
   if (interrupt_input)
-    {
-      sigset_t blocked, procmask;
-      sigemptyset (&blocked);
-      sigaddset (&blocked, SIGIO);
-      pthread_sigmask (SIG_BLOCK, &blocked, &procmask);
-      kbd_buffer_store_event (&event);
-      pthread_sigmask (SIG_SETMASK, &procmask, 0);
-    }
+    kbd_buffer_store_event (&event);
   else
 #endif
     {
@@ -6820,21 +6760,18 @@ record_asynch_buffer_change (void)
 /* Read any terminal input already buffered up by the system
    into the kbd_buffer, but do not wait.
 
-   EXPECTED should be nonzero if the caller knows there is some input.
-
-   Returns the number of keyboard chars read, or -1 meaning
+   Return the number of keyboard chars read, or -1 meaning
    this is a bad time to try to read input.  */
 
-static int
-read_avail_input (int expected)
+int
+gobble_input (void)
 {
   int nread = 0;
   int err = 0;
   struct terminal *t;
 
   /* Store pending user signal events, if any.  */
-  if (store_user_signal_events ())
-    expected = 0;
+  store_user_signal_events ();
 
   /* Loop through the available terminals, and call their input hooks.  */
   t = terminal_list;
@@ -6847,15 +6784,18 @@ read_avail_input (int expected)
           int nr;
           struct input_event hold_quit;
 
+         if (input_blocked_p ())
+           {
+             pending_signals = 1;
+             break;
+           }
+
           EVENT_INIT (hold_quit);
           hold_quit.kind = NO_EVENT;
 
           /* No need for FIONREAD or fcntl; just say don't wait.  */
-          while (nr = (*t->read_socket_hook) (t, expected, &hold_quit), nr > 0)
-            {
-              nread += nr;
-              expected = 0;
-            }
+         while (0 < (nr = (*t->read_socket_hook) (t, &hold_quit)))
+           nread += nr;
 
           if (nr == -1)          /* Not OK to read input now.  */
             {
@@ -6875,7 +6815,7 @@ read_avail_input (int expected)
                    this process rather than to the whole process
                    group?  Perhaps on systems with FIONREAD Emacs is
                    alone in its group.  */
-                kill (getpid (), SIGHUP);
+               terminate_due_to_signal (SIGHUP, 10);
 
               /* XXX Is calling delete_terminal safe here?  It calls delete_frame.  */
              {
@@ -6950,7 +6890,6 @@ decode_keyboard_code (struct tty_display_info *tty,
 
 int
 tty_read_avail_input (struct terminal *terminal,
-                      int expected,
                       struct input_event *hold_quit)
 {
   /* Using KBD_BUFFER_SIZE - 1 here avoids reading more than
@@ -7165,35 +7104,68 @@ tty_read_avail_input (struct terminal *terminal,
 static void
 handle_async_input (void)
 {
-  interrupt_input_pending = 0;
-  pending_signals = pending_atimers;
-
+#ifdef USABLE_SIGIO
   while (1)
     {
-      int nread;
-      nread = read_avail_input (1);
+      int nread = gobble_input ();
       /* -1 means it's not ok to read the input now.
         UNBLOCK_INPUT will read it later; now, avoid infinite loop.
         0 means there was no keyboard input available.  */
       if (nread <= 0)
        break;
     }
+#endif
 }
 
 void
 process_pending_signals (void)
 {
-  if (interrupt_input_pending)
-    handle_async_input ();
+  pending_signals = 0;
+  handle_async_input ();
   do_pending_atimers ();
 }
 
+/* Undo any number of BLOCK_INPUT calls down to level LEVEL,
+   and also (if the level is now 0) reinvoke any pending signal.  */
+
+void
+unblock_input_to (int level)
+{
+  interrupt_input_blocked = level;
+  if (level == 0)
+    {
+      if (pending_signals)
+       process_pending_signals ();
+    }
+  else if (level < 0)
+    emacs_abort ();
+}
+
+/* End critical section.
+
+   If doing signal-driven input, and a signal came in when input was
+   blocked, reinvoke the signal handler now to deal with it.  */
+
+void
+unblock_input (void)
+{
+  unblock_input_to (interrupt_input_blocked - 1);
+}
+
+/* Undo any number of BLOCK_INPUT calls,
+   and also reinvoke any pending signal.  */
+
+void
+totally_unblock_input (void)
+{
+  unblock_input_to (0);
+}
+
 #ifdef USABLE_SIGIO
 
-static void
+void
 handle_input_available_signal (int sig)
 {
-  interrupt_input_pending = 1;
   pending_signals = 1;
 
   if (input_available_clear_time)
@@ -7203,25 +7175,10 @@ handle_input_available_signal (int sig)
 static void
 deliver_input_available_signal (int sig)
 {
-  handle_on_main_thread (sig, handle_input_available_signal);
+  deliver_process_signal (sig, handle_input_available_signal);
 }
 #endif /* USABLE_SIGIO */
 
-/* Send ourselves a SIGIO.
-
-   This function exists so that the UNBLOCK_INPUT macro in
-   blockinput.h can have some way to take care of input we put off
-   dealing with, without assuming that every file which uses
-   UNBLOCK_INPUT also has #included the files necessary to get SIGIO.  */
-void
-reinvoke_input_signal (void)
-{
-#ifdef USABLE_SIGIO
-  handle_async_input ();
-#endif
-}
-
-
 \f
 /* User signal events.  */
 
@@ -7292,7 +7249,7 @@ handle_user_signal (int sig)
        p->npending++;
 #ifdef USABLE_SIGIO
        if (interrupt_input)
-         kill (getpid (), SIGIO);
+         handle_input_available_signal (sig);
        else
 #endif
          {
@@ -7308,7 +7265,7 @@ handle_user_signal (int sig)
 static void
 deliver_user_signal (int sig)
 {
-  handle_on_main_thread (sig, handle_user_signal);
+  deliver_process_signal (sig, handle_user_signal);
 }
 
 static char *
@@ -7323,29 +7280,23 @@ find_user_signal_name (int sig)
   return NULL;
 }
 
-static int
+static void
 store_user_signal_events (void)
 {
   struct user_signal_info *p;
   struct input_event buf;
-  int nstored = 0;
+  bool buf_initialized = 0;
 
   for (p = user_signals; p; p = p->next)
     if (p->npending > 0)
       {
-       sigset_t blocked, procmask;
-
-       if (nstored == 0)
+       if (! buf_initialized)
          {
            memset (&buf, 0, sizeof buf);
            buf.kind = USER_SIGNAL_EVENT;
            buf.frame_or_window = selected_frame;
+           buf_initialized = 1;
          }
-       nstored += p->npending;
-
-       sigemptyset (&blocked);
-       sigaddset (&blocked, p->sig);
-       pthread_sigmask (SIG_BLOCK, &blocked, &procmask);
 
        do
          {
@@ -7354,11 +7305,7 @@ store_user_signal_events (void)
            p->npending--;
          }
        while (p->npending > 0);
-
-       pthread_sigmask (SIG_SETMASK, &procmask, 0);
       }
-
-  return nstored;
 }
 
 \f
@@ -8101,7 +8048,7 @@ process_tool_bar_item (Lisp_Object key, Lisp_Object def, Lisp_Object data, void
 
 /* Access slot with index IDX of vector tool_bar_item_properties.  */
 #define PROP(IDX) AREF (tool_bar_item_properties, (IDX))
-static inline void
+static void
 set_prop (ptrdiff_t idx, Lisp_Object val)
 {
   ASET (tool_bar_item_properties, idx, val);
@@ -10562,9 +10509,9 @@ The file will be closed when Emacs exits.  */)
 {
   if (dribble)
     {
-      BLOCK_INPUT;
+      block_input ();
       fclose (dribble);
-      UNBLOCK_INPUT;
+      unblock_input ();
       dribble = 0;
     }
   if (!NILP (file))
@@ -10753,21 +10700,21 @@ handle_interrupt_signal (int sig)
          from the controlling tty.  */
       internal_last_event_frame = terminal->display_info.tty->top_frame;
 
-      handle_interrupt ();
+      handle_interrupt (1);
     }
 }
 
 static void
 deliver_interrupt_signal (int sig)
 {
-  handle_on_main_thread (sig, handle_interrupt_signal);
+  deliver_process_signal (sig, handle_interrupt_signal);
 }
 
 
 /* If Emacs is stuck because `inhibit-quit' is true, then keep track
    of the number of times C-g has been requested.  If C-g is pressed
    enough times, then quit anyway.  See bug#6585.  */
-static int force_quit_count;
+static int volatile force_quit_count;
 
 /* This routine is called at interrupt level in response to C-g.
 
@@ -10781,7 +10728,7 @@ static int force_quit_count;
    non-nil, it stops the job right away.  */
 
 static void
-handle_interrupt (void)
+handle_interrupt (bool in_signal_handler)
 {
   char c;
 
@@ -10790,13 +10737,16 @@ handle_interrupt (void)
   /* XXX This code needs to be revised for multi-tty support.  */
   if (!NILP (Vquit_flag) && get_named_tty ("/dev/tty"))
     {
-      /* If SIGINT isn't blocked, don't let us be interrupted by
-        another SIGINT, it might be harmful due to non-reentrancy
-        in I/O functions.  */
-      sigset_t blocked;
-      sigemptyset (&blocked);
-      sigaddset (&blocked, SIGINT);
-      pthread_sigmask (SIG_BLOCK, &blocked, 0);
+      if (! in_signal_handler)
+       {
+         /* If SIGINT isn't blocked, don't let us be interrupted by
+            a SIGINT.  It might be harmful due to non-reentrancy
+            in I/O functions.  */
+         sigset_t blocked;
+         sigemptyset (&blocked);
+         sigaddset (&blocked, SIGINT);
+         pthread_sigmask (SIG_BLOCK, &blocked, 0);
+       }
 
       fflush (stdout);
       reset_all_sys_modes ();
@@ -10867,7 +10817,6 @@ handle_interrupt (void)
 #endif /* not MSDOS */
       fflush (stdout);
       init_all_sys_modes ();
-      pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
     }
   else
     {
@@ -10885,15 +10834,14 @@ handle_interrupt (void)
          GCPRO4 (saved.object, saved.global_code,
                  saved.current_syntax_table, saved.old_prop);
          Fsignal (Qquit, Qnil);
-         /* FIXME: AFAIK, `quit' can never return, so this code is dead!  */
          gl_state = saved;
          UNGCPRO;
        }
       else
         { /* Else request quit when it's safe.  */
-          if (NILP (Vquit_flag))
-           force_quit_count = 0;
-         if (++force_quit_count == 3)
+         int count = NILP (Vquit_flag) ? 1 : force_quit_count + 1;
+         force_quit_count = count;
+         if (count == 3)
             {
               immediate_quit = 1;
               Vinhibit_quit = Qnil;
@@ -10902,6 +10850,8 @@ handle_interrupt (void)
         }
     }
 
+  pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
+
 /* TODO: The longjmp in this call throws the NS event loop integration off,
          and it seems to do fine without this.  Probably some attention
         needs to be paid to the setting of waiting_for_input in
@@ -10911,7 +10861,7 @@ handle_interrupt (void)
          separate event loop thread like W32.  */
 #ifndef HAVE_NS
   if (waiting_for_input && !echoing)
-      quit_throw_to_read_char (1);
+    quit_throw_to_read_char (in_signal_handler);
 #endif
 }
 
@@ -10925,22 +10875,12 @@ quit_throw_to_read_char (int from_signal)
   if (!from_signal && EQ (Vquit_flag, Qkill_emacs))
     Fkill_emacs (Qnil);
 
-  pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
   /* Prevent another signal from doing this before we finish.  */
   clear_waiting_for_input ();
   input_pending = 0;
 
   Vunread_command_events = Qnil;
 
-#if 0 /* Currently, sit_for is called from read_char without turning
-        off polling.  And that can call set_waiting_for_input.
-        It seems to be harmless.  */
-#ifdef POLL_FOR_INPUT
-  /* May be > 1 if in recursive minibuffer.  */
-  if (poll_suppress_count == 0)
-    emacs_abort ();
-#endif
-#endif
   if (FRAMEP (internal_last_event_frame)
       && !EQ (internal_last_event_frame, selected_frame))
     do_switch_frame (make_lispy_switch_frame (internal_last_event_frame),
@@ -11331,7 +11271,6 @@ init_keyboard (void)
 #endif
   input_pending = 0;
   interrupt_input_blocked = 0;
-  interrupt_input_pending = 0;
   pending_signals = 0;
 
   /* This means that command_loop_1 won't try to select anything the first
@@ -11352,7 +11291,7 @@ init_keyboard (void)
       /* Before multi-tty support, these handlers used to be installed
          only if the current session was a tty session.  Now an Emacs
          session may have multiple display types, so we always handle
-         SIGINT.  There is special code in interrupt_signal to exit
+         SIGINT.  There is special code in handle_interrupt_signal to exit
          Emacs on SIGINT when there are no termcap frames on the
          controlling terminal.  */
       struct sigaction action;