celluloid 0.16.0 → 0.17.3

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 (177) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +394 -0
  3. data/LICENSE.txt +1 -1
  4. data/README.md +28 -15
  5. data/culture/CONDUCT.md +28 -0
  6. data/culture/Gemfile +9 -0
  7. data/culture/LICENSE.txt +22 -0
  8. data/culture/README.md +22 -0
  9. data/culture/Rakefile +5 -0
  10. data/culture/SYNC.md +70 -0
  11. data/culture/celluloid-culture.gemspec +18 -0
  12. data/culture/gems/README.md +39 -0
  13. data/culture/gems/dependencies.yml +85 -0
  14. data/culture/gems/loader.rb +101 -0
  15. data/culture/rubocop/README.md +38 -0
  16. data/culture/rubocop/lint.yml +8 -0
  17. data/culture/rubocop/metrics.yml +15 -0
  18. data/culture/rubocop/perf.yml +0 -0
  19. data/culture/rubocop/rubocop.yml +5 -0
  20. data/culture/rubocop/style.yml +57 -0
  21. data/culture/spec/gems_spec.rb +2 -0
  22. data/culture/spec/spec_helper.rb +0 -0
  23. data/culture/spec/sync_spec.rb +2 -0
  24. data/culture/sync.rb +56 -0
  25. data/culture/tasks/rspec.rake +5 -0
  26. data/culture/tasks/rubocop.rake +2 -0
  27. data/examples/basic_usage.rb +49 -0
  28. data/examples/futures.rb +38 -0
  29. data/examples/ring.rb +61 -0
  30. data/examples/simple_pmap.rb +14 -0
  31. data/examples/stack.rb +47 -0
  32. data/examples/timers.rb +72 -0
  33. data/lib/celluloid/actor/manager.rb +7 -0
  34. data/lib/celluloid/actor/system.rb +163 -0
  35. data/lib/celluloid/actor.rb +53 -71
  36. data/lib/celluloid/autostart.rb +1 -1
  37. data/lib/celluloid/backported.rb +2 -0
  38. data/lib/celluloid/call/async.rb +16 -0
  39. data/lib/celluloid/call/block.rb +22 -0
  40. data/lib/celluloid/call/sync.rb +70 -0
  41. data/lib/celluloid/calls.rb +24 -114
  42. data/lib/celluloid/cell.rb +32 -20
  43. data/lib/celluloid/condition.rb +5 -6
  44. data/lib/celluloid/core_ext.rb +1 -1
  45. data/lib/celluloid/current.rb +2 -0
  46. data/lib/celluloid/debug.rb +1 -0
  47. data/lib/celluloid/deprecate.rb +21 -0
  48. data/lib/celluloid/exceptions.rb +22 -16
  49. data/lib/celluloid/fiber.rb +3 -3
  50. data/lib/celluloid/future.rb +46 -8
  51. data/lib/celluloid/group/pool.rb +125 -0
  52. data/lib/celluloid/group/spawner.rb +68 -0
  53. data/lib/celluloid/group.rb +61 -0
  54. data/lib/celluloid/logging.rb +5 -5
  55. data/lib/celluloid/mailbox/evented.rb +74 -0
  56. data/lib/celluloid/mailbox.rb +15 -14
  57. data/lib/celluloid/managed.rb +3 -0
  58. data/lib/celluloid/notices.rb +15 -0
  59. data/lib/celluloid/proxies.rb +11 -0
  60. data/lib/celluloid/proxy/abstract.rb +50 -0
  61. data/lib/celluloid/proxy/actor.rb +37 -0
  62. data/lib/celluloid/proxy/async.rb +15 -0
  63. data/lib/celluloid/proxy/block.rb +28 -0
  64. data/lib/celluloid/proxy/cell.rb +66 -0
  65. data/lib/celluloid/proxy/future.rb +20 -0
  66. data/lib/celluloid/proxy/sync.rb +24 -0
  67. data/lib/celluloid/rspec.rb +67 -9
  68. data/lib/celluloid/system_events.rb +69 -14
  69. data/lib/celluloid/task/fibered.rb +45 -0
  70. data/lib/celluloid/task/threaded.rb +59 -0
  71. data/lib/celluloid/{tasks.rb → task.rb} +30 -38
  72. data/lib/celluloid/test.rb +1 -1
  73. data/lib/celluloid/thread.rb +6 -1
  74. data/lib/celluloid/version.rb +3 -0
  75. data/lib/celluloid.rb +151 -130
  76. data/spec/celluloid/actor/system_spec.rb +83 -0
  77. data/spec/celluloid/actor_spec.rb +2 -2
  78. data/spec/celluloid/block_spec.rb +67 -8
  79. data/spec/celluloid/calls_spec.rb +28 -23
  80. data/spec/celluloid/condition_spec.rb +23 -14
  81. data/spec/celluloid/evented_mailbox_spec.rb +1 -31
  82. data/spec/celluloid/future_spec.rb +15 -12
  83. data/spec/celluloid/group/elastic_spec.rb +0 -0
  84. data/spec/celluloid/group/pool_spec.rb +8 -0
  85. data/spec/celluloid/group/spawner_spec.rb +17 -0
  86. data/spec/celluloid/mailbox/evented_spec.rb +40 -0
  87. data/spec/celluloid/mailbox_spec.rb +1 -3
  88. data/spec/celluloid/misc/leak_spec.rb +73 -0
  89. data/spec/celluloid/proxy_spec.rb +33 -0
  90. data/spec/celluloid/task/fibered_spec.rb +5 -0
  91. data/spec/celluloid/task/threaded_spec.rb +5 -0
  92. data/spec/celluloid/timer_spec.rb +14 -16
  93. data/spec/deprecate/actor_system_spec.rb +72 -0
  94. data/spec/deprecate/block_spec.rb +52 -0
  95. data/spec/deprecate/calls_spec.rb +39 -0
  96. data/spec/deprecate/evented_mailbox_spec.rb +34 -0
  97. data/spec/deprecate/future_spec.rb +32 -0
  98. data/spec/deprecate/internal_pool_spec.rb +4 -0
  99. data/spec/shared/actor_examples.rb +1259 -0
  100. data/spec/shared/group_examples.rb +121 -0
  101. data/spec/shared/mailbox_examples.rb +87 -0
  102. data/{lib/celluloid/rspec → spec/shared}/task_examples.rb +9 -8
  103. data/spec/spec_helper.rb +5 -42
  104. data/spec/support/configure_rspec.rb +77 -0
  105. data/spec/support/coverage.rb +4 -0
  106. data/spec/support/crash_checking.rb +68 -0
  107. data/spec/support/debugging.rb +31 -0
  108. data/spec/support/env.rb +21 -0
  109. data/{lib/celluloid/rspec/example_actor_class.rb → spec/support/examples/actor_class.rb} +21 -2
  110. data/spec/support/examples/call_class.rb +37 -0
  111. data/spec/support/examples/evented_mailbox_class.rb +27 -0
  112. data/spec/support/includer.rb +6 -0
  113. data/spec/support/logging.rb +55 -0
  114. data/spec/support/loose_threads.rb +68 -0
  115. data/spec/support/reset_class_variables.rb +27 -0
  116. data/spec/support/sleep_and_wait.rb +14 -0
  117. data/spec/support/stubbing.rb +14 -0
  118. metadata +276 -78
  119. data/lib/celluloid/actor_system.rb +0 -107
  120. data/lib/celluloid/call_chain.rb +0 -13
  121. data/lib/celluloid/cpu_counter.rb +0 -34
  122. data/lib/celluloid/evented_mailbox.rb +0 -73
  123. data/lib/celluloid/fsm.rb +0 -186
  124. data/lib/celluloid/handlers.rb +0 -41
  125. data/lib/celluloid/internal_pool.rb +0 -159
  126. data/lib/celluloid/legacy.rb +0 -9
  127. data/lib/celluloid/links.rb +0 -36
  128. data/lib/celluloid/logger.rb +0 -93
  129. data/lib/celluloid/logging/incident.rb +0 -21
  130. data/lib/celluloid/logging/incident_logger.rb +0 -129
  131. data/lib/celluloid/logging/incident_reporter.rb +0 -48
  132. data/lib/celluloid/logging/log_event.rb +0 -20
  133. data/lib/celluloid/logging/ring_buffer.rb +0 -65
  134. data/lib/celluloid/method.rb +0 -32
  135. data/lib/celluloid/notifications.rb +0 -83
  136. data/lib/celluloid/pool_manager.rb +0 -146
  137. data/lib/celluloid/probe.rb +0 -73
  138. data/lib/celluloid/properties.rb +0 -24
  139. data/lib/celluloid/proxies/abstract_proxy.rb +0 -20
  140. data/lib/celluloid/proxies/actor_proxy.rb +0 -38
  141. data/lib/celluloid/proxies/async_proxy.rb +0 -31
  142. data/lib/celluloid/proxies/block_proxy.rb +0 -29
  143. data/lib/celluloid/proxies/cell_proxy.rb +0 -68
  144. data/lib/celluloid/proxies/future_proxy.rb +0 -35
  145. data/lib/celluloid/proxies/sync_proxy.rb +0 -36
  146. data/lib/celluloid/receivers.rb +0 -63
  147. data/lib/celluloid/registry.rb +0 -57
  148. data/lib/celluloid/responses.rb +0 -44
  149. data/lib/celluloid/rspec/actor_examples.rb +0 -1054
  150. data/lib/celluloid/rspec/mailbox_examples.rb +0 -84
  151. data/lib/celluloid/signals.rb +0 -23
  152. data/lib/celluloid/stack_dump.rb +0 -133
  153. data/lib/celluloid/supervision_group.rb +0 -169
  154. data/lib/celluloid/supervisor.rb +0 -22
  155. data/lib/celluloid/task_set.rb +0 -49
  156. data/lib/celluloid/tasks/task_fiber.rb +0 -43
  157. data/lib/celluloid/tasks/task_thread.rb +0 -53
  158. data/lib/celluloid/thread_handle.rb +0 -50
  159. data/lib/celluloid/uuid.rb +0 -38
  160. data/spec/celluloid/actor_system_spec.rb +0 -69
  161. data/spec/celluloid/cpu_counter_spec.rb +0 -82
  162. data/spec/celluloid/fsm_spec.rb +0 -107
  163. data/spec/celluloid/internal_pool_spec.rb +0 -52
  164. data/spec/celluloid/links_spec.rb +0 -45
  165. data/spec/celluloid/logging/ring_buffer_spec.rb +0 -38
  166. data/spec/celluloid/notifications_spec.rb +0 -120
  167. data/spec/celluloid/pool_spec.rb +0 -92
  168. data/spec/celluloid/probe_spec.rb +0 -121
  169. data/spec/celluloid/properties_spec.rb +0 -42
  170. data/spec/celluloid/registry_spec.rb +0 -64
  171. data/spec/celluloid/stack_dump_spec.rb +0 -64
  172. data/spec/celluloid/supervision_group_spec.rb +0 -65
  173. data/spec/celluloid/supervisor_spec.rb +0 -103
  174. data/spec/celluloid/tasks/task_fiber_spec.rb +0 -5
  175. data/spec/celluloid/tasks/task_thread_spec.rb +0 -5
  176. data/spec/celluloid/thread_handle_spec.rb +0 -26
  177. data/spec/celluloid/uuid_spec.rb +0 -11
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.push File.expand_path("../../lib", __FILE__)
4
+ require "celluloid/current"
5
+
6
+ class TimerExample
7
+ include Celluloid
8
+ attr_reader :fired, :timer
9
+
10
+ def initialize
11
+ @fired = false
12
+ @timer = after(3) { puts "Timer fired!"; @fired = true }
13
+ end
14
+ end
15
+
16
+ #
17
+ # Basic timer example
18
+ #
19
+
20
+ actor = TimerExample.new
21
+
22
+ # The timer hasn't fired yet, so this should be false
23
+ puts "Timer hasn't fired yet, so this should be false: #{actor.fired}"
24
+
25
+ # Even if we wait a second, it still hasn't fired
26
+ sleep 1
27
+ puts "Timer still shouldn't have fired yet: #{actor.fired}"
28
+
29
+ # Wait until after the timer should've fired
30
+ sleep 2.1
31
+ puts "Timer should've fired now: #{actor.fired}"
32
+
33
+ #
34
+ # Cancelling timers
35
+ #
36
+
37
+ actor = TimerExample.new
38
+
39
+ # The timer hasn't fired yet, so this should be false
40
+ puts "Timer hasn't fired yet, so this should be false: #{actor.fired}"
41
+
42
+ # Cancel the timer, which should prevent it from firing
43
+ actor.timer.cancel
44
+
45
+ # Wait until after the timer should've fired
46
+ sleep 3.1
47
+ puts "Timer shouldn't have fired because we cancelled it: #{actor.fired}"
48
+
49
+ class RepeatingTimerExample
50
+ include Celluloid
51
+
52
+ def initialize
53
+ @sheep = 0
54
+ end
55
+
56
+ def count_sheep
57
+ print "<#{self.class.name}> Counting sheep to go to sleep: "
58
+ @timer = every(0.1) do
59
+ @sheep += 1
60
+ print @sheep, " "
61
+ end
62
+ end
63
+
64
+ def stop_counting
65
+ @timer.cancel
66
+ end
67
+ end
68
+
69
+ sleepy_actor = RepeatingTimerExample.new
70
+ sleepy_actor.count_sheep
71
+ sleep 1
72
+ sleepy_actor.stop_counting
@@ -0,0 +1,7 @@
1
+ module Celluloid
2
+ class Actor
3
+ class Manager
4
+ include Celluloid
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,163 @@
1
+ module Celluloid
2
+ extend Forwardable
3
+ def_delegators :actor_system, :[], :[]=
4
+
5
+ class Actor
6
+ class System
7
+ extend Forwardable
8
+ def_delegators :@registry, :[], :get, :[]=, :set, :delete
9
+
10
+ ROOT_SERVICES = begin
11
+ root_services = [
12
+ {
13
+ as: :notifications_fanout,
14
+ type: Celluloid::Notifications::Fanout,
15
+ },
16
+ {
17
+ as: :incident_reporter,
18
+ type: Celluloid::IncidentReporter,
19
+ args: [STDERR],
20
+ },
21
+ {
22
+ as: :public_services,
23
+ type: Celluloid::Supervision::Service::Public,
24
+ accessors: [:services],
25
+ supervise: [],
26
+ },
27
+ ]
28
+ if $CELLULOID_MANAGED
29
+ root_services << {
30
+ as: :actor_manager,
31
+ type: Celluloid::Actor::Manager,
32
+ accessors: [:manager],
33
+ }
34
+ end
35
+ root_services
36
+ end
37
+
38
+ attr_reader :registry, :group
39
+
40
+ # the root of the supervisor tree is established at supervision/root
41
+
42
+ def root_services
43
+ @tree
44
+ end
45
+
46
+ def root_configuration
47
+ @root
48
+ end
49
+
50
+ def initialize
51
+ @tree = nil
52
+ @group = Celluloid.group_class.new
53
+ @registry = Internals::Registry.new
54
+ @root = ROOT_SERVICES
55
+ end
56
+
57
+ # Launch default services
58
+ def start
59
+ within do
60
+ @root = Supervision::Service::Root.define
61
+ @tree = root_configuration.deploy
62
+ # de root_services[:group_manager].manage! @group
63
+ end
64
+ true
65
+ end
66
+
67
+ def within
68
+ old = Thread.current[:celluloid_actor_system]
69
+ Thread.current[:celluloid_actor_system] = self
70
+ yield
71
+ ensure
72
+ Thread.current[:celluloid_actor_system] = old
73
+ end
74
+
75
+ def get_thread
76
+ @group.get do
77
+ Thread.current[:celluloid_actor_system] = self
78
+ yield
79
+ end
80
+ end
81
+
82
+ def stack_dump
83
+ Internals::Stack::Dump.new(@group)
84
+ end
85
+
86
+ def stack_summary
87
+ Internals::Stack::Summary.new(@group)
88
+ end
89
+
90
+ def registered
91
+ @registry.names
92
+ end
93
+
94
+ def clear_registry
95
+ @registry.clear
96
+ end
97
+
98
+ def running
99
+ actors = []
100
+ @group.each do |t|
101
+ next unless t.role == :actor
102
+ actor = t.actor
103
+
104
+ # NOTE - these are in separate statements, since on JRuby t.actor may
105
+ # become nil befor .behavior_proxy() is called
106
+ next unless actor
107
+ next unless actor.respond_to?(:behavior_proxy)
108
+ proxy = actor.behavior_proxy
109
+ actors << proxy
110
+ end
111
+ actors
112
+ end
113
+
114
+ def running?
115
+ @group.active?
116
+ end
117
+
118
+ # Shut down all running actors
119
+ def shutdown
120
+ actors = running
121
+ Timeout.timeout(shutdown_timeout) do
122
+ Internals::Logger.debug "Terminating #{actors.size} #{(actors.size > 1) ? 'actors' : 'actor'}..." if actors.size > 0
123
+
124
+ # Actors cannot self-terminate, you must do it for them
125
+ actors.each do |actor|
126
+ begin
127
+ actor.terminate!
128
+ rescue DeadActorError
129
+ end
130
+ end
131
+
132
+ actors.each do |actor|
133
+ begin
134
+ Actor.join(actor)
135
+ rescue DeadActorError
136
+ end
137
+ end
138
+ end
139
+ rescue Timeout::Error
140
+ Internals::Logger.error("Couldn't cleanly terminate all actors in #{shutdown_timeout} seconds!")
141
+ unless RUBY_PLATFORM == "java" || RUBY_ENGINE == "rbx"
142
+ actors.each do |actor|
143
+ begin
144
+ Actor.kill(actor)
145
+ rescue DeadActorError, MailboxDead
146
+ end
147
+ end
148
+ end
149
+ ensure
150
+ @group.shutdown
151
+ clear_registry
152
+ end
153
+
154
+ def assert_inactive
155
+ @group.assert_inactive
156
+ end
157
+
158
+ def shutdown_timeout
159
+ Celluloid.shutdown_timeout
160
+ end
161
+ end
162
+ end
163
+ end
@@ -1,5 +1,4 @@
1
-
2
- require 'timers'
1
+ require "timers"
3
2
 
4
3
  module Celluloid
5
4
  # Actors are Celluloid's concurrency primitive. They're implemented as
@@ -12,37 +11,37 @@ module Celluloid
12
11
  class << self
13
12
  extend Forwardable
14
13
 
15
- def_delegators "Celluloid.actor_system", :[], :[]=, :delete, :registered, :clear_registry
14
+ def_delegators :"Celluloid.actor_system", :[], :[]=, :delete, :registered, :clear_registry
16
15
 
17
16
  # Obtain the current actor
18
17
  def current
19
18
  actor = Thread.current[:celluloid_actor]
20
- raise NotActorError, "not in actor scope" unless actor
19
+ fail NotActorError, "not in actor scope" unless actor
21
20
  actor.behavior_proxy
22
21
  end
23
22
 
24
23
  # Obtain the name of the current actor
25
24
  def registered_name
26
25
  actor = Thread.current[:celluloid_actor]
27
- raise NotActorError, "not in actor scope" unless actor
26
+ fail NotActorError, "not in actor scope" unless actor
28
27
  actor.name
29
28
  end
30
29
 
31
30
  # Invoke a method on the given actor via its mailbox
32
31
  def call(mailbox, meth, *args, &block)
33
- proxy = SyncProxy.new(mailbox, "UnknownClass")
32
+ proxy = Proxy::Sync.new(mailbox, "UnknownClass")
34
33
  proxy.method_missing(meth, *args, &block)
