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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +20 -0
  3. data/README.md +25 -2
  4. data/lib/celluloid/actor.rb +88 -147
  5. data/lib/celluloid/actor_system.rb +107 -0
  6. data/lib/celluloid/call_chain.rb +1 -1
  7. data/lib/celluloid/calls.rb +16 -16
  8. data/lib/celluloid/cell.rb +89 -0
  9. data/lib/celluloid/condition.rb +25 -8
  10. data/lib/celluloid/cpu_counter.rb +28 -18
  11. data/lib/celluloid/evented_mailbox.rb +10 -16
  12. data/lib/celluloid/exceptions.rb +23 -0
  13. data/lib/celluloid/future.rb +1 -1
  14. data/lib/celluloid/handlers.rb +41 -0
  15. data/lib/celluloid/internal_pool.rb +49 -40
  16. data/lib/celluloid/logger.rb +30 -0
  17. data/lib/celluloid/logging/incident_logger.rb +1 -1
  18. data/lib/celluloid/mailbox.rb +35 -31
  19. data/lib/celluloid/method.rb +8 -0
  20. data/lib/celluloid/pool_manager.rb +19 -2
  21. data/lib/celluloid/probe.rb +73 -0
  22. data/lib/celluloid/properties.rb +2 -2
  23. data/lib/celluloid/proxies/actor_proxy.rb +9 -41
  24. data/lib/celluloid/proxies/cell_proxy.rb +68 -0
  25. data/lib/celluloid/proxies/sync_proxy.rb +1 -1
  26. data/lib/celluloid/receivers.rb +5 -13
  27. data/lib/celluloid/registry.rb +1 -8
  28. data/{spec/support → lib/celluloid/rspec}/actor_examples.rb +58 -15
  29. data/{spec/support → lib/celluloid/rspec}/mailbox_examples.rb +9 -3
  30. data/{spec/support → lib/celluloid/rspec}/task_examples.rb +2 -0
  31. data/lib/celluloid/rspec.rb +4 -3
  32. data/lib/celluloid/stack_dump.rb +34 -11
  33. data/lib/celluloid/supervision_group.rb +26 -14
  34. data/lib/celluloid/tasks/task_fiber.rb +6 -0
  35. data/lib/celluloid/tasks/task_thread.rb +2 -1
  36. data/lib/celluloid/tasks.rb +28 -9
  37. data/lib/celluloid/thread_handle.rb +2 -2
  38. data/lib/celluloid.rb +68 -73
  39. data/spec/celluloid/actor_spec.rb +1 -1
  40. data/spec/celluloid/actor_system_spec.rb +69 -0
  41. data/spec/celluloid/block_spec.rb +1 -1
  42. data/spec/celluloid/calls_spec.rb +1 -1
  43. data/spec/celluloid/condition_spec.rb +14 -3
  44. data/spec/celluloid/cpu_counter_spec.rb +82 -0
  45. data/spec/celluloid/fsm_spec.rb +1 -1
  46. data/spec/celluloid/future_spec.rb +1 -1
  47. data/spec/celluloid/notifications_spec.rb +1 -1
  48. data/spec/celluloid/pool_spec.rb +34 -1
  49. data/spec/celluloid/probe_spec.rb +121 -0
  50. data/spec/celluloid/registry_spec.rb +6 -6
  51. data/spec/celluloid/stack_dump_spec.rb +37 -8
  52. data/spec/celluloid/supervision_group_spec.rb +7 -1
  53. data/spec/celluloid/supervisor_spec.rb +12 -1
  54. data/spec/celluloid/tasks/task_fiber_spec.rb +1 -1
  55. data/spec/celluloid/tasks/task_thread_spec.rb +1 -1
  56. data/spec/celluloid/thread_handle_spec.rb +7 -3
  57. data/spec/celluloid/timer_spec.rb +48 -0
  58. data/spec/spec_helper.rb +20 -7
  59. metadata +51 -26
  60. /data/{spec/support → lib/celluloid/rspec}/example_actor_class.rb +0 -0
