scheduler.scm 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. ; Authors: Richard Kelsey, Jonathan Rees, Mike Sperber, Suresh Jagannathan,
  3. ; Henry Ceijtin
  4. ; A parameterized scheduler.
  5. ; (run-threads event-handler) -> unspecific
  6. ; (event-handler thread time-left event event-data) -> [thread args time]
  7. ; A bogus BLOCKED event is passed to the handler to get the initial thread.
  8. (define (run-threads event-handler)
  9. (call-with-values
  10. (lambda ()
  11. (event-handler #f 0 (enum event-type blocked) '()))
  12. (lambda (thread time)
  13. (if thread
  14. (let loop ((thread thread) (time time))
  15. (call-with-values
  16. (lambda ()
  17. (run thread time))
  18. (lambda (time-left event . event-data)
  19. (call-with-values
  20. (lambda ()
  21. (event-handler thread time-left event event-data))
  22. (lambda (thread time)
  23. (if thread
  24. (loop thread time)))))))))))
  25. ; Same thing, with the addition of a housekeeping thunk that gets
  26. ; run periodically.
  27. (define (run-threads-with-housekeeper event-handler housekeeper delay)
  28. (call-with-values
  29. (lambda ()
  30. (event-handler #f 0 (enum event-type blocked) '()))
  31. (lambda (thread time)
  32. (if thread
  33. (let loop ((thread thread) (time time) (hk-time delay))
  34. (call-with-values
  35. (lambda ()
  36. (run thread time))
  37. (lambda (time-left event . event-data)
  38. (let ((hk-time (let ((temp (- hk-time (- time time-left))))
  39. (if (<= temp 0)
  40. (begin
  41. (housekeeper)
  42. delay)
  43. temp))))
  44. (call-with-values
  45. (lambda ()
  46. (event-handler thread time-left event event-data))
  47. (lambda (thread time)
  48. (if thread
  49. (loop thread time hk-time))))))))))))
  50. ; An event-handler that does round-robin scheduling.
  51. ; Arguments:
  52. ; runnable ; queue of threads
  53. ; quantum ; number of ticks each thread gets
  54. ; dynamic-env ; initial dynamic environments for new threads
  55. ; thread-count ; counter tracking the number of threads
  56. ; event-handler : event-type event-data -> handled?
  57. ; upcall-handler : thread token . args -> return-values
  58. ; wait ; thunk returns #t if scheduling is to continue
  59. (define (round-robin-event-handler runnable quantum dynamic-env thread-count
  60. event-handler upcall-handler wait)
  61. (define (thread-event-handler thread time-left event event-data)
  62. (enum-case event-type event
  63. ;; the thread stops, either temporarily or permanently
  64. ((blocked)
  65. (next-thread))
  66. ((completed killed)
  67. (decrement-counter! thread-count)
  68. (next-thread))
  69. ((out-of-time)
  70. (enqueue! runnable thread)
  71. (next-thread))
  72. ;; the thread keeps running
  73. ((upcall)
  74. (call-with-values
  75. (lambda ()
  76. (apply upcall-handler event-data))
  77. (lambda results
  78. (set-thread-arguments! thread results)
  79. (values thread time-left))))
  80. (else
  81. (asynchronous-event-handler event event-data)
  82. (values thread time-left))))
  83. ;; We call EVENT-HANDLER first so that it can override the default behavior
  84. (define (asynchronous-event-handler event event-data)
  85. (or (event-handler event event-data)
  86. (enum-case event-type event
  87. ((runnable)
  88. (enqueue! runnable (car event-data)))
  89. ((spawned)
  90. (increment-counter! thread-count)
  91. (let ((thread (car event-data)))
  92. (set-thread-dynamic-env! thread dynamic-env)
  93. (set-thread-scheduler! thread (current-thread))
  94. (enqueue! runnable thread)))
  95. ((no-event)
  96. (values))
  97. (else
  98. (assertion-violation 'asynchronous-event-handler "unhandled event"
  99. (cons (enumerand->name event event-type)
  100. event-data)
  101. event-handler)))))
  102. (define (next-thread)
  103. (if (queue-empty? runnable)
  104. (call-with-values
  105. get-next-event!
  106. (lambda (event . data)
  107. (cond ((not (eq? event (enum event-type no-event)))
  108. (asynchronous-event-handler event data)
  109. (next-thread))
  110. ((wait)
  111. (next-thread))
  112. (else
  113. (values #f 0)))))
  114. (values (dequeue! runnable)
  115. quantum)))
  116. thread-event-handler)
  117. ; Simple counting cell
  118. (define (make-counter)
  119. (list 0))
  120. (define counter-value car)
  121. (define (increment-counter! count)
  122. (set-car! count (+ 1 (car count))))
  123. (define (decrement-counter! count)
  124. (set-car! count (- (car count) 1)))
  125. (define (set-counter! count val)
  126. (set-car! count val))