• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright 2016-2020 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.coroutines.internal.*
8 import kotlinx.coroutines.scheduling.*
9 import java.util.concurrent.atomic.*
10 import kotlin.coroutines.*
11 
12 internal const val COROUTINES_SCHEDULER_PROPERTY_NAME = "kotlinx.coroutines.scheduler"
13 
14 internal val useCoroutinesScheduler = systemProp(COROUTINES_SCHEDULER_PROPERTY_NAME).let { value ->
15     when (value) {
16         null, "", "on" -> true
17         "off" -> false
18         else -> error("System property '$COROUTINES_SCHEDULER_PROPERTY_NAME' has unrecognized value '$value'")
19     }
20 }
21 
createDefaultDispatchernull22 internal actual fun createDefaultDispatcher(): CoroutineDispatcher =
23     if (useCoroutinesScheduler) DefaultScheduler else CommonPool
24 
25 /**
26  * Creates context for the new coroutine. It installs [Dispatchers.Default] when no other dispatcher nor
27  * [ContinuationInterceptor] is specified, and adds optional support for debugging facilities (when turned on).
28  *
29  * See [DEBUG_PROPERTY_NAME] for description of debugging facilities on JVM.
30  */
31 @ExperimentalCoroutinesApi
32 public actual fun CoroutineScope.newCoroutineContext(context: CoroutineContext): CoroutineContext {
33     val combined = coroutineContext + context
34     val debug = if (DEBUG) combined + CoroutineId(COROUTINE_ID.incrementAndGet()) else combined
35     return if (combined !== Dispatchers.Default && combined[ContinuationInterceptor] == null)
36         debug + Dispatchers.Default else debug
37 }
38 
39 /**
40  * Executes a block using a given coroutine context.
41  */
withCoroutineContextnull42 internal actual inline fun <T> withCoroutineContext(context: CoroutineContext, countOrElement: Any?, block: () -> T): T {
43     val oldValue = updateThreadContext(context, countOrElement)
44     try {
45         return block()
46     } finally {
47         restoreThreadContext(context, oldValue)
48     }
49 }
50 
51 internal actual val CoroutineContext.coroutineName: String? get() {
52     if (!DEBUG) return null
53     val coroutineId = this[CoroutineId] ?: return null
54     val coroutineName = this[CoroutineName]?.name ?: "coroutine"
55     return "$coroutineName#${coroutineId.id}"
56 }
57 
58 private const val DEBUG_THREAD_NAME_SEPARATOR = " @"
59 
60 internal data class CoroutineId(
61     val id: Long
62 ) : ThreadContextElement<String>, AbstractCoroutineContextElement(CoroutineId) {
63     companion object Key : CoroutineContext.Key<CoroutineId>
toStringnull64     override fun toString(): String = "CoroutineId($id)"
65 
66     override fun updateThreadContext(context: CoroutineContext): String {
67         val coroutineName = context[CoroutineName]?.name ?: "coroutine"
68         val currentThread = Thread.currentThread()
69         val oldName = currentThread.name
70         var lastIndex = oldName.lastIndexOf(DEBUG_THREAD_NAME_SEPARATOR)
71         if (lastIndex < 0) lastIndex = oldName.length
72         currentThread.name = buildString(lastIndex + coroutineName.length + 10) {
73             append(oldName.substring(0, lastIndex))
74             append(DEBUG_THREAD_NAME_SEPARATOR)
75             append(coroutineName)
76             append('#')
77             append(id)
78         }
79         return oldName
80     }
81 
restoreThreadContextnull82     override fun restoreThreadContext(context: CoroutineContext, oldState: String) {
83         Thread.currentThread().name = oldState
84     }
85 }
86