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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8589b43e4b23f4d4bb73cddf2123b436e0ea90ba
4
- data.tar.gz: baa80cc8ded0dc8a050ce3a64a933183575584a4
3
+ metadata.gz: 49c297b646de061530808c991d1e19221dc1b6a7
4
+ data.tar.gz: 1301f31a7ff10f078525eb5e3158428b012d1517
5
5
  SHA512:
6
- metadata.gz: 2c3fbd2d6e8718e62457e39c61bfe95a0da959072af5e05d2162fd12d8aa1aa15137428916766bde9b32f7359f9cab8b21b5883851d5bf432541e1dd531ca719
7
- data.tar.gz: a538eca680505fb8b3192fb6a1b5dbcdcc63ac757d56b00bca5745256bd01d007f40d50aad0c4db2df6a33f13e42efe7af384595b3998e9e4c0166094fa5635a
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 DEBUG, "rejected #{envelope.message} from #{envelope.sender_path}"
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 DEBUG, "finished processing of #{envelope.message.inspect}"
17
+ log(DEBUG) { "finished processing of #{envelope.message.inspect}"}
18
18
  end
19
19
  nil
20
20
  rescue => error
@@ -24,7 +24,6 @@ module Concurrent
24
24
  class AbstractContext
25
25
  include TypeCheck
26
26
  include InternalDelegations
27
- include Concern::Logging
28
27
 
29
28
  attr_reader :core
30
29
 
@@ -91,7 +91,7 @@ module Concurrent
91
91
  # @param [Envelope] envelope
92
92
  def on_envelope(envelope)
93
93
  schedule_execution do
94
- log DEBUG, "was #{envelope.future ? 'asked' : 'told'} #{envelope.message.inspect} by #{envelope.sender}"
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 DEBUG, "event: #{event.inspect} (#{public ? 'public' : 'private'})"
131
+ log(DEBUG) { "event: #{event.inspect} (#{public ? 'public' : 'private'})" }
132
132
  @first_behaviour.on_event(public, event)
133
133
  end
134
134
 
@@ -2,7 +2,7 @@ module Concurrent
2
2
  module Actor
3
3
  class DefaultDeadLetterHandler < RestartingContext
4
4
  def on_message(dead_letter)
5
- log INFO, "got dead letter #{dead_letter.inspect}"
5
+ log(INFO) { "got dead letter #{dead_letter.inspect}"}
6
6
  end
7
7
  end
8
8
  end
@@ -2,6 +2,7 @@ module Concurrent
2
2
  module Actor
3
3
  module InternalDelegations
4
4
  include PublicDelegations
5
+ include Logger::Severity
5
6
 
6
7
  # @see Core#children
7
8
  def children
@@ -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
- size = opts[:size]
51
+ capacity = opts[:capacity] || opts[:size]
52
52
  buffer = opts[:buffer]
53
53
 
54
- if size && buffer == :unbuffered
55
- raise ArgumentError.new('unbuffered channels cannot have a size')
56
- elsif size.nil? && buffer.nil?
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 size == 0 && buffer == :buffered
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 size.nil? || size < 1
63
- raise ArgumentError.new('size must be at least 1 for this buffer type')
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(size)
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, _ = self.next
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, _ = do_next
127
- raise Error if item == Buffer::NO_VALUE
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, _ = self.next?
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 == Buffer::NO_VALUE
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 == Buffer::NO_VALUE
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) == Buffer::NO_VALUE ? nil : item
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 == Buffer::NO_VALUE
178
+ raise Error if item == Concurrent::NULL
174
179
  item
175
180
  end
176
181
 
177
182
  def poll?
178
- if (item = do_poll) == Buffer::NO_VALUE
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 != Buffer::NO_VALUE
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
- attr_accessor :buffer, :validator
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
- raise NotImplementedError
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
- raise NotImplementedError
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; `NO_VALUE` once
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 subsequent items can be taken. Used for iterating
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 open.
136
- # When the buffer is closed but more items remain the second return
137
- # value will also be `true`. When the buffer is closed and the last
138
- # item is taken the second return value will be `false`. When the
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 `NO_VALUE` if
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
- attr_accessor :buffer
198
- attr_writer :closed, :capacity, :size
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 NO_VALUE, false
60
+ return Concurrent::NULL, false
73
61
  elsif !ns_empty?
