From b2844d2c3a4164f570327d10170f1e9d7c4d96fc Mon Sep 17 00:00:00 2001
From: Jukka Heinonen <jhei@iki.fi>
Date: Fri, 13 Jun 2003 16:28:49 +0000
Subject: [PATCH] Split timer code into separate source file. Stop using
 SIGALRM for timers.

---
 dlls/winedos/Makefile.in |   1 +
 dlls/winedos/dosvm.c     |  53 +---------------
 dlls/winedos/timer.c     | 126 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 129 insertions(+), 51 deletions(-)
 create mode 100644 dlls/winedos/timer.c

diff --git a/dlls/winedos/Makefile.in b/dlls/winedos/Makefile.in
index ecf0172da8d..6bff9c36a63 100644
--- a/dlls/winedos/Makefile.in
+++ b/dlls/winedos/Makefile.in
@@ -48,6 +48,7 @@ C_SRCS = \
 	module.c \
 	relay.c \
 	soundblaster.c \
+	timer.c \
 	vga.c \
 	vxd.c \
 	xms.c
diff --git a/dlls/winedos/dosvm.c b/dlls/winedos/dosvm.c
index 0a2bee54aa3..a4a3b6a844d 100644
--- a/dlls/winedos/dosvm.c
+++ b/dlls/winedos/dosvm.c
@@ -374,6 +374,8 @@ DWORD WINAPI DOSVM_Loop( HANDLE hThread )
                           SetEvent( (HANDLE)msg.wParam );
                       }
                       break;
+                  default:
+                      DispatchMessageA(&msg);
                   }
               }
           }
@@ -423,13 +425,6 @@ static WINE_EXCEPTION_FILTER(exception_handler)
     IF_SET(context);
     EnterCriticalSection(&qcrit);
     sig_sent++;
-    while (NtCurrentTeb()->alarms) {
-      DOSVM_QueueEvent(0,DOS_PRIORITY_REALTIME,NULL,NULL);
-      /* hmm, instead of relying on this signal counter, we should
-       * probably check how many ticks have *really* passed, probably using
-       * QueryPerformanceCounter() or something like that */
-      InterlockedDecrement(&(NtCurrentTeb()->alarms));
-    }
     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)) {
@@ -493,40 +488,6 @@ void WINAPI DOSVM_PIC_ioport_out( WORD port, BYTE val)
     }
 }
 
-/***********************************************************************
- *		SetTimer (WINEDOS.@)
- */
-void WINAPI DOSVM_SetTimer( UINT ticks )
-{
-  struct itimerval tim;
-
-  if (dosvm_pid) {
-    /* the PC clocks ticks at 1193180 Hz */
-    tim.it_interval.tv_sec=0;
-    tim.it_interval.tv_usec=MulDiv(ticks,1000000,1193180);
-    /* sanity check */
-    if (!tim.it_interval.tv_usec) tim.it_interval.tv_usec=1;
-    /* first tick value */
-    tim.it_value = tim.it_interval;
-    TRACE_(int)("setting timer tick delay to %ld us\n", tim.it_interval.tv_usec);
-    setitimer(ITIMER_REAL, &tim, NULL);
-  }
-}
-
-/***********************************************************************
- *		GetTimer (WINEDOS.@)
- */
-UINT WINAPI DOSVM_GetTimer( void )
-{
-  struct itimerval tim;
-
-  if (dosvm_pid) {
-    getitimer(ITIMER_REAL, &tim);
-    return MulDiv(tim.it_value.tv_usec,1193180,1000000);
-  }
-  return 0;
-}
-
 #else /* !MZ_SUPPORTED */
 
 /***********************************************************************
@@ -548,16 +509,6 @@ void WINAPI DOSVM_Wait( CONTEXT86 *waitctx ) { }
  */
 void WINAPI DOSVM_PIC_ioport_out( WORD port, BYTE val) {}
 
-/***********************************************************************
- *		SetTimer (WINEDOS.@)
- */
-void WINAPI DOSVM_SetTimer( UINT ticks ) {}
-
-/***********************************************************************
- *		GetTimer (WINEDOS.@)
- */
-UINT WINAPI DOSVM_GetTimer( void ) { return 0; }
-
 /***********************************************************************
  *		QueueEvent (WINEDOS.@)
  */
diff --git a/dlls/winedos/timer.c b/dlls/winedos/timer.c
new file mode 100644
index 00000000000..c1fda0c6373
--- /dev/null
+++ b/dlls/winedos/timer.c
@@ -0,0 +1,126 @@
+/*
+ * 8253/8254 Programmable Interval Timer (PIT) emulation
+ *
+ * Copyright 2003 Jukka Heinonen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "config.h"
+
+#include "dosexe.h"
+#include "wine/debug.h"
+#include "wingdi.h"
+#include "winuser.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(int);
+
+/*
+ * FIXME: Move timer ioport handling here and remove 
+ *        Dosvm.GetTimer/Dosvm.SetTimer.
+ * FIXME: Use QueryPerformanceCounter for
+ *        more precise GetTimer implementation.
+ * FIXME: Use QueryPerformanceCounter (or GetTimer implementation)
+ *        in timer tick routine to compensate for lost ticks. 
+ *        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.
+ */
+
+/* The PC clocks ticks at 1193180 Hz. */
+#define TIMER_FREQ 1193180
+
+/* Unique system timer identifier. */
+static UINT_PTR TIMER_id = 0;
+
+/* Time when timer IRQ was last queued. */
+static DWORD TIMER_stamp = 0;
+
+/* Timer ticks between timer IRQs. */
+static UINT TIMER_ticks = 0;
+
+
+/***********************************************************************
+ *              TIMER_TimerProc
+ */
+static void CALLBACK TIMER_TimerProc( HWND     hwnd,
+                                      UINT     uMsg,
+                                      UINT_PTR idEvent,
+                                      DWORD    dwTime )
+{
+    TIMER_stamp = dwTime;
+    DOSVM_QueueEvent( 0, DOS_PRIORITY_REALTIME, NULL, NULL );
+}
+
+
+/***********************************************************************
+ *              TIMER_DoSetTimer
+ */
+static void WINAPI TIMER_DoSetTimer( ULONG_PTR arg )
+{
+    INT millis = MulDiv( arg, 1000, TIMER_FREQ );
+
+    /* sanity check - too fast timer */
+    if (millis < 1)
+        millis = 1;
+
+    TRACE_(int)( "setting timer tick delay to %d ms\n", millis );
+
+    if (TIMER_id)
+        KillTimer( NULL, TIMER_id );
+
+    TIMER_id = SetTimer( NULL, 0, millis, TIMER_TimerProc );
+    TIMER_stamp = GetTickCount();
+    TIMER_ticks = arg;
+}
+
+
+/***********************************************************************
+ *              GetTimer (WINEDOS.@)
+ */
+UINT WINAPI DOSVM_GetTimer( void )
+{
+    if (!DOSVM_IsWin16())
+    {
+        DWORD millis = GetTickCount() - TIMER_stamp;
+        INT   ticks = MulDiv( millis, TIMER_FREQ, 1000 );
+
+        /* sanity check - tick wrap or suspended process or update race */
+        if (ticks < 0 || ticks >= TIMER_ticks)
+            ticks = 0;
+
+        return ticks;
+    }
+
+    return 0;
+}
+
+
+/***********************************************************************
+ *              SetTimer (WINEDOS.@)
+ */
+void WINAPI DOSVM_SetTimer( UINT ticks )
+{
+    if (!DOSVM_IsWin16())
+        MZ_RunInThread( TIMER_DoSetTimer, ticks );
+}
-- 
GitLab