concurrent-ruby-edge 0.2.0.pre4 → 0.2.0.pre5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|