74
62
  item = buffer.shift
75
- more = !ns_empty? || !ns_closed?
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
- NO_VALUE
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
- buffer.length == 0
101
+ ns_size == 0
110
102
  end
111
103
 
112
104
  # @!macro channel_buffer_full_question
113
105
  def ns_full?
114
- buffer.length == capacity
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/base'
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 < Base
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
- if ns_closed?
65
- return nil, false
66
- elsif (now = Concurrent.monotonic_time) > @next_tick
67
- tick = Concurrent::Channel::Tick.new(@next_tick)
68
- @next_tick = now + @interval
69
- return tick, true
70
- else
71
- return NO_VALUE, true
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
- self.next.first
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
- status, tick = do_poll
36
- if status == :tick
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
- status, tick = do_poll
48
- status == :tick ? tick : NO_VALUE
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
- @closed = false
56
- @empty = false
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
- return :closed, false if ns_closed?
62
-
63
- if Concurrent.monotonic_time > @tick
66
+ if ns_closed?
67
+ return Concurrent::NULL, false
68
+ elsif Concurrent.monotonic_time >= @tick
64
69
  # only one listener gets notified
65
- return :tick, Concurrent::Channel::Tick.new(@tick)
70
+ self.closed = true
71
+ return Concurrent::Channel::Tick.new(@tick), false
66
72
  else
67
- return :wait, true
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
- # Always returns zero (0).
21
- def size() 0; end
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
- # Always returns `true`.
26
- def empty?() true; end
27
+ def empty?
28
+ size == 0
29
+ end
27
30
 
28
31
  # @!macro channel_buffer_full_question
29
- #
30
- # Always returns `false`.
31
- def full?() false; end
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 NO_VALUE if ns_closed? && putting.empty?
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 `NO_VALUE` immediately.
116
+ # buffer is closed, this method will return `Concurrent::NULL` immediately.
114
117
  def poll
115
118
  synchronize do
116
- return NO_VALUE if putting.empty?
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 = synchronize { !putting.empty? }
137
+ more = (item != Concurrent::NULL)
135
138
  return item, more
136
139
  end
137
140
 
138
141
  private
139
142
 
140
- attr_accessor :putting, :taking
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
- self.putting = []
146
- self.taking = []
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
- @error_handler.call(ex) if @error_handler
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(ImmutableArray[value, mark]) # ensures visibility
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
- @State = AtomicReference.new PENDING
186
+ self.internal_state = PENDING
185
187
  end
186
188
 
187
189
  # @return [:pending, :completed]
188
190
  def state
189
- @State.get.to_sym
191
+ internal_state.to_sym
190
192
  end
191
193
 
192
194
  # Is Event/Future pending?
193
195
  # @return [Boolean]
194
- def pending?(state = @State.get)
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 = @State.get)
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 @State.compare_and_set(PENDING, state)
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 = @State.get)
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 = @State.get)
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
- @State.get.value if wait_until_complete timeout
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
- @State.get.reason if wait_until_complete timeout
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
- @State.get.result if wait_until_complete timeout
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
- @State.get.value if wait_until_complete! timeout
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 = @State.get.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 @State.compare_and_set(PENDING, state)
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 = @State.get
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 = @State.get
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
- @State.get.apply block
760
+ internal_state.apply block
764
761
  end
765
762
 
766
763
  private
@@ -26,7 +26,8 @@ module Concurrent
26
26
  private(*attr_volatile_with_cas(:head))
27
27
 
28
28
  def initialize
29
- super(EMPTY)
29
+ super()
30
+ self.head = EMPTY
30
31
  end
31
32
 
32
33
  def empty?
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.pre4
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-10-08 00:00:00.000000000 Z
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.pre4
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.pre4
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