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

📄 synchexceptionmgr.cpp

📁 window下的多线程编程参考书。值得一读
💻 CPP
字号:
//
// FILE: SynchExceptionMgr.cpp
//
// Copyright (c) 1997 by Aaron Michael Cohen and Mike Woodring
//
/////////////////////////////////////////////////////////////////////////

#include <windows.h>
#include <stdio.h>
#include "SynchExceptionMgr.h"

CExceptionHandler                       *CSynchronousExceptionManager::s_APCHandler = 0;
CExceptionHandler::NOTIFICATION_CONTEXT  CSynchronousExceptionManager::s_APCContext = CExceptionHandler::THREAD_EXCEPTION;
DWORD                                    CSynchronousExceptionManager::s_APCExceptionCode = 0;

BOOL CSynchronousExceptionManager::RegisterHandler( CExceptionHandler *pHandler )
{
    CMclAutoLock Lock(m_CritSec);
    BOOL         fOkay;

    fOkay = CExceptionManager::RegisterHandler(pHandler);

    if( fOkay )
    {
        fOkay = m_HandlerInfo.PutOnTailOfList(new CHandlerInfo(pHandler));

        if( !fOkay )
        {
            CExceptionManager::UnregisterHandler(pHandler);
        }
    }

    return(fOkay);
}

void CSynchronousExceptionManager::UnregisterHandler( CExceptionHandler *pHandler )
{
    CMclAutoLock Lock(m_CritSec);

    CSynchronousExceptionManager::ForEachHandler(RemoveHandlerInfo, (DWORD)pHandler);

    CExceptionManager::UnregisterHandler(pHandler);
}

BOOL CSynchronousExceptionManager::RemoveHandlerInfo
(
    CHandlerInfo   *pHandlerInfo,
    DWORD           dwArg1,     // CExceptionHandler *
    DWORD           dwArg2,     // Not used
    DWORD           dwArg3      // Not used
)
{
    BOOL fKeepOnList = TRUE;

    if( pHandlerInfo->GetHandler() == (CExceptionHandler *)dwArg1 )
    {
        delete pHandlerInfo;
        fKeepOnList = FALSE;
    }

    return(fKeepOnList);
}

void CSynchronousExceptionManager::NotifyExceptionHandler
(
    CExceptionHandler                       *pHandler,
    CExceptionHandler::NOTIFICATION_CONTEXT Context,
    DWORD                                   dwExceptionCode
)
{
    CSynchronousExceptionManager::ForEachHandler(ScheduleAPC, (DWORD)pHandler, (DWORD)Context, dwExceptionCode);
}