35
34
  end
36
35
 
37
36
  # Invoke a method asynchronously on an actor via its mailbox
38
37
  def async(mailbox, meth, *args, &block)
39
- proxy = AsyncProxy.new(mailbox, "UnknownClass")
38
+ proxy = Proxy::Async.new(mailbox, "UnknownClass")
40
39
  proxy.method_missing(meth, *args, &block)
41
40
  end
42
41
 
43
42
  # Call a method asynchronously and retrieve its value later
44
43
  def future(mailbox, meth, *args, &block)
45
- proxy = FutureProxy.new(mailbox, "UnknownClass")
44
+ proxy = Proxy::Future.new(mailbox, "UnknownClass")
46
45
  proxy.method_missing(meth, *args, &block)
47
46
  end
48
47
 
@@ -53,13 +52,13 @@ module Celluloid
53
52
 
54
53
  # Watch for exit events from another actor
55
54
  def monitor(actor)
56
- raise NotActorError, "can't link outside actor context" unless Celluloid.actor?
55
+ fail NotActorError, "can't link outside actor context" unless Celluloid.actor?
57
56
  Thread.current[:celluloid_actor].linking_request(actor, :link)
58
57
  end
59
58
 
60
59
  # Stop waiting for exit events from another actor
61
60
  def unmonitor(actor)
