Skip to content

Commit bac9182

Browse files
committed
passing neverConsumingTasks.swift
1 parent 100f70a commit bac9182

File tree

15 files changed

+621
-270
lines changed

15 files changed

+621
-270
lines changed

include/swift/Runtime/Concurrency.h

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,13 +185,15 @@ void swift_task_future_wait_throwing(
185185
/// func swift_taskGroup_wait_next_throwing(
186186
/// waitingTask: Builtin.NativeObject, // current task
187187
/// group: Builtin.RawPointer
188-
/// ) async -> T
188+
/// ) async throws -> T
189189
/// \endcode
190190
SWIFT_EXPORT_FROM(swift_Concurrency)
191191
SWIFT_CC(swiftasync)
192192
void swift_taskGroup_wait_next_throwing(
193-
OpaqueValue *resultPointer, SWIFT_ASYNC_CONTEXT AsyncContext *callerContext,
194-
TaskGroup *group, ThrowingTaskFutureWaitContinuationFunction *resumeFn,
193+
OpaqueValue *resultPointer,
194+
SWIFT_ASYNC_CONTEXT AsyncContext *callerContext,
195+
TaskGroup *group,
196+
ThrowingTaskFutureWaitContinuationFunction *resumeFn,
195197
AsyncContext *callContext);
196198

197199
/// Initialize a `TaskGroup` in the passed `group` memory location.
@@ -287,6 +289,36 @@ void swift_taskGroup_cancelAll(TaskGroup *group);
287289
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
288290
bool swift_taskGroup_isCancelled(TaskGroup *group);
289291

292+
/// Check if the task group is discarding results or not.
293+
///
294+
/// This can be called from any thread. Its Swift signature is
295+
///
296+
/// \code
297+
/// func swift_taskGroup_isDiscardingResults(group: Builtin.RawPointer)
298+
/// \endcode
299+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
300+
bool swift_taskGroup_isDiscardingResults(TaskGroup *group);
301+
302+
/// Wait until all pending tasks from the task group have completed.
303+
/// If this task group is accumulating results, this also discards all those results.
304+
///
305+
/// This can be called from any thread. Its Swift signature is
306+
///
307+
/// \code
308+
/// func swift_taskGroup_waitAll(
309+
/// waitingTask: Builtin.NativeObject, // current task
310+
/// group: Builtin.RawPointer
311+
/// ) async throws
312+
/// \endcode
313+
SWIFT_EXPORT_FROM(swift_Concurrency)
314+
SWIFT_CC(swiftasync)
315+
void swift_taskGroup_waitAll(
316+
OpaqueValue *resultPointer,
317+
SWIFT_ASYNC_CONTEXT AsyncContext *callerContext,
318+
TaskGroup *group,
319+
ThrowingTaskFutureWaitContinuationFunction *resumeFn,
320+
AsyncContext *callContext);
321+
290322
/// Check the readyQueue of a task group, return true if it has no pending tasks.
291323
///
292324
/// This can be called from any thread. Its Swift signature is

lib/IRGen/Callee.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ namespace irgen {
175175
AsyncLetGetThrowing,
176176
AsyncLetFinish,
177177
TaskGroupWaitNext,
178+
TaskGroupWaitAll,
178179
DistributedExecuteTarget,
179180
};
180181

@@ -247,6 +248,7 @@ namespace irgen {
247248
case SpecialKind::AsyncLetGetThrowing:
248249
case SpecialKind::AsyncLetFinish:
249250
case SpecialKind::TaskGroupWaitNext:
251+
case SpecialKind::TaskGroupWaitAll:
250252
return true;
251253
case SpecialKind::DistributedExecuteTarget:
252254
return false;
@@ -277,6 +279,7 @@ namespace irgen {
277279
case SpecialKind::AsyncLetGetThrowing:
278280
case SpecialKind::AsyncLetFinish:
279281
case SpecialKind::TaskGroupWaitNext:
282+
case SpecialKind::TaskGroupWaitAll:
280283
return true;
281284
case SpecialKind::DistributedExecuteTarget:
282285
return false;

lib/IRGen/GenCall.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ FunctionPointerKind::getStaticAsyncContextSize(IRGenModule &IGM) const {
162162
case SpecialKind::AsyncLetGetThrowing:
163163
case SpecialKind::AsyncLetFinish:
164164
case SpecialKind::TaskGroupWaitNext:
165+
case SpecialKind::TaskGroupWaitAll:
165166
case SpecialKind::DistributedExecuteTarget:
166167
// The current guarantee for all of these functions is the same.
167168
// See TaskFutureWaitAsyncContext.

lib/IRGen/GenConcurrency.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,11 +285,9 @@ llvm::Value *irgen::emitCreateTaskGroup(IRGenFunction &IGF,
285285

286286
llvm::CallInst *call;
287287
if (groupFlags) {
288-
fprintf(stderr, "[%s:%d](%s) group flags; invoke -> getTaskGroupInitializeWithFlagsFunctionPointer\n", __FILE_NAME__, __LINE__, __FUNCTION__);
289288
call = IGF.Builder.CreateCall(IGF.IGM.getTaskGroupInitializeWithFlagsFunctionPointer(),
290289
{groupFlags, group, resultTypeMetadata});
291290
} else {
292-
fprintf(stderr, "[%s:%d](%s) no group flags; invoke -> getTaskGroupInitializeFunctionPointer\n", __FILE_NAME__, __LINE__, __FUNCTION__);
293291
call = IGF.Builder.CreateCall(IGF.IGM.getTaskGroupInitializeFunctionPointer(),
294292
{group, resultTypeMetadata});
295293
}

lib/IRGen/IRGenSIL.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2655,6 +2655,9 @@ FunctionPointer::Kind irgen::classifyFunctionPointerKind(SILFunction *fn) {
26552655
if (name.equals("swift_taskGroup_wait_next_throwing"))
26562656
return SpecialKind::TaskGroupWaitNext;
26572657

2658+
if (name.equals("swift_taskGroup_waitAll"))
2659+
return SpecialKind::TaskGroupWaitAll;
2660+
26582661
if (name.equals("swift_distributed_execute_target"))
26592662
return SpecialKind::DistributedExecuteTarget;
26602663
}

stdlib/public/BackDeployConcurrency/CompatibilityOverrideConcurrency.def

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,21 @@ OVERRIDE_TASK_GROUP(taskGroup_isCancelled, bool,
273273
SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift),
274274
swift::, (TaskGroup *group), (group))
275275

276+
OVERRIDE_TASK_GROUP(taskGroup_isDiscardingResults, bool,
277+
SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift),
278+
swift::, (TaskGroup *group), (group))
279+
280+
OVERRIDE_TASK_GROUP(taskGroup_wait_all, void,
281+
SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swiftasync),
282+
swift::,
283+
(OpaqueValue *resultPointer,
284+
SWIFT_ASYNC_CONTEXT AsyncContext *callerContext,
285+
TaskGroup *_group,
286+
ThrowingTaskFutureWaitContinuationFunction *resumeFn,
287+
AsyncContext *callContext),
288+
(resultPointer, callerContext, _group, resumeFn,
289+
callContext))
290+
276291
OVERRIDE_TASK_GROUP(taskGroup_cancelAll, void,
277292
SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift),
278293
swift::, (TaskGroup *group), (group))

stdlib/public/BackDeployConcurrency/TaskGroup.cpp

Lines changed: 33 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,6 @@ class TaskGroupImpl: public TaskGroupTaskStatusRecord {
114114
/// until a next() call eventually picks it up.
115115
AsyncTask *retainedTask;
116116

117-
bool isStorageAccessible() {
118-
return status == PollStatus::Success ||
119-
status == PollStatus::Error ||
120-
status == PollStatus::Empty;
121-
}
122-
123117
static PollResult get(AsyncTask *asyncTask, bool hadErrorResult) {
124118
auto fragment = asyncTask->futureFragment();
125119
return PollResult{
@@ -134,11 +128,11 @@ class TaskGroupImpl: public TaskGroupTaskStatusRecord {
134128
};
135129
}
136130

137-
static PollResult getVoid() {
131+
static PollResult getEmpty(const Metadata *successType) {
138132
return PollResult{
139133
/*status*/ PollStatus::Success,
140134
/*storage*/ nullptr,
141-
/*successType*/nullptr, // TODO: Void.self
135+
/*successType*/successType,
142136
/*task*/ nullptr
143137
};
144138
}
@@ -435,6 +429,17 @@ class TaskGroupImpl: public TaskGroupTaskStatusRecord {
435429
/// or a `PollStatus::MustWait` result if there are tasks in flight
436430
/// and the waitingTask eventually be woken up by a completion.
437431
PollResult poll(AsyncTask *waitingTask);
432+
433+
/// A `discardResults` TaskGroup is not able to wait on individual completions,
434+
/// instead, it can only await on "all pending tasks have been processed".
435+
///
436+
///
437+
/// If unable to complete the waiting task immediately (with an readily
438+
/// available completed task), either returns an `PollStatus::Empty`
439+
/// result if it is known that no pending tasks in the group,
440+
/// or a `PollStatus::MustWait` result if there are tasks in flight
441+
/// and the waitingTask eventually be woken up by a completion.
442+
PollResult waitAll(AsyncTask *waitingTask);
438443
};
439444

440445
} // end anonymous namespace
@@ -593,7 +598,7 @@ void TaskGroupImpl::offer(AsyncTask *completedTask, AsyncContext *context) {
593598
// W:n R:0 P:1 -> W:y R:1 P:1 // complete immediately
594599
// W:n R:0 P:1 -> W:y R:1 P:3 // complete immediately, 2 more pending tasks
595600
auto assumed = statusAddReadyAssumeAcquire();
596-
SWIFT_TASK_DEBUG_LOG("offer task %p to group %p, tasks pending = %d", completedTask, assumed.pendingTasks());
601+
SWIFT_TASK_DEBUG_LOG("offer task %p to group(%p), tasks pending = %d", completedTask, assumed.pendingTasks());
597602

598603
auto asyncContextPrefix = reinterpret_cast<FutureAsyncContextPrefix *>(
599604
reinterpret_cast<char *>(context) - sizeof(FutureAsyncContextPrefix));
@@ -629,13 +634,7 @@ void TaskGroupImpl::offer(AsyncTask *completedTask, AsyncContext *context) {
629634
static_cast<TaskFutureWaitAsyncContext *>(
630635
waitingTask->ResumeContext);
631636

632-
if (isDiscardingResults()) {
633-
fprintf(stderr, "[%s:%d](%s) offer: discardResults\n", __FILE_NAME__, __LINE__, __FUNCTION__);
634-
fillGroupNextResult(waitingContext, result);
635-
} else {
636-
fprintf(stderr, "[%s:%d](%s) offer: NOT\n", __FILE_NAME__, __LINE__, __FUNCTION__);
637-
fillGroupNextResult(waitingContext, result);
638-
}
637+
fillGroupNextResult(waitingContext, result);
639638
detachChild(result.retainedTask);
640639

641640
_swift_tsan_acquire(static_cast<Job *>(waitingTask));
@@ -655,29 +654,20 @@ void TaskGroupImpl::offer(AsyncTask *completedTask, AsyncContext *context) {
655654
// queue when a task polls during next() it will notice that we have a value
656655
// ready for it, and will process it immediately without suspending.
657656
assert(!waitQueue.load(std::memory_order_relaxed));
658-
if (isDiscardingResults()) {
659-
// DO NOT retain the task; and do not store the value in the readyQueue at all (!)
660-
//
661-
// In the "eagerlyRelease" completed tasks mode, we are guaranteed that tasks are of Void type,
662-
// and thus there is no necessity to store values, because we can always "make them up" when polled.
663-
// From the user's perspective, it is indistinguishable if they received the "real value" or one we "made up",
664-
// because Void is always the same, and cannot be examined in any way to determine if it was the "actual" Void or not.
665-
} else {
666-
SWIFT_TASK_DEBUG_LOG("group has no waiting tasks, RETAIN and store ready task = %p",
667-
completedTask);
668-
// Retain the task while it is in the queue;
669-
// it must remain alive until the task group is alive.
670-
swift_retain(completedTask);
671-
672-
auto readyItem = ReadyQueueItem::get(
673-
hadErrorResult ? ReadyStatus::Error : ReadyStatus::Success,
674-
completedTask
675-
);
676-
677-
assert(completedTask == readyItem.getTask());
678-
assert(readyItem.getTask()->isFuture());
679-
readyQueue.enqueue(readyItem);
680-
}
657+
SWIFT_TASK_DEBUG_LOG("group has no waiting tasks, RETAIN and store ready task = %p",
658+
completedTask);
659+
// Retain the task while it is in the queue;
660+
// it must remain alive until the task group is alive.
661+
swift_retain(completedTask);
662+
663+
auto readyItem = ReadyQueueItem::get(
664+
hadErrorResult ? ReadyStatus::Error : ReadyStatus::Success,
665+
completedTask
666+
);
667+
668+
assert(completedTask == readyItem.getTask());
669+
assert(readyItem.getTask()->isFuture());
670+
readyQueue.enqueue(readyItem);
681671

682672
mutex.unlock(); // TODO: remove fragment lock, and use status for synchronization
683673
return;
@@ -713,16 +703,6 @@ SWIFT_CC(swiftasync) static void workaround_function_swift_taskGroup_wait_next_t
713703
// =============================================================================
714704
// ==== group.next() implementation (wait_next and groupPoll) ------------------
715705

716-
SWIFT_CC(swiftasync)
717-
static void swift_taskGroup_wait_next_discardResultsImpl(
718-
OpaqueValue *resultPointer, SWIFT_ASYNC_CONTEXT AsyncContext *callerContext,
719-
TaskGroupImpl *group,
720-
ThrowingTaskFutureWaitContinuationFunction *resumeFunction,
721-
AsyncContext *rawContext,
722-
AsyncTask *waitingTask) {
723-
724-
}
725-
726706
SWIFT_CC(swiftasync)
727707
static void swift_taskGroup_wait_next_throwingImpl(
728708
OpaqueValue *resultPointer, SWIFT_ASYNC_CONTEXT AsyncContext *callerContext,
@@ -736,11 +716,6 @@ static void swift_taskGroup_wait_next_throwingImpl(
736716
auto group = asImpl(_group);
737717
assert(group && "swift_taskGroup_wait_next_throwing was passed context without group!");
738718

739-
if (group->discardResults) {
740-
return swift_taskGroup_wait_next_discardResultsImpl(
741-
callerContext, group, resumeFunction, rawContext, waitingTask)
742-
}
743-
744719
auto context = static_cast<TaskFutureWaitAsyncContext *>(rawContext);
745720
context->ResumeParent =
746721
reinterpret_cast<TaskContinuationFunction *>(resumeFunction);
@@ -767,11 +742,7 @@ static void swift_taskGroup_wait_next_throwingImpl(
767742
case PollStatus::Success:
768743
SWIFT_TASK_DEBUG_LOG("poll group = %p, task = %p, ready task available = %p",
769744
group, waitingTask, polled.retainedTask);
770-
if (isDiscardingResults()) {
771-
fillGroupNextNilResult(context);
772-
} else {
773-
fillGroupNextResult(context, polled);
774-
}
745+
fillGroupNextResult(context, polled);
775746

776747
if (auto completedTask = polled.retainedTask) {
777748
// it would be null for PollStatus::Empty, then we don't need to release
@@ -818,7 +789,7 @@ PollResult TaskGroupImpl::poll(AsyncTask *waitingTask) {
818789
auto assumedStatus = assumed.status;
819790
auto newStatus = TaskGroupImpl::GroupStatus{assumedStatus};
820791
if (status.compare_exchange_strong(
821-
assumedStatus, newStatus.completingPendingReadyWaiting().status,
792+
assumedStatus, newStatus.completingPendingReadyWaiting(this).status,
822793
/*success*/ std::memory_order_relaxed,
823794
/*failure*/ std::memory_order_acquire)) {
824795

@@ -897,14 +868,13 @@ PollResult TaskGroupImpl::poll(AsyncTask *waitingTask) {
897868
}
898869

899870
// =============================================================================
900-
// ==== isEmpty ----------------------------------------------------------------
871+
// ==== Task Group status and flag checks -------------------------------------
872+
901873
SWIFT_CC(swift)
902874
static bool swift_taskGroup_isEmptyImpl(TaskGroup *group) {
903875
return asImpl(group)->isEmpty();
904876
}
905877

906-
// =============================================================================
907-
// ==== isCancelled ------------------------------------------------------------
908878
SWIFT_CC(swift)
909879
static bool swift_taskGroup_isCancelledImpl(TaskGroup *group) {
910880
return asImpl(group)->isCancelled();

stdlib/public/CompatibilityOverride/CompatibilityOverrideConcurrency.def

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,10 @@ OVERRIDE_TASK_GROUP(taskGroup_isCancelled, bool,
307307
SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift),
308308
swift::, (TaskGroup *group), (group))
309309

310+
OVERRIDE_TASK_GROUP(taskGroup_isDiscardingResults, bool,
311+
SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift),
312+
swift::, (TaskGroup *group), (group))
313+
310314
OVERRIDE_TASK_GROUP(taskGroup_cancelAll, void,
311315
SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift),
312316
swift::, (TaskGroup *group), (group))
@@ -316,6 +320,16 @@ OVERRIDE_TASK_GROUP(taskGroup_addPending, bool,
316320
swift::, (TaskGroup *group, bool unconditionally),
317321
(group, unconditionally))
318322

323+
OVERRIDE_TASK_GROUP(taskGroup_waitAll, void,
324+
SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swiftasync),
325+
swift::,
326+
(OpaqueValue *resultPointer,
327+
SWIFT_ASYNC_CONTEXT AsyncContext *callerContext,
328+
TaskGroup *_group,
329+
ThrowingTaskFutureWaitContinuationFunction *resumeFn,
330+
AsyncContext *callContext),
331+
(resultPointer, callerContext, _group, resumeFn,
332+
callContext))
319333

320334
OVERRIDE_TASK_LOCAL(task_reportIllegalTaskLocalBindingWithinWithTaskGroup, void,
321335
SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), swift::,

0 commit comments

Comments
 (0)