diff options
| author | Eli Zaretskii | 2016-12-12 19:08:21 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2016-12-12 19:08:21 +0200 |
| commit | 825f4dd42f0f656bcb4536546b33fe8e54756468 (patch) | |
| tree | 267e32c802f96d0a2e32b82f35fbb924b6656dd5 /src/thread.c | |
| parent | a416e1d6c111527205f3583c8d201bf95af6fa20 (diff) | |
| download | emacs-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.c | 26 |
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); |