• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download

<lambda>null1 package kotlinx.coroutines
2 
3 import kotlinx.coroutines.selects.*
4 import kotlin.coroutines.*
5 import kotlin.time.*
6 import kotlin.time.Duration.Companion.nanoseconds
7 
8 /**
9  * This dispatcher _feature_ is implemented by [CoroutineDispatcher] implementations that natively support
10  * scheduled execution of tasks.
11  *
12  * Implementation of this interface affects operation of
13  * [delay][kotlinx.coroutines.delay] and [withTimeout] functions.
14  *
15  * @suppress **This an internal API and should not be used from general code.**
16  */
17 @InternalCoroutinesApi
18 public interface Delay {
19 
20     /** @suppress **/
21     @Deprecated(
22         message = "Deprecated without replacement as an internal method never intended for public use",
23         level = DeprecationLevel.ERROR
24     ) // Error since 1.6.0
25     public suspend fun delay(time: Long) {
26         if (time <= 0) return // don't delay
27         return suspendCancellableCoroutine { scheduleResumeAfterDelay(time, it) }
28     }
29 
30     /**
31      * Schedules resume of a specified [continuation] after a specified delay [timeMillis].
32      *
33      * Continuation **must be scheduled** to resume even if it is already cancelled, because a cancellation is just
34      * an exception that the coroutine that used `delay` might wanted to catch and process. It might
35      * need to close some resources in its `finally` blocks, for example.
36      *
37      * This implementation is supposed to use dispatcher's native ability for scheduled execution in its thread(s).
38      * In order to avoid an extra delay of execution, the following code shall be used to resume this
39      * [continuation] when the code is already executing in the appropriate thread:
40      *
41      * ```kotlin
42      * with(continuation) { resumeUndispatchedWith(Unit) }
43      * ```
44      */
45     public fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>)
46 
47     /**
48      * Schedules invocation of a specified [block] after a specified delay [timeMillis].
49      * The resulting [DisposableHandle] can be used to [dispose][DisposableHandle.dispose] of this invocation
50      * request if it is not needed anymore.
51      */
52     public fun invokeOnTimeout(timeMillis: Long, block: Runnable, context: CoroutineContext): DisposableHandle =
53         DefaultDelay.invokeOnTimeout(timeMillis, block, context)
54 }
55 
56 /**
57  * Enhanced [Delay] interface that provides additional diagnostics for [withTimeout].
58  * Is going to be removed once there is proper JVM-default support.
59  * Then we'll be able put this function into [Delay] without breaking binary compatibility.
60  */
61 @InternalCoroutinesApi
62 internal interface DelayWithTimeoutDiagnostics : Delay {
63     /**
64      * Returns a string that explains that the timeout has occurred, and explains what can be done about it.
65      */
timeoutMessagenull66     fun timeoutMessage(timeout: Duration): String
67 }
68 
69 /**
70  * Suspends until cancellation, in which case it will throw a [CancellationException].
71  *
72  * This function returns [Nothing], so it can be used in any coroutine,
73  * regardless of the required return type.
74  *
75  * Usage example in callback adapting code:
76  *
77  * ```kotlin
78  * fun currentTemperature(): Flow<Temperature> = callbackFlow {
79  *     val callback = SensorCallback { degreesCelsius: Double ->
80  *         trySend(Temperature.celsius(degreesCelsius))
81  *     }
82  *     try {
83  *         registerSensorCallback(callback)
84  *         awaitCancellation() // Suspends to keep getting updates until cancellation.
85  *     } finally {
86  *         unregisterSensorCallback(callback)
87  *     }
88  * }
89  * ```
90  *
91  * Usage example in (non declarative) UI code:
92  *
93  * ```kotlin
94  * suspend fun showStuffUntilCancelled(content: Stuff): Nothing {
95  *     someSubView.text = content.title
96  *     anotherSubView.text = content.description
97  *     someView.visibleInScope {
98  *         awaitCancellation() // Suspends so the view stays visible.
99  *     }
100  * }
101  * ```
102  */
103 public suspend fun awaitCancellation(): Nothing = suspendCancellableCoroutine {}
104 
105 /**
106  * Delays coroutine for at least the given time without blocking a thread and resumes it after a specified time.
107  * If the given [timeMillis] is non-positive, this function returns immediately.
108  *
109  * This suspending function is cancellable: if the [Job] of the current coroutine is cancelled while this
110  * suspending function is waiting, this function immediately resumes with [CancellationException].
111  * There is a **prompt cancellation guarantee**: even if this function is ready to return the result, but was cancelled
112  * while suspended, [CancellationException] will be thrown. See [suspendCancellableCoroutine] for low-level details.
113  *
114  * If you want to delay forever (until cancellation), consider using [awaitCancellation] instead.
115  *
116  * Note that delay can be used in [select] invocation with [onTimeout][SelectBuilder.onTimeout] clause.
117  *
118  * Implementation note: how exactly time is tracked is an implementation detail of [CoroutineDispatcher] in the context.
119  * @param timeMillis time in milliseconds.
120  */
delaynull121 public suspend fun delay(timeMillis: Long) {
122     if (timeMillis <= 0) return // don't delay
123     return suspendCancellableCoroutine sc@ { cont: CancellableContinuation<Unit> ->
124         // if timeMillis == Long.MAX_VALUE then just wait forever like awaitCancellation, don't schedule.
125         if (timeMillis < Long.MAX_VALUE) {
126             cont.context.delay.scheduleResumeAfterDelay(timeMillis, cont)
127         }
128     }
129 }
130 
131 /**
132  * Delays coroutine for at least the given [duration] without blocking a thread and resumes it after the specified time.
133  * If the given [duration] is non-positive, this function returns immediately.
134  *
135  * This suspending function is cancellable: if the [Job] of the current coroutine is cancelled while this
136  * suspending function is waiting, this function immediately resumes with [CancellationException].
137  * There is a **prompt cancellation guarantee**: even if this function is ready to return the result, but was cancelled
138  * while suspended, [CancellationException] will be thrown. See [suspendCancellableCoroutine] for low-level details.
139  *
140  * If you want to delay forever (until cancellation), consider using [awaitCancellation] instead.
141  *
142  * Note that delay can be used in [select] invocation with [onTimeout][SelectBuilder.onTimeout] clause.
143  *
144  * Implementation note: how exactly time is tracked is an implementation detail of [CoroutineDispatcher] in the context.
145  */
delaynull146 public suspend fun delay(duration: Duration): Unit = delay(duration.toDelayMillis())
147 
148 /** Returns [Delay] implementation of the given context */
149 internal val CoroutineContext.delay: Delay get() = get(ContinuationInterceptor) as? Delay ?: DefaultDelay
150 
151 /**
152  * Convert this duration to its millisecond value. Durations which have a nanosecond component less than
153  * a single millisecond will be rounded up to the next largest millisecond.
154  */
155 internal fun Duration.toDelayMillis(): Long = when (isPositive()) {
156     true -> plus(999_999L.nanoseconds).inWholeMilliseconds
157     false -> 0L
158 }
159