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 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