Replace Martin's implementation of selective blocking by the one in

Scheme 48 1.0.1.

Namely, instead of associating a list of queues with every thread, we
associate a single cell, holding the thread.  That cell is stored in
thread queues, and once a thread is made runnable again, the cell is
set to #f.  The thread-queue accessors ignore cells containing #f.

Implement an experimental OBTAIN-LOCK-MULTIPLE to test the whole
thing.
This commit is contained in:
sperber 2002-08-16 14:11:50 +00:00
parent 51230dfab1
commit ac343ba970
16 changed files with 177 additions and 127 deletions

View File

@ -16,17 +16,14 @@
'())))) '()))))
(define (make-placeholder . id-option) (define (make-placeholder . id-option)
(really-make-placeholder (make-thread-queue) (really-make-placeholder (make-queue)
(if (null? id-option) #f (car id-option)))) (if (null? id-option) #f (car id-option))))
(define (placeholder-value placeholder) (define (placeholder-value placeholder)
(with-interrupts-inhibited (with-interrupts-inhibited
(lambda () (lambda ()
(if (placeholder-queue placeholder) (if (placeholder-queue placeholder)
(begin (block-on-queue (placeholder-queue placeholder)))
(enqueue-thread! (placeholder-queue placeholder)
(current-thread))
(block)))
(placeholder-real-value placeholder)))) (placeholder-real-value placeholder))))
(define (placeholder-set! placeholder value) (define (placeholder-set! placeholder value)
@ -36,11 +33,13 @@
(cond (queue (cond (queue
(set-placeholder-value! placeholder value) (set-placeholder-value! placeholder value)
(set-placeholder-queue! placeholder #f) (set-placeholder-queue! placeholder #f)
(do ((waiters '() (cons (dequeue-thread! queue) (let loop ((waiters '()))
waiters))) (cond
((thread-queue-empty? queue) ((maybe-dequeue-thread! queue)
waiters))) => (lambda (thread)
(else #f))))))) (loop (cons thread waiters))))
(else
waiters))))))))))
(if waiters (if waiters
(for-each make-ready waiters) (for-each make-ready waiters)
(if (not (eq? value (placeholder-value placeholder))) (if (not (eq? value (placeholder-value placeholder)))

View File

@ -26,9 +26,11 @@
; The procedures for manipulating queues. ; The procedures for manipulating queues.
(define (queue-empty? q) (define (queue-empty? q)
;; (debug-message "queue-empty?" (queue? q))
(null? (queue-head q))) (null? (queue-head q)))
(define (enqueue! q v) (define (enqueue! q v)
;; (debug-message "enqueue!" (queue? q))
(let ((p (cons v '()))) (let ((p (cons v '())))
(if (null? (queue-head q)) ;(queue-empty? q) (if (null? (queue-head q)) ;(queue-empty? q)
(set-queue-head! q p) (set-queue-head! q p)
@ -36,11 +38,13 @@
(set-queue-tail! q p))) (set-queue-tail! q p)))
(define (queue-front q) (define (queue-front q)
;; (debug-message "queue-front" (queue? q))
(if (queue-empty? q) (if (queue-empty? q)
(error "queue is empty" q) (error "queue is empty" q)
(car (queue-head q)))) (car (queue-head q))))
(define (dequeue! q) (define (dequeue! q)
;; (debug-message "dequeue!" (queue? q))
(let ((pair (queue-head q))) (let ((pair (queue-head q)))
(cond ((null? pair) ;(queue-empty? q) (cond ((null? pair) ;(queue-empty? q)
(error "empty queue" q)) (error "empty queue" q))
@ -52,7 +56,25 @@
(set-queue-tail! q '())) ; don't retain pointers (set-queue-tail! q '())) ; don't retain pointers
value))))) value)))))
; Same again, except that we return #F if the queue is empty.
; This is a simple way of avoiding a race condition if the queue is known
; not to contain #F.
(define (maybe-dequeue! q)
;; (debug-message "maybe-dequeue!" (queue? q))
(let ((pair (queue-head q)))
(cond ((null? pair) ;(queue-empty? q)
#f)
(else
(let ((value (car pair))
(next (cdr pair)))
(set-queue-head! q next)
(if (null? next)
(set-queue-tail! q '())) ; don't retain pointers
value)))))
(define (on-queue? v q) (define (on-queue? v q)
;; (debug-message "on-queue!" (queue? q))
(memq v (queue-head q))) (memq v (queue-head q)))
; This removes the first occurrence of V from Q. ; This removes the first occurrence of V from Q.
@ -61,6 +83,7 @@
(delete-from-queue-if! q (lambda (x) (eq? x v)))) (delete-from-queue-if! q (lambda (x) (eq? x v))))
(define (delete-from-queue-if! q pred) (define (delete-from-queue-if! q pred)
;; (debug-message "delete-from-queue-if!" (queue? q))
(let ((list (queue-head q))) (let ((list (queue-head q)))
(cond ((null? list) (cond ((null? list)
#f) #f)

View File

@ -152,7 +152,7 @@
; lazily generated list of this level's threads ; lazily generated list of this level's threads
(define (make-command-level repl-thunk repl-data dynamic-env levels throw) (define (make-command-level repl-thunk repl-data dynamic-env levels throw)
(let ((level (really-make-command-level (make-thread-queue) (let ((level (really-make-command-level (make-queue)
(make-counter) (make-counter)
dynamic-env dynamic-env
levels levels
@ -172,7 +172,7 @@
(let ((thread (make-thread thunk (command-level-dynamic-env level) id))) (let ((thread (make-thread thunk (command-level-dynamic-env level) id)))
(set-thread-scheduler! thread (command-thread)) (set-thread-scheduler! thread (command-thread))
(set-thread-data! thread level) (set-thread-data! thread level)
(enqueue-thread! (command-level-queue level) thread) (enqueue! (command-level-queue level) thread)
(increment-counter! (command-level-thread-counter level)) (increment-counter! (command-level-thread-counter level))
thread)) thread))
@ -294,12 +294,7 @@
(*out?* #f)) (*out?* #f))
(for-each (lambda (thread) (for-each (lambda (thread)
(if (thread-continuation thread) (if (thread-continuation thread)
(begin (terminate-level-thread thread level)))
(remove-thread-from-queues! thread)
(interrupt-thread thread
(lambda ignore
(terminate-current-thread)))
(enqueue-thread! queue thread))))
threads) threads)
(dynamic-wind (dynamic-wind
(lambda () (lambda ()
@ -313,6 +308,16 @@
(if (not (null? levels)) (if (not (null? levels))
(reset-command-input! (car levels)))))))) (reset-command-input! (car levels))))))))
; Put the thread on the runnable queue if it is not already there and then
; terminate it. Termination removes the thread from any blocking queues
; and interrupts with a throw that will run any pending dynamic-winds.
(define (terminate-level-thread thread level)
(let ((queue (command-level-queue level)))
(if (not (on-queue? thread queue))
(enqueue! queue thread))
(terminate-thread! thread)))
(define (reset-command-input! level) (define (reset-command-input! level)
(let ((repl (command-level-repl-thread level))) (let ((repl (command-level-repl-thread level)))
(if repl (if repl
@ -367,8 +372,7 @@
(error "non-command-level thread restarted on a command level" (error "non-command-level thread restarted on a command level"
thread)) thread))
((memq level levels) ((memq level levels)
(enqueue-thread! (command-level-queue level) (enqueue! (command-level-queue level) thread))
thread))
(else (else
(warn "dropping thread from exited command level" (warn "dropping thread from exited command level"
thread))) thread)))
@ -447,7 +451,7 @@
(if repl-thread (if repl-thread
(begin (begin
(set-command-level-repl-thread! level #f) (set-command-level-repl-thread! level #f)
(kill-thread! repl-thread))))) (terminate-level-thread repl-thread level)))))
((eq? token repl-data-token) ((eq? token repl-data-token)
(command-level-repl-data level)) (command-level-repl-data level))
((eq? token set-repl-data!-token) ((eq? token set-repl-data!-token)
@ -524,14 +528,10 @@
(define (kill-paused-thread! level) (define (kill-paused-thread! level)
(let ((paused (command-level-paused-thread level))) (let ((paused (command-level-paused-thread level)))
(if (not paused) (if paused
(error "level has no paused thread" level)) (begin
(if (eq? paused (command-level-repl-thread level)) (if (eq? paused (command-level-repl-thread level))
(spawn-repl-thread! level)) (spawn-repl-thread! level))
(interrupt-thread paused terminate-current-thread) (terminate-thread! paused) ; it's already running, so no enqueue
; (lambda ignore (set-command-level-paused-thread! level #f))
; (terminate-current-thread))) (warn "level has no paused thread" level))))
;(enqueue-thread! (command-level-queue level) paused)
(set-command-level-paused-thread! level #f)))

View File

@ -197,6 +197,7 @@
(export lock? (export lock?
make-lock make-lock
obtain-lock obtain-lock
obtain-lock-multiple
maybe-obtain-lock maybe-obtain-lock
release-lock release-lock
lock-owner-uid)) ;really should be internal lock-owner-uid)) ;really should be internal
@ -568,12 +569,10 @@
current-thread current-thread
make-thread-queue
thread-queue-empty?
enqueue-thread! enqueue-thread!
multiple-enqueue-thread! thread-queue-empty?
dequeue-thread! maybe-dequeue-thread!
remove-thread-from-queues! block-on-queue
event-pending? event-pending?
get-next-event! get-next-event!
@ -590,6 +589,7 @@
upcall propogate-upcall upcall propogate-upcall
interrupt-thread interrupt-thread
kill-thread! kill-thread!
terminate-thread!
wake-some-threads wake-some-threads
@ -609,8 +609,9 @@
decrement-counter!)) decrement-counter!))
(define-interface queues-interface (define-interface queues-interface
(export make-queue enqueue! dequeue! queue-empty? (export make-queue enqueue! dequeue! maybe-dequeue! queue-empty?
queue? queue->list queue-length delete-from-queue!)) queue? queue->list queue-front queue-length
delete-from-queue! on-queue?))
(define-interface exceptions-interface (define-interface exceptions-interface
(export define-exception-handler (export define-exception-handler

View File

@ -63,6 +63,7 @@
session-data session-data
define-record-types define-record-types
threads threads-internal threads threads-internal
queues
scheduler scheduler
interrupts interrupts
weak weak
@ -408,7 +409,7 @@
(define-structure placeholders placeholder-interface (define-structure placeholders placeholder-interface
(open scheme-level-1 define-record-types (open scheme-level-1 define-record-types
threads threads-internal threads threads-internal queues
interrupts interrupts
signals) signals)
(files (big placeholder)) (files (big placeholder))

View File

@ -224,7 +224,7 @@
(define-structures ((rts-sigevents rts-sigevents-interface) (define-structures ((rts-sigevents rts-sigevents-interface)
(rts-sigevents-internal rts-sigevents-internal-interface)) (rts-sigevents-internal rts-sigevents-internal-interface))
(open scheme-level-1 define-record-types (open scheme-level-1 define-record-types queues
threads threads-internal threads threads-internal
interrupts interrupts
architecture) architecture)
@ -236,7 +236,7 @@
(define-structures ((threads threads-interface) (define-structures ((threads threads-interface)
(threads-internal threads-internal-interface)) (threads-internal threads-internal-interface))
(open scheme-level-1 enumerated define-record-types queues (open scheme-level-1 enumerated define-record-types queues cells
interrupts interrupts
wind wind
fluids fluids
@ -258,6 +258,7 @@
(define-structure scheduler scheduler-interface (define-structure scheduler scheduler-interface
(open scheme-level-1 threads threads-internal locks (open scheme-level-1 threads threads-internal locks
enumerated enum-case enumerated enum-case
queues
debug-messages debug-messages
signals) ;error signals) ;error
(files (rts scheduler))) (files (rts scheduler)))
@ -267,6 +268,7 @@
scheme-exit-now scheme-exit-now
call-when-deadlocked!) call-when-deadlocked!)
(open scheme-level-1 threads threads-internal scheduler structure-refs (open scheme-level-1 threads threads-internal scheduler structure-refs
queues
session-data session-data
signals ;error signals ;error
handle ;with-handler handle ;with-handler
@ -300,7 +302,8 @@
(unspecific)))))) (unspecific))))))
(define-structure queues queues-interface (define-structure queues queues-interface
(open scheme-level-1 define-record-types signals) (open scheme-level-1 define-record-types signals
debug-messages)
(files (big queue)) (files (big queue))
(optimize auto-integrate)) (optimize auto-integrate))
@ -314,7 +317,7 @@
; (optimize auto-integrate)) ; (optimize auto-integrate))
(define-structure locks locks-interface (define-structure locks locks-interface
(open scheme-level-1 define-record-types interrupts threads threads-internal) (open scheme-level-1 define-record-types queues interrupts threads threads-internal)
(optimize auto-integrate) (optimize auto-integrate)
(files (rts lock))) (files (rts lock)))

View File

@ -23,7 +23,7 @@
(if queue (if queue
(begin (begin
(decrement-channel-wait-count!) (decrement-channel-wait-count!)
(make-ready (dequeue-thread! queue) status)) (make-ready (maybe-dequeue-thread! queue) status))
(debug-message "Warning: dropping ignored channel i/o result {Channel " (debug-message "Warning: dropping ignored channel i/o result {Channel "
(channel-os-index channel) (channel-os-index channel)
" " " "
@ -50,7 +50,7 @@
(add-channel-wait-queue! channel queue) (add-channel-wait-queue! channel queue)
(warn "channel has two pending operations" channel) (warn "channel has two pending operations" channel)
(terminate-current-thread)) (terminate-current-thread))
(let ((queue (make-thread-queue))) (let ((queue (make-queue)))
(increment-channel-wait-count!) (increment-channel-wait-count!)
(enqueue-thread! queue (current-thread)) (enqueue-thread! queue (current-thread))
(add-channel-wait-queue! channel queue) (add-channel-wait-queue! channel queue)
@ -74,7 +74,7 @@
(define (steal-channel! channel owner) (define (steal-channel! channel owner)
(let ((queue (fetch-channel-wait-queue! channel))) (let ((queue (fetch-channel-wait-queue! channel)))
(if queue (if queue
(let ((thread (dequeue-thread! queue))) (let ((thread (maybe-dequeue-thread! queue)))
(cond ((eq? thread owner) (cond ((eq? thread owner)
(decrement-channel-wait-count!) (decrement-channel-wait-count!)
(channel-abort channel)) (channel-abort channel))
@ -156,6 +156,7 @@
(thread-queue-empty? queue)) (thread-queue-empty? queue))
#f #f
queue))) queue)))

View File

@ -20,15 +20,13 @@
(define (make-lock) (define (make-lock)
(let ((uid *lock-uid*)) (let ((uid *lock-uid*))
(set! *lock-uid* (+ uid 1)) (set! *lock-uid* (+ uid 1))
(really-make-lock #f (make-thread-queue) uid))) (really-make-lock #f (make-queue) uid)))
(define (obtain-lock lock) (define (obtain-lock lock)
(with-interrupts-inhibited (with-interrupts-inhibited
(lambda () (lambda ()
(if (lock-owner-uid lock) (if (lock-owner-uid lock)
(begin (block-on-queue (lock-queue lock))
(enqueue-thread! (lock-queue lock) (current-thread))
(block))
(set-lock-owner-uid! lock (thread-uid (current-thread))))))) (set-lock-owner-uid! lock (thread-uid (current-thread)))))))
(define (maybe-obtain-lock lock) (define (maybe-obtain-lock lock)
@ -40,17 +38,34 @@
(set-lock-owner-uid! lock (thread-uid (current-thread))) (set-lock-owner-uid! lock (thread-uid (current-thread)))
#t))))) #t)))))
(define (obtain-lock-multiple . all-locks)
(with-interrupts-inhibited
(lambda ()
(let loop ((locks all-locks))
(cond
((null? locks)
(for-each (lambda (lock)
(enqueue-thread! (lock-queue lock) (current-thread)))
all-locks)
(block))
((lock-owner-uid (car locks))
(loop (cdr locks)))
(else
(set-lock-owner-uid! (car locks)
(thread-uid (current-thread)))))))))
; Returns #t if the lock has no new owner. ; Returns #t if the lock has no new owner.
(define (release-lock lock) (define (release-lock lock)
(with-interrupts-inhibited (with-interrupts-inhibited
(lambda () (lambda ()
(let ((queue (lock-queue lock))) (let ((queue (lock-queue lock)))
(if (thread-queue-empty? queue) (cond
(begin ((maybe-dequeue-thread! queue)
(set-lock-owner-uid! lock #f) => (lambda (next)
#t) (set-lock-owner-uid! lock (thread-uid next))
(let ((next (dequeue-thread! queue))) (make-ready next)
(set-lock-owner-uid! lock (thread-uid next)) #f))
(make-ready next) (else
#f)))))) (set-lock-owner-uid! lock #f)
#t))))))

View File

@ -25,14 +25,14 @@
; are handled specially. The only upcall is for aborting execution. ; are handled specially. The only upcall is for aborting execution.
(define (make-root-event-handler thunk quantum abort) (define (make-root-event-handler thunk quantum abort)
(let ((runnable (make-thread-queue)) (let ((runnable (make-queue))
(thread-count (make-counter)) (thread-count (make-counter))
(safe-dynamic-env (with-handler root-handler get-dynamic-env)) (safe-dynamic-env (with-handler root-handler get-dynamic-env))
(thread (make-thread thunk (thread (make-thread thunk
(get-dynamic-env) (get-dynamic-env)
'scheduler-initial-thread))) 'scheduler-initial-thread)))
(increment-counter! thread-count) (increment-counter! thread-count)
(enqueue-thread! runnable thread) (enqueue! runnable thread)
(round-robin-event-handler (round-robin-event-handler
runnable quantum safe-dynamic-env thread-count runnable quantum safe-dynamic-env thread-count
(lambda args #f) ; we handle no events (lambda args #f) ; we handle no events

View File

@ -74,7 +74,7 @@
(decrement-counter! thread-count) (decrement-counter! thread-count)
(next-thread)) (next-thread))
((out-of-time) ((out-of-time)
(enqueue-thread! runnable thread) (enqueue! runnable thread)
(next-thread)) (next-thread))
;; the thread keeps running ;; the thread keeps running
@ -94,13 +94,13 @@
(or (event-handler event event-data) (or (event-handler event event-data)
(enum-case event-type event (enum-case event-type event
((runnable) ((runnable)
(enqueue-thread! runnable (car event-data))) (enqueue! runnable (car event-data)))
((spawned) ((spawned)
(increment-counter! thread-count) (increment-counter! thread-count)
(enqueue-thread! runnable (enqueue! runnable
(make-thread (car event-data) (make-thread (car event-data)
dynamic-env dynamic-env
(cadr event-data)))) (cadr event-data))))
((narrowed) ((narrowed)
(handle-narrow-event quantum dynamic-env event-data)) (handle-narrow-event quantum dynamic-env event-data))
((no-event) ((no-event)
@ -112,7 +112,7 @@
event-handler))))) event-handler)))))
(define (next-thread) (define (next-thread)
(if (thread-queue-empty? runnable) (if (queue-empty? runnable)
(call-with-values (call-with-values
get-next-event! get-next-event!
(lambda (event . data) (lambda (event . data)
@ -123,7 +123,7 @@
(next-thread)) (next-thread))
(else (else
(values #f 0))))) ; scheduler quits (values #f 0))))) ; scheduler quits
(values (dequeue-thread! runnable) (values (dequeue! runnable)
quantum))) quantum)))
thread-event-handler) thread-event-handler)
@ -134,13 +134,13 @@
(obtain-lock lock) (obtain-lock lock)
(spawn (spawn
(lambda () (lambda ()
(let ((runnable (make-thread-queue)) (let ((runnable (make-queue))
(thread (make-thread (car event-data) (thread (make-thread (car event-data)
dynamic-env dynamic-env
(cadr event-data))) (cadr event-data)))
(thread-count (make-counter))) (thread-count (make-counter)))
(enqueue-thread! runnable thread) (enqueue! runnable thread)
(increment-counter! thread-count) (increment-counter! thread-count)
(run-threads (run-threads

View File

@ -30,8 +30,7 @@
(if (type-in-set? (sigevent-type sigevent) set) (if (type-in-set? (sigevent-type sigevent) set)
sigevent sigevent
(lp sigevent)) (lp sigevent))
(begin (enqueue-thread! sigevent-thread-queue (current-thread)) (begin (block-on-queue sigevent-thread-queue)
(block)
(lp pre-sigevent)))))))) (lp pre-sigevent))))))))
; same as above, but don't block ; same as above, but don't block
@ -53,7 +52,7 @@
(lambda () (lambda ()
(set-sigevent-next! *most-recent-sigevent* (make-sigevent type)) (set-sigevent-next! *most-recent-sigevent* (make-sigevent type))
(set! *most-recent-sigevent* (sigevent-next *most-recent-sigevent*)) (set! *most-recent-sigevent* (sigevent-next *most-recent-sigevent*))
(do ((waiters '() (cons (dequeue-thread! sigevent-thread-queue) (do ((waiters '() (cons (maybe-dequeue-thread! sigevent-thread-queue)
waiters))) waiters)))
((thread-queue-empty? sigevent-thread-queue) ((thread-queue-empty? sigevent-thread-queue)
waiters)))))) waiters))))))
@ -64,7 +63,7 @@
(not (thread-queue-empty? sigevent-thread-queue))) (not (thread-queue-empty? sigevent-thread-queue)))
(define (initialize-sigevents!) (define (initialize-sigevents!)
(set! sigevent-thread-queue (make-thread-queue)) (set! sigevent-thread-queue (make-queue))
(set-interrupt-handler! (enum interrupt os-signal) (set-interrupt-handler! (enum interrupt os-signal)
(lambda (type enabled-interrupts) (lambda (type enabled-interrupts)
; type is already set in the unix signal handler ; type is already set in the unix signal handler

View File

@ -7,12 +7,12 @@
(cond ((not n) (cond ((not n)
(call-error "wrong type argument" sleep user-n)) (call-error "wrong type argument" sleep user-n))
((< 0 n) ((< 0 n)
(let ((queue (make-thread-queue))) ; only one entry, but it must be a queue (let ((cell (make-cell (current-thread))))
(disable-interrupts!) (disable-interrupts!)
(enqueue-thread! queue (current-thread)) (set-thread-cell! (current-thread) cell)
(set! *dozers* (set! *dozers*
(insert (cons (+ (real-time) n) (insert (cons (+ (real-time) n)
queue) cell)
*dozers* *dozers*
(lambda (frob1 frob2) (lambda (frob1 frob2)
(< (car frob1) (car frob2))))) (< (car frob1) (car frob2)))))
@ -29,7 +29,7 @@
#f)) #f))
#f)) #f))
(define *dozers* '()) ; List of (wakeup-time . queue) (define *dozers* '()) ; List of (wakeup-time . cell)
(define (insert x l <) (define (insert x l <)
(cond ((null? l) (list x)) (cond ((null? l) (list x))
@ -50,12 +50,13 @@
(begin (begin
(set! *dozers* '()) (set! *dozers* '())
(values woke? #f)) (values woke? #f))
(let ((next (car dozers))) (let* ((next (car dozers))
(cond ((thread-queue-empty? (cdr next)) (thread (cell-ref (cdr next))))
(cond ((not thread)
(loop (cdr dozers) woke?)) (loop (cdr dozers) woke?))
((< time (car next)) ((< time (car next))
(set! *dozers* dozers) (set! *dozers* dozers)
(values woke? (- (car next) time))) (values woke? (- (car next) time)))
(else (else
(make-ready (dequeue-thread! (cdr next))) (make-ready thread)
(loop (cdr dozers) #t))))))))) (loop (cdr dozers) #t)))))))))

View File

@ -12,7 +12,7 @@
; saved interrupt mask ; saved interrupt mask
; scheduler, which is the thread that RUNs this one ; scheduler, which is the thread that RUNs this one
; remaining time in clock ticks ('waiting = waiting for events) ; remaining time in clock ticks ('waiting = waiting for events)
; queue that is holding this thread, if any ; cell that is holding this thread, if any
; arguments waiting to be passed to the thread when it is next run ; arguments waiting to be passed to the thread when it is next run
; dynamic environment ; dynamic environment
; dynamic point ; dynamic point
@ -41,7 +41,7 @@
(define-record-type thread :thread (define-record-type thread :thread
(really-make-thread dynamic-env dynamic-point cell-env (really-make-thread dynamic-env dynamic-point cell-env
continuation scheduler continuation scheduler
queues arguments cell arguments
events current-task uid name) events current-task uid name)
thread? thread?
(dynamic-env thread-dynamic-env) ;Must be first! (See fluid.scm) (dynamic-env thread-dynamic-env) ;Must be first! (See fluid.scm)
@ -49,7 +49,7 @@
;Must be second! (See fluid.scm) ;Must be second! (See fluid.scm)
(cell-env thread-cell-env) ;Must be fourth! (See thread-env.scm) (cell-env thread-cell-env) ;Must be fourth! (See thread-env.scm)
(continuation thread-continuation set-thread-continuation!) (continuation thread-continuation set-thread-continuation!)
(queues thread-queues set-thread-queues!) (cell thread-cell set-thread-cell!)
(arguments thread-arguments set-thread-arguments!) (arguments thread-arguments set-thread-arguments!)
(time thread-time set-thread-time!) (time thread-time set-thread-time!)
(scheduler thread-scheduler set-thread-scheduler!) (scheduler thread-scheduler set-thread-scheduler!)
@ -77,7 +77,7 @@
(thunk->continuation (thunk->continuation
(thread-top-level thunk)) (thread-top-level thunk))
(current-thread) ; scheduler (current-thread) ; scheduler
#f ; queue #f ; cell
'() ; arguments '() ; arguments
#f ; events #f ; events
#f ; current-task #f ; current-task
@ -180,32 +180,31 @@
; Rename the queue operations as thread-specific ones (both for clarity ; Rename the queue operations as thread-specific ones (both for clarity
; and because we will want to use priority queues in the future). ; and because we will want to use priority queues in the future).
(define make-thread-queue make-queue)
(define thread-queue-empty? queue-empty?)
(define (enqueue-thread! queue thread) (define (enqueue-thread! queue thread)
(if (thread-queues thread) (let ((cell (make-cell thread)))
(error "enqueued thread being added to another queue" thread queue)) (enqueue! queue cell)
(set-thread-queues! thread (list queue)) (set-thread-cell! thread cell)))
(enqueue! queue thread))
(define (multiple-enqueue-thread! queues thread) (define (maybe-dequeue-thread! queue)
(if (thread-queues thread) (let loop ()
(error "enqueued thread being added to another queue" thread queues)) (let ((cell (maybe-dequeue! queue)))
(set-thread-queues! thread queues) (if cell
(for-each (lambda (q) (enqueue! q thread)) queues)) (or (cell-ref cell)
(loop))
#f))))
(define (dequeue-thread! queue) ; Look for a non-empty cell.
(let ((thread (dequeue! queue)))
(for-each (lambda (q) (delete-from-queue! q thread)) (thread-queues thread)) (define (thread-queue-empty? queue)
(set-thread-queues! thread #f) (let loop ()
thread)) (cond ((queue-empty? queue)
#t)
((cell-ref (queue-front queue))
#f)
(else
(dequeue! queue)
(loop)))))
(define (remove-thread-from-queues! thread)
(if (thread-queues thread)
(begin
(for-each (lambda (q) (delete-from-queue! q thread)) (thread-queues thread))
(set-thread-queues! thread #f))))
;---------------- ;----------------
(define current-thread (structure-ref primitives current-thread)) (define current-thread (structure-ref primitives current-thread))
@ -257,13 +256,9 @@
((not (eq? (thread-scheduler thread) scheduler)) ((not (eq? (thread-scheduler thread) scheduler))
(enable-interrupts!) (enable-interrupts!)
(error "thread run by wrong scheduler" thread scheduler)) (error "thread run by wrong scheduler" thread scheduler))
((thread-queues thread) ((thread-cell thread)
(enable-interrupts!) (enable-interrupts!)
(apply debug-message (list "thread run while still on a queue " (error "thread run while still blocked" thread))
(thread-uid thread)
(thread-name thread)
(thread-queues thread)))
(error "thread run while still on a queue" thread))
((and (thread-current-task thread) ((and (thread-current-task thread)
(not (null? (thread-arguments thread)))) (not (null? (thread-arguments thread))))
(enable-interrupts!) (enable-interrupts!)
@ -443,6 +438,12 @@
(define (relinquish-timeslice) (define (relinquish-timeslice)
(suspend (enum event-type out-of-time) '())) (suspend (enum event-type out-of-time) '()))
; Utility procedure for the common case of blocking on a queue.
(define (block-on-queue queue)
(enqueue-thread! queue (current-thread))
(block))
; Send the upcall to the current scheduler and check the return value(s) ; Send the upcall to the current scheduler and check the return value(s)
; to see if it was handled properly. ; to see if it was handled properly.
@ -465,6 +466,13 @@
(lambda ignored (lambda ignored
(exit (enum event-type killed) '())))) (exit (enum event-type killed) '()))))
; Also ends the thread, but lets it run any pending dynamic-winds.
(define (terminate-thread! thread)
(let ((interrupts (set-enabled-interrupts! no-interrupts)))
(clear-thread-cell! thread)
(interrupt-thread thread terminate-current-thread)))
;---------------- ;----------------
; Make THREAD execute PROC the next time it is run. The thread's own ; Make THREAD execute PROC the next time it is run. The thread's own
; continuation is passed whatever PROC returns. ; continuation is passed whatever PROC returns.
@ -596,10 +604,7 @@
; Enqueue a RUNNABLE for THREAD's scheduler. ; Enqueue a RUNNABLE for THREAD's scheduler.
(define (make-ready thread . args) (define (make-ready thread . args)
(if (thread-queues thread) (clear-thread-cell! thread)
(error "trying to schedule a queued thread" thread))
; (if (not (null? (thread-arguments thread)))
; (error "trying to replace thread arguments"))
(set-thread-arguments! thread args) (set-thread-arguments! thread args)
(if (thread-scheduler thread) (if (thread-scheduler thread)
(schedule-event (thread-scheduler thread) (schedule-event (thread-scheduler thread)
@ -607,6 +612,13 @@
thread) thread)
(error "MAKE-READY thread has no scheduler" thread))) (error "MAKE-READY thread has no scheduler" thread)))
(define (clear-thread-cell! thread)
(let ((cell (thread-cell thread)))
(if cell
(begin
(set-thread-cell! thread #f)
(cell-set! cell #f)))))
;---------------- ;----------------
(define (schedule-interrupt! time) (define (schedule-interrupt! time)

View File

@ -292,7 +292,7 @@
usual-resumer ; usual-resumer usual-resumer ; usual-resumer
environments ; with-interaction-environment environments ; with-interaction-environment
fluids-internal ; JMG: get-dynamic-env fluids-internal ; JMG: get-dynamic-env
threads threads-internal scheduler threads threads-internal queues scheduler
structure-refs structure-refs
scsh-utilities scsh-utilities
interrupts interrupts

View File

@ -65,7 +65,7 @@
(lambda () (lambda ()
(let ((dynamic-env (get-dynamic-env)) (let ((dynamic-env (get-dynamic-env))
(*result* 4711)) (*result* 4711))
(let ((runnable (make-thread-queue)) (let ((runnable (make-queue))
(thread (make-thread (lambda () (thread (make-thread (lambda ()
(set! *result* (set! *result*
(start (command-line)))) (start (command-line))))
@ -73,7 +73,7 @@
'scsh-initial-thread)) 'scsh-initial-thread))
(thread-count (make-counter))) (thread-count (make-counter)))
(enqueue-thread! runnable thread) (enqueue! runnable thread)
(increment-counter! thread-count) (increment-counter! thread-count)
(run-threads (run-threads

View File

@ -117,12 +117,7 @@
(lambda () #t) (lambda () #t)
thunk2 thunk2
(lambda () (lambda ()
(savely-kill-thread! (placeholder-value thread)))))) (terminate-thread! (placeholder-value thread))))))
(define (savely-kill-thread! thread)
(remove-thread-from-queues! thread)
(kill-thread! thread)
(make-ready thread))
(define (obtain-all-or-none . locks) (define (obtain-all-or-none . locks)
(let lp ((obtained '()) (needed locks)) (let lp ((obtained '()) (needed locks))