62
- raise NotActorError, "can't link outside actor context" unless Celluloid.actor?
61
+ fail NotActorError, "can't link outside actor context" unless Celluloid.actor?
63
62
  Thread.current[:celluloid_actor].linking_request(actor, :unlink)
64
63
  end
65
64
 
@@ -85,10 +84,12 @@ module Celluloid
85
84
  monitoring?(actor) && Thread.current[:celluloid_actor].links.include?(actor)
86
85
  end
87
86
 
88
- # Forcibly kill a given actor
89
- def kill(actor)
90
- actor.thread.kill
91
- actor.mailbox.shutdown if actor.mailbox.alive?
87
+ unless RUBY_PLATFORM == "java" || RUBY_ENGINE == "rbx"
88
+ # Forcibly kill a given actor
89
+ def kill(actor)
90
+ actor.thread.kill
91
+ actor.mailbox.shutdown if actor.mailbox.alive?
92
+ end
92
93
  end
93
94
 
94
95
  # Wait for an actor to terminate
@@ -109,12 +110,12 @@ module Celluloid
109
110
  @exit_handler = method(:default_exit_handler)
110
111
  @exclusive = options.fetch(:exclusive, false)
111
112
 
112
- @tasks = TaskSet.new
113
- @links = Links.new
114
- @signals = Signals.new
115
113
  @timers = Timers::Group.new
