Fixed synchronisation for ctrl event generation.

This commit is contained in:
Eric Pouech 2002-07-10 20:31:46 +00:00 committed by Alexandre Julliard
parent d386fa75bc
commit b810b53b0a
1 changed files with 95 additions and 67 deletions

View File

@ -474,51 +474,72 @@ static BOOL WINAPI CONSOLE_DefaultHandler(DWORD dwCtrlType)
* This doesn't yet matter, since these handlers are not yet called...!
*/
static unsigned int console_ignore_ctrl_c = 0; /* FIXME: this should be inherited somehow */
static PHANDLER_ROUTINE handlers[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,CONSOLE_DefaultHandler};
struct ConsoleHandler {
PHANDLER_ROUTINE handler;
struct ConsoleHandler* next;
};
static unsigned int CONSOLE_IgnoreCtrlC = 0; /* FIXME: this should be inherited somehow */
static struct ConsoleHandler CONSOLE_DefaultConsoleHandler = {CONSOLE_DefaultHandler, NULL};
static struct ConsoleHandler* CONSOLE_Handlers = &CONSOLE_DefaultConsoleHandler;
static CRITICAL_SECTION CONSOLE_CritSect = CRITICAL_SECTION_INIT("console_ctrl_section");
/*****************************************************************************/
BOOL WINAPI SetConsoleCtrlHandler(PHANDLER_ROUTINE func, BOOL add)
{
int alloc_loop = sizeof(handlers)/sizeof(handlers[0]) - 1;
BOOL ret = TRUE;
FIXME("(%p,%i) - no error checking or testing yet\n", func, add);
if (!func)
{
console_ignore_ctrl_c = add;
return TRUE;
CONSOLE_IgnoreCtrlC = add;
}
if (add)
else if (add)
{
for (; alloc_loop >= 0 && handlers[alloc_loop]; alloc_loop--);
if (alloc_loop <= 0)
{
FIXME("Out of space on CtrlHandler table\n");
return FALSE;
}
handlers[alloc_loop] = func;
struct ConsoleHandler* ch = HeapAlloc(GetProcessHeap(), 0, sizeof(struct ConsoleHandler));
if (!ch) return FALSE;
ch->handler = func;
EnterCriticalSection(&CONSOLE_CritSect);
ch->next = CONSOLE_Handlers;
CONSOLE_Handlers = ch;
LeaveCriticalSection(&CONSOLE_CritSect);
}
else
{
for (; alloc_loop >= 0 && handlers[alloc_loop] != func; alloc_loop--);
if (alloc_loop <= 0)
{
WARN("Attempt to remove non-installed CtrlHandler %p\n", func);
return FALSE;
}
/* sanity check */
if (alloc_loop == sizeof(handlers)/sizeof(handlers[0]) - 1)
{
ERR("Who's trying to remove default handler???\n");
return FALSE;
}
if (alloc_loop)
memmove(&handlers[1], &handlers[0], alloc_loop * sizeof(handlers[0]));
handlers[0] = 0;
struct ConsoleHandler** ch;
EnterCriticalSection(&CONSOLE_CritSect);
for (ch = &CONSOLE_Handlers; *ch; *ch = (*ch)->next)
{
if ((*ch)->handler == func) break;
}
if (*ch)
{
struct ConsoleHandler* rch = *ch;
/* sanity check */
if (rch == &CONSOLE_DefaultConsoleHandler)
{
ERR("Who's trying to remove default handler???\n");
ret = FALSE;
}
else
{
rch = *ch;
*ch = (*ch)->next;
HeapFree(GetProcessHeap(), 0, rch);
}
}
else
{
WARN("Attempt to remove non-installed CtrlHandler %p\n", func);
ret = FALSE;
}
LeaveCriticalSection(&CONSOLE_CritSect);
}
return TRUE;
return ret;
}
static WINE_EXCEPTION_FILTER(CONSOLE_CtrlEventHandler)
@ -527,6 +548,51 @@ static WINE_EXCEPTION_FILTER(CONSOLE_CtrlEventHandler)
return EXCEPTION_EXECUTE_HANDLER;
}
static DWORD WINAPI CONSOLE_HandleCtrlCEntry(void* pmt)
{
struct ConsoleHandler* ch;
EnterCriticalSection(&CONSOLE_CritSect);
/* the debugger didn't continue... so, pass to ctrl handlers */
for (ch = CONSOLE_Handlers; ch; ch = ch->next)
{
if (ch->handler((DWORD)pmt)) break;
}
LeaveCriticalSection(&CONSOLE_CritSect);
return 0;
}
/******************************************************************
* CONSOLE_HandleCtrlC
*
* Check whether the shall manipulate CtrlC events
*/
int CONSOLE_HandleCtrlC(void)
{
/* FIXME: better test whether a console is attached to this process ??? */
extern unsigned CONSOLE_GetNumHistoryEntries(void);
if (CONSOLE_GetNumHistoryEntries() == (unsigned)-1) return 0;
if (CONSOLE_IgnoreCtrlC) return 1;
/* try to pass the exception to the debugger
* if it continues, there's nothing more to do
* otherwise, we need to send the ctrl-event to the handlers
*/
__TRY
{
RaiseException( DBG_CONTROL_C, 0, 0, NULL );
}
__EXCEPT(CONSOLE_CtrlEventHandler)
{
/* Create a separate thread to signal all the events. This would allow to
* synchronize between setting the handlers and actually calling them
*/
CreateThread(NULL, 0, CONSOLE_HandleCtrlCEntry, (void*)CTRL_C_EVENT, 0, NULL);
}
__ENDTRY;
return 1;
}
/******************************************************************************
* GenerateConsoleCtrlEvent [KERNEL32.@] Simulate a CTRL-C or CTRL-BREAK
*
@ -1379,41 +1445,3 @@ unsigned CONSOLE_GetNumHistoryEntries(void)
SERVER_END_REQ;
return ret;
}
/******************************************************************
* CONSOLE_HandleCtrlC
*
* Check whether the shall manipulate CtrlC events
*/
int CONSOLE_HandleCtrlC(void)
{
int i;
/* FIXME: better test whether a console is attached to this process ??? */
extern unsigned CONSOLE_GetNumHistoryEntries(void);
if (CONSOLE_GetNumHistoryEntries() == (unsigned)-1) return 0;
/* try to pass the exception to the debugger
* if it continues, there's nothing more to do
* otherwise, we need to send the ctrl-event to the handlers
*/
__TRY
{
RaiseException( DBG_CONTROL_C, 0, 0, NULL );
}
__EXCEPT(CONSOLE_CtrlEventHandler)
{
/* the debugger didn't continue... so, pass to ctrl handlers */
/* FIXME: since this routine is called while in a signal handler,
* there are some serious synchronisation issues with
* SetConsoleCtrlHandler (trouble ahead)
*/
for (i = 0; i < sizeof(handlers)/sizeof(handlers[0]); i++)
{
if (handlers[i] && (handlers[i])(CTRL_C_EVENT)) break;
}
}
__ENDTRY;
return 1;
}