celluloid-io 0.7.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,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --color
2
+ --format documentation
3
+ --backtrace
4
+ --default_path spec
@@ -0,0 +1,8 @@
1
+ rvm:
2
+ - 1.9.2
3
+ - 1.9.3
4
+ # - rbx # crashing :(
5
+ - jruby
6
+ - ruby-head
7
+
8
+ env: "JRUBY_OPTS=--1.9"
@@ -0,0 +1,3 @@
1
+ 0.7.0
2
+ -----
3
+ * Initial release forked from Celluloid
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source :rubygems
2
+
3
+ gem 'celluloid', :git => 'git://github.com/tarcieri/celluloid'
4
+
5
+ # Specify your gem's dependencies in celluloid-io.gemspec
6
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2011 Tony Arcieri
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,80 @@
1
+ Celluloid::IO
2
+ =============
3
+ [![Build Status](http://travis-ci.org/tarcieri/celluloid-io.png)](http://travis-ci.org/tarcieri/celluloid-io)
4
+
5
+ You don't have to choose between threaded and evented IO! Celluloid::IO provides
6
+ a simple and easy way to wait for IO events inside of a Celluloid actor, which
7
+ runs in its own thread. Any Ruby IO object can be registered and monitored.
8
+ It's a somewhat similar idea to Ruby event frameworks like EventMachine and
9
+ Cool.io, but Celluloid actors automatically wrap up all IO in Fibers,
10
+ resulting in a synchronous API that's duck type compatible with existing IO
11
+ objects.
12
+
13
+ Unlike EventMachine, you can make as many Celluloid::IO actors as you wish,
14
+ each running their own event loop independently from the others. Using many
15
+ actors allows your program to scale across multiple CPU cores on Ruby
16
+ implementations which don't have a GIL, such as JRuby and Rubinius.
17
+
18
+ Like Celluloid::IO? [Join the Google Group](http://groups.google.com/group/celluloid-ruby)
19
+
20
+ Supported Platforms
21
+ -------------------
22
+
23
+ Celluloid works on Ruby 1.9.2+, JRuby 1.6 (in 1.9 mode), and Rubinius 2.0. JRuby
24
+ or Rubinius are the preferred platforms as they support true hardware-level
25
+ parallelism when running Ruby code, whereas MRI/YARV is constrained by a global
26
+ interpreter lock (GIL).
27
+
28
+ To use JRuby in 1.9 mode, you'll need to pass the "--1.9" command line option
29
+ to the JRuby executable, or set the "JRUBY_OPTS=--1.9" environment variable.
30
+
31
+ Celluloid works on Rubinius in either 1.8 or 1.9 mode.
32
+
33
+ Usage
34
+ -----
35
+
36
+ To use Celluloid::IO, define a normal Ruby class that includes Celluloid::IO:
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
68
+
69
+ Contributing to Celluloid::IO
70
+ -----------------------------
71
+
72
+ * Fork Celluloid on github
73
+ * Make your changes and send me a pull request
74
+ * If I like them I'll merge them and give you commit access to my repository
75
+
76
+ License
77
+ -------
78
+
79
+ Copyright (c) 2011 Tony Arcieri. Distributed under the MIT License. See
80
+ LICENSE.txt for further details.
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env rake
2
+ require 'bundler/gem_tasks'
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new
6
+
7
+ task :default => :spec
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/celluloid/io/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Tony Arcieri"]
6
+ gem.email = ["tony.arcieri@gmail.com"]
7
+ gem.description = "Evented IO for Celluloid actors"
8
+ gem.summary = "Celluloid::IO allows you to monitor multiple IO objects within a Celluloid actor"
9
+ gem.homepage = "http://github.com/tarcieri/celluloid-io"
10
+
11
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
12
+ gem.files = `git ls-files`.split("\n")
13
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
14
+ gem.name = "celluloid-io"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Celluloid::IO::VERSION
17
+
18
+ gem.add_development_dependency('celluloid', '>= 0.7.0')
19
+
20
+ gem.add_development_dependency('rake')
21
+ gem.add_development_dependency('rspec', ['>= 2.7.0'])
22
+ end
@@ -0,0 +1,27 @@
1
+ require 'celluloid/io/version'
2
+
3
+ require 'celluloid'
4
+ require 'celluloid/io/mailbox'
5
+ require 'celluloid/io/reactor'
6
+ require 'celluloid/io/waker'
7
+
8
+ module Celluloid
9
+ # Actors with evented IO support
10
+ module IO
11
+ def self.included(klass)
12
+ klass.send :include, Celluloid
13
+ klass.use_mailbox Celluloid::IO::Mailbox
14
+ end
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
21
+
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
26
+ end
27
+ end
@@ -0,0 +1,72 @@
1
+ module Celluloid
2
+ module IO
3
+ # An alternative implementation of Celluloid::Mailbox using Wakers
4
+ class Mailbox < Celluloid::Mailbox
5
+ attr_reader :reactor, :waker
6
+
7
+ def initialize
8
+ @messages = []
9
+ @lock = Mutex.new
10
+ @waker = Waker.new
11
+ @reactor = Reactor.new(@waker)
12
+ end
13
+
14
+ # Add a message to the Mailbox
15
+ def <<(message)
16
+ @lock.synchronize do
17
+ @messages << message
18
+ @waker.signal
19
+ end
20
+ nil
21
+ rescue DeadWakerError
22
+ raise MailboxError, "dead recipient"
23
+ end
24
+
25
+ # Add a high-priority system event to the Mailbox
26
+ def system_event(event)
27
+ @lock.synchronize do
28
+ @messages.unshift event
29
+
30
+ begin
31
+ @waker.signal
32
+ rescue DeadWakerError
33
+ # Silently fail if messages are sent to dead actors
34
+ end
35
+ end
36
+ nil
37
+ end
38
+
39
+ # Receive a message from the Mailbox
40
+ def receive(timeout = nil, &block)
41
+ message = nil
42
+
43
+ begin
44
+ 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)
56
+ end
57
+ end until message
58
+
59
+ message
60
+ rescue IOError, DeadWakerError
61
+ shutdown # force shutdown of the mailbox
62
+ raise MailboxShutdown, "mailbox shutdown called during receive"
63
+ end
64
+
65
+ # Cleanup any IO objects this Mailbox may be using
66
+ def shutdown
67
+ @waker.cleanup
68
+ super
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,63 @@
1
+ module Celluloid
2
+ module IO
3
+ # React to external I/O events. This is kinda sorta supposed to resemble the
4
+ # Reactor design pattern.
5
+ class Reactor
6
+ def initialize(waker)
7
+ @waker = waker
8
+ @readers = {}
9
+ @writers = {}
10
+ end
11
+
12
+ # Wait for the given IO object to become readable
13
+ def wait_readable(io)
14
+ wait_for_io io, @readers
15
+ end
16
+
17
+ # Wait for the given IO object to become writeable
18
+ 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
36
+ end
37
+
38
+ #######
39
+ private
40
+ #######
41
+
42
+ def wait_for_io(io, set)
43
+ # zomg ugly type conversion :(
44
+ unless io.is_a?(IO)
45
+ if IO.respond_to? :try_convert
46
+ io = IO.try_convert(io)
47
+ elsif io.respond_to? :to_io
48
+ io = io.to_io
49
+ else raise TypeError, "can't convert #{io.class} into IO"
50
+ end
51
+ 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
57
+ end
58
+
59
+ Task.suspend
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,5 @@
1
+ module Celluloid
2
+ module IO
3
+ VERSION = "0.7.0"
4
+ end
5
+ end
@@ -0,0 +1,43 @@
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
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe Celluloid::IO do
4
+ it_behaves_like "a Celluloid Actor", Celluloid::IO
5
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe Celluloid::IO::Mailbox do
4
+ it_behaves_like "a Celluloid Mailbox"
5
+ end
@@ -0,0 +1,34 @@
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
@@ -0,0 +1,4 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'celluloid/io'
4
+ require 'celluloid/rspec'
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: celluloid-io
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.7.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Tony Arcieri
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-12-29 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: celluloid
16
+ requirement: &70176481988080 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.7.0
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70176481988080
25
+ - !ruby/object:Gem::Dependency
26
+ name: rake
27
+ requirement: &70176481987440 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70176481987440
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ requirement: &70176481986860 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: 2.7.0
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70176481986860
47
+ description: Evented IO for Celluloid actors
48
+ email:
49
+ - tony.arcieri@gmail.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - .gitignore
55
+ - .rspec
56
+ - .travis.yml
57
+ - CHANGES.md
58
+ - Gemfile
59
+ - LICENSE.txt
60
+ - README.md
61
+ - Rakefile
62
+ - celluloid-io.gemspec
63
+ - lib/celluloid/io.rb
64
+ - lib/celluloid/io/mailbox.rb
65
+ - lib/celluloid/io/reactor.rb
66
+ - lib/celluloid/io/version.rb
67
+ - lib/celluloid/io/waker.rb
68
+ - spec/celluloid/io/actor_spec.rb
69
+ - spec/celluloid/io/mailbox_spec.rb
70
+ - spec/celluloid/io/waker_spec.rb
71
+ - spec/spec_helper.rb
72
+ homepage: http://github.com/tarcieri/celluloid-io
73
+ licenses: []
74
+ post_install_message:
75
+ rdoc_options: []
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ none: false
80
+ requirements:
81
+ - - ! '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirements: []
91
+ rubyforge_project:
92
+ rubygems_version: 1.8.10
93
+ signing_key:
94
+ specification_version: 3
95
+ summary: Celluloid::IO allows you to monitor multiple IO objects within a Celluloid
96
+ actor
97
+ test_files:
98
+ - spec/celluloid/io/actor_spec.rb
99
+ - spec/celluloid/io/mailbox_spec.rb
100
+ - spec/celluloid/io/waker_spec.rb
101
+ - spec/spec_helper.rb