celluloid 0.12.0.pre → 0.12.0.pre2
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/lib/celluloid.rb +15 -5
- data/lib/celluloid/future.rb +5 -3
- data/lib/celluloid/proxies/abstract_proxy.rb +17 -0
- data/lib/celluloid/{actor_proxy.rb → proxies/actor_proxy.rb} +25 -32
- data/lib/celluloid/proxies/async_proxy.rb +19 -0
- data/lib/celluloid/proxies/future_proxy.rb +19 -0
- data/lib/celluloid/tasks/task_thread.rb +25 -16
- data/lib/celluloid/version.rb +1 -1
- data/spec/support/actor_examples.rb +38 -9
- metadata +36 -33
data/lib/celluloid.rb
CHANGED
@@ -133,10 +133,15 @@ module Celluloid
|
|
133
133
|
if block
|
134
134
|
@mailbox_factory = block
|
135
135
|
else
|
136
|
-
|
136
|
+
mailbox_class(klass)
|
137
137
|
end
|
138
138
|
end
|
139
139
|
|
140
|
+
# Define the mailbox class for this class
|
141
|
+
def mailbox_class(klass)
|
142
|
+
@mailbox_factory = proc { klass.new }
|
143
|
+
end
|
144
|
+
|
140
145
|
# Define the default task type for this class
|
141
146
|
def task_class(klass)
|
142
147
|
@task_class = klass
|
@@ -166,10 +171,10 @@ module Celluloid
|
|
166
171
|
# Configuration options for Actor#new
|
167
172
|
def actor_options
|
168
173
|
{
|
169
|
-
:mailbox
|
170
|
-
:exit_handler
|
174
|
+
:mailbox => mailbox_factory,
|
175
|
+
:exit_handler => @exit_handler,
|
171
176
|
:exclusive_methods => @exclusive_methods,
|
172
|
-
:task_class
|
177
|
+
:task_class => @task_class
|
173
178
|
}
|
174
179
|
end
|
175
180
|
|
@@ -370,7 +375,7 @@ module Celluloid
|
|
370
375
|
end
|
371
376
|
|
372
377
|
require 'celluloid/version'
|
373
|
-
|
378
|
+
|
374
379
|
require 'celluloid/calls'
|
375
380
|
require 'celluloid/core_ext'
|
376
381
|
require 'celluloid/cpu_counter'
|
@@ -390,6 +395,11 @@ require 'celluloid/task'
|
|
390
395
|
require 'celluloid/thread_handle'
|
391
396
|
require 'celluloid/uuid'
|
392
397
|
|
398
|
+
require 'celluloid/proxies/abstract_proxy'
|
399
|
+
require 'celluloid/proxies/actor_proxy'
|
400
|
+
require 'celluloid/proxies/async_proxy'
|
401
|
+
require 'celluloid/proxies/future_proxy'
|
402
|
+
|
393
403
|
require 'celluloid/actor'
|
394
404
|
require 'celluloid/future'
|
395
405
|
require 'celluloid/pool_manager'
|
data/lib/celluloid/future.rb
CHANGED
@@ -35,6 +35,11 @@ module Celluloid
|
|
35
35
|
receiver << @call
|
36
36
|
end
|
37
37
|
|
38
|
+
# Check if this future has a value yet
|
39
|
+
def ready?
|
40
|
+
@ready
|
41
|
+
end
|
42
|
+
|
38
43
|
# Obtain the value for this Future
|
39
44
|
def value(timeout = nil)
|
40
45
|
ready = result = nil
|
@@ -91,9 +96,6 @@ module Celluloid
|
|
91
96
|
end
|
92
97
|
alias_method :<<, :signal
|
93
98
|
|
94
|
-
# Is the future ready yet?
|
95
|
-
def ready?; @ready; end
|
96
|
-
|
97
99
|
# Inspect this Celluloid::Future
|
98
100
|
alias_method :inspect, :to_s
|
99
101
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Celluloid
|
2
|
+
# Base class of all Celluloid proxies
|
3
|
+
class AbstractProxy < BasicObject
|
4
|
+
# Needed for storing proxies in data structures
|
5
|
+
needed = [:object_id, :__id__, :hash] - instance_methods
|
6
|
+
if needed.any?
|
7
|
+
include ::Kernel.dup.module_eval {
|
8
|
+
undef_method *(instance_methods - needed)
|
9
|
+
self
|
10
|
+
}
|
11
|
+
|
12
|
+
# rubinius bug? These methods disappear when we include hacked kernel
|
13
|
+
define_method :==, ::BasicObject.instance_method(:==) unless instance_methods.include?(:==)
|
14
|
+
alias_method(:equal?, :==) unless instance_methods.include?(:equal?)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -1,33 +1,25 @@
|
|
1
1
|
module Celluloid
|
2
|
-
# A proxy object returned from Celluloid::Actor.
|
3
|
-
#
|
4
|
-
|
5
|
-
class ActorProxy < BasicObject
|
2
|
+
# A proxy object returned from Celluloid::Actor.new/new_link which converts
|
3
|
+
# the normal Ruby method protocol into an inter-actor message protocol
|
4
|
+
class ActorProxy < AbstractProxy
|
6
5
|
attr_reader :mailbox, :thread
|
7
6
|
|
8
7
|
def initialize(actor)
|
9
8
|
@mailbox, @thread, @klass = actor.mailbox, actor.thread, actor.subject.class.to_s
|
10
9
|
end
|
11
10
|
|
12
|
-
def
|
13
|
-
Actor.call @mailbox, :__send__,
|
11
|
+
def class
|
12
|
+
Actor.call @mailbox, :__send__, :class
|
14
13
|
end
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
if needed.any?
|
19
|
-
include ::Kernel.dup.module_eval {
|
20
|
-
undef_method *(instance_methods - needed)
|
21
|
-
self
|
22
|
-
}
|
23
|
-
|
24
|
-
# rubinius bug? These methods disappear when we include hacked kernel
|
25
|
-
define_method :==, ::BasicObject.instance_method(:==) unless instance_methods.include?(:==)
|
26
|
-
alias_method(:equal?, :==) unless instance_methods.include?(:equal?)
|
15
|
+
def _send_(meth, *args, &block)
|
16
|
+
Actor.call @mailbox, :__send__, meth, *args, &block
|
27
17
|
end
|
28
18
|
|
29
|
-
def
|
30
|
-
Actor.call @mailbox, :
|
19
|
+
def inspect
|
20
|
+
Actor.call @mailbox, :inspect
|
21
|
+
rescue DeadActorError
|
22
|
+
"#<Celluloid::Actor(#{@klass}) dead>"
|
31
23
|
end
|
32
24
|
|
33
25
|
def name
|
@@ -62,21 +54,22 @@ module Celluloid
|
|
62
54
|
Actor.call @mailbox, :to_s
|
63
55
|
end
|
64
56
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
# predicate syntax. TIMTOWTDI!
|
73
|
-
def async(method_name, *args, &block)
|
74
|
-
Actor.async @mailbox, method_name, *args, &block
|
57
|
+
# Obtain an async proxy or explicitly invoke a named async method
|
58
|
+
def async(method_name = nil, *args, &block)
|
59
|
+
if method_name
|
60
|
+
Actor.async @mailbox, method_name, *args, &block
|
61
|
+
else
|
62
|
+
AsyncProxy.new(@mailbox, @klass)
|
63
|
+
end
|
75
64
|
end
|
76
65
|
|
77
|
-
#
|
78
|
-
def future(method_name, *args, &block)
|
79
|
-
|
66
|
+
# Obtain a future proxy or explicitly invoke a named future method
|
67
|
+
def future(method_name = nil, *args, &block)
|
68
|
+
if method_name
|
69
|
+
Actor.future @mailbox, method_name, *args, &block
|
70
|
+
else
|
71
|
+
FutureProxy.new(@mailbox, @klass)
|
72
|
+
end
|
80
73
|
end
|
81
74
|
|
82
75
|
# Terminate the associated actor
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Celluloid
|
2
|
+
# A proxy which sends asynchronous calls to an actor
|
3
|
+
class AsyncProxy < AbstractProxy
|
4
|
+
attr_reader :mailbox
|
5
|
+
|
6
|
+
def initialize(mailbox, klass)
|
7
|
+
@mailbox, @klass = mailbox, klass
|
8
|
+
end
|
9
|
+
|
10
|
+
def inspect
|
11
|
+
"#<Celluloid::AsyncProxy(#{@klass})>"
|
12
|
+
end
|
13
|
+
|
14
|
+
# method_missing black magic to call bang predicate methods asynchronously
|
15
|
+
def method_missing(meth, *args, &block)
|
16
|
+
Actor.async @mailbox, meth, *args, &block
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Celluloid
|
2
|
+
# A proxy which creates future calls to an actor
|
3
|
+
class FutureProxy < AbstractProxy
|
4
|
+
attr_reader :mailbox
|
5
|
+
|
6
|
+
def initialize(mailbox, klass)
|
7
|
+
@mailbox, @klass = mailbox, klass
|
8
|
+
end
|
9
|
+
|
10
|
+
def inspect
|
11
|
+
"#<Celluloid::FutureProxy(#{@klass})>"
|
12
|
+
end
|
13
|
+
|
14
|
+
# method_missing black magic to call bang predicate methods asynchronously
|
15
|
+
def method_missing(meth, *args, &block)
|
16
|
+
Actor.future @mailbox, meth, *args, &block
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -7,27 +7,32 @@ module Celluloid
|
|
7
7
|
def initialize(type)
|
8
8
|
@type = type
|
9
9
|
@status = :new
|
10
|
-
|
11
|
-
@
|
10
|
+
|
11
|
+
@resume_queue = Queue.new
|
12
|
+
@yield_mutex = Mutex.new
|
13
|
+
@yield_cond = ConditionVariable.new
|
12
14
|
|
13
15
|
actor, mailbox = Thread.current[:actor], Thread.current[:mailbox]
|
14
16
|
raise NotActorError, "can't create tasks outside of actors" unless actor
|
15
17
|
|
16
18
|
@thread = InternalPool.get do
|
17
|
-
@status = :running
|
18
|
-
Thread.current[:actor] = actor
|
19
|
-
Thread.current[:mailbox] = mailbox
|
20
|
-
Thread.current[:task] = self
|
21
|
-
actor.tasks << self
|
22
|
-
|
23
19
|
begin
|
24
|
-
@
|
20
|
+
value = @resume_queue.pop
|
21
|
+
raise value if value.is_a?(Task::TerminatedError)
|
22
|
+
|
23
|
+
@status = :running
|
24
|
+
Thread.current[:actor] = actor
|
25
|
+
Thread.current[:mailbox] = mailbox
|
26
|
+
Thread.current[:task] = self
|
27
|
+
actor.tasks << self
|
28
|
+
|
29
|
+
yield
|
25
30
|
rescue Task::TerminatedError
|
26
31
|
# Task was explicitly terminated
|
27
32
|
ensure
|
28
33
|
@status = :dead
|
29
34
|
actor.tasks.delete self
|
30
|
-
@
|
35
|
+
@yield_cond.signal
|
31
36
|
end
|
32
37
|
end
|
33
38
|
end
|
@@ -35,20 +40,24 @@ module Celluloid
|
|
35
40
|
# Suspend the current task, changing the status to the given argument
|
36
41
|
def suspend(status)
|
37
42
|
@status = status
|
38
|
-
@
|
39
|
-
|
43
|
+
@yield_cond.signal
|
44
|
+
value = @resume_queue.pop
|
40
45
|
|
41
|
-
raise
|
46
|
+
raise value if value.is_a?(Task::TerminatedError)
|
42
47
|
@status = :running
|
43
48
|
|
44
|
-
|
49
|
+
value
|
45
50
|
end
|
46
51
|
|
47
52
|
# Resume a suspended task, giving it a value to return if needed
|
48
53
|
def resume(value = nil)
|
49
54
|
raise DeadTaskError, "cannot resume a dead task" unless @thread.alive?
|
50
|
-
|
51
|
-
@
|
55
|
+
|
56
|
+
@yield_mutex.synchronize do
|
57
|
+
@resume_queue.push(value)
|
58
|
+
@yield_cond.wait(@yield_mutex)
|
59
|
+
end
|
60
|
+
|
52
61
|
nil
|
53
62
|
rescue ThreadError
|
54
63
|
raise DeadTaskError, "cannot resume a dead task"
|
data/lib/celluloid/version.rb
CHANGED
@@ -25,22 +25,28 @@ shared_context "a Celluloid Actor" do |included_module|
|
|
25
25
|
actor.object_id.should_not == Kernel.object_id
|
26
26
|
end
|
27
27
|
|
28
|
-
it "
|
28
|
+
it "supports synchronous calls" do
|
29
29
|
actor = actor_class.new "Troy McClure"
|
30
30
|
actor.greet.should == "Hi, I'm Troy McClure"
|
31
31
|
end
|
32
32
|
|
33
|
-
it "
|
33
|
+
it "supports synchronous calls via #method" do
|
34
34
|
method = actor_class.new("Troy McClure").method(:greet)
|
35
35
|
method.call.should == "Hi, I'm Troy McClure"
|
36
36
|
end
|
37
37
|
|
38
|
-
it "
|
38
|
+
it "supports future(:method) syntax for synchronous future calls" do
|
39
39
|
actor = actor_class.new "Troy McClure"
|
40
40
|
future = actor.future :greet
|
41
41
|
future.value.should == "Hi, I'm Troy McClure"
|
42
42
|
end
|
43
43
|
|
44
|
+
it "supports future.method syntax for synchronous future calls" do
|
45
|
+
actor = actor_class.new "Troy McClure"
|
46
|
+
future = actor.future.greet
|
47
|
+
future.value.should == "Hi, I'm Troy McClure"
|
48
|
+
end
|
49
|
+
|
44
50
|
it "handles circular synchronous calls" do
|
45
51
|
klass = Class.new do
|
46
52
|
include included_module
|
@@ -136,19 +142,25 @@ shared_context "a Celluloid Actor" do |included_module|
|
|
136
142
|
end.to raise_exception(Celluloid::DeadActorError)
|
137
143
|
end
|
138
144
|
|
139
|
-
it "
|
145
|
+
it "supports method! syntax for asynchronous calls" do
|
140
146
|
actor = actor_class.new "Troy McClure"
|
141
147
|
actor.change_name! "Charlie Sheen"
|
142
148
|
actor.greet.should == "Hi, I'm Charlie Sheen"
|
143
149
|
end
|
144
150
|
|
145
|
-
it "
|
151
|
+
it "supports async(:method) syntax for asynchronous calls" do
|
146
152
|
actor = actor_class.new "Troy McClure"
|
147
153
|
actor.async :change_name, "Charlie Sheen"
|
148
154
|
actor.greet.should == "Hi, I'm Charlie Sheen"
|
149
155
|
end
|
150
156
|
|
151
|
-
it "
|
157
|
+
it "supports async.method syntax for asynchronous calls" do
|
158
|
+
actor = actor_class.new "Troy McClure"
|
159
|
+
actor.async.change_name "Charlie Sheen"
|
160
|
+
actor.greet.should == "Hi, I'm Charlie Sheen"
|
161
|
+
end
|
162
|
+
|
163
|
+
it "supports asynchronous calls to itself" do
|
152
164
|
actor = actor_class.new "Troy McClure"
|
153
165
|
actor.change_name_async "Charlie Sheen"
|
154
166
|
actor.greet.should == "Hi, I'm Charlie Sheen"
|
@@ -374,7 +386,6 @@ shared_context "a Celluloid Actor" do |included_module|
|
|
374
386
|
obj.should be_signaled
|
375
387
|
end
|
376
388
|
|
377
|
-
# FIXME: This is deadlocking on Travis, and may still have issues
|
378
389
|
it "sends values along with signals" do
|
379
390
|
obj = @signaler.new
|
380
391
|
obj.should_not be_signaled
|
@@ -472,8 +483,6 @@ shared_context "a Celluloid Actor" do |included_module|
|
|
472
483
|
end
|
473
484
|
|
474
485
|
context :timers do
|
475
|
-
# Level of accuracy enforced by the tests (50ms)
|
476
|
-
Q = 0.05
|
477
486
|
|
478
487
|
before do
|
479
488
|
@klass = Class.new do
|
@@ -636,6 +645,26 @@ shared_context "a Celluloid Actor" do |included_module|
|
|
636
645
|
end
|
637
646
|
end
|
638
647
|
|
648
|
+
context :mailbox_class do
|
649
|
+
class ExampleMailbox < Celluloid::Mailbox; end
|
650
|
+
|
651
|
+
subject do
|
652
|
+
Class.new do
|
653
|
+
include included_module
|
654
|
+
mailbox_class ExampleMailbox
|
655
|
+
end
|
656
|
+
end
|
657
|
+
|
658
|
+
it "overrides the mailbox class" do
|
659
|
+
subject.new.mailbox.should be_a ExampleMailbox
|
660
|
+
end
|
661
|
+
|
662
|
+
it "retains custom mailboxes when subclassed" do
|
663
|
+
subclass = Class.new(subject)
|
664
|
+
subclass.new.mailbox.should be_a ExampleMailbox
|
665
|
+
end
|
666
|
+
end
|
667
|
+
|
639
668
|
context :task_class do
|
640
669
|
class ExampleTask < Celluloid::TaskFiber; end
|
641
670
|
|
metadata
CHANGED
@@ -1,62 +1,61 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: celluloid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.12.0.pre
|
5
4
|
prerelease: 7
|
5
|
+
version: 0.12.0.pre2
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Tony Arcieri
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-09-
|
12
|
+
date: 2012-09-03 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: timers
|
16
|
-
|
17
|
-
none: false
|
16
|
+
version_requirements: &2056 !ruby/object:Gem::Requirement
|
18
17
|
requirements:
|
19
18
|
- - ! '>='
|
20
19
|
- !ruby/object:Gem::Version
|
21
20
|
version: 1.0.0
|
22
|
-
|
21
|
+
none: false
|
22
|
+
requirement: *2056
|
23
23
|
prerelease: false
|
24
|
-
|
24
|
+
type: :runtime
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rake
|
27
|
-
|
28
|
-
none: false
|
27
|
+
version_requirements: &2074 !ruby/object:Gem::Requirement
|
29
28
|
requirements:
|
30
29
|
- - ! '>='
|
31
30
|
- !ruby/object:Gem::Version
|
32
31
|
version: '0'
|
33
|
-
|
32
|
+
none: false
|
33
|
+
requirement: *2074
|
34
34
|
prerelease: false
|
35
|
-
|
35
|
+
type: :development
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rspec
|
38
|
-
|
39
|
-
none: false
|
38
|
+
version_requirements: &2092 !ruby/object:Gem::Requirement
|
40
39
|
requirements:
|
41
40
|
- - ! '>='
|
42
41
|
- !ruby/object:Gem::Version
|
43
42
|
version: '0'
|
44
|
-
|
43
|
+
none: false
|
44
|
+
requirement: *2092
|
45
45
|
prerelease: false
|
46
|
-
|
46
|
+
type: :development
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: benchmark_suite
|
49
|
-
|
50
|
-
none: false
|
49
|
+
version_requirements: &2108 !ruby/object:Gem::Requirement
|
51
50
|
requirements:
|
52
51
|
- - ! '>='
|
53
52
|
- !ruby/object:Gem::Version
|
54
53
|
version: '0'
|
55
|
-
|
54
|
+
none: false
|
55
|
+
requirement: *2108
|
56
56
|
prerelease: false
|
57
|
-
|
58
|
-
description: Celluloid enables people to build concurrent programs out of concurrent
|
59
|
-
objects just as easily as they build sequential programs out of sequential objects
|
57
|
+
type: :development
|
58
|
+
description: Celluloid enables people to build concurrent programs out of concurrent objects just as easily as they build sequential programs out of sequential objects
|
60
59
|
email:
|
61
60
|
- tony.arcieri@gmail.com
|
62
61
|
executables: []
|
@@ -64,8 +63,8 @@ extensions: []
|
|
64
63
|
extra_rdoc_files: []
|
65
64
|
files:
|
66
65
|
- README.md
|
66
|
+
- lib/celluloid.rb
|
67
67
|
- lib/celluloid/actor.rb
|
68
|
-
- lib/celluloid/actor_proxy.rb
|
69
68
|
- lib/celluloid/boot.rb
|
70
69
|
- lib/celluloid/calls.rb
|
71
70
|
- lib/celluloid/core_ext.rb
|
@@ -89,12 +88,15 @@ files:
|
|
89
88
|
- lib/celluloid/supervisor.rb
|
90
89
|
- lib/celluloid/system_events.rb
|
91
90
|
- lib/celluloid/task.rb
|
92
|
-
- lib/celluloid/tasks/task_fiber.rb
|
93
|
-
- lib/celluloid/tasks/task_thread.rb
|
94
91
|
- lib/celluloid/thread_handle.rb
|
95
92
|
- lib/celluloid/uuid.rb
|
96
93
|
- lib/celluloid/version.rb
|
97
|
-
- lib/celluloid.rb
|
94
|
+
- lib/celluloid/proxies/abstract_proxy.rb
|
95
|
+
- lib/celluloid/proxies/actor_proxy.rb
|
96
|
+
- lib/celluloid/proxies/async_proxy.rb
|
97
|
+
- lib/celluloid/proxies/future_proxy.rb
|
98
|
+
- lib/celluloid/tasks/task_fiber.rb
|
99
|
+
- lib/celluloid/tasks/task_thread.rb
|
98
100
|
- spec/support/actor_examples.rb
|
99
101
|
- spec/support/example_actor_class.rb
|
100
102
|
- spec/support/mailbox_examples.rb
|
@@ -102,27 +104,28 @@ files:
|
|
102
104
|
homepage: https://github.com/celluloid/celluloid
|
103
105
|
licenses:
|
104
106
|
- MIT
|
105
|
-
post_install_message:
|
107
|
+
post_install_message:
|
106
108
|
rdoc_options: []
|
107
109
|
require_paths:
|
108
110
|
- lib
|
109
111
|
required_ruby_version: !ruby/object:Gem::Requirement
|
110
|
-
none: false
|
111
112
|
requirements:
|
112
113
|
- - ! '>='
|
113
114
|
- !ruby/object:Gem::Version
|
114
|
-
version:
|
115
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
|
+
version: 1.9.2
|
116
116
|
none: false
|
117
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
118
|
requirements:
|
118
119
|
- - ! '>='
|
119
120
|
- !ruby/object:Gem::Version
|
120
121
|
version: 1.3.6
|
122
|
+
none: false
|
121
123
|
requirements: []
|
122
|
-
rubyforge_project:
|
123
|
-
rubygems_version: 1.8.
|
124
|
-
signing_key:
|
124
|
+
rubyforge_project:
|
125
|
+
rubygems_version: 1.8.15
|
126
|
+
signing_key:
|
125
127
|
specification_version: 3
|
126
128
|
summary: Actor-based concurrent object framework for Ruby
|
127
129
|
test_files: []
|
128
|
-
has_rdoc:
|
130
|
+
has_rdoc:
|
131
|
+
...
|