DEADLOCK.MAK
CC_OPTS = /MT /D_MT /O2 /c /YX
all: deadlockexe.exe
deadlockdll.lib: deadlockdll.dll
deadlockdll.dll: deadlockdll.obj
link /DLL /IMPLIB:deadlockdll.lib /EXPORT:FunctionInADLL deadlockdll.obj
deadlockdll.obj: deadlockdll.h deadlockdll.cpp
cl $(CC_OPTS) deadlockdll.cpp
deadlockexe.exe: deadlockdll.lib deadlockexe.obj
link deadlockexe.obj deadlockdll.lib
deadlockexe.obj: deadlockdll.h deadlockexe.cpp
cl $(CC_OPTS) $(DLLIMPORT) deadlockexe.cpp
DEADLOCKDLL.H
__declspec(dllexport) int __stdcall FunctionInADLL(void);
DEADLOCKDLL.CPP
#include <windows.h>
#include <stdio.h>
#include <process.h>
#pragma hdrstop
#include "deadlockdll.h"
CRITICAL_SECTION MyCritSect;
void SecondThreadFunction(void * p); // prototype the second thread function
// Called in the context of the main thread
__declspec(dllexport) int __stdcall FunctionInADLL(void)
{
// Inform user of our startup status
printf( "In primary thread\n" );
// Initialize and enter a run of the mill critical section
InitializeCriticalSection( &MyCritSect );
EnterCriticalSection( &MyCritSect );
// Start up a second thread, which will cause DllMain to be invoked in
// the context of the new thread.
printf( "Starting second thread\n" );
_beginthread( SecondThreadFunction, 0, 0 );
// Make the main thread sleep, thereby giving the second thread enough
// time to execute through DllMain and deadlock
printf( "Sleeping(1) in primary thread\n" );
Sleep( 2000 );
printf("Done sleeping(1) in primary thread\n");
// At this point, thread 1 owns MyCritSect, while thread 2 is blocked
// inside DllMain, waiting for MyCritSect. Unfortunately, thread
// 2 holds the process critical section, which GetProcAddress neeeds.
#if 1
printf( "Before calling GetProcAddress in primary thread\n" );
GetProcAddress( GetModuleHandle("KERNEL32.DLL"), "XYZ" );
printf( "After calling GetProcAddress in primary thread\n" );
#endif
// If the process critical section didn't deadlock us, we'd release the
// app critical section, and the 2nd thread would execute OK.
LeaveCriticalSection( &MyCritSect );
// Make the main thread sleep again, thereby ensuring that the second
// thread has time to complete before the first thread exits
printf( "Sleeping(2) in primary thread\n" );
Sleep( 2000 );
printf("Done sleeping(2) in primary thread\n");
DeleteCriticalSection( &MyCritSect ); // Cleanup code
printf( "Returning from primary thread\n" );
return 0;
}
void SecondThreadFunction(void * p)
{
printf(" In SecondThreadFunction\n" );
}
int WINAPI DllMain( HANDLE hInst, ULONG reason, LPVOID lpReserved )
{
if ( reason == DLL_THREAD_ATTACH )
{
printf(" In DllMain of 2nd thread - Before EnterCriticalSection\n" );
EnterCriticalSection( &MyCritSect );
printf(" In DllMain of 2nd thread - After EnterCriticalSection\n" );
LeaveCriticalSection( &MyCritSect );
printf(" In DllMain of 2nd thread - After LeaveCriticalSection\n" );
}
return 1;
}
DEADLOCKEXE.CPP
#include "deadlockdll.h"
int main()
{
return FunctionInADLL() + 2; // kludge required to prevent
} // compiler from optimizing a
// call to jmp