occam-channel.scm 7.3 KB

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