Files
swift-mirror/include/swift/Runtime/Concurrency.h

1113 lines
43 KiB
C++

//===--- 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/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
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<void(void*), /*throws*/ true>;
/// 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);
/// 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);
/// Allocate memory in a job.
///
/// All allocations will be rounded to a multiple of MAX_ALIGNMENT;
/// if the job does not support allocation, this will return NULL.
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
void *swift_job_allocate(Job *job, size_t size);
/// Deallocate memory in a job.
///
/// 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_job_deallocate(Job *job, void *ptr);
/// 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);
/// Enter the scope of an async let binding, creating a child task of the
/// current task to run the given function.
///
/// Behaves approximately like a Swift function with the following
/// signature, except the generic argument is in a different position:
///
/// \code
/// func swift_asyncLet_start<T>(
/// asyncLet: Builtin.RawPointer,
/// options: Builtin.RawPointer?,
/// operation: __owned @Sendable () async throws -> T,
/// resultBuffer: Builtin.RawPointer
/// )
/// \endcode
///
/// Previous versions of the concurrency runtime also provided a
/// \c swift_asyncLet_start which did not take a result buffer. This
/// function was never used by a released version of the compiler,
/// and it has been removed.
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);
/// Get the value of a non-throwing async let, awaiting the result
/// if necessary.
///
/// This must be called from the parent task of the async let.
///
/// Behaves like a Swift async function with the signature:
///
/// \code
/// func swift_asyncLet_get(
/// _ asyncLet: Builtin.RawPointer,
/// _ resultBuffer: Builtin.RawPointer
/// ) async
/// \endcode
///
/// except that it uses the special calling convention in which the
/// continuation function, parent context, and child context are all
/// passed in separately rather than being stored in the child context.
/// The child async context has a fixed size of 5 * sizeof(void*).
///
/// \c resultBuffer must be the same result buffer that was passed to
/// swift_asyncLet_begin. After asynchronous return, it is guaranteed
/// to be initialized.
///
/// Previous versions of the concurrency runtime also provided a
/// \c swift_asyncLet_wait which was meant to be paired with
/// \c swift_asyncLet_start. This function was never used by
/// a released version of the compiler, and it has been removed.
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync)
void swift_asyncLet_get(SWIFT_ASYNC_CONTEXT AsyncContext *parentContext,
AsyncLet *alet,
void *resultBuffer,
TaskContinuationFunction *continuation,
AsyncContext *childContext);
/// Get the value of a throwing async let, awaiting the result if necessary.
///
/// This must be called from the parent task of the async let.
///
/// Behaves like a Swift async function with the signature:
///
/// \code
/// func swift_asyncLet_get_throwing(
/// _ asyncLet: Builtin.RawPointer,
/// _ resultBuffer: Builtin.RawPointer
/// ) async throws
/// \endcode
///
/// except that it uses the special calling convention in which the
/// continuation function, parent context, and child context are all
/// passed in separately rather than being stored in the child context.
/// The child async context has a fixed size of 5 * sizeof(void*).
///
/// \c resultBuffer must be the same result buffer that was passed to
/// swift_asyncLet_begin. After asynchronous return, it is guaranteed
/// to be initialized unless the operation throws by passing an error
/// to the continuation function.
///
/// Previous versions of the concurrency runtime also provided a
/// \c swift_asyncLet_wait_throwing which was meant to be paired with
/// \c swift_asyncLet_start. This function was never used by
/// a released version of the compiler, and it has been removed.
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync)
void swift_asyncLet_get_throwing(SWIFT_ASYNC_CONTEXT AsyncContext *parentContext,
AsyncLet *alet,
void *resultBuffer,
ThrowingTaskFutureWaitContinuationFunction *
continuation,
AsyncContext *childContext);
/// Exit the scope of an async let binding that was created with
/// swift_asyncLet_begin. If the child task is still running, it is
/// cancelled, and the current task is suspended to await its completion.
///
/// This must be called from the parent task of the async let.
///
/// Behaves like a Swift async function with the signature:
///
/// \code
/// func swift_asyncLet_finish(_ asyncLet: Builtin.RawPointer,
/// _ resultBuffer: Builtin.RawPointer) async
/// \endcode
///
/// except that it uses the special calling convention in which the
/// continuation function, parent context, and child context are all
/// passed in separately rather than being stored in the child context.
/// The child async context has a fixed size of 5 * sizeof(void*).
///
/// \c resultBuffer must be the same result buffer that was passed to
/// swift_asyncLet_begin.
///
/// Prior to asynchronous return, the value in the result buffer is
/// destroyed (if present) and any memory initially allocated for the
/// task is deallocated. Because swift_asyncLet_begin potentially
/// allocates memory on the parent task's task allocator, the call to
/// this function must be properly paired with the begin.
///
/// The async let is invalid after this call and cannot be used again.
///
/// Previous versions of the concurrency runtime also provided a
/// \c swift_asyncLet_end which was not asynchronous and was meant
/// to be paired with \c swift_asyncLet_start. This function was never
/// used by a released version of the compiler, and it has been removed.
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 binding that was created
/// with \c swift_asyncLet_begin, awaiting the task's completion if
/// necessary, and then destroy the task and the binding.
///
/// This must be called from the parent task of the async let.
///
/// Behaves like a Swift async function with the signature:
///
/// \code
/// func swift_asyncLet_get(
/// _ asyncLet: Builtin.RawPointer,
/// _ resultBuffer: Builtin.RawPointer
/// ) async
/// \endcode
///
/// except that it uses the special calling convention in which the
/// continuation function, parent context, and child context are all
/// passed in separately rather than being stored in the child context.
/// The child async context has a fixed size of 5 * sizeof(void*).
///
/// \c resultBuffer must be the same result buffer that was passed to
/// swift_asyncLet_begin. After asynchronous return, this is guaranteed
/// to be initialized.
///
/// The async let is invalid after this call and cannot be used again.
/// Any memory initially allocated for the task is deallocated. Because
/// \c swift_asyncLet_begin potentially allocates memory on the parent
/// task's task allocator, the call to this function must be properly
/// paired with the begin.
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync)
void swift_asyncLet_consume(SWIFT_ASYNC_CONTEXT AsyncContext *callerContext,
AsyncLet *alet,
void *resultBuffer,
TaskContinuationFunction *continuation,
AsyncContext *callContext);
/// Get the value of a throwing async let binding that was created
/// with \c swift_asyncLet_begin, awaiting the task's completion if
/// necessary, and then destroy the task and the binding.
///
/// This must be called from the parent task of the async let.
///
/// Behaves like a Swift async function with the signature:
///
/// \code
/// func swift_asyncLet_get_throwing(
/// _ asyncLet: Builtin.RawPointer,
/// _ resultBuffer: Builtin.RawPointer
/// ) async throws
/// \endcode
///
/// except that it uses the special calling convention in which the
/// continuation function, parent context, and child context are all
/// passed in separately rather than being stored in the child context.
/// The child async context has a fixed size of 5 * sizeof(void*).
///
/// \c resultBuffer must be the same result buffer that was passed to
/// swift_asyncLet_begin. After asynchronous return, it is guaranteed
/// to be initialized unless the operation throws by passing an error
/// to the continuation function.
///
/// The async let is invalid after this call and cannot be used again.
/// Any memory initially allocated for the task is deallocated. Because
/// \c swift_asyncLet_begin potentially allocates memory on the parent
/// task's task allocator, the call to this function must be properly
/// paired with the begin.
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync)
void swift_asyncLet_consume_throwing(SWIFT_ASYNC_CONTEXT AsyncContext *callerContext,
AsyncLet *alet,
void *resultBuffer,
ThrowingTaskFutureWaitContinuationFunction *
continuation,
AsyncContext *callContext);
/// 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(...) { <operation> }`.
///
/// 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<Key>(
/// 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<Value>(
/// 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<Key>(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)
int8_t 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)
int8_t 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.
/// Effectively this is a backwards compatible mode.
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 MUST NOT assert on failure.
/// Even at the cost of not calling 'checkIsolated' if it is available.
MustNotAssert = 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_immediate(AsyncTask* job, SerialExecutorRef targetExecutor);
/// 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_clock_id_wall = 3
};
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