#f)
(define (gc-finish start-value space-remaining)
+ ((ucode-primitive request-interrupts! 1) interrupt-bit/after-gc)
+ (hook/gc-finish start-value space-remaining))
+
+(define (abort-if-heap-low space-remaining)
(if (< space-remaining 4096)
(if gc-boot-loading?
(let ((console ((ucode-primitive tty-output-channel 0))))
(cmdl-message/active
(lambda (port)
port
- (with-gc-notification! #t gc-clean)))))))
- ((ucode-primitive request-interrupts! 1) interrupt-bit/after-gc)
- (hook/gc-finish start-value space-remaining))
+ (with-gc-notification! #t gc-clean))))))))
(define gc-boot-loading?)
(declare (usual-integrations))
\f
+(define (initialize-package!)
+ ;; This hook is run via hook/gc-finish and hook/gc-flip, with
+ ;; absolutely no interrupts(!).
+ (set! hook/record-statistic! signal-gc-events))
+
(define (toggle-gc-notification!)
- (set-fluid! hook/record-statistic!
- (let ((current (fluid hook/record-statistic!)))
- (cond ((eq? current gc-notification) default/record-statistic!)
- ((eq? current default/record-statistic!) gc-notification)
- (else (error "Can't grab GC statistics hook")))))
+ (if (registered-gc-event)
+ (deregister-gc-event)
+ (register-gc-event gc-notification))
unspecific)
(define (set-gc-notification! #!optional on?)
(let ((on? (if (default-object? on?) #T on?)))
- (set-fluid! hook/record-statistic!
- (let ((current (fluid hook/record-statistic!)))
- (if (or (eq? current gc-notification)
- (eq? current default/record-statistic!))
- (if on?
- gc-notification
- default/record-statistic!)
- (error "Can't grab GC statistics hook"))))
+ (if on?
+ (register-gc-event gc-notification)
+ (deregister-gc-event))
unspecific))
(define (with-gc-notification! notify? thunk)
- (let-fluid hook/record-statistic!
- (if notify? gc-notification default/record-statistic!)
- thunk))
+ (let ((outside))
+ (dynamic-wind
+ (lambda ()
+ (set! outside (registered-gc-event))
+ (if notify?
+ (register-gc-event gc-notification)
+ (deregister-gc-event)))
+ thunk
+ (lambda ()
+ (if outside
+ (register-gc-event outside)
+ (deregister-gc-event))
+ (set! outside)))))
(define (gc-notification statistic)
(print-statistic statistic (notification-output-port)))
(declare (usual-integrations))
(define (initialize-package!)
- (set! hook/record-statistic! (make-fluid default/record-statistic!))
+ (set! hook/record-statistic! #f)
(set! history-modes
`((NONE . ,none:install-history!)
(BOUNDED . ,bounded:install-history!)
(set! last-gc-start-clock start-clock)
(set! last-gc-end-clock end-clock)
(record-statistic! statistic)
- ((fluid hook/record-statistic!) statistic)))
+ (if hook/record-statistic!
+ (hook/record-statistic! statistic))))
(define (gc-statistic/meter stat)
(car (gc-statistic/timestamp stat)))
(define hook/record-statistic!)
-(define (default/record-statistic! statistic)
- statistic
- false)
-
(define (gctime)
(internal-time/ticks->seconds total-gc-time))
\f
;; REP Loops
(RUNTIME INTERRUPT-HANDLER)
(RUNTIME GC-STATISTICS)
+ (RUNTIME GC-NOTIFICATION)
(RUNTIME REP)
;; Debugging
(RUNTIME COMPILER-INFO)
hook/gc-start)
(export (runtime error-handler)
hook/hardware-trap)
+ (export (runtime thread)
+ abort-if-heap-low)
(initialization (initialize-package!)))
(define-package (runtime gc-daemons)
(define-package (runtime gc-notification)
(files "gcnote")
(parent (runtime))
+ (export (runtime thread)
+ signal-gc-events)
(export ()
gc-statistic->string
print-gc-statistics
set-gc-notification!
toggle-gc-notification!
- with-gc-notification!))
+ with-gc-notification!)
+ (initialization (initialize-package!)))
(define-package (runtime gc-statistics)
(files "gcstat")
gc-timestamp
gctime)
(export (runtime gc-notification)
- default/record-statistic!
hook/record-statistic!)
(initialization (initialize-package!)))
create-thread-continuation
current-thread
deregister-all-events
+ deregister-gc-event
deregister-io-descriptor-events
deregister-io-thread-event
deregister-subprocess-event
make-thread-mutex
other-running-threads?
permanently-register-io-thread-event
+ register-gc-event
register-io-thread-event
register-subprocess-event
register-timer-event
+ registered-gc-event
restart-thread
set-thread-timer-interval!
signal-thread-event
(maybe-signal-io-thread-events))))
(%maybe-toggle-thread-timer))))
\f
+;;;; GC Events
+
+(define gc-events '()) ;Weak alist of threads X events.
+
+(define (register-gc-event event)
+ (guarantee-procedure-of-arity event 1 'register-gc-event)
+ (without-interrupts
+ (lambda ()
+ (let* ((thread first-running-thread)
+ (entry (weak-assq thread gc-events)))
+ (if entry
+ (weak-set-cdr! entry event)
+ (set! gc-events (cons (weak-cons thread event) gc-events)))))))
+
+(define (deregister-gc-event)
+ (without-interrupts
+ (lambda ()
+ (let ((entry (weak-assq first-running-thread gc-events)))
+ (if entry
+ (set! gc-events (delq! entry gc-events)))))))
+
+(define (registered-gc-event)
+ (without-interrupts
+ (lambda ()
+ (let ((entry (weak-assq first-running-thread gc-events)))
+ (and entry (weak-cdr entry))))))
+
+(define (signal-gc-events statistic)
+ (without-interrupts
+ (lambda ()
+ (set! gc-events (filter! weak-car gc-events))
+ (for-each
+ (lambda (entry)
+ (let ((thread (weak-car entry)))
+ (if (and thread
+ (not (eq? 'DEAD (thread/execution-state thread))))
+ (let ((event (weak-cdr entry)))
+ (%signal-thread-event
+ thread (named-lambda (gc-event)
+ (abort-if-heap-low
+ (gc-statistic/heap-left statistic))
+ (event statistic)))))))
+ gc-events)
+ (%maybe-toggle-thread-timer))))
+
+(define (weak-assq obj alist)
+ (let loop ((alist alist))
+ (if (pair? alist)
+ (let* ((entry (car alist))
+ (key (weak-car entry)))
+ (if (eq? key obj)
+ entry
+ (loop (cdr alist))))
+ #f)))
+\f
;;;; Subprocess Events
(define subprocess-registrations)