116
- @receivers = Receivers.new(@timers)
117
- @handlers = Handlers.new
114
+ @tasks = Internals::TaskSet.new
115
+ @links = Internals::Links.new
116
+ @handlers = Internals::Handlers.new
117
+ @receivers = Internals::Receivers.new(@timers)
118
+ @signals = Internals::Signals.new
118
119
  @running = false
119
120
  @name = nil
120
121
 
@@ -125,13 +126,14 @@ module Celluloid
125
126
 
126
127
  def start
127
128
  @running = true
128
- @thread = ThreadHandle.new(@actor_system, :actor) do
129
+ @thread = Internals::ThreadHandle.new(@actor_system, :actor) do
129
130
  setup_thread
130
131
  run
131
132
  end
132
133
 
133
- @proxy = ActorProxy.new(@thread, @mailbox)
134
+ @proxy = Proxy::Actor.new(@mailbox, @thread)
134
135
  Celluloid::Probe.actor_created(self) if $CELLULOID_MONITORING
136
+ Celluloid::Actor::Manager.actor_created(self) if $CELLULOID_MANAGED
135
137
  end
136
138
 
137
139
  def behavior_proxy
@@ -148,8 +150,8 @@ module Celluloid
148
150
  while @running
149
151
  begin
150
152
  @timers.wait do |interval|
