diff --git a/.gitignore b/.gitignore index aed7103292..52843ca5b7 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ !/.idea/copyright !/.idea/codeStyleSettings.xml !/.idea/codeStyles +!/.idea/dictionaries *.iml .gradle .gradletasknamecache diff --git a/.idea/dictionaries/shared.xml b/.idea/dictionaries/shared.xml new file mode 100644 index 0000000000..3da8e22952 --- /dev/null +++ b/.idea/dictionaries/shared.xml @@ -0,0 +1,9 @@ + + + + kotlinx + lincheck + redirector + + + \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 1ffa02d1ae..0207be9e6e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,7 +12,7 @@ junit_version=4.12 atomicfu_version=0.14.4 knit_version=0.2.2 html_version=0.6.8 -lincheck_version=2.7.1 +lincheck_version=2.10 dokka_version=0.9.16-rdev-2-mpp-hacks byte_buddy_version=1.10.9 reactor_version=3.2.5.RELEASE diff --git a/kotlinx-coroutines-core/build.gradle b/kotlinx-coroutines-core/build.gradle index 314eea350b..da9cdb4994 100644 --- a/kotlinx-coroutines-core/build.gradle +++ b/kotlinx-coroutines-core/build.gradle @@ -184,13 +184,22 @@ jvmTest { minHeapSize = '1g' maxHeapSize = '1g' enableAssertions = true - systemProperty 'java.security.manager', 'kotlinx.coroutines.TestSecurityManager' + if (!Idea.active) { + // We should not set this security manager when `jvmTest` + // is invoked by IntelliJ IDEA since we need to pass + // system properties for Lincheck and stress tests. + // TODO Remove once IDEA is smart enough to select between `jvmTest`/`jvmStressTest`/`jvmLincheckTest` #KTIJ-599 + systemProperty 'java.security.manager', 'kotlinx.coroutines.TestSecurityManager' + } // 'stress' is required to be able to run all subpackage tests like ":jvmTests --tests "*channels*" -Pstress=true" if (!Idea.active && rootProject.properties['stress'] == null) { + exclude '**/*LincheckTest.*' exclude '**/*StressTest.*' } - systemProperty 'kotlinx.coroutines.scheduler.keep.alive.sec', '100000' // any unpark problem hangs test - + if (Idea.active) { + // Configure the IDEA runner for Lincheck + configureJvmForLincheck(jvmTest) + } // TODO: JVM IR generates different stacktrace so temporary disable stacktrace tests if (rootProject.ext.jvm_ir_enabled) { filter { @@ -219,23 +228,41 @@ task jvmStressTest(type: Test, dependsOn: compileTestKotlinJvm) { systemProperty 'kotlinx.coroutines.semaphore.maxSpinCycles', '10' } +task jvmLincheckTest(type: Test, dependsOn: compileTestKotlinJvm) { + classpath = files { jvmTest.classpath } + testClassesDirs = files { jvmTest.testClassesDirs } + include '**/*LincheckTest.*' + enableAssertions = true + testLogging.showStandardStreams = true + configureJvmForLincheck(jvmLincheckTest) +} + +static void configureJvmForLincheck(task) { + task.minHeapSize = '1g' + task.maxHeapSize = '6g' // we may need more space for building an interleaving tree in the model checking mode + task.jvmArgs = ['--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED', // required for transformation + '--add-exports', 'java.base/jdk.internal.util=ALL-UNNAMED'] // in the model checking mode + task.systemProperty 'kotlinx.coroutines.semaphore.segmentSize', '2' + task.systemProperty 'kotlinx.coroutines.semaphore.maxSpinCycles', '1' // better for the model checking mode +} + task jdk16Test(type: Test, dependsOn: [compileTestKotlinJvm, checkJdk16]) { classpath = files { jvmTest.classpath } testClassesDirs = files { jvmTest.testClassesDirs } executable = "$System.env.JDK_16/bin/java" exclude '**/*LFStressTest.*' // lock-freedom tests use LockFreedomTestEnvironment which needs JDK8 - exclude '**/*LCStressTest.*' // lin-check tests use LinChecker which needs JDK8 + exclude '**/*LincheckTest.*' // Lincheck tests use LinChecker which needs JDK8 exclude '**/exceptions/**' // exceptions tests check suppressed exception which needs JDK8 exclude '**/ExceptionsGuideTest.*' exclude '**/RunInterruptibleStressTest.*' // fails on JDK 1.6 due to JDK bug } -// Run these tests only during nightly stress test +// Run jdk16Test test only during nightly stress test jdk16Test.onlyIf { project.properties['stressTest'] != null } -// Always run those tests -task moreTest(dependsOn: [jvmStressTest, jdk16Test]) -build.dependsOn moreTest +// Always check additional test sets +task moreTest(dependsOn: [jvmStressTest, jvmLincheckTest, jdk16Test]) +check.dependsOn moreTest task testsJar(type: Jar, dependsOn: jvmTestClasses) { classifier = 'tests' diff --git a/kotlinx-coroutines-core/common/src/CancellableContinuationImpl.kt b/kotlinx-coroutines-core/common/src/CancellableContinuationImpl.kt index cdb1b78882..a056ef08ed 100644 --- a/kotlinx-coroutines-core/common/src/CancellableContinuationImpl.kt +++ b/kotlinx-coroutines-core/common/src/CancellableContinuationImpl.kt @@ -85,6 +85,13 @@ internal open class CancellableContinuationImpl( public override val isCancelled: Boolean get() = state is CancelledContinuation + // We cannot invoke `state.toString()` since it may cause a circular dependency + private val stateDebugRepresentation get() = when(state) { + is NotCompleted -> "Active" + is CancelledContinuation -> "Cancelled" + else -> "Completed" + } + public override fun initCancellability() { setupCancellation() } @@ -503,7 +510,7 @@ internal open class CancellableContinuationImpl( // For nicer debugging public override fun toString(): String = - "${nameString()}(${delegate.toDebugString()}){$state}@$hexAddress" + "${nameString()}(${delegate.toDebugString()}){$stateDebugRepresentation}@$hexAddress" protected open fun nameString(): String = "CancellableContinuation" diff --git a/kotlinx-coroutines-core/common/src/internal/Symbol.kt b/kotlinx-coroutines-core/common/src/internal/Symbol.kt index 4fa8f540af..cd25d3c1af 100644 --- a/kotlinx-coroutines-core/common/src/internal/Symbol.kt +++ b/kotlinx-coroutines-core/common/src/internal/Symbol.kt @@ -10,7 +10,7 @@ package kotlinx.coroutines.internal * @suppress **This is unstable API and it is subject to change.** */ internal class Symbol(val symbol: String) { - override fun toString(): String = symbol + override fun toString(): String = "<$symbol>" @Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE") inline fun unbox(value: Any?): T = if (value === this) null as T else value as T diff --git a/kotlinx-coroutines-core/jvm/test/AbstractLincheckTest.kt b/kotlinx-coroutines-core/jvm/test/AbstractLincheckTest.kt new file mode 100644 index 0000000000..5ba7acf994 --- /dev/null +++ b/kotlinx-coroutines-core/jvm/test/AbstractLincheckTest.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ +package kotlinx.coroutines + +import org.jetbrains.kotlinx.lincheck.* +import org.jetbrains.kotlinx.lincheck.strategy.managed.modelchecking.* +import org.jetbrains.kotlinx.lincheck.strategy.stress.* +import org.jetbrains.kotlinx.lincheck.verifier.* +import org.junit.* + +abstract class AbstractLincheckTest : VerifierState() { + open fun > O.customize(isStressTest: Boolean): O = this + open fun ModelCheckingOptions.customize(isStressTest: Boolean): ModelCheckingOptions = this + open fun StressOptions.customize(isStressTest: Boolean): StressOptions = this + + @Test + fun modelCheckingTest() = ModelCheckingOptions() + .iterations(if (isStressTest) 100 else 20) + .invocationsPerIteration(if (isStressTest) 10_000 else 1_000) + .commonConfiguration() + .customize(isStressTest) + .check(this::class) + + @Test + fun stressTest() = StressOptions() + .iterations(if (isStressTest) 100 else 20) + .invocationsPerIteration(if (isStressTest) 10_000 else 1_000) + .commonConfiguration() + .customize(isStressTest) + .check(this::class) + + private fun > O.commonConfiguration(): O = this + .actorsBefore(if (isStressTest) 3 else 1) + .threads(3) + .actorsPerThread(if (isStressTest) 4 else 2) + .actorsAfter(if (isStressTest) 3 else 0) + .customize(isStressTest) + + override fun extractState(): Any = error("Not implemented") +} \ No newline at end of file diff --git a/kotlinx-coroutines-core/jvm/test/LCStressOptionsDefault.kt b/kotlinx-coroutines-core/jvm/test/LCStressOptionsDefault.kt deleted file mode 100644 index 62ded9f969..0000000000 --- a/kotlinx-coroutines-core/jvm/test/LCStressOptionsDefault.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ -package kotlinx.coroutines - -import org.jetbrains.kotlinx.lincheck.* -import org.jetbrains.kotlinx.lincheck.strategy.stress.* -import kotlin.reflect.* - -class LCStressOptionsDefault : StressOptions() { - init { - iterations(100 * stressTestMultiplierCbrt) - invocationsPerIteration(1000 * stressTestMultiplierCbrt) - actorsBefore(if (isStressTest) 3 else 0) - threads(3) - actorsPerThread(if (isStressTest) 3 else 2) - } -} - -fun Options<*,*>.check(testClass: KClass<*>) = LinChecker.check(testClass.java, this) \ No newline at end of file diff --git a/kotlinx-coroutines-core/jvm/test/linearizability/ChannelsLCStressTest.kt b/kotlinx-coroutines-core/jvm/test/lincheck/ChannelsLincheckTest.kt similarity index 88% rename from kotlinx-coroutines-core/jvm/test/linearizability/ChannelsLCStressTest.kt rename to kotlinx-coroutines-core/jvm/test/lincheck/ChannelsLincheckTest.kt index 8836fdc7be..fbd5c0d8f3 100644 --- a/kotlinx-coroutines-core/jvm/test/linearizability/ChannelsLCStressTest.kt +++ b/kotlinx-coroutines-core/jvm/test/lincheck/ChannelsLincheckTest.kt @@ -3,7 +3,7 @@ */ @file:Suppress("unused") -package kotlinx.coroutines.linearizability +package kotlinx.coroutines.lincheck import kotlinx.coroutines.* import kotlinx.coroutines.channels.* @@ -11,37 +11,37 @@ import kotlinx.coroutines.channels.Channel.Factory.CONFLATED import kotlinx.coroutines.channels.Channel.Factory.RENDEZVOUS import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED import kotlinx.coroutines.selects.* +import org.jetbrains.kotlinx.lincheck.* import org.jetbrains.kotlinx.lincheck.annotations.* import org.jetbrains.kotlinx.lincheck.annotations.Operation import org.jetbrains.kotlinx.lincheck.paramgen.* import org.jetbrains.kotlinx.lincheck.verifier.* -import org.junit.* -class RendezvousChannelLCStressTest : ChannelLCStressTestBase( +class RendezvousChannelLincheckTest : ChannelLincheckTestBase( c = Channel(RENDEZVOUS), sequentialSpecification = SequentialRendezvousChannel::class.java ) class SequentialRendezvousChannel : SequentialIntChannelBase(RENDEZVOUS) -class Array1ChannelLCStressTest : ChannelLCStressTestBase( +class Array1ChannelLincheckTest : ChannelLincheckTestBase( c = Channel(1), sequentialSpecification = SequentialArray1RendezvousChannel::class.java ) class SequentialArray1RendezvousChannel : SequentialIntChannelBase(1) -class Array2ChannelLCStressTest : ChannelLCStressTestBase( +class Array2ChannelLincheckTest : ChannelLincheckTestBase( c = Channel(2), sequentialSpecification = SequentialArray2RendezvousChannel::class.java ) class SequentialArray2RendezvousChannel : SequentialIntChannelBase(2) -class UnlimitedChannelLCStressTest : ChannelLCStressTestBase( +class UnlimitedChannelLincheckTest : ChannelLincheckTestBase( c = Channel(UNLIMITED), sequentialSpecification = SequentialUnlimitedChannel::class.java ) class SequentialUnlimitedChannel : SequentialIntChannelBase(UNLIMITED) -class ConflatedChannelLCStressTest : ChannelLCStressTestBase( +class ConflatedChannelLincheckTest : ChannelLincheckTestBase( c = Channel(CONFLATED), sequentialSpecification = SequentialConflatedChannel::class.java ) @@ -51,8 +51,11 @@ class SequentialConflatedChannel : SequentialIntChannelBase(CONFLATED) Param(name = "value", gen = IntGen::class, conf = "1:5"), Param(name = "closeToken", gen = IntGen::class, conf = "1:3") ) -abstract class ChannelLCStressTestBase(private val c: Channel, private val sequentialSpecification: Class<*>) { - @Operation +abstract class ChannelLincheckTestBase( + private val c: Channel, + private val sequentialSpecification: Class<*> +) : AbstractLincheckTest() { + @Operation(promptCancellation = true) suspend fun send(@Param(name = "value") value: Int): Any = try { c.send(value) } catch (e: NumberedCancellationException) { @@ -74,7 +77,7 @@ abstract class ChannelLCStressTestBase(private val c: Channel, private val e.testResult } - @Operation + @Operation(promptCancellation = true) suspend fun receive(): Any = try { c.receive() } catch (e: NumberedCancellationException) { @@ -96,7 +99,7 @@ abstract class ChannelLCStressTestBase(private val c: Channel, private val e.testResult } - @Operation + @Operation(causesBlocking = true) fun close(@Param(name = "closeToken") token: Int): Boolean = c.close(NumberedCancellationException(token)) // TODO: this operation should be (and can be!) linearizable, but is not @@ -113,11 +116,8 @@ abstract class ChannelLCStressTestBase(private val c: Channel, private val // @Operation fun isEmpty() = c.isEmpty - @Test - fun test() = LCStressOptionsDefault() - .actorsBefore(0) - .sequentialSpecification(sequentialSpecification) - .check(this::class) + override fun > O.customize(isStressTest: Boolean): O = + actorsBefore(0).sequentialSpecification(sequentialSpecification) } private class NumberedCancellationException(number: Int) : CancellationException() { diff --git a/kotlinx-coroutines-core/jvm/test/linearizability/LockFreeListLCStressTest.kt b/kotlinx-coroutines-core/jvm/test/lincheck/LockFreeListLincheckTest.kt similarity index 83% rename from kotlinx-coroutines-core/jvm/test/linearizability/LockFreeListLCStressTest.kt rename to kotlinx-coroutines-core/jvm/test/lincheck/LockFreeListLincheckTest.kt index 5f91c640a6..4f1bb6ad02 100644 --- a/kotlinx-coroutines-core/jvm/test/linearizability/LockFreeListLCStressTest.kt +++ b/kotlinx-coroutines-core/jvm/test/lincheck/LockFreeListLincheckTest.kt @@ -3,18 +3,17 @@ */ @file:Suppress("unused") -package kotlinx.coroutines.linearizability +package kotlinx.coroutines.lincheck import kotlinx.coroutines.* import kotlinx.coroutines.internal.* import org.jetbrains.kotlinx.lincheck.annotations.* import org.jetbrains.kotlinx.lincheck.annotations.Operation import org.jetbrains.kotlinx.lincheck.paramgen.* -import org.jetbrains.kotlinx.lincheck.verifier.* -import kotlin.test.* +import org.jetbrains.kotlinx.lincheck.strategy.managed.modelchecking.* @Param(name = "value", gen = IntGen::class, conf = "1:5") -class LockFreeListLCStressTest : VerifierState() { +class LockFreeListLincheckTest : AbstractLincheckTest() { class Node(val value: Int): LockFreeLinkedListNode() private val q: LockFreeLinkedListHead = LockFreeLinkedListHead() @@ -43,12 +42,12 @@ class LockFreeListLCStressTest : VerifierState() { private fun Any.isSame(value: Int) = this is Node && this.value == value - @Test - fun testAddRemoveLinearizability() = LCStressOptionsDefault().check(this::class) - override fun extractState(): Any { val elements = ArrayList() q.forEach { elements.add(it.value) } return elements } + + override fun ModelCheckingOptions.customize(isStressTest: Boolean) = + checkObstructionFreedom() } \ No newline at end of file diff --git a/kotlinx-coroutines-core/jvm/test/linearizability/LockFreeTaskQueueLCStressTest.kt b/kotlinx-coroutines-core/jvm/test/lincheck/LockFreeTaskQueueLincheckTest.kt similarity index 50% rename from kotlinx-coroutines-core/jvm/test/linearizability/LockFreeTaskQueueLCStressTest.kt rename to kotlinx-coroutines-core/jvm/test/lincheck/LockFreeTaskQueueLincheckTest.kt index de494cc1e6..2a9164e1d7 100644 --- a/kotlinx-coroutines-core/jvm/test/linearizability/LockFreeTaskQueueLCStressTest.kt +++ b/kotlinx-coroutines-core/jvm/test/lincheck/LockFreeTaskQueueLincheckTest.kt @@ -3,19 +3,21 @@ */ @file:Suppress("unused") -package kotlinx.coroutines.linearizability +package kotlinx.coroutines.lincheck import kotlinx.coroutines.* import kotlinx.coroutines.internal.* +import org.jetbrains.kotlinx.lincheck.* import org.jetbrains.kotlinx.lincheck.annotations.* import org.jetbrains.kotlinx.lincheck.annotations.Operation import org.jetbrains.kotlinx.lincheck.paramgen.* -import org.jetbrains.kotlinx.lincheck.verifier.* +import org.jetbrains.kotlinx.lincheck.strategy.managed.modelchecking.* import org.jetbrains.kotlinx.lincheck.verifier.quiescent.* -import kotlin.test.* @Param(name = "value", gen = IntGen::class, conf = "1:3") -internal abstract class AbstractLockFreeTaskQueueWithoutRemoveLCStressTest protected constructor(singleConsumer: Boolean) : VerifierState() { +internal abstract class AbstractLockFreeTaskQueueWithoutRemoveLincheckTest( + val singleConsumer: Boolean +) : AbstractLincheckTest() { @JvmField protected val q = LockFreeTaskQueue(singleConsumer = singleConsumer) @@ -25,20 +27,24 @@ internal abstract class AbstractLockFreeTaskQueueWithoutRemoveLCStressTest prote @Operation fun addLast(@Param(name = "value") value: Int) = q.addLast(value) - @QuiescentConsistent - @Operation(group = "consumer") - fun removeFirstOrNull() = q.removeFirstOrNull() + override fun > O.customize(isStressTest: Boolean): O = + verifier(QuiescentConsistencyVerifier::class.java) override fun extractState() = q.map { it } to q.isClosed() - @Test - fun testWithRemoveForQuiescentConsistency() = LCStressOptionsDefault() - .verifier(QuiescentConsistencyVerifier::class.java) - .check(this::class) + override fun ModelCheckingOptions.customize(isStressTest: Boolean) = + checkObstructionFreedom() } -@OpGroupConfig(name = "consumer", nonParallel = false) -internal class MCLockFreeTaskQueueWithRemoveLCStressTest : AbstractLockFreeTaskQueueWithoutRemoveLCStressTest(singleConsumer = false) +internal class MCLockFreeTaskQueueWithRemoveLincheckTest : AbstractLockFreeTaskQueueWithoutRemoveLincheckTest(singleConsumer = false) { + @QuiescentConsistent + @Operation(blocking = true) + fun removeFirstOrNull() = q.removeFirstOrNull() +} @OpGroupConfig(name = "consumer", nonParallel = true) -internal class SCLockFreeTaskQueueWithRemoveLCStressTest : AbstractLockFreeTaskQueueWithoutRemoveLCStressTest(singleConsumer = true) \ No newline at end of file +internal class SCLockFreeTaskQueueWithRemoveLincheckTest : AbstractLockFreeTaskQueueWithoutRemoveLincheckTest(singleConsumer = true) { + @QuiescentConsistent + @Operation(group = "consumer") + fun removeFirstOrNull() = q.removeFirstOrNull() +} \ No newline at end of file diff --git a/kotlinx-coroutines-core/jvm/test/linearizability/MutexLCStressTest.kt b/kotlinx-coroutines-core/jvm/test/lincheck/MutexLincheckTest.kt similarity index 54% rename from kotlinx-coroutines-core/jvm/test/linearizability/MutexLCStressTest.kt rename to kotlinx-coroutines-core/jvm/test/lincheck/MutexLincheckTest.kt index 9542b5d8de..6e350660ae 100644 --- a/kotlinx-coroutines-core/jvm/test/linearizability/MutexLCStressTest.kt +++ b/kotlinx-coroutines-core/jvm/test/lincheck/MutexLincheckTest.kt @@ -2,30 +2,31 @@ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. */ @file:Suppress("unused") -package kotlinx.coroutines.linearizability +package kotlinx.coroutines.lincheck import kotlinx.coroutines.* import kotlinx.coroutines.sync.* +import org.jetbrains.kotlinx.lincheck.* import org.jetbrains.kotlinx.lincheck.annotations.Operation -import org.jetbrains.kotlinx.lincheck.verifier.* -import org.junit.* +import org.jetbrains.kotlinx.lincheck.strategy.managed.modelchecking.* -class MutexLCStressTest : VerifierState() { +class MutexLincheckTest : AbstractLincheckTest() { private val mutex = Mutex() @Operation fun tryLock() = mutex.tryLock() - @Operation + @Operation(promptCancellation = true) suspend fun lock() = mutex.lock() @Operation(handleExceptionsAsResult = [IllegalStateException::class]) fun unlock() = mutex.unlock() - @Test - fun test() = LCStressOptionsDefault() - .actorsBefore(0) - .check(this::class) + override fun > O.customize(isStressTest: Boolean): O = + actorsBefore(0) + + override fun ModelCheckingOptions.customize(isStressTest: Boolean) = + checkObstructionFreedom() override fun extractState() = mutex.isLocked } \ No newline at end of file diff --git a/kotlinx-coroutines-core/jvm/test/linearizability/SegmentListRemoveLCStressTest.kt b/kotlinx-coroutines-core/jvm/test/lincheck/SegmentListRemoveLincheckTest.kt similarity index 66% rename from kotlinx-coroutines-core/jvm/test/linearizability/SegmentListRemoveLCStressTest.kt rename to kotlinx-coroutines-core/jvm/test/lincheck/SegmentListRemoveLincheckTest.kt index 5daed99829..5a8d7b475d 100644 --- a/kotlinx-coroutines-core/jvm/test/linearizability/SegmentListRemoveLCStressTest.kt +++ b/kotlinx-coroutines-core/jvm/test/lincheck/SegmentListRemoveLincheckTest.kt @@ -4,18 +4,16 @@ @file:Suppress("unused") -package kotlinx.coroutines.linearizability +package kotlinx.coroutines.lincheck import kotlinx.coroutines.* import kotlinx.coroutines.internal.* +import org.jetbrains.kotlinx.lincheck.* import org.jetbrains.kotlinx.lincheck.annotations.* -import org.jetbrains.kotlinx.lincheck.annotations.Operation import org.jetbrains.kotlinx.lincheck.paramgen.* -import org.jetbrains.kotlinx.lincheck.verifier.* -import org.junit.* +import org.jetbrains.kotlinx.lincheck.strategy.managed.modelchecking.* - -class SegmentListRemoveLCStressTest : VerifierState() { +class SegmentListRemoveLincheckTest : AbstractLincheckTest() { private val q = SegmentBasedQueue() private val segments: Array> @@ -29,6 +27,9 @@ class SegmentListRemoveLCStressTest : VerifierState() { segments[index].removeSegment() } + override fun > O.customize(isStressTest: Boolean): O = this + .actorsBefore(0).actorsAfter(0) + override fun extractState() = segments.map { it.logicallyRemoved } @Validate @@ -37,9 +38,6 @@ class SegmentListRemoveLCStressTest : VerifierState() { q.checkAllSegmentsAreNotLogicallyRemoved() } - @Test - fun test() = LCStressOptionsDefault() - .actorsBefore(0) - .actorsAfter(0) - .check(this::class) + override fun ModelCheckingOptions.customize(isStressTest: Boolean) = + checkObstructionFreedom() } \ No newline at end of file diff --git a/kotlinx-coroutines-core/jvm/test/linearizability/SegmentQueueLCStressTest.kt b/kotlinx-coroutines-core/jvm/test/lincheck/SegmentQueueLincheckTest.kt similarity index 78% rename from kotlinx-coroutines-core/jvm/test/linearizability/SegmentQueueLCStressTest.kt rename to kotlinx-coroutines-core/jvm/test/lincheck/SegmentQueueLincheckTest.kt index 89bf8dfaa4..76a59e39e7 100644 --- a/kotlinx-coroutines-core/jvm/test/linearizability/SegmentQueueLCStressTest.kt +++ b/kotlinx-coroutines-core/jvm/test/lincheck/SegmentQueueLincheckTest.kt @@ -3,18 +3,17 @@ */ @file:Suppress("unused") -package kotlinx.coroutines.linearizability +package kotlinx.coroutines.lincheck import kotlinx.coroutines.* import kotlinx.coroutines.internal.SegmentBasedQueue import org.jetbrains.kotlinx.lincheck.annotations.* import org.jetbrains.kotlinx.lincheck.annotations.Operation import org.jetbrains.kotlinx.lincheck.paramgen.* -import org.jetbrains.kotlinx.lincheck.verifier.* -import org.junit.* +import org.jetbrains.kotlinx.lincheck.strategy.managed.modelchecking.* @Param(name = "value", gen = IntGen::class, conf = "1:5") -class SegmentQueueLCStressTest : VerifierState() { +class SegmentQueueLincheckTest : AbstractLincheckTest() { private val q = SegmentBasedQueue() @Operation @@ -40,6 +39,6 @@ class SegmentQueueLCStressTest : VerifierState() { return elements to closed } - @Test - fun test() = LCStressOptionsDefault().check(this::class) + override fun ModelCheckingOptions.customize(isStressTest: Boolean) = + checkObstructionFreedom() } \ No newline at end of file diff --git a/kotlinx-coroutines-core/jvm/test/lincheck/SemaphoreLincheckTest.kt b/kotlinx-coroutines-core/jvm/test/lincheck/SemaphoreLincheckTest.kt new file mode 100644 index 0000000000..84ce773c15 --- /dev/null +++ b/kotlinx-coroutines-core/jvm/test/lincheck/SemaphoreLincheckTest.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ +@file:Suppress("unused") +package kotlinx.coroutines.lincheck + +import kotlinx.coroutines.* +import kotlinx.coroutines.sync.* +import org.jetbrains.kotlinx.lincheck.* +import org.jetbrains.kotlinx.lincheck.annotations.Operation +import org.jetbrains.kotlinx.lincheck.strategy.managed.modelchecking.* + +abstract class SemaphoreLincheckTestBase(permits: Int) : AbstractLincheckTest() { + private val semaphore = Semaphore(permits) + + @Operation + fun tryAcquire() = semaphore.tryAcquire() + + @Operation(promptCancellation = true) + suspend fun acquire() = semaphore.acquire() + + @Operation(handleExceptionsAsResult = [IllegalStateException::class]) + fun release() = semaphore.release() + + override fun > O.customize(isStressTest: Boolean): O = + actorsBefore(0) + + override fun extractState() = semaphore.availablePermits + + override fun ModelCheckingOptions.customize(isStressTest: Boolean) = + checkObstructionFreedom() +} + +class Semaphore1LincheckTest : SemaphoreLincheckTestBase(1) +class Semaphore2LincheckTest : SemaphoreLincheckTestBase(2) \ No newline at end of file diff --git a/kotlinx-coroutines-core/jvm/test/linearizability/SemaphoreLCStressTest.kt b/kotlinx-coroutines-core/jvm/test/linearizability/SemaphoreLCStressTest.kt deleted file mode 100644 index 52902f4987..0000000000 --- a/kotlinx-coroutines-core/jvm/test/linearizability/SemaphoreLCStressTest.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ -@file:Suppress("unused") -package kotlinx.coroutines.linearizability - -import kotlinx.coroutines.* -import kotlinx.coroutines.sync.* -import org.jetbrains.kotlinx.lincheck.annotations.Operation -import org.jetbrains.kotlinx.lincheck.verifier.* -import org.junit.* - -abstract class SemaphoreLCStressTestBase(permits: Int) : VerifierState() { - private val semaphore = Semaphore(permits) - - @Operation - fun tryAcquire() = semaphore.tryAcquire() - - @Operation - suspend fun acquire() = semaphore.acquire() - - @Operation(handleExceptionsAsResult = [IllegalStateException::class]) - fun release() = semaphore.release() - - @Test - fun test() = LCStressOptionsDefault() - .actorsBefore(0) - .check(this::class) - - override fun extractState() = semaphore.availablePermits -} - -class Semaphore1LCStressTest : SemaphoreLCStressTestBase(1) -class Semaphore2LCStressTest : SemaphoreLCStressTestBase(2) \ No newline at end of file