diff --git a/doc/lispref/threads.texi b/doc/lispref/threads.texi index 58a3a918ef..9830198411 100644 --- a/doc/lispref/threads.texi +++ b/doc/lispref/threads.texi @@ -88,14 +88,8 @@ Basic Thread Functions @code{condition-wait}, or @code{thread-join}; @code{thread-signal} will unblock it. -Since signal handlers in Emacs are located in the main thread, a -signal must be propagated there in order to become visible. The -second @code{signal} call let the thread die: - -@example -(thread-signal main-thread 'error data) -(signal 'error data) -@end example +If @var{thread} is the main thread, the signal is not propagated +there. Instead, it is shown as message in the main thread. @end defun @defun thread-yield diff --git a/src/keyboard.c b/src/keyboard.c index 7fafb41fcc..008d3b9d7c 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -2827,6 +2827,9 @@ read_char (int commandflag, Lisp_Object map, #endif #ifdef USE_FILE_NOTIFY || EQ (XCAR (c), Qfile_notify) +#endif +#ifdef THREADS_ENABLED + || EQ (XCAR (c), Qthread_event) #endif || EQ (XCAR (c), Qconfig_changed_event)) && !end_time) @@ -3739,7 +3742,7 @@ kbd_buffer_get_event (KBOARD **kbp, } #endif /* subprocesses */ -#if !defined HAVE_DBUS && !defined USE_FILE_NOTIFY +#if !defined HAVE_DBUS && !defined USE_FILE_NOTIFY && !defined THREADS_ENABLED if (noninteractive /* In case we are running as a daemon, only do this before detaching from the terminal. */ @@ -3750,7 +3753,7 @@ kbd_buffer_get_event (KBOARD **kbp, *kbp = current_kboard; return obj; } -#endif /* !defined HAVE_DBUS && !defined USE_FILE_NOTIFY */ +#endif /* !defined HAVE_DBUS && !defined USE_FILE_NOTIFY && !defined THREADS_ENABLED */ /* Wait until there is input available. */ for (;;) @@ -3900,6 +3903,9 @@ kbd_buffer_get_event (KBOARD **kbp, #ifdef HAVE_DBUS case DBUS_EVENT: #endif +#ifdef THREADS_ENABLED + case THREAD_EVENT: +#endif #ifdef HAVE_XWIDGETS case XWIDGET_EVENT: #endif @@ -5983,6 +5989,13 @@ make_lispy_event (struct input_event *event) } #endif /* HAVE_DBUS */ +#ifdef THREADS_ENABLED + case THREAD_EVENT: + { + return Fcons (Qthread_event, event->arg); + } +#endif /* THREADS_ENABLED */ + #ifdef HAVE_XWIDGETS case XWIDGET_EVENT: { @@ -11078,6 +11091,10 @@ syms_of_keyboard (void) DEFSYM (Qdbus_event, "dbus-event"); #endif +#ifdef THREADS_ENABLED + DEFSYM (Qthread_event, "thread-event"); +#endif + #ifdef HAVE_XWIDGETS DEFSYM (Qxwidget_event, "xwidget-event"); #endif @@ -11929,6 +11946,12 @@ keys_of_keyboard (void) "dbus-handle-event"); #endif +#ifdef THREADS_ENABLED + /* Define a special event which is raised for thread signals. */ + initial_define_lispy_key (Vspecial_event_map, "thread-event", + "thread-handle-event"); +#endif + #ifdef USE_FILE_NOTIFY /* Define a special event which is raised for notification callback functions. */ diff --git a/src/termhooks.h b/src/termhooks.h index 160bd2f480..8b5f648b43 100644 --- a/src/termhooks.h +++ b/src/termhooks.h @@ -222,6 +222,10 @@ enum event_kind , DBUS_EVENT #endif +#ifdef THREADS_ENABLED + , THREAD_EVENT +#endif + , CONFIG_CHANGED_EVENT #ifdef HAVE_NTGUI diff --git a/src/thread.c b/src/thread.c index 1c73d93865..0234f65e02 100644 --- a/src/thread.c +++ b/src/thread.c @@ -25,6 +25,7 @@ along with GNU Emacs. If not, see . */ #include "process.h" #include "coding.h" #include "syssignal.h" +#include "keyboard.h" static struct thread_state main_thread; @@ -34,7 +35,6 @@ static struct thread_state *all_threads = &main_thread; static sys_mutex_t global_lock; -extern int poll_suppress_count; extern volatile int interrupt_input_blocked; @@ -863,7 +863,8 @@ DEFUN ("thread-signal", Fthread_signal, Sthread_signal, 3, 3, 0, This acts like `signal', but arranges for the signal to be raised in THREAD. If THREAD is the current thread, acts just like `signal'. This will interrupt a blocked call to `mutex-lock', `condition-wait', -or `thread-join' in the target thread. */) +or `thread-join' in the target thread. +Signals to the main thread are ignored quietly. */) (Lisp_Object thread, Lisp_Object error_symbol, Lisp_Object data) { struct thread_state *tstate; @@ -874,13 +875,29 @@ or `thread-join' in the target thread. */) if (tstate == current_thread) Fsignal (error_symbol, data); - /* What to do if thread is already signaled? */ - /* What if error_symbol is Qnil? */ - tstate->error_symbol = error_symbol; - tstate->error_data = data; + if (main_thread_p (tstate)) + { + /* Construct an event. */ + struct input_event event; + EVENT_INIT (event); + event.kind = THREAD_EVENT; + event.frame_or_window = Qnil; + event.arg = list3 (Fcurrent_thread (), error_symbol, data); + + /* Store it into the input event queue. */ + kbd_buffer_store_event (&event); + } + + else + { + /* What to do if thread is already signaled? */ + /* What if error_symbol is Qnil? */ + tstate->error_symbol = error_symbol; + tstate->error_data = data; - if (tstate->wait_condvar) - flush_stack_call_func (thread_signal_callback, tstate); + if (tstate->wait_condvar) + flush_stack_call_func (thread_signal_callback, tstate); + } return Qnil; }