occam-channel.scm 7.3 KB

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