[K/N][Tests] Migrate dylib-interop-exe tests
^KT-61259
This commit is contained in:
committed by
Space Team
parent
83d851dd61
commit
2b2c685827
@@ -0,0 +1,3 @@
|
||||
language = Objective-C
|
||||
headerFilter = **/kt56402.h
|
||||
linkerOpts = -lkt56402
|
||||
@@ -0,0 +1,21 @@
|
||||
#include <inttypes.h>
|
||||
#include <objc/NSObject.h>
|
||||
|
||||
@interface OnDestroyHook: NSObject
|
||||
-(instancetype)init:(void(^)(uintptr_t))onDestroy;
|
||||
-(uintptr_t)identity;
|
||||
@end
|
||||
|
||||
@protocol OnDestroyHook
|
||||
-(uintptr_t)identity;
|
||||
@end
|
||||
|
||||
void startApp(void(^task)());
|
||||
uint64_t currentThreadId();
|
||||
BOOL isMainThread();
|
||||
void spin();
|
||||
|
||||
OnDestroyHook* newGlobal(void(^onDestroy)(uintptr_t));
|
||||
void clearGlobal();
|
||||
|
||||
id<OnDestroyHook> newOnDestroyHook(void(^onDestroy)(uintptr_t));
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* 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)
|
||||
|
||||
import kt56402.*
|
||||
|
||||
import kotlin.concurrent.AtomicInt
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.native.internal.test.testLauncherEntryPoint
|
||||
import kotlin.system.exitProcess
|
||||
import kotlin.test.*
|
||||
import kotlinx.cinterop.*
|
||||
|
||||
class LockedSet<T> {
|
||||
private val lock = AtomicInt(0)
|
||||
private val impl = mutableSetOf<T>()
|
||||
|
||||
private inline fun <R> locked(f: () -> R): R {
|
||||
while (!lock.compareAndSet(0, 1)) {}
|
||||
try {
|
||||
return f()
|
||||
} finally {
|
||||
lock.value = 0
|
||||
}
|
||||
}
|
||||
|
||||
fun add(id: T) = locked {
|
||||
assertFalse(id in impl)
|
||||
impl.add(id)
|
||||
}
|
||||
|
||||
fun remove(id: T) = locked {
|
||||
assertTrue(id in impl)
|
||||
impl.remove(id)
|
||||
}
|
||||
|
||||
operator fun contains(id: T) = locked {
|
||||
id in impl
|
||||
}
|
||||
}
|
||||
|
||||
class OnDestroyHookSub(onDestroy: (ULong) -> Unit) : OnDestroyHook(onDestroy)
|
||||
|
||||
val aliveObjectIds = LockedSet<ULong>()
|
||||
|
||||
fun alloc(ctor: ((ULong) -> Unit) -> ULong): ULong = autoreleasepool {
|
||||
val id = ctor {
|
||||
aliveObjectIds.remove(it)
|
||||
}
|
||||
aliveObjectIds.add(id)
|
||||
id
|
||||
}
|
||||
|
||||
fun waitDestruction(id: ULong) {
|
||||
assertTrue(isMainThread())
|
||||
// Make sure the finalizers are not run on the main thread even for STMS.
|
||||
withWorker {
|
||||
execute(TransferMode.SAFE, {}) {
|
||||
kotlin.native.internal.GC.collect()
|
||||
}.result
|
||||
}
|
||||
while (true) {
|
||||
spin()
|
||||
if (!(id in aliveObjectIds)) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOnMainThread() {
|
||||
assertTrue(isMainThread())
|
||||
val id = alloc { onDestroy ->
|
||||
OnDestroyHook {
|
||||
assertTrue(isMainThread())
|
||||
onDestroy(it)
|
||||
}.identity()
|
||||
}
|
||||
waitDestruction(id)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOnSecondaryThread() {
|
||||
val id = withWorker {
|
||||
execute(TransferMode.SAFE, {}) {
|
||||
assertFalse(isMainThread())
|
||||
alloc { onDestroy ->
|
||||
OnDestroyHook {
|
||||
assertFalse(isMainThread())
|
||||
onDestroy(it)
|
||||
}.identity()
|
||||
}
|
||||
}.result
|
||||
}
|
||||
waitDestruction(id)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSubOnMainThread() {
|
||||
assertTrue(isMainThread())
|
||||
val id = alloc { onDestroy ->
|
||||
OnDestroyHookSub {
|
||||
assertTrue(isMainThread())
|
||||
onDestroy(it)
|
||||
}.identity()
|
||||
}
|
||||
waitDestruction(id)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSubOnSecondaryThread() {
|
||||
val id = withWorker {
|
||||
execute(TransferMode.SAFE, {}) {
|
||||
assertFalse(isMainThread())
|
||||
alloc { onDestroy ->
|
||||
OnDestroyHookSub {
|
||||
assertFalse(isMainThread())
|
||||
onDestroy(it)
|
||||
}.identity()
|
||||
}
|
||||
}.result
|
||||
}
|
||||
waitDestruction(id)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGlobalOnMainThread() {
|
||||
assertTrue(isMainThread())
|
||||
val id = alloc { onDestroy ->
|
||||
val obj = newGlobal {
|
||||
assertTrue(isMainThread())
|
||||
onDestroy(it)
|
||||
}!!
|
||||
clearGlobal()
|
||||
obj.identity()
|
||||
}
|
||||
waitDestruction(id)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGlobalOnSecondaryThread() {
|
||||
val id = withWorker {
|
||||
execute(TransferMode.SAFE, {}) {
|
||||
assertFalse(isMainThread())
|
||||
alloc { onDestroy ->
|
||||
val obj = newGlobal {
|
||||
assertFalse(isMainThread())
|
||||
onDestroy(it)
|
||||
}!!
|
||||
clearGlobal()
|
||||
obj.identity()
|
||||
}
|
||||
}.result
|
||||
}
|
||||
waitDestruction(id)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testProtocolOnMainThread() {
|
||||
assertTrue(isMainThread())
|
||||
val id = alloc { onDestroy ->
|
||||
newOnDestroyHook {
|
||||
assertTrue(isMainThread())
|
||||
onDestroy(it)
|
||||
}!!.identity()
|
||||
}
|
||||
waitDestruction(id)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testProtocolOnSecondaryThread() {
|
||||
val id = withWorker {
|
||||
execute(TransferMode.SAFE, {}) {
|
||||
assertFalse(isMainThread())
|
||||
alloc { onDestroy ->
|
||||
newOnDestroyHook {
|
||||
assertFalse(isMainThread())
|
||||
onDestroy(it)
|
||||
}!!.identity()
|
||||
}
|
||||
}.result
|
||||
}
|
||||
waitDestruction(id)
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) = startApp {
|
||||
val exitCode = testLauncherEntryPoint(args)
|
||||
if (exitCode != 0) {
|
||||
exitProcess(exitCode)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
#include "kt56402.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
#include <pthread.h>
|
||||
#import <AppKit/NSApplication.h>
|
||||
#import <Foundation/NSRunLoop.h>
|
||||
#import <Foundation/NSThread.h>
|
||||
|
||||
@implementation OnDestroyHook {
|
||||
void (^onDestroy_)(uintptr_t);
|
||||
}
|
||||
|
||||
- (uintptr_t)identity {
|
||||
return (uintptr_t)self;
|
||||
}
|
||||
|
||||
- (instancetype)init:(void (^)(uintptr_t))onDestroy {
|
||||
if (self = [super init]) {
|
||||
onDestroy_ = onDestroy;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
onDestroy_([self identity]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface OnDestroyHookPrivate : NSObject<OnDestroyHook>
|
||||
@end
|
||||
|
||||
@implementation OnDestroyHookPrivate {
|
||||
void (^onDestroy_)(uintptr_t);
|
||||
}
|
||||
|
||||
- (uintptr_t)identity {
|
||||
return (uintptr_t)self;
|
||||
}
|
||||
|
||||
- (instancetype)init:(void (^)(uintptr_t))onDestroy {
|
||||
if (self = [super init]) {
|
||||
onDestroy_ = onDestroy;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
onDestroy_([self identity]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
void startApp(void (^task)()) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
// At this point all other scheduled main queue tasks were already executed.
|
||||
// Executing via performBlock to allow a recursive run loop in `spin()`.
|
||||
[[NSRunLoop currentRunLoop] performBlock:^{
|
||||
task();
|
||||
[NSApp terminate:NULL];
|
||||
}];
|
||||
});
|
||||
[[NSApplication sharedApplication] run];
|
||||
}
|
||||
|
||||
uint64_t currentThreadId() {
|
||||
uint64_t result;
|
||||
int ret = pthread_threadid_np(NULL, &result);
|
||||
assert(ret == 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL isMainThread() {
|
||||
return [NSThread isMainThread];
|
||||
}
|
||||
|
||||
void spin() {
|
||||
if ([NSRunLoop currentRunLoop] != [NSRunLoop mainRunLoop]) {
|
||||
fprintf(stderr, "Must spin main run loop\n");
|
||||
exit(1);
|
||||
}
|
||||
[[NSRunLoop currentRunLoop]
|
||||
runMode:NSDefaultRunLoopMode
|
||||
beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
|
||||
}
|
||||
|
||||
OnDestroyHook* global = NULL;
|
||||
|
||||
OnDestroyHook* newGlobal(void(^onDestroy)(uintptr_t)) {
|
||||
global = [[OnDestroyHook alloc] init:onDestroy];
|
||||
return global;
|
||||
}
|
||||
|
||||
void clearGlobal() {
|
||||
global = NULL;
|
||||
}
|
||||
|
||||
id<OnDestroyHook> newOnDestroyHook(void(^onDestroy)(uintptr_t)) {
|
||||
return [[OnDestroyHookPrivate alloc] init:onDestroy];
|
||||
}
|
||||
Reference in New Issue
Block a user