scheduler.scm 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. ;;; Scheduler
  2. ;;; Copyright (C) 2024 David Thompson <dave@spritely.institute>
  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. ;;; Commentary:
  16. ;;;
  17. ;;; A simple scheduler for testing fibers.
  18. ;;;
  19. ;;; Code:
  20. (define-module (hoot scheduler)
  21. #:use-module (hoot binary-heap)
  22. #:use-module (ice-9 match)
  23. #:use-module (ice-9 q)
  24. #:use-module (srfi srfi-9)
  25. #:use-module (srfi srfi-9 gnu)
  26. #:export (make-scheduler
  27. scheduler?
  28. scheduler-empty?
  29. scheduler-run!
  30. scheduler-delay!
  31. scheduler-clear!
  32. scheduler-tick!))
  33. (define-record-type <scheduler>
  34. (%make-scheduler current-jiffy run-queue delayed-tasks)
  35. scheduler?
  36. (current-jiffy scheduler-current-jiffy)
  37. (run-queue scheduler-run-queue)
  38. (delayed-tasks scheduler-delayed-tasks))
  39. (define (print-scheduler scheduler port)
  40. (format port "#<scheduler ~a>" (object-address scheduler)))
  41. (set-record-type-printer! <scheduler> print-scheduler)
  42. ;; Tasks are stored as (time . thunk) pairs.
  43. (define (task<? a b)
  44. (< (car a) (car b)))
  45. (define (make-scheduler current-jiffy)
  46. (%make-scheduler current-jiffy (make-q) (make-heap task<?)))
  47. (define (scheduler-empty? scheduler)
  48. "Return #t if there are no tasks currently in @var{scheduler}."
  49. (and (heap-empty? (scheduler-delayed-tasks scheduler))
  50. (q-empty? (scheduler-run-queue scheduler))))
  51. (define (scheduler-run! scheduler thunk)
  52. "Schedule @var{thunk} to be applied before the end of the current turn of
  53. @var{scheduler}."
  54. (enq! (scheduler-run-queue scheduler) thunk))
  55. (define (scheduler-delay! scheduler thunk delay)
  56. "Schedule @var{thunk} to be applied after @var{delay} jiffies have
  57. passed."
  58. (match scheduler
  59. (($ <scheduler> current-jiffy _ tasks)
  60. (heap-insert! tasks (cons (+ (current-jiffy) delay) thunk)))))
  61. (define (scheduler-clear! scheduler)
  62. "Clear all tasks from @var{scheduler}."
  63. (let ((q (scheduler-run-queue scheduler)))
  64. (let lp ()
  65. (unless (q-empty? q)
  66. (deq! q)
  67. (lp)))
  68. (heap-clear! (scheduler-delayed-tasks scheduler))))
  69. (define (scheduler-tick! scheduler)
  70. "Run delayed tasks in @var{scheduler} whose timeout has passed and then
  71. run all tasks in the run queue."
  72. (match scheduler
  73. (($ <scheduler> current-jiffy q tasks)
  74. (let ((time (current-jiffy)))
  75. ;; Run all tasks whose time has come.
  76. (let lp ()
  77. (unless (heap-empty? tasks)
  78. (match (heap-min tasks)
  79. ((task-time . thunk)
  80. (when (<= task-time time)
  81. (heap-remove! tasks)
  82. (thunk)
  83. (lp))))))
  84. ;; Flush the run queue.
  85. (let lp ()
  86. (unless (q-empty? q)
  87. ((deq! q))
  88. (lp)))))))