winedos / DOSVM_Wait cleanup

Jukka Heinonen jhei at iki.fi
Fri May 2 10:26:24 CDT 2003


In order to fix remaining synchronization bugs and in order to support
IRQs in protected mode, DOSVM requires some restructuring. This patch
removes some VM86 dependencies from dosvm.c and also provides 
a simple workaround for a nasty deadlock. Real workaround would
require true nested interrupt handling in DOSVM_Wait which is
something I would rather not mix with this patch.




Changelog:
    Remove obsolete code from DOSVM_Wait. Prepare DOSVM_Wait
    for handling nested interrupts in both real and protected mode.
    Provide temporary workaround for keyboard related deadlock.




Index: dlls/winedos/dosexe.h
===================================================================
RCS file: /home/wine/wine/dlls/winedos/dosexe.h,v
retrieving revision 1.24
diff -u -r1.24 dosexe.h
--- dlls/winedos/dosexe.h	21 Apr 2003 23:22:53 -0000	1.24
+++ dlls/winedos/dosexe.h	2 May 2003 14:47:28 -0000
@@ -75,8 +75,8 @@
 typedef void (WINAPI *RMCBPROC)(CONTEXT86*);
 typedef void (WINAPI *INTPROC)(CONTEXT86*);
 
-#define DOS_PRIORITY_REALTIME 0  /* IRQ0 */
-#define DOS_PRIORITY_KEYBOARD 1  /* IRQ1 */
+#define DOS_PRIORITY_REALTIME 1  /* IRQ0 - FIXME: should be 0 */
+#define DOS_PRIORITY_KEYBOARD 0  /* IRQ1 - FIXME: should be 1 */
 #define DOS_PRIORITY_VGA      2  /* IRQ9 */
 #define DOS_PRIORITY_MOUSE    5  /* IRQ12 */
 #define DOS_PRIORITY_SERIAL   10 /* IRQ4 */
@@ -106,7 +106,7 @@
 
 /* dosvm.c */
 extern INT WINAPI DOSVM_Enter( CONTEXT86 *context );
-extern void WINAPI DOSVM_Wait( INT read_pipe, HANDLE hObject );
+extern void WINAPI DOSVM_Wait( CONTEXT86 * );
 extern DWORD WINAPI DOSVM_Loop( HANDLE hThread );
 extern void WINAPI DOSVM_QueueEvent( INT irq, INT priority, DOSRELAY relay, LPVOID data );
 extern void WINAPI DOSVM_PIC_ioport_out( WORD port, BYTE val );
@@ -180,7 +180,7 @@
 
 /* int16.c */
 extern void WINAPI DOSVM_Int16Handler(CONTEXT86*);
-extern int WINAPI DOSVM_Int16ReadChar(BYTE*ascii,BYTE*scan,BOOL peek);
+extern BOOL WINAPI DOSVM_Int16ReadChar( BYTE *, BYTE *, CONTEXT86 * );
 extern int WINAPI DOSVM_Int16AddChar(BYTE ascii,BYTE scan);
 
 /* int17.c */




Index: dlls/winedos/dosvm.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/dosvm.c,v
retrieving revision 1.34
diff -u -r1.34 dosvm.c
--- dlls/winedos/dosvm.c	4 Mar 2003 02:16:20 -0000	1.34
+++ dlls/winedos/dosvm.c	2 May 2003 14:47:33 -0000
@@ -90,7 +90,6 @@
 static struct _DOSEVENT *pending_event, *current_event;
 static int sig_sent;
 static HANDLE event_notifier;
-static CONTEXT86 *current_context;
 
 #define SHOULD_PEND(x) \
   (x && ((!current_event) || (x->priority < current_event->priority)))
