Skip to content

Commit c164dc1

Browse files
committed
correct logic for TaskGroup addTask(on: nil)
1 parent 2a09bdb commit c164dc1

File tree

3 files changed

+82
-113
lines changed

3 files changed

+82
-113
lines changed

stdlib/public/Concurrency/Task.cpp

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -886,21 +886,16 @@ static AsyncTaskAndContext swift_task_create_commonImpl(
886886
assert(sizeof(FutureAsyncContextPrefix) == 4 * sizeof(void *));
887887
}
888888

889-
// If we're going to inherit (copy) a task executor preference record,
890-
// we want to store this information in a job flag, such that we can
891-
// efficiently detect if there is an executor preference we need to look for
892-
// in task status records.
893-
//
894-
// The record itself we'll add to the task once it has been created,
895-
// further down this function.
896-
bool shouldPushTaskExecutorPreferenceRecord = false;
897-
// if (parent && targetExecutor.isGeneric()) { // TODO: or like this?
898-
if (taskExecutor.isUndefined() && parent) {
899-
auto parentTaskExecutor = parent->getPreferredTaskExecutor();
900-
if (parentTaskExecutor.isDefined()) {
901-
shouldPushTaskExecutorPreferenceRecord = true;
902-
jobFlags.task_setHasInitialTaskExecutorPreferenceRecord(true);
903-
taskExecutor = parentTaskExecutor;
889+
// Only attempt to inherit parent's executor preference if we didn't set one explicitly,
890+
// which we've recorded in the flag by noticing a task create option higher up in this func.
891+
if (!jobFlags.task_hasInitialTaskExecutorPreferenceRecord()) {
892+
// do we have a parent we can inherit the task executor from?
893+
if (parent) {
894+
auto parentTaskExecutor = parent->getPreferredTaskExecutor();
895+
if (parentTaskExecutor.isDefined()) {
896+
jobFlags.task_setHasInitialTaskExecutorPreferenceRecord(true);
897+
taskExecutor = parentTaskExecutor;
898+
}
904899
}
905900
}
906901

@@ -1028,7 +1023,8 @@ static AsyncTaskAndContext swift_task_create_commonImpl(
10281023
// If the task does not have a specific executor set already via create options,
10291024
// and there is a task executor preference set in the parent,
10301025
// we inherit it by deep-copying the preference record.
1031-
if (shouldPushTaskExecutorPreferenceRecord || taskExecutor.isDefined()) {
1026+
// if (shouldPushTaskExecutorPreferenceRecord || taskExecutor.isDefined()) {
1027+
if (jobFlags.task_hasInitialTaskExecutorPreferenceRecord()) {
10321028
// Implementation note: we must do this AFTER `swift_taskGroup_attachChild`
10331029
// because the group takes a fast-path when attaching the child record.
10341030
assert(jobFlags.task_hasInitialTaskExecutorPreferenceRecord());

stdlib/public/Concurrency/TaskGroup+TaskExecutor.swift

Lines changed: 53 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ extension TaskGroup {
3939
#if $BuiltinCreateAsyncTaskInGroupWithExecutor
4040
let flags = taskCreateFlags(
4141
priority: priority, isChildTask: true, copyTaskLocals: false,
42-
inheritContext: false, enqueueJob: false,
42+
inheritContext: false, enqueueJob: true,
4343
addPendingGroupTaskUnconditionally: true,
4444
isDiscardingTask: false)
4545

@@ -50,17 +50,8 @@ extension TaskGroup {
5050
_getUndefinedTaskExecutor()
5151
}
5252

53-
// if let taskExecutor {
54-
// let executorBuiltin: Builtin.Executor =
55-
// taskExecutor.asUnownedTaskExecutor().executor
56-
//
57-
// Create the task in this group with an executor preference.
53+
// Create the task in this group with an executor preference.
5854
_ = Builtin.createAsyncTaskInGroupWithExecutor(flags, _group, executorBuiltin, operation)
59-
// } else {
60-
// // FIXME: DISABLE THE TASK PREFERENCE (PASS NIL?)
61-
// // Create the task in this group without executor preference.
62-
// fatalError("NOT YET") // _ = Builtin.createAsyncTaskInGroup(flags, _group, operation)
63-
// }
6455
#else
6556
fatalError("Unsupported Swift compiler")
6657
#endif
@@ -95,22 +86,19 @@ extension TaskGroup {
9586
}
9687
let flags = taskCreateFlags(
9788
priority: priority, isChildTask: true, copyTaskLocals: false,
98-
inheritContext: false, enqueueJob: false,
89+
inheritContext: false, enqueueJob: true,
9990
addPendingGroupTaskUnconditionally: false,
10091
isDiscardingTask: false)
10192

102-
if let taskExecutor {
103-
let executorBuiltin: Builtin.Executor =
93+
let executorBuiltin: Builtin.Executor =
94+
if let taskExecutor {
10495
taskExecutor.asUnownedTaskExecutor().executor
96+
} else {
97+
_getUndefinedTaskExecutor()
98+
}
10599

106-
// Create the task in this group with an executor preference.
107-
_ = Builtin.createAsyncTaskInGroupWithExecutor(flags, _group, executorBuiltin, operation)
108-
} else {
109-
// FIXME: DISABLE THE TASK PREFERENCE (PASS NIL?)
110-
// Create the task in this group without executor preference.
111-
fatalError("NOT YET") // _ = Builtin.createAsyncTaskInGroup(flags, _group, operation)
112-
}
113-
100+
// Create the task in this group with an executor preference.
101+
_ = Builtin.createAsyncTaskInGroupWithExecutor(flags, _group, executorBuiltin, operation)
114102
return true
115103
#else
116104
fatalError("Unsupported Swift compiler")
@@ -143,21 +131,19 @@ extension ThrowingTaskGroup {
143131
#if $BuiltinCreateAsyncTaskInGroupWithExecutor
144132
let flags = taskCreateFlags(
145133
priority: priority, isChildTask: true, copyTaskLocals: false,
146-
inheritContext: false, enqueueJob: false,
134+
inheritContext: false, enqueueJob: true,
147135
addPendingGroupTaskUnconditionally: true,
148136
isDiscardingTask: false)
149137

150-
if let taskExecutor {
151-
let executorBuiltin: Builtin.Executor =
138+
let executorBuiltin: Builtin.Executor =
139+
if let taskExecutor {
152140
taskExecutor.asUnownedTaskExecutor().executor
141+
} else {
142+
_getUndefinedTaskExecutor()
143+
}
153144

154-
// Create the task in this group with an executor preference.
155-
_ = Builtin.createAsyncTaskInGroupWithExecutor(flags, _group, executorBuiltin, operation)
156-
} else {
157-
// FIXME: DISABLE THE TASK PREFERENCE (PASS NIL?)
158-
// Create the task in this group without executor preference.
159-
fatalError("NOT YET") // _ = Builtin.createAsyncTaskInGroup(flags, _group, operation)
160-
}
145+
// Create the task in this group with an executor preference.
146+
_ = Builtin.createAsyncTaskInGroupWithExecutor(flags, _group, executorBuiltin, operation)
161147
#else
162148
fatalError("Unsupported Swift compiler")
163149
#endif
@@ -192,22 +178,19 @@ extension ThrowingTaskGroup {
192178
}
193179
let flags = taskCreateFlags(
194180
priority: priority, isChildTask: true, copyTaskLocals: false,
195-
inheritContext: false, enqueueJob: false,
181+
inheritContext: false, enqueueJob: true,
196182
addPendingGroupTaskUnconditionally: false,
197183
isDiscardingTask: false)
198184

199-
if let taskExecutor {
200-
let executorBuiltin: Builtin.Executor =
185+
let executorBuiltin: Builtin.Executor =
186+
if let taskExecutor {
201187
taskExecutor.asUnownedTaskExecutor().executor
188+
} else {
189+
_getUndefinedTaskExecutor()
190+
}
202191

203-
// Create the task in this group with an executor preference.
204-
_ = Builtin.createAsyncTaskInGroupWithExecutor(flags, _group, executorBuiltin, operation)
205-
} else {
206-
// FIXME: DISABLE THE TASK PREFERENCE (PASS NIL?)
207-
// Create the task in this group without executor preference.
208-
fatalError("NOT YET") // _ = Builtin.createAsyncTaskInGroup(flags, _group, operation)
209-
}
210-
192+
// Create the task in this group with an executor preference.
193+
_ = Builtin.createAsyncTaskInGroupWithExecutor(flags, _group, executorBuiltin, operation)
211194
return true
212195
#else
213196
fatalError("Unsupported Swift compiler")
@@ -240,21 +223,19 @@ extension DiscardingTaskGroup {
240223
#if $BuiltinCreateAsyncTaskInGroupWithExecutor
241224
let flags = taskCreateFlags(
242225
priority: priority, isChildTask: true, copyTaskLocals: false,
243-
inheritContext: false, enqueueJob: false,
226+
inheritContext: false, enqueueJob: true,
244227
addPendingGroupTaskUnconditionally: true,
245228
isDiscardingTask: true)
246229

247-
if let taskExecutor {
248-
let executorBuiltin: Builtin.Executor =
230+
let executorBuiltin: Builtin.Executor =
231+
if let taskExecutor {
249232
taskExecutor.asUnownedTaskExecutor().executor
233+
} else {
234+
_getUndefinedTaskExecutor()
235+
}
250236

251-
// Create the task in this group with an executor preference.
252-
_ = Builtin.createAsyncTaskInGroupWithExecutor(flags, _group, executorBuiltin, operation)
253-
} else {
254-
// FIXME: DISABLE THE TASK PREFERENCE (PASS NIL?)
255-
// Create the task in this group without executor preference.
256-
fatalError("NOT YET") // _ = Builtin.createAsyncTaskInGroup(flags, _group, operation)
257-
}
237+
// Create the task in this group with an executor preference.
238+
_ = Builtin.createAsyncTaskInGroupWithExecutor(flags, _group, executorBuiltin, operation)
258239
#else
259240
fatalError("Unsupported Swift compiler")
260241
#endif
@@ -290,22 +271,19 @@ extension DiscardingTaskGroup {
290271
}
291272
let flags = taskCreateFlags(
292273
priority: priority, isChildTask: true, copyTaskLocals: false,
293-
inheritContext: false, enqueueJob: false,
274+
inheritContext: false, enqueueJob: true,
294275
addPendingGroupTaskUnconditionally: false, isDiscardingTask: true
295276
)
296277

278+
let executorBuiltin: Builtin.Executor =
297279
if let taskExecutor {
298-
let executorBuiltin: Builtin.Executor =
299-
taskExecutor.asUnownedTaskExecutor().executor
300-
301-
// Create the task in this group with an executor preference.
302-
_ = Builtin.createAsyncTaskInGroupWithExecutor(flags, _group, executorBuiltin, operation)
280+
taskExecutor.asUnownedTaskExecutor().executor
303281
} else {
304-
// FIXME: DISABLE THE TASK PREFERENCE (PASS NIL?)
305-
// Create the task in this group without executor preference.
306-
fatalError("NOT YET") // _ = Builtin.createAsyncTaskInGroup(flags, _group, operation)
282+
_getUndefinedTaskExecutor()
307283
}
308284

285+
// Create the task in this group with an executor preference.
286+
_ = Builtin.createAsyncTaskInGroupWithExecutor(flags, _group, executorBuiltin, operation)
309287
return true
310288
#else
311289
fatalError("Unsupported Swift compiler")
@@ -338,21 +316,19 @@ extension ThrowingDiscardingTaskGroup {
338316
#if $BuiltinCreateAsyncTaskInGroupWithExecutor
339317
let flags = taskCreateFlags(
340318
priority: priority, isChildTask: true, copyTaskLocals: false,
341-
inheritContext: false, enqueueJob: false,
319+
inheritContext: false, enqueueJob: true,
342320
addPendingGroupTaskUnconditionally: true,
343321
isDiscardingTask: true)
344322

323+
let executorBuiltin: Builtin.Executor =
345324
if let taskExecutor {
346-
let executorBuiltin: Builtin.Executor =
347-
taskExecutor.asUnownedTaskExecutor().executor
348-
349-
// Create the task in this group with an executor preference.
350-
_ = Builtin.createAsyncTaskInGroupWithExecutor(flags, _group, executorBuiltin, operation)
325+
taskExecutor.asUnownedTaskExecutor().executor
351326
} else {
352-
// FIXME: DISABLE THE TASK PREFERENCE (PASS NIL?)
353-
// Create the task in this group without executor preference.
354-
fatalError("NOT YET") // _ = Builtin.createAsyncTaskInGroup(flags, _group, operation)
327+
_getUndefinedTaskExecutor()
355328
}
329+
330+
// Create the task in this group with an executor preference.
331+
_ = Builtin.createAsyncTaskInGroupWithExecutor(flags, _group, executorBuiltin, operation)
356332
#else
357333
fatalError("Unsupported Swift compiler")
358334
#endif
@@ -389,22 +365,19 @@ extension ThrowingDiscardingTaskGroup {
389365
}
390366
let flags = taskCreateFlags(
391367
priority: priority, isChildTask: true, copyTaskLocals: false,
392-
inheritContext: false, enqueueJob: false,
368+
inheritContext: false, enqueueJob: true,
393369
addPendingGroupTaskUnconditionally: false, isDiscardingTask: true
394370
)
395371

372+
let executorBuiltin: Builtin.Executor =
396373
if let taskExecutor {
397-
let executorBuiltin: Builtin.Executor =
398-
taskExecutor.asUnownedTaskExecutor().executor
399-
400-
// Create the task in this group with an executor preference.
401-
_ = Builtin.createAsyncTaskInGroupWithExecutor(flags, _group, executorBuiltin, operation)
374+
taskExecutor.asUnownedTaskExecutor().executor
402375
} else {
403-
// FIXME: DISABLE THE TASK PREFERENCE (PASS NIL?)
404-
// Create the task in this group without executor preference.
405-
fatalError("NOT YET") // _ = Builtin.createAsyncTaskInGroup(flags, _group, operation)
376+
_getUndefinedTaskExecutor()
406377
}
407378

379+
// Create the task in this group with an executor preference.
380+
_ = Builtin.createAsyncTaskInGroupWithExecutor(flags, _group, executorBuiltin, operation)
408381
return true
409382
#else
410383
fatalError("Unsupported Swift compiler")

test/Concurrency/Runtime/async_task_executor_structured_concurrency.swift

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ func testTaskGroup(_ firstExecutor: MyTaskExecutor,
7676

7777
// Disabling task preference, in task group child task
7878
_ = await withTaskGroup(of: Int.self) { group in
79-
dispatchPrecondition(condition: .onQueue(firstExecutor.queue))
79+
dispatchPrecondition(condition: .notOnQueue(firstExecutor.queue))
8080
dispatchPrecondition(condition: .notOnQueue(secondExecutor.queue))
8181

8282
group.addTask(on: secondExecutor) {
@@ -106,51 +106,49 @@ func testTaskGroup(_ firstExecutor: MyTaskExecutor,
106106
return await inner.next()!
107107
}
108108
}
109-
109+
110110
group.addTask(on: secondExecutor) {
111111
dispatchPrecondition(condition: .notOnQueue(firstExecutor.queue))
112112
dispatchPrecondition(condition: .onQueue(secondExecutor.queue))
113-
return await withDiscardingTaskGroup { inner in
113+
await withDiscardingTaskGroup { inner in
114114
inner.addTask(on: nil) {
115115
// disabled the preference
116116
dispatchPrecondition(condition: .notOnQueue(firstExecutor.queue))
117117
dispatchPrecondition(condition: .notOnQueue(secondExecutor.queue))
118-
return 42
119118
}
120119
inner.addTaskUnlessCancelled(on: nil) {
121120
// disabled the preference
122121
dispatchPrecondition(condition: .notOnQueue(firstExecutor.queue))
123122
dispatchPrecondition(condition: .notOnQueue(secondExecutor.queue))
124-
return 42
125123
}
126-
return await inner.next()!
124+
}
125+
return 0
127126
}
128127

129128
group.addTask(on: secondExecutor) {
130129
dispatchPrecondition(condition: .notOnQueue(firstExecutor.queue))
131130
dispatchPrecondition(condition: .onQueue(secondExecutor.queue))
132-
return await withThrowingDiscardingTaskGroup { inner in
131+
try! await withThrowingDiscardingTaskGroup { inner in
133132
inner.addTask(on: nil) {
134133
// disabled the preference
135134
dispatchPrecondition(condition: .notOnQueue(firstExecutor.queue))
136135
dispatchPrecondition(condition: .notOnQueue(secondExecutor.queue))
137-
return 42
138136
}
139137
inner.addTaskUnlessCancelled(on: nil) {
140138
// disabled the preference
141139
dispatchPrecondition(condition: .notOnQueue(firstExecutor.queue))
142140
dispatchPrecondition(condition: .notOnQueue(secondExecutor.queue))
143-
return 42
144141
}
145-
return await inner.next()!
142+
}
143+
return 0
146144
}
147145

148146
return await group.next()!
149147
}
150148
}
151149

152150
func testAsyncLet(_ firstExecutor: MyTaskExecutor,
153-
_ secondExecutor: MyTaskExecutor) async {
151+
_ secondExecutor: MyTaskExecutor) async {
154152
await withTaskExecutor(firstExecutor) {
155153
async let first: Int = {
156154
dispatchPrecondition(condition: .onQueue(firstExecutor.queue))
@@ -184,14 +182,16 @@ func testAsyncLet(_ firstExecutor: MyTaskExecutor,
184182

185183
func testGroupAsyncLet(_ firstExecutor: MyTaskExecutor,
186184
_ secondExecutor: MyTaskExecutor) async {
187-
Tasi(on: firstExecutor) {
188-
dispatchPrecondition(condition: .onQueue(firstExecutor.queue))
189-
dispatchPrecondition(condition: .notOnQueue(secondExecutor.queue))
185+
await withTaskGroup(of: Void.self) { group in
186+
group.addTask(on: firstExecutor) {
187+
dispatchPrecondition(condition: .onQueue(firstExecutor.queue))
188+
dispatchPrecondition(condition: .notOnQueue(secondExecutor.queue))
190189

191-
async let first = expect(firstExecutor)
190+
async let first = expect(firstExecutor)
192191

193-
await withTaskExecutor(on: secondExecutor) {
194-
async let second = expect(secondExecutor)
192+
await withTaskExecutor(secondExecutor) {
193+
async let second = expect(secondExecutor)
194+
}
195195
}
196196
}
197197
}

0 commit comments

Comments
 (0)