celluloid 0.13.0 → 0.14.0.pre

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 (38) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +1 -2
  3. data/lib/celluloid.rb +84 -32
  4. data/lib/celluloid/actor.rb +35 -30
  5. data/lib/celluloid/autostart.rb +0 -13
  6. data/lib/celluloid/calls.rb +71 -23
  7. data/lib/celluloid/core_ext.rb +3 -14
  8. data/lib/celluloid/cpu_counter.rb +1 -1
  9. data/lib/celluloid/evented_mailbox.rb +82 -0
  10. data/lib/celluloid/fsm.rb +2 -0
  11. data/lib/celluloid/future.rb +4 -4
  12. data/lib/celluloid/internal_pool.rb +11 -8
  13. data/lib/celluloid/legacy.rb +14 -13
  14. data/lib/celluloid/logging/incident_logger.rb +2 -2
  15. data/lib/celluloid/mailbox.rb +16 -0
  16. data/lib/celluloid/method.rb +7 -7
  17. data/lib/celluloid/notifications.rb +1 -1
  18. data/lib/celluloid/proxies/abstract_proxy.rb +1 -1
  19. data/lib/celluloid/proxies/actor_proxy.rb +23 -27
  20. data/lib/celluloid/proxies/async_proxy.rb +18 -6
  21. data/lib/celluloid/proxies/block_proxy.rb +29 -0
  22. data/lib/celluloid/proxies/future_proxy.rb +9 -3
  23. data/lib/celluloid/proxies/sync_proxy.rb +31 -0
  24. data/lib/celluloid/receivers.rb +1 -1
  25. data/lib/celluloid/responses.rb +13 -1
  26. data/lib/celluloid/stack_dump.rb +8 -5
  27. data/lib/celluloid/supervision_group.rb +6 -4
  28. data/lib/celluloid/tasks.rb +63 -2
  29. data/lib/celluloid/tasks/task_fiber.rb +6 -46
  30. data/lib/celluloid/tasks/task_thread.rb +8 -44
  31. data/lib/celluloid/thread.rb +82 -0
  32. data/lib/celluloid/thread_handle.rb +3 -2
  33. data/lib/celluloid/version.rb +1 -1
  34. data/spec/support/actor_examples.rb +116 -53
  35. data/spec/support/example_actor_class.rb +7 -1
  36. data/spec/support/mailbox_examples.rb +29 -3
  37. data/spec/support/task_examples.rb +11 -9
  38. metadata +21 -29
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e34a9a2d8dc0a227e68e1d8e5a7e4de3a6a99a5a
4
+ data.tar.gz: 784898577b1163ff5a7756bd8fb4558e105b075c
5
+ SHA512:
6
+ metadata.gz: e1af2a80fa4944959773aac6b1b3c800d28a64810264e6e08b1d794ec46d40752efd8d144f7c63715acd40e8a5a9576aedc3bad6c8a59a7e4b336c0c37585373
7
+ data.tar.gz: 0215cc3ab5bb87b222c9483563c4a4c89aac8ec78f6361715cb3dd2088a4908860aafaed8ec4e519f973ba29bbdaede4722973a0c4be3e177b42997aad5401d6
data/README.md CHANGED
@@ -2,7 +2,6 @@
2
2
  =========
