celluloid 0.13.0 → 0.14.1
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.
- checksums.yaml +7 -0
- data/README.md +1 -2
- data/lib/celluloid/actor.rb +33 -30
- data/lib/celluloid/autostart.rb +0 -13
- data/lib/celluloid/calls.rb +71 -23
- data/lib/celluloid/condition.rb +32 -28
- data/lib/celluloid/core_ext.rb +3 -14
- data/lib/celluloid/cpu_counter.rb +1 -1
- data/lib/celluloid/evented_mailbox.rb +82 -0
- data/lib/celluloid/fsm.rb +2 -0
- data/lib/celluloid/future.rb +22 -31
- data/lib/celluloid/internal_pool.rb +13 -0
- data/lib/celluloid/legacy.rb +14 -13
- data/lib/celluloid/logging/incident_logger.rb +2 -2
- data/lib/celluloid/mailbox.rb +16 -0
- data/lib/celluloid/method.rb +7 -7
- data/lib/celluloid/notifications.rb +1 -1
- data/lib/celluloid/proxies/abstract_proxy.rb +1 -1
- data/lib/celluloid/proxies/actor_proxy.rb +23 -27
- data/lib/celluloid/proxies/async_proxy.rb +18 -6
- data/lib/celluloid/proxies/block_proxy.rb +29 -0
- data/lib/celluloid/proxies/future_proxy.rb +17 -3
- data/lib/celluloid/proxies/sync_proxy.rb +31 -0
- data/lib/celluloid/receivers.rb +1 -1
- data/lib/celluloid/responses.rb +13 -1
- data/lib/celluloid/stack_dump.rb +8 -5
- data/lib/celluloid/supervision_group.rb +10 -10
- data/lib/celluloid/system_events.rb +1 -0
- data/lib/celluloid/tasks/task_fiber.rb +9 -47
- data/lib/celluloid/tasks/task_thread.rb +9 -44
- data/lib/celluloid/tasks.rb +63 -2
- data/lib/celluloid/thread.rb +38 -0
- data/lib/celluloid/thread_handle.rb +5 -3
- data/lib/celluloid/version.rb +1 -1
- data/lib/celluloid.rb +84 -32
- data/spec/support/actor_examples.rb +92 -53
- data/spec/support/example_actor_class.rb +7 -1
- data/spec/support/mailbox_examples.rb +29 -3
- data/spec/support/task_examples.rb +11 -9
- metadata +21 -29
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 83a01356fe7e144f11c0ac9db25951850f53c9b4
|
|
4
|
+
data.tar.gz: 243e2915cef408cf97229f8ec0a512bfb2524fb8
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 60e75d013b08ff7101ea6280b31bd5976ba097e821880e3d6d9b935580c8515d05d8619bc6a3df7be1d2733366d97b482a3668443e59c3c9e397bc6a14e46c75
|
|
7
|
+
data.tar.gz: 3e9fe0851276289183c6ca52e72bc545dc174831d325d78a9682f63087c4f54ff3b6f454babf4b091641a163235f953e02bbf656cfbdce4e093ec35df831e167
|
data/README.md
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
=========
|
|
3
3
|
[](http://rubygems.org/gems/celluloid)
|
|
4
4
|
[](http://travis-ci.org/celluloid/celluloid)
|
|
5
|
-
[](https://gemnasium.com/celluloid/celluloid)
|
|
6
5
|
[](https://codeclimate.com/github/celluloid/celluloid)
|
|
7
6
|
[](https://coveralls.io/r/celluloid/celluloid)
|
|
8
7
|
|
|
@@ -70,7 +69,7 @@ to EventMachine (with a synchronous API instead of callback/deferrable soup)
|
|
|
70
69
|
is available through the [Celluloid::IO](https://github.com/celluloid/celluloid-io)
|
|
71
70
|
library.
|
|
72
71
|
|
|
73
|
-
Like Celluloid? [Join the Google Group](http://groups.google.com/group/celluloid-ruby)
|
|
72
|
+
Like Celluloid? [Join the mailing list/Google Group](http://groups.google.com/group/celluloid-ruby)
|
|
74
73
|
or visit us on IRC at #celluloid on freenode
|
|
75
74
|
|
|
76
75
|
### Is it any good?
|
data/lib/celluloid/actor.rb
CHANGED
|
@@ -10,7 +10,7 @@ module Celluloid
|
|
|
10
10
|
# A timeout occured before the given request could complete
|
|
11
11
|
class TimeoutError < StandardError; end
|
|
12
12
|
|
|
13
|
-
# The
|
|
13
|
+
# The sender made an error, not the current actor
|
|
14
14
|
class AbortError < StandardError
|
|
15
15
|
attr_reader :cause
|
|
16
16
|
|
|
@@ -58,42 +58,28 @@ module Celluloid
|
|
|
58
58
|
|
|
59
59
|
# Invoke a method on the given actor via its mailbox
|
|
60
60
|
def call(mailbox, meth, *args, &block)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
begin
|
|
64
|
-
mailbox << call
|
|
65
|
-
rescue MailboxError
|
|
66
|
-
raise DeadActorError, "attempted to call a dead actor"
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
Celluloid.suspend(:callwait, call).value
|
|
61
|
+
proxy = SyncProxy.new(mailbox, "UnknownClass")
|
|
62
|
+
proxy.method_missing(meth, *args, &block)
|
|
70
63
|
end
|
|
71
64
|
|
|
72
65
|
# Invoke a method asynchronously on an actor via its mailbox
|
|
73
66
|
def async(mailbox, meth, *args, &block)
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
rescue MailboxError
|
|
77
|
-
# Silently swallow asynchronous calls to dead actors. There's no way
|
|
78
|
-
# to reliably generate DeadActorErrors for async calls, so users of
|
|
79
|
-
# async calls should find other ways to deal with actors dying
|
|
80
|
-
# during an async call (i.e. linking/supervisors)
|
|
81
|
-
end
|
|
67
|
+
proxy = AsyncProxy.new(mailbox, "UnknownClass")
|
|
68
|
+
proxy.method_missing(meth, *args, &block)
|
|
82
69
|
end
|
|
83
70
|
|
|
84
71
|
# Call a method asynchronously and retrieve its value later
|
|
85
72
|
def future(mailbox, meth, *args, &block)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
future
|
|
73
|
+
proxy = FutureProxy.new(mailbox, "UnknownClass")
|
|
74
|
+
proxy.method_missing(meth, *args, &block)
|
|
89
75
|
end
|
|
90
76
|
|
|
91
77
|
# Obtain all running actors in the system
|
|
92
78
|
def all
|
|
93
79
|
actors = []
|
|
94
80
|
Thread.list.each do |t|
|
|
95
|
-
|
|
96
|
-
actors << actor.proxy if actor
|
|
81
|
+
next unless t.celluloid? && t.role == :actor
|
|
82
|
+
actors << t.actor.proxy if t.actor && t.actor.respond_to?(:proxy)
|
|
97
83
|
end
|
|
98
84
|
actors
|
|
99
85
|
end
|
|
@@ -142,8 +128,8 @@ module Celluloid
|
|
|
142
128
|
end
|
|
143
129
|
|
|
144
130
|
# Wait for an actor to terminate
|
|
145
|
-
def join(actor)
|
|
146
|
-
actor.thread.join
|
|
131
|
+
def join(actor, timeout = nil)
|
|
132
|
+
actor.thread.join(timeout)
|
|
147
133
|
actor
|
|
148
134
|
end
|
|
149
135
|
end
|
|
@@ -154,6 +140,7 @@ module Celluloid
|
|
|
154
140
|
@mailbox = options[:mailbox] || Mailbox.new
|
|
155
141
|
@exit_handler = options[:exit_handler]
|
|
156
142
|
@exclusives = options[:exclusive_methods]
|
|
143
|
+
@receiver_block_executions = options[:receiver_block_executions]
|
|
157
144
|
@task_class = options[:task_class] || Celluloid.task_class
|
|
158
145
|
|
|
159
146
|
@tasks = TaskSet.new
|
|
@@ -165,9 +152,8 @@ module Celluloid
|
|
|
165
152
|
@exclusive = false
|
|
166
153
|
@name = nil
|
|
167
154
|
|
|
168
|
-
@thread = ThreadHandle.new do
|
|
169
|
-
|
|
170
|
-
Thread.current[:celluloid_mailbox] = @mailbox
|
|
155
|
+
@thread = ThreadHandle.new(:actor) do
|
|
156
|
+
setup_thread
|
|
171
157
|
run
|
|
172
158
|
end
|
|
173
159
|
|
|
@@ -175,6 +161,11 @@ module Celluloid
|
|
|
175
161
|
@subject.instance_variable_set(OWNER_IVAR, self)
|
|
176
162
|
end
|
|
177
163
|
|
|
164
|
+
def setup_thread
|
|
165
|
+
Thread.current[:celluloid_actor] = self
|
|
166
|
+
Thread.current[:celluloid_mailbox] = @mailbox
|
|
167
|
+
end
|
|
168
|
+
|
|
178
169
|
# Run the actor loop
|
|
179
170
|
def run
|
|
180
171
|
begin
|
|
@@ -323,8 +314,20 @@ module Celluloid
|
|
|
323
314
|
when SystemEvent
|
|
324
315
|
handle_system_event message
|
|
325
316
|
when Call
|
|
326
|
-
task(:
|
|
327
|
-
|
|
317
|
+
task(:call, message.method) {
|
|
318
|
+
if @receiver_block_executions && meth = message.method
|
|
319
|
+
if meth == :__send__
|
|
320
|
+
meth = message.arguments.first
|
|
321
|
+
end
|
|
322
|
+
if @receiver_block_executions.include?(meth.to_sym)
|
|
323
|
+
message.execute_block_on_receiver
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
message.dispatch(@subject)
|
|
327
|
+
}
|
|
328
|
+
when BlockCall
|
|
329
|
+
task(:invoke_block) { message.dispatch }
|
|
330
|
+
when BlockResponse, Response
|
|
328
331
|
message.dispatch
|
|
329
332
|
else
|
|
330
333
|
@receivers.handle_message(message)
|
data/lib/celluloid/autostart.rb
CHANGED
|
@@ -1,16 +1,3 @@
|
|
|
1
1
|
require 'celluloid'
|
|
2
2
|
|
|
3
3
|
Celluloid.boot
|
|
4
|
-
|
|
5
|
-
# Terminate all actors at exit
|
|
6
|
-
at_exit do
|
|
7
|
-
if defined?(RUBY_ENGINE) && RUBY_ENGINE == "ruby" && RUBY_VERSION >= "1.9"
|
|
8
|
-
# workaround for MRI bug losing exit status in at_exit block
|
|
9
|
-
# http://bugs.ruby-lang.org/issues/5218
|
|
10
|
-
exit_status = $!.status if $!.is_a?(SystemExit)
|
|
11
|
-
Celluloid.shutdown
|
|
12
|
-
exit exit_status if exit_status
|
|
13
|
-
else
|
|
14
|
-
Celluloid.shutdown
|
|
15
|
-
end
|
|
16
|
-
end
|
data/lib/celluloid/calls.rb
CHANGED
|
@@ -4,19 +4,33 @@ module Celluloid
|
|
|
4
4
|
attr_reader :method, :arguments, :block
|
|
5
5
|
|
|
6
6
|
def initialize(method, arguments = [], block = nil)
|
|
7
|
-
@method, @arguments
|
|
7
|
+
@method, @arguments = method, arguments
|
|
8
|
+
if block
|
|
9
|
+
if Celluloid.exclusive?
|
|
10
|
+
# FIXME: nicer exception
|
|
11
|
+
raise "Cannot execute blocks on sender in exclusive mode"
|
|
12
|
+
end
|
|
13
|
+
@block = BlockProxy.new(self, Celluloid.mailbox, block)
|
|
14
|
+
else
|
|
15
|
+
@block = nil
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def execute_block_on_receiver
|
|
20
|
+
@block && @block.execution = :receiver
|
|
8
21
|
end
|
|
9
22
|
|
|
10
23
|
def dispatch(obj)
|
|
11
|
-
|
|
24
|
+
_block = @block && @block.to_proc
|
|
25
|
+
obj.public_send(@method, *@arguments, &_block)
|
|
12
26
|
rescue NoMethodError => ex
|
|
13
|
-
# Abort if the
|
|
27
|
+
# Abort if the sender made a mistake
|
|
14
28
|
raise AbortError.new(ex) unless obj.respond_to? @method
|
|
15
29
|
|
|
16
30
|
# Otherwise something blew up. Crash this actor
|
|
17
31
|
raise
|
|
18
32
|
rescue ArgumentError => ex
|
|
19
|
-
# Abort if the
|
|
33
|
+
# Abort if the sender made a mistake
|
|
20
34
|
begin
|
|
21
35
|
arity = obj.method(@method).arity
|
|
22
36
|
rescue NameError
|
|
@@ -34,26 +48,16 @@ module Celluloid
|
|
|
34
48
|
# Otherwise something blew up. Crash this actor
|
|
35
49
|
raise
|
|
36
50
|
end
|
|
37
|
-
|
|
38
|
-
def wait
|
|
39
|
-
loop do
|
|
40
|
-
message = Thread.mailbox.receive do |msg|
|
|
41
|
-
msg.respond_to?(:call) and msg.call == self
|
|
42
|
-
end
|
|
43
|
-
break message unless message.is_a?(SystemEvent)
|
|
44
|
-
Thread.current[:celluloid_actor].handle_system_event(message)
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
51
|
end
|
|
48
52
|
|
|
49
53
|
# Synchronous calls wait for a response
|
|
50
54
|
class SyncCall < Call
|
|
51
|
-
attr_reader :
|
|
55
|
+
attr_reader :sender, :task, :chain_id
|
|
52
56
|
|
|
53
|
-
def initialize(
|
|
57
|
+
def initialize(sender, method, arguments = [], block = nil, task = Thread.current[:celluloid_task], chain_id = Thread.current[:celluloid_chain_id])
|
|
54
58
|
super(method, arguments, block)
|
|
55
59
|
|
|
56
|
-
@
|
|
60
|
+
@sender = sender
|
|
57
61
|
@task = task
|
|
58
62
|
@chain_id = chain_id || Celluloid.uuid
|
|
59
63
|
end
|
|
@@ -64,11 +68,11 @@ module Celluloid
|
|
|
64
68
|
respond SuccessResponse.new(self, result)
|
|
65
69
|
rescue Exception => ex
|
|
66
70
|
# Exceptions that occur during synchronous calls are reraised in the
|
|
67
|
-
# context of the
|
|
71
|
+
# context of the sender
|
|
68
72
|
respond ErrorResponse.new(self, ex)
|
|
69
73
|
|
|
70
|
-
# Aborting indicates a protocol error on the part of the
|
|
71
|
-
# It should crash the
|
|
74
|
+
# Aborting indicates a protocol error on the part of the sender
|
|
75
|
+
# It should crash the sender, but the exception isn't reraised
|
|
72
76
|
# Otherwise, it's a bug in this actor and should be reraised
|
|
73
77
|
raise unless ex.is_a?(AbortError)
|
|
74
78
|
ensure
|
|
@@ -81,11 +85,36 @@ module Celluloid
|
|
|
81
85
|
end
|
|
82
86
|
|
|
83
87
|
def respond(message)
|
|
84
|
-
@
|
|
88
|
+
@sender << message
|
|
85
89
|
rescue MailboxError
|
|
86
|
-
# It's possible the
|
|
90
|
+
# It's possible the sender exited or crashed before we could send a
|
|
87
91
|
# response to them.
|
|
88
92
|
end
|
|
93
|
+
|
|
94
|
+
def value
|
|
95
|
+
Celluloid.suspend(:callwait, self).value
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def wait
|
|
99
|
+
loop do
|
|
100
|
+
message = Celluloid.mailbox.receive do |msg|
|
|
101
|
+
msg.respond_to?(:call) and msg.call == self
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
if message.is_a?(SystemEvent)
|
|
105
|
+
Thread.current[:celluloid_actor].handle_system_event(message)
|
|
106
|
+
else
|
|
107
|
+
# FIXME: add check for receiver block execution
|
|
108
|
+
if message.respond_to?(:value)
|
|
109
|
+
# FIXME: disable block execution if on :sender and (exclusive or outside of task)
|
|
110
|
+
# probably now in Call
|
|
111
|
+
break message
|
|
112
|
+
else
|
|
113
|
+
message.dispatch
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
89
118
|
end
|
|
90
119
|
|
|
91
120
|
# Asynchronous calls don't wait for a response
|
|
@@ -95,7 +124,7 @@ module Celluloid
|
|
|
95
124
|
Thread.current[:celluloid_chain_id] = Celluloid.uuid
|
|
96
125
|
super(obj)
|
|
97
126
|
rescue AbortError => ex
|
|
98
|
-
# Swallow aborted async calls, as they indicate the
|
|
127
|
+
# Swallow aborted async calls, as they indicate the sender made a mistake
|
|
99
128
|
Logger.debug("#{obj.class}: async call `#@method` aborted!\n#{Logger.format_exception(ex.cause)}")
|
|
100
129
|
ensure
|
|
101
130
|
Thread.current[:celluloid_chain_id] = nil
|
|
@@ -103,4 +132,23 @@ module Celluloid
|
|
|
103
132
|
|
|
104
133
|
end
|
|
105
134
|
|
|
135
|
+
class BlockCall
|
|
136
|
+
def initialize(block_proxy, sender, arguments, task = Thread.current[:celluloid_task])
|
|
137
|
+
@block_proxy = block_proxy
|
|
138
|
+
@sender = sender
|
|
139
|
+
@arguments = arguments
|
|
140
|
+
@task = task
|
|
141
|
+
end
|
|
142
|
+
attr_reader :task
|
|
143
|
+
|
|
144
|
+
def call
|
|
145
|
+
@block_proxy.call
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def dispatch
|
|
149
|
+
response = @block_proxy.block.call(*@arguments)
|
|
150
|
+
@sender << BlockResponse.new(self, response)
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
106
154
|
end
|
data/lib/celluloid/condition.rb
CHANGED
|
@@ -3,11 +3,30 @@ module Celluloid
|
|
|
3
3
|
|
|
4
4
|
# ConditionVariable-like signaling between tasks and actors
|
|
5
5
|
class Condition
|
|
6
|
+
class Waiter
|
|
7
|
+
def initialize(condition, task, mailbox)
|
|
8
|
+
@condition = condition
|
|
9
|
+
@task = task
|
|
10
|
+
@mailbox = mailbox
|
|
11
|
+
end
|
|
12
|
+
attr_reader :condition, :task
|
|
13
|
+
|
|
14
|
+
def <<(message)
|
|
15
|
+
@mailbox << message
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def wait
|
|
19
|
+
message = @mailbox.receive do |msg|
|
|
20
|
+
msg.is_a?(SignalConditionRequest) && msg.task == Thread.current
|
|
21
|
+
end
|
|
22
|
+
message.value
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
6
26
|
attr_reader :owner
|
|
7
27
|
|
|
8
28
|
def initialize
|
|
9
29
|
@mutex = Mutex.new
|
|
10
|
-
@owner = Thread.current[:celluloid_actor]
|
|
11
30
|
@tasks = []
|
|
12
31
|
end
|
|
13
32
|
|
|
@@ -15,14 +34,18 @@ module Celluloid
|
|
|
15
34
|
def wait
|
|
16
35
|
raise ConditionError, "cannot wait for signals while exclusive" if Celluloid.exclusive?
|
|
17
36
|
|
|
37
|
+
if Thread.current[:celluloid_actor]
|
|
38
|
+
task = Task.current
|
|
39
|
+
else
|
|
40
|
+
task = Thread.current
|
|
41
|
+
end
|
|
42
|
+
waiter = Waiter.new(self, task, Celluloid.mailbox)
|
|
43
|
+
|
|
18
44
|
@mutex.synchronize do
|
|
19
|
-
|
|
20
|
-
raise ConditionError, "can't wait for conditions outside actors" unless actor
|
|
21
|
-
raise ConditionError, "can't wait unless owner" unless actor == @owner
|
|
22
|
-
@tasks << Task.current
|
|
45
|
+
@tasks << waiter
|
|
23
46
|
end
|
|
24
47
|
|
|
25
|
-
result =
|
|
48
|
+
result = Celluloid.suspend :condwait, waiter
|
|
26
49
|
raise result if result.is_a? ConditionError
|
|
27
50
|
result
|
|
28
51
|
end
|
|
@@ -30,10 +53,8 @@ module Celluloid
|
|
|
30
53
|
# Send a signal to the first task waiting on this condition
|
|
31
54
|
def signal(value = nil)
|
|
32
55
|
@mutex.synchronize do
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if task = @tasks.shift
|
|
36
|
-
@owner.mailbox << SignalConditionRequest.new(task, value)
|
|
56
|
+
if waiter = @tasks.shift
|
|
57
|
+
waiter << SignalConditionRequest.new(waiter.task, value)
|
|
37
58
|
else
|
|
38
59
|
Logger.debug("Celluloid::Condition signaled spuriously")
|
|
39
60
|
end
|
|
@@ -43,28 +64,11 @@ module Celluloid
|
|
|
43
64
|
# Broadcast a value to all waiting tasks
|
|
44
65
|
def broadcast(value = nil)
|
|
45
66
|
@mutex.synchronize do
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
@tasks.each { |task| @owner.mailbox << SignalConditionRequest.new(task, value) }
|
|
67
|
+
@tasks.each { |waiter| waiter << SignalConditionRequest.new(waiter.task, value) }
|
|
49
68
|
@tasks.clear
|
|
50
69
|
end
|
|
51
70
|
end
|
|
52
71
|
|
|
53
|
-
# Change the owner of this condition
|
|
54
|
-
def owner=(actor)
|
|
55
|
-
@mutex.synchronize do
|
|
56
|
-
if @owner != actor
|
|
57
|
-
@tasks.each do |task|
|
|
58
|
-
ex = ConditionError.new("ownership changed")
|
|
59
|
-
@owner.mailbox << SignalConditionRequest.new(task, ex)
|
|
60
|
-
end
|
|
61
|
-
@tasks.clear
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
@owner = actor
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
|
|
68
72
|
alias_method :inspect, :to_s
|
|
69
73
|
end
|
|
70
74
|
end
|
data/lib/celluloid/core_ext.rb
CHANGED
|
@@ -1,20 +1,9 @@
|
|
|
1
1
|
require 'celluloid/fiber'
|
|
2
2
|
|
|
3
|
-
# Monkeypatch Thread to allow lazy access to its Celluloid::Mailbox
|
|
4
3
|
class Thread
|
|
5
4
|
attr_accessor :uuid_counter, :uuid_limit
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
current[:celluloid_mailbox] ||= Celluloid::Mailbox.new
|
|
6
|
+
def celluloid?
|
|
7
|
+
false
|
|
10
8
|
end
|
|
11
|
-
|
|
12
|
-
# Receive a message either as an actor or through the local mailbox
|
|
13
|
-
def self.receive(timeout = nil, &block)
|
|
14
|
-
if Celluloid.actor?
|
|
15
|
-
Celluloid.receive(timeout, &block)
|
|
16
|
-
else
|
|
17
|
-
mailbox.receive(timeout, &block)
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
9
|
+
end
|
|
@@ -12,7 +12,7 @@ module Celluloid
|
|
|
12
12
|
Dir["/sys/devices/system/cpu/cpu*"].select { |n| n=~/cpu\d+/ }.count
|
|
13
13
|
end
|
|
14
14
|
when 'mingw', 'mswin'
|
|
15
|
-
@cores = Integer(
|
|
15
|
+
@cores = Integer(ENV["NUMBER_OF_PROCESSORS"][/\d+/])
|
|
16
16
|
else
|
|
17
17
|
@cores = nil
|
|
18
18
|
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
module Celluloid
|
|
2
|
+
# An alternative implementation of Celluloid::Mailbox using Reactor
|
|
3
|
+
class EventedMailbox < Celluloid::Mailbox
|
|
4
|
+
attr_reader :reactor
|
|
5
|
+
|
|
6
|
+
def initialize(reactor_class)
|
|
7
|
+
super()
|
|
8
|
+
# @condition won't be used in the class.
|
|
9
|
+
@reactor = reactor_class.new
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Add a message to the Mailbox
|
|
13
|
+
def <<(message)
|
|
14
|
+
@mutex.lock
|
|
15
|
+
begin
|
|
16
|
+
if mailbox_full
|
|
17
|
+
Logger.debug "Discarded message: #{message}"
|
|
18
|
+
return
|
|
19
|
+
end
|
|
20
|
+
if message.is_a?(SystemEvent)
|
|
21
|
+
# Silently swallow system events sent to dead actors
|
|
22
|
+
return if @dead
|
|
23
|
+
|
|
24
|
+
# SystemEvents are high priority messages so they get added to the
|
|
25
|
+
# head of our message queue instead of the end
|
|
26
|
+
@messages.unshift message
|
|
27
|
+
else
|
|
28
|
+
raise MailboxError, "dead recipient" if @dead
|
|
29
|
+
@messages << message
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
current_actor = Thread.current[:celluloid_actor]
|
|
33
|
+
@reactor.wakeup unless current_actor && current_actor.mailbox == self
|
|
34
|
+
rescue IOError
|
|
35
|
+
raise MailboxError, "dead recipient"
|
|
36
|
+
ensure
|
|
37
|
+
@mutex.unlock rescue nil
|
|
38
|
+
end
|
|
39
|
+
nil
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Receive a message from the Mailbox
|
|
43
|
+
def receive(timeout = nil, &block)
|
|
44
|
+
message = next_message(block)
|
|
45
|
+
|
|
46
|
+
until message
|
|
47
|
+
if timeout
|
|
48
|
+
now = Time.now
|
|
49
|
+
wait_until ||= now + timeout
|
|
50
|
+
wait_interval = wait_until - now
|
|
51
|
+
return if wait_interval < 0
|
|
52
|
+
else
|
|
53
|
+
wait_interval = nil
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
@reactor.run_once(wait_interval)
|
|
57
|
+
message = next_message(block)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
message
|
|
61
|
+
rescue IOError
|
|
62
|
+
shutdown # force shutdown of the mailbox
|
|
63
|
+
raise MailboxShutdown, "mailbox shutdown called during receive"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Obtain the next message from the mailbox that matches the given block
|
|
67
|
+
def next_message(block)
|
|
68
|
+
@mutex.lock
|
|
69
|
+
begin
|
|
70
|
+
super(&block)
|
|
71
|
+
ensure
|
|
72
|
+
@mutex.unlock rescue nil
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Cleanup any IO objects this Mailbox may be using
|
|
77
|
+
def shutdown
|
|
78
|
+
@reactor.shutdown
|
|
79
|
+
super
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
data/lib/celluloid/fsm.rb
CHANGED
|
@@ -62,6 +62,7 @@ module Celluloid
|
|
|
62
62
|
# Be kind and call super if you must redefine initialize
|
|
63
63
|
def initialize(actor = nil)
|
|
64
64
|
@state = self.class.default_state
|
|
65
|
+
@delayed_transition = nil
|
|
65
66
|
@actor = actor
|
|
66
67
|
@actor ||= Celluloid.current_actor if Celluloid.actor?
|
|
67
68
|
end
|
|
@@ -166,6 +167,7 @@ module Celluloid
|
|
|
166
167
|
|
|
167
168
|
def initialize(name, transitions = nil, &block)
|
|
168
169
|
@name, @block = name, block
|
|
170
|
+
@transitions = nil
|
|
169
171
|
@transitions = Array(transitions).map { |t| t.to_sym } if transitions
|
|
170
172
|
end
|
|
171
173
|
|
data/lib/celluloid/future.rb
CHANGED
|
@@ -4,38 +4,30 @@ module Celluloid
|
|
|
4
4
|
# Celluloid::Future objects allow methods and blocks to run in the
|
|
5
5
|
# background, their values requested later
|
|
6
6
|
class Future
|
|
7
|
+
def self.new(*args, &block)
|
|
8
|
+
return super unless block
|
|
9
|
+
|
|
10
|
+
future = new
|
|
11
|
+
Celluloid.internal_pool.get do
|
|
12
|
+
Thread.current.role = :future
|
|
13
|
+
begin
|
|
14
|
+
call = SyncCall.new(future, :call, args)
|
|
15
|
+
call.dispatch(block)
|
|
16
|
+
rescue
|
|
17
|
+
# Exceptions in blocks will get raised when the value is retrieved
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
future
|
|
21
|
+
end
|
|
22
|
+
|
|
7
23
|
attr_reader :address
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def initialize(*args, &block)
|
|
24
|
+
|
|
25
|
+
def initialize
|
|
11
26
|
@address = Celluloid.uuid
|
|
12
27
|
@mutex = Mutex.new
|
|
13
28
|
@ready = false
|
|
14
29
|
@result = nil
|
|
15
30
|
@forwards = nil
|
|
16
|
-
|
|
17
|
-
if block
|
|
18
|
-
@call = SyncCall.new(self, :call, args)
|
|
19
|
-
Celluloid.internal_pool.get do
|
|
20
|
-
begin
|
|
21
|
-
@call.dispatch(block)
|
|
22
|
-
rescue
|
|
23
|
-
# Exceptions in blocks will get raised when the value is retrieved
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
else
|
|
27
|
-
@call = nil
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# Execute the given method in future context
|
|
32
|
-
def execute(receiver, method, args, block)
|
|
33
|
-
@mutex.synchronize do
|
|
34
|
-
raise "already calling" if @call
|
|
35
|
-
@call = SyncCall.new(self, method, args, block)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
receiver << @call
|
|
39
31
|
end
|
|
40
32
|
|
|
41
33
|
# Check if this future has a value yet
|
|
@@ -49,7 +41,6 @@ module Celluloid
|
|
|
49
41
|
|
|
50
42
|
begin
|
|
51
43
|
@mutex.lock
|
|
52
|
-
raise "no call requested" unless @call
|
|
53
44
|
|
|
54
45
|
if @ready
|
|
55
46
|
ready = true
|
|
@@ -57,11 +48,11 @@ module Celluloid
|
|
|
57
48
|
else
|
|
58
49
|
case @forwards
|
|
59
50
|
when Array
|
|
60
|
-
@forwards <<
|
|
51
|
+
@forwards << Celluloid.mailbox
|
|
61
52
|
when NilClass
|
|
62
|
-
@forwards =
|
|
53
|
+
@forwards = Celluloid.mailbox
|
|
63
54
|
else
|
|
64
|
-
@forwards = [@forwards,
|
|
55
|
+
@forwards = [@forwards, Celluloid.mailbox]
|
|
65
56
|
end
|
|
66
57
|
end
|
|
67
58
|
ensure
|
|
@@ -69,7 +60,7 @@ module Celluloid
|
|
|
69
60
|
end
|
|
70
61
|
|
|
71
62
|
unless ready
|
|
72
|
-
result =
|
|
63
|
+
result = Celluloid.receive(timeout) do |msg|
|
|
73
64
|
msg.is_a?(Future::Result) && msg.future == self
|
|
74
65
|
end
|
|
75
66
|
end
|
|
@@ -10,6 +10,10 @@ module Celluloid
|
|
|
10
10
|
@mutex = Mutex.new
|
|
11
11
|
@busy_size = @idle_size = 0
|
|
12
12
|
|
|
13
|
+
reset
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def reset
|
|
13
17
|
# TODO: should really adjust this based on usage
|
|
14
18
|
@max_idle = 16
|
|
15
19
|
end
|
|
@@ -74,6 +78,15 @@ module Celluloid
|
|
|
74
78
|
thread[key] = nil
|
|
75
79
|
end
|
|
76
80
|
end
|
|
81
|
+
|
|
82
|
+
def shutdown
|
|
83
|
+
@mutex.synchronize do
|
|
84
|
+
@max_idle = 0
|
|
85
|
+
@pool.each do |thread|
|
|
86
|
+
thread[:celluloid_queue] << nil
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
77
90
|
end
|
|
78
91
|
|
|
79
92
|
self.internal_pool = InternalPool.new
|