celluloid 0.18.0.pre → 0.18.0.pre2

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 (179) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES.md +114 -39
  3. data/CONDUCT.md +13 -0
  4. data/CONTRIBUTING.md +39 -0
  5. data/README.md +59 -55
  6. data/architecture.md +120 -0
  7. data/examples/basic_usage.rb +1 -1
  8. data/examples/configurations.rb +78 -0
  9. data/examples/futures.rb +1 -1
  10. data/examples/ring.rb +5 -4
  11. data/examples/simple_pmap.rb +1 -1
  12. data/examples/stack.rb +2 -2
  13. data/examples/supervisors_and_registry.rb +82 -0
  14. data/examples/timers.rb +1 -1
  15. data/lib/celluloid.rb +72 -47
  16. data/lib/celluloid/actor.rb +27 -17
  17. data/lib/celluloid/actor/system.rb +13 -29
  18. data/lib/celluloid/autostart.rb +5 -5
  19. data/lib/celluloid/backported.rb +6 -2
  20. data/lib/celluloid/call/async.rb +2 -0
  21. data/lib/celluloid/call/sync.rb +10 -3
  22. data/lib/celluloid/calls.rb +5 -12
  23. data/lib/celluloid/cell.rb +5 -9
  24. data/lib/celluloid/condition.rb +3 -3
  25. data/lib/celluloid/core_ext.rb +0 -2
  26. data/lib/celluloid/current.rb +3 -1
  27. data/lib/celluloid/debug.rb +3 -0
  28. data/lib/celluloid/exceptions.rb +2 -2
  29. data/lib/celluloid/future.rb +7 -9
  30. data/lib/celluloid/group.rb +12 -8
  31. data/lib/celluloid/group/pool.rb +1 -3
  32. data/lib/celluloid/group/spawner.rb +2 -6
  33. data/lib/celluloid/internals/call_chain.rb +15 -0
  34. data/lib/celluloid/internals/cpu_counter.rb +62 -0
  35. data/lib/celluloid/internals/handlers.rb +42 -0
  36. data/lib/celluloid/internals/links.rb +38 -0
  37. data/lib/celluloid/internals/logger.rb +104 -0
  38. data/lib/celluloid/internals/method.rb +34 -0
  39. data/lib/celluloid/internals/properties.rb +32 -0
  40. data/lib/celluloid/internals/receivers.rb +64 -0
  41. data/lib/celluloid/internals/registry.rb +102 -0
  42. data/lib/celluloid/internals/responses.rb +46 -0
  43. data/lib/celluloid/internals/signals.rb +24 -0
  44. data/lib/celluloid/internals/stack.rb +74 -0
  45. data/lib/celluloid/internals/stack/dump.rb +12 -0
  46. data/lib/celluloid/internals/stack/states.rb +72 -0
  47. data/lib/celluloid/internals/stack/summary.rb +12 -0
  48. data/lib/celluloid/internals/task_set.rb +51 -0
  49. data/lib/celluloid/internals/thread_handle.rb +52 -0
  50. data/lib/celluloid/internals/uuid.rb +40 -0
  51. data/lib/celluloid/logging/incident.rb +21 -0
  52. data/lib/celluloid/logging/incident_logger.rb +147 -0
  53. data/lib/celluloid/logging/incident_reporter.rb +49 -0
  54. data/lib/celluloid/logging/log_event.rb +20 -0
  55. data/lib/celluloid/logging/ring_buffer.rb +64 -0
  56. data/lib/celluloid/mailbox.rb +22 -9
  57. data/lib/celluloid/mailbox/evented.rb +13 -5
  58. data/lib/celluloid/managed.rb +6 -3
  59. data/lib/celluloid/notifications.rb +95 -0
  60. data/lib/celluloid/pool.rb +6 -0
  61. data/lib/celluloid/probe.rb +81 -0
  62. data/lib/celluloid/proxy/abstract.rb +9 -9
  63. data/lib/celluloid/proxy/async.rb +1 -1
  64. data/lib/celluloid/proxy/block.rb +2 -2
  65. data/lib/celluloid/proxy/cell.rb +1 -1
  66. data/lib/celluloid/proxy/future.rb +2 -4
  67. data/lib/celluloid/proxy/sync.rb +1 -3
  68. data/lib/celluloid/rspec.rb +22 -33
  69. data/lib/celluloid/supervision.rb +17 -0
  70. data/lib/celluloid/supervision/configuration.rb +169 -0
  71. data/lib/celluloid/supervision/configuration/injections.rb +8 -0
  72. data/lib/celluloid/supervision/configuration/instance.rb +113 -0
  73. data/lib/celluloid/supervision/constants.rb +123 -0
  74. data/lib/celluloid/supervision/container.rb +144 -0
  75. data/lib/celluloid/supervision/container/behavior.rb +89 -0
  76. data/lib/celluloid/supervision/container/behavior/pool.rb +71 -0
  77. data/lib/celluloid/supervision/container/behavior/tree.rb +23 -0
  78. data/lib/celluloid/supervision/container/injections.rb +8 -0
  79. data/lib/celluloid/supervision/container/instance.rb +116 -0
  80. data/lib/celluloid/supervision/container/pool.rb +210 -0
  81. data/{culture/rubocop/perf.yml → lib/celluloid/supervision/container/tree.rb} +0 -0
  82. data/lib/celluloid/supervision/deprecate.rb +9 -0
  83. data/lib/celluloid/supervision/deprecate/supervise.rb +105 -0
  84. data/lib/celluloid/supervision/deprecate/validation.rb +54 -0
  85. data/lib/celluloid/supervision/service.rb +27 -0
  86. data/lib/celluloid/supervision/supervise.rb +34 -0
  87. data/lib/celluloid/supervision/validation.rb +40 -0
  88. data/lib/celluloid/supervision/version.rb +5 -0
  89. data/lib/celluloid/system_events.rb +11 -6
  90. data/lib/celluloid/task.rb +25 -12
  91. data/lib/celluloid/task/fibered.rb +2 -0
  92. data/lib/celluloid/task/threaded.rb +3 -3
  93. data/lib/celluloid/test.rb +5 -2
  94. data/lib/celluloid/thread.rb +0 -2
  95. data/lib/celluloid/version.rb +1 -1
  96. data/spec/celluloid/block_spec.rb +29 -32
  97. data/spec/celluloid/calls_spec.rb +5 -15
  98. data/spec/celluloid/future_spec.rb +2 -2
  99. data/spec/celluloid/internals/cpu_counter_spec.rb +129 -0
  100. data/spec/celluloid/internals/links_spec.rb +43 -0
  101. data/spec/celluloid/internals/properties_spec.rb +40 -0
  102. data/spec/celluloid/internals/registry_spec.rb +62 -0
  103. data/spec/celluloid/internals/stack/dump_spec.rb +4 -0
  104. data/spec/celluloid/internals/stack/summary_spec.rb +4 -0
  105. data/spec/celluloid/internals/thread_handle_spec.rb +60 -0
  106. data/spec/celluloid/internals/uuid_spec.rb +9 -0
  107. data/spec/celluloid/logging/ring_buffer_spec.rb +36 -0
  108. data/spec/celluloid/mailbox/evented_spec.rb +11 -22
  109. data/spec/celluloid/misc/leak_spec.rb +3 -4
  110. data/spec/celluloid/notifications_spec.rb +140 -0
  111. data/spec/celluloid/probe_spec.rb +102 -0
  112. data/spec/celluloid/proxy_spec.rb +30 -30
  113. data/spec/celluloid/supervision/behavior_spec.rb +74 -0
  114. data/spec/celluloid/supervision/configuration_spec.rb +181 -0
  115. data/spec/celluloid/supervision/container_spec.rb +72 -0
  116. data/spec/celluloid/supervision/instance_spec.rb +13 -0
  117. data/spec/celluloid/supervision/root_spec.rb +28 -0
  118. data/spec/celluloid/supervision/supervisor_spec.rb +93 -0
  119. data/spec/celluloid/task/fibered_spec.rb +1 -3
  120. data/spec/celluloid/task/threaded_spec.rb +1 -3
  121. data/spec/shared/actor_examples.rb +58 -33
  122. data/spec/shared/group_examples.rb +2 -2
  123. data/spec/shared/mailbox_examples.rb +1 -1
  124. data/spec/shared/stack_examples.rb +87 -0
  125. data/spec/shared/task_examples.rb +2 -3
  126. data/spec/spec_helper.rb +2 -4
  127. data/spec/support/configure_rspec.rb +2 -3
  128. data/spec/support/coverage.rb +2 -4
  129. data/spec/support/crash_checking.rb +2 -2
  130. data/spec/support/examples/actor_class.rb +3 -8
  131. data/spec/support/examples/call_class.rb +2 -2
  132. data/spec/support/examples/container_class.rb +35 -0
  133. data/spec/support/examples/evented_mailbox_class.rb +1 -2
  134. data/spec/support/examples/stack_classes.rb +58 -0
  135. data/spec/support/examples/stack_methods.rb +23 -0
  136. data/spec/support/examples/subordinate_class.rb +19 -0
  137. data/spec/support/logging.rb +2 -34
  138. data/spec/support/loose_threads.rb +3 -16
  139. data/spec/support/reset_class_variables.rb +5 -1
  140. data/spec/support/stubbing.rb +1 -1
  141. metadata +91 -316
  142. data/culture/CONDUCT.md +0 -38
  143. data/culture/GSoC/1010-why_we_will_participate.md +0 -17
  144. data/culture/GSoC/1020-how_mentors_stay_engaged.md +0 -7
  145. data/culture/GSoC/1030-keeping_students_on_schedule.md +0 -9
  146. data/culture/GSoC/1040-getting_students_involved.md +0 -5
  147. data/culture/GSoC/1050-student_involvement_after.md +0 -5
  148. data/culture/GSoC/README.md +0 -16
  149. data/culture/Gemfile +0 -9
  150. data/culture/LICENSE.txt +0 -22
  151. data/culture/README.md +0 -22
  152. data/culture/Rakefile +0 -5
  153. data/culture/SYNC.md +0 -70
  154. data/culture/celluloid-culture.gemspec +0 -18
  155. data/culture/gems/README.md +0 -39
  156. data/culture/gems/dependencies.yml +0 -93
  157. data/culture/gems/loader.rb +0 -101
  158. data/culture/rubocop/README.md +0 -38
  159. data/culture/rubocop/lint.yml +0 -8
  160. data/culture/rubocop/metrics.yml +0 -15
  161. data/culture/rubocop/rubocop.yml +0 -5
  162. data/culture/rubocop/style.yml +0 -61
  163. data/culture/spec/gems_spec.rb +0 -2
  164. data/culture/spec/spec_helper.rb +0 -0
  165. data/culture/spec/sync_spec.rb +0 -2
  166. data/culture/sync.rb +0 -56
  167. data/culture/tasks/rspec.rake +0 -5
  168. data/culture/tasks/rubocop.rake +0 -2
  169. data/lib/celluloid/actor/manager.rb +0 -7
  170. data/lib/celluloid/deprecate.rb +0 -34
  171. data/lib/celluloid/fiber.rb +0 -32
  172. data/lib/celluloid/notices.rb +0 -15
  173. data/spec/deprecate/actor_system_spec.rb +0 -72
  174. data/spec/deprecate/block_spec.rb +0 -52
  175. data/spec/deprecate/calls_spec.rb +0 -39
  176. data/spec/deprecate/evented_mailbox_spec.rb +0 -34
  177. data/spec/deprecate/future_spec.rb +0 -32
  178. data/spec/deprecate/internal_pool_spec.rb +0 -4
  179. data/spec/support/env.rb +0 -21
