the previous set of patches for handling the CtrlC events on the Win32 console had a (documented) flaw when it came about mutual exclusion this patch should get rid of it incidentally, it fixes #320 A+
Name: con_ctrl ChangeLog: fixed synchronisation for ctrl event generation License: X11 GenDate: 2002/07/10 12:26:16 UTC ModifiedFiles: win32/console.c AddedFiles: =================================================================== RCS file: /home/cvs/cvsroot/wine/wine/win32/console.c,v retrieving revision 1.95 diff -u -u -r1.95 console.c --- win32/console.c 2 Jun 2002 21:22:22 -0000 1.95 +++ win32/console.c 24 Jun 2002 20:47:06 -0000 @@ -474,51 +474,72 @@ * 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 @@ 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 * @@ -1378,42 +1444,5 @@ } 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; }