3
3
  [![Gem Version](https://badge.fury.io/rb/celluloid.png)](http://rubygems.org/gems/celluloid)
4
4
  [![Build Status](https://secure.travis-ci.org/celluloid/celluloid.png?branch=master)](http://travis-ci.org/celluloid/celluloid)
5
- [![Dependency Status](https://gemnasium.com/celluloid/celluloid.png)](https://gemnasium.com/celluloid/celluloid)
6
5
  [![Code Climate](https://codeclimate.com/github/celluloid/celluloid.png)](https://codeclimate.com/github/celluloid/celluloid)
7
6
  [![Coverage Status](https://coveralls.io/repos/celluloid/celluloid/badge.png?branch=master)](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?
@@ -25,6 +25,11 @@ module Celluloid
25
25
  !!Thread.current[:celluloid_actor]
26
26
  end
27
27
 
28
+ # Retrieve the mailbox for the current thread or lazily initialize it
29
+ def mailbox
30
+ Thread.current[:celluloid_mailbox] ||= Celluloid::Mailbox.new
31
+ end
32
+
28
33
  # Generate a Universally Unique Identifier
29
34
  def uuid
30
35
  UUID.generate
@@ -61,13 +66,33 @@ module Celluloid
61
66
  # Launch default services
62
67
  # FIXME: We should set up the supervision hierarchy here
63
68
  def boot
69
+ internal_pool.reset
64
70
  Celluloid::Notifications::Fanout.supervise_as :notifications_fanout
65
71
  Celluloid::IncidentReporter.supervise_as :default_incident_reporter, STDERR
66
72
  end
67
73
 
74
+ def register_shutdown
75
+ return if @shutdown_registered
76
+ # Terminate all actors at exit
77
+ at_exit do
78
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == "ruby" && RUBY_VERSION >= "1.9"
79
+ # workaround for MRI bug losing exit status in at_exit block
80
+ # http://bugs.ruby-lang.org/issues/5218
81
+ exit_status = $!.status if $!.is_a?(SystemExit)
82
+ Celluloid.shutdown
83
+ exit exit_status if exit_status
84
+ else
85
+ Celluloid.shutdown
86
+ end
87
+ end
88
+ @shutdown_registered = true
89
+ end
90
+
68
91
  # Shut down all running actors
69
92
  def shutdown
70
93
  Timeout.timeout(shutdown_timeout) do
94
+ internal_pool.shutdown
95
+
71
96
  actors = Actor.all
72
97
  Logger.debug "Terminating #{actors.size} actors..." if actors.size > 0
73
98
 
@@ -75,14 +100,14 @@ module Celluloid
75
100
  Supervisor.root.terminate if Supervisor.root
76
101
 
77
102
  # Actors cannot self-terminate, you must do it for them
78
- Actor.all.each do |actor|
103
+ actors.each do |actor|
79
104
  begin
80
105
  actor.terminate!
81
106
  rescue DeadActorError, MailboxError
82
107
  end
83
108
  end
84
109
 
85
- Actor.all.each do |actor|
110
+ actors.each do |actor|
86
111
  begin
87
112
  Actor.join(actor)
88
113
  rescue DeadActorError, MailboxError
@@ -91,7 +116,7 @@ module Celluloid
91
116
 
92
117
  Logger.debug "Shutdown completed cleanly"
93
118
  end
94
- rescue Timeout::Error => ex
119
+ rescue Timeout::Error
95
120
  Logger.error("Couldn't cleanly terminate all actors in #{shutdown_timeout} seconds!")
96
121
  end
97
122
  end
@@ -174,13 +199,9 @@ module Celluloid
174
199
  # Define the mailbox class for this class
175
200
  def mailbox_class(klass = nil)
176
201
  if klass
177
- @mailbox_class = klass
178
- elsif defined?(@mailbox_class)
179
- @mailbox_class
180
- elsif superclass.respond_to? :mailbox_class
181
- superclass.mailbox_class
202
+ mailbox.class = klass
182
203
  else
183
- Celluloid::Mailbox
204
+ mailbox.class
184
205
  end
185
206
  end
186
207
 
@@ -213,7 +234,7 @@ module Celluloid
213
234
  def exclusive(*methods)
214
235
  if methods.empty?
215
236
  @exclusive_methods = :all
216
- elsif @exclusive_methods != :all
237
+ elsif !defined?(@exclusive_methods) || @exclusive_methods != :all
217
238
  @exclusive_methods ||= Set.new
218
239
  @exclusive_methods.merge methods.map(&:to_sym)
219
240
  end
@@ -221,24 +242,53 @@ module Celluloid
221
242
 
222
243
  # Mark methods as running blocks on the receiver
223
244
  def execute_block_on_receiver(*methods)
224
- # A noop method in preparation
225
- # See https://github.com/celluloid/celluloid/pull/55
245
+ receiver_block_executions.merge methods.map(&:to_sym)
246
+ end
247
+
248
+ def receiver_block_executions
249
+ @receiver_block_executions ||= Set.new([:after, :every, :receive])
226
250
  end
227
251
 
228
252
  # Configuration options for Actor#new
229
253
  def actor_options
230
254
  {
231
- :mailbox => mailbox_class.new,
255
+ :mailbox => mailbox.build,
232
256
  :proxy_class => proxy_class,
233
257
  :task_class => task_class,
234
258
  :exit_handler => exit_handler,
235
- :exclusive_methods => defined?(@exclusive_methods) ? @exclusive_methods : nil
259
+ :exclusive_methods => defined?(@exclusive_methods) ? @exclusive_methods : nil,
260
+ :receiver_block_executions => receiver_block_executions
236
261
  }
237
262
  end
238
263
 
239
264
  def ===(other)
240
265
  other.kind_of? self
241
266
  end
267
+
268
+ def mailbox
269
+ @mailbox_factory ||= MailboxFactory.new(self)
270
+ end
271
+
272
+ class MailboxFactory
273
+ attr_accessor :class, :max_size
274
+
275
+ def initialize(actor)
276
+ @actor = actor
277
+ @class = nil
278
+ @max_size = nil
279
+ end
280
+
281
+ def build
282
+ mailbox = mailbox_class.new
283
+ mailbox.max_size = @max_size
284
+ mailbox
285
+ end
286
+
287
+ private
288
+ def mailbox_class
289
+ @class || (@actor.superclass.respond_to?(:mailbox_class) && @actor.superclass.mailbox_class) || Celluloid::Mailbox
290
+ end
291
+ end
242
292
  end
243
293
 
244
294
  # These are methods we don't want added to the Celluloid singleton but to be
@@ -265,6 +315,16 @@ module Celluloid
265
315
  @celluloid_owner != Thread.current[:celluloid_actor]
266
316
  end
267
317
 
318
+ def tap
319
+ yield current_actor
320
+ current_actor
321
+ end
322
+
323
+ # Obtain the name of the current actor
324
+ def name
325
+ Actor.name
326
+ end
327
+
268
328
  def inspect
269
329
  str = "#<"
270
330
 
@@ -291,7 +351,7 @@ module Celluloid
291
351
  # directly inside of all classes that include Celluloid
292
352
  #
293
353
 
294
- # Raise an exception in caller context, but stay running
354
+ # Raise an exception in sender context, but stay running
295
355
  def abort(cause)
296
356
  cause = case cause
297
357
  when String then RuntimeError.new(cause)
@@ -326,11 +386,6 @@ module Celluloid
326
386
  Thread.current[:celluloid_chain_id]
327
387
  end
328
388
 
329
- # Obtain the name of the current actor
330
- def name
331
- Actor.name
332
- end
333
-
334
389
  # Obtain the running tasks for this actor
335
390
  def tasks
336
391
  Thread.current[:celluloid_actor].tasks.to_a
@@ -377,7 +432,7 @@ module Celluloid
377
432
  if actor
378
433
  actor.receive(timeout, &block)
379
434
  else
380
- Thread.mailbox.receive(timeout, &block)
435
+ Celluloid.mailbox.receive(timeout, &block)
381
436
  end
382
437
  end
383
438
 
@@ -414,7 +469,7 @@ module Celluloid
414
469
  end
415
470
 
416
471
  # Perform a blocking or computationally intensive action inside an
417
- # asynchronous thread pool, allowing the caller to continue processing other
472
+ # asynchronous thread pool, allowing the sender to continue processing other
418
473
  # messages in its mailbox in the meantime
419
474
  def defer(&block)
420
475
  # This implementation relies on the present implementation of
@@ -424,20 +479,12 @@ module Celluloid
424
479
 
425
480
  # Handle async calls within an actor itself
426
481
  def async(meth = nil, *args, &block)
427
- if meth
428
- Actor.async Thread.current[:celluloid_actor].mailbox, meth, *args, &block
429
- else
430
- Thread.current[:celluloid_actor].proxy.async
431
- end
482
+ Thread.current[:celluloid_actor].proxy.async meth, *args, &block
432
483
  end
433
484
 
434
485
  # Handle calls to future within an actor itself
435
486
  def future(meth = nil, *args, &block)
436
- if meth
437
- Actor.future Thread.current[:celluloid_actor].mailbox, meth, *args, &block
438
- else
439
- Thread.current[:celluloid_actor].proxy.future
440
- end
487
+ Thread.current[:celluloid_actor].proxy.future meth, *args, &block
441
488
  end
442
489
  end
443
490
 
@@ -445,6 +492,7 @@ require 'celluloid/version'
445
492
 
446
493
  require 'celluloid/calls'
447
494
  require 'celluloid/condition'
495
+ require 'celluloid/thread'
448
496
  require 'celluloid/core_ext'
449
497
  require 'celluloid/cpu_counter'
450
498
  require 'celluloid/fiber'
@@ -453,6 +501,7 @@ require 'celluloid/internal_pool'
453
501
  require 'celluloid/links'
454
502
  require 'celluloid/logger'
455
503
  require 'celluloid/mailbox'
504
+ require 'celluloid/evented_mailbox'
456
505
  require 'celluloid/method'
457
506
  require 'celluloid/receivers'
458
507
  require 'celluloid/registry'
@@ -465,9 +514,11 @@ require 'celluloid/thread_handle'
465
514
  require 'celluloid/uuid'
466
515
 
467
516
  require 'celluloid/proxies/abstract_proxy'
517
+ require 'celluloid/proxies/sync_proxy'
468
518
  require 'celluloid/proxies/actor_proxy'
469
519
  require 'celluloid/proxies/async_proxy'
470
520
  require 'celluloid/proxies/future_proxy'
521
+ require 'celluloid/proxies/block_proxy'
471
522
 
472
523
  require 'celluloid/actor'
473
524
  require 'celluloid/future'
@@ -483,3 +534,4 @@ require 'celluloid/legacy' unless defined?(CELLULOID_FUTURE)
483
534
  Celluloid.task_class = Celluloid::TaskFiber
484
535
  Celluloid.logger = Logger.new(STDERR)
485
536
  Celluloid.shutdown_timeout = 10
537
+ Celluloid.register_shutdown
@@ -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 caller made an error, not the current actor
13
+ # The sender made an error, not the current actor
14
14
  class AbortError < StandardError
15
15
  attr_reader :cause
16
16
 
@@ -27,7 +27,7 @@ module Celluloid
27
27
  # normal Ruby objects wrapped in threads which communicate with asynchronous
28
28
  # messages.
29
29
  class Actor
30
- attr_reader :subject, :proxy, :tasks, :links, :mailbox, :thread, :name
30
+ attr_reader :subject, :proxy, :tasks, :links, :mailbox, :thread, :name, :locals
31
31
 
32
32
  class << self
33
33
  extend Forwardable
@@ -58,42 +58,29 @@ 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
- call = SyncCall.new(Thread.mailbox, meth, args, block)
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
- begin
75
- mailbox << AsyncCall.new(meth, args, block)
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
- future = Future.new
87
- future.execute(mailbox, meth, args, block)
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
- actor = t[:celluloid_actor]
96
- actors << actor.proxy if actor and actor.respond_to?(:proxy)
81
+ next unless t.celluloid?
82
+ next if t.task
83
+ actors << t.actor.proxy if t.actor && t.actor.respond_to?(:proxy)
97
84
  end
98
85
  actors
99
86
  end
@@ -142,8 +129,8 @@ module Celluloid
142
129
  end
143
130
 
144
131
  # Wait for an actor to terminate
145
- def join(actor)
146
- actor.thread.join
132
+ def join(actor, timeout = nil)
133
+ actor.thread.join(timeout)
147
134
  actor
148
135
  end
149
136
  end
@@ -154,6 +141,7 @@ module Celluloid
154
141
  @mailbox = options[:mailbox] || Mailbox.new
155
142
  @exit_handler = options[:exit_handler]
156
143
  @exclusives = options[:exclusive_methods]
144
+ @receiver_block_executions = options[:receiver_block_executions]
157
145
  @task_class = options[:task_class] || Celluloid.task_class
158
146
 
159
147
  @tasks = TaskSet.new
@@ -164,10 +152,10 @@ module Celluloid
164
152
  @running = true
165
153
  @exclusive = false
166
154
  @name = nil
155
+ @locals = {}
167
156
 
168
157
  @thread = ThreadHandle.new do
169
- Thread.current[:celluloid_actor] = self
170
- Thread.current[:celluloid_mailbox] = @mailbox
158
+ setup_thread
171
159
  run
172
160
  end
173
161
 
@@ -175,6 +163,11 @@ module Celluloid
175
163
  @subject.instance_variable_set(OWNER_IVAR, self)
176
164
  end
177
165
 
166
+ def setup_thread
167
+ Thread.current[:celluloid_actor] = self
168
+ Thread.current[:celluloid_mailbox] = @mailbox
169
+ end
170
+
178
171
  # Run the actor loop
179
172
  def run
180
173
  begin
@@ -323,8 +316,20 @@ module Celluloid
323
316
  when SystemEvent
324
317
  handle_system_event message
325
318
  when Call
326
- task(:message_handler, message.method) { message.dispatch(@subject) }
327
- when Response
319
+ task(:call, message.method) {
320
+ if @receiver_block_executions && meth = message.method
321
+ if meth == :__send__
322
+ meth = message.arguments.first
323
+ end
324
+ if @receiver_block_executions.include?(meth.to_sym)
325
+ message.execute_block_on_receiver
326
+ end
327
+ end
328
+ message.dispatch(@subject)
329
+ }
330
+ when BlockCall
331
+ task(:invoke_block) { message.dispatch }
332
+ when BlockResponse, Response
328
333
  message.dispatch
329
334
  else
330
335
  @receivers.handle_message(message)
@@ -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
@@ -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, @block = method, arguments, block
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
- obj.public_send(@method, *@arguments, &@block)
24
+ _block = @block && @block.to_proc
25
+ obj.public_send(@method, *@arguments, &_block)
12
26
  rescue NoMethodError => ex
13
- # Abort if the caller made a mistake
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 caller made a mistake
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 :caller, :task, :chain_id
55
+ attr_reader :sender, :task, :chain_id
52
56
 
53
- def initialize(caller, method, arguments = [], block = nil, task = Thread.current[:celluloid_task], chain_id = Thread.current[:celluloid_chain_id])
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
- @caller = caller
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 caller
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 caller
71
- # It should crash the caller, but the exception isn't reraised
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
- @caller << message
88
+ @sender << message
85
89
  rescue MailboxError
86
- # It's possible the caller exited or crashed before we could send a
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 caller made a mistake
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