• 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.scheduling
6 
7 import kotlinx.coroutines.*
8 import kotlinx.coroutines.internal.*
9 import java.util.concurrent.*
10 
11 
12 /**
13  * The name of the default scheduler. The names of the worker threads of [Dispatchers.Default] have it as their prefix.
14  */
15 @JvmField
16 internal val DEFAULT_SCHEDULER_NAME = systemProp(
17     "kotlinx.coroutines.scheduler.default.name", "DefaultDispatcher"
18 )
19 
20 // 100us as default
21 @JvmField
22 internal val WORK_STEALING_TIME_RESOLUTION_NS = systemProp(
23     "kotlinx.coroutines.scheduler.resolution.ns", 100000L
24 )
25 
26 /**
27  * The maximum number of threads allocated for CPU-bound tasks at the default set of dispatchers.
28  *
29  * NOTE: we coerce default to at least two threads to give us chances that multi-threading problems
30  * get reproduced even on a single-core machine, but support explicit setting of 1 thread scheduler if needed
31  */
32 @JvmField
33 internal val CORE_POOL_SIZE = systemProp(
34     "kotlinx.coroutines.scheduler.core.pool.size",
35     AVAILABLE_PROCESSORS.coerceAtLeast(2),
36     minValue = CoroutineScheduler.MIN_SUPPORTED_POOL_SIZE
37 )
38 
39 /** The maximum number of threads allocated for blocking tasks at the default set of dispatchers. */
40 @JvmField
41 internal val MAX_POOL_SIZE = systemProp(
42     "kotlinx.coroutines.scheduler.max.pool.size",
43     CoroutineScheduler.MAX_SUPPORTED_POOL_SIZE,
44     maxValue = CoroutineScheduler.MAX_SUPPORTED_POOL_SIZE
45 )
46 
47 @JvmField
48 internal val IDLE_WORKER_KEEP_ALIVE_NS = TimeUnit.SECONDS.toNanos(
49     systemProp("kotlinx.coroutines.scheduler.keep.alive.sec", 60L)
50 )
51 
52 @JvmField
53 internal var schedulerTimeSource: SchedulerTimeSource = NanoTimeSource
54 
55 /**
56  * Marker indicating that task is CPU-bound and will not block
57  */
58 internal const val TASK_NON_BLOCKING = 0
59 
60 /**
61  * Marker indicating that task may potentially block, thus giving scheduler a hint that additional thread may be required
62  */
63 internal const val TASK_PROBABLY_BLOCKING = 1
64 
65 internal interface TaskContext {
66     val taskMode: Int // TASK_XXX
afterTasknull67     fun afterTask()
68 }
69 
70 private class TaskContextImpl(override val taskMode: Int): TaskContext {
71     override fun afterTask() {
72         // Nothing for non-blocking context
73     }
74 }
75 
76 @JvmField
77 internal val NonBlockingContext: TaskContext = TaskContextImpl(TASK_NON_BLOCKING)
78 
79 @JvmField
80 internal val BlockingContext: TaskContext = TaskContextImpl(TASK_PROBABLY_BLOCKING)
81 
82 @PublishedApi
83 internal abstract class Task internal constructor(
84     // Used by the IDEA debugger via reflection and must be kept binary-compatible, see KTIJ-24102
85     @JvmField var submissionTime: Long,
86     // Used by the IDEA debugger via reflection and must be kept binary-compatible, see KTIJ-24102
87     @JvmField internal var taskContext: TaskContext
88 ) : Runnable {
89     internal constructor() : this(0, NonBlockingContext)
90     internal inline val mode: Int get() = taskContext.taskMode // TASK_XXX
91 }
92 
93 internal inline val Task.isBlocking get() = taskContext.taskMode == TASK_PROBABLY_BLOCKING
94 
95 // Non-reusable Task implementation to wrap Runnable instances that do not otherwise implement task
96 internal class TaskImpl(
97     @JvmField val block: Runnable,
98     submissionTime: Long,
99     taskContext: TaskContext
100 ) : Task(submissionTime, taskContext) {
runnull101     override fun run() {
102         try {
103             block.run()
104         } finally {
105             taskContext.afterTask()
106         }
107     }
108 
toStringnull109     override fun toString(): String =
110         "Task[${block.classSimpleName}@${block.hexAddress}, $submissionTime, $taskContext]"
111 }
112 
113 // Open for tests
114 internal class GlobalQueue : LockFreeTaskQueue<Task>(singleConsumer = false)
115 
116 // Was previously TimeSource, renamed due to KT-42625 and KT-23727
117 internal abstract class SchedulerTimeSource {
118     abstract fun nanoTime(): Long
119 }
120 
121 internal object NanoTimeSource : SchedulerTimeSource() {
nanoTimenull122     override fun nanoTime() = System.nanoTime()
123 }
124