define-module for elisp special modules
[bpt/guile.git] / module / ice-9 / occam-channel.scm
CommitLineData
60eefd9c
MD
1;;;; Occam-like channels
2
cd5fea8d 3;;; Copyright (C) 2003, 2006 Free Software Foundation, Inc.
60eefd9c 4;;;
53befeb7
NJ
5;;;; This library is free software; you can redistribute it and/or
6;;;; modify it under the terms of the GNU Lesser General Public
7;;;; License as published by the Free Software Foundation; either
8;;;; version 3 of the License, or (at your option) any later version.
9;;;;
10;;;; This library is distributed in the hope that it will be useful,
11;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13;;;; Lesser General Public License for more details.
14;;;;
15;;;; You should have received a copy of the GNU Lesser General Public
16;;;; License along with this library; if not, write to the Free Software
17;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
60eefd9c
MD
18
19(define-module (ice-9 occam-channel)
20 #:use-module (oop goops)
21 #:use-module (ice-9 threads)
51407fa0
MD
22 #:export-syntax (alt
23 ;; macro use:
24 oc:lock oc:unlock oc:consequence
25 oc:immediate-dispatch oc:late-dispatch oc:first-channel
26 oc:set-handshake-channel oc:unset-handshake-channel)
fb831451
MD
27 #:export (make-channel
28 ?
29 !
30 make-timer
51407fa0
MD
31 ;; macro use:
32 handshake-channel mutex
33 sender-waiting?
34 immediate-receive late-receive
fb831451
MD
35 )
36 )
60eefd9c
MD
37
38(define no-data '(no-data))
39(define receiver-waiting '(receiver-waiting))
40
fb831451
MD
41(define-class <channel> ())
42
43(define-class <data-channel> (<channel>)
51407fa0 44 (handshake-channel #:accessor handshake-channel)
60eefd9c
MD
45 (data #:accessor data #:init-value no-data)
46 (cv #:accessor cv #:init-form (make-condition-variable))
47 (mutex #:accessor mutex #:init-form (make-mutex)))
48
51407fa0
MD
49(define-method (initialize (ch <data-channel>) initargs)
50 (next-method)
51 (set! (handshake-channel ch) ch))
52
8411a446 53(define-method (make-channel)
fb831451 54 (make <data-channel>))
60eefd9c 55
51407fa0
MD
56(define-method (sender-waiting? (ch <data-channel>))
57 (not (eq? (data ch) no-data)))
58
59(define-method (receiver-waiting? (ch <data-channel>))
60 (eq? (data ch) receiver-waiting))
61
62(define-method (immediate-receive (ch <data-channel>))
63 (signal-condition-variable (cv ch))
60eefd9c
MD
64 (let ((res (data ch)))
65 (set! (data ch) no-data)
51407fa0
MD
66 res))
67
68(define-method (late-receive (ch <data-channel>))
69 (let ((res (data ch)))
70 (set! (data ch) no-data)
71 res))
72
73(define-method (? (ch <data-channel>))
74 (lock-mutex (mutex ch))
75 (let ((res (cond ((receiver-waiting? ch)
76 (unlock-mutex (mutex ch))
77 (scm-error 'misc-error '?
78 "another process is already receiving on ~A"
79 (list ch) #f))
80 ((sender-waiting? ch)
81 (immediate-receive ch))
82 (else
83 (set! (data ch) receiver-waiting)
84 (wait-condition-variable (cv ch) (mutex ch))
85 (late-receive ch)))))
60eefd9c
MD
86 (unlock-mutex (mutex ch))
87 res))
88
fb831451
MD
89(define-method (! (ch <data-channel>))
90 (! ch *unspecified*))
91
92(define-method (! (ch <data-channel>) (x <top>))
51407fa0
MD
93 (lock-mutex (mutex (handshake-channel ch)))
94 (cond ((receiver-waiting? ch)
60eefd9c 95 (set! (data ch) x)
51407fa0
MD
96 (signal-condition-variable (cv (handshake-channel ch))))
97 ((sender-waiting? ch)
98 (unlock-mutex (mutex (handshake-channel ch)))
60eefd9c 99 (scm-error 'misc-error '! "another process is already sending on ~A"
51407fa0
MD
100 (list ch) #f))
101 (else
102 (set! (data ch) x)
103 (wait-condition-variable (cv ch) (mutex ch))))
104 (unlock-mutex (mutex (handshake-channel ch))))
fb831451
MD
105
106;;; Add protocols?
107
108(define-class <port-channel> (<channel>)
109 (port #:accessor port #:init-keyword #:port))
110
111(define-method (make-channel (port <port>))
112 (make <port-channel> #:port port))
113
114(define-method (? (ch <port-channel>))
115 (read (port ch)))
116
117(define-method (! (ch <port-channel>))
118 (write (port ch)))
119
120(define-class <timer-channel> (<channel>))
121
122(define the-timer (make <timer-channel>))
123
124(define timer-cv (make-condition-variable))
125(define timer-mutex (make-mutex))
126
127(define (make-timer)
128 the-timer)
129
130(define (timeofday->us t)
131 (+ (* 1000000 (car t)) (cdr t)))
132
133(define (us->timeofday n)
134 (cons (quotient n 1000000)
135 (remainder n 1000000)))
136
137(define-method (? (ch <timer-channel>))
138 (timeofday->us (gettimeofday)))
139
140(define-method (? (ch <timer-channel>) (t <integer>))
141 (lock-mutex timer-mutex)
142 (wait-condition-variable timer-cv timer-mutex (us->timeofday t))
143 (unlock-mutex timer-mutex))
144
51407fa0
MD
145;;; (alt CLAUSE ...)
146;;;
147;;; CLAUSE ::= ((? CH) FORM ...)
148;;; | (EXP (? CH) FORM ...)
149;;; | (EXP FORM ...)
150;;;
151;;; where FORM ... can be => (lambda (x) ...)
152;;;
153;;; *fixme* Currently only handles <data-channel>:s
154;;;
155
156(define-syntax oc:lock
157 (syntax-rules (?)
158 ((_ ((? ch) form ...)) (lock-mutex (mutex ch)))
159 ((_ (exp (? ch) form ...)) (lock-mutex (mutex ch)))
160 ((_ (exp form ...)) #f)))
161
162(define-syntax oc:unlock
163 (syntax-rules (?)
164 ((_ ((? ch) form ...)) (unlock-mutex (mutex ch)))
165 ((_ (exp (? ch) form ...)) (unlock-mutex (mutex ch)))
166 ((_ (exp form ...)) #f)))
167
168(define-syntax oc:consequence
169 (syntax-rules (=>)
170 ((_ data) data)
171 ((_ data => (lambda (x) e1 e2 ...))
172 (let ((x data)) e1 e2 ...))
173 ((_ data e1 e2 ...)
174 (begin data e1 e2 ...))))
175
176(define-syntax oc:immediate-dispatch
177 (syntax-rules (?)
178 ((_ ((? ch) e1 ...))
179 ((sender-waiting? ch)
180 (oc:consequence (immediate-receive ch) e1 ...)))
181 ((_ (exp (? ch) e1 ...))
182 ((and exp (sender-waiting? ch))
183 (oc:consequence (immediate-receive ch) e1 ...)))
184 ((_ (exp e1 ...))
185 (exp e1 ...))))
186
187(define-syntax oc:late-dispatch
188 (syntax-rules (?)
189 ((_ ((? ch) e1 ...))
190 ((sender-waiting? ch)
191 (oc:consequence (late-receive ch) e1 ...)))
192 ((_ (exp (? ch) e1 ...))
193 ((and exp (sender-waiting? ch))
194 (oc:consequence (late-receive ch) e1 ...)))
195 ((_ (exp e1 ...))
196 (#f))))
197
198(define-syntax oc:first-channel
199 (syntax-rules (?)
200 ((_ ((? ch) e1 ...) c2 ...)
201 ch)
202 ((_ (exp (? ch) e1 ...) c2 ...)
203 ch)
204 ((_ c1 c2 ...)
205 (first-channel c2 ...))))
206
207(define-syntax oc:set-handshake-channel
208 (syntax-rules (?)
209 ((_ ((? ch) e1 ...) handshake)
210 (set! (handshake-channel ch) handshake))
211 ((_ (exp (? ch) e1 ...) handshake)
212 (and exp (set! (handshake-channel ch) handshake)))
213 ((_ (exp e1 ...) handshake)
214 #f)))
215
216(define-syntax oc:unset-handshake-channel
217 (syntax-rules (?)
218 ((_ ((? ch) e1 ...))
219 (set! (handshake-channel ch) ch))
220 ((_ (exp (? ch) e1 ...))
221 (and exp (set! (handshake-channel ch) ch)))
222 ((_ (exp e1 ...))
223 #f)))
224
225(define-syntax alt
226 (lambda (x)
227 (define (else-clause? x)
228 (syntax-case x (else)
229 ((_) #f)
230 ((_ (else e1 e2 ...)) #t)
231 ((_ c1 c2 ...) (else-clause? (syntax (_ c2 ...))))))
232
233 (syntax-case x (else)
234 ((_ c1 c2 ...)
235 (else-clause? x)
236 (syntax (begin
237 (oc:lock c1)
238 (oc:lock c2) ...
239 (let ((res (cond (oc:immediate-dispatch c1)
240 (oc:immediate-dispatch c2) ...)))
241 (oc:unlock c1)
242 (oc:unlock c2) ...
243 res))))
244 ((_ c1 c2 ...)
245 (syntax (begin
246 (oc:lock c1)
247 (oc:lock c2) ...
248 (let ((res (cond (oc:immediate-dispatch c1)
249 (oc:immediate-dispatch c2) ...
250 (else (let ((ch (oc:first-channel c1 c2 ...)))
251 (oc:set-handshake-channel c1 ch)
252 (oc:set-handshake-channel c2 ch) ...
253 (wait-condition-variable (cv ch)
254 (mutex ch))
255 (oc:unset-handshake-channel c1)
256 (oc:unset-handshake-channel c2) ...
257 (cond (oc:late-dispatch c1)
258 (oc:late-dispatch c2) ...))))))
259 (oc:unlock c1)
260 (oc:unlock c2) ...
261 res)))))))