celluloid-io 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +1 -1
- data/CHANGES.md +5 -0
- data/README.md +32 -30
- data/celluloid-io.gemspec +4 -3
- data/lib/celluloid/io.rb +4 -10
- data/lib/celluloid/io/mailbox.rb +23 -26
- data/lib/celluloid/io/reactor.rb +27 -35
- data/lib/celluloid/io/version.rb +1 -1
- metadata +23 -14
- data/lib/celluloid/io/waker.rb +0 -43
- data/spec/celluloid/io/waker_spec.rb +0 -34
data/.travis.yml
CHANGED
data/CHANGES.md
CHANGED
data/README.md
CHANGED
@@ -35,36 +35,38 @@ Usage
|
|
35
35
|
|
36
36
|
To use Celluloid::IO, define a normal Ruby class that includes Celluloid::IO:
|
37
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
|
-
|
38
|
+
```ruby
|
39
|
+
require 'celluloid/io'
|
40
|
+
|
41
|
+
class MyServer
|
42
|
+
include Celluloid::IO
|
43
|
+
|
44
|
+
# Bind a TCP server to the given host and port
|
45
|
+
def initialize(host, port)
|
46
|
+
@server = TCPServer.new host, port
|
47
|
+
run!
|
48
|
+
end
|
49
|
+
|
50
|
+
# Run the TCP server event loop
|
51
|
+
def run
|
52
|
+
while true
|
53
|
+
wait_readable(@server)
|
54
|
+
on_connect @server.accept
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Terminate this server
|
59
|
+
def terminate
|
60
|
+
@server.close
|
61
|
+
super
|
62
|
+
end
|
63
|
+
|
64
|
+
# Called whenever a new connection is opened
|
65
|
+
def on_connect(connection)
|
66
|
+
connection.close
|
67
|
+
end
|
68
|
+
end
|
69
|
+
```
|
68
70
|
|
69
71
|
Contributing to Celluloid::IO
|
70
72
|
-----------------------------
|
data/celluloid-io.gemspec
CHANGED
@@ -15,8 +15,9 @@ Gem::Specification.new do |gem|
|
|
15
15
|
gem.require_paths = ["lib"]
|
16
16
|
gem.version = Celluloid::IO::VERSION
|
17
17
|
|
18
|
-
gem.
|
18
|
+
gem.add_dependency 'celluloid', '~> 0.8.0'
|
19
|
+
gem.add_dependency 'nio4r', '>= 0.2.2'
|
19
20
|
|
20
|
-
gem.add_development_dependency
|
21
|
-
gem.add_development_dependency
|
21
|
+
gem.add_development_dependency 'rake'
|
22
|
+
gem.add_development_dependency 'rspec', '~> 2.7.0'
|
22
23
|
end
|
data/lib/celluloid/io.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'celluloid/io/version'
|
2
2
|
|
3
|
+
require 'forwardable'
|
3
4
|
require 'celluloid'
|
4
5
|
require 'celluloid/io/mailbox'
|
5
6
|
require 'celluloid/io/reactor'
|
6
|
-
require 'celluloid/io/waker'
|
7
7
|
|
8
8
|
module Celluloid
|
9
9
|
# Actors with evented IO support
|
@@ -13,15 +13,9 @@ module Celluloid
|
|
13
13
|
klass.use_mailbox Celluloid::IO::Mailbox
|
14
14
|
end
|
15
15
|
|
16
|
-
|
17
|
-
def wait_readable(io, &block)
|
18
|
-
# Law of demeter be damned!
|
19
|
-
current_actor.mailbox.reactor.wait_readable(io, &block)
|
20
|
-
end
|
16
|
+
extend Forwardable
|
21
17
|
|
22
|
-
# Wait for the given IO object to become writeable
|
23
|
-
|
24
|
-
current_actor.mailbox.reactor.wait_writeable(io, &block)
|
25
|
-
end
|
18
|
+
# Wait for the given IO object to become readable/writeable
|
19
|
+
def_delegators 'current_actor.mailbox.reactor', :wait_readable, :wait_writeable
|
26
20
|
end
|
27
21
|
end
|
data/lib/celluloid/io/mailbox.rb
CHANGED
@@ -1,24 +1,23 @@
|
|
1
1
|
module Celluloid
|
2
2
|
module IO
|
3
|
-
# An alternative implementation of Celluloid::Mailbox using
|
3
|
+
# An alternative implementation of Celluloid::Mailbox using Reactor
|
4
4
|
class Mailbox < Celluloid::Mailbox
|
5
|
-
attr_reader :reactor
|
5
|
+
attr_reader :reactor
|
6
6
|
|
7
7
|
def initialize
|
8
8
|
@messages = []
|
9
9
|
@lock = Mutex.new
|
10
|
-
@
|
11
|
-
@reactor = Reactor.new(@waker)
|
10
|
+
@reactor = Reactor.new
|
12
11
|
end
|
13
12
|
|
14
13
|
# Add a message to the Mailbox
|
15
14
|
def <<(message)
|
16
15
|
@lock.synchronize do
|
17
16
|
@messages << message
|
18
|
-
@
|
17
|
+
@reactor.wakeup
|
19
18
|
end
|
20
19
|
nil
|
21
|
-
rescue
|
20
|
+
rescue IOError
|
22
21
|
raise MailboxError, "dead recipient"
|
23
22
|
end
|
24
23
|
|
@@ -26,10 +25,10 @@ module Celluloid
|
|
26
25
|
def system_event(event)
|
27
26
|
@lock.synchronize do
|
28
27
|
@messages.unshift event
|
29
|
-
|
28
|
+
|
30
29
|
begin
|
31
|
-
@
|
32
|
-
rescue
|
30
|
+
@reactor.wakeup
|
31
|
+
rescue IOError
|
33
32
|
# Silently fail if messages are sent to dead actors
|
34
33
|
end
|
35
34
|
end
|
@@ -38,35 +37,33 @@ module Celluloid
|
|
38
37
|
|
39
38
|
# Receive a message from the Mailbox
|
40
39
|
def receive(timeout = nil, &block)
|
41
|
-
message =
|
40
|
+
message = next_message(&block)
|
42
41
|
|
43
|
-
|
42
|
+
until message
|
44
43
|
if timeout
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
end
|
52
|
-
|
53
|
-
@reactor.run_once(wait_interval) do
|
54
|
-
@waker.wait
|
55
|
-
message = next_message(&block)
|
44
|
+
now = Time.now
|
45
|
+
wait_until ||= now + timeout
|
46
|
+
wait_interval = wait_until - now
|
47
|
+
return if wait_interval < 0
|
48
|
+
else
|
49
|
+
wait_interval = nil
|
56
50
|
end
|
57
|
-
|
51
|
+
|
52
|
+
@reactor.run_once(wait_interval)
|
53
|
+
message = next_message(&block)
|
54
|
+
end
|
58
55
|
|
59
56
|
message
|
60
|
-
rescue IOError
|
57
|
+
rescue IOError
|
61
58
|
shutdown # force shutdown of the mailbox
|
62
59
|
raise MailboxShutdown, "mailbox shutdown called during receive"
|
63
60
|
end
|
64
61
|
|
65
62
|
# Cleanup any IO objects this Mailbox may be using
|
66
63
|
def shutdown
|
67
|
-
@
|
64
|
+
@reactor.shutdown
|
68
65
|
super
|
69
66
|
end
|
70
67
|
end
|
71
68
|
end
|
72
|
-
end
|
69
|
+
end
|
data/lib/celluloid/io/reactor.rb
CHANGED
@@ -1,45 +1,33 @@
|
|
1
|
+
require 'nio'
|
2
|
+
|
1
3
|
module Celluloid
|
2
4
|
module IO
|
3
5
|
# React to external I/O events. This is kinda sorta supposed to resemble the
|
4
6
|
# Reactor design pattern.
|
5
7
|
class Reactor
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
extend Forwardable
|
9
|
+
|
10
|
+
# Unblock the reactor (i.e. to signal it from another thread)
|
11
|
+
def_delegator :@selector, :wakeup
|
12
|
+
# Terminate the reactor
|
13
|
+
def_delegator :@selector, :close, :shutdown
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@selector = NIO::Selector.new
|
10
17
|
end
|
11
18
|
|
12
19
|
# Wait for the given IO object to become readable
|
13
20
|
def wait_readable(io)
|
14
|
-
|
21
|
+
wait io, :r
|
15
22
|
end
|
16
23
|
|
17
24
|
# Wait for the given IO object to become writeable
|
18
25
|
def wait_writeable(io)
|
19
|
-
|
20
|
-
end
|
21
|
-
|
22
|
-
# Run the reactor, waiting for events, and calling the given block if
|
23
|
-
# the reactor is awoken by the waker
|
24
|
-
def run_once(timeout = nil)
|
25
|
-
readers, writers = select(@readers.keys << @waker.io, @writers.keys, [], timeout)
|
26
|
-
return unless readers
|
27
|
-
|
28
|
-
yield if readers.include? @waker.io
|
29
|
-
|
30
|
-
[[readers, @readers], [writers, @writers]].each do |ios, registered|
|
31
|
-
ios.each do |io|
|
32
|
-
task = registered.delete io
|
33
|
-
task.resume if task
|
34
|
-
end
|
35
|
-
end
|
26
|
+
wait io, :w
|
36
27
|
end
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
#######
|
41
|
-
|
42
|
-
def wait_for_io(io, set)
|
28
|
+
|
29
|
+
# Wait for the given IO operation to complete
|
30
|
+
def wait(io, set)
|
43
31
|
# zomg ugly type conversion :(
|
44
32
|
unless io.is_a?(IO)
|
45
33
|
if IO.respond_to? :try_convert
|
@@ -49,14 +37,18 @@ module Celluloid
|
|
49
37
|
else raise TypeError, "can't convert #{io.class} into IO"
|
50
38
|
end
|
51
39
|
end
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
40
|
+
|
41
|
+
monitor = @selector.register(io, set)
|
42
|
+
monitor.value = Task.current
|
43
|
+
Task.suspend :iowait
|
44
|
+
end
|
45
|
+
|
46
|
+
# Run the reactor, waiting for events or wakeup signal
|
47
|
+
def run_once(timeout = nil)
|
48
|
+
@selector.select_each(timeout) do |monitor|
|
49
|
+
monitor.value.resume
|
50
|
+
@selector.deregister(monitor.io)
|
57
51
|
end
|
58
|
-
|
59
|
-
Task.suspend
|
60
52
|
end
|
61
53
|
end
|
62
54
|
end
|
data/lib/celluloid/io/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: celluloid-io
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,22 +9,33 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2012-01-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: celluloid
|
16
|
-
requirement: &
|
16
|
+
requirement: &70254645083180 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.8.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70254645083180
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: nio4r
|
27
|
+
requirement: &70254645082660 !ruby/object:Gem::Requirement
|
17
28
|
none: false
|
18
29
|
requirements:
|
19
30
|
- - ! '>='
|
20
31
|
- !ruby/object:Gem::Version
|
21
|
-
version: 0.
|
22
|
-
type: :
|
32
|
+
version: 0.2.2
|
33
|
+
type: :runtime
|
23
34
|
prerelease: false
|
24
|
-
version_requirements: *
|
35
|
+
version_requirements: *70254645082660
|
25
36
|
- !ruby/object:Gem::Dependency
|
26
37
|
name: rake
|
27
|
-
requirement: &
|
38
|
+
requirement: &70254645082180 !ruby/object:Gem::Requirement
|
28
39
|
none: false
|
29
40
|
requirements:
|
30
41
|
- - ! '>='
|
@@ -32,18 +43,18 @@ dependencies:
|
|
32
43
|
version: '0'
|
33
44
|
type: :development
|
34
45
|
prerelease: false
|
35
|
-
version_requirements: *
|
46
|
+
version_requirements: *70254645082180
|
36
47
|
- !ruby/object:Gem::Dependency
|
37
48
|
name: rspec
|
38
|
-
requirement: &
|
49
|
+
requirement: &70254645081480 !ruby/object:Gem::Requirement
|
39
50
|
none: false
|
40
51
|
requirements:
|
41
|
-
- -
|
52
|
+
- - ~>
|
42
53
|
- !ruby/object:Gem::Version
|
43
54
|
version: 2.7.0
|
44
55
|
type: :development
|
45
56
|
prerelease: false
|
46
|
-
version_requirements: *
|
57
|
+
version_requirements: *70254645081480
|
47
58
|
description: Evented IO for Celluloid actors
|
48
59
|
email:
|
49
60
|
- tony.arcieri@gmail.com
|
@@ -64,10 +75,8 @@ files:
|
|
64
75
|
- lib/celluloid/io/mailbox.rb
|
65
76
|
- lib/celluloid/io/reactor.rb
|
66
77
|
- lib/celluloid/io/version.rb
|
67
|
-
- lib/celluloid/io/waker.rb
|
68
78
|
- spec/celluloid/io/actor_spec.rb
|
69
79
|
- spec/celluloid/io/mailbox_spec.rb
|
70
|
-
- spec/celluloid/io/waker_spec.rb
|
71
80
|
- spec/spec_helper.rb
|
72
81
|
homepage: http://github.com/tarcieri/celluloid-io
|
73
82
|
licenses: []
|
@@ -97,5 +106,5 @@ summary: Celluloid::IO allows you to monitor multiple IO objects within a Cellul
|
|
97
106
|
test_files:
|
98
107
|
- spec/celluloid/io/actor_spec.rb
|
99
108
|
- spec/celluloid/io/mailbox_spec.rb
|
100
|
-
- spec/celluloid/io/waker_spec.rb
|
101
109
|
- spec/spec_helper.rb
|
110
|
+
has_rdoc:
|
data/lib/celluloid/io/waker.rb
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
module Celluloid
|
2
|
-
module IO
|
3
|
-
class DeadWakerError < StandardError; end # You can't wake the dead
|
4
|
-
|
5
|
-
# Wakes up sleepy threads so that they can check their mailbox
|
6
|
-
# Works like a ConditionVariable, except it's implemented as an IO object so
|
7
|
-
# that it can be multiplexed alongside other IO objects.
|
8
|
-
class Waker
|
9
|
-
PAYLOAD = "\0" # the payload doesn't matter. each byte is a signal
|
10
|
-
def initialize
|
11
|
-
@receiver, @sender = ::IO.pipe
|
12
|
-
end
|
13
|
-
|
14
|
-
# Wakes up the thread that is waiting for this Waker
|
15
|
-
def signal
|
16
|
-
@sender << PAYLOAD
|
17
|
-
nil
|
18
|
-
rescue IOError, Errno::EPIPE, Errno::EBADF
|
19
|
-
raise DeadWakerError, "waker is already dead"
|
20
|
-
end
|
21
|
-
|
22
|
-
# Wait for another thread to signal this Waker
|
23
|
-
def wait
|
24
|
-
byte = @receiver.read(1)
|
25
|
-
raise DeadWakerError, "can't wait on a dead waker" unless byte == PAYLOAD
|
26
|
-
rescue IOError, RuntimeError
|
27
|
-
raise DeadWakerError, "can't wait on a dead waker"
|
28
|
-
end
|
29
|
-
|
30
|
-
# Return the IO object which will be readable when this Waker is signaled
|
31
|
-
def io
|
32
|
-
@receiver
|
33
|
-
end
|
34
|
-
|
35
|
-
# Clean up the IO objects associated with this waker
|
36
|
-
def cleanup
|
37
|
-
@receiver.close rescue nil
|
38
|
-
@sender.close rescue nil
|
39
|
-
nil
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Celluloid::IO::Waker do
|
4
|
-
it "blocks until awoken" do
|
5
|
-
waker = Celluloid::IO::Waker.new
|
6
|
-
thread = Thread.new do
|
7
|
-
waker.wait
|
8
|
-
:done
|
9
|
-
end
|
10
|
-
|
11
|
-
# Assert that the thread can't be joined at this point
|
12
|
-
thread.join(0).should be_nil
|
13
|
-
|
14
|
-
waker.signal
|
15
|
-
thread.value.should == :done
|
16
|
-
end
|
17
|
-
|
18
|
-
it "returns an IO object that can be multiplexed with IO.select" do
|
19
|
-
waker = Celluloid::IO::Waker.new
|
20
|
-
waker.io.should be_an_instance_of(IO)
|
21
|
-
|
22
|
-
thread = Thread.new do
|
23
|
-
readable, _, _ = select [waker.io]
|
24
|
-
waker.wait
|
25
|
-
:done
|
26
|
-
end
|
27
|
-
|
28
|
-
# Assert that the thread can't be joined at this point
|
29
|
-
thread.join(0).should be_nil
|
30
|
-
|
31
|
-
waker.signal
|
32
|
-
thread.value.should == :done
|
33
|
-
end
|
34
|
-
end
|