Add rough, but fairly well-debugged implementation of many CML

primitives.
This commit is contained in:
Mike Sperber 2003-05-12 07:38:33 +00:00
parent 13d95988e4
commit 91d2bb15c8
7 changed files with 1126 additions and 0 deletions

38
cml/async-channels.scm Normal file
View File

@ -0,0 +1,38 @@
(define-record-type :async-channel
(really-make-async-channel in-channel out-channel)
async-channel?
(in-channel async-channel-in-channel)
(out-channel async-channel-out-channel))
(define (make-async-channel)
(let ((in-channel (make-channel))
(out-channel (make-channel)))
(spawn
(lambda ()
(let ((queue (make-queue)))
(let loop ()
(if (queue-empty? queue)
(begin
(enqueue! queue (receive in-channel))
(loop))
(select
(list
(wrap (receive-rv in-channel)
(lambda (message)
(enqueue! queue message)
(loop)))
(wrap (send-rv out-channel (queue-front queue))
(lambda (ignore)
(dequeue! queue)
(loop))))))))))
(really-make-async-channel in-channel
out-channel)))
(define (send-async channel message)
(send (async-channel-in-channel channel) message))
(define (receive-async-rv channel)
(receive-rv (async-channel-out-channel channel)))
(define (receive-async channel)
(sync (receive-async-rv channel)))

100
cml/channel.scm Normal file
View File

@ -0,0 +1,100 @@
(define-record-type :channel
(really-make-channel priority in out)
channel?
(priority channel-priority set-channel-priority!)
;; queue of trans-id * #f
(in channel-in)
;; queue of trans-id * message
(out channel-out))
(define-record-type :q-item
(make-q-item trans-id message cleanup-thunk wrap-proc)
q-item?
(trans-id q-item-trans-id)
(message q-item-message)
(cleanup-thunk q-item-cleanup-thunk)
(wrap-proc q-item-wrap-proc))
(define (make-channel)
(really-make-channel 1 (make-queue) (make-queue)))
(define (channel=? channel-1 channel-2)
(eq? channel-1 channel-2))
(define (clean-and-enqueue! queue value)
(clean-queue-head! queue)
(enqueue! queue value))
(define (clean-and-dequeue! queue)
(let loop ()
(if (queue-empty? queue)
#f
(let ((front (dequeue! queue)))
(if (trans-id-cancelled? (q-item-trans-id front))
(loop)
front)))))
(define (clean-queue-head! queue)
(let loop ()
(if (not (queue-empty? queue))
(let ((front (queue-front queue)))
(if (trans-id-cancelled? (q-item-trans-id front))
(begin
(dequeue! queue)
(loop)))))))
(define (send-rv channel message)
(make-base
(lambda ()
(let ((in (channel-in channel)))
(clean-queue-head! in)
(if (queue-empty? in)
(make-blocked (lambda (trans-id cleanup-thunk wrap-proc)
(clean-and-enqueue! (channel-out channel)
(make-q-item trans-id
message
cleanup-thunk
wrap-proc))))
(let ((priority (channel-priority channel)))
(set-channel-priority! channel (+ 1 priority))
(make-enabled
priority
(lambda ()
(let ((q-item (dequeue! in)))
(set-channel-priority! channel 1)
((q-item-cleanup-thunk q-item))
(cr-trans-id-wakeup (q-item-trans-id q-item)
(cons message
(q-item-wrap-proc q-item)))
(unspecific))))))))))
(define (send channel message)
(sync (send-rv channel message)))
(define (receive-rv channel)
(make-base
(lambda ()
(let ((out (channel-out channel)))
(clean-queue-head! out)
(if (queue-empty? out)
(make-blocked (lambda (trans-id cleanup-thunk wrap-proc)
(clean-and-enqueue! (channel-in channel)
(make-q-item trans-id
#f
cleanup-thunk
wrap-proc))))
(let ((priority (channel-priority channel)))
(set-channel-priority! channel (+ 1 priority))
(make-enabled
priority
(lambda ()
(let ((q-item (dequeue! out)))
(set-channel-priority! channel 1)
((q-item-cleanup-thunk q-item))
(cr-trans-id-wakeup (q-item-trans-id q-item)
(cons (unspecific)
(q-item-wrap-proc q-item)))
(q-item-message q-item))))))))))
(define (receive channel)
(sync (receive-rv channel)))

