File: thread.zuo

package info (click to toggle)
zuo 1.12-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,352 kB
  • sloc: ansic: 6,374; makefile: 39
file content (164 lines) | stat: -rw-r--r-- 7,503 bytes parent folder | download | duplicates (5)
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#lang zuo

(require "harness.zuo")

(alert "threads")

(check (call-in-main-thread
        (lambda ()
          (define ch (channel))
          (define msgs (channel))
          (thread (lambda () (channel-put msgs (list "read" (channel-get ch)))))
          (thread (lambda () (channel-put msgs "write") (channel-put ch 'hello)))
          (list (channel-get msgs)
                (channel-get msgs))))
       '("write" ("read" hello)))

(check (call-in-main-thread
        (lambda ()
          (define ch (channel))
          (define go (channel))
          (for-each (lambda (i) (channel-put ch i)) '(a b c d))
          (thread (lambda ()
                    (for-each (lambda (v) (channel-put ch (list v (channel-get ch))))
                              '(1 2 3 4))
                    (channel-put go 'ok)))
          (channel-get go)
          (map (lambda (i) (channel-get ch)) '(_ _ _ _))))
       '((1 a) (2 b) (3 c) (4 d)))

(check (call-in-main-thread
        (lambda ()
          (define ch (channel))
          (define go (channel))
          (define ls '(a b c d))
          (for-each (lambda (i) (channel-put ch i)) ls)
          (for-each (lambda (v)
                      (thread (lambda ()
                                (channel-put ch (list v (channel-get ch)))
                                (channel-put go 'ok))))
                    (map symbol->string ls))
          (for-each (lambda (i) (channel-get go)) ls)
          (map (lambda (i) (channel-get ch)) '(_ _ _ _))))
       ;; this is the result for now, at least, since everything is deterministic
       ;; and the scheduler's enquring strategy adds a new thread to the front
       '(("d" a) ("c" b) ("b" c) ("a" d)))

;; Each thread starts a process, but the wait might immediately succeed every time
(check (let ([r (call-in-main-thread
                 (lambda ()
                   (define ch (channel))
                   (define ls '(a b c d))
                   (for-each (lambda (id)
                               (thread
                                (lambda ()
                                  (define p (process (hash-ref (runtime-env) 'exe)
                                                     ""
                                                     (~a id)
                                                     (hash 'stdin 'pipe 'stdout 'pipe)))
                                  (define to (hash-ref p 'stdin))
                                  (fd-write to (~a "#lang zuo\n"
                                                   (~s '(alert (hash-ref (runtime-env) 'args)))))
                                  (fd-close to)
                                  (define from (hash-ref p 'stdout))
                                  (define str (fd-read from eof))
                                  (fd-close from)
                                  (thread-process-wait (hash-ref p 'process))
                                  (channel-put ch str))))
                             ls)
                   (map (lambda (i) (channel-get ch)) ls)))])
         (and (= (length r) 4)
              (andmap (lambda (s) (member s r))
                      '("(list \"a\")\n" "(list \"b\")\n" "(list \"c\")\n" "(list \"d\")\n"))
              #t)))

;; Each thread starts a process, relies on the main thread to finish it
(check (let ([r (call-in-main-thread
                 (lambda ()
                   (define ch (channel))
                   (define done (channel))
                   (define ls '(a b c d))
                   (for-each (lambda (id)
                               (thread
                                (lambda ()
                                  (define p (process (hash-ref (runtime-env) 'exe)
                                                     ""
                                                     (~a id)
                                                     (hash 'stdin 'pipe 'stdout 'pipe)))
                                  (channel-put ch p)
                                  (thread-process-wait (hash-ref p 'process))
                                  (channel-put done 'ok))))
                             ls)
                   (define results
                     (map (lambda (i)
                            (define p (channel-get ch))
                            (define to (hash-ref p 'stdin))
                            (define from (hash-ref p 'stdout))
                            (fd-write to (~a "#lang zuo\n"
                                             (~s '(alert (hash-ref (runtime-env) 'args)))))
                            (fd-close to)
                            (define str (fd-read from eof))
                            (fd-close from)
                            str)
                          ls))
                   (for-each (lambda (id) (channel-get done)) ls)
                   results))])
         (and (= (length r) 4)
              (andmap (lambda (s) (member s r))
                      '("(list \"a\")\n" "(list \"b\")\n" "(list \"c\")\n" "(list \"d\")\n"))
              #t)))

;; Each thread starts a process, main thread waits on all
(check (let ([r (call-in-main-thread
                 (lambda ()
                   (define ch (channel))
                   (define go (channel))
                   (define ls '(a b c d))
                   (for-each (lambda (id)
                               (thread
                                (lambda ()
                                  (define p (process (hash-ref (runtime-env) 'exe)
                                                     ""
                                                     (~a id)
                                                     (hash 'stdin 'pipe 'stdout 'pipe)))
                                  (channel-put ch (hash-ref p 'process))
                                  (channel-get go)
                                  (define to (hash-ref p 'stdin))
                                  (fd-write to (~a "#lang zuo\n"
                                                   (~s '(alert (hash-ref (runtime-env) 'args)))))
                                  (fd-close to)
                                  (define from (hash-ref p 'stdout))
                                  (define str (fd-read from eof))
                                  (fd-close from)
                                  (channel-put ch str))))
                             ls)
                   (define ps (map (lambda (i) (channel-get ch)) ls))
                   (for-each (lambda (i) (channel-put go i)) ls)
                   (let loop ([ps ps])
                     (unless (null? ps)
                       (define p (apply thread-process-wait ps))
                       (loop (remove p ps))))
                   (map (lambda (i) (channel-get ch)) ls)))])
         (and (= (length r) 4)
              (andmap (lambda (s) (member s r))
                      '("(list \"a\")\n" "(list \"b\")\n" "(list \"c\")\n" "(list \"d\")\n"))
              #t)))

(check-fail (begin
              (require zuo/thread)
              (call-in-main-thread
               (lambda () (channel-get (channel)))))
            "main thread is stuck")

(check-fail (begin
              (require zuo/thread)
              (call-in-main-thread
               (lambda ()
                 ((call/prompt (lambda () (call/cc (lambda (k) k)))) 0))))
            "main thread is stuck")

(check (channel-try-get (channel)) #f)
(check (let ([ch (channel)])
         (channel-put ch "x")
         (channel-try-get ch))
       "x")