From bab5aba08371b57b4e907af31cbc97e49662d8c0 Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Mon, 28 Nov 2016 12:27:10 +1300 Subject: [PATCH] Crude steps toward reloadable Syndicate modules --- racket/syndicate/reload.rkt | 79 +++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 racket/syndicate/reload.rkt diff --git a/racket/syndicate/reload.rkt b/racket/syndicate/reload.rkt new file mode 100644 index 0000000..9b26ba2 --- /dev/null +++ b/racket/syndicate/reload.rkt @@ -0,0 +1,79 @@ +#lang syndicate/actor +;; Crude steps toward reloadable Syndicate modules + +(provide (except-out (struct-out reload-pending) reload-pending) + (rename-out [reload-pending ]) + (rename-out [make-reload-pending reload-pending]) + + stop-when-reloaded + spawn-reloader + spawn-reloader*) + +(define-logger syndicate/reload) + +(require (for-syntax racket/base)) +(require racket/rerequire) + +(require/activate syndicate/drivers/filesystem) + +(struct reload-pending (filename) #:prefab) ;; ASSERTION + +(define-syntax (make-reload-pending stx) + (quasisyntax/loc stx + (reload-pending '#,(path->string (syntax-source stx))))) + +(define-syntax (stop-when-reloaded stx) + (syntax-case stx () + [(_ body ...) + (quasisyntax/loc stx + (stop-when (asserted (reload-pending '#,(path->string (syntax-source stx)))) + body ...))])) + +(define-syntax-rule (spawn-reloader module-path) + (spawn-reloader* 'module-path)) + +(define (spawn-reloader* module-path) + (define mpi (module-path-index-join module-path #f)) + (define rpath (module-path-index-resolve mpi)) + (define path (let ((p (resolved-module-path-name rpath))) + (if (pair? p) (car p) p))) + (if (path? path) + (spawn-reloader** module-path (path->string path)) + (log-syndicate/reload-error "Could not process module-path ~v" module-path))) + +(define counter + (let ((count 0)) + (lambda (_pathstr) + (begin0 count + (set! count (+ count 1)))))) + +(define (spawn-reloader** module-path pathstr) + (actor #:name (list 'reloader pathstr) + (field [reloading? #f]) + (define (reload!) + (when (not (reloading?)) + (reloading? #t) + (react (field [obstacles-cleared? #f]) + (define/query-value obstacles-exist? #f (observe (reload-pending pathstr)) #t + #:on-add (log-syndicate/reload-info "waiting to reload ~v" pathstr) + #:on-remove (obstacles-cleared? #t)) + (assert #:when (obstacles-exist?) (reload-pending pathstr)) + (on-start (flush!) + (obstacles-cleared? (not (obstacles-exist?)))) + (stop-when (rising-edge (obstacles-cleared?)) + (flush!) ;; Wait one turn for effects of newly-cleared obstacles + (log-syndicate/reload-info "(re)loading ~v" pathstr) + (dynamic-rerequire module-path) + (schedule-actions! + ((dynamic-require `(submod ,module-path syndicate-main) + 'activate!))) + (reloading? #f))))) + + (field [previous-version #f]) + (define/query-value latest-version #f (file-content pathstr counter $p) p) + (begin/dataflow + (when (not (equal? (latest-version) (previous-version))) + (if (latest-version) + (reload!) + (log-syndicate/reload-warning "Module ~v does not exist" pathstr)) + (previous-version (latest-version))))))