@@ -0,0 +1,73 @@
1
+ require 'celluloid'
2
+
3
+ $CELLULOID_MONITORING = true
4
+
5
+ module Celluloid
6
+ class Probe
7
+ include Celluloid
8
+ include Celluloid::Notifications
9
+
10
+ NOTIFICATIONS_TOPIC_BASE = 'celluloid.events.%s'
11
+ INITIAL_EVENTS = Queue.new
12
+
13
+ class << self
14
+ def run
15
+ # spawn the actor if not found
16
+ supervise_as(:probe_actor) unless Actor[:probe_actor] && Actor[:probe_actor].alive?
17
+ end
18
+
19
+ def actor_created(actor)
20
+ trigger_event(:actor_created, actor)
21
+ end
22
+
23
+ def actor_named(actor)
24
+ trigger_event(:actor_named, actor)
25
+ end
26
+
27
+ def actor_died(actor)
28
+ trigger_event(:actor_died, actor)
29
+ end
30
+
31
+ def actors_linked(a, b)
32
+ a = find_actor(a)
33
+ b = find_actor(b)
34
+ trigger_event(:actors_linked, a, b)
35
+ end
36
+
37
+ private
38
+
39
+ def trigger_event(name, *args)
40
+ return unless $CELLULOID_MONITORING
41
+ probe_actor = Actor[:probe_actor]
42
+ if probe_actor
43
+ probe_actor.async.dispatch_event(name, args)
44
+ else
45
+ INITIAL_EVENTS << [name, args]
46
+ end
47
+ end
48
+
49
+ def find_actor(obj)
50
+ if obj.__send__(:class) == Actor
51
+ obj
52
+ elsif owner = obj.instance_variable_get(OWNER_IVAR)
53
+ owner
54
+ end
55
+ end
56
+ end
57
+
58
+ def initialize
59
+ async.first_run
60
+ end
61
+
62
+ def first_run
63
+ until INITIAL_EVENTS.size == 0
64
+ event = INITIAL_EVENTS.pop
65
+ dispatch_event(*event)
66
+ end
67
+ end
68
+
69
+ def dispatch_event(cmd, args)
70
+ publish(NOTIFICATIONS_TOPIC_BASE % cmd, args)
71
+ end
72
+ end
73
+ end
@@ -9,7 +9,7 @@ module Celluloid
9
9
 
10
10
  ancestors.first.send(:define_singleton_method, name) do |value = nil, *extra|
11
11
  if value
12
- value = value ? [value, *extra] : [] if multi
12
+ value = value ? [value, *send(name), *extra].uniq : [] if multi
13
13
  instance_variable_set(ivar_name, value)
14
14
  elsif instance_variables.include?(ivar_name)
15
15
  instance_variable_get(ivar_name)
@@ -21,4 +21,4 @@ module Celluloid
21
21
  end
22
22
  end
23
23
  end
24
- end
24
+ end
@@ -1,59 +1,27 @@
1
1
  module Celluloid
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 < SyncProxy
5
- attr_reader :thread
2
+ # A proxy which controls the Actor lifecycle
3
+ class ActorProxy < AbstractProxy
4
+ attr_reader :thread, :mailbox
6
5
 
7
6
  # Used for reflecting on proxy objects themselves
8
7
  def __class__; ActorProxy; end
9
8
 
10
- def initialize(actor)
11
- @thread = actor.thread
12
-
13
- super(actor.mailbox, actor.subject.class.to_s)
14
- @sync_proxy = SyncProxy.new(@mailbox, @klass)
15
- @async_proxy = AsyncProxy.new(@mailbox, @klass)
16
- @future_proxy = FutureProxy.new(@mailbox, @klass)
17
- end
18
-
19
- def _send_(meth, *args, &block)
20
- method_missing :__send__, meth, *args, &block
9
+ def initialize(thread, mailbox)
10
+ @thread = thread
11
+ @mailbox = mailbox
21
12
  end
22
13
 
23
14
  def inspect
24
- method_missing :inspect
15
+ # TODO: use a system event to fetch actor state: tasks?
16
+ "#<Celluloid::ActorProxy(#{@mailbox.address}) alive>"
25
17
  rescue DeadActorError
