celluloid 0.15.2 → 0.16.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.
- checksums.yaml +4 -4
- data/LICENSE.txt +20 -0
- data/README.md +25 -2
- data/lib/celluloid/actor.rb +88 -147
- data/lib/celluloid/actor_system.rb +107 -0
- data/lib/celluloid/call_chain.rb +1 -1
- data/lib/celluloid/calls.rb +16 -16
- data/lib/celluloid/cell.rb +89 -0
- data/lib/celluloid/condition.rb +25 -8
- data/lib/celluloid/cpu_counter.rb +28 -18
- data/lib/celluloid/evented_mailbox.rb +10 -16
- data/lib/celluloid/exceptions.rb +23 -0
- data/lib/celluloid/future.rb +1 -1
- data/lib/celluloid/handlers.rb +41 -0
- data/lib/celluloid/internal_pool.rb +49 -40
- data/lib/celluloid/logger.rb +30 -0
- data/lib/celluloid/logging/incident_logger.rb +1 -1
- data/lib/celluloid/mailbox.rb +35 -31
- data/lib/celluloid/method.rb +8 -0
- data/lib/celluloid/pool_manager.rb +19 -2
- data/lib/celluloid/probe.rb +73 -0
- data/lib/celluloid/properties.rb +2 -2
- data/lib/celluloid/proxies/actor_proxy.rb +9 -41
- data/lib/celluloid/proxies/cell_proxy.rb +68 -0
- data/lib/celluloid/proxies/sync_proxy.rb +1 -1
- data/lib/celluloid/receivers.rb +5 -13
- data/lib/celluloid/registry.rb +1 -8
- data/{spec/support → lib/celluloid/rspec}/actor_examples.rb +58 -15
- data/{spec/support → lib/celluloid/rspec}/mailbox_examples.rb +9 -3
- data/{spec/support → lib/celluloid/rspec}/task_examples.rb +2 -0
- data/lib/celluloid/rspec.rb +4 -3
- data/lib/celluloid/stack_dump.rb +34 -11
- data/lib/celluloid/supervision_group.rb +26 -14
- data/lib/celluloid/tasks/task_fiber.rb +6 -0
- data/lib/celluloid/tasks/task_thread.rb +2 -1
- data/lib/celluloid/tasks.rb +28 -9
- data/lib/celluloid/thread_handle.rb +2 -2
- data/lib/celluloid.rb +68 -73
- data/spec/celluloid/actor_spec.rb +1 -1
- data/spec/celluloid/actor_system_spec.rb +69 -0
- data/spec/celluloid/block_spec.rb +1 -1
- data/spec/celluloid/calls_spec.rb +1 -1
- data/spec/celluloid/condition_spec.rb +14 -3
- data/spec/celluloid/cpu_counter_spec.rb +82 -0
- data/spec/celluloid/fsm_spec.rb +1 -1
- data/spec/celluloid/future_spec.rb +1 -1
- data/spec/celluloid/notifications_spec.rb +1 -1
- data/spec/celluloid/pool_spec.rb +34 -1
- data/spec/celluloid/probe_spec.rb +121 -0
- data/spec/celluloid/registry_spec.rb +6 -6
- data/spec/celluloid/stack_dump_spec.rb +37 -8
- data/spec/celluloid/supervision_group_spec.rb +7 -1
- data/spec/celluloid/supervisor_spec.rb +12 -1
- data/spec/celluloid/tasks/task_fiber_spec.rb +1 -1
- data/spec/celluloid/tasks/task_thread_spec.rb +1 -1
- data/spec/celluloid/thread_handle_spec.rb +7 -3
- data/spec/celluloid/timer_spec.rb +48 -0
- data/spec/spec_helper.rb +20 -7
- metadata +51 -26
- /data/{spec/support → lib/celluloid/rspec}/example_actor_class.rb +0 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
module Celluloid
|
|
2
|
+
OWNER_IVAR = :@celluloid_owner # reference to owning actor
|
|
3
|
+
|
|
4
|
+
# Wrap the given subject with an Cell
|
|
5
|
+
class Cell
|
|
6
|
+
class ExitHandler
|
|
7
|
+
def initialize(behavior, subject, method_name)
|
|
8
|
+
@behavior = behavior
|
|
9
|
+
@subject = subject
|
|
10
|
+
@method_name = method_name
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def call(event)
|
|
14
|
+
@behavior.task(:exit_handler, @method_name) do
|
|
15
|
+
@subject.send(@method_name, event.actor, event.reason)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def initialize(subject, options, actor_options)
|
|
21
|
+
@actor = Actor.new(self, actor_options)
|
|
22
|
+
@subject = subject
|
|
23
|
+
@receiver_block_executions = options[:receiver_block_executions]
|
|
24
|
+
@exclusive_methods = options[:exclusive_methods]
|
|
25
|
+
@finalizer = options[:finalizer]
|
|
26
|
+
|
|
27
|
+
@subject.instance_variable_set(OWNER_IVAR, @actor)
|
|
28
|
+
|
|
29
|
+
if exit_handler_name = options[:exit_handler_name]
|
|
30
|
+
@actor.exit_handler = ExitHandler.new(self, @subject, exit_handler_name)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
@actor.handle(Call) do |message|
|
|
34
|
+
invoke(message)
|
|
35
|
+
end
|
|
36
|
+
@actor.handle(BlockCall) do |message|
|
|
37
|
+
task(:invoke_block) { message.dispatch }
|
|
38
|
+
end
|
|
39
|
+
@actor.handle(BlockResponse, Response) do |message|
|
|
40
|
+
message.dispatch
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
@actor.start
|
|
44
|
+
@proxy = (options[:proxy_class] || CellProxy).new(@actor.proxy, @actor.mailbox, @subject.class.to_s)
|
|
45
|
+
end
|
|
46
|
+
attr_reader :proxy, :subject
|
|
47
|
+
|
|
48
|
+
def invoke(call)
|
|
49
|
+
meth = call.method
|
|
50
|
+
if meth == :__send__
|
|
51
|
+
meth = call.arguments.first
|
|
52
|
+
end
|
|
53
|
+
if @receiver_block_executions && meth
|
|
54
|
+
if @receiver_block_executions.include?(meth.to_sym)
|
|
55
|
+
call.execute_block_on_receiver
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
task(:call, meth, :dangerous_suspend => meth == :initialize) {
|
|
60
|
+
call.dispatch(@subject)
|
|
61
|
+
}
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def task(task_type, method_name = nil, meta = nil, &block)
|
|
65
|
+
meta ||= {}
|
|
66
|
+
meta.merge!(:method_name => method_name)
|
|
67
|
+
@actor.task(task_type, meta) do
|
|
68
|
+
if @exclusive_methods && method_name && @exclusive_methods.include?(method_name.to_sym)
|
|
69
|
+
Celluloid.exclusive { yield }
|
|
70
|
+
else
|
|
71
|
+
yield
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Run the user-defined finalizer, if one is set
|
|
77
|
+
def shutdown
|
|
78
|
+
return unless @finalizer && @subject.respond_to?(@finalizer, true)
|
|
79
|
+
|
|
80
|
+
task(:finalizer, @finalizer, :dangerous_suspend => true) do
|
|
81
|
+
begin
|
|
82
|
+
@subject.__send__(@finalizer)
|
|
83
|
+
rescue => ex
|
|
84
|
+
Logger.crash("#{@subject.class} finalizer crashed!", ex)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
data/lib/celluloid/condition.rb
CHANGED
|
@@ -4,10 +4,11 @@ module Celluloid
|
|
|
4
4
|
# ConditionVariable-like signaling between tasks and threads
|
|
5
5
|
class Condition
|
|
6
6
|
class Waiter
|
|
7
|
-
def initialize(condition, task, mailbox)
|
|
7
|
+
def initialize(condition, task, mailbox, timeout)
|
|
8
8
|
@condition = condition
|
|
9
9
|
@task = task
|
|
10
10
|
@mailbox = mailbox
|
|
11
|
+
@timeout = timeout
|
|
11
12
|
end
|
|
12
13
|
attr_reader :condition, :task
|
|
13
14
|
|
|
@@ -16,9 +17,14 @@ module Celluloid
|
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
def wait
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
begin
|
|
21
|
+
message = @mailbox.receive(@timeout) do |msg|
|
|
22
|
+
msg.is_a?(SignalConditionRequest) && msg.task == Thread.current
|
|
23
|
+
end
|
|
24
|
+
rescue TimeoutError
|
|
25
|
+
raise ConditionError, "timeout after #{@timeout.inspect} seconds"
|
|
26
|
+
end until message
|
|
27
|
+
|
|
22
28
|
message.value
|
|
23
29
|
end
|
|
24
30
|
end
|
|
@@ -29,21 +35,30 @@ module Celluloid
|
|
|
29
35
|
end
|
|
30
36
|
|
|
31
37
|
# Wait for the given signal and return the associated value
|
|
32
|
-
def wait
|
|
38
|
+
def wait(timeout = nil)
|
|
33
39
|
raise ConditionError, "cannot wait for signals while exclusive" if Celluloid.exclusive?
|
|
34
40
|
|
|
35
|
-
if Thread.current[:celluloid_actor]
|
|
41
|
+
if actor = Thread.current[:celluloid_actor]
|
|
36
42
|
task = Task.current
|
|
43
|
+
if timeout
|
|
44
|
+
bt = caller
|
|
45
|
+
timer = actor.timers.after(timeout) do
|
|
46
|
+
exception = ConditionError.new("timeout after #{timeout.inspect} seconds")
|
|
47
|
+
exception.set_backtrace bt
|
|
48
|
+
task.resume exception
|
|
49
|
+
end
|
|
50
|
+
end
|
|
37
51
|
else
|
|
38
52
|
task = Thread.current
|
|
39
53
|
end
|
|
40
|
-
waiter = Waiter.new(self, task, Celluloid.mailbox)
|
|
54
|
+
waiter = Waiter.new(self, task, Celluloid.mailbox, timeout)
|
|
41
55
|
|
|
42
56
|
@mutex.synchronize do
|
|
43
57
|
@waiters << waiter
|
|
44
58
|
end
|
|
45
59
|
|
|
46
60
|
result = Celluloid.suspend :condwait, waiter
|
|
61
|
+
timer.cancel if timer
|
|
47
62
|
raise result if result.is_a? ConditionError
|
|
48
63
|
result
|
|
49
64
|
end
|
|
@@ -54,7 +69,9 @@ module Celluloid
|
|
|
54
69
|
if waiter = @waiters.shift
|
|
55
70
|
waiter << SignalConditionRequest.new(waiter.task, value)
|
|
56
71
|
else
|
|
57
|
-
Logger.
|
|
72
|
+
Logger.with_backtrace(caller(3)) do |logger|
|
|
73
|
+
logger.debug("Celluloid::Condition signaled spuriously")
|
|
74
|
+
end
|
|
58
75
|
end
|
|
59
76
|
end
|
|
60
77
|
end
|
|
@@ -1,24 +1,34 @@
|
|
|
1
|
-
require 'rbconfig'
|
|
2
|
-
|
|
3
1
|
module Celluloid
|
|
4
2
|
module CPUCounter
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
when 'linux'
|
|
9
|
-
@cores = if File.exists?("/sys/devices/system/cpu/present")
|
|
10
|
-
File.read("/sys/devices/system/cpu/present").split('-').last.to_i+1
|
|
11
|
-
else
|
|
12
|
-
Dir["/sys/devices/system/cpu/cpu*"].select { |n| n=~/cpu\d+/ }.count
|
|
3
|
+
class << self
|
|
4
|
+
def cores
|
|
5
|
+
@cores ||= count_cores
|
|
13
6
|
end
|
|
14
|
-
when 'mingw', 'mswin'
|
|
15
|
-
@cores = Integer(ENV["NUMBER_OF_PROCESSORS"][/\d+/])
|
|
16
|
-
else
|
|
17
|
-
@cores = nil
|
|
18
|
-
end
|
|
19
7
|
|
|
20
|
-
|
|
21
|
-
end
|
|
22
|
-
end
|
|
8
|
+
private
|
|
23
9
|
|
|
10
|
+
def count_cores
|
|
11
|
+
result = from_env || from_sysdev || from_sysctl
|
|
12
|
+
Integer(result.to_s[/\d+/], 10) if result
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def from_env
|
|
16
|
+
result = ENV['NUMBER_OF_PROCESSORS']
|
|
17
|
+
result if result
|
|
18
|
+
end
|
|
24
19
|
|
|
20
|
+
def from_sysdev
|
|
21
|
+
::IO.read('/sys/devices/system/cpu/present').split('-').last.to_i + 1
|
|
22
|
+
rescue Errno::ENOENT
|
|
23
|
+
result = Dir['/sys/devices/system/cpu/cpu*'].count { |n| n =~ /cpu\d+/ }
|
|
24
|
+
result unless result.zero?
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def from_sysctl
|
|
28
|
+
result = `sysctl -n hw.ncpu`
|
|
29
|
+
result if $?.success?
|
|
30
|
+
rescue Errno::ENOENT
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -37,24 +37,18 @@ module Celluloid
|
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
# Receive a message from the Mailbox
|
|
40
|
-
def
|
|
41
|
-
message
|
|
42
|
-
|
|
43
|
-
|
|
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)
|
|
54
|
-
message = next_message(block)
|
|
40
|
+
def check(timeout = nil, &block)
|
|
41
|
+
# Get a message if it is available and process it immediately if possible:
|
|
42
|
+
if message = next_message(block)
|
|
43
|
+
return message
|
|
55
44
|
end
|
|
56
45
|
|
|
57
|
-
|
|
46
|
+
# ... otherwise, run the reactor once, either blocking or will return
|
|
47
|
+
# after the given timeout:
|
|
48
|
+
@reactor.run_once(timeout)
|
|
49
|
+
|
|
50
|
+
# No message was received:
|
|
51
|
+
return nil
|
|
58
52
|
rescue IOError
|
|
59
53
|
raise MailboxShutdown, "mailbox shutdown called during receive"
|
|
60
54
|
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Celluloid
|
|
2
|
+
# Base class of all Celluloid errors
|
|
3
|
+
Error = Class.new(StandardError)
|
|
4
|
+
|
|
5
|
+
# Don't do Actor-like things outside Actor scope
|
|
6
|
+
NotActorError = Class.new(Celluloid::Error)
|
|
7
|
+
|
|
8
|
+
# Trying to do something to a dead actor
|
|
9
|
+
DeadActorError = Class.new(Celluloid::Error)
|
|
10
|
+
|
|
11
|
+
# A timeout occured before the given request could complete
|
|
12
|
+
TimeoutError = Class.new(Celluloid::Error)
|
|
13
|
+
|
|
14
|
+
# The sender made an error, not the current actor
|
|
15
|
+
class AbortError < Celluloid::Error
|
|
16
|
+
attr_reader :cause
|
|
17
|
+
|
|
18
|
+
def initialize(cause)
|
|
19
|
+
@cause = cause
|
|
20
|
+
super "caused by #{cause.inspect}: #{cause.to_s}"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
data/lib/celluloid/future.rb
CHANGED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'set'
|
|
2
|
+
|
|
3
|
+
module Celluloid
|
|
4
|
+
class Handlers
|
|
5
|
+
def initialize
|
|
6
|
+
@handlers = Set.new
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def handle(*patterns, &block)
|
|
10
|
+
patterns.each do |pattern|
|
|
11
|
+
handler = Handler.new pattern, block
|
|
12
|
+
@handlers << handler
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Handle incoming messages
|
|
17
|
+
def handle_message(message)
|
|
18
|
+
if handler = @handlers.find { |h| h.match(message) }
|
|
19
|
+
handler.call message
|
|
20
|
+
handler
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Methods blocking on a call to receive
|
|
26
|
+
class Handler
|
|
27
|
+
def initialize(pattern, block)
|
|
28
|
+
@pattern = pattern
|
|
29
|
+
@block = block
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Match a message with this receiver's block
|
|
33
|
+
def match(message)
|
|
34
|
+
@pattern === message
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def call(message)
|
|
38
|
+
@block.call message
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -6,9 +6,11 @@ module Celluloid
|
|
|
6
6
|
attr_accessor :max_idle
|
|
7
7
|
|
|
8
8
|
def initialize
|
|
9
|
-
@group = ThreadGroup.new
|
|
10
9
|
@mutex = Mutex.new
|
|
11
|
-
@
|
|
10
|
+
@idle_threads = []
|
|
11
|
+
@all_threads = []
|
|
12
|
+
@busy_size = 0
|
|
13
|
+
@idle_size = 0
|
|
12
14
|
|
|
13
15
|
# TODO: should really adjust this based on usage
|
|
14
16
|
@max_idle = 16
|
|
@@ -16,17 +18,15 @@ module Celluloid
|
|
|
16
18
|
end
|
|
17
19
|
|
|
18
20
|
def busy_size
|
|
19
|
-
@
|
|
21
|
+
@busy_size
|
|
20
22
|
end
|
|
21
23
|
|
|
22
24
|
def idle_size
|
|
23
|
-
@
|
|
25
|
+
@idle_size
|
|
24
26
|
end
|
|
25
27
|
|
|
26
28
|
def assert_running
|
|
27
|
-
unless running?
|
|
28
|
-
raise Error, "Thread pool is not running"
|
|
29
|
-
end
|
|
29
|
+
raise Error, "Thread pool is not running" unless running?
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
def assert_inactive
|
|
@@ -45,17 +45,15 @@ module Celluloid
|
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
def active?
|
|
48
|
-
|
|
48
|
+
busy_size + idle_size > 0
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
def each
|
|
52
|
-
|
|
53
|
-
yield thread
|
|
54
|
-
end
|
|
52
|
+
to_a.each {|thread| yield thread }
|
|
55
53
|
end
|
|
56
54
|
|
|
57
55
|
def to_a
|
|
58
|
-
@
|
|
56
|
+
@mutex.synchronize { @all_threads.dup }
|
|
59
57
|
end
|
|
60
58
|
|
|
61
59
|
# Get a thread from the pool, running the given block
|
|
@@ -64,15 +62,16 @@ module Celluloid
|
|
|
64
62
|
assert_running
|
|
65
63
|
|
|
66
64
|
begin
|
|
67
|
-
|
|
68
|
-
if idle.empty?
|
|
65
|
+
if @idle_threads.empty?
|
|
69
66
|
thread = create
|
|
70
67
|
else
|
|
71
|
-
thread =
|
|
68
|
+
thread = @idle_threads.pop
|
|
69
|
+
@idle_size = @idle_threads.length
|
|
72
70
|
end
|
|
73
71
|
end until thread.status # handle crashed threads
|
|
74
72
|
|
|
75
73
|
thread.busy = true
|
|
74
|
+
@busy_size += 1
|
|
76
75
|
thread[:celluloid_queue] << block
|
|
77
76
|
thread
|
|
78
77
|
end
|
|
@@ -82,15 +81,46 @@ module Celluloid
|
|
|
82
81
|
def put(thread)
|
|
83
82
|
@mutex.synchronize do
|
|
84
83
|
thread.busy = false
|
|
85
|
-
if idle_size >= @max_idle
|
|
84
|
+
if idle_size + 1 >= @max_idle
|
|
86
85
|
thread[:celluloid_queue] << nil
|
|
87
|
-
@
|
|
86
|
+
@busy_size -= 1
|
|
87
|
+
@all_threads.delete(thread)
|
|
88
88
|
else
|
|
89
|
+
@idle_threads.push thread
|
|
90
|
+
@busy_size -= 1
|
|
91
|
+
@idle_size = @idle_threads.length
|
|
89
92
|
clean_thread_locals(thread)
|
|
90
93
|
end
|
|
91
94
|
end
|
|
92
95
|
end
|
|
93
96
|
|
|
97
|
+
def shutdown
|
|
98
|
+
@mutex.synchronize do
|
|
99
|
+
finalize
|
|
100
|
+
@all_threads.each do |thread|
|
|
101
|
+
thread[:celluloid_queue] << nil
|
|
102
|
+
end
|
|
103
|
+
@all_threads.clear
|
|
104
|
+
@idle_threads.clear
|
|
105
|
+
@busy_size = 0
|
|
106
|
+
@idle_size = 0
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def kill
|
|
111
|
+
@mutex.synchronize do
|
|
112
|
+
finalize
|
|
113
|
+
@running = false
|
|
114
|
+
|
|
115
|
+
@all_threads.shift.kill until @all_threads.empty?
|
|
116
|
+
@idle_threads.clear
|
|
117
|
+
@busy_size = 0
|
|
118
|
+
@idle_size = 0
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
private
|
|
123
|
+
|
|
94
124
|
# Create a new thread with an associated queue of procs to run
|
|
95
125
|
def create
|
|
96
126
|
queue = Queue.new
|
|
@@ -107,8 +137,8 @@ module Celluloid
|
|
|
107
137
|
end
|
|
108
138
|
|
|
109
139
|
thread[:celluloid_queue] = queue
|
|
110
|
-
@
|
|
111
|
-
@
|
|
140
|
+
# @idle_threads << thread
|
|
141
|
+
@all_threads << thread
|
|
112
142
|
thread
|
|
113
143
|
end
|
|
114
144
|
|
|
@@ -122,27 +152,6 @@ module Celluloid
|
|
|
122
152
|
end
|
|
123
153
|
end
|
|
124
154
|
|
|
125
|
-
def shutdown
|
|
126
|
-
@mutex.synchronize do
|
|
127
|
-
finalize
|
|
128
|
-
@threads.each do |thread|
|
|
129
|
-
thread[:celluloid_queue] << nil
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
def kill
|
|
135
|
-
@mutex.synchronize do
|
|
136
|
-
finalize
|
|
137
|
-
@running = false
|
|
138
|
-
|
|
139
|
-
@threads.shift.kill until @threads.empty?
|
|
140
|
-
@group.list.each(&:kill)
|
|
141
|
-
end
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
private
|
|
145
|
-
|
|
146
155
|
def finalize
|
|
147
156
|
@max_idle = 0
|
|
148
157
|
end
|
data/lib/celluloid/logger.rb
CHANGED
|
@@ -1,8 +1,38 @@
|
|
|
1
1
|
module Celluloid
|
|
2
2
|
module Logger
|
|
3
|
+
class WithBacktrace
|
|
4
|
+
def initialize(backtrace)
|
|
5
|
+
@backtrace = backtrace
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def debug(string)
|
|
9
|
+
Celluloid.logger.debug(decorate(string))
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def info(string)
|
|
13
|
+
Celluloid.logger.info(decorate(string))
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def warn(string)
|
|
17
|
+
Celluloid.logger.warn(decorate(string))
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def error(string)
|
|
21
|
+
Celluloid.logger.error(decorate(string))
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def decorate(string)
|
|
25
|
+
[string, @backtrace].join("\n\t")
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
3
29
|
@exception_handlers = []
|
|
4
30
|
module_function
|
|
5
31
|
|
|
32
|
+
def with_backtrace(backtrace)
|
|
33
|
+
yield WithBacktrace.new(backtrace) if Celluloid.logger
|
|
34
|
+
end
|
|
35
|
+
|
|
6
36
|
# Send a debug message
|
|
7
37
|
def debug(string)
|
|
8
38
|
Celluloid.logger.debug(string) if Celluloid.logger
|
data/lib/celluloid/mailbox.rb
CHANGED
|
@@ -45,52 +45,39 @@ module Celluloid
|
|
|
45
45
|
end
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
-
# Receive a message from the Mailbox
|
|
49
|
-
|
|
48
|
+
# Receive a message from the Mailbox. May return nil and may return before
|
|
49
|
+
# the specified timeout.
|
|
50
|
+
def check(timeout = nil, &block)
|
|
50
51
|
message = nil
|
|
51
52
|
|
|
52
53
|
@mutex.lock
|
|
53
54
|
begin
|
|
54
55
|
raise MailboxDead, "attempted to receive from a dead mailbox" if @dead
|
|
55
56
|
|
|
56
|
-
|
|
57
|
+
Timers::Wait.for(timeout) do |remaining|
|
|
57
58
|
message = next_message(&block)
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
wait_interval = wait_until - now
|
|
64
|
-
return if wait_interval <= 0
|
|
65
|
-
else
|
|
66
|
-
wait_interval = nil
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
@condition.wait(@mutex, wait_interval)
|
|
70
|
-
end
|
|
71
|
-
end until message
|
|
72
|
-
|
|
73
|
-
message
|
|
60
|
+
break message if message
|
|
61
|
+
|
|
62
|
+
@condition.wait(@mutex, remaining)
|
|
63
|
+
end
|
|
74
64
|
ensure
|
|
75
65
|
@mutex.unlock rescue nil
|
|
76
66
|
end
|
|
67
|
+
|
|
68
|
+
return message
|
|
77
69
|
end
|
|
78
70
|
|
|
79
|
-
#
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
yield(msg) || msg.is_a?(SystemEvent)
|
|
71
|
+
# Receive a letter from the mailbox. Guaranteed to return a message. If
|
|
72
|
+
# timeout is exceeded, raise a TimeoutError.
|
|
73
|
+
def receive(timeout = nil, &block)
|
|
74
|
+
Timers::Wait.for(timeout) do |remaining|
|
|
75
|
+
if message = check(timeout, &block)
|
|
76
|
+
return message
|
|
86
77
|
end
|
|
87
|
-
|
|
88
|
-
message = @messages.slice!(index, 1).first if index
|
|
89
|
-
else
|
|
90
|
-
message = @messages.shift
|
|
91
78
|
end
|
|
92
|
-
|
|
93
|
-
|
|
79
|
+
|
|
80
|
+
raise TimeoutError.new("receive timeout exceeded")
|
|
94
81
|
end
|
|
95
82
|
|
|
96
83
|
# Shut down this mailbox and clean up its contents
|
|
@@ -141,6 +128,23 @@ module Celluloid
|
|
|
141
128
|
|
|
142
129
|
private
|
|
143
130
|
|
|
131
|
+
# Retrieve the next message in the mailbox
|
|
132
|
+
def next_message
|
|
133
|
+
message = nil
|
|
134
|
+
|
|
135
|
+
if block_given?
|
|
136
|
+
index = @messages.index do |msg|
|
|
137
|
+
yield(msg) || msg.is_a?(SystemEvent)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
message = @messages.slice!(index, 1).first if index
|
|
141
|
+
else
|
|
142
|
+
message = @messages.shift
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
message
|
|
146
|
+
end
|
|
147
|
+
|
|
144
148
|
def dead_letter(message)
|
|
145
149
|
Logger.debug "Discarded message (mailbox is dead): #{message}" if $CELLULOID_DEBUG
|
|
146
150
|
end
|
data/lib/celluloid/method.rb
CHANGED
|
@@ -13,6 +13,14 @@ module Celluloid
|
|
|
13
13
|
@proxy.method_missing(:method, @name).arity
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
+
def name
|
|
17
|
+
@proxy.method_missing(:method, @name).name
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def parameters
|
|
21
|
+
@proxy.method_missing(:method, @name).parameters
|
|
22
|
+
end
|
|
23
|
+
|
|
16
24
|
def call(*args, &block)
|
|
17
25
|
@proxy.__send__(@name, *args, &block)
|
|
18
26
|
end
|
|
@@ -10,7 +10,7 @@ module Celluloid
|
|
|
10
10
|
finalizer :__shutdown__
|
|
11
11
|
|
|
12
12
|
def initialize(worker_class, options = {})
|
|
13
|
-
@size = options[:size] || [Celluloid.cores, 2].max
|
|
13
|
+
@size = options[:size] || [Celluloid.cores || 2, 2].max
|
|
14
14
|
raise ArgumentError, "minimum pool size is 2" if @size < 2
|
|
15
15
|
|
|
16
16
|
@worker_class = worker_class
|
|
@@ -24,7 +24,7 @@ module Celluloid
|
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def __shutdown__
|
|
27
|
-
terminators = (@idle + @busy).
|
|
27
|
+
terminators = (@idle + @busy).map do |actor|
|
|
28
28
|
begin
|
|
29
29
|
actor.future(:terminate)
|
|
30
30
|
rescue DeadActorError
|
|
@@ -81,6 +81,23 @@ module Celluloid
|
|
|
81
81
|
@size
|
|
82
82
|
end
|
|
83
83
|
|
|
84
|
+
def size=(new_size)
|
|
85
|
+
new_size = [0, new_size].max
|
|
86
|
+
|
|
87
|
+
if new_size > size
|
|
88
|
+
delta = new_size - size
|
|
89
|
+
delta.times { @idle << @worker_class.new_link(*@args) }
|
|
90
|
+
else
|
|
91
|
+
(size - new_size).times do
|
|
92
|
+
worker = __provision_worker__
|
|
93
|
+
unlink worker
|
|
94
|
+
@busy.delete worker
|
|
95
|
+
worker.terminate
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
@size = new_size
|
|
99
|
+
end
|
|
100
|
+
|
|
84
101
|
def busy_size
|
|
85
102
|
@busy.length
|
|
86
103
|
end
|