concurrent-ruby 0.6.0.pre.2 → 0.6.0

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 (91) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -8
  3. data/lib/concurrent.rb +2 -0
  4. data/lib/concurrent/actor/actor.rb +3 -3
  5. data/lib/concurrent/actor/postable.rb +1 -1
  6. data/lib/concurrent/actors.rb +0 -3
  7. data/lib/concurrent/actress.rb +75 -0
  8. data/lib/concurrent/actress/ad_hoc.rb +14 -0
  9. data/lib/concurrent/actress/context.rb +96 -0
  10. data/lib/concurrent/actress/core.rb +204 -0
  11. data/lib/concurrent/actress/core_delegations.rb +37 -0
  12. data/lib/concurrent/actress/doc.md +53 -0
  13. data/lib/concurrent/actress/envelope.rb +25 -0
  14. data/lib/concurrent/actress/errors.rb +14 -0
  15. data/lib/concurrent/actress/reference.rb +64 -0
  16. data/lib/concurrent/actress/type_check.rb +48 -0
  17. data/lib/concurrent/agent.rb +20 -11
  18. data/lib/concurrent/async.rb +54 -25
  19. data/lib/concurrent/atomic/atomic.rb +48 -0
  20. data/lib/concurrent/atomic/atomic_boolean.rb +13 -13
  21. data/lib/concurrent/atomic/atomic_fixnum.rb +9 -17
  22. data/lib/concurrent/atomic/copy_on_notify_observer_set.rb +7 -4
  23. data/lib/concurrent/atomic/copy_on_write_observer_set.rb +16 -14
  24. data/lib/concurrent/atomic/event.rb +11 -16
  25. data/lib/concurrent/atomics.rb +1 -0
  26. data/lib/concurrent/channel/channel.rb +4 -2
  27. data/lib/concurrent/collection/blocking_ring_buffer.rb +1 -1
  28. data/lib/concurrent/configuration.rb +59 -47
  29. data/lib/concurrent/delay.rb +28 -12
  30. data/lib/concurrent/dereferenceable.rb +6 -6
  31. data/lib/concurrent/errors.rb +30 -0
  32. data/lib/concurrent/executor/executor.rb +11 -4
  33. data/lib/concurrent/executor/immediate_executor.rb +1 -0
  34. data/lib/concurrent/executor/java_thread_pool_executor.rb +4 -0
  35. data/lib/concurrent/executor/one_by_one.rb +24 -12
  36. data/lib/concurrent/executor/per_thread_executor.rb +1 -0
  37. data/lib/concurrent/executor/ruby_single_thread_executor.rb +2 -1
  38. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +7 -2
  39. data/lib/concurrent/executor/ruby_thread_pool_worker.rb +3 -0
  40. data/lib/concurrent/executor/timer_set.rb +1 -1
  41. data/lib/concurrent/future.rb +0 -2
  42. data/lib/concurrent/ivar.rb +31 -6
  43. data/lib/concurrent/logging.rb +17 -0
  44. data/lib/concurrent/mvar.rb +45 -0
  45. data/lib/concurrent/obligation.rb +61 -20
  46. data/lib/concurrent/observable.rb +7 -0
  47. data/lib/concurrent/promise.rb +1 -0
  48. data/lib/concurrent/runnable.rb +2 -2
  49. data/lib/concurrent/supervisor.rb +1 -2
  50. data/lib/concurrent/timer_task.rb +17 -13
  51. data/lib/concurrent/tvar.rb +113 -73
  52. data/lib/concurrent/utility/processor_count.rb +141 -116
  53. data/lib/concurrent/utility/timeout.rb +4 -5
  54. data/lib/concurrent/version.rb +1 -1
  55. data/spec/concurrent/actor/postable_shared.rb +1 -1
  56. data/spec/concurrent/actress_spec.rb +191 -0
  57. data/spec/concurrent/async_spec.rb +35 -3
  58. data/spec/concurrent/atomic/atomic_boolean_spec.rb +1 -1
  59. data/spec/concurrent/atomic/atomic_fixnum_spec.rb +1 -1
  60. data/spec/concurrent/atomic/atomic_spec.rb +133 -0
  61. data/spec/concurrent/atomic/count_down_latch_spec.rb +1 -1
  62. data/spec/concurrent/collection/priority_queue_spec.rb +1 -1
  63. data/spec/concurrent/configuration_spec.rb +5 -2
  64. data/spec/concurrent/delay_spec.rb +14 -0
  65. data/spec/concurrent/exchanger_spec.rb +4 -9
  66. data/spec/concurrent/executor/java_cached_thread_pool_spec.rb +1 -1
  67. data/spec/concurrent/executor/java_fixed_thread_pool_spec.rb +1 -1
  68. data/spec/concurrent/executor/java_single_thread_executor_spec.rb +1 -1
  69. data/spec/concurrent/executor/java_thread_pool_executor_spec.rb +1 -1
  70. data/spec/concurrent/executor/ruby_thread_pool_executor_spec.rb +4 -4
  71. data/spec/concurrent/ivar_spec.rb +2 -2
  72. data/spec/concurrent/obligation_spec.rb +113 -24
  73. data/spec/concurrent/observable_shared.rb +4 -0
  74. data/spec/concurrent/observable_spec.rb +8 -3
  75. data/spec/concurrent/runnable_spec.rb +2 -2
  76. data/spec/concurrent/scheduled_task_spec.rb +1 -0
  77. data/spec/concurrent/supervisor_spec.rb +26 -11
  78. data/spec/concurrent/timer_task_spec.rb +36 -35
  79. data/spec/concurrent/tvar_spec.rb +1 -1
  80. data/spec/concurrent/utility/timer_spec.rb +8 -8
  81. data/spec/spec_helper.rb +8 -18
  82. data/spec/support/example_group_extensions.rb +48 -0
  83. metadata +23 -16
  84. data/lib/concurrent/actor/actor_context.rb +0 -77
  85. data/lib/concurrent/actor/actor_ref.rb +0 -67
  86. data/lib/concurrent/actor/simple_actor_ref.rb +0 -94
  87. data/lib/concurrent_ruby_ext.bundle +0 -0
  88. data/spec/concurrent/actor/actor_context_spec.rb +0 -29
  89. data/spec/concurrent/actor/actor_ref_shared.rb +0 -263
  90. data/spec/concurrent/actor/simple_actor_ref_spec.rb +0 -135
  91. data/spec/support/functions.rb +0 -25
