(exception:string-contains-nul): New exception pattern.
[bpt/guile.git] / 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;;;
73be1d9e
MV
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 2.1 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
92205699 17;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
60eefd9c
MD
18
19(define-module (ice-9 occam-channel)
51407fa0 20 #:use-syntax (ice-9 syncase)
60eefd9c
MD
21 #:use-module (oop goops)
22 #:use-module (ice-9 threads)
51407fa0
MD
23 #:export-syntax (alt
24 ;; macro use:
25 oc:lock oc:unlock oc:consequence
26 oc:immediate-dispatch oc:late-dispatch oc:first-channel
27 oc:set-handshake-channel oc:unset-handshake-channel)
fb831451
MD
28 #:export (make-channel
29 ?
30 !
31 make-timer
51407fa0
MD
32 ;; macro use:
33 handshake-channel mutex
34 sender-waiting?
35 immediate-receive late-receive
fb831451
MD
36 )
37 )
60eefd9c
MD
38
39(define no-data '(no-data))
40(define receiver-waiting '(receiver-waiting))
41
fb831451
MD
42(define-class <channel> ())
43
44(define-class <data-channel> (<channel>)
51407fa0 45 (handshake-channel #:accessor handshake-channel)
60eefd9c
MD
46 (data #:accessor data #:init-value no-data)
47 (cv #:accessor cv #:init-form (make-condition-variable))
48 (mutex #:accessor mutex #:init-form (make-mutex)))
49
51407fa0
MD
50(define-method (initialize (ch <data-channel>) initargs)
51 (next-method)
52 (set! (handshake-channel ch) ch))
53
8411a446 54(define-method (make-channel)
fb831451 55 (make <data-channel>))
60eefd9c 56
51407fa0
MD
57(define-method (sender-waiting? (ch <data-channel>))
58 (not (eq? (data ch) no-data)))
59
60(define-method (receiver-waiting? (ch <data-channel>))
61 (eq? (data ch) receiver-waiting))
62
63(define-method (immediate-receive (ch <data-channel>))
64 (signal-condition-variable (cv ch))
60eefd9c
MD
65 (let ((res (data ch)))
66 (set! (data ch) no-data)
51407fa0
MD
67 res))
68
69(define-method (late-receive (ch <data-channel>))
70 (let ((res (data ch)))
71 (set! (data ch) no-data)
72 res))
73
74(define-method (? (ch <data-channel>))
75 (lock-mutex (mutex ch))
76 (let ((res (cond ((receiver-waiting? ch)
77 (unlock-mutex (mutex ch))
78 (scm-error 'misc-error '?
79 "another process is already receiving on ~A"
80 (list ch) #f))
81 ((sender-waiting? ch)
82 (immediate-receive ch))
83 (else
84 (set! (data ch) receiver-waiting)
85 (wait-condition-variable (cv ch) (mutex ch))
86 (late-receive ch)))))
60eefd9c
MD
87 (unlock-mutex (mutex ch))
88 res))
89
fb831451
MD
90(define-method (! (ch <data-channel>))
91 (! ch *unspecified*))
92
93(define-method (! (ch <data-channel>) (x <top>))
51407fa0
MD
94 (lock-mutex (mutex (handshake-channel ch)))
95 (cond ((receiver-waiting? ch)
60eefd9c 96 (set! (data ch) x)
51407fa0
MD
97 (signal-condition-variable (cv (handshake-channel ch))))
98 ((sender-waiting? ch)
99 (unlock-mutex (mutex (handshake-channel ch)))
60eefd9c 100 (scm-error 'misc-error '! "another process is already sending on ~A"
51407fa0
MD
101 (list ch) #f))
102 (else
103 (set! (data ch) x)
104 (wait-condition-variable (cv ch) (mutex ch))))
105 (unlock-mutex (mutex (handshake-channel ch))))
fb831451
MD
106
107;;; Add protocols?
108
109(define-class <port-channel> (<channel>)
110 (port #:accessor port #:init-keyword #:port))
111
112(define-method (make-channel (port <port>))
113 (make <port-channel> #:port port))
114
115(define-method (? (ch <port-channel>))
116 (read (port ch)))
117
118(define-method (! (ch <port-channel>))
119 (write (port ch)))
120
121(define-class <timer-channel> (<channel>))
122
123(define the-timer (make <timer-channel>))
124
125(define timer-cv (make-condition-variable))
126(define timer-mutex (make-mutex))
127
128(define (make-timer)
129 the-timer)
130
131(define (timeofday->us t)
132 (+ (* 1000000 (car t)) (cdr t)))
133
134(define (us->timeofday n)
135 (cons (quotient n 1000000)
136 (remainder n 1000000)))
137
138(define-method (? (ch <timer-channel>))
139 (timeofday->us (gettimeofday)))
140
141(define-method (? (ch <timer-channel>) (t <integer>))
142 (lock-mutex timer-mutex)
143 (wait-condition-variable timer-cv timer-mutex (us->timeofday t))
144 (unlock-mutex timer-mutex))
145
51407fa0
MD
146;;; (alt CLAUSE ...)
147;;;
148;;; CLAUSE ::= ((? CH) FORM ...)
149;;; | (EXP (? CH) FORM ...)
150;;; | (EXP FORM ...)
151;;;
152;;; where FORM ... can be => (lambda (x) ...)
153;;;
154;;; *fixme* Currently only handles <data-channel>:s
155;;;
156
157(define-syntax oc:lock
158 (syntax-rules (?)
159 ((_ ((? ch) form ...)) (lock-mutex (mutex ch)))
160 ((_ (exp (? ch) form ...)) (lock-mutex (mutex ch)))
161 ((_ (exp form ...)) #f)))
162
163(define-syntax oc:unlock
164 (syntax-rules (?)
165 ((_ ((? ch) form ...)) (unlock-mutex (mutex ch)))
166 ((_ (exp (? ch) form ...)) (unlock-mutex (mutex ch)))
167 ((_ (exp form ...)) #f)))
168
169(define-syntax oc:consequence
170 (syntax-rules (=>)
171 ((_ data) data)
172 ((_ data => (lambda (x) e1 e2 ...))
173 (let ((x data)) e1 e2 ...))
174 ((_ data e1 e2 ...)
175 (begin data e1 e2 ...))))
176
177(define-syntax oc:immediate-dispatch
178 (syntax-rules (?)
179 ((_ ((? ch) e1 ...))
180 ((sender-waiting? ch)
181 (oc:consequence (immediate-receive ch) e1 ...)))
182 ((_ (exp (? ch) e1 ...))
183 ((and exp (sender-waiting? ch))
184 (oc:consequence (immediate-receive ch) e1 ...)))
185 ((_ (exp e1 ...))
186 (exp e1 ...))))
187
188(define-syntax oc:late-dispatch
189 (syntax-rules (?)
190 ((_ ((? ch) e1 ...))
191 ((sender-waiting? ch)
192 (oc:consequence (late-receive ch) e1 ...)))
193 ((_ (exp (? ch) e1 ...))
194 ((and exp (sender-waiting? ch))
195 (oc:consequence (late-receive ch) e1 ...)))
196 ((_ (exp e1 ...))
197 (#f))))
198
199(define-syntax oc:first-channel
200 (syntax-rules (?)
201 ((_ ((? ch) e1 ...) c2 ...)
202 ch)
203 ((_ (exp (? ch) e1 ...) c2 ...)
204 ch)
205 ((_ c1 c2 ...)
206 (first-channel c2 ...))))
207
208(define-syntax oc:set-handshake-channel
209 (syntax-rules (?)
210 ((_ ((? ch) e1 ...) handshake)
211 (set! (handshake-channel ch) handshake))
212 ((_ (exp (? ch) e1 ...) handshake)
213 (and exp (set! (handshake-channel ch) handshake)))
214 ((_ (exp e1 ...) handshake)
215 #f)))
216
217(define-syntax oc:unset-handshake-channel
218 (syntax-rules (?)
219 ((_ ((? ch) e1 ...))
220 (set! (handshake-channel ch) ch))
221 ((_ (exp (? ch) e1 ...))
222 (and exp (set! (handshake-channel ch) ch)))
223 ((_ (exp e1 ...))
224 #f)))
225
226(define-syntax alt
227 (lambda (x)
228 (define (else-clause? x)
229 (syntax-case x (else)
230 ((_) #f)
231 ((_ (else e1 e2 ...)) #t)
232 ((_ c1 c2 ...) (else-clause? (syntax (_ c2 ...))))))
233
234 (syntax-case x (else)
235 ((_ c1 c2 ...)
236 (else-clause? x)
237 (syntax (begin
238 (oc:lock c1)
239 (oc:lock c2) ...
240 (let ((res (cond (oc:immediate-dispatch c1)
241 (oc:immediate-dispatch c2) ...)))
242 (oc:unlock c1)
243 (oc:unlock c2) ...
244 res))))
245 ((_ c1 c2 ...)
246 (syntax (begin
247 (oc:lock c1)
248 (oc:lock c2) ...
249 (let ((res (cond (oc:immediate-dispatch c1)
250 (oc:immediate-dispatch c2) ...
251 (else (let ((ch (oc:first-channel c1 c2 ...)))
252 (oc:set-handshake-channel c1 ch)
253 (oc:set-handshake-channel c2 ch) ...
254 (wait-condition-variable (cv ch)
255 (mutex ch))
256 (oc:unset-handshake-channel c1)
257 (oc:unset-handshake-channel c2) ...
258 (cond (oc:late-dispatch c1)
259 (oc:late-dispatch c2) ...))))))
260 (oc:unlock c1)
261 (oc:unlock c2) ...
262 res)))))))