Fix cleaner tests on mingw (#4457)

This commit is contained in:
Alexander Shabalin
2020-10-22 13:23:30 +03:00
committed by GitHub
parent 02d4dc08a8
commit eb576258e3
7 changed files with 41 additions and 54 deletions
+1
View File
@@ -962,6 +962,7 @@ standaloneTest("cleaner_in_tls_main_with_checker") {
standaloneTest("cleaner_in_tls_worker") {
enabled = (project.testTarget != 'wasm32') // Cleaners need workers
source = "runtime/basic/cleaner_in_tls_worker.kt"
flags = ['-Xopt-in=kotlin.native.internal.InternalForKotlinNative']
}
standaloneTest("worker_bound_reference0") {
@@ -2,7 +2,7 @@
* 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(ExperimentalTime::class, ExperimentalStdlibApi::class)
@file:OptIn(ExperimentalStdlibApi::class)
package runtime.basic.cleaner_basic
@@ -11,7 +11,6 @@ import kotlin.test.*
import kotlin.native.internal.*
import kotlin.native.concurrent.*
import kotlin.native.ref.WeakReference
import kotlin.time.*
class AtomicBoolean(initialValue: Boolean) {
private val impl = AtomicInt(if (initialValue) 1 else 0)
@@ -111,20 +110,6 @@ fun testCleanerFailWithNonShareableArgument() {
}
}
inline fun tryWithTimeout(timeoutSeconds: Int, f: () -> Unit): Unit {
val timeout = TimeSource.Monotonic.markNow() + timeoutSeconds.seconds
while (true) {
try {
f()
return
} catch (e: Throwable) {
if (timeout.hasPassedNow()) {
throw e
}
}
}
}
@Test
fun testCleanerCleansWithoutGC() {
val called = AtomicBoolean(false);
@@ -145,12 +130,12 @@ fun testCleanerCleansWithoutGC() {
GC.collect()
assertNull(cleanerWeak!!.value)
tryWithTimeout(3) {
GC.collect() // Collect local stack (from previous iteration)
assertTrue(called.value)
// If this fails, GC has somehow ran on the cleaners worker.
assertNotNull(funBoxWeak!!.value)
}
waitCleanerWorker()
assertTrue(called.value)
// If this fails, GC has somehow ran on the cleaners worker.
assertNotNull(funBoxWeak!!.value)
}
val globalInt = AtomicInt(0)
@@ -2,13 +2,12 @@
* 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(ExperimentalTime::class, ExperimentalStdlibApi::class)
@file:OptIn(ExperimentalStdlibApi::class)
import kotlin.test.*
import kotlin.native.concurrent.*
import kotlin.native.internal.*
import kotlin.time.*
@ThreadLocal
var tlsCleaner: Cleaner? = null
@@ -25,9 +24,8 @@ fun main() {
}
worker.requestTermination().result
val timeout = TimeSource.Monotonic.markNow() + 3.seconds
while (value.value == 0 || timeout.hasNotPassedNow()) {}
waitWorkerTermination(worker)
waitCleanerWorker()
assertEquals(42, value.value)
}
@@ -2,7 +2,7 @@
* 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(ExperimentalTime::class, ExperimentalStdlibApi::class)
@file:OptIn(ExperimentalStdlibApi::class)
package runtime.basic.cleaner_workers
@@ -11,7 +11,6 @@ import kotlin.test.*
import kotlin.native.internal.*
import kotlin.native.concurrent.*
import kotlin.native.ref.WeakReference
import kotlin.time.*
class AtomicBoolean(initialValue: Boolean) {
private val impl = AtomicInt(if (initialValue) 1 else 0)
@@ -59,20 +58,6 @@ fun testCleanerDestroyInChild() {
worker.requestTermination().result
}
inline fun tryWithTimeout(timeoutSeconds: Int, f: () -> Unit): Unit {
val timeout = TimeSource.Monotonic.markNow() + timeoutSeconds.seconds
while (true) {
try {
f()
return
} catch (e: Throwable) {
if (timeout.hasPassedNow()) {
throw e
}
}
}
}
@Test
fun testCleanerDestroyWithChild() {
val worker = Worker.start()
@@ -92,15 +77,13 @@ fun testCleanerDestroyWithChild() {
GC.collect()
worker.requestTermination().result
waitWorkerTermination(worker)
tryWithTimeout(3) {
GC.collect() // Collect local stack (from previous iteration)
performGCOnCleanerWorker() // Collect cleaners stack
performGCOnCleanerWorker() // Collect cleaners stack
assertNull(cleanerWeak!!.value)
assertTrue(called.value)
assertNull(funBoxWeak!!.value)
}
assertNull(cleanerWeak!!.value)
assertTrue(called.value)
assertNull(funBoxWeak!!.value)
}
@Test
+10 -4
View File
@@ -474,12 +474,14 @@ class State {
}
template <typename F>
void waitNativeWorkersTerminationUnlocked(F waitForWorker) {
void waitNativeWorkersTerminationUnlocked(bool checkLeaks, F waitForWorker) {
std::vector<std::pair<KInt, pthread_t>> workersToWait;
{
Locker locker(&lock_);
checkNativeWorkersLeakLocked();
if (checkLeaks) {
checkNativeWorkersLeakLocked();
}
for (auto& kvp : terminating_native_workers_) {
RuntimeAssert(!pthread_equal(kvp.second, pthread_self()), "Native worker is joining with itself");
@@ -742,13 +744,13 @@ void WorkerDestroyThreadDataIfNeeded(KInt id) {
void WaitNativeWorkersTermination() {
#if WITH_WORKERS
theState()->waitNativeWorkersTerminationUnlocked([](KInt worker) { return true; });
theState()->waitNativeWorkersTerminationUnlocked(true, [](KInt worker) { return true; });
#endif
}
void WaitNativeWorkerTermination(KInt id) {
#if WITH_WORKERS
theState()->waitNativeWorkersTerminationUnlocked([id](KInt worker) { return worker == id; });
theState()->waitNativeWorkersTerminationUnlocked(false, [id](KInt worker) { return worker == id; });
#endif
}
@@ -1060,4 +1062,8 @@ void Kotlin_Worker_ensureNeverFrozen(KRef object) {
EnsureNeverFrozen(object);
}
void Kotlin_Worker_waitTermination(KInt id) {
WaitNativeWorkerTermination(id);
}
} // extern "C"
@@ -7,6 +7,7 @@ package kotlin.native.concurrent
import kotlin.native.internal.DescribeObjectForDebugging
import kotlin.native.internal.ExportForCppRuntime
import kotlin.native.internal.InternalForKotlinNative
import kotlin.native.internal.debugDescription
import kotlin.native.identityHashCode
import kotlin.reflect.KClass
@@ -100,3 +101,7 @@ internal fun ThrowIllegalObjectSharingException(typeInfo: NativePtr, address: Na
@SymbolName("Kotlin_AtomicReference_checkIfFrozen")
external internal fun checkIfFrozen(ref: Any?)
@InternalForKotlinNative
@SymbolName("Kotlin_Worker_waitTermination")
external public fun waitWorkerTermination(worker: Worker)
@@ -96,6 +96,15 @@ fun performGCOnCleanerWorker() =
GC.collect()
}.result
/**
* Wait for a worker that executes Cleaner blocks to complete its scheduled tasks.
*/
@InternalForKotlinNative
fun waitCleanerWorker() =
getCleanerWorker().execute(TransferMode.SAFE, {}) {
Unit
}.result
@SymbolName("Kotlin_CleanerImpl_getCleanerWorker")
external private fun getCleanerWorker(): Worker