@@ -1,125 +1,150 @@
1
1
  require 'rbconfig'
2
+ require 'concurrent/delay'
2
3
 
3
4
  module Concurrent
4
5
 
5
- # Number of processors seen by the OS and used for process scheduling. For performance
6
- # reasons the calculated value will be memoized on the first call.
7
- #
8
- # When running under JRuby the Java runtime call `java.lang.Runtime.getRuntime.availableProcessors`
9
- # will be used. According to the Java documentation this "value may change
10
- # during a particular invocation of the virtual machine... [applications]
11
- # should therefore occasionally poll this property." Subsequently the result
12
- # will NOT be memoized under JRuby.
13
- #
14
- # On Windows the Win32 API will be queried for the `NumberOfLogicalProcessors from Win32_Processor`.
15
- # This will return the total number "logical processors for the current instance of the processor",
16
- # which taked into account hyperthreading.
17
- #
18
- # * AIX: /usr/sbin/pmcycles (AIX 5+), /usr/sbin/lsdev
19
- # * BSD: /sbin/sysctl
20
- # * Cygwin: /proc/cpuinfo
21
- # * Darwin: /usr/bin/hwprefs, /usr/sbin/sysctl
22
- # * HP-UX: /usr/sbin/ioscan
23
- # * IRIX: /usr/sbin/sysconf
24
- # * Linux: /proc/cpuinfo
25
- # * Minix 3+: /proc/cpuinfo
26
- # * Solaris: /usr/sbin/psrinfo
27
- # * Tru64 UNIX: /usr/sbin/psrinfo
28
- # * UnixWare: /usr/sbin/psrinfo
29
- #
30
- # @return [Integer] number of processors seen by the OS or Java runtime
31
- #
32
- # @see https://github.com/grosser/parallel/blob/4fc8b89d08c7091fe0419ca8fba1ec3ce5a8d185/lib/parallel.rb
33
- #
34
- # @see http://docs.oracle.com/javase/6/docs/api/java/lang/Runtime.html#availableProcessors()
35
- # @see http://msdn.microsoft.com/en-us/library/aa394373(v=vs.85).aspx
36
- def processor_count
37
- if RUBY_PLATFORM == 'java'
38
- java.lang.Runtime.getRuntime.availableProcessors
39
- else
40
- @@processor_count ||= begin
41
- os_name = RbConfig::CONFIG["target_os"]
42
- if os_name =~ /mingw|mswin/
43
- require 'win32ole'
44
- result = WIN32OLE.connect("winmgmts://").ExecQuery(
45
- "select NumberOfLogicalProcessors from Win32_Processor")
46
- result.to_enum.collect(&:NumberOfLogicalProcessors).reduce(:+)
47
- elsif File.readable?("/proc/cpuinfo")
48
- IO.read("/proc/cpuinfo").scan(/^processor/).size
49
- elsif File.executable?("/usr/bin/hwprefs")
50
- IO.popen("/usr/bin/hwprefs thread_count").read.to_i
51
- elsif File.executable?("/usr/sbin/psrinfo")
52
- IO.popen("/usr/sbin/psrinfo").read.scan(/^.*on-*line/).size
53
- elsif File.executable?("/usr/sbin/ioscan")
54
- IO.popen("/usr/sbin/ioscan -kC processor") do |out|
55
- out.read.scan(/^.*processor/).size
56
- end
57
- elsif File.executable?("/usr/sbin/pmcycles")
58
- IO.popen("/usr/sbin/pmcycles -m").read.count("\n")
59
- elsif File.executable?("/usr/sbin/lsdev")
60
- IO.popen("/usr/sbin/lsdev -Cc processor -S 1").read.count("\n")
61
- elsif File.executable?("/usr/sbin/sysconf") and os_name =~ /irix/i
62
- IO.popen("/usr/sbin/sysconf NPROC_ONLN").read.to_i
63
- elsif File.executable?("/usr/sbin/sysctl")
64
- IO.popen("/usr/sbin/sysctl -n hw.ncpu").read.to_i
65
- elsif File.executable?("/sbin/sysctl")
66
- IO.popen("/sbin/sysctl -n hw.ncpu").read.to_i
67
- else
68
- 1
69
- end
70
- end
6
+ class ProcessorCounter
7
+ def initialize
8
+ @processor_count = Delay.new { compute_processor_count }
9
+ @physical_processor_count = Delay.new { compute_physical_processor_count }
71
10
  end
