Much improved quit/transition protocol.

This commit is contained in:
Tony Garnock-Jones 2015-03-06 11:21:50 +00:00
parent 9f631e6143
commit 98bfbef056
9 changed files with 78 additions and 31 deletions

View File

@ -2,7 +2,8 @@
;; Core implementation of Incremental Network Calculus. ;; Core implementation of Incremental Network Calculus.
(provide (struct-out message) (provide (struct-out message)
(struct-out quit) (except-out (struct-out quit) quit)
(rename-out [quit <quit>])
(except-out (struct-out spawn) spawn) (except-out (struct-out spawn) spawn)
(rename-out [spawn <spawn>]) (rename-out [spawn <spawn>])
(struct-out process) (struct-out process)
@ -36,6 +37,7 @@
pub pub
unpub unpub
(rename-out [make-quit quit])
make-world make-world
spawn-world spawn-world
(rename-out [spawn-process spawn]) (rename-out [spawn-process spawn])
@ -57,7 +59,6 @@
(struct message (body) #:prefab) (struct message (body) #:prefab)
;; Actions ⊃ Events ;; Actions ⊃ Events
(struct quit () #:prefab)
(struct spawn (boot) #:prefab) (struct spawn (boot) #:prefab)
;; Processes (machine states): (process Matcher (Option Behavior) Any) ;; Processes (machine states): (process Matcher (Option Behavior) Any)
@ -73,14 +74,19 @@
;; - a (transition Any (Constreeof Action)), a new Process state to ;; - a (transition Any (Constreeof Action)), a new Process state to
;; be held by its World and a sequence of Actions for the World ;; be held by its World and a sequence of Actions for the World
;; to take on the transitioning Process's behalf. ;; to take on the transitioning Process's behalf.
;; - a (quit (Constreeof Action)), signalling that the Process should
;; never again be handed an event, and that any queued actions
;; should be performed, followed by the sequence of Actions given,
;; and then the process should be garbage-collected.
(struct transition (state actions) #:transparent) (struct transition (state actions) #:transparent)
(struct quit (actions) #:prefab)
;; A PID is a Nat. ;; A PID is a Nat.
;; A Label is a PID or 'meta. ;; A Label is a PID or 'meta.
;; VM private states ;; VM private states
(struct world (next-pid ;; PID (struct world (next-pid ;; PID
pending-action-queue ;; (Queueof (Cons Label Action)) pending-action-queue ;; (Queueof (Cons Label (U Action 'quit)))
runnable-pids ;; (Setof PID) runnable-pids ;; (Setof PID)
routing-table ;; (Matcherof (Setof Label)) routing-table ;; (Matcherof (Setof Label))
process-table ;; (HashTable PID Process) process-table ;; (HashTable PID Process)
@ -90,7 +96,7 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (event? x) (or (patch? x) (message? x))) (define (event? x) (or (patch? x) (message? x)))
(define (action? x) (or (event? x) (spawn? x) (quit? x))) (define (action? x) (or (event? x) (spawn? x)))
(define (meta-label? x) (eq? x 'meta)) (define (meta-label? x) (eq? x 'meta))
@ -122,13 +128,16 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (ensure-transition v) (define (ensure-transition v)
(if (or (not v) (transition? v)) (if (or (not v) (transition? v) (quit? v))
v v
(raise (exn:fail:contract (format "Expected transition (or #f); got ~v" v) (raise (exn:fail:contract (format "Expected transition, quit or #f; got ~v" v)
(current-continuation-marks))))) (current-continuation-marks)))))
(define (clean-transition t) (define (clean-transition t)
(and t (transition (transition-state t) (clean-actions (transition-actions t))))) (match t
[#f #f]
[(quit actions) (quit (clean-actions actions))]
[(transition state actions) (transition state (clean-actions actions))]))
(define (clean-actions actions) (define (clean-actions actions)
(filter (lambda (x) (and (action? x) (not (patch-empty? x)))) (flatten actions))) (filter (lambda (x) (and (action? x) (not (patch-empty? x)))) (flatten actions)))
@ -142,6 +151,10 @@
(lambda () (clean-transition (ensure-transition (behavior e old-state)))) (lambda () (clean-transition (ensure-transition (behavior e old-state))))
(match-lambda (match-lambda
[#f w] [#f w]
[(and q (quit final-actions))
(trace-process-step e pid p #f q)
(enqueue-actions (disable-process pid #f w) pid (append final-actions
(list 'quit)))]
[(and t (transition new-state new-actions)) [(and t (transition new-state new-actions))
(trace-process-step e pid p #f t) (trace-process-step e pid p #f t)
(update-process pid (update-process pid
@ -150,7 +163,7 @@
w)]) w)])
(lambda (exn) (lambda (exn)
(trace-process-step e pid p exn #f) (trace-process-step e pid p exn #f)
(enqueue-actions (disable-process pid exn w) pid (list (quit)))))])) (enqueue-actions (disable-process pid exn w) pid (list 'quit))))]))
(define (send-event/guard delta pid w) (define (send-event/guard delta pid w)
(if (patch-empty? delta) (if (patch-empty? delta)
@ -158,7 +171,10 @@
(send-event delta pid w))) (send-event delta pid w)))
(define (disable-process pid exn w) (define (disable-process pid exn w)
(log-error "Process ~a died with exception:\n~a" (cons pid (trace-pid-stack)) (exn->string exn)) (when exn
(log-error "Process ~a died with exception:\n~a"
(cons pid (trace-pid-stack))
(exn->string exn)))
(match (hash-ref (world-process-table w) pid #f) (match (hash-ref (world-process-table w) pid #f)
[#f w] [#f w]
[old-p [old-p
@ -190,6 +206,9 @@
(queue-append-list (world-pending-action-queue w) (queue-append-list (world-pending-action-queue w)
(for/list [(a actions)] (cons label a)))])) (for/list [(a actions)] (cons label a)))]))
(define (make-quit . actions)
(quit actions))
(define-syntax-rule (spawn-process behavior-exp initial-state-exp initial-patch-exp ...) (define-syntax-rule (spawn-process behavior-exp initial-state-exp initial-patch-exp ...)
(spawn (lambda (pid) (spawn (lambda (pid)
(process (apply-patch (matcher-empty) (process (apply-patch (matcher-empty)
@ -215,10 +234,14 @@
(make-world (boot-actions-thunk)))))) (make-world (boot-actions-thunk))))))
(define (transition-bind k t0) (define (transition-bind k t0)
(match-define (transition state0 actions0) t0) (match t0
(match (k state0) [#f (error 'transition-bind "Cannot bind from transition #f with continuation ~v" k)]
[#f t0] [(quit _) t0]
[(transition state1 actions1) (transition state1 (cons actions0 actions1))])) [(transition state0 actions0)
(match (k state0)
[#f t0]
[(quit actions1) (quit (cons actions0 actions1))]
[(transition state1 actions1) (transition state1 (cons actions0 actions1))])]))
(define (sequence-transitions t0 . steps) (define (sequence-transitions t0 . steps)
(foldl transition-bind t0 steps)) (foldl transition-bind t0 steps))
@ -274,7 +297,7 @@
(trace-pid-stack) (trace-pid-stack)
(exn->string exn)) (exn->string exn))
(transition w '())))] (transition w '())))]
[(quit) ['quit
(define pt (world-process-table w)) (define pt (world-process-table w))
(match (hash-ref pt label #f) (match (hash-ref pt label #f)
[#f (transition w '())] [#f (transition w '())]
@ -374,6 +397,7 @@
(pretty-print w) (pretty-print w)
(match (world-handle-event #f w) (match (world-handle-event #f w)
[#f (values w (flatten actions))] [#f (values w (flatten actions))]
[(quit new-actions) (values w (flatten (cons actions new-actions)))]
[(transition new-w new-actions) (loop new-w (cons actions new-actions))]))) [(transition new-w new-actions) (loop new-w (cons actions new-actions))])))
(step* (make-world '())) (step* (make-world '()))

View File

@ -134,9 +134,11 @@
(define maybe-spawn (apply check-and-maybe-spawn-fn (define maybe-spawn (apply check-and-maybe-spawn-fn
new-aggregate new-aggregate
projection-results)) projection-results))
(transition new-aggregate (when maybe-spawn (list maybe-spawn (quit))))] (if maybe-spawn
(quit maybe-spawn)
(transition new-aggregate '()))]
[(message (timer-expired (== timer-id) _)) [(message (timer-expired (== timer-id) _))
(transition current-aggregate (list (timeout-handler) (quit)))] (quit (timeout-handler))]
[_ #f])) [_ #f]))
(matcher-empty) (matcher-empty)
(patch base-interests (matcher-empty)) (patch base-interests (matcher-empty))

View File

@ -61,7 +61,7 @@
[(? patch? p) [(? patch? p)
(cond [(matcher-empty? (patch-removed p)) #f] ;; peer hasn't quit yet: do nothing. (cond [(matcher-empty? (patch-removed p)) #f] ;; peer hasn't quit yet: do nothing.
[else (channel-put control-ch 'quit) [else (channel-put control-ch 'quit)
(transition s (quit))])] (quit)])]
[(message (at-meta (? udp-packet? p))) [(message (at-meta (? udp-packet? p)))
(transition s (message p))] (transition s (message p))]
[(message (udp-packet _ (udp-remote-address host port) body)) [(message (udp-packet _ (udp-remote-address host port) body))

View File

@ -33,7 +33,7 @@
(define (echoer e s) (define (echoer e s)
(match e (match e
[(message (at-meta (external-event _ (list (? eof-object?))))) [(message (at-meta (external-event _ (list (? eof-object?)))))
(transition s (quit))] (quit)]
[(message (at-meta (external-event _ (list line)))) [(message (at-meta (external-event _ (list line))))
(transition s (message `(print (got-line ,line))))] (transition s (message `(print (got-line ,line))))]
[_ #f])) [_ #f]))
@ -49,9 +49,9 @@
#f] #f]
[(message (timer-expired 'tick now)) [(message (timer-expired 'tick now))
(printf "TICK ~v\n" now) (printf "TICK ~v\n" now)
(transition (+ s 1) (if (< s 3) (if (< s 3)
(message (set-timer 'tick 1000 'relative)) (transition (+ s 1) (message (set-timer 'tick 1000 'relative)))
(quit)))] (quit))]
[_ #f])) [_ #f]))
(spawn-timer-driver) (spawn-timer-driver)

View File

@ -31,7 +31,7 @@
(define (echoer e s) (define (echoer e s)
(match e (match e
[(message (at-meta (external-event _ (list (? eof-object?))))) [(message (at-meta (external-event _ (list (? eof-object?)))))
(transition s (quit))] (quit)]
[(message (at-meta (external-event _ (list line)))) [(message (at-meta (external-event _ (list line))))
(transition s (message `(print (got-line ,line))))] (transition s (message `(print (got-line ,line))))]
[_ #f])) [_ #f]))
@ -44,9 +44,9 @@
#f] #f]
[(message (timer-expired 'tick now)) [(message (timer-expired 'tick now))
(printf "TICK ~v\n" now) (printf "TICK ~v\n" now)
(transition (+ s 1) (if (< s 3) (if (< s 3)
(message (set-timer 'tick 1000 'relative)) (transition (+ s 1) (message (set-timer 'tick 1000 'relative)))
(quit)))] (quit))]
[_ #f])) [_ #f]))
(define (printer e s) (define (printer e s)

View File

@ -8,7 +8,7 @@
(match e (match e
[(message (udp-packet src dst #"quit\n")) [(message (udp-packet src dst #"quit\n"))
(log-info "Got quit request") (log-info "Got quit request")
(transition s (list (message (udp-packet dst src #"Goodbye!\n")) (quit)))] (quit (message (udp-packet dst src #"Goodbye!\n")))]
[(message (udp-packet src dst body)) [(message (udp-packet src dst body))
(log-info "Got packet from ~v: ~v" src body) (log-info "Got packet from ~v: ~v" src body)
(define reply (string->bytes/utf-8 (format "You said: ~a" body))) (define reply (string->bytes/utf-8 (format "You said: ~a" body)))

View File

@ -7,6 +7,8 @@
(struct-out advertise) (struct-out advertise)
empty-patch empty-patch
patch-empty? patch-empty?
patch-non-empty?
patch/removed?
lift-patch lift-patch
drop-patch drop-patch
strip-interests strip-interests
@ -55,6 +57,14 @@
(matcher-empty? (patch-added p)) (matcher-empty? (patch-added p))
(matcher-empty? (patch-removed p)))) (matcher-empty? (patch-removed p))))
(define (patch-non-empty? p)
(and (patch? p)
(or (matcher-non-empty? (patch-added p))
(matcher-non-empty? (patch-removed p)))))
(define (patch/removed? p)
(and (patch? p) (matcher-non-empty? (patch-removed p))))
(define (lift-patch p) (define (lift-patch p)
(match-define (patch in out) p) (match-define (patch in out) p)
(patch (pattern->matcher #t (at-meta (embedded-matcher in))) (patch (pattern->matcher #t (at-meta (embedded-matcher in)))

View File

@ -20,10 +20,12 @@
matcher? ;; expensive; see implementation matcher? ;; expensive; see implementation
matcher-empty matcher-empty
matcher-empty? matcher-empty?
matcher-non-empty?
pattern->matcher pattern->matcher
pattern->matcher* pattern->matcher*
matcher-union matcher-union
matcher-intersect matcher-intersect
empty-set-guard
matcher-subtract-combiner matcher-subtract-combiner
matcher-subtract matcher-subtract
matcher-match-value matcher-match-value
@ -144,6 +146,10 @@
;; True iff the argument is the empty matcher ;; True iff the argument is the empty matcher
(define (matcher-empty? r) (not r)) (define (matcher-empty? r) (not r))
;; Matcher -> Boolean
;; True iff the argument is NOT the empty matcher
(define (matcher-non-empty? r) (not (matcher-empty? r)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Smart constructors & accessors ;; Smart constructors & accessors
;; ;;
@ -337,9 +343,11 @@
(lambda (h) #f) (lambda (h) #f)
(lambda (h) #f))) (lambda (h) #f)))
(define (empty-set-guard s)
(if (set-empty? s) #f s))
(define (matcher-subtract-combiner s1 s2) (define (matcher-subtract-combiner s1 s2)
(define r (set-subtract s1 s2)) (empty-set-guard (set-subtract s1 s2)))
(if (set-empty? r) #f r))
;; Matcher Matcher -> Matcher ;; Matcher Matcher -> Matcher
;; Removes re2's mappings from re1. ;; Removes re2's mappings from re1.

View File

@ -122,8 +122,11 @@
(output "Process ~a died with exception:\n~a\n" (output "Process ~a died with exception:\n~a\n"
pidstr pidstr
(exn->string exn)))) (exn->string exn))))
(when (quit? t)
(with-color BRIGHT-RED
(output "Process ~a exited normally.\n" pidstr)))
(when (or relevant-exn? show-process-states-post?) (when (or relevant-exn? show-process-states-post?)
(when t (when (transition? t)
(unless (boring-state? (transition-state t)) (unless (boring-state? (transition-state t))
(when (not (equal? (process-state p) (transition-state t))) (when (not (equal? (process-state p) (transition-state t)))
(with-color YELLOW (with-color YELLOW
@ -132,7 +135,7 @@
[('internal-step (list pids a old-w t)) [('internal-step (list pids a old-w t))
(when t ;; inert worlds don't change interestingly (when t ;; inert worlds don't change interestingly
(define pidstr (format-pids pids)) (define pidstr (format-pids pids))
(define new-w (transition-state t)) (define new-w (if (transition? t) (transition-state t) old-w))
(define old-processes (world-process-table old-w)) (define old-processes (world-process-table old-w))
(define new-processes (world-process-table new-w)) (define new-processes (world-process-table new-w))
(define newcount (hash-count new-processes)) (define newcount (hash-count new-processes))
@ -155,7 +158,7 @@
(unless (matcher-empty? interests) (unless (matcher-empty? interests)
(output "~a's initial interests:\n" newpidstr) (output "~a's initial interests:\n" newpidstr)
(pretty-print-matcher interests (current-error-port))))] (pretty-print-matcher interests (current-error-port))))]
[(quit) ['quit
(when (or show-process-lifecycle? show-actions?) (when (or show-process-lifecycle? show-actions?)
(match (hash-ref old-processes (car pids) (lambda () #f)) (match (hash-ref old-processes (car pids) (lambda () #f))
[#f (void)] [#f (void)]