* src/thread.h (m_getcjmp): New member of 'struct thread_state'.
(getcjmp): Define to current thread's 'm_getcjmp'.
* src/thread.c (maybe_reacquire_global_lock): Switch to main
thread, since this is called from a SIGINT handler, which always
runs in the context of the main thread.
* src/lisp.h (sys_jmp_buf, sys_setjmp, sys_longjmp): Move the
definitions before thread.h is included, as thread.h now uses
sys_jmp_buf.
* src/keyboard.c (getcjmp): Remove declaration.
(read_char): Don't call maybe_reacquire_global_lock here.
(handle_interrupt): Call maybe_reacquire_global_lock here, if
invoked from the SIGINT handler, to make sure
quit_throw_to_read_char runs with main thread's Lisp bindings and
uses the main thread's jmp_buf buffer. (Bug#28630)
/* Message normally displayed by Vtop_level. */
static Lisp_Object regular_top_level_message;
-/* For longjmp to where kbd input is being done. */
-
-static sys_jmp_buf getcjmp;
-
/* True while displaying for echoing. Delays C-g throwing. */
static bool echoing;
so restore it now. */
restore_getcjmp (save_jump);
pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
-#if THREADS_ENABLED
- maybe_reacquire_global_lock ();
-#endif
unbind_to (jmpcount, Qnil);
XSETINT (c, quit_char);
internal_last_event_frame = selected_frame;
outside of polling since we don't get SIGIO like X and we don't have a
separate event loop thread like W32. */
#ifndef HAVE_NS
+#ifdef THREADS_ENABLED
+ /* If we were called from a signal handler, we must be in the main
+ thread, see deliver_process_signal. So we must make sure the
+ main thread holds the global lock. */
+ if (in_signal_handler)
+ maybe_reacquire_global_lock ();
+#endif
if (waiting_for_input && !echoing)
quit_throw_to_read_char (in_signal_handler);
#endif
== (offsetof (struct Lisp_Vector, contents)
+ SUB_CHAR_TABLE_OFFSET * sizeof (Lisp_Object)));
+
+/* Save and restore the instruction and environment pointers,
+ without affecting the signal mask. */
+
+#ifdef HAVE__SETJMP
+typedef jmp_buf sys_jmp_buf;
+# define sys_setjmp(j) _setjmp (j)
+# define sys_longjmp(j, v) _longjmp (j, v)
+#elif defined HAVE_SIGSETJMP
+typedef sigjmp_buf sys_jmp_buf;
+# define sys_setjmp(j) sigsetjmp (j, 0)
+# define sys_longjmp(j, v) siglongjmp (j, v)
+#else
+/* A platform that uses neither _longjmp nor siglongjmp; assume
+ longjmp does not affect the sigmask. */
+typedef jmp_buf sys_jmp_buf;
+# define sys_setjmp(j) setjmp (j)
+# define sys_longjmp(j, v) longjmp (j, v)
+#endif
+
#include "thread.h"
/***********************************************************************
static struct Lisp_Kboard_Objfwd ko_fwd; \
defvar_kboard (&ko_fwd, lname, offsetof (KBOARD, vname ## _)); \
} while (false)
-\f
-/* Save and restore the instruction and environment pointers,
- without affecting the signal mask. */
-
-#ifdef HAVE__SETJMP
-typedef jmp_buf sys_jmp_buf;
-# define sys_setjmp(j) _setjmp (j)
-# define sys_longjmp(j, v) _longjmp (j, v)
-#elif defined HAVE_SIGSETJMP
-typedef sigjmp_buf sys_jmp_buf;
-# define sys_setjmp(j) sigsetjmp (j, 0)
-# define sys_longjmp(j, v) siglongjmp (j, v)
-#else
-/* A platform that uses neither _longjmp nor siglongjmp; assume
- longjmp does not affect the sigmask. */
-typedef jmp_buf sys_jmp_buf;
-# define sys_setjmp(j) setjmp (j)
-# define sys_longjmp(j, v) longjmp (j, v)
-#endif
\f
/* Elisp uses several stacks:
post_acquire_global_lock (self);
}
-/* This is called from keyboard.c when it detects that SIGINT
- interrupted thread_select before the current thread could acquire
- the lock. We must acquire the lock to prevent a thread from
- running without holding the global lock, and to avoid repeated
- calls to sys_mutex_unlock, which invokes undefined behavior. */
+/* This is called from keyboard.c when it detects that SIGINT was
+ delivered to the main thread and interrupted thread_select before
+ the main thread could acquire the lock. We must acquire the lock
+ to prevent a thread from running without holding the global lock,
+ and to avoid repeated calls to sys_mutex_unlock, which invokes
+ undefined behavior. */
void
maybe_reacquire_global_lock (void)
{
+ /* SIGINT handler is always run on the main thread, see
+ deliver_process_signal, so reflect that in our thread-tracking
+ variables. */
+ current_thread = &main_thread;
+
if (current_thread->not_holding_lock)
{
struct thread_state *self = current_thread;
bool m_waiting_for_input;
#define waiting_for_input (current_thread->m_waiting_for_input)
+ /* For longjmp to where kbd input is being done. This is per-thread
+ so that if more than one thread calls read_char, they don't
+ clobber each other's getcjmp, which will cause
+ quit_throw_to_read_char crash due to using a wrong stack. */
+ sys_jmp_buf m_getcjmp;
+#define getcjmp (current_thread->m_getcjmp)
+
/* The OS identifier for this thread. */
sys_thread_t thread_id;