72
- rescue
73
- return 1
11
+
12
+ # Number of processors seen by the OS and used for process scheduling. For performance
13
+ # reasons the calculated value will be memoized on the first call.
14
+ #
15
+ # When running under JRuby the Java runtime call `java.lang.Runtime.getRuntime.availableProcessors`
16
+ # will be used. According to the Java documentation this "value may change
17
+ # during a particular invocation of the virtual machine... [applications]
18
+ # should therefore occasionally poll this property." Subsequently the result
19
+ # will NOT be memoized under JRuby.
20
+ #
21
+ # On Windows the Win32 API will be queried for the `NumberOfLogicalProcessors from Win32_Processor`.
22
+ # This will return the total number "logical processors for the current instance of the processor",
23
+ # which taked into account hyperthreading.
24
+ #
25
+ # * AIX: /usr/sbin/pmcycles (AIX 5+), /usr/sbin/lsdev
26
+ # * BSD: /sbin/sysctl
27
+ # * Cygwin: /proc/cpuinfo
28
+ # * Darwin: /usr/bin/hwprefs, /usr/sbin/sysctl
29
+ # * HP-UX: /usr/sbin/ioscan
30
+ # * IRIX: /usr/sbin/sysconf
31
+ # * Linux: /proc/cpuinfo
32
+ # * Minix 3+: /proc/cpuinfo
33
+ # * Solaris: /usr/sbin/psrinfo
34
+ # * Tru64 UNIX: /usr/sbin/psrinfo
35
+ # * UnixWare: /usr/sbin/psrinfo
36
+ #
37
+ # @return [Integer] number of processors seen by the OS or Java runtime
38
+ #
39
+ # @see https://github.com/grosser/parallel/blob/4fc8b89d08c7091fe0419ca8fba1ec3ce5a8d185/lib/parallel.rb
40
+ #
41
+ # @see http://docs.oracle.com/javase/6/docs/api/java/lang/Runtime.html#availableProcessors()
42
+ # @see http://msdn.microsoft.com/en-us/library/aa394373(v=vs.85).aspx
43
+ def processor_count
44
+ @processor_count.value
45
+ end
46
+
47
+ # Number of physical processor cores on the current system. For performance reasons
48
+ # the calculated value will be memoized on the first call.
49
+ #
50
+ # On Windows the Win32 API will be queried for the `NumberOfCores from Win32_Processor`.
51
+ # This will return the total number "of cores for the current instance of the processor."
52
+ # On Unix-like operating systems either the `hwprefs` or `sysctl` utility will be called
53
+ # in a subshell and the returned value will be used. In the rare case where none of these
54
+ # methods work or an exception is raised the function will simply return 1.
55
+ #
56
+ # @return [Integer] number physical processor cores on the current system
57
+ #
58
+ # @see https://github.com/grosser/parallel/blob/4fc8b89d08c7091fe0419ca8fba1ec3ce5a8d185/lib/parallel.rb
59
+ #
60
+ # @see http://msdn.microsoft.com/en-us/library/aa394373(v=vs.85).aspx
61
+ # @see http://www.unix.com/man-page/osx/1/HWPREFS/
62
+ # @see http://linux.die.net/man/8/sysctl
63
+ def physical_processor_count
64
+ @physical_processor_count.value
65
+ end
66
+
67
+ private
68
+
69
+ def compute_processor_count
70
+ if RUBY_PLATFORM == 'java'
71
+ java.lang.Runtime.getRuntime.availableProcessors
72
+ else
73
+ os_name = RbConfig::CONFIG["target_os"]
74
+ if os_name =~ /mingw|mswin/
75
+ require 'win32ole'
76
+ result = WIN32OLE.connect("winmgmts://").ExecQuery(
77
+ "select NumberOfLogicalProcessors from Win32_Processor")
78
+ result.to_enum.collect(&:NumberOfLogicalProcessors).reduce(:+)
79
+ elsif File.readable?("/proc/cpuinfo")
80
+ IO.read("/proc/cpuinfo").scan(/^processor/).size
81
+ elsif File.executable?("/usr/bin/hwprefs")
82
+ IO.popen("/usr/bin/hwprefs thread_count").read.to_i
83
+ elsif File.executable?("/usr/sbin/psrinfo")
84
+ IO.popen("/usr/sbin/psrinfo").read.scan(/^.*on-*line/).size
85
+ elsif File.executable?("/usr/sbin/ioscan")
86
+ IO.popen("/usr/sbin/ioscan -kC processor") do |out|
87
+ out.read.scan(/^.*processor/).size
88
+ end
89
+ elsif File.executable?("/usr/sbin/pmcycles")
90
+ IO.popen("/usr/sbin/pmcycles -m").read.count("\n")
91
+ elsif File.executable?("/usr/sbin/lsdev")
92
+ IO.popen("/usr/sbin/lsdev -Cc processor -S 1").read.count("\n")
93
+ elsif File.executable?("/usr/sbin/sysconf") and os_name =~ /irix/i
94
+ IO.popen("/usr/sbin/sysconf NPROC_ONLN").read.to_i
95
+ elsif File.executable?("/usr/sbin/sysctl")
96
+ IO.popen("/usr/sbin/sysctl -n hw.ncpu").read.to_i
97
+ elsif File.executable?("/sbin/sysctl")
98
+ IO.popen("/sbin/sysctl -n hw.ncpu").read.to_i
99
+ else
100
+ 1
101
+ end
102
+ end
103
+ rescue
104
+ return 1
105
+ end
106
+
107
+ def compute_physical_processor_count
108
+ ppc = case RbConfig::CONFIG["target_os"]
109
+ when /darwin1/
110
+ IO.popen("/usr/sbin/sysctl -n hw.physicalcpu").read.to_i
111
+ when /linux/
112
+ cores = {} # unique physical ID / core ID combinations
113
+ phy = 0
114
+ IO.read("/proc/cpuinfo").scan(/^physical id.*|^core id.*/) do |ln|
115
+ if ln.start_with?("physical")
116
+ phy = ln[/\d+/]
117
+ elsif ln.start_with?("core")
118
+ cid = phy + ":" + ln[/\d+/]
119
+ cores[cid] = true if not cores[cid]
120
+ end
121
+ end
122
+ cores.count
123
+ when /mswin|mingw/
124
+ require 'win32ole'
125
+ result_set = WIN32OLE.connect("winmgmts://").ExecQuery(
126
+ "select NumberOfCores from Win32_Processor")
127
+ result_set.to_enum.collect(&:NumberOfCores).reduce(:+)
128
+ else
129
+ processor_count
130
+ end
131
+ # fall back to logical count if physical info is invalid
132
+ ppc > 0 ? ppc : processor_count
133
+ rescue
134
+ return 1
135
+ end
136
+ end
137
+
138
+ # create the default ProcessorCounter on load
139
+ @processor_counter = ProcessorCounter.new
140
+ singleton_class.send :attr_reader, :processor_counter
141
+
142
+ def self.processor_count
143
+ processor_counter.processor_count
74
144
  end
