//===--- Concurrency.h - Runtime interface for concurrency ------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 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 // //===----------------------------------------------------------------------===// // // The runtime interface for concurrency. // //===----------------------------------------------------------------------===// #ifndef SWIFT_RUNTIME_CONCURRENCY_H #define SWIFT_RUNTIME_CONCURRENCY_H #include "swift/ABI/AsyncLet.h" #include "swift/ABI/Coro.h" #include "swift/ABI/Task.h" #include "swift/ABI/TaskGroup.h" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wreturn-type-c-linkage" // Does the runtime use a cooperative global executor? #if defined(SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY) #define SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR 1 #else #define SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR 0 #endif // Does the runtime use a task-thread model? #if defined(SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY) #define SWIFT_CONCURRENCY_TASK_TO_THREAD_MODEL 1 #else #define SWIFT_CONCURRENCY_TASK_TO_THREAD_MODEL 0 #endif // Does the runtime integrate with libdispatch? #if defined(SWIFT_CONCURRENCY_USES_DISPATCH) #define SWIFT_CONCURRENCY_ENABLE_DISPATCH SWIFT_CONCURRENCY_USES_DISPATCH #else #define SWIFT_CONCURRENCY_ENABLE_DISPATCH 0 #endif // Does the runtime provide priority escalation support? #ifndef SWIFT_CONCURRENCY_ENABLE_PRIORITY_ESCALATION #if SWIFT_CONCURRENCY_ENABLE_DISPATCH && \ __has_include() && __APPLE__ && \ (defined(__arm64__) || defined(__x86_64__)) #define SWIFT_CONCURRENCY_ENABLE_PRIORITY_ESCALATION 1 #else #define SWIFT_CONCURRENCY_ENABLE_PRIORITY_ESCALATION 0 #endif #endif /* SWIFT_CONCURRENCY_ENABLE_PRIORITY_ESCALATION */ namespace swift { class DefaultActor; class TaskOptionRecord; struct SwiftError; struct AsyncTaskAndContext { AsyncTask *Task; AsyncContext *InitialContext; }; /// Create a task object. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) AsyncTaskAndContext swift_task_create( size_t taskCreateFlags, TaskOptionRecord *options, const Metadata *futureResultType, void *closureEntry, HeapObject *closureContext); /// Caution: not all future-initializing functions actually throw, so /// this signature may be incorrect. using FutureAsyncSignature = AsyncSignature; /// Create a task object. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) AsyncTaskAndContext swift_task_create_common( size_t taskCreateFlags, TaskOptionRecord *options, const Metadata *futureResultType, TaskContinuationFunction *function, void *closureContext, size_t initialContextSize); #if SWIFT_CONCURRENCY_TASK_TO_THREAD_MODEL #define SWIFT_TASK_RUN_INLINE_INITIAL_CONTEXT_BYTES 4096 /// Begin an async context in the current sync context and run the indicated /// closure in it. /// /// This is only supported under the task-to-thread concurrency model and /// relies on a synchronous implementation of task blocking in order to work. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_task_run_inline(OpaqueValue *result, void *closureAFP, OpaqueValue *closureContext, const Metadata *futureResultType); #endif /// Allocate memory in a task. /// /// This must be called synchronously with the task. /// /// All allocations will be rounded to a multiple of MAX_ALIGNMENT. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void *swift_task_alloc(size_t size); /// Deallocate memory in a task. /// /// The pointer provided must be the last pointer allocated on /// this task that has not yet been deallocated; that is, memory /// must be allocated and deallocated in a strict stack discipline. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_task_dealloc(void *ptr); /// Deallocate multiple memory allocations in a task. /// /// The pointer provided must be a pointer previously allocated on /// this task that has not yet been deallocated. All allocations up to and /// including that allocation will be deallocated. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_task_dealloc_through(void *ptr); // TODO: CoroutineAccessors: Eliminate this entry point and replace its uses // with direct references the globals. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) CoroAllocator *swift_coro_getGlobalAllocator(CoroAllocatorFlags flags); // TODO: CoroutineAccessors: Mark the underlying struct const. SWIFT_EXPORT_FROM(swift_Concurrency) CoroAllocator *const _swift_coro_task_allocator; // TODO: CoroutineAccessors: Move these declarations back to swiftCore {{ SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void *swift_coro_alloc(CoroAllocator *allocator, size_t size); SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_coro_dealloc(CoroAllocator *allocator, void *ptr); // TODO: CoroutineAccessors: Mark the underlying struct const. SWIFT_EXPORT_FROM(swift_Concurrency) CoroAllocator *const _swift_coro_malloc_allocator; // }} TODO: CoroutineAccessors /// Cancel a task and all of its child tasks. /// /// This can be called from any thread. /// /// This has no effect if the task is already cancelled. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_task_cancel(AsyncTask *task); /// Cancel all the child tasks that belong to the `group`. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_task_cancel_group_child_tasks(TaskGroup *group); /// Escalate the priority of a task and all of its child tasks. /// /// This can be called from any thread. /// /// This has no effect if the task already has at least the given priority. /// Returns the priority of the task. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) JobPriority swift_task_escalate(AsyncTask *task, JobPriority newPriority); // TODO: "async let wait" and "async let destroy" would be expressed // similar to like TaskFutureWait; /// Wait for a non-throwing future task to complete. /// /// This can be called from any thread. Its Swift signature is /// /// \code /// func swift_task_future_wait(on task: _owned Builtin.NativeObject) async /// -> Success /// \endcode SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync) void swift_task_future_wait(OpaqueValue *, SWIFT_ASYNC_CONTEXT AsyncContext *, AsyncTask *, TaskContinuationFunction *, AsyncContext *); /// Wait for a potentially-throwing future task to complete. /// /// This can be called from any thread. Its Swift signature is /// /// \code /// func swift_task_future_wait_throwing(on task: _owned Builtin.NativeObject) /// async throws -> Success /// \endcode SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync) void swift_task_future_wait_throwing( OpaqueValue *, SWIFT_ASYNC_CONTEXT AsyncContext *, AsyncTask *, ThrowingTaskFutureWaitContinuationFunction *, AsyncContext *); /// Wait for a readyQueue of a Channel to become non empty. /// /// This can be called from any thread. Its Swift signature is /// /// \code /// func swift_taskGroup_wait_next_throwing( /// waitingTask: Builtin.NativeObject, // current task /// group: Builtin.RawPointer /// ) async throws -> T /// \endcode SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync) void swift_taskGroup_wait_next_throwing( OpaqueValue *resultPointer, SWIFT_ASYNC_CONTEXT AsyncContext *callerContext, TaskGroup *group, ThrowingTaskFutureWaitContinuationFunction *resumeFn, AsyncContext *callContext); /// Initialize a `TaskGroup` in the passed `group` memory location. /// The caller is responsible for retaining and managing the group's lifecycle. /// /// Its Swift signature is /// /// \code /// func swift_taskGroup_initialize(group: Builtin.RawPointer) /// \endcode SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_taskGroup_initialize(TaskGroup *group, const Metadata *T); /// Initialize a `TaskGroup` in the passed `group` memory location. /// The caller is responsible for retaining and managing the group's lifecycle. /// /// Its Swift signature is /// /// \code /// func swift_taskGroup_initialize(flags: Int, group: Builtin.RawPointer) /// \endcode SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_taskGroup_initializeWithFlags(size_t flags, TaskGroup *group, const Metadata *T); /// Initialize a `TaskGroup` in the passed `group` memory location. /// The caller is responsible for retaining and managing the group's lifecycle. /// /// Its Swift signature is /// /// \code /// func swift_taskGroup_initialize(flags: Int, group: Builtin.RawPointer) /// \endcode SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_taskGroup_initializeWithOptions(size_t flags, TaskGroup *group, const Metadata *T, TaskOptionRecord *options); /// Attach a child task to the parent task's task group record. /// /// This function MUST be called from the AsyncTask running the task group. /// /// Since the group (or rather, its record) is inserted in the parent task at /// creation we do not need the parent task here, the group already is attached /// to it. /// Its Swift signature is /// /// \code /// func swift_taskGroup_attachChild( /// group: Builtin.RawPointer, /// child: Builtin.NativeObject /// ) /// \endcode SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_taskGroup_attachChild(TaskGroup *group, AsyncTask *child); /// Its Swift signature is /// /// This function MUST be called from the AsyncTask running the task group. /// /// \code /// func swift_taskGroup_destroy(_ group: Builtin.RawPointer) /// \endcode SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_taskGroup_destroy(TaskGroup *group); /// Before starting a task group child task, inform the group that there is one /// more 'pending' child to account for. /// /// This function SHOULD be called from the AsyncTask running the task group, /// however is generally thread-safe as it only works with the group status. /// /// Its Swift signature is /// /// \code /// func swift_taskGroup_addPending( /// group: Builtin.RawPointer, /// unconditionally: Bool /// ) -> Bool /// \endcode SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) bool swift_taskGroup_addPending(TaskGroup *group, bool unconditionally); /// Cancel all tasks in the group. /// This also prevents new tasks from being added. /// /// This can be called from any thread. /// /// Its Swift signature is /// /// \code /// func swift_taskGroup_cancelAll(group: Builtin.RawPointer) /// \endcode SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_taskGroup_cancelAll(TaskGroup *group); /// Check ONLY if the group was explicitly cancelled, e.g. by `cancelAll`. /// /// This check DOES NOT take into account the task in which the group is running /// being cancelled or not. /// /// This can be called from any thread. Its Swift signature is /// /// \code /// func swift_taskGroup_isCancelled(group: Builtin.RawPointer) /// \endcode SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) bool swift_taskGroup_isCancelled(TaskGroup *group); /// Wait until all pending tasks from the task group have completed. /// If this task group is accumulating results, this also discards all those results. /// /// This can be called from any thread. Its Swift signature is /// /// \code /// func swift_taskGroup_waitAll( /// waitingTask: Builtin.NativeObject, // current task /// group: Builtin.RawPointer, /// bodyError: Swift.Error? /// ) async throws /// \endcode SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync) void swift_taskGroup_waitAll( OpaqueValue *resultPointer, SWIFT_ASYNC_CONTEXT AsyncContext *callerContext, TaskGroup *group, SwiftError *bodyError, ThrowingTaskFutureWaitContinuationFunction *resumeFn, AsyncContext *callContext); /// Check the readyQueue of a task group, return true if it has no pending tasks. /// /// This can be called from any thread. Its Swift signature is /// /// \code /// func swift_taskGroup_isEmpty( /// _ group: Builtin.RawPointer /// ) -> Bool /// \endcode SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) bool swift_taskGroup_isEmpty(TaskGroup *group); /// DEPRECATED. swift_asyncLet_begin is used instead. /// Its Swift signature is /// /// \code /// func swift_asyncLet_start( /// asyncLet: Builtin.RawPointer, /// options: Builtin.RawPointer?, /// operation: __owned @Sendable () async throws -> T /// ) /// \endcode SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_asyncLet_start(AsyncLet *alet, TaskOptionRecord *options, const Metadata *futureResultType, void *closureEntryPoint, HeapObject *closureContext); /// Begin an async let child task. /// Its Swift signature is /// /// \code /// func swift_asyncLet_start( /// asyncLet: Builtin.RawPointer, /// options: Builtin.RawPointer?, /// operation: __owned @Sendable () async throws -> T, /// resultBuffer: Builtin.RawPointer /// ) /// \endcode SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_asyncLet_begin(AsyncLet *alet, TaskOptionRecord *options, const Metadata *futureResultType, void *closureEntryPoint, HeapObject *closureContext, void *resultBuffer); /// This matches the ABI of a closure `(Builtin.RawPointer) async -> T` using AsyncLetWaitSignature = SWIFT_CC(swiftasync) void(OpaqueValue *, SWIFT_ASYNC_CONTEXT AsyncContext *, AsyncTask *, Metadata *); /// DEPRECATED. swift_asyncLet_get is used instead. /// Wait for a non-throwing async-let to complete. /// /// This can be called from any thread. Its Swift signature is /// /// \code /// func swift_asyncLet_wait( /// _ asyncLet: _owned Builtin.RawPointer /// ) async -> Success /// \endcode SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync) void swift_asyncLet_wait(OpaqueValue *, SWIFT_ASYNC_CONTEXT AsyncContext *, AsyncLet *, TaskContinuationFunction *, AsyncContext *); /// DEPRECATED. swift_asyncLet_get_throwing is used instead. /// Wait for a potentially-throwing async-let to complete. /// /// This can be called from any thread. Its Swift signature is /// /// \code /// func swift_asyncLet_wait_throwing( /// _ asyncLet: _owned Builtin.RawPointer /// ) async throws -> Success /// \endcode SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync) void swift_asyncLet_wait_throwing(OpaqueValue *, SWIFT_ASYNC_CONTEXT AsyncContext *, AsyncLet *, ThrowingTaskFutureWaitContinuationFunction *, AsyncContext *); /// DEPRECATED. swift_asyncLet_finish is used instead. /// Its Swift signature is /// /// \code /// func swift_asyncLet_end(_ alet: Builtin.RawPointer) /// \endcode SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_asyncLet_end(AsyncLet *alet); /// Get the value of a non-throwing async-let, awaiting the result if necessary. /// /// This can be called from any thread. Its Swift signature is /// /// \code /// func swift_asyncLet_get( /// _ asyncLet: Builtin.RawPointer, /// _ resultBuffer: Builtin.RawPointer /// ) async /// \endcode /// /// \c result points at the variable storage for the binding. It is /// uninitialized until the first call to \c swift_asyncLet_get or /// \c swift_asyncLet_get_throwing. That first call initializes the storage /// with the result of the child task. Subsequent calls do nothing and leave /// the value in place. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync) void swift_asyncLet_get(SWIFT_ASYNC_CONTEXT AsyncContext *, AsyncLet *, void *, TaskContinuationFunction *, AsyncContext *); /// Get the value of a throwing async-let, awaiting the result if necessary. /// /// This can be called from any thread. Its Swift signature is /// /// \code /// func swift_asyncLet_get_throwing( /// _ asyncLet: Builtin.RawPointer, /// _ resultBuffer: Builtin.RawPointer /// ) async throws /// \endcode /// /// \c result points at the variable storage for the binding. It is /// uninitialized until the first call to \c swift_asyncLet_get or /// \c swift_asyncLet_get_throwing. That first call initializes the storage /// with the result of the child task. Subsequent calls do nothing and leave /// the value in place. A pointer to the storage inside the child task is /// returned if the task completes successfully, otherwise the error from the /// child task is thrown. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync) void swift_asyncLet_get_throwing(SWIFT_ASYNC_CONTEXT AsyncContext *, AsyncLet *, void *, ThrowingTaskFutureWaitContinuationFunction *, AsyncContext *); /// Exit the scope of an async-let binding. If the task is still running, it /// is cancelled, and we await its completion; otherwise, we destroy the /// value in the variable storage. /// /// Its Swift signature is /// /// \code /// func swift_asyncLet_finish(_ asyncLet: Builtin.RawPointer, /// _ resultBuffer: Builtin.RawPointer) async /// \endcode SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync) void swift_asyncLet_finish(SWIFT_ASYNC_CONTEXT AsyncContext *, AsyncLet *, void *, TaskContinuationFunction *, AsyncContext *); /// Get the value of a non-throwing async-let, awaiting the result if necessary, /// and then destroy the child task. The result buffer is left initialized after /// returning. /// /// This can be called from any thread. Its Swift signature is /// /// \code /// func swift_asyncLet_get( /// _ asyncLet: Builtin.RawPointer, /// _ resultBuffer: Builtin.RawPointer /// ) async /// \endcode /// /// \c result points at the variable storage for the binding. It is /// uninitialized until the first call to \c swift_asyncLet_get or /// \c swift_asyncLet_get_throwing. The child task will be invalidated after /// this call, so the `async let` can not be gotten or finished afterward. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync) void swift_asyncLet_consume(SWIFT_ASYNC_CONTEXT AsyncContext *, AsyncLet *, void *, TaskContinuationFunction *, AsyncContext *); /// Get the value of a throwing async-let, awaiting the result if necessary, /// and then destroy the child task. The result buffer is left initialized after /// returning. /// /// This can be called from any thread. Its Swift signature is /// /// \code /// func swift_asyncLet_get_throwing( /// _ asyncLet: Builtin.RawPointer, /// _ resultBuffer: Builtin.RawPointer /// ) async throws /// \endcode /// /// \c result points at the variable storage for the binding. It is /// uninitialized until the first call to \c swift_asyncLet_get or /// \c swift_asyncLet_get_throwing. That first call initializes the storage /// with the result of the child task. Subsequent calls do nothing and leave /// the value in place. The child task will be invalidated after /// this call, so the `async let` can not be gotten or finished afterward. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync) void swift_asyncLet_consume_throwing(SWIFT_ASYNC_CONTEXT AsyncContext *, AsyncLet *, void *, ThrowingTaskFutureWaitContinuationFunction *, AsyncContext *); /// Returns true if the currently executing AsyncTask has a /// 'TaskGroupTaskStatusRecord' present. /// /// This can be called from any thread. /// /// Its Swift signature is /// /// \code /// func swift_taskGroup_hasTaskGroupRecord() /// \endcode SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) bool swift_taskGroup_hasTaskGroupRecord(); // FIXME: not used? we have swift_task_hasTaskGroupStatusRecord /// Signifies whether the current task is in the middle of executing the /// operation block of a `with(Throwing)TaskGroup(...) { }`. /// /// Task local values must use un-structured allocation for values bound in this /// scope, as they may be referred to by `group.spawn`-ed tasks and therefore /// out-life the scope of a task-local value binding. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) bool swift_task_hasTaskGroupStatusRecord(); /// Push an executor preference onto the current task. /// The pushed reference does not keep the executor alive, and it is the /// responsibility of the end user to ensure that the task executor reference /// remains valid throughout the time it may be used by any task. /// /// Runtime availability: Swift 9999. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) TaskExecutorPreferenceStatusRecord* swift_task_pushTaskExecutorPreference(TaskExecutorRef executor); /// Remove a single task executor preference record from the current task. /// /// Must be passed the record intended to be removed (returned by /// `swift_task_pushTaskExecutorPreference`). /// /// Failure to remove the expected record should result in a runtime crash as it /// signals a bug in record handling by the concurrency library -- a record push /// must always be paired with a record pop. /// /// Runtime availability: Swift 6.0 SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_task_popTaskExecutorPreference(TaskExecutorPreferenceStatusRecord* record); SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) size_t swift_task_getJobFlags(AsyncTask* task); SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) bool swift_task_isCancelled(AsyncTask* task); /// Returns the current priority of the task which is >= base priority of the /// task. This function does not exist in the base ABI of this library and must /// be deployment limited SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) JobPriority swift_task_currentPriority(AsyncTask *task); /// Returns the base priority of the task. This function does not exist in the /// base ABI of this library and must be deployment limited. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) JobPriority swift_task_basePriority(AsyncTask *task); /// Returns the priority of the job. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) JobPriority swift_concurrency_jobPriority(Job *job); /// Create and add an cancellation record to the task. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) CancellationNotificationStatusRecord* swift_task_addCancellationHandler( CancellationNotificationStatusRecord::FunctionType handler, void *handlerContext); /// Remove the passed cancellation record from the task. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_task_removeCancellationHandler( CancellationNotificationStatusRecord *record); /// Create and add an priority escalation record to the task. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) EscalationNotificationStatusRecord* swift_task_addPriorityEscalationHandler( EscalationNotificationStatusRecord::FunctionType handler, void *handlerContext); /// Remove the passed priority escalation record from the task. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_task_removePriorityEscalationHandler( EscalationNotificationStatusRecord *record); /// Create a NullaryContinuationJob from a continuation. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) NullaryContinuationJob* swift_task_createNullaryContinuationJob( size_t priority, AsyncTask *continuation); SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_task_deinitOnExecutor(void *object, DeinitWorkFunction *work, SerialExecutorRef newExecutor, size_t flags); /// Report error about attempting to bind a task-local value from an illegal context. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_task_reportIllegalTaskLocalBindingWithinWithTaskGroup( const unsigned char *file, uintptr_t fileLength, bool fileIsASCII, uintptr_t line); /// Get a task local value from either the current task, or fallback task-local /// storage. /// /// Its Swift signature is /// /// \code /// func _taskLocalValueGet( /// keyType: Any.Type /*Key.Type*/ /// ) -> UnsafeMutableRawPointer? where Key: TaskLocalKey /// \endcode SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) OpaqueValue* swift_task_localValueGet(const HeapObject *key); /// Bind a task local key to a value in the context of either the current /// AsyncTask if present, or in the thread-local fallback context if no task /// available. /// /// Its Swift signature is /// /// \code /// public func _taskLocalValuePush( /// keyType: Any.Type/*Key.Type*/, /// value: __owned Value /// ) /// \endcode SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_task_localValuePush(const HeapObject *key, /* +1 */ OpaqueValue *value, const Metadata *valueType); /// Pop a single task local binding from the binding stack of the current task, /// or the fallback thread-local storage if no task is available. /// /// This operation must be paired up with a preceding "push" operation, as otherwise /// it may attempt to "pop" off an empty value stuck which will lead to a crash. /// /// The Swift surface API ensures proper pairing of push and pop operations. /// /// Its Swift signature is /// /// \code /// public func _taskLocalValuePop() /// \endcode SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_task_localValuePop(); /// Copy all task locals from the current context to the target task. /// /// Its Swift signature is /// /// \code /// func swift_task_localsCopyTo(AsyncTask* task) /// \endcode SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_task_localsCopyTo(AsyncTask* target); /// Switch the current task to a new executor if we aren't already /// running on a compatible executor. /// /// The resumption function pointer and continuation should be set /// appropriately in the task. /// /// Generally the compiler should inline a fast-path compatible-executor /// check to avoid doing the suspension work. This function should /// generally be tail-called, as it may continue executing the task /// synchronously if possible. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync) void swift_task_switch(SWIFT_ASYNC_CONTEXT AsyncContext *resumeToContext, TaskContinuationFunction *resumeFunction, SerialExecutorRef newExecutor); /// Mark a task for enqueue on a new executor and then enqueue it. /// /// The resumption function pointer and continuation should be set /// appropriately in the task. /// /// Generally you should call swift_task_switch to switch execution /// synchronously when possible. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_task_enqueueTaskOnExecutor(AsyncTask *task, SerialExecutorRef executor); /// Enqueue the given job to run asynchronously on the given executor. /// /// The resumption function pointer and continuation should be set /// appropriately in the task. /// /// Generally you should call swift_task_switch to switch execution /// synchronously when possible. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_task_enqueue(Job *job, SerialExecutorRef executor); /// Enqueue the given job to run asynchronously on the global /// execution pool. /// /// The resumption function pointer and continuation should be set /// appropriately in the task. /// /// Generally you should call swift_task_switch to switch execution /// synchronously when possible. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_task_enqueueGlobal(Job *job); /// Invoke an executor's `checkIsolated` implementation; /// It will crash if the current executor is NOT the passed executor. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_task_checkIsolated(SerialExecutorRef executor); /// Invoke a Swift executor's `checkIsolated` implementation; returns /// `true` if it invoked the Swift implementation, `false` otherwise. /// Executors will want to call this from their `swift_task_checkIsolatedImpl` /// implementation. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) bool swift_task_invokeSwiftCheckIsolated(SerialExecutorRef executor); /// Invoke an executor's `isIsolatingCurrentContext` implementation; SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) bool swift_task_isIsolatingCurrentContext(SerialExecutorRef executor); /// Invoke a Swift executor's `isIsolatingCurrentContext` implementation; returns /// `true` if it invoked the Swift implementation, `false` otherwise. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) bool swift_task_invokeSwiftIsIsolatingCurrentContext(SerialExecutorRef executor); /// A count in nanoseconds. using JobDelay = unsigned long long; SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_task_enqueueGlobalWithDelay(JobDelay delay, Job *job); SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_task_enqueueGlobalWithDeadline(long long sec, long long nsec, long long tsec, long long tnsec, int clock, Job *job); /// Enqueue the given job on the main executor. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_task_enqueueMainExecutor(Job *job); /// WARNING: This method is expected to CRASH when caller is not on the /// expected executor. /// /// Return true if the caller is running in a Task on the passed Executor. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) bool swift_task_isOnExecutor( HeapObject * executor, const Metadata *selfType, const SerialExecutorWitnessTable *wtable); SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) bool swift_executor_isComplexEquality(SerialExecutorRef ref); /// Return the 64bit TaskID (if the job is an AsyncTask), /// or the 32bits of the job Id otherwise. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) uint64_t swift_task_getJobTaskId(Job *job); #if SWIFT_CONCURRENCY_ENABLE_DISPATCH /// Enqueue the given job on the main executor. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_task_enqueueOnDispatchQueue(Job *job, HeapObject *queue); #endif // Declare all the hooks #define SWIFT_CONCURRENCY_HOOK(returnType, name, ...) \ typedef SWIFT_CC(swift) returnType (*name##_original)(__VA_ARGS__); \ typedef SWIFT_CC(swift) returnType \ (*name##_hook_t)(__VA_ARGS__, name##_original original); \ SWIFT_EXPORT_FROM(swift_Concurrency) name##_hook_t name##_hook #define SWIFT_CONCURRENCY_HOOK0(returnType, name) \ typedef SWIFT_CC(swift) returnType (*name##_original)(); \ typedef SWIFT_CC(swift) returnType \ (*name##_hook_t)(name##_original original); \ SWIFT_EXPORT_FROM(swift_Concurrency) name##_hook_t name##_hook #include "ConcurrencyHooks.def" // This is a compatibility hook, *not* a concurrency hook typedef SWIFT_CC(swift) void (*swift_task_asyncMainDrainQueue_original)(); typedef SWIFT_CC(swift) void (*swift_task_asyncMainDrainQueue_override)( swift_task_asyncMainDrainQueue_original original); SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void (*swift_task_asyncMainDrainQueue_hook)( swift_task_asyncMainDrainQueue_original original, swift_task_asyncMainDrainQueue_override compatOverride); /// Initialize the runtime storage for a default actor. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_defaultActor_initialize(DefaultActor *actor); /// Destroy the runtime storage for a default actor. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_defaultActor_destroy(DefaultActor *actor); /// Deallocate an instance of a default actor. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_defaultActor_deallocate(DefaultActor *actor); /// Deallocate an instance of what might be a default actor. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_defaultActor_deallocateResilient(HeapObject *actor); /// Initialize the runtime storage for a non-default distributed actor. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_nonDefaultDistributedActor_initialize(NonDefaultDistributedActor *actor); /// Create and initialize the runtime storage for a distributed remote actor. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) OpaqueValue* swift_distributedActor_remote_initialize(const Metadata *actorType); /// Enqueue a job on the default actor implementation. /// /// The job must be ready to run. Notably, if it's a task, that /// means that the resumption function and context should have been /// set appropriately. /// /// Jobs are assumed to be "self-consuming": once it starts running, /// the job memory is invalidated and the executor should not access it /// again. /// /// Jobs are generally expected to keep the actor alive during their /// execution. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_defaultActor_enqueue(Job *job, DefaultActor *actor); /// Check if the actor is a distributed 'remote' actor instance. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) bool swift_distributed_actor_is_remote(HeapObject *actor); /// Do a primitive suspension of the current task, as if part of /// a continuation, although this does not provide any of the /// higher-level continuation semantics. The current task is returned; /// its ResumeFunction and ResumeContext will need to be initialized, /// and then it will need to be enqueued or run as a job later. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) AsyncTask *swift_task_suspend(); /// Prepare a continuation in the current task. /// /// The caller should initialize the Parent, ResumeParent, /// and NormalResult fields. This function will initialize the other /// fields with appropriate defaults; the caller may then overwrite /// them if desired. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) AsyncTask *swift_continuation_init(ContinuationAsyncContext *context, AsyncContinuationFlags flags); /// Await an initialized continuation. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync) void swift_continuation_await(ContinuationAsyncContext *continuationContext); /// Resume a task from a non-throwing continuation, given a normal /// result which has already been stored into the continuation. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_continuation_resume(AsyncTask *continuation); /// Resume a task from a potentially-throwing continuation, given a /// normal result which has already been stored into the continuation. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_continuation_throwingResume(AsyncTask *continuation); /// Resume a task from a potentially-throwing continuation by throwing /// an error. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_continuation_throwingResumeWithError(AsyncTask *continuation, /* +1 */ SwiftError *error); /// SPI helper to log a misuse of a `CheckedContinuation` to the appropriate places in the OS. extern "C" SWIFT_CC(swift) void swift_continuation_logFailedCheck(const char *message); /// Drain the queue SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_task_asyncMainDrainQueue [[noreturn]](); /// Drain the global executor. This does the same as the above, but /// swift_task_asyncMainDrainQueue() is a compatibility override point, /// whereas this function has a concurrency hook. The default /// swift_task_asyncMainDrainQueue() implementation just calls this function. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_task_drainGlobalExecutor [[noreturn]](); /// Establish that the current thread is running as the given /// executor, then run a job. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_job_run(Job *job, SerialExecutorRef executor); /// Establish that the current thread is running as the given /// executor, then run a job. /// /// Runtime availability: Swift 6.0 SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_job_run_on_task_executor(Job *job, TaskExecutorRef executor); /// Establish that the current thread is running as the given /// executor, then run a job. /// /// Runtime availability: Swift 6.0 SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_job_run_on_serial_and_task_executor(Job *job, SerialExecutorRef serialExecutor, TaskExecutorRef taskExecutor); /// Return the current thread's active task reference. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) AsyncTask *swift_task_getCurrent(void); /// Return the current thread's active executor reference. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) SerialExecutorRef swift_task_getCurrentExecutor(void); /// Return the main-actor executor reference. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) SerialExecutorRef swift_task_getMainExecutor(void); /// Test if an executor is the main executor. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) bool swift_task_isMainExecutor(SerialExecutorRef executor); /// Return the preferred task executor of the current task, /// or ``TaskExecutorRef::undefined()`` if no preference. /// /// A stored preference may be `undefined` explicitly, /// which is semantically equivalent to having no preference. /// /// The returned reference must be treated carefully, /// because it is *unmanaged*, meaning that the fact /// that the task "has" this preference does not imply its lifetime. /// /// Developers who use task executor preference MUST guarantee /// their lifetime exceeds any use of such executor. For example, /// they should be created as "forever" alive singletons, or otherwise /// guarantee their lifetime extends beyond all potential uses of them by tasks. /// /// Runtime availability: Swift 9999 SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) TaskExecutorRef swift_task_getPreferredTaskExecutor(void); SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) bool swift_task_isCurrentExecutor(SerialExecutorRef executor); /// This is an options enum that is used to pass flags to /// swift_task_isCurrentExecutorWithFlags. It is meant to be a flexible toggle. /// /// Since this is an options enum, so all values should be powers of 2. /// /// NOTE: We are purposely leaving this as a uint64_t so that on all platforms /// this could be a pointer to a different enum instance if we need it to be. enum swift_task_is_current_executor_flag : uint64_t { /// We aren't passing any flags. None = 0x0, /// This is not used today, but is just future ABI reservation. /// /// The intention is that we may want the ability to tell future versions of /// the runtime that this uint64_t is actually a pointer that it should /// dereference and then have further extended behavior controlled by a /// different enum. By placing this here, we ensure that we will have a tagged /// pointer compatible flag for this purpose. TaggedPointer = 0x1, /// This is not used today, but is just future ABI reservation. /// /// \see swift_task_is_current_executor_flag::TaggedPointer TaggedPointer2 = 0x2, /// This is not used today, but is just future ABI reservation. /// /// \see swift_task_is_current_executor_flag::TaggedPointer TaggedPointer3 = 0x4, /// The routine should assert on failure. Assert = 0x8, /// The routine should use 'isIsolatingCurrentContext' function on the /// 'expected' executor instead of `checkIsolated`. HasIsIsolatingCurrentContext = 0x10, }; SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) bool swift_task_isCurrentExecutorWithFlags( SerialExecutorRef executor, swift_task_is_current_executor_flag flags); SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_task_reportUnexpectedExecutor( const unsigned char *file, uintptr_t fileLength, bool fileIsASCII, uintptr_t line, SerialExecutorRef executor); SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) JobPriority swift_task_getCurrentThreadPriority(void); SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) const char *swift_task_getCurrentTaskName(void); SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_task_startOnMainActor(AsyncTask* job); SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_task_startSynchronously(AsyncTask* job); /// Donate this thread to the global executor until either the /// given condition returns true or we've run out of cooperative /// tasks to run. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_task_donateThreadToGlobalExecutorUntil(bool (*condition)(void*), void *context); enum swift_clock_id : int { swift_clock_id_continuous = 1, swift_clock_id_suspending = 2 }; SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_get_time(long long *seconds, long long *nanoseconds, swift_clock_id clock_id); SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_get_clock_res(long long *seconds, long long *nanoseconds, swift_clock_id clock_id); #ifdef __APPLE__ /// A magic symbol whose address is the mask to apply to a frame pointer to /// signal that it is an async frame. Do not try to read the actual value of /// this global, it will crash. /// /// On ARM64_32, the address is only 32 bits, and therefore this value covers /// the top 32 bits of the in-memory frame pointer. On other 32-bit platforms, /// the bit is not used and the address is always 0. SWIFT_EXPORT_FROM(swift_Concurrency) struct { char c; } swift_async_extendedFramePointerFlags; #endif } #pragma clang diagnostic pop #endif