C ++ 11 std :: mutex in Visual Studio 2012 deadlock when blocking from DllMain ()

I see a dead end with std::mutex

when mutex is locked from DllMain()

Below is a minimal DLL test case that shows the problem for me. My actual code is blocking the mutex because it uses member functions that can also be used outside of initialization during a normal function.

I think the problem is a deadlock between the scheduler as shown in the call stack of the thread main()

and another thread (possibly) spawned by the scheduler. It seems like the deadlock happened before it main()

actually gets executed.

I would appreciate any advice on how to fix / resolve the deadlock.

Simple DLL:

static void testFunc()
{
    std::mutex mtx;
    mtx.lock();

    mtx.unlock();
}


BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        testFunc ();
        break;

    case DLL_THREAD_ATTACH:
        testFunc ();
        break;

    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

      

At the dead end in the process, there are two threads:

Not Flagged >   6408    0   Main Thread Main Thread msvcr110d.dll!Concurrency::details::SchedulerBase::SchedulerBase    Normal
Not Flagged     7600    0   Worker Thread   ntdll.dll!_TppWaiterpThread@4() ntdll.dll!_NtDelayExecution@8   Normal

      

Here is the main()

thread call stack :

    ntdll.dll!_NtWaitForKeyedEvent@16() Unknown
    ntdll.dll!_TppWaitpSet@16() Unknown
    ntdll.dll!_TppSetWaitInterrupt@12() Unknown
    ntdll.dll!_RtlRegisterWait@24() Unknown
    kernel32.dll!_RegisterWaitForSingleObject@24()  Unknown
>   msvcr110d.dll!Concurrency::details::SchedulerBase::SchedulerBase(const Concurrency::SchedulerPolicy & policy) Line 152  C++
    msvcr110d.dll!Concurrency::details::ThreadScheduler::ThreadScheduler(const Concurrency::SchedulerPolicy & policy) Line 26   C++
    msvcr110d.dll!Concurrency::details::ThreadScheduler::Create(const Concurrency::SchedulerPolicy & policy) Line 34    C++
    msvcr110d.dll!Concurrency::details::SchedulerBase::CreateWithoutInitializing(const Concurrency::SchedulerPolicy & policy) Line 276  C++
    msvcr110d.dll!Concurrency::details::SchedulerBase::GetDefaultScheduler() Line 650   C++
    msvcr110d.dll!Concurrency::details::SchedulerBase::CreateContextFromDefaultScheduler() Line 567 C++
    msvcr110d.dll!Concurrency::details::SchedulerBase::CurrentContext() Line 399    C++
    msvcr110d.dll!Concurrency::details::LockQueueNode::LockQueueNode(unsigned int timeout) Line 616 C++
    msvcr110d.dll!Concurrency::critical_section::lock() Line 1017   C++
    msvcp110d.dll!mtx_do_lock(_Mtx_internal_imp_t * * mtx, const xtime * target) Line 65    C++
    msvcp110d.dll!_Mtx_lock(_Mtx_internal_imp_t * * mtx) Line 144   C++
    ConsoleApplicationDll.dll!std::_Mtx_lockX(_Mtx_internal_imp_t * * _Mtx) Line 68 C++
    ConsoleApplicationDll.dll!std::_Mutex_base::lock() Line 43  C++
    ConsoleApplicationDll.dll!testFunc() Line 16    C++
    ConsoleApplicationDll.dll!DllMain(HINSTANCE__ * hModule, unsigned long ul_reason_for_call, void * lpReserved) Line 29   C++
    ConsoleApplicationDll.dll!__DllMainCRTStartup(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 508    C
    ConsoleApplicationDll.dll!_DllMainCRTStartup(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 472 C
    ntdll.dll!_LdrpCallInitRoutine@16() Unknown
    ntdll.dll!_LdrpRunInitializeRoutines@4()    Unknown
    ntdll.dll!_LdrpInitializeProcess@8()    Unknown
    ntdll.dll!__LdrpInitialize@8()  Unknown
    ntdll.dll!_LdrInitializeThunk@8()   Unknown

      

The second call stack of the thread is short:

>   ntdll.dll!_NtDelayExecution@8() Unknown
    ntdll.dll!__LdrpInitialize@8()  Unknown
    ntdll.dll!_LdrInitializeThunk@8()   Unknown

      

EDIT 1:

WinDbg confirms that this is a bootloader blocking issue:

PRIMARY_PROBLEM_CLASS:  APPLICATION_HANG_HungIn_LoaderLock

      

+3


source to share


2 answers


It seems like using initialization QueueUserAPC()

for the queue is always done before main (), but from blocking the dreaded bootloader. This looks like a solution to my problem.

EDIT 1



After some testing, it seems that the APC method works if I put the APC from DllMain()

, but it doesn't work if I queue the APC from the ctor of a static global class instance. IOW, the use of APC is unevenly applicable across all possible combinations of compilers and build modes for me.

+1


source


Check "Guidelines for creating DLL files" :



You shouldn't be doing the following tasks from DllMain:

  • Call LoadLibrary or LoadLibraryEx (directly or indirectly). This can lead to deadlock or crash.
  • Synchronize with other streams. This can lead to a dead end.
+4


source







All Articles