[KERNEL32]: Bug fix CTRL-C handler registration/deregistration/notification, needed for correct console shutdown behavior.

svn path=/trunk/; revision=46041
This commit is contained in:
Sir Richard 2010-03-09 20:13:19 +00:00
parent 9c91a4dc46
commit e2d31e88e4
2 changed files with 111 additions and 79 deletions

View file

@ -19,16 +19,17 @@
#define NDEBUG #define NDEBUG
#include <debug.h> #include <debug.h>
extern BOOL WINAPI DefaultConsoleCtrlHandler(DWORD Event);
extern __declspec(noreturn) VOID CALLBACK ConsoleControlDispatcher(DWORD CodeAndFlag);
extern RTL_CRITICAL_SECTION ConsoleLock; extern RTL_CRITICAL_SECTION ConsoleLock;
extern BOOL ConsoleInitialized; extern BOOL ConsoleInitialized;
extern BOOL WINAPI IsDebuggerPresent(VOID); extern BOOL WINAPI IsDebuggerPresent(VOID);
/* GLOBALS *******************************************************************/ /* GLOBALS *******************************************************************/
static PHANDLER_ROUTINE* CtrlHandlers = NULL; PHANDLER_ROUTINE InitialHandler[1];
static ULONG NrCtrlHandlers = 0; PHANDLER_ROUTINE* CtrlHandlers;
ULONG NrCtrlHandlers;
ULONG NrAllocatedHandlers;
#define INPUTEXENAME_BUFLEN 256 #define INPUTEXENAME_BUFLEN 256
static WCHAR InputExeName[INPUTEXENAME_BUFLEN] = L""; static WCHAR InputExeName[INPUTEXENAME_BUFLEN] = L"";
@ -49,7 +50,7 @@ DefaultConsoleCtrlHandler(DWORD Event)
break; break;
case CTRL_SHUTDOWN_EVENT: case CTRL_SHUTDOWN_EVENT:
DPRINT("Ctrl Shutdown Event\n"); DPRINT1("Ctrl Shutdown Event\n");
break; break;
case CTRL_CLOSE_EVENT: case CTRL_CLOSE_EVENT:
@ -57,15 +58,14 @@ DefaultConsoleCtrlHandler(DWORD Event)
break; break;
case CTRL_LOGOFF_EVENT: case CTRL_LOGOFF_EVENT:
DPRINT("Ctrl Logoff Event\n"); DPRINT1("Ctrl Logoff Event\n");
break; break;
} }
ExitProcess(0); ExitProcess(CONTROL_C_EXIT);
return TRUE; return TRUE;
} }
__declspec(noreturn) __declspec(noreturn)
VOID VOID
CALLBACK CALLBACK
@ -74,7 +74,8 @@ ConsoleControlDispatcher(DWORD CodeAndFlag)
DWORD nExitCode = 0; DWORD nExitCode = 0;
DWORD nCode = CodeAndFlag & MAXLONG; DWORD nCode = CodeAndFlag & MAXLONG;
UINT i; UINT i;
EXCEPTION_RECORD erException;
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
switch(nCode) switch(nCode)
@ -82,51 +83,77 @@ ConsoleControlDispatcher(DWORD CodeAndFlag)
case CTRL_C_EVENT: case CTRL_C_EVENT:
case CTRL_BREAK_EVENT: case CTRL_BREAK_EVENT:
{ {
if(IsDebuggerPresent()) if (IsDebuggerPresent())
{ {
EXCEPTION_RECORD erException; erException.ExceptionCode = (nCode == CTRL_C_EVENT ?
erException.ExceptionCode = DBG_CONTROL_C : DBG_CONTROL_BREAK);
(nCode == CTRL_C_EVENT ? DBG_CONTROL_C : DBG_CONTROL_BREAK);
erException.ExceptionFlags = 0; erException.ExceptionFlags = 0;
erException.ExceptionRecord = NULL; erException.ExceptionRecord = NULL;
erException.ExceptionAddress = &DefaultConsoleCtrlHandler; erException.ExceptionAddress = DefaultConsoleCtrlHandler;
erException.NumberParameters = 0; erException.NumberParameters = 0;
RtlRaiseException(&erException);
_SEH2_TRY
{
RtlRaiseException(&erException);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
RtlEnterCriticalSection(&ConsoleLock);
if ((nCode != CTRL_C_EVENT) ||
(NtCurrentPeb()->ProcessParameters->ConsoleFlags != 1))
{
for (i = NrCtrlHandlers; i > 0; i--)
{
if (CtrlHandlers[i - 1](nCode)) break;
}
}
RtlLeaveCriticalSection(&ConsoleLock);
}
_SEH2_END;
ExitThread(0);
} }
if (!ConsoleInitialized) ExitThread(0); break;
RtlEnterCriticalSection(&ConsoleLock);
if (!(nCode == CTRL_C_EVENT &&
NtCurrentPeb()->ProcessParameters->ConsoleFlags & 1))
{
for(i = NrCtrlHandlers; i > 0; -- i)
if(CtrlHandlers[i - 1](nCode)) break;
}
RtlLeaveCriticalSection(&ConsoleLock);
ExitThread(0);
} }
case CTRL_CLOSE_EVENT: case CTRL_CLOSE_EVENT:
case CTRL_LOGOFF_EVENT: case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT: case CTRL_SHUTDOWN_EVENT:
break; break;
case 3:
ExitThread(0);
break;
case 4:
ExitProcess(CONTROL_C_EXIT);
break;
default: ExitThread(0); default:
ASSERT(FALSE);
break;
} }
if (!ConsoleInitialized) ExitThread(0); ASSERT(ConsoleInitialized);
RtlEnterCriticalSection(&ConsoleLock); RtlEnterCriticalSection(&ConsoleLock);
nExitCode = 0;
if (!(nCode == CTRL_C_EVENT && if ((nCode != CTRL_C_EVENT) || (NtCurrentPeb()->ProcessParameters->ConsoleFlags != 1))
NtCurrentPeb()->ProcessParameters->ConsoleFlags & 1))
{ {
i = NrCtrlHandlers; for (i = NrCtrlHandlers; i > 0; i--)
while (i > 0)
{ {
if (i == 1 && (CodeAndFlag & MINLONG) && if ((i == 1) &&
(nCode == CTRL_LOGOFF_EVENT || nCode == CTRL_SHUTDOWN_EVENT)) (CodeAndFlag & MINLONG) &&
((nCode == CTRL_LOGOFF_EVENT) || (nCode == CTRL_SHUTDOWN_EVENT)))
{
break; break;
}
if (CtrlHandlers[i - 1](nCode)) if (CtrlHandlers[i - 1](nCode))
{ {
@ -135,14 +162,17 @@ ConsoleControlDispatcher(DWORD CodeAndFlag)
case CTRL_CLOSE_EVENT: case CTRL_CLOSE_EVENT:
case CTRL_LOGOFF_EVENT: case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT: case CTRL_SHUTDOWN_EVENT:
case 3:
nExitCode = CodeAndFlag; nExitCode = CodeAndFlag;
break;
} }
break; break;
} }
--i;
} }
} }
RtlLeaveCriticalSection(&ConsoleLock); RtlLeaveCriticalSection(&ConsoleLock);
ExitThread(nExitCode); ExitThread(nExitCode);
} }
@ -3235,38 +3265,37 @@ static
BOOL BOOL
AddConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine) AddConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine)
{ {
PHANDLER_ROUTINE* NewCtrlHandlers = NULL;
if (HandlerRoutine == NULL) if (HandlerRoutine == NULL)
{ {
NtCurrentPeb()->ProcessParameters->ConsoleFlags = TRUE; NtCurrentPeb()->ProcessParameters->ConsoleFlags = TRUE;
return(TRUE); return TRUE;
} }
else
if (NrCtrlHandlers == NrAllocatedHandlers)
{ {
NrCtrlHandlers++; NewCtrlHandlers = RtlAllocateHeap(RtlGetProcessHeap(),
if (CtrlHandlers == NULL) 0,
(NrCtrlHandlers + 4) * sizeof(PHANDLER_ROUTINE));
if (NewCtrlHandlers == NULL)
{ {
CtrlHandlers = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
NrCtrlHandlers * sizeof(PHANDLER_ROUTINE));
}
else
{
CtrlHandlers = RtlReAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
(PVOID)CtrlHandlers,
NrCtrlHandlers * sizeof(PHANDLER_ROUTINE));
}
if (CtrlHandlers == NULL)
{
NrCtrlHandlers = 0;
SetLastError(ERROR_NOT_ENOUGH_MEMORY); SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE; return FALSE;
} }
CtrlHandlers[NrCtrlHandlers - 1] = HandlerRoutine; memmove(NewCtrlHandlers, CtrlHandlers, sizeof(PHANDLER_ROUTINE) * NrCtrlHandlers);
return TRUE;
if (NrAllocatedHandlers > 1) RtlFreeHeap(RtlGetProcessHeap(), 0, CtrlHandlers);
CtrlHandlers = NewCtrlHandlers;
NrAllocatedHandlers += 4;
} }
ASSERT(NrCtrlHandlers < NrAllocatedHandlers);
CtrlHandlers[NrCtrlHandlers++] = HandlerRoutine;
return TRUE;
} }
@ -3279,30 +3308,27 @@ RemoveConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine)
if (HandlerRoutine == NULL) if (HandlerRoutine == NULL)
{ {
NtCurrentPeb()->ProcessParameters->ConsoleFlags = FALSE; NtCurrentPeb()->ProcessParameters->ConsoleFlags = FALSE;
return(TRUE); return TRUE;
} }
else
{
for (i = 0; i < NrCtrlHandlers; i++)
{
if ( ((void*)(CtrlHandlers[i])) == (void*)HandlerRoutine)
{
NrCtrlHandlers--;
memmove(CtrlHandlers + i,
CtrlHandlers + i + 1,
(NrCtrlHandlers - i) * sizeof(PHANDLER_ROUTINE));
CtrlHandlers = RtlReAllocateHeap(RtlGetProcessHeap(), for (i = 0; i < NrCtrlHandlers; i++)
HEAP_ZERO_MEMORY, {
(PVOID)CtrlHandlers, if (CtrlHandlers[i] == HandlerRoutine)
NrCtrlHandlers * sizeof(PHANDLER_ROUTINE)); {
return(TRUE); if (i < (NrCtrlHandlers - 1))
{
memmove(&CtrlHandlers[i],
&CtrlHandlers[i+1],
(NrCtrlHandlers - i + 1) * sizeof(PHANDLER_ROUTINE));
} }
NrCtrlHandlers--;
return TRUE;
} }
} }
SetLastError(ERROR_INVALID_PARAMETER); SetLastError(ERROR_INVALID_PARAMETER);
return(FALSE); return FALSE;
} }

