mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
rdar://147907609 When starting tasks synchronously on task groups, the task create flags for isSynchronousStart and isDiscardingTask were always set to `false`. With this change the former will always be `true` and the latter conditionally `true` for discarding task groups.
245 lines
7.7 KiB
Swift
245 lines
7.7 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2020-2025 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import Swift
|
|
@_implementationOnly import SwiftConcurrencyInternalShims
|
|
|
|
// ==== Task.startSynchronously ------------------------------------------------
|
|
|
|
% METHOD_VARIANTS = [
|
|
% 'THROWING',
|
|
% 'NON_THROWING',
|
|
% ]
|
|
% OPERATION_PARAM = '@_inheritActorContext @_implicitSelfCapture _ operation: __owned @Sendable @escaping () async throws -> Success'
|
|
% for METHOD_VARIANT in METHOD_VARIANTS:
|
|
|
|
% IS_THROWING = METHOD_VARIANT == 'THROWING'
|
|
% if IS_THROWING:
|
|
% FAILURE_TYPE = 'Error'
|
|
% else:
|
|
% FAILURE_TYPE = 'Never'
|
|
% end
|
|
|
|
@available(SwiftStdlib 6.2, *)
|
|
extension Task where Failure == ${FAILURE_TYPE} {
|
|
|
|
/// Create and immediately start running a new task in the context of the calling thread/task.
|
|
///
|
|
/// This function _starts_ the created task on the calling context.
|
|
/// The task will continue executing on the caller's context until it suspends,
|
|
/// and after suspension will resume on the adequate executor. For a nonisolated
|
|
/// operation this means running on the global concurrent pool, and on an isolated
|
|
/// operation it means the appropriate executor of that isolation context.
|
|
///
|
|
/// As indicated by the lack of `async` on this method, this method does _not_
|
|
/// suspend, and instead takes over the calling task's (thread's) execution in
|
|
/// a synchronous manner.
|
|
///
|
|
/// Other than the execution semantics discussed above, the created task
|
|
/// is semantically equivalent to its basic version which can be
|
|
/// created using ``Task/init``.
|
|
///
|
|
/// - Parameters:
|
|
/// - name: The high-level human-readable name given for this task
|
|
/// - priority: The priority of the task.
|
|
/// Pass `nil` to use the ``Task/basePriority`` of the current task (if there is one).
|
|
/// - operation: the operation to be run immediately upon entering the task.
|
|
/// - Returns: A reference to the unstructured task which may be awaited on.
|
|
@available(SwiftStdlib 6.2, *)
|
|
@discardableResult
|
|
public static func startSynchronously(
|
|
name: String? = nil,
|
|
priority: TaskPriority? = nil,
|
|
@_inheritActorContext @_implicitSelfCapture _ operation: __owned sending @escaping () async throws -> Success
|
|
) -> Task<Success, ${FAILURE_TYPE}> {
|
|
let flags = taskCreateFlags(
|
|
priority: priority,
|
|
isChildTask: false,
|
|
copyTaskLocals: true,
|
|
inheritContext: true,
|
|
enqueueJob: false, // don't enqueue, we'll run it manually
|
|
addPendingGroupTaskUnconditionally: false,
|
|
isDiscardingTask: false,
|
|
isSynchronousStart: true
|
|
)
|
|
|
|
var task: Builtin.NativeObject?
|
|
#if $BuiltinCreateAsyncTaskName
|
|
if let name {
|
|
task =
|
|
name.utf8CString.withUnsafeBufferPointer { nameBytes in
|
|
Builtin.createTask(
|
|
flags: flags,
|
|
taskName: nameBytes.baseAddress!._rawValue,
|
|
operation: operation).0
|
|
}
|
|
}
|
|
#endif
|
|
if task == nil {
|
|
// either no task name was set, or names are unsupported
|
|
task = Builtin.createTask(
|
|
flags: flags,
|
|
operation: operation).0
|
|
}
|
|
|
|
_startTaskSynchronously(task!)
|
|
return Task<Success, ${FAILURE_TYPE}>(task!)
|
|
}
|
|
}
|
|
%end
|
|
|
|
%{
|
|
GROUP_AND_OP_INFO = [
|
|
(
|
|
'TaskGroup',
|
|
[
|
|
'startTaskSynchronously',
|
|
'startTaskSynchronouslyUnlessCancelled'
|
|
],
|
|
'',
|
|
'ChildTaskResult'
|
|
),
|
|
(
|
|
'ThrowingTaskGroup',
|
|
[
|
|
'startTaskSynchronously',
|
|
'startTaskSynchronouslyUnlessCancelled'
|
|
],
|
|
'throws ',
|
|
'ChildTaskResult'
|
|
),
|
|
(
|
|
'DiscardingTaskGroup',
|
|
[
|
|
'startTaskSynchronously',
|
|
'startTaskSynchronouslyUnlessCancelled'
|
|
],
|
|
'',
|
|
'Void'
|
|
),
|
|
(
|
|
'ThrowingDiscardingTaskGroup',
|
|
[
|
|
'startTaskSynchronously',
|
|
'startTaskSynchronouslyUnlessCancelled'
|
|
],
|
|
'throws ',
|
|
'Void'
|
|
),
|
|
]
|
|
}%
|
|
% for (GROUP_TYPE, METHOD_NAMES, THROWS, RESULT_TYPE) in GROUP_AND_OP_INFO:
|
|
% for METHOD_NAME in METHOD_NAMES:
|
|
@available(SwiftStdlib 6.2, *)
|
|
extension ${GROUP_TYPE} {
|
|
|
|
/// Create and immediately start running a new child task in the context of the calling thread/task.
|
|
///
|
|
/// This function _starts_ the created task on the calling context.
|
|
/// The task will continue executing on the caller's context until it suspends,
|
|
/// and after suspension will resume on the adequate executor. For a nonisolated
|
|
/// operation this means running on the global concurrent pool, and on an isolated
|
|
/// operation it means the appropriate executor of that isolation context.
|
|
///
|
|
/// As indicated by the lack of `async` on this method, this method does _not_
|
|
/// suspend, and instead takes over the calling task's (thread's) execution in
|
|
/// a synchronous manner.
|
|
///
|
|
/// Other than the execution semantics discussed above, the created task
|
|
/// is semantically equivalent to its basic version which can be
|
|
/// created using ``${GROUP_TYPE}/addTask``.
|
|
@available(SwiftStdlib 6.2, *)
|
|
public func ${METHOD_NAME}( // in ${GROUP_TYPE}
|
|
name: String? = nil,
|
|
priority: TaskPriority? = nil,
|
|
operation: sending @escaping () async ${THROWS}-> ${RESULT_TYPE}
|
|
) {
|
|
let flags = taskCreateFlags(
|
|
priority: priority,
|
|
isChildTask: true,
|
|
copyTaskLocals: false,
|
|
inheritContext: false,
|
|
enqueueJob: false, // don't enqueue, we'll run it manually
|
|
addPendingGroupTaskUnconditionally: true,
|
|
isDiscardingTask: ${'true' if 'Discarding' in GROUP_TYPE else 'false'},
|
|
isSynchronousStart: true
|
|
)
|
|
|
|
// Create the task in this group.
|
|
let (task, _) = Builtin.createTask(
|
|
flags: flags,
|
|
taskGroup: self._group,
|
|
operation: operation
|
|
)
|
|
_startTaskSynchronously(task)
|
|
}
|
|
}
|
|
% end # METHOD_NAMES
|
|
%end # GROUP_TYPES
|
|
|
|
// ==== Legacy SPI -------------------------------------------------------------
|
|
|
|
% METHOD_VARIANTS = [
|
|
% 'THROWING',
|
|
% 'NON_THROWING',
|
|
% ]
|
|
% OPERATION_PARAM = '@_inheritActorContext @_implicitSelfCapture _ operation: __owned @Sendable @escaping @MainActor () async throws -> Success'
|
|
% for METHOD_VARIANT in METHOD_VARIANTS:
|
|
|
|
% IS_THROWING = METHOD_VARIANT == 'THROWING'
|
|
% if IS_THROWING:
|
|
% FAILURE_TYPE = 'Error'
|
|
% else:
|
|
% FAILURE_TYPE = 'Never'
|
|
% OPERATION_PARAM = OPERATION_PARAM.replace('throws', '')
|
|
% end
|
|
|
|
#if !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY && !SWIFT_CONCURRENCY_EMBEDDED
|
|
@available(SwiftStdlib 5.9, *)
|
|
extension Task where Failure == ${FAILURE_TYPE} {
|
|
|
|
@_spi(MainActorUtilities)
|
|
@MainActor
|
|
@available(SwiftStdlib 5.9, *)
|
|
@discardableResult
|
|
public static func startOnMainActor(
|
|
priority: TaskPriority? = nil,
|
|
${OPERATION_PARAM}
|
|
) -> Task<Success, ${FAILURE_TYPE}> {
|
|
let flags = taskCreateFlags(
|
|
priority: priority,
|
|
isChildTask: false,
|
|
copyTaskLocals: true,
|
|
inheritContext: true,
|
|
enqueueJob: false,
|
|
addPendingGroupTaskUnconditionally: false,
|
|
isDiscardingTask: false,
|
|
isSynchronousStart: false
|
|
)
|
|
|
|
let (task, _) = Builtin.createAsyncTask(flags, operation)
|
|
_startTaskOnMainActor(task)
|
|
|
|
return Task<Success, ${FAILURE_TYPE}>(task)
|
|
}
|
|
}
|
|
#endif
|
|
% end
|
|
|
|
// Internal Runtime Functions --------------------------------------------------
|
|
|
|
@_silgen_name("swift_task_startOnMainActor")
|
|
internal func _startTaskOnMainActor(_ task: Builtin.NativeObject)
|
|
|
|
@_silgen_name("swift_task_startSynchronously")
|
|
internal func _startTaskSynchronously(_ task: Builtin.NativeObject)
|