1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-21 12:10:26 +02:00

SRFI-18 threads disjoint from guile threads

* doc/ref/srfi-modules.texi (SRFI-18 Threads): Update.
* module/srfi/srfi-18.scm (<mutex>): Add owner field.
  (<thread>): New data type.
  (make-thread): Adapt for boxed threads.
  (thread-start!, thread-terminate!): Likewise.
  (mutex-state): Adapt for boxed threads.
  (mutex-lock!, mutex-unlock!): Update owner field.
This commit is contained in:
Andy Wingo 2016-11-04 22:35:19 +01:00
parent bb4e955f0c
commit 3ce76c38cb
2 changed files with 78 additions and 67 deletions

View file

@ -2085,6 +2085,9 @@ execution until @code{thread-start!} is called on it. Second, SRFI-18
threads are constructed with a top-level exception handler that threads are constructed with a top-level exception handler that
captures any exceptions that are thrown on thread exit. captures any exceptions that are thrown on thread exit.
SRFI-18 threads are disjoint from Guile's primitive threads.
@xref{Threads}, for more on Guile's primitive facility.
@defun current-thread @defun current-thread
Returns the thread that called this function. This is the same Returns the thread that called this function. This is the same
procedure as the same-named built-in procedure @code{current-thread} procedure as the same-named built-in procedure @code{current-thread}

View file