75
- module_function :processor_count
76
145
 
77
- # Number of physical processor cores on the current system. For performance reasons
78
- # the calculated value will be memoized on the first call.
79
- #
80
- # On Windows the Win32 API will be queried for the `NumberOfCores from Win32_Processor`.
81
- # This will return the total number "of cores for the current instance of the processor."
82
- # On Unix-like operating systems either the `hwprefs` or `sysctl` utility will be called
83
- # in a subshell and the returned value will be used. In the rare case where none of these
84
- # methods work or an exception is raised the function will simply return 1.
85
- #
86
- # @return [Integer] number physical processor cores on the current system
87
- #
88
- # @see https://github.com/grosser/parallel/blob/4fc8b89d08c7091fe0419ca8fba1ec3ce5a8d185/lib/parallel.rb
89
- #
90
- # @see http://msdn.microsoft.com/en-us/library/aa394373(v=vs.85).aspx
91
- # @see http://www.unix.com/man-page/osx/1/HWPREFS/
92
- # @see http://linux.die.net/man/8/sysctl
93
- def physical_processor_count
94
- @@physical_processor_count ||= begin
95
- ppc = case RbConfig::CONFIG["target_os"]
96
- when /darwin1/
97
- IO.popen("/usr/sbin/sysctl -n hw.physicalcpu").read.to_i
98
- when /linux/
99
- cores = {} # unique physical ID / core ID combinations
100
- phy = 0
101
- IO.read("/proc/cpuinfo").scan(/^physical id.*|^core id.*/) do |ln|
102
- if ln.start_with?("physical")
103
- phy = ln[/\d+/]
104
- elsif ln.start_with?("core")
105
- cid = phy + ":" + ln[/\d+/]
106
- cores[cid] = true if not cores[cid]
107
- end
108
- end
109
- cores.count
110
- when /mswin|mingw/
111
- require 'win32ole'
112
- result_set = WIN32OLE.connect("winmgmts://").ExecQuery(
113
- "select NumberOfCores from Win32_Processor")
114
- result_set.to_enum.collect(&:NumberOfCores).reduce(:+)
115
- else
116
- processor_count
117
- end
118
- # fall back to logical count if physical info is invalid
119
- ppc > 0 ? ppc : processor_count
120
- end
121
- rescue
122
- return 1
146
+ def self.physical_processor_count
147
+ processor_counter.physical_processor_count
123
148
  end