151
- interval = 0 if interval and interval < 0
152
-
153
+ interval = 0 if interval && interval < 0
154
+
153
155
  if message = @mailbox.check(interval)
154
156
  handle_message(message)
155
157
 
@@ -158,13 +160,16 @@ module Celluloid
158
160
  end
159
161
  rescue MailboxShutdown
160
162
  @running = false
163
+ rescue MailboxDead
164
+ # TODO: not tests (but fails occasionally in tests)
165
+ @running = false
161
166
  end
162
167
  end
163
168
 
164
169
  shutdown
165
- rescue Exception => ex
170
+ rescue ::Exception => ex
166
171
  handle_crash(ex)
167
- raise unless ex.is_a? StandardError
172
+ raise unless ex.is_a?(StandardError) || ex.is_a?(Celluloid::Interruption)
168
173
  end
169
174
 
170
175
  # Terminate this actor
@@ -185,25 +190,22 @@ module Celluloid
185
190
  msg.actor.mailbox.address == receiver.mailbox.address &&
186
191
  msg.type == type
187
192
  end
188
- rescue TimeoutError
193
+ rescue TaskTimeout
189
194
  next # IO reactor did something, no message in queue yet.
190
195
  end
191
196
 
192
197
  if message.instance_of? LinkingResponse
193
198
  Celluloid::Probe.actors_linked(self, receiver) if $CELLULOID_MONITORING
194
-
195
- # We're done!
196
199
  system_events.each { |ev| @mailbox << ev }
197
-
198
200
  return
199
201
  elsif message.is_a? SystemEvent
200
202
  # Queue up pending system events to be processed after we've successfully linked
201
203
  system_events << message
202
- else raise "Unexpected message type: #{message.class}. Expected LinkingResponse, NilClass, SystemEvent."
204
+ else fail "Unexpected message type: #{message.class}. Expected LinkingResponse, NilClass, SystemEvent."
203
205
  end
204
206
  end
