winedos / Cleanups and some DPMI irq stuff

Jukka Heinonen jhei at iki.fi
Thu Jun 19 10:00:22 CDT 2003


This patch adds some preliminary stuff needed 
in order to support DPMI IRQs.




Changelog:
  Add int31 VIF manipulation functions.
  Fix asynchronous event locking.
  Make asynchronous event handling support DPMI.




Index: dlls/winedos/dosvm.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/dosvm.c,v
retrieving revision 1.39
diff -u -r1.39 dosvm.c
--- dlls/winedos/dosvm.c	16 Jun 2003 01:17:30 -0000	1.39
+++ dlls/winedos/dosvm.c	19 Jun 2003 14:50:51 -0000
@@ -70,14 +70,6 @@
 # include <sys/mman.h>
 #endif
 
-#define IF_CLR(ctx)     ((ctx)->EFlags &= ~VIF_MASK)
-#define IF_SET(ctx)     ((ctx)->EFlags |= VIF_MASK)
-#define IF_ENABLED(ctx) ((ctx)->EFlags & VIF_MASK)
-#define SET_PEND(ctx)   ((ctx)->EFlags |= VIP_MASK)
-#define CLR_PEND(ctx)   ((ctx)->EFlags &= ~VIP_MASK)
-#define IS_PEND(ctx)    ((ctx)->EFlags & VIP_MASK)
-
-#undef TRY_PICRETURN
 
 typedef struct _DOSEVENT {
   int irq,priority;
@@ -88,7 +80,6 @@
 
 static CRITICAL_SECTION qcrit = CRITICAL_SECTION_INIT("DOSVM");
 static struct _DOSEVENT *pending_event, *current_event;
-static int sig_sent;
 static HANDLE event_notifier;
 
 
@@ -113,50 +104,122 @@
 }
 
 