124
- module_function :physical_processor_count
149
+
125
150
  end
@@ -1,18 +1,17 @@
1
1
  require 'rbconfig'
2
2
  require 'thread'
3
3
 
4
- module Concurrent
4
+ require 'concurrent/errors'
5
5
 
6
- # Error raised when an operations times out.
7
- TimeoutError = Class.new(StandardError)
6
+ module Concurrent
8
7
 
9
8
  # Wait the given number of seconds for the block operation to complete.
10
9
  #
11
10
  # @param [Integer] seconds The number of seconds to wait
12
11
  #
13
- # @return The result of the block operation
12
+ # @return [Object] The result of the block operation
14
13
  #
15
- # @raise Concurrent::TimeoutError when the block operation does not complete
14
+ # @raise [Concurrent::TimeoutError] when the block operation does not complete
16
15
  # in the allotted number of seconds.
17
16
  #
18
17
  # @note This method is intended to be a simpler and more reliable replacement
@@ -1,3 +1,3 @@
1
1
  module Concurrent
2
- VERSION = '0.6.0.pre.2'
2
+ VERSION = '0.6.0'
3
3
  end
@@ -94,7 +94,7 @@ share_examples_for :postable do
94
94
  it 'raises Concurrent::Runnable::LifecycleError when not running' do
