strand 0.1.0 → 0.2.0.rc0
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.
- data/.gitignore +3 -0
- data/CHANGELOG +13 -0
- data/Gemfile +3 -15
- data/LICENSE.txt +1 -0
- data/README.rdoc +12 -19
- data/Rakefile +10 -57
- data/lib/strand.rb +151 -126
- data/lib/strand/atc.rb +1 -1
- data/lib/strand/em/condition_variable.rb +57 -0
- data/lib/strand/em/mutex.rb +63 -0
- data/lib/strand/em/queue.rb +84 -0
- data/lib/strand/em/thread.rb +305 -0
- data/lib/strand/monitor.rb +193 -0
- data/lib/strand/version.rb +3 -0
- data/spec/spec_helper.rb +9 -5
- data/spec/strand/alive.rb +62 -0
- data/spec/strand/condition_variable.rb +10 -0
- data/spec/strand/condition_variable/broadcast.rb +61 -0
- data/spec/strand/condition_variable/signal.rb +62 -0
- data/spec/strand/condition_variable/wait.rb +20 -0
- data/spec/strand/current.rb +15 -0
- data/spec/strand/exit.rb +148 -0
- data/spec/strand/join.rb +60 -0
- data/spec/strand/local_storage.rb +98 -0
- data/spec/strand/mutex.rb +244 -0
- data/spec/strand/pass.rb +9 -0
- data/spec/strand/queue.rb +124 -0
- data/spec/strand/raise.rb +142 -0
- data/spec/strand/run.rb +5 -0
- data/spec/strand/shared.rb +14 -0
- data/spec/strand/sleep.rb +51 -0
- data/spec/strand/status.rb +44 -0
- data/spec/strand/stop.rb +58 -0
- data/spec/strand/strand.rb +32 -0
- data/spec/strand/value.rb +39 -0
- data/spec/strand/wakeup.rb +60 -0
- data/spec/strand_spec.rb +51 -0
- data/spec/support/fixtures.rb +305 -0
- data/spec/support/scratch.rb +17 -0
- data/spec/thread_spec.rb +20 -0
- data/strand.gemspec +23 -0
- metadata +72 -58
- data/Gemfile.lock +0 -40
- data/lib/strand/condition_variable.rb +0 -78
- data/spec/condition_variable_spec.rb +0 -82
- data/test/helper.rb +0 -30
- data/test/test_strand.rb +0 -121
data/spec/thread_spec.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'strand/shared'
|
3
|
+
|
4
|
+
describe ::Thread do
|
5
|
+
|
6
|
+
let (:strand_type) { ::Thread }
|
7
|
+
let (:strand_exception) { ThreadError }
|
8
|
+
|
9
|
+
around(:each) do |example|
|
10
|
+
ScratchPad.clear
|
11
|
+
example.run
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should not be running in event machine" do
|
15
|
+
Strand.event_machine?.should be_false
|
16
|
+
end
|
17
|
+
|
18
|
+
include_examples Strand
|
19
|
+
end
|
20
|
+
|
data/strand.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'strand/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "strand"
|
8
|
+
gem.version = Strand::VERSION
|
9
|
+
gem.authors = ["Grant Gardner","Christopher J. Bottaro"]
|
10
|
+
gem.email = ["grant@lastweekend.com.au", "cjbottaro@alumni.cs.utexas.edu"]
|
11
|
+
gem.description = %q{Get thread-like behavior from fibers using EventMachine.}
|
12
|
+
gem.summary = %q{Make fibers behave like threads using EventMachine}
|
13
|
+
gem.homepage = "http://rubygems.org/gems/strand"
|
14
|
+
gem.files = `git ls-files`.split($/)
|
15
|
+
gem.test_files = `git ls-files -- {test,spec}/*`.split($/)
|
16
|
+
gem.require_paths = ["lib"]
|
17
|
+
gem.licenses = %q{MIT}
|
18
|
+
|
19
|
+
gem.add_development_dependency 'rspec'
|
20
|
+
gem.add_development_dependency 'em-spec'
|
21
|
+
gem.add_development_dependency 'rr'
|
22
|
+
gem.add_development_dependency 'eventmachine', '~> 0.12.0'
|
23
|
+
end
|
metadata
CHANGED
@@ -1,63 +1,52 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: strand
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.2.0.rc0
|
5
|
+
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
|
+
- Grant Gardner
|
8
9
|
- Christopher J. Bottaro
|
9
10
|
autorequire:
|
10
11
|
bindir: bin
|
11
12
|
cert_chain: []
|
12
|
-
date:
|
13
|
+
date: 2012-12-13 00:00:00.000000000 Z
|
13
14
|
dependencies:
|
14
15
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
16
|
-
requirement:
|
16
|
+
name: rspec
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
17
18
|
none: false
|
18
19
|
requirements:
|
19
|
-
- -
|
20
|
+
- - ! '>='
|
20
21
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
22
|
+
version: '0'
|
22
23
|
type: :development
|
23
24
|
prerelease: false
|
24
|
-
version_requirements:
|
25
|
-
- !ruby/object:Gem::Dependency
|
26
|
-
name: em-spec
|
27
|
-
requirement: &70284397100280 !ruby/object:Gem::Requirement
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
28
26
|
none: false
|
29
27
|
requirements:
|
30
28
|
- - ! '>='
|
31
29
|
- !ruby/object:Gem::Version
|
32
30
|
version: '0'
|
33
|
-
type: :development
|
34
|
-
prerelease: false
|
35
|
-
version_requirements: *70284397100280
|
36
31
|
- !ruby/object:Gem::Dependency
|
37
|
-
name:
|
38
|
-
requirement:
|
32
|
+
name: em-spec
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
39
34
|
none: false
|
40
35
|
requirements:
|
41
|
-
- -
|
36
|
+
- - ! '>='
|
42
37
|
- !ruby/object:Gem::Version
|
43
|
-
version: 0
|
38
|
+
version: '0'
|
44
39
|
type: :development
|
45
40
|
prerelease: false
|
46
|
-
version_requirements:
|
47
|
-
- !ruby/object:Gem::Dependency
|
48
|
-
name: jeweler
|
49
|
-
requirement: &70284397153900 !ruby/object:Gem::Requirement
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
42
|
none: false
|
51
43
|
requirements:
|
52
|
-
- -
|
44
|
+
- - ! '>='
|
53
45
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
55
|
-
type: :development
|
56
|
-
prerelease: false
|
57
|
-
version_requirements: *70284397153900
|
46
|
+
version: '0'
|
58
47
|
- !ruby/object:Gem::Dependency
|
59
|
-
name:
|
60
|
-
requirement:
|
48
|
+
name: rr
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
61
50
|
none: false
|
62
51
|
requirements:
|
63
52
|
- - ! '>='
|
@@ -65,53 +54,81 @@ dependencies:
|
|
65
54
|
version: '0'
|
66
55
|
type: :development
|
67
56
|
prerelease: false
|
68
|
-
version_requirements:
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: rr
|
71
|
-
requirement: &70284397150240 !ruby/object:Gem::Requirement
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
72
58
|
none: false
|
73
59
|
requirements:
|
74
60
|
- - ! '>='
|
75
61
|
- !ruby/object:Gem::Version
|
76
62
|
version: '0'
|
77
|
-
type: :development
|
78
|
-
prerelease: false
|
79
|
-
version_requirements: *70284397150240
|
80
63
|
- !ruby/object:Gem::Dependency
|
81
|
-
name:
|
82
|
-
requirement:
|
64
|
+
name: eventmachine
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
83
66
|
none: false
|
84
67
|
requirements:
|
85
|
-
- -
|
68
|
+
- - ~>
|
86
69
|
- !ruby/object:Gem::Version
|
87
|
-
version:
|
70
|
+
version: 0.12.0
|
88
71
|
type: :development
|
89
72
|
prerelease: false
|
90
|
-
version_requirements:
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ~>
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: 0.12.0
|
91
79
|
description: Get thread-like behavior from fibers using EventMachine.
|
92
|
-
email:
|
80
|
+
email:
|
81
|
+
- grant@lastweekend.com.au
|
82
|
+
- cjbottaro@alumni.cs.utexas.edu
|
93
83
|
executables: []
|
94
84
|
extensions: []
|
95
|
-
extra_rdoc_files:
|
96
|
-
- LICENSE.txt
|
97
|
-
- README.rdoc
|
85
|
+
extra_rdoc_files: []
|
98
86
|
files:
|
99
87
|
- .document
|
88
|
+
- .gitignore
|
100
89
|
- .rspec
|
90
|
+
- CHANGELOG
|
101
91
|
- Gemfile
|
102
|
-
- Gemfile.lock
|
103
92
|
- LICENSE.txt
|
104
93
|
- README.rdoc
|
105
94
|
- Rakefile
|
106
95
|
- VERSION
|
107
96
|
- lib/strand.rb
|
108
97
|
- lib/strand/atc.rb
|
109
|
-
- lib/strand/condition_variable.rb
|
110
|
-
-
|
98
|
+
- lib/strand/em/condition_variable.rb
|
99
|
+
- lib/strand/em/mutex.rb
|
100
|
+
- lib/strand/em/queue.rb
|
101
|
+
- lib/strand/em/thread.rb
|
102
|
+
- lib/strand/monitor.rb
|
103
|
+
- lib/strand/version.rb
|
111
104
|
- spec/spec_helper.rb
|
112
|
-
-
|
113
|
-
-
|
114
|
-
|
105
|
+
- spec/strand/alive.rb
|
106
|
+
- spec/strand/condition_variable.rb
|
107
|
+
- spec/strand/condition_variable/broadcast.rb
|
108
|
+
- spec/strand/condition_variable/signal.rb
|
109
|
+
- spec/strand/condition_variable/wait.rb
|
110
|
+
- spec/strand/current.rb
|
111
|
+
- spec/strand/exit.rb
|
112
|
+
- spec/strand/join.rb
|
113
|
+
- spec/strand/local_storage.rb
|
114
|
+
- spec/strand/mutex.rb
|
115
|
+
- spec/strand/pass.rb
|
116
|
+
- spec/strand/queue.rb
|
117
|
+
- spec/strand/raise.rb
|
118
|
+
- spec/strand/run.rb
|
119
|
+
- spec/strand/shared.rb
|
120
|
+
- spec/strand/sleep.rb
|
121
|
+
- spec/strand/status.rb
|
122
|
+
- spec/strand/stop.rb
|
123
|
+
- spec/strand/strand.rb
|
124
|
+
- spec/strand/value.rb
|
125
|
+
- spec/strand/wakeup.rb
|
126
|
+
- spec/strand_spec.rb
|
127
|
+
- spec/support/fixtures.rb
|
128
|
+
- spec/support/scratch.rb
|
129
|
+
- spec/thread_spec.rb
|
130
|
+
- strand.gemspec
|
131
|
+
homepage: http://rubygems.org/gems/strand
|
115
132
|
licenses:
|
116
133
|
- MIT
|
117
134
|
post_install_message:
|
@@ -124,19 +141,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
124
141
|
- - ! '>='
|
125
142
|
- !ruby/object:Gem::Version
|
126
143
|
version: '0'
|
127
|
-
segments:
|
128
|
-
- 0
|
129
|
-
hash: -933947513672593859
|
130
144
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
131
145
|
none: false
|
132
146
|
requirements:
|
133
|
-
- - ! '
|
147
|
+
- - ! '>'
|
134
148
|
- !ruby/object:Gem::Version
|
135
|
-
version:
|
149
|
+
version: 1.3.1
|
136
150
|
requirements: []
|
137
151
|
rubyforge_project:
|
138
|
-
rubygems_version: 1.8.
|
152
|
+
rubygems_version: 1.8.24
|
139
153
|
signing_key:
|
140
154
|
specification_version: 3
|
141
|
-
summary: Make fibers behave like threads using EventMachine
|
155
|
+
summary: Make fibers behave like threads using EventMachine
|
142
156
|
test_files: []
|
data/Gemfile.lock
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
GEM
|
2
|
-
remote: http://rubygems.org/
|
3
|
-
specs:
|
4
|
-
bacon (1.1.0)
|
5
|
-
diff-lcs (1.1.2)
|
6
|
-
em-spec (0.2.5)
|
7
|
-
bacon
|
8
|
-
eventmachine
|
9
|
-
rspec (~> 2.6.0)
|
10
|
-
test-unit
|
11
|
-
eventmachine (0.12.10)
|
12
|
-
git (1.2.5)
|
13
|
-
jeweler (1.6.4)
|
14
|
-
bundler (~> 1.0)
|
15
|
-
git (>= 1.2.5)
|
16
|
-
rake
|
17
|
-
rake (0.9.2)
|
18
|
-
rcov (0.9.9)
|
19
|
-
rr (1.0.3)
|
20
|
-
rspec (2.6.0)
|
21
|
-
rspec-core (~> 2.6.0)
|
22
|
-
rspec-expectations (~> 2.6.0)
|
23
|
-
rspec-mocks (~> 2.6.0)
|
24
|
-
rspec-core (2.6.4)
|
25
|
-
rspec-expectations (2.6.0)
|
26
|
-
diff-lcs (~> 1.1.2)
|
27
|
-
rspec-mocks (2.6.0)
|
28
|
-
test-unit (2.3.2)
|
29
|
-
|
30
|
-
PLATFORMS
|
31
|
-
ruby
|
32
|
-
|
33
|
-
DEPENDENCIES
|
34
|
-
bundler (~> 1.0.0)
|
35
|
-
em-spec
|
36
|
-
eventmachine (~> 0.12.0)
|
37
|
-
jeweler (~> 1.6.4)
|
38
|
-
rcov
|
39
|
-
rr
|
40
|
-
rspec
|
@@ -1,78 +0,0 @@
|
|
1
|
-
class Strand
|
2
|
-
# Provides for Strands (Fibers) what Ruby's ConditionVariable provides for Threads.
|
3
|
-
class ConditionVariable
|
4
|
-
|
5
|
-
# Create a new condition variable.
|
6
|
-
def initialize
|
7
|
-
@waiters = []
|
8
|
-
end
|
9
|
-
|
10
|
-
# Wait until signaled. Returns true upon returning.
|
11
|
-
# x = nil
|
12
|
-
# cond = Strand::ConditionVariable.new
|
13
|
-
# Strand.new{ cond.wait; x = 1; cond.signal }
|
14
|
-
# puts x # => nil
|
15
|
-
# cond.signal
|
16
|
-
# cond.wait # => true
|
17
|
-
# puts x # => 1
|
18
|
-
# If timeout is a number, then returns false if timed out or true if signaled.
|
19
|
-
# x = nil
|
20
|
-
# cond = Strand::ConditionVariable.new
|
21
|
-
# Strand.new{ cond.wait; x = 1; cond.signal }
|
22
|
-
# puts x # => nil
|
23
|
-
# cond.wait(0.01) # => false
|
24
|
-
# puts x # => nil
|
25
|
-
def wait(timeout = nil)
|
26
|
-
# Get the fiber that called us.
|
27
|
-
fiber = Fiber.current
|
28
|
-
|
29
|
-
# Add the fiber to the list of waiters.
|
30
|
-
@waiters << fiber
|
31
|
-
|
32
|
-
# Setup the timer if they specified a timeout
|
33
|
-
timer = EM::Timer.new(timeout){ fiber.resume(:timeout) } if timeout
|
34
|
-
|
35
|
-
# Wait for signal or timeout.
|
36
|
-
if Fiber.yield == :timeout
|
37
|
-
# Timeout occurred.
|
38
|
-
|
39
|
-
# Remove from list of waiters.
|
40
|
-
@waiters.delete(fiber)
|
41
|
-
|
42
|
-
false
|
43
|
-
else
|
44
|
-
# Ok we were signaled.
|
45
|
-
|
46
|
-
# Cancel the timer if there is one.
|
47
|
-
timer.cancel if timer
|
48
|
-
|
49
|
-
true
|
50
|
-
end
|
51
|
-
|
52
|
-
end
|
53
|
-
|
54
|
-
# Asynchronously resume a fiber waiting on this condition variable.
|
55
|
-
# The waiter is not resumed immediately, but on the next tick of EM's reactor loop.
|
56
|
-
# cond = Strand::ConditionVariable.new
|
57
|
-
# Strand.new{ puts 1; cond.wait; puts 2 }
|
58
|
-
# puts 3
|
59
|
-
# cond.signal
|
60
|
-
# puts 4
|
61
|
-
# # output is...
|
62
|
-
# 1
|
63
|
-
# 3
|
64
|
-
# 4
|
65
|
-
# 2
|
66
|
-
def signal
|
67
|
-
# If there are no waiters, do nothing.
|
68
|
-
return if @waiters.empty?
|
69
|
-
|
70
|
-
# Find a waiter to wake up.
|
71
|
-
waiter = @waiters.shift
|
72
|
-
|
73
|
-
# Resume it on next tick.
|
74
|
-
EM.next_tick{ waiter.resume }
|
75
|
-
end
|
76
|
-
|
77
|
-
end
|
78
|
-
end
|
@@ -1,82 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe Strand::ConditionVariable do
|
4
|
-
include EM::SpecHelper
|
5
|
-
|
6
|
-
context "calling #wait" do
|
7
|
-
before(:each) do
|
8
|
-
@cond = described_class.new
|
9
|
-
@atc = Atc.new :timeout => 0.01
|
10
|
-
end
|
11
|
-
it "should block until signaled" do
|
12
|
-
em do
|
13
|
-
Strand.new{ @cond.wait; @atc.signal(1) }
|
14
|
-
@atc.wait(1).should be_false
|
15
|
-
@cond.signal
|
16
|
-
@atc.wait(1).should be_true
|
17
|
-
done
|
18
|
-
end
|
19
|
-
end
|
20
|
-
it "should block until timed out" do
|
21
|
-
em do
|
22
|
-
Strand.new{ @cond.wait(0.02); @atc.signal(1) }
|
23
|
-
@atc.wait(1).should be_false
|
24
|
-
@atc.wait(1).should be_true
|
25
|
-
done
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
context "calling #signal" do
|
31
|
-
context "with no waiters" do
|
32
|
-
before(:all){ @cond = described_class.new }
|
33
|
-
it "should not do anything" do
|
34
|
-
@cond.signal.should be_nil
|
35
|
-
end
|
36
|
-
end
|
37
|
-
context "with a single waiter" do
|
38
|
-
before(:all) do
|
39
|
-
@cond = described_class.new
|
40
|
-
@atc = Atc.new :timeout => 0.01
|
41
|
-
Strand.new{ @cond.wait; @atc.signal(1) }
|
42
|
-
end
|
43
|
-
it "should wake up the waiter" do
|
44
|
-
em do
|
45
|
-
@atc.wait(1).should be_false
|
46
|
-
@cond.signal
|
47
|
-
@atc.wait(1).should be_true
|
48
|
-
done
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
context "with multiple waiters" do
|
53
|
-
before(:all) do
|
54
|
-
@cond = described_class.new
|
55
|
-
@atc = Atc.new :timeout => 0.01
|
56
|
-
Strand.new{ @cond.wait; @atc.signal(1) }
|
57
|
-
Strand.new{ @cond.wait; @atc.signal(2) }
|
58
|
-
end
|
59
|
-
it "should wake up the first waiter" do
|
60
|
-
em do
|
61
|
-
@atc.wait(1).should be_false
|
62
|
-
@atc.wait(2).should be_false
|
63
|
-
@cond.signal
|
64
|
-
@atc.wait(1).should be_true
|
65
|
-
@atc.wait(2).should be_false
|
66
|
-
done
|
67
|
-
end
|
68
|
-
end
|
69
|
-
it "then wake up the second waiter" do
|
70
|
-
em do
|
71
|
-
@atc.wait(1).should be_true
|
72
|
-
@atc.wait(2).should be_false
|
73
|
-
@cond.signal
|
74
|
-
@atc.wait(1).should be_true
|
75
|
-
@atc.wait(2).should be_true
|
76
|
-
done
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
end
|