-
Notifications
You must be signed in to change notification settings - Fork 138
/
coop_threads.pir
168 lines (113 loc) · 2.67 KB
/
coop_threads.pir
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
165
166
167
168
# Copyright (C) 2010-2012, Parrot Foundation.
# $Id$
=head1 DESCRIPTION
This file demonstrates cooperative concurrency using continuations on Parrot.
See also http://www.parrot.org/content/threads-are-continuations
=cut
=head1 th_init
First, we create an array to store unscheduled threads in. For simplicity,
this is stored in a global.
=cut
.include 'interpinfo.pasm'
.sub th_init
$P0 = new 'ResizablePMCArray'
set_global 'threads', $P0
.end
=head1 th_create
This is the 'spawn' call. It takes a sub and schedules it to run as a
thread.
=cut
.sub th_create
.param pmc in_sub
$P0 = get_global 'threads'
push $P0, in_sub
.end
=head1 th_resched
This is the 'yield' call. When called from a running thread, it saves the
current point in the computation as a continuation and runs the next thread.
=cut
.sub th_resched
.local pmc cur_th, next_th, ths
ths = get_global 'threads'
# This gets the return continuation for the currently running sub.
# When this continuation is invoked, it will be as if this call
# to th_resched just returned.
cur_th = interpinfo .INTERPINFO_CURRENT_CONT
push ths, cur_th
again:
next_th = shift ths
invokecc next_th
$I0 = ths
if $I0 > 0 goto again
.end
=head1 th_main
This starts up the thread system (after some threads have been scheduled) and makes
sure the program doesn't exit before all the threads have run to completion.
=cut
.sub th_main
.local pmc ths
again1:
ths = get_global 'threads'
$I0 = ths
if $I0 <= 0 goto done
th_resched()
goto again1
done:
.end
=head1
That's it. All we need now is some test threads and a main function to run them.
=cut
.sub sub1
say "sub1: Hallo"
th_resched()
say "sub1: Dance! <(\"< >\")> <(\"<"
th_resched()
say "sub1: Bye"
.end
.sub sub2
say "sub2: Hallo"
th_resched()
say "sub2: Dance! >\")> <(\"< >\")>"
th_resched()
say "sub2: Bye"
.end
.sub sub3
say "sub3: Good morning"
th_resched()
$I0 = 5
$I1 = $I0 + 3
th_resched()
print "sub3: 5 + 3 = "
say $I1
th_resched()
say "sub3: Is leaving."
.end
.sub main :main
th_init()
$P0 = get_global 'sub1'
th_create($P0)
$P0 = get_global 'sub3'
th_create($P0)
$P0 = get_global 'sub2'
th_create($P0)
th_main()
say "All done"
.end
=head1 EXPECTED OUTPUT
The program should (and does) produce this output:
sub1: Hallo
sub3: Good morning
sub2: Hallo
sub1: Dance! <("< >")> <("<
sub2: Dance! >")> <("< >")>
sub1: Bye
sub3: 5 + 3 = 8
sub2: Bye
sub3: Is leaving.
All done
=cut
# Local Variables:
# mode: pir
# fill-column: 100
# End:
# vim: expandtab shiftwidth=4 ft=pir: