[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:
+13
-10
@@ -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())
|
||||
|
||||
Reference in New Issue
Block a user