celluloid 0.13.0 → 0.14.0.pre

Sign up to get free protection for your applications and to get access to all the features.
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