From a5abaae70f4b4b783e5319f306ad3638120d8e4a Mon Sep 17 00:00:00 2001 From: Alexander Shabalin Date: Wed, 18 Mar 2020 12:39:33 +0300 Subject: [PATCH] Add a test --- backend.native/tests/build.gradle | 5 ++ .../tests/runtime/basic/initializers6.kt | 75 +++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 backend.native/tests/runtime/basic/initializers6.kt diff --git a/backend.native/tests/build.gradle b/backend.native/tests/build.gradle index ae42d5f30e5..c6a231429b3 100644 --- a/backend.native/tests/build.gradle +++ b/backend.native/tests/build.gradle @@ -2675,6 +2675,11 @@ task initializers5(type: KonanLocalTest) { source = "runtime/basic/initializers5.kt" } +task initializers6(type: KonanLocalTest) { + disabled = project.testTarget == 'wasm32' // Needs workers. + source = "runtime/basic/initializers6.kt" +} + task expression_as_statement(type: KonanLocalTest) { expectedFail = (project.testTarget == 'wasm32') // uses exceptions. goldValue = "Ok\n" diff --git a/backend.native/tests/runtime/basic/initializers6.kt b/backend.native/tests/runtime/basic/initializers6.kt new file mode 100644 index 00000000000..4fc1af5c530 --- /dev/null +++ b/backend.native/tests/runtime/basic/initializers6.kt @@ -0,0 +1,75 @@ +/* + * 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. + */ + +package runtime.basic.initializers6 + +import kotlin.test.* + +import kotlin.native.concurrent.* + +val aWorkerId = 2 +val bWorkersCount = 3 + +val aWorkerUnlocker = AtomicInt(0) +val bWorkerUnlocker = AtomicInt(0) + +object A { + init { + // Must be called by aWorker only. + assertEquals(aWorkerId, Worker.current.id) + // Only allow b workers to run, when a worker has started initialization. + bWorkerUnlocker.increment() + // Only proceed with initialization, when all b workers have started executing. + while (aWorkerUnlocker.value < bWorkersCount) {} + // And now wait a bit, to increase probability of races. + Worker.current.park(1000 * 1000L) + } + val a = produceA() + val b = produceB() +} + +fun produceA(): String { + // Must've been called by aWorker only. + assertEquals(aWorkerId, Worker.current.id) + return "A" +} + +fun produceB(): String { + // Must've been called by aWorker only. + assertEquals(aWorkerId, Worker.current.id) + // Also check that it's ok to get A.a while initializing A.b. + return "B+${A.a}" +} + +@Test fun runTest() { + val aWorker = Worker.start() + // This test relies on aWorkerId value. + assertEquals(aWorkerId, aWorker.id) + val bWorkers = Array(bWorkersCount, { _ -> Worker.start() }) + + val aFuture = aWorker.execute(TransferMode.SAFE, {}, { + A.b + }) + val bFutures = Array(bWorkers.size, { + bWorkers[it].execute(TransferMode.SAFE, {}, { + // Wait until A has started to initialize. + while (bWorkerUnlocker.value < 1) {} + // Now allow A initialization to continue. + aWorkerUnlocker.increment() + // And this should not've tried to init A itself. + A.a + A.b + }) + }) + + for (future in bFutures) { + assertEquals("AB+A", future.result) + } + assertEquals("B+A", aFuture.result) + + for (worker in bWorkers) { + worker.requestTermination().result + } + aWorker.requestTermination().result +}