[K/N][tests] Migrate various runtime/ tests ^KT-61259
This commit is contained in:
committed by
Space Team
parent
7ad4e58a7a
commit
d88092aa94
@@ -1,302 +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.
|
||||
*/
|
||||
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class, FreezingIsDeprecated::class,
|
||||
kotlin.native.runtime.NativeRuntimeApi::class, kotlinx.cinterop.ExperimentalForeignApi::class)
|
||||
|
||||
package runtime.basic.cleaner_basic
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.internal.*
|
||||
import kotlin.concurrent.AtomicInt
|
||||
import kotlin.concurrent.AtomicNativePtr
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.native.ref.WeakReference
|
||||
import kotlin.native.ref.Cleaner
|
||||
import kotlin.native.ref.createCleaner
|
||||
import kotlin.native.runtime.GC
|
||||
|
||||
class AtomicBoolean(initialValue: Boolean) {
|
||||
private val impl = AtomicInt(if (initialValue) 1 else 0)
|
||||
|
||||
init {
|
||||
freeze()
|
||||
}
|
||||
|
||||
public var value: Boolean
|
||||
get() = impl.value != 0
|
||||
set(new) { impl.value = if (new) 1 else 0 }
|
||||
}
|
||||
|
||||
class FunBox(private val impl: () -> Unit) {
|
||||
fun call() {
|
||||
impl()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCleanerLambda() {
|
||||
val called = AtomicBoolean(false);
|
||||
var funBoxWeak: WeakReference<FunBox>? = null
|
||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||
{
|
||||
val cleaner = {
|
||||
val funBox = FunBox { called.value = true }.freeze()
|
||||
funBoxWeak = WeakReference(funBox)
|
||||
createCleaner(funBox) { it.call() }
|
||||
}()
|
||||
GC.collect() // Make sure local funBox reference is gone
|
||||
cleanerWeak = WeakReference(cleaner)
|
||||
assertFalse(called.value)
|
||||
}()
|
||||
|
||||
GC.collect()
|
||||
performGCOnCleanerWorker()
|
||||
|
||||
assertNull(cleanerWeak!!.value)
|
||||
assertTrue(called.value)
|
||||
assertNull(funBoxWeak!!.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCleanerNonSharedLambda() {
|
||||
// Only for experimental MM.
|
||||
if (Platform.memoryModel != MemoryModel.EXPERIMENTAL) {
|
||||
return
|
||||
}
|
||||
val called = AtomicBoolean(false);
|
||||
var funBoxWeak: WeakReference<FunBox>? = null
|
||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||
{
|
||||
val cleaner = {
|
||||
val funBox = FunBox { called.value = true }
|
||||
funBoxWeak = WeakReference(funBox)
|
||||
createCleaner(funBox) { it.call() }
|
||||
}()
|
||||
GC.collect() // Make sure local funBox reference is gone
|
||||
cleanerWeak = WeakReference(cleaner)
|
||||
assertFalse(called.value)
|
||||
}()
|
||||
|
||||
GC.collect()
|
||||
performGCOnCleanerWorker()
|
||||
|
||||
assertNull(cleanerWeak!!.value)
|
||||
assertTrue(called.value)
|
||||
assertNull(funBoxWeak!!.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCleanerAnonymousFunction() {
|
||||
val called = AtomicBoolean(false);
|
||||
var funBoxWeak: WeakReference<FunBox>? = null
|
||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||
{
|
||||
val cleaner = {
|
||||
val funBox = FunBox { called.value = true }.freeze()
|
||||
funBoxWeak = WeakReference(funBox)
|
||||
createCleaner(funBox, fun (it: FunBox) { it.call() })
|
||||
}()
|
||||
GC.collect() // Make sure local funBox reference is gone
|
||||
cleanerWeak = WeakReference(cleaner)
|
||||
assertFalse(called.value)
|
||||
}()
|
||||
|
||||
GC.collect()
|
||||
performGCOnCleanerWorker()
|
||||
|
||||
assertNull(cleanerWeak!!.value)
|
||||
assertTrue(called.value)
|
||||
assertNull(funBoxWeak!!.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCleanerNonSharedAnonymousFunction() {
|
||||
// Only for experimental MM.
|
||||
if (Platform.memoryModel != MemoryModel.EXPERIMENTAL) {
|
||||
return
|
||||
}
|
||||
val called = AtomicBoolean(false);
|
||||
var funBoxWeak: WeakReference<FunBox>? = null
|
||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||
{
|
||||
val cleaner = {
|
||||
val funBox = FunBox { called.value = true }
|
||||
funBoxWeak = WeakReference(funBox)
|
||||
createCleaner(funBox, fun (it: FunBox) { it.call() })
|
||||
}()
|
||||
GC.collect() // Make sure local funBox reference is gone
|
||||
cleanerWeak = WeakReference(cleaner)
|
||||
assertFalse(called.value)
|
||||
}()
|
||||
|
||||
GC.collect()
|
||||
performGCOnCleanerWorker()
|
||||
|
||||
assertNull(cleanerWeak!!.value)
|
||||
assertTrue(called.value)
|
||||
assertNull(funBoxWeak!!.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCleanerFunctionReference() {
|
||||
val called = AtomicBoolean(false);
|
||||
var funBoxWeak: WeakReference<FunBox>? = null
|
||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||
{
|
||||
val cleaner = {
|
||||
val funBox = FunBox { called.value = true }.freeze()
|
||||
funBoxWeak = WeakReference(funBox)
|
||||
createCleaner(funBox, FunBox::call)
|
||||
}()
|
||||
GC.collect() // Make sure local funBox reference is gone
|
||||
cleanerWeak = WeakReference(cleaner)
|
||||
assertFalse(called.value)
|
||||
}()
|
||||
|
||||
GC.collect()
|
||||
performGCOnCleanerWorker()
|
||||
|
||||
assertNull(cleanerWeak!!.value)
|
||||
assertTrue(called.value)
|
||||
assertNull(funBoxWeak!!.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCleanerNonSharedFunctionReference() {
|
||||
// Only for experimental MM.
|
||||
if (Platform.memoryModel != MemoryModel.EXPERIMENTAL) {
|
||||
return
|
||||
}
|
||||
val called = AtomicBoolean(false);
|
||||
var funBoxWeak: WeakReference<FunBox>? = null
|
||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||
{
|
||||
val cleaner = {
|
||||
val funBox = FunBox { called.value = true }
|
||||
funBoxWeak = WeakReference(funBox)
|
||||
createCleaner(funBox, FunBox::call)
|
||||
}()
|
||||
GC.collect() // Make sure local funBox reference is gone
|
||||
cleanerWeak = WeakReference(cleaner)
|
||||
assertFalse(called.value)
|
||||
}()
|
||||
|
||||
GC.collect()
|
||||
performGCOnCleanerWorker()
|
||||
|
||||
assertNull(cleanerWeak!!.value)
|
||||
assertTrue(called.value)
|
||||
assertNull(funBoxWeak!!.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCleanerFailWithNonShareableArgument() {
|
||||
// Only for legacy MM.
|
||||
if (Platform.memoryModel == MemoryModel.EXPERIMENTAL) {
|
||||
return
|
||||
}
|
||||
val funBox = FunBox {}
|
||||
assertFailsWith<IllegalArgumentException> {
|
||||
createCleaner(funBox) {}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCleanerCleansWithoutGC() {
|
||||
val called = AtomicBoolean(false);
|
||||
var funBoxWeak: WeakReference<FunBox>? = null
|
||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||
{
|
||||
val cleaner = {
|
||||
val funBox = FunBox { called.value = true }.freeze()
|
||||
funBoxWeak = WeakReference(funBox)
|
||||
createCleaner(funBox) { it.call() }
|
||||
}()
|
||||
GC.collect() // Make sure local funBox reference is gone
|
||||
cleaner.freeze()
|
||||
cleanerWeak = WeakReference(cleaner)
|
||||
assertFalse(called.value)
|
||||
}()
|
||||
|
||||
GC.collect()
|
||||
|
||||
assertNull(cleanerWeak!!.value)
|
||||
|
||||
waitCleanerWorker()
|
||||
|
||||
assertTrue(called.value)
|
||||
|
||||
// Only for legacy MM.
|
||||
if (Platform.memoryModel != MemoryModel.EXPERIMENTAL) {
|
||||
// If this fails, GC has somehow ran on the cleaners worker.
|
||||
assertNotNull(funBoxWeak!!.value)
|
||||
}
|
||||
}
|
||||
|
||||
val globalInt = AtomicInt(0)
|
||||
|
||||
@Test
|
||||
fun testCleanerWithInt() {
|
||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||
{
|
||||
val cleaner = createCleaner(42) {
|
||||
globalInt.value = it
|
||||
}.freeze()
|
||||
cleanerWeak = WeakReference(cleaner)
|
||||
assertEquals(0, globalInt.value)
|
||||
}()
|
||||
|
||||
GC.collect()
|
||||
performGCOnCleanerWorker()
|
||||
|
||||
assertNull(cleanerWeak!!.value)
|
||||
assertEquals(42, globalInt.value)
|
||||
}
|
||||
|
||||
val globalPtr = AtomicNativePtr(NativePtr.NULL)
|
||||
|
||||
@Test
|
||||
fun testCleanerWithNativePtr() {
|
||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||
{
|
||||
val cleaner = createCleaner(NativePtr.NULL + 42L) {
|
||||
globalPtr.value = it
|
||||
}
|
||||
cleanerWeak = WeakReference(cleaner)
|
||||
assertEquals(NativePtr.NULL, globalPtr.value)
|
||||
}()
|
||||
|
||||
GC.collect()
|
||||
performGCOnCleanerWorker()
|
||||
|
||||
assertNull(cleanerWeak!!.value)
|
||||
assertEquals(NativePtr.NULL + 42L, globalPtr.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCleanerWithException() {
|
||||
val called = AtomicBoolean(false);
|
||||
var funBoxWeak: WeakReference<FunBox>? = null
|
||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||
{
|
||||
val funBox = FunBox { called.value = true }.freeze()
|
||||
funBoxWeak = WeakReference(funBox)
|
||||
val cleaner = createCleaner(funBox) {
|
||||
it.call()
|
||||
error("Cleaner block failed")
|
||||
}
|
||||
cleanerWeak = WeakReference(cleaner)
|
||||
}()
|
||||
|
||||
GC.collect()
|
||||
performGCOnCleanerWorker()
|
||||
|
||||
assertNull(cleanerWeak!!.value)
|
||||
// Cleaners block started executing.
|
||||
assertTrue(called.value)
|
||||
// Even though the block failed, the captured funBox is freed.
|
||||
assertNull(funBoxWeak!!.value)
|
||||
}
|
||||
@@ -1,22 +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.
|
||||
*/
|
||||
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class)
|
||||
|
||||
import kotlin.native.ref.Cleaner
|
||||
import kotlin.native.ref.createCleaner
|
||||
import kotlin.native.Platform
|
||||
|
||||
fun main() {
|
||||
// Cleaner holds onto a finalization lambda. If it doesn't get executed,
|
||||
// the memory will leak. Suppress memory leak checker to check for cleaners
|
||||
// leak only.
|
||||
Platform.isMemoryLeakCheckerActive = false
|
||||
Platform.isCleanersLeakCheckerActive = true
|
||||
// This cleaner will run, because with the checker active this cleaner
|
||||
// will get collected, block scheduled and executed before cleaners are disabled.
|
||||
createCleaner(42) {
|
||||
println(it)
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
42
|
||||
@@ -1,21 +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.
|
||||
*/
|
||||
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class)
|
||||
|
||||
import kotlin.native.ref.createCleaner
|
||||
import kotlin.native.Platform
|
||||
|
||||
fun main() {
|
||||
// Cleaner holds onto a finalization lambda. If it doesn't get executed,
|
||||
// the memory will leak. Suppress memory leak checker to check for cleaners
|
||||
// leak only.
|
||||
Platform.isMemoryLeakCheckerActive = false
|
||||
Platform.isCleanersLeakCheckerActive = false
|
||||
// This cleaner will not run, because with the checker inactive this cleaner
|
||||
// will not get collected before cleaners are disabled.
|
||||
createCleaner(42) {
|
||||
println(it)
|
||||
}
|
||||
}
|
||||
@@ -1,27 +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.
|
||||
*/
|
||||
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class)
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.native.ref.Cleaner
|
||||
import kotlin.native.ref.createCleaner
|
||||
import kotlin.native.Platform
|
||||
|
||||
@ThreadLocal
|
||||
var tlsCleaner: Cleaner? = null
|
||||
|
||||
fun main() {
|
||||
// Cleaner holds onto a finalization lambda. If it doesn't get executed,
|
||||
// the memory will leak. Suppress memory leak checker to check for cleaners
|
||||
// leak only.
|
||||
Platform.isMemoryLeakCheckerActive = false
|
||||
Platform.isCleanersLeakCheckerActive = true
|
||||
// This cleaner won't be run
|
||||
tlsCleaner = createCleaner(42) {
|
||||
println(it)
|
||||
}
|
||||
}
|
||||
-27
@@ -1,27 +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.
|
||||
*/
|
||||
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class)
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.native.ref.Cleaner
|
||||
import kotlin.native.ref.createCleaner
|
||||
import kotlin.native.Platform
|
||||
|
||||
@ThreadLocal
|
||||
var tlsCleaner: Cleaner? = null
|
||||
|
||||
fun main() {
|
||||
// Cleaner holds onto a finalization lambda. If it doesn't get executed,
|
||||
// the memory will leak. Suppress memory leak checker to check for cleaners
|
||||
// leak only.
|
||||
Platform.isMemoryLeakCheckerActive = false
|
||||
Platform.isCleanersLeakCheckerActive = false
|
||||
// This cleaner won't be run
|
||||
tlsCleaner = createCleaner(42) {
|
||||
println(it)
|
||||
}
|
||||
}
|
||||
@@ -1,36 +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.
|
||||
*/
|
||||
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class, kotlin.native.runtime.NativeRuntimeApi::class, ObsoleteWorkersApi::class)
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.concurrent.AtomicInt
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.native.internal.*
|
||||
import kotlin.native.ref.Cleaner
|
||||
import kotlin.native.ref.createCleaner
|
||||
import kotlin.native.runtime.GC
|
||||
|
||||
@ThreadLocal
|
||||
var tlsCleaner: Cleaner? = null
|
||||
|
||||
val value = AtomicInt(0)
|
||||
|
||||
fun main() {
|
||||
val worker = Worker.start()
|
||||
|
||||
worker.execute(TransferMode.SAFE, {}) {
|
||||
tlsCleaner = createCleaner(42) {
|
||||
value.value = it
|
||||
}
|
||||
}
|
||||
|
||||
worker.requestTermination().result
|
||||
waitWorkerTermination(worker)
|
||||
GC.collect()
|
||||
waitCleanerWorker()
|
||||
|
||||
assertEquals(42, value.value)
|
||||
}
|
||||
@@ -1,23 +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.
|
||||
*/
|
||||
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class)
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.ref.Cleaner
|
||||
import kotlin.native.ref.createCleaner
|
||||
import kotlin.native.Platform
|
||||
|
||||
// This cleaner won't be run, because it's deinitialized with globals after
|
||||
// cleaners are disabled.
|
||||
val globalCleaner = createCleaner(42) {
|
||||
println(it)
|
||||
}
|
||||
|
||||
fun main() {
|
||||
Platform.isCleanersLeakCheckerActive = true
|
||||
// Make sure cleaner is initialized.
|
||||
assertNotNull(globalCleaner)
|
||||
}
|
||||
@@ -1,21 +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.
|
||||
*/
|
||||
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class)
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.ref.Cleaner
|
||||
import kotlin.native.ref.createCleaner
|
||||
|
||||
// This cleaner won't be run, because it's deinitialized with globals after
|
||||
// cleaners are disabled.
|
||||
val globalCleaner = createCleaner(42) {
|
||||
println(it)
|
||||
}
|
||||
|
||||
fun main() {
|
||||
// Make sure cleaner is initialized.
|
||||
assertNotNull(globalCleaner)
|
||||
}
|
||||
@@ -1,179 +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.
|
||||
*/
|
||||
@file:OptIn(ExperimentalStdlibApi::class, FreezingIsDeprecated::class, kotlin.experimental.ExperimentalNativeApi::class, kotlin.native.runtime.NativeRuntimeApi::class, ObsoleteWorkersApi::class)
|
||||
|
||||
package runtime.basic.cleaner_workers
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.internal.*
|
||||
import kotlin.concurrent.AtomicInt
|
||||
import kotlin.concurrent.AtomicReference
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.native.ref.WeakReference
|
||||
import kotlin.native.ref.Cleaner
|
||||
import kotlin.native.ref.createCleaner
|
||||
import kotlin.native.runtime.GC
|
||||
|
||||
class AtomicBoolean(initialValue: Boolean) {
|
||||
private val impl = AtomicInt(if (initialValue) 1 else 0)
|
||||
|
||||
init {
|
||||
freeze()
|
||||
}
|
||||
|
||||
public var value: Boolean
|
||||
get() = impl.value != 0
|
||||
set(new) { impl.value = if (new) 1 else 0 }
|
||||
}
|
||||
|
||||
class FunBox(private val impl: () -> Unit) {
|
||||
fun call() {
|
||||
impl()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCleanerDestroyInChild() {
|
||||
val worker = Worker.start()
|
||||
|
||||
val called = AtomicBoolean(false);
|
||||
var funBoxWeak: WeakReference<FunBox>? = null
|
||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||
worker.execute(TransferMode.SAFE, {
|
||||
val funBox = FunBox { called.value = true }.freeze()
|
||||
funBoxWeak = WeakReference(funBox)
|
||||
val cleaner = createCleaner(funBox) { it.call() }
|
||||
cleanerWeak = WeakReference(cleaner)
|
||||
Pair(called, cleaner)
|
||||
}) { (called, cleaner) ->
|
||||
assertFalse(called.value)
|
||||
}.result
|
||||
|
||||
GC.collect()
|
||||
worker.execute(TransferMode.SAFE, {}) { GC.collect() }.result
|
||||
performGCOnCleanerWorker()
|
||||
|
||||
assertNull(cleanerWeak!!.value)
|
||||
assertTrue(called.value)
|
||||
assertNull(funBoxWeak!!.value)
|
||||
|
||||
worker.requestTermination().result
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCleanerDestroyWithChild() {
|
||||
val worker = Worker.start()
|
||||
|
||||
val called = AtomicBoolean(false);
|
||||
var funBoxWeak: WeakReference<FunBox>? = null
|
||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||
worker.execute(TransferMode.SAFE, {
|
||||
val funBox = FunBox { called.value = true }.freeze()
|
||||
funBoxWeak = WeakReference(funBox)
|
||||
val cleaner = createCleaner(funBox) { it.call() }
|
||||
cleanerWeak = WeakReference(cleaner)
|
||||
Pair(called, cleaner)
|
||||
}) { (called, cleaner) ->
|
||||
assertFalse(called.value)
|
||||
}.result
|
||||
|
||||
GC.collect()
|
||||
worker.requestTermination().result
|
||||
waitWorkerTermination(worker)
|
||||
|
||||
performGCOnCleanerWorker() // Collect cleaners stack
|
||||
|
||||
assertNull(cleanerWeak!!.value)
|
||||
assertTrue(called.value)
|
||||
assertNull(funBoxWeak!!.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCleanerDestroyInMain() {
|
||||
val worker = Worker.start()
|
||||
|
||||
val called = AtomicBoolean(false);
|
||||
var funBoxWeak: WeakReference<FunBox>? = null
|
||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||
{
|
||||
val result = worker.execute(TransferMode.SAFE, { called }) { called ->
|
||||
val funBox = FunBox { called.value = true }.freeze()
|
||||
val cleaner = createCleaner(funBox) { it.call() }
|
||||
Triple(cleaner, WeakReference(funBox), WeakReference(cleaner))
|
||||
}.result
|
||||
val cleaner = result.first
|
||||
funBoxWeak = result.second
|
||||
cleanerWeak = result.third
|
||||
assertFalse(called.value)
|
||||
}()
|
||||
|
||||
GC.collect()
|
||||
worker.execute(TransferMode.SAFE, {}) { GC.collect() }.result
|
||||
performGCOnCleanerWorker()
|
||||
|
||||
assertNull(cleanerWeak!!.value)
|
||||
assertTrue(called.value)
|
||||
assertNull(funBoxWeak!!.value)
|
||||
|
||||
worker.requestTermination().result
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCleanerDestroyShared() {
|
||||
val worker = Worker.start()
|
||||
|
||||
val called = AtomicBoolean(false);
|
||||
var funBoxWeak: WeakReference<FunBox>? = null
|
||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||
val cleanerHolder: AtomicReference<Cleaner?> = AtomicReference(null);
|
||||
{
|
||||
val funBox = FunBox { called.value = true }.freeze()
|
||||
funBoxWeak = WeakReference(funBox)
|
||||
val cleaner = createCleaner(funBox) { it.call() }
|
||||
cleanerWeak = WeakReference(cleaner)
|
||||
cleanerHolder.value = cleaner
|
||||
worker.execute(TransferMode.SAFE, { Pair(called, cleanerHolder) }) { (called, cleanerHolder) ->
|
||||
cleanerHolder.value = null
|
||||
assertFalse(called.value)
|
||||
}.result
|
||||
}()
|
||||
|
||||
GC.collect()
|
||||
worker.execute(TransferMode.SAFE, {}) { GC.collect() }.result
|
||||
performGCOnCleanerWorker()
|
||||
|
||||
assertNull(cleanerWeak!!.value)
|
||||
assertTrue(called.value)
|
||||
assertNull(funBoxWeak!!.value)
|
||||
|
||||
worker.requestTermination().result
|
||||
}
|
||||
|
||||
@ThreadLocal
|
||||
var tlsValue = 11
|
||||
|
||||
@Test
|
||||
fun testCleanerWithTLS() {
|
||||
val worker = Worker.start()
|
||||
|
||||
tlsValue = 12
|
||||
|
||||
val value = AtomicInt(0)
|
||||
worker.execute(TransferMode.SAFE, {value}) {
|
||||
tlsValue = 13
|
||||
createCleaner(it) {
|
||||
it.value = tlsValue
|
||||
}
|
||||
Unit
|
||||
}.result
|
||||
|
||||
worker.execute(TransferMode.SAFE, {}) { GC.collect() }.result
|
||||
performGCOnCleanerWorker()
|
||||
|
||||
assertEquals(11, value.value)
|
||||
|
||||
worker.requestTermination().result
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
val x = initRuntimeIfNeeded()
|
||||
|
||||
fun main() {
|
||||
}
|
||||
@@ -1,76 +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.
|
||||
*/
|
||||
|
||||
@file:OptIn(ObsoleteWorkersApi::class)
|
||||
package runtime.basic.initializers6
|
||||
|
||||
import kotlin.test.*
|
||||
import kotlin.concurrent.AtomicInt
|
||||
import kotlin.concurrent.*
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
val aWorkerId = AtomicInt(0)
|
||||
val bWorkersCount = 3
|
||||
|
||||
val aWorkerUnlocker = AtomicInt(0)
|
||||
val bWorkerUnlocker = AtomicInt(0)
|
||||
|
||||
object A {
|
||||
init {
|
||||
// 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.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.
|
||||
Worker.current.park(100 * 1000L)
|
||||
}
|
||||
val a = produceA()
|
||||
val b = produceB()
|
||||
}
|
||||
|
||||
fun produceA(): String {
|
||||
// Must've been called by aWorker only.
|
||||
assertEquals(aWorkerId.value, Worker.current.id)
|
||||
return "A"
|
||||
}
|
||||
|
||||
fun produceB(): String {
|
||||
// Must've been called by aWorker only.
|
||||
assertEquals(aWorkerId.value, Worker.current.id)
|
||||
// Also check that it's ok to get A.a while initializing A.b.
|
||||
return "B+${A.a}"
|
||||
}
|
||||
|
||||
@Test fun runTest() {
|
||||
val aWorker = Worker.start()
|
||||
aWorkerId.value = aWorker.id
|
||||
val bWorkers = Array(bWorkersCount, { _ -> Worker.start() })
|
||||
|
||||
val aFuture = aWorker.execute(TransferMode.SAFE, {}, {
|
||||
A.b
|
||||
})
|
||||
val bFutures = Array(bWorkers.size, {
|
||||
bWorkers[it].execute(TransferMode.SAFE, {}, {
|
||||
// Wait until A has started to initialize.
|
||||
while (bWorkerUnlocker.value < 1) {}
|
||||
// Now allow A initialization to continue.
|
||||
aWorkerUnlocker.incrementAndGet()
|
||||
// And this should not've tried to init A itself.
|
||||
A.a + A.b
|
||||
})
|
||||
})
|
||||
|
||||
for (future in bFutures) {
|
||||
assertEquals("AB+A", future.result)
|
||||
}
|
||||
assertEquals("B+A", aFuture.result)
|
||||
|
||||
for (worker in bWorkers) {
|
||||
worker.requestTermination().result
|
||||
}
|
||||
aWorker.requestTermination().result
|
||||
}
|
||||
@@ -1,6 +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.
|
||||
*/
|
||||
|
||||
fun main() {}
|
||||
Reference in New Issue
Block a user