scheduler.scm 4.1 KB

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