@@ -19,7 +19,7 @@ package kotlinx.coroutines.experimental.channels
19
19
import kotlinx.coroutines.experimental.CancellableContinuation
20
20
import kotlinx.coroutines.experimental.internal.LockFreeLinkedListHead
21
21
import kotlinx.coroutines.experimental.internal.LockFreeLinkedListNode
22
- import kotlinx.coroutines.experimental.removeOnCompletion
22
+ import kotlinx.coroutines.experimental.removeOnCancel
23
23
import kotlinx.coroutines.experimental.suspendCancellableCoroutine
24
24
25
25
/* *
@@ -72,17 +72,17 @@ public abstract class AbstractChannel<E> : Channel<E> {
72
72
73
73
// ------ SendChannel ------
74
74
75
- override val isClosedForSend: Boolean get() = closedForSend != null
76
- override val isFull: Boolean get() = queue.next() !is ReceiveOrClosed <* > && isBufferFull
75
+ public final override val isClosedForSend: Boolean get() = closedForSend != null
76
+ public final override val isFull: Boolean get() = queue.next() !is ReceiveOrClosed <* > && isBufferFull
77
77
78
- suspend override fun send (element : E ) {
78
+ public final override suspend fun send (element : E ) {
79
79
// fast path -- try offer non-blocking
80
80
if (offer(element)) return
81
81
// slow-path does suspend
82
82
return sendSuspend(element)
83
83
}
84
84
85
- override fun offer (element : E ): Boolean {
85
+ public final override fun offer (element : E ): Boolean {
86
86
val result = offerInternal(element)
87
87
return when {
88
88
result == = OFFER_SUCCESS -> true
@@ -96,7 +96,7 @@ public abstract class AbstractChannel<E> : Channel<E> {
96
96
loop@ while (true ) {
97
97
if (enqueueSend(send)) {
98
98
cont.initCancellability() // make it properly cancellable
99
- cont.removeOnCompletion (send)
99
+ cont.removeOnCancel (send)
100
100
return @sc
101
101
}
102
102
// hm... something is not right. try to offer
@@ -120,13 +120,16 @@ public abstract class AbstractChannel<E> : Channel<E> {
120
120
else
121
121
queue.addLastIfPrev(send, { it !is ReceiveOrClosed <* > })
122
122
123
- override fun close (cause : Throwable ? ): Boolean {
123
+ public final override fun close (cause : Throwable ? ): Boolean {
124
124
val closed = Closed <E >(cause)
125
125
while (true ) {
126
126
val receive = takeFirstReceiveOrPeekClosed()
127
127
if (receive == null ) {
128
128
// queue empty or has only senders -- try add last "Closed" item to the queue
129
- if (queue.addLastIfPrev(closed, { it !is ReceiveOrClosed <* > })) return true
129
+ if (queue.addLastIfPrev(closed, { it !is ReceiveOrClosed <* > })) {
130
+ afterClose(cause)
131
+ return true
132
+ }
130
133
continue // retry on failure
131
134
}
132
135
if (receive is Closed <* >) return false // already marked as closed -- nothing to do
@@ -135,6 +138,11 @@ public abstract class AbstractChannel<E> : Channel<E> {
135
138
}
136
139
}
137
140
141
+ /* *
142
+ * Invoked after successful [close].
143
+ */
144
+ protected open fun afterClose (cause : Throwable ? ) {}
145
+
138
146
/* *
139
147
* Retrieves first receiving waiter from the queue or returns closed token.
140
148
*/
@@ -143,11 +151,11 @@ public abstract class AbstractChannel<E> : Channel<E> {
143
151
144
152
// ------ ReceiveChannel ------
145
153
146
- override val isClosedForReceive: Boolean get() = closedForReceive != null && isBufferEmpty
147
- override val isEmpty: Boolean get() = queue.next() !is Send && isBufferEmpty
154
+ public final override val isClosedForReceive: Boolean get() = closedForReceive != null && isBufferEmpty
155
+ public final override val isEmpty: Boolean get() = queue.next() !is Send && isBufferEmpty
148
156
149
157
@Suppress(" UNCHECKED_CAST" )
150
- suspend override fun receive (): E {
158
+ public final override suspend fun receive (): E {
151
159
// fast path -- try poll non-blocking
152
160
val result = pollInternal()
153
161
if (result != = POLL_EMPTY ) return receiveResult(result)
@@ -167,7 +175,7 @@ public abstract class AbstractChannel<E> : Channel<E> {
167
175
while (true ) {
168
176
if (enqueueReceive(receive)) {
169
177
cont.initCancellability() // make it properly cancellable
170
- cont.removeOnCompletion( receive)
178
+ removeReceiveOnCancel(cont, receive)
171
179
return @sc
172
180
}
173
181
// hm... something is not right. try to poll
@@ -183,14 +191,16 @@ public abstract class AbstractChannel<E> : Channel<E> {
183
191
}
184
192
}
185
193
186
- private fun enqueueReceive (receive : Receive <E >) =
187
- if (hasBuffer)
188
- queue.addLastIfPrevAndIf(receive, { it !is Send }, { isBufferEmpty })
189
- else
194
+ private fun enqueueReceive (receive : Receive <E >): Boolean {
195
+ val result = if (hasBuffer)
196
+ queue.addLastIfPrevAndIf(receive, { it !is Send }, { isBufferEmpty }) else
190
197
queue.addLastIfPrev(receive, { it !is Send })
198
+ if (result) onEnqueuedReceive()
199
+ return result
200
+ }
191
201
192
202
@Suppress(" UNCHECKED_CAST" )
193
- suspend override fun receiveOrNull (): E ? {
203
+ public final override suspend fun receiveOrNull (): E ? {
194
204
// fast path -- try poll non-blocking
195
205
val result = pollInternal()
196
206
if (result != = POLL_EMPTY ) return receiveOrNullResult(result)
@@ -213,7 +223,7 @@ public abstract class AbstractChannel<E> : Channel<E> {
213
223
while (true ) {
214
224
if (enqueueReceive(receive)) {
215
225
cont.initCancellability() // make it properly cancellable
216
- cont.removeOnCompletion( receive)
226
+ removeReceiveOnCancel(cont, receive)
217
227
return @sc
218
228
}
219
229
// hm... something is not right. try to poll
@@ -233,12 +243,12 @@ public abstract class AbstractChannel<E> : Channel<E> {
233
243
}
234
244
235
245
@Suppress(" UNCHECKED_CAST" )
236
- override fun poll (): E ? {
246
+ public final override fun poll (): E ? {
237
247
val result = pollInternal()
238
248
return if (result == = POLL_EMPTY ) null else receiveOrNullResult(result)
239
249
}
240
250
241
- override fun iterator (): ChannelIterator <E > = Iterator (this )
251
+ public final override fun iterator (): ChannelIterator <E > = Iterator (this )
242
252
243
253
/* *
244
254
* Retrieves first sending waiter from the queue or returns closed token.
@@ -262,6 +272,23 @@ public abstract class AbstractChannel<E> : Channel<E> {
262
272
override fun toString (): String = string
263
273
}
264
274
275
+ private fun removeReceiveOnCancel (cont : CancellableContinuation <* >, receive : Receive <* >) {
276
+ cont.onCompletion {
277
+ if (cont.isCancelled && receive.remove())
278
+ onCancelledReceive()
279
+ }
280
+ }
281
+
282
+ /* *
283
+ * Invoked when receiver is successfully enqueued to the queue of waiting receivers.
284
+ */
285
+ protected open fun onEnqueuedReceive () {}
286
+
287
+ /* *
288
+ * Invoked when enqueued receiver was successfully cancelled.
289
+ */
290
+ protected open fun onCancelledReceive () {}
291
+
265
292
private class Iterator <E >(val channel : AbstractChannel <E >) : ChannelIterator<E> {
266
293
var result: Any? = POLL_EMPTY // E | POLL_CLOSED | POLL_EMPTY
267
294
@@ -288,7 +315,7 @@ public abstract class AbstractChannel<E> : Channel<E> {
288
315
while (true ) {
289
316
if (channel.enqueueReceive(receive)) {
290
317
cont.initCancellability() // make it properly cancellable
291
- cont.removeOnCompletion( receive)
318
+ channel.removeReceiveOnCancel(cont, receive)
292
319
return @sc
293
320
}
294
321
// hm... something is not right. try to poll
0 commit comments