@@ -140,7 +139,7 @@
 {
   LPDOSEVENT event, cur, prev;
 
-  if (current_context) {
+  if (MZ_Current()) {
     event = malloc(sizeof(DOSEVENT));
     if (!event) {
       ERR("out of memory allocating event entry\n");
@@ -259,79 +258,74 @@
   }
 }
 
+
 /***********************************************************************
- *		Wait (WINEDOS.@)
+ *		DOSVM_Wait
+ *
+ * Wait for asynchronous events. This routine temporarily enables
+ * interrupts and waits until some asynchronous event has been 
+ * processed.
  */
-void WINAPI DOSVM_Wait( INT read_pipe, HANDLE hObject )
+void WINAPI DOSVM_Wait( CONTEXT86 *waitctx )
 {
-  MSG msg;
-  DWORD waitret;
-  HANDLE objs[3];
-  int objc;
-  BOOL got_msg = FALSE;
-
-  objs[0]=GetStdHandle(STD_INPUT_HANDLE);
-  objs[1]=event_notifier;
-  objs[2]=hObject;
-  objc=hObject?3:2;
-  do {
-    /* check for messages (waste time before the response check below) */
-    if (PeekMessageA)
+    if (SHOULD_PEND(pending_event)) 
     {
-        while (PeekMessageA(&msg,0,0,0,PM_REMOVE|PM_NOYIELD)) {
-            /* got a message */
-            DOSVM_ProcessMessage(&msg);
-            /* we don't need a TranslateMessage here */
-            DispatchMessageA(&msg);
-            got_msg = TRUE;
-        }
-    }
-chk_console_input:
-    if (!got_msg) {
-      /* check for console input */
-      INPUT_RECORD msg;
-      DWORD num;
-      if (PeekConsoleInputA(objs[0],&msg,1,&num) && num) {
-        DOSVM_ProcessConsole();
-        got_msg = TRUE;
-      }
-    }
-    if (read_pipe == -1) {
-      /* dispatch pending events */
-      if (SHOULD_PEND(pending_event)) {
-        CONTEXT86 context = *current_context;
+        /*
+         * FIXME: This does not work in protected mode DOS programs.
+         * FIXME: If we have pending IRQ which has 16-bit handler,
+         *        DOSVM_SendQueuedEvents may stuck in which case application
+         *        deadlocks. This is why keyboard events must have top 
+         *        priority (default timer IRQ handler is 16-bit code).
+         * FIXME: Critical section locking is broken.
+         */
+        CONTEXT86 context = *waitctx;
         IF_SET(&context);
         SET_PEND(&context);
         DOSVM_SendQueuedEvents(&context);
-        got_msg = TRUE;
-      }
-      if (got_msg) break;
-    } else {
-      fd_set readfds;
-      struct timeval timeout={0,0};
-      /* quick check for response from dosmod
-       * (faster than doing the full blocking wait, if data already available) */
-      FD_ZERO(&readfds); FD_SET(read_pipe,&readfds);
-      if (select(read_pipe+1,&readfds,NULL,NULL,&timeout)>0)
-	break;
-    }
-    /* nothing yet, block while waiting for something to do */
-    if (MsgWaitForMultipleObjects)
-        waitret = MsgWaitForMultipleObjects(objc,objs,FALSE,INFINITE,QS_ALLINPUT);
-    else
-        waitret = WaitForMultipleObjects(objc,objs,FALSE,INFINITE);
-
-    if (waitret==(DWORD)-1) {
-      ERR_(module)("dosvm wait error=%ld\n",GetLastError());
     }
-    if ((read_pipe != -1) && hObject) {
-      if (waitret==(WAIT_OBJECT_0+2)) break;
+    else
+    {
+        HANDLE objs[2];
+        int    objc = DOSVM_IsWin16() ? 2 : 1;
+        DWORD  waitret;
+
+        objs[0] = event_notifier;
+        objs[1] = GetStdHandle(STD_INPUT_HANDLE);
+
+        waitret = MsgWaitForMultipleObjects( objc, objs, FALSE, 
+                                             INFINITE, QS_ALLINPUT );
+        
+        if (waitret == WAIT_OBJECT_0)
+        {
+            /*
+             * New pending event has been queued, we ignore it
+             * here because it will be processed on next call to
+             * DOSVM_Wait.
+             */
+        }
+        else if (objc == 2 && waitret == WAIT_OBJECT_0 + 1)
+        {
+            DOSVM_ProcessConsole();
+        }
+        else if (waitret == WAIT_OBJECT_0 + objc)
+        {
+            MSG msg;
+            while (PeekMessageA(&msg,0,0,0,PM_REMOVE|PM_NOYIELD)) 
+            {
+                /* got a message */
+                DOSVM_ProcessMessage(&msg);
+                /* we don't need a TranslateMessage here */
+                DispatchMessageA(&msg);
+            }
+        }
+        else
+        {
+            ERR_(module)( "dosvm wait error=%ld\n", GetLastError() );
+        }
     }
-    if (waitret==WAIT_OBJECT_0)
-      goto chk_console_input;
-  } while (TRUE);
 }
 
+
 DWORD WINAPI DOSVM_Loop( HANDLE hThread )
 {
   HANDLE objs[2];
@@ -434,7 +428,7 @@
        * QueryPerformanceCounter() or something like that */
       InterlockedDecrement(&(NtCurrentTeb()->alarms));
     }
-    TRACE_(int)("context=%p, current=%p\n", context, current_context);
+    TRACE_(int)("context=%p\n", context);
     TRACE_(int)("cs:ip=%04lx:%04lx, ss:sp=%04lx:%04lx\n", context->SegCs, context->Eip, context->SegSs, context->Esp);
     if (!ISV86(context)) {
       ERR_(int)("@#&*%%, winedos signal handling is *still* messed up\n");
@@ -450,9 +444,6 @@
 
 int WINAPI DOSVM_Enter( CONTEXT86 *context )
 {
-  CONTEXT86 *old_context = current_context;
-
-  current_context = context;
   __TRY
   {
     __wine_enter_vm86( context );
@@ -463,7 +454,7 @@
     TRACE_(module)( "leaving vm86 mode\n" );
   }
   __ENDTRY
-  current_context = old_context;
+
   return 0;
 }
 
@@ -489,7 +480,7 @@
 	  /* another event is pending, which we should probably
 	   * be able to process now */
 	  TRACE("another event pending, setting flag\n");
-	  current_context->EFlags |= VIP_MASK;
+	  NtCurrentTeb()->vm86_pending |= VIP_MASK;
 	}
       } else {
 	WARN("EOI without active IRQ\n");




Index: dlls/winedos/int16.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/int16.c,v
retrieving revision 1.10
diff -u -r1.10 int16.c
--- dlls/winedos/int16.c	2 Jan 2003 17:59:47 -0000	1.10
+++ dlls/winedos/int16.c	2 May 2003 14:47:37 -0000
@@ -59,7 +59,7 @@
       /* Returns: AH = Scan code
                   AL = ASCII character */
       TRACE("Get Keystroke\n");
-      DOSVM_Int16ReadChar(&ascii, &scan, FALSE);
+      DOSVM_Int16ReadChar(&ascii, &scan, context);
       SET_AL( context, ascii );
       SET_AH( context, scan );
       break;
@@ -69,7 +69,7 @@
       /*          AH = Scan code */
       /*          AL = ASCII character */
       TRACE("Check for Keystroke\n");
-      if (!DOSVM_Int16ReadChar(&ascii, &scan, TRUE))
+      if (!DOSVM_Int16ReadChar(&ascii, &scan, NULL))
       {
           SET_ZFLAG(context);
       }
@@ -111,7 +111,7 @@
       TRACE("Get Enhanced Keystroke - Partially supported\n");
       /* Returns: AH = Scan code
                   AL = ASCII character */
-      DOSVM_Int16ReadChar(&ascii, &scan, FALSE);
+      DOSVM_Int16ReadChar(&ascii, &scan, context);
       SET_AL( context, ascii );
       SET_AH( context, scan );
       break;
@@ -122,7 +122,7 @@
       /*          AH = Scan code */
       /*          AL = ASCII character */
       TRACE("Check for Enhanced Keystroke - Partially supported\n");
-      if (!DOSVM_Int16ReadChar(&ascii, &scan, TRUE))
+      if (!DOSVM_Int16ReadChar(&ascii, &scan, NULL))
       {
           SET_ZFLAG(context);
       }
@@ -145,31 +145,51 @@
    }
 }
 
-int WINAPI DOSVM_Int16ReadChar(BYTE*ascii,BYTE*scan,BOOL peek)
+/**********************************************************************
+ *	    DOSVM_Int16ReadChar
+ *
+ * Either peek into keyboard buffer or wait for next keystroke.
+ *
+ * If waitctx is NULL, return TRUE if buffer had keystrokes and
+ * FALSE if buffer is empty. Returned keystroke will be left into buffer.
+ * 
+ * If waitctx is non-NULL, wait until keystrokes are available.
+ * Return value will always be TRUE and returned keystroke will be
+ * removed from buffer.
+ */
+int WINAPI DOSVM_Int16ReadChar(BYTE *ascii, BYTE *scan, CONTEXT86 *waitctx)
 {
-  BIOSDATA *data = BIOS_DATA;
-  WORD CurOfs = data->NextKbdCharPtr;
+    BIOSDATA *data = BIOS_DATA;
+    WORD CurOfs = data->NextKbdCharPtr;
 
-  /* check if there's data in buffer */
-  if (peek) {
-    if (CurOfs == data->FirstKbdCharPtr)
-      return 0;
-  } else {
-    while (CurOfs == data->FirstKbdCharPtr) {
-      /* no input available yet, so wait... */
-      DOSVM_Wait( -1, 0 );
+    /* check if there's data in buffer */
+    if (waitctx)
+    {
+        /* wait until input is available... */
+        while (CurOfs == data->FirstKbdCharPtr)
+            DOSVM_Wait( waitctx );
     }
-  }
-  /* read from keyboard queue */
-  TRACE("(%p,%p,%d) -> %02x %02x\n",ascii,scan,peek,((BYTE*)data)[CurOfs],((BYTE*)data)[CurOfs+1]);
-  if (ascii) *ascii = ((BYTE*)data)[CurOfs];
-  if (scan) *scan = ((BYTE*)data)[CurOfs+1];
-  if (!peek) {
-    CurOfs += 2;
-    if (CurOfs >= data->KbdBufferEnd) CurOfs = data->KbdBufferStart;
-    data->NextKbdCharPtr = CurOfs;
-  }
-  return 1;
+    else
+    {
+        if (CurOfs == data->FirstKbdCharPtr)
+            return FALSE;
+    }
+
+    /* read from keyboard queue */
+    TRACE( "(%p,%p,%p) -> %02x %02x\n", ascii, scan, waitctx,
+           ((BYTE*)data)[CurOfs], ((BYTE*)data)[CurOfs+1] );
+
+    if (ascii) *ascii = ((BYTE*)data)[CurOfs];
+    if (scan) *scan = ((BYTE*)data)[CurOfs+1];
+
+    if (waitctx) 
+    {
+        CurOfs += 2;
+        if (CurOfs >= data->KbdBufferEnd) CurOfs = data->KbdBufferStart;
+        data->NextKbdCharPtr = CurOfs;
+    }
+
+    return TRUE;
 }
 
 int WINAPI DOSVM_Int16AddChar(BYTE ascii,BYTE scan)




Index: dlls/winedos/int21.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/int21.c,v
retrieving revision 1.29
diff -u -r1.29 int21.c
--- dlls/winedos/int21.c	21 Apr 2003 23:22:53 -0000	1.29
+++ dlls/winedos/int21.c	2 May 2003 14:47:44 -0000
@@ -94,7 +94,7 @@
  * Reads a character from the standard input.
  * Extended keycodes will be returned as two separate characters.
  */
-static BOOL INT21_ReadChar( BYTE *input, BOOL peek )
+static BOOL INT21_ReadChar( BYTE *input, CONTEXT86 *waitctx )
 {
     static BYTE pending_scan = 0;
 
@@ -102,7 +102,7 @@
     {
         if (input)
             *input = pending_scan;
-        if (!peek)
+        if (waitctx)
             pending_scan = 0;
         return TRUE;
     }
@@ -110,12 +110,12 @@
     {
         BYTE ascii;
         BYTE scan;
-        if (!DOSVM_Int16ReadChar( &ascii, &scan, peek ))
+        if (!DOSVM_Int16ReadChar( &ascii, &scan, waitctx ))
             return FALSE;
 
         if (input)
             *input = ascii;
-        if (!peek && !ascii)
+        if (waitctx && !ascii)
             pending_scan = scan;
         return TRUE;
     }
@@ -328,7 +328,7 @@
         BYTE ascii;
         BYTE scan;
 
-        DOSVM_Int16ReadChar( &ascii, &scan, FALSE );
+        DOSVM_Int16ReadChar( &ascii, &scan, context );
 
         if (ascii == '\r' || ascii == '\n')
         {
@@ -1312,7 +1312,7 @@
         {
             BYTE ascii;
             TRACE("DIRECT CHARACTER INPUT WITH ECHO\n");
-            INT21_ReadChar( &ascii, FALSE );
+            INT21_ReadChar( &ascii, context );
             SET_AL( context, ascii );
             /*
              * FIXME: What to echo when extended keycodes are read?
@@ -1337,10 +1337,10 @@
         {
             TRACE("Direct Console Input\n");
 
-            if (INT21_ReadChar( NULL, TRUE ))
+            if (INT21_ReadChar( NULL, NULL ))
             {
                 BYTE ascii;
-                INT21_ReadChar( &ascii, FALSE );
+                INT21_ReadChar( &ascii, context );
                 SET_AL( context, ascii );
                 RESET_ZFLAG( context );
             }
@@ -1367,7 +1367,7 @@
         {
             BYTE ascii;
             TRACE("DIRECT CHARACTER INPUT WITHOUT ECHO\n");
-            INT21_ReadChar( &ascii, FALSE );
+            INT21_ReadChar( &ascii, context );
             SET_AL( context, ascii );
         }
         break;
@@ -1376,7 +1376,7 @@
         {
             BYTE ascii;
             TRACE("CHARACTER INPUT WITHOUT ECHO\n");
-            INT21_ReadChar( &ascii, FALSE );
+            INT21_ReadChar( &ascii, context );
             SET_AL( context, ascii );
         }
         break;
@@ -1414,7 +1414,7 @@
     case 0x0b: /* GET STDIN STATUS */
         TRACE( "GET STDIN STATUS\n" );
         {
-            if (INT21_ReadChar( NULL, TRUE ))
+            if (INT21_ReadChar( NULL, NULL ))
                 SET_AL( context, 0xff ); /* character available */
             else
                 SET_AL( context, 0 ); /* no character available */




Index: dlls/winedos/devices.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/devices.c,v
retrieving revision 1.7
diff -u -r1.7 devices.c
--- dlls/winedos/devices.c	7 Dec 2002 23:46:41 -0000	1.7
+++ dlls/winedos/devices.c	2 May 2003 14:47:49 -0000
@@ -282,7 +282,7 @@
 	  /* check for new keyboard input */
 	  while (CurOfs == bios->FirstKbdCharPtr) {
 	    /* no input available yet, so wait... */
-	    DOSVM_Wait( -1, 0 );
+	    DOSVM_Wait( ctx );
 	  }
 	  /* read from keyboard queue (call int16?) */
 	  data = ((WORD*)bios)[CurOfs];
@@ -301,7 +301,7 @@
 	  /* check for new keyboard input */
 	  while (CurOfs == bios->FirstKbdCharPtr) {
 	    /* no input available yet, so wait... */
-	    DOSVM_Wait( -1, 0 );
+	    DOSVM_Wait( ctx );
 	  }
 	  /* read from keyboard queue (call int16?) */
 	  data = ((WORD*)bios)[CurOfs];



-- 
Jukka Heinonen <http://www.iki.fi/jhei/>



More information about the wine-patches mailing list