-static void DOSVM_SendQueuedEvent(CONTEXT86 *context)
+/***********************************************************************
+ *              DOSVM_SendOneEvent
+ *
+ * Process single pending event.
+ *
+ * This function should be called with queue critical section locked. 
+ * The function temporarily releases the critical section if it is 
+ * possible that internal interrupt handler or user procedure will 
+ * be called. This is because we may otherwise get a deadlock if
+ * another thread is waiting for the same critical section.
+ */
+static void DOSVM_SendOneEvent( CONTEXT86 *context )
 {
-  LPDOSEVENT event = pending_event;
+    LPDOSEVENT event = pending_event;
 
-  if (DOSVM_HasPendingEvents()) {
-    /* remove from "pending" list */
+    /* Remove from pending events list. */
     pending_event = event->next;
-    /* process event */
-    if (event->irq>=0) {
-      /* it's an IRQ, move it to "current" list */
-      event->next = current_event;
-      current_event = event;
-      TRACE("dispatching IRQ %d\n",event->irq);
-      /* note that if DOSVM_SimulateInt calls an internal interrupt directly,
-       * current_event might be cleared (and event freed) in this very call! */
-      DOSVM_HardwareInterruptRM( context, (event->irq < 8) ? 
-                                 (event->irq + 8) : (event->irq - 8 + 0x70) );
-    } else {
-      /* callback event */
-      TRACE("dispatching callback event\n");
-      (*event->relay)(context,event->data);
-      free(event);
+
+    /* Process active event. */
+    if (event->irq >= 0) 
+    {
+        BYTE intnum = (event->irq < 8) ?
+            (event->irq + 8) : (event->irq - 8 + 0x70);
+            
+        /* Event is an IRQ, move it to current events list. */
+        event->next = current_event;
+        current_event = event;
+
+        TRACE( "Dispatching IRQ %d.\n", event->irq );
+
+        if (ISV86(context))
+        {
+            /* 
+             * Note that if DOSVM_HardwareInterruptRM calls an internal 
+             * interrupt directly, current_event might be cleared 
+             * (and event freed) in this call.
+             */
+            LeaveCriticalSection(&qcrit);
+            DOSVM_HardwareInterruptRM( context, intnum );
+            EnterCriticalSection(&qcrit);
+        }
+        else
+        {
+            /*
+             * This routine only modifies current context so it is
+             * not necessary to release critical section.
+             */
+            DOSVM_HardwareInterruptPM( context, intnum );
+        }
+    } 
+    else 
+    {
+        /* Callback event. */
+        TRACE( "Dispatching callback event.\n" );
+
+        LeaveCriticalSection(&qcrit);
+        (*event->relay)( context, event->data );
+        EnterCriticalSection(&qcrit);
+
+        free(event);
     }
-  }
-  if (!DOSVM_HasPendingEvents()) {
-    TRACE("clearing Pending flag\n");
-    CLR_PEND(context);
-  }
 }
 
-static void DOSVM_SendQueuedEvents(CONTEXT86 *context)
+
+/***********************************************************************
+ *              DOSVM_SendQueuedEvents
+ *
+ * As long as interrupts are enabled, process all pending events 
+ * that are not blocked by currently active event.
+ */
+static void DOSVM_SendQueuedEvents( CONTEXT86 *context )
 {
-  /* we will send all queued events as long as interrupts are enabled,
-   * but IRQ events will disable interrupts again */
-  while (IS_PEND(context) && IF_ENABLED(context))
-    DOSVM_SendQueuedEvent(context);
+    EnterCriticalSection(&qcrit);
+
+    TRACE( "Called in %s mode %s events pending (time=%ld)\n",
+           ISV86(context) ? "real" : "protected",
+           DOSVM_HasPendingEvents() ? "with" : "without",
+           GetTickCount() );
+    TRACE( "cs:ip=%04lx:%08lx, ss:sp=%04lx:%08lx\n", 
+           context->SegCs, context->Eip, context->SegSs, context->Esp);
+
+    while (DOSVM_HasPendingEvents() && 
+           (ISV86(context) ? 
+            (context->EFlags & VIF_MASK) : NtCurrentTeb()->dpmi_vif))
+    {
+        DOSVM_SendOneEvent(context);
+
+        /*
+         * Event handling may have turned pending events flag on.
+         * We disable it here because this prevents some
+         * unnecessary calls to this function.
+         */
+        NtCurrentTeb()->vm86_pending = 0;
+    }
+
+    if (DOSVM_HasPendingEvents())
+    {
+        /*
+         * Interrupts disabled, but there are still
+         * pending events, make sure that pending flag is turned on.
+         */
+        TRACE( "Another event is pending, setting VIP flag.\n" );
+        NtCurrentTeb()->vm86_pending |= VIP_MASK;
+    }
+
+    LeaveCriticalSection(&qcrit);
 }
 
+
 /***********************************************************************
  *		QueueEvent (WINEDOS.@)
  */
 void WINAPI DOSVM_QueueEvent( INT irq, INT priority, DOSRELAY relay, LPVOID data)
 {
   LPDOSEVENT event, cur, prev;
+  BOOL       old_pending;
 
   if (MZ_Current()) {
     event = malloc(sizeof(DOSEVENT));
@@ -168,6 +231,8 @@
     event->relay = relay; event->data = data;
 
     EnterCriticalSection(&qcrit);
+    old_pending = DOSVM_HasPendingEvents();
+
     /* insert event into linked list, in order *after*
      * all earlier events of higher or equal priority */
     cur = pending_event; prev = NULL;
@@ -179,18 +244,18 @@
     if (prev) prev->next = event;
     else pending_event = event;
 
-    /* alert the vm86 about the new event */
-    if (!sig_sent) {
+    if (!old_pending && DOSVM_HasPendingEvents()) {
       TRACE("new event queued, signalling (time=%ld)\n", GetTickCount());
+      
+      /* Alert VM86 thread about the new event. */
       kill(dosvm_pid,SIGUSR2);
-      sig_sent++;
+
+      /* Wake up DOSVM_Wait so that it can serve pending events. */
+      SetEvent(event_notifier);
     } else {
       TRACE("new event queued (time=%ld)\n", GetTickCount());
     }
 
-    /* Wake up DOSVM_Wait so that it can serve pending events. */
-    SetEvent(event_notifier);
-
     LeaveCriticalSection(&qcrit);
   } else {
     /* DOS subsystem not running */
@@ -289,9 +354,6 @@
 {
     if (DOSVM_HasPendingEvents())
     {
-        /*
-         * FIXME: Critical section locking is broken.
-         */
         CONTEXT86 context = *waitctx;
         
         /*
@@ -312,8 +374,7 @@
             context.Esp = 0;
         }
 
-        IF_SET(&context);
-        SET_PEND(&context);
+        context.EFlags |= VIF_MASK;
         context.SegCs = 0;
         context.Eip = 0;
 
@@ -459,18 +520,12 @@
 
   case EXCEPTION_VM86_STI:
   /* case EXCEPTION_VM86_PICRETURN: */
-    IF_SET(context);
-    EnterCriticalSection(&qcrit);
-    sig_sent++;
-    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");
-    }
-    TRACE_(int)("DOS task enabled interrupts %s events pending, sending events (time=%ld)\n", IS_PEND(context)?"with":"without", GetTickCount());
+    if (!ISV86(context))
+      ERR( "Protected mode STI caught by real mode handler!\n" );
+
+    context->EFlags |= VIF_MASK;
+    context->EFlags &= ~VIP_MASK;
     DOSVM_SendQueuedEvents(context);
-    sig_sent=0;
-    LeaveCriticalSection(&qcrit);
     return EXCEPTION_CONTINUE_EXECUTION;
   }
   return EXCEPTION_CONTINUE_SEARCH;




Index: dlls/winedos/int31.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/int31.c,v
retrieving revision 1.22
diff -u -r1.22 int31.c
--- dlls/winedos/int31.c	13 Jun 2003 23:17:34 -0000	1.22
+++ dlls/winedos/int31.c	19 Jun 2003 14:50:58 -0000
@@ -1062,7 +1062,6 @@
         break;
 
     case 0x0300:  /* Simulate real mode interrupt */
-
         TRACE( "Simulate real mode interrupt %d.\n", BL_reg(context));
         DOSVM_CallRMInt( context );
         break;
@@ -1250,6 +1249,26 @@
     case 0x0800:  /* Physical address mapping */
         FIXME( "physical address mapping (0x%08lx) - unimplemented\n", 
                MAKELONG(CX_reg(context),BX_reg(context)) );
+        break;
+
+    case 0x0900:  /* Get and Disable Virtual Interrupt State */
+        TRACE( "Get and Disable Virtual Interrupt State: %ld\n", 
+               NtCurrentTeb()->dpmi_vif );
+        SET_AL( context, NtCurrentTeb()->dpmi_vif ? 1 : 0 );
+        NtCurrentTeb()->dpmi_vif = 0;
+        break;
+
+    case 0x0901:  /* Get and Enable Virtual Interrupt State */
+        TRACE( "Get and Enable Virtual Interrupt State: %ld\n", 
+               NtCurrentTeb()->dpmi_vif );
+        SET_AL( context, NtCurrentTeb()->dpmi_vif ? 1 : 0 );
+        NtCurrentTeb()->dpmi_vif = 1;
+        break;
+
+    case 0x0902:  /* Get Virtual Interrupt State */
+        TRACE( "Get Virtual Interrupt State: %ld\n", 
+               NtCurrentTeb()->dpmi_vif );
+        SET_AL( context, NtCurrentTeb()->dpmi_vif ? 1 : 0 );
         break;
 
     case 0x0e00:  /* Get Coprocessor Status (1.0) */



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



More information about the wine-patches mailing list