diff --git a/backend.native/tests/build.gradle b/backend.native/tests/build.gradle index 04ca9d154fb..6b7235637d6 100644 --- a/backend.native/tests/build.gradle +++ b/backend.native/tests/build.gradle @@ -1018,6 +1018,12 @@ task atomic0(type: KonanLocalTest) { source = "runtime/workers/atomic0.kt" } +standaloneTest("atomic1") { + // Note: This test reproduces a race, so it'll start flaking if problem is reintroduced. + enabled = (project.testTarget != 'wasm32') // Workers need pthreads. + source = "runtime/workers/atomic1.kt" +} + task lazy0(type: KonanLocalTest) { enabled = (project.testTarget != 'wasm32') // Workers need pthreads. goldValue = "OK\n" diff --git a/backend.native/tests/runtime/workers/atomic1.kt b/backend.native/tests/runtime/workers/atomic1.kt new file mode 100644 index 00000000000..d6b065a2f83 --- /dev/null +++ b/backend.native/tests/runtime/workers/atomic1.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the LICENSE file. + */ + +// Note: This test reproduces a race, so it'll start flaking if problem is reintroduced. + +import kotlin.test.* + +import kotlin.native.concurrent.* +import kotlin.native.internal.* + +val thrashGC = AtomicInt(1) +val canStartCreating = AtomicInt(0) +val createdCount = AtomicInt(0) +val canStartReading = AtomicInt(0) +const val atomicsCount = 1000 +const val workersCount = 10 + +fun main() { + val gcWorker = Worker.start() + val future = gcWorker.execute(TransferMode.SAFE, {}, { + canStartCreating.value = 1 + while (thrashGC.value != 0) { + GC.collectCyclic() + } + GC.collect() + }) + + while (canStartCreating.value == 0) {} + + val workers = Array(workersCount) { Worker.start() } + val futures = workers.map { + it.execute(TransferMode.SAFE, {}, { + val atomics = Array(atomicsCount) { + AtomicReference(Any().freeze()) + } + createdCount.increment() + while (canStartReading.value == 0) {} + GC.collect() + atomics.all { it.value != null } + }) + } + + while (createdCount.value != workersCount) {} + + thrashGC.value = 0 + future.result + GC.collect() + canStartReading.value = 1 + + assertTrue(futures.all { it.result }) + + for (worker in workers) { + worker.requestTermination().result + } + gcWorker.requestTermination().result +}