205
207
 
206
- raise TimeoutError, "linking timeout of #{LINKING_TIMEOUT} seconds exceeded"
208
+ fail TaskTimeout, "linking timeout of #{LINKING_TIMEOUT} seconds exceeded with receiver: #{receiver}"
207
209
  end
208
210
  end
209
211
 
@@ -216,16 +218,17 @@ module Celluloid
216
218
  def wait(name)
217
219
  @signals.wait name
218
220
  end
219
-
221
+
222
+ # Register a new handler for a given pattern
220
223
  def handle(*patterns, &block)
221
224
  @handlers.handle(*patterns, &block)
222
225
  end
223
226
 
224
227
  # Receive an asynchronous message
225
228
  def receive(timeout = nil, &block)
226
- loop do
229
+ while true
227
230
  message = @receivers.receive(timeout, &block)
228
- break message unless message.is_a?(SystemEvent)
231
+ return message unless message.is_a?(SystemEvent)
229
232
 
230
233
  handle_system_event(message)
231
234
  end
@@ -245,7 +248,7 @@ module Celluloid
245
248
  bt = caller
246
249
  task = Task.current
247
250
  timer = @timers.after(duration) do
248
- exception = Task::TimeoutError.new("execution expired")
251
+ exception = TaskTimeout.new("execution expired")
249
252
  exception.set_backtrace bt
250
253
  task.resume exception
251
254
  end
@@ -279,48 +282,23 @@ module Celluloid
279
282
  def handle_message(message)
280
283
  unless @handlers.handle_message(message)
281
284
  unless @receivers.handle_message(message)
282
- Logger.debug "Discarded message (unhandled): #{message}" if $CELLULOID_DEBUG
285
+ Internals::Logger.debug "Discarded message (unhandled): #{message}" if $CELLULOID_DEBUG
283
286
  end
284
287
  end
285
288
  message
286
289
  end
287
290
 
288
- # Handle high-priority system event messages
289
- def handle_system_event(event)
290
- if event.instance_of? ExitEvent
291
- handle_exit_event(event)
292
- elsif event.instance_of? LinkingRequest
293
- event.process(links)
294
- elsif event.instance_of? NamingRequest
295
- @name = event.name
296
- Celluloid::Probe.actor_named(self) if $CELLULOID_MONITORING
297
- elsif event.instance_of? TerminationRequest
298
- terminate
299
- elsif event.instance_of? SignalConditionRequest
300
- event.call
301
- else
302
- Logger.debug "Discarded message (unhandled): #{message}" if $CELLULOID_DEBUG
303
- end
304
- end
305
-
306
- # Handle exit events received by this actor
307
- def handle_exit_event(event)
308
- @links.delete event.actor
309
-
310
- @exit_handler.call(event)
311
- end
312
-
313
291
  def default_exit_handler(event)
314
- raise event.reason if event.reason
292
+ fail event.reason if event.reason
315
293
  end
316
294
 
317
295
  # Handle any exceptions that occur within a running actor
318
296
  def handle_crash(exception)
319
297
  # TODO: add meta info
320
- Logger.crash("Actor crashed!", exception)
298
+ Internals::Logger.crash("Actor crashed!", exception)
321
299
  shutdown ExitEvent.new(behavior_proxy, exception)
322
300
  rescue => ex
323
- Logger.crash("ERROR HANDLER CRASHED!", ex)
301
+ Internals::Logger.crash("Actor#handle_crash CRASHED!", ex)
324
302
  end
325
303
 
326
304
  # Handle cleaning up this actor after it exits
@@ -337,26 +315,30 @@ module Celluloid
337
315
  Celluloid::Probe.actor_died(self) if $CELLULOID_MONITORING
338
316
  @mailbox.shutdown
339
317
  @links.each do |actor|
340
- if actor.mailbox.alive?
341
- actor.mailbox << exit_event
342
- end
318
+ actor.mailbox << exit_event if actor.mailbox.alive?
343
319
  end
344
320
 
345
- tasks.to_a.each(&:terminate)
321
+ tasks.to_a.each do |task|
322
+ begin
323
+ task.terminate
324
+ rescue DeadTaskError
325
+ # TODO: not tested (failed on Travis)
326
+ end
327
+ end
346
328
  rescue => ex
347
329
  # TODO: metadata
