Console fix

Eric Pouech eric.pouech at wanadoo.fr
Wed Jul 10 07:28:19 CDT 2002


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+
-------------- next part --------------
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;
 }
 


More information about the wine-patches mailing list