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