@@ -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)};
@@ -976,7 +987,8 @@ static void fillGroupNextResult(TaskFutureWaitAsyncContext *context,
976
987
return ;
977
988
978
989
case PollStatus::Error: {
979
- fillGroupNextErrorResult (context, reinterpret_cast <SwiftError *>(result.storage ));
990
+ auto error = reinterpret_cast <SwiftError *>(result.storage );
991
+ fillGroupNextErrorResult (context, error);
980
992
return ;
981
993
}
982
994
@@ -1652,9 +1664,17 @@ static void swift_taskGroup_waitAllImpl(
1652
1664
#endif /* __ARM_ARCH_7K__ */
1653
1665
1654
1666
case PollStatus::Error:
1655
- SWIFT_TASK_GROUP_DEBUG_LOG (group, " waitAll found error, waiting task = %p, status:%s" ,
1656
- waitingTask, group->statusString ().c_str ());
1667
+ SWIFT_TASK_GROUP_DEBUG_LOG (group, " waitAll found error, waiting task = %p, body error = %p, status:%s" ,
1668
+ waitingTask, bodyError, group->statusString ().c_str ());
1669
+ #if SWIFT_TASK_GROUP_BODY_THROWN_ERROR_WINS
1670
+ if (bodyError) {
1671
+ fillGroupNextErrorResult (context, bodyError);
1672
+ } else {
1673
+ fillGroupNextResult (context, polled);
1674
+ }
1675
+ #else // so, not SWIFT_TASK_GROUP_BODY_THROWN_ERROR_WINS
1657
1676
fillGroupNextResult (context, polled);
1677
+ #endif // SWIFT_TASK_GROUP_BODY_THROWN_ERROR_WINS
1658
1678
if (auto completedTask = polled.retainedTask ) {
1659
1679
// Remove the child from the task group's running tasks list.
1660
1680
_swift_taskGroup_detachChild (asAbstract (group), completedTask);
@@ -1732,9 +1752,6 @@ PollResult TaskGroupBase::waitAll(AsyncTask *waitingTask) {
1732
1752
auto discardingGroup = asDiscardingImpl (this );
1733
1753
ReadyQueueItem firstErrorItem;
1734
1754
if (readyQueue.dequeue (firstErrorItem)) {
1735
- fprintf (stderr, " [%s:%d](%s) waitAll EMPTY AND dequeued from readyQueue: %s\n " , __FILE_NAME__, __LINE__, __FUNCTION__,
1736
- (firstErrorItem.getStatus () == ReadyStatus::Error ? " error" :
1737
- (firstErrorItem.getStatus () == ReadyStatus::RawError) ? " raw-error" : " wat" ));
1738
1755
if (firstErrorItem.getStatus () == ReadyStatus::Error) {
1739
1756
result = PollResult::get (firstErrorItem.getTask (), /* hadErrorResult=*/ true );
1740
1757
} else if (firstErrorItem.getStatus () == ReadyStatus::RawError) {
@@ -1747,7 +1764,7 @@ PollResult TaskGroupBase::waitAll(AsyncTask *waitingTask) {
1747
1764
return result;
1748
1765
}
1749
1766
1750
- SWIFT_TASK_GROUP_DEBUG_LOG (this , " group is empty, no pending tasks, status = %s" , assumed.to_string (this ));
1767
+ SWIFT_TASK_GROUP_DEBUG_LOG (this , " group is empty, no pending tasks, status = %s" , assumed.to_string (this ). c_str () );
1751
1768
// No tasks in flight, we know no tasks were submitted before this poll
1752
1769
// was issued, and if we parked here we'd potentially never be woken up.
1753
1770
// Bail out and return `nil` from `group.next()`.
0 commit comments