-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathexample_multitasking.ss
109 lines (86 loc) · 2.82 KB
/
example_multitasking.ss
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
(library (schemesh example multitasking (0 8 1))
(export
tasks make-task task-yield task-resume)
(import
(rnrs)
(only (chezscheme) logbit? procedure-arity-mask void)
(only (schemesh bootstrap) assert*)
(schemesh containers span))
(define tasks
(let ((sp (span)))
(lambda () sp)))
(define-record-type
(task %make-task task?)
(fields
id
(mutable status) ; one of: 'new 'running 'failed
(mutable result)
start-proc
(mutable resume-proc)
(mutable yield-proc))
(nongenerative #{task hvcyofcpj596hi922bdsnfbh9-3}))
(define (task-find task-or-id)
(let ((all (tasks))
(x task-or-id))
(cond
((task? x)
x)
((and (fixnum? x) (fx<? -1 x (span-length all)))
(span-ref all x))
(else
#f))))
(define (task-end task result)
(task-status-set! task 'failed)
(task-result-set! task result)
result)
(define (make-task start-proc)
(assert* 'make-task (procedure? start-proc))
(assert* 'make-task (logbit? 1 (procedure-arity-mask start-proc)))
(let* ((all (tasks))
(id (span-length all))
(wrapper-proc
(lambda (task)
(task-end task (start-proc task))))
(task (%make-task id 'new #f wrapper-proc #f #f)))
(span-insert-right! all task)
task))
;; resume running task. returns when task calls (task-end) or (task-yield)
(define (task-resume task-or-id)
(let ((task (task-find task-or-id)))
(assert* 'task-resume task)
(call/cc
;; Capture the continuation representing THIS call to task-resume
(lambda (susp)
(let ((proc (case (task-status task)
((new failed) (task-start-proc task))
((running) (task-resume-proc task))
(else #f))))
(when proc
(task-status-set! task 'running)
(task-result-set! task #f)
(task-yield-proc-set! task susp)
(proc task)))))))
;; yield this task and return intermediate-result to whoever called (task-resume task)
(define (task-yield task intermediate-result)
(assert* 'task-yield (task-yield-proc task))
(call/cc
;; Capture the continuation representing THIS call to task-yield
(lambda (cont)
;; store it as task's resume-proc
(task-resume-proc-set! task (lambda (task) (cont)))
;; yield task, i.e. call its yield-proc, and also unset yield-proc
(let ((yield (task-yield-proc task)))
(task-yield-proc-set! task #f)
(yield intermediate-result)))))
) ; close library
(import (schemesh example multitasking))
(make-task
(lambda (task)
(format #t "I am task ~s\n" task)
(task-yield task 42)
(format #t "I am still task ~s\n" task)
(task-yield task 43)
(format #t "I am really task ~s\n" task)
; (task-end task 44)
44))
(void)