; -*- Mode: Scheme; Syntax: Scheme; Package: Scheme; -*- ; Copyright (c) 1993, 1994 Richard Kelsey and Jonathan Rees. See file COPYING. ; This is file wind.scm. (Rhymes with "find," not "pinned.") ;;;; Dynamic-wind ; This is a version of dynamic-wind that tries to do "the right thing" ; in the presence of multiple threads of control. ; This definition of "the right thing" is due to Pavel Curtis, and is ; the one used in Scheme Xerox. It is very different from what you will ; find in, say, MIT Scheme. ; ; When we want to go to a new target state (e.g. on invoking a ; continuation), we ascend to the nearest common ancestor of the ; current state and the target state, executing the "out" (or ; "unwind") thunk for each state on the way; then we climb back down ; to the target state executing the "in" thunk for each state. Unlike ; the Hanson/Lamping algorithm, the tree of states is not altered in ; any way. ; ; Each thread starts out in the root state, but continuations capture ; the state where they're created. ; Dynamic-wind (define (dynamic-wind in body out) (in) (let ((results (let-dynamic-point (let ((here (get-dynamic-point))) (make-point (+ (point-depth here) 1) in out (get-dynamic-env) here)) (lambda () (call-with-values body list))))) (out) (apply values results))) ; call-with-current-continuation (define (call-with-current-continuation proc) (primitive-cwcc (lambda (cont) (let ((env (get-dynamic-env))) (proc (continuation->procedure cont env)))))) ;don't close over proc (define (continuation->procedure cont env) (lambda results (travel-to-point! (get-dynamic-point) (env-dynamic-point env)) (set-dynamic-env! env) (with-continuation cont (lambda () (apply values results))))) ; Point in state space = ; dynamic-env = dynamic environment for execution of the in and out thunks (define-record-type point :point (make-point depth in out dynamic-env parent) (depth point-depth) (in point-in) (out point-out) (dynamic-env point-dynamic-env) (parent point-parent)) (define root-point ;Shared among all state spaces (make-point 0 (lambda () (error "winding in to root!")) (lambda () (error "winding out of root!")) '() ;(empty-dynamic-env) ;Should never be seen #f)) (define $dynamic-point (make-fluid root-point)) (define (get-dynamic-point) (fluid $dynamic-point)) (define (env-dynamic-point env) (fluid-lookup env $dynamic-point)) (define (let-dynamic-point point thunk) (let-fluid $dynamic-point point thunk)) ; Go to a point in state space. This involves running out-thunks from ; the current point out to its common ancestor with the target, and ; then running in-thunks from the ancestor to the target. (define (travel-to-point! here target) (cond ((eq? here target) 'done) ((< (point-depth here) (point-depth target)) (travel-to-point! here (point-parent target)) (set-dynamic-env! (point-dynamic-env target)) ((point-in target))) (else (set-dynamic-env! (point-dynamic-env here)) ((point-out here)) (travel-to-point! (point-parent here) target)))) ; (put 'let-dynamic-point 'scheme-indent-hook 1)