winedos / Minor timer improvements

Jukka Heinonen jhei at iki.fi
Sun Nov 30 12:37:43 CST 2003


This patch fixes one simple bug and adds
a check that print out an error if timer handling
has been stuck for 60 seconds. This check is triggered
when some DPMI programs are executed because DPMI 
asynchronous event handling does not currently work.
The check should make it easier to find out whether
asynchronous event handling is working properly.




Changelog:
  Add upper limit for the number of pending timer interrupts.
  Check if timer has been stuck and issue an error to user.
  Fix handling of timer period zero.




Index: dlls/winedos/timer.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/timer.c,v
retrieving revision 1.4
diff -u -r1.4 timer.c
--- dlls/winedos/timer.c	30 Sep 2003 00:22:12 -0000	1.4
+++ dlls/winedos/timer.c	30 Nov 2003 18:26:36 -0000
@@ -35,11 +35,6 @@
  *        This should also make it possible to
  *        emulate really fast timers.
  * FIXME: Support special timer modes in addition to periodic mode.
- * FIXME: Make sure that there are only limited number
- *        of pending timer IRQ events queued. This makes sure that
- *        timer handling does not eat all available memory even
- *        if IRQ handling stops for some reason (suspended process?). 
- *        This is easy to do by using DOSRELAY parameter.
  * FIXME: Use timeSetEvent, NtSetEvent or timer thread for more precise
  *        timing.
  * FIXME: Move Win16 timer emulation code here.
@@ -48,6 +43,9 @@
 /* The PC clocks ticks at 1193180 Hz. */
 #define TIMER_FREQ 1193180
 
+/* How many timer IRQs can be pending at any time. */
+#define TIMER_MAX_PENDING 20
+
 /* Unique system timer identifier. */
 static UINT_PTR TIMER_id = 0;
 
@@ -57,6 +55,22 @@
 /* Timer ticks between timer IRQs. */
 static UINT TIMER_ticks = 0;
 
+/* Number of pending timer IRQs. */
+static LONG TIMER_pending = 0;
+
+
+/*********************************************************************** 
+ *              TIMER_Relay
+ *
+ * Decrement the number of pending IRQs after IRQ handler has been 
+ * called. This function will be called even if application has its 
+ * own IRQ handler that does not jump to builtin IRQ handler.
+ */
+static void TIMER_Relay( CONTEXT86 *context, void *data )
+{
+    InterlockedDecrement( &TIMER_pending );
+}
+
 
 /***********************************************************************
  *              TIMER_TimerProc
@@ -66,8 +80,26 @@
                                       UINT_PTR idEvent,
                                       DWORD    dwTime )
 {
-    TIMER_stamp = dwTime;
-    DOSVM_QueueEvent( 0, DOS_PRIORITY_REALTIME, NULL, NULL );
+    LONG pending = InterlockedIncrement( &TIMER_pending );
+
+    if (pending >= TIMER_MAX_PENDING)
+    {
+        DWORD delta = (dwTime >= TIMER_stamp) ? 
+            (dwTime - TIMER_stamp) : (0xffffffff - (TIMER_stamp - dwTime));
+
+        if (delta >= 60000)
+        {
+            ERR( "DOS timer has been stuck for 60 seconds...\n" );
+            TIMER_stamp = dwTime;
+        }
+
+        InterlockedDecrement( &TIMER_pending );
+    }
+    else
+    {
+        TIMER_stamp = dwTime;
+        DOSVM_QueueEvent( 0, DOS_PRIORITY_REALTIME, TIMER_Relay, NULL );
+    }
 }
 
 
@@ -119,6 +151,10 @@
  */
 void WINAPI DOSVM_SetTimer( UINT ticks )
 {
+    /* PIT interprets zero as a maximum length delay. */
+    if (ticks == 0)
+        ticks = 0x10000;
+
     if (!DOSVM_IsWin16())
         MZ_RunInThread( TIMER_DoSetTimer, ticks );
 }



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



More information about the wine-patches mailing list