Skip to content

Commit 022ed7a

Browse files
committed
[Concurrency] Add TaskGroup.startTaskSynchronously funcs
1 parent 56f28ee commit 022ed7a

File tree

5 files changed

+208
-23
lines changed

5 files changed

+208
-23
lines changed

stdlib/public/Concurrency/Task+startSynchronously.swift.gyb

Lines changed: 119 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@
1313
import Swift
1414
@_implementationOnly import SwiftConcurrencyInternalShims
1515

16+
// ==== Task.startSynchronously ------------------------------------------------
17+
1618
% METHOD_VARIANTS = [
1719
% 'THROWING',
1820
% 'NON_THROWING',
1921
% ]
20-
% OPERATION_PARAM = '@_inheritActorContext @_implicitSelfCapture _ operation: __owned @Sendable @escaping @MainActor () async throws -> Success'
22+
% OPERATION_PARAM = '@_inheritActorContext @_implicitSelfCapture _ operation: __owned @Sendable @escaping () async throws -> Success'
2123
% for METHOD_VARIANT in METHOD_VARIANTS:
2224

2325
% IS_THROWING = METHOD_VARIANT == 'THROWING'
@@ -27,8 +29,6 @@ import Swift
2729
% FAILURE_TYPE = 'Never'
2830
% end
2931

