aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEli Zaretskii2017-01-18 18:00:16 +0200
committerEli Zaretskii2017-01-18 18:00:16 +0200
commit571532605bc0db221c76e36067435e4355e0d1a1 (patch)
tree5a8120468d552a682c5bbfc1ec9f83c80d364b11
parentdbb29d7eb428dd53617d31a9cc159d889deb1e8e (diff)
downloademacs-571532605bc0db221c76e36067435e4355e0d1a1.tar.gz
emacs-571532605bc0db221c76e36067435e4355e0d1a1.zip
Rudimentary error handling for non-main threads
* src/thread.c (last_thread_error): New static variable. (syms_of_threads): Staticpro it. (record_thread_error, Fthread_last_error): New functions. (syms_of_threads): Defsubr Fthread_last_error. * doc/lispref/threads.texi (Basic Thread Functions): Document thread-last-error. * test/src/thread-tests.el (thread-errors, thread-signal-early) (threads-condvar-wait): Test the values returned by thread-last-error.
-rw-r--r--doc/lispref/threads.texi11
-rw-r--r--src/thread.c20
-rw-r--r--test/src/thread-tests.el17
3 files changed, 41 insertions, 7 deletions
diff --git a/doc/lispref/threads.texi b/doc/lispref/threads.texi
index d6cf99d2332..71742f576e5 100644
--- a/doc/lispref/threads.texi
+++ b/doc/lispref/threads.texi
@@ -127,6 +127,17 @@ Return a list of all the live thread objects. A new list is returned
127by each invocation. 127by each invocation.
128@end defun 128@end defun
129 129
130When code run by a thread signals an error that is unhandled, the
131thread exits. Other threads can access the error form which caused
132the thread to exit using the following function.
133
134@defun thread-last-error
135This function returns the last error form recorded when a thread
136exited due to an error. Each thread that exits abnormally overwrites
137the form stored by the previous thread's error with a new value, so
138only the last one can be accessed.
139@end defun
140
130@node Mutexes 141@node Mutexes
131@section Mutexes 142@section Mutexes
132 143
diff --git a/src/thread.c b/src/thread.c
index 5498fe5efcb..6048516659e 100644
--- a/src/thread.c
+++ b/src/thread.c
@@ -663,10 +663,13 @@ invoke_thread_function (void)
663 return unbind_to (count, Qnil); 663 return unbind_to (count, Qnil);
664} 664}
665 665
666static Lisp_Object last_thread_error;
667
666static Lisp_Object 668static Lisp_Object
667do_nothing (Lisp_Object whatever) 669record_thread_error (Lisp_Object error_form)
668{ 670{
669 return whatever; 671 last_thread_error = error_form;
672 return error_form;
670} 673}
671 674
672static void * 675static void *
@@ -695,7 +698,7 @@ run_thread (void *state)
695 handlerlist_sentinel->next = NULL; 698 handlerlist_sentinel->next = NULL;
696 699
697 /* It might be nice to do something with errors here. */ 700 /* It might be nice to do something with errors here. */
698 internal_condition_case (invoke_thread_function, Qt, do_nothing); 701 internal_condition_case (invoke_thread_function, Qt, record_thread_error);
699 702
700 update_processes_for_thread_death (Fcurrent_thread ()); 703 update_processes_for_thread_death (Fcurrent_thread ());
701 704
@@ -944,6 +947,13 @@ DEFUN ("all-threads", Fall_threads, Sall_threads, 0, 0, 0,
944 return result; 947 return result;
945} 948}
946 949
950DEFUN ("thread-last-error", Fthread_last_error, Sthread_last_error, 0, 0, 0,
951 doc: /* Return the last error form recorded by a dying thread. */)
952 (void)
953{
954 return last_thread_error;
955}
956
947 957
948 958
949bool 959bool
@@ -1028,6 +1038,10 @@ syms_of_threads (void)
1028 defsubr (&Scondition_notify); 1038 defsubr (&Scondition_notify);
1029 defsubr (&Scondition_mutex); 1039 defsubr (&Scondition_mutex);
1030 defsubr (&Scondition_name); 1040 defsubr (&Scondition_name);
1041 defsubr (&Sthread_last_error);
1042
1043 staticpro (&last_thread_error);
1044 last_thread_error = Qnil;
1031 } 1045 }
1032 1046
1033 DEFSYM (Qthreadp, "threadp"); 1047 DEFSYM (Qthreadp, "threadp");
diff --git a/test/src/thread-tests.el b/test/src/thread-tests.el
index df8222a21aa..849b2e3dd1b 100644
--- a/test/src/thread-tests.el
+++ b/test/src/thread-tests.el
@@ -222,8 +222,15 @@
222 222
223(ert-deftest thread-errors () 223(ert-deftest thread-errors ()
224 "Test what happens when a thread signals an error." 224 "Test what happens when a thread signals an error."
225 (should (threadp (make-thread #'call-error "call-error"))) 225 (let (th1 th2)
226 (should (threadp (make-thread #'thread-custom "thread-custom")))) 226 (setq th1 (make-thread #'call-error "call-error"))
227 (should (threadp th1))
228 (while (thread-alive-p th1)
229 (thread-yield))
230 (should (equal (thread-last-error)
231 '(error "Error is called")))
232 (setq th2 (make-thread #'thread-custom "thread-custom"))
233 (should (threadp th2))))
227 234
228(ert-deftest thread-sticky-point () 235(ert-deftest thread-sticky-point ()
229 "Test bug #25165 with point movement in cloned buffer." 236 "Test bug #25165 with point movement in cloned buffer."
@@ -242,7 +249,8 @@
242 (while t (thread-yield)))))) 249 (while t (thread-yield))))))
243 (thread-signal thread 'error nil) 250 (thread-signal thread 'error nil)
244 (sit-for 1) 251 (sit-for 1)
245 (should-not (thread-alive-p thread)))) 252 (should-not (thread-alive-p thread))
253 (should (equal (thread-last-error) '(error)))))
246 254
247(defvar threads-condvar nil) 255(defvar threads-condvar nil)
248 256
@@ -287,6 +295,7 @@
287 (thread-signal new-thread 'error '("Die, die, die!")) 295 (thread-signal new-thread 'error '("Die, die, die!"))
288 (sleep-for 0.1) 296 (sleep-for 0.1)
289 ;; Make sure the thread died. 297 ;; Make sure the thread died.
290 (should (= (length (all-threads)) 1)))) 298 (should (= (length (all-threads)) 1))
299 (should (equal (thread-last-error) '(error "Die, die, die!")))))
291 300
292;;; threads.el ends here 301;;; threads.el ends here