concurrent-ruby 0.6.1 → 0.7.0.rc0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/concurrent.rb +3 -4
  4. data/lib/concurrent/atomic.rb +46 -0
  5. data/lib/concurrent/atomic_reference/concurrent_update_error.rb +7 -0
  6. data/lib/concurrent/atomic_reference/delegated_update.rb +28 -0
  7. data/lib/concurrent/atomic_reference/direct_update.rb +28 -0
  8. data/lib/concurrent/atomic_reference/jruby.rb +8 -0
  9. data/lib/concurrent/atomic_reference/mutex_atomic.rb +47 -0
  10. data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +24 -0
  11. data/lib/concurrent/atomic_reference/rbx.rb +16 -0
  12. data/lib/concurrent/atomic_reference/ruby.rb +16 -0
  13. data/lib/concurrent/atomics.rb +1 -1
  14. data/lib/concurrent/configuration.rb +1 -1
  15. data/lib/concurrent/supervisor.rb +1 -1
  16. data/lib/concurrent/timer_task.rb +0 -36
  17. data/lib/concurrent/version.rb +1 -1
  18. data/lib/concurrent_ruby_ext.so +0 -0
  19. data/lib/extension_helper.rb +9 -0
  20. metadata +16 -148
  21. data/lib/concurrent/actor/actor.rb +0 -270
  22. data/lib/concurrent/actor/postable.rb +0 -102
  23. data/lib/concurrent/actors.rb +0 -2
  24. data/lib/concurrent/atomic/atomic.rb +0 -48
  25. data/lib/concurrent/runnable.rb +0 -90
  26. data/lib/concurrent/stoppable.rb +0 -20
  27. data/spec/concurrent/actor/actor_spec.rb +0 -376
  28. data/spec/concurrent/actor/postable_shared.rb +0 -218
  29. data/spec/concurrent/actress_spec.rb +0 -211
  30. data/spec/concurrent/agent_spec.rb +0 -500
  31. data/spec/concurrent/async_spec.rb +0 -352
  32. data/spec/concurrent/atomic/atomic_boolean_spec.rb +0 -172
  33. data/spec/concurrent/atomic/atomic_fixnum_spec.rb +0 -186
  34. data/spec/concurrent/atomic/atomic_spec.rb +0 -133
  35. data/spec/concurrent/atomic/condition_spec.rb +0 -171
  36. data/spec/concurrent/atomic/copy_on_notify_observer_set_spec.rb +0 -10
  37. data/spec/concurrent/atomic/copy_on_write_observer_set_spec.rb +0 -10
  38. data/spec/concurrent/atomic/count_down_latch_spec.rb +0 -151
  39. data/spec/concurrent/atomic/cyclic_barrier_spec.rb +0 -248
  40. data/spec/concurrent/atomic/event_spec.rb +0 -200
  41. data/spec/concurrent/atomic/observer_set_shared.rb +0 -242
  42. data/spec/concurrent/atomic/thread_local_var_spec.rb +0 -113
  43. data/spec/concurrent/channel/buffered_channel_spec.rb +0 -151
  44. data/spec/concurrent/channel/channel_spec.rb +0 -39
  45. data/spec/concurrent/channel/probe_spec.rb +0 -77
  46. data/spec/concurrent/channel/unbuffered_channel_spec.rb +0 -132
  47. data/spec/concurrent/collection/blocking_ring_buffer_spec.rb +0 -149
  48. data/spec/concurrent/collection/priority_queue_spec.rb +0 -317
  49. data/spec/concurrent/collection/ring_buffer_spec.rb +0 -126
  50. data/spec/concurrent/configuration_spec.rb +0 -69
  51. data/spec/concurrent/dataflow_spec.rb +0 -242
  52. data/spec/concurrent/delay_spec.rb +0 -91
  53. data/spec/concurrent/dereferenceable_shared.rb +0 -146
  54. data/spec/concurrent/exchanger_spec.rb +0 -66
  55. data/spec/concurrent/executor/cached_thread_pool_shared.rb +0 -115
  56. data/spec/concurrent/executor/fixed_thread_pool_shared.rb +0 -136
  57. data/spec/concurrent/executor/global_thread_pool_shared.rb +0 -35
  58. data/spec/concurrent/executor/immediate_executor_spec.rb +0 -12
  59. data/spec/concurrent/executor/java_cached_thread_pool_spec.rb +0 -44
  60. data/spec/concurrent/executor/java_fixed_thread_pool_spec.rb +0 -64
  61. data/spec/concurrent/executor/java_single_thread_executor_spec.rb +0 -21
  62. data/spec/concurrent/executor/java_thread_pool_executor_spec.rb +0 -71
  63. data/spec/concurrent/executor/per_thread_executor_spec.rb +0 -57
  64. data/spec/concurrent/executor/ruby_cached_thread_pool_spec.rb +0 -69
  65. data/spec/concurrent/executor/ruby_fixed_thread_pool_spec.rb +0 -39
  66. data/spec/concurrent/executor/ruby_single_thread_executor_spec.rb +0 -18
  67. data/spec/concurrent/executor/ruby_thread_pool_executor_spec.rb +0 -171
  68. data/spec/concurrent/executor/safe_task_executor_spec.rb +0 -103
  69. data/spec/concurrent/executor/thread_pool_class_cast_spec.rb +0 -52
  70. data/spec/concurrent/executor/thread_pool_executor_shared.rb +0 -155
  71. data/spec/concurrent/executor/thread_pool_shared.rb +0 -269
  72. data/spec/concurrent/executor/timer_set_spec.rb +0 -183
  73. data/spec/concurrent/future_spec.rb +0 -329
  74. data/spec/concurrent/ivar_spec.rb +0 -215
  75. data/spec/concurrent/mvar_spec.rb +0 -380
  76. data/spec/concurrent/obligation_shared.rb +0 -102
  77. data/spec/concurrent/obligation_spec.rb +0 -282
  78. data/spec/concurrent/observable_shared.rb +0 -177
  79. data/spec/concurrent/observable_spec.rb +0 -56
  80. data/spec/concurrent/options_parser_spec.rb +0 -71
  81. data/spec/concurrent/promise_spec.rb +0 -367
  82. data/spec/concurrent/runnable_shared.rb +0 -68
  83. data/spec/concurrent/runnable_spec.rb +0 -235
  84. data/spec/concurrent/scheduled_task_spec.rb +0 -340
  85. data/spec/concurrent/stoppable_shared.rb +0 -37
  86. data/spec/concurrent/supervisor_spec.rb +0 -1149
  87. data/spec/concurrent/timer_task_spec.rb +0 -256
  88. data/spec/concurrent/tvar_spec.rb +0 -137
  89. data/spec/concurrent/utility/processor_count_spec.rb +0 -20
  90. data/spec/concurrent/utility/timeout_spec.rb +0 -50
  91. data/spec/concurrent/utility/timer_spec.rb +0 -52
  92. data/spec/spec_helper.rb +0 -41
  93. data/spec/support/example_group_extensions.rb +0 -52
  94. data/spec/support/less_than_or_equal_to_matcher.rb +0 -5