@@ -3,14 +3,14 @@ module Celluloid
3
3
  attr_accessor :group
4
4
 
5
5
  def initialize
6
- @pid = $$
6
+ @pid = $PROCESS_ID
7
7
  @mutex = Mutex.new
8
8
  @group = []
9
9
  @running = true
10
10
  end
11
11
 
12
12
  def assert_active
13
- fail Celluloid::NotActive unless active?
13
+ raise Celluloid::NotActive unless active?
14
14
  end
15
15
 
16
16
  def assert_inactive
@@ -18,7 +18,7 @@ module Celluloid
18
18
  if RUBY_PLATFORM == "java"
19
19
  Celluloid.logger.warn "Group is still active"
20
20
  else
21
- fail Celluloid::StillActive
21
+ raise Celluloid::StillActive
22
22
  end
23
23
  end
24
24
 
@@ -27,7 +27,7 @@ module Celluloid
27
27
  end
28
28
 
29
29
  def forked?
30
- @pid != $$
30
+ @pid != $PROCESS_ID
31
31
  end
32
32
 
33
33
  def to_a
@@ -40,7 +40,11 @@ module Celluloid
40
40
  def purge(thread)
41
41
  @mutex.synchronize do
42
42
  @group.delete(thread)
43
- thread.kill rescue nil
43
+ begin
44
+ thread.kill
45
+ rescue
46
+ nil
47
+ end
44
48
  end
