⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 umsfreevirtualprocessorroot.cpp

📁 C语言库函数的原型,有用的拿去
💻 CPP
📖 第 1 页 / 共 4 页
字号:
    {
        CORE_ASSERT(OnPrimary());
        CORE_ASSERT(pProxy->GetCriticalRegionType() != OutsideCriticalRegion);

        HANDLE hWaitObjects[2];
        int count = 2;

        //
        // NOTE: It is *ABSOLUTELY* imperative that the critical notification event come FIRST in the wait order!
        // Critically blocked proxies cannot be on the transfer list. So do not wait on transfer list events.
        //
        hWaitObjects[0] = m_hCriticalNotificationEvent;
        hWaitObjects[1] = SchedulerProxy()->GetCompletionListEvent();

        //
        // Continue blocking until we either pull something off the completion list (in which case we simply sleep again) or the
        // critical notification event is signaled (indicating that someone pulled the critical item off the list).  When the critical
        // notification event is signaled, whatever we are critically blocking upon *SHOULD* be runnable (assuming it wasn't asynchronously
        // suspended in the interim or some such silly thing).
        //
        for(;;)
        {
            SchedulerProxy()->SweepCompletionList();

            //
            // Even if we were the one to sweep pProxy off the list, we must still perform the wait -- the event must be reset for the next
            // critical blocking.
            //
            DWORD result = WaitForMultipleObjects(count, hWaitObjects, FALSE, INFINITE);

            if (result == WAIT_OBJECT_0)
            {
#if defined(_DEBUG)
                pProxy->m_UMSDebugBits |= UMS_DEBUGBIT_CRITICALAWAKENING;
#endif // _DEBUG

                //
                // For threads we burn, they come back through the critical notification path here and simply do not get executed.  Any return
                // from CriticalBlockAndExecute indicates thread termination.
                //
                if (pProxy->IsTerminated())
                    return;

                Execute(pProxy, false, true);
                
                //
                // If we get here, it means that ExecuteUmsThread failed (because of asynchronous suspension such as APC).
                // In that case, we really just need to loop up and wait for this object to appear on the completion list again.
                // Note that if we succeed, they just reset the stack frame of the primary and this magically disappears off the stack (e.g.:
                // ExecuteUmsThread does *NOT* return ever on success).
                //
            }

            //
            // In either case -- failure or something appearing on the completion list, we need to sweep the list and wait again until the critical
            // notification event is signaled. 
            //
            
        }
    }

    /// <summary>
    ///     Called in order to handle a UMS thread blocking.
    /// </summary>
    /// <param name="pBlockedProxy">
    ///     The thread that is blocking.
    /// </param>
    /// <param name="fAsynchronous">
    ///     An indication of whether the blocking was due to an asynchronous event (e.g.: page fault) or a synchronous one (e.g.: calling an API
    ///     which explicitly blocked.
    /// </param>
    void UMSFreeVirtualProcessorRoot::HandleBlocking(UMSFreeThreadProxy *pBlockedProxy, bool fAsynchronous)
    {
        RVPMTRACE(MTRACE_EVT_RETURNTOPRIMARY_BLOCKED, pBlockedProxy, this, fAsynchronous);

        CriticalRegionType type = pBlockedProxy->GetCriticalRegionType();

        //
        // We control thread lifetimes within the RM.  Any thread which we are burning on the way out must be in a hyper-critical region.
        //
        CORE_ASSERT(!pBlockedProxy->IsTerminated() || type == InsideHyperCriticalRegion);

        for (;;)
        {
            if (type == InsideHyperCriticalRegion || (type == InsideCriticalRegion && fAsynchronous))
            {
                RVPMTRACE(MTRACE_EVT_CRITICALBLOCK, pBlockedProxy, this, fAsynchronous);
#if defined(_DEBUG)
                pBlockedProxy->m_UMSDebugBits |= UMS_DEBUGBIT_CRITICALBLOCK;
#endif // _DEBUG
                pBlockedProxy->NotifyBlocked(true);
                CriticalBlockAndExecute(pBlockedProxy);

                //
                // CriticalBlockAndExecute always performs a UMS::ExecuteUMSThread until it succeeds or the thread terminates.  If it succeeds,
                // the stack is snapped back and we never get here.  Getting here implies that the thread terminated.
                //
                CORE_ASSERT(pBlockedProxy->IsTerminated());
                delete pBlockedProxy;
                return;
            }

            RVPMTRACE(MTRACE_EVT_UMSBLOCKED, pBlockedProxy, this, fAsynchronous);

#if defined(_DEBUG)
            pBlockedProxy->m_UMSDebugBits |= UMS_DEBUGBIT_BLOCKED;
#endif // _DEBUG
            pBlockedProxy->NotifyBlocked(false);

            InvokeSchedulingContext(fAsynchronous);

        }
    }

    /// <summary>
    ///     Called in order to handle a UMS thread cooperative yielding.
    /// </summary>
    /// <param name="pProxy">
    ///     The thread that is yielding.
    /// </param>
    void UMSFreeVirtualProcessorRoot::HandleYielding(UMSFreeThreadProxy *pProxy)
    {
        RVPMTRACE(MTRACE_EVT_RETURNTOPRIMARY_YIELD, pProxy, this, NULL);
        CORE_ASSERT(pProxy->m_yieldAction != UMSThreadProxy::ActionNone);

#if defined(_DEBUG)
        pProxy->m_UMSDebugBits |= UMS_DEBUGBIT_YIELDED;
#endif // _DEBUG

        switch(pProxy->m_yieldAction)
        {
            //
            // Someone performed a SwitchTo(..., Nesting).  The UT which performed this call already created a transmogrified primary
            // to transmogrify itself into a "virtual"-thread.  We simply need to message that primary that it's now safe to execute the
            // thread.
            //
            case UMSThreadProxy::ActionTransmogrify:

                //
                // Intentional Fall Through:
                //

            //
            // Someone performed a SwitchTo.  We do not block the thread (per-kernel-block), the thread simply put data in its
            // messaging block and explicitly yielded to the primary.
            //
            case UMSThreadProxy::ActionSwitchTo:
            {
                UMSFreeThreadProxy *pNextProxy = NULL;

                if (pProxy->m_pNextProxy != NULL)
                {
                    pNextProxy = static_cast<UMSFreeThreadProxy *>(pProxy->m_pNextProxy);

#if defined(_DEBUG)
                    CORE_ASSERT((pNextProxy->m_UMSDebugBits & UMS_DEBUGBIT_DEACTIVATEDPROXY) == 0);
#endif
                }

                //
                // We need to make sure that the transmogrified primary does this when the transmogrification is complete.  Otherwise, someone
                // may wind up trying to run pProxy prematurely on the exit of the nesting.
                //
                if (pProxy->m_yieldAction == UMSThreadProxy::ActionTransmogrify)
                {
                    //
                    // The transmogrification might not even be created yet!  Notify the transmogrificator.  It will defer unblock it if necessary.
                    //
                    GetResourceManager()->GetTransmogrificator()->UnblockTransmogrification(pProxy);
                }
                else
                {
                    pProxy->NotifyBlocked(false);
                }

                if (pNextProxy != NULL)
                {
                    Execute(pNextProxy, false, false);
                }
                else
                {
                    //
                    // Someone wants to *DIRECTLY* switch to the primary.  Note that this is *NOT* an infinite loop as the execution
                    // will snap out the stack.
                    //
                    for (;;)
                    {
                        InvokeSchedulingContext(false);
                    }
                }

                CORE_ASSERT(false);
                break;
            }

            //
            // Someone performed a SwitchTo(..., idle).  We do not block the thread (per-kernel-block), the thread simply put data
            // in its messaging block and explicitly yielded to the primary.  We do, however, put the thread back on the idle pool.
            //
            case UMSThreadProxy::ActionSwitchToAndRetire:
            {
                UMSFreeThreadProxy *pNextProxy = NULL;
                
                if (pProxy->m_pNextProxy != NULL)
                {
                    pNextProxy = static_cast<UMSFreeThreadProxy *>(pProxy->m_pNextProxy);

                    RVPMTRACE(MTRACE_EVT_CONTEXT_RELEASED, pProxy, this, pNextProxy);
                }
                else
                {
                    RVPMTRACE(MTRACE_EVT_CONTEXT_RELEASED, pProxy, this, NULL);
                }

        #if defined(_DEBUG)
                pProxy->m_UMSDebugBits |= UMS_DEBUGBIT_FREELIST;
        #endif // _DEBUG

                pProxy->NotifyBlocked(false);
                pProxy->ReturnIdleProxy();

                if (pNextProxy != NULL)
                {
                    Execute(pNextProxy, false, false);
                }
                else
                {
                    //
                    // Someone wants to *DIRECTLY* switch to the primary.  Note that this is *NOT* an infinite loop as the execution
                    // will snap out the stack.
                    //
                    for (;;)
                    {
                        InvokeSchedulingContext(false);
                    }
                }

                CORE_ASSERT(false);
                break;
            }

            //
            // Someone called YieldToSystem. Yield the time quantum to the operating system using SwitchToThread
            // and re-execute the UT.
            //
            case UMSThreadProxy::ActionYieldToSystem:
            {
                pProxy->NotifyBlocked(false);
                YieldToSystem();
                Execute(pProxy, false, false);
                CORE_ASSERT(false);
                break;
            }

            //
            // Someone performed a Deactivate on the virtual processor root that was running this context.
            //
            case UMSThreadProxy::ActionDeactivate:
            {
                CORE_ASSERT(pProxy->m_pLastRoot == this);

                //
                // The semantics around Deactivate make it perfectly safe to mark it blocked now.  Normally, we cannot touch pProxy
                // afterward, but Deactivate is special.
                //
                pProxy->NotifyBlocked(false);

        #if defined(_DEBUG)
                pProxy->m_UMSDebugBits |= UMS_DEBUGBIT_DEACTIVATEDPROXY;
        #endif // _DEBUG

                if (InternalDeactivate())
                    pProxy->m_activationCause = UMSThreadProxy::ActivationCauseActivate;
                else
                    pProxy->m_activationCause = UMSThreadProxy::ActivationCauseCompletionNotification;

                CORE_ASSERT(pProxy->m_pLastRoot == this);
                Execute(static_cast<UMSFreeThreadProxy *>(m_pExecutingProxy), false, false);
                break;
            }

            //
            // The thread is being freed (because it exited the dispatch loop).  It may or may not be pooled.
            //
            case UMSThreadProxy::ActionFree:
            case UMSThreadProxy::ActionResetForSwitchOut:
            {
                bool fFreeThread = (pProxy->m_yieldAction == UMSThreadProxy::ActionFree);

                if (fFreeThread)
                {
                    RVPMTRACE(MTRACE_EVT_CONTEXT_RELEASED, pProxy, this, NULL);
                    pProxy->NotifyBlocked(false);
                    pProxy->ReturnIdleProxy();
                }
                else
                {
                    // 
                    // If the proxy is switching out blocking, then we need to exit hypercritical
                    // region since it could be resumed on another vproc.
                    //
                    CORE_ASSERT(pProxy->GetCriticalRegionType() == InsideHyperCriticalRegion);
                    pProxy->ExitHyperCriticalRegion();
                    pProxy->NotifyBlocked(false);
                }

                if (!m_fDelete)
                {
                    m_pExecutingProxy = NULL;
                    m_fActivated = false;
                    WaitForSingleObject(m_hBlock, INFINITE);

                    //
                    // Right now, we semantically leave undefined the activate call after a context exits the dispatch loop.
                    // 
                    CORE_ASSERT(m_pExecutingProxy == NULL);
                    CORE_ASSERT(m_fDelete);
                }

                break;
            }

            case UMSThreadProxy::ActionStartup:
            {
                //
                // UT startup (Thread engine should take care of running proxies on startup.
                // Virtual processor root shall not see any proxy prior to startup).
                //
                CORE_ASSERT(false);
                break;
            }

            default:
                CORE_ASSERT(false);
        }
    }

    /// <summary>
    ///     Called in order to invoke the scheduler's scheduling context.
    /// </summary>
    /// <param name="fAsynchronous">
    ///     If invocation of this context is due to previous context blocking, then was it due to an asynchronous event (e.g.: page fault).

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -