From 4de3198c10c4efaeaffdf43ba5e5b0f1729a7f09 Mon Sep 17 00:00:00 2001 From: Helmut Eller Date: Tue, 25 Jul 2023 10:03:53 +0200 Subject: [PATCH] Make condition-wait interruptible by C-g Code like (let* ((mutex (make-mutex)) (cvar (make-condition-variable mutex))) (with-mutex mutex (condition-wait cvar))) will block in pthread_cond_wait. The problem is that pthread_cond_wait may or may not return when it gets interrupted by a signal (SIGIO). On Linux it doesn't return and so even if a signal handler sets pending_signals=true nobody processes those pending signals. The patch modifies the signal handler so that it will force a spurious wakeup when the current thread is blocked in condition-wait. * src/keyboard.c (handle_input_available_signal) (handle_interrupt): Call maybe_awake_current_thread. * src/thread.c (maybe_awake_current_thread): New. * src/thread.h (maybe_awake_current_thread): New prototype. --- src/keyboard.c | 8 +++++++- src/thread.c | 16 ++++++++++++++++ src/thread.h | 1 + 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/keyboard.c b/src/keyboard.c index 41cda2e65de..f45bafa96c0 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -7745,6 +7745,10 @@ handle_input_available_signal (int sig) if (input_available_clear_time) *input_available_clear_time = make_timespec (0, 0); + +#ifdef THREADS_ENABLED + maybe_awake_current_thread (); +#endif } static void @@ -11556,8 +11560,10 @@ handle_interrupt (bool in_signal_handler) /* 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) + if (in_signal_handler) { maybe_reacquire_global_lock (); + maybe_awake_current_thread(); + } #endif if (waiting_for_input && !echoing) quit_throw_to_read_char (in_signal_handler); diff --git a/src/thread.c b/src/thread.c index b8ca56fd372..0bd949f5779 100644 --- a/src/thread.c +++ b/src/thread.c @@ -172,6 +172,22 @@ maybe_reacquire_global_lock (void) } } +/* This is called from keyboard.c when it sets pending_signals=true. + If the current thread is waiting, we create a spurious wakeup by + broadcasting on wait_condvar. This is necessary because + pthread_cond_wait may or may not return if it was interrupted by a + signal (SIGIO). Without the wakeup, nobody would process a + potential C-g. +*/ +void +maybe_awake_current_thread (void) +{ + if (current_thread->wait_condvar != NULL) + { + sys_cond_broadcast (current_thread->wait_condvar); + } +} + static void diff --git a/src/thread.h b/src/thread.h index 9b14cc44f35..60f601a6248 100644 --- a/src/thread.h +++ b/src/thread.h @@ -311,6 +311,7 @@ extern void finalize_one_thread (struct thread_state *state); extern void finalize_one_mutex (struct Lisp_Mutex *); extern void finalize_one_condvar (struct Lisp_CondVar *); extern void maybe_reacquire_global_lock (void); +extern void maybe_awake_current_thread (void); extern void init_threads (void); extern void syms_of_threads (void); -- 2.39.2