@@ -1,183 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module Concurrent
4
-
5
- describe TimerSet do
6
-
7
- subject{ TimerSet.new(executor: ImmediateExecutor.new) }
8
-
9
- after(:each){ subject.kill }
10
-
11
- it 'uses the executor given at construction' do
12
- executor = double(:executor)
13
- executor.should_receive(:post).with(no_args)
14
- subject = TimerSet.new(executor: executor)
15
- subject.post(0){ nil }
16
- sleep(0.1)
17
- end
18
-
19
- it 'uses the global task pool be default' do
20
- Concurrent.configuration.global_task_pool.should_receive(:post).with(no_args)
21
- subject = TimerSet.new
22
- subject.post(0){ nil }
23
- sleep(0.1)
24
- end
25
-
26
- it 'executes a given task when given a Time' do
27
- latch = CountDownLatch.new(1)
28
- subject.post(Time.now + 0.1){ latch.count_down }
29
- latch.wait(0.2).should be_true
30
- end
31
-
32
- it 'executes a given task when given an interval in seconds' do
33
- latch = CountDownLatch.new(1)
34
- subject.post(0.1){ latch.count_down }
35
- latch.wait(0.2).should be_true
36
- end
37
-
38
- it 'passes all arguments to the task on execution' do
39
- expected = nil
40
- latch = CountDownLatch.new(1)
41
- subject.post(0.1, 1, 2, 3) do |*args|
42
- expected = args
43
- latch.count_down
44
- end
45
- latch.wait(0.2).should be_true
46
- expected.should eq [1, 2, 3]
47
- end
48
-
49
- it 'immediately posts a task when the delay is zero' do
50
- Thread.should_not_receive(:new).with(any_args)
51
- subject.post(0){ true }
52
- end
53
-
54
- it 'does not execute tasks early' do
55
- expected = AtomicFixnum.new(0)
56
- subject.post(0.2){ expected.increment }
57
- sleep(0.15)
58
- expected.value.should eq 0
59
- sleep(0.10)
60
- expected.value.should eq 1
61
- end
62
-
63
- it 'raises an exception when given a task with a past Time value' do
64
- expect {
65
- subject.post(Time.now - 10){ nil }
66
- }.to raise_error(ArgumentError)
67
- end
68
-
69
- it 'raises an exception when given a task with a delay less than zero' do
70
- expect {
71
- subject.post(-10){ nil }
72
- }.to raise_error(ArgumentError)
73
- end
74
-
75
- it 'raises an exception when no block given' do
76
- expect {
77
- subject.post(10)
78
- }.to raise_error(ArgumentError)
79
- end
80
-
81
- it 'executes all tasks scheduled for the same time' do
82
- latch = CountDownLatch.new(5)
83
- 5.times{ subject.post(0.1){ latch.count_down } }
84
- latch.wait(0.2).should be_true
85
- end
86
-
87
- it 'executes tasks with different times in schedule order' do
88
- expected = []
89
- 3.times{|i| subject.post(i/10){ expected << i } }
90
- sleep(0.3)
91
- expected.should eq [0, 1, 2]
92
- end
93
-
94
- it 'cancels all pending tasks on #shutdown' do
95
- expected = AtomicFixnum.new(0)
96
- 10.times{ subject.post(0.2){ expected.increment } }
97
- sleep(0.1)
98
- subject.shutdown
99
- sleep(0.2)
100
- expected.value.should eq 0
101
- end
102
-
103
- it 'cancels all pending tasks on #kill' do
104
- expected = AtomicFixnum.new(0)
105
- 10.times{ subject.post(0.2){ expected.increment } }
106
- sleep(0.1)
107
- subject.kill
108
- sleep(0.2)
109
- expected.value.should eq 0
110
- end
111
-
112
- it 'stops the monitor thread on #shutdown' do
113
- timer_executor = subject.instance_variable_get(:@timer_executor)
114
- subject.shutdown
115
- sleep(0.1)
116
- timer_executor.should_not be_running
117
- end
118
-
119
- it 'kills the monitor thread on #kill' do
120
- timer_executor = subject.instance_variable_get(:@timer_executor)
121
- subject.kill
122
- sleep(0.1)
123
- timer_executor.should_not be_running
124
- end
125
-
126
- it 'rejects tasks once shutdown' do
127
- expected = AtomicFixnum.new(0)
128
- subject.shutdown
129
- sleep(0.1)
130
- subject.post(0){ expected.increment }.should be_false
131
- sleep(0.1)
132
- expected.value.should eq 0
133
- end
134
-
135
- it 'rejects tasks once killed' do
136
- expected = AtomicFixnum.new(0)
137
- subject.kill
138
- sleep(0.1)
139
- subject.post(0){ expected.increment }.should be_false
140
- sleep(0.1)
141
- expected.value.should eq 0
142
- end
143
-
144
- it 'is running? when first created' do
145
- subject.should be_running
146
- subject.should_not be_shutdown
147
- end
148
-
149
- it 'is running? after tasks have been post' do
150
- subject.post(0.1){ nil }
151
- subject.should be_running
152
- subject.should_not be_shutdown
153
- end
154
-
155
- it 'is shutdown? after shutdown completes' do
156
- subject.shutdown
157
- sleep(0.1)
158
- subject.should_not be_running
159
- subject.should be_shutdown
160
- end
161
-
162
- it 'is shutdown? after being killed' do
163
- subject.kill
164
- sleep(0.1)
165
- subject.should_not be_running
166
- subject.should be_shutdown
167
- end
168
-
169
- specify '#wait_for_termination returns true if shutdown completes before timeout' do
170
- subject.post(0.1){ nil }
171
- sleep(0.1)
172
- subject.shutdown
173
- subject.wait_for_termination(0.1).should be_true
174
- end
175
-
176
- specify '#wait_for_termination returns false on timeout' do
177
- subject.post(0.1){ nil }
178
- sleep(0.1)
179
- # do not call shutdown -- force timeout
180
- subject.wait_for_termination(0.1).should be_false
181
- end
182
- end
183
- end
@@ -1,329 +0,0 @@
1
- require 'spec_helper'
2
- require_relative 'dereferenceable_shared'
3
- require_relative 'obligation_shared'
4
- require_relative 'observable_shared'
5
-
6
- module Concurrent
7
-
8
- describe Future do
9
-
10
- let!(:value) { 10 }
11
- let(:executor) { PerThreadExecutor.new }
12
-
13
- subject do
14
- Future.new(executor: executor){
15
- value
16
- }.execute.tap{ sleep(0.1) }
17
- end
18
-
19
- context 'behavior' do
20
-
21
- # obligation
22
-
23
- let!(:fulfilled_value) { 10 }
24
- let!(:rejected_reason) { StandardError.new('mojo jojo') }
25
-
26
- let(:pending_subject) do
27
- Future.new(executor: executor){ sleep(3); fulfilled_value }.execute
28
- end
29
-
30
- let(:fulfilled_subject) do
31
- Future.new(executor: executor){ fulfilled_value }.execute.tap{ sleep(0.1) }
32
- end
33
-
34
- let(:rejected_subject) do
35
- Future.new(executor: executor){ raise rejected_reason }.execute.tap{ sleep(0.1) }
36
- end
37
-
38
- it_should_behave_like :obligation
39
-
40
- # dereferenceable
41
-
42
- def dereferenceable_subject(value, opts = {})
43
- opts = opts.merge(executor: executor)
44
- Future.new(opts){ value }.execute.tap{ sleep(0.1) }
45
- end
46
-
47
- def dereferenceable_observable(opts = {})
48
- opts = opts.merge(executor: executor)
49
- Future.new(opts){ 'value' }
50
- end
51
-
52
- def execute_dereferenceable(subject)
53
- subject.execute
54
- sleep(0.1)
55
- end
56
-
57
- it_should_behave_like :dereferenceable
58
-
59
- # observable
60
-
61
- subject{ Future.new{ nil } }
62
-
63
- def trigger_observable(observable)
64
- observable.execute
65
- sleep(0.1)
66
- end
67
-
68
- it_should_behave_like :observable
69
- end
70
-
71
- context 'subclassing' do
72
-
73
- subject{ Future.execute(executor: executor){ 42 } }
74
-
75
- it 'protects #set' do
76
- expect{ subject.set(100) }.to raise_error
77
- end
78
-
79
- it 'protects #fail' do
80
- expect{ subject.fail }.to raise_error
81
- end
82
-
83
- it 'protects #complete' do
84
- expect{ subject.complete(true, 100, nil) }.to raise_error
85
- end
86
- end
87
-
88
- context '#initialize' do
89
-
90
- let(:executor) { ImmediateExecutor.new }
91
-
92
- it 'sets the state to :unscheduled' do
93
- Future.new(executor: executor){ nil }.should be_unscheduled
94
- end
95
-
96
- it 'raises an exception when no block given' do
97
- expect {
98
- Future.new.execute
99
- }.to raise_error(ArgumentError)
100
- end
101
-
102
- it 'uses the executor given with the :executor option' do
103
- executor.should_receive(:post)
104
- Future.execute(executor: executor){ nil }
105
- end
106
-
107
- it 'uses the global operation pool when :operation is true' do
108
- Concurrent.configuration.should_receive(:global_operation_pool).and_return(executor)
109
- Future.execute(operation: true){ nil }
110
- end
111
-
112
- it 'uses the global task pool when :task is true' do
113
- Concurrent.configuration.should_receive(:global_task_pool).and_return(executor)
114
- Future.execute(task: true){ nil }
115
- end
116
-
117
- it 'uses the global task pool by default' do
118
- Concurrent.configuration.should_receive(:global_task_pool).and_return(executor)
119
- Future.execute{ nil }
120
- end
121
- end
122
-
123
- context 'instance #execute' do
124
-
125
- it 'does nothing unless the state is :unscheduled' do
126
- executor = ImmediateExecutor.new
127
- executor.should_not_receive(:post).with(any_args)
128
- future = Future.new(executor: executor){ nil }
129
- future.instance_variable_set(:@state, :pending)
130
- future.execute
131
- future.instance_variable_set(:@state, :rejected)
132
- future.execute
133
- future.instance_variable_set(:@state, :fulfilled)
134
- future.execute
135
- end
136
-
137
- it 'posts the block given on construction' do
138
- executor.should_receive(:post).with(any_args)
139
- future = Future.new(executor: executor){ nil }
140
- future.execute
141
- end
142
-
143
- it 'sets the state to :pending' do
144
- future = Future.new(executor: executor){ sleep(0.1) }
145
- future.execute
146
- future.should be_pending
147
- end
148
-
149
- it 'returns self' do
150
- future = Future.new(executor: executor){ nil }
151
- future.execute.should be future
152
- end
153
- end
154
-
155
- context 'class #execute' do
156
-
157
- let(:executor) { ImmediateExecutor.new }
158
-
159
- it 'creates a new Future' do
160
- future = Future.execute(executor: executor){ nil }
161
- future.should be_a(Future)
162
- end
163
-
164
- it 'passes the block to the new Future' do
165
- @expected = false
166
- Future.execute(executor: executor){ @expected = true }
167
- @expected.should be_true
168
- end
169
-
170
- it 'calls #execute on the new Future' do
171
- future = double('future')
172
- Future.stub(:new).with(any_args).and_return(future)
173
- future.should_receive(:execute).with(no_args)
174
- Future.execute{ nil }
175
- end
176
- end
177
-
178
- context 'fulfillment' do
179
-
180
- let(:executor) { ImmediateExecutor.new }
181
-
182
- it 'passes all arguments to handler' do
183
- @expected = false
184
- Future.new(executor: executor){ @expected = true }.execute
185
- @expected.should be_true
186
- end
187
-
188
- it 'sets the value to the result of the handler' do
189
- future = Future.new(executor: executor){ 42 }.execute
190
- future.value.should eq 42
191
- end
192
-
193
- it 'sets the state to :fulfilled when the block completes' do
194
- future = Future.new(executor: executor){ 42 }.execute
195
- future.should be_fulfilled
196
- end
197
-
198
- it 'sets the value to nil when the handler raises an exception' do
199
- future = Future.new(executor: executor){ raise StandardError }.execute
200
- future.value.should be_nil
201
- end
202
-
203
- it 'sets the state to :rejected when the handler raises an exception' do
204
- future = Future.new(executor: executor){ raise StandardError }.execute
205
- future.should be_rejected
206
- end
207
-
208
- context 'aliases' do
209
-
210
- it 'aliases #realized? for #fulfilled?' do
211
- subject.should be_realized
212
- end
213
-
214
- it 'aliases #deref for #value' do
215
- subject.deref.should eq value
216
- end
217
- end
218
- end
219
-
220
- context 'observation' do
221
-
222
- let(:executor) { ImmediateExecutor.new }
223
-
224
- let(:clazz) do
225
- Class.new do
226
- attr_reader :value
227
- attr_reader :reason
228
- attr_reader :count
229
- define_method(:update) do |time, value, reason|
230
- @count = @count.to_i + 1
231
- @value = value
232
- @reason = reason
233
- end
234
- end
235
- end
236
-
237
- let(:observer) { clazz.new }
238
-
239
- it 'notifies all observers on fulfillment' do
240
- future = Future.new(executor: executor){ 42 }
241
- future.add_observer(observer)
242
-
243
- future.execute
244
-
245
- observer.value.should == 42
246
- observer.reason.should be_nil
247
- end
248
-
249
- it 'notifies all observers on rejection' do
250
- future = Future.new(executor: executor){ raise StandardError }
251
- future.add_observer(observer)
252
-
253
- future.execute
254
-
255
- observer.value.should be_nil
256
- observer.reason.should be_a(StandardError)
257
- end
258
-
259
- it 'notifies an observer added after fulfillment' do
260
- future = Future.new(executor: executor){ 42 }.execute
261
- future.add_observer(observer)
262
- observer.value.should == 42
263
- end
264
-
265
- it 'notifies an observer added after rejection' do
266
- future = Future.new(executor: executor){ raise StandardError }.execute
267
- future.add_observer(observer)
268
- observer.reason.should be_a(StandardError)
269
- end
270
-
271
- it 'does not notify existing observers when a new observer added after fulfillment' do
272
- future = Future.new(executor: executor){ 42 }.execute
273
- future.add_observer(observer)
274
-
275
- observer.count.should == 1
276
-
277
- o2 = clazz.new
278
- future.add_observer(o2)
279
-
280
- observer.count.should == 1
281
- o2.value.should == 42
282
- end
283
-
284
- it 'does not notify existing observers when a new observer added after rejection' do
285
- future = Future.new(executor: executor){ raise StandardError }.execute
286
- future.add_observer(observer)
287
-
288
- observer.count.should == 1
289
-
290
- o2 = clazz.new
291
- future.add_observer(o2)
292
-
293
- observer.count.should == 1
294
- o2.reason.should be_a(StandardError)
295
- end
296
-
297
- context 'deadlock avoidance' do
298
-
299
- def reentrant_observer(future)
300
- obs = Object.new
301
- obs.define_singleton_method(:update) do |time, value, reason|
302
- @value = future.value
303
- end
304
- obs.define_singleton_method(:value) { @value }
305
- obs
306
- end
307
-
308
- it 'should notify observers outside mutex lock' do
309
- future = Future.new(executor: executor){ 42 }
310
- obs = reentrant_observer(future)
311
-
312
- future.add_observer(obs)
313
- future.execute
314
-
315
- obs.value.should eq 42
316
- end
317
-
318
- it 'should notify a new observer added after fulfillment outside lock' do
319
- future = Future.new(executor: executor){ 42 }.execute
320
- obs = reentrant_observer(future)
321
-
322
- future.add_observer(obs)
323
-
324
- obs.value.should eq 42
325
- end
326
- end
327
- end
328
- end
329
- end