@@ -36,34 +36,38 @@ internal open class ArrayChannel<E>(
36
36
*/
37
37
private var buffer: Array <Any ?> = arrayOfNulls<Any ?>(min(capacity, 8 ))
38
38
private var head: Int = 0
39
- private var size = 0 // Invariant: size <= capacity
39
+ private val size = atomic( 0 ) // Invariant: size <= capacity
40
40
41
41
protected final override val isBufferAlwaysEmpty: Boolean get() = false
42
- protected final override val isBufferEmpty: Boolean get() = lock.withLock { size == 0 }
42
+ protected final override val isBufferEmpty: Boolean get() = size.value == 0
43
43
protected final override val isBufferAlwaysFull: Boolean get() = false
44
- protected final override val isBufferFull: Boolean get() = lock.withLock { size == capacity }
44
+ protected final override val isBufferFull: Boolean get() = size.value == capacity
45
+
46
+ override val isFull: Boolean get() = lock.withLock { isFullImpl }
47
+ override val isEmpty: Boolean get() = lock.withLock { isEmptyImpl }
48
+ override val isClosedForReceive: Boolean get() = lock.withLock { super .isClosedForReceive }
45
49
46
50
// result is `OFFER_SUCCESS | OFFER_FAILED | Closed`
47
51
protected override fun offerInternal (element : E ): Any {
48
52
var receive: ReceiveOrClosed <E >? = null
49
53
lock.withLock {
50
- val size = this .size
54
+ val size = this .size.value
51
55
closedForSend?.let { return it }
52
56
if (size < capacity) {
53
57
// tentatively put element to buffer
54
- this .size = size + 1 // update size before checking queue (!!!)
58
+ this .size.value = size + 1 // update size before checking queue (!!!)
55
59
// check for receivers that were waiting on empty queue
56
60
if (size == 0 ) {
57
61
loop@ while (true ) {
58
62
receive = takeFirstReceiveOrPeekClosed() ? : break @loop // break when no receivers queued
59
63
if (receive is Closed ) {
60
- this .size = size // restore size
64
+ this .size.value = size // restore size
61
65
return receive!!
62
66
}
63
67
val token = receive!! .tryResumeReceive(element, null )
64
68
if (token != null ) {
65
69
assert { token == = RESUME_TOKEN }
66
- this .size = size // restore size
70
+ this .size.value = size // restore size
67
71
return @withLock
68
72
}
69
73
}
@@ -84,26 +88,26 @@ internal open class ArrayChannel<E>(
84
88
protected override fun offerSelectInternal (element : E , select : SelectInstance <* >): Any {
85
89
var receive: ReceiveOrClosed <E >? = null
86
90
lock.withLock {
87
- val size = this .size
91
+ val size = this .size.value
88
92
closedForSend?.let { return it }
89
93
if (size < capacity) {
90
94
// tentatively put element to buffer
91
- this .size = size + 1 // update size before checking queue (!!!)
95
+ this .size.value = size + 1 // update size before checking queue (!!!)
92
96
// check for receivers that were waiting on empty queue
93
97
if (size == 0 ) {
94
98
loop@ while (true ) {
95
99
val offerOp = describeTryOffer(element)
96
100
val failure = select.performAtomicTrySelect(offerOp)
97
101
when {
98
102
failure == null -> { // offered successfully
99
- this .size = size // restore size
103
+ this .size.value = size // restore size
100
104
receive = offerOp.result
101
105
return @withLock
102
106
}
103
107
failure == = OFFER_FAILED -> break @loop // cannot offer -> Ok to queue to buffer
104
108
failure == = RETRY_ATOMIC -> {} // retry
105
109
failure == = ALREADY_SELECTED || failure is Closed <* > -> {
106
- this .size = size // restore size
110
+ this .size.value = size // restore size
107
111
return failure
108
112
}
109
113
else -> error(" performAtomicTrySelect(describeTryOffer) returned $failure " )
@@ -112,7 +116,7 @@ internal open class ArrayChannel<E>(
112
116
}
113
117
// let's try to select sending this element to buffer
114
118
if (! select.trySelect()) { // :todo: move trySelect completion outside of lock
115
- this .size = size // restore size
119
+ this .size.value = size // restore size
116
120
return ALREADY_SELECTED
117
121
}
118
122
ensureCapacity(size)
@@ -127,6 +131,10 @@ internal open class ArrayChannel<E>(
127
131
return receive!! .offerResult
128
132
}
129
133
134
+ override fun enqueueSend (send : Send ): Any? = lock.withLock {
135
+ super .enqueueSend(send)
136
+ }
137
+
130
138
// Guarded by lock
131
139
private fun ensureCapacity (currentSize : Int ) {
132
140
if (currentSize >= buffer.size) {
@@ -146,12 +154,12 @@ internal open class ArrayChannel<E>(
146
154
var resumed = false
147
155
var result: Any? = null
148
156
lock.withLock {
149
- val size = this .size
157
+ val size = this .size.value
150
158
if (size == 0 ) return closedForSend ? : POLL_FAILED // when nothing can be read from buffer
151
159
// size > 0: not empty -- retrieve element
152
160
result = buffer[head]
153
161
buffer[head] = null
154
- this .size = size - 1 // update size before checking queue (!!!)
162
+ this .size.value = size - 1 // update size before checking queue (!!!)
155
163
// check for senders that were waiting on full queue
156
164
var replacement: Any? = POLL_FAILED
157
165
if (size == capacity) {
@@ -167,7 +175,7 @@ internal open class ArrayChannel<E>(
167
175
}
168
176
}
169
177
if (replacement != = POLL_FAILED && replacement !is Closed <* >) {
170
- this .size = size // restore size
178
+ this .size.value = size // restore size
171
179
buffer[(head + size) % buffer.size] = replacement
172
180
}
173
181
head = (head + 1 ) % buffer.size
@@ -184,12 +192,12 @@ internal open class ArrayChannel<E>(
184
192
var success = false
185
193
var result: Any? = null
186
194
lock.withLock {
187
- val size = this .size
195
+ val size = this .size.value
188
196
if (size == 0 ) return closedForSend ? : POLL_FAILED
189
197
// size > 0: not empty -- retrieve element
190
198
result = buffer[head]
191
199
buffer[head] = null
192
- this .size = size - 1 // update size before checking queue (!!!)
200
+ this .size.value = size - 1 // update size before checking queue (!!!)
193
201
// check for senders that were waiting on full queue
194
202
var replacement: Any? = POLL_FAILED
195
203
if (size == capacity) {
@@ -206,7 +214,7 @@ internal open class ArrayChannel<E>(
206
214
failure == = POLL_FAILED -> break @loop // cannot poll -> Ok to take from buffer
207
215
failure == = RETRY_ATOMIC -> {} // retry
208
216
failure == = ALREADY_SELECTED -> {
209
- this .size = size // restore size
217
+ this .size.value = size // restore size
210
218
buffer[head] = result // restore head
211
219
return failure
212
220
}
@@ -221,12 +229,12 @@ internal open class ArrayChannel<E>(
221
229
}
222
230
}
223
231
if (replacement != = POLL_FAILED && replacement !is Closed <* >) {
224
- this .size = size // restore size
232
+ this .size.value = size // restore size
225
233
buffer[(head + size) % buffer.size] = replacement
226
234
} else {
227
235
// failed to poll or is already closed --> let's try to select receiving this element from buffer
228
236
if (! select.trySelect()) { // :todo: move trySelect completion outside of lock
229
- this .size = size // restore size
237
+ this .size.value = size // restore size
230
238
buffer[head] = result // restore head
231
239
return ALREADY_SELECTED
232
240
}
@@ -239,16 +247,20 @@ internal open class ArrayChannel<E>(
239
247
return result
240
248
}
241
249
250
+ override fun enqueueReceiveInternal (receive : Receive <E >): Boolean = lock.withLock {
251
+ super .enqueueReceiveInternal(receive)
252
+ }
253
+
242
254
// Note: this function is invoked when channel is already closed
243
255
override fun onCancelIdempotent (wasClosed : Boolean ) {
244
256
// clear buffer first, but do not wait for it in helpers
245
257
if (wasClosed) {
246
258
lock.withLock {
247
- repeat(size) {
259
+ repeat(size.value ) {
248
260
buffer[head] = 0
249
261
head = (head + 1 ) % buffer.size
250
262
}
251
- size = 0
263
+ size.value = 0
252
264
}
253
265
}
254
266
// then clean all queued senders
@@ -258,5 +270,5 @@ internal open class ArrayChannel<E>(
258
270
// ------ debug ------
259
271
260
272
override val bufferDebugString: String
261
- get() = " (buffer:capacity=$capacity ,size=$size )"
273
+ get() = " (buffer:capacity=$capacity ,size=${ size.value} )"
262
274
}
0 commit comments