-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathb_program.rb
141 lines (125 loc) · 2.69 KB
/
b_program.rb
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
require 'rubygems'
require 'continuation'
class BProgram
attr_accessor :arbiter, :bthreads, :le,
:in_pipe, :out_pipe, :emitq,
:cont, :return_cont
def initialize(arbiter)
@le = :startevent
@arbiter = arbiter
@bthreads = []
@in_pipe = []
@out_pipe = []
@emitq = []
end
def start
p "starting program"
callcc do |cc|
@return_cont = cc
bp_loop
end
end
def bp_loop
# p "BP loop!"
resume_bthreads
delete_finished_bthreads
# p "checking if all bthreads finished"
if bthreads.empty?
p "all finished!"
push_out_pipe
@return_cont.call
end
# p "not all finished"
arbiter.next_event
@le = arbiter.next_event
if !@le && !@in_pipe.empty?
@le = @in_pipe.shift
end
if (@le)
bp_loop
else
push_out_pipe
# p "waiting for external event..."
@return_cont.call
end
end
def resume_bthreads
# puts "#of bthreads: #{bthreads.length}"
bthreads.each do |bt|
wait = bt.wait.include? @le
# p "%s : %s in req+wait?" % [bt.inspect, @le.inspect]
req = bt.request.include? @le
if req || wait
# p "resuming %s " % bt.inspect
resume bt, @le
end
end
end
def push_out_pipe
while [email protected]? do
ev = @emitq.shift
# p "emitting #{ev.inspect}"
@out_pipe.push ev
end
end
def delete_finished_bthreads
bthreads.delete_if do |bt|
if (!bt.alive?)
# p "deleted bthread " + bt.inspect
end
!bt.alive?
end
end
def fire(ev)
if @in_pipe.empty?
@le = ev
callcc do |cc|
@return_cont = cc
bp_loop
end
else
@in_pipe.push ev
end
end
def back_to_caller
push_out_pipe
# p "returned to caller..."
@return_cont.call
end
def emit(ev)
# p "added #{ev.inspect} to emitq"
@emitq.push ev
end
def resume(bt, le)
callcc do |cc|
@cont = cc
bt.resume le
end
end
def bsync
@cont.call
end
# legal events to trigger can only be req&&!block
def legal_events
requested = []
bthreads.each do |bt|
# p "%s asked for %s" %[bt.inspect, bt.request.inspect]
requested.concat Array(bt.request)
end
if requested.empty?
# p "nothing was requested"
return []
end
requested.uniq!
bthreads.each do |bt|
requested.delete_if { |ev|
del = bt.block.include? ev
# p "%s blocks %s" %[bt.inspect, ev.inspect] if del
del
}
end
# added in_pipe drawing to implicitly trigger the external events
# without the need to artificially check for them
requested || @in_pipe.shift
end
end