• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3  */
4 
5 package kotlinx.coroutines
6 
7 import kotlinx.cinterop.*
8 import platform.CoreFoundation.*
9 import platform.darwin.*
10 import kotlin.coroutines.*
11 import kotlin.native.concurrent.*
12 import kotlin.native.internal.NativePtr
13 
isMainThreadnull14 internal fun isMainThread(): Boolean = CFRunLoopGetCurrent() == CFRunLoopGetMain()
15 
16 internal actual fun createMainDispatcher(default: CoroutineDispatcher): MainCoroutineDispatcher = DarwinMainDispatcher(false)
17 
18 internal actual fun createDefaultDispatcher(): CoroutineDispatcher = DarwinGlobalQueueDispatcher
19 
20 private object DarwinGlobalQueueDispatcher : CoroutineDispatcher() {
21     override fun dispatch(context: CoroutineContext, block: Runnable) {
22         autoreleasepool {
23             dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT.convert(), 0u)) {
24                 block.run()
25             }
26         }
27     }
28 }
29 
30 private class DarwinMainDispatcher(
31     private val invokeImmediately: Boolean
32 ) : MainCoroutineDispatcher(), Delay {
33 
34     override val immediate: MainCoroutineDispatcher =
35         if (invokeImmediately) this else DarwinMainDispatcher(true)
36 
isDispatchNeedednull37     override fun isDispatchNeeded(context: CoroutineContext): Boolean = !(invokeImmediately && isMainThread())
38 
39     override fun dispatch(context: CoroutineContext, block: Runnable) {
40         autoreleasepool {
41             dispatch_async(dispatch_get_main_queue()) {
42                 block.run()
43             }
44         }
45     }
46 
scheduleResumeAfterDelaynull47     override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) {
48         val timer = Timer()
49         val timerBlock: TimerBlock = {
50             timer.dispose()
51             continuation.resume(Unit)
52         }
53         timer.start(timeMillis, timerBlock)
54         continuation.disposeOnCancellation(timer)
55     }
56 
invokeOnTimeoutnull57     override fun invokeOnTimeout(timeMillis: Long, block: Runnable, context: CoroutineContext): DisposableHandle {
58         val timer = Timer()
59         val timerBlock: TimerBlock = {
60             timer.dispose()
61             block.run()
62         }
63         timer.start(timeMillis, timerBlock)
64         return timer
65     }
66 
toStringnull67     override fun toString(): String =
68         "MainDispatcher${ if(invokeImmediately) "[immediate]" else "" }"
69 }
70 
71 private typealias TimerBlock = (CFRunLoopTimerRef?) -> Unit
72 
73 private val TIMER_NEW = NativePtr.NULL
74 private val TIMER_DISPOSED = NativePtr.NULL.plus(1)
75 
76 private class Timer : DisposableHandle {
77     private val ref = AtomicNativePtr(TIMER_NEW)
78 
79     fun start(timeMillis: Long, timerBlock: TimerBlock) {
80         val fireDate = CFAbsoluteTimeGetCurrent() + timeMillis / 1000.0
81         val timer = CFRunLoopTimerCreateWithHandler(null, fireDate, 0.0, 0u, 0, timerBlock)
82         CFRunLoopAddTimer(CFRunLoopGetMain(), timer, kCFRunLoopCommonModes)
83         if (!ref.compareAndSet(TIMER_NEW, timer.rawValue)) {
84             // dispose was already called concurrently
85             release(timer)
86         }
87     }
88 
89     override fun dispose() {
90         while (true) {
91             val ptr = ref.value
92             if (ptr == TIMER_DISPOSED) return
93             if (ref.compareAndSet(ptr, TIMER_DISPOSED)) {
94                 if (ptr != TIMER_NEW) release(interpretCPointer(ptr))
95                 return
96             }
97         }
98     }
99 
100     private fun release(timer: CFRunLoopTimerRef?) {
101         CFRunLoopRemoveTimer(CFRunLoopGetMain(), timer, kCFRunLoopCommonModes)
102         CFRelease(timer)
103     }
104 }
105 
<lambda>null106 internal actual inline fun platformAutoreleasePool(crossinline block: () -> Unit): Unit = autoreleasepool { block() }
107