repl.scm 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. ;; Fibers: cooperative, event-driven user-space threads.
  2. ;;;; Copyright (C) 2016 Free Software Foundation, Inc.
  3. ;;;;
  4. ;;;; This library is free software; you can redistribute it and/or
  5. ;;;; modify it under the terms of the GNU Lesser General Public
  6. ;;;; License as published by the Free Software Foundation; either
  7. ;;;; version 3 of the License, or (at your option) any later version.
  8. ;;;;
  9. ;;;; This library is distributed in the hope that it will be useful,
  10. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. ;;;; Lesser General Public License for more details.
  13. ;;;;
  14. ;;;; You should have received a copy of the GNU Lesser General Public
  15. ;;;; License along with this library; if not, write to the Free Software
  16. ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. ;;;;
  18. (define-module (fibers repl)
  19. #:use-module (system repl common)
  20. #:use-module (system repl command)
  21. #:use-module (ice-9 match)
  22. #:use-module (ice-9 format)
  23. #:use-module ((ice-9 threads)
  24. #:select (call-with-new-thread cancel-thread join-thread))
  25. #:use-module (fibers)
  26. #:use-module (fibers nameset)
  27. #:use-module (fibers scheduler))
  28. (define-once schedulers-nameset (make-nameset))
  29. (define (fold-all-schedulers f seed)
  30. "Fold @var{f} over the set of known schedulers. @var{f} will be
  31. invoked as @code{(@var{f} @var{name} @var{scheduler} @var{seed})}."
  32. (nameset-fold f schedulers-nameset seed))
  33. (define (scheduler-by-name name)
  34. "Return the scheduler named @var{name}, or @code{#f} if no scheduler
  35. of that name is known."
  36. (nameset-ref schedulers-nameset name))
  37. (define repl-current-scheds (make-doubly-weak-hash-table))
  38. (define (repl-current-sched repl)
  39. (hashq-ref repl-current-scheds repl))
  40. (define (repl-set-current-sched! repl name sched verbose?)
  41. (when verbose?
  42. (format #t "Scheduler ~a on thread ~a is now current\n."
  43. name (scheduler-kernel-thread sched)))
  44. (hashq-set! repl-current-scheds repl sched))
  45. (define* (repl-ensure-current-sched repl #:optional (verbose? #t))
  46. (define (sched-alive? sched)
  47. ;; FIXME: ensure scheduler has not been destroyed.
  48. (and (scheduler-kernel-thread sched)))
  49. (or (repl-current-sched repl)
  50. (let lp ((scheds (fold-all-schedulers acons '())))
  51. (match scheds
  52. (()
  53. (let* ((sched (make-scheduler))
  54. (name (nameset-add! schedulers-nameset sched))
  55. (thread (call-with-new-thread
  56. (lambda ()
  57. (run-fibers #:scheduler sched)))))
  58. (when verbose?
  59. (format #t "No active schedulers; spawned a new one (#~a).\n"
  60. name))
  61. (repl-set-current-sched! repl name sched verbose?)
  62. sched))
  63. (((id . (and sched (? sched-alive?))) . scheds)
  64. (when verbose?
  65. (format #t "No current scheduler; choosing scheduler #~a randomly.\n"
  66. id))
  67. (repl-set-current-sched! repl id sched verbose?)
  68. sched)))))
  69. (define-meta-command ((scheds fibers) repl)
  70. "scheds
  71. Show a list of schedulers."
  72. (match (sort (fold-all-schedulers acons '())
  73. (match-lambda*
  74. (((id1 . _) (id2 . _)) (< id1 id2))))
  75. (() (format #t "No schedulers.\n"))
  76. (schedulers
  77. (format #t "~a ~8t~a\n" "sched" "kernel thread")
  78. (format #t "~a ~8t~a\n" "-----" "-------------")
  79. (for-each
  80. (match-lambda
  81. ((id . sched)
  82. (format #t "~a ~8t~a\n" id (scheduler-kernel-thread sched))))
  83. schedulers))))
  84. (define-meta-command ((spawn-sched fibers) repl)
  85. "spawn-sched
  86. Create a new scheduler for fibers, and run it on a new kernel thread."
  87. (let* ((sched (make-scheduler))
  88. (name (nameset-add! schedulers-nameset sched)))
  89. (call-with-new-thread (lambda ()
  90. (call-with-new-thread
  91. (lambda ()
  92. (run-fibers #:scheduler sched)))))
  93. (format #t "Spawned scheduler #~a.\n" name)))
  94. (define-meta-command ((kill-sched fibers) repl name)
  95. "kill-sched NAME
  96. Shut down a scheduler."
  97. (let ((sched (or (scheduler-by-name name)
  98. (error "no scheduler with name" name))))
  99. (cond
  100. ((scheduler-kernel-thread sched)
  101. => (lambda (thread)
  102. (format #t "Killing thread running scheduler #~a...\n" name)
  103. (cancel-thread thread)
  104. (join-thread thread)
  105. (format #t "Thread running scheduler #~a stopped.\n" name)))
  106. (else
  107. (format #t "Scheduler #~a not running.\n" name)))))
  108. (define-meta-command ((spawn-fiber fibers) repl (form) #:optional sched)
  109. "spawn-fiber EXP [SCHED]
  110. Spawn a new fiber that runs EXP.
  111. If SCHED is given, the fiber will be spawned on the given scheduler."
  112. (let ((thunk (repl-prepare-eval-thunk repl (repl-parse repl form)))
  113. (sched (repl-ensure-current-sched repl)))
  114. (spawn-fiber thunk sched)))