diff --git a/Runtimes/Core/Concurrency/CMakeLists.txt b/Runtimes/Core/Concurrency/CMakeLists.txt index ab7af17f61f4d..5ae60448943f4 100644 --- a/Runtimes/Core/Concurrency/CMakeLists.txt +++ b/Runtimes/Core/Concurrency/CMakeLists.txt @@ -1,5 +1,7 @@ add_subdirectory(InternalShims) +gyb_expand(TaskGroup+addTask.swift.gyb TaskGroup+addTask.swift) + add_library(swift_Concurrency Actor.cpp AsyncLet.cpp @@ -77,10 +79,11 @@ add_library(swift_Concurrency Task+TaskExecutor.swift TaskCancellation.swift TaskGroup.swift - TaskGroup+TaskExecutor.swift TaskLocal.swift TaskSleep.swift - TaskSleepDuration.swift) + TaskSleepDuration.swift + "${CMAKE_CURRENT_BINARY_DIR}/TaskGroup+addTask.swift") + include(${SwiftCore_CONCURRENCY_GLOBAL_EXECUTOR}.cmake) target_compile_definitions(swift_Concurrency PRIVATE $<$:-DSWIFT_TARGET_LIBRARY_NAME=swift_Concurrency> diff --git a/include/swift/ABI/MetadataValues.h b/include/swift/ABI/MetadataValues.h index d514b103cd752..e39f963202e8f 100644 --- a/include/swift/ABI/MetadataValues.h +++ b/include/swift/ABI/MetadataValues.h @@ -2730,6 +2730,7 @@ class JobFlags : public FlagSet { // 27 is currently unused Task_IsAsyncLetTask = 28, Task_HasInitialTaskExecutorPreference = 29, + Task_HasInitialTaskName = 30, }; // clang-format on @@ -2766,6 +2767,9 @@ class JobFlags : public FlagSet { FLAGSET_DEFINE_FLAG_ACCESSORS(Task_HasInitialTaskExecutorPreference, task_hasInitialTaskExecutorPreference, task_setHasInitialTaskExecutorPreference) + FLAGSET_DEFINE_FLAG_ACCESSORS(Task_HasInitialTaskName, + task_hasInitialTaskName, + task_setHasInitialTaskName) }; /// Kinds of task status record. @@ -2795,6 +2799,9 @@ enum class TaskStatusRecordKind : uint8_t { /// enqueued on. TaskExecutorPreference = 5, + /// A human-readable task name. + TaskName = 6, + // Kinds >= 192 are private to the implementation. First_Reserved = 192, Private_RecordLock = 192 @@ -2818,6 +2825,8 @@ enum class TaskOptionRecordKind : uint8_t { /// Set the initial task executor preference of the task. InitialTaskExecutorUnowned = 5, InitialTaskExecutorOwned = 6, + // Set a human-readable task name. + InitialTaskName = 7, /// Request a child task for swift_task_run_inline. RunInline = UINT8_MAX, }; diff --git a/include/swift/ABI/Task.h b/include/swift/ABI/Task.h index e450332b6c3d6..cf585020abdd4 100644 --- a/include/swift/ABI/Task.h +++ b/include/swift/ABI/Task.h @@ -421,6 +421,28 @@ class AsyncTask : public Job { /// Checking this is, of course, inherently race-prone on its own. bool isCancelled() const; + // ==== INITIAL TASK RECORDS ================================================= + // A task may have a number of "initial" records set, they MUST be set in the + // following order to make the task-local allocation/deallocation's stack + // discipline easy to work out at the tasks destruction: + // + // - Initial TaskName + // - Initial ExecutorPreference + + // ==== Task Naming ---------------------------------------------------------- + + /// At task creation a task may be assigned a name. + void pushInitialTaskName(const char* taskName); + void dropInitialTaskNameRecord(); + + /// Get the initial task name that was given to this task during creation, + /// or nullptr if the task has no name + const char* getTaskName(); + + bool hasInitialTaskNameRecord() const { + return Flags.task_hasInitialTaskName(); + } + // ==== Task Executor Preference --------------------------------------------- /// Get the preferred task executor reference if there is one set for this diff --git a/include/swift/ABI/TaskOptions.h b/include/swift/ABI/TaskOptions.h index 421901fc9e4bb..f1b8448e3841f 100644 --- a/include/swift/ABI/TaskOptions.h +++ b/include/swift/ABI/TaskOptions.h @@ -131,6 +131,26 @@ class InitialTaskExecutorOwnedPreferenceTaskOptionRecord } }; +class InitialTaskNameTaskOptionRecord + : public TaskOptionRecord { + + const char* TaskName; + +public: + InitialTaskNameTaskOptionRecord( + const char* taskName) + : TaskOptionRecord(TaskOptionRecordKind::InitialTaskName), + TaskName(taskName) {} + + const char* getTaskName() const { + return TaskName; + } + + static bool classof(const TaskOptionRecord *record) { + return record->getKind() == TaskOptionRecordKind::InitialTaskName; + } +}; + /// Task option to specify the initial serial executor for the task. class InitialSerialExecutorTaskOptionRecord : public TaskOptionRecord { const SerialExecutorRef Executor; diff --git a/include/swift/ABI/TaskStatus.h b/include/swift/ABI/TaskStatus.h index 8a61b0de01b65..81406ceb1db91 100644 --- a/include/swift/ABI/TaskStatus.h +++ b/include/swift/ABI/TaskStatus.h @@ -325,6 +325,22 @@ class TaskExecutorPreferenceStatusRecord : public TaskStatusRecord { } }; +class TaskNameStatusRecord : public TaskStatusRecord { +private: + const char *Name; + +public: + TaskNameStatusRecord(const char *name) + : TaskStatusRecord(TaskStatusRecordKind::TaskName), + Name(name) {} + + const char *getName() { return Name; } + + static bool classof(const TaskStatusRecord *record) { + return record->getKind() == TaskStatusRecordKind::TaskName; + } +}; + // This record is allocated for a task to record what it is dependent on before // the task can make progress again. class TaskDependencyStatusRecord : public TaskStatusRecord { diff --git a/include/swift/AST/ASTSynthesis.h b/include/swift/AST/ASTSynthesis.h index d4ee25064e87f..340124f439d81 100644 --- a/include/swift/AST/ASTSynthesis.h +++ b/include/swift/AST/ASTSynthesis.h @@ -57,6 +57,7 @@ enum SingletonTypeSynthesizer { _taskExecutor, // the '_Concurrency.TaskExecutor' protocol _actor, // the '_Concurrency.Actor' protocol _distributedActor, // the 'Distributed.DistributedActor' protocol + _unsafeRawBufferPointer // UnsafeRawBufferPointer }; inline Type synthesizeType(SynthesisContext &SC, SingletonTypeSynthesizer kind) { @@ -89,6 +90,8 @@ inline Type synthesizeType(SynthesisContext &SC, case _distributedActor: return SC.Context.getProtocol(KnownProtocolKind::DistributedActor) ->getDeclaredInterfaceType(); + case _unsafeRawBufferPointer: + return SC.Context.getUnsafeRawBufferPointerType(); case _copyable: return SC.Context.getProtocol(KnownProtocolKind::Copyable) ->getDeclaredInterfaceType(); diff --git a/include/swift/AST/Builtins.def b/include/swift/AST/Builtins.def index 6b0351691f0ef..ff7327bf7de72 100644 --- a/include/swift/AST/Builtins.def +++ b/include/swift/AST/Builtins.def @@ -954,7 +954,8 @@ BUILTIN_MISC_OPERATION(UnprotectedAddressOfBorrowOpaque, "unprotectedAddressOfBo /// createTask(flags: Int, /// initialSerialExecutor: (Builtin.Executor)? = nil, /// taskGroup: Builtin.RawPointer? = nil, -/// initialTaskExecutor: (Builtin.Executor)? = nil, +/// initialTaskExecutorDeprecated: (Builtin.Executor)? = nil, +/// initialTaskExecutorOwned: (any TaskExecutor)? = nil, /// operation: sending @escaping () async throws -> T) /// -> Builtin.NativeObject, Builtin.RawPointer) /// diff --git a/include/swift/Basic/Features.def b/include/swift/Basic/Features.def index fe0484e628a2c..ce9ec50af00d0 100644 --- a/include/swift/Basic/Features.def +++ b/include/swift/Basic/Features.def @@ -151,6 +151,7 @@ BASELINE_LANGUAGE_FEATURE(BuiltinBuildExecutor, 0, "Executor-building builtins") BASELINE_LANGUAGE_FEATURE(BuiltinBuildComplexEqualityExecutor, 0, "Executor-building for 'complexEquality executor' builtins") BASELINE_LANGUAGE_FEATURE(BuiltinBuildMainExecutor, 0, "MainActor executor building builtin") BASELINE_LANGUAGE_FEATURE(BuiltinCreateAsyncTaskOwnedTaskExecutor, 0, "Task create with owned TaskExecutor") +BASELINE_LANGUAGE_FEATURE(BuiltinCreateAsyncTaskName, 0, "Task create with a name") BASELINE_LANGUAGE_FEATURE(BuiltinCreateAsyncTaskInGroup, 0, "Task create in task group builtin with extra flags") BASELINE_LANGUAGE_FEATURE(BuiltinCreateAsyncTaskInGroupWithExecutor, 0, "Task create in task group builtin with extra flags") BASELINE_LANGUAGE_FEATURE(BuiltinCreateAsyncDiscardingTaskInGroup, 0, "Task create in discarding task group builtin, accounting for the Void return type") diff --git a/include/swift/Runtime/Concurrency.h b/include/swift/Runtime/Concurrency.h index ee4e713c592b7..e47231fc96def 100644 --- a/include/swift/Runtime/Concurrency.h +++ b/include/swift/Runtime/Concurrency.h @@ -1022,6 +1022,9 @@ void swift_task_reportUnexpectedExecutor( 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); diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index a6197ebb043f2..53712e47a9b74 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -1573,6 +1573,7 @@ static ValueDecl *getCreateTask(ASTContext &ctx, Identifier id) { _existential(_taskExecutor), /*else*/ _executor))), _nil)), + _label("taskName", _defaulted(_optional(_rawPointer), _nil)), _label("operation", _sending(_function(_async(_throws(_thick)), _typeparam(0), _parameters())))), @@ -1597,6 +1598,7 @@ static ValueDecl *getCreateDiscardingTask(ASTContext &ctx, Identifier id) { _existential(_taskExecutor), /*else*/ _executor))), _nil)), + _label("taskName", _defaulted(_optional(_rawPointer), _nil)), _label("operation", _sending(_function(_async(_throws(_thick)), _void, _parameters())))), _tuple(_nativeObject, _rawPointer)); diff --git a/lib/IRGen/GenConcurrency.cpp b/lib/IRGen/GenConcurrency.cpp index f110c45b81755..95945c087da3d 100644 --- a/lib/IRGen/GenConcurrency.cpp +++ b/lib/IRGen/GenConcurrency.cpp @@ -747,6 +747,29 @@ struct InitialTaskExecutorOwnedRecordTraits { } }; +struct InitialTaskNameRecordTraits { + static StringRef getLabel() { + return "task_name"; + } + static llvm::StructType *getRecordType(IRGenModule &IGM) { + return IGM.SwiftInitialTaskNameTaskOptionRecordTy; + } + static TaskOptionRecordFlags getRecordFlags() { + return TaskOptionRecordFlags(TaskOptionRecordKind::InitialTaskName); + } + static CanType getValueType(ASTContext &ctx) { + return ctx.TheRawPointerType; + } + + // Create 'InitialTaskNameTaskOptionRecord' + void initialize(IRGenFunction &IGF, Address recordAddr, + Explosion &taskName) const { + auto record = + IGF.Builder.CreateStructGEP(recordAddr, 1, 2 * IGF.IGM.getPointerSize()); + IGF.Builder.CreateStore(taskName.claimNext(), record); + } +}; + } // end anonymous namespace static llvm::Value * @@ -783,12 +806,20 @@ maybeAddInitialTaskExecutorOwnedOptionRecord(IRGenFunction &IGF, taskExecutorExistential); } +static llvm::Value * +maybeAddTaskNameOptionRecord(IRGenFunction &IGF, llvm::Value *prevOptions, + OptionalExplosion &taskName) { + return maybeAddOptionRecord(IGF, prevOptions, InitialTaskNameRecordTraits(), + taskName); +} + std::pair irgen::emitTaskCreate(IRGenFunction &IGF, llvm::Value *flags, OptionalExplosion &serialExecutor, OptionalExplosion &taskGroup, OptionalExplosion &taskExecutorUnowned, OptionalExplosion &taskExecutorExistential, + OptionalExplosion &taskName, Explosion &taskFunction, SubstitutionMap subs) { llvm::Value *taskOptions = @@ -825,6 +856,9 @@ irgen::emitTaskCreate(IRGenFunction &IGF, llvm::Value *flags, IGF, taskOptions, taskExecutorExistential); } + // Add an option record for the initial task name, if present. + taskOptions = maybeAddTaskNameOptionRecord(IGF, taskOptions, taskName); + // In embedded Swift, create and pass result type info. taskOptions = maybeAddEmbeddedSwiftResultTypeInfo(IGF, taskOptions, resultType); diff --git a/lib/IRGen/GenConcurrency.h b/lib/IRGen/GenConcurrency.h index ec4bc110118b7..509e948c4c553 100644 --- a/lib/IRGen/GenConcurrency.h +++ b/lib/IRGen/GenConcurrency.h @@ -106,6 +106,7 @@ emitTaskCreate(IRGenFunction &IGF, llvm::Value *flags, OptionalExplosion &taskGroup, OptionalExplosion &taskExecutorUnowned, OptionalExplosion &taskExecutorExistential, + OptionalExplosion &taskName, Explosion &taskFunction, SubstitutionMap subs); diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index 6052ea72b0242..21e0db0937f50 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -724,6 +724,11 @@ IRGenModule::IRGenModule(IRGenerator &irgen, SwiftTaskOptionRecordTy, // Base option record SwiftExecutorTy, // Executor }); + SwiftInitialTaskNameTaskOptionRecordTy = + createStructType(*this, "swift.task_name_task_option", { + SwiftTaskOptionRecordTy, // Base option record + Int8PtrTy, // Task name string (char*) + }); SwiftJobTy = createStructType(*this, "swift.job", { RefCountedStructTy, // object header Int8PtrTy, Int8PtrTy, // SchedulerPrivate diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index aed5c3f5e718d..64a41501c5e09 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -829,6 +829,7 @@ class IRGenModule { llvm::StructType *SwiftTaskGroupTaskOptionRecordTy; llvm::StructType *SwiftInitialTaskExecutorUnownedPreferenceTaskOptionRecordTy; llvm::StructType *SwiftInitialTaskExecutorOwnedPreferenceTaskOptionRecordTy; + llvm::StructType *SwiftInitialTaskNameTaskOptionRecordTy; llvm::StructType *SwiftResultTypeInfoTaskOptionRecordTy; llvm::PointerType *SwiftJobPtrTy; llvm::IntegerType *ExecutorFirstTy; diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index 8f54b1a579b6f..2f68da9171512 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -3734,19 +3734,21 @@ static void emitBuiltinStackDealloc(IRGenSILFunction &IGF, static void emitBuiltinCreateAsyncTask(IRGenSILFunction &IGF, swift::BuiltinInst *i) { - assert(i->getOperandValues().size() == 6 && - "createAsyncTask needs 6 operands"); + assert(i->getOperandValues().size() == 7 && + "createAsyncTask needs 7 operands"); auto flags = IGF.getLoweredSingletonExplosion(i->getOperand(0)); auto serialExecutor = IGF.getLoweredOptionalExplosion(i->getOperand(1)); auto taskGroup = IGF.getLoweredOptionalExplosion(i->getOperand(2)); auto taskExecutorUnowned = IGF.getLoweredOptionalExplosion(i->getOperand(3)); auto taskExecutorOwned = IGF.getLoweredOptionalExplosion(i->getOperand(4)); - Explosion taskFunction = IGF.getLoweredExplosion(i->getOperand(5)); + // %11 = enum $Optional, #Optional.some!enumelt, %10 : $UnsafeRawBufferPointer // user: %20 + auto taskName = IGF.getLoweredOptionalExplosion(i->getOperand(5)); + Explosion taskFunction = IGF.getLoweredExplosion(i->getOperand(6)); auto taskAndContext = emitTaskCreate(IGF, flags, serialExecutor, taskGroup, taskExecutorUnowned, taskExecutorOwned, - taskFunction, i->getSubstitutions()); + taskName, taskFunction, i->getSubstitutions()); Explosion out; out.add(taskAndContext.first); out.add(taskAndContext.second); diff --git a/lib/SIL/Verifier/SILVerifier.cpp b/lib/SIL/Verifier/SILVerifier.cpp index 1c196448ae884..799c73a863c3f 100644 --- a/lib/SIL/Verifier/SILVerifier.cpp +++ b/lib/SIL/Verifier/SILVerifier.cpp @@ -2427,8 +2427,8 @@ class SILVerifier : public SILVerifierBase { if (builtinKind == BuiltinValueKind::CreateAsyncTask) { requireType(BI->getType(), _object(_tuple(_nativeObject, _rawPointer)), "result of createAsyncTask"); - require(arguments.size() == 6, - "createAsyncTask expects six arguments"); + require(arguments.size() == 7, + "createAsyncTask expects seven arguments"); requireType(arguments[0]->getType(), _object(_swiftInt), "first argument of createAsyncTask"); requireType(arguments[1]->getType(), _object(_optional(_executor)), @@ -2448,7 +2448,9 @@ class SILVerifier : public SILVerifierBase { _object(_optional(_executor)), "fifth argument of createAsyncTask"); } - auto fnType = requireObjectType(SILFunctionType, arguments[5], + requireType(arguments[5]->getType(), _object(_optional(_rawPointer)), + "sixth argument of createAsyncTask"); + auto fnType = requireObjectType(SILFunctionType, arguments[6], "result of createAsyncTask"); bool haveSending = F.getASTContext().LangOpts.hasFeature(Feature::SendingArgsAndResults); diff --git a/lib/SILGen/SILGenBuiltin.cpp b/lib/SILGen/SILGenBuiltin.cpp index dac0e2fab314a..5e8ee29335033 100644 --- a/lib/SILGen/SILGenBuiltin.cpp +++ b/lib/SILGen/SILGenBuiltin.cpp @@ -1636,6 +1636,14 @@ static ManagedValue emitCreateAsyncTask(SILGenFunction &SGF, SILLocation loc, } }(); + ManagedValue taskName = [&] { + if (options & CreateTaskOptions::OptionalEverything) { + return nextArg().getAsSingleValue(SGF); + } else { + return emitOptionalNone(ctx.TheRawPointerType); + } + }(); + auto functionValue = [&] { // No reabstraction required. if (options & CreateTaskOptions::Discarding) { @@ -1693,6 +1701,7 @@ static ManagedValue emitCreateAsyncTask(SILGenFunction &SGF, SILLocation loc, taskGroup.getUnmanagedValue(), taskExecutorDeprecated.getUnmanagedValue(), taskExecutorConsuming.forward(SGF), + taskName.forward(SGF), functionValue.forward(SGF) }; diff --git a/stdlib/public/Concurrency/Actor.cpp b/stdlib/public/Concurrency/Actor.cpp index 5c7e1219d78b5..1b80ffd9e1d2c 100644 --- a/stdlib/public/Concurrency/Actor.cpp +++ b/stdlib/public/Concurrency/Actor.cpp @@ -314,6 +314,18 @@ JobPriority swift::swift_task_getCurrentThreadPriority() { #endif } +const char *swift_task_getTaskName(AsyncTask *task) { + if (!task) { + return nullptr; + } + return task->getTaskName(); +} + +const char *swift::swift_task_getCurrentTaskName() { + auto task = swift_task_getCurrent(); + return swift_task_getTaskName(task); +} + // Implemented in Swift to avoid some annoying hard-coding about // SerialExecutor's protocol witness table. We could inline this // with effort, though. diff --git a/stdlib/public/Concurrency/CMakeLists.txt b/stdlib/public/Concurrency/CMakeLists.txt index a38f4230192ad..f2fcde252df11 100644 --- a/stdlib/public/Concurrency/CMakeLists.txt +++ b/stdlib/public/Concurrency/CMakeLists.txt @@ -144,7 +144,7 @@ set(SWIFT_RUNTIME_CONCURRENCY_SWIFT_SOURCES Task+TaskExecutor.swift TaskCancellation.swift TaskGroup.swift - TaskGroup+TaskExecutor.swift + TaskGroup+Embedded.swift DiscardingTaskGroup.swift TaskLocal.swift TaskSleep.swift @@ -181,6 +181,9 @@ add_swift_target_library(swift_Concurrency ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} I ${SWIFT_RUNTIME_CONCURRENCY_EXECUTOR_SOURCES} ${SWIFT_RUNTIME_CONCURRENCY_SWIFT_SOURCES} + GYB_SOURCES + TaskGroup+addTask.swift.gyb + SWIFT_MODULE_DEPENDS_ANDROID Android SWIFT_MODULE_DEPENDS_LINUX Glibc SWIFT_MODULE_DEPENDS_LINUX_STATIC Musl diff --git a/stdlib/public/Concurrency/DiscardingTaskGroup.swift b/stdlib/public/Concurrency/DiscardingTaskGroup.swift index 940757b014fda..1de2e5311abcf 100644 --- a/stdlib/public/Concurrency/DiscardingTaskGroup.swift +++ b/stdlib/public/Concurrency/DiscardingTaskGroup.swift @@ -186,152 +186,6 @@ public struct DiscardingTaskGroup { let _: Void? = try await _taskGroupWaitAll(group: _group, bodyError: nil) } - /// Adds a child task to the group. - /// - /// - Parameters: - /// - priority: The priority of the operation task. - /// Omit this parameter or pass `.unspecified` - /// to set the child task's priority to the priority of the group. - /// - operation: The operation to execute as part of the task group. - @_alwaysEmitIntoClient - #if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY - @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model", renamed: "addTask(operation:)") - #endif - public mutating func addTask( - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async -> Void - ) { -#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY - let flags = taskCreateFlags( - priority: priority, isChildTask: true, copyTaskLocals: false, - inheritContext: false, enqueueJob: false, - addPendingGroupTaskUnconditionally: true, isDiscardingTask: true - ) -#else - let flags = taskCreateFlags( - priority: priority, isChildTask: true, copyTaskLocals: false, - inheritContext: false, enqueueJob: true, - addPendingGroupTaskUnconditionally: true, isDiscardingTask: true - ) -#endif - - // Create the task in this group. - let builtinSerialExecutor = - Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - - _ = Builtin.createDiscardingTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - operation: operation) - } - - /// Adds a child task to the group, unless the group has been canceled. - /// - /// - Parameters: - /// - priority: The priority of the operation task. - /// Omit this parameter or pass `.unspecified` - /// to set the child task's priority to the priority of the group. - /// - operation: The operation to execute as part of the task group. - /// - Returns: `true` if the child task was added to the group; - /// otherwise `false`. - @_alwaysEmitIntoClient - #if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY - @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model", renamed: "addTask(operation:)") - #endif - public mutating func addTaskUnlessCancelled( - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async -> Void - ) -> Bool { - let canAdd = _taskGroupAddPendingTask(group: _group, unconditionally: false) - - guard canAdd else { - // the group is cancelled and is not accepting any new work - return false - } -#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY - let flags = taskCreateFlags( - priority: priority, isChildTask: true, copyTaskLocals: false, - inheritContext: false, enqueueJob: false, - addPendingGroupTaskUnconditionally: false, isDiscardingTask: true - ) -#else - let flags = taskCreateFlags( - priority: priority, isChildTask: true, copyTaskLocals: false, - inheritContext: false, enqueueJob: true, - addPendingGroupTaskUnconditionally: false, isDiscardingTask: true - ) -#endif - - // Create the task in this group. - let builtinSerialExecutor = - Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - - _ = Builtin.createDiscardingTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - operation: operation) - - return true - } - - @_alwaysEmitIntoClient - public mutating func addTask( - operation: sending @escaping @isolated(any) () async -> Void - ) { - let flags = taskCreateFlags( - priority: nil, isChildTask: true, copyTaskLocals: false, - inheritContext: false, enqueueJob: true, - addPendingGroupTaskUnconditionally: true, isDiscardingTask: true - ) - - // Create the task in this group. - let builtinSerialExecutor = - Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - - _ = Builtin.createDiscardingTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - operation: operation) - } - - /// Adds a child task to the group, unless the group has been canceled. - /// - /// - Parameters: - /// - operation: The operation to execute as part of the task group. - /// - Returns: `true` if the child task was added to the group; - /// otherwise `false`. -#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY - @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model", renamed: "addTaskUnlessCancelled(operation:)") -#endif - @_alwaysEmitIntoClient - public mutating func addTaskUnlessCancelled( - operation: sending @escaping @isolated(any) () async -> Void - ) -> Bool { - let canAdd = _taskGroupAddPendingTask(group: _group, unconditionally: false) - - guard canAdd else { - // the group is cancelled and is not accepting any new work - return false - } - - let flags = taskCreateFlags( - priority: nil, isChildTask: true, copyTaskLocals: false, - inheritContext: false, enqueueJob: true, - addPendingGroupTaskUnconditionally: false, isDiscardingTask: true - ) - - // Create the task in this group. - let builtinSerialExecutor = - Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - - _ = Builtin.createDiscardingTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - operation: operation) - - return true - } - /// A Boolean value that indicates whether the group has any remaining tasks. /// /// At the start of the body of a `withDiscardingTaskGroup(of:returning:body:)` call, @@ -624,63 +478,6 @@ public struct ThrowingDiscardingTaskGroup { let _: Void? = try await _taskGroupWaitAll(group: _group, bodyError: bodyError) } -#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY - @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model", renamed: "addTask(operation:)") -#endif - @_alwaysEmitIntoClient - public mutating func addTask( - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async throws -> Void - ) { - let flags = taskCreateFlags( - priority: priority, isChildTask: true, copyTaskLocals: false, - inheritContext: false, enqueueJob: true, - addPendingGroupTaskUnconditionally: true, isDiscardingTask: true - ) - - // Create the task in this group. - let builtinSerialExecutor = - Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - - _ = Builtin.createDiscardingTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - operation: operation) - } - -#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY - @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model", renamed: "addTask(operation:)") -#endif - @_alwaysEmitIntoClient - public mutating func addTaskUnlessCancelled( - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async throws -> Void - ) -> Bool { - let canAdd = _taskGroupAddPendingTask(group: _group, unconditionally: false) - - guard canAdd else { - // the group is cancelled and is not accepting any new work - return false - } - - let flags = taskCreateFlags( - priority: priority, isChildTask: true, copyTaskLocals: false, - inheritContext: false, enqueueJob: true, - addPendingGroupTaskUnconditionally: false, isDiscardingTask: true - ) - - // Create the task in this group. - let builtinSerialExecutor = - Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - - _ = Builtin.createDiscardingTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - operation: operation) - - return true - } - /// A Boolean value that indicates whether the group has any remaining tasks. /// /// At the start of the body of a `withThrowingDiscardingTaskGroup(returning:body:)` call, diff --git a/stdlib/public/Concurrency/SourceCompatibilityShims.swift b/stdlib/public/Concurrency/SourceCompatibilityShims.swift index aafa463b38b9d..b3ffbdc8a8796 100644 --- a/stdlib/public/Concurrency/SourceCompatibilityShims.swift +++ b/stdlib/public/Concurrency/SourceCompatibilityShims.swift @@ -89,7 +89,7 @@ extension Task where Success == Never, Failure == Never { @available(SwiftStdlib 5.1, *) extension Task where Failure == Error { -#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY + #if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY @discardableResult @_alwaysEmitIntoClient @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") @@ -99,7 +99,7 @@ extension Task where Failure == Error { ) -> Task { fatalError("Unavailable in task-to-thread concurrency model") } -#else + #else @discardableResult @_alwaysEmitIntoClient @available(*, deprecated, message: "`Task.runDetached` was replaced by `Task.detached` and will be removed shortly.") @@ -109,7 +109,7 @@ extension Task where Failure == Error { ) -> Task { detached(priority: priority, operation: operation) } -#endif + #endif } #if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY @@ -264,9 +264,9 @@ extension Task where Success == Never, Failure == Never { @available(*, deprecated, message: "`Task.withGroup` was replaced by `withThrowingTaskGroup` and `withTaskGroup` and will be removed shortly.") @_alwaysEmitIntoClient public static func withGroup( - resultType: TaskResult.Type, - returning returnType: BodyResult.Type = BodyResult.self, - body: (inout Task.Group) async throws -> BodyResult + resultType: TaskResult.Type, + returning returnType: BodyResult.Type = BodyResult.self, + body: (inout Task.Group) async throws -> BodyResult ) async rethrows -> BodyResult { try await withThrowingTaskGroup(of: resultType) { group in try await body(&group) @@ -304,8 +304,8 @@ extension TaskGroup { @available(*, deprecated, renamed: "addTask(priority:operation:)") @_alwaysEmitIntoClient public mutating func add( - priority: TaskPriority? = nil, - operation: __owned @Sendable @escaping () async -> ChildTaskResult + priority: TaskPriority? = nil, + operation: __owned @Sendable @escaping () async -> ChildTaskResult ) async -> Bool { return self.addTaskUnlessCancelled(priority: priority) { await operation() @@ -353,8 +353,8 @@ extension TaskGroup { extension TaskGroup { @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model", renamed: "addTaskUnlessCancelled(operation:)") public mutating func add( - priority: TaskPriority? = nil, - operation: __owned @Sendable @escaping () async -> ChildTaskResult + priority: TaskPriority? = nil, + operation: __owned @Sendable @escaping () async -> ChildTaskResult ) async -> Bool { fatalError("Unavailable in task-to-thread concurrency model") } @@ -362,7 +362,7 @@ extension TaskGroup { @available(*, deprecated, renamed: "addTaskUnlessCancelled(operation:)") @_alwaysEmitIntoClient public mutating func add( - operation: __owned @Sendable @escaping () async -> ChildTaskResult + operation: __owned @Sendable @escaping () async -> ChildTaskResult ) async -> Bool { return self.addTaskUnlessCancelled { await operation() @@ -578,4 +578,4 @@ public typealias UnsafeThrowingContinuation = UnsafeContinuation @available(SwiftStdlib 5.1, *) @available(*, deprecated, renamed: "UnownedJob") -public typealias PartialAsyncTask = UnownedJob +public typealias PartialAsyncTask = UnownedJob \ No newline at end of file diff --git a/stdlib/public/Concurrency/Task+TaskExecutor.swift b/stdlib/public/Concurrency/Task+TaskExecutor.swift index f10493e13c1fe..e52df4c3f5888 100644 --- a/stdlib/public/Concurrency/Task+TaskExecutor.swift +++ b/stdlib/public/Concurrency/Task+TaskExecutor.swift @@ -112,7 +112,7 @@ import Swift /// /// // child tasks execute on default executor (same as case 0): /// async let x = ... -/// await withTaskGroup(of: Int.self) { group in g.addTask { 7 } } +/// await withTaskGroup(of: Int.self) { group in group.addTask { 7 } } /// } /// } /// } diff --git a/stdlib/public/Concurrency/Task.cpp b/stdlib/public/Concurrency/Task.cpp index efd730c84f5bc..32fbe9f6c9eba 100644 --- a/stdlib/public/Concurrency/Task.cpp +++ b/stdlib/public/Concurrency/Task.cpp @@ -208,6 +208,8 @@ TaskExecutorRef _task_taskExecutor_getTaskExecutorRef( TaskExecutorRef InitialTaskExecutorOwnedPreferenceTaskOptionRecord::getExecutorRefFromUnownedTaskExecutor() const { + if (!Identity) return TaskExecutorRef::undefined(); + TaskExecutorRef executorRef = _task_taskExecutor_getTaskExecutorRef( Identity, /*selfType=*/swift_getObjectType(Identity), @@ -721,6 +723,7 @@ swift_task_create_commonImpl(size_t rawTaskCreateFlags, // Collect the options we know about. SerialExecutorRef serialExecutor = SerialExecutorRef::generic(); TaskExecutorRef taskExecutor = TaskExecutorRef::undefined(); + const char* taskName = nullptr; bool taskExecutorIsOwned = false; TaskGroup *group = nullptr; AsyncLet *asyncLet = nullptr; @@ -736,8 +739,8 @@ swift_task_create_commonImpl(size_t rawTaskCreateFlags, case TaskOptionRecordKind::InitialTaskExecutorUnowned: taskExecutor = cast(option) ->getExecutorRef(); - jobFlags.task_setHasInitialTaskExecutorPreference(true); taskExecutorIsOwned = false; + jobFlags.task_setHasInitialTaskExecutorPreference(true); break; case TaskOptionRecordKind::InitialTaskExecutorOwned: @@ -751,6 +754,12 @@ swift_task_create_commonImpl(size_t rawTaskCreateFlags, #endif break; + case TaskOptionRecordKind::InitialTaskName: + taskName = cast(option) + ->getTaskName(); + jobFlags.task_setHasInitialTaskName(true); + break; + case TaskOptionRecordKind::TaskGroup: group = cast(option)->getGroup(); assert(group && "Missing group"); @@ -1123,13 +1132,14 @@ swift_task_create_commonImpl(size_t rawTaskCreateFlags, task->_private().Local.initializeLinkParent(task, parent); } - // FIXME: add discarding flag - // FIXME: add task executor concurrency::trace::task_create( task, parent, group, asyncLet, static_cast(task->Flags.getPriority()), task->Flags.task_isChildTask(), task->Flags.task_isFuture(), - task->Flags.task_isGroupChildTask(), task->Flags.task_isAsyncLetTask()); + task->Flags.task_isGroupChildTask(), task->Flags.task_isAsyncLetTask(), + taskCreateFlags.isDiscardingTask(), + task->Flags.task_hasInitialTaskExecutorPreference(), + taskName); // Attach to the group, if needed. if (group) { @@ -1155,17 +1165,24 @@ swift_task_create_commonImpl(size_t rawTaskCreateFlags, asyncLet_addImpl(task, asyncLet, !hasAsyncLetResultBuffer); } - // Task executor preference - // If the task does not have a specific executor set already via create - // options, and there is a task executor preference set in the parent, we - // inherit it by deep-copying the preference record. if - // (shouldPushTaskExecutorPreferenceRecord || taskExecutor.isDefined()) { - if (jobFlags.task_hasInitialTaskExecutorPreference()) { - // Implementation note: we must do this AFTER `swift_taskGroup_attachChild` - // because the group takes a fast-path when attaching the child record. - assert(jobFlags.task_hasInitialTaskExecutorPreference()); - task->pushInitialTaskExecutorPreference( - taskExecutor, /*owned=*/taskExecutorIsOwned); + // ==== Initial Task records + { + // Task executor preference + // If the task does not have a specific executor set already via create + // options, and there is a task executor preference set in the parent, we + // inherit it by deep-copying the preference record. if + // (shouldPushTaskExecutorPreferenceRecord || taskExecutor.isDefined()) { + if (jobFlags.task_hasInitialTaskExecutorPreference()) { + // Implementation note: we must do this AFTER `swift_taskGroup_attachChild` + // because the group takes a fast-path when attaching the child record. + task->pushInitialTaskExecutorPreference(taskExecutor, + /*owned=*/taskExecutorIsOwned); + } + + // Task name + if (jobFlags.task_hasInitialTaskName()) { + task->pushInitialTaskName(taskName); + } } // If we're supposed to enqueue the task, do so now. diff --git a/stdlib/public/Concurrency/Task.swift b/stdlib/public/Concurrency/Task.swift index e5e93ff70d09c..d8c60ca0de311 100644 --- a/stdlib/public/Concurrency/Task.swift +++ b/stdlib/public/Concurrency/Task.swift @@ -677,8 +677,7 @@ extension Task where Failure == Never { Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor let (task, _) = Builtin.createTask(flags: flags, - initialSerialExecutor: - builtinSerialExecutor, + initialSerialExecutor: builtinSerialExecutor, operation: operation) self._task = task @@ -686,6 +685,111 @@ extension Task where Failure == Never { #endif } +@available(SwiftStdlib 6.2, *) +extension Task where Failure == Never { +#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY + @discardableResult + @_alwaysEmitIntoClient + @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") + public init( + name: String? = nil, + priority: TaskPriority? = nil, + @_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async -> Success + ) { + fatalError("Unavailable in task-to-thread concurrency model.") + } +#elseif $Embedded + @discardableResult + @_alwaysEmitIntoClient + @available(SwiftStdlib 6.2, *) + public init( + name: String? = nil, + // TaskExecutor is unavailable in embedded + priority: TaskPriority? = nil, + @_inheritActorContext @_implicitSelfCapture operation: sending @escaping () async -> Success + ) { + // Set up the job flags for a new task. + let flags = taskCreateFlags( + priority: priority, isChildTask: false, copyTaskLocals: true, + inheritContext: true, enqueueJob: true, + addPendingGroupTaskUnconditionally: false, + isDiscardingTask: false) + + // Create the asynchronous task. + let (task, _) = Builtin.createAsyncTask(flags, operation) + + self._task = task + } +#else + /// Runs the given nonthrowing operation asynchronously + /// as part of a new top-level task on behalf of the current actor. + /// + /// Use this function when creating asynchronous work + /// that operates on behalf of the synchronous function that calls it. + /// Like `Task.detached(priority:operation:)`, + /// this function creates a separate, top-level task. + /// Unlike `Task.detached(priority:operation:)`, + /// the task created by `Task.init(priority:operation:)` + /// inherits the priority and actor context of the caller, + /// so the operation is treated more like an asynchronous extension + /// to the synchronous operation. + /// + /// You need to keep a reference to the task + /// if you want to cancel it by calling the `Task.cancel()` method. + /// Discarding your reference to a detached task + /// doesn't implicitly cancel that task, + /// it only makes it impossible for you to explicitly cancel the task. + /// + /// - Parameters: + /// - name: The high-level name given for this task + /// - priority: The priority of the task. + /// Pass `nil` to use the priority from `Task.currentPriority`. + /// - operation: The operation to perform. + @discardableResult + @_alwaysEmitIntoClient + @available(SwiftStdlib 6.2, *) + public init( + name: String? = nil, + priority: TaskPriority? = nil, + @_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async -> Success + ) { + // Set up the job flags for a new task. + let flags = taskCreateFlags( + priority: priority, isChildTask: false, copyTaskLocals: true, + inheritContext: true, enqueueJob: true, + addPendingGroupTaskUnconditionally: false, + isDiscardingTask: false) + + // Create the asynchronous task. + let builtinSerialExecutor = + Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor + + var task: Builtin.NativeObject? + #if $BuiltinCreateAsyncTaskName + if var name { + task = + name.utf8CString.withUnsafeBufferPointer { nameBytes in + Builtin.createTask( + flags: flags, + initialSerialExecutor: builtinSerialExecutor, + taskName: nameBytes.baseAddress!._rawValue, + operation: operation).0 + } + } + #endif + if task == nil { + // either no task name was set, or names are unsupported + task = Builtin.createTask( + flags: flags, + initialSerialExecutor: builtinSerialExecutor, + operation: operation).0 + } + + self._task = task! + } +#endif +} + @available(SwiftStdlib 5.1, *) extension Task where Failure == Error { #if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY @@ -749,6 +853,112 @@ extension Task where Failure == Error { #endif } + +@available(SwiftStdlib 6.2, *) +extension Task where Failure == Error { + #if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY + @discardableResult + @_alwaysEmitIntoClient + @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") + public init( + name: String? = nil, + priority: TaskPriority? = nil, + @_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async throws -> Success +) { + fatalError("Unavailable in task-to-thread concurrency model.") +} + #elseif $Embedded + @discardableResult + @_alwaysEmitIntoClient + @available(SwiftStdlib 6.2, *) + public init( + name: String? = nil, + // TaskExecutor is unavailable in embedded + priority: TaskPriority? = nil, + @_inheritActorContext @_implicitSelfCapture operation: sending @escaping () async throws -> Success +) { + // Set up the job flags for a new task. + let flags = taskCreateFlags( + priority: priority, isChildTask: false, copyTaskLocals: true, + inheritContext: true, enqueueJob: true, + addPendingGroupTaskUnconditionally: false, + isDiscardingTask: false) + + // Create the asynchronous task. + let (task, _) = Builtin.createAsyncTask(flags, operation) + +self._task = task +} + #else + /// Runs the given nonthrowing operation asynchronously + /// as part of a new top-level task on behalf of the current actor. + /// + /// Use this function when creating asynchronous work + /// that operates on behalf of the synchronous function that calls it. + /// Like `Task.detached(priority:operation:)`, + /// this function creates a separate, top-level task. + /// Unlike `Task.detached(priority:operation:)`, + /// the task created by `Task.init(priority:operation:)` + /// inherits the priority and actor context of the caller, + /// so the operation is treated more like an asynchronous extension + /// to the synchronous operation. + /// + /// You need to keep a reference to the task + /// if you want to cancel it by calling the `Task.cancel()` method. + /// Discarding your reference to a detached task + /// doesn't implicitly cancel that task, + /// it only makes it impossible for you to explicitly cancel the task. + /// + /// - Parameters: + /// - name: The high-level name given for this task + /// - priority: The priority of the task. + /// Pass `nil` to use the priority from `Task.currentPriority`. + /// - operation: The operation to perform. + @discardableResult + @_alwaysEmitIntoClient + @available(SwiftStdlib 6.2, *) + public init( + name: String? = nil, + priority: TaskPriority? = nil, + @_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async throws -> Success +) { + // Set up the job flags for a new task. + let flags = taskCreateFlags( + priority: priority, isChildTask: false, copyTaskLocals: true, + inheritContext: true, enqueueJob: true, + addPendingGroupTaskUnconditionally: false, + isDiscardingTask: false) + + // Create the asynchronous task. + let builtinSerialExecutor = + Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor + + var task: Builtin.NativeObject? + #if $BuiltinCreateAsyncTaskName +if var name { + task = + name.utf8CString.withUnsafeBufferPointer { nameBytes in + Builtin.createTask( + flags: flags, + initialSerialExecutor: builtinSerialExecutor, + taskName: nameBytes.baseAddress!._rawValue, + operation: operation).0 + } +} + #endif +if task == nil { + // either no task name was set, or names are unsupported + task = Builtin.createTask( + flags: flags, + initialSerialExecutor: builtinSerialExecutor, + operation: operation).0 +} + +self._task = task! +} + #endif +} + // ==== Detached Tasks --------------------------------------------------------- @available(SwiftStdlib 5.1, *) @@ -811,6 +1021,85 @@ extension Task where Failure == Never { #endif } +@available(SwiftStdlib 6.2, *) +extension Task where Failure == Never { +#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY + @discardableResult + @_alwaysEmitIntoClient + @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") + public static func detached( + name: String? = nil, + priority: TaskPriority? = nil, + operation: sending @escaping @isolated(any) () async -> Success + ) -> Task { + fatalError("Unavailable in task-to-thread concurrency model") + } +#else + /// Runs the given nonthrowing operation asynchronously + /// as part of a new top-level task. + /// + /// Don't use a detached task if it's possible + /// to model the operation using structured concurrency features like child tasks. + /// Child tasks inherit the parent task's priority and task-local storage, + /// and canceling a parent task automatically cancels all of its child tasks. + /// You need to handle these considerations manually with a detached task. + /// + /// You need to keep a reference to the detached task + /// if you want to cancel it by calling the `Task.cancel()` method. + /// Discarding your reference to a detached task + /// doesn't implicitly cancel that task, + /// it only makes it impossible for you to explicitly cancel the task. + /// + /// - Parameters: + /// - name: Human readable name of the task. + /// - priority: The priority of the task. + /// - operation: The operation to perform. + /// + /// - Returns: A reference to the task. + @discardableResult + @_alwaysEmitIntoClient + public static func detached( + name: String? = nil, + priority: TaskPriority? = nil, + operation: sending @escaping @isolated(any) () async -> Success + ) -> Task { + // Set up the job flags for a new task. + let flags = taskCreateFlags( + priority: priority, isChildTask: false, copyTaskLocals: false, + inheritContext: false, enqueueJob: true, + addPendingGroupTaskUnconditionally: false, + isDiscardingTask: false) + + // Create the asynchronous task. + let builtinSerialExecutor = + Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor + + var task: Builtin.NativeObject? + #if $BuiltinCreateAsyncTaskName + if var name { + task = + name.utf8CString.withUnsafeBufferPointer { nameBytes in + Builtin.createTask( + flags: flags, + initialSerialExecutor: builtinSerialExecutor, + taskName: nameBytes.baseAddress!._rawValue, + operation: operation).0 + } + } + #endif + if task == nil { + // either no task name was set, or names are unsupported + task = Builtin.createTask( + flags: flags, + initialSerialExecutor: builtinSerialExecutor, + operation: operation).0 + } + + return Task(task!) + } +#endif +} + @available(SwiftStdlib 5.1, *) extension Task where Failure == Error { #if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY @@ -873,6 +1162,112 @@ extension Task where Failure == Error { #endif } +@available(SwiftStdlib 6.2, *) +extension Task where Failure == Error { +#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY + @discardableResult + @_alwaysEmitIntoClient + @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") + public static func detached( + name: String? = nil, + priority: TaskPriority? = nil, + operation: sending @escaping @isolated(any) () async throws -> Success + ) -> Task { + fatalError("Unavailable in task-to-thread concurrency model") + } +#else + /// Runs the given throwing operation asynchronously + /// as part of a new top-level task. + /// + /// If the operation throws an error, this method propagates that error. + /// + /// Don't use a detached task if it's possible + /// to model the operation using structured concurrency features like child tasks. + /// Child tasks inherit the parent task's priority and task-local storage, + /// and canceling a parent task automatically cancels all of its child tasks. + /// You need to handle these considerations manually with a detached task. + /// + /// You need to keep a reference to the detached task + /// if you want to cancel it by calling the `Task.cancel()` method. + /// Discarding your reference to a detached task + /// doesn't implicitly cancel that task, + /// it only makes it impossible for you to explicitly cancel the task. + /// + /// - Parameters: + /// - priority: The priority of the task. + /// - operation: The operation to perform. + /// + /// - Returns: A reference to the task. + @discardableResult + @_alwaysEmitIntoClient + public static func detached( + name: String? = nil, + priority: TaskPriority? = nil, + operation: sending @escaping @isolated(any) () async throws -> Success + ) -> Task { + // Set up the job flags for a new task. + let flags = taskCreateFlags( + priority: priority, isChildTask: false, copyTaskLocals: false, + inheritContext: false, enqueueJob: true, + addPendingGroupTaskUnconditionally: false, + isDiscardingTask: false) + + // Create the asynchronous task future. + let builtinSerialExecutor = + Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor + + var task: Builtin.NativeObject? + #if $BuiltinCreateAsyncTaskName + if var name { + task = + name.utf8CString.withUnsafeBufferPointer { nameBytes in + Builtin.createTask( + flags: flags, + initialSerialExecutor: builtinSerialExecutor, + taskName: nameBytes.baseAddress!._rawValue, + operation: operation).0 + } + } + #endif + if task == nil { + // either no task name was set, or names are unsupported + task = Builtin.createTask( + flags: flags, + initialSerialExecutor: builtinSerialExecutor, + operation: operation).0 + } + + return Task(task!) + } +#endif +} + +// ==== 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) + /// } + /// } + /// } + /// } + @available(SwiftStdlib 6.2, *) + public static var name: String? { + return _getCurrentTaskNameString() + } +} + // ==== Voluntary Suspension ----------------------------------------------------- @available(SwiftStdlib 5.1, *) @@ -1206,6 +1601,20 @@ func _reportUnexpectedExecutor(_ _filenameStart: Builtin.RawPointer, @_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 = _getCurrentTaskName() { + String(cString: stringPtr) + } else { + nil + } +} + + #if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY @available(SwiftStdlib 5.8, *) @usableFromInline diff --git a/stdlib/public/Concurrency/TaskGroup+Embedded.swift b/stdlib/public/Concurrency/TaskGroup+Embedded.swift new file mode 100644 index 0000000000000..60e7b518b2a11 --- /dev/null +++ b/stdlib/public/Concurrency/TaskGroup+Embedded.swift @@ -0,0 +1,276 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import Swift + +// FIXME: This is a workaround for trouble including gyb-generated sources + +#if SWIFT_CONCURRENCY_EMBEDDED + +@available(SwiftStdlib 5.1, *) +extension TaskGroup { + + @available(SwiftStdlib 5.1, *) + @_alwaysEmitIntoClient + public mutating func addTask( + priority: TaskPriority? = nil, + operation: sending @escaping @isolated(any) () async -> ChildTaskResult + ) { + let flags = taskCreateFlags( + priority: priority, + isChildTask: true, + copyTaskLocals: false, + inheritContext: false, + enqueueJob: true, + addPendingGroupTaskUnconditionally: true, + isDiscardingTask: false + ) + + let builtinSerialExecutor = + Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor + + _ = Builtin.createTask( + flags: flags, + initialSerialExecutor: builtinSerialExecutor, + taskGroup: _group, + operation: operation).0 + } + + @available(SwiftStdlib 5.1, *) + @_alwaysEmitIntoClient + public mutating func addTaskUnlessCancelled( + priority: TaskPriority? = nil, + operation: sending @escaping @isolated(any) () async -> ChildTaskResult + ) -> Bool { + let canAdd = _taskGroupAddPendingTask(group: _group, unconditionally: false) + + guard canAdd else { + return false + } + + let flags = taskCreateFlags( + priority: priority, + isChildTask: true, + copyTaskLocals: false, + inheritContext: false, + enqueueJob: true, + addPendingGroupTaskUnconditionally: false, + isDiscardingTask: true + ) + + let builtinSerialExecutor = + Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor + + _ = Builtin.createTask( + flags: flags, + initialSerialExecutor: builtinSerialExecutor, + taskGroup: _group, + operation: operation).0 + + return true + } +} + +@available(SwiftStdlib 5.1, *) +extension ThrowingTaskGroup { + + @available(SwiftStdlib 5.1, *) + @_alwaysEmitIntoClient + public mutating func addTask( + priority: TaskPriority? = nil, + operation: sending @escaping @isolated(any) () async throws -> ChildTaskResult + ) { + let flags = taskCreateFlags( + priority: priority, + isChildTask: true, + copyTaskLocals: false, + inheritContext: false, + enqueueJob: true, + addPendingGroupTaskUnconditionally: true, + isDiscardingTask: false + ) + + let builtinSerialExecutor = + Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor + + _ = Builtin.createTask( + flags: flags, + initialSerialExecutor: builtinSerialExecutor, + taskGroup: _group, + operation: operation).0 + } + + @available(SwiftStdlib 5.1, *) + @_alwaysEmitIntoClient + public mutating func addTaskUnlessCancelled( + priority: TaskPriority? = nil, + operation: sending @escaping @isolated(any) () async throws -> ChildTaskResult + ) -> Bool { + let canAdd = _taskGroupAddPendingTask(group: _group, unconditionally: false) + + guard canAdd else { + return false + } + + let flags = taskCreateFlags( + priority: priority, + isChildTask: true, + copyTaskLocals: false, + inheritContext: false, + enqueueJob: true, + addPendingGroupTaskUnconditionally: false, + isDiscardingTask: true + ) + + let builtinSerialExecutor = + Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor + + _ = Builtin.createTask( + flags: flags, + initialSerialExecutor: builtinSerialExecutor, + taskGroup: _group, + operation: operation).0 + + return true + } +} + +@available(SwiftStdlib 5.9, *) +extension DiscardingTaskGroup { + + @available(SwiftStdlib 5.9, *) + @_alwaysEmitIntoClient + public mutating func addTask( + priority: TaskPriority? = nil, + operation: sending @escaping @isolated(any) () async -> Void + ) { + let flags = taskCreateFlags( + priority: priority, + isChildTask: true, + copyTaskLocals: false, + inheritContext: false, + enqueueJob: true, + addPendingGroupTaskUnconditionally: true, + isDiscardingTask: true + ) + + let builtinSerialExecutor = + Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor + + _ = Builtin.createTask( + flags: flags, + initialSerialExecutor: builtinSerialExecutor, + taskGroup: _group, + operation: operation).0 + } + + @available(SwiftStdlib 5.9, *) + @_alwaysEmitIntoClient + public mutating func addTaskUnlessCancelled( + priority: TaskPriority? = nil, + operation: sending @escaping @isolated(any) () async -> Void + ) -> Bool { + let canAdd = _taskGroupAddPendingTask(group: _group, unconditionally: false) + + guard canAdd else { + return false + } + + let flags = taskCreateFlags( + priority: priority, + isChildTask: true, + copyTaskLocals: false, + inheritContext: false, + enqueueJob: true, + addPendingGroupTaskUnconditionally: false, + isDiscardingTask: true + ) + + let builtinSerialExecutor = + Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor + + _ = Builtin.createTask( + flags: flags, + initialSerialExecutor: builtinSerialExecutor, + taskGroup: _group, + operation: operation).0 + + return true + } +} + +@available(SwiftStdlib 5.9, *) +extension ThrowingDiscardingTaskGroup { + + @available(SwiftStdlib 5.9, *) + @_alwaysEmitIntoClient + public mutating func addTask( + priority: TaskPriority? = nil, + operation: sending @escaping @isolated(any) () async throws -> Void + ) { + let flags = taskCreateFlags( + priority: priority, + isChildTask: true, + copyTaskLocals: false, + inheritContext: false, + enqueueJob: true, + addPendingGroupTaskUnconditionally: true, + isDiscardingTask: true + ) + + let builtinSerialExecutor = + Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor + + + _ = Builtin.createTask( + flags: flags, + initialSerialExecutor: builtinSerialExecutor, + taskGroup: _group, + operation: operation).0 + } + + @available(SwiftStdlib 5.9, *) + @_alwaysEmitIntoClient + public mutating func addTaskUnlessCancelled( + priority: TaskPriority? = nil, + operation: sending @escaping @isolated(any) () async throws -> Void + ) -> Bool { + let canAdd = _taskGroupAddPendingTask(group: _group, unconditionally: false) + + guard canAdd else { + return false + } + + let flags = taskCreateFlags( + priority: priority, + isChildTask: true, + copyTaskLocals: false, + inheritContext: false, + enqueueJob: true, + addPendingGroupTaskUnconditionally: false, + isDiscardingTask: true + ) + + let builtinSerialExecutor = + Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor + + _ = Builtin.createTask( + flags: flags, + initialSerialExecutor: builtinSerialExecutor, + taskGroup: _group, + operation: operation).0 + + return true + } +} + +#endif diff --git a/stdlib/public/Concurrency/TaskGroup+TaskExecutor.swift b/stdlib/public/Concurrency/TaskGroup+TaskExecutor.swift deleted file mode 100644 index 531b1ee303bb0..0000000000000 --- a/stdlib/public/Concurrency/TaskGroup+TaskExecutor.swift +++ /dev/null @@ -1,468 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 - -// None of TaskExecutor APIs are available in task-to-thread concurrency model. -#if !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY - -@_unavailableInEmbedded -@available(SwiftStdlib 6.0, *) -extension TaskGroup { - /// Adds a child task to the group and enqueue it on the specified executor. - /// - /// - Parameters: - /// - taskExecutor: The task executor that the child task should be started on and keep using. - /// Explicitly passing `nil` as the executor preference is equivalent to - /// calling the `addTask` method without a preference, and effectively - /// means to inherit the outer context's executor preference. - /// - priority: The priority of the operation task. - /// Omit this parameter or pass `.unspecified` - /// to set the child task's priority to the priority of the group. - /// - operation: The operation to execute as part of the task group. - @_alwaysEmitIntoClient - public mutating func addTask( - executorPreference taskExecutor: (any TaskExecutor)?, - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async -> ChildTaskResult - ) { - guard let taskExecutor else { - return self.addTask(priority: priority, operation: operation) - } - let flags = taskCreateFlags( - priority: priority, isChildTask: true, copyTaskLocals: false, - inheritContext: false, enqueueJob: true, - addPendingGroupTaskUnconditionally: true, - isDiscardingTask: false) - - let builtinSerialExecutor = - Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - -#if $BuiltinCreateAsyncTaskOwnedTaskExecutor - _ = Builtin.createTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - initialTaskExecutorConsuming: taskExecutor, - operation: operation) -#else - let executorBuiltin: Builtin.Executor = - taskExecutor.asUnownedTaskExecutor().executor - - _ = Builtin.createTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - initialTaskExecutor: executorBuiltin, - operation: operation) -#endif - } - - /// Adds a child task to the group and enqueue it on the specified executor, unless the group has been canceled. - /// - /// - Parameters: - /// - taskExecutor: The task executor that the child task should be started on and keep using. - /// If `nil` is passed explicitly, that parent task's executor preference (if any), - /// will be ignored. In order to inherit the parent task's executor preference - /// invoke `addTaskUnlessCancelled()` without passing a value to the `taskExecutor` parameter, - /// and it will be inherited automatically. - /// - priority: The priority of the operation task. - /// Omit this parameter or pass `.unspecified` - /// to set the child task's priority to the priority of the group. - /// - operation: The operation to execute as part of the task group. - /// - Returns: `true` if the child task was added to the group; - /// otherwise `false`. - @_alwaysEmitIntoClient - public mutating func addTaskUnlessCancelled( - executorPreference taskExecutor: (any TaskExecutor)?, - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async -> ChildTaskResult - ) -> Bool { - guard let taskExecutor else { - return self.addTaskUnlessCancelled(priority: priority, operation: operation) - } - let canAdd = _taskGroupAddPendingTask(group: _group, unconditionally: false) - - guard canAdd else { - // the group is cancelled and is not accepting any new work - return false - } - let flags = taskCreateFlags( - priority: priority, isChildTask: true, copyTaskLocals: false, - inheritContext: false, enqueueJob: true, - addPendingGroupTaskUnconditionally: false, - isDiscardingTask: false) - - // Create the task in this group with an executor preference. - let builtinSerialExecutor = - Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - -#if $BuiltinCreateAsyncTaskOwnedTaskExecutor - _ = Builtin.createTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - initialTaskExecutorConsuming: taskExecutor, - operation: operation) -#else - let executorBuiltin: Builtin.Executor = - taskExecutor.asUnownedTaskExecutor().executor - - _ = Builtin.createTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - initialTaskExecutor: executorBuiltin, - operation: operation) -#endif - - return true - } -} - -// ==== ThrowingTaskGroup ------------------------------------------------------------------------------------------------------ - -@_unavailableInEmbedded -@available(SwiftStdlib 6.0, *) -extension ThrowingTaskGroup { - /// Adds a child task to the group and enqueue it on the specified executor. - /// - /// - Parameters: - /// - taskExecutor: The task executor that the child task should be started on and keep using. - /// If `nil` is passed explicitly, that parent task's executor preference (if any), - /// will be ignored. In order to inherit the parent task's executor preference - /// invoke `addTask()` without passing a value to the `taskExecutor` parameter, - /// and it will be inherited automatically. - /// - priority: The priority of the operation task. - /// Omit this parameter or pass `.unspecified` - /// to set the child task's priority to the priority of the group. - /// - operation: The operation to execute as part of the task group. - @_alwaysEmitIntoClient - public mutating func addTask( - executorPreference taskExecutor: (any TaskExecutor)?, - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async throws -> ChildTaskResult - ) { - guard let taskExecutor else { - return self.addTask(priority: priority, operation: operation) - } - let flags = taskCreateFlags( - priority: priority, isChildTask: true, copyTaskLocals: false, - inheritContext: false, enqueueJob: true, - addPendingGroupTaskUnconditionally: true, - isDiscardingTask: false) - - // Create the task in this group with an executor preference. - let builtinSerialExecutor = - Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - -#if $BuiltinCreateAsyncTaskOwnedTaskExecutor - _ = Builtin.createTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - initialTaskExecutorConsuming: taskExecutor, - operation: operation) -#else - let executorBuiltin: Builtin.Executor = - taskExecutor.asUnownedTaskExecutor().executor - - _ = Builtin.createTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - initialTaskExecutor: executorBuiltin, - operation: operation) -#endif - } - - /// Adds a child task to the group and enqueue it on the specified executor, unless the group has been canceled. - /// - /// - Parameters: - /// - taskExecutor: The task executor that the child task should be started on and keep using. - /// - priority: The priority of the operation task. - /// Omit this parameter or pass `.unspecified` - /// to set the child task's priority to the priority of the group. - /// - operation: The operation to execute as part of the task group. - /// - Returns: `true` if the child task was added to the group; - /// otherwise `false`. - @_alwaysEmitIntoClient - public mutating func addTaskUnlessCancelled( - executorPreference taskExecutor: (any TaskExecutor)?, - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async throws -> ChildTaskResult - ) -> Bool { - guard let taskExecutor else { - return self.addTaskUnlessCancelled(priority: priority, operation: operation) - } - let canAdd = _taskGroupAddPendingTask(group: _group, unconditionally: false) - - guard canAdd else { - // the group is cancelled and is not accepting any new work - return false - } - let flags = taskCreateFlags( - priority: priority, isChildTask: true, copyTaskLocals: false, - inheritContext: false, enqueueJob: true, - addPendingGroupTaskUnconditionally: false, - isDiscardingTask: false) - - // Create the task in this group with an executor preference. - let builtinSerialExecutor = - Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - -#if $BuiltinCreateAsyncTaskOwnedTaskExecutor - _ = Builtin.createTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - initialTaskExecutorConsuming: taskExecutor, - operation: operation) -#else - let executorBuiltin: Builtin.Executor = - taskExecutor.asUnownedTaskExecutor().executor - - _ = Builtin.createTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - initialTaskExecutor: executorBuiltin, - operation: operation) -#endif - - return true - } -} - -// ==== DiscardingTaskGroup ------------------------------------------------------------------------------------------------------ - -@_unavailableInEmbedded -@available(SwiftStdlib 6.0, *) -extension DiscardingTaskGroup { - /// Adds a child task to the group and enqueue it on the specified executor. - /// - /// - Parameters: - /// - taskExecutor: The task executor that the child task should be started on and keep using. - /// If `nil` is passed explicitly, that parent task's executor preference (if any), - /// will be ignored. In order to inherit the parent task's executor preference - /// invoke `addTask()` without passing a value to the `taskExecutor` parameter, - /// and it will be inherited automatically. - /// - priority: The priority of the operation task. - /// Omit this parameter or pass `.unspecified` - /// to set the child task's priority to the priority of the group. - /// - operation: The operation to execute as part of the task group. - @_alwaysEmitIntoClient - public mutating func addTask( - executorPreference taskExecutor: (any TaskExecutor)?, - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async -> Void - ) { - guard let taskExecutor else { - return self.addTask(priority: priority, operation: operation) - } - let flags = taskCreateFlags( - priority: priority, isChildTask: true, copyTaskLocals: false, - inheritContext: false, enqueueJob: true, - addPendingGroupTaskUnconditionally: true, - isDiscardingTask: true) - - // Create the task in this group with an executor preference. - let builtinSerialExecutor = - Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - -#if $BuiltinCreateAsyncTaskOwnedTaskExecutor - _ = Builtin.createTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - initialTaskExecutorConsuming: taskExecutor, - operation: operation) -#else - let executorBuiltin: Builtin.Executor = - taskExecutor.asUnownedTaskExecutor().executor - - _ = Builtin.createTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - initialTaskExecutor: executorBuiltin, - operation: operation) -#endif - } - - /// Adds a child task to the group and set it up with the passed in task executor preference, - /// unless the group has been canceled. - /// - /// - Parameters: - /// - taskExecutor: The task executor that the child task should be started on and keep using. - /// If `nil` is passed explicitly, that parent task's executor preference (if any), - /// will be ignored. In order to inherit the parent task's executor preference - /// invoke `addTask()` without passing a value to the `taskExecutor` parameter, - /// and it will be inherited automatically. - /// - priority: The priority of the operation task. - /// Omit this parameter or pass `.unspecified` - /// to set the child task's priority to the priority of the group. - /// - operation: The operation to execute as part of the task group. - /// - Returns: `true` if the child task was added to the group; - /// otherwise `false`. - @_alwaysEmitIntoClient - public mutating func addTaskUnlessCancelled( - executorPreference taskExecutor: (any TaskExecutor)?, - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async -> Void - ) -> Bool { - guard let taskExecutor else { - return self.addTaskUnlessCancelled(priority: priority, operation: operation) - } - let canAdd = _taskGroupAddPendingTask(group: _group, unconditionally: false) - - guard canAdd else { - // the group is cancelled and is not accepting any new work - return false - } - let flags = taskCreateFlags( - priority: priority, isChildTask: true, copyTaskLocals: false, - inheritContext: false, enqueueJob: true, - addPendingGroupTaskUnconditionally: false, isDiscardingTask: true - ) - - // Create the task in this group with an executor preference. - let builtinSerialExecutor = - Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - -#if $BuiltinCreateAsyncTaskOwnedTaskExecutor - _ = Builtin.createTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - initialTaskExecutorConsuming: taskExecutor, - operation: operation) -#else - let executorBuiltin: Builtin.Executor = - taskExecutor.asUnownedTaskExecutor().executor - - _ = Builtin.createTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - initialTaskExecutor: executorBuiltin, - operation: operation) -#endif - - return true - } -} - -// ==== ThrowingDiscardingTaskGroup ------------------------------------------------------------------------------------------------------ - -@_unavailableInEmbedded -@available(SwiftStdlib 6.0, *) -extension ThrowingDiscardingTaskGroup { - /// Adds a child task to the group and set it up with the passed in task executor preference. - /// - /// - Parameters: - /// - taskExecutor: The task executor that the child task should be started on and keep using. - /// If `nil` is passed explicitly, that parent task's executor preference (if any), - /// will be ignored. In order to inherit the parent task's executor preference - /// invoke `addTask()` without passing a value to the `taskExecutor` parameter, - /// and it will be inherited automatically. - /// - priority: The priority of the operation task. - /// Omit this parameter or pass `.unspecified` - /// to set the child task's priority to the priority of the group. - /// - operation: The operation to execute as part of the task group. - @_alwaysEmitIntoClient - public mutating func addTask( - executorPreference taskExecutor: (any TaskExecutor)?, - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async throws -> Void - ) { - guard let taskExecutor else { - return self.addTask(priority: priority, operation: operation) - } - let flags = taskCreateFlags( - priority: priority, isChildTask: true, copyTaskLocals: false, - inheritContext: false, enqueueJob: true, - addPendingGroupTaskUnconditionally: true, - isDiscardingTask: true) - - // Create the task in this group with an executor preference. - let builtinSerialExecutor = - Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - -#if $BuiltinCreateAsyncTaskOwnedTaskExecutor - _ = Builtin.createTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - initialTaskExecutorConsuming: taskExecutor, - operation: operation) -#else - let executorBuiltin: Builtin.Executor = - taskExecutor.asUnownedTaskExecutor().executor - - _ = Builtin.createTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - initialTaskExecutor: executorBuiltin, - operation: operation) -#endif - } - - /// Adds a child task to the group and set it up with the passed in task executor preference, - /// unless the group has been canceled. - /// - /// - Parameters: - /// - taskExecutor: The task executor that the child task should be started on and keep using. - /// If `nil` is passed explicitly, that parent task's executor preference (if any), - /// will be ignored. In order to inherit the parent task's executor preference - /// invoke `addTask()` without passing a value to the `taskExecutor` parameter, - /// and it will be inherited automatically. - /// - priority: The priority of the operation task. - /// Omit this parameter or pass `.unspecified` - /// to set the child task's priority to the priority of the group. - /// - operation: The operation to execute as part of the task group. - /// - Returns: `true` if the child task was added to the group; - /// otherwise `false`. - @_alwaysEmitIntoClient - public mutating func addTaskUnlessCancelled( - executorPreference taskExecutor: (any TaskExecutor)?, - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async throws -> Void - ) -> Bool { - guard let taskExecutor else { - return self.addTaskUnlessCancelled(priority: priority, operation: operation) - } - let canAdd = _taskGroupAddPendingTask(group: _group, unconditionally: false) - - guard canAdd else { - // the group is cancelled and is not accepting any new work - return false - } - let flags = taskCreateFlags( - priority: priority, isChildTask: true, copyTaskLocals: false, - inheritContext: false, enqueueJob: true, - addPendingGroupTaskUnconditionally: false, isDiscardingTask: true - ) - - // Create the task in this group with an executor preference. - let builtinSerialExecutor = - Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - -#if $BuiltinCreateAsyncTaskOwnedTaskExecutor - _ = Builtin.createTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - initialTaskExecutorConsuming: taskExecutor, - operation: operation) -#else - let executorBuiltin: Builtin.Executor = - taskExecutor.asUnownedTaskExecutor().executor - - _ = Builtin.createTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - initialTaskExecutor: executorBuiltin, - operation: operation) -#endif - - return true - } -} - -#endif diff --git a/stdlib/public/Concurrency/TaskGroup+addTask.swift.gyb b/stdlib/public/Concurrency/TaskGroup+addTask.swift.gyb new file mode 100644 index 0000000000000..6b829e37ddb49 --- /dev/null +++ b/stdlib/public/Concurrency/TaskGroup+addTask.swift.gyb @@ -0,0 +1,311 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// ==== addTask / addTaskUnlessCancelled --------------------------------------- +% # Generate: +% # - both method kinds (2) +% # - for every task group kind (4) +% # - every overload that we need to keep for ABI compatibility +% # - #if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY guarded versions making the methods unavailable + +% for (IFDEF, TYPES, ALL_AVAILABILITY, ADD_TASK_METHOD_VARIANT, PARAMS) in [ +% # ----------------------------------------------------------------------- +% # === Added task name --------------------------------------------------- +% ( +% '', # no #if condition +% [ +% 'TaskGroup', +% 'ThrowingTaskGroup', +% 'DiscardingTaskGroup', +% 'ThrowingDiscardingTaskGroup' +% ], +% [ +% '@available(SwiftStdlib 6.2, *)', +% '@_unavailableInEmbedded', # since TaskExecutor is not available on embedded +% ], +% ['addTask', 'addTaskUnlessCancelled'], +% [ +% 'name: String? = nil', +% 'executorPreference taskExecutor: (any TaskExecutor)? = nil', +% 'priority: TaskPriority? = nil', +% # throws and ChildTaskResult will be adjusted per task group type +% 'operation: sending @escaping @isolated(any) () async throws -> ChildTaskResult' +% ], +% ), +% # ----------------------------------------------------------------------- +% # === Added TaskExecutor +% ( +% '', # no #if condition +% [ +% 'TaskGroup', +% 'ThrowingTaskGroup', +% 'DiscardingTaskGroup', +% 'ThrowingDiscardingTaskGroup' +% ], +% [ +% '@available(SwiftStdlib 6.0, *)', +% '@_unavailableInEmbedded', # since TaskExecutor is not available on embedded +% ], +% ['addTask', 'addTaskUnlessCancelled'], +% [ +% 'executorPreference taskExecutor: (any TaskExecutor)? = nil', +% 'priority: TaskPriority? = nil', +% # throws and ChildTaskResult will be adjusted per task group type +% 'operation: sending @escaping @isolated(any) () async throws -> ChildTaskResult' +% ], +% ), +% ( +% 'SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY', +% [ +% 'TaskGroup', +% 'ThrowingTaskGroup', +% ], +% [ +% '@available(SwiftStdlib 5.7, *)', +% '@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model", renamed: "addTask(operation:)")', +% ], +% ['addTask', 'addTaskUnlessCancelled'], +% [ +% 'priority: TaskPriority? = nil', +% # throws and ChildTaskResult will be adjusted per task group type +% 'operation: sending @escaping @isolated(any) () async throws -> ChildTaskResult' +% ], +% ), +% ( +% 'SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY', +% [ +% 'TaskGroup', +% 'ThrowingTaskGroup', +% ], +% [ +% '// version for task to thread model, without priority parameter', +% ], +% ['addTask', 'addTaskUnlessCancelled'], +% [ +% # throws and ChildTaskResult will be adjusted per task group type +% 'operation: sending @escaping @isolated(any) () async throws -> ChildTaskResult' +% ], +% ), +% # ----------------------------------------------------------------------- +% # === Baseline +% ( +% '!SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY', +% [ +% 'TaskGroup', +% 'ThrowingTaskGroup', +% ], +% [ +% '@available(SwiftStdlib 5.1, *)', +% ], +% ['addTask', 'addTaskUnlessCancelled'], +% [ +% 'priority: TaskPriority? = nil', +% # throws and ChildTaskResult will be adjusted per task group type +% 'operation: sending @escaping @isolated(any) () async throws -> ChildTaskResult' +% ], +% ), +% ]: +% +% for TYPE in TYPES: +% IS_DISCARDING = 'Discarding' in TYPE +% IS_THROWING = 'Throwing' in TYPE +% +% def adjust_params_for_group_kind(params): +% res = [] +% for p in params: +% np = p +% if IS_DISCARDING: +% np = np.replace("-> ChildTaskResult", "-> Void") +% if not IS_THROWING: +% np = np.replace("throws", "") +% res.append(np) +% return res +% +% for METHOD_NAME in ADD_TASK_METHOD_VARIANT: +% +% IS_ADD_UNLESS_CANCELLED = METHOD_NAME == "addTaskUnlessCancelled" +% IS_IMPL_UNAVAILABLE = any('Unavailable in task-to-thread' in av for av in ALL_AVAILABILITY) +% IS_TASK_TO_THREAD_MODEL = 'SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY' == IFDEF +% +% HAS_TASK_PRIORITY = any('priority:' in param for param in PARAMS) +% HAS_TASK_NAME = any('name:' in param for param in PARAMS) +% HAS_TASK_EXECUTOR = any('taskExecutor:' in param for param in PARAMS) +% +% ARROW_RETURN_TYPE = "-> Bool " if IS_ADD_UNLESS_CANCELLED else "" +% +% if IS_DISCARDING: +% TASK_CREATE_FN = 'Builtin.createDiscardingTask' +% else: +% TASK_CREATE_FN = 'Builtin.createTask' +% end + +% if IFDEF: +#if ${IFDEF} +% end + +% if IS_DISCARDING: +@available(SwiftStdlib 5.9, *) +% else: +@available(SwiftStdlib 5.1, *) +% end +extension ${TYPE} { + + % if IS_ADD_UNLESS_CANCELLED: + /// Adds a child task to the group, unless the group has been canceled. + /// Returns a boolean value indicating if the task was successfully added to the group or not. + % else: + /// Adds a child task to the group. + % end + /// + % if IS_THROWING: + /// This method doesn't throw an error, even if the child task does. + /// Instead, the corresponding call to `ThrowingTaskGroup.next()` rethrows that error. + % end + /// + /// - Parameters: + % if HAS_TASK_NAME: + /// - name: Human readable name of this task. + % end + % if HAS_TASK_EXECUTOR: + /// - taskExecutor: + /// - taskExecutor: The task executor that the child task should be started on and keep using. + /// Explicitly passing `nil` as the executor preference is equivalent to + /// calling the `addTask` method without a preference, and effectively + /// means to inherit the outer context's executor preference. + /// You can also pass the ``globalConcurrentExecutor`` global executor explicitly. + % end + % if HAS_TASK_PRIORITY: + /// - priority: The priority of the operation task. + /// Omit this parameter or pass `nil` to inherit the task group's base priority. + % end + /// Omit this parameter or pass `.unspecified` + /// to set the child task's priority to the priority of the group. + /// - operation: The operation to execute as part of the task group. + % if IS_ADD_UNLESS_CANCELLED: + /// - Returns: `true` if the child task was added to the group; + /// otherwise `false`. + % end + ${"\n ".join(ALL_AVAILABILITY)} + @_alwaysEmitIntoClient + public mutating func ${METHOD_NAME}( + ${",\n ".join(adjust_params_for_group_kind(PARAMS))} + ) ${ARROW_RETURN_TYPE}{ + % if IS_IMPL_UNAVAILABLE: + fatalError("Unavailable in task-to-thread concurrency model") + % else: # !IS_IMPL_UNAVAILABLE + % if IS_ADD_UNLESS_CANCELLED: + let canAdd = _taskGroupAddPendingTask(group: _group, unconditionally: false) + + guard canAdd else { + // the group is cancelled and is not accepting any new work + return false + } + % end # IS_ADD_UNLESS_CANCELLED + + let flags = taskCreateFlags( + priority: ${'priority' if HAS_TASK_PRIORITY else 'nil'}, + isChildTask: true, + copyTaskLocals: false, + inheritContext: false, + % if IS_TASK_TO_THREAD_MODEL: + // task-to-thread model; don't enqueue as we'll run inline + enqueueJob: false, + % else: + enqueueJob: true, + % end + % if IS_ADD_UNLESS_CANCELLED: + % # In this case, we already added the pending task count before we create the task + % # so we must not add to the pending counter again. + addPendingGroupTaskUnconditionally: false, + % else: + addPendingGroupTaskUnconditionally: true, + % end + isDiscardingTask: ${str(IS_DISCARDING).lower()} + ) + + let builtinSerialExecutor = + Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor + + var task: Builtin.NativeObject? + + % # These #if conditionals are in specific order because if we have the "latest one", + % # we definitely have the prior ones, as we always keep adding parameters. + % if HAS_TASK_NAME: + #if $BuiltinCreateAsyncTaskName + if var name { + task = + name.utf8CString.withUnsafeBufferPointer { nameBytes in + ${TASK_CREATE_FN}( + flags: flags, + initialSerialExecutor: builtinSerialExecutor, + taskGroup: _group, + initialTaskExecutorConsuming: taskExecutor, + taskName: nameBytes.baseAddress!._rawValue, + operation: operation).0 + } + } + #endif // $BuiltinCreateAsyncTaskName + % end # HAS_TASK_NAME + + // Task name was not set, or task name createTask is unavailable + % if HAS_TASK_EXECUTOR: + if task == nil, let taskExecutor { + #if $BuiltinCreateAsyncTaskOwnedTaskExecutor + task = ${TASK_CREATE_FN}( + flags: flags, + initialSerialExecutor: builtinSerialExecutor, + taskGroup: _group, + initialTaskExecutorConsuming: taskExecutor, + operation: operation).0 + #else + // legacy branch for the non-consuming task executor + let executorBuiltin: Builtin.Executor = + taskExecutor.asUnownedTaskExecutor().executor + + task = ${TASK_CREATE_FN}( + flags: flags, + initialSerialExecutor: builtinSerialExecutor, + taskGroup: _group, + initialTaskExecutor: executorBuiltin, + operation: operation).0 + #endif + } + % end + + % # The baseline fallback, if no other create calls could be used + if task == nil { + task = ${TASK_CREATE_FN}( + flags: flags, + initialSerialExecutor: builtinSerialExecutor, + taskGroup: _group, + operation: operation).0 + } + + // Assert that we did create the task, but there's no need to store it, + // as it was added to the group itself. + assert(task != nil, "Expected task to be created!") + % if IS_ADD_UNLESS_CANCELLED: + return true // task successfully enqueued + % end + % end # !IS_IMPL_UNAVAILABLE + } + +} +% if IFDEF: +#endif +% end + +% end +% end +% end diff --git a/stdlib/public/Concurrency/TaskGroup.swift b/stdlib/public/Concurrency/TaskGroup.swift index a6fedaa3e2aae..bcf1b1a1fd654 100644 --- a/stdlib/public/Concurrency/TaskGroup.swift +++ b/stdlib/public/Concurrency/TaskGroup.swift @@ -46,9 +46,9 @@ import Swift /// by calling the `cancelAll()` method on the task group, /// or by canceling the task in which the group is running. /// -/// If you call `addTask(priority:operation:)` to create a new task in a canceled group, +/// If you call `addTask(name:priority:operation:)` to create a new task in a canceled group, /// that task is immediately canceled after creation. -/// Alternatively, you can call `addTaskUnlessCancelled(priority:operation:)`, +/// Alternatively, you can call `addTaskUnlessCancelled(name:priority:operation:)`, /// which doesn't create the task if the group has already been canceled. /// Choosing between these two functions /// lets you control how to react to cancellation within a group: @@ -159,9 +159,9 @@ public func _unsafeInheritExecutor_withTaskGroup( /// by calling the `cancelAll()` method on the task group, /// or by canceling the task in which the group is running. /// -/// If you call `addTask(priority:operation:)` to create a new task in a canceled group, +/// If you call `addTask(name:priority:operation:)` to create a new task in a canceled group, /// that task is immediately canceled after creation. -/// Alternatively, you can call `addTaskUnlessCancelled(priority:operation:)`, +/// Alternatively, you can call `addTaskUnlessCancelled(name:priority:operation:)`, /// which doesn't create the task if the group has already been canceled. /// Choosing between these two functions /// lets you control how to react to cancellation within a group: @@ -307,8 +307,8 @@ public func _unsafeInheritExecutor_withThrowingTaskGroup { self._group = group } -#if !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY - /// Adds a child task to the group. - /// - /// - Parameters: - /// - priority: The priority of the operation task. - /// Omit this parameter or pass `.unspecified` - /// to set the child task's priority to the priority of the group. - /// - operation: The operation to execute as part of the task group. - @_alwaysEmitIntoClient - public mutating func addTask( - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async -> ChildTaskResult - ) { -#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY - let flags = taskCreateFlags( - priority: priority, isChildTask: true, copyTaskLocals: false, - inheritContext: false, enqueueJob: false, - addPendingGroupTaskUnconditionally: true, - isDiscardingTask: false - ) -#else - let flags = taskCreateFlags( - priority: priority, isChildTask: true, copyTaskLocals: false, - inheritContext: false, enqueueJob: true, - addPendingGroupTaskUnconditionally: true, - isDiscardingTask: false) -#endif - - // Create the task in this group. - let builtinSerialExecutor = - Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - _ = Builtin.createTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - operation: operation) - } - - /// Adds a child task to the group, unless the group has been canceled. - /// - /// - Parameters: - /// - priority: The priority of the operation task. - /// Omit this parameter or pass `.unspecified` - /// to set the child task's priority to the priority of the group. - /// - operation: The operation to execute as part of the task group. - /// - Returns: `true` if the child task was added to the group; - /// otherwise `false`. - @_alwaysEmitIntoClient - public mutating func addTaskUnlessCancelled( - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async -> ChildTaskResult - ) -> Bool { - let canAdd = _taskGroupAddPendingTask(group: _group, unconditionally: false) - - guard canAdd else { - // the group is cancelled and is not accepting any new work - return false - } -#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY - let flags = taskCreateFlags( - priority: priority, isChildTask: true, copyTaskLocals: false, - inheritContext: false, enqueueJob: false, - addPendingGroupTaskUnconditionally: false, - isDiscardingTask: false) -#else - let flags = taskCreateFlags( - priority: priority, isChildTask: true, copyTaskLocals: false, - inheritContext: false, enqueueJob: true, - addPendingGroupTaskUnconditionally: false, - isDiscardingTask: false) -#endif - - // Create the task in this group. - let builtinSerialExecutor = - Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - _ = Builtin.createTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - operation: operation) - - return true - } - -#else // if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY - @available(SwiftStdlib 5.7, *) - @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model", renamed: "addTask(operation:)") - public mutating func addTask( - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async -> ChildTaskResult - ) { - fatalError("Unavailable in task-to-thread concurrency model") - } - - /// Adds a child task to the group. - /// - /// - Parameters: - /// - operation: The operation to execute as part of the task group. - @_alwaysEmitIntoClient - public mutating func addTask( - operation: sending @escaping @isolated(any) () async -> ChildTaskResult - ) { - let flags = taskCreateFlags( - priority: nil, isChildTask: true, copyTaskLocals: false, - inheritContext: false, enqueueJob: true, - addPendingGroupTaskUnconditionally: true, - isDiscardingTask: false) - - // Create the task in this group. - let builtinSerialExecutor = - Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - _ = Builtin.createTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - operation: operation) - } - - @available(SwiftStdlib 5.7, *) - @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model", renamed: "addTaskUnlessCancelled(operation:)") - public mutating func addTaskUnlessCancelled( - priority: TaskPriority? = nil, - operation: sending @escaping () async -> ChildTaskResult - ) -> Bool { - fatalError("Unavailable in task-to-thread concurrency model") - } - - /// Adds a child task to the group, unless the group has been canceled. - /// - /// - Parameters: - /// - operation: The operation to execute as part of the task group. - /// - Returns: `true` if the child task was added to the group; - /// otherwise `false`. - @_alwaysEmitIntoClient - public mutating func addTaskUnlessCancelled( - operation: sending @escaping @isolated(any) () async -> ChildTaskResult - ) -> Bool { - let canAdd = _taskGroupAddPendingTask(group: _group, unconditionally: false) - - guard canAdd else { - // the group is cancelled and is not accepting any new work - return false - } - - let flags = taskCreateFlags( - priority: nil, isChildTask: true, copyTaskLocals: false, - inheritContext: false, enqueueJob: true, - addPendingGroupTaskUnconditionally: false, - isDiscardingTask: false) - - // Create the task in this group. - let builtinSerialExecutor = - Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - _ = Builtin.createTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - operation: operation) - - return true - } -#endif - /// Wait for the next child task to complete, /// and return the value it returned. /// @@ -777,151 +618,6 @@ public struct ThrowingTaskGroup { } } -#if !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY - /// Adds a child task to the group. - /// - /// This method doesn't throw an error, even if the child task does. - /// Instead, the corresponding call to `ThrowingTaskGroup.next()` rethrows that error. - /// - /// - Parameters: - /// - priority: The priority of the operation task. - /// Omit this parameter or pass `.unspecified` - /// to set the child task's priority to the priority of the group. - /// - operation: The operation to execute as part of the task group. - @_alwaysEmitIntoClient - public mutating func addTask( - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async throws -> ChildTaskResult - ) { - let flags = taskCreateFlags( - priority: priority, isChildTask: true, copyTaskLocals: false, - inheritContext: false, enqueueJob: true, - addPendingGroupTaskUnconditionally: true, - isDiscardingTask: false - ) - - // Create the task in this group. - let builtinSerialExecutor = - Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - _ = Builtin.createTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - operation: operation) - } - - /// Adds a child task to the group, unless the group has been canceled. - /// - /// This method doesn't throw an error, even if the child task does. - /// Instead, the corresponding call to `ThrowingTaskGroup.next()` rethrows that error. - /// - /// - Parameters: - /// - priority: The priority of the operation task. - /// Omit this parameter or pass `.unspecified` - /// to set the child task's priority to the priority of the group. - /// - operation: The operation to execute as part of the task group. - /// - Returns: `true` if the child task was added to the group; - /// otherwise `false`. - @_alwaysEmitIntoClient - public mutating func addTaskUnlessCancelled( - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async throws -> ChildTaskResult - ) -> Bool { - let canAdd = _taskGroupAddPendingTask(group: _group, unconditionally: false) - - guard canAdd else { - // the group is cancelled and is not accepting any new work - return false - } - - let flags = taskCreateFlags( - priority: priority, isChildTask: true, copyTaskLocals: false, - inheritContext: false, enqueueJob: true, - addPendingGroupTaskUnconditionally: false, - isDiscardingTask: false) - - // Create the task in this group. - let builtinSerialExecutor = - Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - _ = Builtin.createTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - operation: operation) - - return true - } -#else - @available(SwiftStdlib 5.7, *) - @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model", renamed: "addTask(operation:)") - public mutating func addTask( - priority: TaskPriority? = nil, - operation: sending @escaping () async throws -> ChildTaskResult - ) { - fatalError("Unavailable in task-to-thread concurrency model") - } - - /// Adds a child task to the group. - /// - /// This method doesn't throw an error, even if the child task does. - /// Instead, the corresponding call to `ThrowingTaskGroup.next()` rethrows that error. - /// - /// - Parameters: - /// - operation: The operation to execute as part of the task group. - @_alwaysEmitIntoClient - public mutating func addTask( - operation: sending @escaping () async throws -> ChildTaskResult - ) { - let flags = taskCreateFlags( - priority: nil, isChildTask: true, copyTaskLocals: false, - inheritContext: false, enqueueJob: true, - addPendingGroupTaskUnconditionally: true, - isDiscardingTask: false) - - // Create the task in this group. - _ = Builtin.createAsyncTaskInGroup(flags, _group, operation) - } - - @available(SwiftStdlib 5.7, *) - @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model", renamed: "addTaskUnlessCancelled(operation:)") - public mutating func addTaskUnlessCancelled( - priority: TaskPriority? = nil, - operation: sending @escaping () async throws -> ChildTaskResult - ) -> Bool { - fatalError("Unavailable in task-to-thread concurrency model") - } - - /// Adds a child task to the group, unless the group has been canceled. - /// - /// This method doesn't throw an error, even if the child task does. - /// Instead, the corresponding call to `ThrowingTaskGroup.next()` rethrows that error. - /// - /// - Parameters: - /// - operation: The operation to execute as part of the task group. - /// - Returns: `true` if the child task was added to the group; - /// otherwise `false`. - @_alwaysEmitIntoClient - public mutating func addTaskUnlessCancelled( - operation: sending @escaping () async throws -> ChildTaskResult - ) -> Bool { - let canAdd = _taskGroupAddPendingTask(group: _group, unconditionally: false) - - guard canAdd else { - // the group is cancelled and is not accepting any new work - return false - } - - let flags = taskCreateFlags( - priority: nil, isChildTask: true, copyTaskLocals: false, - inheritContext: false, enqueueJob: true, - addPendingGroupTaskUnconditionally: false, - isDiscardingTask: false) - - // Create the task in this group. - _ = Builtin.createAsyncTaskInGroup(flags, _group, operation) - - return true - } -#endif - /// Wait for the next child task to complete, /// and return the value it returned or rethrow the error it threw. /// diff --git a/stdlib/public/Concurrency/TaskPrivate.h b/stdlib/public/Concurrency/TaskPrivate.h index 361af35590ca3..afec14705b8c4 100644 --- a/stdlib/public/Concurrency/TaskPrivate.h +++ b/stdlib/public/Concurrency/TaskPrivate.h @@ -790,23 +790,29 @@ struct AsyncTask::PrivateStorage { /// Called on the thread that was previously executing the task that we are /// now trying to complete. void complete(AsyncTask *task) { - // If during task creation we created a task preference record; - // we must destroy it here; The record is task-local allocated, - // so we must do so specifically here, before the task-local storage - // elements are destroyed; in order to respect stack-discipline of - // the task-local allocator. - if (task->hasInitialTaskExecutorPreferenceRecord()) { - task->dropInitialTaskExecutorPreferenceRecord(); + // If during task creation we created a any Initial* records, destroy them. + // + // Initial records are task-local allocated, so we must do so specifically + // here, before the task-local storage elements are destroyed; in order to + // respect stack-discipline of the task-local allocator. + { + if (task->hasInitialTaskNameRecord()) { + task->dropInitialTaskNameRecord(); + } + if (task->hasInitialTaskExecutorPreferenceRecord()) { + task->dropInitialTaskExecutorPreferenceRecord(); + } } // Drain unlock the task and remove any overrides on thread as a // result of the task auto oldStatus = task->_private()._status().load(std::memory_order_relaxed); while (true) { - // Task is completing, it shouldn't have any records and therefore - // cannot be status record locked. - assert(oldStatus.getInnermostRecord() == NULL); - assert(!oldStatus.isStatusRecordLocked()); + // Task is completing + assert(oldStatus.getInnermostRecord() == NULL && + "Status records should have been removed by this time!"); + assert(!oldStatus.isStatusRecordLocked() && + "Task is completing, cannot be locked anymore!"); assert(oldStatus.isRunning()); diff --git a/stdlib/public/Concurrency/TaskStatus.cpp b/stdlib/public/Concurrency/TaskStatus.cpp index a38e3c9331213..f2288a52d8105 100644 --- a/stdlib/public/Concurrency/TaskStatus.cpp +++ b/stdlib/public/Concurrency/TaskStatus.cpp @@ -741,7 +741,7 @@ void AsyncTask::dropInitialTaskExecutorPreferenceRecord() { SWIFT_TASK_DEBUG_LOG("[InitialTaskExecutorPreference] Drop initial task " "preference record from task:%p", this); - assert(this->hasInitialTaskExecutorPreferenceRecord()); + assert(hasInitialTaskExecutorPreferenceRecord()); HeapObject *executorIdentityToRelease = nullptr; withStatusRecordLock(this, [&](ActiveTaskStatus status) { @@ -781,6 +781,89 @@ void AsyncTask::dropInitialTaskExecutorPreferenceRecord() { swift_unknownObjectRelease(executorIdentityToRelease); } +/******************************************************************************/ +/************************** TASK NAMING ***************************************/ +/******************************************************************************/ + +void AsyncTask::pushInitialTaskName(const char* _taskName) { + assert(_taskName && "Task name must not be null!"); + assert(hasInitialTaskNameRecord() && "Attempted pushing name but task has no initial task name flag!"); + + void *allocation = _swift_task_alloc_specific( + this, sizeof(class TaskNameStatusRecord)); + + // TODO: Copy the string maybe into the same allocation at an offset or retain the swift string? + char* taskNameCopy = reinterpret_cast( + _swift_task_alloc_specific(this, strlen(_taskName) + 1/*null terminator*/)); + (void) strcpy(/*dst=*/taskNameCopy, /*src=*/_taskName); + + auto record = + ::new (allocation) TaskNameStatusRecord(taskNameCopy); + SWIFT_TASK_DEBUG_LOG("[TaskName] Create initial task name record %p " + "for task:%p, name:%s", record, this, taskNameCopy); + + addStatusRecord(this, record, + [&](ActiveTaskStatus oldStatus, ActiveTaskStatus &newStatus) { + return true; // always add the record + }); +} + +void AsyncTask::dropInitialTaskNameRecord() { + if (!hasInitialTaskNameRecord()) { + return; + } + + SWIFT_TASK_DEBUG_LOG("[TaskName] Drop initial task name record for task:%p", this); + withStatusRecordLock(this, [&](ActiveTaskStatus status) { + for (auto cur : status.records()) { + if (cur->getKind() == TaskStatusRecordKind::TaskName) { + auto record = cast(cur); + + SWIFT_TASK_DEBUG_LOG("[TaskName] Drop initial task name record %p " + "for task:%p", record, this); + + removeStatusRecordLocked(status, record); + // Since we first allocated the record, and then the string copy + char *name = const_cast(record->getName()); + _swift_task_dealloc_specific(this, name); + _swift_task_dealloc_specific(this, record); + return; + } + } + + // This drop mirrors the push "initial" name during task creation; + // so it must always reliably always have a preference to drop. + assert(false && "dropInitialTaskNameRecord must be guaranteed to drop " + "the initial task name record if it was present"); + }); +} + +const char* +AsyncTask::getTaskName() { + // We first check the executor preference status flag, in order to avoid + // having to scan through the records of the task checking if there was + // such record. + // + // This is an optimization in order to make the enqueue/run + // path of a task avoid excessive work if a task had many records. + if (!hasInitialTaskNameRecord()) { + return nullptr; + } + + const char *data = nullptr; + withStatusRecordLock(this, [&](ActiveTaskStatus status) { + for (auto record : status.records()) { + if (record->getKind() == TaskStatusRecordKind::TaskName) { + auto nameRecord = cast(record); + data = nameRecord->getName(); + return; + } + } + }); + + return data; +} + /**************************************************************************/ /************************** CHILD TASK MANAGEMENT *************************/ /**************************************************************************/ @@ -906,6 +989,10 @@ static void performCancellationAction(TaskStatusRecord *record) { // Cancellation has no impact on executor preference. case TaskStatusRecordKind::TaskExecutorPreference: break; + + // Cancellation has no impact on task names. + case TaskStatusRecordKind::TaskName: + break; } // Other cases can fall through here and be ignored. @@ -974,14 +1061,6 @@ static void performEscalationAction(TaskStatusRecord *record, return; } - // Cancellation notifications can be ignore. - case TaskStatusRecordKind::CancellationNotification: - return; - - /// Executor preference we can ignore. - case TaskStatusRecordKind::TaskExecutorPreference: - return; - // Escalation notifications need to be called. case TaskStatusRecordKind::EscalationNotification: { auto notification = @@ -1002,6 +1081,15 @@ static void performEscalationAction(TaskStatusRecord *record, // anything to do anyway. case TaskStatusRecordKind::Private_RecordLock: return; + // Cancellation notifications can be ignore. + case TaskStatusRecordKind::CancellationNotification: + return; + /// Executor preference we can ignore. + case TaskStatusRecordKind::TaskExecutorPreference: + return; + /// Task names don't matter to priority escalation. + case TaskStatusRecordKind::TaskName: + return; } // Other cases can fall through here and be ignored. diff --git a/stdlib/public/Concurrency/TracingSignpost.h b/stdlib/public/Concurrency/TracingSignpost.h index af53cb9fa9225..09ac64b69f86d 100644 --- a/stdlib/public/Concurrency/TracingSignpost.h +++ b/stdlib/public/Concurrency/TracingSignpost.h @@ -182,7 +182,9 @@ inline void actor_note_job_queue(HeapObject *actor, Job *first, inline void task_create(AsyncTask *task, AsyncTask *parent, TaskGroup *group, AsyncLet *asyncLet, uint8_t jobPriority, bool isChildTask, bool isFuture, bool isGroupChildTask, - bool isAsyncLetTask) { + bool isAsyncLetTask, bool isDiscardingTask, + bool hasInitialTaskExecutorPreference, + const char* taskName) { ENSURE_LOGS(); auto id = os_signpost_id_make_with_pointer(TaskLog, task); auto parentID = parent ? parent->getTaskId() : 0; @@ -191,10 +193,12 @@ inline void task_create(AsyncTask *task, AsyncTask *parent, TaskGroup *group, "task=%" PRIx64 " resumefn=%p jobPriority=%u isChildTask=%{bool}d, isFuture=%{bool}d " "isGroupChildTask=%{bool}d isAsyncLetTask=%{bool}d parent=%" PRIx64 - " group=%p asyncLet=%p", + " group=%p asyncLet=%p " + "isDiscardingTask=%{bool}d hasInitialTaskExecutorPreference=%{bool}d " + "taskName=%{public}s", task->getTaskId(), task->getResumeFunctionForLogging(true), jobPriority, isChildTask, isFuture, isGroupChildTask, isAsyncLetTask, parentID, group, - asyncLet); + asyncLet, isDiscardingTask, hasInitialTaskExecutorPreference, taskName); } inline void task_destroy(AsyncTask *task) { diff --git a/stdlib/public/Concurrency/TracingStubs.h b/stdlib/public/Concurrency/TracingStubs.h index 5464565937935..179434e926be7 100644 --- a/stdlib/public/Concurrency/TracingStubs.h +++ b/stdlib/public/Concurrency/TracingStubs.h @@ -44,12 +44,13 @@ inline void actor_note_job_queue(HeapObject *actor, Job *first, inline void task_create(AsyncTask *task, AsyncTask *parent, TaskGroup *group, AsyncLet *asyncLet, uint8_t jobPriority, bool isChildTask, bool isFuture, bool isGroupChildTask, - bool isAsyncLetTask) {} + bool isAsyncLetTask, bool isDiscardingTask, + bool hasInitialTaskExecutorPreference, + const char* taskName) {} inline void task_destroy(AsyncTask *task) {} -inline void task_wait(AsyncTask *task, AsyncTask *waitingOn, uintptr_t status) { -} +inline void task_wait(AsyncTask *task, AsyncTask *waitingOn, uintptr_t status) {} inline void task_resume(AsyncTask *task) {} diff --git a/test/Concurrency/Runtime/async_task_naming.swift b/test/Concurrency/Runtime/async_task_naming.swift new file mode 100644 index 0000000000000..7b597a1271dd6 --- /dev/null +++ b/test/Concurrency/Runtime/async_task_naming.swift @@ -0,0 +1,115 @@ +// RUN: %target-run-simple-swift( -Xfrontend -disable-availability-checking) | %FileCheck %s + +// REQUIRES: executable_test +// REQUIRES: concurrency + +// REQUIRES: concurrency_runtime +// UNSUPPORTED: back_deployment_runtime + +func pretendToThrow() throws {} + +func test() async { + // CHECK: Task.name = NONE OK + print("Task.name = \(Task.name ?? "NONE OK")") + + _ = await Task(name: "Caplin the Task") { + // CHECK: Task.name = Caplin the Task + print("Task.name = \(Task.name ?? "NONE")") + return 12 + }.value + + _ = try? await Task(name: "Caplin the Throwing Task") { + // CHECK: Task.name = Caplin the Throwing Task + print("Task.name = \(Task.name ?? "NONE")") + try pretendToThrow() + await Task { + // CHECK: Does not inherit Task.name = NONE OK + print("Does not inherit Task.name = \(Task.name ?? "NONE OK")") + }.value + return 12 + }.value + + _ = await Task.detached(name: "Caplin the Detached Task") { + // CHECK: Task.name = Caplin the Detached Task + print("Task.name = \(Task.name ?? "NONE")") + return 12 + }.value + + _ = try? await Task.detached(name: "Caplin the Detached Throwing Task") { + // CHECK: Task.name = Caplin the Detached Throwing Task + print("Task.name = \(Task.name ?? "NONE")") + try pretendToThrow() + return 12 + }.value + + _ = await withTaskGroup(of: Int.self) { g in + g.addTask( + name: "Caplin the TaskGroup Task", + executorPreference: nil) { + // CHECK: Task.name = Caplin the TaskGroup Task + print("Task.name = \(Task.name ?? "NONE")") + return 12 + } + _ = await g.next() + _ = g.addTaskUnlessCancelled( + name: "Caplin the TaskGroup Task (unless cancelled)", + executorPreference: nil) { + // CHECK: Task.name = Caplin the TaskGroup Task (unless cancelled) + print("Task.name = \(Task.name ?? "NONE")") + return 12 + } + } + + _ = await withThrowingTaskGroup(of: Int.self) { g in + g.addTask( + name: "Caplin the ThrowingTaskGroup Task", + executorPreference: nil) { + // CHECK: Task.name = Caplin the ThrowingTaskGroup Task + print("Task.name = \(Task.name ?? "NONE")") + return 12 + } + _ = try? await g.next() + _ = g.addTaskUnlessCancelled( + name: "Caplin the ThrowingTaskGroup Task (unless cancelled)", + executorPreference: nil) { + // CHECK: Task.name = Caplin the ThrowingTaskGroup Task (unless cancelled) + print("Task.name = \(Task.name ?? "NONE")") + return 12 + } + } + + _ = await withDiscardingTaskGroup { g in + g.addTask( + name: "Caplin the DiscardingTaskGroup Task", + executorPreference: nil) { + // CHECK: Task.name = Caplin the DiscardingTaskGroup Task + print("Task.name = \(Task.name ?? "NONE")") + } + } + _ = await withDiscardingTaskGroup { g in + _ = g.addTaskUnlessCancelled( + name: "Caplin the DiscardingTaskGroup Task (unless cancelled)", + executorPreference: nil) { + // CHECK: Task.name = Caplin the DiscardingTaskGroup Task (unless cancelled) + print("Task.name = \(Task.name ?? "NONE")") + } + } + _ = try? await withThrowingDiscardingTaskGroup { g in + g.addTask( + name: "Caplin the ThrowingDiscardingTaskGroup Task", + executorPreference: nil) { + // CHECK: Task.name = Caplin the ThrowingDiscardingTaskGroup Task + print("Task.name = \(Task.name ?? "NONE")") + } + } + _ = try? await withThrowingDiscardingTaskGroup { g in + _ = g.addTaskUnlessCancelled( + name: "Caplin the ThrowingDiscardingTaskGroup Task (unless cancelled)", + executorPreference: nil) { + // CHECK: Task.name = Caplin the ThrowingDiscardingTaskGroup Task (unless cancelled) + print("Task.name = \(Task.name ?? "NONE")") + } + } +} + +await test() diff --git a/test/Concurrency/async_main.swift b/test/Concurrency/async_main.swift index 358c4b0a3770f..9fd02723d1f2f 100644 --- a/test/Concurrency/async_main.swift +++ b/test/Concurrency/async_main.swift @@ -71,11 +71,12 @@ func asyncFunc() async { // CHECK-SIL-NEXT: [[GROUP:%.*]] = enum $Optional, #Optional.none // CHECK-SIL-NEXT: [[TASK_EXECUTOR_UNOWNED:%.*]] = enum $Optional, #Optional.none // CHECK-SIL-NEXT: [[TASK_EXECUTOR_OWNED:%.*]] = enum $Optional, #Optional.none +// CHECK-SIL-NEXT: [[TASK_NAME:%.*]] = enum $Optional, #Optional.none // CHECK-SIL-NEXT: // function_ref thunk for @escaping @convention(thin) @async () -> () // CHECK-SIL-NEXT: [[THUNK_FN:%.*]] = function_ref @$sIetH_yts5Error_pIegHrzo_TR : $@convention(thin) @async (@convention(thin) @async () -> ()) -> (@out (), @error any Error) // CHECK-SIL-NEXT: [[THUNK:%.*]] = partial_apply [callee_guaranteed] [[THUNK_FN]]([[ASYNC_MAIN_FN]]) : $@convention(thin) @async (@convention(thin) @async () -> ()) -> (@out (), @error any Error) // CHECK-SIL-NEXT: [[CONVERTED_THUNK:%.*]] = convert_function [[THUNK]] : $@async @callee_guaranteed () -> (@out (), @error any Error) to $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for <()> -// CHECK-SIL-NEXT: [[TASK_RESULT:%.*]] = builtin "createAsyncTask"<()>([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[GROUP]] : $Optional, [[TASK_EXECUTOR_UNOWNED]] : $Optional, [[TASK_EXECUTOR_OWNED]] : $Optional, [[CONVERTED_THUNK]] : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for <()>) : $(Builtin.NativeObject, Builtin.RawPointer) +// CHECK-SIL-NEXT: [[TASK_RESULT:%.*]] = builtin "createAsyncTask"<()>([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[GROUP]] : $Optional, [[TASK_EXECUTOR_UNOWNED]] : $Optional, [[TASK_EXECUTOR_OWNED]] : $Optional, [[TASK_NAME]] : $Optional, [[CONVERTED_THUNK]] : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for <()>) : $(Builtin.NativeObject, Builtin.RawPointer) // CHECK-SIL-NEXT: [[TASK:%.*]] = tuple_extract [[TASK_RESULT]] : $(Builtin.NativeObject, Builtin.RawPointer), 0 // CHECK-SIL-NEXT: // function_ref swift_job_run // CHECK-SIL-NEXT: [[RUN_FN:%.*]] = function_ref @swift_job_run : $@convention(thin) (UnownedJob, UnownedSerialExecutor) -> () diff --git a/test/Concurrency/async_task_locals_basic_warnings.swift b/test/Concurrency/async_task_locals_basic_warnings.swift index d82f3a5b6c62f..7e751d038629d 100644 --- a/test/Concurrency/async_task_locals_basic_warnings.swift +++ b/test/Concurrency/async_task_locals_basic_warnings.swift @@ -3,6 +3,7 @@ // RUN: %target-swift-frontend -I %t -plugin-path %swift-plugin-dir -target %target-swift-5.1-abi-triple -strict-concurrency=complete -parse-as-library %s -emit-sil -o /dev/null -verify // RUN: %target-swift-frontend -I %t -plugin-path %swift-plugin-dir -target %target-swift-5.1-abi-triple -strict-concurrency=complete -parse-as-library %s -emit-sil -o /dev/null -verify -enable-upcoming-feature RegionBasedIsolation +// RUN: %target-swift-frontend -I %t -plugin-path %swift-plugin-dir -disable-availability-checking -swift-version 6 -parse-as-library %s -emit-sil -o /dev/null -verify // REQUIRES: concurrency // REQUIRES: swift_feature_RegionBasedIsolation diff --git a/test/IRGen/async/builtins.sil b/test/IRGen/async/builtins.sil index ba47613d8f1e0..9ad7f105d3919 100644 --- a/test/IRGen/async/builtins.sil +++ b/test/IRGen/async/builtins.sil @@ -39,7 +39,8 @@ bb0(%flags : $Int, %taskFunction: @owned $@async @callee_guaranteed @substituted %optTaskGroup = enum $Optional, #Optional.none %optTaskExecutor = enum $Optional, #Optional.none %optTaskExecutorOwned = enum $Optional, #Optional.none - %20 = builtin "createAsyncTask"(%flags : $Int, %optSerialExecutor : $Optional, %optTaskGroup : $Optional, %optTaskExecutor : $Optional, %optTaskExecutorOwned : $Optional, %taskFunction : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error Error) for ) : $(Builtin.NativeObject, Builtin.RawPointer) + %taskName = enum $Optional, #Optional.none + %20 = builtin "createAsyncTask"(%flags : $Int, %optSerialExecutor : $Optional, %optTaskGroup : $Optional, %optTaskExecutor : $Optional, %optTaskExecutorOwned : $Optional, %taskName : $Optional, %taskFunction : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error Error) for ) : $(Builtin.NativeObject, Builtin.RawPointer) destroy_value %20 : $(Builtin.NativeObject, Builtin.RawPointer) %21 = tuple () return %21 : $() @@ -65,7 +66,8 @@ bb0(%flags : $Int, %serialExecutor : $Builtin.Executor, %taskFunction: @owned $@ %optTaskGroup = enum $Optional, #Optional.none %optTaskExecutor = enum $Optional, #Optional.none %optTaskExecutorOwned = enum $Optional, #Optional.none - %20 = builtin "createAsyncTask"(%flags : $Int, %optSerialExecutor : $Optional, %optTaskGroup : $Optional, %optTaskExecutor : $Optional, %optTaskExecutorOwned : $Optional, %taskFunction : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error Error) for ) : $(Builtin.NativeObject, Builtin.RawPointer) + %taskName = enum $Optional, #Optional.none + %20 = builtin "createAsyncTask"(%flags : $Int, %optSerialExecutor : $Optional, %optTaskGroup : $Optional, %optTaskExecutor : $Optional, %optTaskExecutorOwned : $Optional, %taskName : $Optional, %taskFunction : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error Error) for ) : $(Builtin.NativeObject, Builtin.RawPointer) destroy_value %20 : $(Builtin.NativeObject, Builtin.RawPointer) %21 = tuple () return %21 : $() @@ -88,7 +90,8 @@ bb0(%taskGroup : $Builtin.RawPointer, %taskFunction : $@async @callee_guaranteed %optTaskGroup = enum $Optional, #Optional.some!enumelt, %taskGroup : $Builtin.RawPointer %optTaskExecutor = enum $Optional, #Optional.none %optTaskExecutorOwned = enum $Optional, #Optional.none - %9 = builtin "createAsyncTask"(%flags : $Int, %optSerialExecutor : $Optional, %optTaskGroup : $Optional, %optTaskExecutor : $Optional, %optTaskExecutorOwned : $Optional, %taskFunction : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error Error) for ) : $(Builtin.NativeObject, Builtin.RawPointer) + %taskName = enum $Optional, #Optional.none + %9 = builtin "createAsyncTask"(%flags : $Int, %optSerialExecutor : $Optional, %optTaskGroup : $Optional, %optTaskExecutor : $Optional, %optTaskExecutorOwned : $Optional, %taskName : $Optional, %taskFunction : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error Error) for ) : $(Builtin.NativeObject, Builtin.RawPointer) %10 = tuple_extract %9 : $(Builtin.NativeObject, Builtin.RawPointer), 0 strong_release %10 : $Builtin.NativeObject %12 = tuple () @@ -118,7 +121,8 @@ bb0(%flags : $Int, %optTaskGroup : $Optional, %taskFunction: %optSerialExecutor = enum $Optional, #Optional.none %optTaskExecutor = enum $Optional, #Optional.none %optTaskExecutorOwned = enum $Optional, #Optional.none - %20 = builtin "createAsyncTask"(%flags : $Int, %optSerialExecutor : $Optional, %optTaskGroup : $Optional, %optTaskExecutor : $Optional, %optTaskExecutorOwned : $Optional, %taskFunction : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error Error) for ) : $(Builtin.NativeObject, Builtin.RawPointer) + %taskName = enum $Optional, #Optional.none + %20 = builtin "createAsyncTask"(%flags : $Int, %optSerialExecutor : $Optional, %optTaskGroup : $Optional, %optTaskExecutor : $Optional, %optTaskExecutorOwned : $Optional, %taskName : $Optional, %taskFunction : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error Error) for ) : $(Builtin.NativeObject, Builtin.RawPointer) destroy_value %20 : $(Builtin.NativeObject, Builtin.RawPointer) %result = tuple () return %result : $() @@ -131,9 +135,10 @@ bb0(%taskGroup : $Builtin.RawPointer, %taskFunction : $@async @callee_guaranteed %optTaskGroup = enum $Optional, #Optional.some!enumelt, %taskGroup : $Builtin.RawPointer %optTaskExecutor = enum $Optional, #Optional.none %optTaskExecutorOwned = enum $Optional, #Optional.none + %taskName = enum $Optional, #Optional.none // CHECK-NOT: br i1 // CHECK: call swift{{(tail)?}}cc %swift.async_task_and_context @swift_task_create( - %9 = builtin "createAsyncTask"(%flags : $Int, %optSerialExecutor : $Optional, %optTaskGroup : $Optional, %optTaskExecutor : $Optional, %optTaskExecutorOwned : $Optional, %taskFunction : $@async @callee_guaranteed () -> @error Error) : $(Builtin.NativeObject, Builtin.RawPointer) + %9 = builtin "createAsyncTask"(%flags : $Int, %optSerialExecutor : $Optional, %optTaskGroup : $Optional, %optTaskExecutor : $Optional, %optTaskExecutorOwned : $Optional, %taskName : $Optional, %taskFunction : $@async @callee_guaranteed () -> @error Error) : $(Builtin.NativeObject, Builtin.RawPointer) %10 = tuple_extract %9 : $(Builtin.NativeObject, Builtin.RawPointer), 0 strong_release %10 : $Builtin.NativeObject %12 = tuple () @@ -147,6 +152,7 @@ bb0(%taskGroup : $Builtin.RawPointer, %taskExecutor : $Builtin.Executor, %taskFu %optTaskGroup = enum $Optional, #Optional.some!enumelt, %taskGroup : $Builtin.RawPointer %optTaskExecutor = enum $Optional, #Optional.some!enumelt, %taskExecutor : $Builtin.Executor %optTaskExecutorOwned = enum $Optional, #Optional.none + %taskName = enum $Optional, #Optional.none // CHECK: [[GROUP_RECORD:%.*]] = alloca %swift.task_group_task_option // CHECK: [[EXECUTOR_RECORD:%.*]] = alloca %swift.task_executor_task_option // CHECK-NOT: br i1 @@ -171,7 +177,7 @@ bb0(%taskGroup : $Builtin.RawPointer, %taskExecutor : $Builtin.Executor, %taskFu // CHECK: store [[INT]] %2, ptr [[EXECUTOR_IMPL_GEP]], align // CHECK: call swift{{(tail)?}}cc %swift.async_task_and_context @swift_task_create([[INT]] %5, ptr [[EXECUTOR_RECORD]] - %9 = builtin "createAsyncTask"(%flags : $Int, %optSerialExecutor : $Optional, %optTaskGroup : $Optional, %optTaskExecutor: $Optional, %optTaskExecutorOwned : $Optional, %taskFunction : $@async @callee_guaranteed () -> @error Error) : $(Builtin.NativeObject, Builtin.RawPointer) + %9 = builtin "createAsyncTask"(%flags : $Int, %optSerialExecutor : $Optional, %optTaskGroup : $Optional, %optTaskExecutor: $Optional, %optTaskExecutorOwned : $Optional, %taskName : $Optional, %taskFunction : $@async @callee_guaranteed () -> @error Error) : $(Builtin.NativeObject, Builtin.RawPointer) %10 = tuple_extract %9 : $(Builtin.NativeObject, Builtin.RawPointer), 0 strong_release %10 : $Builtin.NativeObject %12 = tuple () @@ -185,8 +191,9 @@ bb0(%flags : $Int, %taskGroup : $Builtin.RawPointer, %taskFunction: @owned $@asy %optTaskGroup = enum $Optional, #Optional.some!enumelt, %taskGroup : $Builtin.RawPointer %optTaskExecutor = enum $Optional, #Optional.none %optTaskExecutorOwned = enum $Optional, #Optional.none + %taskName = enum $Optional, #Optional.none // CHECK: [[NEW_TASK_AND_CONTEXT:%.*]] = call swift{{(tail)?}}cc %swift.async_task_and_context @swift_task_create( - %20 = builtin "createAsyncTask"<()>(%flags : $Int, %optSerialExecutor : $Optional, %optTaskGroup : $Optional, %optTaskExecutor : $Optional, %optTaskExecutorOwned : $Optional, %taskFunction : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error Error) for <()>) : $(Builtin.NativeObject, Builtin.RawPointer) + %20 = builtin "createAsyncTask"<()>(%flags : $Int, %optSerialExecutor : $Optional, %optTaskGroup : $Optional, %optTaskExecutor : $Optional, %optTaskExecutorOwned : $Optional, %taskName : $Optional, %taskFunction : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error Error) for <()>) : $(Builtin.NativeObject, Builtin.RawPointer) destroy_value %20 : $(Builtin.NativeObject, Builtin.RawPointer) %21 = tuple () return %21 : $() diff --git a/test/SILGen/async_builtins.swift b/test/SILGen/async_builtins.swift index 03cebdcec4b09..b7358581eea0b 100644 --- a/test/SILGen/async_builtins.swift +++ b/test/SILGen/async_builtins.swift @@ -22,10 +22,11 @@ public struct X { // CHECK: [[GROUP:%.*]] = enum $Optional, #Optional.none // CHECK: [[TASK_EXECUTOR:%.*]] = enum $Optional, #Optional.none // CHECK: [[TASK_EXECUTOR_OWNED:%.*]] = enum $Optional<[[TASK_EXECUTOR_OWNED_TYPE:.*]]>, #Optional.none + // CHECK: [[TASK_NAME:%.*]] = enum $Optional, #Optional.none // CHECK: [[CLOSURE_FN:%.*]] = function_ref @$s4test1XV12launchFutureyyxlFxyYaKcfU_ : // CHECK: [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE_FN]]({{.*}}) : $@convention(thin) @async <τ_0_0> (@in_guaranteed τ_0_0) -> (@out τ_0_0, @error any Error) // CHECK: [[CONVERTED_CLOSURE:%.*]] = convert_function [[CLOSURE]] : $@async @callee_guaranteed () -> (@out T, @error any Error) to $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for - // CHECK: builtin "createAsyncTask"([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[GROUP]] : $Optional, [[TASK_EXECUTOR]] : $Optional, [[TASK_EXECUTOR_OWNED]] : $Optional<[[TASK_EXECUTOR_OWNED_TYPE]]>, [[CONVERTED_CLOSURE]] : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for ) : $(Builtin.NativeObject, Builtin.RawPointer) + // CHECK: builtin "createAsyncTask"([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[GROUP]] : $Optional, [[TASK_EXECUTOR]] : $Optional, [[TASK_EXECUTOR_OWNED]] : $Optional<[[TASK_EXECUTOR_OWNED_TYPE]]>, [[TASK_NAME]] : $Optional, [[CONVERTED_CLOSURE]] : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for ) : $(Builtin.NativeObject, Builtin.RawPointer) func launchFuture(_ value: T) { _ = Builtin.createAsyncTask(0) { () async throws -> T in return value @@ -38,10 +39,11 @@ public struct X { // CHECK: [[GROUP:%.*]] = enum $Optional, #Optional.some!enumelt, %1 : $Builtin.RawPointer // CHECK: [[TASK_EXECUTOR:%.*]] = enum $Optional, #Optional.none // CHECK: [[TASK_EXECUTOR_OWNED:%.*]] = enum $Optional<[[TASK_EXECUTOR_OWNED_TYPE:.*]]>, #Optional.none + // CHECK: [[TASK_NAME:%.*]] = enum $Optional, #Optional.none // CHECK: [[CLOSURE_FN:%.*]] = function_ref @$s4test1XV16launchGroupChild_5groupyx_BptlFxyYaKcfU_ : // CHECK: [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE_FN]]({{.*}}) : $@convention(thin) @async <τ_0_0> (@in_guaranteed τ_0_0) -> (@out τ_0_0, @error any Error) // CHECK: [[CONVERTED_CLOSURE:%.*]] = convert_function [[CLOSURE]] : $@async @callee_guaranteed () -> (@out T, @error any Error) to $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for - // CHECK: builtin "createAsyncTask"([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[GROUP]] : $Optional, [[TASK_EXECUTOR]] : $Optional, [[TASK_EXECUTOR_OWNED]] : $Optional<[[TASK_EXECUTOR_OWNED_TYPE]]>, [[CONVERTED_CLOSURE]] : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for ) : $(Builtin.NativeObject, Builtin.RawPointer) + // CHECK: builtin "createAsyncTask"([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[GROUP]] : $Optional, [[TASK_EXECUTOR]] : $Optional, [[TASK_EXECUTOR_OWNED]] : $Optional<[[TASK_EXECUTOR_OWNED_TYPE]]>, [[TASK_NAME]] : $Optional, [[CONVERTED_CLOSURE]] : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for ) : $(Builtin.NativeObject, Builtin.RawPointer) func launchGroupChild(_ value: T, group: Builtin.RawPointer) { _ = Builtin.createAsyncTaskInGroup(0, group) { () async throws -> T in return value @@ -54,9 +56,10 @@ public struct X { // CHECK: [[GROUP:%.*]] = enum $Optional, #Optional.some!enumelt, %0 : $Builtin.RawPointer // CHECK: [[TASK_EXECUTOR:%.*]] = enum $Optional, #Optional.none // CHECK: [[TASK_EXECUTOR_OWNED:%.*]] = enum $Optional<[[TASK_EXECUTOR_OWNED_TYPE:.*]]>, #Optional.none + // CHECK: [[TASK_NAME:%.*]] = enum $Optional, #Optional.none // CHECK: [[CLOSURE_FN:%.*]] = function_ref @$s4test1XV26launchDiscardingGroupChild5groupyBp_tFyyYaKcfU_ : // CHECK: [[CLOSURE:%.*]] = thin_to_thick_function [[CLOSURE_FN]] - // CHECK: builtin "createAsyncTask"([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[GROUP]] : $Optional, [[TASK_EXECUTOR]] : $Optional, [[TASK_EXECUTOR_OWNED]] : $Optional<[[TASK_EXECUTOR_OWNED_TYPE]]>, [[CLOSURE]] : $@async @callee_guaranteed () -> @error any Error) : $(Builtin.NativeObject, Builtin.RawPointer) + // CHECK: builtin "createAsyncTask"([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[GROUP]] : $Optional, [[TASK_EXECUTOR]] : $Optional, [[TASK_EXECUTOR_OWNED]] : $Optional<[[TASK_EXECUTOR_OWNED_TYPE]]>, [[TASK_NAME]] : $Optional, [[CLOSURE]] : $@async @callee_guaranteed () -> @error any Error) : $(Builtin.NativeObject, Builtin.RawPointer) func launchDiscardingGroupChild(group: Builtin.RawPointer) { _ = Builtin.createAsyncDiscardingTaskInGroup(0, group) { () async throws in return @@ -73,10 +76,11 @@ public struct X { // CHECK: [[GROUP:%.*]] = enum $Optional, #Optional.none // CHECK: [[TASK_EXECUTOR:%.*]] = enum $Optional, #Optional.some!enumelt, %1 : $Builtin.Executor // CHECK: [[TASK_EXECUTOR_OWNED:%.*]] = enum $Optional<[[TASK_EXECUTOR_OWNED_TYPE:.*]]>, #Optional.none + // CHECK: [[TASK_NAME:%.*]] = enum $Optional, #Optional.none // CHECK: [[CLOSURE_FN:%.*]] = function_ref @$s4test1XV24launchFutureWithExecutor_8executoryx_BetlFxyYaKcfU_ : // CHECK: [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE_FN]]({{.*}}) : $@convention(thin) @async <τ_0_0> (@in_guaranteed τ_0_0) -> (@out τ_0_0, @error any Error) // CHECK: [[CONVERTED_CLOSURE:%.*]] = convert_function [[CLOSURE]] : $@async @callee_guaranteed () -> (@out T, @error any Error) to $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for - // CHECK: builtin "createAsyncTask"([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[GROUP]] : $Optional, [[TASK_EXECUTOR]] : $Optional, [[TASK_EXECUTOR_OWNED]] : $Optional<[[TASK_EXECUTOR_OWNED_TYPE]]>, [[CONVERTED_CLOSURE]] : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for ) : $(Builtin.NativeObject, Builtin.RawPointer) + // CHECK: builtin "createAsyncTask"([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[GROUP]] : $Optional, [[TASK_EXECUTOR]] : $Optional, [[TASK_EXECUTOR_OWNED]] : $Optional<[[TASK_EXECUTOR_OWNED_TYPE]]>, [[TASK_NAME]] : $Optional, [[CONVERTED_CLOSURE]] : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for ) : $(Builtin.NativeObject, Builtin.RawPointer) func launchFutureWithExecutor(_ value: T, executor: Builtin.Executor) { _ = Builtin.createAsyncTaskWithExecutor(0, executor) { () async throws -> T in return value @@ -89,9 +93,10 @@ public struct X { // CHECK: [[GROUP:%.*]] = enum $Optional, #Optional.some!enumelt, %0 : $Builtin.RawPointer // CHECK: [[TASK_EXECUTOR:%.*]] = enum $Optional, #Optional.some!enumelt, %1 : $Builtin.Executor // CHECK: [[TASK_EXECUTOR_OWNED:%.*]] = enum $Optional<[[TASK_EXECUTOR_OWNED_TYPE:.*]]>, #Optional.none + // CHECK: [[TASK_NAME:%.*]] = enum $Optional, #Optional.none // CHECK: [[CLOSURE_FN:%.*]] = function_ref @$s4test1XV34launchDiscardingFutureWithExecutor5group8executoryBp_BetFyyYaKcfU_ : // CHECK: [[CLOSURE:%.*]] = thin_to_thick_function [[CLOSURE_FN]] - // CHECK: builtin "createAsyncTask"([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[GROUP]] : $Optional, [[TASK_EXECUTOR]] : $Optional, [[TASK_EXECUTOR_OWNED]] : $Optional<[[TASK_EXECUTOR_OWNED_TYPE]]>, [[CLOSURE]] : $@async @callee_guaranteed () -> @error any Error) : $(Builtin.NativeObject, Builtin.RawPointer) + // CHECK: builtin "createAsyncTask"([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[GROUP]] : $Optional, [[TASK_EXECUTOR]] : $Optional, [[TASK_EXECUTOR_OWNED]] : $Optional<[[TASK_EXECUTOR_OWNED_TYPE]]>, [[TASK_NAME]] : $Optional, [[CLOSURE]] : $@async @callee_guaranteed () -> @error any Error) : $(Builtin.NativeObject, Builtin.RawPointer) func launchDiscardingFutureWithExecutor(group: Builtin.RawPointer, executor: Builtin.Executor) { _ = Builtin.createAsyncDiscardingTaskInGroupWithExecutor(0, group, executor) { () async throws in return @@ -105,9 +110,10 @@ public struct X { // CHECK-NEXT: [[OPT_GROUP:%.*]] = enum $Optional, #Optional.none // CHECK-NEXT: [[OPT_TASK_EXECUTOR:%.*]] = enum $Optional, #Optional.none // CHECK: [[TASK_EXECUTOR_OWNED:%.*]] = enum $Optional<[[TASK_EXECUTOR_OWNED_TYPE:.*]]>, #Optional.none +// CHECK: [[TASK_NAME:%.*]] = enum $Optional, #Optional.none // CHECK: [[CLOSURE:%.*]] = partial_apply // CHECK-NEXT: [[CONVERTED_CLOSURE:%.*]] = convert_function [[CLOSURE]] : $@async @callee_guaranteed () -> (@out T, @error any Error) to $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for -// CHECK-NEXT: builtin "createAsyncTask"([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[OPT_GROUP]] : $Optional, [[OPT_TASK_EXECUTOR]] : $Optional, [[TASK_EXECUTOR_OWNED]] : $Optional<[[TASK_EXECUTOR_OWNED_TYPE]]>, [[CONVERTED_CLOSURE]] : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for ) : $(Builtin.NativeObject, Builtin.RawPointer) +// CHECK-NEXT: builtin "createAsyncTask"([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[OPT_GROUP]] : $Optional, [[OPT_TASK_EXECUTOR]] : $Optional, [[TASK_EXECUTOR_OWNED]] : $Optional<[[TASK_EXECUTOR_OWNED_TYPE]]>, [[TASK_NAME]] : $Optional, [[CONVERTED_CLOSURE]] : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for ) : $(Builtin.NativeObject, Builtin.RawPointer) func testCreateTask(value: T) { _ = Builtin.createTask(flags: 0) { value @@ -120,9 +126,10 @@ func testCreateTask(value: T) { // CHECK-NEXT: [[OPT_GROUP:%.*]] = enum $Optional, #Optional.some!enumelt, %0 : $Builtin.RawPointer // CHECK-NEXT: [[OPT_TASK_EXECUTOR:%.*]] = enum $Optional, #Optional.none // CHECK: [[TASK_EXECUTOR_OWNED:%.*]] = enum $Optional<[[TASK_EXECUTOR_OWNED_TYPE:.*]]>, #Optional.none +// CHECK: [[TASK_NAME:%.*]] = enum $Optional, #Optional.none // CHECK: [[CLOSURE:%.*]] = partial_apply // CHECK-NEXT: [[CONVERTED_CLOSURE:%.*]] = convert_function [[CLOSURE]] : $@async @callee_guaranteed () -> (@out T, @error any Error) to $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for -// CHECK-NEXT: builtin "createAsyncTask"([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[OPT_GROUP]] : $Optional, [[OPT_TASK_EXECUTOR]] : $Optional, [[TASK_EXECUTOR_OWNED]] : $Optional<[[TASK_EXECUTOR_OWNED_TYPE]]>, [[CONVERTED_CLOSURE]] : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for ) : $(Builtin.NativeObject, Builtin.RawPointer) +// CHECK-NEXT: builtin "createAsyncTask"([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[OPT_GROUP]] : $Optional, [[OPT_TASK_EXECUTOR]] : $Optional, [[TASK_EXECUTOR_OWNED]] : $Optional<[[TASK_EXECUTOR_OWNED_TYPE]]>, [[TASK_NAME]] : $Optional, [[CONVERTED_CLOSURE]] : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for ) : $(Builtin.NativeObject, Builtin.RawPointer) func testCreateTask(group: Builtin.RawPointer, value: T) { _ = Builtin.createTask(flags: 0, taskGroup: group) { value @@ -135,9 +142,10 @@ func testCreateTask(group: Builtin.RawPointer, value: T) { // CHECK-NEXT: [[OPT_GROUP:%.*]] = enum $Optional, #Optional.none // CHECK-NEXT: [[OPT_TASK_EXECUTOR:%.*]] = enum $Optional, #Optional.some!enumelt, %0 : $Builtin.Executor // CHECK: [[TASK_EXECUTOR_OWNED:%.*]] = enum $Optional<[[TASK_EXECUTOR_OWNED_TYPE:.*]]>, #Optional.none +// CHECK: [[TASK_NAME:%.*]] = enum $Optional, #Optional.none // CHECK: [[CLOSURE:%.*]] = partial_apply // CHECK-NEXT: [[CONVERTED_CLOSURE:%.*]] = convert_function [[CLOSURE]] : $@async @callee_guaranteed () -> (@out T, @error any Error) to $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for -// CHECK-NEXT: builtin "createAsyncTask"([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[OPT_GROUP]] : $Optional, [[OPT_TASK_EXECUTOR]] : $Optional, [[TASK_EXECUTOR_OWNED]] : $Optional<[[TASK_EXECUTOR_OWNED_TYPE]]>, [[CONVERTED_CLOSURE]] : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for ) : $(Builtin.NativeObject, Builtin.RawPointer) +// CHECK-NEXT: builtin "createAsyncTask"([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[OPT_GROUP]] : $Optional, [[OPT_TASK_EXECUTOR]] : $Optional, [[TASK_EXECUTOR_OWNED]] : $Optional<[[TASK_EXECUTOR_OWNED_TYPE]]>, [[TASK_NAME]] : $Optional, [[CONVERTED_CLOSURE]] : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for ) : $(Builtin.NativeObject, Builtin.RawPointer) func testCreateTask(taskExecutor: Builtin.Executor, value: T) { _ = Builtin.createTask(flags: 0, initialTaskExecutor: taskExecutor) { value @@ -150,9 +158,10 @@ func testCreateTask(taskExecutor: Builtin.Executor, value: T) { // CHECK-NEXT: [[OPT_GROUP:%.*]] = enum $Optional, #Optional.none // CHECK-NEXT: [[OPT_TASK_EXECUTOR:%.*]] = enum $Optional, #Optional.none // CHECK: [[TASK_EXECUTOR_OWNED:%.*]] = enum $Optional<[[TASK_EXECUTOR_OWNED_TYPE:.*]]>, #Optional.none +// CHECK: [[TASK_NAME:%.*]] = enum $Optional, #Optional.none // CHECK: [[CLOSURE:%.*]] = partial_apply // CHECK-NEXT: [[CONVERTED_CLOSURE:%.*]] = convert_function [[CLOSURE]] : $@async @callee_guaranteed () -> (@out T, @error any Error) to $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for -// CHECK-NEXT: builtin "createAsyncTask"([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[OPT_GROUP]] : $Optional, [[OPT_TASK_EXECUTOR]] : $Optional, [[TASK_EXECUTOR_OWNED]] : $Optional<[[TASK_EXECUTOR_OWNED_TYPE]]>, [[CONVERTED_CLOSURE]] : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for ) : $(Builtin.NativeObject, Builtin.RawPointer) +// CHECK-NEXT: builtin "createAsyncTask"([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[OPT_GROUP]] : $Optional, [[OPT_TASK_EXECUTOR]] : $Optional, [[TASK_EXECUTOR_OWNED]] : $Optional<[[TASK_EXECUTOR_OWNED_TYPE]]>, [[TASK_NAME]] : $Optional, [[CONVERTED_CLOSURE]] : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for ) : $(Builtin.NativeObject, Builtin.RawPointer) func testCreateTask(serialExecutor: Builtin.Executor, value: T) { _ = Builtin.createTask(flags: 0, initialSerialExecutor: serialExecutor) { value @@ -164,15 +173,32 @@ func testCreateTask(serialExecutor: Builtin.Executor, value: T) { // CHECK-NEXT: [[OPT_GROUP:%.*]] = enum $Optional, #Optional.some!enumelt, %0 : $Builtin.RawPointer // CHECK-NEXT: [[OPT_TASK_EXECUTOR:%.*]] = enum $Optional, #Optional.some!enumelt, %1 : $Builtin.Executor // CHECK: [[TASK_EXECUTOR_OWNED:%.*]] = enum $Optional<[[TASK_EXECUTOR_OWNED_TYPE:.*]]>, #Optional.none +// CHECK: [[TASK_NAME:%.*]] = enum $Optional, #Optional.none // CHECK: [[CLOSURE:%.*]] = partial_apply // CHECK-NEXT: [[CONVERTED_CLOSURE:%.*]] = convert_function [[CLOSURE]] : $@async @callee_guaranteed () -> (@out T, @error any Error) to $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for -// CHECK-NEXT: builtin "createAsyncTask"([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[OPT_GROUP]] : $Optional, [[OPT_TASK_EXECUTOR]] : $Optional, [[TASK_EXECUTOR_OWNED]] : $Optional<[[TASK_EXECUTOR_OWNED_TYPE]]>, [[CONVERTED_CLOSURE]] : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for ) : $(Builtin.NativeObject, Builtin.RawPointer) +// CHECK-NEXT: builtin "createAsyncTask"([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[OPT_GROUP]] : $Optional, [[OPT_TASK_EXECUTOR]] : $Optional, [[TASK_EXECUTOR_OWNED]] : $Optional<[[TASK_EXECUTOR_OWNED_TYPE]]>, [[TASK_NAME]] : $Optional, [[CONVERTED_CLOSURE]] : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for ) : $(Builtin.NativeObject, Builtin.RawPointer) func testCreateTask(group: Builtin.RawPointer, executor: Builtin.Executor, value: T) { _ = Builtin.createTask(flags: 0, taskGroup: group, initialTaskExecutor: executor) { value } } +// CHECK-LABEL: sil hidden [ossa] @$s4test0A15CreateNamedTask5group8executor4name5valueyBp_BeBpxtlF +// CHECK: [[FLAGS:%.*]] = apply +// CHECK-NEXT: [[OPT_SERIAL_EXECUTOR:%.*]] = enum $Optional, #Optional.none!enumelt +// CHECK-NEXT: [[OPT_GROUP:%.*]] = enum $Optional, #Optional.some!enumelt, %0 : $Builtin.RawPointer +// CHECK-NEXT: [[OPT_TASK_EXECUTOR:%.*]] = enum $Optional, #Optional.some!enumelt, %1 : $Builtin.Executor +// CHECK: [[TASK_EXECUTOR_OWNED:%.*]] = enum $Optional<[[TASK_EXECUTOR_OWNED_TYPE:.*]]>, #Optional.none +// CHECK: [[TASK_NAME:%.*]] = enum $Optional, #Optional.some!enumelt, %2 : $Builtin.RawPointer +// CHECK: [[CLOSURE:%.*]] = partial_apply +// CHECK-NEXT: [[CONVERTED_CLOSURE:%.*]] = convert_function [[CLOSURE]] : $@async @callee_guaranteed () -> (@out T, @error any Error) to $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for +// CHECK-NEXT: builtin "createAsyncTask"([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[OPT_GROUP]] : $Optional, [[OPT_TASK_EXECUTOR]] : $Optional, [[TASK_EXECUTOR_OWNED]] : $Optional<[[TASK_EXECUTOR_OWNED_TYPE]]>, [[TASK_NAME]] : $Optional, [[CONVERTED_CLOSURE]] : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for ) : $(Builtin.NativeObject, Builtin.RawPointer) +func testCreateNamedTask(group: Builtin.RawPointer, executor: Builtin.Executor, name: Builtin.RawPointer, value: T) { + _ = Builtin.createTask(flags: 0, taskGroup: group, initialTaskExecutor: executor, taskName: name) { + value + } +} + // A discarding task without a group is not currently a legal // combination; if we start enforcing that, feel free to change this // as needed. @@ -182,8 +208,9 @@ func testCreateTask(group: Builtin.RawPointer, executor: Builtin.Executor, va // CHECK-NEXT: [[OPT_GROUP:%.*]] = enum $Optional, #Optional.none // CHECK-NEXT: [[OPT_TASK_EXECUTOR:%.*]] = enum $Optional, #Optional.none // CHECK: [[TASK_EXECUTOR_OWNED:%.*]] = enum $Optional<[[TASK_EXECUTOR_OWNED_TYPE:.*]]>, #Optional.none +// CHECK: [[TASK_NAME:%.*]] = enum $Optional, #Optional.none // CHECK: [[CLOSURE:%.*]] = partial_apply -// CHECK-NEXT: builtin "createAsyncTask"([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[OPT_GROUP]] : $Optional, [[OPT_TASK_EXECUTOR]] : $Optional, [[TASK_EXECUTOR_OWNED]] : $Optional<[[TASK_EXECUTOR_OWNED_TYPE]]>, [[CLOSURE]] : $@async @callee_guaranteed () -> @error any Error) : $(Builtin.NativeObject, Builtin.RawPointer) +// CHECK-NEXT: builtin "createAsyncTask"([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[OPT_GROUP]] : $Optional, [[OPT_TASK_EXECUTOR]] : $Optional, [[TASK_EXECUTOR_OWNED]] : $Optional<[[TASK_EXECUTOR_OWNED_TYPE]]>, [[TASK_NAME]] : $Optional, [[CLOSURE]] : $@async @callee_guaranteed () -> @error any Error) : $(Builtin.NativeObject, Builtin.RawPointer) func testCreateDiscardingTask(value: T) { _ = Builtin.createDiscardingTask(flags: 0) { _ = value @@ -199,13 +226,15 @@ func testCreateDiscardingTask(value: T) { // CHECK-NEXT: [[OPT_GROUP:%.*]] = enum $Optional, #Optional.some!enumelt, %0 : $Builtin.RawPointer // CHECK-NEXT: [[OPT_TASK_EXECUTOR:%.*]] = enum $Optional, #Optional.some!enumelt, %1 : $Builtin.Executor // CHECK: [[TASK_EXECUTOR_OWNED:%.*]] = enum $Optional<[[TASK_EXECUTOR_OWNED_TYPE:.*]]>, #Optional.none +// CHECK: [[TASK_NAME:%.*]] = enum $Optional, #Optional.none // CHECK: [[CLOSURE:%.*]] = partial_apply -// CHECK-NEXT: builtin "createAsyncTask"([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[OPT_GROUP]] : $Optional, [[OPT_TASK_EXECUTOR]] : $Optional, [[TASK_EXECUTOR_OWNED]] : $Optional<[[TASK_EXECUTOR_OWNED_TYPE]]>, [[CLOSURE]] : $@async @callee_guaranteed () -> @error any Error) : $(Builtin.NativeObject, Builtin.RawPointer) +// CHECK-NEXT: builtin "createAsyncTask"([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[OPT_GROUP]] : $Optional, [[OPT_TASK_EXECUTOR]] : $Optional, [[TASK_EXECUTOR_OWNED]] : $Optional<[[TASK_EXECUTOR_OWNED_TYPE]]>, [[TASK_NAME]] : $Optional, [[CLOSURE]] : $@async @callee_guaranteed () -> @error any Error) : $(Builtin.NativeObject, Builtin.RawPointer) func testCreateDiscardingTask(group: Builtin.RawPointer, executor: Builtin.Executor, value: T) { _ = Builtin.createDiscardingTask(flags: 0, taskGroup: group, initialTaskExecutor: executor) { _ = value } } + // CHECK-LABEL: sil [ossa] @$s4test26usesWithUnsafeContinuationyyYaF : $@convention(thin) @async () -> () { public func usesWithUnsafeContinuation() async { // trivial resume type diff --git a/test/abi/macOS/arm64/concurrency.swift b/test/abi/macOS/arm64/concurrency.swift index d7198e513ac90..e0968cea980f7 100644 --- a/test/abi/macOS/arm64/concurrency.swift +++ b/test/abi/macOS/arm64/concurrency.swift @@ -383,3 +383,8 @@ Added: _$sSct16escalatePriority_2toySct_ScPtFZ Added: _$sScT16escalatePriority_2toyScTyxq_G_ScPtFZ Added: _$ss33withTaskPriorityEscalationHandler9operation02onC9Escalated9isolationxxyYaq_YKXE_yScPYbXEScA_pSgYitYaq_YKs5ErrorR_r0_lF Added: _$ss33withTaskPriorityEscalationHandler9operation02onC9Escalated9isolationxxyYaq_YKXE_yScPYbXEScA_pSgYitYaq_YKs5ErrorR_r0_lFTu + +// task names +Added: _$sScTss5NeverORszABRs_rlE4nameSSSgvgZ +Added: _$sScTss5NeverORszABRs_rlE4nameSSSgvpZMV +Added: _swift_task_getCurrentTaskName \ No newline at end of file diff --git a/test/abi/macOS/x86_64/concurrency.swift b/test/abi/macOS/x86_64/concurrency.swift index 02b8852656961..96c50db4dbc7d 100644 --- a/test/abi/macOS/x86_64/concurrency.swift +++ b/test/abi/macOS/x86_64/concurrency.swift @@ -383,3 +383,8 @@ Added: _$sSct16escalatePriority_2toySct_ScPtFZ Added: _$sScT16escalatePriority_2toyScTyxq_G_ScPtFZ Added: _$ss33withTaskPriorityEscalationHandler9operation02onC9Escalated9isolationxxyYaq_YKXE_yScPYbXEScA_pSgYitYaq_YKs5ErrorR_r0_lF Added: _$ss33withTaskPriorityEscalationHandler9operation02onC9Escalated9isolationxxyYaq_YKXE_yScPYbXEScA_pSgYitYaq_YKs5ErrorR_r0_lFTu + +// task names +Added: _$sScTss5NeverORszABRs_rlE4nameSSSgvgZ +Added: _$sScTss5NeverORszABRs_rlE4nameSSSgvpZMV +Added: _swift_task_getCurrentTaskName \ No newline at end of file diff --git a/test/embedded/concurrency-taskgroup2.swift b/test/embedded/concurrency-discardingtaskgroup.swift similarity index 100% rename from test/embedded/concurrency-taskgroup2.swift rename to test/embedded/concurrency-discardingtaskgroup.swift diff --git a/test/embedded/dependencies-concurrency-custom-executor.swift b/test/embedded/dependencies-concurrency-custom-executor.swift index 4f3e4c172c25f..8a88a02577cc9 100644 --- a/test/embedded/dependencies-concurrency-custom-executor.swift +++ b/test/embedded/dependencies-concurrency-custom-executor.swift @@ -26,6 +26,7 @@ // DEP: _putchar // DEP: _puts // DEP: _strlen +// DEP: _strcpy // DEP: _vprintf // DEP: _vsnprintf diff --git a/test/embedded/dependencies-concurrency-custom-executor2.swift b/test/embedded/dependencies-concurrency-custom-executor2.swift index edb1c91103c5b..540ac54e7d029 100644 --- a/test/embedded/dependencies-concurrency-custom-executor2.swift +++ b/test/embedded/dependencies-concurrency-custom-executor2.swift @@ -25,6 +25,7 @@ // DEP: _putchar // DEP: _puts // DEP: _strlen +// DEP: _strcpy // DEP: _vprintf // DEP: _vsnprintf diff --git a/test/embedded/dependencies-concurrency.swift b/test/embedded/dependencies-concurrency.swift index f4b9b61bfa1cb..70a12bbfb81e5 100644 --- a/test/embedded/dependencies-concurrency.swift +++ b/test/embedded/dependencies-concurrency.swift @@ -26,6 +26,7 @@ // DEP: _putchar // DEP: _puts // DEP: _strlen +// DEP: _strcpy // DEP: _vprintf // DEP: _vsnprintf diff --git a/test/embedded/dependencies-concurrency2.swift b/test/embedded/dependencies-concurrency2.swift index 3eb7d25076beb..50e3ba3a7029b 100644 --- a/test/embedded/dependencies-concurrency2.swift +++ b/test/embedded/dependencies-concurrency2.swift @@ -23,6 +23,7 @@ // DEP: _putchar // DEP: _puts // DEP: _strlen +// DEP: _strcpy // DEP: _swift_task_asyncMainDrainQueueImpl // DEP: _swift_task_enqueueGlobalImpl // DEP: _swift_task_getMainExecutorImpl