File: scheduler.scm

package info (click to toggle)
scheme48 1.9.2-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 18,232 kB
  • sloc: lisp: 88,907; ansic: 87,519; sh: 3,224; makefile: 771
file content (146 lines) | stat: -rw-r--r-- 4,333 bytes parent folder | download | duplicates (4)
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
; Part of Scheme 48 1.9.  See file COPYING for notices and license.

; Authors: Richard Kelsey, Jonathan Rees, Mike Sperber, Suresh Jagannathan, 
; Henry Ceijtin

; A parameterized scheduler.

; (run-threads event-handler) -> unspecific
;   (event-handler thread time-left event event-data) -> [thread args time]
; A bogus BLOCKED event is passed to the handler to get the initial thread.

(define (run-threads event-handler)
  (call-with-values
   (lambda ()
     (event-handler #f 0 (enum event-type blocked) '()))
   (lambda (thread time)
     (if thread
	 (let loop ((thread thread) (time time))
	   (call-with-values
	    (lambda ()
	      (run thread time))
	    (lambda (time-left event . event-data)
	      (call-with-values
	       (lambda ()
		 (event-handler thread time-left event event-data))
	       (lambda (thread time)
		 (if thread
		     (loop thread time)))))))))))
	    
; Same thing, with the addition of a housekeeping thunk that gets
; run periodically.

(define (run-threads-with-housekeeper event-handler housekeeper delay)
  (call-with-values
   (lambda ()
     (event-handler #f 0 (enum event-type blocked) '()))
   (lambda (thread time)
     (if thread
	 (let loop ((thread thread) (time time) (hk-time delay))
	   (call-with-values
	    (lambda ()
	      (run thread time))
	    (lambda (time-left event . event-data)
	      (let ((hk-time (let ((temp (- hk-time (- time time-left))))
			       (if (<= temp 0)
				   (begin
				     (housekeeper)
				     delay)
				   temp))))
		(call-with-values
		 (lambda ()
		   (event-handler thread time-left event event-data))
		 (lambda (thread time)
		   (if thread
		       (loop thread time hk-time))))))))))))

; An event-handler that does round-robin scheduling.
; Arguments:
;    runnable         ; queue of threads
;    quantum          ; number of ticks each thread gets
;    dynamic-env      ; initial dynamic environments for new threads
;    thread-count     ; counter tracking the number of threads
;    event-handler : event-type event-data -> handled?
;    upcall-handler : thread token . args -> return-values
;    wait             ; thunk returns #t if scheduling is to continue

(define (round-robin-event-handler runnable quantum dynamic-env thread-count
				   event-handler upcall-handler wait)

  (define (thread-event-handler thread time-left event event-data)
    (enum-case event-type event

      ;; the thread stops, either temporarily or permanently
      ((blocked)
       (next-thread))
      ((completed killed)
       (decrement-counter! thread-count)
       (next-thread))
      ((out-of-time)
       (enqueue! runnable thread)
       (next-thread))

      ;; the thread keeps running
      ((upcall)
       (call-with-values
	(lambda ()
	  (apply upcall-handler event-data))
	(lambda results
	  (set-thread-arguments! thread results)
	  (values thread time-left))))
      (else
       (asynchronous-event-handler event event-data)
       (values thread time-left))))

  ;; We call EVENT-HANDLER first so that it can override the default behavior
  (define (asynchronous-event-handler event event-data)
    (or (event-handler event event-data)
	(enum-case event-type event
	  ((runnable)
	   (enqueue! runnable (car event-data)))
	  ((spawned)
	   (increment-counter! thread-count)
	   (let ((thread (car event-data)))
	     (set-thread-dynamic-env! thread dynamic-env)
	     (set-thread-scheduler! thread (current-thread))
	     (enqueue! runnable thread)))
	  ((no-event)
	   (values))
	  (else
	   (assertion-violation 'asynchronous-event-handler "unhandled event"
				(cons (enumerand->name event event-type)
				      event-data)
				event-handler)))))

  (define (next-thread)
    (if (queue-empty? runnable)
	(call-with-values
	  get-next-event!
	  (lambda (event . data)
	    (cond ((not (eq? event (enum event-type no-event)))
		   (asynchronous-event-handler event data)
		   (next-thread))
		  ((wait)
		   (next-thread))
		  (else
		   (values #f 0)))))
	(values (dequeue! runnable)
		quantum)))

  thread-event-handler)

; Simple counting cell

(define (make-counter)
  (list 0))

(define counter-value car)

(define (increment-counter! count)
  (set-car! count (+ 1 (car count))))

(define (decrement-counter! count)
  (set-car! count (- (car count) 1)))

(define (set-counter! count val)
  (set-car! count val))