queue.scm 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. ; Copyright (c) 1993-2007 by Richard Kelsey and Jonathan Rees. See file COPYING.
  2. ; Queues
  3. ; Richard's code with Jonathan's names.
  4. ;
  5. ; Richard's names: Jonathan's names (modified by popular demand):
  6. ; make-empty-queue make-queue
  7. ; add-to-queue! enqueue!
  8. ; remove-from-queue! dequeue!
  9. ;
  10. ; Now using optimistic concurrency. We really need two sets of procedures to
  11. ; allow those who don't care to avoid the cost of the concurrency checks.
  12. (define-synchronized-record-type queue :queue
  13. (really-make-queue uid head tail)
  14. (head tail) ; synchronize on these
  15. queue?
  16. (uid queue-uid)
  17. (head real-queue-head set-queue-head!)
  18. (tail queue-tail set-queue-tail!))
  19. (define queue-uid (list 0))
  20. (define (next-uid)
  21. (atomically
  22. (let ((uid (provisional-car queue-uid)))
  23. (provisional-set-car! queue-uid (+ uid 1))
  24. uid)))
  25. (define (make-queue)
  26. (really-make-queue (next-uid) '() '()))
  27. ; The procedures for manipulating queues.
  28. (define (queue-empty? q)
  29. (null? (real-queue-head q)))
  30. (define (enqueue! q v)
  31. (ensure-atomicity!
  32. (let ((p (cons v '())))
  33. (cond ((null? (real-queue-head q))
  34. (set-queue-head! q p))
  35. ((null? (queue-tail q)) ; someone got in first
  36. (invalidate-current-proposal!))
  37. (else
  38. (set-cdr! (queue-tail q) p)))
  39. (set-queue-tail! q p))))
  40. (define (queue-head q)
  41. (ensure-atomicity
  42. (if (queue-empty? q)
  43. (error "queue is empty" q)
  44. (car (real-queue-head q)))))
  45. (define (dequeue! q)
  46. (ensure-atomicity
  47. (let ((pair (real-queue-head q)))
  48. (cond ((null? pair) ;(queue-empty? q)
  49. (error "empty queue" q))
  50. (else
  51. (let ((value (car pair))
  52. (next (cdr pair)))
  53. (set-queue-head! q next)
  54. (if (null? next)
  55. (set-queue-tail! q '())) ; don't retain pointers
  56. value))))))
  57. ; Same again, except that we return #F if the queue is empty.
  58. ; This is a simple way of avoiding a race condition if the queue is known
  59. ; not to contain #F.
  60. (define (maybe-dequeue! q)
  61. (ensure-atomicity
  62. (let ((pair (real-queue-head q)))
  63. (cond ((null? pair) ;(queue-empty? q)
  64. #f)
  65. (else
  66. (let ((value (car pair))
  67. (next (cdr pair)))
  68. (set-queue-head! q next)
  69. (if (null? next)
  70. (set-queue-tail! q '())) ; don't retain pointers
  71. value))))))
  72. (define (empty-queue! q)
  73. (ensure-atomicity
  74. (set-queue-head! q '())
  75. (set-queue-tail! q '())))
  76. (define (on-queue? q v)
  77. (ensure-atomicity
  78. (memq v (real-queue-head q))))
  79. ; This removes the first occurrence of V from Q.
  80. (define (delete-from-queue! q v)
  81. (delete-from-queue-if! q
  82. (lambda (x)
  83. (eq? x v))))
  84. (define (delete-from-queue-if! q pred)
  85. (ensure-atomicity
  86. (let ((head (real-queue-head q)))
  87. (cond ((null? head)
  88. #f)
  89. ((pred (car head))
  90. (set-queue-head! q (cdr head))
  91. ;; force proposal check
  92. (set-queue-tail! q (if (null? (cdr head))
  93. '()
  94. (let ((p (queue-tail q)))
  95. (cons (car p) (cdr p)))))
  96. #t)
  97. ((null? (cdr head))
  98. #f)
  99. (else
  100. (let loop ((list head))
  101. (let ((tail (cdr list)))
  102. (cond ((null? tail)
  103. #f)
  104. ((pred (car tail))
  105. (set-cdr! list (cdr tail))
  106. ;; force proposal check
  107. (set-queue-head! q (cons (car head) (cdr head)))
  108. (set-queue-tail! q (if (null? (cdr tail))
  109. list
  110. (let ((p (queue-tail q)))
  111. (cons (car p) (cdr p)))))
  112. #t)
  113. (else
  114. (loop tail))))))))))
  115. (define (queue->list q)
  116. (ensure-atomicity
  117. (map (lambda (x) x)
  118. (real-queue-head q))))
  119. (define (list->queue list)
  120. (if (null? list)
  121. (make-queue)
  122. (let ((head (cons (car list) '())))
  123. (let loop ((rest (cdr list)) (tail head))
  124. (if (null? rest)
  125. (really-make-queue (next-uid) head tail)
  126. (begin
  127. (let ((next (cons (car rest) '())))
  128. (set-cdr! tail next)
  129. (loop (cdr rest) next))))))))
  130. (define (queue-length q)
  131. (ensure-atomicity
  132. (length (real-queue-head q))))