//===----------------------------------------------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2020-2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import Swift @_implementationOnly import SwiftConcurrencyInternalShims // ==== Task.immediate --------------------------------------------------------- % METHOD_VARIANTS = [ % 'THROWING', % 'NON_THROWING', % ] % OPERATION_PARAM = '@_inheritActorContext @_implicitSelfCapture _ operation: __owned @Sendable @escaping () async throws -> Success' % for METHOD_VARIANT in METHOD_VARIANTS: % IS_THROWING = METHOD_VARIANT == 'THROWING' % if IS_THROWING: % FAILURE_TYPE = 'Error' % else: % FAILURE_TYPE = 'Never' % end @available(SwiftStdlib 6.2, *) extension Task where Failure == ${FAILURE_TYPE} { @available(SwiftStdlib 6.2, *) @available(*, deprecated, renamed: "immediate") @discardableResult public static func startSynchronously( name: String? = nil, priority: TaskPriority? = nil, @_implicitSelfCapture @_inheritActorContext(always) _ operation: sending @isolated(any) @escaping () async throws -> Success ) -> Task { immediate(name: name, priority: priority, operation: operation) } /// Create and immediately start running a new task in the context of the calling thread/task. /// /// This function _starts_ the created task on the calling context. /// The task will continue executing on the caller's context until it suspends, /// and after suspension will resume on the adequate executor. For a nonisolated /// operation this means running on the global concurrent pool, and on an isolated /// operation it means the appropriate executor of that isolation context. /// /// As indicated by the lack of `async` on this method, this method does _not_ /// suspend, and instead takes over the calling task's (thread's) execution in /// a synchronous manner. /// /// Other than the execution semantics discussed above, the created task /// is semantically equivalent to its basic version which can be /// created using ``Task/init``. /// /// - Parameters: /// - name: The high-level human-readable name given for this task /// - priority: The priority of the task. /// Pass `nil` to use the ``Task/basePriority`` of the current task (if there is one). /// - operation: the operation to be run immediately upon entering the task. /// - Returns: A reference to the unstructured task which may be awaited on. @available(SwiftStdlib 6.2, *) @_alwaysEmitIntoClient @discardableResult public static func immediate( name: String? = nil, priority: TaskPriority? = nil, % # NOTE: This closure cannot be 'sending' because we'll trigger ' pattern that the region based isolation checker does not understand how to check' % # In this case: `func syncOnMyGlobalActor() { Task.immediate { @MyGlobalActor in } }` @_implicitSelfCapture @_inheritActorContext(always) operation: sending @isolated(any) @escaping () async throws -> Success ) -> Task { let builtinSerialExecutor = unsafe Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor // Determine if we're switching isolation dynamically. // If not, we can run the task synchronously and therefore MUST NOT "enqueue" it. let flagsMustNotCrash: UInt64 = 0 let canRunSynchronously: Bool = if let builtinSerialExecutor { _taskIsCurrentExecutor(executor: builtinSerialExecutor, flags: flagsMustNotCrash) } else { true // if there is not target executor, we can run synchronously } let flags = taskCreateFlags( priority: priority, isChildTask: false, copyTaskLocals: true, inheritContext: true, enqueueJob: !canRunSynchronously, addPendingGroupTaskUnconditionally: false, isDiscardingTask: false, isSynchronousStart: true ) var task: Builtin.NativeObject? #if $BuiltinCreateAsyncTaskName if let name { task = unsafe name.utf8CString.withUnsafeBufferPointer { nameBytes in Builtin.createTask( flags: flags, initialSerialExecutor: builtinSerialExecutor, taskName: nameBytes.baseAddress!._rawValue, operation: operation).0 } } #endif if task == nil { // either no task name was set, or names are unsupported task = Builtin.createTask( flags: flags, operation: operation).0 } if canRunSynchronously { _startTaskImmediately(task!, targetExecutor: builtinSerialExecutor) } return Task(task!) } } %end %{ GROUP_AND_OP_INFO = [ ( 'TaskGroup', [ 'addImmediateTask', 'addImmediateTaskUnlessCancelled' ], '', 'ChildTaskResult' ), ( 'ThrowingTaskGroup', [ 'addImmediateTask', 'addImmediateTaskUnlessCancelled' ], 'throws ', 'ChildTaskResult' ), ( 'DiscardingTaskGroup', [ 'addImmediateTask', 'addImmediateTaskUnlessCancelled' ], '', 'Void' ), ( 'ThrowingDiscardingTaskGroup', [ 'addImmediateTask', 'addImmediateTaskUnlessCancelled' ], 'throws ', 'Void' ), ] }% % for (GROUP_TYPE, METHOD_NAMES, THROWS, RESULT_TYPE) in GROUP_AND_OP_INFO: % for METHOD_NAME in METHOD_NAMES: @available(SwiftStdlib 6.2, *) extension ${GROUP_TYPE} { /// Create and immediately start running a new child task in the context of the calling thread/task. /// /// This function _starts_ the created task on the calling context. /// The task will continue executing on the caller's context until it suspends, /// and after suspension will resume on the adequate executor. For a nonisolated /// operation this means running on the global concurrent pool, and on an isolated /// operation it means the appropriate executor of that isolation context. /// /// As indicated by the lack of `async` on this method, this method does _not_ /// suspend, and instead takes over the calling task's (thread's) execution in /// a synchronous manner. /// /// Other than the execution semantics discussed above, the created task /// is semantically equivalent to its basic version which can be /// created using ``${GROUP_TYPE}/addTask``. @available(SwiftStdlib 6.2, *) @_alwaysEmitIntoClient public func ${METHOD_NAME}( // in ${GROUP_TYPE} name: String? = nil, priority: TaskPriority? = nil, @_inheritActorContext @_implicitSelfCapture operation: sending @isolated(any) @escaping () async ${THROWS}-> ${RESULT_TYPE} ) { let flags = taskCreateFlags( priority: priority, isChildTask: true, copyTaskLocals: false, inheritContext: false, enqueueJob: false, // don't enqueue, we'll run it manually addPendingGroupTaskUnconditionally: true, isDiscardingTask: ${'true' if 'Discarding' in GROUP_TYPE else 'false'}, isSynchronousStart: true ) // Create the asynchronous task. let builtinSerialExecutor = unsafe Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor // Create the task in this group. let (task, _) = Builtin.createTask( flags: flags, initialSerialExecutor: builtinSerialExecutor, taskGroup: self._group, operation: operation ) _startTaskImmediately(task, targetExecutor: builtinSerialExecutor) } } % end # METHOD_NAMES %end # GROUP_TYPES // ==== Legacy SPI ------------------------------------------------------------- % METHOD_VARIANTS = [ % 'THROWING', % 'NON_THROWING', % ] % OPERATION_PARAM = '@_inheritActorContext @_implicitSelfCapture _ operation: __owned @Sendable @escaping @MainActor () async throws -> Success' % for METHOD_VARIANT in METHOD_VARIANTS: % IS_THROWING = METHOD_VARIANT == 'THROWING' % if IS_THROWING: % FAILURE_TYPE = 'Error' % else: % FAILURE_TYPE = 'Never' % OPERATION_PARAM = OPERATION_PARAM.replace('throws', '') % end #if !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY && !SWIFT_CONCURRENCY_EMBEDDED @available(SwiftStdlib 5.9, *) extension Task where Failure == ${FAILURE_TYPE} { @_spi(MainActorUtilities) @MainActor @available(SwiftStdlib 5.9, *) @discardableResult public static func startOnMainActor( priority: TaskPriority? = nil, ${OPERATION_PARAM} ) -> Task { let flags = taskCreateFlags( priority: priority, isChildTask: false, copyTaskLocals: true, inheritContext: true, enqueueJob: false, addPendingGroupTaskUnconditionally: false, isDiscardingTask: false, isSynchronousStart: false ) let (task, _) = Builtin.createAsyncTask(flags, operation) _startTaskOnMainActor(task) return Task(task) } } #endif % end // Internal Runtime Functions -------------------------------------------------- @_silgen_name("swift_task_startOnMainActor") internal func _startTaskOnMainActor(_ task: Builtin.NativeObject) @available(SwiftStdlib 6.2, *) @_silgen_name("swift_task_immediate") @usableFromInline internal func _startTaskImmediately(_ task: Builtin.NativeObject, targetExecutor: Builtin.Executor?)