@@ -64,6 +64,21 @@ fprintf(stderr, "[%#lx] [%s:%d][group(%p%s)] (%s) " fmt "\n", \
64
64
65
65
using FutureFragment = AsyncTask::FutureFragment;
66
66
67
+ // / During evolution discussions we opted to implement the following semantic of
68
+ // / a discarding task-group throw:
69
+ // / - the error thrown out of withThrowingDiscardingTaskGroup { ... } always "wins",
70
+ // / even if the group already had an error stored within.
71
+ // /
72
+ // / This is harder to implement, since we have to always store the "first error from children",
73
+ // / and keep it around until body completes, and only then are we able to decide which error to
74
+ // / re-throw; If we threw the body task, we must swift_release the stored "first child error" (if it was present).
75
+ // /
76
+ // / Implementation of "rethrow the first child error" just works in `waitAll`,
77
+ // / since we poll the error and resume the waiting task with it immediately.
78
+ // /
79
+ // / Change this flag, or expose a boolean to offer developers a choice of behavior.
80
+ #define SWIFT_TASK_GROUP_BODY_THROWN_ERROR_WINS 1
81
+
67
82
namespace {
68
83
class TaskStatusRecord ;
69
84
struct TaskGroupStatus ;
@@ -237,10 +252,6 @@ class TaskGroupBase : public TaskGroupTaskStatusRecord {
237
252
}
238
253
239
254
static ReadyQueueItem get (ReadyStatus status, AsyncTask *task) {
240
- fprintf (stderr, " [%s:%d](%s) store ReadyQueueItem = %s\n " , __FILE_NAME__, __LINE__, __FUNCTION__,
241
- status == ReadyStatus::Error ? " error" :
242
- (status == ReadyStatus::RawError ? " raw-error" :
243
- (status == ReadyStatus::Success ? " success" : " other" )));
244
255
assert (task == nullptr || task->isFuture ());
245
256
return ReadyQueueItem{
246
257
reinterpret_cast <uintptr_t >(task) | static_cast <uintptr_t >(status)};
@@ -983,7 +994,8 @@ static void fillGroupNextResult(TaskFutureWaitAsyncContext *context,
983
994
return ;
984
995
985
996
case PollStatus::Error: {
986
- fillGroupNextErrorResult (context, reinterpret_cast <SwiftError *>(result.storage ));
997
+ auto error = reinterpret_cast <SwiftError *>(result.storage );
998
+ fillGroupNextErrorResult (context, error);
987
999
return ;
988
1000
}
989
1001
@@ -1659,9 +1671,17 @@ static void swift_taskGroup_waitAllImpl(
1659
1671
#endif /* __ARM_ARCH_7K__ */
1660
1672
1661
1673
case PollStatus::Error:
1662
- SWIFT_TASK_GROUP_DEBUG_LOG (group, " waitAll found error, waiting task = %p, status:%s" ,
1663
- waitingTask, group->statusString ().c_str ());
1674
+ SWIFT_TASK_GROUP_DEBUG_LOG (group, " waitAll found error, waiting task = %p, body error = %p, status:%s" ,
1675
+ waitingTask, bodyError, group->statusString ().c_str ());
1676
+ #if SWIFT_TASK_GROUP_BODY_THROWN_ERROR_WINS
1677
+ if (bodyError) {
1678
+ fillGroupNextErrorResult (context, bodyError);
1679
+ } else {
1680
+ fillGroupNextResult (context, polled);
1681
+ }
1682
+ #else // so, not SWIFT_TASK_GROUP_BODY_THROWN_ERROR_WINS
1664
1683
fillGroupNextResult (context, polled);
1684
+ #endif // SWIFT_TASK_GROUP_BODY_THROWN_ERROR_WINS
1665
1685
if (auto completedTask = polled.retainedTask ) {
1666
1686
// Remove the child from the task group's running tasks list.
1667
1687
_swift_taskGroup_detachChild (asAbstract (group), completedTask);
@@ -1739,9 +1759,6 @@ PollResult TaskGroupBase::waitAll(AsyncTask *waitingTask) {
1739
1759
auto discardingGroup = asDiscardingImpl (this );
1740
1760
ReadyQueueItem firstErrorItem;
1741
1761
if (readyQueue.dequeue (firstErrorItem)) {
1742
- fprintf (stderr, " [%s:%d](%s) waitAll EMPTY AND dequeued from readyQueue: %s\n " , __FILE_NAME__, __LINE__, __FUNCTION__,
1743
- (firstErrorItem.getStatus () == ReadyStatus::Error ? " error" :
1744
- (firstErrorItem.getStatus () == ReadyStatus::RawError) ? " raw-error" : " wat" ));
1745
1762
if (firstErrorItem.getStatus () == ReadyStatus::Error) {
1746
1763
result = PollResult::get (firstErrorItem.getTask (), /* hadErrorResult=*/ true );
1747
1764
} else if (firstErrorItem.getStatus () == ReadyStatus::RawError) {
@@ -1754,7 +1771,7 @@ PollResult TaskGroupBase::waitAll(AsyncTask *waitingTask) {
1754
1771
return result;
1755
1772
}
1756
1773
1757
- SWIFT_TASK_GROUP_DEBUG_LOG (this , " group is empty, no pending tasks, status = %s" , assumed.to_string (this ));
1774
+ SWIFT_TASK_GROUP_DEBUG_LOG (this , " group is empty, no pending tasks, status = %s" , assumed.to_string (this ). c_str () );
1758
1775
// No tasks in flight, we know no tasks were submitted before this poll
1759
1776
// was issued, and if we parked here we'd potentially never be woken up.
1760
1777
// Bail out and return `nil` from `group.next()`.
0 commit comments