summaryrefslogtreecommitdiff
path: root/fibers/repl.scm
blob: afb9dc14ae7575f8dde6f4b29f9d548755c2e6fb (about) (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
;; Fibers: cooperative, event-driven user-space threads.

;;;; Copyright (C) 2016 Free Software Foundation, Inc.
;;;;
;;;; This library is free software; you can redistribute it and/or
;;;; modify it under the terms of the GNU Lesser General Public
;;;; License as published by the Free Software Foundation; either
;;;; version 3 of the License, or (at your option) any later version.
;;;;
;;;; This library is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;;;; Lesser General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU Lesser General Public
;;;; License along with this library; if not, write to the Free Software
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;;;;

(define-module (fibers repl)
  #:use-module (system repl common)
  #:use-module (system repl command)
  #:use-module (ice-9 match)
  #:use-module (ice-9 format)
  #:use-module ((ice-9 threads) #:select (call-with-new-thread))
  #:use-module (fibers)
  #:use-module (fibers internal))

(define (sleep-forever)
  (let lp () (sleep 3600) (lp)))

(define repl-current-scheds (make-doubly-weak-hash-table))
(define (repl-current-sched repl)
  (hashq-ref repl-current-scheds repl))
(define (repl-set-current-sched! repl sched verbose?)
  (when verbose?
    (format #t "Scheduler ~a on thread ~a is now current\n."
            (scheduler-name sched) (scheduler-kernel-thread sched)))
  (hashq-set! repl-current-scheds repl sched))
(define* (repl-ensure-current-sched repl #:optional (verbose? #t))
  (define (sched-alive? sched)
    ;; FIXME: ensure scheduler has not been destroyed.
    (and (scheduler-kernel-thread sched)))
  (or (repl-current-sched repl)
      (let lp ((scheds (fold-all-schedulers acons '())))
        (match scheds
          (()
           (let* ((sched (make-scheduler))
                  (thread (call-with-new-thread
                           (lambda ()
                             (run-fibers sleep-forever
                                         #:scheduler sched)))))
             (when verbose?
               (format #t "No active schedulers; spawned a new one.\n"))
             (repl-set-current-sched! repl sched verbose?)
             sched))
          (((id . (and sched (? sched-alive?))) . scheds)
           (when verbose?
             (format #t "No current scheduler; choosing one randomly.\n"))
           (repl-set-current-sched! repl sched verbose?)
           sched)))))

(define-meta-command ((scheds fibers) repl)
  "scheds
Show a list of schedulers."
  (match (sort (fold-all-schedulers acons '())
               (match-lambda*
                 (((id1 . _) (id2 . _)) (< id1 id2))))
    (() (format #t "No schedulers.\n"))
    (schedulers
     (format #t "~a ~8t~a\n" "sched" "kernel thread")
     (format #t "~a ~8t~a\n" "-----" "-------------")
     (for-each
      (match-lambda
        ((id . sched)
         (format #t "~a ~8t~a\n" id (scheduler-kernel-thread sched))))
      schedulers))))

(define-meta-command ((spawn-sched fibers) repl)
  "spawn-sched
Create a new scheduler for fibers, and run it on a new kernel thread."
  (call-with-new-thread (lambda ()
                          (run-fibers sleep-forever))))

(define-meta-command ((kill-sched fibers) repl sched)
  "kill-sched SCHED
Shut down a scheduler."
  (display "Don't know how to do that yet!\n"))

(define-meta-command ((fibers fibers) repl #:optional sched)
  "fibers [SCHED]
Show a list of fibers.

If SCHED is given, limit to fibers bound to the given scheduler."
  (let ((sched (and sched
                    (or (scheduler-by-name sched)
                        (error "no scheduler with name" sched)))))
    (match (sort (fold-all-fibers acons '())
                 (match-lambda*
                   (((id1 . _) (id2 . _)) (< id1 id2))))
      (() (format #t "No fibers.\n"))
      (fibers
       (format #t "~a ~8t~a\n" "fiber" "state")
       (format #t "~a ~8t~a\n" "-----" "-----")
       (for-each
        (match-lambda
          ((id . fiber)
           ;; How to show fiber data?  Would be nice to say "suspended
           ;; at foo.scm:32:4".
           (when (or (not sched) (eq? (fiber-scheduler fiber) sched))
             (format #t "~a ~8t~a\n" id
                     (if (fiber-continuation fiber) "(suspended)" "")))))
        fibers)))))

(define-meta-command ((spawn-fiber fibers) repl (form) #:optional sched)
  "spawn-fiber EXP [SCHED]
Spawn a new fiber that runs EXP.

If SCHED is given, the fiber will be spawned on the given scheduler."
  (let ((thunk (repl-prepare-eval-thunk repl (repl-parse repl form)))
        (sched (repl-ensure-current-sched repl)))
    (spawn-fiber thunk sched)))

(define-meta-command ((kill-fiber fibers) repl fiber)
  "kill-fiber FIBER
Shut down a fiber."
  (display "Don't know how to do that yet!\n"))