concurrent-ruby-edge 0.2.0.pre4 → 0.2.0.pre5
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.
- checksums.yaml +4 -4
- data/lib/concurrent/actor/behaviour/abstract.rb +1 -2
- data/lib/concurrent/actor/behaviour/sets_results.rb +1 -1
- data/lib/concurrent/actor/context.rb +0 -1
- data/lib/concurrent/actor/core.rb +2 -2
- data/lib/concurrent/actor/default_dead_letter_handler.rb +1 -1
- data/lib/concurrent/actor/internal_delegations.rb +1 -0
- data/lib/concurrent/channel.rb +44 -21
- data/lib/concurrent/channel/buffer/base.rb +51 -23
- data/lib/concurrent/channel/buffer/buffered.rb +11 -19
- data/lib/concurrent/channel/buffer/ticker.rb +14 -55
- data/lib/concurrent/channel/buffer/timer.rb +33 -27
- data/lib/concurrent/channel/buffer/unbuffered.rb +21 -16
- data/lib/concurrent/channel/selector.rb +6 -1
- data/lib/concurrent/channel/tick.rb +3 -1
- data/lib/concurrent/edge/atomic_markable_reference.rb +2 -1
- data/lib/concurrent/edge/future.rb +18 -21
- data/lib/concurrent/edge/lock_free_stack.rb +2 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 49c297b646de061530808c991d1e19221dc1b6a7
|
4
|
+
data.tar.gz: 1301f31a7ff10f078525eb5e3158428b012d1517
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b4850c4f01294b27c7bfeae6a0ad37ee22a255be4097e318fcfeca022de20f5436a756ea7ff7754f39148483c728a6867267b585240719d2d9981fc317c1944
|
7
|
+
data.tar.gz: 46e2136e70cc3b20d1fd3f4a118010b4c26190bd218811fea3a3e53cb03668a89a5744f7f59e71aefa498ed6936f61deab8d4fe525c0a466ff9f95e620e2ed3a
|
@@ -6,7 +6,6 @@ module Concurrent
|
|
6
6
|
class Abstract
|
7
7
|
include TypeCheck
|
8
8
|
include InternalDelegations
|
9
|
-
include Concern::Logging
|
10
9
|
|
11
10
|
attr_reader :core, :subsequent
|
12
11
|
|
@@ -42,7 +41,7 @@ module Concurrent
|
|
42
41
|
def reject_envelope(envelope)
|
43
42
|
envelope.reject! ActorTerminated.new(reference)
|
44
43
|
dead_letter_routing << envelope unless envelope.future
|
45
|
-
log
|
44
|
+
log(DEBUG) { "rejected #{envelope.message} from #{envelope.sender_path}"}
|
46
45
|
end
|
47
46
|
end
|
48
47
|
end
|
@@ -14,7 +14,7 @@ module Concurrent
|
|
14
14
|
result = pass envelope
|
15
15
|
if result != MESSAGE_PROCESSED && !envelope.future.nil?
|
16
16
|
envelope.future.success result
|
17
|
-
log
|
17
|
+
log(DEBUG) { "finished processing of #{envelope.message.inspect}"}
|
18
18
|
end
|
19
19
|
nil
|
20
20
|
rescue => error
|
@@ -91,7 +91,7 @@ module Concurrent
|
|
91
91
|
# @param [Envelope] envelope
|
92
92
|
def on_envelope(envelope)
|
93
93
|
schedule_execution do
|
94
|
-
log
|
94
|
+
log(DEBUG) { "was #{envelope.future ? 'asked' : 'told'} #{envelope.message.inspect} by #{envelope.sender}" }
|
95
95
|
process_envelope envelope
|
96
96
|
end
|
97
97
|
nil
|
@@ -128,7 +128,7 @@ module Concurrent
|
|
128
128
|
end
|
129
129
|
|
130
130
|
def broadcast(public, event)
|
131
|
-
log
|
131
|
+
log(DEBUG) { "event: #{event.inspect} (#{public ? 'public' : 'private'})" }
|
132
132
|
@first_behaviour.on_event(public, event)
|
133
133
|
end
|
134
134
|
|
data/lib/concurrent/channel.rb
CHANGED
@@ -12,7 +12,7 @@ module Concurrent
|
|
12
12
|
include Enumerable
|
13
13
|
|
14
14
|
# NOTE: Move to global IO pool once stable
|
15
|
-
GOROUTINES = Concurrent::CachedThreadPool.new
|
15
|
+
GOROUTINES = Concurrent::CachedThreadPool.new(auto_terminate: true)
|
16
16
|
private_constant :GOROUTINES
|
17
17
|
|
18
18
|
BUFFER_TYPES = {
|
@@ -48,22 +48,22 @@ module Concurrent
|
|
48
48
|
return
|
49
49
|
end
|
50
50
|
|
51
|
-
|
51
|
+
capacity = opts[:capacity] || opts[:size]
|
52
52
|
buffer = opts[:buffer]
|
53
53
|
|
54
|
-
if
|
55
|
-
raise ArgumentError.new('unbuffered channels cannot have a
|
56
|
-
elsif
|
54
|
+
if capacity && buffer == :unbuffered
|
55
|
+
raise ArgumentError.new('unbuffered channels cannot have a capacity')
|
56
|
+
elsif capacity.nil? && buffer.nil?
|
57
57
|
self.buffer = BUFFER_TYPES[:unbuffered].new
|
58
|
-
elsif
|
58
|
+
elsif capacity == 0 && buffer == :buffered
|
59
59
|
self.buffer = BUFFER_TYPES[:unbuffered].new
|
60
60
|
elsif buffer == :unbuffered
|
61
61
|
self.buffer = BUFFER_TYPES[:unbuffered].new
|
62
|
-
elsif
|
63
|
-
raise ArgumentError.new('
|
62
|
+
elsif capacity.nil? || capacity < 1
|
63
|
+
raise ArgumentError.new('capacity must be at least 1 for this buffer type')
|
64
64
|
else
|
65
65
|
buffer ||= :buffered
|
66
|
-
self.buffer = BUFFER_TYPES[buffer].new(
|
66
|
+
self.buffer = BUFFER_TYPES[buffer].new(capacity)
|
67
67
|
end
|
68
68
|
|
69
69
|
self.validator = opts.fetch(:validator, DEFAULT_VALIDATOR)
|
@@ -116,20 +116,25 @@ module Concurrent
|
|
116
116
|
end
|
117
117
|
|
118
118
|
def take
|
119
|
-
item
|
120
|
-
item
|
119
|
+
item = do_take
|
120
|
+
item == Concurrent::NULL ? nil : item
|
121
121
|
end
|
122
122
|
alias_method :receive, :take
|
123
123
|
alias_method :~, :take
|
124
124
|
|
125
125
|
def take!
|
126
|
-
item
|
127
|
-
raise Error if item ==
|
126
|
+
item = do_take
|
127
|
+
raise Error if item == Concurrent::NULL
|
128
128
|
item
|
129
129
|
end
|
130
130
|
|
131
131
|
def take?
|
132
|
-
item
|
132
|
+
item = do_take
|
133
|
+
item = if item == Concurrent::NULL
|
134
|
+
Concurrent::Maybe.nothing
|
135
|
+
else
|
136
|
+
Concurrent::Maybe.just(item)
|
137
|
+
end
|
133
138
|
item
|
134
139
|
end
|
135
140
|
|
@@ -150,13 +155,13 @@ module Concurrent
|
|
150
155
|
# end
|
151
156
|
def next
|
152
157
|
item, more = do_next
|
153
|
-
item = nil if item ==
|
158
|
+
item = nil if item == Concurrent::NULL
|
154
159
|
return item, more
|
155
160
|
end
|
156
161
|
|
157
162
|
def next?
|
158
163
|
item, more = do_next
|
159
|
-
item = if item ==
|
164
|
+
item = if item == Concurrent::NULL
|
160
165
|
Concurrent::Maybe.nothing
|
161
166
|
else
|
162
167
|
Concurrent::Maybe.just(item)
|
@@ -165,17 +170,17 @@ module Concurrent
|
|
165
170
|
end
|
166
171
|
|
167
172
|
def poll
|
168
|
-
(item = do_poll) ==
|
173
|
+
(item = do_poll) == Concurrent::NULL ? nil : item
|
169
174
|
end
|
170
175
|
|
171
176
|
def poll!
|
172
177
|
item = do_poll
|
173
|
-
raise Error if item ==
|
178
|
+
raise Error if item == Concurrent::NULL
|
174
179
|
item
|
175
180
|
end
|
176
181
|
|
177
182
|
def poll?
|
178
|
-
if (item = do_poll) ==
|
183
|
+
if (item = do_poll) == Concurrent::NULL
|
179
184
|
Concurrent::Maybe.nothing
|
180
185
|
else
|
181
186
|
Concurrent::Maybe.just(item)
|
@@ -186,7 +191,7 @@ module Concurrent
|
|
186
191
|
raise ArgumentError.new('no block given') unless block_given?
|
187
192
|
loop do
|
188
193
|
item, more = do_next
|
189
|
-
if item !=
|
194
|
+
if item != Concurrent::NULL
|
190
195
|
yield(item)
|
191
196
|
elsif !more
|
192
197
|
break
|
@@ -238,7 +243,21 @@ module Concurrent
|
|
238
243
|
|
239
244
|
private
|
240
245
|
|
241
|
-
|
246
|
+
def validator
|
247
|
+
@validator
|
248
|
+
end
|
249
|
+
|
250
|
+
def validator=(value)
|
251
|
+
@validator = value
|
252
|
+
end
|
253
|
+
|
254
|
+
def buffer
|
255
|
+
@buffer
|
256
|
+
end
|
257
|
+
|
258
|
+
def buffer=(value)
|
259
|
+
@buffer = value
|
260
|
+
end
|
242
261
|
|
243
262
|
def validate(value, allow_nil, raise_error)
|
244
263
|
if !allow_nil && value.nil?
|
@@ -261,6 +280,10 @@ module Concurrent
|
|
261
280
|
buffer.offer(item)
|
262
281
|
end
|
263
282
|
|
283
|
+
def do_take
|
284
|
+
buffer.take
|
285
|
+
end
|
286
|
+
|
264
287
|
def do_next
|
265
288
|
buffer.next
|
266
289
|
end
|
@@ -4,9 +4,6 @@ module Concurrent
|
|
4
4
|
class Channel
|
5
5
|
module Buffer
|
6
6
|
|
7
|
-
# Placeholder for when a buffer slot contains no value.
|
8
|
-
NO_VALUE = Object.new
|
9
|
-
|
10
7
|
# Abstract base class for all Channel buffers.
|
11
8
|
#
|
12
9
|
# {Concurrent::Channel} objects maintain an internal, queue-like
|
@@ -18,11 +15,6 @@ module Concurrent
|
|
18
15
|
# used as a channel buffer should extend this class.
|
19
16
|
class Base < Synchronization::LockableObject
|
20
17
|
|
21
|
-
# @!macro [attach] channel_buffer_size_reader
|
22
|
-
#
|
23
|
-
# The number of items currently in the buffer.
|
24
|
-
attr_reader :size
|
25
|
-
|
26
18
|
# @!macro [attach] channel_buffer_capacity_reader
|
27
19
|
#
|
28
20
|
# The maximum number of values which can be {#put} onto the buffer
|
@@ -53,6 +45,13 @@ module Concurrent
|
|
53
45
|
true
|
54
46
|
end
|
55
47
|
|
48
|
+
# @!macro [attach] channel_buffer_size_reader
|
49
|
+
#
|
50
|
+
# The number of items currently in the buffer.
|
51
|
+
def size
|
52
|
+
synchronize { ns_size }
|
53
|
+
end
|
54
|
+
|
56
55
|
# @!macro [attach] channel_buffer_empty_question
|
57
56
|
#
|
58
57
|
# Predicate indicating if the buffer is empty.
|
@@ -61,7 +60,7 @@ module Concurrent
|
|
61
60
|
#
|
62
61
|
# @raise [NotImplementedError] until overridden in a subclass.
|
63
62
|
def empty?
|
64
|
-
|
63
|
+
synchronize { ns_empty? }
|
65
64
|
end
|
66
65
|
|
67
66
|
# @!macro [attach] channel_buffer_full_question
|
@@ -72,7 +71,7 @@ module Concurrent
|
|
72
71
|
#
|
73
72
|
# @raise [NotImplementedError] until overridden in a subclass.
|
74
73
|
def full?
|
75
|
-
|
74
|
+
synchronize { ns_full? }
|
76
75
|
end
|
77
76
|
|
78
77
|
# @!macro [attach] channel_buffer_put
|
@@ -116,7 +115,7 @@ module Concurrent
|
|
116
115
|
# are available the remaining items can still be taken. Once the
|
117
116
|
# buffer closes, no remaining items can be taken.
|
118
117
|
#
|
119
|
-
# @return [Object] the item removed from the buffer; `
|
118
|
+
# @return [Object] the item removed from the buffer; `Concurrent::NULL` once
|
120
119
|
# the buffer has closed.
|
121
120
|
#
|
122
121
|
# @raise [NotImplementedError] until overridden in a subclass.
|
@@ -126,19 +125,16 @@ module Concurrent
|
|
126
125
|
|
127
126
|
# @!macro [attach] channel_buffer_next
|
128
127
|
#
|
129
|
-
# Take the next item from the buffer and also return a boolean
|
130
|
-
# indicating if
|
128
|
+
# Take the next "item" from the buffer and also return a boolean
|
129
|
+
# indicating if "more" items can be taken. Used for iterating
|
131
130
|
# over a buffer until it is closed and empty.
|
132
131
|
#
|
133
132
|
# If the buffer is open but no items remain the calling thread will
|
134
133
|
# block until an item is available. The second of the two return
|
135
|
-
# values, a boolean, will always be `true` when the buffer is
|
136
|
-
#
|
137
|
-
#
|
138
|
-
#
|
139
|
-
# buffer is both closed and empty the first return value will be
|
140
|
-
# `NO_VALUE` and the second return value will be `false`.
|
141
|
-
# be `false` when the buffer is both closed and empty.
|
134
|
+
# values, "more" (a boolean), will always be `true` when the buffer is
|
135
|
+
# open. The "more" value will be `false` when the channel has been
|
136
|
+
# closed and all values have already been received. When "more" is
|
137
|
+
# false the returned item will be `Concurrent::NULL`.
|
142
138
|
#
|
143
139
|
# Note that when multiple threads access the same channel a race
|
144
140
|
# condition can occur when using this method. A call to `next` from
|
@@ -162,7 +158,7 @@ module Concurrent
|
|
162
158
|
# immediately. Failing to return a value does not necessarily
|
163
159
|
# indicate that the buffer is closed, just that it is empty.
|
164
160
|
#
|
165
|
-
# @return [Object] the next item from the buffer or `
|
161
|
+
# @return [Object] the next item from the buffer or `Concurrent::NULL` if
|
166
162
|
# the buffer is empty.
|
167
163
|
#
|
168
164
|
# @raise [NotImplementedError] until overridden in a subclass.
|
@@ -194,12 +190,44 @@ module Concurrent
|
|
194
190
|
|
195
191
|
private
|
196
192
|
|
197
|
-
|
198
|
-
|
193
|
+
def buffer
|
194
|
+
@buffer
|
195
|
+
end
|
196
|
+
|
197
|
+
def buffer=(value)
|
198
|
+
@buffer = value
|
199
|
+
end
|
200
|
+
|
201
|
+
def closed=(value)
|
202
|
+
@closed = value
|
203
|
+
end
|
204
|
+
|
205
|
+
def capacity=(value)
|
206
|
+
@capacity = value
|
207
|
+
end
|
208
|
+
|
209
|
+
def size=(value)
|
210
|
+
@size = value
|
211
|
+
end
|
199
212
|
|
200
213
|
def ns_initialize(*args)
|
201
214
|
end
|
202
215
|
|
216
|
+
# @!macro channel_buffer_size_reader
|
217
|
+
def ns_size
|
218
|
+
raise NotImplementedError
|
219
|
+
end
|
220
|
+
|
221
|
+
# @!macro channel_buffer_empty_question
|
222
|
+
def ns_empty?
|
223
|
+
raise NotImplementedError
|
224
|
+
end
|
225
|
+
|
226
|
+
# @!macro channel_buffer_full_question
|
227
|
+
def ns_full?
|
228
|
+
raise NotImplementedError
|
229
|
+
end
|
230
|
+
|
203
231
|
# @!macro channel_buffer_closed_question
|
204
232
|
def ns_closed?
|
205
233
|
@closed
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'concurrent/constants'
|
1
2
|
require 'concurrent/channel/buffer/base'
|
2
3
|
|
3
4
|
module Concurrent
|
@@ -10,19 +11,6 @@ module Concurrent
|
|
10
11
|
# an item is removed from the buffer, creating spare capacity.
|
11
12
|
class Buffered < Base
|
12
13
|
|
13
|
-
# @!macro channel_buffer_empty_question
|
14
|
-
def empty?
|
15
|
-
synchronize { ns_empty? }
|
16
|
-
end
|
17
|
-
|
18
|
-
# @!macro channel_buffer_full_question
|
19
|
-
#
|
20
|
-
# Will return `true` once the number of items in the buffer reaches
|
21
|
-
# the {#size} value specified during initialization.
|
22
|
-
def full?
|
23
|
-
synchronize { ns_full? }
|
24
|
-
end
|
25
|
-
|
26
14
|
# @!macro channel_buffer_put
|
27
15
|
#
|
28
16
|
# New items can be put onto the buffer until the number of items in
|
@@ -69,11 +57,10 @@ module Concurrent
|
|
69
57
|
loop do
|
70
58
|
synchronize do
|
71
59
|
if ns_closed? && ns_empty?
|
72
|
-
return
|
60
|
+
return Concurrent::NULL, false
|
73
61
|
elsif !ns_empty?
|
74
62
|
item = buffer.shift
|
75
|
-
|
76
|
-
return item, more
|
63
|
+
return item, true
|
77
64
|
end
|
78
65
|
end
|
79
66
|
Thread.pass
|
@@ -84,7 +71,7 @@ module Concurrent
|
|
84
71
|
def poll
|
85
72
|
synchronize do
|
86
73
|
if ns_empty?
|
87
|
-
|
74
|
+
Concurrent::NULL
|
88
75
|
else
|
89
76
|
buffer.shift
|
90
77
|
end
|
@@ -104,14 +91,19 @@ module Concurrent
|
|
104
91
|
self.buffer = []
|
105
92
|
end
|
106
93
|
|
94
|
+
# @!macro channel_buffer_size_reader
|
95
|
+
def ns_size
|
96
|
+
buffer.size
|
97
|
+
end
|
98
|
+
|
107
99
|
# @!macro channel_buffer_empty_question
|
108
100
|
def ns_empty?
|
109
|
-
|
101
|
+
ns_size == 0
|
110
102
|
end
|
111
103
|
|
112
104
|
# @!macro channel_buffer_full_question
|
113
105
|
def ns_full?
|
114
|
-
|
106
|
+
ns_size == capacity
|
115
107
|
end
|
116
108
|
|
117
109
|
# @!macro channel_buffer_put
|
@@ -1,74 +1,33 @@
|
|
1
|
+
require 'concurrent/constants'
|
1
2
|
require 'concurrent/utility/monotonic_time'
|
2
3
|
require 'concurrent/channel/tick'
|
3
|
-
require 'concurrent/channel/buffer/
|
4
|
+
require 'concurrent/channel/buffer/timer'
|
4
5
|
|
5
6
|
module Concurrent
|
6
7
|
class Channel
|
7
8
|
module Buffer
|
8
9
|
|
9
|
-
class Ticker <
|
10
|
-
|
11
|
-
def size() 1; end
|
12
|
-
|
13
|
-
def empty?() false; end
|
14
|
-
|
15
|
-
def full?() true; end
|
16
|
-
|
17
|
-
def put(item)
|
18
|
-
false
|
19
|
-
end
|
20
|
-
|
21
|
-
def offer(item)
|
22
|
-
false
|
23
|
-
end
|
24
|
-
|
25
|
-
def take
|
26
|
-
loop do
|
27
|
-
result, _ = do_poll
|
28
|
-
if result.nil?
|
29
|
-
return NO_VALUE
|
30
|
-
elsif result != NO_VALUE
|
31
|
-
return result
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def next
|
37
|
-
loop do
|
38
|
-
result, _ = do_poll
|
39
|
-
if result.nil?
|
40
|
-
return NO_VALUE, false
|
41
|
-
elsif result != NO_VALUE
|
42
|
-
return result, true
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def poll
|
48
|
-
result, _ = do_poll
|
49
|
-
if result.nil? || result == NO_VALUE
|
50
|
-
NO_VALUE
|
51
|
-
else
|
52
|
-
result
|
53
|
-
end
|
54
|
-
end
|
10
|
+
class Ticker < Timer
|
55
11
|
|
56
12
|
private
|
57
13
|
|
58
14
|
def ns_initialize(interval)
|
59
15
|
@interval = interval.to_f
|
60
16
|
@next_tick = Concurrent.monotonic_time + interval
|
17
|
+
self.capacity = 1
|
61
18
|
end
|
62
19
|
|
63
20
|
def do_poll
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
21
|
+
synchronize do
|
22
|
+
if ns_closed?
|
23
|
+
return Concurrent::NULL, false
|
24
|
+
elsif (now = Concurrent.monotonic_time) >= @next_tick
|
25
|
+
tick = Concurrent::Channel::Tick.new(@next_tick)
|
26
|
+
@next_tick = now + @interval
|
27
|
+
return tick, true
|
28
|
+
else
|
29
|
+
return nil, true
|
30
|
+
end
|
72
31
|
end
|
73
32
|
end
|
74
33
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'concurrent/constants'
|
1
2
|
require 'concurrent/utility/monotonic_time'
|
2
3
|
require 'concurrent/channel/tick'
|
3
4
|
require 'concurrent/channel/buffer/base'
|
@@ -8,16 +9,6 @@ module Concurrent
|
|
8
9
|
|
9
10
|
class Timer < Base
|
10
11
|
|
11
|
-
def size() 1; end
|
12
|
-
|
13
|
-
def empty?
|
14
|
-
synchronized { @empty }
|
15
|
-
end
|
16
|
-
|
17
|
-
def full?
|
18
|
-
!empty?
|
19
|
-
end
|
20
|
-
|
21
12
|
def put(item)
|
22
13
|
false
|
23
14
|
end
|
@@ -27,44 +18,59 @@ module Concurrent
|
|
27
18
|
end
|
28
19
|
|
29
20
|
def take
|
30
|
-
|
21
|
+
loop do
|
22
|
+
tick, _ = do_poll
|
23
|
+
if tick
|
24
|
+
return tick
|
25
|
+
else
|
26
|
+
Thread.pass
|
27
|
+
end
|
28
|
+
end
|
31
29
|
end
|
32
30
|
|
33
31
|
def next
|
34
32
|
loop do
|
35
|
-
|
36
|
-
|
37
|
-
return tick, false
|
38
|
-
# AFAIK a Go timer will block forever if stopped
|
39
|
-
#elsif status == :closed
|
40
|
-
#return false, false
|
41
|
-
end
|
33
|
+
tick, more = do_poll
|
34
|
+
return tick, more if tick
|
42
35
|
Thread.pass
|
43
36
|
end
|
44
37
|
end
|
45
38
|
|
46
39
|
def poll
|
47
|
-
|
48
|
-
|
40
|
+
tick, _ = do_poll
|
41
|
+
tick = Concurrent::NULL unless tick
|
42
|
+
tick
|
49
43
|
end
|
50
44
|
|
51
45
|
private
|
52
46
|
|
53
47
|
def ns_initialize(delay)
|
54
48
|
@tick = Concurrent.monotonic_time + delay.to_f
|
55
|
-
|
56
|
-
|
49
|
+
self.capacity = 1
|
50
|
+
end
|
51
|
+
|
52
|
+
def ns_size
|
53
|
+
0
|
54
|
+
end
|
55
|
+
|
56
|
+
def ns_empty?
|
57
|
+
false
|
58
|
+
end
|
59
|
+
|
60
|
+
def ns_full?
|
61
|
+
true
|
57
62
|
end
|
58
63
|
|
59
64
|
def do_poll
|
60
65
|
synchronize do
|
61
|
-
|
62
|
-
|
63
|
-
|
66
|
+
if ns_closed?
|
67
|
+
return Concurrent::NULL, false
|
68
|
+
elsif Concurrent.monotonic_time >= @tick
|
64
69
|
# only one listener gets notified
|
65
|
-
|
70
|
+
self.closed = true
|
71
|
+
return Concurrent::Channel::Tick.new(@tick), false
|
66
72
|
else
|
67
|
-
return
|
73
|
+
return nil, true
|
68
74
|
end
|
69
75
|
end
|
70
76
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'concurrent/constants'
|
1
2
|
require 'concurrent/channel/buffer/base'
|
2
3
|
require 'concurrent/atomic/atomic_reference'
|
3
4
|
|
@@ -16,19 +17,21 @@ module Concurrent
|
|
16
17
|
class Unbuffered < Base
|
17
18
|
|
18
19
|
# @!macro channel_buffer_size_reader
|
19
|
-
|
20
|
-
|
21
|
-
|
20
|
+
def size
|
21
|
+
synchronize do
|
22
|
+
putting.empty? ? 0 : 1
|
23
|
+
end
|
24
|
+
end
|
22
25
|
|
23
26
|
# @!macro channel_buffer_empty_question
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
+
def empty?
|
28
|
+
size == 0
|
29
|
+
end
|
27
30
|
|
28
31
|
# @!macro channel_buffer_full_question
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
+
def full?
|
33
|
+
!empty?
|
34
|
+
end
|
32
35
|
|
33
36
|
# @!macro channel_buffer_put
|
34
37
|
#
|
@@ -85,7 +88,7 @@ module Concurrent
|
|
85
88
|
# and this method will return.
|
86
89
|
def take
|
87
90
|
mine = synchronize do
|
88
|
-
return
|
91
|
+
return Concurrent::NULL if ns_closed? && putting.empty?
|
89
92
|
|
90
93
|
ref = Concurrent::AtomicReference.new(nil)
|
91
94
|
if putting.empty?
|
@@ -110,10 +113,10 @@ module Concurrent
|
|
110
113
|
# waiting to {#put} items onto the buffer. When there is a thread
|
111
114
|
# waiting to put an item this method will take the item and return
|
112
115
|
# it immediately. When there are no threads waiting to put or the
|
113
|
-
# buffer is closed, this method will return `
|
116
|
+
# buffer is closed, this method will return `Concurrent::NULL` immediately.
|
114
117
|
def poll
|
115
118
|
synchronize do
|
116
|
-
return
|
119
|
+
return Concurrent::NULL if putting.empty?
|
117
120
|
|
118
121
|
put = putting.shift
|
119
122
|
value = put.value
|
@@ -131,19 +134,21 @@ module Concurrent
|
|
131
134
|
# @see {#take}
|
132
135
|
def next
|
133
136
|
item = take
|
134
|
-
more =
|
137
|
+
more = (item != Concurrent::NULL)
|
135
138
|
return item, more
|
136
139
|
end
|
137
140
|
|
138
141
|
private
|
139
142
|
|
140
|
-
|
143
|
+
def putting() @putting; end
|
144
|
+
|
145
|
+
def taking() @taking; end
|
141
146
|
|
142
147
|
# @!macro channel_buffer_initialize
|
143
148
|
def ns_initialize
|
144
149
|
# one will always be empty
|
145
|
-
|
146
|
-
|
150
|
+
@putting = []
|
151
|
+
@taking = []
|
147
152
|
self.closed = false
|
148
153
|
self.capacity = 1
|
149
154
|
end
|
@@ -54,6 +54,7 @@ module Concurrent
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def execute
|
57
|
+
raise Channel::Error.new('no clauses given') if @clauses.empty?
|
57
58
|
loop do
|
58
59
|
done = @clauses.each do |clause|
|
59
60
|
result = clause.execute
|
@@ -63,7 +64,11 @@ module Concurrent
|
|
63
64
|
Thread.pass
|
64
65
|
end
|
65
66
|
rescue => ex
|
66
|
-
|
67
|
+
if @error_handler
|
68
|
+
@error_handler.call(ex)
|
69
|
+
else
|
70
|
+
raise ex
|
71
|
+
end
|
67
72
|
end
|
68
73
|
end
|
69
74
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'concurrent/synchronization'
|
1
2
|
require 'concurrent/utility/monotonic_time'
|
2
3
|
|
3
4
|
module Concurrent
|
@@ -13,8 +14,9 @@ module Concurrent
|
|
13
14
|
# @see Concurrent.monotonic_time
|
14
15
|
# @see Concurrent::Channel.ticker
|
15
16
|
# @see Concurrent::Channel.timer
|
16
|
-
class Tick
|
17
|
+
class Tick < Synchronization::Object
|
17
18
|
include Comparable
|
19
|
+
safe_initialization!
|
18
20
|
|
19
21
|
STRING_FORMAT = '%F %T.%6N %z %Z'.freeze
|
20
22
|
|
@@ -15,7 +15,8 @@ module Concurrent
|
|
15
15
|
|
16
16
|
# @!macro [attach] atomic_markable_reference_method_initialize
|
17
17
|
def initialize(value = nil, mark = false)
|
18
|
-
super(
|
18
|
+
super()
|
19
|
+
self.reference = ImmutableArray[value, mark]
|
19
20
|
end
|
20
21
|
|
21
22
|
# @!macro [attach] atomic_markable_reference_method_compare_and_set
|
@@ -131,6 +131,8 @@ module Concurrent
|
|
131
131
|
# Represents an event which will happen in future (will be completed). It has to always happen.
|
132
132
|
class Event < Synchronization::LockableObject
|
133
133
|
safe_initialization!
|
134
|
+
private(*attr_volatile_with_cas(:internal_state))
|
135
|
+
public :internal_state
|
134
136
|
include Concern::Deprecation
|
135
137
|
include Concern::Logging
|
136
138
|
|
@@ -181,17 +183,17 @@ module Concurrent
|
|
181
183
|
# TODO (pitr 12-Sep-2015): replace with AtomicFixnum, avoid aba problem
|
182
184
|
# TODO (pitr 12-Sep-2015): look at java.util.concurrent solution
|
183
185
|
@Waiters = LockFreeStack.new
|
184
|
-
|
186
|
+
self.internal_state = PENDING
|
185
187
|
end
|
186
188
|
|
187
189
|
# @return [:pending, :completed]
|
188
190
|
def state
|
189
|
-
|
191
|
+
internal_state.to_sym
|
190
192
|
end
|
191
193
|
|
192
194
|
# Is Event/Future pending?
|
193
195
|
# @return [Boolean]
|
194
|
-
def pending?(state =
|
196
|
+
def pending?(state = internal_state)
|
195
197
|
!state.completed?
|
196
198
|
end
|
197
199
|
|
@@ -203,7 +205,7 @@ module Concurrent
|
|
203
205
|
|
204
206
|
# Has the Event been completed?
|
205
207
|
# @return [Boolean]
|
206
|
-
def completed?(state =
|
208
|
+
def completed?(state = internal_state)
|
207
209
|
state.completed?
|
208
210
|
end
|
209
211
|
|
@@ -314,7 +316,7 @@ module Concurrent
|
|
314
316
|
|
315
317
|
# @!visibility private
|
316
318
|
def complete_with(state, raise_on_reassign = true)
|
317
|
-
if
|
319
|
+
if compare_and_set_internal_state(PENDING, state)
|
318
320
|
#(state)
|
319
321
|
# go to synchronized block only if there were waiting threads
|
320
322
|
synchronize { ns_broadcast } if @Waiters.clear
|
@@ -370,11 +372,6 @@ module Concurrent
|
|
370
372
|
@Waiters.each.to_a
|
371
373
|
end
|
372
374
|
|
373
|
-
# @!visibility private
|
374
|
-
def internal_state
|
375
|
-
@State.get
|
376
|
-
end
|
377
|
-
|
378
375
|
private
|
379
376
|
|
380
377
|
# @return [true, false]
|
@@ -537,7 +534,7 @@ module Concurrent
|
|
537
534
|
|
538
535
|
# Has Future been success?
|
539
536
|
# @return [Boolean]
|
540
|
-
def success?(state =
|
537
|
+
def success?(state = internal_state)
|
541
538
|
state.completed? && state.success?
|
542
539
|
end
|
543
540
|
|
@@ -548,7 +545,7 @@ module Concurrent
|
|
548
545
|
|
549
546
|
# Has Future been failed?
|
550
547
|
# @return [Boolean]
|
551
|
-
def failed?(state =
|
548
|
+
def failed?(state = internal_state)
|
552
549
|
state.completed? && !state.success?
|
553
550
|
end
|
554
551
|
|
@@ -564,7 +561,7 @@ module Concurrent
|
|
564
561
|
# @!macro edge.periodical_wait
|
565
562
|
def value(timeout = nil)
|
566
563
|
touch
|
567
|
-
|
564
|
+
internal_state.value if wait_until_complete timeout
|
568
565
|
end
|
569
566
|
|
570
567
|
# @return [Exception, nil] the reason of the Future's failure
|
@@ -572,7 +569,7 @@ module Concurrent
|
|
572
569
|
# @!macro edge.periodical_wait
|
573
570
|
def reason(timeout = nil)
|
574
571
|
touch
|
575
|
-
|
572
|
+
internal_state.reason if wait_until_complete timeout
|
576
573
|
end
|
577
574
|
|
578
575
|
# @return [Array(Boolean, Object, Exception), nil] triplet of success, value, reason
|
@@ -580,7 +577,7 @@ module Concurrent
|
|
580
577
|
# @!macro edge.periodical_wait
|
581
578
|
def result(timeout = nil)
|
582
579
|
touch
|
583
|
-
|
580
|
+
internal_state.result if wait_until_complete timeout
|
584
581
|
end
|
585
582
|
|
586
583
|
# Wait until Future is #complete?
|
@@ -602,14 +599,14 @@ module Concurrent
|
|
602
599
|
# @!macro edge.periodical_wait
|
603
600
|
def value!(timeout = nil)
|
604
601
|
touch
|
605
|
-
|
602
|
+
internal_state.value if wait_until_complete! timeout
|
606
603
|
end
|
607
604
|
|
608
605
|
# @example allows failed Future to be risen
|
609
606
|
# raise Concurrent.future.fail
|
610
607
|
def exception(*args)
|
611
608
|
raise 'obligation is not failed' unless failed?
|
612
|
-
reason =
|
609
|
+
reason = internal_state.reason
|
613
610
|
if reason.is_a?(::Array)
|
614
611
|
reason.each { |e| log ERROR, 'Edge::Future', e }
|
615
612
|
Concurrent::Error.new 'multiple exceptions, inspect log'
|
@@ -728,7 +725,7 @@ module Concurrent
|
|
728
725
|
|
729
726
|
# @!visibility private
|
730
727
|
def complete_with(state, raise_on_reassign = true)
|
731
|
-
if
|
728
|
+
if compare_and_set_internal_state(PENDING, state)
|
732
729
|
@Waiters.clear
|
733
730
|
synchronize { ns_broadcast }
|
734
731
|
call_callbacks state
|
@@ -746,12 +743,12 @@ module Concurrent
|
|
746
743
|
|
747
744
|
# @!visibility private
|
748
745
|
def add_callback(method, *args)
|
749
|
-
state =
|
746
|
+
state = internal_state
|
750
747
|
if completed?(state)
|
751
748
|
call_callback method, state, *args
|
752
749
|
else
|
753
750
|
@Callbacks.push [method, *args]
|
754
|
-
state =
|
751
|
+
state = internal_state
|
755
752
|
# take back if it was completed in the meanwhile
|
756
753
|
call_callbacks state if completed?(state)
|
757
754
|
end
|
@@ -760,7 +757,7 @@ module Concurrent
|
|
760
757
|
|
761
758
|
# @!visibility private
|
762
759
|
def apply(block)
|
763
|
-
|
760
|
+
internal_state.apply block
|
764
761
|
end
|
765
762
|
|
766
763
|
private
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: concurrent-ruby-edge
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.0.
|
4
|
+
version: 0.2.0.pre5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jerry D'Antonio
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2015-
|
13
|
+
date: 2015-11-04 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: concurrent-ruby
|
@@ -18,14 +18,14 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - "~>"
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 1.0.0.
|
21
|
+
version: 1.0.0.pre5
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
requirements:
|
26
26
|
- - "~>"
|
27
27
|
- !ruby/object:Gem::Version
|
28
|
-
version: 1.0.0.
|
28
|
+
version: 1.0.0.pre5
|
29
29
|
description: |
|
30
30
|
These features are under active development and may change frequently. They are expected not to
|
31
31
|
keep backward compatibility (there may also lack tests and documentation). Semantic versions will
|