celluloid 0.15.2 → 0.16.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 (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