348
- Logger.crash("CLEANUP CRASHED!", ex)
330
+ Internals::Logger.crash("CLEANUP CRASHED!", ex)
349
331
  end
350
332
 
351
333
  # Run a method inside a task unless it's exclusive
352
334
  def task(task_type, meta = nil)
353
- @task_class.new(task_type, meta) {
335
+ @task_class.new(task_type, meta) do
354
336
  if @exclusive
355
337
  Celluloid.exclusive { yield }
356
338
  else
357
339
  yield
358
340
  end
359
- }.resume
341
+ end.resume
360
342
  end
361
343
  end
362
344
  end
@@ -1,3 +1,3 @@
1
- require 'celluloid'
1
+ require "celluloid"
2
2
 
3
3
  Celluloid.start
@@ -0,0 +1,2 @@
1
+ $CELLULOID_BACKPORTED = true
2
+ require "celluloid/autostart"
@@ -0,0 +1,16 @@
1
+ module Celluloid
2
+ class Call
3
+ # Asynchronous calls don't wait for a response
4
+ class Async < Call
5
+ def dispatch(obj)
6
+ Internals::CallChain.current_id = Celluloid.uuid
7
+ super(obj)
8
+ rescue AbortError => ex
9
+ # Swallow aborted async calls, as they indicate the sender made a mistake
10
+ Internals::Logger.debug("#{obj.class}: async call `#{@method}` aborted!\n#{Internals::Logger.format_exception(ex.cause)}")
11
+ ensure
12
+ Internals::CallChain.current_id = nil
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,22 @@
1
+ module Celluloid
2
+ class Call
3
+ class Block
4
+ def initialize(block_proxy, sender, arguments, task = Thread.current[:celluloid_task])
5
+ @block_proxy = block_proxy
6
+ @sender = sender
7
+ @arguments = arguments
8
+ @task = task
9
+ end
10
+ attr_reader :task
11
+
12
+ def call
13
+ @block_proxy.call
14
+ end
15
+
16
+ def dispatch
17
+ response = @block_proxy.block.call(*@arguments)
18
+ @sender << Internals::Response::Block.new(self, response)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,70 @@
1
+ module Celluloid
2
+ class Call
3
+ # Synchronous calls wait for a response
4
+ class Sync < Call
5
+ attr_reader :sender, :task, :chain_id
6
+
7
+ def initialize(sender, method, arguments = [], block = nil, task = Thread.current[:celluloid_task], chain_id = Internals::CallChain.current_id)
8
+ super(method, arguments, block)
9
+ @sender = sender
10
+ @task = task
11
+ @chain_id = chain_id || Celluloid.uuid
12
+ end
13
+
14
+ def dispatch(obj)
15
+ Internals::CallChain.current_id = @chain_id
16
+ result = super(obj)
17
+ respond Internals::Response::Success.new(self, result)
18
+ rescue ::Exception => ex
19
+ # Exceptions that occur during synchronous calls are reraised in the
20
+ # context of the sender
21
+ respond Internals::Response::Error.new(self, ex)
22
+
23
+ # Aborting indicates a protocol error on the part of the sender
24
+ # It should crash the sender, but the exception isn't reraised
25
+ # Otherwise, it's a bug in this actor and should be reraised
26
+ raise unless ex.is_a?(AbortError)
27
+ ensure
28
+ Internals::CallChain.current_id = nil
29
+ end
30
+
31
+ def cleanup
32
+ exception = DeadActorError.new("attempted to call a dead actor: #{self.method}")
33
+ respond Internals::Response::Error.new(self, exception)
34
+ end
35
+
36
+ def respond(message)
37
+ @sender << message
38
+ end
39
+
40
+ def response
41
+ Celluloid.suspend(:callwait, self)
42
+ end
43
+
44
+ def value
45
+ response.value
46
+ end
47
+
48
+ def wait
49
+ while true
50
+ message = Celluloid.mailbox.receive do |msg|
51
+ msg.respond_to?(:call) && msg.call == self
52
+ end
53
+
54
+ if message.is_a?(SystemEvent)
55
+ Thread.current[:celluloid_actor].handle_system_event(message)
56
+ else
57
+ # FIXME: add check for receiver block execution
58
+ if message.respond_to?(:value)
59
+ # FIXME: disable block execution if on :sender and (exclusive or outside of task)
60
+ # probably now in Call
61
+ return message
62
+ else
63
+ message.dispatch
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end