#lang racket/base ;; Breaking the infinite tower of nested dataspaces, connecting to Racket at the fracture line. (provide current-ground-event-async-channel ground-send! ground-assert! ground-retract! signal-background-activity! extend-ground-boot! run-ground) (define-logger syndicate/ground) (require racket/async-channel) (require racket/set) (require racket/match) (require racket/list) (require "dataspace.rkt") (require "syntax.rkt") (define current-ground-event-async-channel (make-parameter #f)) (define *ground-boot-extensions* '()) (define (ground-enqueue! item) (async-channel-put (current-ground-event-async-channel) item)) (define (ground-send! body) (ground-enqueue! (lambda (ac) (enqueue-send! ac body)))) (define (ground-assert! assertion) (ground-enqueue! (lambda (ac) (adhoc-assert! ac assertion)))) (define (ground-retract! assertion) (ground-enqueue! (lambda (ac) (adhoc-retract! ac assertion)))) (define (signal-background-activity! delta) (ground-enqueue! delta)) (define (extend-ground-boot! proc) (set! *ground-boot-extensions* (cons proc *ground-boot-extensions*))) (define (run-ground* boot-proc) (define ch (make-async-channel)) (parameterize ((current-ground-event-async-channel ch)) (define ground-event-relay-actor #f) (define background-activity-count 0) (define (handle-ground-event-item item) (match item [(? procedure? proc) (push-script! ground-event-relay-actor (lambda () (proc ground-event-relay-actor)))] [(? number? delta) (set! background-activity-count (+ background-activity-count delta))])) (define (drain-external-events) (define item (async-channel-try-get ch)) (when item (handle-ground-event-item item) (drain-external-events))) (define ground-event-relay-evt (handle-evt ch (lambda (item) (handle-ground-event-item item) (drain-external-events)))) (define ds (make-dataspace (lambda () (schedule-script! (current-actor) (lambda () (spawn #:name 'ground-event-relay (set! ground-event-relay-actor (current-actor)) ;; v Adds a dummy endpoint to keep this actor alive (begin/dataflow (void))))) (schedule-script! (current-actor) (lambda () (boot-proc) (let ((extensions (reverse *ground-boot-extensions*))) (set! *ground-boot-extensions* '()) (for [(p (in-list extensions))] (p)))))))) (let loop () (define work-remaining? (run-scripts! ds)) (define events-expected? (positive? background-activity-count)) (log-syndicate/ground-debug "GROUND: ~a; ~a background activities" (if work-remaining? "busy" "idle") background-activity-count) (cond [events-expected? (sync ground-event-relay-evt (if work-remaining? (system-idle-evt) never-evt)) (loop)] [work-remaining? (sync ground-event-relay-evt (system-idle-evt)) (loop)] [else (sync (handle-evt ground-event-relay-evt (lambda _ (loop))) (system-idle-evt))])))) (define (run-ground boot-proc) (if (equal? (getenv "SYNDICATE_PROFILE") "ground") (let () (local-require profile) (profile (run-ground* boot-proc))) (run-ground* boot-proc)))