celluloid-io 0.7.0 → 0.8.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.
data/.travis.yml CHANGED
@@ -1,7 +1,7 @@
1
1
  rvm:
2
2
  - 1.9.2
3
3
  - 1.9.3
4
- # - rbx # crashing :(
4
+ # - rbx crashing :(
5
5
  - jruby
6
6
  - ruby-head
7
7
 
data/CHANGES.md CHANGED
@@ -1,3 +1,8 @@
1
+ 0.8.0
2
+ -----
3
+ * Switch to nio4r-based reactor
4
+ * Compatibility with Celluloid 0.8.0 API changes
5
+
1
6
  0.7.0
2
7
  -----
3
8
  * Initial release forked from Celluloid
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
- require 'celluloid/io'
39
-
40
- class MyServer
41
- include Celluloid::IO
42
-
43
- # Bind a TCP server to the given host and port
44
- def initialize(host, port)
45
- @server = TCPServer.new host, port
46
- run!
47
- end
48
-
49
- # Run the TCP server event loop
50
- def run
51
- while true
52
- wait_readable(@server)
53
- on_connect @server.accept
54
- end
55
- end
56
-
57
- # Terminate this server
58
- def terminate
59
- @server.close
60
- super
61
- end
62
-
63
- # Called whenever a new connection is opened
64
- def on_connect(connection)
65
- connection.close
66
- end
67
- end
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.add_development_dependency('celluloid', '>= 0.7.0')
18
+ gem.add_dependency 'celluloid', '~> 0.8.0'
19
+ gem.add_dependency 'nio4r', '>= 0.2.2'
19
20
 
20
- gem.add_development_dependency('rake')
21
- gem.add_development_dependency('rspec', ['>= 2.7.0'])
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
- # Wait for the given IO object to become readable
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
- def wait_writeable(io, &block)
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
@@ -1,24 +1,23 @@
1
1
  module Celluloid
2
2
  module IO
3
- # An alternative implementation of Celluloid::Mailbox using Wakers
3
+ # An alternative implementation of Celluloid::Mailbox using Reactor
4
4
  class Mailbox < Celluloid::Mailbox
5
- attr_reader :reactor, :waker
5
+ attr_reader :reactor
6
6
 
7
7
  def initialize
8
8
  @messages = []
9
9
  @lock = Mutex.new
10
- @waker = Waker.new
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
- @waker.signal
17
+ @reactor.wakeup
19
18
  end
20
19
  nil
21
- rescue DeadWakerError
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
- @waker.signal
32
- rescue DeadWakerError
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 = nil
40
+ message = next_message(&block)
42
41
 
43
- begin
42
+ until message
44
43
  if timeout
45
- now = Time.now
46
- wait_until ||= now + timeout
47
- wait_interval = wait_until - now
48
- return if wait_interval < 0
49
- else
50
- wait_interval = nil
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
- end until message
51
+
52
+ @reactor.run_once(wait_interval)
53
+ message = next_message(&block)
54
+ end
58
55
 
59
56
  message
60
- rescue IOError, DeadWakerError
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
- @waker.cleanup
64
+ @reactor.shutdown
68
65
  super
69
66
  end
70
67
  end
71
68
  end
72
- end
69
+ end
@@ -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
- def initialize(waker)
7
- @waker = waker
8
- @readers = {}
9
- @writers = {}
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
- wait_for_io io, @readers
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
- wait_for_io io, @writers
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
- private
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
- if set.has_key? io
54
- raise ArgumentError, "another method is already waiting on #{io.inspect}"
55
- else
56
- set[io] = Task.current
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
@@ -1,5 +1,5 @@
1
1
  module Celluloid
2
2
  module IO
3
- VERSION = "0.7.0"
3
+ VERSION = "0.8.0"
4
4
  end
5
5
  end
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.7.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: 2011-12-29 00:00:00.000000000 Z
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: &70176481988080 !ruby/object:Gem::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.7.0
22
- type: :development
32
+ version: 0.2.2
33
+ type: :runtime
23
34
  prerelease: false
24
- version_requirements: *70176481988080
35
+ version_requirements: *70254645082660
25
36
  - !ruby/object:Gem::Dependency
26
37
  name: rake
27
- requirement: &70176481987440 !ruby/object:Gem::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: *70176481987440
46
+ version_requirements: *70254645082180
36
47
  - !ruby/object:Gem::Dependency
37
48
  name: rspec
38
- requirement: &70176481986860 !ruby/object:Gem::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: *70176481986860
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:
@@ -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