30-
// ==== Task.startSynchronously ------------------------------------------------
31-
3232
@available(SwiftStdlib 6.2, *)
3333
extension Task where Failure == ${FAILURE_TYPE} {
3434

@@ -55,9 +55,9 @@ extension Task where Failure == ${FAILURE_TYPE} {
5555
/// - Returns: A reference to the unstructured task which may be awaited on.
5656
@available(SwiftStdlib 6.2, *)
5757
@discardableResult
58-
public static func _startSynchronously(
58+
public static func startSynchronously(
5959
priority: TaskPriority? = nil,
60-
@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async -> Success
60+
@_inheritActorContext @_implicitSelfCapture _ operation: __owned sending @escaping () async throws -> Success
6161
) -> Task<Success, ${FAILURE_TYPE}> {
6262
let flags = taskCreateFlags(
6363
priority: priority,
@@ -75,8 +75,121 @@ extension Task where Failure == ${FAILURE_TYPE} {
7575
return Task<Success, ${FAILURE_TYPE}>(task)
7676
}
7777
}
78+
%end
79+
80+
% OPERATION_PARAM = 'operation: sending @escaping () async throws -> ChildTaskResult'
81+
% for (GROUP_TYPE, METHOD_NAMES) in [
82+
% (
83+
% 'TaskGroup',
84+
% [
85+
% 'startTaskSynchronously',
86+
% 'startTaskSynchronouslyUnlessCancelled'
87+
% ]
88+
% ),
89+
% (
90+
% 'ThrowingTaskGroup',
91+
% [
92+
% 'startTaskSynchronously',
93+
% 'startTaskSynchronouslyUnlessCancelled'
94+
% ]
95+
% ),
96+
% (
97+
% 'DiscardingTaskGroup',
98+
% [
99+
% 'startTaskSynchronously',
100+
% 'startTaskSynchronouslyUnlessCancelled'
101+
% ]
102+
% ),
103+
% (
104+
% 'ThrowingDiscardingTaskGroup',
105+
% [
106+
% 'startTaskSynchronously',
107+
% 'startTaskSynchronouslyUnlessCancelled'
108+
% ]
109+
% ),
110+
% ]:
111+
% for METHOD_NAME in METHOD_NAMES:
112+
113+
% IS_DISCARDING = 'Discarding' in GROUP_TYPE
114+
% IS_THROWING = 'Throwing' in GROUP_TYPE
115+
116+
% if not IS_THROWING:
117+
% OPERATION_PARAM = OPERATION_PARAM.replace('throws', '')
118+
% end
119+
120+
% if IS_DISCARDING:
121+
% OPERATION_PARAM = OPERATION_PARAM.replace('ChildTaskResult', 'Void')
122+
% end
123+
124+
% if IS_THROWING:
125+
% FAILURE_TYPE = 'Error'
126+
% else:
127+
% FAILURE_TYPE = 'Never'
128+
% end
129+
130+
@available(SwiftStdlib 6.2, *)
131+
extension ${GROUP_TYPE} {
132+
133+
/// Create and immediately start running a new child task in the context of the calling thread/task.
134+
///
135+
/// This function _starts_ the created task on the calling context.
136+
/// The task will continue executing on the caller's context until it suspends,
137+
/// and after suspension will resume on the adequate executor. For a nonisolated
138+
/// operation this means running on the global concurrent pool, and on an isolated
139+
/// operation it means the appropriate executor of that isolation context.
140+
///
141+
/// As indicated by the lack of `async` on this method, this method does _not_
142+
/// suspend, and instead takes over the calling task's (thread's) execution in
143+
/// a synchronous manner.
144+
///
145+
/// Other than the execution semantics discussed above, the created task
146+
/// is semantically equivalent to its basic version which can be
147+
/// created using ``${GROUP_TYPE}/addTask``.
148+
@available(SwiftStdlib 6.2, *)
149+
public func ${METHOD_NAME}( // in ${GROUP_TYPE}
150+
priority: TaskPriority? = nil,
151+
${OPERATION_PARAM}
152+
) {
153+
let flags = taskCreateFlags(
154+
priority: priority,
155+
isChildTask: true,
156+
copyTaskLocals: false,
157+
inheritContext: false,
158+
enqueueJob: false, // don't enqueue, we'll run it manually
159+
addPendingGroupTaskUnconditionally: true,
160+
isDiscardingTask: false,
161+
isSynchronousStart: false
162+
)
163+
164+
// Create the task in this group.
165+
let (task, _) = Builtin.createTask(
166+
flags: flags,
167+
taskGroup: self._group,
168+
operation: operation
169+
)
170+
_startTaskSynchronously(task)
171+
}
172+
}
173+
%end # METHOD_NAMES
174+
%end # GROUP_TYPES
78175

79176
// ==== Legacy SPI -------------------------------------------------------------
177+
178+
% METHOD_VARIANTS = [
179+
% 'THROWING',
180+
% 'NON_THROWING',
181+
% ]
182+
% OPERATION_PARAM = '@_inheritActorContext @_implicitSelfCapture _ operation: __owned @Sendable @escaping @MainActor () async throws -> Success'
183+
% for METHOD_VARIANT in METHOD_VARIANTS:
184+
185+
% IS_THROWING = METHOD_VARIANT == 'THROWING'
186+
% if IS_THROWING:
187+
% FAILURE_TYPE = 'Error'
188+
% else:
189+
% FAILURE_TYPE = 'Never'
190+
% OPERATION_PARAM = OPERATION_PARAM.replace('throws', '')
191+
% end
192+
80193
#if !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY && !SWIFT_CONCURRENCY_EMBEDDED
81194
@available(SwiftStdlib 5.9, *)
82195
extension Task where Failure == ${FAILURE_TYPE} {
@@ -87,7 +200,7 @@ extension Task where Failure == ${FAILURE_TYPE} {
87200
@discardableResult
88201
public static func startOnMainActor(
89202
priority: TaskPriority? = nil,
90-
${OPERATION_PARAM if IS_THROWING else OPERATION_PARAM.replace("throws", "")}
203+
${OPERATION_PARAM}
91204
) -> Task<Success, ${FAILURE_TYPE}> {
92205
let flags = taskCreateFlags(
93206
priority: priority,

test/Concurrency/Runtime/startSynchronously.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ func syncOnMyGlobalActor() -> [Task<Void, Never>] {
7777

7878
print("before startSynchronously [thread:\(getCurrentThreadID())] @ :\(#line)")
7979
let outerTID = getCurrentThreadID()
80-
let tt = Task._startSynchronously { @MyGlobalActor in
80+
let tt = Task.startSynchronously { @MyGlobalActor in
8181
let innerTID = getCurrentThreadID()
8282
print("inside startSynchronously, outer thread = \(outerTID)")
8383
print("inside startSynchronously, inner thread = \(innerTID)")
@@ -103,7 +103,7 @@ func syncOnNonTaskThread(synchronousTask behavior: SynchronousTaskBehavior) {
103103
print("before startSynchronously [thread:\(getCurrentThreadID())] @ :\(#line)")
104104

105105
let outerTID = getCurrentThreadID()
106-
let tt = Task._startSynchronously {
106+
let tt = Task.startSynchronously {
107107
dispatchPrecondition(condition: .onQueue(queue))
108108

109109
let innerTID = getCurrentThreadID()
@@ -258,7 +258,7 @@ func callActorFromStartSynchronousTask(recipient rec: TargetActorToCall) {
258258
queue.async {
259259
let outerTID = getCurrentThreadID()
260260
print("before startSynchronously [thread:\(outerTID)] @ :\(#line)")
261-
let tt = Task._startSynchronously {
261+
let tt = Task.startSynchronously {
262262
dispatchPrecondition(condition: .onQueue(queue))
263263

264264
let innerTID = getCurrentThreadID()
@@ -332,14 +332,14 @@ callActorFromStartSynchronousTask(recipient: .recipientOnQueue(RecipientOnQueue(
332332
// allowing the 'after startSynchronously' to run.
333333
//
334334
// CHECK-NEXT: inside startSynchronously, call rec.sync() [thread:[[CALLING_THREAD4]]]
335-
// CHECK: NaiveQueueExecutor(recipient-actor-queue).enqueue
335+
// CHECK: NaiveQueueExecutor(recipient-actor-queue) enqueue
336336
// CHECK: after startSynchronously
337337
// CHECK-NOT: ERROR!
338338
// CHECK: inside startSynchronously, call rec.sync() done
339339

340340
// CHECK-NOT: ERROR!
341341
// CHECK: inside startSynchronously, call rec.async()
342-
// CHECK: NaiveQueueExecutor(recipient-actor-queue).enqueue
342+
// CHECK: NaiveQueueExecutor(recipient-actor-queue) enqueue
343343
// CHECK-NOT: ERROR!
344344
// CHECK: inside startSynchronously, call rec.async() done
345345

@@ -355,9 +355,9 @@ final class NaiveQueueExecutor: SerialExecutor {
355355

356356
public func enqueue(_ job: consuming ExecutorJob) {
357357
let unowned = UnownedJob(job)
358-
print("NaiveQueueExecutor(\(self.queue.label)).enqueue... [thread:\(getCurrentThreadID())]")
358+
print("NaiveQueueExecutor(\(self.queue.label)) enqueue... [thread:\(getCurrentThreadID())]")
359359
queue.async {
360-
print("NaiveQueueExecutor(\(self.queue.label)).enqueue: run [thread:\(getCurrentThreadID())]")
360+
print("NaiveQueueExecutor(\(self.queue.label)) enqueue: run [thread:\(getCurrentThreadID())]")
361361
unowned.runSynchronously(on: self.asUnownedSerialExecutor())
362362
}
363363
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// RUN: %target-build-swift -swift-version 6 %s -strict-concurrency=complete -Xfrontend -verify
2+
3+
// REQUIRES: concurrency
4+
5+
@available(SwiftStdlib 6.2, *)
6+
func sync() -> Task<String, Never> {
7+
Task.startSynchronously {
8+
return ""
9+
}
10+
}
11+
12+
@available(SwiftStdlib 6.2, *)
13+
func async() async throws {
14+
let t1 = Task.startSynchronously {
15+
return ""
16+
}
17+
let _: String = await t1.value
18+
19+
let t2: Task<String, Error> = Task.startSynchronously {
20+
throw CancellationError()
21+
}
22+
let _: String = try await t2.value
23+
24+
await withTaskGroup(of: Int.self) { group in
25+
group.startTaskSynchronously { 1 }
26+
group.startTaskSynchronouslyUnlessCancelled { 2 }
27+
}
28+
await withThrowingTaskGroup(of: Int.self) { group in
29+
group.startTaskSynchronously { 1 }
30+
group.startTaskSynchronouslyUnlessCancelled { 2 }
31+
}
32+
await withDiscardingTaskGroup { group in
33+
group.startTaskSynchronously { }
34+
group.startTaskSynchronouslyUnlessCancelled { }
35+
}
36+
try await withThrowingDiscardingTaskGroup { group in
37+
group.startTaskSynchronously { }
38+
group.startTaskSynchronouslyUnlessCancelled { }
39+
}
40+
}

test/abi/macOS/arm64/concurrency.swift

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -384,9 +384,25 @@ Added: _$sScT16escalatePriority_2toyScTyxq_G_ScPtFZ
384384
Added: _$ss33withTaskPriorityEscalationHandler9operation02onC9Escalated9isolationxxyYaq_YKXE_yScPYbXEScA_pSgYitYaq_YKs5ErrorR_r0_lF
385385
Added: _$ss33withTaskPriorityEscalationHandler9operation02onC9Escalated9isolationxxyYaq_YKXE_yScPYbXEScA_pSgYitYaq_YKs5ErrorR_r0_lFTu
386386

387-
// Task._startSynchronously
387+
// Task.DispatchSerialQueue
388388
Added: _swift_task_startSynchronously
389-
// static (extension in Swift):Swift.Task< where B == Swift.Never>._startSynchronously(name: Swift.String?, priority: Swift.TaskPriority?, operation: __owned @Sendable () async -> A) -> Swift.Task<A, Swift.Never>
390-
Added: _$sScTss5NeverORs_rlE19_startSynchronously4name8priority9operationScTyxABGSSSg_ScPSgxyYaYbcntFZ
391-
// static (extension in Swift):Swift.Task< where B == Swift.Error>._startSynchronously(name: Swift.String?, priority: Swift.TaskPriority?, operation: __owned @Sendable () async -> A) -> Swift.Task<A, Swift.Error>
392-
Added: _$sScTss5Error_pRs_rlE19_startSynchronously4name8priority9operationScTyxsAA_pGSSSg_ScPSgxyYaYbcntFZ
389+
// static (extension in Swift):Swift.Task< where B == Swift.Error>.startSynchronously(priority: Swift.TaskPriority?, _: __owned () async throws -> A) -> Swift.Task<A, Swift.Error>
390+
Added: _$sScTss5Error_pRs_rlE18startSynchronously8priority_ScTyxsAA_pGScPSg_xyYaKcntFZ
391+
// static (extension in Swift):Swift.Task< where B == Swift.Never>.startSynchronously(priority: Swift.TaskPriority?, _: __owned () async throws -> A) -> Swift.Task<A, Swift.Never>
392+
Added: _$sScTss5NeverORs_rlE18startSynchronously8priority_ScTyxABGScPSg_xyYaKcntFZ
393+
// Swift.TaskGroup.startTaskSynchronously(priority: Swift.TaskPriority?, operation: __owned () async -> A) -> ()
394+
Added: _$sScG22startTaskSynchronously8priority9operationyScPSg_xyYacntF
395+
// Swift.TaskGroup.startTaskSynchronouslyUnlessCancelled(priority: Swift.TaskPriority?, operation: __owned () async -> A) -> ()
396+
Added: _$sScG37startTaskSynchronouslyUnlessCancelled8priority9operationyScPSg_xyYacntF
397+
// Swift.ThrowingTaskGroup.startTaskSynchronously(priority: Swift.TaskPriority?, operation: __owned () async -> A) -> ()
398+
Added: _$sScg22startTaskSynchronously8priority9operationyScPSg_xyYacntF
399+
// Swift.ThrowingTaskGroup.startTaskSynchronouslyUnlessCancelled(priority: Swift.TaskPriority?, operation: __owned () async -> A) -> ()
400+
Added: _$sScg37startTaskSynchronouslyUnlessCancelled8priority9operationyScPSg_xyYacntF
401+
// Swift.DiscardingTaskGroup.startTaskSynchronously(priority: Swift.TaskPriority?, operation: __owned () async -> ()) -> ()
402+
Added: _$ss19DiscardingTaskGroupV05startB13Synchronously8priority9operationyScPSg_yyYacntF
403+
// Swift.DiscardingTaskGroup.startTaskSynchronouslyUnlessCancelled(priority: Swift.TaskPriority?, operation: __owned () async -> ()) -> ()
404+
Added: _$ss19DiscardingTaskGroupV05startB28SynchronouslyUnlessCancelled8priority9operationyScPSg_yyYacntF
405+
// Swift.ThrowingDiscardingTaskGroup.startTaskSynchronously(priority: Swift.TaskPriority?, operation: __owned () async -> ()) -> ()
406+
Added: _$ss27ThrowingDiscardingTaskGroupV05startC13Synchronously8priority9operationyScPSg_yyYacntF
407+
// Swift.ThrowingDiscardingTaskGroup.startTaskSynchronouslyUnlessCancelled(priority: Swift.TaskPriority?, operation: __owned () async -> ()) -> ()
408+
Added: _$ss27ThrowingDiscardingTaskGroupV05startC28SynchronouslyUnlessCancelled8priority9operationyScPSg_yyYacntF

test/abi/macOS/x86_64/concurrency.swift

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -384,9 +384,25 @@ Added: _$sScT16escalatePriority_2toyScTyxq_G_ScPtFZ
384384
Added: _$ss33withTaskPriorityEscalationHandler9operation02onC9Escalated9isolationxxyYaq_YKXE_yScPYbXEScA_pSgYitYaq_YKs5ErrorR_r0_lF
385385
Added: _$ss33withTaskPriorityEscalationHandler9operation02onC9Escalated9isolationxxyYaq_YKXE_yScPYbXEScA_pSgYitYaq_YKs5ErrorR_r0_lFTu
386386

387-
// Task._startSynchronously
387+
// Task.DispatchSerialQueue
388388
Added: _swift_task_startSynchronously
389-
// static (extension in Swift):Swift.Task< where B == Swift.Never>._startSynchronously(name: Swift.String?, priority: Swift.TaskPriority?, operation: __owned @Sendable () async -> A) -> Swift.Task<A, Swift.Never>
390-
Added: _$sScTss5NeverORs_rlE19_startSynchronously4name8priority9operationScTyxABGSSSg_ScPSgxyYaYbcntFZ
391-
// static (extension in Swift):Swift.Task< where B == Swift.Error>._startSynchronously(name: Swift.String?, priority: Swift.TaskPriority?, operation: __owned @Sendable () async -> A) -> Swift.Task<A, Swift.Error>
392-
Added: _$sScTss5Error_pRs_rlE19_startSynchronously4name8priority9operationScTyxsAA_pGSSSg_ScPSgxyYaYbcntFZ
389+
// static (extension in Swift):Swift.Task< where B == Swift.Error>.startSynchronously(priority: Swift.TaskPriority?, _: __owned () async throws -> A) -> Swift.Task<A, Swift.Error>
390+
Added: _$sScTss5Error_pRs_rlE18startSynchronously8priority_ScTyxsAA_pGScPSg_xyYaKcntFZ
391+
// static (extension in Swift):Swift.Task< where B == Swift.Never>.startSynchronously(priority: Swift.TaskPriority?, _: __owned () async throws -> A) -> Swift.Task<A, Swift.Never>
392+
Added: _$sScTss5NeverORs_rlE18startSynchronously8priority_ScTyxABGScPSg_xyYaKcntFZ
393+
// Swift.TaskGroup.startTaskSynchronously(priority: Swift.TaskPriority?, operation: __owned () async -> A) -> ()
394+
Added: _$sScG22startTaskSynchronously8priority9operationyScPSg_xyYacntF
395+
// Swift.TaskGroup.startTaskSynchronouslyUnlessCancelled(priority: Swift.TaskPriority?, operation: __owned () async -> A) -> ()
396+
Added: _$sScG37startTaskSynchronouslyUnlessCancelled8priority9operationyScPSg_xyYacntF
397+
// Swift.ThrowingTaskGroup.startTaskSynchronously(priority: Swift.TaskPriority?, operation: __owned () async -> A) -> ()
398+
Added: _$sScg22startTaskSynchronously8priority9operationyScPSg_xyYacntF
399+
// Swift.ThrowingTaskGroup.startTaskSynchronouslyUnlessCancelled(priority: Swift.TaskPriority?, operation: __owned () async -> A) -> ()
400+
Added: _$sScg37startTaskSynchronouslyUnlessCancelled8priority9operationyScPSg_xyYacntF
401+
// Swift.DiscardingTaskGroup.startTaskSynchronously(priority: Swift.TaskPriority?, operation: __owned () async -> ()) -> ()
402+
Added: _$ss19DiscardingTaskGroupV05startB13Synchronously8priority9operationyScPSg_yyYacntF
403+
// Swift.DiscardingTaskGroup.startTaskSynchronouslyUnlessCancelled(priority: Swift.TaskPriority?, operation: __owned () async -> ()) -> ()
404+
Added: _$ss19DiscardingTaskGroupV05startB28SynchronouslyUnlessCancelled8priority9operationyScPSg_yyYacntF
405+
// Swift.ThrowingDiscardingTaskGroup.startTaskSynchronously(priority: Swift.TaskPriority?, operation: __owned () async -> ()) -> ()
406+
Added: _$ss27ThrowingDiscardingTaskGroupV05startC13Synchronously8priority9operationyScPSg_yyYacntF
407+
// Swift.ThrowingDiscardingTaskGroup.startTaskSynchronouslyUnlessCancelled(priority: Swift.TaskPriority?, operation: __owned () async -> ()) -> ()
408+
Added: _$ss27ThrowingDiscardingTaskGroupV05startC28SynchronouslyUnlessCancelled8priority9operationyScPSg_yyYacntF

0 commit comments

Comments
 (0)