119 lines
3.6 KiB
Scheme
119 lines
3.6 KiB
Scheme
; Copyright (c) 1993-1999 by Richard Kelsey and Jonathan Rees. See file COPYING.
|
|
|
|
|
|
; Interrupts
|
|
|
|
; Create and install a vector of interrupt handlers. We want this to happen
|
|
; as early as possible. All but the post-gc and keyboard interrupts raise an
|
|
; exception by default. We exit when a keyboard interrupt occurs. The default
|
|
; post-gc handler is defined below.
|
|
|
|
(define (initialize-interrupts! spawn-on-root thunk)
|
|
(primitive-cwcc
|
|
(lambda (exit)
|
|
(let ((handlers (make-vector interrupt-count 0)))
|
|
(do ((i 0 (+ i 1)))
|
|
((= i interrupt-count))
|
|
(vector-set! handlers
|
|
i
|
|
(lambda stuff
|
|
(apply signal (cons 'interrupt (cons i stuff))))))
|
|
(vector-set! handlers
|
|
(enum interrupt post-gc)
|
|
(post-gc-handler spawn-on-root))
|
|
(vector-set! handlers
|
|
(enum interrupt keyboard)
|
|
(lambda args
|
|
(with-continuation exit (lambda () -1))))
|
|
(set-interrupt-handlers! handlers)
|
|
(session-data-set! interrupt-handlers handlers))
|
|
(set-enabled-interrupts! all-interrupts)
|
|
(thunk))))
|
|
|
|
(define interrupt-handlers (make-session-data-slot! 0))
|
|
|
|
; Set an interrupt handler.
|
|
|
|
(define (set-interrupt-handler! interrupt handler)
|
|
(vector-set! (session-data-ref interrupt-handlers)
|
|
interrupt
|
|
handler))
|
|
|
|
(define no-interrupts 0)
|
|
|
|
(define all-interrupts
|
|
(- (arithmetic-shift 1 interrupt-count) 1))
|
|
|
|
(define (with-interrupts-inhibited thunk)
|
|
(with-interrupts no-interrupts thunk))
|
|
|
|
(define (with-interrupts-allowed thunk)
|
|
(with-interrupts all-interrupts thunk))
|
|
|
|
(define (disable-interrupts!)
|
|
(set-enabled-interrupts! no-interrupts))
|
|
|
|
(define (enable-interrupts!)
|
|
(set-enabled-interrupts! all-interrupts))
|
|
|
|
(define (with-interrupts interrupts thunk)
|
|
;; I might consider using dynamic-wind here, but (a) I'm worried
|
|
;; about the speed of thread switching (which uses this) and (b)
|
|
;; it's a pretty bad idea to throw in or out of one of these anyhow.
|
|
(let ((ei (set-enabled-interrupts! interrupts)))
|
|
(call-with-values thunk
|
|
(lambda results
|
|
(set-enabled-interrupts! ei)
|
|
(apply values results)))))
|
|
|
|
(define (enabled-interrupts) ;For debugging
|
|
(let ((e (set-enabled-interrupts! 0)))
|
|
(set-enabled-interrupts! e)
|
|
e))
|
|
|
|
;----------------
|
|
; Post-GC interrupts
|
|
|
|
(define *post-gc-procedures* '())
|
|
|
|
(define (call-after-gc! thunk)
|
|
(if (not (memq thunk *post-gc-procedures*))
|
|
(set! *post-gc-procedures* (cons thunk *post-gc-procedures*))))
|
|
|
|
(define (post-gc-handler spawn-on-root)
|
|
(lambda (finalizer-list enabled-interrupts)
|
|
(let ((space (memory-status (enum memory-status-option available) 0)))
|
|
(if (> (session-data-ref required-post-gc-space)
|
|
space)
|
|
(spawn-on-root
|
|
(lambda ()
|
|
((session-data-ref space-shortage-handler)
|
|
(session-data-ref required-post-gc-space)
|
|
space)))))
|
|
(spawn-on-root
|
|
(lambda ()
|
|
(for-each (lambda (p)
|
|
((cdr p) (car p)))
|
|
finalizer-list)
|
|
(for-each (lambda (thunk)
|
|
(thunk))
|
|
*post-gc-procedures*))
|
|
'post-gc-handler)
|
|
(set-enabled-interrupts! enabled-interrupts)))
|
|
|
|
; Notifying someone if an insufficient amount of memory is reclaimed by
|
|
; a garbage collection. The amount defaults to 10% of the heap.
|
|
|
|
(define required-post-gc-space (make-session-data-slot! 0))
|
|
|
|
(define space-shortage-handler
|
|
(make-session-data-slot! (lambda (required space) #f)))
|
|
|
|
(define (call-before-heap-overflow! handler . maybe-required-space)
|
|
(session-data-set! required-post-gc-space
|
|
(if (null? maybe-required-space)
|
|
(quotient (memory-status (enum memory-status-option heap-size) 0)
|
|
10)
|
|
(car maybe-required-space)))
|
|
(session-data-set! space-shortage-handler handler))
|