minimart-2014/minimart/ground.rkt

97 lines
3.6 KiB
Racket
Raw Normal View History

2013-10-28 09:53:51 +00:00
#lang racket/base
2014-06-11 20:21:45 +00:00
;; Breaking the infinite tower of nested Worlds, connecting to the "real" world at the fracture line.
2013-10-28 09:53:51 +00:00
2014-06-11 20:02:46 +00:00
(require racket/async-channel)
2014-05-14 03:15:36 +00:00
(require racket/set)
2013-10-28 09:53:51 +00:00
(require racket/match)
(require racket/list)
(require "core.rkt")
(require "gestalt.rkt")
2013-10-28 09:53:51 +00:00
(provide (struct-out event)
2014-06-11 20:02:46 +00:00
send-ground-message
run-ground)
2013-10-28 09:53:51 +00:00
2014-06-11 20:21:45 +00:00
;; A GroundEvent is a pair of a Racket (evt?) event and its yielded
;; results.
;; - (event RacketEvent (Listof Any))
2013-10-28 09:53:51 +00:00
(struct event (descriptor values) #:prefab)
2014-06-11 20:21:45 +00:00
;; (Parameterof (Option AsyncChannel))
;; Communication channel from auxiliary (usually driver) threads to
;; the currently-active ground VM.
2014-06-11 20:02:46 +00:00
(define current-ground-event-async-channel (make-parameter #f))
2014-06-11 20:21:45 +00:00
;; Any -> Void
;; Sends a (non-feedback) message at the ground-VM metalevel.
2014-06-11 20:02:46 +00:00
(define (send-ground-message body)
(match (current-ground-event-async-channel)
[(? async-channel? ch) (async-channel-put ch (send body))]
[_ (error 'send-ground-message "Called outside dynamic scope of run-ground")]))
2014-06-11 20:21:45 +00:00
;; RacketEvent -> RacketEvent
;; Wraps a CML-style Racket event with a handler that sends the event
;; results via the ground VM.
2013-10-28 09:53:51 +00:00
(define (event-handler descriptor)
(handle-evt descriptor (lambda vs (send (event descriptor vs)))))
2014-06-11 20:21:45 +00:00
;; CompiledProjection
;; Used to extract event descriptors and results from subscriptions
;; from the ground VM's contained World.
(define event-projection (compile-gestalt-projection (event (?!) ?)))
2014-05-14 03:15:36 +00:00
2014-06-11 20:21:45 +00:00
;; Gestalt -> (Listof RacketEvent)
;; Projects out the active event subscriptions from the given gestalt.
2014-05-14 03:15:36 +00:00
(define (extract-active-events gestalt)
(define es (matcher-key-set (gestalt-project gestalt 0 0 #f event-projection)))
2014-05-14 03:15:36 +00:00
;; TODO: how should the following error be handled, ideally?
;; In principle, security restrictions should make it impossible.
;; But absent those, what should be done? Should an offending
;; process be identified and terminated?
2014-06-14 16:41:17 +00:00
(unless es (error 'extract-active-events "User program subscribed to wildcard event"))
2014-05-14 03:15:36 +00:00
(for/list [(ev (in-set es))]
(match-define (list e) ev)
2014-05-14 03:15:36 +00:00
(event-handler e)))
2013-10-28 09:53:51 +00:00
2014-06-11 20:21:45 +00:00
;; RacketEvent
;; Used only when the system is not provably inert, in order to let it
;; take further internal reductions.
2013-10-28 09:53:51 +00:00
(define idle-handler
(handle-evt (system-idle-evt) (lambda _ #f)))
2014-06-11 20:21:45 +00:00
;; Action* -> Void
;; Runs a ground VM, booting the outermost World with the given Actions.
(define (run-ground . boot-actions)
2014-06-11 20:02:46 +00:00
(parameterize ((current-ground-event-async-channel (make-async-channel)))
(let await-interrupt ((inert? #f) (p (spawn-world boot-actions)) (active-events '()))
(define active-gestalt (process-gestalt p))
(define event-list (if inert?
active-events
(cons idle-handler active-events)))
(if (and (null? event-list) (gestalt-empty? active-gestalt))
2014-06-11 20:02:46 +00:00
(begin (log-info "run-ground: Terminating because inert")
(void))
(let ((e (apply sync (current-ground-event-async-channel) event-list)))
2014-06-11 20:02:46 +00:00
(match (deliver-event e -2 p)
[#f ;; inert
(await-interrupt #t p active-events)]
[(transition new-state actions)
(let process-actions ((actions (flatten actions)) (g active-gestalt))
2014-06-11 20:02:46 +00:00
(match actions
['()
(await-interrupt #f
(struct-copy process p
[gestalt g]
[state new-state])
(extract-active-events g))]
2014-06-11 20:02:46 +00:00
[(cons a actions)
(match a
[(routing-update gestalt)
(process-actions actions gestalt)]
2014-06-11 20:02:46 +00:00
[(quit)
(log-info "run-ground: Terminating by request")
(void)]
[_
(log-warning "run-ground: ignoring useless meta-action ~v" a)
(process-actions actions g)])]))]))))))