26
- "#<Celluloid::ActorProxy(#{@klass}) dead>"
27
- end
28
-
29
- def method(name)
30
- Method.new(self, name)
18
+ "#<Celluloid::ActorProxy(#{@mailbox.address}) dead>"
31
19
  end
32
20
 
33
21
  def alive?
34
22
  @mailbox.alive?
35
23
  end
36
24
 
37
- alias_method :sync, :method_missing
38
-
39
- # Obtain an async proxy or explicitly invoke a named async method
40
- def async(method_name = nil, *args, &block)
41
- if method_name
42
- @async_proxy.method_missing method_name, *args, &block
43
- else
44
- @async_proxy
45
- end
46
- end
47
-
48
- # Obtain a future proxy or explicitly invoke a named future method
49
- def future(method_name = nil, *args, &block)
50
- if method_name
51
- @future_proxy.method_missing method_name, *args, &block
52
- else
53
- @future_proxy
54
- end
55
- end
56
-
57
25
  # Terminate the associated actor
58
26
  def terminate
59
27
  terminate!
@@ -0,0 +1,68 @@
1
+ module Celluloid
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 CellProxy < SyncProxy
5
+ # Used for reflecting on proxy objects themselves
6
+ def __class__; CellProxy; end
7
+
8
+ def initialize(actor_proxy, mailbox, klass)
9
+ super(mailbox, klass)
10
+ @actor_proxy = actor_proxy
11
+ @sync_proxy = SyncProxy.new(mailbox, klass)
12
+ @async_proxy = AsyncProxy.new(mailbox, klass)
13
+ @future_proxy = FutureProxy.new(mailbox, klass)
14
+ end
15
+
16
+ def _send_(meth, *args, &block)
17
+ method_missing :__send__, meth, *args, &block
18
+ end
19
+
20
+ def inspect
21
+ method_missing :inspect
22
+ rescue DeadActorError
23
+ "#<Celluloid::CellProxy(#{@klass}) dead>"
24
+ end
25
+
26
+ def method(name)
27
+ Method.new(self, name)
28
+ end
29
+
30
+ alias_method :sync, :method_missing
31
+
32
+ # Obtain an async proxy or explicitly invoke a named async method
33
+ def async(method_name = nil, *args, &block)
34
+ if method_name
35
+ @async_proxy.method_missing method_name, *args, &block
36
+ else
37
+ @async_proxy
38
+ end
39
+ end
40
+
41
+ # Obtain a future proxy or explicitly invoke a named future method
42
+ def future(method_name = nil, *args, &block)
43
+ if method_name
44
+ @future_proxy.method_missing method_name, *args, &block
45
+ else
46
+ @future_proxy
47
+ end
48
+ end
49
+
50
+ def alive?
51
+ @actor_proxy.alive?
52
+ end
53
+
54
+ def thread
55
+ @actor_proxy.thread
56
+ end
57
+
58
+ # Terminate the associated actor
59
+ def terminate
60
+ @actor_proxy.terminate
61
+ end
62
+
63
+ # Terminate the associated actor asynchronously
64
+ def terminate!
65
+ @actor_proxy.terminate!
66
+ end
67
+ end
68
+ end
@@ -15,7 +15,7 @@ module Celluloid
15
15
  end
16
16
 
17
17
  def respond_to?(meth, include_private = false)
18
- __class__.instance_methods.include?(meth) || super
18
+ __class__.instance_methods.include?(meth) || method_missing(:respond_to?, meth, include_private)
19
19
  end
20
20
 
21
21
  def method_missing(meth, *args, &block)
@@ -1,12 +1,13 @@
1
1
  require 'set'
2
+
2
3
  require 'timers'
3
4
 
4
5
  module Celluloid
5
6
  # Allow methods to directly interact with the actor protocol
6
7
  class Receivers
7
- def initialize
8
+ def initialize(timers)
8
9
  @receivers = Set.new
9
- @timers = Timers.new
10
+ @timers = timers
10
11
  end
11
12
 
