This repository has been archived on 2022-08-10. You can view files and clone it, but cannot push or open issues or pull requests.
chez-openbsd/ta6ob/examples/rabbit.ss
2022-08-09 23:28:25 +02:00

91 lines
3 KiB
Scheme

;;; rabbit
;;; The rabbit program highlights the use of continuations and
;;; timer interrupts to perform thread scheduling. The scheduler
;;; maintains a thread queue and operating system primitives for
;;; dispatching and thread creation. The queue is only visible
;;; to the operating system kernel and all accesses are performed
;;; with the timer off to prevent corruption.
;;; (thread exp) will create a thread out of exp and place it in
;;; the thread queue. you may do this for as many threads as
;;; you like. (dispatch) starts the threads going. If the
;;; thread queue ever becomes empty, dispatch exits. Threads
;;; may create other threads.
;;; The rabbit function creates a thread that spawns two offspring
;;; and dies. Each thread has a generation number associated with
;;; it. The generation number of each rabbit is one lower than that
;;; of it's parent; rabbits in generation 0 are sterile.
;;; load the queue datatype -- might need a fuller pathname
(load "queue.ss")
;;; swap-time determines the number of timer ticks in a time slice
(define swap-time
(make-parameter
100
(lambda (x)
(unless (and (integer? x) (positive? x))
(error 'swap-time "~s is not a positive integer" x))
x)))
(define dispatch #f)
(define thread #f)
(let ([pq (queue)])
(set! dispatch
(lambda ()
(unless (pq 'empty?)
; the thread queue holds continuations---grab one and invoke it
(let ([next (pq 'get)])
(set-timer (swap-time))
(next #f)))))
(set! thread
(lambda (thunk)
(call/cc
(lambda (return)
(call/cc
(lambda (k)
; turn off the timer while accessing the queue
(let ([time-left (set-timer 0)])
; put the thread on the queue
(pq 'put k)
(set-timer time-left)
; get out of here
(return #f))))
; the first time through we will return before getting
; here. the second time is when a thread is first
; dispatched from the thread queue.
(thunk)
(set-timer 0)
(dispatch)))))
(timer-interrupt-handler
(lambda ()
(printf "swapping~%")
(call/cc
(lambda (l)
; place the continuation of the interrupt on the queue
(pq 'put l)
(dispatch))))))
;;; *delay-max* gives the maximum random delay before a rabbit
;;; reaches child-bearing age.
(define *delay-max* 10000)
(define rabbit
(lambda (n)
(thread
(lambda ()
(printf "~s~%" n)
(unless (zero? n)
(do ([i (random *delay-max*) (1- i)]) ((zero? i)))
(rabbit (1- n))
(rabbit (1- n)))))))
;;; try:
;;; (rabbit 3)
;;; (rabbit 5)
;;; (dispatch)