sunterlib/s48/cml/jar.scm

103 lines
2.4 KiB
Scheme

; 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)))