Skip to content

Commit 3d70abb

Browse files
committed
Add initial support of lightweight thread.
1 parent be49a9e commit 3d70abb

File tree

3 files changed

+108
-0
lines changed

3 files changed

+108
-0
lines changed

mrbgem.rake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ MRuby::Gem::Specification.new('mruby-uv') do |spec|
44
spec.summary = 'libuv mruby binding'
55
spec.add_dependency 'mruby-time', core: 'mruby-time'
66
spec.add_dependency 'mruby-sprintf', core: 'mruby-sprintf'
7+
spec.add_dependency 'mruby-fiber', core: 'mruby-fiber'
78

89
def self.run_command(env, command)
910
fail "#{command} failed" unless system(env, command)

mrblib/yarn.rb

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
module UV
2+
def self.sleep sec
3+
current_yarn.sleep sec
4+
end
5+
6+
def self.current_yarn
7+
ret = UV.current_loop.current_yarn
8+
raise "yarn not running" if ret.nil?
9+
ret
10+
end
11+
12+
class Loop
13+
attr_reader :current_yarn
14+
15+
def current_yarn=(y)
16+
raise "cannot double run yarn" if current_yarn
17+
raise "not yarn" unless y.kind_of? UV::Yarn
18+
19+
@current_yarn = y
20+
end
21+
22+
def clear_current_yarn
23+
@current_yarn = nil
24+
end
25+
end
26+
27+
class Yarn
28+
def initialize(loop = UV.current_loop, &blk)
29+
@fiber = Fiber.new(&blk)
30+
@loop = loop
31+
end
32+
33+
attr_reader :loop, :error
34+
35+
def ended?; @fiber.nil? end
36+
def result
37+
raise "not ended" unless ended?
38+
@result
39+
end
40+
41+
def check_error
42+
raise @error if @error
43+
end
44+
45+
def timer
46+
@timer ||= UV::Timer.new
47+
# raise 'timer already used' if @timer.active?
48+
@timer
49+
end
50+
51+
def to_proc
52+
@proc ||= Proc.new{|*args, &blk| self.resume(*args, &blk) }
53+
end
54+
55+
def start(*args)
56+
raise "already started" if @started
57+
@started = true
58+
59+
resume(*args)
60+
end
61+
62+
def sleep sec
63+
timer.start(sec * 1000.0, 0) do
64+
self.resume
65+
end
66+
Fiber.yield(timer, self)
67+
end
68+
69+
def resume(*args)
70+
raise "cannot resume unstarted yarn" unless @started
71+
raise "cannot run ended yarn" if ended?
72+
73+
@loop.current_yarn = self
74+
75+
prev_loop = UV.current_loop
76+
@loop.make_current
77+
78+
*ret = @fiber.resume(*args)
79+
80+
if @fiber.alive?
81+
raise "invalid yield" if !ret.first.kind_of?(UV::Req) && !ret.first.kind_of?(UV::Timer)
82+
else
83+
@fiber = nil
84+
@result = ret
85+
end
86+
87+
rescue => e
88+
@error = e
89+
90+
ensure
91+
@loop.clear_current_yarn
92+
prev_loop.make_current if prev_loop
93+
end
94+
end
95+
end

test/yarn.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
assert "Yarn" do
2+
y = UV::Yarn.new do
3+
t = UV.current_loop.now
4+
UV.sleep 0.1
5+
assert_true (UV.current_loop.now - t) >= 100
6+
UV.sleep 0.1
7+
assert_true (UV.current_loop.now - t) >= 200
8+
end
9+
10+
y.start
11+
y.loop.run
12+
end

0 commit comments

Comments
 (0)