2003-04-02 23:12:53 +00:00
|
|
|
/*
|
2003-05-18 17:16:18 +00:00
|
|
|
* ReactOS W32 Subsystem
|
|
|
|
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program 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 General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*/
|
2004-02-19 21:12:11 +00:00
|
|
|
/* $Id: timer.c,v 1.23 2004/02/19 21:12:09 weiden Exp $
|
2003-04-02 23:12:53 +00:00
|
|
|
*
|
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS kernel
|
|
|
|
* PURPOSE: Window timers messages
|
|
|
|
* FILE: subsys/win32k/ntuser/timer.c
|
|
|
|
* PROGRAMER: Gunnar
|
2003-10-15 13:39:09 +00:00
|
|
|
* Thomas Weidenmueller (w3seek@users.sourceforge.net)
|
|
|
|
* REVISION HISTORY: 10/04/2003 Implemented System Timers
|
2003-04-02 23:12:53 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
|
|
|
|
#include <ddk/ntddk.h>
|
|
|
|
#include <win32k/win32k.h>
|
|
|
|
#include <win32k/ntuser.h>
|
|
|
|
#include <internal/ntoskrnl.h>
|
|
|
|
#include <internal/ps.h>
|
|
|
|
#include <include/msgqueue.h>
|
2003-10-04 22:36:37 +00:00
|
|
|
#include <include/window.h>
|
|
|
|
#include <include/error.h>
|
2003-10-16 22:07:37 +00:00
|
|
|
#include <include/timer.h>
|
2004-02-19 21:12:11 +00:00
|
|
|
#include <include/tags.h>
|
2003-04-02 23:12:53 +00:00
|
|
|
#include <messages.h>
|
|
|
|
#include <napi/win32.h>
|
|
|
|
|
|
|
|
#define NDEBUG
|
|
|
|
#include <debug.h>
|
|
|
|
|
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
|
2003-05-22 02:07:22 +00:00
|
|
|
//windows 2000 has room for 32768 handle-less timers
|
|
|
|
#define NUM_HANDLE_LESS_TIMERS 1024
|
2003-04-02 23:12:53 +00:00
|
|
|
|
|
|
|
static FAST_MUTEX Mutex;
|
|
|
|
static LIST_ENTRY TimerListHead;
|
2003-10-04 22:36:37 +00:00
|
|
|
static LIST_ENTRY SysTimerListHead;
|
2003-04-02 23:12:53 +00:00
|
|
|
static KTIMER Timer;
|
|
|
|
static RTL_BITMAP HandleLessTimersBitMap;
|
|
|
|
static PVOID HandleLessTimersBitMapBuffer;
|
|
|
|
static ULONG HintIndex = 0;
|
|
|
|
static HANDLE MsgTimerThreadHandle;
|
|
|
|
static CLIENT_ID MsgTimerThreadId;
|
|
|
|
|
|
|
|
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
//return true if the new timer became the first entry
|
2003-06-05 22:47:47 +00:00
|
|
|
//must hold mutex while calling this
|
2003-10-15 13:39:09 +00:00
|
|
|
BOOL FASTCALL
|
|
|
|
IntInsertTimerAscendingOrder(PMSG_TIMER_ENTRY NewTimer, BOOL SysTimer)
|
2003-04-02 23:12:53 +00:00
|
|
|
{
|
2003-11-03 20:31:39 +00:00
|
|
|
PLIST_ENTRY ListHead;
|
2003-10-15 13:39:09 +00:00
|
|
|
|
2003-11-03 20:31:39 +00:00
|
|
|
ListHead = SysTimer ? &SysTimerListHead : &TimerListHead;
|
|
|
|
|
|
|
|
InsertAscendingList(ListHead,
|
|
|
|
MSG_TIMER_ENTRY,
|
2004-01-18 22:30:39 +00:00
|
|
|
ListEntry,
|
|
|
|
NewTimer,
|
2003-11-03 20:31:39 +00:00
|
|
|
Timeout.QuadPart);
|
|
|
|
|
|
|
|
return IsFirstEntry(ListHead, &NewTimer->ListEntry);
|
2003-04-02 23:12:53 +00:00
|
|
|
}
|
|
|
|
|
2003-10-15 13:39:09 +00:00
|
|
|
//must hold mutex while calling this
|
|
|
|
PMSG_TIMER_ENTRY FASTCALL
|
|
|
|
IntRemoveTimer(HWND hWnd, UINT_PTR IDEvent, HANDLE ThreadID, BOOL SysTimer)
|
2003-06-05 22:47:47 +00:00
|
|
|
{
|
2003-10-15 13:39:09 +00:00
|
|
|
PMSG_TIMER_ENTRY MsgTimer;
|
|
|
|
PLIST_ENTRY EnumEntry;
|
|
|
|
|
|
|
|
if(!SysTimer)
|
|
|
|
{
|
|
|
|
//remove timer if already in the queue
|
|
|
|
EnumEntry = TimerListHead.Flink;
|
|
|
|
while (EnumEntry != &TimerListHead)
|
|
|
|
{
|
2003-10-04 22:36:37 +00:00
|
|
|
MsgTimer = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
|
|
|
|
EnumEntry = EnumEntry->Flink;
|
2003-10-15 13:39:09 +00:00
|
|
|
|
|
|
|
if (MsgTimer->Msg.hwnd == hWnd &&
|
|
|
|
MsgTimer->Msg.wParam == (WPARAM)IDEvent &&
|
|
|
|
MsgTimer->ThreadID == ThreadID)
|
2003-10-04 22:36:37 +00:00
|
|
|
{
|
2003-10-15 13:39:09 +00:00
|
|
|
RemoveEntryList(&MsgTimer->ListEntry);
|
|
|
|
return MsgTimer;
|
2003-10-04 22:36:37 +00:00
|
|
|
}
|
2003-10-15 13:39:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//remove timer if already in the queue
|
|
|
|
EnumEntry = SysTimerListHead.Flink;
|
|
|
|
while (EnumEntry != &SysTimerListHead)
|
|
|
|
{
|
2003-06-05 22:47:47 +00:00
|
|
|
MsgTimer = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
|
|
|
|
EnumEntry = EnumEntry->Flink;
|
2003-10-15 13:39:09 +00:00
|
|
|
|
|
|
|
if (MsgTimer->Msg.hwnd == hWnd &&
|
|
|
|
MsgTimer->Msg.wParam == (WPARAM)IDEvent &&
|
|
|
|
MsgTimer->ThreadID == ThreadID)
|
2003-06-05 22:47:47 +00:00
|
|
|
{
|
2003-10-15 13:39:09 +00:00
|
|
|
RemoveEntryList(&MsgTimer->ListEntry);
|
|
|
|
return MsgTimer;
|
2003-06-05 22:47:47 +00:00
|
|
|
}
|
2003-10-15 13:39:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
2003-06-05 22:47:47 +00:00
|
|
|
}
|
|
|
|
|
2003-04-02 23:12:53 +00:00
|
|
|
|
2003-10-15 13:39:09 +00:00
|
|
|
/*
|
|
|
|
* NOTE: It doesn't kill timers. It just removes them from the list.
|
|
|
|
*/
|
|
|
|
VOID FASTCALL
|
|
|
|
RemoveTimersThread(HANDLE ThreadID)
|
2003-04-02 23:12:53 +00:00
|
|
|
{
|
2003-10-15 13:39:09 +00:00
|
|
|
PMSG_TIMER_ENTRY MsgTimer;
|
|
|
|
PLIST_ENTRY EnumEntry;
|
|
|
|
|
|
|
|
ExAcquireFastMutex(&Mutex);
|
2003-10-04 22:36:37 +00:00
|
|
|
|
|
|
|
EnumEntry = SysTimerListHead.Flink;
|
2003-10-15 13:39:09 +00:00
|
|
|
while (EnumEntry != &SysTimerListHead)
|
2003-10-04 22:36:37 +00:00
|
|
|
{
|
2003-10-15 13:39:09 +00:00
|
|
|
MsgTimer = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
|
|
|
|
EnumEntry = EnumEntry->Flink;
|
|
|
|
|
|
|
|
if (MsgTimer->ThreadID == ThreadID)
|
2003-10-04 22:36:37 +00:00
|
|
|
{
|
2003-10-15 13:39:09 +00:00
|
|
|
RemoveEntryList(&MsgTimer->ListEntry);
|
|
|
|
ExFreePool(MsgTimer);
|
2003-10-04 22:36:37 +00:00
|
|
|
}
|
|
|
|
}
|
2003-10-15 13:39:09 +00:00
|
|
|
|
|
|
|
EnumEntry = TimerListHead.Flink;
|
|
|
|
while (EnumEntry != &TimerListHead)
|
|
|
|
{
|
|
|
|
MsgTimer = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
|
|
|
|
EnumEntry = EnumEntry->Flink;
|
|
|
|
|
|
|
|
if (MsgTimer->ThreadID == ThreadID)
|
|
|
|
{
|
|
|
|
if (MsgTimer->Msg.hwnd == NULL)
|
|
|
|
{
|
|
|
|
RtlClearBits(&HandleLessTimersBitMap, ((UINT_PTR)MsgTimer->Msg.wParam) - 1, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
RemoveEntryList(&MsgTimer->ListEntry);
|
|
|
|
ExFreePool(MsgTimer);
|
|
|
|
}
|
2003-10-04 22:36:37 +00:00
|
|
|
}
|
2003-10-15 13:39:09 +00:00
|
|
|
|
|
|
|
ExReleaseFastMutex(&Mutex);
|
2003-04-02 23:12:53 +00:00
|
|
|
}
|
|
|
|
|
2003-10-15 13:39:09 +00:00
|
|
|
UINT_PTR FASTCALL
|
|
|
|
IntSetTimer(HWND hWnd, UINT_PTR nIDEvent, UINT uElapse, TIMERPROC lpTimerFunc, BOOL SystemTimer)
|
2003-04-02 23:12:53 +00:00
|
|
|
{
|
2003-10-15 13:39:09 +00:00
|
|
|
ULONG Index;
|
|
|
|
PMSG_TIMER_ENTRY MsgTimer2, MsgTimer = NULL;
|
|
|
|
PMSG_TIMER_ENTRY NewTimer;
|
|
|
|
PLIST_ENTRY EnumEntry;
|
|
|
|
LARGE_INTEGER CurrentTime;
|
|
|
|
PWINDOW_OBJECT WindowObject;
|
|
|
|
HANDLE ThreadID;
|
|
|
|
UINT_PTR Ret = 0;
|
|
|
|
|
|
|
|
ThreadID = PsGetCurrentThreadId();
|
|
|
|
KeQuerySystemTime(&CurrentTime);
|
|
|
|
ExAcquireFastMutex(&Mutex);
|
|
|
|
|
|
|
|
if((hWnd == NULL) && !SystemTimer)
|
2003-07-06 23:04:19 +00:00
|
|
|
{
|
2003-10-15 13:39:09 +00:00
|
|
|
/* find a free, handle-less timer id */
|
|
|
|
Index = RtlFindClearBitsAndSet(&HandleLessTimersBitMap, 1, HintIndex);
|
|
|
|
|
|
|
|
if(Index == (ULONG) -1)
|
|
|
|
{
|
|
|
|
ExReleaseFastMutex(&Mutex);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
HintIndex = ++Index;
|
|
|
|
ExReleaseFastMutex(&Mutex);
|
|
|
|
return Index;
|
2003-07-06 23:04:19 +00:00
|
|
|
}
|
2003-10-15 13:39:09 +00:00
|
|
|
else
|
2003-10-04 22:36:37 +00:00
|
|
|
{
|
2003-10-15 13:39:09 +00:00
|
|
|
WindowObject = IntGetWindowObject(hWnd);
|
|
|
|
if(!WindowObject)
|
|
|
|
{
|
|
|
|
ExReleaseFastMutex(&Mutex);
|
|
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(WindowObject->OwnerThread != PsGetCurrentThread())
|
|
|
|
{
|
|
|
|
IntReleaseWindowObject(WindowObject);
|
|
|
|
ExReleaseFastMutex(&Mutex);
|
|
|
|
SetLastWin32Error(ERROR_ACCESS_DENIED);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
IntReleaseWindowObject(WindowObject);
|
|
|
|
|
|
|
|
/* remove timer if already in the queue */
|
2003-11-12 22:53:31 +00:00
|
|
|
MsgTimer = IntRemoveTimer(hWnd, nIDEvent, ThreadID, SystemTimer);
|
2003-10-04 22:36:37 +00:00
|
|
|
}
|
|
|
|
|
2003-10-15 13:39:09 +00:00
|
|
|
#if 1
|
|
|
|
|
|
|
|
/* Win NT/2k/XP */
|
|
|
|
if(uElapse > 0x7fffffff)
|
|
|
|
uElapse = 1;
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
/* Win Server 2003 */
|
|
|
|
if(uElapse > 0x7fffffff)
|
|
|
|
uElapse = 0x7fffffff;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Win 2k/XP */
|
|
|
|
if(uElapse < 10)
|
|
|
|
uElapse = 10;
|
|
|
|
|
|
|
|
if(MsgTimer)
|
2003-10-04 22:36:37 +00:00
|
|
|
{
|
2003-10-15 13:39:09 +00:00
|
|
|
/* modify existing (removed) timer */
|
|
|
|
NewTimer = MsgTimer;
|
|
|
|
|
|
|
|
NewTimer->Period = uElapse;
|
|
|
|
NewTimer->Timeout.QuadPart = CurrentTime.QuadPart + (uElapse * 10000);
|
|
|
|
NewTimer->Msg.lParam = (LPARAM)lpTimerFunc;
|
2003-10-04 22:36:37 +00:00
|
|
|
}
|
2003-10-15 13:39:09 +00:00
|
|
|
else
|
2003-10-04 22:36:37 +00:00
|
|
|
{
|
2003-10-15 13:39:09 +00:00
|
|
|
/* FIXME: use lookaside? */
|
2004-02-19 21:12:11 +00:00
|
|
|
NewTimer = ExAllocatePoolWithTag(PagedPool, sizeof(MSG_TIMER_ENTRY), TAG_TIMER);
|
2003-10-15 13:39:09 +00:00
|
|
|
if(!NewTimer)
|
|
|
|
{
|
|
|
|
ExReleaseFastMutex(&Mutex);
|
|
|
|
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
NewTimer->Msg.hwnd = hWnd;
|
|
|
|
NewTimer->Msg.message = (SystemTimer ? WM_SYSTIMER : WM_TIMER);
|
|
|
|
NewTimer->Msg.wParam = (WPARAM)nIDEvent;
|
|
|
|
NewTimer->Msg.lParam = (LPARAM)lpTimerFunc;
|
|
|
|
NewTimer->Period = uElapse;
|
|
|
|
NewTimer->Timeout.QuadPart = CurrentTime.QuadPart + (uElapse * 10000);
|
|
|
|
NewTimer->ThreadID = ThreadID;
|
2003-10-04 22:36:37 +00:00
|
|
|
}
|
2003-10-15 13:39:09 +00:00
|
|
|
|
|
|
|
Ret = nIDEvent; // FIXME - return lpTimerProc if it's not a system timer
|
|
|
|
|
|
|
|
if(SystemTimer)
|
2003-10-04 22:36:37 +00:00
|
|
|
{
|
2003-10-15 13:39:09 +00:00
|
|
|
if(IntInsertTimerAscendingOrder(NewTimer, TRUE))
|
2003-10-04 22:36:37 +00:00
|
|
|
{
|
2003-10-15 13:39:09 +00:00
|
|
|
EnumEntry = TimerListHead.Flink;
|
|
|
|
if(EnumEntry != &TimerListHead)
|
|
|
|
{
|
|
|
|
MsgTimer2 = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
|
|
|
|
if (NewTimer->Timeout.QuadPart < MsgTimer2->Timeout.QuadPart)
|
|
|
|
{
|
|
|
|
/* new timer is first in queue and expires first */
|
|
|
|
KeSetTimer(&Timer, NewTimer->Timeout, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* new timer is first in queue and expires first */
|
|
|
|
KeSetTimer(&Timer, NewTimer->Timeout, NULL);
|
|
|
|
}
|
2003-10-04 22:36:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2003-10-15 13:39:09 +00:00
|
|
|
{
|
|
|
|
if(IntInsertTimerAscendingOrder(NewTimer, FALSE))
|
|
|
|
{
|
|
|
|
EnumEntry = SysTimerListHead.Flink;
|
|
|
|
if(EnumEntry != &SysTimerListHead)
|
|
|
|
{
|
|
|
|
MsgTimer2 = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
|
|
|
|
if (NewTimer->Timeout.QuadPart < MsgTimer2->Timeout.QuadPart)
|
|
|
|
{
|
|
|
|
/* new timer is first in queue and expires first */
|
|
|
|
KeSetTimer(&Timer, NewTimer->Timeout, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* new timer is first in queue and expires first */
|
|
|
|
KeSetTimer(&Timer, NewTimer->Timeout, NULL);
|
|
|
|
}
|
|
|
|
}
|
2003-10-04 22:36:37 +00:00
|
|
|
}
|
|
|
|
|
2003-10-15 13:39:09 +00:00
|
|
|
ExReleaseFastMutex(&Mutex);
|
2003-10-04 22:36:37 +00:00
|
|
|
|
2003-10-15 13:39:09 +00:00
|
|
|
return Ret;
|
2003-10-04 22:36:37 +00:00
|
|
|
}
|
|
|
|
|
2003-10-15 13:39:09 +00:00
|
|
|
BOOL FASTCALL
|
|
|
|
IntKillTimer(HWND hWnd, UINT_PTR uIDEvent, BOOL SystemTimer)
|
2003-10-04 22:36:37 +00:00
|
|
|
{
|
2003-10-15 13:39:09 +00:00
|
|
|
PMSG_TIMER_ENTRY MsgTimer;
|
|
|
|
PWINDOW_OBJECT WindowObject;
|
|
|
|
|
|
|
|
ExAcquireFastMutex(&Mutex);
|
|
|
|
|
|
|
|
/* handle-less timer? */
|
|
|
|
if((hWnd == NULL) && !SystemTimer)
|
|
|
|
{
|
|
|
|
if(!RtlAreBitsSet(&HandleLessTimersBitMap, uIDEvent - 1, 1))
|
|
|
|
{
|
|
|
|
/* bit was not set */
|
|
|
|
/* FIXME: set the last error */
|
|
|
|
ExReleaseFastMutex(&Mutex);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
RtlClearBits(&HandleLessTimersBitMap, uIDEvent - 1, 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
WindowObject = IntGetWindowObject(hWnd);
|
|
|
|
if(!WindowObject)
|
|
|
|
{
|
|
|
|
ExReleaseFastMutex(&Mutex);
|
|
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if(WindowObject->OwnerThread != PsGetCurrentThread())
|
|
|
|
{
|
|
|
|
IntReleaseWindowObject(WindowObject);
|
|
|
|
ExReleaseFastMutex(&Mutex);
|
|
|
|
SetLastWin32Error(ERROR_ACCESS_DENIED);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
IntReleaseWindowObject(WindowObject);
|
|
|
|
}
|
|
|
|
|
|
|
|
MsgTimer = IntRemoveTimer(hWnd, uIDEvent, PsGetCurrentThreadId(), SystemTimer);
|
|
|
|
|
|
|
|
ExReleaseFastMutex(&Mutex);
|
|
|
|
|
|
|
|
if(MsgTimer == NULL)
|
|
|
|
{
|
|
|
|
/* didn't find timer */
|
|
|
|
/* FIXME: set the last error */
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* FIXME: use lookaside? */
|
|
|
|
ExFreePool(MsgTimer);
|
|
|
|
|
|
|
|
return TRUE;
|
2003-04-02 23:12:53 +00:00
|
|
|
}
|
|
|
|
|
2003-12-26 10:47:20 +00:00
|
|
|
extern VOID STDCALL ValidateNonPagedPool(VOID);
|
2004-02-10 18:11:12 +00:00
|
|
|
static VOID STDCALL
|
2003-10-15 13:39:09 +00:00
|
|
|
TimerThreadMain(PVOID StartContext)
|
2003-04-02 23:12:53 +00:00
|
|
|
{
|
2003-10-15 13:39:09 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
LARGE_INTEGER CurrentTime;
|
|
|
|
PLIST_ENTRY EnumEntry;
|
|
|
|
PMSG_TIMER_ENTRY MsgTimer, MsgTimer2;
|
|
|
|
PETHREAD Thread;
|
2003-12-21 20:37:42 +00:00
|
|
|
PETHREAD *ThreadsToDereference;
|
2003-12-23 21:34:52 +00:00
|
|
|
ULONG ThreadsToDereferenceCount, ThreadsToDereferencePos, i;
|
2003-10-15 13:39:09 +00:00
|
|
|
|
|
|
|
for(;;)
|
|
|
|
{
|
|
|
|
Status = KeWaitForSingleObject(&Timer,
|
|
|
|
Executive,
|
|
|
|
KernelMode,
|
|
|
|
FALSE,
|
|
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("Error waiting in TimerThreadMain\n");
|
|
|
|
KEBUGCHECK(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
ExAcquireFastMutex(&Mutex);
|
|
|
|
|
|
|
|
KeQuerySystemTime(&CurrentTime);
|
|
|
|
|
2003-12-21 20:37:42 +00:00
|
|
|
ThreadsToDereferenceCount = ThreadsToDereferencePos = 0;
|
|
|
|
|
|
|
|
for (EnumEntry = TimerListHead.Flink;
|
|
|
|
EnumEntry != &TimerListHead;
|
|
|
|
EnumEntry = EnumEntry->Flink)
|
|
|
|
{
|
|
|
|
MsgTimer = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
|
|
|
|
if (CurrentTime.QuadPart >= MsgTimer->Timeout.QuadPart)
|
|
|
|
++ThreadsToDereferenceCount;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (EnumEntry = SysTimerListHead.Flink;
|
|
|
|
EnumEntry != &SysTimerListHead;
|
|
|
|
EnumEntry = EnumEntry->Flink)
|
|
|
|
{
|
|
|
|
MsgTimer = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
|
|
|
|
if (CurrentTime.QuadPart >= MsgTimer->Timeout.QuadPart)
|
|
|
|
++ThreadsToDereferenceCount;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2004-02-19 21:12:11 +00:00
|
|
|
ThreadsToDereference = (PETHREAD *)ExAllocatePoolWithTag(
|
|
|
|
NonPagedPool, ThreadsToDereferenceCount * sizeof(PETHREAD), TAG_TIMERTD);
|
2003-12-21 20:37:42 +00:00
|
|
|
|
2003-10-15 13:39:09 +00:00
|
|
|
EnumEntry = TimerListHead.Flink;
|
|
|
|
while (EnumEntry != &TimerListHead)
|
|
|
|
{
|
|
|
|
MsgTimer = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
|
|
|
|
|
|
|
|
if (CurrentTime.QuadPart >= MsgTimer->Timeout.QuadPart)
|
2003-04-02 23:12:53 +00:00
|
|
|
{
|
2003-12-26 10:47:20 +00:00
|
|
|
EnumEntry = EnumEntry->Flink;
|
|
|
|
|
2003-10-15 13:39:09 +00:00
|
|
|
RemoveEntryList(&MsgTimer->ListEntry);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FIXME: 1) Find a faster way of getting the thread message queue? (lookup by id is slow)
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(PsLookupThreadByThreadId(MsgTimer->ThreadID, &Thread)))
|
|
|
|
{
|
|
|
|
ExFreePool(MsgTimer);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2003-10-22 19:02:13 +00:00
|
|
|
MsqPostMessage(((PW32THREAD)Thread->Win32Thread)->MessageQueue, MsqCreateMessage(&MsgTimer->Msg));
|
2003-10-15 13:39:09 +00:00
|
|
|
|
2003-12-21 20:37:42 +00:00
|
|
|
ThreadsToDereference[ThreadsToDereferencePos] = Thread;
|
|
|
|
++ThreadsToDereferencePos;
|
2003-10-15 13:39:09 +00:00
|
|
|
|
|
|
|
//set up next periodic timeout
|
2003-12-26 10:47:20 +00:00
|
|
|
do
|
|
|
|
{
|
|
|
|
MsgTimer->Timeout.QuadPart += (MsgTimer->Period * 10000);
|
|
|
|
}
|
|
|
|
while (MsgTimer->Timeout.QuadPart <= CurrentTime.QuadPart);
|
2003-10-15 13:39:09 +00:00
|
|
|
IntInsertTimerAscendingOrder(MsgTimer, FALSE);
|
2003-04-02 23:12:53 +00:00
|
|
|
}
|
2003-10-15 13:39:09 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2003-12-21 20:37:42 +00:00
|
|
|
|
2003-10-15 13:39:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
EnumEntry = SysTimerListHead.Flink;
|
|
|
|
while (EnumEntry != &SysTimerListHead)
|
|
|
|
{
|
|
|
|
MsgTimer2 = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
|
2003-10-04 22:36:37 +00:00
|
|
|
|
2003-10-15 13:39:09 +00:00
|
|
|
if (CurrentTime.QuadPart >= MsgTimer2->Timeout.QuadPart)
|
2003-10-04 22:36:37 +00:00
|
|
|
{
|
2003-12-26 10:47:20 +00:00
|
|
|
EnumEntry = EnumEntry->Flink;
|
|
|
|
|
2003-10-15 13:39:09 +00:00
|
|
|
RemoveEntryList(&MsgTimer2->ListEntry);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FIXME: 1) Find a faster way of getting the thread message queue? (lookup by id is slow)
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(PsLookupThreadByThreadId(MsgTimer2->ThreadID, &Thread)))
|
|
|
|
{
|
|
|
|
ExFreePool(MsgTimer2);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
MsqPostMessage(((PW32THREAD)Thread->Win32Thread)->MessageQueue, MsqCreateMessage(&MsgTimer2->Msg));
|
|
|
|
|
2003-12-21 20:37:42 +00:00
|
|
|
ThreadsToDereference[ThreadsToDereferencePos] = Thread;
|
|
|
|
++ThreadsToDereferencePos;
|
2003-10-15 13:39:09 +00:00
|
|
|
|
|
|
|
//set up next periodic timeout
|
2003-12-26 10:47:20 +00:00
|
|
|
do
|
|
|
|
{
|
|
|
|
MsgTimer2->Timeout.QuadPart += (MsgTimer2->Period * 10000);
|
|
|
|
}
|
|
|
|
while (MsgTimer2->Timeout.QuadPart <= CurrentTime.QuadPart);
|
2003-10-15 13:39:09 +00:00
|
|
|
IntInsertTimerAscendingOrder(MsgTimer2, TRUE);
|
2003-10-04 22:36:37 +00:00
|
|
|
}
|
2003-10-15 13:39:09 +00:00
|
|
|
else
|
2003-04-02 23:12:53 +00:00
|
|
|
{
|
2003-10-15 13:39:09 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//set up next timeout from first entry (if any)
|
|
|
|
if (!IsListEmpty(&TimerListHead))
|
|
|
|
{
|
|
|
|
MsgTimer = CONTAINING_RECORD( TimerListHead.Flink, MSG_TIMER_ENTRY, ListEntry);
|
|
|
|
if(!IsListEmpty(&SysTimerListHead))
|
|
|
|
{
|
|
|
|
MsgTimer2 = CONTAINING_RECORD( SysTimerListHead.Flink, MSG_TIMER_ENTRY, ListEntry);
|
|
|
|
if(MsgTimer->Timeout.QuadPart <= MsgTimer2->Timeout.QuadPart)
|
|
|
|
KeSetTimer(&Timer, MsgTimer->Timeout, NULL);
|
|
|
|
else
|
|
|
|
KeSetTimer(&Timer, MsgTimer2->Timeout, NULL);
|
2003-04-02 23:12:53 +00:00
|
|
|
}
|
2003-10-15 13:39:09 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
KeSetTimer(&Timer, MsgTimer->Timeout, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(!IsListEmpty(&SysTimerListHead))
|
2003-04-02 23:12:53 +00:00
|
|
|
{
|
2003-10-15 13:39:09 +00:00
|
|
|
MsgTimer2 = CONTAINING_RECORD( SysTimerListHead.Flink, MSG_TIMER_ENTRY, ListEntry);
|
|
|
|
KeSetTimer(&Timer, MsgTimer2->Timeout, NULL);
|
2003-04-02 23:12:53 +00:00
|
|
|
}
|
2003-07-29 18:17:53 +00:00
|
|
|
else
|
|
|
|
{
|
2003-10-15 13:39:09 +00:00
|
|
|
/* Reinitialize the timer, this reset the state of the timer event on which we wait */
|
|
|
|
KeInitializeTimer(&Timer);
|
2003-07-29 18:17:53 +00:00
|
|
|
}
|
2003-10-15 13:39:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ExReleaseFastMutex(&Mutex);
|
2003-12-21 20:37:42 +00:00
|
|
|
|
2003-12-23 21:34:52 +00:00
|
|
|
for (i = 0; i < ThreadsToDereferencePos; i++)
|
|
|
|
ObDereferenceObject(ThreadsToDereference[i]);
|
2003-12-21 20:37:42 +00:00
|
|
|
|
|
|
|
ExFreePool(ThreadsToDereference);
|
2003-10-15 13:39:09 +00:00
|
|
|
}
|
|
|
|
}
|
2003-04-02 23:12:53 +00:00
|
|
|
|
2003-10-15 13:39:09 +00:00
|
|
|
NTSTATUS FASTCALL
|
|
|
|
InitTimerImpl(VOID)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
|
|
ULONG BitmapBytes;
|
|
|
|
|
|
|
|
BitmapBytes = ROUND_UP(NUM_HANDLE_LESS_TIMERS, sizeof(ULONG) * 8) / 8;
|
|
|
|
|
|
|
|
InitializeListHead(&TimerListHead);
|
|
|
|
InitializeListHead(&SysTimerListHead);
|
|
|
|
KeInitializeTimer(&Timer);
|
|
|
|
ExInitializeFastMutex(&Mutex);
|
|
|
|
|
2004-02-19 21:12:11 +00:00
|
|
|
HandleLessTimersBitMapBuffer = ExAllocatePoolWithTag(PagedPool, BitmapBytes, TAG_TIMERBMP);
|
2003-10-15 13:39:09 +00:00
|
|
|
RtlInitializeBitMap(&HandleLessTimersBitMap,
|
|
|
|
HandleLessTimersBitMapBuffer,
|
|
|
|
BitmapBytes * 8);
|
|
|
|
|
|
|
|
//yes we need this, since ExAllocatePool isn't supposed to zero out allocated memory
|
|
|
|
RtlClearAllBits(&HandleLessTimersBitMap);
|
|
|
|
|
|
|
|
Status = PsCreateSystemThread(&MsgTimerThreadHandle,
|
|
|
|
THREAD_ALL_ACCESS,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
&MsgTimerThreadId,
|
|
|
|
TimerThreadMain,
|
|
|
|
NULL);
|
|
|
|
return Status;
|
|
|
|
}
|
2003-04-02 23:12:53 +00:00
|
|
|
|
|
|
|
|
2003-10-15 13:39:09 +00:00
|
|
|
UINT_PTR
|
|
|
|
STDCALL
|
|
|
|
NtUserSetTimer
|
|
|
|
(
|
|
|
|
HWND hWnd,
|
|
|
|
UINT_PTR nIDEvent,
|
|
|
|
UINT uElapse,
|
|
|
|
TIMERPROC lpTimerFunc
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return IntSetTimer(hWnd, nIDEvent, uElapse, lpTimerFunc, FALSE);
|
2003-04-02 23:12:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-10-15 13:39:09 +00:00
|
|
|
BOOL
|
|
|
|
STDCALL
|
|
|
|
NtUserKillTimer
|
|
|
|
(
|
|
|
|
HWND hWnd,
|
|
|
|
UINT_PTR uIDEvent
|
|
|
|
)
|
2003-04-02 23:12:53 +00:00
|
|
|
{
|
2003-10-15 13:39:09 +00:00
|
|
|
return IntKillTimer(hWnd, uIDEvent, FALSE);
|
|
|
|
}
|
2003-04-02 23:12:53 +00:00
|
|
|
|
|
|
|
|
2003-10-15 13:39:09 +00:00
|
|
|
UINT_PTR
|
|
|
|
STDCALL
|
|
|
|
NtUserSetSystemTimer(
|
|
|
|
HWND hWnd,
|
|
|
|
UINT_PTR nIDEvent,
|
|
|
|
UINT uElapse,
|
|
|
|
TIMERPROC lpTimerFunc
|
|
|
|
)
|
|
|
|
{
|
2003-10-15 19:28:57 +00:00
|
|
|
return IntSetTimer(hWnd, nIDEvent, uElapse, lpTimerFunc, TRUE);
|
2003-10-15 13:39:09 +00:00
|
|
|
}
|
2003-04-02 23:12:53 +00:00
|
|
|
|
|
|
|
|
2003-10-15 13:39:09 +00:00
|
|
|
BOOL
|
|
|
|
STDCALL
|
|
|
|
NtUserKillSystemTimer(
|
|
|
|
HWND hWnd,
|
|
|
|
UINT_PTR uIDEvent
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return IntKillTimer(hWnd, uIDEvent, TRUE);
|
2003-04-02 23:12:53 +00:00
|
|
|
}
|
|
|
|
|
2003-05-18 17:16:18 +00:00
|
|
|
/* EOF */
|