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 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