mame-threadfiber 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3 @@
1
+ === 1.0.0 / 2008-08-24
2
+
3
+ * first release.
@@ -0,0 +1,6 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ lib/threadfiber.rb
6
+ test/test_threadfiber.rb
@@ -0,0 +1,36 @@
1
+ = threadfiber
2
+
3
+ * http://github.com/mame/threadfiber/tree/master
4
+
5
+ == DESCRIPTION:
6
+
7
+ ThreadFiber is an implementation of fiber using threads.
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+
12
+ == SYNOPSIS:
13
+
14
+ require "threadfiber"
15
+
16
+ f = ThreadFiber.new do
17
+ p :foo
18
+ Fiber.yield
19
+ p :bar
20
+ end
21
+
22
+ f.resume #=> :foo
23
+ f.resume #=> :bar
24
+
25
+ == REQUIREMENTS:
26
+
27
+ None
28
+
29
+ == INSTALL:
30
+
31
+ * gem install mame-threadfiber
32
+
33
+ == LICENSE:
34
+
35
+ Copyright:: Yusuke Endoh <mame@tsg.ne.jp>
36
+ License:: Ruby's
@@ -0,0 +1,12 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ require './lib/threadfiber.rb'
6
+
7
+ Hoe.new('threadfiber', ThreadFiber::VERSION) do |p|
8
+ p.rubyforge_name = 'threadfiberx' # if different than lowercase project name
9
+ p.developer('Yusuke Endoh', 'mame@tsg.ne.jp')
10
+ end
11
+
12
+ # vim: syntax=Ruby
@@ -0,0 +1,94 @@
1
+ require "thread"
2
+
3
+ class ThreadFiber
4
+ VERSION = "1.0.0"
5
+
6
+ @@fibers = {}
7
+
8
+ def initialize(&block)
9
+ unless block_given?
10
+ raise(ArgumentError, "tried to create Fiber without a block")
11
+ end
12
+
13
+ @resume_mutex = Mutex.new
14
+ @switch_mutex = Mutex.new
15
+ @switch_cond = ConditionVariable.new
16
+ @arg, @exception, @dead = nil, nil, false
17
+ @switch_mutex.synchronize do
18
+ th = Thread.new do
19
+ arg, exc = call_block(switch, &block)
20
+ @switch_mutex.synchronize do
21
+ @arg, @exception, @dead = arg, exc, true
22
+ @switch_cond.signal
23
+ end
24
+ @@fibers.delete(Thread.current)
25
+ end
26
+ @@fibers[th] = self
27
+ @switch_cond.wait(@switch_mutex)
28
+ end
29
+ end
30
+
31
+ def call_block(arg, &block)
32
+ [yield(arg), nil]
33
+ rescue ThreadError
34
+ case $!.message
35
+ when "return can't jump across threads"
36
+ [nil, LocalJumpError.new("unexpected return")]
37
+ when /\Auncaught throw/
38
+ [nil, ArgumentError.new($!.message)]
39
+ else
40
+ [nil, $!]
41
+ end
42
+ rescue Exception
43
+ [nil, $!]
44
+ end
45
+
46
+ def switch(*args)
47
+ @switch_mutex.synchronize do
48
+ raise(FiberError, "dead fiber called") if @dead
49
+ @arg = args.size <= 1 ? args.first : args
50
+ @switch_cond.signal
51
+ @switch_cond.wait(@switch_mutex)
52
+ raise @exception if @exception
53
+ @arg
54
+ end
55
+ end
56
+
57
+ def resume(*args)
58
+ if @resume_mutex.try_lock
59
+ begin
60
+ switch(*args)
61
+ ensure
62
+ @resume_mutex.unlock
63
+ end
64
+ else
65
+ raise(FiberError, "double resume")
66
+ end
67
+ end
68
+
69
+ def resume_wait(*args)
70
+ @resume_mutex.synchronize { switch(*args) }
71
+ end
72
+
73
+ def self.yield(*args)
74
+ fib = current
75
+ raise(FiberError, "can't yield from root fiber") unless fib
76
+ fib.switch(*args)
77
+ end
78
+
79
+ def self.current
80
+ @@fibers[Thread.current]
81
+ end
82
+
83
+ def self.deploy
84
+ Object.instance_eval do
85
+ remove_const(:Fiber) if const_defined?(:Fiber)
86
+ const_set(:Fiber, ThreadFiber)
87
+ end
88
+ end
89
+ end
90
+
91
+ unless defined?(FiberError)
92
+ class FiberError < StandardError
93
+ end
94
+ end
@@ -0,0 +1,168 @@
1
+ require 'test/unit'
2
+ require 'threadfiber'
3
+ begin
4
+ require 'continuation'
5
+ rescue LoadError
6
+ end
7
+ ThreadFiber.deploy
8
+
9
+ class TestFiber < Test::Unit::TestCase
10
+ def test_normal
11
+ f = Fiber.current
12
+ assert_equal(:ok2,
13
+ Fiber.new{|e|
14
+ assert_equal(:ok1, e)
15
+ Fiber.yield :ok2
16
+ }.resume(:ok1)
17
+ )
18
+ assert_equal([:a, :b], Fiber.new{|a, b| [a, b]}.resume(:a, :b))
19
+ end
20
+
21
+ def test_term
22
+ assert_equal(:ok, Fiber.new{:ok}.resume)
23
+ assert_equal([:a, :b, :c, :d, :e],
24
+ Fiber.new{
25
+ Fiber.new{
26
+ Fiber.new{
27
+ Fiber.new{
28
+ [:a]
29
+ }.resume + [:b]
30
+ }.resume + [:c]
31
+ }.resume + [:d]
32
+ }.resume + [:e])
33
+ end
34
+
35
+ def test_many_fibers
36
+ max = 100
37
+ assert_equal(max, max.times{
38
+ Fiber.new{}
39
+ })
40
+ assert_equal(max,
41
+ max.times{|i|
42
+ Fiber.new{
43
+ }.resume
44
+ }
45
+ )
46
+ end
47
+
48
+ def test_many_fibers_with_threads
49
+ max = 10
50
+ @cnt = 0
51
+ (1..10).map{|ti|
52
+ Thread.new{
53
+ max.times{|i|
54
+ Fiber.new{
55
+ @cnt += 1
56
+ }.resume
57
+ }
58
+ }
59
+ }.each{|t|
60
+ t.join
61
+ }
62
+ assert_equal(:ok, :ok)
63
+ end
64
+
65
+ def test_error
66
+ assert_raise(ArgumentError){
67
+ Fiber.new # Fiber without block
68
+ }
69
+ # assert_raise(FiberError){
70
+ # f = Fiber.new{}
71
+ # Thread.new{f.resume}.join # Fiber yielding across thread
72
+ # }
73
+ assert_raise(FiberError){
74
+ f = Fiber.new{}
75
+ f.resume
76
+ f.resume
77
+ }
78
+ assert_raise(RuntimeError){
79
+ f = Fiber.new{
80
+ @c = callcc{|c| @c = c}
81
+ }.resume
82
+ @c.call # cross fiber callcc
83
+ }
84
+ assert_raise(RuntimeError){
85
+ Fiber.new{
86
+ raise
87
+ }.resume
88
+ }
89
+ assert_raise(FiberError){
90
+ Fiber.yield
91
+ }
92
+ assert_raise(FiberError){
93
+ fib = Fiber.new{
94
+ fib.resume
95
+ }
96
+ fib.resume
97
+ }
98
+ assert_raise(FiberError){
99
+ fib = Fiber.new{
100
+ Fiber.new{
101
+ fib.resume
102
+ }.resume
103
+ }
104
+ fib.resume
105
+ }
106
+ end
107
+
108
+ def test_return
109
+ assert_raise(LocalJumpError){
110
+ Fiber.new do
111
+ return
112
+ end.resume
113
+ }
114
+ end
115
+
116
+ def test_throw
117
+ assert_raise(ArgumentError){
118
+ Fiber.new do
119
+ throw :a
120
+ end.resume
121
+ }
122
+ end
123
+
124
+ # def test_transfer
125
+ # ary = []
126
+ # f2 = nil
127
+ # f1 = Fiber.new{
128
+ # ary << f2.transfer(:foo)
129
+ # :ok
130
+ # }
131
+ # f2 = Fiber.new{
132
+ # ary << f1.transfer(:baz)
133
+ # :ng
134
+ # }
135
+ # assert_equal(:ok, f1.transfer)
136
+ # assert_equal([:baz], ary)
137
+ # end
138
+
139
+ def test_tls
140
+ #
141
+ def tvar(var, val)
142
+ old = Thread.current[var]
143
+ begin
144
+ Thread.current[var] = val
145
+ yield
146
+ ensure
147
+ Thread.current[var] = old
148
+ end
149
+ end
150
+
151
+ fb = Fiber.new {
152
+ assert_equal(nil, Thread.current[:v]); tvar(:v, :x) {
153
+ assert_equal(:x, Thread.current[:v]); Fiber.yield
154
+ assert_equal(:x, Thread.current[:v]); }
155
+ assert_equal(nil, Thread.current[:v]); Fiber.yield
156
+ raise # unreachable
157
+ }
158
+
159
+ assert_equal(nil, Thread.current[:v]); tvar(:v,1) {
160
+ assert_equal(1, Thread.current[:v]); tvar(:v,3) {
161
+ assert_equal(3, Thread.current[:v]); fb.resume
162
+ assert_equal(3, Thread.current[:v]); }
163
+ assert_equal(1, Thread.current[:v]); }
164
+ assert_equal(nil, Thread.current[:v]); fb.resume
165
+ assert_equal(nil, Thread.current[:v]);
166
+ end
167
+ end
168
+
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mame-threadfiber
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Yusuke Endoh
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-08-24 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: hoe
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.7.0
23
+ version:
24
+ description: ThreadFiber is an implementation of fiber using threads.
25
+ email:
26
+ - mame@tsg.ne.jp
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - History.txt
33
+ - Manifest.txt
34
+ - README.txt
35
+ files:
36
+ - History.txt
37
+ - Manifest.txt
38
+ - README.txt
39
+ - Rakefile
40
+ - lib/threadfiber.rb
41
+ - test/test_threadfiber.rb
42
+ has_rdoc: true
43
+ homepage: http://github.com/mame/threadfiber/tree/master
44
+ post_install_message:
45
+ rdoc_options:
46
+ - --main
47
+ - README.txt
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ version:
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: "0"
61
+ version:
62
+ requirements: []
63
+
64
+ rubyforge_project: threadfiberx
65
+ rubygems_version: 1.2.0
66
+ signing_key:
67
+ specification_version: 2
68
+ summary: ThreadFiber is an implementation of fiber using threads.
69
+ test_files:
70
+ - test/test_threadfiber.rb