@@ -265,6 +265,14 @@ internal class ByteBufferChannel(
265
265
if (newState == = ReadWriteBufferState .IdleEmpty ) {
266
266
toRelease?.let { releaseBuffer(it.initial) }
267
267
resumeWriteOp()
268
+ } else {
269
+ if (newState is ReadWriteBufferState .IdleNonEmpty && newState.capacity.isEmpty()) {
270
+ if (newState.capacity.tryLockForRelease() && State .compareAndSet(this , newState, ReadWriteBufferState .IdleEmpty )) {
271
+ newState.capacity.resetForWrite()
272
+ releaseBuffer(newState.initial)
273
+ resumeWriteOp()
274
+ }
275
+ }
268
276
}
269
277
}
270
278
@@ -288,7 +296,7 @@ internal class ByteBufferChannel(
288
296
}
289
297
290
298
private fun tryCompleteJoining (joined : JoiningState ): Boolean {
291
- if (! tryReleaseBuffer()) return false
299
+ if (! tryReleaseBuffer(true )) return false
292
300
ensureClosedJoined(joined)
293
301
294
302
resumeReadOp { IllegalStateException (" Joining is in progress" ) }
@@ -300,7 +308,7 @@ internal class ByteBufferChannel(
300
308
private fun tryTerminate (): Boolean {
301
309
if (closed == null ) return false
302
310
303
- if (! tryReleaseBuffer()) return false
311
+ if (! tryReleaseBuffer(false )) return false
304
312
305
313
joining?.let { ensureClosedJoined(it) }
306
314
@@ -310,7 +318,7 @@ internal class ByteBufferChannel(
310
318
return true
311
319
}
312
320
313
- private fun tryReleaseBuffer (): Boolean {
321
+ private fun tryReleaseBuffer (forceTermination : Boolean ): Boolean {
314
322
var toRelease: ReadWriteBufferState .Initial ? = null
315
323
316
324
updateState { state ->
@@ -329,6 +337,10 @@ internal class ByteBufferChannel(
329
337
toRelease = state.initial
330
338
ReadWriteBufferState .Terminated
331
339
}
340
+ forceTermination && state is ReadWriteBufferState .IdleNonEmpty && state.capacity.tryLockForRelease() -> {
341
+ toRelease = state.initial
342
+ ReadWriteBufferState .Terminated
343
+ }
332
344
else -> return false
333
345
}
334
346
}
@@ -464,15 +476,15 @@ internal class ByteBufferChannel(
464
476
return consumed
465
477
}
466
478
467
- final suspend override fun readFully (dst : ByteArray , offset : Int , length : Int ) {
479
+ final override suspend fun readFully (dst : ByteArray , offset : Int , length : Int ) {
468
480
val consumed = readAsMuchAsPossible(dst, offset, length)
469
481
470
482
if (consumed < length) {
471
483
return readFullySuspend(dst, offset + consumed, length - consumed)
472
484
}
473
485
}
474
486
475
- final suspend override fun readFully (dst : ByteBuffer ): Int {
487
+ final override suspend fun readFully (dst : ByteBuffer ): Int {
476
488
val rc = readAsMuchAsPossible(dst)
477
489
if (! dst.hasRemaining()) return rc
478
490
@@ -490,7 +502,7 @@ internal class ByteBufferChannel(
490
502
return copied
491
503
}
492
504
493
- private suspend tailrec fun readFullySuspend (dst : ByteArray , offset : Int , length : Int ) {
505
+ private tailrec suspend fun readFullySuspend (dst : ByteArray , offset : Int , length : Int ) {
494
506
if (! readSuspend(1 )) throw ClosedReceiveChannelException (" Unexpected EOF: expected $length more bytes" )
495
507
496
508
val consumed = readAsMuchAsPossible(dst, offset, length)
@@ -560,7 +572,7 @@ internal class ByteBufferChannel(
560
572
return readAvailable(dst)
561
573
}
562
574
563
- final suspend override fun readPacket (size : Int , headerSizeHint : Int ): ByteReadPacket {
575
+ final override suspend fun readPacket (size : Int , headerSizeHint : Int ): ByteReadPacket {
564
576
closed?.cause?.let { throw it }
565
577
566
578
if (size == 0 ) return ByteReadPacket .Empty
@@ -626,7 +638,7 @@ internal class ByteBufferChannel(
626
638
}
627
639
}
628
640
629
- final suspend override fun readByte (): Byte {
641
+ final override suspend fun readByte (): Byte {
630
642
var b: Byte = 0
631
643
632
644
val rc = reading {
@@ -649,7 +661,7 @@ internal class ByteBufferChannel(
649
661
return readByte()
650
662
}
651
663
652
- final suspend override fun readBoolean (): Boolean {
664
+ final override suspend fun readBoolean (): Boolean {
653
665
var b = false
654
666
655
667
val rc = reading {
@@ -672,7 +684,7 @@ internal class ByteBufferChannel(
672
684
return readBoolean()
673
685
}
674
686
675
- final suspend override fun readShort (): Short {
687
+ final override suspend fun readShort (): Short {
676
688
var sh: Short = 0
677
689
678
690
val rc = reading {
@@ -1262,8 +1274,10 @@ internal class ByteBufferChannel(
1262
1274
1263
1275
flush()
1264
1276
1265
- if (src.availableForRead == 0 && ! src.readSuspendImpl(1 )) {
1266
- if (joined == null || src.tryCompleteJoining(joined)) break
1277
+ if (src.availableForRead == 0 ) {
1278
+ if (src.readSuspendImpl(1 )) {
1279
+ if (joined != null && src.tryCompleteJoining(joined)) break
1280
+ } else if (joined == null || src.tryCompleteJoining(joined)) break
1267
1281
}
1268
1282
1269
1283
if (joining != null ) {
@@ -1618,7 +1632,7 @@ internal class ByteBufferChannel(
1618
1632
read(min, block)
1619
1633
}
1620
1634
1621
- suspend override fun writePacket (packet : ByteReadPacket ) {
1635
+ override suspend fun writePacket (packet : ByteReadPacket ) {
1622
1636
joining?.let { resolveDelegation(this , it)?.let { return it.writePacket(packet) } }
1623
1637
1624
1638
try {
@@ -1753,6 +1767,7 @@ internal class ByteBufferChannel(
1753
1767
} finally {
1754
1768
if (locked > 0 ) {
1755
1769
ringBufferCapacity.completeRead(locked)
1770
+ locked = 0
1756
1771
}
1757
1772
}
1758
1773
}
@@ -2101,9 +2116,20 @@ internal class ByteBufferChannel(
2101
2116
2102
2117
private val readSuspendContinuationCache = MutableDelegateContinuation <Boolean >()
2103
2118
2119
+ @Suppress(" NOTHING_TO_INLINE" )
2120
+ private inline fun readSuspendPredicate (size : Int ): Boolean {
2121
+ val state = state
2122
+
2123
+ if (state.capacity.availableForRead >= size) return false
2124
+ if (joining != null && writeOp != null &&
2125
+ (state == = ReadWriteBufferState .IdleEmpty || state is ReadWriteBufferState .IdleNonEmpty )) return false
2126
+
2127
+ return true
2128
+ }
2129
+
2104
2130
private fun suspensionForSize (size : Int , c : Continuation <Boolean >): Any {
2105
2131
do {
2106
- if (this .state.capacity.availableForRead >= size) {
2132
+ if (! readSuspendPredicate( size) ) {
2107
2133
c.resume(true )
2108
2134
break
2109
2135
}
@@ -2116,13 +2142,13 @@ internal class ByteBufferChannel(
2116
2142
}
2117
2143
return COROUTINE_SUSPENDED
2118
2144
}
2119
- } while (! setContinuation({ readOp }, ReadOp , c, { closed == null && state.capacity.availableForRead < size }))
2145
+ } while (! setContinuation({ readOp }, ReadOp , c, { closed == null && readSuspendPredicate( size) }))
2120
2146
2121
2147
return COROUTINE_SUSPENDED
2122
2148
}
2123
2149
2124
2150
private suspend fun readSuspendImpl (size : Int ): Boolean {
2125
- if (state.capacity.availableForRead >= size) return true
2151
+ if (! readSuspendPredicate( size) ) return true
2126
2152
2127
2153
return suspendCoroutineOrReturn { raw ->
2128
2154
val c = readSuspendContinuationCache
@@ -2131,6 +2157,9 @@ internal class ByteBufferChannel(
2131
2157
}
2132
2158
}
2133
2159
2160
+ private fun shouldResumeReadOp () = joining != null &&
2161
+ (state == = ReadWriteBufferState .IdleEmpty || state is ReadWriteBufferState .IdleNonEmpty )
2162
+
2134
2163
private fun writeSuspendPredicate (size : Int ): Boolean {
2135
2164
val joined = joining
2136
2165
val state = state
@@ -2159,6 +2188,10 @@ internal class ByteBufferChannel(
2159
2188
2160
2189
flushImpl(1 , minWriteSize = size)
2161
2190
2191
+ if (shouldResumeReadOp()) {
2192
+ resumeReadOp()
2193
+ }
2194
+
2162
2195
COROUTINE_SUSPENDED
2163
2196
}
2164
2197
@@ -2192,6 +2225,10 @@ internal class ByteBufferChannel(
2192
2225
} while (! setContinuation({ writeOp }, WriteOp , c, { writeSuspendPredicate(size) }))
2193
2226
2194
2227
flushImpl(1 , minWriteSize = size)
2228
+
2229
+ if (shouldResumeReadOp()) {
2230
+ resumeReadOp()
2231
+ }
2195
2232
}
2196
2233
}
2197
2234
0 commit comments