celluloid 0.15.2 → 0.16.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +20 -0
  3. data/README.md +29 -2
  4. data/lib/celluloid.rb +68 -73
  5. data/lib/celluloid/actor.rb +69 -123
  6. data/lib/celluloid/actor_system.rb +107 -0
  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 +2 -0
  11. data/lib/celluloid/evented_mailbox.rb +2 -1
  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 +0 -3
  16. data/lib/celluloid/logger.rb +30 -0
  17. data/lib/celluloid/logging/incident_logger.rb +1 -1
  18. data/lib/celluloid/mailbox.rb +19 -18
  19. data/lib/celluloid/method.rb +8 -0
  20. data/lib/celluloid/pool_manager.rb +1 -1
  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 +1 -0
  27. data/lib/celluloid/registry.rb +1 -8
  28. data/lib/celluloid/stack_dump.rb +34 -11
  29. data/lib/celluloid/supervision_group.rb +26 -14
  30. data/lib/celluloid/tasks.rb +6 -9
  31. data/lib/celluloid/tasks/task_fiber.rb +6 -0
  32. data/lib/celluloid/tasks/task_thread.rb +2 -1
  33. data/lib/celluloid/thread_handle.rb +2 -2
  34. data/spec/celluloid/actor_spec.rb +1 -1
  35. data/spec/celluloid/actor_system_spec.rb +69 -0
  36. data/spec/celluloid/block_spec.rb +1 -1
  37. data/spec/celluloid/calls_spec.rb +1 -1
  38. data/spec/celluloid/condition_spec.rb +14 -3
  39. data/spec/celluloid/cpu_counter_spec.rb +9 -0
  40. data/spec/celluloid/fsm_spec.rb +1 -1
  41. data/spec/celluloid/future_spec.rb +1 -1
  42. data/spec/celluloid/notifications_spec.rb +1 -1
  43. data/spec/celluloid/pool_spec.rb +1 -1
  44. data/spec/celluloid/probe_spec.rb +121 -0
  45. data/spec/celluloid/registry_spec.rb +6 -6
  46. data/spec/celluloid/stack_dump_spec.rb +37 -8
  47. data/spec/celluloid/supervision_group_spec.rb +7 -1
  48. data/spec/celluloid/supervisor_spec.rb +12 -1
  49. data/spec/celluloid/tasks/task_fiber_spec.rb +1 -1
  50. data/spec/celluloid/tasks/task_thread_spec.rb +1 -1
  51. data/spec/celluloid/thread_handle_spec.rb +7 -3
  52. data/spec/spec_helper.rb +20 -7
  53. data/spec/support/actor_examples.rb +33 -15
  54. data/spec/support/mailbox_examples.rb +9 -3
  55. data/spec/support/task_examples.rb +2 -0
  56. metadata +32 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f22a9c7d89b293484d7dcbe03cda32d7055ee42a
4
- data.tar.gz: a13abc0b96f0e4931f6ff20457f9665282a4d08b
3
+ metadata.gz: 3f9e4bf5d8e26e99c5321bc02c61cafa9de48600
4
+ data.tar.gz: b239f25215d8c3ca0c9c27cd3e08954fa62ee35c
5
5
  SHA512:
6
- metadata.gz: fba64fd21b7f58cf3fab69cdcfe889b4b95478a5bcad61557b1376e3965bc73583eeaf215be7003e886cc0fdd6a239aa79dd3738cd6ad831ce1c114435da4ff0
7
- data.tar.gz: fea6248e5f4e1931485673a458182ca86f380820b2e18acd7d90618203f8c6a193bdf33213161d397153dd43485bb4e1907ff65fb9efd14cc7c6a70cfcb4c309
6
+ metadata.gz: be0d373d83500400c1135176382097f8bdffeb378fbce48f95852195975984a626221292ade6182ba84cc5a9ca06fa0849461d28c68e9adea33c129396ab39a3
7
+ data.tar.gz: 6f6cd39aec05a5b8f4b461ad88cd6c960a37d5832ca36ee5f633bf0e3229b294fb714668dcf87d843e162749507c301d14d32d2ae2d344c726b3f55346f9e6c8
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011-2014 Tony Arcieri
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -94,6 +94,28 @@ The following API documentation is also available:
94
94
  * [Celluloid class methods](http://rubydoc.info/gems/celluloid/Celluloid/ClassMethods)
95
95
  * [All Celluloid classes](http://rubydoc.info/gems/celluloid/index)
96
96
 
97
+ Related Projects
98
+ ----------------
99
+
100
+ Celluloid is the parent project of a related ecosystem of other projects. If you
101
+ like Celluloid we definitely recommend you check them out:
102
+
103
+ * [Celluloid::IO][celluloid-io]: "Evented" IO support for Celluloid actors
104
+ * [Celluloid::ZMQ][celluloid-zmq]: "Evented" 0MQ support for Celluloid actors
105
+ * [DCell][dcell]: The Celluloid actor protocol distributed over 0MQ
106
+ * [Reel][reel]: An "evented" web server based on Celluloid::IO
107
+ * [Lattice][lattice]: A concurrent realtime web framework based on Celluloid::IO
108
+ * [nio4r][nio4r]: "New IO for Ruby": high performance IO selectors
109
+ * [Timers][timers]: A generic Ruby timer library for event-based systems
110
+
111
+ [celluloid-io]: https://github.com/celluloid/celluloid-io/
112
+ [celluloid-zmq]: https://github.com/celluloid/celluloid-zmq/
113
+ [dcell]: https://github.com/celluloid/dcell/
114
+ [reel]: https://github.com/celluloid/reel/
115
+ [lattice]: https://github.com/celluloid/lattice/
116
+ [nio4r]: https://github.com/celluloid/nio4r/
117
+ [timers]: https://github.com/celluloid/timers/
118
+
97
119
  Installation
98
120
  ------------
99
121
 
@@ -131,7 +153,8 @@ Celluloid requires Ruby 1.9 mode on all interpreters.
131
153
  Additional Reading
132
154
  ------------------
133
155
 
134
- * [Concurrent Object-Oriented Programming in Python with ATOM](http://python.org/workshops/1997-10/proceedings/atom/):
156
+ * [Concurrent Object-Oriented Programming in Python with
157
+ ATOM](http://citeseerx.ist.psu.edu/viewdoc/download;jsessionid=11A3EACE78AAFF6D6D62A64118AFCA7C?doi=10.1.1.47.5074&rep=rep1&type=pdf):
135
158
  a similar system to Celluloid written in Python
136
159
 
137
160
  Contributing to Celluloid
@@ -145,5 +168,9 @@ Contributing to Celluloid
145
168
  License
146
169
  -------
147
170
 
148
- Copyright (c) 2013 Tony Arcieri. Distributed under the MIT License. See
171
+ Copyright (c) 2011-2014 Tony Arcieri. Distributed under the MIT License. See
149
172
  LICENSE.txt for further details.
173
+
174
+
175
+ [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/celluloid/celluloid/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
176
+
@@ -3,25 +3,32 @@ require 'thread'
3
3
  require 'timeout'
4
4
  require 'set'
5
5
 
6
- if defined?(JRUBY_VERSION) && JRUBY_VERSION == "1.7.3"
7
- raise "Celluloid is broken on JRuby 1.7.3. Please upgrade to 1.7.4+"
8
- end
9
-
10
6
  module Celluloid
11
- VERSION = '0.15.2'
12
- Error = Class.new StandardError
7
+ # Expose all instance methods as singleton methods
8
+ extend self
9
+
10
+ VERSION = '0.16.0.pre'
13
11
 
14
- extend self # expose all instance methods as singleton methods
12
+ # Linking times out after 5 seconds
13
+ LINKING_TIMEOUT = 5
15
14
 
16
15
  # Warning message added to Celluloid objects accessed outside their actors
17
16
  BARE_OBJECT_WARNING_MESSAGE = "WARNING: BARE CELLULOID OBJECT "
18
17
 
19
18
  class << self
20
- attr_accessor :internal_pool # Internal thread pool
19
+ attr_writer :actor_system # Default Actor System
21
20
  attr_accessor :logger # Thread-safe logger class
22
21
  attr_accessor :task_class # Default task type to use
23
22
  attr_accessor :shutdown_timeout # How long actors have to terminate
24
23
 
24
+ def actor_system
25
+ if Thread.current.celluloid?
26
+ Thread.current[:celluloid_actor_system] or raise Error, "actor system not running"
27
+ else
28
+ Thread.current[:celluloid_actor_system] || @actor_system or raise Error, "Celluloid is not yet started; use Celluloid.boot"
29
+ end
30
+ end
31
+
25
32
  def included(klass)
26
33
  klass.send :extend, ClassMethods
27
34
  klass.send :include, InstanceMethods
@@ -29,19 +36,29 @@ module Celluloid
29
36
  klass.send :extend, Properties
30
37
 
31
38
  klass.property :mailbox_class, :default => Celluloid::Mailbox
32
- klass.property :proxy_class, :default => Celluloid::ActorProxy
39
+ klass.property :proxy_class, :default => Celluloid::CellProxy
33
40
  klass.property :task_class, :default => Celluloid.task_class
34
41
  klass.property :mailbox_size
35
42
 
43
+ klass.property :exclusive_actor, :default => false
44
+ klass.property :exclusive_methods, :multi => true
36
45
  klass.property :execute_block_on_receiver,
37
46
  :default => [:after, :every, :receive],
38
47
  :multi => true
39
48
 
40
49
  klass.property :finalizer
41
- klass.property :exit_handler
50
+ klass.property :exit_handler_name
42
51
 
43
52
  klass.send(:define_singleton_method, :trap_exit) do |*args|
44
- exit_handler(*args)
53
+ exit_handler_name(*args)
54
+ end
55
+
56
+ klass.send(:define_singleton_method, :exclusive) do |*args|
57
+ if args.any?
58
+ exclusive_methods(*exclusive_methods, *args)
59
+ else
60
+ exclusive_actor true
61
+ end
45
62
  end
46
63
  end
47
64
 
@@ -69,7 +86,7 @@ module Celluloid
69
86
 
70
87
  # Perform a stack dump of all actors to the given output object
71
88
  def stack_dump(output = STDERR)
72
- Celluloid::StackDump.new.dump(output)
89
+ actor_system.stack_dump.print(output)
73
90
  end
74
91
  alias_method :dump, :stack_dump
75
92
 
@@ -106,18 +123,15 @@ module Celluloid
106
123
  end
107
124
 
108
125
  def init
109
- self.internal_pool = InternalPool.new
126
+ @actor_system = ActorSystem.new
110
127
  end
111
128
 
112
- # Launch default services
113
- # FIXME: We should set up the supervision hierarchy here
114
129
  def start
115
- Celluloid::Notifications::Fanout.supervise_as :notifications_fanout
116
- Celluloid::IncidentReporter.supervise_as :default_incident_reporter, STDERR
130
+ actor_system.start
117
131
  end
118
132
 
119
133
  def running?
120
- internal_pool
134
+ actor_system && actor_system.running?
121
135
  end
122
136
 
123
137
  def register_shutdown
@@ -139,41 +153,7 @@ module Celluloid
139
153
 
140
154
  # Shut down all running actors
141
155
  def shutdown
142
- actors = Actor.all
143
-
144
- Timeout.timeout(shutdown_timeout) do
145
- internal_pool.shutdown
146
-
147
- Logger.debug "Terminating #{actors.size} #{(actors.size > 1) ? 'actors' : 'actor'}..." if actors.size > 0
148
-
149
- # Attempt to shut down the supervision tree, if available
150
- Supervisor.root.terminate if Supervisor.root
151
-
152
- # Actors cannot self-terminate, you must do it for them
153
- actors.each do |actor|
154
- begin
155
- actor.terminate!
156
- rescue DeadActorError
157
- end
158
- end
159
-
160
- actors.each do |actor|
161
- begin
162
- Actor.join(actor)
163
- rescue DeadActorError
164
- end
165
- end
166
- end
167
- rescue Timeout::Error
168
- Logger.error("Couldn't cleanly terminate all actors in #{shutdown_timeout} seconds!")
169
- actors.each do |actor|
170
- begin
171
- Actor.kill(actor)
172
- rescue DeadActorError, MailboxDead
173
- end
174
- end
175
- ensure
176
- internal_pool.kill
156
+ actor_system.shutdown
177
157
  end
178
158
 
179
159
  def version
@@ -185,7 +165,7 @@ module Celluloid
185
165
  module ClassMethods
186
166
  # Create a new actor
187
167
  def new(*args, &block)
188
- proxy = Actor.new(allocate, actor_options).proxy
168
+ proxy = Cell.new(allocate, behavior_options, actor_options).proxy
189
169
  proxy._send_(:initialize, *args, &block)
190
170
  proxy
191
171
  end
@@ -195,7 +175,7 @@ module Celluloid
195
175
  def new_link(*args, &block)
196
176
  raise NotActorError, "can't link outside actor context" unless Celluloid.actor?
197
177
 
198
- proxy = Actor.new(allocate, actor_options).proxy
178
+ proxy = Cell.new(allocate, behavior_options, actor_options).proxy
199
179
  Actor.link(proxy)
200
180
  proxy._send_(:initialize, *args, &block)
201
181
  proxy
@@ -233,26 +213,28 @@ module Celluloid
233
213
  Actor.join(new(*args, &block))
234
214
  end
235
215
 
236
- # Mark methods as running exclusively
237
- def exclusive(*methods)
238
- if methods.empty?
239
- @exclusive_methods = :all
240
- elsif !defined?(@exclusive_methods) || @exclusive_methods != :all
241
- @exclusive_methods ||= Set.new
242
- @exclusive_methods.merge methods.map(&:to_sym)
243
- end
216
+ def actor_system
217
+ Celluloid.actor_system
244
218
  end
245
219
 
246
220
  # Configuration options for Actor#new
247
221
  def actor_options
248
222
  {
223
+ :actor_system => actor_system,
249
224
  :mailbox_class => mailbox_class,
250
225
  :mailbox_size => mailbox_size,
251
- :proxy_class => proxy_class,
252
226
  :task_class => task_class,
253
- :exit_handler => exit_handler,
254
- :exclusive_methods => defined?(@exclusive_methods) ? @exclusive_methods : nil,
255
- :receiver_block_executions => execute_block_on_receiver
227
+ :exclusive => exclusive_actor,
228
+ }
229
+ end
230
+
231
+ def behavior_options
232
+ {
233
+ :proxy_class => proxy_class,
234
+ :exclusive_methods => exclusive_methods,
235
+ :exit_handler_name => exit_handler_name,
236
+ :finalizer => finalizer,
237
+ :receiver_block_executions => execute_block_on_receiver,
256
238
  }
257
239
  end
258
240
 
@@ -291,9 +273,10 @@ module Celluloid
291
273
  end
292
274
 
293
275
  # Obtain the name of the current actor
294
- def name
295
- Actor.name
276
+ def registered_name
277
+ Actor.registered_name
296
278
  end
279
+ alias_method :name, :registered_name
297
280
 
298
281
  def inspect
299
282
  return "..." if Celluloid.detect_recursion
@@ -303,7 +286,7 @@ module Celluloid
303
286
  if leaked?
304
287
  str << Celluloid::BARE_OBJECT_WARNING_MESSAGE
305
288
  else
306
- str << "Celluloid::ActorProxy"
289
+ str << "Celluloid::CellProxy"
307
290
  end
308
291
 
309
292
  str << "(#{self.class}:0x#{object_id.to_s(16)})"
@@ -335,7 +318,7 @@ module Celluloid
335
318
 
336
319
  # Terminate this actor
337
320
  def terminate
338
- Thread.current[:celluloid_actor].proxy.terminate!
321
+ Thread.current[:celluloid_actor].behavior_proxy.terminate!
339
322
  end
340
323
 
341
324
  # Send a signal with the given name to all waiting methods
@@ -458,15 +441,21 @@ module Celluloid
458
441
 
459
442
  # Handle async calls within an actor itself
460
443
  def async(meth = nil, *args, &block)
461
- Thread.current[:celluloid_actor].proxy.async meth, *args, &block
444
+ Thread.current[:celluloid_actor].behavior_proxy.async meth, *args, &block
462
445
  end
463
446
 
464
447
  # Handle calls to future within an actor itself
465
448
  def future(meth = nil, *args, &block)
466
- Thread.current[:celluloid_actor].proxy.future meth, *args, &block
449
+ Thread.current[:celluloid_actor].behavior_proxy.future meth, *args, &block
467
450
  end
468
451
  end
469
452
 
453
+ if defined?(JRUBY_VERSION) && JRUBY_VERSION == "1.7.3"
454
+ raise "Celluloid is broken on JRuby 1.7.3. Please upgrade to 1.7.4+"
455
+ end
456
+
457
+ require 'celluloid/exceptions'
458
+
470
459
  require 'celluloid/calls'
471
460
  require 'celluloid/call_chain'
472
461
  require 'celluloid/condition'
@@ -482,6 +471,7 @@ require 'celluloid/mailbox'
482
471
  require 'celluloid/evented_mailbox'
483
472
  require 'celluloid/method'
484
473
  require 'celluloid/properties'
474
+ require 'celluloid/handlers'
485
475
  require 'celluloid/receivers'
486
476
  require 'celluloid/registry'
487
477
  require 'celluloid/responses'
@@ -495,13 +485,16 @@ require 'celluloid/uuid'
495
485
 
496
486
  require 'celluloid/proxies/abstract_proxy'
497
487
  require 'celluloid/proxies/sync_proxy'
488
+ require 'celluloid/proxies/cell_proxy'
498
489
  require 'celluloid/proxies/actor_proxy'
499
490
  require 'celluloid/proxies/async_proxy'
500
491
  require 'celluloid/proxies/future_proxy'
501
492
  require 'celluloid/proxies/block_proxy'
502
493
 
503
494
  require 'celluloid/actor'
495
+ require 'celluloid/cell'
504
496
  require 'celluloid/future'
497
+ require 'celluloid/actor_system'
505
498
  require 'celluloid/pool_manager'
506
499
  require 'celluloid/supervision_group'
507
500
  require 'celluloid/supervisor'
@@ -510,6 +503,8 @@ require 'celluloid/logging'
510
503
 
511
504
  require 'celluloid/legacy' unless defined?(CELLULOID_FUTURE)
512
505
 
506
+ $CELLULOID_MONITORING = false
507
+
513
508
  # Configure default systemwide settings
514
509
  Celluloid.task_class = Celluloid::TaskFiber
515
510
  Celluloid.logger = Logger.new(STDERR)
@@ -1,56 +1,27 @@
1
1
  require 'timers'
2
2
 
3
3
  module Celluloid
4
- # Don't do Actor-like things outside Actor scope
5
- class NotActorError < Celluloid::Error; end
6
-
7
- # Trying to do something to a dead actor
8
- class DeadActorError < Celluloid::Error; end
9
-
10
- # A timeout occured before the given request could complete
11
- class TimeoutError < Celluloid::Error; end
12
-
13
- # The sender made an error, not the current actor
14
- class AbortError < Celluloid::Error
15
- attr_reader :cause
16
-
17
- def initialize(cause)
18
- @cause = cause
19
- super "caused by #{cause.inspect}: #{cause.to_s}"
20
- end
21
- end
22
-
23
- LINKING_TIMEOUT = 5 # linking times out after 5 seconds
24
- OWNER_IVAR = :@celluloid_owner # reference to owning actor
25
-
26
4
  # Actors are Celluloid's concurrency primitive. They're implemented as
27
5
  # normal Ruby objects wrapped in threads which communicate with asynchronous
28
6
  # messages.
29
7
  class Actor
30
- attr_reader :subject, :proxy, :tasks, :links, :mailbox, :thread, :name
8
+ attr_reader :behavior, :proxy, :tasks, :links, :mailbox, :thread, :name, :timers
9
+ attr_writer :exit_handler
31
10
 
32
11
  class << self
33
12
  extend Forwardable
34
13
 
35
- def_delegators "Celluloid::Registry.root", :[], :[]=
36
-
37
- def registered
38
- Registry.root.names
39
- end
40
-
41
- def clear_registry
42
- Registry.root.clear
43
- end
14
+ def_delegators "Celluloid.actor_system", :[], :[]=, :delete, :registered, :clear_registry
44
15
 
45
16
  # Obtain the current actor
46
17
  def current
47
18
  actor = Thread.current[:celluloid_actor]
48
19
  raise NotActorError, "not in actor scope" unless actor
49
- actor.proxy
20
+ actor.behavior_proxy
50
21
  end
51
22
 
52
23
  # Obtain the name of the current actor
53
- def name
24
+ def registered_name
54
25
  actor = Thread.current[:celluloid_actor]
55
26
  raise NotActorError, "not in actor scope" unless actor
56
27
  actor.name
@@ -76,12 +47,7 @@ module Celluloid
76
47
 
77
48
  # Obtain all running actors in the system
78
49
  def all
79
- actors = []
80
- Celluloid.internal_pool.each do |t|
81
- next unless t.role == :actor
82
- actors << t.actor.proxy if t.actor && t.actor.respond_to?(:proxy)
83
- end
84
- actors
50
+ Celluloid.actor_system.running
85
51
  end
86
52
 
87
53
  # Watch for exit events from another actor
@@ -131,34 +97,44 @@ module Celluloid
131
97
  end
132
98
  end
133
99
 
134
- # Wrap the given subject with an Actor
135
- def initialize(subject, options = {})
136
- @subject = subject
100
+ def initialize(behavior, options)
101
+ @behavior = behavior
137
102
 
103
+ @actor_system = options.fetch(:actor_system)
138
104
  @mailbox = options.fetch(:mailbox_class, Mailbox).new
139
105
  @mailbox.max_size = options.fetch(:mailbox_size, nil)
140
106
 
141
107
  @task_class = options[:task_class] || Celluloid.task_class
142
- @exit_handler = options[:exit_handler]
143
- @exclusives = options[:exclusive_methods]
144
- @receiver_block_executions = options[:receiver_block_executions]
108
+ @exit_handler = method(:default_exit_handler)
109
+ @exclusive = options.fetch(:exclusive, false)
145
110
 
146
111
  @tasks = TaskSet.new
147
112
  @links = Links.new
148
113
  @signals = Signals.new
149
114
  @receivers = Receivers.new
150
115
  @timers = Timers.new
151
- @running = true
152
- @exclusive = false
116
+ @handlers = Handlers.new
117
+ @running = false
153
118
  @name = nil
154
119
 
155
- @thread = ThreadHandle.new(:actor) do
120
+ handle(SystemEvent) do |message|
121
+ handle_system_event message
122
+ end
123
+ end
124
+
125
+ def start
126
+ @running = true
127
+ @thread = ThreadHandle.new(@actor_system, :actor) do
156
128
  setup_thread
157
129
  run
158
130
  end
159
131
 
160
- @proxy = (options[:proxy_class] || ActorProxy).new(self)
161
- @subject.instance_variable_set(OWNER_IVAR, self)
132
+ @proxy = ActorProxy.new(@thread, @mailbox)
133
+ Celluloid::Probe.actor_created(self) if $CELLULOID_MONITORING
134
+ end
135
+
136
+ def behavior_proxy
137
+ @behavior.proxy
162
138
  end
163
139
 
164
140
  def setup_thread
@@ -168,18 +144,16 @@ module Celluloid
168
144
 
169
145
  # Run the actor loop
170
146
  def run
171
- begin
172
- while @running
173
- if message = @mailbox.receive(timeout_interval)
174
- handle_message message
175
- else
176
- # No message indicates a timeout
177
- @timers.fire
178
- @receivers.fire_timers
179
- end
147
+ while @running
148
+ begin
149
+ message = @mailbox.receive(timeout_interval)
150
+ handle_message message
151
+ rescue TimeoutError
152
+ @timers.fire
153
+ @receivers.fire_timers
154
+ rescue MailboxShutdown
155
+ @running = false
180
156
  end
181
- rescue MailboxShutdown
182
- # If the mailbox detects shutdown, exit the actor
183
157
  end
184
158
 
185
159
  shutdown
@@ -208,14 +182,14 @@ module Celluloid
208
182
  msg.type == type
209
183
  end
210
184
 
211
- case message
212
- when LinkingResponse
185
+ if message.instance_of? LinkingResponse
186
+ Celluloid::Probe.actors_linked(self, receiver) if $CELLULOID_MONITORING
213
187
  # We're done!
214
- system_events.each { |ev| handle_system_event(ev) }
188
+ system_events.each { |ev| @mailbox << ev }
215
189
  return
216
- when NilClass
190
+ elsif message.instance_of? NilClass
217
191
  raise TimeoutError, "linking timeout of #{LINKING_TIMEOUT} seconds exceeded"
218
- when SystemEvent
192
+ elsif message.instance_of? SystemEvent
219
193
  # Queue up pending system events to be processed after we've successfully linked
220
194
  system_events << message
221
195
  else raise 'wtf'
@@ -234,6 +208,10 @@ module Celluloid
234
208
  @signals.wait name
235
209
  end
236
210
 
211
+ def handle(*patterns, &block)
212
+ @handlers.handle(*patterns, &block)
213
+ end
214
+
237
215
  # Receive an asynchronous message
238
216
  def receive(timeout = nil, &block)
239
217
  loop do
@@ -304,28 +282,7 @@ module Celluloid
304
282
 
305
283
  # Handle standard low-priority messages
306
284
  def handle_message(message)
307
- case message
308
- when SystemEvent
309
- handle_system_event message
310
- when Call
311
- meth = message.method
312
- if meth == :__send__
313
- meth = message.arguments.first
314
- end
315
- if @receiver_block_executions && meth
316
- if @receiver_block_executions.include?(meth.to_sym)
317
- message.execute_block_on_receiver
318
- end
319
- end
320
-
321
- task(:call, :method_name => meth, :dangerous_suspend => meth == :initialize) {
322
- message.dispatch(@subject)
323
- }
324
- when BlockCall
325
- task(:invoke_block) { message.dispatch }
326
- when BlockResponse, Response
327
- message.dispatch
328
- else
285
+ unless @handlers.handle_message(message)
329
286
  unless @receivers.handle_message(message)
330
287
  Logger.debug "Discarded message (unhandled): #{message}" if $CELLULOID_DEBUG
331
288
  end
@@ -335,17 +292,19 @@ module Celluloid
335
292
 
336
293
  # Handle high-priority system event messages
337
294
  def handle_system_event(event)
338
- case event
339
- when ExitEvent
340
- task(:exit_handler, :method_name => @exit_handler) { handle_exit_event event }
341
- when LinkingRequest
295
+ if event.instance_of? ExitEvent
296
+ handle_exit_event(event)
297
+ elsif event.instance_of? LinkingRequest
342
298
  event.process(links)
343
- when NamingRequest
299
+ elsif event.instance_of? NamingRequest
344
300
  @name = event.name
345
- when TerminationRequest
301
+ Celluloid::Probe.actor_named(self) if $CELLULOID_MONITORING
302
+ elsif event.instance_of? TerminationRequest
346
303
  terminate
347
- when SignalConditionRequest
304
+ elsif event.instance_of? SignalConditionRequest
348
305
  event.call
306
+ else
307
+ Logger.debug "Discarded message (unhandled): #{message}" if $CELLULOID_DEBUG
349
308
  end
350
309
  end
351
310
 
@@ -353,47 +312,34 @@ module Celluloid
353
312
  def handle_exit_event(event)
354
313
  @links.delete event.actor
355
314
 
356
- # Run the exit handler if available
357
- return @subject.send(@exit_handler, event.actor, event.reason) if @exit_handler
315
+ @exit_handler.call(event)
316
+ end
358
317
 
359
- # Reraise exceptions from linked actors
360
- # If no reason is given, actor terminated cleanly
318
+ def default_exit_handler(event)
361
319
  raise event.reason if event.reason
362
320
  end
363
321
 
364
322
  # Handle any exceptions that occur within a running actor
365
323
  def handle_crash(exception)
366
- Logger.crash("#{@subject.class} crashed!", exception)
367
- shutdown ExitEvent.new(@proxy, exception)
324
+ # TODO: add meta info
325
+ Logger.crash("Actor crashed!", exception)
326
+ shutdown ExitEvent.new(behavior_proxy, exception)
368
327
  rescue => ex
369
- Logger.crash("#{@subject.class}: ERROR HANDLER CRASHED!", ex)
328
+ Logger.crash("ERROR HANDLER CRASHED!", ex)
370
329
  end
371
330
 
372
331
  # Handle cleaning up this actor after it exits
373
- def shutdown(exit_event = ExitEvent.new(@proxy))
374
- run_finalizer
332
+ def shutdown(exit_event = ExitEvent.new(behavior_proxy))
333
+ @behavior.shutdown
375
334
  cleanup exit_event
376
335
  ensure
377
336
  Thread.current[:celluloid_actor] = nil
378
337
  Thread.current[:celluloid_mailbox] = nil
379
338
  end
380
339
 
381
- # Run the user-defined finalizer, if one is set
382
- def run_finalizer
383
- finalizer = @subject.class.finalizer
384
- return unless finalizer && @subject.respond_to?(finalizer, true)
385
-
386
- task(:finalizer, :method_name => finalizer, :dangerous_suspend => true) do
387
- begin
388
- @subject.__send__(finalizer)
389
- rescue => ex
390
- Logger.crash("#{@subject.class}#finalize crashed!", ex)
391
- end
392
- end
393
- end
394
-
395
340
  # Clean up after this actor
396
341
  def cleanup(exit_event)
342
+ Celluloid::Probe.actor_died(self) if $CELLULOID_MONITORING
397
343
  @mailbox.shutdown
398
344
  @links.each do |actor|
399
345
  if actor.mailbox.alive?
@@ -401,16 +347,16 @@ module Celluloid
401
347
  end
402
348
  end
403
349
 
404
- tasks.to_a.each { |task| task.terminate }
350
+ tasks.to_a.each(&:terminate)
405
351
  rescue => ex
406
- Logger.crash("#{@subject.class}: CLEANUP CRASHED!", ex)
352
+ # TODO: metadata
353
+ Logger.crash("CLEANUP CRASHED!", ex)
407
354
  end
408
355
 
409
356
  # Run a method inside a task unless it's exclusive
410
357
  def task(task_type, meta = nil)
411
- method_name = meta && meta.fetch(:method_name, nil)
412
358
  @task_class.new(task_type, meta) {
413
- if @exclusives && (@exclusives == :all || (method_name && @exclusives.include?(method_name.to_sym)))
359
+ if @exclusive
414
360
  Celluloid.exclusive { yield }
415
361
  else
416
362
  yield