From 2f22b0a6b0bc675d442ccfb786ffe32cd0602cc9 Mon Sep 17 00:00:00 2001 From: Alexander Shabalin Date: Wed, 30 Aug 2023 18:10:34 +0200 Subject: [PATCH] [K/N] Migrate runtime/atomics tests to new testing infra ^KT-61259 --- .../backend.native/tests/build.gradle | 27 - .../tests/runtime/atomics/atomic0.kt | 180 ------ .../tests/runtime/atomics/atomic0.out | 3 - .../tests/runtime/atomics/atomic1.kt | 61 -- .../runtime/atomics/atomic_array_smoke.kt | 596 ------------------ .../runtime/atomics/atomic_array_stress.kt | 87 --- .../tests/runtime/atomics/atomic_smoke.kt | 189 ------ .../tests/runtime/atomics/atomic_stress.kt | 97 --- .../test/concurrent/AtomicArrayTest.kt | 570 +++++++++++++++++ .../test/concurrent/AtomicStressTest.kt | 238 +++++++ .../runtime/test/concurrent/AtomicTest.kt | 217 +++++++ .../kotlin/konan/blackboxtest/StdlibTest.kt | 5 +- 12 files changed, 1028 insertions(+), 1242 deletions(-) delete mode 100644 kotlin-native/backend.native/tests/runtime/atomics/atomic0.kt delete mode 100644 kotlin-native/backend.native/tests/runtime/atomics/atomic0.out delete mode 100644 kotlin-native/backend.native/tests/runtime/atomics/atomic1.kt delete mode 100644 kotlin-native/backend.native/tests/runtime/atomics/atomic_array_smoke.kt delete mode 100644 kotlin-native/backend.native/tests/runtime/atomics/atomic_array_stress.kt delete mode 100644 kotlin-native/backend.native/tests/runtime/atomics/atomic_smoke.kt delete mode 100644 kotlin-native/backend.native/tests/runtime/atomics/atomic_stress.kt create mode 100644 kotlin-native/runtime/test/concurrent/AtomicArrayTest.kt create mode 100644 kotlin-native/runtime/test/concurrent/AtomicStressTest.kt create mode 100644 kotlin-native/runtime/test/concurrent/AtomicTest.kt diff --git a/kotlin-native/backend.native/tests/build.gradle b/kotlin-native/backend.native/tests/build.gradle index 6618ded4b60..e205ae22c08 100644 --- a/kotlin-native/backend.native/tests/build.gradle +++ b/kotlin-native/backend.native/tests/build.gradle @@ -1008,33 +1008,6 @@ standaloneTest("freeze_disabled") { testLogger = KonanTest.Logger.SILENT } -tasks.register("atomicSmokeTest", KonanLocalTest) { - source = "runtime/atomics/atomic_smoke.kt" -} - -tasks.register("atomicStressTest", KonanLocalTest) { - source = "runtime/atomics/atomic_stress.kt" -} - -tasks.register("atomic0", KonanLocalTest) { - useGoldenData = true - source = "runtime/atomics/atomic0.kt" -} - -standaloneTest("atomic1") { - // Note: This test reproduces a race, so it'll start flaking if problem is reintroduced. - enabled = false // Needs USE_CYCLIC_GC, which is disabled. - source = "runtime/atomics/atomic1.kt" -} - -tasks.register("atomicArraySmokeTest", KonanLocalTest) { - source = "runtime/atomics/atomic_array_smoke.kt" -} - -tasks.register("atomicArrayStressTest", KonanLocalTest) { - source = "runtime/atomics/atomic_array_stress.kt" -} - tasks.register("lazy0", KonanLocalTest) { useGoldenData = true source = "runtime/workers/lazy0.kt" diff --git a/kotlin-native/backend.native/tests/runtime/atomics/atomic0.kt b/kotlin-native/backend.native/tests/runtime/atomics/atomic0.kt deleted file mode 100644 index 4329f6b26ae..00000000000 --- a/kotlin-native/backend.native/tests/runtime/atomics/atomic0.kt +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class, FreezingIsDeprecated::class, ObsoleteWorkersApi::class) -package runtime.atomics.atomic0 - -import kotlin.test.* - -import kotlin.native.concurrent.* -import kotlin.concurrent.AtomicInt -import kotlin.concurrent.AtomicLong -import kotlin.concurrent.AtomicReference - -fun test1(workers: Array) { - val atomic = AtomicInt(15) - val futures = Array(workers.size, { workerIndex -> - workers[workerIndex].execute(TransferMode.SAFE, { atomic }) { - input -> input.addAndGet(1) - } - }) - futures.forEach { - it.result - } - println(atomic.value) -} - -fun test2(workers: Array) { - val atomic = AtomicInt(1) - val counter = AtomicInt(0) - val futures = Array(workers.size, { workerIndex -> - workers[workerIndex].execute(TransferMode.SAFE, { Triple(atomic, workerIndex, counter) }) { - (place, index, result) -> - // Here we simulate mutex using [place] location to store tag of the current worker. - // When it is negative - worker executes exclusively. - val tag = index + 1 - while (place.compareAndExchange(tag, -tag) != tag) {} - val ok1 = result.addAndGet(1) == index + 1 - // Now, let the next worker run. - val ok2 = place.compareAndExchange(-tag, tag + 1) == -tag - ok1 && ok2 - } - }) - futures.forEach { - assertEquals(it.result, true) - } - println(counter.value) -} - -data class Data(val value: Int) - -fun test3(workers: Array) { - val common = AtomicReference(null) - val futures = Array(workers.size, { workerIndex -> - workers[workerIndex].execute(TransferMode.SAFE, { Pair(common, workerIndex) }) { - (place, index) -> - val mine = Data(index).freeze() - // Try to publish our own data, until successful, in a tight loop. - while (!place.compareAndSet(null, mine)) {} - } - }) - val seen = mutableSetOf() - for (i in 0 until workers.size) { - do { - val current = common.value - if (current != null && !seen.contains(current)) { - seen += current - // Let others publish. - assertEquals(common.compareAndExchange(current, null), current) - break - } - } while (true) - } - futures.forEach { - it.result - } - assertEquals(seen.size, workers.size) -} - -fun test4LegacyMM() { - assertFailsWith { - AtomicReference(Data(1)) - } - assertFailsWith { - AtomicReference(null).compareAndExchange(null, Data(2)) - } -} - -fun test4() { - run { - val ref = AtomicReference(Data(1)) - assertEquals(1, ref.value.value) - } - run { - val ref = AtomicReference(null) - ref.compareAndExchange(null, Data(2)) - assertEquals(2, ref.value!!.value) - } - if (Platform.isFreezingEnabled) { - run { - val ref = AtomicReference(null).freeze() - assertFailsWith { - ref.compareAndExchange(null, Data(2)) - } - } - } -} - -fun test5LegacyMM() { - assertFailsWith { - AtomicReference(null).value = Data(2) - } - val ref = AtomicReference(null) - val value = Data(3).freeze() - assertEquals(null, ref.value) - ref.value = value - assertEquals(3, ref.value!!.value) -} - -fun test5() { - val ref = AtomicReference(null) - ref.value = Data(2) - assertEquals(2, ref.value!!.value) - ref.value = Data(3).freeze() - assertEquals(3, ref.value!!.value) -} - -fun test6() { - val int = AtomicInt(0) - int.value = 239 - assertEquals(239, int.value) - val long = AtomicLong(0) - long.value = 239L - assertEquals(239L, long.value) -} - -@Suppress("DEPRECATION_ERROR") -fun test7() { - val ref = AtomicReference(Array(1) { "hey" }) - ref.value[0] = "ho" - assertEquals(ref.value[0], "ho") - ref.value = Array(1) { "po" } - assertEquals(ref.value[0], "po") - ref.freeze() - if (Platform.isFreezingEnabled) { - assertFailsWith { - ref.value = Array(1) { "no" } - } - assertFailsWith { - ref.value[0] = "go" - } - } - ref.value = Array(1) { "so" }.freeze() - assertEquals(ref.value[0], "so") -} - -@Test fun runTest() { - val COUNT = 20 - val workers = Array(COUNT, { _ -> Worker.start()}) - - test1(workers) - test2(workers) - test3(workers) - if (Platform.memoryModel == MemoryModel.EXPERIMENTAL) { - test4() - test5() - } else { - test4LegacyMM() - test5LegacyMM() - } - test6() - test7() - - workers.forEach { - it.requestTermination().result - } - println("OK") -} - diff --git a/kotlin-native/backend.native/tests/runtime/atomics/atomic0.out b/kotlin-native/backend.native/tests/runtime/atomics/atomic0.out deleted file mode 100644 index 3cb3acfc7d5..00000000000 --- a/kotlin-native/backend.native/tests/runtime/atomics/atomic0.out +++ /dev/null @@ -1,3 +0,0 @@ -35 -20 -OK diff --git a/kotlin-native/backend.native/tests/runtime/atomics/atomic1.kt b/kotlin-native/backend.native/tests/runtime/atomics/atomic1.kt deleted file mode 100644 index eff1a0871f8..00000000000 --- a/kotlin-native/backend.native/tests/runtime/atomics/atomic1.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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. -@file:OptIn(kotlin.native.runtime.NativeRuntimeApi::class) - -import kotlin.test.* - -import kotlin.concurrent.AtomicInt -import kotlin.native.concurrent.* -import kotlin.native.internal.* -import kotlin.native.runtime.GC - -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.incrementAndGet() - 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 -} diff --git a/kotlin-native/backend.native/tests/runtime/atomics/atomic_array_smoke.kt b/kotlin-native/backend.native/tests/runtime/atomics/atomic_array_smoke.kt deleted file mode 100644 index 23b807a56a7..00000000000 --- a/kotlin-native/backend.native/tests/runtime/atomics/atomic_array_smoke.kt +++ /dev/null @@ -1,596 +0,0 @@ -/* - * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:OptIn(kotlin.ExperimentalStdlibApi::class) - -package runtime.atomics.atomic_array_smoke - -import kotlin.test.* -import kotlin.concurrent.* - -@Test -fun testAtomicIntArrayConstructor() { - val arr1 = AtomicIntArray(6) - assertEquals(arr1[4], 0) - assertEquals(arr1.length, 6) - - val arr2 = AtomicIntArray(10) { i: Int -> i * 10 } - assertEquals(arr2[4], 40) - assertEquals(arr2.length, 10) - - val emptyArr = AtomicIntArray(0) - assertEquals(emptyArr.length, 0) - - assertFailsWith { - val arrNegativeSize = AtomicIntArray(-5) - } -} - -@Test -fun testAtomicIntArrayGetElement() { - val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 } - for (i in 0 until atomicIntArr.length) { - assertEquals(i * 10, atomicIntArr[i], "testAtomicIntArrayGetElement: FAIL $i") - } - assertFailsWith { - val res = atomicIntArr[22] - }.let { ex -> - assertEquals("The index 22 is out of the bounds of the AtomicIntArray with size 10.", ex.message) - } - assertFailsWith { - val res = atomicIntArr[-1] - }.let { ex -> - assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message) - } -} - -@Test -fun testAtomicIntArraySetElement() { - val atomicIntArr = AtomicIntArray(10) - for (i in 0 until atomicIntArr.length) { - atomicIntArr[i] = i * 10 - } - for (i in 0 until atomicIntArr.length) { - assertEquals(i * 10, atomicIntArr[i], "testAtomicIntArraySetElement: FAIL $i") - } - assertFailsWith { - atomicIntArr[22] = 100 - }.let { ex -> - assertEquals("The index 22 is out of the bounds of the AtomicIntArray with size 10.", ex.message) - } - assertFailsWith { - atomicIntArr[-1] = 100 - }.let { ex -> - assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message) - } -} - -@Test -fun testAtomicIntArrayCompareAndExchange() { - val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 } - val res1 = atomicIntArr.compareAndExchange(2, 20, 222) // success - assertTrue(res1 == 20 && atomicIntArr[2] == 222, "testAtomicIntArrayCompareAndExchange: FAIL 1") - val res2 = atomicIntArr.compareAndExchange(2, 222, 2222) // success - assertTrue(res2 == 222 && atomicIntArr[2] == 2222, "testAtomicIntArrayCompareAndExchange: FAIL 2") - val res3 = atomicIntArr.compareAndExchange(2, 223, 22222) // should fail - assertTrue(res3 == 2222 && atomicIntArr[2] == 2222, "testAtomicIntArrayCompareAndExchange: FAIL 3") - val res4 = atomicIntArr.compareAndExchange(9, 10, 999) // should fail - assertTrue(res4 == 90 && atomicIntArr[9] == 90, "testAtomicIntArrayCompareAndExchange: FAIL 4") - assertFailsWith { - val res = atomicIntArr.compareAndExchange(10, 33535, 39530) - }.let { ex -> - assertEquals("The index 10 is out of the bounds of the AtomicIntArray with size 10.", ex.message) - } - assertFailsWith { - val res = atomicIntArr.compareAndExchange(-1, 33535, 39530) - }.let { ex -> - assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message) - } -} - -@Test -fun testAtomicIntArrayCompareAndSet() { - val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 } - val res1 = atomicIntArr.compareAndSet(2, 20, 222) // success - assertTrue(res1 && atomicIntArr[2] == 222, "testAtomicIntArrayCompareAndSet: FAIL 1") - val res2 = atomicIntArr.compareAndSet(2, 222, 2222) // success - assertTrue(res2 && atomicIntArr[2] == 2222, "testAtomicIntArrayCompareAndSet: FAIL 2") - val res3 = atomicIntArr.compareAndSet(2, 223, 22222) // should fail - assertTrue(!res3 && atomicIntArr[2] == 2222, "testAtomicIntArrayCompareAndSet: FAIL 3") - val res4 = atomicIntArr.compareAndSet(9, 10, 999) // should fail - assertTrue(!res4 && atomicIntArr[9] == 90, "testAtomicIntArrayCompareAndSet: FAIL 4") - assertFailsWith { - val res = atomicIntArr.compareAndSet(10, 33535, 39530) - }.let { ex -> - assertEquals("The index 10 is out of the bounds of the AtomicIntArray with size 10.", ex.message) - } - assertFailsWith { - val res = atomicIntArr.compareAndSet(-1, 33535, 39530) - }.let { ex -> - assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message) - } -} - -@Test -fun testAtomicIntArrayGetAndSet() { - val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 } - assertEquals(20, atomicIntArr.getAndSet(2, 200), "testAtomicIntArrayGetAndSet: FAIL 1") - assertEquals(200, atomicIntArr.getAndSet(2, 2000), "testAtomicIntArrayGetAndSet: FAIL 2") - assertEquals(2000, atomicIntArr[2], "testAtomicIntArrayGetAndSet: FAIL 3") - assertFailsWith { - val res = atomicIntArr.getAndSet(22, 33535) - }.let { ex -> - assertEquals("The index 22 is out of the bounds of the AtomicIntArray with size 10.", ex.message) - } - assertFailsWith { - val res = atomicIntArr.getAndSet(-1, 33535) - }.let { ex -> - assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message) - } -} - -@Test -fun testAtomicIntArrayGetAndAdd() { - val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 } - assertEquals(10, atomicIntArr.getAndAdd(1, 100), "testAtomicIntArrayGetAndAdd: FAIL 1") - assertEquals(110, atomicIntArr[1], "testAtomicIntArrayGetAndAdd: FAIL 2") - assertEquals(110, atomicIntArr.getAndAdd(1, -100), "testAtomicIntArrayGetAndAdd: FAIL 3") - assertEquals(10, atomicIntArr[1], "testAtomicIntArrayGetAndAdd: FAIL 4") - assertFailsWith { - val res = atomicIntArr.getAndAdd(22, 33535) - }.let { ex -> - assertEquals("The index 22 is out of the bounds of the AtomicIntArray with size 10.", ex.message) - } - assertFailsWith { - val res = atomicIntArr.getAndAdd(-1, 33535) - }.let { ex -> - assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message) - } -} - -@Test -fun testAtomicIntArrayAddAndGet() { - val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 } - assertEquals(110, atomicIntArr.addAndGet(1, 100), "testAtomicIntArrayAddAndGet: FAIL 1") - assertEquals(110, atomicIntArr[1], "testAtomicIntArrayAddAndGet: FAIL 2") - assertEquals(10, atomicIntArr.addAndGet(1, -100), "testAtomicIntArrayAddAndGet: FAIL 3") - assertEquals(10, atomicIntArr[1], "testAtomicIntArrayAddAndGet: FAIL 4") - assertFailsWith { - val res = atomicIntArr.addAndGet(22, 33535) - }.let { ex -> - assertEquals("The index 22 is out of the bounds of the AtomicIntArray with size 10.", ex.message) - } - assertFailsWith { - val res = atomicIntArr.addAndGet(-1, 33535) - }.let { ex -> - assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message) - } -} - -@Test -fun testAtomicIntArrayGetAndIncrement() { - val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 } - assertEquals(10, atomicIntArr.getAndIncrement(1), "testAtomicIntArrayGetAndIncrement: FAIL 1") - assertEquals(11, atomicIntArr[1], "testAtomicIntArrayGetAndIncrement: FAIL 2") - assertEquals(11, atomicIntArr.getAndIncrement(1), "testAtomicIntArrayGetAndIncrement: FAIL 3") - assertEquals(12, atomicIntArr[1], "testAtomicIntArrayGetAndIncrement: FAIL 4") - assertFailsWith { - val res = atomicIntArr.getAndIncrement(22) - }.let { ex -> - assertEquals("The index 22 is out of the bounds of the AtomicIntArray with size 10.", ex.message) - } - assertFailsWith { - val res = atomicIntArr.getAndIncrement(-1) - }.let { ex -> - assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message) - } -} - -@Test -fun testAtomicIntArrayIncrementAndGet() { - val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 } - assertEquals(11, atomicIntArr.incrementAndGet(1), "testAtomicIntArrayIncrementAndGet: FAIL 1") - assertEquals(11, atomicIntArr[1], "testAtomicIntArrayIncrementAndGet: FAIL 2") - assertEquals(12, atomicIntArr.incrementAndGet(1), "testAtomicIntArrayIncrementAndGet: FAIL 3") - assertEquals(12, atomicIntArr[1], "testAtomicIntArrayIncrementAndGet: FAIL 4") - assertFailsWith { - val res = atomicIntArr.incrementAndGet(22) - }.let { ex -> - assertEquals("The index 22 is out of the bounds of the AtomicIntArray with size 10.", ex.message) - } - assertFailsWith { - val res = atomicIntArr.incrementAndGet(-1) - }.let { ex -> - assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message) - } -} - -@Test -fun testAtomicIntArrayGetAndDecrement() { - val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 } - assertEquals(10, atomicIntArr.getAndDecrement(1), "testAtomicIntArrayGetAndDecrement: FAIL 1") - assertEquals(9, atomicIntArr[1], "testAtomicIntArrayGetAndDecrement: FAIL 2") - assertEquals(9, atomicIntArr.getAndDecrement(1), "testAtomicIntArrayGetAndDecrement: FAIL 3") - assertEquals(8, atomicIntArr[1], "testAtomicIntArrayGetAndDecrement: FAIL 4") - assertFailsWith { - val res = atomicIntArr.getAndDecrement(22) - }.let { ex -> - assertEquals("The index 22 is out of the bounds of the AtomicIntArray with size 10.", ex.message) - } - assertFailsWith { - val res = atomicIntArr.getAndDecrement(-1) - }.let { ex -> - assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message) - } -} - -@Test -fun testAtomicIntArrayDecrementAndGet() { - val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 } - assertEquals(9, atomicIntArr.decrementAndGet(1), "testAtomicIntArrayDecrementAndGet: FAIL 1") - assertEquals(9, atomicIntArr[1], "testAtomicIntArrayDecrementAndGet: FAIL 2") - assertEquals(8, atomicIntArr.decrementAndGet(1), "testAtomicIntArrayDecrementAndGet: FAIL 3") - assertEquals(8, atomicIntArr[1], "testAtomicIntArrayDecrementAndGet: FAIL 4") - assertFailsWith { - val res = atomicIntArr.decrementAndGet(22) - }.let { ex -> - assertEquals("The index 22 is out of the bounds of the AtomicIntArray with size 10.", ex.message) - } - assertFailsWith { - val res = atomicIntArr.decrementAndGet(-1) - }.let { ex -> - assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message) - } -} - -@Test -fun testAtomicLongArrayConstructor() { - val arr1 = AtomicLongArray(6) - assertEquals(arr1[4], 0L) - assertEquals(arr1.length, 6) - val arr2 = AtomicLongArray(10) { i: Int -> i * 10L } - assertEquals(arr2[4], 40L) - assertEquals(arr2.length, 10) - - val emptyArr = AtomicLongArray(0) - assertEquals(emptyArr.length, 0) - - assertFailsWith { - val arrNegativeSize = AtomicLongArray(-5) - } -} - -@Test -fun testAtomicLongArrayGetElement() { - val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L } - for (i in 0 until atomicLongArr.length) { - assertEquals(i * 10L, atomicLongArr[i], "testAtomicLongArrayGetElement: FAIL $i") - } - assertFailsWith { - val res = atomicLongArr[22] - }.let { ex -> - assertEquals("The index 22 is out of the bounds of the AtomicLongArray with size 10.", ex.message) - } - assertFailsWith { - val res = atomicLongArr[-1] - }.let { ex -> - assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message) - } -} - -@Test -fun testAtomicLongArraySetElement() { - val atomicLongArr = AtomicLongArray(10) - for (i in 0 until atomicLongArr.length) { - atomicLongArr[i] = i * 10L - } - for (i in 0 until atomicLongArr.length) { - assertEquals(i * 10L, atomicLongArr[i], "testAtomicLongArraySetElement: FAIL $i") - } - assertFailsWith { - atomicLongArr[10] = 3998009 - }.let { ex -> - assertEquals("The index 10 is out of the bounds of the AtomicLongArray with size 10.", ex.message) - } - assertFailsWith { - atomicLongArr[-1] = 3998009 - }.let { ex -> - assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message) - } -} - -@Test -fun testAtomicLongArrayCompareAndExchange() { - val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L } - val res1 = atomicLongArr.compareAndExchange(2, 20L, 222L) // success - assertTrue(res1 == 20L && atomicLongArr[2] == 222L, "testAtomicLongArrayCompareAndExchange: FAIL 1") - val res2 = atomicLongArr.compareAndExchange(2, 222L, 2222L) // success - assertTrue(res2 == 222L && atomicLongArr[2] == 2222L, "testAtomicLongArrayCompareAndExchange: FAIL 2") - val res3 = atomicLongArr.compareAndExchange(2, 223L, 22222L) // should fail - assertTrue(res3 == 2222L && atomicLongArr[2] == 2222L, "testAtomicLongArrayCompareAndExchange: FAIL 3") - val res4 = atomicLongArr.compareAndExchange(9, 10L, 999L) // should fail - assertTrue(res4 == 90L && atomicLongArr[9] == 90L, "testAtomicLongArrayCompareAndExchange: FAIL 4") - assertFailsWith { - atomicLongArr.compareAndExchange(10, 9353, 39058308) - }.let { ex -> - assertEquals("The index 10 is out of the bounds of the AtomicLongArray with size 10.", ex.message) - } - assertFailsWith { - atomicLongArr.compareAndExchange(-1, 9353, 39058308) - }.let { ex -> - assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message) - } -} - -@Test -fun testAtomicLongArrayCompareAndSet() { - val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L } - val res1 = atomicLongArr.compareAndSet(2, 20L, 222L) // success - assertTrue(res1 && atomicLongArr[2] == 222L, "testAtomicLongArrayCompareAndSet: FAIL 1") - val res2 = atomicLongArr.compareAndSet(2, 222L, 2222L) // success - assertTrue(res2 && atomicLongArr[2] == 2222L, "testAtomicLongArrayCompareAndSet: FAIL 2") - val res3 = atomicLongArr.compareAndSet(2, 223L, 22222L) // should fail - assertTrue(!res3 && atomicLongArr[2] == 2222L, "testAtomicLongArrayCompareAndSet: FAIL 3") - val res4 = atomicLongArr.compareAndSet(9, 10L, 999L) // should fail - assertTrue(!res4 && atomicLongArr[9] == 90L, "testAtomicLongArrayCompareAndSet: FAIL 4") - assertFailsWith { - atomicLongArr.compareAndSet(10, 9353, 39058308) - }.let { ex -> - assertEquals("The index 10 is out of the bounds of the AtomicLongArray with size 10.", ex.message) - } - assertFailsWith { - atomicLongArr.compareAndSet(-1, 9353, 39058308) - }.let { ex -> - assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message) - } -} - -@Test -fun testAtomicLongArrayGetAndSet() { - val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L } - assertEquals(20L, atomicLongArr.getAndSet(2, 200L), "testAtomicLongArrayGetAndSet: FAIL 1") - assertEquals(200L, atomicLongArr.getAndSet(2, 2000L), "testAtomicLongArrayGetAndSet: FAIL 2") - assertEquals(2000L, atomicLongArr[2], "testAtomicLongArrayGetAndSet: FAIL 3") - assertFailsWith { - val res = atomicLongArr.getAndSet(22, 9353) - }.let { ex -> - assertEquals("The index 22 is out of the bounds of the AtomicLongArray with size 10.", ex.message) - } - assertFailsWith { - val res = atomicLongArr.getAndSet(-1, 9353) - }.let { ex -> - assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message) - } -} - -@Test -fun testAtomicLongArrayGetAndAdd() { - val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L } - assertEquals(10L, atomicLongArr.getAndAdd(1, 100L), "testAtomicLongArrayGetAndAdd: FAIL 1") - assertEquals(110L, atomicLongArr[1], "testAtomicLongArrayGetAndAdd: FAIL 2") - assertEquals(110L, atomicLongArr.getAndAdd(1, -100L), "testAtomicLongArrayGetAndAdd: FAIL 3") - assertEquals(10L, atomicLongArr[1], "testAtomicLongArrayGetAndAdd: FAIL 4") - assertFailsWith { - val res = atomicLongArr.getAndAdd(100, 9353) - }.let { ex -> - assertEquals("The index 100 is out of the bounds of the AtomicLongArray with size 10.", ex.message) - } - assertFailsWith { - val res = atomicLongArr.getAndAdd(-1, 9353) - }.let { ex -> - assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message) - } -} - -@Test -fun testAtomicLongArrayAddAndGet() { - val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L } - assertEquals(110L, atomicLongArr.addAndGet(1, 100L), "testAtomicLongArrayAddAndGet: FAIL 1") - assertEquals(110L, atomicLongArr[1], "testAtomicLongArrayAddAndGet: FAIL 2") - assertEquals(10L, atomicLongArr.addAndGet(1, -100L), "testAtomicLongArrayAddAndGet: FAIL 3") - assertEquals(10L, atomicLongArr[1], "testAtomicLongArrayAddAndGet: FAIL 4") - assertFailsWith { - val res = atomicLongArr.addAndGet(22, 33535) - }.let { ex -> - assertEquals("The index 22 is out of the bounds of the AtomicLongArray with size 10.", ex.message) - } - assertFailsWith { - val res = atomicLongArr.addAndGet(-1, 33535) - }.let { ex -> - assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message) - } -} - -@Test -fun testAtomicLongArrayGetAndIncrement() { - val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L } - assertEquals(10L, atomicLongArr.getAndIncrement(1), "testAtomicLongArrayGetAndIncrement: FAIL 1") - assertEquals(11L, atomicLongArr[1], "testAtomicLongArrayGetAndIncrement: FAIL 2") - assertEquals(11L, atomicLongArr.getAndIncrement(1), "testAtomicLongArrayGetAndIncrement: FAIL 3") - assertEquals(12L, atomicLongArr[1], "testAtomicLongArrayGetAndIncrement: FAIL 4") - assertFailsWith { - val res = atomicLongArr.getAndIncrement(22) - }.let { ex -> - assertEquals("The index 22 is out of the bounds of the AtomicLongArray with size 10.", ex.message) - } - assertFailsWith { - val res = atomicLongArr.addAndGet(-1, 33535) - }.let { ex -> - assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message) - } -} - -@Test -fun testAtomicLongArrayIncrementAndGet() { - val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L } - assertEquals(11L, atomicLongArr.incrementAndGet(1), "testAtomicLongArrayIncrementAndGet: FAIL 1") - assertEquals(11L, atomicLongArr[1], "testAtomicLongArrayIncrementAndGet: FAIL 2") - assertEquals(12L, atomicLongArr.incrementAndGet(1), "testAtomicLongArrayIncrementAndGet: FAIL 3") - assertEquals(12L, atomicLongArr[1], "testAtomicLongArrayIncrementAndGet: FAIL 4") - assertFailsWith { - val res = atomicLongArr.incrementAndGet(22) - }.let { ex -> - assertEquals("The index 22 is out of the bounds of the AtomicLongArray with size 10.", ex.message) - } - assertFailsWith { - val res = atomicLongArr.incrementAndGet(-1) - }.let { ex -> - assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message) - } -} - -@Test -fun testAtomicLongArrayGetAndDecrement() { - val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L } - assertEquals(10L, atomicLongArr.getAndDecrement(1), "testAtomicLongArrayGetAndDecrement: FAIL 1") - assertEquals(9L, atomicLongArr[1], "testAtomicLongArrayGetAndDecrement: FAIL 2") - assertEquals(9L, atomicLongArr.getAndDecrement(1), "testAtomicLongArrayGetAndDecrement: FAIL 3") - assertEquals(8L, atomicLongArr[1], "testAtomicLongArrayGetAndDecrement: FAIL 4") - assertFailsWith { - val res = atomicLongArr.getAndDecrement(22) - }.let { ex -> - assertEquals("The index 22 is out of the bounds of the AtomicLongArray with size 10.", ex.message) - } - assertFailsWith { - val res = atomicLongArr.getAndDecrement(-1) - }.let { ex -> - assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message) - } -} - -@Test -fun testAtomicLongArrayDecrementAndGet() { - val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L } - assertEquals(9L, atomicLongArr.decrementAndGet(1), "testAtomicLongArrayDecrementAndGet: FAIL 1") - assertEquals(9L, atomicLongArr[1], "testAtomicLongArrayDecrementAndGet: FAIL 2") - assertEquals(8L, atomicLongArr.decrementAndGet(1), "testAtomicLongArrayDecrementAndGet: FAIL 3") - assertEquals(8L, atomicLongArr[1], "testAtomicLongArrayDecrementAndGet: FAIL 4") - assertFailsWith { - val res = atomicLongArr.decrementAndGet(22) - }.let { ex -> - assertEquals("The index 22 is out of the bounds of the AtomicLongArray with size 10.", ex.message) - } - assertFailsWith { - val res = atomicLongArr.decrementAndGet(-1) - }.let { ex -> - assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message) - } -} - -@Test -fun testAtomicArrayConstructor() { - val arr2 = AtomicArray(10) { null } - assertEquals(arr2[4], null) - assertEquals(arr2.length, 10) - - val emptyArr = AtomicArray(0) { "aa" } - assertEquals(emptyArr.length, 0) - - assertFailsWith { - val arrNegativeSize = AtomicArray(-5) { "aa" } - } -} - -@Test -fun testAtomicArrayGetElement() { - val refArr = AtomicArray(10) { i -> "a$i" } - for (i in 0 until refArr.length) { - assertEquals("a$i", refArr[i], "testAtomicArrayGetElement: FAIL $i") - } - assertFailsWith { - val res = refArr[100] - }.let { ex -> - assertEquals("The index 100 is out of the bounds of the AtomicArray with size 10.", ex.message) - } - assertFailsWith { - val res = refArr[-1] - }.let { ex -> - assertEquals("The index -1 is out of the bounds of the AtomicArray with size 10.", ex.message) - } -} - -@Test -fun testAtomicArraySetElement() { - val refArr = AtomicArray(10) { null } - for (i in 0 until refArr.length) { - refArr[i] = "a$i" - } - for (i in 0 until refArr.length) { - assertEquals("a$i", refArr[i], "testAtomicArraySetElement: FAIL $i") - } - assertFailsWith { - refArr[100] = "aaa" - }.let { ex -> - assertEquals("The index 100 is out of the bounds of the AtomicArray with size 10.", ex.message) - } - assertFailsWith { - refArr[-1] = "aaa" - }.let { ex -> - assertEquals("The index -1 is out of the bounds of the AtomicArray with size 10.", ex.message) - } -} - -@Test -fun testAtomicArrayCompareAndExchange() { - val refArr = AtomicArray(10) { null } - val newValue = "aaa" - val res1 = refArr.compareAndExchange(3, null, newValue) - assertTrue(res1 == null && refArr[3] == newValue, "testAtomicArrayCompareAndExchange: FAIL 1") - val res2 = refArr.compareAndExchange(3, newValue, "bbb") - assertTrue(res2 == newValue && refArr[3] == "bbb", "testAtomicArrayCompareAndExchange: FAIL 2") - val res3 = refArr.compareAndExchange(3, newValue, "ccc") - assertTrue(res3 == "bbb" && refArr[3] == "bbb", "testAtomicArrayCompareAndExchange: FAIL 3") - assertFailsWith { - refArr.compareAndExchange(10, "aaa", "jdndkj") - }.let { ex -> - assertEquals("The index 10 is out of the bounds of the AtomicArray with size 10.", ex.message) - } - assertFailsWith { - refArr.compareAndExchange(-1, "aaa", "jdndkj") - }.let { ex -> - assertEquals("The index -1 is out of the bounds of the AtomicArray with size 10.", ex.message) - } -} - -@Test -fun testAtomicArrayCompareAndSet() { - val refArr = AtomicArray(10) { null } - val newValue = "aaa" - val res1 = refArr.compareAndSet(3, null, newValue) - assertTrue(res1 && refArr[3] == newValue, "testAtomicArrayCompareAndSet: FAIL 1") - val res2 = refArr.compareAndSet(3, newValue, "bbb") - assertTrue(res2 && refArr[3] == "bbb", "testAtomicArrayCompareAndSet: FAIL 2") - val res3 = refArr.compareAndSet(3, newValue, "ccc") - assertTrue(!res3 && refArr[3] == "bbb", "testAtomicArrayCompareAndSet: FAIL 3") - assertFailsWith { - refArr.compareAndSet(10, "aaa", "jdndkj") - }.let { ex -> - assertEquals("The index 10 is out of the bounds of the AtomicArray with size 10.", ex.message) - } - assertFailsWith { - refArr.compareAndSet(-1, "aaa", "jdndkj") - }.let { ex -> - assertEquals("The index -1 is out of the bounds of the AtomicArray with size 10.", ex.message) - } -} - -@Test -fun testAtomicArrayGetAndSet() { - val refArr = AtomicArray(10) { null } - val res4 = refArr.getAndSet(4, "aaa") - assertEquals(null, res4, "testAtomicArrayGetAndSet: FAIL 1") - val res5 = refArr.getAndSet(4, "bbb") - assertEquals("aaa", res5, "testAtomicArrayGetAndSet: FAIL 2") - assertFailsWith { - refArr.getAndSet(10, "aaa") - }.let { ex -> - assertEquals("The index 10 is out of the bounds of the AtomicArray with size 10.", ex.message) - } - assertFailsWith { - refArr.getAndSet(-1, "aaa") - }.let { ex -> - assertEquals("The index -1 is out of the bounds of the AtomicArray with size 10.", ex.message) - } -} \ No newline at end of file diff --git a/kotlin-native/backend.native/tests/runtime/atomics/atomic_array_stress.kt b/kotlin-native/backend.native/tests/runtime/atomics/atomic_array_stress.kt deleted file mode 100644 index 9d324656f33..00000000000 --- a/kotlin-native/backend.native/tests/runtime/atomics/atomic_array_stress.kt +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:OptIn(kotlin.ExperimentalStdlibApi::class) - -package runtime.atomics.atomic_array_stress - -import kotlin.test.* -import kotlin.concurrent.* -import kotlin.native.concurrent.* - -fun testAtomicIntArrayStress(workers: Array) { - val intArr = AtomicIntArray(10) - val futures = Array(workers.size, { workerIndex -> - workers[workerIndex].execute(TransferMode.SAFE, { intArr }) { intArr -> - for (i in 0 until 500) { - val index = (0 until intArr.length).random() - intArr.incrementAndGet(index) - } - } - }) - futures.forEach { - it.result - } - var sum = 0 - for (i in 0 until intArr.length) { - sum += intArr[i] - } - assertEquals(workers.size * 500, sum) -} - -fun testAtomicLongArrayStress(workers: Array) { - val longArr = AtomicLongArray(10) - val futures = Array(workers.size, { workerIndex -> - workers[workerIndex].execute(TransferMode.SAFE, { longArr }) { longArr -> - for (i in 0 until 500) { - val index = (0 until longArr.length).random() - longArr.incrementAndGet(index) - } - } - }) - futures.forEach { - it.result - } - var sum = 0L - for (i in 0 until longArr.length) { - sum += longArr[i] - } - assertEquals(workers.size.toLong() * 500, sum) -} - -private class A(val n: Int) - -fun testAtomicArrayStress(workers: Array) { - val refArr = AtomicArray(10) { A(0) } - val futures = Array(workers.size, { workerIndex -> - workers[workerIndex].execute(TransferMode.SAFE, { refArr }) { refArr -> - for (i in 0 until 500) { - val index = (0 until refArr.length).random() - while(true) { - val cur = refArr[index] - val newValue = A(((cur as A).n + 1)) - if (refArr.compareAndSet(index, cur, newValue)) break - } - } - } - }) - futures.forEach { - it.result - } - var sum = 0 - for (i in 0 until refArr.length) { - sum += (refArr[i] as A).n - } - assertEquals(workers.size * 500, sum) -} - -@Test -fun runStressTest() { - val COUNT = 20 - val workers = Array(COUNT, { _ -> Worker.start()}) - testAtomicIntArrayStress(workers) - testAtomicLongArrayStress(workers) - testAtomicArrayStress(workers) -} \ No newline at end of file diff --git a/kotlin-native/backend.native/tests/runtime/atomics/atomic_smoke.kt b/kotlin-native/backend.native/tests/runtime/atomics/atomic_smoke.kt deleted file mode 100644 index bd5483f8fee..00000000000 --- a/kotlin-native/backend.native/tests/runtime/atomics/atomic_smoke.kt +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:OptIn(FreezingIsDeprecated::class, kotlinx.cinterop.ExperimentalForeignApi::class) -package runtime.atomics.atomic_smoke - -import kotlin.test.* -import kotlin.concurrent.AtomicInt -import kotlin.concurrent.AtomicLong -import kotlin.concurrent.AtomicReference -import kotlin.concurrent.AtomicNativePtr -import kotlin.native.internal.NativePtr - -@Test -fun ctor_Int() { - val x = AtomicInt(0) - assertEquals(x.value, 0) -} - -@Test -fun ctor_Long() { - val x = AtomicLong(0) - assertEquals(x.value, 0) -} - -@Test -fun setter_Int() { - val x = AtomicInt(0) - x.value = 1 - assertEquals(x.value, 1) -} - -@Test -fun setter_Long() { - val x = AtomicLong(0) - x.value = 1 - assertEquals(x.value, 1) -} - -@Test -fun addAndGet_Int() { - val x = AtomicInt(1) - val result = x.addAndGet(2) - assertEquals(result, 1 + 2) - assertEquals(x.value, result) -} - -@Test -fun addAndGet_Long() { - val x = AtomicLong(1) - val result = x.addAndGet(2L) - assertEquals(result, 1 + 2) - assertEquals(x.value, result) -} - -@Test -fun compareAndSwap_Int() { - val x = AtomicInt(0) - val successValue = x.compareAndExchange(0, 1) - assertEquals(successValue, 0) - assertEquals(x.value, 1) - val failValue = x.compareAndExchange(0, 2) - assertEquals(failValue, 1) - assertEquals(x.value, 1) -} - -@Test -fun compareAndSwap_Long() { - val x = AtomicLong(0) - val successValue = x.compareAndExchange(0, 1) - assertEquals(successValue, 0) - assertEquals(x.value, 1) - val failValue = x.compareAndExchange(0, 2) - assertEquals(failValue, 1) - assertEquals(x.value, 1) -} - -@Test -fun compareAndSet_Int() { - val x = AtomicInt(0) - val successValue = x.compareAndSet(0, 1) - assertTrue(successValue) - assertEquals(x.value, 1) - val failValue = x.compareAndSet(0, 2) - assertFalse(failValue) - assertEquals(x.value, 1) -} - -@Test -fun compareAndSet_Long() { - val x = AtomicLong(0) - val successValue = x.compareAndSet(0, 1) - assertTrue(successValue) - assertEquals(x.value, 1) - val failValue = x.compareAndSet(0, 2) - assertFalse(failValue) - assertEquals(x.value, 1) -} - -@Test -fun testAtomicInt() { - val atomic = AtomicInt(3) - assertEquals(3, atomic.value) - atomic.value = 5 - assertEquals(5, atomic.value) - assertEquals(5, atomic.getAndSet(6)) - assertEquals(6, atomic.value) - assertTrue(atomic.compareAndSet(6, 8)) - assertFalse(atomic.compareAndSet(9, 1)) - assertEquals(8, atomic.value) - assertEquals(8, atomic.getAndAdd(5)) - assertEquals(13, atomic.value) - assertEquals(18, atomic.addAndGet(5)) - assertEquals(18, atomic.getAndIncrement()) - assertEquals(19, atomic.value) - assertEquals(20, atomic.incrementAndGet()) - assertEquals(20, atomic.value) - assertEquals(20, atomic.getAndDecrement()) - assertEquals(19, atomic.value) - assertEquals(18, atomic.decrementAndGet()) - assertEquals(18, atomic.value) - assertEquals(18, atomic.compareAndExchange(18, 56)) - assertEquals(56, atomic.compareAndExchange(18, 56)) - assertEquals(56, atomic.compareAndExchange(18, 56)) -} - -@Test -fun testAtomicLong() { - val atomic = AtomicLong(1424920024888900000) - assertEquals(1424920024888900000, atomic.value) - atomic.value = 2424920024888900000 - assertEquals(2424920024888900000, atomic.value) - assertEquals(2424920024888900000, atomic.getAndSet(3424920024888900000)) - assertEquals(3424920024888900000, atomic.value) - assertTrue(atomic.compareAndSet(3424920024888900000, 4424920024888900000)) - assertFalse(atomic.compareAndSet(9, 1)) - assertEquals(4424920024888900000, atomic.value) - assertEquals(4424920024888900000, atomic.getAndAdd(100000)) - assertEquals(4424920024889000000, atomic.value) - assertEquals(4424920024890000000, atomic.addAndGet(1000000L)) - assertEquals(4424920024890000000, atomic.getAndIncrement()) - assertEquals(4424920024890000001, atomic.value) - assertEquals(4424920024890000002, atomic.incrementAndGet()) - assertEquals(4424920024890000002, atomic.value) - assertEquals(4424920024890000002, atomic.getAndDecrement()) - assertEquals(4424920024890000001, atomic.value) - assertEquals(4424920024890000000, atomic.decrementAndGet()) - assertEquals(4424920024890000000, atomic.value) - assertEquals(4424920024890000000, atomic.compareAndExchange(4424920024890000000, 5424920024890000000)) - assertEquals(5424920024890000000, atomic.compareAndExchange(18, 56)) - assertEquals(5424920024890000000, atomic.compareAndExchange(18, 56)) -} - -@Test -fun testAtomicRef() { - val atomic = AtomicReference>(listOf("a", "b", "c")) - assertEquals(listOf("a", "b", "c"), atomic.value) - atomic.value = listOf("a", "b", "a") - assertEquals(listOf("a", "b", "a"), atomic.value) - assertEquals(listOf("a", "b", "a"), atomic.getAndSet(listOf("a", "a", "a"))) - assertEquals(listOf("a", "a", "a"), atomic.value) - var cur = atomic.value - assertTrue(atomic.compareAndSet(cur, listOf("b", "b", "b"))) - assertFalse(atomic.compareAndSet(listOf("a", "a", "a"), listOf("b", "b", "b"))) - assertEquals(listOf("b", "b", "b"), atomic.value) - cur = atomic.value - assertEquals(listOf("b", "b", "b"), atomic.compareAndExchange(cur, listOf("c", "c", "c"))) - assertEquals(listOf("c", "c", "c"), atomic.compareAndExchange(cur, listOf("d", "d", "d"))) - assertEquals(listOf("c", "c", "c"), atomic.compareAndExchange(cur, listOf("c", "c", "c"))) -} - -@Test -fun testNativePtr() { - val atomic = AtomicNativePtr(NativePtr.NULL) - assertEquals(NativePtr.NULL, atomic.value) - atomic.value = NativePtr.NULL.plus(10L) - assertEquals(10L, atomic.value.toLong()) - assertTrue(atomic.compareAndSet(NativePtr.NULL.plus(10L), NativePtr.NULL.plus(20L))) - assertEquals(20L, atomic.value.toLong()) - assertFalse(atomic.compareAndSet(NativePtr.NULL.plus(10L), NativePtr.NULL.plus(20L))) - assertEquals(20L, atomic.value.toLong()) - assertEquals(NativePtr.NULL.plus(20L), atomic.compareAndExchange(NativePtr.NULL.plus(20L), NativePtr.NULL.plus(30L))) - assertEquals(NativePtr.NULL.plus(30L), atomic.compareAndExchange(NativePtr.NULL.plus(20L), NativePtr.NULL.plus(40L))) - assertEquals(NativePtr.NULL.plus(30L), atomic.compareAndExchange(NativePtr.NULL.plus(20L), NativePtr.NULL.plus(50L))) - assertEquals(30L, atomic.getAndSet(NativePtr.NULL.plus(55L)).toLong()) - assertEquals(55L, atomic.value.toLong()) -} diff --git a/kotlin-native/backend.native/tests/runtime/atomics/atomic_stress.kt b/kotlin-native/backend.native/tests/runtime/atomics/atomic_stress.kt deleted file mode 100644 index d981372df41..00000000000 --- a/kotlin-native/backend.native/tests/runtime/atomics/atomic_stress.kt +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:OptIn(FreezingIsDeprecated::class) -package runtime.atomics.atomic_stress - -import kotlin.test.* -import kotlin.native.concurrent.* -import kotlin.concurrent.* -import kotlin.concurrent.AtomicInt -import kotlin.concurrent.AtomicLong -import kotlin.concurrent.AtomicReference -import kotlin.native.internal.NativePtr - -fun testAtomicIntStress(workers: Array) { - val atomic = AtomicInt(10) - val futures = Array(workers.size, { workerIndex -> - workers[workerIndex].execute(TransferMode.SAFE, { atomic }) { - atomic -> atomic.addAndGet(1000) - } - }) - futures.forEach { - it.result - } - assertEquals(10 + 1000 * workers.size, atomic.value) -} - -fun testAtomicLongStress(workers: Array) { - val atomic = AtomicLong(10L) - val futures = Array(workers.size, { workerIndex -> - workers[workerIndex].execute(TransferMode.SAFE, { atomic }) { - atomic -> atomic.addAndGet(9999999999) - } - }) - futures.forEach { - it.result - } - assertEquals(10L + 9999999999 * workers.size, atomic.value) -} - -private class LockFreeStack { - private val top = AtomicReference?>(null) - - private class Node(val value: T, val next: Node?) - - fun isEmpty(): Boolean = top.value == null - - fun push(value: T) { - while(true) { - val cur = top.value - val upd = Node(value, cur) - if (top.compareAndSet(cur, upd)) return - } - } - - fun pop(): T? { - while(true) { - val cur = top.value - if (cur == null) return null - if (top.compareAndSet(cur, cur.next)) return cur.value - } - } -} - -fun testAtomicReferenceStress(workers: Array) { - val stack = LockFreeStack() - val writers = Array(workers.size, { workerIndex -> - workers[workerIndex].execute(TransferMode.SAFE, { stack to workerIndex}) { - (stack, workerIndex) -> stack.push(workerIndex) - } - }) - writers.forEach { it.result } - - val seen = mutableSetOf() - while(!stack.isEmpty()) { - val value = stack.pop() - assertNotNull(value) - seen.add(value) - } - assertEquals(workers.size, seen.size) -} - -@Test -fun runStressTest() { - val COUNT = 20 - val workers = Array(COUNT, { _ -> Worker.start()}) - - testAtomicIntStress(workers) - testAtomicLongStress(workers) - testAtomicReferenceStress(workers) - - workers.forEach { - it.requestTermination().result - } -} diff --git a/kotlin-native/runtime/test/concurrent/AtomicArrayTest.kt b/kotlin-native/runtime/test/concurrent/AtomicArrayTest.kt new file mode 100644 index 00000000000..a6f29af5871 --- /dev/null +++ b/kotlin-native/runtime/test/concurrent/AtomicArrayTest.kt @@ -0,0 +1,570 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package test.concurrent + +import kotlin.concurrent.* +import kotlin.test.* + +class AtomicIntArrayTest { + @Test fun ctor() { + val arr1 = AtomicIntArray(6) + assertEquals(arr1[4], 0) + assertEquals(arr1.length, 6) + + val arr2 = AtomicIntArray(10) { i: Int -> i * 10 } + assertEquals(arr2[4], 40) + assertEquals(arr2.length, 10) + + val emptyArr = AtomicIntArray(0) + assertEquals(emptyArr.length, 0) + + assertFailsWith { + val arrNegativeSize = AtomicIntArray(-5) + } + } + + @Test fun getter() { + val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 } + for (i in 0 until atomicIntArr.length) { + assertEquals(i * 10, atomicIntArr[i], "getter: FAIL $i") + } + assertFailsWith { + val res = atomicIntArr[22] + }.let { ex -> + assertEquals("The index 22 is out of the bounds of the AtomicIntArray with size 10.", ex.message) + } + assertFailsWith { + val res = atomicIntArr[-1] + }.let { ex -> + assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message) + } + } + + @Test fun setter() { + val atomicIntArr = AtomicIntArray(10) + for (i in 0 until atomicIntArr.length) { + atomicIntArr[i] = i * 10 + } + for (i in 0 until atomicIntArr.length) { + assertEquals(i * 10, atomicIntArr[i], "setter: FAIL $i") + } + assertFailsWith { + atomicIntArr[22] = 100 + }.let { ex -> + assertEquals("The index 22 is out of the bounds of the AtomicIntArray with size 10.", ex.message) + } + assertFailsWith { + atomicIntArr[-1] = 100 + }.let { ex -> + assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message) + } + } + + @Test fun addAndGet() { + val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 } + assertEquals(110, atomicIntArr.addAndGet(1, 100), "addAndGet: FAIL 1") + assertEquals(110, atomicIntArr[1], "addAndGet: FAIL 2") + assertEquals(10, atomicIntArr.addAndGet(1, -100), "addAndGet: FAIL 3") + assertEquals(10, atomicIntArr[1], "addAndGet: FAIL 4") + assertFailsWith { + val res = atomicIntArr.addAndGet(22, 33535) + }.let { ex -> + assertEquals("The index 22 is out of the bounds of the AtomicIntArray with size 10.", ex.message) + } + assertFailsWith { + val res = atomicIntArr.addAndGet(-1, 33535) + }.let { ex -> + assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message) + } + } + + @Test fun compareAndExchange() { + val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 } + val res1 = atomicIntArr.compareAndExchange(2, 20, 222) // success + assertTrue(res1 == 20 && atomicIntArr[2] == 222, "compareAndExchange: FAIL 1") + val res2 = atomicIntArr.compareAndExchange(2, 222, 2222) // success + assertTrue(res2 == 222 && atomicIntArr[2] == 2222, "compareAndExchange: FAIL 2") + val res3 = atomicIntArr.compareAndExchange(2, 223, 22222) // should fail + assertTrue(res3 == 2222 && atomicIntArr[2] == 2222, "compareAndExchange: FAIL 3") + val res4 = atomicIntArr.compareAndExchange(9, 10, 999) // should fail + assertTrue(res4 == 90 && atomicIntArr[9] == 90, "compareAndExchange: FAIL 4") + assertFailsWith { + val res = atomicIntArr.compareAndExchange(10, 33535, 39530) + }.let { ex -> + assertEquals("The index 10 is out of the bounds of the AtomicIntArray with size 10.", ex.message) + } + assertFailsWith { + val res = atomicIntArr.compareAndExchange(-1, 33535, 39530) + }.let { ex -> + assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message) + } + } + + @Test fun compareAndSet() { + val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 } + val res1 = atomicIntArr.compareAndSet(2, 20, 222) // success + assertTrue(res1 && atomicIntArr[2] == 222, "compareAndSet: FAIL 1") + val res2 = atomicIntArr.compareAndSet(2, 222, 2222) // success + assertTrue(res2 && atomicIntArr[2] == 2222, "compareAndSet: FAIL 2") + val res3 = atomicIntArr.compareAndSet(2, 223, 22222) // should fail + assertTrue(!res3 && atomicIntArr[2] == 2222, "compareAndSet: FAIL 3") + val res4 = atomicIntArr.compareAndSet(9, 10, 999) // should fail + assertTrue(!res4 && atomicIntArr[9] == 90, "compareAndSet: FAIL 4") + assertFailsWith { + val res = atomicIntArr.compareAndSet(10, 33535, 39530) + }.let { ex -> + assertEquals("The index 10 is out of the bounds of the AtomicIntArray with size 10.", ex.message) + } + assertFailsWith { + val res = atomicIntArr.compareAndSet(-1, 33535, 39530) + }.let { ex -> + assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message) + } + } + + @Test fun getAndSet() { + val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 } + assertEquals(20, atomicIntArr.getAndSet(2, 200), "getAndSet: FAIL 1") + assertEquals(200, atomicIntArr.getAndSet(2, 2000), "getAndSet: FAIL 2") + assertEquals(2000, atomicIntArr[2], "getAndSet: FAIL 3") + assertFailsWith { + val res = atomicIntArr.getAndSet(22, 33535) + }.let { ex -> + assertEquals("The index 22 is out of the bounds of the AtomicIntArray with size 10.", ex.message) + } + assertFailsWith { + val res = atomicIntArr.getAndSet(-1, 33535) + }.let { ex -> + assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message) + } + } + + @Test fun getAndAdd() { + val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 } + assertEquals(10, atomicIntArr.getAndAdd(1, 100), "getAndAdd: FAIL 1") + assertEquals(110, atomicIntArr[1], "getAndAdd: FAIL 2") + assertEquals(110, atomicIntArr.getAndAdd(1, -100), "getAndAdd: FAIL 3") + assertEquals(10, atomicIntArr[1], "getAndAdd: FAIL 4") + assertFailsWith { + val res = atomicIntArr.getAndAdd(22, 33535) + }.let { ex -> + assertEquals("The index 22 is out of the bounds of the AtomicIntArray with size 10.", ex.message) + } + assertFailsWith { + val res = atomicIntArr.getAndAdd(-1, 33535) + }.let { ex -> + assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message) + } + } + + @Test fun getAndIncrement() { + val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 } + assertEquals(10, atomicIntArr.getAndIncrement(1), "getAndIncrement: FAIL 1") + assertEquals(11, atomicIntArr[1], "getAndIncrement: FAIL 2") + assertEquals(11, atomicIntArr.getAndIncrement(1), "getAndIncrement: FAIL 3") + assertEquals(12, atomicIntArr[1], "getAndIncrement: FAIL 4") + assertFailsWith { + val res = atomicIntArr.getAndIncrement(22) + }.let { ex -> + assertEquals("The index 22 is out of the bounds of the AtomicIntArray with size 10.", ex.message) + } + assertFailsWith { + val res = atomicIntArr.getAndIncrement(-1) + }.let { ex -> + assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message) + } + } + + @Test fun incrementAndGet() { + val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 } + assertEquals(11, atomicIntArr.incrementAndGet(1), "incrementAndGet: FAIL 1") + assertEquals(11, atomicIntArr[1], "incrementAndGet: FAIL 2") + assertEquals(12, atomicIntArr.incrementAndGet(1), "incrementAndGet: FAIL 3") + assertEquals(12, atomicIntArr[1], "incrementAndGet: FAIL 4") + assertFailsWith { + val res = atomicIntArr.incrementAndGet(22) + }.let { ex -> + assertEquals("The index 22 is out of the bounds of the AtomicIntArray with size 10.", ex.message) + } + assertFailsWith { + val res = atomicIntArr.incrementAndGet(-1) + }.let { ex -> + assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message) + } + } + + @Test fun getAndDecrement() { + val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 } + assertEquals(10, atomicIntArr.getAndDecrement(1), "getAndDecrement: FAIL 1") + assertEquals(9, atomicIntArr[1], "getAndDecrement: FAIL 2") + assertEquals(9, atomicIntArr.getAndDecrement(1), "getAndDecrement: FAIL 3") + assertEquals(8, atomicIntArr[1], "getAndDecrement: FAIL 4") + assertFailsWith { + val res = atomicIntArr.getAndDecrement(22) + }.let { ex -> + assertEquals("The index 22 is out of the bounds of the AtomicIntArray with size 10.", ex.message) + } + assertFailsWith { + val res = atomicIntArr.getAndDecrement(-1) + }.let { ex -> + assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message) + } + } + + @Test fun decrementAndGet() { + val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 } + assertEquals(9, atomicIntArr.decrementAndGet(1), "decrementAndGet: FAIL 1") + assertEquals(9, atomicIntArr[1], "decrementAndGet: FAIL 2") + assertEquals(8, atomicIntArr.decrementAndGet(1), "decrementAndGet: FAIL 3") + assertEquals(8, atomicIntArr[1], "decrementAndGet: FAIL 4") + assertFailsWith { + val res = atomicIntArr.decrementAndGet(22) + }.let { ex -> + assertEquals("The index 22 is out of the bounds of the AtomicIntArray with size 10.", ex.message) + } + assertFailsWith { + val res = atomicIntArr.decrementAndGet(-1) + }.let { ex -> + assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message) + } + } +} + +class AtomicLongArrayTest { + @Test fun ctor() { + val arr1 = AtomicLongArray(6) + assertEquals(arr1[4], 0L) + assertEquals(arr1.length, 6) + val arr2 = AtomicLongArray(10) { i: Int -> i * 10L } + assertEquals(arr2[4], 40L) + assertEquals(arr2.length, 10) + + val emptyArr = AtomicLongArray(0) + assertEquals(emptyArr.length, 0) + + assertFailsWith { + val arrNegativeSize = AtomicLongArray(-5) + } + } + + @Test fun getter() { + val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L } + for (i in 0 until atomicLongArr.length) { + assertEquals(i * 10L, atomicLongArr[i], "getter: FAIL $i") + } + assertFailsWith { + val res = atomicLongArr[22] + }.let { ex -> + assertEquals("The index 22 is out of the bounds of the AtomicLongArray with size 10.", ex.message) + } + assertFailsWith { + val res = atomicLongArr[-1] + }.let { ex -> + assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message) + } + } + + @Test fun setter() { + val atomicLongArr = AtomicLongArray(10) + for (i in 0 until atomicLongArr.length) { + atomicLongArr[i] = i * 10L + } + for (i in 0 until atomicLongArr.length) { + assertEquals(i * 10L, atomicLongArr[i], "setter: FAIL $i") + } + assertFailsWith { + atomicLongArr[10] = 3998009 + }.let { ex -> + assertEquals("The index 10 is out of the bounds of the AtomicLongArray with size 10.", ex.message) + } + assertFailsWith { + atomicLongArr[-1] = 3998009 + }.let { ex -> + assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message) + } + } + + @Test fun addAndGet() { + val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L } + assertEquals(110L, atomicLongArr.addAndGet(1, 100L), "addAndGet: FAIL 1") + assertEquals(110L, atomicLongArr[1], "addAndGet: FAIL 2") + assertEquals(10L, atomicLongArr.addAndGet(1, -100L), "addAndGet: FAIL 3") + assertEquals(10L, atomicLongArr[1], "addAndGet: FAIL 4") + assertFailsWith { + val res = atomicLongArr.addAndGet(22, 33535) + }.let { ex -> + assertEquals("The index 22 is out of the bounds of the AtomicLongArray with size 10.", ex.message) + } + assertFailsWith { + val res = atomicLongArr.addAndGet(-1, 33535) + }.let { ex -> + assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message) + } + } + + @Test fun compareAndExchange() { + val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L } + val res1 = atomicLongArr.compareAndExchange(2, 20L, 222L) // success + assertTrue(res1 == 20L && atomicLongArr[2] == 222L, "compareAndExchange: FAIL 1") + val res2 = atomicLongArr.compareAndExchange(2, 222L, 2222L) // success + assertTrue(res2 == 222L && atomicLongArr[2] == 2222L, "compareAndExchange: FAIL 2") + val res3 = atomicLongArr.compareAndExchange(2, 223L, 22222L) // should fail + assertTrue(res3 == 2222L && atomicLongArr[2] == 2222L, "compareAndExchange: FAIL 3") + val res4 = atomicLongArr.compareAndExchange(9, 10L, 999L) // should fail + assertTrue(res4 == 90L && atomicLongArr[9] == 90L, "compareAndExchange: FAIL 4") + assertFailsWith { + atomicLongArr.compareAndExchange(10, 9353, 39058308) + }.let { ex -> + assertEquals("The index 10 is out of the bounds of the AtomicLongArray with size 10.", ex.message) + } + assertFailsWith { + atomicLongArr.compareAndExchange(-1, 9353, 39058308) + }.let { ex -> + assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message) + } + } + + @Test fun compareAndSet() { + val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L } + val res1 = atomicLongArr.compareAndSet(2, 20L, 222L) // success + assertTrue(res1 && atomicLongArr[2] == 222L, "compareAndSet: FAIL 1") + val res2 = atomicLongArr.compareAndSet(2, 222L, 2222L) // success + assertTrue(res2 && atomicLongArr[2] == 2222L, "compareAndSet: FAIL 2") + val res3 = atomicLongArr.compareAndSet(2, 223L, 22222L) // should fail + assertTrue(!res3 && atomicLongArr[2] == 2222L, "compareAndSet: FAIL 3") + val res4 = atomicLongArr.compareAndSet(9, 10L, 999L) // should fail + assertTrue(!res4 && atomicLongArr[9] == 90L, "compareAndSet: FAIL 4") + assertFailsWith { + atomicLongArr.compareAndSet(10, 9353, 39058308) + }.let { ex -> + assertEquals("The index 10 is out of the bounds of the AtomicLongArray with size 10.", ex.message) + } + assertFailsWith { + atomicLongArr.compareAndSet(-1, 9353, 39058308) + }.let { ex -> + assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message) + } + } + + @Test fun getAndSet() { + val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L } + assertEquals(20L, atomicLongArr.getAndSet(2, 200L), "getAndSet: FAIL 1") + assertEquals(200L, atomicLongArr.getAndSet(2, 2000L), "getAndSet: FAIL 2") + assertEquals(2000L, atomicLongArr[2], "getAndSet: FAIL 3") + assertFailsWith { + val res = atomicLongArr.getAndSet(22, 9353) + }.let { ex -> + assertEquals("The index 22 is out of the bounds of the AtomicLongArray with size 10.", ex.message) + } + assertFailsWith { + val res = atomicLongArr.getAndSet(-1, 9353) + }.let { ex -> + assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message) + } + } + + @Test fun getAndAdd() { + val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L } + assertEquals(10L, atomicLongArr.getAndAdd(1, 100L), "getAndAdd: FAIL 1") + assertEquals(110L, atomicLongArr[1], "getAndAdd: FAIL 2") + assertEquals(110L, atomicLongArr.getAndAdd(1, -100L), "getAndAdd: FAIL 3") + assertEquals(10L, atomicLongArr[1], "getAndAdd: FAIL 4") + assertFailsWith { + val res = atomicLongArr.getAndAdd(100, 9353) + }.let { ex -> + assertEquals("The index 100 is out of the bounds of the AtomicLongArray with size 10.", ex.message) + } + assertFailsWith { + val res = atomicLongArr.getAndAdd(-1, 9353) + }.let { ex -> + assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message) + } + } + + @Test fun getAndIncrement() { + val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L } + assertEquals(10L, atomicLongArr.getAndIncrement(1), "getAndIncrement: FAIL 1") + assertEquals(11L, atomicLongArr[1], "getAndIncrement: FAIL 2") + assertEquals(11L, atomicLongArr.getAndIncrement(1), "getAndIncrement: FAIL 3") + assertEquals(12L, atomicLongArr[1], "getAndIncrement: FAIL 4") + assertFailsWith { + val res = atomicLongArr.getAndIncrement(22) + }.let { ex -> + assertEquals("The index 22 is out of the bounds of the AtomicLongArray with size 10.", ex.message) + } + assertFailsWith { + val res = atomicLongArr.addAndGet(-1, 33535) + }.let { ex -> + assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message) + } + } + + @Test fun incrementAndGet() { + val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L } + assertEquals(11L, atomicLongArr.incrementAndGet(1), "incrementAndGet: FAIL 1") + assertEquals(11L, atomicLongArr[1], "incrementAndGet: FAIL 2") + assertEquals(12L, atomicLongArr.incrementAndGet(1), "incrementAndGet: FAIL 3") + assertEquals(12L, atomicLongArr[1], "incrementAndGet: FAIL 4") + assertFailsWith { + val res = atomicLongArr.incrementAndGet(22) + }.let { ex -> + assertEquals("The index 22 is out of the bounds of the AtomicLongArray with size 10.", ex.message) + } + assertFailsWith { + val res = atomicLongArr.incrementAndGet(-1) + }.let { ex -> + assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message) + } + } + + @Test fun getAndDecrement() { + val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L } + assertEquals(10L, atomicLongArr.getAndDecrement(1), "getAndDecrement: FAIL 1") + assertEquals(9L, atomicLongArr[1], "getAndDecrement: FAIL 2") + assertEquals(9L, atomicLongArr.getAndDecrement(1), "getAndDecrement: FAIL 3") + assertEquals(8L, atomicLongArr[1], "getAndDecrement: FAIL 4") + assertFailsWith { + val res = atomicLongArr.getAndDecrement(22) + }.let { ex -> + assertEquals("The index 22 is out of the bounds of the AtomicLongArray with size 10.", ex.message) + } + assertFailsWith { + val res = atomicLongArr.getAndDecrement(-1) + }.let { ex -> + assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message) + } + } + + @Test fun decrementAndGet() { + val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L } + assertEquals(9L, atomicLongArr.decrementAndGet(1), "decrementAndGet: FAIL 1") + assertEquals(9L, atomicLongArr[1], "decrementAndGet: FAIL 2") + assertEquals(8L, atomicLongArr.decrementAndGet(1), "decrementAndGet: FAIL 3") + assertEquals(8L, atomicLongArr[1], "decrementAndGet: FAIL 4") + assertFailsWith { + val res = atomicLongArr.decrementAndGet(22) + }.let { ex -> + assertEquals("The index 22 is out of the bounds of the AtomicLongArray with size 10.", ex.message) + } + assertFailsWith { + val res = atomicLongArr.decrementAndGet(-1) + }.let { ex -> + assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message) + } + } +} + +class AtomicArrayTest { + @Test fun ctor() { + val arr2 = AtomicArray(10) { null } + assertEquals(arr2[4], null) + assertEquals(arr2.length, 10) + + val emptyArr = AtomicArray(0) { Data(1) } + assertEquals(emptyArr.length, 0) + + assertFailsWith { + val arrNegativeSize = AtomicArray(-5) { Data(1) } + } + } + + @Test fun getter() { + val refArr = AtomicArray(10) { i -> Data(i) } + for (i in 0 until refArr.length) { + assertEquals(Data(i), refArr[i], "getter: FAIL $i") + } + assertFailsWith { + val res = refArr[100] + }.let { ex -> + assertEquals("The index 100 is out of the bounds of the AtomicArray with size 10.", ex.message) + } + assertFailsWith { + val res = refArr[-1] + }.let { ex -> + assertEquals("The index -1 is out of the bounds of the AtomicArray with size 10.", ex.message) + } + } + + @Test fun setter() { + val refArr = AtomicArray(10) { null } + for (i in 0 until refArr.length) { + refArr[i] = Data(i) + } + for (i in 0 until refArr.length) { + assertEquals(Data(i), refArr[i], "setter: FAIL $i") + } + assertFailsWith { + refArr[100] = Data(100) + }.let { ex -> + assertEquals("The index 100 is out of the bounds of the AtomicArray with size 10.", ex.message) + } + assertFailsWith { + refArr[-1] = Data(-1) + }.let { ex -> + assertEquals("The index -1 is out of the bounds of the AtomicArray with size 10.", ex.message) + } + } + + @Test fun compareAndExchange() { + val refArr = AtomicArray(10) { null } + val newValue = Data(1) + val res1 = refArr.compareAndExchange(3, null, newValue) + assertTrue(res1 == null && refArr[3] == newValue, "compareAndExchange: FAIL 1") + val res2 = refArr.compareAndExchange(3, newValue, Data(2)) + assertTrue(res2 == newValue && refArr[3] == Data(2), "compareAndExchange: FAIL 2") + val res3 = refArr.compareAndExchange(3, newValue, Data(3)) + assertTrue(res3 == Data(2) && refArr[3] == Data(2), "compareAndExchange: FAIL 3") + assertFailsWith { + refArr.compareAndExchange(10, newValue, Data(4)) + }.let { ex -> + assertEquals("The index 10 is out of the bounds of the AtomicArray with size 10.", ex.message) + } + assertFailsWith { + refArr.compareAndExchange(-1, newValue, Data(4)) + }.let { ex -> + assertEquals("The index -1 is out of the bounds of the AtomicArray with size 10.", ex.message) + } + } + + @Test fun compareAndSet() { + val refArr = AtomicArray(10) { null } + val newValue = Data(1) + val res1 = refArr.compareAndSet(3, null, newValue) + assertTrue(res1 && refArr[3] == newValue, "testAtomicArrayCompareAndSet: FAIL 1") + val res2 = refArr.compareAndSet(3, newValue, Data(2)) + assertTrue(res2 && refArr[3] == Data(2), "testAtomicArrayCompareAndSet: FAIL 2") + val res3 = refArr.compareAndSet(3, newValue, Data(3)) + assertTrue(!res3 && refArr[3] == Data(2), "testAtomicArrayCompareAndSet: FAIL 3") + assertFailsWith { + refArr.compareAndSet(10, newValue, Data(4)) + }.let { ex -> + assertEquals("The index 10 is out of the bounds of the AtomicArray with size 10.", ex.message) + } + assertFailsWith { + refArr.compareAndSet(-1, newValue, Data(4)) + }.let { ex -> + assertEquals("The index -1 is out of the bounds of the AtomicArray with size 10.", ex.message) + } + } + + @Test fun getAndSet() { + val refArr = AtomicArray(10) { null } + val res4 = refArr.getAndSet(4, Data(1)) + assertEquals(null, res4, "getAndSet: FAIL 1") + val res5 = refArr.getAndSet(4, Data(2)) + assertEquals(Data(1), res5, "getAndSet: FAIL 2") + assertFailsWith { + refArr.getAndSet(10, Data(1)) + }.let { ex -> + assertEquals("The index 10 is out of the bounds of the AtomicArray with size 10.", ex.message) + } + assertFailsWith { + refArr.getAndSet(-1, Data(1)) + }.let { ex -> + assertEquals("The index -1 is out of the bounds of the AtomicArray with size 10.", ex.message) + } + } +} \ No newline at end of file diff --git a/kotlin-native/runtime/test/concurrent/AtomicStressTest.kt b/kotlin-native/runtime/test/concurrent/AtomicStressTest.kt new file mode 100644 index 00000000000..64f5b7013d9 --- /dev/null +++ b/kotlin-native/runtime/test/concurrent/AtomicStressTest.kt @@ -0,0 +1,238 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package test.concurrent + +import kotlin.concurrent.* +import kotlin.native.concurrent.Future +import kotlin.native.concurrent.TransferMode +import kotlin.native.concurrent.Worker +import kotlin.test.* + +object ThreadPool { + private var _workers: Array? = null + + public fun init(threadCount: Int) { + _workers = Array(threadCount) { Worker.start() } + } + + public fun deinit() { + _workers?.forEach { + it.requestTermination().result + } + _workers = null + } + + public fun execute(f: (Int) -> T): List> = _workers?.mapIndexed { index, worker -> + worker.execute(TransferMode.SAFE, { Pair(f, index) }) { (f, index) -> + f(index) + } + } ?: error("Call ThreadPool.init() first") +} + +class AtomicIntStressTest { + @BeforeTest fun init() = ThreadPool.init(20) + @AfterTest fun deinit() = ThreadPool.deinit() + + @Test fun addAndGet() { + val atomic = AtomicInt(10) + val futures = ThreadPool.execute { + atomic.addAndGet(1000) + } + futures.forEach { + it.result + } + assertEquals(10 + 1000 * futures.size, atomic.value) + } + + @Test fun incrementAndGet() { + val initial = 15 + val atomic = AtomicInt(initial) + val futures = ThreadPool.execute { + atomic.incrementAndGet() + } + futures.forEach { + it.result + } + assertEquals(initial + futures.size, atomic.value) + } + + @Test fun mutex() { + val place = AtomicInt(1) + val counter = AtomicInt(0) + val futures = ThreadPool.execute { index -> + // Here we simulate mutex using [place] location to store tag of the current worker. + // When it is negative - worker executes exclusively. + val tag = index + 1 + while (place.compareAndExchange(tag, -tag) != tag) {} + assertEquals(index + 1, counter.incrementAndGet()) + // Now, let the next worker run. + val previousPlace = place.compareAndExchange(-tag, tag + 1) + assertEquals(-tag, previousPlace) + } + futures.forEach { + it.result + } + assertEquals(futures.size, counter.value) + } +} + +class AtomicLongStressTest { + @BeforeTest fun init() = ThreadPool.init(20) + @AfterTest fun deinit() = ThreadPool.deinit() + + @Test fun addAndGet() { + val atomic = AtomicLong(10L) + val futures = ThreadPool.execute { + atomic.addAndGet(9999999999) + } + futures.forEach { + it.result + } + assertEquals(10L + 9999999999 * futures.size, atomic.value) + } +} + +private class LockFreeStack { + private val top = AtomicReference?>(null) + + private class Node(val value: T, val next: Node?) + + fun isEmpty(): Boolean = top.value == null + + fun push(value: T) { + while(true) { + val cur = top.value + val upd = Node(value, cur) + if (top.compareAndSet(cur, upd)) return + } + } + + fun pop(): T? { + while(true) { + val cur = top.value + if (cur == null) return null + if (top.compareAndSet(cur, cur.next)) return cur.value + } + } +} + +class AtomicStressTest { + @BeforeTest fun init() = ThreadPool.init(20) + @AfterTest fun deinit() = ThreadPool.deinit() + + @Test fun mutex() { + val common = AtomicReference(null) + val futures = ThreadPool.execute { index -> + // Try to publish our own data, until successful, in a tight loop. + while (!common.compareAndSet(null, Data(index))) {} + } + val seen = mutableListOf() + futures.forEach { + while(true) { + val current = common.value ?: continue + // Each worker publishes exactly once + assertFalse(seen.contains(current.value)) + seen.add(current.value) + // Let others publish. + common.compareAndExchange(current, null) + break + } + } + futures.forEach { + it.result + } + assertContentEquals(futures.indices, seen.sorted()) + } + + @Test fun stackConcurrentPush() { + val stack = LockFreeStack() + val writers = ThreadPool.execute { + stack.push(it) + } + writers.forEach { it.result } + + val seen = mutableSetOf() + while(!stack.isEmpty()) { + val value = stack.pop() + assertNotNull(value) + seen.add(value) + } + assertEquals(writers.size, seen.size) + } +} + +class AtomicIntArrayStressTest { + @BeforeTest fun init() = ThreadPool.init(20) + @AfterTest fun deinit() = ThreadPool.deinit() + + @Test fun incrementAndGet() { + val intArr = AtomicIntArray(10) + val futures = ThreadPool.execute { + for (i in 0 until 500) { + val index = (0 until intArr.length).random() + intArr.incrementAndGet(index) + } + } + futures.forEach { + it.result + } + var sum = 0 + for (i in 0 until intArr.length) { + sum += intArr[i] + } + assertEquals(futures.size * 500, sum) + } +} + +class AtomicLongArrayStressTest { + @BeforeTest fun init() = ThreadPool.init(20) + @AfterTest fun deinit() = ThreadPool.deinit() + + @Test fun incrementAndGet() { + val longArr = AtomicLongArray(10) + val futures = ThreadPool.execute { + for (i in 0 until 500) { + val index = (0 until longArr.length).random() + longArr.incrementAndGet(index) + } + } + futures.forEach { + it.result + } + var sum = 0L + for (i in 0 until longArr.length) { + sum += longArr[i] + } + assertEquals(futures.size.toLong() * 500, sum) + } +} + +class AtomicArrayStressTest { + @BeforeTest fun init() = ThreadPool.init(20) + @AfterTest fun deinit() = ThreadPool.deinit() + + @Test fun compareAndSet() { + val refArr = AtomicArray(10) { Data(0) } + val futures = ThreadPool.execute { + for (i in 0 until 500) { + val index = (0 until refArr.length).random() + while(true) { + val cur = refArr[index] + val newValue = Data(cur.value + 1) + if (refArr.compareAndSet(index, cur, newValue)) break + } + } + } + futures.forEach { + it.result + } + var sum = 0 + for (i in 0 until refArr.length) { + sum += refArr[i].value + } + assertEquals(futures.size * 500, sum) + } +} diff --git a/kotlin-native/runtime/test/concurrent/AtomicTest.kt b/kotlin-native/runtime/test/concurrent/AtomicTest.kt new file mode 100644 index 00000000000..3cf2bcb1ed3 --- /dev/null +++ b/kotlin-native/runtime/test/concurrent/AtomicTest.kt @@ -0,0 +1,217 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package test.concurrent + +import kotlin.concurrent.* +import kotlin.native.internal.NativePtr +import kotlin.test.* + +data class Data(val value: Int) + +class AtomicIntTest { + @Test fun ctor() { + val x = AtomicInt(0) + assertEquals(x.value, 0) + } + + @Test fun setter() { + val x = AtomicInt(0) + x.value = 1 + assertEquals(x.value, 1) + } + + @Test fun addAndGet() { + val x = AtomicInt(1) + val result = x.addAndGet(2) + assertEquals(result, 1 + 2) + assertEquals(x.value, result) + } + + @Test fun compareAndExchange() { + val x = AtomicInt(0) + val successValue = x.compareAndExchange(0, 1) + assertEquals(successValue, 0) + assertEquals(x.value, 1) + val failValue = x.compareAndExchange(0, 2) + assertEquals(failValue, 1) + assertEquals(x.value, 1) + } + + @Test fun compareAndSet() { + val x = AtomicInt(0) + val successValue = x.compareAndSet(0, 1) + assertTrue(successValue) + assertEquals(x.value, 1) + val failValue = x.compareAndSet(0, 2) + assertFalse(failValue) + assertEquals(x.value, 1) + } + + @Test fun smoke() { + val atomic = AtomicInt(3) + assertEquals(3, atomic.value) + atomic.value = 5 + assertEquals(5, atomic.value) + assertEquals(5, atomic.getAndSet(6)) + assertEquals(6, atomic.value) + assertTrue(atomic.compareAndSet(6, 8)) + assertFalse(atomic.compareAndSet(9, 1)) + assertEquals(8, atomic.value) + assertEquals(8, atomic.getAndAdd(5)) + assertEquals(13, atomic.value) + assertEquals(18, atomic.addAndGet(5)) + assertEquals(18, atomic.getAndIncrement()) + assertEquals(19, atomic.value) + assertEquals(20, atomic.incrementAndGet()) + assertEquals(20, atomic.value) + assertEquals(20, atomic.getAndDecrement()) + assertEquals(19, atomic.value) + assertEquals(18, atomic.decrementAndGet()) + assertEquals(18, atomic.value) + assertEquals(18, atomic.compareAndExchange(18, 56)) + assertEquals(56, atomic.compareAndExchange(18, 56)) + assertEquals(56, atomic.compareAndExchange(18, 56)) + } +} + +class AtomicLongTest { + @Test fun ctor() { + val x = AtomicLong(0) + assertEquals(x.value, 0) + } + + @Test fun setter() { + val x = AtomicLong(0) + x.value = 1 + assertEquals(x.value, 1) + } + + @Test fun addAndGet() { + val x = AtomicLong(1) + val result = x.addAndGet(2L) + assertEquals(result, 1 + 2) + assertEquals(x.value, result) + } + + @Test fun compareAndExchange() { + val x = AtomicLong(0) + val successValue = x.compareAndExchange(0, 1) + assertEquals(successValue, 0) + assertEquals(x.value, 1) + val failValue = x.compareAndExchange(0, 2) + assertEquals(failValue, 1) + assertEquals(x.value, 1) + } + + @Test fun compareAndSet() { + val x = AtomicLong(0) + val successValue = x.compareAndSet(0, 1) + assertTrue(successValue) + assertEquals(x.value, 1) + val failValue = x.compareAndSet(0, 2) + assertFalse(failValue) + assertEquals(x.value, 1) + } + + @Test fun smoke() { + val atomic = AtomicLong(1424920024888900000) + assertEquals(1424920024888900000, atomic.value) + atomic.value = 2424920024888900000 + assertEquals(2424920024888900000, atomic.value) + assertEquals(2424920024888900000, atomic.getAndSet(3424920024888900000)) + assertEquals(3424920024888900000, atomic.value) + assertTrue(atomic.compareAndSet(3424920024888900000, 4424920024888900000)) + assertFalse(atomic.compareAndSet(9, 1)) + assertEquals(4424920024888900000, atomic.value) + assertEquals(4424920024888900000, atomic.getAndAdd(100000)) + assertEquals(4424920024889000000, atomic.value) + assertEquals(4424920024890000000, atomic.addAndGet(1000000L)) + assertEquals(4424920024890000000, atomic.getAndIncrement()) + assertEquals(4424920024890000001, atomic.value) + assertEquals(4424920024890000002, atomic.incrementAndGet()) + assertEquals(4424920024890000002, atomic.value) + assertEquals(4424920024890000002, atomic.getAndDecrement()) + assertEquals(4424920024890000001, atomic.value) + assertEquals(4424920024890000000, atomic.decrementAndGet()) + assertEquals(4424920024890000000, atomic.value) + assertEquals(4424920024890000000, atomic.compareAndExchange(4424920024890000000, 5424920024890000000)) + assertEquals(5424920024890000000, atomic.compareAndExchange(18, 56)) + assertEquals(5424920024890000000, atomic.compareAndExchange(18, 56)) + } +} + +class AtomicReferenceTest { + @Test fun ctor() { + val x = AtomicReference(Data(1)) + assertEquals(x.value, Data(1)) + } + + @Test fun setter() { + val x = AtomicReference(Data(1)) + x.value = Data(2) + assertEquals(x.value, Data(2)) + } + + @Test fun compareAndExchange() { + val initial = Data(1) + val new = Data(2) + val x = AtomicReference(initial) + val successValue = x.compareAndExchange(initial, new) + assertEquals(successValue, initial) + assertEquals(x.value, new) + val failValue = x.compareAndExchange(initial, Data(3)) + assertEquals(failValue, new) + assertEquals(x.value, new) + } + + @Test fun compareAndSet() { + val initial = Data(1) + val new = Data(2) + val x = AtomicReference(initial) + val successValue = x.compareAndSet(initial, new) + assertTrue(successValue) + assertEquals(x.value, new) + val failValue = x.compareAndSet(initial, Data(2)) + assertFalse(failValue) + assertEquals(x.value, new) + } + + @Test + fun smoke() { + val atomic = AtomicReference>(listOf(Data(1), Data(2), Data(3))) + assertEquals(listOf(Data(1), Data(2), Data(3)), atomic.value) + atomic.value = listOf(Data(1), Data(2), Data(1)) + assertEquals(listOf(Data(1), Data(2), Data(1)), atomic.value) + assertEquals(listOf(Data(1), Data(2), Data(1)), atomic.getAndSet(listOf(Data(1), Data(1), Data(1)))) + assertEquals(listOf(Data(1), Data(1), Data(1)), atomic.value) + var cur = atomic.value + assertTrue(atomic.compareAndSet(cur, listOf(Data(2), Data(2), Data(2)))) + assertFalse(atomic.compareAndSet(listOf(Data(1), Data(1), Data(1)), listOf(Data(2), Data(2), Data(2)))) + assertEquals(listOf(Data(2), Data(2), Data(2)), atomic.value) + cur = atomic.value + assertEquals(listOf(Data(2), Data(2), Data(2)), atomic.compareAndExchange(cur, listOf(Data(3), Data(3), Data(3)))) + assertEquals(listOf(Data(3), Data(3), Data(3)), atomic.compareAndExchange(cur, listOf(Data(4), Data(4), Data(4)))) + assertEquals(listOf(Data(3), Data(3), Data(3)), atomic.compareAndExchange(cur, listOf(Data(3), Data(3), Data(3)))) + } +} + +class AtomicNativePtrTest { + @Test fun smoke() { + val atomic = AtomicNativePtr(NativePtr.NULL) + assertEquals(NativePtr.NULL, atomic.value) + atomic.value = NativePtr.NULL.plus(10L) + assertEquals(10L, atomic.value.toLong()) + assertTrue(atomic.compareAndSet(NativePtr.NULL.plus(10L), NativePtr.NULL.plus(20L))) + assertEquals(20L, atomic.value.toLong()) + assertFalse(atomic.compareAndSet(NativePtr.NULL.plus(10L), NativePtr.NULL.plus(20L))) + assertEquals(20L, atomic.value.toLong()) + assertEquals(NativePtr.NULL.plus(20L), atomic.compareAndExchange(NativePtr.NULL.plus(20L), NativePtr.NULL.plus(30L))) + assertEquals(NativePtr.NULL.plus(30L), atomic.compareAndExchange(NativePtr.NULL.plus(20L), NativePtr.NULL.plus(40L))) + assertEquals(NativePtr.NULL.plus(30L), atomic.compareAndExchange(NativePtr.NULL.plus(20L), NativePtr.NULL.plus(50L))) + assertEquals(30L, atomic.getAndSet(NativePtr.NULL.plus(55L)).toLong()) + assertEquals(55L, atomic.value.toLong()) + } +} \ No newline at end of file diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/StdlibTest.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/StdlibTest.kt index 35e98c645e7..0a287562140 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/StdlibTest.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/StdlibTest.kt @@ -24,7 +24,7 @@ import org.junit.jupiter.api.TestFactory TC( name = "default", runnerType = TestRunnerType.DEFAULT, - freeCompilerArgs = [ENABLE_MPP, STDLIB_IS_A_FRIEND, ENABLE_X_STDLIB_API, ENABLE_X_ENCODING_API, ENABLE_RANGE_UNTIL], + freeCompilerArgs = [ENABLE_MPP, STDLIB_IS_A_FRIEND, ENABLE_X_STDLIB_API, ENABLE_X_ENCODING_API, ENABLE_X_FOREIGN_API, ENABLE_RANGE_UNTIL], sourceLocations = [ "libraries/stdlib/test/**.kt", "libraries/stdlib/common/test/**.kt", @@ -47,7 +47,7 @@ class StdlibTest : AbstractNativeBlackBoxTest() { TC( name = "default", runnerType = TestRunnerType.DEFAULT, - freeCompilerArgs = [ENABLE_MPP, STDLIB_IS_A_FRIEND, ENABLE_X_STDLIB_API, ENABLE_X_ENCODING_API, ENABLE_RANGE_UNTIL, + freeCompilerArgs = [ENABLE_MPP, STDLIB_IS_A_FRIEND, ENABLE_X_STDLIB_API, ENABLE_X_ENCODING_API, ENABLE_X_FOREIGN_API, ENABLE_RANGE_UNTIL, "-Xcommon-sources=libraries/stdlib/common/test/jsCollectionFactories.kt", "-Xcommon-sources=libraries/stdlib/common/test/testUtils.kt", "-Xcommon-sources=libraries/stdlib/test/testUtils.kt", @@ -74,5 +74,6 @@ private const val ENABLE_MPP = "-Xmulti-platform" internal const val STDLIB_IS_A_FRIEND = "-friend-modules=$KOTLIN_NATIVE_DISTRIBUTION/klib/common/stdlib" private const val ENABLE_X_STDLIB_API = "-opt-in=kotlin.ExperimentalStdlibApi" private const val ENABLE_X_ENCODING_API = "-opt-in=kotlin.io.encoding.ExperimentalEncodingApi" +private const val ENABLE_X_FOREIGN_API = "-opt-in=kotlinx.cinterop.ExperimentalForeignApi" private const val ENABLE_RANGE_UNTIL = "-XXLanguage:+RangeUntilOperator" // keep until 1.8 private const val DISABLED_STDLIB_TEST = "test.collections.CollectionTest.abstractCollectionToArray" \ No newline at end of file