From a0d07a719bef0d333e10666ca262a20126837777 Mon Sep 17 00:00:00 2001 From: James Tabor Date: Thu, 15 Jan 2009 23:15:31 +0000 Subject: [PATCH] - Rewrite Timers, nothing is using it except a bogus system timer for raw input thread is loaded and running. svn path=/trunk/; revision=38779 --- .../subsystems/win32/win32k/include/input.h | 2 + .../subsystems/win32/win32k/include/tags.h | 1 + .../subsystems/win32/win32k/include/timer.h | 12 +- .../subsystems/win32/win32k/ntuser/input.c | 91 +++++++- .../subsystems/win32/win32k/ntuser/message.c | 7 +- .../subsystems/win32/win32k/ntuser/ntstubs.c | 2 +- .../subsystems/win32/win32k/ntuser/timer.c | 207 +++++++++++++++++- 7 files changed, 309 insertions(+), 13 deletions(-) diff --git a/reactos/subsystems/win32/win32k/include/input.h b/reactos/subsystems/win32/win32k/include/input.h index 41e4eda629e..1a97b3afd50 100644 --- a/reactos/subsystems/win32/win32k/include/input.h +++ b/reactos/subsystems/win32/win32k/include/input.h @@ -37,4 +37,6 @@ PKBL UserHklToKbl(HKL hKl); #define ThreadHasInputAccess(W32Thread) \ (TRUE) +extern PTHREADINFO ptiRawInput; + #endif /* _WIN32K_INPUT_H */ diff --git a/reactos/subsystems/win32/win32k/include/tags.h b/reactos/subsystems/win32/win32k/include/tags.h index cd5e5ca3e27..eb1478b36a6 100644 --- a/reactos/subsystems/win32/win32k/include/tags.h +++ b/reactos/subsystems/win32/win32k/include/tags.h @@ -26,6 +26,7 @@ #define TAG_CALLBACK TAG('C', 'B', 'C', 'K') /* callback memory */ #define TAG_WINSTA TAG('W', 'S', 'T', 'A') /* window station */ #define TAG_PDCE TAG('U', 's', 'd', 'c') /* dce */ +#define TAG_INPUT TAG('U', 's', 's', 'y') /* Input */ /* gdi objects from the handle table */ #define TAG_DC TAG('G', 'l', 'a', '1') /* dc */ diff --git a/reactos/subsystems/win32/win32k/include/timer.h b/reactos/subsystems/win32/win32k/include/timer.h index 1123241ed07..283f18ae104 100644 --- a/reactos/subsystems/win32/win32k/include/timer.h +++ b/reactos/subsystems/win32/win32k/include/timer.h @@ -4,7 +4,7 @@ typedef struct _TIMER { LIST_ENTRY ptmrList; - PW32THREADINFO pti; + PTHREADINFO pti; PWINDOW_OBJECT pWnd; // hWnd UINT_PTR nID; // Specifies a nonzero timer identifier. INT cmsCountdown; // uElapse @@ -22,13 +22,19 @@ typedef struct _TIMER #define TMRF_INIT 0x0008 #define TMRF_ONESHOT 0x0010 #define TMRF_WAITING 0x0020 +#define TMRF_TIFROMWND 0x0040 + +extern PKTIMER MasterTimer; NTSTATUS FASTCALL InitTimerImpl(VOID); BOOL FASTCALL IntKillTimer(HWND Wnd, UINT_PTR IDEvent, BOOL SystemTimer); UINT_PTR FASTCALL IntSetTimer(HWND Wnd, UINT_PTR IDEvent, UINT Elapse, TIMERPROC TimerFunc, BOOL SystemTimer); PTIMER FASTCALL FindSystemTimer(PMSG); -BOOL FASTCALL ValidateTimerCallback(PW32THREADINFO,PWINDOW_OBJECT,WPARAM,LPARAM); +BOOL FASTCALL ValidateTimerCallback(PTHREADINFO,PWINDOW_OBJECT,WPARAM,LPARAM); VOID CALLBACK SystemTimerProc(HWND,UINT,UINT_PTR,DWORD); -UINT_PTR FASTCALL SetSystemTimer(HWND,UINT_PTR,UINT,TIMERPROC); +UINT_PTR FASTCALL SetSystemTimer(PWINDOW_OBJECT,UINT_PTR,UINT,TIMERPROC); +BOOL FASTCALL PostTimerMessages(HWND); +VOID FASTCALL ProcessTimers(VOID); +VOID FASTCALL StartTheTimers(VOID); #endif /* _WIN32K_TIMER_H */ diff --git a/reactos/subsystems/win32/win32k/ntuser/input.c b/reactos/subsystems/win32/win32k/ntuser/input.c index d7c67271d59..cc332edda1d 100644 --- a/reactos/subsystems/win32/win32k/ntuser/input.c +++ b/reactos/subsystems/win32/win32k/ntuser/input.c @@ -36,9 +36,12 @@ #include extern BYTE gQueueKeyStateTable[]; +extern NTSTATUS Win32kInitWin32Thread(PETHREAD Thread); /* GLOBALS *******************************************************************/ +PTHREADINFO ptiRawInput; +PKTIMER MasterTimer; static HANDLE MouseDeviceHandle; static HANDLE MouseThreadHandle; @@ -46,6 +49,8 @@ static CLIENT_ID MouseThreadId; static HANDLE KeyboardThreadHandle; static CLIENT_ID KeyboardThreadId; static HANDLE KeyboardDeviceHandle; +static HANDLE RawInputThreadHandle; +static CLIENT_ID RawInputThreadId; static KEVENT InputThreadsStart; static BOOLEAN InputThreadsRunning = FALSE; @@ -468,7 +473,6 @@ KeyboardThreadMain(PVOID StartContext) MSG msg; PUSER_MESSAGE_QUEUE FocusQueue; struct _ETHREAD *FocusThread; - extern NTSTATUS Win32kInitWin32Thread(PETHREAD Thread); PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans = NULL; UINT ModifierState = 0; @@ -832,6 +836,79 @@ KeyboardEscape: } +static PVOID Objects[2]; +/* + Raw Input Thread. + Since this relies on InputThreadsStart, just fake it. + */ +static VOID APIENTRY +RawInputThreadMain(PVOID StartContext) +{ + NTSTATUS Status; + LARGE_INTEGER DueTime; + + DueTime.QuadPart = (LONGLONG)(-10000000); + + do + { + KEVENT Event; + KeInitializeEvent(&Event, NotificationEvent, FALSE); + Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &DueTime); + } while (!NT_SUCCESS(Status)); + + + Objects[0] = &InputThreadsStart; + + MasterTimer = ExAllocatePoolWithTag(NonPagedPool, sizeof(KTIMER), TAG_INPUT); + if (!MasterTimer) + { + DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n"); + return; + } + KeInitializeTimer(MasterTimer); + Objects[1] = MasterTimer; + + // This thread requires win32k! + Status = Win32kInitWin32Thread(PsGetCurrentThread()); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n"); + return; //(Status); + } + + ptiRawInput = PsGetCurrentThreadWin32Thread(); + DPRINT1("\nRaw Input Thread 0x%x \n", ptiRawInput); + + + KeSetPriorityThread(&PsGetCurrentThread()->Tcb, + LOW_REALTIME_PRIORITY + 3); + + UserEnterExclusive(); + StartTheTimers(); + UserLeave(); + + // + // ATM, we just have one job to handle, merge the other two later. + // + for(;;) + { + DPRINT( "Raw Input Thread Waiting for start event\n" ); + + Status = KeWaitForMultipleObjects( 2, + Objects, + WaitAll, //WaitAny, + WrUserRequest, + KernelMode, + TRUE, + NULL, + NULL); + DPRINT( "Raw Input Thread Starting...\n" ); + + ProcessTimers(); + } + DPRINT1("Raw Input Thread Exit!\n"); +} + NTSTATUS FASTCALL InitInputImpl(VOID) { @@ -845,6 +922,18 @@ InitInputImpl(VOID) DPRINT1("Failed to initialize default keyboard layout!\n"); } + Status = PsCreateSystemThread(&RawInputThreadHandle, + THREAD_ALL_ACCESS, + NULL, + NULL, + &RawInputThreadId, + RawInputThreadMain, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Win32K: Failed to create raw thread.\n"); + } + Status = PsCreateSystemThread(&KeyboardThreadHandle, THREAD_ALL_ACCESS, NULL, diff --git a/reactos/subsystems/win32/win32k/ntuser/message.c b/reactos/subsystems/win32/win32k/ntuser/message.c index 76486456d64..efb04957c25 100644 --- a/reactos/subsystems/win32/win32k/ntuser/message.c +++ b/reactos/subsystems/win32/win32k/ntuser/message.c @@ -360,7 +360,7 @@ IntDispatchMessage(PMSG pMsg) { if (pMsg->message == WM_TIMER) { - if (ValidateTimerCallback(GetW32ThreadInfo(),Window,pMsg->wParam,pMsg->lParam)) + if (ValidateTimerCallback(PsGetCurrentThreadWin32Thread(),Window,pMsg->wParam,pMsg->lParam)) { return co_IntCallWindowProc((WNDPROC)pMsg->lParam, TRUE, @@ -829,6 +829,11 @@ CheckMessages: goto MsgExit; } + if (ThreadQueue->WakeMask & QS_TIMER) + if (PostTimerMessages(hWnd)) // If there are timers ready, + goto CheckMessages; // go back and process them. + + // LOL! Polling Timer Queue? How much time is spent doing this? /* Check for WM_(SYS)TIMER messages */ Present = MsqGetTimerMessage(ThreadQueue, hWnd, MsgFilterMin, MsgFilterMax, &Msg->Msg, RemoveMessages); diff --git a/reactos/subsystems/win32/win32k/ntuser/ntstubs.c b/reactos/subsystems/win32/win32k/ntuser/ntstubs.c index 286b7399a6d..0c3acf45ef3 100644 --- a/reactos/subsystems/win32/win32k/ntuser/ntstubs.c +++ b/reactos/subsystems/win32/win32k/ntuser/ntstubs.c @@ -1117,7 +1117,7 @@ NtUserValidateTimerCallback( goto Exit; } - Ret = ValidateTimerCallback(GetW32ThreadInfo(), Window, wParam, lParam); + Ret = ValidateTimerCallback(PsGetCurrentThreadWin32Thread(), Window, wParam, lParam); Exit: UserLeave(); diff --git a/reactos/subsystems/win32/win32k/ntuser/timer.c b/reactos/subsystems/win32/win32k/ntuser/timer.c index e9291eb5a14..42b2df5e326 100644 --- a/reactos/subsystems/win32/win32k/ntuser/timer.c +++ b/reactos/subsystems/win32/win32k/ntuser/timer.c @@ -37,6 +37,9 @@ /* GLOBALS *******************************************************************/ static PTIMER FirstpTmr = NULL; +static LONG TimeLast = 0; + +#define MAX_ELAPSE_TIME 0x7FFFFFFF /* Windows 2000 has room for 32768 window-less timers */ #define NUM_WINDOW_LESS_TIMERS 1024 @@ -54,6 +57,7 @@ static ULONG HintIndex = 0; ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&Mutex) /* FUNCTIONS *****************************************************************/ +static PTIMER FASTCALL CreateTimer(VOID) @@ -144,7 +148,7 @@ FindSystemTimer(PMSG pMsg) BOOL FASTCALL -ValidateTimerCallback(PW32THREADINFO pti, +ValidateTimerCallback(PTHREADINFO pti, PWINDOW_OBJECT Window, WPARAM wParam, LPARAM lParam) @@ -158,7 +162,7 @@ ValidateTimerCallback(PW32THREADINFO pti, { if ( (lParam == (LPARAM)pTmr->pfn) && (pTmr->flags & (TMRF_SYSTEM|TMRF_RIT)) && - (pTmr->pti->pi == pti->pi) ) + (pTmr->pti->ThreadInfo->kpi == pti->ThreadInfo->kpi) ) break; pTmr = (PTIMER)pTmr->ptmrList.Flink; @@ -172,13 +176,73 @@ ValidateTimerCallback(PW32THREADINFO pti, // Rename it to IntSetTimer after move. UINT_PTR FASTCALL -InternalSetTimer(HWND Wnd, UINT_PTR IDEvent, UINT Elapse, TIMERPROC TimerFunc, BOOL SystemTimer) +InternalSetTimer( PWINDOW_OBJECT Window, + UINT_PTR IDEvent, + UINT Elapse, + TIMERPROC TimerFunc, + INT Type) { - return 0; + PTIMER pTmr; + LARGE_INTEGER DueTime; + DueTime.QuadPart = (LONGLONG)(-10000000); + +#if 0 + /* Windows NT/2k/XP behaviour */ + if (Elapse > MAX_ELAPSE_TIME) + { + DPRINT("Adjusting uElapse\n"); + Elapse = 1; + } +#else + /* Windows XP SP2 and Windows Server 2003 behaviour */ + if (Elapse > MAX_ELAPSE_TIME) + { + DPRINT("Adjusting uElapse\n"); + Elapse = MAX_ELAPSE_TIME; + } +#endif + + /* Windows 2k/XP and Windows Server 2003 SP1 behaviour */ + if (Elapse < 10) + { + DPRINT("Adjusting uElapse\n"); + Elapse = 10; + } + + pTmr = FindTimer(Window, IDEvent, Type, FALSE); + if (!pTmr) + { + pTmr = CreateTimer(); + if (!pTmr) return 0; + + if (Window && (Type & TMRF_TIFROMWND)) + pTmr->pti = Window->OwnerThread->Tcb.Win32Thread; + else + { + if (Type & TMRF_RIT) + pTmr->pti = ptiRawInput; + else + pTmr->pti = PsGetCurrentThreadWin32Thread(); + } + pTmr->pWnd = Window; + pTmr->cmsCountdown = Elapse; + pTmr->cmsRate = Elapse; + pTmr->flags = Type|TMRF_INIT; // Set timer to Init mode. + pTmr->pfn = TimerFunc; + pTmr->nID = IDEvent; + + InsertTailList(&FirstpTmr->ptmrList, &pTmr->ptmrList); + } + + // Start the timer thread! + KeSetTimer(MasterTimer, DueTime, NULL); + + if (!pTmr->nID) return 1; + return pTmr->nID; } // -// Process system timers. +// Process win32k system timers. // VOID CALLBACK @@ -187,18 +251,147 @@ SystemTimerProc(HWND hwnd, UINT_PTR idEvent, DWORD dwTime) { + DPRINT( "Timer Running!\n" ); +} + +VOID +FASTCALL +StartTheTimers(VOID) +{ + // Need to start gdi syncro timers then start timer with Hang App proc + // that calles Idle process so the screen savers will know to run...... + InternalSetTimer(NULL, 0, 1000, SystemTimerProc, TMRF_RIT); } UINT_PTR FASTCALL -SetSystemTimer( HWND hWnd, +SetSystemTimer( PWINDOW_OBJECT Window, UINT_PTR nIDEvent, UINT uElapse, TIMERPROC lpTimerFunc) { - return 0; + if (Window && Window->OwnerThread->ThreadsProcess != PsGetCurrentProcess()) + { + SetLastWin32Error(ERROR_ACCESS_DENIED); + return 0; + } + return InternalSetTimer( Window, nIDEvent, uElapse, lpTimerFunc, TMRF_SYSTEM); } +BOOL +FASTCALL +PostTimerMessages(HWND hWnd) +{ + PUSER_MESSAGE_QUEUE ThreadQueue; + MSG Msg; + PTHREADINFO pti; + PWINDOW_OBJECT pWnd = NULL; + BOOL Hit = FALSE; + PTIMER pTmr = FirstpTmr; + + if (!pTmr) return FALSE; + + if (hWnd) + { + pWnd = UserGetWindowObject(hWnd); + if (!pWnd || !pWnd->Wnd) return FALSE; + } + + pti = PsGetCurrentThreadWin32Thread(); + ThreadQueue = pti->MessageQueue; + + KeEnterCriticalRegion(); + do + { + if ( (pTmr->flags & TMRF_READY) && + (pTmr->pti == pti) && + (pTmr->pWnd == pWnd)) + { + Msg.hwnd = hWnd; + Msg.message = (pTmr->flags & TMRF_SYSTEM) ? WM_SYSTIMER : WM_TIMER; + Msg.wParam = (WPARAM) pTmr->nID; + Msg.lParam = (LPARAM) pTmr->pfn; + MsqPostMessage(ThreadQueue, &Msg, FALSE, QS_POSTMESSAGE); + + pTmr->flags &= ~TMRF_READY; + ThreadQueue->WakeMask = ~QS_TIMER; + Hit = TRUE; + } + + pTmr = (PTIMER)pTmr->ptmrList.Flink; + } while (pTmr != FirstpTmr); + KeLeaveCriticalRegion(); + + return Hit; +} + +VOID +FASTCALL +ProcessTimers(VOID) +{ + LARGE_INTEGER TickCount, DueTime; + LONG Time; + PTIMER pTmr = FirstpTmr; + + if (!pTmr) return; + + UserEnterExclusive(); + + KeQueryTickCount(&TickCount); + Time = MsqCalculateMessageTime(&TickCount); + + DueTime.QuadPart = (LONGLONG)(-10000000); + + do + { + if (pTmr->flags & TMRF_WAITING) + { + pTmr = (PTIMER)pTmr->ptmrList.Flink; + continue; + } + + if (pTmr->flags & TMRF_INIT) + pTmr->flags &= ~TMRF_INIT; // Skip this run. + else + { + if (pTmr->cmsCountdown < 0) + { + if (!(pTmr->flags & TMRF_READY)) + { + if (pTmr->flags & TMRF_ONESHOT) + pTmr->flags |= TMRF_WAITING; + + if (pTmr->flags & TMRF_RIT) + { + // Hard coded call here, inside raw input thread. + pTmr->pfn(NULL, WM_SYSTIMER, pTmr->nID, (LPARAM)pTmr); + } + else + { + pTmr->flags |= TMRF_READY; // Set timer ready to be ran. + // Set thread message queue for this timer. + if (pTmr->pti->MessageQueue) + { // Wakeup thread + pTmr->pti->MessageQueue->WakeMask |= QS_TIMER; + KeSetEvent(pTmr->pti->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE); + } + } + } + pTmr->cmsCountdown = pTmr->cmsRate; + } + else + pTmr->cmsCountdown -= Time - TimeLast; + } + pTmr = (PTIMER)pTmr->ptmrList.Flink; + } while (pTmr != FirstpTmr); + + // Restart the timer thread! + KeSetTimer(MasterTimer, DueTime, NULL); + + TimeLast = Time; + + UserLeave(); +} // //