File: coop_threads.pir

package info (click to toggle)
parrot 6.6.0-1
  • links: PTS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 25,164 kB
  • ctags: 16,050
  • sloc: ansic: 110,715; perl: 94,382; yacc: 1,911; lex: 1,529; lisp: 1,163; cpp: 782; python: 646; ruby: 335; sh: 140; makefile: 129; cs: 49; asm: 30
file content (168 lines) | stat: -rw-r--r-- 2,756 bytes parent folder | download
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 subs and main function

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: