[K/N] Stabilization of Atomics API

`AtomicInt`, `AtomicLong`, `AtomicReference` and `AtomicNativePtr` classes were moved to `kotlin.concurrent` package. The corresponding classes from `kotlin.native.concurrent` were deprecated with warning since Kotlin 1.9.

In order to prepare for further commonization of Atomics API the following changes were made:
* `kotlin.concurrent.AtomicInt`: 
    * `increment(): Unit` and `decrement(): Unit` methods were deprecated with error
    * New methods were added: `incrementAndGet(): Int` , `decrementAndGet(): Int`, `getAndIncrement(): Int`, `getAndDecrement(): Int`, `getAndSet(newValue: Int): Int` 
* `kotlin.concurrent.AtomicLong`:
    * `increment(): Unit` and `decrement(): Unit` methods were deprecated with error
    * New methods were added: `incrementAndGet(): Long`, `decrementAndGet(): Long`, `getAndIncrement(): Long`, `getAndDecrement(): Long`, `getAndSet(newValue: Long): Long`
    * Deprecated `AtomicLong()` constructor with default parameter value
* For all atomic classes `compareAndSwap` method was renamed to `compareAndExchange`

See KT-58074 for more details.

Merge-request: KT-MR-9272
Merged-by: Maria Sokolova <maria.sokolova@jetbrains.com>
This commit is contained in:
mvicsokolova
2023-04-25 16:55:42 +00:00
committed by Space Team
parent 1c56a71b14
commit 75b4469757
33 changed files with 1162 additions and 493 deletions
@@ -1165,21 +1165,26 @@ standaloneTest("freeze_disabled") {
testLogger = KonanTest.Logger.SILENT
}
task atomicSmokeTest(type: KonanLocalTest) {
enabled = isExperimentalMM // do not run the test on the legacy MM
source = "runtime/atomics/atomic_smoke.kt"
}
task atomicStressTest(type: KonanLocalTest) {
enabled = isExperimentalMM // do not run the test on the legacy MM
source = "runtime/atomics/atomic_stress.kt"
}
task atomic0(type: KonanLocalTest) {
enabled = (project.testTarget != 'wasm32') // Workers need pthreads.
useGoldenData = true
source = "runtime/workers/atomic0.kt"
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/workers/atomic1.kt"
}
task atomic2(type: KonanLocalTest) {
source = "runtime/workers/atomic2.kt"
source = "runtime/atomics/atomic1.kt"
}
task lazy0(type: KonanLocalTest) {
@@ -1,14 +1,17 @@
/*
* Copyright 2010-2018 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.
* 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, ObsoleteWorkersApi::class)
package runtime.workers.atomic0
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<Worker>) {
val atomic = AtomicInt(15)
@@ -32,10 +35,10 @@ fun test2(workers: Array<Worker>) {
// 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.compareAndSwap(tag, -tag) != tag) {}
while (place.compareAndExchange(tag, -tag) != tag) {}
val ok1 = result.addAndGet(1) == index + 1
// Now, let the next worker run.
val ok2 = place.compareAndSwap(-tag, tag + 1) == -tag
val ok2 = place.compareAndExchange(-tag, tag + 1) == -tag
ok1 && ok2
}
})
@@ -64,7 +67,7 @@ fun test3(workers: Array<Worker>) {
if (current != null && !seen.contains(current)) {
seen += current
// Let others publish.
assertEquals(common.compareAndSwap(current, null), current)
assertEquals(common.compareAndExchange(current, null), current)
break
}
} while (true)
@@ -80,7 +83,7 @@ fun test4LegacyMM() {
AtomicReference(Data(1))
}
assertFailsWith<InvalidMutabilityException> {
AtomicReference<Data?>(null).compareAndSwap(null, Data(2))
AtomicReference<Data?>(null).compareAndExchange(null, Data(2))
}
}
@@ -91,14 +94,14 @@ fun test4() {
}
run {
val ref = AtomicReference<Data?>(null)
ref.compareAndSwap(null, Data(2))
ref.compareAndExchange(null, Data(2))
assertEquals(2, ref.value!!.value)
}
if (Platform.isFreezingEnabled) {
run {
val ref = AtomicReference<Data?>(null).freeze()
assertFailsWith<InvalidMutabilityException> {
ref.compareAndSwap(null, Data(2))
ref.compareAndExchange(null, Data(2))
}
}
}
@@ -132,7 +135,7 @@ fun test6() {
assertEquals(239L, long.value)
}
@Suppress("DEPRECATION_ERROR")
fun test7() {
val ref = FreezableAtomicReference(Array(1) { "hey" })
ref.value[0] = "ho"
@@ -0,0 +1,189 @@
/*
* 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_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<List<String>>(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())
}
@@ -0,0 +1,92 @@
/*
* 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<Worker>) {
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<Worker>) {
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<T> {
private val top = AtomicReference<Node<T>?>(null)
private class Node<T>(val value: T, val next: Node<T>?)
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<Worker>) {
val stack = LockFreeStack<Int>()
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<Int>()
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)
}
@@ -9,6 +9,8 @@ package runtime.basic.initializers6
import kotlin.test.*
import kotlin.native.concurrent.*
import kotlin.concurrent.*
import kotlin.concurrent.AtomicInt
val aWorkerId = AtomicInt(0)
val bWorkersCount = 3
@@ -21,7 +23,7 @@ object A {
// Must be called by aWorker only.
assertEquals(aWorkerId.value, Worker.current.id)
// Only allow b workers to run, when a worker has started initialization.
bWorkerUnlocker.increment()
bWorkerUnlocker.incrementAndGet()
// 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.
@@ -57,7 +59,7 @@ fun produceB(): String {
// Wait until A has started to initialize.
while (bWorkerUnlocker.value < 1) {}
// Now allow A initialization to continue.
aWorkerUnlocker.increment()
aWorkerUnlocker.incrementAndGet()
// And this should not've tried to init A itself.
A.a + A.b
})
@@ -1,94 +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.
*/
import kotlin.test.*
import kotlin.native.concurrent.*
@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(2)
assertEquals(result, 1 + 2)
assertEquals(x.value, result)
}
@Test
fun compareAndSwap_Int() {
val x = AtomicInt(0)
val successValue = x.compareAndSwap(0, 1)
assertEquals(successValue, 0)
assertEquals(x.value, 1)
val failValue = x.compareAndSwap(0, 2)
assertEquals(failValue, 1)
assertEquals(x.value, 1)
}
@Test
fun compareAndSwap_Long() {
val x = AtomicLong(0)
val successValue = x.compareAndSwap(0, 1)
assertEquals(successValue, 0)
assertEquals(x.value, 1)
val failValue = x.compareAndSwap(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)
}
@@ -9,6 +9,8 @@ package runtime.workers.lazy4
import kotlin.test.*
import kotlin.native.concurrent.*
import kotlin.concurrent.*
import kotlin.concurrent.AtomicInt
const val WORKERS_COUNT = 20
@@ -24,7 +26,7 @@ fun concurrentLazyAccess(freeze: Boolean, mode: LazyThreadSafetyMode) {
val initializerCallCount = AtomicInt(0)
val c = C(argumentMode) {
initializerCallCount.increment()
initializerCallCount.incrementAndGet()
IntHolder(42)
}
if (freeze) {
@@ -36,7 +38,7 @@ fun concurrentLazyAccess(freeze: Boolean, mode: LazyThreadSafetyMode) {
val canStart = AtomicInt(0)
val futures = Array(workers.size) { i ->
workers[i].execute(TransferMode.SAFE, { Triple(inited, canStart, c) }) { (inited, canStart, c) ->
inited.increment()
inited.incrementAndGet()
while (canStart.value != 1) {}
c.data
}
@@ -4,6 +4,9 @@ package runtime.workers.worker10
import kotlin.test.*
import kotlin.native.concurrent.*
import kotlin.concurrent.*
import kotlin.concurrent.AtomicInt
import kotlin.concurrent.AtomicReference
import kotlin.native.ref.WeakReference
import kotlinx.cinterop.StableRef
@@ -93,14 +96,14 @@ val semaphore = AtomicInt(0)
val worker = Worker.start()
val future = worker.execute(TransferMode.SAFE, { null }) {
val value = atomicRef.value
semaphore.increment()
semaphore.incrementAndGet()
while (semaphore.value != 2) {}
println(value.toString() != "")
}
while (semaphore.value != 1) {}
atomicRef.value = null
kotlin.native.runtime.GC.collect()
semaphore.increment()
semaphore.incrementAndGet()
future.result
worker.requestTermination().result
}
@@ -110,14 +113,14 @@ val semaphore = AtomicInt(0)
val worker = Worker.start()
val future = worker.execute(TransferMode.SAFE, { null }) {
val value = stableRef.get()
semaphore.increment()
semaphore.incrementAndGet()
while (semaphore.value != 2) {}
println(value.toString() != "")
}
while (semaphore.value != 1) {}
stableRef.dispose()
kotlin.native.runtime.GC.collect()
semaphore.increment()
semaphore.incrementAndGet()
future.result
worker.requestTermination().result
}
@@ -133,7 +136,7 @@ val stableHolder1 = StableRef.create(("hello" to "world").freeze())
semaphore.value = 0
val future = worker.execute(TransferMode.SAFE, { WeakReference(stableHolder1.get()) }) {
ensureWeakIs(it, "hello" to "world")
semaphore.increment()
semaphore.incrementAndGet()
while (semaphore.value != 2) {}
kotlin.native.runtime.GC.collect()
ensureWeakIs(it, null)
@@ -141,7 +144,7 @@ val stableHolder1 = StableRef.create(("hello" to "world").freeze())
while (semaphore.value != 1) {}
stableHolder1.dispose()
kotlin.native.runtime.GC.collect()
semaphore.increment()
semaphore.incrementAndGet()
future.result
worker.requestTermination().result
}
@@ -153,7 +156,7 @@ val stableHolder2 = StableRef.create(("hello" to "world").freeze())
semaphore.value = 0
val future = worker.execute(TransferMode.SAFE, { WeakReference(stableHolder2.get()) }) {
val value = it.get()
semaphore.increment()
semaphore.incrementAndGet()
while (semaphore.value != 2) {}
kotlin.native.runtime.GC.collect()
assertEquals("hello" to "world", value)
@@ -161,7 +164,7 @@ val stableHolder2 = StableRef.create(("hello" to "world").freeze())
while (semaphore.value != 1) {}
stableHolder2.dispose()
kotlin.native.runtime.GC.collect()
semaphore.increment()
semaphore.incrementAndGet()
future.result
worker.requestTermination().result
}
@@ -171,15 +174,15 @@ val atomicRef2 = AtomicReference<Any?>(Any().freeze())
semaphore.value = 0
val worker = Worker.start()
val future = worker.execute(TransferMode.SAFE, { null }) {
val value = atomicRef2.compareAndSwap(null, null)
semaphore.increment()
val value = atomicRef2.compareAndExchange(null, null)
semaphore.incrementAndGet()
while (semaphore.value != 2) {}
assertEquals(true, value.toString() != "")
}
while (semaphore.value != 1) {}
atomicRef2.value = null
kotlin.native.runtime.GC.collect()
semaphore.increment()
semaphore.incrementAndGet()
future.result
worker.requestTermination().result
}
@@ -9,6 +9,8 @@ package runtime.workers.worker11
import kotlin.test.*
import kotlin.native.concurrent.*
import kotlin.concurrent.*
import kotlin.concurrent.AtomicInt
import kotlinx.cinterop.convert
data class Job(val index: Int, var input: Int, var counter: Int)
@@ -79,7 +81,7 @@ val counters = Array(COUNT) { AtomicInt(0) }
workerIndex
}) { index ->
assertEquals(0, counters[index].value)
counters[index].increment()
counters[index].incrementAndGet()
}
}
futures2.forEach { it.result }
@@ -7,8 +7,8 @@
package runtime.workers.worker4
import kotlin.test.*
import kotlin.native.concurrent.*
import kotlin.concurrent.AtomicInt
@Test fun runTest1() {
withWorker {
@@ -32,13 +32,14 @@ import kotlin.native.concurrent.*
assertTrue(Worker.current.processQueue())
assertEquals(1, counter.value)
// Let main proceed.
counter.increment() // counter becomes 2 here.
counter.incrementAndGet() // counter becomes 2 here.
assertTrue(Worker.current.park(10_000_000, true))
assertEquals(3, counter.value)
}.freeze())
executeAfter(0, {
counter.increment()
counter.incrementAndGet()
Unit
}.freeze())
while (counter.value < 2) {
@@ -46,7 +47,8 @@ import kotlin.native.concurrent.*
}
executeAfter(0, {
counter.increment()
counter.incrementAndGet()
Unit
}.freeze())
while (counter.value == 2) {
@@ -60,7 +62,8 @@ import kotlin.native.concurrent.*
val counter = AtomicInt(0)
worker.executeAfter(0, {
assertEquals("Lumberjack", Worker.current.name)
counter.increment()
counter.incrementAndGet()
Unit
}.freeze())
while (counter.value == 0) {
@@ -76,7 +79,8 @@ import kotlin.native.concurrent.*
@Test fun runTest4() {
val counter = AtomicInt(0)
Worker.current.executeAfter(10_000, {
counter.increment()
counter.incrementAndGet()
Unit
}.freeze())
assertTrue(Worker.current.park(1_000_000, process = true))
assertEquals(1, counter.value)
@@ -88,7 +92,8 @@ import kotlin.native.concurrent.*
withWorker {
executeAfter(1000, {
main.executeAfter(1, {
counter.increment()
counter.incrementAndGet()
Unit
}.freeze())
}.freeze())
assertTrue(main.park(1000L * 1000 * 1000, process = true))
@@ -106,13 +111,13 @@ import kotlin.native.concurrent.*
withWorker {
val f1 = execute(TransferMode.SAFE, { counter }) { counter ->
Worker.current.park(Long.MAX_VALUE / 1000L, process = true)
counter.increment()
counter.incrementAndGet()
}
// wait a bit
Worker.current.park(10_000L)
// submit a task
val f2 = execute(TransferMode.SAFE, { counter }) { counter ->
counter.increment()
counter.incrementAndGet()
}
f1.consume {}
f2.consume {}
@@ -139,14 +144,15 @@ import kotlin.native.concurrent.*
submitters.forEach {
it.executeAfter(0L, {
readySubmittersCounter.increment()
readySubmittersCounter.incrementAndGet()
// Wait for other submitters, to make them all start at the same time:
while (readySubmittersCounter.value != numberOfSubmitters) {}
// Concurrently submit tasks with matching scheduled execution time:
repeat(numberOfTasks) {
targetWorker.executeAfter(delayInMicroseconds, {
executedTasksCounter.increment()
executedTasksCounter.incrementAndGet()
Unit
}.freeze())
}
@@ -157,7 +163,8 @@ import kotlin.native.concurrent.*
// the test still might hang without a fix.
targetWorker.executeAfter(delayInMicroseconds + 1, {
mainWorker.executeAfter(0L, {
finishedBatchesCounter.increment()
finishedBatchesCounter.incrementAndGet()
Unit
}.freeze())
}.freeze())
}.freeze())