Fixed synchronisation for ctrl event generation.
This commit is contained in:
parent
d386fa75bc
commit
b810b53b0a
150
win32/console.c
150
win32/console.c
|
@ -474,51 +474,72 @@ static BOOL WINAPI CONSOLE_DefaultHandler(DWORD dwCtrlType)
|
||||||
* This doesn't yet matter, since these handlers are not yet called...!
|
* 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 */
|
struct ConsoleHandler {
|
||||||
static PHANDLER_ROUTINE handlers[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,CONSOLE_DefaultHandler};
|
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)
|
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);
|
FIXME("(%p,%i) - no error checking or testing yet\n", func, add);
|
||||||
|
|
||||||
if (!func)
|
if (!func)
|
||||||
{
|
{
|
||||||
console_ignore_ctrl_c = add;
|
CONSOLE_IgnoreCtrlC = add;
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
if (add)
|
else if (add)
|
||||||
{
|
{
|
||||||
for (; alloc_loop >= 0 && handlers[alloc_loop]; alloc_loop--);
|
struct ConsoleHandler* ch = HeapAlloc(GetProcessHeap(), 0, sizeof(struct ConsoleHandler));
|
||||||
if (alloc_loop <= 0)
|
|
||||||
{
|
if (!ch) return FALSE;
|
||||||
FIXME("Out of space on CtrlHandler table\n");
|
ch->handler = func;
|
||||||
return FALSE;
|
EnterCriticalSection(&CONSOLE_CritSect);
|
||||||
}
|
ch->next = CONSOLE_Handlers;
|
||||||
handlers[alloc_loop] = func;
|
CONSOLE_Handlers = ch;
|
||||||
|
LeaveCriticalSection(&CONSOLE_CritSect);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (; alloc_loop >= 0 && handlers[alloc_loop] != func; alloc_loop--);
|
struct ConsoleHandler** ch;
|
||||||
if (alloc_loop <= 0)
|
EnterCriticalSection(&CONSOLE_CritSect);
|
||||||
|
for (ch = &CONSOLE_Handlers; *ch; *ch = (*ch)->next)
|
||||||
{
|
{
|
||||||
WARN("Attempt to remove non-installed CtrlHandler %p\n", func);
|
if ((*ch)->handler == func) break;
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
if (*ch)
|
||||||
|
{
|
||||||
|
struct ConsoleHandler* rch = *ch;
|
||||||
|
|
||||||
/* sanity check */
|
/* sanity check */
|
||||||
if (alloc_loop == sizeof(handlers)/sizeof(handlers[0]) - 1)
|
if (rch == &CONSOLE_DefaultConsoleHandler)
|
||||||
{
|
{
|
||||||
ERR("Who's trying to remove default handler???\n");
|
ERR("Who's trying to remove default handler???\n");
|
||||||
return FALSE;
|
ret = FALSE;
|
||||||
}
|
}
|
||||||
if (alloc_loop)
|
else
|
||||||
memmove(&handlers[1], &handlers[0], alloc_loop * sizeof(handlers[0]));
|
{
|
||||||
handlers[0] = 0;
|
rch = *ch;
|
||||||
|
*ch = (*ch)->next;
|
||||||
|
HeapFree(GetProcessHeap(), 0, rch);
|
||||||
}
|
}
|
||||||
return TRUE;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WARN("Attempt to remove non-installed CtrlHandler %p\n", func);
|
||||||
|
ret = FALSE;
|
||||||
|
}
|
||||||
|
LeaveCriticalSection(&CONSOLE_CritSect);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WINE_EXCEPTION_FILTER(CONSOLE_CtrlEventHandler)
|
static WINE_EXCEPTION_FILTER(CONSOLE_CtrlEventHandler)
|
||||||
|
@ -527,6 +548,51 @@ static WINE_EXCEPTION_FILTER(CONSOLE_CtrlEventHandler)
|
||||||
return EXCEPTION_EXECUTE_HANDLER;
|
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
|
* GenerateConsoleCtrlEvent [KERNEL32.@] Simulate a CTRL-C or CTRL-BREAK
|
||||||
*
|
*
|
||||||
|
@ -1379,41 +1445,3 @@ unsigned CONSOLE_GetNumHistoryEntries(void)
|
||||||
SERVER_END_REQ;
|
SERVER_END_REQ;
|
||||||
return ret;
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue