1919package io.realm.kotlin.internal.interop
2020
2121import io.realm.kotlin.internal.interop.Constants.ENCRYPTION_KEY_LENGTH
22- import io.realm.kotlin.internal.interop.RealmInterop.safeKString
2322import io.realm.kotlin.internal.interop.sync.ApiKeyWrapper
2423import io.realm.kotlin.internal.interop.sync.AppError
2524import io.realm.kotlin.internal.interop.sync.AuthProvider
@@ -80,7 +79,6 @@ import kotlinx.cinterop.usePinned
8079import kotlinx.cinterop.value
8180import kotlinx.coroutines.CoroutineDispatcher
8281import kotlinx.coroutines.CoroutineScope
83- import kotlinx.coroutines.CoroutineStart
8482import kotlinx.coroutines.launch
8583import org.mongodb.kbson.BsonObjectId
8684import org.mongodb.kbson.ObjectId
@@ -494,11 +492,10 @@ actual object RealmInterop {
494492 )
495493 }
496494
497- actual fun realm_open (config : RealmConfigurationPointer , dispatcher : CoroutineDispatcher ? ): Pair <LiveRealmPointer , Boolean > {
495+ actual fun realm_open (config : RealmConfigurationPointer , scheduler : RealmSchedulerPointer ): Pair <LiveRealmPointer , Boolean > {
498496 val fileCreated = atomic(false )
499497 val callback = DataInitializationCallback {
500498 fileCreated.value = true
501- true
502499 }
503500 realm_wrapper.realm_config_set_data_initialization_function(
504501 config.cptr(),
@@ -516,21 +513,75 @@ actual object RealmInterop {
516513 // val dispatcher = runBlocking { coroutineContext[CoroutineDispatcher.Key] }
517514 // but requires opting in for @ExperimentalStdlibApi, and have really gotten it to play
518515 // for default cases.
519- if (dispatcher != null ) {
520- val scheduler = checkedPointerResult(createSingleThreadDispatcherScheduler(dispatcher))
521- realm_wrapper.realm_config_set_scheduler(config.cptr(), scheduler)
522- } else {
523- // If there is no notification dispatcher use the default scheduler.
524- // Re-verify if this is actually needed when notification scheduler is fully in place.
525- val scheduler = checkedPointerResult(realm_wrapper.realm_scheduler_make_default())
526- realm_wrapper.realm_config_set_scheduler(config.cptr(), scheduler)
527- }
516+ realm_wrapper.realm_config_set_scheduler(config.cptr(), scheduler.cptr())
517+
528518 val realmPtr = CPointerWrapper <LiveRealmT >(realm_wrapper.realm_open(config.cptr()))
529519 // Ensure that we can read version information, etc.
530520 realm_begin_read(realmPtr)
531521 return Pair (realmPtr, fileCreated.value)
532522 }
533523
524+ actual fun realm_create_scheduler (): RealmSchedulerPointer {
525+ // If there is no notification dispatcher use the default scheduler.
526+ // Re-verify if this is actually needed when notification scheduler is fully in place.
527+ val scheduler = checkedPointerResult(realm_wrapper.realm_scheduler_make_default())
528+ return CPointerWrapper <RealmSchedulerT >(scheduler)
529+ }
530+
531+ actual fun realm_create_scheduler (dispatcher : CoroutineDispatcher ): RealmSchedulerPointer {
532+ printlntid(" createSingleThreadDispatcherScheduler" )
533+ val scheduler = SingleThreadDispatcherScheduler (tid(), dispatcher)
534+
535+ val capi_scheduler: CPointer < realm_scheduler_t> = checkedPointerResult(
536+ realm_wrapper.realm_scheduler_new(
537+ // userdata: kotlinx.cinterop.CValuesRef<*>?,
538+ scheduler.ref,
539+
540+ // free: realm_wrapper.realm_free_userdata_func_t? /* = kotlinx.cinterop.CPointer<kotlinx.cinterop.CFunction<(kotlinx.cinterop.COpaquePointer? /* = kotlinx.cinterop.CPointer<out kotlinx.cinterop.CPointed>? */) -> kotlin.Unit>>? */,
541+ staticCFunction<COpaquePointer ?, Unit > { userdata ->
542+ printlntid(" free" )
543+ userdata?.asStableRef<SingleThreadDispatcherScheduler >()?.dispose()
544+ },
545+
546+ // notify: realm_wrapper.realm_scheduler_notify_func_t? /* = kotlinx.cinterop.CPointer<kotlinx.cinterop.CFunction<(kotlinx.cinterop.COpaquePointer? /* = kotlinx.cinterop.CPointer<out kotlinx.cinterop.CPointed>? */) -> kotlin.Unit>>? */,
547+ staticCFunction<COpaquePointer ?, Unit > { userdata ->
548+ // Must be thread safe
549+ val scheduler =
550+ userdata!! .asStableRef<SingleThreadDispatcherScheduler >().get()
551+ printlntid(" $scheduler notify" )
552+ try {
553+ scheduler.notify()
554+ } catch (e: Exception ) {
555+ // Should never happen, but is included for development to get some indicators
556+ // on errors instead of silent crashes.
557+ e.printStackTrace()
558+ }
559+ },
560+
561+ // is_on_thread: realm_wrapper.realm_scheduler_is_on_thread_func_t? /* = kotlinx.cinterop.CPointer<kotlinx.cinterop.CFunction<(kotlinx.cinterop.COpaquePointer? /* = kotlinx.cinterop.CPointer<out kotlinx.cinterop.CPointed>? */) -> kotlin.Boolean>>? */,
562+ staticCFunction<COpaquePointer ?, Boolean > { userdata ->
563+ // Must be thread safe
564+ val scheduler =
565+ userdata!! .asStableRef<SingleThreadDispatcherScheduler >().get()
566+ printlntid(" is_on_thread[$scheduler ] ${scheduler.threadId} " + tid())
567+ scheduler.threadId == tid()
568+ },
569+
570+ // is_same_as: realm_wrapper.realm_scheduler_is_same_as_func_t? /* = kotlinx.cinterop.CPointer<kotlinx.cinterop.CFunction<(kotlinx.cinterop.COpaquePointer? /* = kotlinx.cinterop.CPointer<out kotlinx.cinterop.CPointed>? */, kotlinx.cinterop.COpaquePointer? /* = kotlinx.cinterop.CPointer<out kotlinx.cinterop.CPointed>? */) -> kotlin.Boolean>>? */,
571+ staticCFunction<COpaquePointer ?, COpaquePointer ?, Boolean > { userdata, other ->
572+ userdata == other
573+ },
574+
575+ // can_deliver_notifications: realm_wrapper.realm_scheduler_can_deliver_notifications_func_t? /* = kotlinx.cinterop.CPointer<kotlinx.cinterop.CFunction<(kotlinx.cinterop.COpaquePointer? /* = kotlinx.cinterop.CPointer<out kotlinx.cinterop.CPointed>? */) -> kotlin.Boolean>>? */,
576+ staticCFunction<COpaquePointer ?, Boolean > { _ -> true },
577+ )
578+ ) ? : error(" Couldn't create scheduler" )
579+
580+ scheduler.set_scheduler(capi_scheduler)
581+
582+ return CPointerWrapper <RealmSchedulerT >(capi_scheduler)
583+ }
584+
534585 actual fun realm_open_synchronized (config : RealmConfigurationPointer ): RealmAsyncOpenTaskPointer {
535586 return CPointerWrapper (realm_wrapper.realm_open_synchronized(config.cptr()))
536587 }
@@ -3241,61 +3292,6 @@ actual object RealmInterop {
32413292 ? : throw NullPointerException (identifier?.let { " '$identifier ' shouldn't be null." })
32423293 }
32433294
3244- private fun createSingleThreadDispatcherScheduler (
3245- dispatcher : CoroutineDispatcher
3246- ): CPointer <realm_scheduler_t> {
3247- printlntid(" createSingleThreadDispatcherScheduler" )
3248- val scheduler = SingleThreadDispatcherScheduler (tid(), dispatcher)
3249-
3250- val capi_scheduler: CPointer < realm_scheduler_t> = checkedPointerResult(
3251- realm_wrapper.realm_scheduler_new(
3252- // userdata: kotlinx.cinterop.CValuesRef<*>?,
3253- scheduler.ref,
3254-
3255- // free: realm_wrapper.realm_free_userdata_func_t? /* = kotlinx.cinterop.CPointer<kotlinx.cinterop.CFunction<(kotlinx.cinterop.COpaquePointer? /* = kotlinx.cinterop.CPointer<out kotlinx.cinterop.CPointed>? */) -> kotlin.Unit>>? */,
3256- staticCFunction<COpaquePointer ?, Unit > { userdata ->
3257- printlntid(" free" )
3258- userdata?.asStableRef<SingleThreadDispatcherScheduler >()?.dispose()
3259- },
3260-
3261- // notify: realm_wrapper.realm_scheduler_notify_func_t? /* = kotlinx.cinterop.CPointer<kotlinx.cinterop.CFunction<(kotlinx.cinterop.COpaquePointer? /* = kotlinx.cinterop.CPointer<out kotlinx.cinterop.CPointed>? */) -> kotlin.Unit>>? */,
3262- staticCFunction<COpaquePointer ?, Unit > { userdata ->
3263- // Must be thread safe
3264- val scheduler =
3265- userdata!! .asStableRef<SingleThreadDispatcherScheduler >().get()
3266- printlntid(" $scheduler notify" )
3267- try {
3268- scheduler.notify()
3269- } catch (e: Exception ) {
3270- // Should never happen, but is included for development to get some indicators
3271- // on errors instead of silent crashes.
3272- e.printStackTrace()
3273- }
3274- },
3275-
3276- // is_on_thread: realm_wrapper.realm_scheduler_is_on_thread_func_t? /* = kotlinx.cinterop.CPointer<kotlinx.cinterop.CFunction<(kotlinx.cinterop.COpaquePointer? /* = kotlinx.cinterop.CPointer<out kotlinx.cinterop.CPointed>? */) -> kotlin.Boolean>>? */,
3277- staticCFunction<COpaquePointer ?, Boolean > { userdata ->
3278- // Must be thread safe
3279- val scheduler =
3280- userdata!! .asStableRef<SingleThreadDispatcherScheduler >().get()
3281- printlntid(" is_on_thread[$scheduler ] ${scheduler.threadId} " + tid())
3282- scheduler.threadId == tid()
3283- },
3284-
3285- // is_same_as: realm_wrapper.realm_scheduler_is_same_as_func_t? /* = kotlinx.cinterop.CPointer<kotlinx.cinterop.CFunction<(kotlinx.cinterop.COpaquePointer? /* = kotlinx.cinterop.CPointer<out kotlinx.cinterop.CPointed>? */, kotlinx.cinterop.COpaquePointer? /* = kotlinx.cinterop.CPointer<out kotlinx.cinterop.CPointed>? */) -> kotlin.Boolean>>? */,
3286- staticCFunction<COpaquePointer ?, COpaquePointer ?, Boolean > { userdata, other ->
3287- userdata == other
3288- },
3289-
3290- // can_deliver_notifications: realm_wrapper.realm_scheduler_can_deliver_notifications_func_t? /* = kotlinx.cinterop.CPointer<kotlinx.cinterop.CFunction<(kotlinx.cinterop.COpaquePointer? /* = kotlinx.cinterop.CPointer<out kotlinx.cinterop.CPointed>? */) -> kotlin.Boolean>>? */,
3291- staticCFunction<COpaquePointer ?, Boolean > { userdata -> true },
3292- )
3293- ) ? : error(" Couldn't create scheduler" )
3294- scheduler.set_scheduler(capi_scheduler)
3295- scheduler
3296- return capi_scheduler
3297- }
3298-
32993295 private fun <R > handleAppCallback (
33003296 userData : COpaquePointer ? ,
33013297 error : CPointer <realm_app_error_t>? ,
@@ -3401,7 +3397,7 @@ actual object RealmInterop {
34013397 }
34023398
34033399 override fun notify () {
3404- val function : suspend CoroutineScope .() -> Unit = {
3400+ scope.launch {
34053401 try {
34063402 printlntid(" on dispatcher" )
34073403 realm_wrapper.realm_scheduler_perform_work(scheduler)
@@ -3411,11 +3407,6 @@ actual object RealmInterop {
34113407 e.printStackTrace()
34123408 }
34133409 }
3414- scope.launch(
3415- scope.coroutineContext,
3416- CoroutineStart .DEFAULT ,
3417- function
3418- )
34193410 }
34203411 }
34213412}
0 commit comments