static int scanHostlist ( HostEntry *h, ARRAY8Ptr clientAddress, CARD16 connectionType, ChooserFunc function, char *closure, int depth, int broadcast) { int haveLocalhost = 0; for (; h; h = h->next) { switch (h->type) { case HOST_ALIAS: if (indirectAlias (h->entry.aliasName, clientAddress, connectionType, function, closure, depth, broadcast)) haveLocalhost = 1; break; case HOST_ADDRESS: if (XdmcpARRAY8Equal (getLocalAddress(), &h->entry.hostAddress)) haveLocalhost = 1; else if (function) (*function) (connectionType, &h->entry.hostAddress, closure); break; case HOST_BROADCAST: if (broadcast) { ARRAY8 temp; if (function) { temp.data = (BYTE *) BROADCAST_STRING; temp.length = strlen ((char *)temp.data); (*function) (connectionType, &temp, closure); } } break; } } return haveLocalhost; }
void __cdecl _UnrealizedChore::_UnstructuredChoreWrapper(_UnrealizedChore * pChore) { InternalContextBase *pContext = static_cast<InternalContextBase *> (SchedulerBase::FastCurrentContext()); // The context could be canceled if it was already prepared for steal (this happens during a block unblock race) ASSERT(pContext != NULL && (!pContext->HasInlineCancellation() || pContext->GetRootCollection() != NULL)); _TaskCollection* pTaskCollection = static_cast<_TaskCollection *> (pChore->_M_pTaskCollection); // // pOriginContext is only safe to touch if the act of stealing from a non-detached context put a hold on that context // to block deletion until we are chained for cancellation. // ContextBase *pOriginContext = reinterpret_cast <ContextBase *> (pTaskCollection->_M_pOwningContext); SafeRWList<ListEntry> *pList = reinterpret_cast<SafeRWList<ListEntry> *> (pTaskCollection->_M_stealTracker); pChore->_PrepareStealUnstructured(pContext); _CancellationTokenState *pTokenState = pTaskCollection->_GetTokenState(); _CancellationTokenRegistration *pRegistration = NULL; if (_CancellationTokenState::_IsValid(pTokenState)) { pRegistration = pTokenState->_RegisterCallback(reinterpret_cast<TaskProc>(&_UnrealizedChore::_CancelViaToken), (ContextBase *)pContext); } // // Waiting on the indirect alias may throw (e.g.: the entire context may have been canceled). If it // throws, we need to deal with appropriate marshaling. // try { // // Set up an indirect alias for this task collection. Any usage of the original task collection // within this stolen chore will automatically redirect through the indirect alias. This allows // preservation of single-threaded semantics within the task collection while allowing it to be "accessed" // from stolen chores (multiple threads). // // This stack based collection will wait on stolen chores at destruction time. In the event the collection is not // used during the steal, this doesn't do much. // _TaskCollection indirectAlias(pTaskCollection, false); pContext->SetIndirectAlias(&indirectAlias); try { // // We need to consider this a possible interruption point. It's entirely possible that we stole and raced with a // cancellation thread. The collection was canceled after we stole(e.g.: removed from the WSQ) but before we added ourselves // to the stealing chain list above. In this case, the entire context will wait until completion (bad). Immediately // after we go on the list (a memory barrier), we need to check the collection cancellation flag. If the collection is going away, // we need to get out *NOW* otherwise the entire subtree executes. // if (pTaskCollection->_M_pOriginalCollection->_M_exitCode != 0 || (_CancellationTokenState::_IsValid(pTokenState) && pTokenState->_IsCanceled()) || (pTaskCollection->_M_executionStatus != TASKCOLLECTION_EXECUTION_STATUS_CLEAR && pTaskCollection->_M_executionStatus != TASKCOLLECTION_EXECUTION_STATUS_INLINE && pTaskCollection->_M_executionStatus != TASKCOLLECTION_EXECUTION_STATUS_INLINE_WAIT_WITH_OVERFLOW_STACK)) throw _Interruption_exception(); pChore->m_pFunction(pChore); } catch(const _Interruption_exception &) { // // If someone manually threw _Interruption_exception, we will have a cancel count but not a canceled context. This // means we need to apply the cancel one level up. Normally, the act of throwing would do that via being caught in the // wait, but this is special "marshaling" for _Interruption_exception. // if (pContext->HasInlineCancellation() && !pContext->IsEntireContextCanceled()) pTaskCollection->_Cancel(); } catch(...) { // // Track the exception that was thrown here and subsequently cancel all work. _RaisedException makes the decision on what // exceptions to keep and what to discard. The flags it sets will indicate to the thread calling ::Wait that it must rethrow. // pTaskCollection->_RaisedException(); pTaskCollection->_Cancel(); } indirectAlias._Wait(); } catch(const _Interruption_exception &) { // // If someone manually threw _Interruption_exception out of a task on the indirect alias, the same thing applies as to // a directly stolen chore (above). // if (pContext->HasInlineCancellation() && !pContext->IsEntireContextCanceled()) pTaskCollection->_Cancel(); } catch(...) { // // Track the exception that was thrown here and subsequently cancel all work. _RaisedException makes the decision on what // exceptions to keep and what to discard. The flags it sets will indicate to the thread calling ::Wait that it must rethrow. // pTaskCollection->_RaisedException(); pTaskCollection->_Cancel(); } pContext->SetIndirectAlias(NULL); ASSERT(pContext->GetGoverningTokenState() == NULL); if ( !pChore->_M_fDetached) { // // pOriginContext may die at any point (detachment). When it does, it will transfer the stolen chore trace from the context to the // given task collection (us) under lock. We can, therefore, take this lock and check if we are still okay to check the context. // pList->AcquireWrite(); if (pContext->IsContextChainedStealer()) pOriginContext->RemoveStealer(pContext); else pList->UnlockedRemove(&(pContext->m_stealChain)); pTaskCollection->_M_activeStealersForCancellation--; pList->ReleaseWrite(); } else { pList->Remove(&(pContext->m_stealChain)); } if (pRegistration != NULL) { pTokenState->_DeregisterCallback(pRegistration); pRegistration->_Release(); } pContext->ClearCancel(); pContext->ClearAliasTable(); pContext->SetRootCollection(NULL); pChore->_M_pTaskCollection = NULL; pTaskCollection->_NotifyCompletedChoreAndFree(pChore); }