45
49
  end
46
50
 
@@ -53,15 +57,15 @@ module Celluloid
53
57
  end
54
58
 
55
59
  def get
56
- fail NotImplementedError
60
+ raise NotImplementedError
57
61
  end
58
62
 
59
63
  def create
60
- fail NotImplementedError
64
+ raise NotImplementedError
61
65
  end
62
66
 
63
67
  def shutdown
64
- fail NotImplementedError
68
+ raise NotImplementedError
65
69
  end
66
70
  end
67
71
  end
@@ -1,5 +1,3 @@
1
- require "thread"
2
-
3
1
  module Celluloid
4
2
  class Group
5
3
  class Pool < Group
@@ -12,7 +10,7 @@ module Celluloid
12
10
  super
13
11
  @mutex = Mutex.new
14
12
  @idle_threads = []
15
- @group = []
13
+ @group = []
16
14
  @busy_size = 0
17
15
  @idle_size = 0
18
16
 
@@ -1,5 +1,3 @@
1
- require "thread"
2
-
3
1
  module Celluloid
4
2
  class Group
5
3
  class Spawner < Group
@@ -11,7 +9,7 @@ module Celluloid
11
9
 
12
10
  def get(&block)
13
11
  assert_active
14
- fail ArgumentError.new("No block sent to Spawner.get()") unless block_given?
12
+ raise ArgumentError, "No block sent to Spawner.get()" unless block_given?
15
13
  instantiate block
