mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Concurrency] Cancelled group should only spawn already cancelled tasks
This commit is contained in:
@@ -39,6 +39,9 @@ public:
|
|||||||
|
|
||||||
/// Upon a future task's completion, offer it to the task group it belongs to.
|
/// Upon a future task's completion, offer it to the task group it belongs to.
|
||||||
void offer(AsyncTask *completed, AsyncContext *context);
|
void offer(AsyncTask *completed, AsyncContext *context);
|
||||||
|
|
||||||
|
/// Checks the cancellation status of the group.
|
||||||
|
bool isCancelled();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace swift
|
} // end namespace swift
|
||||||
|
|||||||
@@ -565,7 +565,8 @@ static AsyncTaskAndContext swift_task_create_group_future_commonImpl(
|
|||||||
// In a task group we would not have allowed the `add` to create a child anymore,
|
// In a task group we would not have allowed the `add` to create a child anymore,
|
||||||
// however better safe than sorry and `async let` are not expressed as task groups,
|
// however better safe than sorry and `async let` are not expressed as task groups,
|
||||||
// so they may have been spawned in any case still.
|
// so they may have been spawned in any case still.
|
||||||
if (swift_task_isCancelled(parent))
|
if (swift_task_isCancelled(parent) ||
|
||||||
|
(group && group->isCancelled()))
|
||||||
swift_task_cancel(task);
|
swift_task_cancel(task);
|
||||||
|
|
||||||
// Initialize task locals with a link to the parent task.
|
// Initialize task locals with a link to the parent task.
|
||||||
|
|||||||
@@ -508,6 +508,10 @@ void TaskGroup::offer(AsyncTask *completedTask, AsyncContext *context) {
|
|||||||
asImpl(this)->offer(completedTask, context);
|
asImpl(this)->offer(completedTask, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TaskGroup::isCancelled() {
|
||||||
|
return asImpl(this)->isCancelled();
|
||||||
|
}
|
||||||
|
|
||||||
static void fillGroupNextResult(TaskFutureWaitAsyncContext *context,
|
static void fillGroupNextResult(TaskFutureWaitAsyncContext *context,
|
||||||
PollResult result) {
|
PollResult result) {
|
||||||
/// Fill in the result value
|
/// Fill in the result value
|
||||||
|
|||||||
@@ -355,12 +355,12 @@ public struct TaskGroup<ChildTaskResult> {
|
|||||||
_taskGroupIsEmpty(_group)
|
_taskGroupIsEmpty(_group)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cancel all the remaining tasks in the group.
|
/// Cancel all the remaining, and future, tasks in the group.
|
||||||
///
|
///
|
||||||
/// A cancelled group will not will NOT accept new tasks being added into it.
|
/// A cancelled group will not will create new tasks when the `asyncUnlessCancelled`,
|
||||||
///
|
/// function is used. It will, however, continue to create tasks when the plain `async`
|
||||||
/// Any results, including errors thrown by tasks affected by this
|
/// function is used. Such tasks will be created yet immediately cancelled, allowing
|
||||||
/// cancellation, are silently discarded.
|
/// the tasks to perform some short-cut implementation, if they are responsive to cancellation.
|
||||||
///
|
///
|
||||||
/// This function may be called even from within child (or any other) tasks,
|
/// This function may be called even from within child (or any other) tasks,
|
||||||
/// and will reliably cause the group to become cancelled.
|
/// and will reliably cause the group to become cancelled.
|
||||||
|
|||||||
@@ -37,13 +37,16 @@ func test_taskGroup_cancel_then_add() async {
|
|||||||
let none = await group.next()
|
let none = await group.next()
|
||||||
print("next second: \(none)") // CHECK: next second: nil
|
print("next second: \(none)") // CHECK: next second: nil
|
||||||
|
|
||||||
group.spawn { 3 }
|
group.spawn {
|
||||||
print("added third, unconditionally") // CHECK: added third, unconditionally
|
print("child task isCancelled: \(Task.isCancelled)") // CHECK: child task isCancelled: true
|
||||||
print("group isCancelled: \(group.isCancelled)") // CHECK: group isCancelled: true
|
return 3
|
||||||
|
}
|
||||||
let three = await group.next()!
|
let three = await group.next()!
|
||||||
print("next third: \(three)") // CHECK: next third: 3
|
print("next third: \(three)") // CHECK: next third: 3
|
||||||
|
|
||||||
|
print("added third, unconditionally") // CHECK: added third, unconditionally
|
||||||
|
print("group isCancelled: \(group.isCancelled)") // CHECK: group isCancelled: true
|
||||||
|
|
||||||
return one + (none ?? 0)
|
return one + (none ?? 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user