Fix linearizability in AbstractChannel#sendSuspend, add infrastructure to inject custom execution into linearizability checker
diff --git a/common/kotlinx-coroutines-core-common/src/channels/AbstractChannel.kt b/common/kotlinx-coroutines-core-common/src/channels/AbstractChannel.kt
index ee9b416..3392b70 100644
--- a/common/kotlinx-coroutines-core-common/src/channels/AbstractChannel.kt
+++ b/common/kotlinx-coroutines-core-common/src/channels/AbstractChannel.kt
@@ -192,6 +192,7 @@
                     return@sc
                 }
                 is Closed<*> -> {
+                    helpClose(enqueueResult)
                     cont.resumeWithException(enqueueResult.sendException)
                     return@sc
                 }
@@ -205,6 +206,7 @@
                 }
                 offerResult === OFFER_FAILED -> continue@loop
                 offerResult is Closed<*> -> {
+                    helpClose(offerResult)
                     cont.resumeWithException(offerResult.sendException)
                     return@sc
                 }
diff --git a/core/kotlinx-coroutines-core/test/channels/ChannelIsClosedLinearizabilityTest.kt b/core/kotlinx-coroutines-core/test/channels/ChannelIsClosedLinearizabilityTest.kt
index 03d52a7..f4cd7df 100644
--- a/core/kotlinx-coroutines-core/test/channels/ChannelIsClosedLinearizabilityTest.kt
+++ b/core/kotlinx-coroutines-core/test/channels/ChannelIsClosedLinearizabilityTest.kt
@@ -53,6 +53,17 @@
             .addThread(1, 3)
             .addThread(1, 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/linearizability/FixedBehaviourExecutionGenerator.kt b/core/kotlinx-coroutines-core/test/linearizability/FixedBehaviourExecutionGenerator.kt
new file mode 100644
index 0000000..b223bba
--- /dev/null
+++ b/core/kotlinx-coroutines-core/test/linearizability/FixedBehaviourExecutionGenerator.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.coroutines.experimental.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
+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/LinTesting.kt b/core/kotlinx-coroutines-core/test/linearizability/LinTesting.kt
similarity index 100%
rename from core/kotlinx-coroutines-core/test/LinTesting.kt
rename to core/kotlinx-coroutines-core/test/linearizability/LinTesting.kt