celluloid 0.16.0 → 0.17.3
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 +4 -4
- data/CHANGES.md +394 -0
- data/LICENSE.txt +1 -1
- data/README.md +28 -15
- data/culture/CONDUCT.md +28 -0
- data/culture/Gemfile +9 -0
- data/culture/LICENSE.txt +22 -0
- data/culture/README.md +22 -0
- data/culture/Rakefile +5 -0
- data/culture/SYNC.md +70 -0
- data/culture/celluloid-culture.gemspec +18 -0
- data/culture/gems/README.md +39 -0
- data/culture/gems/dependencies.yml +85 -0
- data/culture/gems/loader.rb +101 -0
- data/culture/rubocop/README.md +38 -0
- data/culture/rubocop/lint.yml +8 -0
- data/culture/rubocop/metrics.yml +15 -0
- data/culture/rubocop/perf.yml +0 -0
- data/culture/rubocop/rubocop.yml +5 -0
- data/culture/rubocop/style.yml +57 -0
- data/culture/spec/gems_spec.rb +2 -0
- data/culture/spec/spec_helper.rb +0 -0
- data/culture/spec/sync_spec.rb +2 -0
- data/culture/sync.rb +56 -0
- data/culture/tasks/rspec.rake +5 -0
- data/culture/tasks/rubocop.rake +2 -0
- data/examples/basic_usage.rb +49 -0
- data/examples/futures.rb +38 -0
- data/examples/ring.rb +61 -0
- data/examples/simple_pmap.rb +14 -0
- data/examples/stack.rb +47 -0
- data/examples/timers.rb +72 -0
- data/lib/celluloid/actor/manager.rb +7 -0
- data/lib/celluloid/actor/system.rb +163 -0
- data/lib/celluloid/actor.rb +53 -71
- data/lib/celluloid/autostart.rb +1 -1
- data/lib/celluloid/backported.rb +2 -0
- data/lib/celluloid/call/async.rb +16 -0
- data/lib/celluloid/call/block.rb +22 -0
- data/lib/celluloid/call/sync.rb +70 -0
- data/lib/celluloid/calls.rb +24 -114
- data/lib/celluloid/cell.rb +32 -20
- data/lib/celluloid/condition.rb +5 -6
- data/lib/celluloid/core_ext.rb +1 -1
- data/lib/celluloid/current.rb +2 -0
- data/lib/celluloid/debug.rb +1 -0
- data/lib/celluloid/deprecate.rb +21 -0
- data/lib/celluloid/exceptions.rb +22 -16
- data/lib/celluloid/fiber.rb +3 -3
- data/lib/celluloid/future.rb +46 -8
- data/lib/celluloid/group/pool.rb +125 -0
- data/lib/celluloid/group/spawner.rb +68 -0
- data/lib/celluloid/group.rb +61 -0
- data/lib/celluloid/logging.rb +5 -5
- data/lib/celluloid/mailbox/evented.rb +74 -0
- data/lib/celluloid/mailbox.rb +15 -14
- data/lib/celluloid/managed.rb +3 -0
- data/lib/celluloid/notices.rb +15 -0
- data/lib/celluloid/proxies.rb +11 -0
- data/lib/celluloid/proxy/abstract.rb +50 -0
- data/lib/celluloid/proxy/actor.rb +37 -0
- data/lib/celluloid/proxy/async.rb +15 -0
- data/lib/celluloid/proxy/block.rb +28 -0
- data/lib/celluloid/proxy/cell.rb +66 -0
- data/lib/celluloid/proxy/future.rb +20 -0
- data/lib/celluloid/proxy/sync.rb +24 -0
- data/lib/celluloid/rspec.rb +67 -9
- data/lib/celluloid/system_events.rb +69 -14
- data/lib/celluloid/task/fibered.rb +45 -0
- data/lib/celluloid/task/threaded.rb +59 -0
- data/lib/celluloid/{tasks.rb → task.rb} +30 -38
- data/lib/celluloid/test.rb +1 -1
- data/lib/celluloid/thread.rb +6 -1
- data/lib/celluloid/version.rb +3 -0
- data/lib/celluloid.rb +151 -130
- data/spec/celluloid/actor/system_spec.rb +83 -0
- data/spec/celluloid/actor_spec.rb +2 -2
- data/spec/celluloid/block_spec.rb +67 -8
- data/spec/celluloid/calls_spec.rb +28 -23
- data/spec/celluloid/condition_spec.rb +23 -14
- data/spec/celluloid/evented_mailbox_spec.rb +1 -31
- data/spec/celluloid/future_spec.rb +15 -12
- data/spec/celluloid/group/elastic_spec.rb +0 -0
- data/spec/celluloid/group/pool_spec.rb +8 -0
- data/spec/celluloid/group/spawner_spec.rb +17 -0
- data/spec/celluloid/mailbox/evented_spec.rb +40 -0
- data/spec/celluloid/mailbox_spec.rb +1 -3
- data/spec/celluloid/misc/leak_spec.rb +73 -0
- data/spec/celluloid/proxy_spec.rb +33 -0
- data/spec/celluloid/task/fibered_spec.rb +5 -0
- data/spec/celluloid/task/threaded_spec.rb +5 -0
- data/spec/celluloid/timer_spec.rb +14 -16
- data/spec/deprecate/actor_system_spec.rb +72 -0
- data/spec/deprecate/block_spec.rb +52 -0
- data/spec/deprecate/calls_spec.rb +39 -0
- data/spec/deprecate/evented_mailbox_spec.rb +34 -0
- data/spec/deprecate/future_spec.rb +32 -0
- data/spec/deprecate/internal_pool_spec.rb +4 -0
- data/spec/shared/actor_examples.rb +1259 -0
- data/spec/shared/group_examples.rb +121 -0
- data/spec/shared/mailbox_examples.rb +87 -0
- data/{lib/celluloid/rspec → spec/shared}/task_examples.rb +9 -8
- data/spec/spec_helper.rb +5 -42
- data/spec/support/configure_rspec.rb +77 -0
- data/spec/support/coverage.rb +4 -0
- data/spec/support/crash_checking.rb +68 -0
- data/spec/support/debugging.rb +31 -0
- data/spec/support/env.rb +21 -0
- data/{lib/celluloid/rspec/example_actor_class.rb → spec/support/examples/actor_class.rb} +21 -2
- data/spec/support/examples/call_class.rb +37 -0
- data/spec/support/examples/evented_mailbox_class.rb +27 -0
- data/spec/support/includer.rb +6 -0
- data/spec/support/logging.rb +55 -0
- data/spec/support/loose_threads.rb +68 -0
- data/spec/support/reset_class_variables.rb +27 -0
- data/spec/support/sleep_and_wait.rb +14 -0
- data/spec/support/stubbing.rb +14 -0
- metadata +276 -78
- data/lib/celluloid/actor_system.rb +0 -107
- data/lib/celluloid/call_chain.rb +0 -13
- data/lib/celluloid/cpu_counter.rb +0 -34
- data/lib/celluloid/evented_mailbox.rb +0 -73
- data/lib/celluloid/fsm.rb +0 -186
- data/lib/celluloid/handlers.rb +0 -41
- data/lib/celluloid/internal_pool.rb +0 -159
- data/lib/celluloid/legacy.rb +0 -9
- data/lib/celluloid/links.rb +0 -36
- data/lib/celluloid/logger.rb +0 -93
- data/lib/celluloid/logging/incident.rb +0 -21
- data/lib/celluloid/logging/incident_logger.rb +0 -129
- data/lib/celluloid/logging/incident_reporter.rb +0 -48
- data/lib/celluloid/logging/log_event.rb +0 -20
- data/lib/celluloid/logging/ring_buffer.rb +0 -65
- data/lib/celluloid/method.rb +0 -32
- data/lib/celluloid/notifications.rb +0 -83
- data/lib/celluloid/pool_manager.rb +0 -146
- data/lib/celluloid/probe.rb +0 -73
- data/lib/celluloid/properties.rb +0 -24
- data/lib/celluloid/proxies/abstract_proxy.rb +0 -20
- data/lib/celluloid/proxies/actor_proxy.rb +0 -38
- data/lib/celluloid/proxies/async_proxy.rb +0 -31
- data/lib/celluloid/proxies/block_proxy.rb +0 -29
- data/lib/celluloid/proxies/cell_proxy.rb +0 -68
- data/lib/celluloid/proxies/future_proxy.rb +0 -35
- data/lib/celluloid/proxies/sync_proxy.rb +0 -36
- data/lib/celluloid/receivers.rb +0 -63
- data/lib/celluloid/registry.rb +0 -57
- data/lib/celluloid/responses.rb +0 -44
- data/lib/celluloid/rspec/actor_examples.rb +0 -1054
- data/lib/celluloid/rspec/mailbox_examples.rb +0 -84
- data/lib/celluloid/signals.rb +0 -23
- data/lib/celluloid/stack_dump.rb +0 -133
- data/lib/celluloid/supervision_group.rb +0 -169
- data/lib/celluloid/supervisor.rb +0 -22
- data/lib/celluloid/task_set.rb +0 -49
- data/lib/celluloid/tasks/task_fiber.rb +0 -43
- data/lib/celluloid/tasks/task_thread.rb +0 -53
- data/lib/celluloid/thread_handle.rb +0 -50
- data/lib/celluloid/uuid.rb +0 -38
- data/spec/celluloid/actor_system_spec.rb +0 -69
- data/spec/celluloid/cpu_counter_spec.rb +0 -82
- data/spec/celluloid/fsm_spec.rb +0 -107
- data/spec/celluloid/internal_pool_spec.rb +0 -52
- data/spec/celluloid/links_spec.rb +0 -45
- data/spec/celluloid/logging/ring_buffer_spec.rb +0 -38
- data/spec/celluloid/notifications_spec.rb +0 -120
- data/spec/celluloid/pool_spec.rb +0 -92
- data/spec/celluloid/probe_spec.rb +0 -121
- data/spec/celluloid/properties_spec.rb +0 -42
- data/spec/celluloid/registry_spec.rb +0 -64
- data/spec/celluloid/stack_dump_spec.rb +0 -64
- data/spec/celluloid/supervision_group_spec.rb +0 -65
- data/spec/celluloid/supervisor_spec.rb +0 -103
- data/spec/celluloid/tasks/task_fiber_spec.rb +0 -5
- data/spec/celluloid/tasks/task_thread_spec.rb +0 -5
- data/spec/celluloid/thread_handle_spec.rb +0 -26
- data/spec/celluloid/uuid_spec.rb +0 -11
data/lib/celluloid/calls.rb
CHANGED
|
@@ -4,13 +4,15 @@ module Celluloid
|
|
|
4
4
|
attr_reader :method, :arguments, :block
|
|
5
5
|
|
|
6
6
|
def initialize(method, arguments = [], block = nil)
|
|
7
|
-
@
|
|
7
|
+
@retry = 0
|
|
8
|
+
@method = method
|
|
9
|
+
@arguments = arguments
|
|
8
10
|
if block
|
|
9
11
|
if Celluloid.exclusive?
|
|
10
12
|
# FIXME: nicer exception
|
|
11
|
-
|
|
13
|
+
fail "Cannot execute blocks on sender in exclusive mode"
|
|
12
14
|
end
|
|
13
|
-
@block =
|
|
15
|
+
@block = Proxy::Block.new(Celluloid.mailbox, self, block)
|
|
14
16
|
else
|
|
15
17
|
@block = nil
|
|
16
18
|
end
|
|
@@ -22,130 +24,38 @@ module Celluloid
|
|
|
22
24
|
|
|
23
25
|
def dispatch(obj)
|
|
24
26
|
check(obj)
|
|
25
|
-
|
|
26
|
-
obj.public_send(@method, *@arguments, &
|
|
27
|
+
_b = @block && @block.to_proc
|
|
28
|
+
obj.public_send(@method, *@arguments, &_b)
|
|
29
|
+
# rescue Celluloid::TaskTimeout => ex
|
|
30
|
+
# raise ex unless ( @retry += 1 ) <= RETRY_CALL_LIMIT
|
|
31
|
+
# puts "retrying"
|
|
32
|
+
# Internals::Logger.warn("TaskTimeout at Call dispatch. Retrying in #{RETRY_CALL_WAIT} seconds. ( Attempt #{@retry} of #{RETRY_CALL_LIMIT} )")
|
|
33
|
+
# sleep RETRY_CALL_WAIT
|
|
34
|
+
# retry
|
|
27
35
|
end
|
|
28
36
|
|
|
29
37
|
def check(obj)
|
|
30
|
-
|
|
31
|
-
|
|
38
|
+
# NOTE: don't use respond_to? here
|
|
32
39
|
begin
|
|
33
|
-
|
|
40
|
+
meth = obj.method(@method)
|
|
34
41
|
rescue NameError
|
|
35
|
-
|
|
42
|
+
raise NoMethodError, "undefined method `#{@method}' for #<#{obj.class}:0x#{obj.object_id.to_s(16)}>"
|
|
36
43
|
end
|
|
37
44
|
|
|
45
|
+
arity = meth.arity
|
|
46
|
+
|
|
38
47
|
if arity >= 0
|
|
39
|
-
|
|
48
|
+
fail ArgumentError, "wrong number of arguments (#{@arguments.size} for #{arity})" if @arguments.size != arity
|
|
40
49
|
elsif arity < -1
|
|
41
50
|
mandatory_args = -arity - 1
|
|
42
|
-
|
|
51
|
+
fail ArgumentError, "wrong number of arguments (#{@arguments.size} for #{mandatory_args}+)" if arguments.size < mandatory_args
|
|
43
52
|
end
|
|
44
53
|
rescue => ex
|
|
45
54
|
raise AbortError.new(ex)
|
|
46
55
|
end
|
|
47
56
|
end
|
|
48
|
-
|
|
49
|
-
# Synchronous calls wait for a response
|
|
50
|
-
class SyncCall < Call
|
|
51
|
-
attr_reader :sender, :task, :chain_id
|
|
52
|
-
|
|
53
|
-
def initialize(sender, method, arguments = [], block = nil, task = Thread.current[:celluloid_task], chain_id = CallChain.current_id)
|
|
54
|
-
super(method, arguments, block)
|
|
55
|
-
|
|
56
|
-
@sender = sender
|
|
57
|
-
@task = task
|
|
58
|
-
@chain_id = chain_id || Celluloid.uuid
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def dispatch(obj)
|
|
62
|
-
CallChain.current_id = @chain_id
|
|
63
|
-
result = super(obj)
|
|
64
|
-
respond SuccessResponse.new(self, result)
|
|
65
|
-
rescue Exception => ex
|
|
66
|
-
# Exceptions that occur during synchronous calls are reraised in the
|
|
67
|
-
# context of the sender
|
|
68
|
-
respond ErrorResponse.new(self, ex)
|
|
69
|
-
|
|
70
|
-
# Aborting indicates a protocol error on the part of the sender
|
|
71
|
-
# It should crash the sender, but the exception isn't reraised
|
|
72
|
-
# Otherwise, it's a bug in this actor and should be reraised
|
|
73
|
-
raise unless ex.is_a?(AbortError)
|
|
74
|
-
ensure
|
|
75
|
-
CallChain.current_id = nil
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def cleanup
|
|
79
|
-
exception = DeadActorError.new("attempted to call a dead actor")
|
|
80
|
-
respond ErrorResponse.new(self, exception)
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def respond(message)
|
|
84
|
-
@sender << message
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def response
|
|
88
|
-
Celluloid.suspend(:callwait, self)
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
def value
|
|
92
|
-
response.value
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
def wait
|
|
96
|
-
loop do
|
|
97
|
-
message = Celluloid.mailbox.receive do |msg|
|
|
98
|
-
msg.respond_to?(:call) and msg.call == self
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
if message.is_a?(SystemEvent)
|
|
102
|
-
Thread.current[:celluloid_actor].handle_system_event(message)
|
|
103
|
-
else
|
|
104
|
-
# FIXME: add check for receiver block execution
|
|
105
|
-
if message.respond_to?(:value)
|
|
106
|
-
# FIXME: disable block execution if on :sender and (exclusive or outside of task)
|
|
107
|
-
# probably now in Call
|
|
108
|
-
break message
|
|
109
|
-
else
|
|
110
|
-
message.dispatch
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
# Asynchronous calls don't wait for a response
|
|
118
|
-
class AsyncCall < Call
|
|
119
|
-
|
|
120
|
-
def dispatch(obj)
|
|
121
|
-
CallChain.current_id = Celluloid.uuid
|
|
122
|
-
super(obj)
|
|
123
|
-
rescue AbortError => ex
|
|
124
|
-
# Swallow aborted async calls, as they indicate the sender made a mistake
|
|
125
|
-
Logger.debug("#{obj.class}: async call `#@method` aborted!\n#{Logger.format_exception(ex.cause)}")
|
|
126
|
-
ensure
|
|
127
|
-
CallChain.current_id = nil
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
class BlockCall
|
|
133
|
-
def initialize(block_proxy, sender, arguments, task = Thread.current[:celluloid_task])
|
|
134
|
-
@block_proxy = block_proxy
|
|
135
|
-
@sender = sender
|
|
136
|
-
@arguments = arguments
|
|
137
|
-
@task = task
|
|
138
|
-
end
|
|
139
|
-
attr_reader :task
|
|
140
|
-
|
|
141
|
-
def call
|
|
142
|
-
@block_proxy.call
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
def dispatch
|
|
146
|
-
response = @block_proxy.block.call(*@arguments)
|
|
147
|
-
@sender << BlockResponse.new(self, response)
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
|
|
151
57
|
end
|
|
58
|
+
|
|
59
|
+
require "celluloid/call/sync"
|
|
60
|
+
require "celluloid/call/async"
|
|
61
|
+
require "celluloid/call/block"
|
data/lib/celluloid/cell.rb
CHANGED
|
@@ -33,57 +33,69 @@ module Celluloid
|
|
|
33
33
|
@actor.handle(Call) do |message|
|
|
34
34
|
invoke(message)
|
|
35
35
|
end
|
|
36
|
-
@actor.handle(
|
|
36
|
+
@actor.handle(Call::Block) do |message|
|
|
37
37
|
task(:invoke_block) { message.dispatch }
|
|
38
38
|
end
|
|
39
|
-
@actor.handle(
|
|
39
|
+
@actor.handle(Internals::Response::Block, Internals::Response) do |message|
|
|
40
40
|
message.dispatch
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
@actor.start
|
|
44
|
-
@proxy = (options[:proxy_class] ||
|
|
44
|
+
@proxy = (options[:proxy_class] || Proxy::Cell).new(@actor.mailbox, @actor.proxy, @subject.class.to_s)
|
|
45
45
|
end
|
|
46
46
|
attr_reader :proxy, :subject
|
|
47
47
|
|
|
48
|
+
def self.dispatch
|
|
49
|
+
proc do |subject|
|
|
50
|
+
subject[:call].dispatch(subject[:subject])
|
|
51
|
+
subject[:call] = nil
|
|
52
|
+
subject[:subject] = nil
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
48
56
|
def invoke(call)
|
|
49
57
|
meth = call.method
|
|
50
|
-
if meth == :__send__
|
|
51
|
-
meth = call.arguments.first
|
|
52
|
-
end
|
|
58
|
+
meth = call.arguments.first if meth == :__send__
|
|
53
59
|
if @receiver_block_executions && meth
|
|
54
60
|
if @receiver_block_executions.include?(meth.to_sym)
|
|
55
61
|
call.execute_block_on_receiver
|
|
56
62
|
end
|
|
57
63
|
end
|
|
58
64
|
|
|
59
|
-
task(:call, meth, :
|
|
60
|
-
|
|
61
|
-
}
|
|
65
|
+
task(:call, meth, {call: call, subject: @subject},
|
|
66
|
+
dangerous_suspend: meth == :initialize, &Cell.dispatch)
|
|
62
67
|
end
|
|
63
68
|
|
|
64
|
-
def task(task_type, method_name = nil, meta = nil, &
|
|
69
|
+
def task(task_type, method_name = nil, subject = nil, meta = nil, &_block)
|
|
65
70
|
meta ||= {}
|
|
66
|
-
meta.merge!(:
|
|
71
|
+
meta.merge!(method_name: method_name)
|
|
67
72
|
@actor.task(task_type, meta) do
|
|
68
73
|
if @exclusive_methods && method_name && @exclusive_methods.include?(method_name.to_sym)
|
|
69
|
-
Celluloid.exclusive { yield }
|
|
74
|
+
Celluloid.exclusive { yield subject }
|
|
70
75
|
else
|
|
71
|
-
yield
|
|
76
|
+
yield subject
|
|
72
77
|
end
|
|
73
78
|
end
|
|
74
79
|
end
|
|
75
80
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
return unless @finalizer && @subject.respond_to?(@finalizer, true)
|
|
79
|
-
|
|
80
|
-
task(:finalizer, @finalizer, :dangerous_suspend => true) do
|
|
81
|
+
def self.shutdown
|
|
82
|
+
proc do |subject|
|
|
81
83
|
begin
|
|
82
|
-
|
|
84
|
+
subject[:subject].__send__(subject[:call])
|
|
83
85
|
rescue => ex
|
|
84
|
-
Logger.crash("#{
|
|
86
|
+
Internals::Logger.crash("#{subject[:subject].class} finalizer crashed!", ex)
|
|
85
87
|
end
|
|
88
|
+
subject[:call] = nil
|
|
89
|
+
subject[:subject] = nil
|
|
86
90
|
end
|
|
87
91
|
end
|
|
92
|
+
|
|
93
|
+
# Run the user-defined finalizer, if one is set
|
|
94
|
+
def shutdown
|
|
95
|
+
return unless @finalizer && @subject.respond_to?(@finalizer, true)
|
|
96
|
+
|
|
97
|
+
task(:finalizer, @finalizer, {call: @finalizer, subject: @subject},
|
|
98
|
+
dangerous_suspend: true, &Cell.shutdown)
|
|
99
|
+
end
|
|
88
100
|
end
|
|
89
101
|
end
|
data/lib/celluloid/condition.rb
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
module Celluloid
|
|
2
|
-
class ConditionError < Celluloid::Error; end
|
|
3
|
-
|
|
4
2
|
# ConditionVariable-like signaling between tasks and threads
|
|
5
3
|
class Condition
|
|
6
4
|
class Waiter
|
|
@@ -21,7 +19,7 @@ module Celluloid
|
|
|
21
19
|
message = @mailbox.receive(@timeout) do |msg|
|
|
22
20
|
msg.is_a?(SignalConditionRequest) && msg.task == Thread.current
|
|
23
21
|
end
|
|
24
|
-
rescue
|
|
22
|
+
rescue TimedOut
|
|
25
23
|
raise ConditionError, "timeout after #{@timeout.inspect} seconds"
|
|
26
24
|
end until message
|
|
27
25
|
|
|
@@ -36,7 +34,7 @@ module Celluloid
|
|
|
36
34
|
|
|
37
35
|
# Wait for the given signal and return the associated value
|
|
38
36
|
def wait(timeout = nil)
|
|
39
|
-
|
|
37
|
+
fail ConditionError, "cannot wait for signals while exclusive" if Celluloid.exclusive?
|
|
40
38
|
|
|
41
39
|
if actor = Thread.current[:celluloid_actor]
|
|
42
40
|
task = Task.current
|
|
@@ -59,7 +57,8 @@ module Celluloid
|
|
|
59
57
|
|
|
60
58
|
result = Celluloid.suspend :condwait, waiter
|
|
61
59
|
timer.cancel if timer
|
|
62
|
-
|
|
60
|
+
fail result if result.is_a?(ConditionError)
|
|
61
|
+
return yield(result) if block_given?
|
|
63
62
|
result
|
|
64
63
|
end
|
|
65
64
|
|
|
@@ -69,7 +68,7 @@ module Celluloid
|
|
|
69
68
|
if waiter = @waiters.shift
|
|
70
69
|
waiter << SignalConditionRequest.new(waiter.task, value)
|
|
71
70
|
else
|
|
72
|
-
Logger.with_backtrace(caller(3)) do |logger|
|
|
71
|
+
Internals::Logger.with_backtrace(caller(3)) do |logger|
|
|
73
72
|
logger.debug("Celluloid::Condition signaled spuriously")
|
|
74
73
|
end
|
|
75
74
|
end
|
data/lib/celluloid/core_ext.rb
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
$CELLULOID_DEBUG = true
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
class Thread
|
|
2
|
+
def self.mailbox
|
|
3
|
+
Celluloid.mailbox
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def self.receive(timeout = nil, &block)
|
|
7
|
+
Celluloid.receive(timeout, &block)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# TODO: Remove link to Interal::Logger
|
|
12
|
+
module Celluloid
|
|
13
|
+
SyncCall = Call::Sync
|
|
14
|
+
EventedMailbox = Mailbox::Evented
|
|
15
|
+
InternalPool = Group::Pool
|
|
16
|
+
TaskThread = Task::Threaded
|
|
17
|
+
TaskFiber = Task::Fibered
|
|
18
|
+
ActorSystem = Actor::System
|
|
19
|
+
Task::TerminatedError = TaskTerminated
|
|
20
|
+
Task::TimeoutError = TaskTimeout
|
|
21
|
+
end
|
data/lib/celluloid/exceptions.rb
CHANGED
|
@@ -1,23 +1,29 @@
|
|
|
1
1
|
module Celluloid
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
# Trying to do something to a dead actor
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
# The sender made an error, not the current actor
|
|
15
|
-
class AbortError < Celluloid::Error
|
|
2
|
+
class Error < StandardError; end
|
|
3
|
+
class Interruption < Exception; end
|
|
4
|
+
class TimedOut < Celluloid::Interruption; end # Distinguished from `Timeout`
|
|
5
|
+
class StillActive < Celluloid::Error; end
|
|
6
|
+
class NotActive < Celluloid::Error; end
|
|
7
|
+
class NotActorError < Celluloid::Error; end # Don't do Actor-like things outside Actor scope
|
|
8
|
+
class DeadActorError < Celluloid::Error; end # Trying to do something to a dead actor
|
|
9
|
+
class NotTaskError < Celluloid::Error; end # Asked to do task-related things outside a task
|
|
10
|
+
class DeadTaskError < Celluloid::Error; end # Trying to resume a dead task
|
|
11
|
+
class TaskTerminated < Celluloid::Interruption; end # Kill a running task after terminate
|
|
12
|
+
class TaskTimeout < Celluloid::TimedOut; end # A timeout occured before the given request could complete
|
|
13
|
+
class ConditionError < Celluloid::Error; end
|
|
14
|
+
class AbortError < Celluloid::Error # The sender made an error, not the current actor
|
|
16
15
|
attr_reader :cause
|
|
17
|
-
|
|
18
16
|
def initialize(cause)
|
|
19
17
|
@cause = cause
|
|
20
|
-
super "caused by #{cause.inspect}: #{cause
|
|
18
|
+
super "caused by #{cause.inspect}: #{cause}"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
class ThreadLeak < Celluloid::Error; end
|
|
22
|
+
module Feature
|
|
23
|
+
module Requires
|
|
24
|
+
class RubiniusOrJRuby < Celluloid::Error; end
|
|
25
|
+
class Rubinius < Celluloid::Error; end
|
|
26
|
+
class JRuby < Celluloid::Error; end
|
|
21
27
|
end
|
|
22
28
|
end
|
|
23
29
|
end
|
data/lib/celluloid/fiber.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Fibers are hard... let's go shopping!
|
|
2
2
|
begin
|
|
3
|
-
require
|
|
3
|
+
require "fiber"
|
|
4
4
|
rescue LoadError => ex
|
|
5
5
|
if defined? JRUBY_VERSION
|
|
6
6
|
if RUBY_VERSION < "1.9.2"
|
|
@@ -9,9 +9,9 @@ rescue LoadError => ex
|
|
|
9
9
|
|
|
10
10
|
# Fibers are broken on JRuby 1.6.5. This works around the issue
|
|
11
11
|
if JRUBY_VERSION[/^1\.6\.5/]
|
|
12
|
-
require
|
|
12
|
+
require "jruby"
|
|
13
13
|
org.jruby.ext.fiber.FiberExtLibrary.new.load(JRuby.runtime, false)
|
|
14
|
-
class org
|
|
14
|
+
class org.jruby.ext.fiber::ThreadFiber
|
|
15
15
|
field_accessor :state
|
|
16
16
|
end
|
|
17
17
|
|
data/lib/celluloid/future.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "thread"
|
|
2
2
|
|
|
3
3
|
module Celluloid
|
|
4
4
|
# Celluloid::Future objects allow methods and blocks to run in the
|
|
@@ -8,9 +8,13 @@ module Celluloid
|
|
|
8
8
|
return super unless block
|
|
9
9
|
|
|
10
10
|
future = new
|
|
11
|
-
|
|
11
|
+
# task = Thread.current[:celluloid_task]
|
|
12
|
+
# actor = Thread.current[:celluloid_actor]
|
|
13
|
+
Internals::ThreadHandle.new(Celluloid.actor_system, :future) do
|
|
12
14
|
begin
|
|
13
|
-
|
|
15
|
+
# Thread.current[:celluloid_task] = task
|
|
16
|
+
# Thread.current[:celluloid_actor] = actor
|
|
17
|
+
call = Call::Sync.new(future, :call, args)
|
|
14
18
|
call.dispatch(block)
|
|
15
19
|
rescue
|
|
16
20
|
# Exceptions in blocks will get raised when the value is retrieved
|
|
@@ -21,12 +25,36 @@ module Celluloid
|
|
|
21
25
|
|
|
22
26
|
attr_reader :address
|
|
23
27
|
|
|
24
|
-
def initialize
|
|
28
|
+
def initialize(&block)
|
|
25
29
|
@address = Celluloid.uuid
|
|
26
30
|
@mutex = Mutex.new
|
|
27
31
|
@ready = false
|
|
28
32
|
@result = nil
|
|
29
33
|
@forwards = nil
|
|
34
|
+
@cancelled = false
|
|
35
|
+
|
|
36
|
+
if block
|
|
37
|
+
@call = Call::Sync.new(self, :call, args)
|
|
38
|
+
Celluloid.internal_pool.get do
|
|
39
|
+
begin
|
|
40
|
+
@call.dispatch(block)
|
|
41
|
+
rescue
|
|
42
|
+
# Exceptions in blocks will get raised when the value is retrieved
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
else
|
|
46
|
+
@call = nil
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Execute the given method in future context
|
|
51
|
+
def execute(receiver, method, args, block)
|
|
52
|
+
@mutex.synchronize do
|
|
53
|
+
fail "already calling" if @call
|
|
54
|
+
@call = Call::Sync.new(self, method, args, block)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
receiver << @call
|
|
30
58
|
end
|
|
31
59
|
|
|
32
60
|
# Check if this future has a value yet
|
|
@@ -65,19 +93,20 @@ module Celluloid
|
|
|
65
93
|
end
|
|
66
94
|
|
|
67
95
|
if result
|
|
68
|
-
result.value
|
|
96
|
+
(result.respond_to?(:value)) ? result.value : result
|
|
69
97
|
else
|
|
70
|
-
|
|
98
|
+
fail TimedOut, "Timed out"
|
|
71
99
|
end
|
|
72
100
|
end
|
|
73
101
|
alias_method :call, :value
|
|
74
102
|
|
|
75
103
|
# Signal this future with the given result value
|
|
76
104
|
def signal(value)
|
|
105
|
+
return if @cancelled
|
|
77
106
|
result = Result.new(value, self)
|
|
78
107
|
|
|
79
108
|
@mutex.synchronize do
|
|
80
|
-
|
|
109
|
+
fail "the future has already happened!" if @ready
|
|
81
110
|
|
|
82
111
|
if @forwards
|
|
83
112
|
@forwards.is_a?(Array) ? @forwards.each { |f| f << result } : @forwards << result
|
|
@@ -89,6 +118,14 @@ module Celluloid
|
|
|
89
118
|
end
|
|
90
119
|
alias_method :<<, :signal
|
|
91
120
|
|
|
121
|
+
def cancel(error)
|
|
122
|
+
response = ErrorResponse.new(@call, error)
|
|
123
|
+
signal response
|
|
124
|
+
@mutex.synchronize do
|
|
125
|
+
@cancelled = true
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
92
129
|
# Inspect this Celluloid::Future
|
|
93
130
|
alias_method :inspect, :to_s
|
|
94
131
|
|
|
@@ -97,7 +134,8 @@ module Celluloid
|
|
|
97
134
|
attr_reader :future
|
|
98
135
|
|
|
99
136
|
def initialize(result, future)
|
|
100
|
-
@result
|
|
137
|
+
@result = result
|
|
138
|
+
@future = future
|
|
101
139
|
end
|
|
102
140
|
|
|
103
141
|
def value
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
require "thread"
|
|
2
|
+
|
|
3
|
+
module Celluloid
|
|
4
|
+
class Group
|
|
5
|
+
class Pool < Group
|
|
6
|
+
# You do not want to use this. Truly, you do not. There is no scenario when you will.
|
|
7
|
+
# But. If you somehow do.. `Celluloid.group_class = Celluloid::Group::Pool` and weep.
|
|
8
|
+
|
|
9
|
+
attr_accessor :max_idle
|
|
10
|
+
|
|
11
|
+
def initialize
|
|
12
|
+
super
|
|
13
|
+
@mutex = Mutex.new
|
|
14
|
+
@idle_threads = []
|
|
15
|
+
@group = []
|
|
16
|
+
@busy_size = 0
|
|
17
|
+
@idle_size = 0
|
|
18
|
+
|
|
19
|
+
# TODO: should really adjust this based on usage
|
|
20
|
+
@max_idle = 16
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def idle?
|
|
24
|
+
busy_size.count == 0
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def busy?
|
|
28
|
+
busy_size.count > 0
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
attr_reader :busy_size
|
|
32
|
+
|
|
33
|
+
attr_reader :idle_size
|
|
34
|
+
|
|
35
|
+
# Get a thread from the pool, running the given block
|
|
36
|
+
def get(&block)
|
|
37
|
+
@mutex.synchronize do
|
|
38
|
+
assert_active
|
|
39
|
+
|
|
40
|
+
begin
|
|
41
|
+
if @idle_threads.empty?
|
|
42
|
+
thread = create
|
|
43
|
+
else
|
|
44
|
+
thread = @idle_threads.pop
|
|
45
|
+
@idle_size = @idle_threads.length
|
|
46
|
+
end
|
|
47
|
+
end until thread.status # handle crashed threads
|
|
48
|
+
|
|
49
|
+
thread.busy = true
|
|
50
|
+
@busy_size += 1
|
|
51
|
+
thread[:celluloid_queue] << block
|
|
52
|
+
thread
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Return a thread to the pool
|
|
57
|
+
def put(thread)
|
|
58
|
+
@mutex.synchronize do
|
|
59
|
+
thread.busy = false
|
|
60
|
+
if idle_size + 1 >= @max_idle
|
|
61
|
+
thread[:celluloid_queue] << nil
|
|
62
|
+
@busy_size -= 1
|
|
63
|
+
@group.delete(thread)
|
|
64
|
+
else
|
|
65
|
+
@idle_threads.push thread
|
|
66
|
+
@busy_size -= 1
|
|
67
|
+
@idle_size = @idle_threads.length
|
|
68
|
+
clean_thread_locals(thread)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def shutdown
|
|
74
|
+
@running = false
|
|
75
|
+
@mutex.synchronize do
|
|
76
|
+
finalize
|
|
77
|
+
@group.each do |thread|
|
|
78
|
+
thread[:celluloid_queue] << nil
|
|
79
|
+
end
|
|
80
|
+
@group.shift.kill until @group.empty?
|
|
81
|
+
@idle_threads.clear
|
|
82
|
+
@busy_size = 0
|
|
83
|
+
@idle_size = 0
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
private
|
|
88
|
+
|
|
89
|
+
# Create a new thread with an associated queue of procs to run
|
|
90
|
+
def create
|
|
91
|
+
queue = Queue.new
|
|
92
|
+
thread = Thread.new do
|
|
93
|
+
while proc = queue.pop
|
|
94
|
+
begin
|
|
95
|
+
proc.call
|
|
96
|
+
rescue ::Exception => ex
|
|
97
|
+
Internals::Logger.crash("thread crashed", ex)
|
|
98
|
+
ensure
|
|
99
|
+
put thread
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
thread[:celluloid_queue] = queue
|
|
105
|
+
# @idle_threads << thread
|
|
106
|
+
@group << thread
|
|
107
|
+
thread
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Clean the thread locals of an incoming thread
|
|
111
|
+
def clean_thread_locals(thread)
|
|
112
|
+
thread.keys.each do |key|
|
|
113
|
+
next if key == :celluloid_queue
|
|
114
|
+
|
|
115
|
+
# Ruby seems to lack an API for deleting thread locals. WTF, Ruby?
|
|
116
|
+
thread[key] = nil
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def finalize
|
|
121
|
+
@max_idle = 0
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|