@ -80,10 +80,10 @@
terminated-thread-exception? terminated-thread-exception?
uncaught-exception? uncaught-exception?
uncaught-exception-reason) uncaught-exception-reason)
#:re-export ((threads:current-thread . current-thread) #:re-export ((srfi-34:raise . raise))
(threads:thread? . thread?)
(srfi-34:raise . raise))
#:replace (current-time #:replace (current-time
current-thread
thread?
make-thread make-thread
make-mutex make-mutex
mutex? mutex?
@ -112,11 +112,12 @@
(reason uncaught-exception-reason)) (reason uncaught-exception-reason))
(define-record-type <mutex> (define-record-type <mutex>
(%make-mutex prim name specific) (%make-mutex prim name specific owner)
mutex? mutex?
(prim mutex-prim) (prim mutex-prim)
(name mutex-name) (name mutex-name)
(specific mutex-specific mutex-specific-set!)) (specific mutex-specific mutex-specific-set!)
(owner mutex-owner set-mutex-owner!))
(define-record-type <condition-variable> (define-record-type <condition-variable>
(%make-condition-variable prim name specific) (%make-condition-variable prim name specific)
@ -125,10 +126,16 @@
(name condition-variable-name) (name condition-variable-name)
(specific condition-variable-specific condition-variable-specific-set!)) (specific condition-variable-specific condition-variable-specific-set!))
(define object-names (make-weak-key-hash-table)) (define-record-type <thread>
(define object-specifics (make-weak-key-hash-table)) (%make-thread prim name specific start-conds exception)
(define thread-start-conds (make-weak-key-hash-table)) thread?
(define thread->exception (make-object-property)) (prim thread-prim set-thread-prim!)
(name thread-name)
(specific thread-specific thread-specific-set!)
(start-conds thread-start-conds set-thread-start-conds!)
(exception thread-exception set-thread-exception!))
(define current-thread (make-parameter (%make-thread #f #f #f #f #f)))
(define thread-mutexes (make-parameter #f)) (define thread-mutexes (make-parameter #f))
;; EXCEPTIONS ;; EXCEPTIONS
@ -177,50 +184,37 @@
mutexes)))))) mutexes))))))
(define* (make-thread thunk #:optional name) (define* (make-thread thunk #:optional name)
(let ((sm (make-mutex 'start-mutex)) (let* ((sm (make-mutex 'start-mutex))
(sc (make-condition-variable 'start-condition-variable))) (sc (make-condition-variable 'start-condition-variable))
(thread (%make-thread #f name #f (cons sm sc) #f)))
(mutex-lock! sm) (mutex-lock! sm)
(let ((t (threads:call-with-new-thread (let ((prim (threads:call-with-new-thread
(lambda () (lambda ()
(catch #t (catch #t
(lambda ()
(with-thread-mutex-cleanup
(lambda () (lambda ()
(mutex-lock! sm) (parameterize ((current-thread thread))
(condition-variable-signal! sc) (with-thread-mutex-cleanup
(mutex-unlock! sm sc) (lambda ()
(thunk)))) (mutex-lock! sm)
(lambda (key . args) (condition-variable-signal! sc)
(set! (thread->exception (threads:current-thread)) (mutex-unlock! sm sc)
(condition (&uncaught-exception (thunk)))))
(reason (lambda (key . args)
(match (cons key args) (set-thread-exception!
(('srfi-34 obj) obj) thread
(obj obj)))))))))))) (condition (&uncaught-exception
(when name (hashq-set! object-names t name)) (reason
(match (cons key args)
(('srfi-34 obj) obj)
(obj obj))))))))))))
(set-thread-prim! thread prim)
(mutex-unlock! sm sc) (mutex-unlock! sm sc)
(hashq-set! thread-start-conds t (cons sm sc)) thread)))
t)))
(define (thread-name thread)
(hashq-ref object-names
(check-arg-type threads:thread? thread "thread-name")))
(define (thread-specific thread)
(hashq-ref object-specifics
(check-arg-type threads:thread? thread "thread-specific")))
(define (thread-specific-set! thread obj)
(hashq-set! object-specifics
(check-arg-type threads:thread? thread "thread-specific-set!")
obj)
*unspecified*)
(define (thread-start! thread) (define (thread-start! thread)
(match (hashq-ref thread-start-conds (match (thread-start-conds thread)
(check-arg-type threads:thread? thread "thread-start!"))
((smutex . scond) ((smutex . scond)
(hashq-remove! thread-start-conds thread) (set-thread-start-conds! thread #f)
(mutex-lock! smutex) (mutex-lock! smutex)
(condition-variable-signal! scond) (condition-variable-signal! scond)
(mutex-unlock! smutex)) (mutex-unlock! smutex))
@ -267,27 +261,28 @@
;; A unique value. ;; A unique value.
(define %cancel-sentinel (list 'cancelled)) (define %cancel-sentinel (list 'cancelled))
(define (thread-terminate! thread) (define (thread-terminate! thread)
(threads:cancel-thread thread %cancel-sentinel) (threads:cancel-thread (thread-prim thread) %cancel-sentinel)
*unspecified*) *unspecified*)
;; A unique value. ;; A unique value.
(define %timeout-sentinel (list 1)) (define %timeout-sentinel (list 1))
(define* (thread-join! thread #:optional (timeout %timeout-sentinel) (define* (thread-join! thread #:optional (timeout %timeout-sentinel)
(timeoutval %timeout-sentinel)) (timeoutval %timeout-sentinel))
(with-exception-handlers-here (let ((t (thread-prim thread)))
(lambda () (with-exception-handlers-here
(let ((v (if (eq? timeout %timeout-sentinel) (lambda ()
(threads:join-thread thread) (let* ((v (if (eq? timeout %timeout-sentinel)
(threads:join-thread thread timeout %timeout-sentinel)))) (threads:join-thread t)
(cond (threads:join-thread t timeout %timeout-sentinel))))
((eq? v %timeout-sentinel) (cond
(if (eq? timeoutval %timeout-sentinel) ((eq? v %timeout-sentinel)
(srfi-34:raise (condition (&join-timeout-exception))) (if (eq? timeoutval %timeout-sentinel)
timeoutval)) (srfi-34:raise (condition (&join-timeout-exception)))
((eq? v %cancel-sentinel) timeoutval))
(srfi-34:raise (condition (&terminated-thread-exception)))) ((eq? v %cancel-sentinel)
((thread->exception thread) => srfi-34:raise) (srfi-34:raise (condition (&terminated-thread-exception))))
(else v)))))) ((thread-exception thread) => srfi-34:raise)
(else v)))))))
;; MUTEXES ;; MUTEXES
;; These functions are all pass-thrus to the existing Guile implementations. ;; These functions are all pass-thrus to the existing Guile implementations.
@ -297,38 +292,51 @@
'allow-external-unlock 'allow-external-unlock
'recursive) 'recursive)
name name
#f
#f)) #f))
(define (mutex-state mutex) (define (mutex-state mutex)
(let* ((prim (mutex-prim mutex)) (let* ((prim (mutex-prim mutex))
(owner (threads:mutex-owner prim))) (owner (mutex-owner mutex)))
(if owner (if owner
(if (threads:thread-exited? owner) 'abandoned owner) (if (and=> (thread-prim owner) threads:thread-exited?)
'abandoned
owner)
(if (> (threads:mutex-level prim) 0) 'not-owned 'not-abandoned)))) (if (> (threads:mutex-level prim) 0) 'not-owned 'not-abandoned))))
(define (abandon-mutex! mutex) (define (abandon-mutex! mutex)
#t) #t)
(define (mutex-lock! mutex . args) (define* (mutex-lock! mutex #:optional timeout (thread (current-thread)))
(let ((mutexes (thread-mutexes))) (let ((mutexes (thread-mutexes)))
(when mutexes (when mutexes
(hashq-set! mutexes mutex #t))) (hashq-set! mutexes mutex #t)))
(with-exception-handlers-here (with-exception-handlers-here
(lambda () (lambda ()
(catch 'abandoned-mutex-error (catch 'abandoned-mutex-error
(lambda () (apply threads:lock-mutex (mutex-prim mutex) args)) (lambda ()
(cond
((threads:lock-mutex (mutex-prim mutex) timeout)
(set-mutex-owner! mutex thread)
#t)
(else #f)))
(lambda (key . args) (lambda (key . args)
(set-mutex-owner! mutex thread)
(srfi-34:raise (srfi-34:raise
(condition (&abandoned-mutex-exception)))))))) (condition (&abandoned-mutex-exception))))))))
(define mutex-unlock! (define mutex-unlock!
(case-lambda (case-lambda
((mutex) ((mutex)
(threads:unlock-mutex (mutex-prim mutex))) (set-mutex-owner! mutex #f)
(threads:unlock-mutex (mutex-prim mutex))
#t)
((mutex cond) ((mutex cond)
(set-mutex-owner! mutex #f)
(threads:unlock-mutex (mutex-prim mutex) (threads:unlock-mutex (mutex-prim mutex)
(condition-variable-prim cond))) (condition-variable-prim cond)))
((mutex cond timeout) ((mutex cond timeout)
(set-mutex-owner! mutex #f)
(threads:unlock-mutex (mutex-prim mutex) (threads:unlock-mutex (mutex-prim mutex)
(condition-variable-prim cond) (condition-variable-prim cond)
timeout)))) timeout))))