From b2844d2c3a4164f570327d10170f1e9d7c4d96fc Mon Sep 17 00:00:00 2001 From: Jukka Heinonen 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 ); +}