Update lincheck
diff --git a/core/kotlinx-coroutines-core/build.gradle b/core/kotlinx-coroutines-core/build.gradle
index adb0176..7e3c0bf 100644
--- a/core/kotlinx-coroutines-core/build.gradle
+++ b/core/kotlinx-coroutines-core/build.gradle
@@ -3,7 +3,7 @@
*/
dependencies {
- testCompile "com.devexperts.lincheck:core:$lincheck_version"
+ testCompile "com.devexperts.lincheck:lincheck:$lincheck_version"
testCompile "com.esotericsoftware:kryo:4.0.0"
}
diff --git a/core/kotlinx-coroutines-core/test/internal/LockFreeTaskQueueLinearizabilityTest.kt b/core/kotlinx-coroutines-core/test/internal/LockFreeTaskQueueLinearizabilityTest.kt
deleted file mode 100644
index 91ae937..0000000
--- a/core/kotlinx-coroutines-core/test/internal/LockFreeTaskQueueLinearizabilityTest.kt
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-@file:Suppress("unused")
-
-package kotlinx.coroutines.internal
-
-import com.devexperts.dxlab.lincheck.*
-import com.devexperts.dxlab.lincheck.annotations.*
-import com.devexperts.dxlab.lincheck.paramgen.*
-import com.devexperts.dxlab.lincheck.stress.*
-import kotlinx.coroutines.*
-import kotlin.test.*
-
-@OpGroupConfigs(OpGroupConfig(name = "consumer", nonParallel = true))
-@Param(name = "value", gen = IntGen::class, conf = "1:3")
-class LockFreeTaskQueueLinearizabilityTestSC : LockFreeTaskQueueLinearizabilityTestBase() {
- private lateinit var q: LockFreeTaskQueue<Int>
-
- @Reset
- fun resetQueue() {
- q = LockFreeTaskQueue(singleConsumer = true) // SINGLE-CONSUMER !!!
- }
-
- @Operation
- fun close() = q.close()
-
- @Operation
- fun addLast(@Param(name = "value") value: Int) = q.addLast(value)
-
- /**
- * Note, that removeFirstOrNull is not linearizable w.r.t. to addLast, so here
- * we test only linearizability of close.
- */
-// @Operation(group = "consumer")
-// fun removeFirstOrNull() = q.removeFirstOrNull()
-
- @Test
- fun testSC() = linTest()
-}
-
-@OpGroupConfigs(OpGroupConfig(name = "consumer", nonParallel = true))
-@Param(name = "value", gen = IntGen::class, conf = "1:3")
-class LockFreeTaskQueueLinearizabilityTestMC : LockFreeTaskQueueLinearizabilityTestBase() {
- private lateinit var q: LockFreeTaskQueue<Int>
-
- @Reset
- fun resetQueue() {
- q = LockFreeTaskQueue(singleConsumer = false) // MULTI-CONSUMER !!!
- }
-
- @Operation
- fun close() = q.close()
-
- @Operation
- fun addLast(@Param(name = "value") value: Int) = q.addLast(value)
-
- /**
- * Note, that removeFirstOrNull is not linearizable w.r.t. to addLast, so here
- * we test only linearizability of close.
- */
-// @Operation(group = "consumer")
-// fun removeFirstOrNull() = q.removeFirstOrNull()
-
- @Test
- fun testMC() = linTest()
-}
-
-open class LockFreeTaskQueueLinearizabilityTestBase : TestBase() {
- fun linTest() {
- val options = StressOptions()
- .iterations(100 * stressTestMultiplierSqrt)
- .invocationsPerIteration(1000 * stressTestMultiplierSqrt)
- .addThread(1, 3)
- .addThread(1, 3)
- .addThread(1, 3)
- LinChecker.check(this::class.java, options)
- }
-}
\ No newline at end of file
diff --git a/core/kotlinx-coroutines-core/test/channels/ChannelIsClosedLinearizabilityTest.kt b/core/kotlinx-coroutines-core/test/linearizability/ChannelIsClosedLinearizabilityTest.kt
similarity index 68%
rename from core/kotlinx-coroutines-core/test/channels/ChannelIsClosedLinearizabilityTest.kt
rename to core/kotlinx-coroutines-core/test/linearizability/ChannelIsClosedLinearizabilityTest.kt
index 70f5481..7cc2df0 100644
--- a/core/kotlinx-coroutines-core/test/channels/ChannelIsClosedLinearizabilityTest.kt
+++ b/core/kotlinx-coroutines-core/test/linearizability/ChannelIsClosedLinearizabilityTest.kt
@@ -3,13 +3,14 @@
*/
@file:Suppress("unused")
-package kotlinx.coroutines.channels
+package kotlinx.coroutines.linearizability
import com.devexperts.dxlab.lincheck.*
import com.devexperts.dxlab.lincheck.annotations.*
import com.devexperts.dxlab.lincheck.paramgen.*
-import com.devexperts.dxlab.lincheck.stress.*
+import com.devexperts.dxlab.lincheck.strategy.stress.*
import kotlinx.coroutines.*
+import kotlinx.coroutines.channels.*
import org.junit.*
import java.io.*
@@ -17,12 +18,7 @@
class ChannelIsClosedLinearizabilityTest : TestBase() {
private val lt = LinTesting()
- private lateinit var channel: Channel<Int>
-
- @Reset
- fun resetChannel() {
- channel = Channel()
- }
+ private val channel = Channel<Int>()
@Operation(runOnce = true)
fun send1(@Param(name = "value") value: Int) = lt.run("send1") { channel.send(value) }
@@ -50,20 +46,8 @@
val options = StressOptions()
.iterations(100)
.invocationsPerIteration(1000 * stressTestMultiplier)
- .addThread(1, 3)
- .addThread(1, 3)
- .addThread(1, 3)
+ .threads(3)
.verifier(LinVerifier::class.java)
- .injectExecution { actors, methods ->
- actors[0].add(actorMethod(methods, "receive1"))
- actors[0].add(actorMethod(methods, "receive2"))
- actors[0].add(actorMethod(methods, "close1"))
-
- actors[1].add(actorMethod(methods, "send2"))
- actors[1].add(actorMethod(methods, "send1"))
-
- actors[2].add(actorMethod(methods, "isClosedForSend"))
- }
LinChecker.check(ChannelIsClosedLinearizabilityTest::class.java, options)
}
diff --git a/core/kotlinx-coroutines-core/test/channels/ChannelLinearizabilityTest.kt b/core/kotlinx-coroutines-core/test/linearizability/ChannelLinearizabilityTest.kt
similarity index 84%
rename from core/kotlinx-coroutines-core/test/channels/ChannelLinearizabilityTest.kt
rename to core/kotlinx-coroutines-core/test/linearizability/ChannelLinearizabilityTest.kt
index 9f02767..6ce2319 100644
--- a/core/kotlinx-coroutines-core/test/channels/ChannelLinearizabilityTest.kt
+++ b/core/kotlinx-coroutines-core/test/linearizability/ChannelLinearizabilityTest.kt
@@ -3,28 +3,29 @@
*/
@file:Suppress("unused")
-package kotlinx.coroutines.channels
+package kotlinx.coroutines.linearizability
import com.devexperts.dxlab.lincheck.*
import com.devexperts.dxlab.lincheck.annotations.*
import com.devexperts.dxlab.lincheck.paramgen.*
-import com.devexperts.dxlab.lincheck.stress.*
+import com.devexperts.dxlab.lincheck.strategy.stress.*
import kotlinx.coroutines.*
+import kotlinx.coroutines.channels.*
import org.junit.*
import java.io.*
@Param(name = "value", gen = IntGen::class, conf = "1:3")
class ChannelLinearizabilityTest : TestBase() {
- private val lt = LinTesting()
- private var capacity = 0
- private lateinit var channel: Channel<Int>
-
- @Reset
- fun resetChannel() {
- channel = Channel(capacity)
+ private companion object {
+ // Emulating ctor argument for lincheck
+ var capacity = 0
}
+ private val lt = LinTesting()
+ private var channel: Channel<Int> = Channel(capacity)
+
+
@Operation(runOnce = true)
fun send1(@Param(name = "value") value: Int) = lt.run("send1") { channel.send(value) }
@@ -68,13 +69,11 @@
fun testUnlimitedChannelLinearizability() = runTest(Channel.UNLIMITED)
private fun runTest(capacity: Int) {
- this.capacity = capacity
+ ChannelLinearizabilityTest.capacity = capacity
val options = StressOptions()
.iterations(100)
.invocationsPerIteration(1000 * stressTestMultiplier)
- .addThread(1, 3)
- .addThread(1, 3)
- .addThread(1, 3)
+ .threads(3)
.verifier(LinVerifier::class.java)
LinChecker.check(ChannelLinearizabilityTest::class.java, options)
}
diff --git a/core/kotlinx-coroutines-core/test/linearizability/FixedBehaviourExecutionGenerator.kt b/core/kotlinx-coroutines-core/test/linearizability/FixedBehaviourExecutionGenerator.kt
deleted file mode 100644
index 1e36672..0000000
--- a/core/kotlinx-coroutines-core/test/linearizability/FixedBehaviourExecutionGenerator.kt
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package kotlinx.coroutines.channels
-
-import com.devexperts.dxlab.lincheck.*
-import com.devexperts.dxlab.lincheck.execution.*
-import java.util.*
-
-typealias ExecutionBuilder = (List<MutableList<Actor>>, List<ActorGenerator>) -> Unit
-
-/**
- * Example of usage:
- *
- * ```
- * StressOptions().injectExecution { actors, methods ->
- * actors[0].add(actorMethod(methods, "receive1"))
- * actors[0].add(actorMethod(methods, "receive2"))
- *
- * actors[1].add(actorMethod(methods, "send2"))
- * actors[1].add(actorMethod(methods, "send1"))
- * }
- *
- * ```
- *
- * Will produce
- * ```
- * Actors per thread:
- * [receive1(), receive2()]
- * [send2(), send1()]
- * ```
- * at the first iteration.
- *
- * DSL will be improved when this method will be used frequently
- */
-fun Options<*, *>.injectExecution(behaviourBuilder: ExecutionBuilder): Options<*, *> {
- injectedBehaviour.add(behaviourBuilder)
- executionGenerator(FixedBehaviourInjectorExecutionGenerator::class.java)
- return this
-}
-
-fun actorMethod(generators: List<ActorGenerator>, name: String): Actor =
- generators.find { it.generate().method.name.contains(name) }?.generate() ?: error("Actor method $name is not found in ${generators.map { it.generate().method.name }}")
-
-private val injectedBehaviour: Queue<ExecutionBuilder> = ArrayDeque<ExecutionBuilder>()
-
-class FixedBehaviourInjectorExecutionGenerator(testConfiguration: CTestConfiguration, testStructure: CTestStructure)
- : ExecutionGenerator(testConfiguration, testStructure) {
-
- private val randomGenerator = RandomExecutionGenerator(testConfiguration, testStructure)
-
- override fun nextExecution(): List<List<Actor>> {
- val injector = injectedBehaviour.poll()
- if (injector != null) {
- val parallelGroup = ArrayList(testStructure.actorGenerators)
- val actorsPerThread = ArrayList<MutableList<Actor>>()
- for (i in testConfiguration.threadConfigurations.indices) {
- actorsPerThread.add(ArrayList())
- }
-
- injector.invoke(actorsPerThread, parallelGroup)
- return actorsPerThread
- }
-
- return randomGenerator.nextExecution()
- }
-}
-
-// Ad-hoc fixed execution injection for lin-checker
-@Suppress("unused")
-class FixedBehaviourExecutionGenerator(testConfiguration: CTestConfiguration, testStructure: CTestStructure)
- : ExecutionGenerator(testConfiguration, testStructure) {
-
- override fun nextExecution(): List<List<Actor>> {
- val parallelGroup = ArrayList(testStructure.actorGenerators)
- val actorsPerThread = ArrayList<MutableList<Actor>>()
- for (i in testConfiguration.threadConfigurations.indices) {
- actorsPerThread.add(ArrayList())
- }
-
-
- actorsPerThread[0].add(actorMethod(parallelGroup, "receive1"))
- actorsPerThread[0].add(actorMethod(parallelGroup, "receive2"))
- actorsPerThread[0].add(actorMethod(parallelGroup, "close1"))
-
- actorsPerThread[1].add(actorMethod(parallelGroup, "send2"))
- actorsPerThread[1].add(actorMethod(parallelGroup, "send1"))
-
- return actorsPerThread
- }
-}
\ No newline at end of file
diff --git a/core/kotlinx-coroutines-core/test/linearizability/LinTesting.kt b/core/kotlinx-coroutines-core/test/linearizability/LinTesting.kt
index 878dd64..14cf2a7 100644
--- a/core/kotlinx-coroutines-core/test/linearizability/LinTesting.kt
+++ b/core/kotlinx-coroutines-core/test/linearizability/LinTesting.kt
@@ -6,6 +6,8 @@
import com.devexperts.dxlab.lincheck.Actor
import com.devexperts.dxlab.lincheck.Result
+import com.devexperts.dxlab.lincheck.Utils.*
+import com.devexperts.dxlab.lincheck.execution.*
import com.devexperts.dxlab.lincheck.verifier.Verifier
import java.lang.reflect.Method
import java.util.*
@@ -57,22 +59,21 @@
}
}
-class LinVerifier(
- actorsPerThread: List<List<Actor>>, testInstance: Any, resetMethod: Method?
-) : Verifier(actorsPerThread, testInstance, resetMethod) {
+class LinVerifier(scenario: ExecutionScenario,
+ testClass: Class<*>) : Verifier {
private val possibleResultsSet: Set<List<List<Result>>> =
- generateAllLinearizableExecutions(actorsPerThread)
+ generateAllLinearizableExecutions(scenario.parallelExecution)
.asSequence()
.map { linEx: List<Actor> ->
- val res: List<Result> = executeActors(testInstance, linEx)
+ val res: List<Result> = executeActors(testClass.newInstance(), linEx)
val actorIds = linEx.asSequence().withIndex().associateBy({ it.value}, { it.index })
- actorsPerThread.map { actors -> actors.map { actor -> res[actorIds[actor]!!] } }
+ scenario.parallelExecution.map { actors -> actors.map { actor -> res[actorIds[actor]!!] } }
}.toSet()
- override fun verifyResults(results: List<List<Result>>) {
- if (!valid(results)) {
+ override fun verifyResults(results: ExecutionResult): Boolean {
+ if (!valid(results.parallelResults)) {
println("\nNon-linearizable execution:")
- printResults(results)
+ printResults(results.parallelResults)
println("\nPossible linearizable executions:")
possibleResultsSet.forEach { possibleResults ->
printResults(possibleResults)
@@ -80,6 +81,8 @@
}
throw AssertionError("Non-linearizable execution detected, see log for details")
}
+
+ return true
}
private fun printResults(results: List<List<Result>>) {
@@ -103,7 +106,7 @@
private fun generateAllLinearizableExecutions(actorsPerThread: List<List<Actor>>): List<List<Actor>> {
val executions = ArrayList<List<Actor>>()
generateLinearizableExecutions0(
- executions, actorsPerThread, ArrayList<Actor>(), IntArray(actorsPerThread.size),
+ executions, actorsPerThread, ArrayList(), IntArray(actorsPerThread.size),
actorsPerThread.sumBy { it.size })
return executions
}
diff --git a/core/kotlinx-coroutines-core/test/internal/LockFreeListLinearizabilityTest.kt b/core/kotlinx-coroutines-core/test/linearizability/LockFreeListLinearizabilityTest.kt
similarity index 81%
rename from core/kotlinx-coroutines-core/test/internal/LockFreeListLinearizabilityTest.kt
rename to core/kotlinx-coroutines-core/test/linearizability/LockFreeListLinearizabilityTest.kt
index d87b1fb..c474e4c 100644
--- a/core/kotlinx-coroutines-core/test/internal/LockFreeListLinearizabilityTest.kt
+++ b/core/kotlinx-coroutines-core/test/linearizability/LockFreeListLinearizabilityTest.kt
@@ -3,25 +3,21 @@
*/
@file:Suppress("unused")
-package kotlinx.coroutines.internal
+package kotlinx.coroutines.linearizability
import com.devexperts.dxlab.lincheck.*
import com.devexperts.dxlab.lincheck.annotations.*
import com.devexperts.dxlab.lincheck.paramgen.*
-import com.devexperts.dxlab.lincheck.stress.*
+import com.devexperts.dxlab.lincheck.strategy.stress.*
import kotlinx.coroutines.*
+import kotlinx.coroutines.internal.*
import kotlin.test.*
@Param(name = "value", gen = IntGen::class, conf = "1:3")
class LockFreeListLinearizabilityTest : TestBase() {
class Node(val value: Int): LockFreeLinkedListNode()
- private lateinit var q: LockFreeLinkedListHead
-
- @Reset
- fun resetList() {
- q = LockFreeLinkedListHead()
- }
+ private val q: LockFreeLinkedListHead = LockFreeLinkedListHead()
@Operation
fun addLast(@Param(name = "value") value: Int) {
@@ -52,10 +48,7 @@
val options = StressOptions()
.iterations(100)
.invocationsPerIteration(1000 * stressTestMultiplier)
- .addThread(1, 2)
- .addThread(1, 2)
- .addThread(1, 2)
- .addThread(1, 2)
+ .threads(4)
LinChecker.check(LockFreeListLinearizabilityTest::class.java, options)
}
}
\ No newline at end of file
diff --git a/core/kotlinx-coroutines-core/test/linearizability/LockFreeTaskQueueLinearizabilityTest.kt b/core/kotlinx-coroutines-core/test/linearizability/LockFreeTaskQueueLinearizabilityTest.kt
new file mode 100644
index 0000000..aa6285b
--- /dev/null
+++ b/core/kotlinx-coroutines-core/test/linearizability/LockFreeTaskQueueLinearizabilityTest.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2016-2018 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 com.devexperts.dxlab.lincheck.*
+import com.devexperts.dxlab.lincheck.annotations.*
+import com.devexperts.dxlab.lincheck.paramgen.*
+import com.devexperts.dxlab.lincheck.strategy.stress.*
+import kotlinx.coroutines.*
+import kotlinx.coroutines.internal.*
+import kotlin.test.*
+
+@OpGroupConfig.OpGroupConfigs(OpGroupConfig(name = "consumer", nonParallel = true))
+@Param(name = "value", gen = IntGen::class, conf = "1:3")
+class LockFreeTaskQueueLinearizabilityTest : TestBase() {
+
+ private companion object {
+ var singleConsumer = false
+ }
+
+ private val q: LockFreeTaskQueue<Int> = LockFreeTaskQueue(singleConsumer)
+
+ @Operation
+ fun close() = q.close()
+
+ @Operation
+ fun addLast(@Param(name = "value") value: Int) = q.addLast(value)
+
+ /**
+ * Note, that removeFirstOrNull is not linearizable w.r.t. to addLast, so here
+ * we test only linearizability of close.
+ */
+// @Operation(group = "consumer")
+// fun removeFirstOrNull() = q.removeFirstOrNull()
+
+ @Test
+ fun testLinearizabilitySC() {
+ singleConsumer = true
+ linTest()
+ }
+
+ @Test
+ fun testLinearizabilityMC() {
+ singleConsumer = false
+ linTest()
+ }
+
+ private fun linTest() {
+ val options = StressOptions()
+ .iterations(100 * stressTestMultiplierSqrt)
+ .invocationsPerIteration(1000 * stressTestMultiplierSqrt)
+ .threads(3)
+ LinChecker.check(LockFreeTaskQueueLinearizabilityTest::class.java, options)
+ }
+}
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index df587f5..18afb0e 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -8,7 +8,7 @@
junit_version=4.12
atomicFU_version=0.11.12
html_version=0.6.8
-lincheck_version=1.9
+lincheck_version=2.0
dokka_version=0.9.16-rdev-2-mpp-hacks
bintray_version=1.8.2-SNAPSHOT
artifactory_plugin_version=4.7.3