aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2017-10-04 10:27:49 +0300
committerEli Zaretskii2017-10-04 10:27:49 +0300
commitea39d470bf35e45f1d8e39795f06ac74b3c37fc7 (patch)
tree406dbe320ffd5c9e2a31fd1b8568e119e50e9279 /src
parentfdbaebde08f4e53e3fc06fae99398c68a4e285fb (diff)
downloademacs-ea39d470bf35e45f1d8e39795f06ac74b3c37fc7.tar.gz
emacs-ea39d470bf35e45f1d8e39795f06ac74b3c37fc7.zip
Avoid crashes on C-g when several threads wait for input
* 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)
Diffstat (limited to 'src')
-rw-r--r--src/keyboard.c14
-rw-r--r--src/lisp.h39
-rw-r--r--src/thread.c16
-rw-r--r--src/thread.h7
4 files changed, 45 insertions, 31 deletions
diff --git a/src/keyboard.c b/src/keyboard.c
index e8701b88708..ee353d2b078 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -145,10 +145,6 @@ static Lisp_Object recover_top_level_message;
145/* Message normally displayed by Vtop_level. */ 145/* Message normally displayed by Vtop_level. */
146static Lisp_Object regular_top_level_message; 146static Lisp_Object regular_top_level_message;
147 147
148/* For longjmp to where kbd input is being done. */
149
150static sys_jmp_buf getcjmp;
151
152/* True while displaying for echoing. Delays C-g throwing. */ 148/* True while displaying for echoing. Delays C-g throwing. */
153 149
154static bool echoing; 150static bool echoing;
@@ -2570,9 +2566,6 @@ read_char (int commandflag, Lisp_Object map,
2570 so restore it now. */ 2566 so restore it now. */
2571 restore_getcjmp (save_jump); 2567 restore_getcjmp (save_jump);
2572 pthread_sigmask (SIG_SETMASK, &empty_mask, 0); 2568 pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
2573#if THREADS_ENABLED
2574 maybe_reacquire_global_lock ();
2575#endif
2576 unbind_to (jmpcount, Qnil); 2569 unbind_to (jmpcount, Qnil);
2577 XSETINT (c, quit_char); 2570 XSETINT (c, quit_char);
2578 internal_last_event_frame = selected_frame; 2571 internal_last_event_frame = selected_frame;
@@ -10508,6 +10501,13 @@ handle_interrupt (bool in_signal_handler)
10508 outside of polling since we don't get SIGIO like X and we don't have a 10501 outside of polling since we don't get SIGIO like X and we don't have a
10509 separate event loop thread like W32. */ 10502 separate event loop thread like W32. */
10510#ifndef HAVE_NS 10503#ifndef HAVE_NS
10504#ifdef THREADS_ENABLED
10505 /* If we were called from a signal handler, we must be in the main
10506 thread, see deliver_process_signal. So we must make sure the
10507 main thread holds the global lock. */
10508 if (in_signal_handler)
10509 maybe_reacquire_global_lock ();
10510#endif
10511 if (waiting_for_input && !echoing) 10511 if (waiting_for_input && !echoing)
10512 quit_throw_to_read_char (in_signal_handler); 10512 quit_throw_to_read_char (in_signal_handler);
10513#endif 10513#endif
diff --git a/src/lisp.h b/src/lisp.h
index 680c25d4c49..bdb162aea4c 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -1865,6 +1865,26 @@ verify (offsetof (struct Lisp_Sub_Char_Table, contents)
1865 == (offsetof (struct Lisp_Vector, contents) 1865 == (offsetof (struct Lisp_Vector, contents)
1866 + SUB_CHAR_TABLE_OFFSET * sizeof (Lisp_Object))); 1866 + SUB_CHAR_TABLE_OFFSET * sizeof (Lisp_Object)));
1867 1867
1868
1869/* Save and restore the instruction and environment pointers,
1870 without affecting the signal mask. */
1871
1872#ifdef HAVE__SETJMP
1873typedef jmp_buf sys_jmp_buf;
1874# define sys_setjmp(j) _setjmp (j)
1875# define sys_longjmp(j, v) _longjmp (j, v)
1876#elif defined HAVE_SIGSETJMP
1877typedef sigjmp_buf sys_jmp_buf;
1878# define sys_setjmp(j) sigsetjmp (j, 0)
1879# define sys_longjmp(j, v) siglongjmp (j, v)
1880#else
1881/* A platform that uses neither _longjmp nor siglongjmp; assume
1882 longjmp does not affect the sigmask. */
1883typedef jmp_buf sys_jmp_buf;
1884# define sys_setjmp(j) setjmp (j)
1885# define sys_longjmp(j, v) longjmp (j, v)
1886#endif
1887
1868#include "thread.h" 1888#include "thread.h"
1869 1889
1870/*********************************************************************** 1890/***********************************************************************
@@ -3003,25 +3023,6 @@ extern void defvar_kboard (struct Lisp_Kboard_Objfwd *, const char *, int);
3003 static struct Lisp_Kboard_Objfwd ko_fwd; \ 3023 static struct Lisp_Kboard_Objfwd ko_fwd; \
3004 defvar_kboard (&ko_fwd, lname, offsetof (KBOARD, vname ## _)); \ 3024 defvar_kboard (&ko_fwd, lname, offsetof (KBOARD, vname ## _)); \
3005 } while (false) 3025 } while (false)
3006
3007/* Save and restore the instruction and environment pointers,
3008 without affecting the signal mask. */
3009
3010#ifdef HAVE__SETJMP
3011typedef jmp_buf sys_jmp_buf;
3012# define sys_setjmp(j) _setjmp (j)
3013# define sys_longjmp(j, v) _longjmp (j, v)
3014#elif defined HAVE_SIGSETJMP
3015typedef sigjmp_buf sys_jmp_buf;
3016# define sys_setjmp(j) sigsetjmp (j, 0)
3017# define sys_longjmp(j, v) siglongjmp (j, v)
3018#else
3019/* A platform that uses neither _longjmp nor siglongjmp; assume
3020 longjmp does not affect the sigmask. */
3021typedef jmp_buf sys_jmp_buf;
3022# define sys_setjmp(j) setjmp (j)
3023# define sys_longjmp(j, v) longjmp (j, v)
3024#endif
3025 3026
3026 3027
3027/* Elisp uses several stacks: 3028/* Elisp uses several stacks:
diff --git a/src/thread.c b/src/thread.c
index 42d7791ad0f..d075bdb3a13 100644
--- a/src/thread.c
+++ b/src/thread.c
@@ -101,14 +101,20 @@ acquire_global_lock (struct thread_state *self)
101 post_acquire_global_lock (self); 101 post_acquire_global_lock (self);
102} 102}
103 103
104/* This is called from keyboard.c when it detects that SIGINT 104/* This is called from keyboard.c when it detects that SIGINT was
105 interrupted thread_select before the current thread could acquire 105 delivered to the main thread and interrupted thread_select before
106 the lock. We must acquire the lock to prevent a thread from 106 the main thread could acquire the lock. We must acquire the lock
107 running without holding the global lock, and to avoid repeated 107 to prevent a thread from running without holding the global lock,
108 calls to sys_mutex_unlock, which invokes undefined behavior. */ 108 and to avoid repeated calls to sys_mutex_unlock, which invokes
109 undefined behavior. */
109void 110void
110maybe_reacquire_global_lock (void) 111maybe_reacquire_global_lock (void)
111{ 112{
113 /* SIGINT handler is always run on the main thread, see
114 deliver_process_signal, so reflect that in our thread-tracking
115 variables. */
116 current_thread = &main_thread;
117
112 if (current_thread->not_holding_lock) 118 if (current_thread->not_holding_lock)
113 { 119 {
114 struct thread_state *self = current_thread; 120 struct thread_state *self = current_thread;
diff --git a/src/thread.h b/src/thread.h
index 7fce8674f0e..cb2133d72d4 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -158,6 +158,13 @@ struct thread_state
158 bool m_waiting_for_input; 158 bool m_waiting_for_input;
159#define waiting_for_input (current_thread->m_waiting_for_input) 159#define waiting_for_input (current_thread->m_waiting_for_input)
160 160
161 /* For longjmp to where kbd input is being done. This is per-thread
162 so that if more than one thread calls read_char, they don't
163 clobber each other's getcjmp, which will cause
164 quit_throw_to_read_char crash due to using a wrong stack. */
165 sys_jmp_buf m_getcjmp;
166#define getcjmp (current_thread->m_getcjmp)
167
161 /* The OS identifier for this thread. */ 168 /* The OS identifier for this thread. */
162 sys_thread_t thread_id; 169 sys_thread_t thread_id;
163 170