| // IGNORE_KLIB_BACKEND_ERRORS_WITH_CUSTOM_SECOND_STAGE: Native:* |
| // ^^^ KT-86026 TODO: Rework testdata to move functions/globals definitions from .def/.h into separate source files |
| |
| // TARGET_BACKEND: NATIVE |
| // MODULE: cinterop |
| // FILE: kt44283.def |
| --- |
| #include <stdlib.h> |
| #include <pthread.h> |
| |
| typedef struct { |
| int d; |
| } TestStruct; |
| |
| typedef struct { |
| void (*f)(TestStruct data); |
| } ThreadData; |
| |
| void *dispatch(void *rawArg) { |
| ThreadData *arg = rawArg; |
| arg->f((TestStruct) {.d = 1}); |
| return NULL; |
| } |
| |
| void invokeFromThread(void (*f)(TestStruct data)) { |
| pthread_t thread_id; |
| ThreadData *threadData = malloc(sizeof(ThreadData)); |
| threadData->f = f; |
| pthread_create(&thread_id, NULL, dispatch, (void *) threadData); |
| pthread_join(thread_id, NULL); |
| } |
| |
| |
| // MODULE: main(cinterop) |
| // FILE: main.kt |
| @file:OptIn(kotlin.native.runtime.NativeRuntimeApi::class) |
| |
| import kotlinx.cinterop.* |
| import kt44283.* |
| import kotlin.concurrent.AtomicInt |
| import kotlin.test.* |
| |
| val callbackCounter = AtomicInt(0) |
| |
| @ExperimentalForeignApi |
| fun box(): String { |
| val func = staticCFunction<CValue<TestStruct>, Unit> { |
| kotlin.native.runtime.GC.collect() // Helps to ensure that "runtime" is already initialized. |
| |
| memScoped { |
| println("Hello, Kotlin/Native! ${it.ptr.pointed.d}") |
| } |
| callbackCounter.incrementAndGet() |
| } |
| |
| assertEquals(0, callbackCounter.value) |
| invokeFromThread(func.reinterpret()) |
| assertEquals(1, callbackCounter.value) |
| |
| return "OK" |
| } |