View file

@ -41,7 +41,10 @@ RTL_CRITICAL_SECTION ConsoleLock;
extern BOOL WINAPI DefaultConsoleCtrlHandler(DWORD Event); extern BOOL WINAPI DefaultConsoleCtrlHandler(DWORD Event);
extern __declspec(noreturn) VOID CALLBACK ConsoleControlDispatcher(DWORD CodeAndFlag); extern __declspec(noreturn) VOID CALLBACK ConsoleControlDispatcher(DWORD CodeAndFlag);
extern PHANDLER_ROUTINE InitialHandler[1];
extern PHANDLER_ROUTINE* CtrlHandlers;
extern ULONG NrCtrlHandlers;
extern ULONG NrAllocatedHandlers;
extern BOOL FASTCALL NlsInit(VOID); extern BOOL FASTCALL NlsInit(VOID);
extern VOID FASTCALL NlsUninit(VOID); extern VOID FASTCALL NlsUninit(VOID);
BOOLEAN InWindows = FALSE; BOOLEAN InWindows = FALSE;
@ -178,7 +181,10 @@ BasepInitConsole(VOID)
/* Initialize Console Ctrl Handler */ /* Initialize Console Ctrl Handler */
ConsoleInitialized = TRUE; ConsoleInitialized = TRUE;
RtlInitializeCriticalSection(&ConsoleLock); RtlInitializeCriticalSection(&ConsoleLock);
SetConsoleCtrlHandler(DefaultConsoleCtrlHandler, TRUE); NrAllocatedHandlers = 1;
NrCtrlHandlers = 1;
CtrlHandlers = InitialHandler;
CtrlHandlers[0] = DefaultConsoleCtrlHandler;
/* Now use the proper console handle */ /* Now use the proper console handle */
Request.Data.AllocConsoleRequest.Console = Parameters->ConsoleHandle; Request.Data.AllocConsoleRequest.Console = Parameters->ConsoleHandle;