/tests/channels.lisp

http://github.com/sykopomp/chanl · Lisp · 227 lines · 194 code · 19 blank · 14 comment · 0 complexity · 400bf0f2fa3dd3f9954fc79bfaa75b47 MD5 · raw file

  1. ;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10; indent-tabs-mode: nil -*-
  2. ;;;;
  3. ;;;; Copyright © 2009 Kat Marchan, Adlai Chandrasekhar
  4. ;;;;
  5. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  6. (in-package :chanl)
  7. (def-suite channels :in chanl)
  8. (def-suite construction :in channels)
  9. (in-suite construction)
  10. (test make-unbuffered
  11. (let ((chan (make-instance 'channel)))
  12. (is (channelp chan))
  13. (is (not (channel-buffered-p chan)))
  14. (is (= 0 (channel-readers chan)))
  15. (is (= 0 (channel-writers chan)))
  16. (is (eq *secret-unbound-value* (channel-value chan)))
  17. (is (send-blocks-p chan))
  18. (is (recv-blocks-p chan))
  19. ;; We don't really have predicates for these, but if they exist, we assume
  20. ;; they're what they're suposed to be.
  21. (is (channel-lock chan))
  22. (is (channel-send-ok chan))
  23. (is (channel-recv-ok chan))))
  24. #+ (or sbcl (and ccl (or x86 x86_64)))
  25. (test make-cas
  26. (let ((chan (make-instance 'cas-channel)))
  27. (is (channelp chan))
  28. (is (not (channel-buffered-p chan)))
  29. (is (= 0 (channel-readers chan)))
  30. (is (= 0 (channel-writers chan)))
  31. (is (eq *secret-unbound-value* (channel-value chan)))
  32. (is (send-blocks-p chan))
  33. (is (recv-blocks-p chan))))
  34. (test make-stack
  35. (let ((chan (make-instance 'stack-channel)))
  36. (is (channelp chan))
  37. (is (channel-buffered-p chan))
  38. (is (null (channel-value chan)))
  39. (is (= 0 (channel-readers chan)))
  40. (is (= 0 (channel-writers chan)))
  41. (is (not (send-blocks-p chan)))
  42. (is (recv-blocks-p chan))
  43. ;; We don't really have predicates for these, but if they exist, we assume
  44. ;; they're what they're suposed to be.
  45. (is (channel-lock chan))
  46. (is (channel-send-ok chan))
  47. (is (channel-recv-ok chan))))
  48. (test make-bounded
  49. (let ((chan (make-instance 'bounded-channel :size 10)))
  50. (is (channelp chan))
  51. (is (channel-buffered-p chan))
  52. (is (queuep (channel-value chan)))
  53. (is (= 10 (queue-length (channel-value chan))))
  54. (is (= 0 (channel-readers chan)))
  55. (is (= 0 (channel-writers chan)))
  56. (is (not (send-blocks-p chan)))
  57. (is (recv-blocks-p chan))
  58. ;; We don't really have predicates for these, but if they exist, we assume
  59. ;; they're what they're suposed to be.
  60. (is (channel-lock chan))
  61. (is (channel-send-ok chan))
  62. (is (channel-recv-ok chan))))
  63. (test make-unbounded
  64. (let ((chan (make-instance 'unbounded-channel)))
  65. (is (channelp chan))
  66. (is (channel-buffered-p chan))
  67. (is (equal '(()) (channel-value chan)))
  68. (is (= 0 (channel-readers chan)))
  69. (is (= 0 (channel-writers chan)))
  70. (is (not (send-blocks-p chan)))
  71. (is (recv-blocks-p chan))
  72. ;; We don't really have predicates for these, but if they exist, we assume
  73. ;; they're what they're suposed to be.
  74. (is (channel-lock chan))
  75. (is (channel-send-ok chan))
  76. (is (channel-recv-ok chan))))
  77. (test make-invalid
  78. (signals error (make-instance 'buffered-channel :size nil))
  79. (signals error (make-instance 'buffered-channel :size -1)))
  80. (def-suite messaging :in channels)
  81. (def-suite sending :in messaging)
  82. (in-suite sending)
  83. (test send-unbuffered
  84. (let ((channel (make-instance 'channel)))
  85. (is (null (send channel 'test :blockp nil)))
  86. (pexec () (recv channel))
  87. (is (eq channel (send channel 'test)))
  88. (pexec () (recv channel))
  89. (is (eq channel (send channel 'test)))
  90. (pexec () (recv channel))
  91. (sleep 0.5) ;hax to let the thread start working
  92. (is (eq channel (send channel 'test :blockp nil)))))
  93. #+sbcl ; FIXME! livelock on ccl
  94. (test send-cas
  95. (let ((channel (make-instance 'cas-channel)))
  96. (is (null (send channel 'test :blockp nil)))
  97. (pexec () (recv channel))
  98. (is (eq channel (send channel 'test)))
  99. (pexec () (recv channel))
  100. (is (eq channel (send channel 'test)))
  101. (pexec () (recv channel))
  102. (sleep 0.5) ; hax, wait for read-state
  103. (is (eq channel (send channel 'test :blockp nil)))))
  104. (test send-buffered
  105. (let ((channel (make-instance 'bounded-channel :size 1)))
  106. (is (eq channel (send channel 'test :blockp nil)))
  107. (recv channel)
  108. (is (eq channel (send channel 'test)))
  109. (is (null (send channel 'test :blockp nil)))
  110. (pexec () (recv channel))
  111. (is (eq channel (send channel 'test)))))
  112. (test send-sequence
  113. (let ((channels (loop repeat 3 collect (make-instance 'channel))))
  114. (is (null (send channels 'test :blockp nil)))
  115. (pexec () (recv (elt channels 1)))
  116. (is (eq (elt channels 1) (send channels 'test)))))
  117. (def-suite receiving :in messaging)
  118. (in-suite receiving)
  119. (test recv-unbuffered
  120. (let ((channel (make-instance 'channel)))
  121. (is (null (nth-value 1 (recv channel :blockp nil))))
  122. (is (null (values (recv channel :blockp nil))))
  123. (pexec () (send channel 'test))
  124. (multiple-value-bind (value rec-chan)
  125. (recv channel)
  126. (is (eq channel rec-chan))
  127. (is (eq 'test value)))
  128. ;; repeat it just to make sure it doesn't fuck up the second time around
  129. (pexec () (send channel 'test))
  130. (multiple-value-bind (value rec-chan)
  131. (recv channel)
  132. (is (eq channel rec-chan))
  133. (is (eq 'test value)))
  134. (pexec () (send channel 'test))
  135. (sleep 0.5)
  136. (is (eq 'test (recv channel :blockp nil)))))
  137. (test recv-buffered
  138. (let ((channel (make-instance 'bounded-channel :size 1)))
  139. (is (null (recv channel :blockp nil)))
  140. (is (null (nth-value 1 (recv channel :blockp nil))))
  141. (send channel 'test)
  142. (multiple-value-bind (value rec-chan)
  143. (recv channel)
  144. (is (eq channel rec-chan))
  145. (is (eq 'test value)))
  146. (is (null (recv channel :blockp nil)))
  147. (is (null (nth-value 1 (recv channel :blockp nil))))
  148. (pexec () (send channel 'test))
  149. (is (eq 'test (recv channel)))))
  150. (test recv-sequence
  151. (let ((channels (loop repeat 3 collect (make-instance 'channel))))
  152. (is (null (recv channels :blockp nil)))
  153. (is (null (nth-value 1 (recv channels :blockp nil))))
  154. (pexec () (send (elt channels 1) 'test))
  155. (multiple-value-bind (value rec-chan)
  156. (recv channels)
  157. (is (eq 'test value))
  158. (is (eq (elt channels 1) rec-chan)))))
  159. (def-suite racing :in channels)
  160. (in-suite racing)
  161. (defun setup-race (thread-count class &rest channel-args)
  162. (let ((lock (bt:make-lock "bt:semaphore")) (nrx 0) (ntx 0) start
  163. (channel (apply #'make-instance class channel-args)))
  164. (macrolet ((with-counter ((place) &body body)
  165. `(unwind-protect
  166. (progn (bt:with-lock-held (lock) (incf ,place)) ,@body)
  167. (bt:with-lock-held (lock) (decf ,place))))
  168. (await (place) `(loop :until (= ,place thread-count))))
  169. (flet ((recver () (with-counter (nrx) (recv channel)))
  170. (sender (x)
  171. (lambda ()
  172. (with-counter (ntx)
  173. (loop :until start :do (bt:thread-yield))
  174. (send channel x))))
  175. (strcat (&rest things) (format () "~{~A~}" things)))
  176. (let ((threads (loop :for n :below thread-count
  177. :collect (bt:make-thread #'recver :name (strcat "r" n))
  178. :collect (bt:make-thread (sender n) :name (strcat "s" n)))))
  179. (await nrx) (await ntx) (setf start t)
  180. (values threads channel))))))
  181. (test racing
  182. (macrolet ((test-case (class count kind)
  183. `(multiple-value-bind (threads channel) (setup-race ,count ',class)
  184. (let* ((pass nil)
  185. (verifier (pexec ()
  186. (mapc #'bt:join-thread threads)
  187. (setf pass t))))
  188. (sleep 5) (is (eq pass t)
  189. (concatenate
  190. 'string ,(format () "count=~D, ~A" count kind)
  191. (with-output-to-string (*standard-output*)
  192. (format t "~%~%Contested Channel:~%")
  193. (describe channel)
  194. (format t "~%~%Competing Threads:~%")
  195. (mapc 'describe
  196. (remove () threads
  197. :key #'bt:thread-alive-p)))))
  198. (unless pass
  199. (mapc #'bt:destroy-thread
  200. (remove () threads
  201. :key #'bt:thread-alive-p))
  202. (kill (task-thread verifier)))))))
  203. (test-case channel 3 "unbuffered")
  204. (test-case channel 6 "unbuffered")
  205. (test-case channel 10 "unbuffered")
  206. (test-case unbounded-channel 3 "unbounded")
  207. (test-case unbounded-channel 6 "unbounded")
  208. (test-case unbounded-channel 10 "unbounded")))