Skip to content

Commit b2ed1d6

Browse files
committed
Introduce SegmentQueueSynchronizer abstraction for synchronization primitives and ReadWriteMutex
Signed-off-by: Nikita Koval <[email protected]>
1 parent 43b6be5 commit b2ed1d6

File tree

6 files changed

+18
-2
lines changed

6 files changed

+18
-2
lines changed

Diff for: kotlinx-coroutines-core/common/src/internal/SegmentQueueSynchronizer.kt

+6-2
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ internal abstract class SegmentQueueSynchronizer<T : Any> {
209209
returnValue(value)
210210
}
211211

212+
@Suppress("INFERRED_TYPE_VARIABLE_INTO_POSSIBLE_EMPTY_INTERSECTION")
212213
internal fun suspendCancelled(): T? {
213214
// Increment `suspendIdx` and find the segment
214215
// with the corresponding id. It is guaranteed
@@ -238,14 +239,15 @@ internal abstract class SegmentQueueSynchronizer<T : Any> {
238239
if (value !== BROKEN && segment.cas(i, value, TAKEN)) {
239240
// The elimination is performed successfully,
240241
// complete with the value stored in the cell.
242+
@Suppress("UNCHECKED_CAST")
241243
return value as T
242244
}
243245
// The cell is broken, this can happen only in the `SYNC` resumption mode.
244246
assert { resumeMode == SYNC && segment.get(i) === BROKEN }
245247
return null
246248
}
247249

248-
@Suppress("UNCHECKED_CAST")
250+
@Suppress("UNCHECKED_CAST", "INFERRED_TYPE_VARIABLE_INTO_POSSIBLE_EMPTY_INTERSECTION")
249251
internal fun suspend(waiter: Waiter): Boolean {
250252
// Increment `suspendIdx` and find the segment
251253
// with the corresponding id. It is guaranteed
@@ -335,7 +337,7 @@ internal abstract class SegmentQueueSynchronizer<T : Any> {
335337
* moves [resumeIdx] to the first possibly non-cancelled cell, i.e.,
336338
* to the first segment id multiplied by [SEGMENT_SIZE].
337339
*/
338-
@Suppress("UNCHECKED_CAST")
340+
@Suppress("UNCHECKED_CAST", "INFERRED_TYPE_VARIABLE_INTO_POSSIBLE_EMPTY_INTERSECTION")
339341
private fun tryResumeImpl(value: T, adjustResumeIdx: Boolean): Int {
340342
// Check that `adjustResumeIdx` is `false` in the simple cancellation mode.
341343
assertNot { cancellationMode == SIMPLE && adjustResumeIdx }
@@ -561,12 +563,14 @@ internal abstract class SegmentQueueSynchronizer<T : Any> {
561563
// provided by a concurrent `resume(..)`.
562564
// The value could be put only in the asynchronous mode,
563565
// so the `resume(..)` call above must not fail.
566+
@Suppress("UNCHECKED_CAST")
564567
resume(value as T)
565568
} else {
566569
// The `resume(..)` that will come to this cell should be refused.
567570
// Mark the cell correspondingly and help a concurrent
568571
// `resume(..)` to process its value if needed.
569572
val value = markRefuse(index) ?: return
573+
@Suppress("UNCHECKED_CAST")
570574
returnRefusedValue(value as T)
571575
}
572576
}

Diff for: kotlinx-coroutines-core/common/src/sync/Mutex.kt

+1
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ internal open class MutexImpl(locked: Boolean) : SegmentQueueSynchronizer<Unit>(
232232
assert { this.owner.value === NO_OWNER }
233233
when (waiter) {
234234
is CancellableContinuation<*> -> {
235+
@Suppress("UNCHECKED_CAST")
235236
waiter as CancellableContinuation<Unit>
236237
waiter.resume(Unit, null)
237238
}

Diff for: kotlinx-coroutines-core/common/src/sync/ReadWriteMutex.kt

+1
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ internal class ReadWriteMutexImpl : ReadWriteMutex, Mutex {
217217
if (owner != null) error("ReadWriteMutex.write does not support owners")
218218
writeLock()
219219
}
220+
@Suppress("OVERRIDE_DEPRECATION")
220221
override val onLock: SelectClause2<Any?, Mutex> get() = error("ReadWriteMutex.write does not support `onLock`")
221222
override fun holdsLock(owner: Any) = error("ReadWriteMutex.write does not support owners")
222223
override fun unlock(owner: Any?) {

Diff for: kotlinx-coroutines-core/common/test/sync/MutexTest.kt

+1
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ class MutexTest : TestBase() {
140140
}
141141

142142
@Test
143+
@Suppress("DEPRECATION")
143144
fun testIllegalStateInvariant() = runTest {
144145
val mutex = Mutex()
145146
val owner = Any()

Diff for: kotlinx-coroutines-core/jvm/test/TestBase.kt

+8
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,14 @@ public actual open class TestBase(private var disableOutCheck: Boolean) {
255255
protected suspend fun currentDispatcher() = coroutineContext[ContinuationInterceptor]!!
256256
}
257257

258+
fun <T> CancellableContinuation<T>.tryResume0(value: T, onCancellation: (Throwable?) -> Unit): Boolean {
259+
tryResume(value, null, onCancellation).let {
260+
if (it == null) return false
261+
completeResume(it)
262+
return true
263+
}
264+
}
265+
258266
/*
259267
* We ignore tests that test **real** non-virtualized tests with time on Windows, because
260268
* our CI Windows is virtualized itself (oh, the irony) and its clock resolution is dozens of ms,

Diff for: kotlinx-coroutines-core/jvm/test/lincheck/MutexLincheckTest.kt

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class MutexLincheckTest : AbstractLincheckTest() {
2525

2626
// TODO: `onLock` with non-null owner is non-linearizable
2727
// onLock may suspend in case of clause re-registration.
28+
@Suppress("DEPRECATION")
2829
@Operation(allowExtraSuspension = true, promptCancellation = true)
2930
suspend fun onLock() = select<Unit> { mutex.onLock(null) {} }
3031

0 commit comments

Comments
 (0)