channels.scm 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. ;;; Hoot implementation of Fibers
  2. ;;; Copyright (C) 2024 Igalia, S.L.
  3. ;;;
  4. ;;; Licensed under the Apache License, Version 2.0 (the "License");
  5. ;;; you may not use this file except in compliance with the License.
  6. ;;; You may obtain a copy of the License at
  7. ;;;
  8. ;;; http://www.apache.org/licenses/LICENSE-2.0
  9. ;;;
  10. ;;; Unless required by applicable law or agreed to in writing, software
  11. ;;; distributed under the License is distributed on an "AS IS" BASIS,
  12. ;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. ;;; See the License for the specific language governing permissions and
  14. ;;; limitations under the License.
  15. (define-module (fibers channels)
  16. #:use-module (srfi srfi-9)
  17. #:use-module (ice-9 match)
  18. #:use-module (fibers waiter-queue)
  19. #:use-module (fibers operations)
  20. #:export (make-channel
  21. channel?
  22. put-operation
  23. get-operation
  24. put-message
  25. get-message))
  26. (define-record-type <channel>
  27. (%make-channel getq putq)
  28. channel?
  29. (getq channel-getq)
  30. (putq channel-putq))
  31. (define (make-channel)
  32. "Make a fresh channel."
  33. (%make-channel (make-waiter-queue) (make-waiter-queue)))
  34. (define (put-operation channel message)
  35. "Make an operation that if and when it completes will rendezvous
  36. with a receiver fiber to send @var{message} over @var{channel}."
  37. (match channel
  38. (($ <channel> getq putq)
  39. (define (try-fn)
  40. (match (waiter-queue-pop! getq #f)
  41. (#f #f)
  42. (resume-get
  43. (resume-get (lambda () message))
  44. (lambda () (values)))))
  45. (define (block-fn state resume-put)
  46. (waiter-queue-push! putq state (cons resume-put message))
  47. (values))
  48. (make-base-operation #f try-fn block-fn))))
  49. (define (get-operation channel)
  50. "Make an operation that if and when it completes will rendezvous
  51. with a sender fiber to receive one value from @var{channel}."
  52. (match channel
  53. (($ <channel> getq putq)
  54. (define (try-fn)
  55. (match (waiter-queue-pop! putq #f)
  56. (#f #f)
  57. ((resume-put . message)
  58. (resume-put (lambda () (values)))
  59. (lambda () message))))
  60. (define (block-fn state resume-get)
  61. (waiter-queue-push! getq state resume-get)
  62. (values))
  63. (make-base-operation #f try-fn block-fn))))
  64. (define (put-message channel message)
  65. "Send @var{message} on @var{channel}, and return zero values. If
  66. there is already another fiber waiting to receive a message on this
  67. channel, give it our message and continue. Otherwise, block until a
  68. receiver becomes available."
  69. (perform-operation (put-operation channel message)))
  70. (define (get-message channel)
  71. "Receive a message from @var{channel} and return it. If there is
  72. already another fiber waiting to send a message on this channel, take
  73. its message directly. Otherwise, block until a sender becomes
  74. available."
  75. (perform-operation (get-operation channel)))