1 ;; Simple Actor Machine
3 ;; Houses a population of actors which can communicate using messages
4 ;; with actors on the same machine or other machines via the network.
17 (chicken process-context)
30 (define sam-host "localhost")
31 (define sam-port 8000)
33 (define (make-address host port id)
35 (make-uri #:scheme "actor"
38 #:path (list '/ id))))
40 (define (make-local-address . args)
41 (make-address sam-host
47 (define (address-id address)
48 (cadr (uri-path (uri-reference address))))
50 (define address->uri uri-reference)
52 (define (address-local? address)
53 (let ((uri (address->uri address)))
54 (and (equal? (uri-host uri) sam-host)
55 (equal? (uri-port uri) sam-port))))
57 (define actor-table (make-hash-table))
59 (define (make-actor beh)
60 (let* ((address (make-local-address))
61 (id (address-id address)))
62 (hash-table-set! actor-table id beh)
65 (define (deliver-message address . message)
66 (if trace (print "Delivering to " address ": " message))
67 (let ((id (address-id address)))
68 (let ((behaviour (hash-table-ref/default actor-table id '())))
70 (print "Warning: discarded message" message " to unknown actor " address)
71 (match (apply (hash-table-ref actor-table id) (cons address message))
72 ('done (hash-table-delete! actor-table id))
74 (new-beh (hash-table-set! actor-table id new-beh)))))))
78 (define local-queue-mutex (make-mutex "message queue"))
79 (define message-available-mutex (make-mutex "message available"))
80 (mutex-lock! message-available-mutex #f #f)
81 (define local-queue (make-fifo))
83 (define (send-message address . message)
84 (apply (if (address-local? address)
87 (cons address message)))
89 (define (send-local-message address . message)
90 (mutex-lock! local-queue-mutex)
91 (fifo-push local-queue (cons address message))
92 (mutex-unlock! message-available-mutex)
93 (mutex-unlock! local-queue-mutex))
95 (define (send-network-message address . message)
96 (let ((s (udp-open-socket))
97 (uri (address->uri address))
98 (packet (with-output-to-string
100 (write (cons address message))))))
106 (udp-close-socket s)))
108 (define (send-message-later address time . message)
112 (apply send-message (cons address message)))))
114 (define (next-local-message)
116 (mutex-lock! message-available-mutex #f #f)
117 (mutex-lock! local-queue-mutex)
118 (set! res (fifo-pop local-queue))
119 (if (not (fifo-empty? local-queue))
120 (mutex-unlock! message-available-mutex))
121 (mutex-unlock! local-queue-mutex)
124 (define (start-scheduler)
126 (apply deliver-message (next-local-message))
132 (define (start-network-listener)
135 (let ((s (udp-open-socket*)))
136 (udp-bind! s #f sam-port)
138 (let-values (((n str) (udp-recv s 1024)))
139 (match (with-input-from-string str read)
140 ((address message ...)
141 (apply send-message (cons address message)))
143 (print "Warning: received badly formatted message string '" str "'"))))
148 (define reader-queue-mutex (make-mutex "reader queue"))
149 (define reader-available-mutex (make-mutex "reader available"))
150 (mutex-lock! reader-available-mutex #f #f)
151 (define reader-queue (make-fifo))
153 (define (next-reader)
155 (mutex-lock! reader-available-mutex #f #f)
156 (mutex-lock! reader-queue-mutex)
157 (set! res (fifo-pop reader-queue))
158 (if (not (fifo-empty? reader-queue))
159 (mutex-unlock! reader-available-mutex))
160 (mutex-unlock! reader-queue-mutex)
163 (define (start-console)
167 (let ((reader (next-reader)))
168 (##sys#thread-block-for-i/o! (current-thread) 0 #t)
170 (send-message reader (read-line)))
173 ;; System initialization
175 (define (system-beh self . message)
179 (print "## System actor received shutdown message.")
183 (('print strings ...)
184 (apply print strings)
188 (mutex-lock! reader-queue-mutex)
189 (fifo-push reader-queue reader)
190 (mutex-unlock! reader-available-mutex)
191 (mutex-unlock! reader-queue-mutex)
194 (define (boot-sam host port main-beh)
198 (start-network-listener)
199 (send-message (make-actor main-beh) (make-actor system-beh))