1 ;; Simple Actor Machine
3 ;; A virtual machine which houses a population of actors which can
4 ;; communicate using messages with actors on the same machine or other
5 ;; machines via the network.
20 (chicken process-context)
33 (define sam-host "localhost")
34 (define sam-port 8000)
36 (define (make-address host port id)
39 (define (make-local-address . args)
40 (make-address sam-host
46 (define (address-id address)
48 (define (address-host address)
50 (define (address-port address)
52 (define (address->string address)
54 (make-uri #:scheme "actor"
55 #:host (address-host address)
56 #:port (address-port address)
57 #:path (list '/ (address-id address)))))
58 (define (string->address str)
59 (let ((uri (uri-reference str)))
60 (make-address (uri-host uri)
62 (cadr (uri-path uri)))))
64 (define (address-local? address)
65 (and (equal? (address-host address) sam-host)
66 (equal? (address-port address) sam-port)))
68 (define actor-table (make-hash-table))
70 (define (make-actor beh)
71 (let* ((address (make-local-address))
72 (id (address-id address)))
73 (hash-table-set! actor-table id beh)
76 (define (deliver-message address . message)
77 (if trace (print "Delivering to " address ": " message))
78 (let ((id (address-id address)))
79 (let ((behaviour (hash-table-ref/default actor-table id '())))
81 (print "Warning: discarded message " message
82 " to unknown actor id " id)
83 (match (apply (hash-table-ref actor-table id) (cons address message))
84 ('done (hash-table-delete! actor-table id))
86 (new-beh (hash-table-set! actor-table id new-beh)))))))
90 (define local-queue-mutex (make-mutex "message queue"))
91 (define message-available-mutex (make-mutex "message available"))
92 (mutex-lock! message-available-mutex #f #f)
93 (define local-queue (make-fifo))
95 (define (send-message address . message)
96 (apply (if (address-local? address)
99 (cons address message)))
101 (define (send-local-message address . message)
102 (mutex-lock! local-queue-mutex)
103 (fifo-push local-queue (cons address message))
104 (mutex-unlock! message-available-mutex)
105 (mutex-unlock! local-queue-mutex))
107 (define (send-network-message address . message)
108 (let ((s (udp-open-socket))
109 (packet (with-output-to-string
111 (write (cons address message))))))
114 (address-host address)
115 (address-port address))
117 (udp-close-socket s)))
119 (define (send-message-later address time . message)
123 (apply send-message (cons address message)))))
125 (define (next-local-message)
127 (mutex-lock! message-available-mutex #f #f)
128 (mutex-lock! local-queue-mutex)
129 (set! res (fifo-pop local-queue))
130 (if (not (fifo-empty? local-queue))
131 (mutex-unlock! message-available-mutex))
132 (mutex-unlock! local-queue-mutex)
135 (define (start-scheduler)
137 (apply deliver-message (next-local-message))
143 (define (start-network-listener)
146 (let ((s (udp-open-socket*)))
147 (udp-bind! s #f sam-port)
149 (let-values (((n str) (udp-recv s 65536)))
150 (match (with-input-from-string str read)
151 ((address message ...)
152 (apply send-message (cons address message)))
154 (print "Warning: received badly formatted message string '" str "'"))))
159 (define reader-queue-mutex (make-mutex "reader queue"))
160 (define reader-available-mutex (make-mutex "reader available"))
161 (mutex-lock! reader-available-mutex #f #f)
162 (define reader-queue (make-fifo))
164 (define (next-reader)
166 (mutex-lock! reader-available-mutex #f #f)
167 (mutex-lock! reader-queue-mutex)
168 (set! res (fifo-pop reader-queue))
169 (if (not (fifo-empty? reader-queue))
170 (mutex-unlock! reader-available-mutex))
171 (mutex-unlock! reader-queue-mutex)
174 (define (start-console)
178 (let ((reader (next-reader)))
179 (##sys#thread-block-for-i/o! (current-thread) 0 #t)
181 (send-message reader (read-line)))
184 ;; System initialization
186 (define (system-beh self . message)
190 (print "## System actor received shutdown message.")
194 (('print strings ...)
195 (apply print strings)
199 (mutex-lock! reader-queue-mutex)
200 (fifo-push reader-queue reader)
201 (mutex-unlock! reader-available-mutex)
202 (mutex-unlock! reader-queue-mutex)
205 (define (boot-sam host port main-beh)
209 (start-network-listener)
210 (send-message (make-actor main-beh) (make-actor system-beh))