102
cml/jar.scm Normal file
View File

@ -0,0 +1,102 @@
; Jars (multiple-assignment cells for use with threads)
; these are equivalent to ID-90 M-structures
(define-record-type :jar
(really-make-jar priority queue value id)
jar?
(priority jar-priority set-jar-priority!)
(queue jar-queue)
(value jar-value set-jar-value!)
(id jar-id))
(define the-empty-jar-value (list 'empty-jar))
(define (empty-jar-value? thing)
(eq? thing the-empty-jar-value))
(define-record-discloser :jar
(lambda (jar)
(cons 'jar
(if (jar-id jar)
(list (jar-id jar))
'()))))
(define-record-type :q-item
(make-q-item trans-id cleanup-thunk wrap-proc)
q-item?
(trans-id q-item-trans-id)
(cleanup-thunk q-item-cleanup-thunk)
(wrap-proc q-item-wrap-proc))
(define (clean-and-enqueue! queue value)
(clean-queue-head! queue)
(enqueue! queue value))
(define (clean-and-dequeue! queue)
(let loop ()
(if (queue-empty? queue)
#f
(let ((front (dequeue! queue)))
(if (trans-id-cancelled? (q-item-trans-id front))
(loop)
front)))))
(define (clean-queue-head! queue)
(let loop ()
(if (not (queue-empty? queue))
(let ((front (queue-front queue)))
(if (trans-id-cancelled? (q-item-trans-id front))
(begin
(dequeue! queue)
(loop)))))))
(define (make-jar . id-option)
(really-make-jar 0
(make-queue)
the-empty-jar-value
(if (null? id-option)
#f
(car id-option))))
(define (jar-take-rv jar)
(make-base
(lambda ()
(cond
((empty-jar-value? (jar-value jar))
(make-blocked
(lambda (trans-id cleanup-thunk wrap-proc)
(clean-and-enqueue! (jar-queue jar)
(make-q-item trans-id
cleanup-thunk
wrap-proc)))))
(else
(let ((priority (jar-priority jar)))
(set-jar-priority! jar (+ 1 priority))
(make-enabled
priority
(lambda ()
(let ((value (jar-value jar)))
(set-jar-value! jar the-empty-jar-value)
value)))))))))
(define (jar-put! jar value)
(enter-cr!)
(cond
((empty-jar-value? (jar-value jar))
(cond
((clean-and-dequeue! (jar-queue jar))
=> (lambda (q-item)
((q-item-cleanup-thunk q-item))
(cr-trans-id-wakeup (q-item-trans-id q-item)
(cons value
(q-item-wrap-proc q-item)))))
(else
(set-jar-value! jar value)))
(leave-cr!)
(unspecific))
(else
(leave-cr!)
(error "jar is already full" jar value))))
(define (jar-take jar)
(sync (jar-take-rv jar)))

96
cml/packages.scm Normal file
View File

@ -0,0 +1,96 @@
(define-interface trans-ids-interface
(export enter-cr! leave-cr!
leave-cr-and-block!
trans-id?
make-trans-id
cr-trans-id-wait cr-trans-id-wakeup cr-maybe-trans-id-wakeup
trans-id-thread-uid trans-id-cancelled?))
(define-interface rendezvous-interface
(export always-rv never-rv
guard with-nack choose wrap
sync
select))
(define-interface make-rendezvous-interface
(export make-blocked make-enabled make-base))
(define-interface rendezvous-channels-interface
(export make-channel
channel?
send-rv send
receive-rv receive))
(define-interface rendezvous-async-channels-interface
(export make-async-channel
async-channel?
send-async
receive-async-rv
receive-async))
(define-interface rendezvous-placeholders-interface
(export make-placeholder
placeholder?
placeholder-value
placeholder-set!
placeholder-value-rv))
(define-interface rendezvous-jars-interface
(export make-jar
jar?
jar-take
jar-put!
jar-take-rv))
(define-structure trans-ids trans-ids-interface
(open scheme
srfi-9 big-util
threads threads-internal interrupts
locks placeholders)
(files trans-id))
(define-structures ((rendezvous rendezvous-interface)
(make-rendezvous make-rendezvous-interface))
(open scheme
srfi-9 (subset define-record-types (define-record-discloser))
trans-ids
threads threads-internal
big-util
(subset util (unspecific)))
(files rendezvous))
(define-structure rendezvous-channels rendezvous-channels-interface
(open scheme
srfi-9
trans-ids rendezvous make-rendezvous
queues
big-util
(subset util (unspecific)))
(files channel))
(define-structure rendezvous-async-channels rendezvous-async-channels-interface
(open scheme
rendezvous
rendezvous-channels
threads
queues
srfi-9)
(files async-channels))
(define-structure rendezvous-placeholders rendezvous-placeholders-interface
(open scheme
srfi-9 (subset define-record-types (define-record-discloser))
trans-ids rendezvous make-rendezvous
queues
signals
(subset util (unspecific)))
(files placeholder))
(define-structure rendezvous-jars rendezvous-jars-interface
(open scheme
srfi-9 (subset define-record-types (define-record-discloser))
trans-ids rendezvous make-rendezvous
queues
signals
(subset util (unspecific)))
(files jar))

101
cml/placeholder.scm Normal file
View File

@ -0,0 +1,101 @@
; Placeholders (single-assignment cells for use with threads)
(define-record-type :placeholder
(really-make-placeholder priority queue value id)
placeholder?
(priority placeholder-priority set-placeholder-priority!)
(queue placeholder-queue set-placeholder-queue!)
(value placeholder-value-internal set-placeholder-value!)
(id placeholder-id))
(define-record-discloser :placeholder
(lambda (placeholder)
(cons 'placeholder
(if (placeholder-id placeholder)
(list (placeholder-id placeholder))
'()))))
(define-record-type :q-item
(make-q-item trans-id cleanup-thunk wrap-proc)
q-item?
(trans-id q-item-trans-id)
(cleanup-thunk q-item-cleanup-thunk)
(wrap-proc q-item-wrap-proc))
(define (clean-and-enqueue! queue value)
(clean-queue-head! queue)
(enqueue! queue value))
(define (clean-and-dequeue! queue)
(let loop ()
(if (queue-empty? queue)
#f
(let ((front (dequeue! queue)))
(if (trans-id-cancelled? (q-item-trans-id front))
(loop)
front)))))
(define (clean-queue-head! queue)
(let loop ()
(if (not (queue-empty? queue))
(let ((front (queue-front queue)))
(if (trans-id-cancelled? (q-item-trans-id front))
(begin
(dequeue! queue)
(loop)))))))
(define (make-placeholder . id-option)
(really-make-placeholder 0
(make-queue)
(unspecific)
(if (null? id-option)
#f
(car id-option))))
(define (placeholder-value-rv placeholder)
(make-base
(lambda ()
(cond
((placeholder-queue placeholder)
=> (lambda (queue)
(make-blocked
(lambda (trans-id cleanup-thunk wrap-proc)
(clean-and-enqueue! queue
(make-q-item trans-id
cleanup-thunk
wrap-proc))))))
(else
(let ((priority (placeholder-priority placeholder)))
(set-placeholder-priority! placeholder (+ 1 priority))
(make-enabled
priority
(lambda ()
(placeholder-value-internal placeholder)))))))))
(define (placeholder-set! placeholder value)
(enter-cr!)
(cond
((placeholder-queue placeholder)
=> (lambda (queue)
(set-placeholder-value! placeholder value)
(set-placeholder-queue! placeholder #f)
(let loop ()
(cond
((clean-and-dequeue! queue)
=> (lambda (q-item)
((q-item-cleanup-thunk q-item))
(cr-trans-id-wakeup (q-item-trans-id q-item)
(cons value
(q-item-wrap-proc q-item)))
(loop)))))
(leave-cr!)
(unspecific)))
(else
(leave-cr!)
(error "placeholder is already assigned" placeholder value))))
(define (placeholder-value placeholder)
(sync (placeholder-value-rv placeholder)))

619
cml/rendezvous.scm Normal file
View File

@ -0,0 +1,619 @@
(define-record-type :prim-rv
(really-make-prim-rv wrap-proc poll-thunk)
prim-rv?
(wrap-proc prim-rv-wrap-proc)
(poll-thunk prim-rv-poll-thunk))
(define (make-prim-rv poll-thunk)
(really-make-prim-rv identity poll-thunk))
(define-record-type :enabled
(make-enabled priority do-thunk)
enabled?
(priority enabled-priority)
(do-thunk enabled-do-thunk))
;; PROC is a procedure with two arguments:
;; a TRANS-ID and a WRAP-PROC.
;; TRANS-ID is the transaction ID of the blocked thread. WRAP-PROC is
;; the complete, composed-together chain of WRAP procedures of the
;; event.
;; The TRANS-ID should be fed, when it's woken up, a pair
;; consisting of a return value and a wrap-proc procedure.
(define-record-type :blocked
(make-blocked proc)
blocked?
(proc blocked-proc))
(define-record-type :base
(really-make-base prim-rvs)
base?
(prim-rvs base-prim-rvs))
(define (make-base poll-thunk)
(really-make-base (list (make-prim-rv poll-thunk))))
(define-record-type :choose
(make-choose rvs)
choose?
(rvs choose-rvs))
(define-record-type :guard
(make-guard thunk)
guard?
(thunk guard-thunk))
(define-record-type :with-nack
(make-nack proc)
nack?
(proc nack-proc))
;; Condition variables for internal use
(define-record-type :cvar
(really-make-cvar state)
cvar?
;; this can be one of the two below:
(state cvar-state set-cvar-state!))
(define-record-type :cvar-unset-state
(make-cvar-unset-state blocked)
cvar-unset-state?
;; this is a list of :CVAR-ITEM
(blocked cvar-unset-state-blocked set-cvar-unset-state-blocked!))
(define-record-type :cvar-item
(make-cvar-item trans-id cleanup-thunk wrap-proc)
cvar-item?
(trans-id cvar-item-trans-id)
(cleanup-thunk cvar-item-cleanup-thunk)
(wrap-proc cvar-item-wrap-proc))
(define-record-type :cvar-set-state
(make-cvar-set-state priority)
cvar-set-state?
(priority cvar-set-state-priority set-cvar-set-state-priority!))
(define (make-cvar)
(really-make-cvar (make-cvar-unset-state '())))
(define (cr-cvar-set! cvar)
(let ((state (cvar-state cvar)))
(cond
((cvar-unset-state? state)
(for-each (lambda (cvar-item)
((cvar-item-cleanup-thunk cvar-item))
(cr-maybe-trans-id-wakeup (cvar-item-trans-id cvar-item)
(cons (unspecific)
(cvar-item-wrap-proc cvar-item))))
(cvar-unset-state-blocked state))
(set-cvar-state! cvar (make-cvar-set-state 1)))
(else
(error "cvar already set")))))
(define (cvar-get-rv cvar)
(make-base
(lambda ()
(let ((state (cvar-state cvar)))
(cond
((cvar-set-state? state)
(let ((priority (cvar-set-state-priority state)))
(set-cvar-set-state-priority! state (+ 1 priority))
(make-enabled priority
(lambda ()
(set-cvar-set-state-priority! state 1)
(unspecific)))))
(else
(make-blocked
(lambda (trans-id cleanup-thunk wrap-proc)
(set-cvar-unset-state-blocked!
state
(cons (make-cvar-item trans-id cleanup-thunk wrap-proc)
(cvar-unset-state-blocked state)))))))))))
(define (always-rv value)
(make-base
(lambda ()
(make-enabled -1
(lambda ()
value)))))
(define (never-rv)
(really-make-base '()))
(define (guard rv)
(make-guard rv))
(define (with-nack rv)
(make-nack rv))
(define (gather-prim-rvs rev-rvs prim-rvs)
(cond
((null? rev-rvs) (really-make-base prim-rvs))
((not (base? (car rev-rvs)))
(if (null? prim-rvs)
(gather rev-rvs '())
(gather rev-rvs (list (really-make-base prim-rvs)))))
;; (car rev-rvs) is base
(else
(gather-prim-rvs (cdr rev-rvs)
(append (base-prim-rvs (car rev-rvs))
prim-rvs)))))
(define (gather rev-rvs rvs)
(cond
((not (null? rev-rvs))
(let ((rv (car rev-rvs)))
(cond
((choose? rv)
(gather (cdr rev-rvs) (append (choose-rvs rv) rvs)))
((and (base? rv)
(not (null? rvs))
(base? (car rvs)))
(gather (cdr rev-rvs)
(cons (really-make-base (append (base-prim-rvs rv)
(base-prim-rvs (car rvs))))
(cdr rvs))))
(else
(gather (cdr rev-rvs) (cons rv rvs))))))
((null? (cdr rvs)) (car rvs))
(else (make-choose rvs))))
(define (choose . rvs)
(gather-prim-rvs (reverse rvs) '()))
(define (compose f g)
(lambda (x)
(f (g x))))
(define (wrap-prim-rv prim-rv wrap-proc)
(really-make-prim-rv (compose wrap-proc
(prim-rv-wrap-proc prim-rv))
(prim-rv-poll-thunk prim-rv)))
(define (wrap rv wrap-proc)
(cond
((base? rv)
(really-make-base (map (lambda (prim-rv)
(wrap-prim-rv prim-rv wrap-proc))
(base-prim-rvs rv))))
((choose? rv)
(make-choose (map (lambda (rv)
(wrap rv wrap-proc))
(choose-rvs rv))))
((guard? rv)
(make-guard (lambda ()
(wrap ((guard-thunk rv)) wrap-proc))))
((nack? rv)
(make-nack (lambda (nack-rv)
(wrap ((nack-proc rv) nack-rv) wrap-proc))))))
(define-record-type :base-group
(really-make-base-group prim-rvs)
base-group?
(prim-rvs base-group-prim-rvs))
(define-record-discloser :base-group
(lambda (base-group)
(cons 'base-group
(base-group-prim-rvs base-group))))
(define-record-type :choose-group
(make-choose-group groups)
choose-group?
(groups choose-group-groups))
(define-record-discloser :choose-group
(lambda (choose-group)
(cons 'choose-group
(choose-group-groups choose-group))))
(define-record-type :nack-group
(make-nack-group cvar group)
nack-group?
(cvar nack-group-cvar)
(group nack-group-group))
(define-record-discloser :nack-group
(lambda (nack-group)
(list 'nack-group
(nack-group-group nack-group))))
(define (force-rv rv)
(cond
((base? rv)
(really-make-base-group (base-prim-rvs rv)))
(else
(really-force-rv rv))))
(define (force-prim-rvs rvs prim-rvs)
(if (null? rvs)
(really-make-base-group prim-rvs)
(let* ((rv (car rvs))
(group (really-force-rv rv)))
(cond
((base-group? group)
(force-prim-rvs (cdr rvs)
(append (base-group-prim-rvs group)
prim-rvs)))
((choose-group? group)
(force-rvs (cdr rvs)
(append (choose-group-groups group)
(list (really-make-base-group prim-rvs)))))
(else
(force-rvs (cdr rvs)
(list group (really-make-base-group prim-rvs))))))))
(define (force-rvs rvs groups)
(cond
((not (null? rvs))
(let* ((rv (car rvs))
(group (really-force-rv rv)))
(cond
((and (base-group? group)
(not (null? groups))
(base-group? (car groups)))
(force-rvs (cdr rvs)
(cons (really-make-base-group
(append (base-group-prim-rvs group)
(base-group-prim-rvs (car groups))))
(cdr groups))))
((choose-group? group)
(force-rvs (cdr rvs)
(append (choose-group-groups group)
groups)))
(else
(force-rvs (cdr rvs) (cons group groups))))))
((null? (cdr groups))
(car groups))
(else
(make-choose-group groups))))
;; this corresponds to force' in Reppy's implementation
(define (really-force-rv rv)
(cond
((guard? rv)
(really-force-rv ((guard-thunk rv))))
((nack? rv)
(let ((cvar (make-cvar)))
(make-nack-group cvar
(really-force-rv
((nack-proc rv)
(cvar-get-rv cvar))))))
((base? rv)
(really-make-base-group (base-prim-rvs rv)))
((choose? rv)
(force-prim-rvs (choose-rvs rv) '()))))
(define (sync-prim-rv prim-rv)
(let ((poll-thunk (prim-rv-poll-thunk prim-rv))
(wrap-proc (prim-rv-wrap-proc prim-rv)))
(enter-cr!)
(let ((status ((prim-rv-poll-thunk prim-rv))))
(cond
((enabled? status)
(let ((value ((enabled-do-thunk status))))
(leave-cr!)
(wrap-proc value)))
((blocked? status)
(let ((trans-id (make-trans-id)))
((blocked-proc status) trans-id values wrap-proc)
(let ((pair (cr-trans-id-wait trans-id)))
((cdr pair) (car pair)))))))))
(define (select-do-thunk priority+do-list n)
(cond
((null? (cdr priority+do-list))
(cdar priority+do-list))
(else
(let ((priority
(lambda (p)
(if (= p -1)
n
p))))
(let max ((rest priority+do-list)
(maximum 0)
(k 0) ; (length do-thunks)
(do-list '())) ; #### list of pairs do-thunk * wrap-proc
(cond
((not (null? rest))
(let* ((pair (car rest))
(p (priority (car pair)))
(stuff (cdr pair)))
(cond
((> p maximum)
(max (cdr rest) p 1 (list stuff)))
((= p maximum)
(max (cdr rest) maximum (+ 1 k) (cons stuff do-list)))
(else
(max (cdr rest) maximum k do-list)))))
((null? (cdr do-list))
(car do-list))
(else
;; List.nth(doFns, random k)
(car do-list))))))))
(define (sync-prim-rvs prim-rvs)
(cond
((null? prim-rvs) (block))
((null? (cdr prim-rvs)) (sync-prim-rv (car prim-rvs)))
(else
(let ()
(define (find-enabled prim-rvs block-procs wrap-procs)
(if (null? prim-rvs)
(let ((trans-id (make-trans-id)))
(for-each (lambda (block-proc wrap-proc)
(block-proc trans-id values wrap-proc))
block-procs wrap-procs)
(let ((pair (cr-trans-id-wait trans-id)))
((cdr pair) (car pair))))
(let* ((prim-rv (car prim-rvs))
(poll-thunk (prim-rv-poll-thunk prim-rv))
(wrap-proc (prim-rv-wrap-proc prim-rv))
(status (poll-thunk)))
(cond
((enabled? status)
(handle-enabled (cdr prim-rvs)
(list
(cons (enabled-priority status)
(cons (enabled-do-thunk status)
wrap-proc)))
1))
((blocked? status)
(find-enabled (cdr prim-rvs)
(cons (blocked-proc status)
block-procs)
(cons wrap-proc wrap-procs)))))))
(define (handle-enabled prim-rvs priority+do-list priority)
(if (null? prim-rvs)
(let* ((stuff (select-do-thunk priority+do-list priority))
(do-thunk (car stuff))
(wrap-proc (cdr stuff)))
(let ((value (do-thunk)))
(leave-cr!)
(wrap-proc value)))
(let* ((prim-rv (car prim-rvs))
(poll-thunk (prim-rv-poll-thunk prim-rv))
(wrap-proc (prim-rv-wrap-proc prim-rv))
(status (poll-thunk)))
(cond
((enabled? status)
(handle-enabled (cdr prim-rvs)
(cons (cons (enabled-priority status)
(cons (enabled-do-thunk status)
wrap-proc))
priority+do-list)
(+ 1 priority)))
(else
(handle-enabled (cdr prim-rvs)
priority+do-list
priority))))))
(enter-cr!)
(find-enabled prim-rvs '() '())))))
(define (sync rv)
(let ((group (force-rv rv)))
(cond
((base-group? group)
(sync-prim-rvs (base-group-prim-rvs group)))
(else
(sync-group group)))))
(define-record-type :ack-flag
(really-make-ack-flag acked?)
ack-flag?
(acked? flag-acked? set-flag-acked?!))
(define (make-ack-flag)
(really-make-ack-flag #f))
(define (ack-flag! ack-flag)
(set-flag-acked?! ack-flag #t))
(define-record-type :flag-set
(make-flag-set cvar ack-flags)
flag-set?
(cvar flag-set-cvar)
(ack-flags flag-set-ack-flags))
(define (check-cvars! flag-sets)
(for-each check-cvar! flag-sets))
(define (check-cvar! flag-set)
(let loop ((ack-flags (flag-set-ack-flags flag-set)))
(cond
((null? ack-flags)
(cr-cvar-set! (flag-set-cvar flag-set)))
((flag-acked? (car ack-flags))
(values))
(else
(loop (cdr ack-flags))))))
;; this corresponds to syncOnGrp from Reppy's code
(define (sync-group group)
(call-with-values
(lambda () (collect-group group))
(lambda (prim-rv+ack-flag-list flag-sets)
(if (null? (cdr prim-rv+ack-flag-list))
(sync-prim-rv (caar prim-rv+ack-flag-list))
(really-sync-group prim-rv+ack-flag-list flag-sets)))))
;; This is analogous to SYNC-PRIM-RVS
(define (really-sync-group prim-rv+ack-flag-list flag-sets)
(define (find-enabled prim-rv+ack-flag-list
block-proc+ack-flag-list
wrap-procs)
(if (null? prim-rv+ack-flag-list)
(let ((trans-id (make-trans-id)))
(for-each (lambda (block-proc+ack-flag wrap-proc)
(let ((block-proc (car block-proc+ack-flag))
(ack-flag (cdr block-proc+ack-flag)))
(block-proc trans-id
(lambda ()
(ack-flag! ack-flag)
(check-cvars! flag-sets))
wrap-proc)))
block-proc+ack-flag-list wrap-procs)
(let ((pair (cr-trans-id-wait trans-id)))
((cdr pair) (car pair))))
(let* ((prim-rv (caar prim-rv+ack-flag-list))
(ack-flag (cdar prim-rv+ack-flag-list))
(poll-thunk (prim-rv-poll-thunk prim-rv))
(wrap-proc (prim-rv-wrap-proc prim-rv))
(status (poll-thunk)))
(cond
((enabled? status)
(handle-enabled (cdr prim-rv+ack-flag-list)
(list
(cons (enabled-priority status)
(cons (cons (enabled-do-thunk status) ack-flag)
wrap-proc)))
1))
((blocked? status)
(find-enabled (cdr prim-rv+ack-flag-list)
(cons (cons (blocked-proc status) ack-flag)
block-proc+ack-flag-list)
(cons wrap-proc wrap-procs)))))))
(define (handle-enabled prim-rv+ack-flag-list priority+do-list priority)
(if (null? prim-rv+ack-flag-list)
(let* ((stuff (select-do-thunk priority+do-list priority))
(more-stuff (car stuff))
(do-thunk (car more-stuff))
(ack-flag (cdr more-stuff))
(wrap-proc (cdr stuff)))
(ack-flag! ack-flag)
(check-cvars! flag-sets)
(let ((value (do-thunk)))
(leave-cr!)
(wrap-proc value)))
(let* ((prim-rv+ack-flag (car prim-rv+ack-flag-list))
(prim-rv (car prim-rv+ack-flag))
(ack-flag (cdr prim-rv+ack-flag))
(poll-thunk (prim-rv-poll-thunk prim-rv))
(wrap-proc (prim-rv-wrap-proc prim-rv))
(status (poll-thunk)))
(cond
((enabled? status)
(handle-enabled (cdr prim-rv+ack-flag-list)
(cons (cons (enabled-priority status)
(cons (cons (enabled-do-thunk status) ack-flag)
wrap-proc))
priority+do-list)
(+ 1 priority)))
(else
(handle-enabled (cdr prim-rv+ack-flag-list)
priority+do-list
priority))))))
(enter-cr!)
(find-enabled prim-rv+ack-flag-list '() '()))
(define (collect-group group)
(cond
((choose-group? group)
(gather-choose-group group))
(else
(gather-wrapped group '() '()))))
(define (gather-choose-group group)
(let ((ack-flag (make-ack-flag)))
(let gather ((group group)
(prim-rv+ack-flag-list '())
(flag-sets '()))
(cond
((base-group? group)
(let append ((prim-rvs (base-group-prim-rvs group))
(prim-rv+ack-flag-list prim-rv+ack-flag-list))
(if (null? prim-rvs)
(values prim-rv+ack-flag-list flag-sets)
(append (cdr prim-rvs)
(cons (cons (car prim-rvs) ack-flag)
prim-rv+ack-flag-list)))))
((choose-group? group)
;; fold-left
(let loop ((groups (choose-group-groups group))
(prim-rv+ack-flag-list prim-rv+ack-flag-list)
(flag-sets flag-sets))
(if (null? groups)
(values prim-rv+ack-flag-list flag-sets)
(call-with-values
(lambda ()
(gather (car groups)
prim-rv+ack-flag-list
flag-sets))
(lambda (prim-rv+ack-flag-list flag-sets)
(loop (cdr groups)
prim-rv+ack-flag-list
flag-sets))))))
((nack-group? group)
(gather-wrapped group prim-rv+ack-flag-list flag-sets))))))
(define (gather-wrapped group prim-rv+ack-flag-list flag-sets)
(call-with-values
(lambda ()
(let gather ((group group)
(prim-rv+ack-flag-list prim-rv+ack-flag-list)
(all-flags '())
(flag-sets flag-sets))
(cond
((base-group? group)
(let append ((prim-rvs (base-group-prim-rvs group))
(prim-rv+ack-flag-list prim-rv+ack-flag-list)
(all-flags all-flags))
(if (null? prim-rvs)
(values prim-rv+ack-flag-list
all-flags
flag-sets)
(let ((ack-flag (make-ack-flag)))
(append (cdr prim-rvs)
(cons (cons (car prim-rvs) ack-flag)
prim-rv+ack-flag-list)
(cons ack-flag all-flags))))))
((choose-group? group)
;; fold-left
(let loop ((groups (choose-group-groups group))
(prim-rv+ack-flag-list prim-rv+ack-flag-list)
(all-flags all-flags)
(flag-sets flag-sets))
(if (null? groups)
(values prim-rv+ack-flag-list
all-flags
flag-sets)
(call-with-values
(lambda ()
(gather (car groups)
prim-rv+ack-flag-list
all-flags
flag-sets))
(lambda (prim-rv+ack-flag-list all-flags flag-sets)
(loop (cdr groups)
prim-rv+ack-flag-list all-flags flag-sets))))))
((nack-group? group)
(call-with-values
(lambda ()
(gather (nack-group-group group)
prim-rv+ack-flag-list
'()
flag-sets))
(lambda (prim-rv+ack-flag-list all-flags-new flag-sets)
(values prim-rv+ack-flag-list
(append all-flags-new all-flags)
(cons (make-flag-set (nack-group-cvar group)
all-flags-new)
flag-sets))))))))
(lambda (prim-rv+ack-flag-list all-flags flag-sets)
(values prim-rv+ack-flag-list flag-sets))))
(define (select . rvs)
(sync (apply choose rvs)))

70
cml/trans-id.scm Normal file
View File

@ -0,0 +1,70 @@
(define *cr-lock* (make-lock))
(define *cr-interrupt-mask* #f)
(define (enter-cr!)
(let ((old-enabled (set-enabled-interrupts! no-interrupts)))
(if (= old-enabled no-interrupts)
(error "tried to enter critical region from critical region")
(set! *cr-interrupt-mask* old-enabled))))
(define (leave-cr!)
(set-enabled-interrupts! *cr-interrupt-mask*))
(define (leave-cr-and-block!)
(leave-cr!)
(block))
(define (in-cr?)
(let* ((old-enabled (set-enabled-interrupts! no-interrupts))
(yes? (= old-enabled no-interrupts)))
(set-enabled-interrupts! old-enabled)
yes?))
;; This replaces trans-id REF in Reppy's code
(define-record-type :trans-id
(really-make-trans-id maybe-thread-uid placeholder)
trans-id?
(maybe-thread-uid trans-id-maybe-thread-uid
set-trans-id-maybe-thread-uid!)
(placeholder trans-id-placeholder set-trans-id-placeholder!))
(define (make-trans-id)
(really-make-trans-id (thread-uid (current-thread))
(make-placeholder)))
;; this stuff needs to move into WAKEUP
(define (cr-trans-id-wait trans-id)
(if (not (in-cr?))
(error "not in critical region"))
(if (trans-id-cancelled? trans-id)
(error "wait on cancelled trans-id"))
(let ((placeholder (trans-id-placeholder trans-id)))
(leave-cr!)
(placeholder-value placeholder)))
(define (cr-trans-id-wakeup trans-id value)
(if (not (in-cr?))
(error "not in critical region"))
(if (trans-id-cancelled? trans-id)
(error "wakeup on cancelled trans-id"))
(let ((placeholder (trans-id-placeholder trans-id)))
(set-trans-id-maybe-thread-uid! trans-id #f)
(set-trans-id-placeholder! trans-id 'no-placeholder)
(placeholder-set! placeholder value)))
(define (cr-maybe-trans-id-wakeup trans-id value)
(if (not (in-cr?))
(error "not in critical region"))
(if (not (trans-id-cancelled? trans-id))
(cr-trans-id-wakeup trans-id value)))
(define (trans-id-cancelled? trans-id)
(not (trans-id-maybe-thread-uid trans-id)))
(define (trans-id-thread-uid trans-id)
(if (trans-id-cancelled? trans-id)
(error "trans-id cancelled"))
(trans-id-maybe-thread-uid trans-id))