[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Guile-commits] 01/17: cancel-thread via asyncs, not pthread_cancel
From: |
Andy Wingo |
Subject: |
[Guile-commits] 01/17: cancel-thread via asyncs, not pthread_cancel |
Date: |
Mon, 31 Oct 2016 21:39:36 +0000 (UTC) |
wingo pushed a commit to branch master
in repository guile.
commit a04739b31a561879368c61f7599844fc9a85a7a6
Author: Andy Wingo <address@hidden>
Date: Thu Oct 27 21:22:28 2016 +0200
cancel-thread via asyncs, not pthread_cancel
* module/ice-9/threads.scm (cancel-tag): New variable.
(cancel-thread): New Scheme function.
(call-with-new-thread): Install a prompt around the thread.
* libguile/threads.h (scm_i_thread): Remove cancelled member.
* libguile/threads.c (scm_cancel_thread): Call out to Scheme. Always
available, and works on the current thread too.
(scm_set_thread_cleanup_x, scm_thread_cleanup): Adapt.
(scm_init_ice_9_threads): Capture cancel-thread var.
* doc/ref/api-scheduling.texi (Threads): Update.
* NEWS: Update.
---
NEWS | 3 +++
doc/ref/api-scheduling.texi | 19 ++++++++-----------
libguile/threads.c | 36 +++++++++---------------------------
libguile/threads.h | 1 -
module/ice-9/threads.scm | 30 +++++++++++++++++++++++++-----
5 files changed, 45 insertions(+), 44 deletions(-)
diff --git a/NEWS b/NEWS
index 0702eb2..06f2e8c 100644
--- a/NEWS
+++ b/NEWS
@@ -38,6 +38,9 @@ trivial unused data structure. Now that we have deprecated
the old
only refer to "asyncs".
* Bug fixes
+** cancel-thread uses asynchronous interrupts, not pthread_cancel
+
+See "Asyncs" in the manual, for more on asynchronous interrupts.
Previous changes in 2.1.x (changes since the 2.0.x series):
diff --git a/doc/ref/api-scheduling.texi b/doc/ref/api-scheduling.texi
index 551b3fb..45b5315 100644
--- a/doc/ref/api-scheduling.texi
+++ b/doc/ref/api-scheduling.texi
@@ -114,17 +114,14 @@ immediate context switch to one of them. Otherwise, yield
has no effect.
@deffn {Scheme Procedure} cancel-thread thread
@deffnx {C Function} scm_cancel_thread (thread)
-Asynchronously notify @var{thread} to exit. Immediately after
-receiving this notification, @var{thread} will call its cleanup handler
-(if one has been set) and then terminate, aborting any evaluation that
-is in progress.
-
-Because Guile threads are isomorphic with POSIX threads, @var{thread}
-will not receive its cancellation signal until it reaches a cancellation
-point. See your operating system's POSIX threading documentation for
-more information on cancellation points; note that in Guile, unlike
-native POSIX threads, a thread can receive a cancellation notification
-while attempting to lock a mutex.
+Asynchronously interrupt @var{thread} and ask it to terminate.
address@hidden post thunks will run, but throw handlers will not.
+If @var{thread} has already terminated or been signaled to terminate,
+this function is a no-op.
+
+Under this hood, thread cancellation uses @code{system-async-mark} and
address@hidden @xref{Asyncs} for more on asynchronous
+interrupts.
@end deffn
@deffn {Scheme Procedure} set-thread-cleanup! thread proc
diff --git a/libguile/threads.c b/libguile/threads.c
index 2a315e4..8ac0832 100644
--- a/libguile/threads.c
+++ b/libguile/threads.c
@@ -438,7 +438,6 @@ guilify_self_1 (struct GC_stack_base *base)
abort ();
scm_i_pthread_mutex_init (&t.admin_mutex, NULL);
- t.canceled = 0;
t.exited = 0;
t.guile_mode = 0;
@@ -1012,34 +1011,14 @@ SCM_DEFINE (scm_yield, "yield", 0, 0, 0,
/* Some systems, notably Android, lack 'pthread_cancel'. Don't provide
'cancel-thread' on these systems. */
-#if !SCM_USE_PTHREAD_THREADS || defined HAVE_PTHREAD_CANCEL
+static SCM cancel_thread_var;
-SCM_DEFINE (scm_cancel_thread, "cancel-thread", 1, 0, 0,
- (SCM thread),
-"Asynchronously force the target @var{thread} to terminate. @var{thread} "
-"cannot be the current thread, and if @var{thread} has already terminated or "
-"been signaled to terminate, this function is a no-op.")
-#define FUNC_NAME s_scm_cancel_thread
+SCM
+scm_cancel_thread (SCM thread)
{
- scm_i_thread *t = NULL;
-
- SCM_VALIDATE_THREAD (1, thread);
- t = SCM_I_THREAD_DATA (thread);
- scm_i_scm_pthread_mutex_lock (&t->admin_mutex);
- if (!t->canceled)
- {
- t->canceled = 1;
- scm_i_pthread_mutex_unlock (&t->admin_mutex);
- scm_i_pthread_cancel (t->pthread);
- }
- else
- scm_i_pthread_mutex_unlock (&t->admin_mutex);
-
+ scm_call_1 (scm_variable_ref (cancel_thread_var), thread);
return SCM_UNSPECIFIED;
}
-#undef FUNC_NAME
-
-#endif
SCM_DEFINE (scm_set_thread_cleanup_x, "set-thread-cleanup!", 2, 0, 0,
(SCM thread, SCM proc),
@@ -1056,7 +1035,7 @@ SCM_DEFINE (scm_set_thread_cleanup_x,
"set-thread-cleanup!", 2, 0, 0,
t = SCM_I_THREAD_DATA (thread);
scm_i_pthread_mutex_lock (&t->admin_mutex);
- if (!(t->exited || t->canceled))
+ if (!t->exited)
t->cleanup_handler = proc;
scm_i_pthread_mutex_unlock (&t->admin_mutex);
@@ -1077,7 +1056,7 @@ SCM_DEFINE (scm_thread_cleanup, "thread-cleanup", 1, 0, 0,
t = SCM_I_THREAD_DATA (thread);
scm_i_pthread_mutex_lock (&t->admin_mutex);
- ret = (t->exited || t->canceled) ? SCM_BOOL_F : t->cleanup_handler;
+ ret = t->exited ? SCM_BOOL_F : t->cleanup_handler;
scm_i_pthread_mutex_unlock (&t->admin_mutex);
return ret;
@@ -2073,6 +2052,9 @@ scm_init_ice_9_threads (void *unused)
{
#include "libguile/threads.x"
+ cancel_thread_var =
+ scm_module_variable (scm_current_module (),
+ scm_from_latin1_symbol ("cancel-thread"));
call_with_new_thread_var =
scm_module_variable (scm_current_module (),
scm_from_latin1_symbol ("call-with-new-thread"));
diff --git a/libguile/threads.h b/libguile/threads.h
index 241907d..90bb661 100644
--- a/libguile/threads.h
+++ b/libguile/threads.h
@@ -68,7 +68,6 @@ typedef struct scm_i_thread {
scm_i_pthread_mutex_t *held_mutex;
SCM result;
- int canceled;
int exited;
/* Boolean indicating whether the thread is in guile mode. */
diff --git a/module/ice-9/threads.scm b/module/ice-9/threads.scm
index f0f08e0..4b2f6c6 100644
--- a/module/ice-9/threads.scm
+++ b/module/ice-9/threads.scm
@@ -31,6 +31,7 @@
(define-module (ice-9 threads)
#:use-module (ice-9 match)
+ #:use-module (ice-9 control)
;; These bindings are marked as #:replace because when deprecated code
;; is enabled, (ice-9 deprecated) also exports these names.
;; (Referencing one of the deprecated names prints a warning directing
@@ -86,6 +87,21 @@
+(define cancel-tag (make-prompt-tag "cancel"))
+(define (cancel-thread thread)
+ "Asynchronously interrupt the target @var{thread} and ask it to
+terminate. @code{dynamic-wind} post thunks will run, but throw handlers
+will not. If @var{thread} has already terminated or been signaled to
+terminate, this function is a no-op."
+ (system-async-mark
+ (lambda ()
+ (catch #t
+ (lambda ()
+ (abort-to-prompt cancel-tag))
+ (lambda _
+ (error "thread cancellation failed, throwing error instead???"))))
+ thread))
+
(define* (call-with-new-thread thunk #:optional handler)
"Call @code{thunk} in a new thread and with a new dynamic state,
returning a new thread object representing the thread. The procedure
@@ -106,11 +122,15 @@ Once @var{thunk} or @var{handler} returns, the return
value is made the
(with-mutex mutex
(%call-with-new-thread
(lambda ()
- (lock-mutex mutex)
- (set! thread (current-thread))
- (signal-condition-variable cv)
- (unlock-mutex mutex)
- (thunk)))
+ (call-with-prompt cancel-tag
+ (lambda ()
+ (lock-mutex mutex)
+ (set! thread (current-thread))
+ (signal-condition-variable cv)
+ (unlock-mutex mutex)
+ (thunk))
+ (lambda (k . args)
+ (apply values args)))))
(let lp ()
(unless thread
(wait-condition-variable cv mutex)
- [Guile-commits] 07/17: srfi-18: Use parameters., (continued)
- [Guile-commits] 07/17: srfi-18: Use parameters., Andy Wingo, 2016/10/31
- [Guile-commits] 10/17: srfi-18: Avoid call/cc., Andy Wingo, 2016/10/31
- [Guile-commits] 11/17: Rationalize exception handling in srfi-18, Andy Wingo, 2016/10/31
- [Guile-commits] 17/17: Remove thread cleanup facility, Andy Wingo, 2016/10/31
- [Guile-commits] 02/17: Fix srfi-34 indentation, Andy Wingo, 2016/10/31
- [Guile-commits] 12/17: Refactor thread-join! to use optional args., Andy Wingo, 2016/10/31
- [Guile-commits] 13/17: Trim srfi-18 thread startup machinery, Andy Wingo, 2016/10/31
- [Guile-commits] 14/17: cancel-thread can take arguments, Andy Wingo, 2016/10/31
- [Guile-commits] 03/17: srfi-18: Improve style., Andy Wingo, 2016/10/31
- [Guile-commits] 15/17: srfi-18: thread-terminate! without cleanup handlers, Andy Wingo, 2016/10/31
- [Guile-commits] 01/17: cancel-thread via asyncs, not pthread_cancel,
Andy Wingo <=
- [Guile-commits] 08/17: srfi-18: Use srfi-35 conditions., Andy Wingo, 2016/10/31
- [Guile-commits] 16/17: REPL server avoids thread cleanup handlers, Andy Wingo, 2016/10/31
- [Guile-commits] 09/17: srfi-18: Inline uses of srfi-18-exception-preserver., Andy Wingo, 2016/10/31