//===----------------------------------------------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2020 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 ------------------------------------------------------------------- /// A unit of asynchronous work. /// /// When you create an instance of `Task`, /// you provide a closure that contains the work for that task to perform. /// Tasks can start running immediately after creation; /// you don't explicitly start or schedule them. /// After creating a task, you use the instance to interact with it --- /// for example, to wait for it to complete or to cancel it. /// It's not a programming error to discard a reference to a task /// without waiting for that task to finish or canceling it. /// A task runs regardless of whether you keep a reference to it. /// However, if you discard the reference to a task, /// you give up the ability /// to wait for that task's result or cancel the task. /// /// To support operations on the current task, /// which can be either a detached task or child task, /// `Task` also exposes class methods like `yield()`. /// Because these methods are asynchronous, /// they're always invoked as part of an existing task. /// /// Only code that's running as part of the task can interact with that task. /// To interact with the current task, /// you call one of the static methods on `Task`. /// /// A task's execution can be seen as a series of periods where the task ran. /// Each such period ends at a suspension point or the /// completion of the task. /// These periods of execution are represented by instances of `PartialAsyncTask`. /// Unless you're implementing a custom executor, /// you don't directly interact with partial tasks. /// /// For information about the language-level concurrency model that `Task` is part of, /// see [Concurrency][concurrency] in [The Swift Programming Language][tspl]. /// /// [concurrency]: https://docs.swift.org/swift-book/LanguageGuide/Concurrency.html /// [tspl]: https://docs.swift.org/swift-book/ /// /// Task Cancellation /// ================= /// /// Tasks include a shared mechanism for indicating cancellation, /// but not a shared implementation for how to handle cancellation. /// Depending on the work you're doing in the task, /// the correct way to stop that work varies. /// Likewise, /// it's the responsibility of the code running as part of the task /// to check for cancellation whenever stopping is appropriate. /// In a long-task that includes multiple pieces, /// you might need to check for cancellation at several points, /// and handle cancellation differently at each point. /// If you only need to throw an error to stop the work, /// call the `Task.checkCancellation()` function to check for cancellation. /// Other responses to cancellation include /// returning the work completed so far, returning an empty result, or returning `nil`. /// /// Cancellation is a purely Boolean state; /// there's no way to include additional information /// like the reason for cancellation. /// This reflects the fact that a task can be canceled for many reasons, /// and additional reasons can accrue during the cancellation process. /// /// ### Task closure lifetime /// Tasks are initialized by passing a closure containing the code that will be executed by a given task. /// /// After this code has run to completion, the task has completed, resulting in either /// a failure or result value, this closure is eagerly released. /// /// Retaining a task object doesn't indefinitely retain the closure, /// because any references that a task holds are released /// after the task completes. /// Consequently, tasks rarely need to capture weak references to values. /// /// For example, in the following snippet of code it is not necessary to capture the actor as `weak`, /// because as the task completes it'll let go of the actor reference, breaking the /// reference cycle between the Task and the actor holding it. /// /// ``` /// struct Work: Sendable {} /// /// actor Worker { /// var work: Task? /// var result: Work? /// /// deinit { /// // even though the task is still retained, /// // once it completes it no longer causes a reference cycle with the actor /// /// print("deinit actor") /// } /// /// func start() { /// work = Task { /// print("start task work") /// try? await Task.sleep(for: .seconds(3)) /// self.result = Work() // we captured self /// print("completed task work") /// // but as the task completes, this reference is released /// } /// // we keep a strong reference to the task /// } /// } /// ``` /// /// And using it like this: /// /// ``` /// await Worker().start() /// ``` /// /// Note that the actor is only retained by the start() method's use of `self`, /// and that the start method immediately returns, without waiting for the /// unstructured `Task` to finish. Once the task is completed and its closure is /// destroyed, the strong reference to the actor is also released allowing the /// actor to deinitialize as expected. /// /// Therefore, the above call will consistently result in the following output: /// /// ```other /// start task work /// completed task work /// deinit actor /// ``` @available(SwiftStdlib 5.1, *) @frozen public struct Task: Sendable { @usableFromInline internal let _task: Builtin.NativeObject @_alwaysEmitIntoClient internal init(_ task: Builtin.NativeObject) { self._task = task } } @available(SwiftStdlib 5.1, *) extension Task { /// The result from a throwing task, after it completes. /// /// If the task hasn't completed, /// accessing this property waits for it to complete /// and its priority increases to that of the current task. /// Note that this might not be as effective as /// creating the task with the correct priority, /// depending on the executor's scheduling details. /// /// If the task throws an error, this property propagates that error. /// Tasks that respond to cancellation by throwing `CancellationError` /// have that error propagated here upon cancellation. /// /// - Returns: The task's result. public var value: Success { get async throws { return try await _taskFutureGetThrowing(_task) } } /// The result or error from a throwing task, after it completes. /// /// If the task hasn't completed, /// accessing this property waits for it to complete /// and its priority increases to that of the current task. /// Note that this might not be as effective as /// creating the task with the correct priority, /// depending on the executor's scheduling details. /// /// - Returns: If the task succeeded, /// `.success` with the task's result as the associated value; /// otherwise, `.failure` with the error as the associated value. public var result: Result { get async { do { return .success(try await value) } catch { return .failure(error as! Failure) // as!-safe, guaranteed to be Failure } } } /// Cancels this task. /// /// Cancelling a task has three primary effects: /// /// - It flags the task as canceled. /// - It causes any active cancellation handlers on the task to run, once. /// - It cancels any child tasks and task groups of the task, including /// those created in the future. If those tasks have cancellation handlers, /// they also are triggered. /// /// Task cancellation is cooperative and idempotent. /// /// Cancelling a task does not automatically cause arbitrary functions on the task /// to stop running or throw errors. A function _may_ choose to react /// to cancellation by ending its work early, and it is conventional to /// signal that to callers by throwing `CancellationError`. However, /// a function that doesn't specifically check for cancellation will /// run to completion normally, even if the task it is running on is /// canceled. However, that function might still end early if it calls /// other code that handles cancellation by throwing and that function doesn't /// handle the error. /// /// It's safe to cancel a task from any task or thread. It's safe for /// multiple tasks or threads to cancel the same task at the same /// time. Cancelling a task that has already been canceled has no /// additional effect. /// /// `cancel` may need to acquire locks and synchronously run /// arbitrary cancellation-handler code associated with the /// canceled task. To reduce the risk of deadlock, it is /// recommended that callers release any locks they might be /// holding before they call cancel. /// /// If the task has already run past the last point where it could have /// performed a cancellation check, cancelling it may have no observable effects. /// /// - SeeAlso: `Task.checkCancellation()` /// - SeeAlso: `withTaskCancellationHandler(operation:onCancel:isolation:)` public func cancel() { Builtin.cancelAsyncTask(_task) } } @available(SwiftStdlib 5.1, *) extension Task where Failure == Never { /// The result from a nonthrowing task, after it completes. /// /// If the task hasn't completed yet, /// accessing this property waits for it to complete /// and its priority increases to that of the current task. /// Note that this might not be as effective as /// creating the task with the correct priority, /// depending on the executor's scheduling details. /// /// Tasks that never throw an error can still check for cancellation, /// but they need to use an approach like returning `nil` /// instead of throwing an error. public var value: Success { get async { return await _taskFutureGet(_task) } } } @available(SwiftStdlib 5.1, *) extension Task: Hashable { public func hash(into hasher: inout Hasher) { UnsafeRawPointer(Builtin.bridgeToRawPointer(_task)).hash(into: &hasher) } } @available(SwiftStdlib 5.1, *) extension Task: Equatable { public static func ==(lhs: Self, rhs: Self) -> Bool { unsafe UnsafeRawPointer(Builtin.bridgeToRawPointer(lhs._task)) == UnsafeRawPointer(Builtin.bridgeToRawPointer(rhs._task)) } } // ==== Task Priority ---------------------------------------------------------- /// The priority of a task. /// /// The executor determines how priority information affects the way tasks are scheduled. /// The behavior varies depending on the executor currently being used. /// Typically, executors attempt to run tasks with a higher priority /// before tasks with a lower priority. /// However, the semantics of how priority is treated are left up to each /// platform and `Executor` implementation. /// /// Child tasks automatically inherit their parent task's priority. /// Detached tasks created by `detach(priority:operation:)` don't inherit task priority /// because they aren't attached to the current task. /// /// In some situations the priority of a task is elevated --- /// that is, the task is treated as it if had a higher priority, /// without actually changing the priority of the task: /// /// - If a task runs on behalf of an actor, /// and a new higher-priority task is enqueued to the actor, /// then the actor's current task is temporarily elevated /// to the priority of the enqueued task. /// This priority elevation allows the new task /// to be processed at the priority it was enqueued with. /// - If a higher-priority task calls the `get()` method, /// then the priority of this task increases until the task completes. /// /// In both cases, priority elevation helps you prevent a low-priority task /// from blocking the execution of a high priority task, /// which is also known as *priority inversion*. @available(SwiftStdlib 5.1, *) public struct TaskPriority: RawRepresentable, Sendable { public typealias RawValue = UInt8 public var rawValue: UInt8 public init(rawValue: UInt8) { self.rawValue = rawValue } public static let high: TaskPriority = .init(rawValue: 0x19) @_alwaysEmitIntoClient public static var medium: TaskPriority { .init(rawValue: 0x15) } public static let low: TaskPriority = .init(rawValue: 0x11) public static let userInitiated: TaskPriority = high public static let utility: TaskPriority = low public static let background: TaskPriority = .init(rawValue: 0x09) @available(*, deprecated, renamed: "medium") public static let `default`: TaskPriority = .init(rawValue: 0x15) } @available(SwiftStdlib 5.1, *) extension TaskPriority: Equatable { public static func == (lhs: TaskPriority, rhs: TaskPriority) -> Bool { lhs.rawValue == rhs.rawValue } public static func != (lhs: TaskPriority, rhs: TaskPriority) -> Bool { lhs.rawValue != rhs.rawValue } } @available(SwiftStdlib 5.1, *) extension TaskPriority: Comparable { public static func < (lhs: TaskPriority, rhs: TaskPriority) -> Bool { lhs.rawValue < rhs.rawValue } public static func <= (lhs: TaskPriority, rhs: TaskPriority) -> Bool { lhs.rawValue <= rhs.rawValue } public static func > (lhs: TaskPriority, rhs: TaskPriority) -> Bool { lhs.rawValue > rhs.rawValue } public static func >= (lhs: TaskPriority, rhs: TaskPriority) -> Bool { lhs.rawValue >= rhs.rawValue } } @available(SwiftStdlib 5.9, *) @_unavailableInEmbedded extension TaskPriority: CustomStringConvertible { @available(SwiftStdlib 5.9, *) public var description: String { switch self.rawValue { case Self.low.rawValue: return "\(Self.self).low" case Self.medium.rawValue: return "\(Self.self).medium" case Self.high.rawValue: return "\(Self.self).high" case Self.background.rawValue: return "\(Self.self).background" default: return "\(Self.self)(rawValue: \(self.rawValue))" } } } #if !SWIFT_CONCURRENCY_EMBEDDED @available(SwiftStdlib 5.1, *) extension TaskPriority: Codable { } #endif @available(SwiftStdlib 5.1, *) extension Task where Success == Never, Failure == Never { /// The current task's priority. /// /// If you access this property outside of any task, /// this queries the system to determine the /// priority at which the current function is running. /// If the system can't provide a priority, /// this property's value is `Priority.default`. public static var currentPriority: TaskPriority { unsafe withUnsafeCurrentTask { unsafeTask in // If we are running on behalf of a task, use that task's priority. if let unsafeTask = unsafe unsafeTask { return unsafe unsafeTask.priority } // Otherwise, query the system. return TaskPriority(rawValue: UInt8(_getCurrentThreadPriority())) } } /// The current task's base priority. /// /// If you access this property outside of any task, this returns nil @available(SwiftStdlib 5.7, *) public static var basePriority: TaskPriority? { unsafe withUnsafeCurrentTask { task in // If we are running on behalf of a task, use that task's priority. if let unsafeTask = unsafe task { return unsafe TaskPriority(rawValue: _taskBasePriority(unsafeTask._task)) } return nil } } } @available(SwiftStdlib 5.1, *) extension TaskPriority { /// Downgrade user-interactive to user-initiated. var _downgradeUserInteractive: TaskPriority { return self } } // ==== Job Flags -------------------------------------------------------------- /// Flags for schedulable jobs. /// /// This is a port of the C++ FlagSet. @available(SwiftStdlib 5.1, *) struct JobFlags { /// Kinds of schedulable jobs. enum Kind: Int32 { case task = 0 } /// The actual bit representation of these flags. var bits: Int32 = 0 /// The kind of job described by these flags. var kind: Kind { get { Kind(rawValue: bits & 0xFF)! } set { bits = (bits & ~0xFF) | newValue.rawValue } } /// Whether this is an asynchronous task. var isAsyncTask: Bool { kind == .task } /// The priority given to the job. var priority: TaskPriority? { get { let value = (Int(bits) & 0xFF00) >> 8 if value == 0 { return nil } return TaskPriority(rawValue: UInt8(value)) } set { bits = (bits & ~0xFF00) | Int32((Int(newValue?.rawValue ?? 0) << 8)) } } /// Whether this is a child task. var isChildTask: Bool { get { (bits & (1 << 24)) != 0 } set { if newValue { bits = bits | 1 << 24 } else { bits = (bits & ~(1 << 24)) } } } /// Whether this is a future. var isFuture: Bool { get { (bits & (1 << 25)) != 0 } set { if newValue { bits = bits | 1 << 25 } else { bits = (bits & ~(1 << 25)) } } } /// Whether this is a group child. var isGroupChildTask: Bool { get { (bits & (1 << 26)) != 0 } set { if newValue { bits = bits | 1 << 26 } else { bits = (bits & ~(1 << 26)) } } } /// Whether this is a task created by the 'async' operation, which /// conceptually continues the work of the synchronous code that invokes /// it. var isContinuingAsyncTask: Bool { get { (bits & (1 << 27)) != 0 } set { if newValue { bits = bits | 1 << 27 } else { bits = (bits & ~(1 << 27)) } } } } // ==== Task Creation Flags -------------------------------------------------- /// Form task creation flags for use with the createAsyncTask builtins. @available(SwiftStdlib 5.1, *) @_alwaysEmitIntoClient func taskCreateFlags( priority: TaskPriority?, isChildTask: Bool, copyTaskLocals: Bool, inheritContext: Bool, enqueueJob: Bool, addPendingGroupTaskUnconditionally: Bool, isDiscardingTask: Bool, isSynchronousStart: Bool ) -> Int { var bits = 0 bits |= (bits & ~0xFF) | Int(priority?.rawValue ?? 0) if isChildTask { bits |= 1 << 8 } if copyTaskLocals { bits |= 1 << 10 } if inheritContext { bits |= 1 << 11 } if enqueueJob { bits |= 1 << 12 } if addPendingGroupTaskUnconditionally { bits |= 1 << 13 } if isDiscardingTask { bits |= 1 << 14 } // 15 is used by 'IsTaskFunctionConsumed' if isSynchronousStart { bits |= 1 << 16 } return bits } // ==== Task Name -------------------------------------------------------------- @available(SwiftStdlib 6.2, *) extension Task where Success == Never, Failure == Never { /// Returns the human-readable name of the current task, /// if it was set during the tasks' creation. /// /// Tasks can be named during their creation, which can be helpful to identify /// unique tasks which may be created at same source locations, for example: /// /// func process(items: [Int]) async { /// await withTaskGroup { group in /// for item in items { /// group.addTask(name: "process-\(item)") { /// await process(item) /// } /// } /// } /// } /// /// ### Task name availability /// The task name is only available when running with a recent runtime (Swift 6.2+). /// /// ``Task`` initializers which may accept a task name are more available than this property, /// for convenience purposes, in order to not have to set task names conditionally /// however their effect is runtime dependent, and is reflected in the availability of this property. @available(SwiftStdlib 6.2, *) public static var name: String? { return _getCurrentTaskNameString() } } // ==== Voluntary Suspension ----------------------------------------------------- @available(SwiftStdlib 5.1, *) extension Task where Success == Never, Failure == Never { /// Suspends the current task and allows other tasks to execute. /// /// A task can voluntarily suspend itself /// in the middle of a long-running operation /// that doesn't contain any suspension points, /// to let other tasks run for a while /// before execution returns to this task. /// /// If this task is the highest-priority task in the system, /// the executor immediately resumes execution of the same task. /// As such, /// this method isn't necessarily a way to avoid resource starvation. public static func yield() async { return await Builtin.withUnsafeContinuation { (continuation: Builtin.RawUnsafeContinuation) -> Void in let job = _taskCreateNullaryContinuationJob( priority: Int(Task.currentPriority.rawValue), continuation: continuation) #if !$Embedded && !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY if #available(StdlibDeploymentTarget 6.2, *) { let executor = Task.currentExecutor executor.enqueue(ExecutorJob(context: job)) } else { fatalError("we shouldn't get here; if we have, availability is broken") } #else _enqueueJobGlobal(job) #endif } } } // ==== UnsafeCurrentTask ------------------------------------------------------ /// Calls a closure with an unsafe reference to the current task. /// /// If you call this function from the body of an asynchronous function, /// the unsafe task handle passed to the closure is always non-`nil` /// because an asynchronous function always runs in the context of a task. /// However, if you call this function from the body of a synchronous function, /// and that function isn't executing in the context of any task, /// the unsafe task handle is `nil`. /// /// Don't store an unsafe task reference /// for use outside this method's closure. /// Storing an unsafe reference doesn't affect the task's actual life cycle, /// and the behavior of accessing an unsafe task reference /// outside of the `withUnsafeCurrentTask(body:)` method's closure isn't defined. /// There's no safe way to retrieve a reference to the current task /// and save it for long-term use. /// To query the current task without saving a reference to it, /// use properties like `currentPriority`. /// If you need to store a reference to a task, /// create an unstructured task using `Task.detached(priority:operation:)` instead. /// /// - Parameters: /// - body: A closure that takes an `UnsafeCurrentTask` parameter. /// If `body` has a return value, /// that value is also used as the return value /// for the `withUnsafeCurrentTask(body:)` function. /// /// - Returns: The return value, if any, of the `body` closure. @available(SwiftStdlib 5.1, *) public func withUnsafeCurrentTask(body: (UnsafeCurrentTask?) throws -> T) rethrows -> T { guard let _task = _getCurrentAsyncTask() else { return try body(nil) } // FIXME: This retain seems pretty wrong, however if we don't we WILL crash // with "destroying a task that never completed" in the task's destroy. // How do we solve this properly? Builtin.retain(_task) return try unsafe body(UnsafeCurrentTask(_task)) } @available(SwiftStdlib 6.0, *) public func withUnsafeCurrentTask(body: (UnsafeCurrentTask?) async throws -> T) async rethrows -> T { guard let _task = _getCurrentAsyncTask() else { return try await body(nil) } // FIXME: This retain seems pretty wrong, however if we don't we WILL crash // with "destroying a task that never completed" in the task's destroy. // How do we solve this properly? Builtin.retain(_task) return try unsafe await body(UnsafeCurrentTask(_task)) } /// An unsafe reference to the current task. /// /// To get an instance of `UnsafeCurrentTask` for the current task, /// call the `withUnsafeCurrentTask(body:)` method. /// Don't store an unsafe task reference /// for use outside that method's closure. /// Storing an unsafe reference doesn't affect the task's actual life cycle, /// and the behavior of accessing an unsafe task reference /// outside of the `withUnsafeCurrentTask(body:)` method's closure isn't defined. /// /// Only APIs on `UnsafeCurrentTask` that are also part of `Task` /// are safe to invoke from a task other than /// the task that this `UnsafeCurrentTask` instance refers to. /// Calling other APIs from another task is undefined behavior, /// breaks invariants in other parts of the program running on this task, /// and may lead to crashes or data loss. /// /// For information about the language-level concurrency model that `UnsafeCurrentTask` is part of, /// see [Concurrency][concurrency] in [The Swift Programming Language][tspl]. /// /// [concurrency]: https://docs.swift.org/swift-book/LanguageGuide/Concurrency.html /// [tspl]: https://docs.swift.org/swift-book/ @available(SwiftStdlib 5.1, *) @unsafe public struct UnsafeCurrentTask { internal let _task: Builtin.NativeObject // May only be created by the standard library. internal init(_ task: Builtin.NativeObject) { unsafe self._task = task } /// A Boolean value that indicates whether the current task was canceled. /// /// After the value of this property becomes `true`, it remains `true` indefinitely. /// There is no way to uncancel a task. /// /// - SeeAlso: `checkCancellation()` public var isCancelled: Bool { unsafe _taskIsCancelled(_task) } /// The current task's priority. /// /// - SeeAlso: `TaskPriority` /// - SeeAlso: `Task.currentPriority` public var priority: TaskPriority { unsafe TaskPriority(rawValue: _taskCurrentPriority(_task)) } /// The current task's base priority. /// /// - SeeAlso: `TaskPriority` /// - SeeAlso: `Task.basePriority` @available(SwiftStdlib 5.9, *) public var basePriority: TaskPriority { unsafe TaskPriority(rawValue: _taskBasePriority(_task)) } /// Cancel the current task. public func cancel() { unsafe _taskCancel(_task) } } @available(SwiftStdlib 5.1, *) @available(*, unavailable) extension UnsafeCurrentTask: Sendable { } @available(SwiftStdlib 5.1, *) extension UnsafeCurrentTask: @unsafe Hashable { public func hash(into hasher: inout Hasher) { unsafe UnsafeRawPointer(Builtin.bridgeToRawPointer(_task)).hash(into: &hasher) } } @available(SwiftStdlib 5.1, *) extension UnsafeCurrentTask: Equatable { public static func ==(lhs: Self, rhs: Self) -> Bool { unsafe UnsafeRawPointer(Builtin.bridgeToRawPointer(lhs._task)) == UnsafeRawPointer(Builtin.bridgeToRawPointer(rhs._task)) } } // ==== Internal --------------------------------------------------------------- @available(SwiftStdlib 5.1, *) @_silgen_name("swift_task_getCurrent") public func _getCurrentAsyncTask() -> Builtin.NativeObject? @available(SwiftStdlib 5.1, *) @_silgen_name("swift_task_getJobFlags") func getJobFlags(_ task: Builtin.NativeObject) -> JobFlags @available(SwiftStdlib 5.1, *) @_silgen_name("swift_task_enqueueGlobal") @usableFromInline func _enqueueJobGlobal(_ task: Builtin.Job) @available(SwiftStdlib 5.9, *) func _enqueueJobGlobal(_ task: UnownedJob) { _enqueueJobGlobal(task._context) } @available(SwiftStdlib 5.1, *) @_silgen_name("swift_task_enqueueGlobalWithDelay") @usableFromInline func _enqueueJobGlobalWithDelay(_ delay: UInt64, _ task: Builtin.Job) @available(SwiftStdlib 5.9, *) func _enqueueJobGlobalWithDelay(_ delay: UInt64, _ task: UnownedJob) { return _enqueueJobGlobalWithDelay(delay, task._context) } @available(StdlibDeploymentTarget 5.7, *) @_silgen_name("swift_task_enqueueGlobalWithDeadline") @usableFromInline func _enqueueJobGlobalWithDeadline(_ seconds: Int64, _ nanoseconds: Int64, _ toleranceSec: Int64, _ toleranceNSec: Int64, _ clock: Int32, _ task: UnownedJob) @available(SwiftStdlib 5.1, *) @usableFromInline @_silgen_name("swift_task_asyncMainDrainQueue") internal func _asyncMainDrainQueue() -> Never @available(SwiftStdlib 5.1, *) @usableFromInline @_silgen_name("swift_task_getMainExecutor") internal func _getMainExecutor() -> Builtin.Executor /// Get the default generic serial executor. /// /// It is used by default used by tasks and default actors, /// unless other executors are specified. @available(SwiftStdlib 6.0, *) @usableFromInline internal func _getGenericSerialExecutor() -> Builtin.Executor { // The `SerialExecutorRef` to "default generic executor" is guaranteed // to be a zero value; // // As the runtime relies on this in multiple places, // so instead of a runtime call to get this executor ref, we bitcast a "zero" // of expected size to the builtin executor type. unsafe unsafeBitCast((UInt(0), UInt(0)), to: Builtin.Executor.self) } #if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY @available(SwiftStdlib 5.1, *) @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") @usableFromInline @preconcurrency internal func _runAsyncMain(_ asyncFun: @Sendable @escaping () async throws -> ()) { fatalError("Unavailable in task-to-thread concurrency model") } #elseif !SWIFT_CONCURRENCY_EMBEDDED @available(SwiftStdlib 5.1, *) @usableFromInline @preconcurrency internal func _runAsyncMain(_ asyncFun: @Sendable @escaping () async throws -> ()) { let taskFlags = taskCreateFlags( priority: nil, isChildTask: false, copyTaskLocals: false, inheritContext: false, enqueueJob: false, addPendingGroupTaskUnconditionally: false, isDiscardingTask: false, isSynchronousStart: false) let (theTask, _) = Builtin.createAsyncTask(taskFlags) { do { try await asyncFun() exit(0) } catch { _errorInMain(error) } } let job = Builtin.convertTaskToJob(theTask) if #available(StdlibDeploymentTarget 6.2, *) { MainActor.executor.enqueue(ExecutorJob(context: job)) } else { fatalError("we shouldn't get here; if we have, availability is broken") } _asyncMainDrainQueue() } #endif // FIXME: both of these ought to take their arguments _owned so that // we can do a move out of the future in the common case where it's // unreferenced @available(SwiftStdlib 5.1, *) @_silgen_name("swift_task_future_wait") public func _taskFutureGet(_ task: Builtin.NativeObject) async -> T @available(SwiftStdlib 5.1, *) @_silgen_name("swift_task_future_wait_throwing") public func _taskFutureGetThrowing(_ task: Builtin.NativeObject) async throws -> T @available(SwiftStdlib 5.1, *) @_silgen_name("swift_task_cancel") public func _taskCancel(_ task: Builtin.NativeObject) @available(SwiftStdlib 5.1, *) @_silgen_name("swift_task_isCancelled") @usableFromInline func _taskIsCancelled(_ task: Builtin.NativeObject) -> Bool @_silgen_name("swift_task_currentPriority") internal func _taskCurrentPriority(_ task: Builtin.NativeObject) -> UInt8 @available(SwiftStdlib 6.2, *) @_silgen_name("swift_task_escalate") @discardableResult internal func _taskEscalate(_ task: Builtin.NativeObject, newPriority: UInt8) -> UInt8 @available(SwiftStdlib 5.1, *) @_silgen_name("swift_task_basePriority") internal func _taskBasePriority(_ task: Builtin.NativeObject) -> UInt8 @available(SwiftStdlib 5.1, *) @_silgen_name("swift_task_createNullaryContinuationJob") func _taskCreateNullaryContinuationJob(priority: Int, continuation: Builtin.RawUnsafeContinuation) -> Builtin.Job @available(SwiftStdlib 5.1, *) @usableFromInline @_silgen_name("swift_task_isCurrentExecutor") func _taskIsCurrentExecutor(_ executor: Builtin.Executor) -> Bool @available(SwiftStdlib 6.2, *) @_silgen_name("swift_task_isCurrentExecutorWithFlags") @usableFromInline internal func _taskIsCurrentExecutor( executor: Builtin.Executor, flags: UInt64) -> Bool @available(SwiftStdlib 6.2, *) extension GlobalActor { @available(SwiftStdlib 6.2, *) @_silgen_name("_swift_task_isCurrentGlobalActor") internal static func _taskIsCurrentGlobalActor() -> Bool { let executor = unsafe sharedUnownedExecutor return unsafe _taskIsCurrentExecutor(executor: executor.executor, flags: 0) } } @available(SwiftStdlib 5.1, *) @usableFromInline @_silgen_name("swift_task_reportUnexpectedExecutor") func _reportUnexpectedExecutor(_ _filenameStart: Builtin.RawPointer, _ _filenameLength: Builtin.Word, _ _filenameIsASCII: Builtin.Int1, _ _line: Builtin.Word, _ _executor: Builtin.Executor) @available(SwiftStdlib 5.1, *) @_silgen_name("swift_task_getCurrentThreadPriority") func _getCurrentThreadPriority() -> Int @available(SwiftStdlib 6.2, *) @_silgen_name("swift_task_getCurrentTaskName") internal func _getCurrentTaskName() -> UnsafePointer? @available(SwiftStdlib 6.2, *) internal func _getCurrentTaskNameString() -> String? { if let stringPtr = unsafe _getCurrentTaskName() { unsafe String(cString: stringPtr) } else { nil } } #if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY @available(SwiftStdlib 5.8, *) @usableFromInline @_unavailableFromAsync(message: "Use _taskRunInline from a sync context to begin an async context.") internal func _taskRunInline(_ body: () async -> T) -> T { #if compiler(>=5.5) && $BuiltinTaskRunInline return Builtin.taskRunInline(body) #else fatalError("Unsupported Swift compiler") #endif } @available(SwiftStdlib 5.8, *) extension Task where Failure == Never { /// Start an async context within the current sync context and run the /// provided async closure, returning the value it produces. @available(SwiftStdlib 5.8, *) @_spi(_TaskToThreadModel) @_unavailableFromAsync(message: "Use Task.runInline from a sync context to begin an async context.") public static func runInline(_ body: () async -> Success) -> Success { return _taskRunInline(body) } } @available(SwiftStdlib 5.8, *) extension Task where Failure == Error { @available(SwiftStdlib 5.8, *) @_alwaysEmitIntoClient @usableFromInline internal static func _runInlineHelper( body: () async -> Result, rescue: (Result) throws -> T ) rethrows -> T { return try rescue( _taskRunInline(body) ) } /// Start an async context within the current sync context and run the /// provided async closure, returning or throwing the value or error it /// produces. @available(SwiftStdlib 5.8, *) @_spi(_TaskToThreadModel) @_unavailableFromAsync(message: "Use Task.runInline from a sync context to begin an async context.") public static func runInline(_ body: () async throws -> Success) rethrows -> Success { return try _runInlineHelper( body: { do { let value = try await body() return Result.success(value) } catch let error { return Result.failure(error) } }, rescue: { try $0.get() } ) } } #endif #if _runtime(_ObjC) #if !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY /// Intrinsic used by SILGen to launch a task for bridging a Swift async method /// which was called through its ObjC-exported completion-handler-based API. @available(SwiftStdlib 5.1, *) @_alwaysEmitIntoClient @usableFromInline internal func _runTaskForBridgedAsyncMethod(@_inheritActorContext _ body: __owned @Sendable @escaping () async -> Void) { #if compiler(>=5.6) Task(operation: body) #else Task { await body() return 0 } #endif } #endif #endif