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