16
14
  end
17
15
 
@@ -52,9 +50,7 @@ module Celluloid
52
50
  Internals::Logger.crash("thread crashed", ex)
53
51
  Thread.current[:celluloid_thread_state] = :error
54
52
  ensure
55
- unless Thread.current[:celluloid_thread_state] == :error
56
- Thread.current[:celluloid_thread_state] = :finished
57
- end
53
+ Thread.current[:celluloid_thread_state] = :finished unless Thread.current[:celluloid_thread_state] == :error
58
54
  @mutex.synchronize { @group.delete Thread.current }
59
55
  Thread.exit
60
56
  end
@@ -0,0 +1,15 @@
1
+ module Celluloid
2
+ module Internals
3
+ class CallChain
4
+ def self.current_id=(value)
5
+ Thread.current[:celluloid_chain_id] = value
6
+ task = Thread.current[:celluloid_task]
7
+ task.chain_id = value if task
8
+ end
9
+
10
+ def self.current_id
11
+ Thread.current[:celluloid_chain_id]
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,62 @@
1
+ module Celluloid
2
+ module Internals
3
+ module CPUCounter
4
+ class << self
5
+ def cores
6
+ @cores ||= count_cores
7
+ end
8
+
9
+ def count_cores
10
+ from_result(from_env || from_sysdev || from_java || from_proc || from_win32ole || from_sysctl) || 1
11
+ end
12
+
13
+ def from_env
14
+ result = ENV["NUMBER_OF_PROCESSORS"]
15
+ result if result && !result.empty?
16
+ rescue
17
+ end
18
+
19
+ def from_sysdev
20
+ ::IO.read("/sys/devices/system/cpu/present").split("-").last.to_i + 1
21
+ rescue Errno::ENOENT
22
+ begin
23
+ result = Dir["/sys/devices/system/cpu/cpu*"].count { |n| n =~ /cpu\d+/ }
24
+ result unless result.zero?
25
+ rescue
26
+ end
27
+ rescue
28
+ end
29
+
30
+ def from_java
31
+ Java::Java.lang.Runtime.getRuntime.availableProcessors if defined? Java::Java
32
+ rescue
33
+ end
34
+
35
+ def from_proc
36
+ File.read("/proc/cpuinfo").scan(/^processor\s*:/).size if File.exist?("/proc/cpuinfo")
37
+ rescue
38
+ end
39
+
40
+ def from_win32ole
41
+ require "win32ole"
42
+ WIN32OLE.connect("winmgmts://").ExecQuery("select * from Win32_ComputerSystem").NumberOfProcessors
43
+ rescue LoadError
44
+ rescue
45
+ end
46
+
47
+ def from_sysctl
48
+ Integer `sysctl -n hw.ncpu 2>/dev/null`
49
+ rescue
50
+ end
51
+
52
+ def from_result(result)
53
+ if result
54
+ i = Integer(result.to_s[/\d+/], 10)
55
+ return i if i > 0
56
+ end
57
+ rescue
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,42 @@
1
+ require "set"
2
+
3
+ module Celluloid
4
+ module Internals
5
+ class Handlers
6
+ def initialize
7
+ @handlers = Set.new
8
+ end
9
+
10
+ def handle(*patterns, &block)
11
+ patterns.each do |pattern|
12
+ handler = Handler.new pattern, block
13
+ @handlers << handler
14
+ end
15
+ end
16
+
17
+ # Handle incoming messages
18
+ def handle_message(message)
19
+ handler = @handlers.find { |h| h.match(message) }
20
+ handler.call(message) if handler
21
+ handler
22
+ end
23
+ end
24
+
25
+ # Methods blocking on a call to receive
26
+ class Handler
27
+ def initialize(pattern, block)
28
+ @pattern = pattern
29
+ @block = block
30
+ end
31
+
32
+ # Match a message with this receiver's block
33
+ def match(message)
34
+ @pattern === message
35
+ end
36
+
37
+ def call(message)
38
+ @block.call message
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,38 @@
1
+ module Celluloid
2
+ module Internals
3
+ # Linked actors send each other system events
4
+ class Links
5
+ include Enumerable
6
+
7
+ def initialize
8
+ @links = {}
9
+ end
10
+
11
+ # Add an actor to the current links
12
+ def <<(actor)
13
+ @links[actor.mailbox.address] = actor
14
+ end
15
+
16
+ # Do links include the given actor?
17
+ def include?(actor)
18
+ @links.key? actor.mailbox.address
19
+ end
20
+
21
+ # Remove an actor from the links
22
+ def delete(actor)
23
+ @links.delete actor.mailbox.address
24
+ end
25
+
26
+ # Iterate through all links
27
+ def each
28
+ @links.each { |_, actor| yield(actor) }
29
+ end
30
+
31
+ # Generate a string representation
32
+ def inspect
33
+ links = map(&:inspect).join(",")
34
+ "#<#{self.class}[#{links}]>"
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,104 @@
1
+ module Celluloid
2
+ module Internals
3
+ module Logger
4
+ class WithBacktrace
5
+ def initialize(backtrace)
6
+ @backtrace = backtrace
7
+ end
8
+
9
+ def debug(string)
10
+ # !!! DO NOT INTRODUCE ADDITIONAL GLOBAL VARIABLES !!!
11
+ # rubocop:disable Style/GlobalVars
12
+ Celluloid.logger.debug(decorate(string)) if $CELLULOID_DEBUG
13
+ # rubocop:enable Style/GlobalVars
14
+ end
15
+
16
+ def info(string)
17
+ Celluloid.logger.info(decorate(string))
18
+ end
19
+
20
+ def warn(string)
21
+ Celluloid.logger.warn(decorate(string))
22
+ end
23
+
24
+ def error(string)
25
+ Celluloid.logger.error(decorate(string))
26
+ end
27
+
28
+ def decorate(string)
29
+ [string, @backtrace].join("\n\t")
30
+ end
31
+ end
32
+
33
+ @exception_handlers = []
34
+
35
+ module_function
36
+
37
+ def with_backtrace(backtrace)
38
+ yield WithBacktrace.new(backtrace) if Celluloid.logger
39
+ end
40
+
41
+ # Send a debug message
42
+ def debug(string)
43
+ # !!! DO NOT INTRODUCE ADDITIONAL GLOBAL VARIABLES !!!
44
+ # rubocop:disable Style/GlobalVars
45
+ Celluloid.logger.debug(string) if Celluloid.logger && $CELLULOID_DEBUG
46
+ # rubocop:enable Style/GlobalVars
47
+ end
48
+
49
+ # Send a info message
50
+ def info(string)
51
+ Celluloid.logger.info(string) if Celluloid.logger
52
+ end
53
+
54
+ # Send a warning message
55
+ def warn(string)
56
+ Celluloid.logger.warn(string) if Celluloid.logger
57
+ end
58
+
59
+ # Send an error message
60
+ def error(string)
61
+ Celluloid.logger.error(string) if Celluloid.logger
62
+ end
63
+
64
+ # Handle a crash
65
+ def crash(string, exception)
66
+ if Celluloid.log_actor_crashes
67
+ string << "\n" << format_exception(exception)
68
+ error string
69
+ end
70
+
71
+ @exception_handlers.each do |handler|
72
+ begin
73
+ handler.call(exception)
74
+ rescue => ex
75
+ error "EXCEPTION HANDLER CRASHED:\n" << format_exception(ex)
76
+ end
77
+ end
78
+ end
79
+
80
+ # Note a deprecation
81
+ def deprecate(message)
82
+ trace = caller.join("\n\t")
83
+ warn "DEPRECATION WARNING: #{message}\n\t#{trace}"
84
+ end
85
+
86
+ # Define an exception handler
87
+ # NOTE: These should be defined at application start time
88
+ def exception_handler(&block)
89
+ @exception_handlers << block
90
+ nil
91
+ end
92
+
93
+ # Format an exception message
94
+ def format_exception(exception)
95
+ str = "#{exception.class}: #{exception}\n\t"
96
+ str << if exception.backtrace
97
+ exception.backtrace.join("\n\t")
98
+ else
99
+ "EMPTY BACKTRACE\n\t"
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,34 @@
1
+ module Celluloid
2
+ module Internals
3
+ # Method handles that route through an actor proxy
4
+ class Method
5
+ def initialize(proxy, name)
6
+ raise NoMethodError, "undefined method `#{name}'" unless proxy.respond_to? name
7
+
8
+ @proxy = proxy
9
+ @name = name
10
+ @klass = @proxy.class
11
+ end
12
+
13
+ def arity
14
+ @proxy.method_missing(:method, @name).arity
15
+ end
16
+
17
+ def name
18
+ @proxy.method_missing(:method, @name).name
19
+ end
20
+
21
+ def parameters
22
+ @proxy.method_missing(:method, @name).parameters
23
+ end
24
+
25
+ def call(*args, &block)
26
+ @proxy.__send__(@name, *args, &block)
27
+ end
28
+
29
+ def inspect
30
+ "#<Celluloid::Internals::Method #{@klass}##{@name}>"
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,32 @@
1
+ module Celluloid
2
+ module Internals
3
+ # Properties define inheritable attributes of classes, somewhat similar to
4
+ # Rails cattr_*/mattr_* or class_attribute
5
+ module Properties
6
+ def property(name, opts = {})
7
+ default = opts.fetch(:default, nil)
8
+ multi = opts.fetch(:multi, false)
9
+ ivar_name = "@#{name}".to_sym
10
+
11
+ singleton = class << ancestors.first; self; end
12
+ begin
13
+ singleton.send(:remove_method, name)
14
+ rescue
15
+ nil
16
+ end
17
+ singleton.send(:define_method, name) do |value = nil, *extra|
18
+ if value
19
+ value = value ? [value, *send(name), *extra].uniq : [] if multi
20
+ instance_variable_set(ivar_name, value)
21
+ elsif instance_variables.include?(ivar_name)
22
+ instance_variable_get(ivar_name)
23
+ elsif superclass.respond_to? name
24
+ superclass.send(name)
25
+ else
26
+ default
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,64 @@
1
+ require "set"
2
+ require "timers"
3
+
4
+ module Celluloid
5
+ module Internals
6
+ # Allow methods to directly interact with the actor protocol
7
+ class Receivers
8
+ def initialize(timers)
9
+ @receivers = Set.new
10
+ @timers = timers
11
+ end
12
+
13
+ # Receive an asynchronous message
14
+ def receive(timeout = nil, &block)
15
+ if Celluloid.exclusive?
16
+ Celluloid.mailbox.receive(timeout, &block)
17
+ else
18
+ receiver = Receiver.new block
19
+
20
+ if timeout
21
+ receiver.timer = @timers.after(timeout) do
22
+ @receivers.delete receiver
23
+ receiver.resume
24
+ end
25
+ end
26
+
27
+ @receivers << receiver
28
+ Task.suspend :receiving
29
+ end
30
+ end
31
+
32
+ # Handle incoming messages
33
+ def handle_message(message)
34
+ receiver = @receivers.find { |r| r.match(message) }
35
+ return unless receiver
36
+
37
+ @receivers.delete receiver
38
+ receiver.timer.cancel if receiver.timer
39
+ receiver.resume message
40
+ message
41
+ end
42
+ end
43
+
44
+ # Methods blocking on a call to receive
45
+ class Receiver
46
+ attr_accessor :timer
47
+
48
+ def initialize(block)
49
+ @block = block
50
+ @task = Task.current
51
+ @timer = nil
52
+ end
53
+
54
+ # Match a message with this receiver's block
55
+ def match(message)
56
+ @block ? @block.call(message) : true
57
+ end
58
+
59
+ def resume(message = nil)
60
+ @task.resume message
61
+ end
62
+ end
63
+ end
64
+ end