* FILE: subsystems/win32/win32k/ntuser/timer.c
* PROGRAMER: Gunnar
* Thomas Weidenmueller (w3seek@users.sourceforge.net)
+ * Michael Martin (michael.martin@reactos.org)
* REVISION HISTORY: 10/04/2003 Implemented System Timers
*
*/
/* INCLUDES ******************************************************************/
-#include <w32k.h>
+#include <win32k.h>
#define NDEBUG
#include <debug.h>
#define MAX_ELAPSE_TIME 0x7FFFFFFF
/* Windows 2000 has room for 32768 window-less timers */
-#define NUM_WINDOW_LESS_TIMERS 1024
+#define NUM_WINDOW_LESS_TIMERS 32768
static FAST_MUTEX Mutex;
static RTL_BITMAP WindowLessTimersBitMap;
static PVOID WindowLessTimersBitMapBuffer;
-static ULONG HintIndex = 0;
+static ULONG HintIndex = 1;
+ERESOURCE TimerLock;
#define IntLockWindowlessTimerBitmap() \
ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&Mutex)
#define IntUnlockWindowlessTimerBitmap() \
ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&Mutex)
+#define TimerEnterExclusive() \
+{ \
+ KeEnterCriticalRegion(); \
+ ExAcquireResourceExclusiveLite(&TimerLock, TRUE); \
+}
+
+#define TimerLeave() \
+{ \
+ ExReleaseResourceLite(&TimerLock); \
+ KeLeaveCriticalRegion(); \
+}
+
+
/* FUNCTIONS *****************************************************************/
static
PTIMER
if (!FirstpTmr)
{
+ ExInitializeResourceLite(&TimerLock);
FirstpTmr = UserCreateObject(gHandleTable, NULL, &Handle, otTimer, sizeof(TIMER));
- if (FirstpTmr) InitializeListHead(&FirstpTmr->ptmrList);
+ if (FirstpTmr)
+ {
+ FirstpTmr->head.h = Handle;
+ InitializeListHead(&FirstpTmr->ptmrList);
+ }
Ret = FirstpTmr;
}
else
{
Ret = UserCreateObject(gHandleTable, NULL, &Handle, otTimer, sizeof(TIMER));
- if (Ret) InsertTailList(&FirstpTmr->ptmrList, &Ret->ptmrList);
- }
+ if (Ret)
+ {
+ Ret->head.h = Handle;
+ InsertTailList(&FirstpTmr->ptmrList, &Ret->ptmrList);
+ }
+ }
return Ret;
}
FASTCALL
RemoveTimer(PTIMER pTmr)
{
+ BOOL Ret = FALSE;
if (pTmr)
{
+ /* Set the flag, it will be removed when ready */
RemoveEntryList(&pTmr->ptmrList);
- UserDeleteObject( UserHMGetHandle(pTmr), otTimer);
- return TRUE;
+ if ((pTmr->pWnd == NULL) && (!(pTmr->flags & TMRF_SYSTEM)))
+ {
+ UINT_PTR IDEvent;
+
+ IDEvent = NUM_WINDOW_LESS_TIMERS - pTmr->nID;
+ IntLockWindowlessTimerBitmap();
+ RtlClearBit(&WindowLessTimersBitMap, IDEvent);
+ IntUnlockWindowlessTimerBitmap();
+ }
+ UserDereferenceObject(pTmr);
+ Ret = UserDeleteObject( UserHMGetHandle(pTmr), otTimer);
}
- return FALSE;
+ if (!Ret) DPRINT1("Warning: Unable to delete timer\n");
+
+ return Ret;
}
PTIMER
FASTCALL
-FindTimer(PWINDOW_OBJECT Window,
+FindTimer(PWND Window,
UINT_PTR nID,
- UINT flags,
- BOOL Distroy)
+ UINT flags)
{
PLIST_ENTRY pLE;
- PTIMER pTmr = FirstpTmr;
- KeEnterCriticalRegion();
+ PTIMER pTmr = FirstpTmr, RetTmr = NULL;
+ TimerEnterExclusive();
do
{
if (!pTmr) break;
pTmr->pWnd == Window &&
(pTmr->flags & (TMRF_SYSTEM|TMRF_RIT)) == (flags & (TMRF_SYSTEM|TMRF_RIT)))
{
- if (Distroy)
- {
- RemoveTimer(pTmr);
- pTmr = (PTIMER)1; // We are here to remove the timer.
- }
+ RetTmr = pTmr;
break;
}
pLE = pTmr->ptmrList.Flink;
pTmr = CONTAINING_RECORD(pLE, TIMER, ptmrList);
} while (pTmr != FirstpTmr);
- KeLeaveCriticalRegion();
+ TimerLeave();
- return pTmr;
+ return RetTmr;
}
PTIMER
{
PLIST_ENTRY pLE;
PTIMER pTmr = FirstpTmr;
- KeEnterCriticalRegion();
+ TimerEnterExclusive();
do
{
if (!pTmr) break;
break;
pLE = pTmr->ptmrList.Flink;
- pTmr = CONTAINING_RECORD(pLE, TIMER, ptmrList);
+ pTmr = CONTAINING_RECORD(pLE, TIMER, ptmrList);
} while (pTmr != FirstpTmr);
- KeLeaveCriticalRegion();
+ TimerLeave();
return pTmr;
}
BOOL
FASTCALL
ValidateTimerCallback(PTHREADINFO pti,
- PWINDOW_OBJECT Window,
- WPARAM wParam,
LPARAM lParam)
{
PLIST_ENTRY pLE;
+ BOOL Ret = FALSE;
PTIMER pTmr = FirstpTmr;
if (!pTmr) return FALSE;
- KeEnterCriticalRegion();
+ TimerEnterExclusive();
do
{
if ( (lParam == (LPARAM)pTmr->pfn) &&
- (pTmr->flags & (TMRF_SYSTEM|TMRF_RIT)) &&
+ !(pTmr->flags & (TMRF_SYSTEM|TMRF_RIT)) &&
(pTmr->pti->ppi == pti->ppi) )
+ {
+ Ret = TRUE;
break;
-
+ }
pLE = pTmr->ptmrList.Flink;
pTmr = CONTAINING_RECORD(pLE, TIMER, ptmrList);
} while (pTmr != FirstpTmr);
- KeLeaveCriticalRegion();
-
- if (!pTmr) return FALSE;
+ TimerLeave();
- return TRUE;
+ return Ret;
}
-// Rename it to IntSetTimer after move.
UINT_PTR FASTCALL
-InternalSetTimer( PWINDOW_OBJECT Window,
+IntSetTimer( PWND Window,
UINT_PTR IDEvent,
UINT Elapse,
TIMERPROC TimerFunc,
INT Type)
{
PTIMER pTmr;
+ UINT Ret = IDEvent;
LARGE_INTEGER DueTime;
- DueTime.QuadPart = (LONGLONG)(-10000000);
+ DueTime.QuadPart = (LONGLONG)(-5000000);
#if 0
/* Windows NT/2k/XP behaviour */
Elapse = 10;
}
- pTmr = FindTimer(Window, IDEvent, Type, FALSE);
+ /* Passing an IDEvent of 0 and the SetTimer returns 1.
+ It will create the timer with an ID of 0 */
+ if ((Window) && (IDEvent == 0))
+ Ret = 1;
+
+ pTmr = FindTimer(Window, IDEvent, Type);
+
+ if ((!pTmr) && (Window == NULL) && (!(Type & TMRF_SYSTEM)))
+ {
+ IntLockWindowlessTimerBitmap();
+
+ IDEvent = RtlFindClearBitsAndSet(&WindowLessTimersBitMap, 1, HintIndex);
+
+ if (IDEvent == (UINT_PTR) -1)
+ {
+ IntUnlockWindowlessTimerBitmap();
+ DPRINT1("Unable to find a free window-less timer id\n");
+ SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
+ ASSERT(FALSE);
+ return 0;
+ }
+
+ IDEvent = NUM_WINDOW_LESS_TIMERS - IDEvent;
+ Ret = IDEvent;
+
+ IntUnlockWindowlessTimerBitmap();
+ }
+
if (!pTmr)
{
pTmr = CreateTimer();
if (!pTmr) return 0;
- if (Window && (Type & TMRF_TIFROMWND))
- pTmr->pti = Window->pti->pEThread->Tcb.Win32Thread;
- else
- {
- if (Type & TMRF_RIT)
- pTmr->pti = ptiRawInput;
- else
- pTmr->pti = PsGetCurrentThreadWin32Thread();
+ if (Window && (Type & TMRF_TIFROMWND))
+ pTmr->pti = Window->head.pti->pEThread->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);
+ pTmr->flags = Type|TMRF_INIT;
+ }
+ else
+ {
+ pTmr->cmsCountdown = Elapse;
+ pTmr->cmsRate = Elapse;
}
+ ASSERT(MasterTimer != NULL);
// Start the timer thread!
- KeSetTimer(MasterTimer, DueTime, NULL);
+ if (pTmr == FirstpTmr)
+ KeSetTimer(MasterTimer, DueTime, NULL);
- if (!pTmr->nID) return 1;
- return pTmr->nID;
+ return Ret;
}
//
{
// 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);
+ IntSetTimer(NULL, 0, 1000, SystemTimerProc, TMRF_RIT);
}
UINT_PTR
FASTCALL
-SetSystemTimer( PWINDOW_OBJECT Window,
+SystemTimerSet( PWND Window,
UINT_PTR nIDEvent,
UINT uElapse,
- TIMERPROC lpTimerFunc)
+ TIMERPROC lpTimerFunc)
{
- if (Window && Window->pti->pEThread->ThreadsProcess != PsGetCurrentProcess())
+ if (Window && Window->head.pti->pEThread->ThreadsProcess != PsGetCurrentProcess())
{
SetLastWin32Error(ERROR_ACCESS_DENIED);
+ DPRINT("SysemTimerSet: Access Denied!\n");
return 0;
}
- return InternalSetTimer( Window, nIDEvent, uElapse, lpTimerFunc, TMRF_SYSTEM);
+ return IntSetTimer( Window, nIDEvent, uElapse, lpTimerFunc, TMRF_SYSTEM);
}
BOOL
FASTCALL
-PostTimerMessages(PWINDOW_OBJECT Window)
+PostTimerMessages(PWND Window)
{
PLIST_ENTRY pLE;
PUSER_MESSAGE_QUEUE ThreadQueue;
if (!pTmr) return FALSE;
- if (Window && (int)Window != 1)
- {
- if (!Window->Wnd) return FALSE;
- }
-
pti = PsGetCurrentThreadWin32Thread();
ThreadQueue = pti->MessageQueue;
- KeEnterCriticalRegion();
+ TimerEnterExclusive();
+
do
{
if ( (pTmr->flags & TMRF_READY) &&
(pTmr->pti == pti) &&
- (pTmr->pWnd == Window))
+ ((pTmr->pWnd == Window) || (Window == NULL)) )
{
- Msg.hwnd = Window->hSelf;
+ Msg.hwnd = (pTmr->pWnd) ? pTmr->pWnd->head.h : 0;
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);
+ MsqPostMessage(ThreadQueue, &Msg, FALSE, QS_TIMER);
pTmr->flags &= ~TMRF_READY;
ThreadQueue->WakeMask = ~QS_TIMER;
Hit = TRUE;
+ break;
}
pLE = pTmr->ptmrList.Flink;
pTmr = CONTAINING_RECORD(pLE, TIMER, ptmrList);
} while (pTmr != FirstpTmr);
- KeLeaveCriticalRegion();
+
+ TimerLeave();
return Hit;
}
LONG Time;
PLIST_ENTRY pLE;
PTIMER pTmr = FirstpTmr;
+ LONG TimerCount = 0;
if (!pTmr) return;
- UserEnterExclusive();
+ TimerEnterExclusive();
KeQueryTickCount(&TickCount);
Time = MsqCalculateMessageTime(&TickCount);
- DueTime.QuadPart = (LONGLONG)(-10000000);
+ DueTime.QuadPart = (LONGLONG)(-500000);
do
{
+ TimerCount++;
if (pTmr->flags & TMRF_WAITING)
{
pLE = pTmr->ptmrList.Flink;
continue;
}
- if (pTmr->flags & TMRF_INIT)
+ if (pTmr->flags & TMRF_INIT)
+ {
pTmr->flags &= ~TMRF_INIT; // Skip this run.
+ }
else
{
if (pTmr->cmsCountdown < 0)
{
- if (!(pTmr->flags & TMRF_READY))
+ ASSERT(pTmr->pti);
+ if ((!(pTmr->flags & TMRF_READY)) && (!(pTmr->pti->TIF_flags & TIF_INCLEANUP)))
{
if (pTmr->flags & TMRF_ONESHOT)
pTmr->flags |= TMRF_WAITING;
// Set thread message queue for this timer.
if (pTmr->pti->MessageQueue)
{ // Wakeup thread
- pTmr->pti->MessageQueue->WakeMask |= QS_TIMER;
+ ASSERT(pTmr->pti->MessageQueue->NewMessages != NULL);
KeSetEvent(pTmr->pti->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
}
}
else
pTmr->cmsCountdown -= Time - TimeLast;
}
+
pLE = pTmr->ptmrList.Flink;
pTmr = CONTAINING_RECORD(pLE, TIMER, ptmrList);
} while (pTmr != FirstpTmr);
// Restart the timer thread!
+ ASSERT(MasterTimer != NULL);
KeSetTimer(MasterTimer, DueTime, NULL);
TimeLast = Time;
- UserLeave();
+ TimerLeave();
+ DPRINT("TimerCount = %d\n", TimerCount);
}
-//
-//
-// Old Timer Queueing
-//
-//
-UINT_PTR FASTCALL
-IntSetTimer(HWND Wnd, UINT_PTR IDEvent, UINT Elapse, TIMERPROC TimerFunc, BOOL SystemTimer)
+BOOL FASTCALL
+DestroyTimersForWindow(PTHREADINFO pti, PWND Window)
{
- PWINDOW_OBJECT Window;
- UINT_PTR Ret = 0;
- PTHREADINFO pti;
- PUSER_MESSAGE_QUEUE MessageQueue;
+ PLIST_ENTRY pLE;
+ PTIMER pTmr = FirstpTmr;
+ BOOL TimersRemoved = FALSE;
- DPRINT("IntSetTimer wnd %x id %p elapse %u timerproc %p systemtimer %s\n",
- Wnd, IDEvent, Elapse, TimerFunc, SystemTimer ? "TRUE" : "FALSE");
-
- if ((Wnd == NULL) && ! SystemTimer)
- {
- DPRINT("Window-less timer\n");
- /* find a free, window-less timer id */
- IntLockWindowlessTimerBitmap();
- IDEvent = RtlFindClearBitsAndSet(&WindowLessTimersBitMap, 1, HintIndex);
+ if ((FirstpTmr == NULL) || (Window == NULL))
+ return FALSE;
- if (IDEvent == (UINT_PTR) -1)
- {
- IntUnlockWindowlessTimerBitmap();
- DPRINT1("Unable to find a free window-less timer id\n");
- SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
- return 0;
- }
+ TimerEnterExclusive();
- HintIndex = ++IDEvent;
- IntUnlockWindowlessTimerBitmap();
- Ret = IDEvent;
- pti = PsGetCurrentThreadWin32Thread();
- MessageQueue = pti->MessageQueue;
- }
- else
+ do
{
- if (!(Window = UserGetWindowObject(Wnd)))
- {
- DPRINT1("Invalid window handle\n");
- return 0;
- }
-
- if (Window->pti->pEThread->ThreadsProcess != PsGetCurrentProcess())
+ if ((pTmr) && (pTmr->pti == pti) && (pTmr->pWnd == Window))
{
- DPRINT1("Trying to set timer for window in another process (shatter attack?)\n");
- SetLastWin32Error(ERROR_ACCESS_DENIED);
- return 0;
+ TimersRemoved = RemoveTimer(pTmr);
}
+ pLE = pTmr->ptmrList.Flink;
+ pTmr = CONTAINING_RECORD(pLE, TIMER, ptmrList);
+ } while (pTmr != FirstpTmr);
- Ret = IDEvent;
- MessageQueue = Window->pti->MessageQueue;
- }
-
-#if 0
-
- /* Windows NT/2k/XP behaviour */
- if (Elapse > 0x7fffffff)
- {
- DPRINT("Adjusting uElapse\n");
- Elapse = 1;
- }
+ TimerLeave();
-#else
+ return TimersRemoved;
+}
- /* Windows XP SP2 and Windows Server 2003 behaviour */
- if (Elapse > 0x7fffffff)
- {
- DPRINT("Adjusting uElapse\n");
- Elapse = 0x7fffffff;
- }
+BOOL FASTCALL
+DestroyTimersForThread(PTHREADINFO pti)
+{
+ PLIST_ENTRY pLE;
+ PTIMER pTmr = FirstpTmr;
+ BOOL TimersRemoved = FALSE;
-#endif
+ if (FirstpTmr == NULL)
+ return FALSE;
- /* Windows 2k/XP and Windows Server 2003 SP1 behaviour */
- if (Elapse < 10)
- {
- DPRINT("Adjusting uElapse\n");
- Elapse = 10;
- }
+ TimerEnterExclusive();
- if (! MsqSetTimer(MessageQueue, Wnd,
- IDEvent, Elapse, TimerFunc,
- SystemTimer ? WM_SYSTIMER : WM_TIMER))
+ do
{
- DPRINT1("Failed to set timer in message queue\n");
- SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
- return 0;
- }
+ if ((pTmr) && (pTmr->pti == pti))
+ {
+ TimersRemoved = RemoveTimer(pTmr);
+ }
+ pLE = pTmr->ptmrList.Flink;
+ pTmr = CONTAINING_RECORD(pLE, TIMER, ptmrList);
+ } while (pTmr != FirstpTmr);
+ TimerLeave();
- return Ret;
+ return TimersRemoved;
}
-
BOOL FASTCALL
-IntKillTimer(HWND Wnd, UINT_PTR IDEvent, BOOL SystemTimer)
+IntKillTimer(PWND Window, UINT_PTR IDEvent, BOOL SystemTimer)
{
- PTHREADINFO pti;
- PWINDOW_OBJECT Window = NULL;
-
- DPRINT("IntKillTimer wnd %x id %p systemtimer %s\n",
- Wnd, IDEvent, SystemTimer ? "TRUE" : "FALSE");
-
- pti = PsGetCurrentThreadWin32Thread();
- if (Wnd)
- {
- Window = UserGetWindowObject(Wnd);
-
- if (! MsqKillTimer(pti->MessageQueue, Wnd,
- IDEvent, SystemTimer ? WM_SYSTIMER : WM_TIMER))
- {
- // Give it another chance to find the timer.
- if (Window && !( MsqKillTimer(Window->pti->MessageQueue, Wnd,
- IDEvent, SystemTimer ? WM_SYSTIMER : WM_TIMER)))
- {
- DPRINT1("Unable to locate timer in message queue for Window.\n");
- SetLastWin32Error(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
- }
- }
-
- /* window-less timer? */
- if ((Wnd == NULL) && ! SystemTimer)
- {
- if (! MsqKillTimer(pti->MessageQueue, Wnd,
- IDEvent, SystemTimer ? WM_SYSTIMER : WM_TIMER))
- {
- DPRINT1("Unable to locate timer in message queue for Window-less timer.\n");
- SetLastWin32Error(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
-
- /* Release the id */
- IntLockWindowlessTimerBitmap();
+ PTIMER pTmr = NULL;
+ DPRINT("IntKillTimer Window %x id %p systemtimer %s\n",
+ Window, IDEvent, SystemTimer ? "TRUE" : "FALSE");
- ASSERT(RtlAreBitsSet(&WindowLessTimersBitMap, IDEvent - 1, 1));
- RtlClearBits(&WindowLessTimersBitMap, IDEvent - 1, 1);
+ pTmr = FindTimer(Window, IDEvent, SystemTimer ? TMRF_SYSTEM : 0);
- IntUnlockWindowlessTimerBitmap();
+ if (pTmr)
+ {
+ TimerEnterExclusive();
+ RemoveTimer(pTmr);
+ TimerLeave();
}
- return TRUE;
+ return pTmr ? TRUE : FALSE;
}
-NTSTATUS FASTCALL
+INIT_FUNCTION
+NTSTATUS
+NTAPI
InitTimerImpl(VOID)
{
ULONG BitmapBytes;
ExInitializeFastMutex(&Mutex);
BitmapBytes = ROUND_UP(NUM_WINDOW_LESS_TIMERS, sizeof(ULONG) * 8) / 8;
- WindowLessTimersBitMapBuffer = ExAllocatePoolWithTag(PagedPool, BitmapBytes, TAG_TIMERBMP);
+ WindowLessTimersBitMapBuffer = ExAllocatePoolWithTag(NonPagedPool, BitmapBytes, TAG_TIMERBMP);
if (WindowLessTimersBitMapBuffer == NULL)
{
return STATUS_UNSUCCESSFUL;
WindowLessTimersBitMapBuffer,
BitmapBytes * 8);
- /* yes we need this, since ExAllocatePool isn't supposed to zero out allocated memory */
+ /* yes we need this, since ExAllocatePoolWithTag isn't supposed to zero out allocated memory */
RtlClearAllBits(&WindowLessTimersBitMap);
return STATUS_SUCCESS;
TIMERPROC lpTimerFunc
)
{
+ PWND Window;
DECLARE_RETURN(UINT_PTR);
DPRINT("Enter NtUserSetTimer\n");
UserEnterExclusive();
+ Window = UserGetWindowObject(hWnd);
+ UserLeave();
- RETURN(IntSetTimer(hWnd, nIDEvent, uElapse, lpTimerFunc, FALSE));
+ RETURN(IntSetTimer(Window, nIDEvent, uElapse, lpTimerFunc, TMRF_TIFROMWND));
CLEANUP:
DPRINT("Leave NtUserSetTimer, ret=%i\n", _ret_);
- UserLeave();
+
END_CLEANUP;
}
UINT_PTR uIDEvent
)
{
+ PWND Window;
DECLARE_RETURN(BOOL);
DPRINT("Enter NtUserKillTimer\n");
UserEnterExclusive();
+ Window = UserGetWindowObject(hWnd);
+ UserLeave();
- RETURN(IntKillTimer(hWnd, uIDEvent, FALSE));
+ RETURN(IntKillTimer(Window, uIDEvent, FALSE));
CLEANUP:
DPRINT("Leave NtUserKillTimer, ret=%i\n", _ret_);
- UserLeave();
END_CLEANUP;
}
DECLARE_RETURN(UINT_PTR);
DPRINT("Enter NtUserSetSystemTimer\n");
- UserEnterExclusive();
- // This is wrong, lpTimerFunc is NULL!
- RETURN(IntSetTimer(hWnd, nIDEvent, uElapse, lpTimerFunc, TRUE));
+ RETURN(IntSetTimer(UserGetWindowObject(hWnd), nIDEvent, uElapse, NULL, TMRF_SYSTEM));
CLEANUP:
DPRINT("Leave NtUserSetSystemTimer, ret=%i\n", _ret_);
- UserLeave();
END_CLEANUP;
}