diff --git a/clc/dll/src/SubItem.cpp b/clc/dll/src/SubItem.cpp index 7d75caa12..7b088f6d5 100644 --- a/clc/dll/src/SubItem.cpp +++ b/clc/dll/src/SubItem.cpp @@ -203,6 +203,8 @@ struct PhaseContainerOperator : BinaryOperator auto resultRoot = resultHolder.GetNew(); for (auto resWalker = resultRoot; resWalker; resWalker = resultRoot->WalkCurrSubTree(resWalker)) { + assert(!resWalker->HasInterest()); + auto srcItem = sourceContainer->FindItem(resWalker->GetRelativeName(resultHolder.GetNew())); if (!srcItem) continue; @@ -216,16 +218,18 @@ struct PhaseContainerOperator : BinaryOperator auto srcPhaseNumber = srcItem->GetPhaseNumber(); MG_CHECK(srcPhaseNumber < resultPhaseNumber); - if (resWalker != resultRoot) // avoid updating all fenced items before getting them - resWalker->GetOrCreateSupplCache()->InitAt(srcItem); + if (srcItem->WasFailed()) + resWalker->Fail(srcItem); - assert(!resWalker->HasInterest()); + if (!IsUnit(resWalker) && !IsDataItem(resWalker)) + continue; + + if (resWalker != resultRoot) + resWalker->GetOrCreateSupplCache()->InitAt(srcItem); if (IsUnit(resWalker)) resWalker->SetReferredItem(srcItem); - if (srcItem->WasFailed()) - resWalker->Fail(srcItem); } } assert(resultHolder); @@ -258,136 +262,62 @@ struct PhaseContainerOperator : BinaryOperator auto resultRoot = resultHolder.GetNew(); assert(resultRoot); - using fence_member_pair = std::pair; - using fence_work_data = std::vector; - fence_work_data futureDataContainer; - auto resultPhaseNumber = resultHolder.m_PhaseNumber; assert(resultPhaseNumber > 0); - std::atomic phaseContainerStatus = task_status::activated; std::exception_ptr fenceErrorPtr; - auto resWalker = resultRoot; - // now, collect all targets that this Phase should calculate and start a Main Thread action to do so. - // this should be done before supplier Fences do this and after target collection and interest-setting of consuming Fences. - // so each Phase Calculation causes an avalange of interest in targets in higher fences and then their calculation before this calculation starts - PostMainThreadTask(resultPhaseNumber, [this, sourceContainer, resultRoot, &resWalker, &phaseContainerStatus, &fenceErrorPtr, &resultHolder, resultPhaseNumber, &futureDataContainer](bool mustCancel)-> bool - { - phaseContainerStatus = task_status::running; - - // work on exporting stuff from main thread - if (!mustCancel) - { - try { - tmp_swapper lockFence(s_CurrBlockedPhaseNumber, resultPhaseNumber); - s_CurrPhaseContainer = resultRoot; - for (; resWalker; resWalker = resultRoot->WalkCurrSubTree(resWalker)) - { - assert(resWalker->GetCurrPhaseNumber() == resultPhaseNumber); - - auto resInterestPtr = resWalker->GetInterestPtrOrNull(); - if (!resInterestPtr) - continue; - - auto srcItem = sourceContainer->FindItem(resWalker->GetRelativeName(resultRoot)); - assert(srcItem); - assert(srcItem->GetCurrPhaseNumber() < resultPhaseNumber); - MG_CHECK(!srcItem->IsCacheItem()); - - s_CurrBlockedPhaseItem = srcItem.get(); - if (!srcItem->SuspendibleUpdate(PS_Committed)) - { - if (srcItem->WasFailed()) - resWalker->Fail(srcItem); - if (SuspendTrigger::DidSuspend()) - return false; - } - assert(!SuspendTrigger::DidSuspend()); - - if (!IsUnit(resWalker) && !IsDataItem(resWalker)) - continue; - - // assert(resWalker->DoesHaveSupplInterest()); - - auto dc = srcItem->mc_DC; - if (!dc) - resWalker->Fail(mySSPrintF("PhaseContainer: Source %s has no calculation rule so its data cannot be collected", srcItem->GetSourceName()).c_str(), FR_Data); - else - { - auto fd = dc->CallCalcResult(); - if (SuspendTrigger::DidSuspend()) - return false; - - futureDataContainer.emplace_back(std::move(resInterestPtr), std::move(fd)); - } - } - } - catch (Concurrency::task_canceled&) - { - throw; - } - catch (...) - { - fenceErrorPtr = std::current_exception(); - phaseContainerStatus = task_status::exception; - return true; - } - } - phaseContainerStatus = task_status::done; - WakeUpJoiners(); - return true; - } - ); - - { - DoWorkWhileWaitingFor(&phaseContainerStatus); - if (phaseContainerStatus == task_status::exception && fenceErrorPtr) - std::rethrow_exception(fenceErrorPtr); - } - // check that all sub-items of result-holder are/become up-to-date or uninteresting - for (const auto& fd: futureDataContainer) + for (auto resWalker = resultRoot; resWalker; resWalker = resultRoot->WalkCurrSubTree(resWalker)) { - auto resItem = const_cast(fd.first.get_ptr()); - auto dc = fd.second; + assert(resWalker->GetCurrPhaseNumber() == resultPhaseNumber); - assert(resItem); - assert(dc); - - if (!dc) + if (!IsUnit(resWalker) && !IsDataItem(resWalker)) continue; - if (dc->WasFailed(FR_MetaInfo)) - { - resItem->Fail(dc.get_ptr()); + auto resInterestPtr = resWalker->GetInterestPtrOrNull(); + if (!resInterestPtr) continue; - } - WaitReady(dc->GetUlt()); - if (dc->WasFailed(FR_Data)) - resItem->Fail(dc.get_ptr()); - else + + auto srcItem = static_cast( resWalker->GetSupplCache()->GetSupplier(0) ); + assert(srcItem->GetID() == resWalker->GetID()); + + assert(srcItem->GetCurrPhaseNumber() < resultPhaseNumber); + + auto dc = srcItem->mc_DC; + if (!dc) + resWalker->Fail(mySSPrintF("PhaseContainer: Source %s has no calculation rule so its data cannot be collected", srcItem->GetSourceName()).c_str(), FR_Data); + else if (dc->WasFailed(FR_MetaInfo)) + resWalker->Fail(dc.get_ptr()); + else { - auto srcUltItem = dc->GetUlt(); - assert(srcUltItem); - assert(CheckDataReady(srcUltItem)); - if (IsDataItem(resItem)) - AsDataItem(resItem)->m_DataObject = AsDataItem(srcUltItem)->m_DataObject; + WaitReady(dc->GetUlt()); + if (dc->WasFailed(FR_Data)) + resWalker->Fail(dc.get_ptr()); else { - assert(IsUnit(srcUltItem)); - visit(AsUnit(srcUltItem), - [&resItem](const Unit*srcUltUnit) { checked_valcast*>(resItem)->m_RangeDataPtr = srcUltUnit->m_RangeDataPtr; } - ); + auto srcUltItem = dc->GetUlt(); + assert(srcUltItem); + assert(CheckDataReady(srcUltItem)); + if (IsDataItem(resWalker)) + AsDataItem(resWalker)->m_DataObject = AsDataItem(srcUltItem)->m_DataObject; + else + { + assert(IsUnit(srcUltItem)); + visit(AsUnit(srcUltItem), + [&resWalker](const Unit*srcUltUnit) { checked_valcast*>(resWalker)->m_RangeDataPtr = srcUltUnit->m_RangeDataPtr; } + ); + } + if (dc->WasFailed()) + resWalker->Fail(dc.get_ptr()); + if (srcUltItem->WasFailed()) + resWalker->Fail(srcUltItem); + + resWalker->SetIsInstantiated(); } - if (dc->WasFailed()) - resItem->Fail(dc.get_ptr()); - if (srcUltItem->WasFailed()) - resItem->Fail(srcUltItem); } - resItem->SetIsInstantiated(); - resItem->StopSupplInterest(); + resWalker->StopSupplInterest(); } DataReadLock msgLock(AsDataItem(args[1])); diff --git a/tic/dll/src/ItemLocks.cpp b/tic/dll/src/ItemLocks.cpp index 168e7dc3e..c23f7e87f 100644 --- a/tic/dll/src/ItemLocks.cpp +++ b/tic/dll/src/ItemLocks.cpp @@ -770,7 +770,7 @@ bool WaitForReadyOrSuspendTrigger(const TreeItem* item) else { assert(IsMultiThreaded2()); - DoWorkWhileWaitingFor(nullptr); // max 500 milliseconds or actual work + DoWorkWhileWaiting(); // max 500 milliseconds or actual work SuspendTrigger::MarkProgress(); // Is ti or any other item indeed progressing without dropping off from scope if (counter++ == 20) // sporadious wakeup at least every 10 secs to release from mysterious hang SuspendTrigger::DoSuspend(); diff --git a/tic/dll/src/OperationContext.cpp b/tic/dll/src/OperationContext.cpp index 4f8805662..3a3fcd835 100644 --- a/tic/dll/src/OperationContext.cpp +++ b/tic/dll/src/OperationContext.cpp @@ -2308,7 +2308,7 @@ task_status OperationContext::Join() } // ***************************************************************************** -// Section: DoWorkWhileWaitingFor +// Section: DoWorkWhileWaiting // ***************************************************************************** // // Cooperative waiting helper to make progress while waiting for a fence status. @@ -2316,53 +2316,45 @@ task_status OperationContext::Join() // // ***************************************************************************** -TIC_CALL void DoWorkWhileWaitingFor(std::atomic* fenceStatus) +TIC_CALL void DoWorkWhileWaiting() { if (!IsMetaThread()) StealOneTileTask(true); - while (!fenceStatus || IsActiveOrRunning(*fenceStatus)) + if (IsMetaThread()) { - if (IsMetaThread()) - { // if (SuspendTrigger::MustSuspend()) // return false; - ProcessMainThreadOpers(); - ProcessSuspendibleTasks(); - SuspendTrigger::MarkProgress(); - } + ProcessMainThreadOpers(); + ProcessSuspendibleTasks(); + SuspendTrigger::MarkProgress(); + } - auto currentFinishCount = GetCurrFinishedCount(); + auto currentFinishCount = GetCurrFinishedCount(); - StartOperationContexts(); - if (!IsMetaThread()) - while (!fenceStatus || IsActiveOrRunning(*fenceStatus)) - { - if (!StealOneTask()) - break; - if (!fenceStatus) - return; // let caller reconsider after one tasks has been done and no explicit termination condition variable is provided - } + StartOperationContexts(); + if (!IsMetaThread()) + { + if (StealOneTask()) + return; // let caller reconsider after one tasks has been done as no explicit termination condition variable is provided + } - leveled_std_section::unique_lock lock(cs_ThreadMessing); - if (fenceStatus && *fenceStatus > task_status::running) - break; + leveled_std_section::unique_lock lock(cs_ThreadMessing); - if (currentFinishCount != s_CurrFinishedCount) - continue; + if (currentFinishCount != s_CurrFinishedCount) + return; - if (IsMetaThread() && HasMainThreadTasks()) - continue; + if (IsMetaThread()) + { + if (HasMainThreadTasks()) + return; if (SuspendTrigger::MustSuspend()) return; - - // wait for conditioin that was certainly not met just after setting the thread messing lock - cv_TaskCompleted.wait_for(lock.m_BaseLock, std::chrono::milliseconds(500)); - - if (!fenceStatus) - return; // let caller reconsider after one tasks has been done and no explicit termination condition variable is provided } + + // wait for conditioin that was certainly not met just after setting the thread messing lock + cv_TaskCompleted.wait_for(lock.m_BaseLock, std::chrono::milliseconds(500)); } // ***************************************************************************** diff --git a/tic/dll/src/OperationContext.h b/tic/dll/src/OperationContext.h index 76d762d2a..b58722a23 100644 --- a/tic/dll/src/OperationContext.h +++ b/tic/dll/src/OperationContext.h @@ -323,9 +323,9 @@ struct OperationContext : std::enable_shared_from_this // Global monotonic counter to assign new phase numbers for batch scheduling/waiting. TIC_CALL auto GetNextPhaseNumber() -> phase_number; -// DoWorkWhileWaitingFor -// Allow current thread to perform other work while waiting for a phase to complete. -TIC_CALL void DoWorkWhileWaitingFor(std::atomic* phaseContainerStatus); +// DoWorkWhileWaiting +// Allow current thread to perform other work. +TIC_CALL void DoWorkWhileWaiting(); // WakeUpJoiners // Notifies threads/contexts waiting on global join conditions to re-check status.