winedos / DOSVM_Wait cleanup

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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/>


[Index of Archives]     [Gimp for Windows]     [Red Hat]     [Samba]     [Yosemite Camping]     [Graphics Cards]     [Wine Home]

  Powered by Linux