12
13
  # Receive an asynchronous message
@@ -28,24 +29,15 @@ module Celluloid
28
29
  end
29
30
  end
30
31
 
31
- # How long to wait until the next timer fires
32
- def wait_interval
33
- @timers.wait_interval
34
- end
35
-
36
- # Fire any pending timers
37
- def fire_timers
38
- @timers.fire
39
- end
40
-
41
32
  # Handle incoming messages
42
33
  def handle_message(message)
43
34
  receiver = @receivers.find { |r| r.match(message) }
44
35
  return unless receiver
45
36
 
46
37
  @receivers.delete receiver
47
- @timers.cancel receiver.timer if receiver.timer
38
+ receiver.timer.cancel if receiver.timer
48
39
  receiver.resume message
40
+ message
49
41
  end
50
42
  end
51
43
 
@@ -3,10 +3,6 @@ require 'thread'
3
3
  module Celluloid
4
4
  # The Registry allows us to refer to specific actors by human-meaningful names
5
5
  class Registry
6
- class << self
7
- attr_reader :root
8
- end
9
-
10
6
  def initialize
11
7
  @registry = {}
12
8
  @registry_lock = Mutex.new
@@ -15,7 +11,7 @@ module Celluloid
15
11
  # Register an Actor
16
12
  def []=(name, actor)
17
13
  actor_singleton = class << actor; self; end
18
- unless actor_singleton.ancestors.include? ActorProxy
14
+ unless actor_singleton.ancestors.include? AbstractProxy
19
15
  raise TypeError, "not an actor"
20
16
  end
21
17
 
@@ -57,8 +53,5 @@ module Celluloid
57
53
  end
58
54
  hash
59
55
  end
60
-
61
- # Create the default registry
62
- @root = new
63
56
  end
64
57
  end
@@ -65,6 +65,19 @@ shared_examples "Celluloid::Actor examples" do |included_module, task_klass|
65
65
  method.arity.should be(1)
66
66
  end
67
67
 
68
+ it "supports #name calls via #method" do
69
+ method = actor_class.new("Troy McClure").method(:greet)
70
+ method.name.should == :greet
71
+ end
72
+
73
+ it "supports #parameters via #method" do
74
+ method = actor_class.new("Troy McClure").method(:greet)
75
+ method.parameters.should == []
76
+
77
+ method = actor_class.new("Troy McClure").method(:change_name)
78
+ method.parameters.should == [[:req, :new_name]]
79
+ end
80
+
68
81
  it "supports future(:method) syntax for synchronous future calls" do
69
82
  actor = actor_class.new "Troy McClure"
70
83
  future = actor.future :greet
@@ -148,7 +161,6 @@ shared_examples "Celluloid::Actor examples" do |included_module, task_klass|
148
161
  end
149
162
  end
150
163
 
151
- Celluloid.logger = double.as_null_object
152
164
  Celluloid.logger.should_receive(:warn).with(/Dangerously suspending task: type=:call, meta={:method_name=>:initialize}, status=:sleeping/)
153
165
 
154
166
  actor = klass.new
@@ -175,7 +187,6 @@ shared_examples "Celluloid::Actor examples" do |included_module, task_klass|
175
187
  end
176
188
  end
177
189
 
178
- Celluloid.logger = double.as_null_object
179
190
  Celluloid.logger.should_receive(:warn).with(/Dangerously suspending task: type=:finalizer, meta={:method_name=>:cleanup}, status=:sleeping/)
180
191
 
181
192
  actor = klass.new
@@ -221,7 +232,7 @@ shared_examples "Celluloid::Actor examples" do |included_module, task_klass|
221
232
 
222
233
  it "inspects properly" do
223
234
  actor = actor_class.new "Troy McClure"
