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