concurrent-ruby 0.6.0.pre.2 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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