BOOL CSynchronousExceptionManager::ScheduleAPC
(
    CHandlerInfo   *pHandlerInfo,
    DWORD           dwArg1,     // CExceptionHandler *pHandler
    DWORD           dwArg2,     // CExceptionHandler::NOTIFICATION_CONTEXT Context
    DWORD           dwArg3      // Exception code
)
{
    // This function is called indirectly by NotifyExceptionHandler for each handler info
    // element on the list of registered handlers.  But since the base class is already
    // iterating over the list of registered handlers, we only want to schedule an APC
    // to the handler that matches the one specified by dwArg1.
    //
    if( pHandlerInfo->GetHandler() != (CExceptionHandler *)dwArg1 )
    {
        // Skip this handler, keeping him on the list.
        //
        return(TRUE);
    }

    // If the handler specified by dwArg1 is the handler for the current
    // thread, we just call directly to the OnException function.  Otherwise,
    // the call to SuspendThread will suspend this thread, and we'll never
    // continue executing.
    //
    if( pHandlerInfo->GetThreadId() != GetCurrentThreadId() )
    {
        HANDLE hThread = pHandlerInfo->GetThreadHandle();

        printf(
            "[tid 0x%08lx] Scheduling APC to handler 0x%x, ctx = %s, ecode = 0x%x\n",
            GetCurrentThreadId(),
            pHandlerInfo->GetHandler(),
            (dwArg2 == CExceptionHandler::THREAD_EXCEPTION ? "thread" : "unhandled"),
            dwArg3
        );

        if( SuspendThread(hThread) != 0xffffffff )
        {
            CONTEXT ThreadContext;
            BOOL    fSetThreadContext = FALSE;

            memset(&ThreadContext, 0, sizeof(ThreadContext));

            ThreadContext.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;

            if( GetThreadContext(hThread, &ThreadContext) )
            {
                ThreadContext.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;

                // Warning: begin Intel architecture specific code
                //
                ThreadContext.Eip = (DWORD)APCCallback;
                //
                // Warning: end of Intel architecture specific code

                // Information about the exception is be passed to the APC
                // routine (APCCallback) through the following three static class
                // member variables.
                //
                s_APCHandler        = (CExceptionHandler *)dwArg1;
                s_APCContext        = (CExceptionHandler::NOTIFICATION_CONTEXT)dwArg2;
                s_APCExceptionCode  = dwArg3;

                fSetThreadContext = SetThreadContext(hThread, &ThreadContext);
            }

            ResumeThread(hThread);

            if( fSetThreadContext )
            {
                // Only bother waiting for the thread to exit if we successfully
                // altered its context.  As soon as the thread executes user mode
                // code again, it's context will be set to the start of the
                // APCCallback function.  Note that even if we timeout waiting for
                // that to occur, it can still happen between the time that we timeout
                // and ExitProcess is called.
                //
                WaitForSingleObject(hThread, 5000);
            }
        }
    }
    else
    {
        ((CExceptionHandler *)dwArg1)->OnException((CExceptionHandler::NOTIFICATION_CONTEXT)dwArg2, dwArg3);
    }

    // Since the objective of this routine is to schedule an APC to the target
    // thread that causes it to execute its cleanup function that then automatically
    // call ExitThread, we don't need to keep any handlers in the list.  This is
    // true whether or not we succeed in altering that thread's context.  When this
    // function returns FALSE, the handler info structure is removed from the list
    // and deleted, which causes the thread handle to be closed.
    //
    return(FALSE);
}

void CSynchronousExceptionManager::ForEachHandler( PHANDLERINFO_ITERATOR pfxnIterator, DWORD dwArg1, DWORD dwArg2, DWORD dwArg3 )
{
    CMclLinkedList<CHandlerInfo *>  Handlers;
    CHandlerInfo                   *pHandlerInfo = 0;

    while( m_HandlerInfo.GetFromHeadOfList(pHandlerInfo, 0) )
    {
        if( pfxnIterator(pHandlerInfo, dwArg1, dwArg2, dwArg3) )
        {
            // Keep this handler on the list of registered handlers.
            //
            Handlers.PutOnTailOfList(pHandlerInfo);
        }
    }

    while( Handlers.GetFromHeadOfList(pHandlerInfo, 0) )
    {
        m_HandlerInfo.PutOnTailOfList(pHandlerInfo);
    }
}

// APCCallback
//
// This static class member function is invoked in the context of the thread
// that is being notified of an exception in another thread.  The parameters
// to this function are passed to this function by the ScheduleAPC function
// using three class static member variables.  This function then performs
// the call to the virtual OnException function that is implemented by the
// object being notified of the exception.  After the thread has been notified,
// it is terminated with an exit code of -1.
//
void _cdecl CSynchronousExceptionManager::APCCallback( void )
{
    printf(
        "[tid 0x%08lx] APCCallback executing for handler 0x%x, ctx = %x, ecode = 0x%x\n",
        GetCurrentThreadId(),
        s_APCHandler,
        (s_APCContext == CExceptionHandler::THREAD_EXCEPTION ? "thread" : "unhandled"),
        s_APCExceptionCode
    );

    if( s_APCHandler )
    {
        s_APCHandler->OnException(s_APCContext, s_APCExceptionCode);
    }

    ExitThread(0xffffffff);
}

⌨️ 快捷键说明

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