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