Skip to content

Commit 511983e

Browse files
committed
Forbid casting Mutex to a Semaphore
Fixes #4026
1 parent b7cbe09 commit 511983e

File tree

4 files changed

+17
-8
lines changed

4 files changed

+17
-8
lines changed

kotlinx-coroutines-core/common/src/sync/Mutex.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ public suspend inline fun <T> Mutex.withLock(owner: Any? = null, action: () -> T
127127
}
128128

129129

130-
internal open class MutexImpl(locked: Boolean) : SemaphoreImpl(1, if (locked) 1 else 0), Mutex {
130+
internal open class MutexImpl(locked: Boolean) : SemaphoreAndMutexImpl(1, if (locked) 1 else 0), Mutex {
131131
/**
132132
* After the lock is acquired, the corresponding owner is stored in this field.
133133
* The [unlock] operation checks the owner and either re-sets it to [NO_OWNER],

kotlinx-coroutines-core/common/src/sync/Semaphore.kt

+10-6
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ public suspend inline fun <T> Semaphore.withPermit(action: () -> T): T {
8787
}
8888

8989
@Suppress("UNCHECKED_CAST")
90-
internal open class SemaphoreImpl(private val permits: Int, acquiredPermits: Int) : Semaphore {
90+
internal open class SemaphoreAndMutexImpl(private val permits: Int, acquiredPermits: Int) {
9191
/*
9292
The queue of waiting acquirers is essentially an infinite array based on the list of segments
9393
(see `SemaphoreSegment`); each segment contains a fixed number of slots. To determine a slot for each enqueue
@@ -144,11 +144,11 @@ internal open class SemaphoreImpl(private val permits: Int, acquiredPermits: Int
144144
* cannot be greater than 2^31 in any real application.
145145
*/
146146
private val _availablePermits = atomic(permits - acquiredPermits)
147-
override val availablePermits: Int get() = max(_availablePermits.value, 0)
147+
val availablePermits: Int get() = max(_availablePermits.value, 0)
148148

149149
private val onCancellationRelease = { _: Throwable, _: Unit, _: CoroutineContext -> release() }
150150

151-
override fun tryAcquire(): Boolean {
151+
fun tryAcquire(): Boolean {
152152
while (true) {
153153
// Get the current number of available permits.
154154
val p = _availablePermits.value
@@ -167,7 +167,7 @@ internal open class SemaphoreImpl(private val permits: Int, acquiredPermits: Int
167167
}
168168
}
169169

170-
override suspend fun acquire() {
170+
suspend fun acquire() {
171171
// Decrement the number of available permits.
172172
val p = decPermits()
173173
// Is the permit acquired?
@@ -239,7 +239,7 @@ internal open class SemaphoreImpl(private val permits: Int, acquiredPermits: Int
239239
}
240240
}
241241

242-
override fun release() {
242+
fun release() {
243243
while (true) {
244244
// Increment the number of available permits.
245245
val p = _availablePermits.getAndIncrement()
@@ -346,12 +346,16 @@ internal open class SemaphoreImpl(private val permits: Int, acquiredPermits: Int
346346
} else false
347347
}
348348
is SelectInstance<*> -> {
349-
trySelect(this@SemaphoreImpl, Unit)
349+
trySelect(this@SemaphoreAndMutexImpl, Unit)
350350
}
351351
else -> error("unexpected: $this")
352352
}
353353
}
354354

355+
private class SemaphoreImpl(
356+
permits: Int, acquiredPermits: Int
357+
): SemaphoreAndMutexImpl(permits, acquiredPermits), Semaphore
358+
355359
private fun createSegment(id: Long, prev: SemaphoreSegment?) = SemaphoreSegment(id, prev, 0)
356360

357361
private class SemaphoreSegment(id: Long, prev: SemaphoreSegment?, pointers: Int) : Segment<SemaphoreSegment>(id, prev, pointers) {

kotlinx-coroutines-core/common/test/sync/MutexTest.kt

+5
Original file line numberDiff line numberDiff line change
@@ -192,4 +192,9 @@ class MutexTest : TestBase() {
192192
}
193193
}
194194
}
195+
196+
@Test
197+
fun testMutexIsNotSemaphore() {
198+
assertIsNot<Semaphore>(Mutex())
199+
}
195200
}

kotlinx-coroutines-core/jvm/test/lincheck/SemaphoreLincheckTest.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import org.jetbrains.kotlinx.lincheck.annotations.Operation
99
import org.jetbrains.kotlinx.lincheck.strategy.managed.modelchecking.*
1010

1111
abstract class SemaphoreLincheckTestBase(permits: Int) : AbstractLincheckTest() {
12-
private val semaphore = SemaphoreImpl(permits = permits, acquiredPermits = 0)
12+
private val semaphore = SemaphoreAndMutexImpl(permits = permits, acquiredPermits = 0)
1313

1414
@Operation
1515
fun tryAcquire() = semaphore.tryAcquire()

0 commit comments

Comments
 (0)