95
95
  expect {
96
96
  subject.post!(1, 'Hello World!')
97
- }.to raise_error(Concurrent::Runnable::LifecycleError)
97
+ }.to raise_error(Concurrent::LifecycleError)
98
98
  end
99
99
 
100
100
  it 'blocks for up to the given number of seconds' do
@@ -0,0 +1,191 @@
1
+ require 'spec_helper'
2
+ require 'concurrent/actress'
3
+
4
+ module Concurrent
5
+ module Actress
6
+ describe 'Concurrent::Actress' do
7
+
8
+ class Ping
9
+ include Context
10
+
11
+ def initialize(queue)
12
+ @queue = queue
13
+ end
14
+
15
+ def on_message(message)
16
+ case message
17
+ when :terminate
18
+ terminate!
19
+ when :child
20
+ AdHoc.spawn(:pong, @queue) { |queue| -> m { queue << m } }
21
+ else
22
+ @queue << message
23
+ message
24
+ end
25
+ end
26
+ end
27
+
28
+ # def trace!
29
+ # set_trace_func proc { |event, file, line, id, binding, classname|
30
+ # # thread = eval('Thread.current', binding).object_id.to_s(16)
31
+ # printf "%8s %20s %20s %s %s:%-2d\n", event, id, classname, nil, file, line
32
+ # }
33
+ # yield
34
+ # ensure
35
+ # set_trace_func nil
36
+ # end
37
+
38
+ #describe 'stress test' do
39
+ #pending('may cause deadlock which prevents test run from completing.')
40
+ #1.times do |i|
41
+ #it format('run %3d', i) do
42
+ ## puts format('run %3d', i)
43
+ #Array.new(10).map do
44
+ #Thread.new do
45
+ #10.times do
46
+ ## trace! do
47
+ #queue = Queue.new
48
+ #actor = Ping.spawn :ping, queue
49
+
50
+ ## when spawn returns children are set
51
+ #Concurrent::Actress::ROOT.send(:core).instance_variable_get(:@children).should include(actor)
52
+
53
+ #actor << 'a' << 1
54
+ #queue.pop.should eq 'a'
55
+ #actor.ask(2).value.should eq 2
56
+
57
+ #actor.parent.should eq Concurrent::Actress::ROOT
58
+ #Concurrent::Actress::ROOT.path.should eq '/'
59
+ #actor.path.should eq '/ping'
60
+ #child = actor.ask(:child).value
61
+ #child.path.should eq '/ping/pong'
62
+ #queue.clear
63
+ #child.ask(3)
64
+ #queue.pop.should eq 3
65
+
66
+ #actor << :terminate
67
+ #actor.ask(:blow_up).wait.should be_rejected
68
+ #end
69
+ #end
70
+ #end.each(&:join)
71
+ #end
72
+ #end
73
+ #end
74
+
75
+ describe 'spawning' do
76
+ #describe 'Actress#spawn' do
77
+ #behaviour = -> v { -> _ { v } }
78
+ #subjects = { spawn: -> { Actress.spawn(AdHoc, :ping, 'arg', &behaviour) },
79
+ #context_spawn: -> { AdHoc.spawn(:ping, 'arg', &behaviour) },
80
+ #spawn_by_hash: -> { Actress.spawn(class: AdHoc, name: :ping, args: ['arg'], &behaviour) },
81
+ #context_spawn_by_hash: -> { AdHoc.spawn(name: :ping, args: ['arg'], &behaviour) } }
82
+
83
+ #subjects.each do |desc, subject_definition|
84
+ #describe desc do
85
+ #subject &subject_definition
86
+ #its(:path) { pending('may cause deadlock which prevents test run from completing.'); should eq '/ping' }
87
+ #its(:parent) { pending('may cause deadlock which prevents test run from completing.'); should eq ROOT }
88
+ #its(:name) { pending('may cause deadlock which prevents test run from completing.'); should eq 'ping' }
89
+ #its(:executor) { pending('may cause deadlock which prevents test run from completing.'); should eq Concurrent.configuration.global_task_pool }
90
+ #its(:reference) { pending('may cause deadlock which prevents test run from completing.'); should eq subject }
91
+ #it 'returns ars' do
92
+ #subject.ask!(:anything).should eq 'arg'
93
+ #end
94
+ #end
95
+ #end
96
+ #end
97
+
98
+ it 'terminates on failed initialization' do
99
+ pending('may cause deadlock which prevents test run from completing.')
100
+ a = AdHoc.spawn(name: :fail, logger: Concurrent.configuration.no_logger) { raise }
101
+ a.ask(nil).wait.rejected?.should be_true
102
+ a.terminated?.should be_true
103
+ end
104
+
105
+ it 'terminates on failed initialization and raises with spawn!' do
106
+ pending('may cause deadlock which prevents test run from completing.')
107
+ expect do
108
+ AdHoc.spawn!(name: :fail, logger: Concurrent.configuration.no_logger) { raise 'm' }
109
+ end.to raise_error(StandardError, 'm')
110
+ end
111
+
112
+ it 'terminates on failed message processing' do
113
+ pending('may cause deadlock which prevents test run from completing.')
114
+ a = AdHoc.spawn(name: :fail, logger: Concurrent.configuration.no_logger) { -> _ { raise } }
115
+ a.ask(nil).wait.rejected?.should be_true
116
+ a.terminated?.should be_true
117
+ end
118
+ end
119
+
120
+ describe 'messaging' do
121
+ subject { AdHoc.spawn(:add) { c = 0; -> v { c = c + v } } }
122
+ specify do
123
+ pending('may cause deadlock which prevents test run from completing.')
124
+ subject.tell(1).tell(1)
125
+ subject << 1 << 1
126
+ subject.ask(0).value!.should eq 4
127
+ end
128
+ end
129
+
130
+ describe 'children' do
131
+ let(:parent) do
132
+ AdHoc.spawn(:parent) do
133
+ -> message do
134
+ if message == :child
135
+ AdHoc.spawn(:child) { -> _ { parent } }
136
+ else
137
+ children
138
+ end
139
+ end
140
+ end
141
+ end
142
+
143
+ it 'has children set after a child is created' do
144
+ pending('may cause deadlock which prevents test run from completing.')
145
+ child = parent.ask!(:child)
146
+ parent.ask!(nil).should include(child)
147
+ child.ask!(nil).should eq parent
148
+ end
149
+ end
150
+
151
+ describe 'envelope' do
152
+ subject { AdHoc.spawn(:subject) { -> _ { envelope } } }
153
+ specify do
154
+ pending('may cause deadlock which prevents test run from completing.')
155
+ envelope = subject.ask!('a')
156
+ envelope.should be_a_kind_of Envelope
157
+ envelope.message.should eq 'a'
158
+ envelope.ivar.should be_completed
159
+ envelope.ivar.value.should eq envelope
160
+ envelope.sender.should eq Thread.current
161
+ end
162
+ end
163
+
164
+ describe 'termination' do
165
+ subject do
166
+ AdHoc.spawn(:parent) do
167
+ child = AdHoc.spawn(:child) { -> v { v } }
168
+ -> v do
169
+ if v == :terminate
170
+ terminate!
171
+ else
172
+ child
173
+ end
174
+ end
175
+ end
176
+ end
177
+
178
+ it 'terminates with all its children' do
179
+ pending('may cause deadlock which prevents test run from completing.')
180
+ child = subject.ask! :child
181
+ subject.terminated?.should be_false
182
+ subject.ask(:terminate).wait
183
+ subject.terminated?.should be_true
184
+ child.terminated.wait
185
+ child.terminated?.should be_true
186
+ end
187
+ end
188
+
189
+ end
190
+ end
191
+ end