224
- actor.inspect.should match(/Celluloid::ActorProxy\(/)
235
+ actor.inspect.should match(/Celluloid::CellProxy\(/)
225
236
  actor.inspect.should match(/#{actor_class}/)
226
237
  actor.inspect.should include('@name="Troy McClure"')
227
238
  actor.inspect.should_not include("@celluloid")
@@ -230,7 +241,7 @@ shared_examples "Celluloid::Actor examples" do |included_module, task_klass|
230
241
  it "inspects properly when dead" do
231
242
  actor = actor_class.new "Troy McClure"
232
243
  actor.terminate
233
- actor.inspect.should match(/Celluloid::ActorProxy\(/)
244
+ actor.inspect.should match(/Celluloid::CellProxy\(/)
234
245
  actor.inspect.should match(/#{actor_class}/)
235
246
  actor.inspect.should include('dead')
236
247
  end
@@ -252,7 +263,7 @@ shared_examples "Celluloid::Actor examples" do |included_module, task_klass|
252
263
  itchy.other = scratchy
253
264
 
254
265
  inspection = itchy.inspect
255
- inspection.should match(/Celluloid::ActorProxy\(/)
266
+ inspection.should match(/Celluloid::CellProxy\(/)
256
267
  inspection.should include("...")
257
268
  end
258
269
 
@@ -274,6 +285,31 @@ shared_examples "Celluloid::Actor examples" do |included_module, task_klass|
274
285
  actor.send('foo').should eq('oof')
275
286
  end
276
287
 
288
+ context "when executing under JRuby" do
289
+ let(:klass) {
290
+ Class.new do
291
+ include included_module
292
+ task_class task_klass
293
+
294
+ def current_thread_name
295
+ java_thread.get_name
296
+ end
297
+
298
+ def java_thread
299
+ Thread.current.to_java.getNativeThread
300
+ end
301
+ end
302
+ }
303
+
304
+ it "sets execution info" do
305
+ klass.new.current_thread_name.should == "Class#current_thread_name"
306
+ end
307
+
308
+ it "unsets execution info after task completion" do
309
+ klass.new.java_thread.get_name.should == "<unused>"
310
+ end
311
+ end if RUBY_PLATFORM == "java"
312
+
277
313
  context "mocking methods" do
278
314
  let(:actor) { actor_class.new "Troy McClure" }
279
315
 
@@ -300,27 +336,27 @@ shared_examples "Celluloid::Actor examples" do |included_module, task_klass|
300
336
  end
301
337
 
302
338
  it "includes both sender and receiver in exception traces" do
303
- ExampleReceiver = Class.new do
339
+ example_receiver = Class.new do
304
340
  include included_module
305
341
  task_class task_klass
306
342
 
307
- def receiver_method
343
+ define_method(:receiver_method) do
308
344
  raise ExampleCrash, "the spec purposely crashed me :("
309
345
  end
310
346
  end
311
347
 
312
- ExampleCaller = Class.new do
348
+ excample_caller = Class.new do
313
349
  include included_module
314
350
  task_class task_klass
315
351
 
316
- def sender_method
317
- ExampleReceiver.new.receiver_method
352
+ define_method(:sender_method) do
353
+ example_receiver.new.receiver_method
318
354
  end
319
355
  end
320
356
 
321
357
  ex = nil
322
358
  begin
323
- ExampleCaller.new.sender_method
359
+ excample_caller.new.sender_method
324
360
  rescue => ex
325
361
  end
326
362
 
@@ -404,6 +440,15 @@ shared_examples "Celluloid::Actor examples" do |included_module, task_klass|
404
440
  end.to raise_exception(Celluloid::DeadActorError)
405
441
  end
406
442
 
443
+ it "terminates cleanly on Celluloid shutdown" do
444
+ Celluloid::Actor.stub(:kill).and_call_original
445
+
446
+ actor = actor_class.new "Arnold Schwarzenegger"
447
+
448
+ Celluloid.shutdown
449
+ Celluloid::Actor.should_not have_received(:kill)
450
+ end
451
+
407
452
  it "raises the right DeadActorError if terminate! called after terminated" do
408
453
  actor = actor_class.new "Arnold Schwarzenegger"
409
454
  actor.terminate
@@ -414,8 +459,7 @@ shared_examples "Celluloid::Actor examples" do |included_module, task_klass|
414
459
  end
415
460
 
416
461
  it "logs a warning when terminating tasks" do
417
- Celluloid.logger = double.as_null_object
418
- Celluloid.logger.should_receive(:warn).with("Terminating task: type=:call, meta={:method_name=>:sleepy}, status=:sleeping")
462
+ Celluloid.logger.should_receive(:warn).with(/^Terminating task: type=:call, meta={:method_name=>:sleepy}, status=:sleeping\n/)
419
463
 
420
464
  actor = actor_class.new "Arnold Schwarzenegger"
421
465
  actor.async.sleepy 10
@@ -923,7 +967,7 @@ shared_examples "Celluloid::Actor examples" do |included_module, task_klass|
923
967
  end
924
968
 
925
969
  context :proxy_class do
926
- class ExampleProxy < Celluloid::ActorProxy
970
+ class ExampleProxy < Celluloid::CellProxy
927
971
  def subclass_proxy?
928
972
  true
929
973
  end
@@ -1000,7 +1044,6 @@ shared_examples "Celluloid::Actor examples" do |included_module, task_klass|
1000
1044
 
1001
1045
  context "raw message sends" do
1002
1046
  it "logs on unhandled messages" do
1003
- Celluloid.logger = double.as_null_object
1004
1047
  Celluloid.logger.should_receive(:debug).with("Discarded message (unhandled): first")
1005
1048
 
1006
1049
  actor = actor_class.new "Irma Gladden"
@@ -1,4 +1,9 @@
1
1
  shared_context "a Celluloid Mailbox" do
2
+ after do
3
+ Celluloid.logger.stub(:debug)
4
+ subject.shutdown if subject.alive?
5
+ end
6
+
2
7
  it "receives messages" do
3
8
  message = :ohai
4
9
 
@@ -34,7 +39,10 @@ shared_context "a Celluloid Mailbox" do
34
39
  interval = 0.1
35
40
  started_at = Time.now
36
41
 
37
- subject.receive(interval) { false }
42
+ expect do
43
+ subject.receive(interval) { false }
44
+ end.to raise_exception(Celluloid::TimeoutError)
45
+
38
46
  (Time.now - started_at).should be_within(Celluloid::TIMER_QUANTUM).of interval
39
47
  end
40
48
 
@@ -55,7 +63,6 @@ shared_context "a Celluloid Mailbox" do
55
63
  end
56
64
 
57
65
  it "logs discarded messages" do
58
- Celluloid.logger = double.as_null_object
59
66
  Celluloid.logger.should_receive(:debug).with("Discarded message (mailbox is dead): third")
60
67
 
61
68
  subject.max_size = 2
@@ -65,7 +72,6 @@ shared_context "a Celluloid Mailbox" do
65
72
  end
66
73
 
67
74
  it "discard messages when dead" do
68
- Celluloid.logger = double.as_null_object
69
75
  Celluloid.logger.should_receive(:debug).with("Discarded message (mailbox is dead): first")
70
76
  Celluloid.logger.should_receive(:debug).with("Discarded message (mailbox is dead): second")
71
77
  Celluloid.logger.should_receive(:debug).with("Discarded message (mailbox is dead): third")
@@ -17,11 +17,13 @@ shared_context "a Celluloid Task" do |task_class|
17
17
  subject { task_class.new(task_type, {}) { Celluloid::Task.suspend(suspend_state) } }
18
18
 
19
19
  before :each do
20
+ Thread.current[:celluloid_actor_system] = Celluloid.actor_system
20
21
  Thread.current[:celluloid_actor] = actor
21
22
  end
22
23
 
23
24
  after :each do
24
25
  Thread.current[:celluloid_actor] = nil
26
+ Thread.current[:celluloid_actor_system] = nil
25
27
  end
26
28
 
27
29
  it "begins with status :new" do
@@ -1,6 +1,7 @@
1
- require File.expand_path('../../../spec/support/example_actor_class', __FILE__)
2
- require File.expand_path('../../../spec/support/actor_examples', __FILE__)
3
- require File.expand_path('../../../spec/support/mailbox_examples', __FILE__)
1
+ require 'celluloid/rspec/example_actor_class'
2
+ require 'celluloid/rspec/actor_examples'
3
+ require 'celluloid/rspec/mailbox_examples'
4
+ require 'celluloid/rspec/task_examples'
4
5
 
5
6
  module Celluloid
6
7
  # Timer accuracy enforced by the tests (50ms)
@@ -16,17 +16,21 @@ module Celluloid
16
16
 
17
17
  class ActorState
18
18
  include DisplayBacktrace
19
-
20
- attr_accessor :subject_id, :subject_class, :name
19
+ attr_accessor :name, :id, :cell
21
20
  attr_accessor :status, :tasks
22
21
  attr_accessor :backtrace
23
22
 
24
23
  def dump
25
24
  string = ""
26
- string << "Celluloid::Actor 0x#{subject_id.to_s(16)}: #{subject_class}"
25
+ string << "Celluloid::Actor 0x#{id.to_s(16)}"
27
26
  string << " [#{name}]" if name
28
27
  string << "\n"
29
28
 
29
+ if cell
30
+ string << cell.dump
31
+ string << "\n"
32
+ end
33
+
30
34
  if status == :idle
31
35
  string << "State: Idle (waiting for messages)\n"
32
36
  display_backtrace backtrace, string
@@ -46,12 +50,18 @@ module Celluloid
46
50
  end
47
51
  end
48
52
 
49
- class ThreadState < Struct.new(:thread_id, :backtrace)
53
+ class CellState < Struct.new(:subject_id, :subject_class)
54
+ def dump
55
+ "Celluloid::Cell 0x#{subject_id.to_s(16)}: #{subject_class}"
56
+ end
57
+ end
58
+
59
+ class ThreadState < Struct.new(:thread_id, :backtrace, :role)
50
60
  include DisplayBacktrace
51
61
 
52
62
  def dump
53
63
  string = ""
54
- string << "Thread 0x#{thread_id.to_s(16)}:\n"
64
+ string << "Thread 0x#{thread_id.to_s(16)} (#{role}):\n"
55
65
  display_backtrace backtrace, string
56
66
  string
57
67
  end
@@ -59,7 +69,9 @@ module Celluloid
59
69
 
60
70
  attr_accessor :actors, :threads
61
71
 
62
- def initialize
72
+ def initialize(internal_pool)
73
+ @internal_pool = internal_pool
74
+
63
75
  @actors = []
64
76
  @threads = []
65
77
 
@@ -67,7 +79,7 @@ module Celluloid
67
79
  end
68
80
 
69
81
  def snapshot
70
- Celluloid.internal_pool.each do |thread|
82
+ @internal_pool.each do |thread|
71
83
  if thread.role == :actor
72
84
  @actors << snapshot_actor(thread.actor) if thread.actor
73
85
  else
@@ -78,8 +90,12 @@ module Celluloid
78
90
 
79
91
  def snapshot_actor(actor)
80
92
  state = ActorState.new
81
- state.subject_id = actor.subject.object_id
82
- state.subject_class = actor.subject.class
93
+ state.id = actor.object_id
94
+
95
+ # TODO: delegate to the behavior
96
+ if actor.behavior.is_a?(Cell)
97
+ state.cell = snapshot_cell(actor.behavior)
98
+ end
83
99
 
84
100
  tasks = actor.tasks
85
101
  if tasks.empty?
@@ -93,11 +109,18 @@ module Celluloid
93
109
  state
94
110
  end
95
111
 
112
+ def snapshot_cell(behavior)
113
+ state = CellState.new
114
+ state.subject_id = behavior.subject.object_id
115
+ state.subject_class = behavior.subject.class
116
+ state
117
+ end
118
+
96
119
  def snapshot_thread(thread)
97
- ThreadState.new(thread.object_id, thread.backtrace)
120
+ ThreadState.new(thread.object_id, thread.backtrace, thread.role)
98
121
  end
99
122
 
100
- def dump(output = STDERR)
123
+ def print(output = STDERR)
101
124
  @actors.each do |actor|
102
125
  output.print actor.dump
103
126
  end