#lang racket/base (provide engine? engine-thread engine-inhabitant-count make-engine adjust-inhabitant-count! queue-task!) (require (only-in racket/exn exn->string)) (require "support/counter.rkt") (define-logger syndicate/task) (struct engine (id thread [inhabitant-count #:mutable]) #:methods gen:custom-write [(define (write-proc e port mode) (fprintf port "#" (engine-id e)))]) (define generate-engine-id (make-counter)) (define (make-engine initial-inhabitant-count) (define e (engine (generate-engine-id) (thread (lambda () (thread-receive) ;; delay boot until we're ready (log-syndicate/task-info "~a starting" e) (with-handlers ([exn? (handle-unexpected-task-runner-termination e)]) (let loop () (log-syndicate/task-debug "~a task count: ~a" e (engine-inhabitant-count e)) (when (positive? (engine-inhabitant-count e)) ((thread-receive)) (loop))) (log-syndicate/task-info "~a stopping" e)))) initial-inhabitant-count)) (thread-send (engine-thread e) 'boot) e) (define (adjust-inhabitant-count! e delta) (queue-task! e (lambda () (set-engine-inhabitant-count! e (+ (engine-inhabitant-count e) delta))))) (define ((handle-unexpected-task-runner-termination e) exn) (log-syndicate/task-error "~a terminated unexpectedly!\n~a" e (exn->string exn)) (exit 1)) (define (queue-task! e thunk) (thread-send (engine-thread e) thunk))