51
51
using namespace swift ;
52
52
53
53
#if 0
54
- #define SWIFT_TASK_GROUP_DEBUG_LOG(group, fmt, ...) \
54
+ #define SWIFT_TASK_GROUP_DEBUG_LOG(group, fmt, ...) \
55
55
fprintf(stderr, "[%#lx] [%s:%d][group(%p%s)] (%s) " fmt "\n", \
56
56
(unsigned long)Thread::current().platformThreadId(), \
57
57
__FILE__, __LINE__, \
58
58
group, group->isDiscardingResults() ? ",discardResults" : "", \
59
59
__FUNCTION__, \
60
60
__VA_ARGS__)
61
+
62
+ #define SWIFT_TASK_GROUP_DEBUG_LOG_0(group, fmt, ...) \
63
+ fprintf(stderr, "[%#lx] [%s:%d][group(%p)] (%s) " fmt "\n", \
64
+ (unsigned long)Thread::current().platformThreadId(), \
65
+ __FILE__, __LINE__, \
66
+ group, \
67
+ __FUNCTION__, \
68
+ __VA_ARGS__)
61
69
#else
62
70
#define SWIFT_TASK_GROUP_DEBUG_LOG (group, fmt, ...) (void )0
71
+ #define SWIFT_TASK_GROUP_DEBUG_LOG_0 (group, fmt, ...) (void )0
63
72
#endif
64
73
65
74
using FutureFragment = AsyncTask::FutureFragment;
@@ -354,7 +363,11 @@ class TaskGroupBase : public TaskGroupTaskStatusRecord {
354
363
// / There can be only at-most-one waiting task on a group at any given time,
355
364
// / and the waiting task is expected to be the parent task in which the group
356
365
// / body is running.
357
- PollResult waitAll (AsyncTask *waitingTask);
366
+ // /
367
+ // / \param bodyError error thrown by the body of a with...TaskGroup method
368
+ // / \param waitingTask the task waiting on the group
369
+ // / \return how the waiting task should be handled, e.g. must wait or can be completed immediately
370
+ PollResult waitAll (SwiftError* bodyError, AsyncTask *waitingTask);
358
371
359
372
// Enqueue the completed task onto ready queue if there are no waiting tasks yet
360
373
virtual void enqueueCompletedTask (AsyncTask *completedTask, bool hadErrorResult) = 0;
@@ -411,6 +424,15 @@ class TaskGroupBase : public TaskGroupTaskStatusRecord {
411
424
virtual TaskGroupStatus statusAddPendingTaskRelaxed (bool unconditionally) = 0;
412
425
};
413
426
427
+ static std::string to_string (TaskGroupBase::PollStatus status) {
428
+ switch (status) {
429
+ case TaskGroupBase::PollStatus::Empty: return " Empty" ;
430
+ case TaskGroupBase::PollStatus::MustWait: return " MustWait" ;
431
+ case TaskGroupBase::PollStatus::Success: return " Success" ;
432
+ case TaskGroupBase::PollStatus::Error: return " Error" ;
433
+ }
434
+ }
435
+
414
436
// / The status of a task group.
415
437
// /
416
438
// / Its exact structure depends on the type of group, and therefore a group must be passed to operations
@@ -855,8 +877,8 @@ static void swift_taskGroup_initializeWithFlagsImpl(size_t rawGroupFlags,
855
877
TaskGroup *group, const Metadata *T) {
856
878
857
879
TaskGroupFlags groupFlags (rawGroupFlags);
858
- SWIFT_TASK_DEBUG_LOG ( " group(%p) create; flags: isDiscardingResults=%d" ,
859
- group, groupFlags.isDiscardResults ());
880
+ SWIFT_TASK_GROUP_DEBUG_LOG_0 ( group, " create group ; flags: isDiscardingResults=%d" ,
881
+ groupFlags.isDiscardResults ());
860
882
861
883
TaskGroupBase *impl;
862
884
if (groupFlags.isDiscardResults ()) {
@@ -1618,7 +1640,7 @@ static void swift_taskGroup_waitAllImpl(
1618
1640
waitingTask->ResumeContext = rawContext;
1619
1641
1620
1642
auto group = asBaseImpl (_group);
1621
- PollResult polled = group->waitAll (waitingTask);
1643
+ PollResult polled = group->waitAll (bodyError, waitingTask);
1622
1644
1623
1645
auto context = static_cast <TaskFutureWaitAsyncContext *>(rawContext);
1624
1646
context->ResumeParent =
@@ -1627,23 +1649,13 @@ static void swift_taskGroup_waitAllImpl(
1627
1649
context->errorResult = nullptr ;
1628
1650
context->successResultPointer = resultPointer;
1629
1651
1630
- SWIFT_TASK_GROUP_DEBUG_LOG (group, " waitAllImpl, waiting task = %p, bodyError = %p, status:%s" ,
1631
- waitingTask, bodyError, group->statusString ().c_str ());
1652
+ SWIFT_TASK_GROUP_DEBUG_LOG (group, " waitAllImpl, waiting task = %p, bodyError = %p, status:%s, polled.status = %s " ,
1653
+ waitingTask, bodyError, group->statusString ().c_str (), to_string (polled. status ). c_str () );
1632
1654
1633
1655
switch (polled.status ) {
1634
1656
case PollStatus::MustWait:
1635
- SWIFT_TASK_GROUP_DEBUG_LOG (group, " waitAll MustWait, pending tasks exist, waiting task = %p" ,
1657
+ SWIFT_TASK_GROUP_DEBUG_LOG (group, " waitAllImpl MustWait, pending tasks exist, waiting task = %p" ,
1636
1658
waitingTask);
1637
- if (bodyError && group->isDiscardingResults ()) {
1638
- auto discardingGroup = asDiscardingImpl (_group);
1639
- bool storedBodyError = discardingGroup->offerBodyError (bodyError);
1640
- if (storedBodyError) {
1641
- SWIFT_TASK_GROUP_DEBUG_LOG (
1642
- group, " waitAll, stored error thrown by with...Group body, error = %p" ,
1643
- bodyError);
1644
- }
1645
- }
1646
-
1647
1659
// The waiting task has been queued on the channel,
1648
1660
// there were pending tasks so it will be woken up eventually.
1649
1661
#ifdef __ARM_ARCH_7K__
@@ -1654,7 +1666,7 @@ static void swift_taskGroup_waitAllImpl(
1654
1666
#endif /* __ARM_ARCH_7K__ */
1655
1667
1656
1668
case PollStatus::Error:
1657
- SWIFT_TASK_GROUP_DEBUG_LOG (group, " waitAll found error , waiting task = %p, body error = %p, status:%s" ,
1669
+ SWIFT_TASK_GROUP_DEBUG_LOG (group, " waitAllImpl Error , waiting task = %p, body error = %p, status:%s" ,
1658
1670
waitingTask, bodyError, group->statusString ().c_str ());
1659
1671
#if SWIFT_TASK_GROUP_BODY_THROWN_ERROR_WINS
1660
1672
if (bodyError) {
@@ -1676,17 +1688,10 @@ static void swift_taskGroup_waitAllImpl(
1676
1688
return waitingTask->runInFullyEstablishedContext ();
1677
1689
1678
1690
case PollStatus::Empty:
1679
- // / Anything else than a "MustWait" can be treated as a successful poll.
1680
- // / Only if there are in flight pending tasks do we need to wait after all.
1681
- SWIFT_TASK_GROUP_DEBUG_LOG (group, " waitAll %s, waiting task = %p, status:%s" ,
1682
- polled.status == TaskGroupBase::PollStatus::Empty ? " empty" : " success" ,
1683
- waitingTask, group->statusString ().c_str ());
1684
-
1685
-
1686
1691
case PollStatus::Success:
1687
1692
// / Anything else than a "MustWait" can be treated as a successful poll.
1688
1693
// / Only if there are in flight pending tasks do we need to wait after all.
1689
- SWIFT_TASK_GROUP_DEBUG_LOG (group, " waitAll %s, waiting task = %p, status:%s" ,
1694
+ SWIFT_TASK_GROUP_DEBUG_LOG (group, " waitAllImpl %s, waiting task = %p, status:%s" ,
1690
1695
polled.status == TaskGroupBase::PollStatus::Empty ? " empty" : " success" ,
1691
1696
waitingTask, group->statusString ().c_str ());
1692
1697
@@ -1717,10 +1722,13 @@ bool DiscardingTaskGroup::offerBodyError(SwiftError* _Nonnull bodyError) {
1717
1722
return true ;
1718
1723
}
1719
1724
1720
- PollResult TaskGroupBase::waitAll (AsyncTask *waitingTask) {
1725
+ // / Must be called while holding the `taskGroup.lock`!
1726
+ // / This is because the discarding task group still has some follow-up operations that must
1727
+ // / be performed atomically after this operation sometimes, so we cannot unlock inside `waitAll` itself.
1728
+ PollResult TaskGroupBase::waitAll (SwiftError* bodyError, AsyncTask *waitingTask) {
1721
1729
lock (); // TODO: remove group lock, and use status for synchronization
1722
-
1723
- SWIFT_TASK_GROUP_DEBUG_LOG (this , " waitAll, status = %s" , statusString ().c_str ());
1730
+
1731
+ SWIFT_TASK_GROUP_DEBUG_LOG (this , " waitAll, bodyError = %p, status = %s" , bodyError , statusString ().c_str ());
1724
1732
PollResult result = PollResult::getEmpty (this ->successType );
1725
1733
result.status = PollStatus::Empty;
1726
1734
result.storage = nullptr ;
@@ -1764,6 +1772,18 @@ PollResult TaskGroupBase::waitAll(AsyncTask *waitingTask) {
1764
1772
}
1765
1773
1766
1774
// ==== 2) Add to wait queue -------------------------------------------------
1775
+
1776
+ // ---- 2.1) Discarding task group may need to story the bodyError before we park
1777
+ if (bodyError && isDiscardingResults ()) {
1778
+ auto discardingGroup = asDiscardingImpl (this );
1779
+ bool storedBodyError = discardingGroup->offerBodyError (bodyError);
1780
+ if (storedBodyError) {
1781
+ SWIFT_TASK_GROUP_DEBUG_LOG (
1782
+ this , " waitAll, stored error thrown by with...Group body, error = %p" ,
1783
+ bodyError);
1784
+ }
1785
+ }
1786
+
1767
1787
auto waitHead = waitQueue.load (std::memory_order_acquire);
1768
1788
_swift_tsan_release (static_cast <Job *>(waitingTask));
1769
1789
while (true ) {
0 commit comments