aboutsummaryrefslogtreecommitdiffstats
path: root/src/thread.c
diff options
context:
space:
mode:
authorEli Zaretskii2016-12-12 19:08:21 +0200
committerEli Zaretskii2016-12-12 19:08:21 +0200
commit825f4dd42f0f656bcb4536546b33fe8e54756468 (patch)
tree267e32c802f96d0a2e32b82f35fbb924b6656dd5 /src/thread.c
parenta416e1d6c111527205f3583c8d201bf95af6fa20 (diff)
downloademacs-825f4dd42f0f656bcb4536546b33fe8e54756468.tar.gz
emacs-825f4dd42f0f656bcb4536546b33fe8e54756468.zip
Avoid crashing if a new thread is signaled right away
* src/thread.c (post_acquire_global_lock): Don't raise the pending signal if the thread's handlers were not yet set up, as that will cause Emacs to exit with a fatal error. This can happen if a thread is signaled as soon as make-thread returns, before the new thread had an opportunity to acquire the global lock, set up the handlers, and call the thread function. * test/src/thread-tests.el (thread-signal-early): New test.
Diffstat (limited to 'src/thread.c')
-rw-r--r--src/thread.c26
1 files changed, 15 insertions, 11 deletions
diff --git a/src/thread.c b/src/thread.c
index 6e9ca2e256b..e8cb430119f 100644
--- a/src/thread.c
+++ b/src/thread.c
@@ -77,7 +77,12 @@ post_acquire_global_lock (struct thread_state *self)
77 set_buffer_internal_2 (current_buffer); 77 set_buffer_internal_2 (current_buffer);
78 } 78 }
79 79
80 if (!NILP (current_thread->error_symbol)) 80 /* We could have been signaled while waiting to grab the global lock
81 for the first time since this thread was created, in which case
82 we didn't yet have the opportunity to set up the handlers. Delay
83 raising the signal in that case (it will be actually raised when
84 the thread comes here after acquiring the lock the next time). */
85 if (!NILP (current_thread->error_symbol) && handlerlist)
81 { 86 {
82 Lisp_Object sym = current_thread->error_symbol; 87 Lisp_Object sym = current_thread->error_symbol;
83 Lisp_Object data = current_thread->error_data; 88 Lisp_Object data = current_thread->error_data;
@@ -622,16 +627,15 @@ run_thread (void *state)
622 627
623 acquire_global_lock (self); 628 acquire_global_lock (self);
624 629
625 { /* Put a dummy catcher at top-level so that handlerlist is never NULL. 630 /* Put a dummy catcher at top-level so that handlerlist is never NULL.
626 This is important since handlerlist->nextfree holds the freelist 631 This is important since handlerlist->nextfree holds the freelist
627 which would otherwise leak every time we unwind back to top-level. */ 632 which would otherwise leak every time we unwind back to top-level. */
628 handlerlist_sentinel = xzalloc (sizeof (struct handler)); 633 handlerlist_sentinel = xzalloc (sizeof (struct handler));
629 handlerlist = handlerlist_sentinel->nextfree = handlerlist_sentinel; 634 handlerlist = handlerlist_sentinel->nextfree = handlerlist_sentinel;
630 struct handler *c = push_handler (Qunbound, CATCHER); 635 struct handler *c = push_handler (Qunbound, CATCHER);
631 eassert (c == handlerlist_sentinel); 636 eassert (c == handlerlist_sentinel);
632 handlerlist_sentinel->nextfree = NULL; 637 handlerlist_sentinel->nextfree = NULL;
633 handlerlist_sentinel->next = NULL; 638 handlerlist_sentinel->next = NULL;
634 }
635 639
636 /* It might be nice to do something with errors here. */ 640 /* It might be nice to do something with errors here. */
637 internal_condition_case (invoke_thread_function, Qt, do_nothing); 641 internal_condition_case (invoke_thread_function, Qt, do_nothing);