mirror of
https://github.com/reactos/reactos.git
synced 2025-02-24 09:25:10 +00:00
Generate timer messages instead of queueing them
svn path=/trunk/; revision=12387
This commit is contained in:
parent
3149ec5ad0
commit
cffcbe1d74
8 changed files with 468 additions and 397 deletions
|
@ -40,6 +40,16 @@ typedef struct _USER_SENT_MESSAGE_NOTIFY
|
||||||
LIST_ENTRY ListEntry;
|
LIST_ENTRY ListEntry;
|
||||||
} USER_SENT_MESSAGE_NOTIFY, *PUSER_SENT_MESSAGE_NOTIFY;
|
} USER_SENT_MESSAGE_NOTIFY, *PUSER_SENT_MESSAGE_NOTIFY;
|
||||||
|
|
||||||
|
typedef struct _TIMER_ENTRY{
|
||||||
|
LIST_ENTRY ListEntry;
|
||||||
|
LARGE_INTEGER ExpiryTime;
|
||||||
|
HWND Wnd;
|
||||||
|
UINT_PTR IDEvent;
|
||||||
|
UINT Period;
|
||||||
|
TIMERPROC TimerFunc;
|
||||||
|
UINT Msg;
|
||||||
|
} TIMER_ENTRY, *PTIMER_ENTRY;
|
||||||
|
|
||||||
typedef struct _USER_MESSAGE_QUEUE
|
typedef struct _USER_MESSAGE_QUEUE
|
||||||
{
|
{
|
||||||
/* Reference counter, only access this variable with interlocked functions! */
|
/* Reference counter, only access this variable with interlocked functions! */
|
||||||
|
@ -55,6 +65,8 @@ typedef struct _USER_MESSAGE_QUEUE
|
||||||
LIST_ENTRY NotifyMessagesListHead;
|
LIST_ENTRY NotifyMessagesListHead;
|
||||||
/* Queue for hardware messages for the queue. */
|
/* Queue for hardware messages for the queue. */
|
||||||
LIST_ENTRY HardwareMessagesListHead;
|
LIST_ENTRY HardwareMessagesListHead;
|
||||||
|
/* List of timers, sorted on expiry time (earliest first) */
|
||||||
|
LIST_ENTRY TimerListHead;
|
||||||
/* Lock for the hardware message list. */
|
/* Lock for the hardware message list. */
|
||||||
KMUTEX HardwareLock;
|
KMUTEX HardwareLock;
|
||||||
/* Lock for the queue. */
|
/* Lock for the queue. */
|
||||||
|
@ -144,13 +156,12 @@ MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue);
|
||||||
PUSER_MESSAGE_QUEUE FASTCALL
|
PUSER_MESSAGE_QUEUE FASTCALL
|
||||||
MsqGetHardwareMessageQueue(VOID);
|
MsqGetHardwareMessageQueue(VOID);
|
||||||
NTSTATUS FASTCALL
|
NTSTATUS FASTCALL
|
||||||
MsqWaitForNewMessage(PUSER_MESSAGE_QUEUE MessageQueue);
|
|
||||||
NTSTATUS FASTCALL
|
|
||||||
MsqInitializeImpl(VOID);
|
MsqInitializeImpl(VOID);
|
||||||
BOOLEAN FASTCALL
|
BOOLEAN FASTCALL
|
||||||
MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue);
|
MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue);
|
||||||
NTSTATUS FASTCALL
|
NTSTATUS FASTCALL
|
||||||
MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue);
|
MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue, HWND WndFilter,
|
||||||
|
UINT MsgFilterMin, UINT MsgFilterMax);
|
||||||
VOID FASTCALL
|
VOID FASTCALL
|
||||||
MsqSendNotifyMessage(PUSER_MESSAGE_QUEUE MessageQueue,
|
MsqSendNotifyMessage(PUSER_MESSAGE_QUEUE MessageQueue,
|
||||||
PUSER_SENT_MESSAGE_NOTIFY NotifyMessage);
|
PUSER_SENT_MESSAGE_NOTIFY NotifyMessage);
|
||||||
|
@ -248,6 +259,24 @@ IntMsqSetWakeMask(DWORD WakeMask);
|
||||||
BOOL FASTCALL
|
BOOL FASTCALL
|
||||||
IntMsqClearWakeMask(VOID);
|
IntMsqClearWakeMask(VOID);
|
||||||
|
|
||||||
|
BOOLEAN FASTCALL
|
||||||
|
MsqSetTimer(PUSER_MESSAGE_QUEUE MessageQueue, HWND Wnd,
|
||||||
|
UINT_PTR IDEvent, UINT Period, TIMERPROC TimerFunc,
|
||||||
|
UINT Msg);
|
||||||
|
BOOLEAN FASTCALL
|
||||||
|
MsqKillTimer(PUSER_MESSAGE_QUEUE MessageQueue, HWND Wnd,
|
||||||
|
UINT_PTR IDEvent, UINT Msg);
|
||||||
|
BOOLEAN FASTCALL
|
||||||
|
MsqGetTimerMessage(PUSER_MESSAGE_QUEUE MessageQueue,
|
||||||
|
HWND WndFilter, UINT MsgFilterMin, UINT MsgFilterMax,
|
||||||
|
MSG *Msg, BOOLEAN Restart);
|
||||||
|
BOOLEAN FASTCALL
|
||||||
|
MsqGetFirstTimerExpiry(PUSER_MESSAGE_QUEUE MessageQueue,
|
||||||
|
HWND WndFilter, UINT MsgFilterMin, UINT MsgFilterMax,
|
||||||
|
PLARGE_INTEGER FirstTimerExpiry);
|
||||||
|
VOID FASTCALL
|
||||||
|
MsqRemoveTimersWindow(PUSER_MESSAGE_QUEUE MessageQueue, HWND Wnd);
|
||||||
|
|
||||||
#endif /* _WIN32K_MSGQUEUE_H */
|
#endif /* _WIN32K_MSGQUEUE_H */
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
|
@ -1,18 +1,8 @@
|
||||||
#ifndef _WIN32K_TIMER_H
|
#ifndef _WIN32K_TIMER_H
|
||||||
#define _WIN32K_TIMER_H
|
#define _WIN32K_TIMER_H
|
||||||
|
|
||||||
typedef struct _MSG_TIMER_ENTRY{
|
|
||||||
LIST_ENTRY ListEntry;
|
|
||||||
LARGE_INTEGER Timeout;
|
|
||||||
HANDLE ThreadID;
|
|
||||||
UINT Period;
|
|
||||||
MSG Msg;
|
|
||||||
} MSG_TIMER_ENTRY, *PMSG_TIMER_ENTRY;
|
|
||||||
|
|
||||||
NTSTATUS FASTCALL InitTimerImpl(VOID);
|
NTSTATUS FASTCALL InitTimerImpl(VOID);
|
||||||
VOID FASTCALL RemoveTimersThread(HANDLE ThreadID);
|
BOOL FASTCALL IntKillTimer(HWND Wnd, UINT_PTR IDEvent, BOOL SystemTimer);
|
||||||
VOID FASTCALL RemoveTimersWindow(HWND hWnd);
|
UINT_PTR FASTCALL IntSetTimer(HWND Wnd, UINT_PTR IDEvent, UINT Elapse, TIMERPROC TimerFunc, BOOL SystemTimer);
|
||||||
PMSG_TIMER_ENTRY FASTCALL IntRemoveTimer(HWND hWnd, UINT_PTR IDEvent, HANDLE ThreadID, BOOL SysTimer);
|
|
||||||
UINT_PTR FASTCALL IntSetTimer(HWND hWnd, UINT_PTR nIDEvent, UINT uElapse, TIMERPROC lpTimerFunc, BOOL SystemTimer);
|
|
||||||
|
|
||||||
#endif /* _WIN32K_TIMER_H */
|
#endif /* _WIN32K_TIMER_H */
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
/* $Id: dllmain.c,v 1.85 2004/12/24 17:45:58 weiden Exp $
|
/* $Id: dllmain.c,v 1.86 2004/12/29 19:55:01 gvg Exp $
|
||||||
*
|
*
|
||||||
* Entry Point for win32k.sys
|
* Entry Point for win32k.sys
|
||||||
*/
|
*/
|
||||||
|
@ -184,7 +184,6 @@ Win32kThreadCallback (struct _ETHREAD *Thread,
|
||||||
|
|
||||||
Win32Thread->IsExiting = TRUE;
|
Win32Thread->IsExiting = TRUE;
|
||||||
HOOK_DestroyThreadHooks(Thread);
|
HOOK_DestroyThreadHooks(Thread);
|
||||||
RemoveTimersThread(Win32Thread->MessageQueue);
|
|
||||||
UnregisterThreadHotKeys(Thread);
|
UnregisterThreadHotKeys(Thread);
|
||||||
DestroyThreadWindows(Thread);
|
DestroyThreadWindows(Thread);
|
||||||
IntBlockInput(Win32Thread, FALSE);
|
IntBlockInput(Win32Thread, FALSE);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $Id: caret.c,v 1.16 2004/12/25 22:59:10 navaraf Exp $
|
/* $Id: caret.c,v 1.17 2004/12/29 19:55:01 gvg Exp $
|
||||||
*
|
*
|
||||||
* COPYRIGHT: See COPYING in the top level directory
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
* PROJECT: ReactOS kernel
|
* PROJECT: ReactOS kernel
|
||||||
|
@ -240,7 +240,7 @@ NtUserCreateCaret(
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
IntRemoveTimer(hWnd, IDCARETTIMER, PsGetCurrentThreadId(), TRUE);
|
IntKillTimer(hWnd, IDCARETTIMER, TRUE);
|
||||||
|
|
||||||
ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
|
ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
|
||||||
|
|
||||||
|
@ -325,7 +325,7 @@ NtUserHideCaret(
|
||||||
|
|
||||||
if(ThreadQueue->CaretInfo->Visible)
|
if(ThreadQueue->CaretInfo->Visible)
|
||||||
{
|
{
|
||||||
IntRemoveTimer(hWnd, IDCARETTIMER, PsGetCurrentThreadId(), TRUE);
|
IntKillTimer(hWnd, IDCARETTIMER, TRUE);
|
||||||
|
|
||||||
IntHideCaret(ThreadQueue->CaretInfo);
|
IntHideCaret(ThreadQueue->CaretInfo);
|
||||||
ThreadQueue->CaretInfo->Visible = 0;
|
ThreadQueue->CaretInfo->Visible = 0;
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
/* $Id: message.c,v 1.78 2004/12/25 22:59:10 navaraf Exp $
|
/* $Id: message.c,v 1.79 2004/12/29 19:55:01 gvg Exp $
|
||||||
*
|
*
|
||||||
* COPYRIGHT: See COPYING in the top level directory
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
* PROJECT: ReactOS kernel
|
* PROJECT: ReactOS kernel
|
||||||
|
@ -690,7 +690,14 @@ IntPeekMessage(PUSER_MESSAGE Msg,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME - get WM_(SYS)TIMER messages */
|
/* Check for WM_(SYS)TIMER messages */
|
||||||
|
Present = MsqGetTimerMessage(ThreadQueue, Wnd, MsgFilterMin, MsgFilterMax,
|
||||||
|
&Msg->Msg, RemoveMessages);
|
||||||
|
if (Present)
|
||||||
|
{
|
||||||
|
Msg->FreeLParam = FALSE;
|
||||||
|
goto MessageFound;
|
||||||
|
}
|
||||||
|
|
||||||
if(Present)
|
if(Present)
|
||||||
{
|
{
|
||||||
|
@ -862,9 +869,9 @@ IntWaitMessage(HWND Wnd,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Nothing found. Wait for new messages. */
|
/* Nothing found. Wait for new messages. */
|
||||||
Status = MsqWaitForNewMessages(ThreadQueue);
|
Status = MsqWaitForNewMessages(ThreadQueue, Wnd, MsgFilterMin, MsgFilterMax);
|
||||||
}
|
}
|
||||||
while (STATUS_WAIT_0 <= Status && Status <= STATUS_WAIT_63);
|
while ((STATUS_WAIT_0 <= Status && Status <= STATUS_WAIT_63) || STATUS_TIMEOUT == Status);
|
||||||
|
|
||||||
SetLastNtError(Status);
|
SetLastNtError(Status);
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
/* $Id: msgqueue.c,v 1.111 2004/12/25 22:59:10 navaraf Exp $
|
/* $Id: msgqueue.c,v 1.112 2004/12/29 19:55:01 gvg Exp $
|
||||||
*
|
*
|
||||||
* COPYRIGHT: See COPYING in the top level directory
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
* PROJECT: ReactOS kernel
|
* PROJECT: ReactOS kernel
|
||||||
|
@ -53,6 +53,7 @@ static KMUTEX HardwareMessageQueueLock;
|
||||||
static KEVENT HardwareMessageEvent;
|
static KEVENT HardwareMessageEvent;
|
||||||
|
|
||||||
static PAGED_LOOKASIDE_LIST MessageLookasideList;
|
static PAGED_LOOKASIDE_LIST MessageLookasideList;
|
||||||
|
static PAGED_LOOKASIDE_LIST TimerLookasideList;
|
||||||
|
|
||||||
#define IntLockSystemMessageQueue(OldIrql) \
|
#define IntLockSystemMessageQueue(OldIrql) \
|
||||||
KeAcquireSpinLock(&SystemMessageQueueLock, &OldIrql)
|
KeAcquireSpinLock(&SystemMessageQueueLock, &OldIrql)
|
||||||
|
@ -145,6 +146,13 @@ MsqInitializeImpl(VOID)
|
||||||
sizeof(USER_MESSAGE),
|
sizeof(USER_MESSAGE),
|
||||||
0,
|
0,
|
||||||
256);
|
256);
|
||||||
|
ExInitializePagedLookasideList(&TimerLookasideList,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
sizeof(TIMER_ENTRY),
|
||||||
|
0,
|
||||||
|
64);
|
||||||
|
|
||||||
return(STATUS_SUCCESS);
|
return(STATUS_SUCCESS);
|
||||||
}
|
}
|
||||||
|
@ -1195,16 +1203,29 @@ MsqFindMessage(IN PUSER_MESSAGE_QUEUE MessageQueue,
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS FASTCALL
|
NTSTATUS FASTCALL
|
||||||
MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue)
|
MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue, HWND WndFilter,
|
||||||
|
UINT MsgFilterMin, UINT MsgFilterMax)
|
||||||
{
|
{
|
||||||
PVOID WaitObjects[2] = {MessageQueue->NewMessages, &HardwareMessageEvent};
|
PVOID WaitObjects[2] = {MessageQueue->NewMessages, &HardwareMessageEvent};
|
||||||
|
LARGE_INTEGER TimerExpiry;
|
||||||
|
PLARGE_INTEGER Timeout;
|
||||||
|
|
||||||
|
if (MsqGetFirstTimerExpiry(MessageQueue, WndFilter, MsgFilterMin, MsgFilterMax, &TimerExpiry))
|
||||||
|
{
|
||||||
|
Timeout = &TimerExpiry;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Timeout = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return(KeWaitForMultipleObjects(2,
|
return(KeWaitForMultipleObjects(2,
|
||||||
WaitObjects,
|
WaitObjects,
|
||||||
WaitAny,
|
WaitAny,
|
||||||
Executive,
|
Executive,
|
||||||
UserMode,
|
UserMode,
|
||||||
FALSE,
|
FALSE,
|
||||||
NULL,
|
Timeout,
|
||||||
NULL));
|
NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1228,6 +1249,7 @@ MsqInitializeMessageQueue(struct _ETHREAD *Thread, PUSER_MESSAGE_QUEUE MessageQu
|
||||||
InitializeListHead(&MessageQueue->PostedMessagesListHead);
|
InitializeListHead(&MessageQueue->PostedMessagesListHead);
|
||||||
InitializeListHead(&MessageQueue->SentMessagesListHead);
|
InitializeListHead(&MessageQueue->SentMessagesListHead);
|
||||||
InitializeListHead(&MessageQueue->HardwareMessagesListHead);
|
InitializeListHead(&MessageQueue->HardwareMessagesListHead);
|
||||||
|
InitializeListHead(&MessageQueue->TimerListHead);
|
||||||
InitializeListHead(&MessageQueue->DispatchingMessagesHead);
|
InitializeListHead(&MessageQueue->DispatchingMessagesHead);
|
||||||
InitializeListHead(&MessageQueue->LocalDispatchingMessagesHead);
|
InitializeListHead(&MessageQueue->LocalDispatchingMessagesHead);
|
||||||
KeInitializeMutex(&MessageQueue->HardwareLock, 0);
|
KeInitializeMutex(&MessageQueue->HardwareLock, 0);
|
||||||
|
@ -1267,6 +1289,7 @@ MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
|
||||||
{
|
{
|
||||||
PLIST_ENTRY CurrentEntry;
|
PLIST_ENTRY CurrentEntry;
|
||||||
PUSER_MESSAGE CurrentMessage;
|
PUSER_MESSAGE CurrentMessage;
|
||||||
|
PTIMER_ENTRY CurrentTimer;
|
||||||
PUSER_SENT_MESSAGE CurrentSentMessage;
|
PUSER_SENT_MESSAGE CurrentSentMessage;
|
||||||
|
|
||||||
IntLockMessageQueue(MessageQueue);
|
IntLockMessageQueue(MessageQueue);
|
||||||
|
@ -1311,6 +1334,14 @@ MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
|
||||||
ExFreePool(CurrentSentMessage);
|
ExFreePool(CurrentSentMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* cleanup timers */
|
||||||
|
while (! IsListEmpty(&MessageQueue->TimerListHead))
|
||||||
|
{
|
||||||
|
CurrentEntry = RemoveHeadList(&MessageQueue->TimerListHead);
|
||||||
|
CurrentTimer = CONTAINING_RECORD(CurrentEntry, TIMER_ENTRY, ListEntry);
|
||||||
|
ExFreeToPagedLookasideList(&TimerLookasideList, CurrentTimer);
|
||||||
|
}
|
||||||
|
|
||||||
/* notify senders of dispatching messages. This needs to be cleaned up if e.g.
|
/* notify senders of dispatching messages. This needs to be cleaned up if e.g.
|
||||||
ExitThread() was called in a SendMessage() umode callback */
|
ExitThread() was called in a SendMessage() umode callback */
|
||||||
while (!IsListEmpty(&MessageQueue->LocalDispatchingMessagesHead))
|
while (!IsListEmpty(&MessageQueue->LocalDispatchingMessagesHead))
|
||||||
|
@ -1476,4 +1507,300 @@ MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue, ULONG Type, HWND hWnd)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
static VOID FASTCALL
|
||||||
|
DumpTimerList(PUSER_MESSAGE_QUEUE MessageQueue)
|
||||||
|
{
|
||||||
|
PLIST_ENTRY Current;
|
||||||
|
PTIMER_ENTRY Timer;
|
||||||
|
|
||||||
|
Current = MessageQueue->TimerListHead.Flink;
|
||||||
|
if (Current == &MessageQueue->TimerListHead)
|
||||||
|
{
|
||||||
|
DPRINT("timer list is empty for queue %p\n", MessageQueue);
|
||||||
|
}
|
||||||
|
while (Current != &MessageQueue->TimerListHead)
|
||||||
|
{
|
||||||
|
Timer = CONTAINING_RECORD(Current, TIMER_ENTRY, ListEntry);
|
||||||
|
DPRINT("queue %p timer %p expiry %I64d wnd %x id %p period %u timerproc %p msg %u\n",
|
||||||
|
MessageQueue, Timer, Timer->ExpiryTime.QuadPart, Timer->Wnd, Timer->IDEvent,
|
||||||
|
Timer->Period, Timer->TimerFunc, Timer->Msg);
|
||||||
|
Current = Current->Flink;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* ! defined(NDEBUG) */
|
||||||
|
|
||||||
|
/* Must have the message queue locked while calling this */
|
||||||
|
static VOID FASTCALL
|
||||||
|
InsertTimer(PUSER_MESSAGE_QUEUE MessageQueue, PTIMER_ENTRY NewTimer)
|
||||||
|
{
|
||||||
|
PLIST_ENTRY Current;
|
||||||
|
|
||||||
|
Current = MessageQueue->TimerListHead.Flink;
|
||||||
|
while (Current != &MessageQueue->TimerListHead)
|
||||||
|
{
|
||||||
|
if (NewTimer->ExpiryTime.QuadPart <
|
||||||
|
CONTAINING_RECORD(Current, TIMER_ENTRY, ListEntry)->ExpiryTime.QuadPart)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Current = Current->Flink;
|
||||||
|
}
|
||||||
|
|
||||||
|
InsertTailList(Current, &NewTimer->ListEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Must have the message queue locked while calling this */
|
||||||
|
static PTIMER_ENTRY FASTCALL
|
||||||
|
RemoveTimer(PUSER_MESSAGE_QUEUE MessageQueue, HWND Wnd, UINT_PTR IDEvent, UINT Msg)
|
||||||
|
{
|
||||||
|
PTIMER_ENTRY Timer;
|
||||||
|
PLIST_ENTRY EnumEntry;
|
||||||
|
|
||||||
|
/* Remove timer if already in the queue */
|
||||||
|
EnumEntry = MessageQueue->TimerListHead.Flink;
|
||||||
|
while (EnumEntry != &MessageQueue->TimerListHead)
|
||||||
|
{
|
||||||
|
Timer = CONTAINING_RECORD(EnumEntry, TIMER_ENTRY, ListEntry);
|
||||||
|
EnumEntry = EnumEntry->Flink;
|
||||||
|
|
||||||
|
if (Timer->Wnd == Wnd &&
|
||||||
|
Timer->IDEvent == IDEvent &&
|
||||||
|
Timer->Msg == Msg)
|
||||||
|
{
|
||||||
|
RemoveEntryList(&Timer->ListEntry);
|
||||||
|
return Timer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOLEAN FASTCALL
|
||||||
|
MsqSetTimer(PUSER_MESSAGE_QUEUE MessageQueue, HWND Wnd,
|
||||||
|
UINT_PTR IDEvent, UINT Period, TIMERPROC TimerFunc,
|
||||||
|
UINT Msg)
|
||||||
|
{
|
||||||
|
PTIMER_ENTRY Timer;
|
||||||
|
LARGE_INTEGER CurrentTime;
|
||||||
|
|
||||||
|
DPRINT("MsqSetTimer queue %p wnd %x id %p period %u timerproc %p msg %d\n",
|
||||||
|
MessageQueue, Wnd, IDEvent, Period, TimerFunc, Msg);
|
||||||
|
|
||||||
|
IntLockMessageQueue(MessageQueue);
|
||||||
|
Timer = RemoveTimer(MessageQueue, Wnd, IDEvent, Msg);
|
||||||
|
if (NULL == Timer)
|
||||||
|
{
|
||||||
|
Timer = ExAllocateFromPagedLookasideList(&TimerLookasideList);
|
||||||
|
if (NULL == Timer)
|
||||||
|
{
|
||||||
|
IntUnLockMessageQueue(MessageQueue);
|
||||||
|
DPRINT1("Failed to allocate timer entry\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
DPRINT("Allocated new timer entry %p\n", Timer);
|
||||||
|
Timer->Wnd = Wnd;
|
||||||
|
Timer->IDEvent = IDEvent;
|
||||||
|
Timer->Msg = Msg;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DPRINT("Updating existing timer entry %p\n", Timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
KeQuerySystemTime(&CurrentTime);
|
||||||
|
Timer->ExpiryTime.QuadPart = CurrentTime.QuadPart +
|
||||||
|
(ULONGLONG) Period * (ULONGLONG) 10000;
|
||||||
|
Timer->Period = Period;
|
||||||
|
Timer->TimerFunc = TimerFunc;
|
||||||
|
DPRINT("Insert timer now %I64d expiry %I64d\n", CurrentTime.QuadPart,
|
||||||
|
Timer->ExpiryTime.QuadPart);
|
||||||
|
|
||||||
|
InsertTimer(MessageQueue, Timer);
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
DumpTimerList(MessageQueue);
|
||||||
|
#endif /* ! defined(NDEBUG) */
|
||||||
|
|
||||||
|
IntUnLockMessageQueue(MessageQueue);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOLEAN FASTCALL
|
||||||
|
MsqKillTimer(PUSER_MESSAGE_QUEUE MessageQueue, HWND Wnd,
|
||||||
|
UINT_PTR IDEvent, UINT Msg)
|
||||||
|
{
|
||||||
|
PTIMER_ENTRY Timer;
|
||||||
|
|
||||||
|
DPRINT("MsqKillTimer queue %p wnd %x id %p msg %d\n",
|
||||||
|
MessageQueue, Wnd, IDEvent, Msg);
|
||||||
|
|
||||||
|
IntLockMessageQueue(MessageQueue);
|
||||||
|
Timer = RemoveTimer(MessageQueue, Wnd, IDEvent, Msg);
|
||||||
|
|
||||||
|
if (NULL == Timer)
|
||||||
|
{
|
||||||
|
DPRINT("Failed to remove timer from list, not found\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ExFreeToPagedLookasideList(&TimerLookasideList, Timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
DumpTimerList(MessageQueue);
|
||||||
|
#endif /* ! defined(NDEBUG) */
|
||||||
|
|
||||||
|
IntUnLockMessageQueue(MessageQueue);
|
||||||
|
|
||||||
|
return NULL != Timer;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOLEAN FASTCALL
|
||||||
|
MsqGetTimerMessage(PUSER_MESSAGE_QUEUE MessageQueue,
|
||||||
|
HWND WndFilter, UINT MsgFilterMin, UINT MsgFilterMax,
|
||||||
|
MSG *Msg, BOOLEAN Restart)
|
||||||
|
{
|
||||||
|
PTIMER_ENTRY Timer;
|
||||||
|
LARGE_INTEGER CurrentTime;
|
||||||
|
PLIST_ENTRY EnumEntry;
|
||||||
|
BOOLEAN GotMessage;
|
||||||
|
|
||||||
|
DPRINT("MsqGetTimerMessage queue %p msg %p restart %s\n",
|
||||||
|
MessageQueue, Msg, Restart ? "TRUE" : "FALSE");
|
||||||
|
|
||||||
|
IntLockMessageQueue(MessageQueue);
|
||||||
|
KeQuerySystemTime(&CurrentTime);
|
||||||
|
DPRINT("Current time %I64d\n", CurrentTime.QuadPart);
|
||||||
|
EnumEntry = MessageQueue->TimerListHead.Flink;
|
||||||
|
GotMessage = FALSE;
|
||||||
|
while (EnumEntry != &MessageQueue->TimerListHead)
|
||||||
|
{
|
||||||
|
Timer = CONTAINING_RECORD(MessageQueue->TimerListHead.Flink,
|
||||||
|
TIMER_ENTRY, ListEntry);
|
||||||
|
DPRINT("Checking timer %p wnd %x expiry %I64d\n", Timer, Timer->wnd,
|
||||||
|
Timer->ExpiryTime.QuadPart);
|
||||||
|
EnumEntry = EnumEntry->Flink;
|
||||||
|
if ((NULL == WndFilter || Timer->Wnd == WndFilter) &&
|
||||||
|
((MsgFilterMin == 0 && MsgFilterMax == 0) ||
|
||||||
|
(MsgFilterMin <= Timer->Msg &&
|
||||||
|
Timer->Msg <= MsgFilterMax)))
|
||||||
|
{
|
||||||
|
if (Timer->ExpiryTime.QuadPart <= CurrentTime.QuadPart)
|
||||||
|
{
|
||||||
|
DPRINT("Timer is expired\n");
|
||||||
|
GotMessage = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DPRINT("No need to check later timers\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DPRINT("timer %p (wnd %x msg %d) failed filter wnd %x msgmin %d msgmax %d\n",
|
||||||
|
Timer, Timer->Wnd, Timer->Msg, WndFilter, MsgFilterMin, MsgFilterMax);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! GotMessage)
|
||||||
|
{
|
||||||
|
DPRINT("No timer pending\n");
|
||||||
|
IntUnLockMessageQueue(MessageQueue);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Msg->hwnd = Timer->Wnd;
|
||||||
|
Msg->message = Timer->Msg;
|
||||||
|
Msg->wParam = (WPARAM) Timer->IDEvent;
|
||||||
|
Msg->lParam = (LPARAM) Timer->TimerFunc;
|
||||||
|
|
||||||
|
if (Restart)
|
||||||
|
{
|
||||||
|
RemoveEntryList(&Timer->ListEntry);
|
||||||
|
Timer->ExpiryTime.QuadPart = CurrentTime.QuadPart +
|
||||||
|
(ULONGLONG) Timer->Period * (ULONGLONG) 10000;
|
||||||
|
DPRINT("Restarting timer %p expires %I64d\n", Timer, Timer->ExpiryTime.QuadPart);
|
||||||
|
InsertTimer(MessageQueue, Timer);
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
DumpTimerList(MessageQueue);
|
||||||
|
#endif /* ! defined(NDEBUG) */
|
||||||
|
}
|
||||||
|
|
||||||
|
IntUnLockMessageQueue(MessageQueue);
|
||||||
|
|
||||||
|
DPRINT("Created message wnd %x msg %d wParam %u lParam %u\n", Msg->hwnd, Msg->message,
|
||||||
|
Msg->wParam, Msg->lParam);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID FASTCALL
|
||||||
|
MsqRemoveTimersWindow(PUSER_MESSAGE_QUEUE MessageQueue, HWND Wnd)
|
||||||
|
{
|
||||||
|
PTIMER_ENTRY Timer;
|
||||||
|
PLIST_ENTRY EnumEntry;
|
||||||
|
|
||||||
|
DPRINT("MsqRemoveTimersWindow queue %p wnd %x\n", MessageQueue, Wnd);
|
||||||
|
|
||||||
|
IntLockMessageQueue(MessageQueue);
|
||||||
|
EnumEntry = MessageQueue->TimerListHead.Flink;
|
||||||
|
while (EnumEntry != &MessageQueue->TimerListHead)
|
||||||
|
{
|
||||||
|
Timer = CONTAINING_RECORD(EnumEntry, TIMER_ENTRY, ListEntry);
|
||||||
|
EnumEntry = EnumEntry->Flink;
|
||||||
|
if (Timer->Wnd == Wnd)
|
||||||
|
{
|
||||||
|
DPRINT("Removing timer %p because its window is going away\n", Timer);
|
||||||
|
RemoveEntryList(&Timer->ListEntry);
|
||||||
|
ExFreeToPagedLookasideList(&TimerLookasideList, Timer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
DumpTimerList(MessageQueue);
|
||||||
|
#endif /* ! defined(NDEBUG) */
|
||||||
|
|
||||||
|
IntUnLockMessageQueue(MessageQueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOLEAN FASTCALL
|
||||||
|
MsqGetFirstTimerExpiry(PUSER_MESSAGE_QUEUE MessageQueue,
|
||||||
|
HWND WndFilter, UINT MsgFilterMin, UINT MsgFilterMax,
|
||||||
|
PLARGE_INTEGER FirstTimerExpiry)
|
||||||
|
{
|
||||||
|
PTIMER_ENTRY Timer;
|
||||||
|
PLIST_ENTRY EnumEntry;
|
||||||
|
|
||||||
|
DPRINT("MsqGetFirstTimerExpiry queue %p wndfilter %x msgfiltermin %d msgfiltermax %d expiry %p\n",
|
||||||
|
MessageQueue, WndFilter, MsgFilterMin, MsgFilterMax, FirstTimerExpiry);
|
||||||
|
|
||||||
|
IntLockMessageQueue(MessageQueue);
|
||||||
|
EnumEntry = MessageQueue->TimerListHead.Flink;
|
||||||
|
while (EnumEntry != &MessageQueue->TimerListHead)
|
||||||
|
{
|
||||||
|
Timer = CONTAINING_RECORD(MessageQueue->TimerListHead.Flink,
|
||||||
|
TIMER_ENTRY, ListEntry);
|
||||||
|
EnumEntry = EnumEntry->Flink;
|
||||||
|
if ((NULL == WndFilter || Timer->Wnd == WndFilter) &&
|
||||||
|
((MsgFilterMin == 0 && MsgFilterMax == 0) ||
|
||||||
|
(MsgFilterMin <= Timer->Msg &&
|
||||||
|
Timer->Msg <= MsgFilterMax)))
|
||||||
|
{
|
||||||
|
*FirstTimerExpiry = Timer->ExpiryTime;
|
||||||
|
DPRINT("First timer expires %I64d\n", Timer->ExpiryTime);
|
||||||
|
IntUnLockMessageQueue(MessageQueue);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IntUnLockMessageQueue(MessageQueue);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
/* $Id: timer.c,v 1.37 2004/12/25 22:59:10 navaraf Exp $
|
/* $Id: timer.c,v 1.38 2004/12/29 19:55:01 gvg Exp $
|
||||||
*
|
*
|
||||||
* COPYRIGHT: See COPYING in the top level directory
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
* PROJECT: ReactOS kernel
|
* PROJECT: ReactOS kernel
|
||||||
|
@ -32,446 +32,165 @@
|
||||||
|
|
||||||
#include <w32k.h>
|
#include <w32k.h>
|
||||||
|
|
||||||
#define NDEBUG
|
#undef NDEBUG
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
|
|
||||||
/* GLOBALS *******************************************************************/
|
/* GLOBALS *******************************************************************/
|
||||||
|
|
||||||
//windows 2000 has room for 32768 window-less timers
|
/* Windows 2000 has room for 32768 window-less timers */
|
||||||
#define NUM_WINDOW_LESS_TIMERS 1024
|
#define NUM_WINDOW_LESS_TIMERS 1024
|
||||||
|
|
||||||
static FAST_MUTEX Mutex;
|
static FAST_MUTEX Mutex;
|
||||||
static LIST_ENTRY TimerListHead;
|
|
||||||
static KTIMER Timer;
|
|
||||||
static RTL_BITMAP WindowLessTimersBitMap;
|
static RTL_BITMAP WindowLessTimersBitMap;
|
||||||
static PVOID WindowLessTimersBitMapBuffer;
|
static PVOID WindowLessTimersBitMapBuffer;
|
||||||
static ULONG HintIndex = 0;
|
static ULONG HintIndex = 0;
|
||||||
static HANDLE MsgTimerThreadHandle;
|
|
||||||
static CLIENT_ID MsgTimerThreadId;
|
|
||||||
|
|
||||||
|
|
||||||
#define IntLockTimerList() \
|
#define IntLockWindowlessTimerBitmap() \
|
||||||
ExAcquireFastMutex(&Mutex)
|
ExAcquireFastMutex(&Mutex)
|
||||||
|
|
||||||
#define IntUnLockTimerList() \
|
#define IntUnlockWindowlessTimerBitmap() \
|
||||||
ExReleaseFastMutex(&Mutex)
|
ExReleaseFastMutex(&Mutex)
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
|
|
||||||
//return true if the new timer became the first entry
|
|
||||||
//must hold mutex while calling this
|
|
||||||
BOOL FASTCALL
|
|
||||||
IntInsertTimerAscendingOrder(PMSG_TIMER_ENTRY NewTimer)
|
|
||||||
{
|
|
||||||
PLIST_ENTRY current;
|
|
||||||
|
|
||||||
current = TimerListHead.Flink;
|
|
||||||
while (current != &TimerListHead)
|
|
||||||
{
|
|
||||||
if (CONTAINING_RECORD(current, MSG_TIMER_ENTRY, ListEntry)->Timeout.QuadPart >=\
|
|
||||||
NewTimer->Timeout.QuadPart)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
current = current->Flink;
|
|
||||||
}
|
|
||||||
|
|
||||||
InsertTailList(current, &NewTimer->ListEntry);
|
|
||||||
|
|
||||||
return TimerListHead.Flink == &NewTimer->ListEntry;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//must hold mutex while calling this
|
|
||||||
PMSG_TIMER_ENTRY FASTCALL
|
|
||||||
IntRemoveTimer(HWND hWnd, UINT_PTR IDEvent, HANDLE ThreadID, BOOL SysTimer)
|
|
||||||
{
|
|
||||||
PMSG_TIMER_ENTRY MsgTimer;
|
|
||||||
PLIST_ENTRY EnumEntry;
|
|
||||||
|
|
||||||
//remove timer if already in the queue
|
|
||||||
EnumEntry = TimerListHead.Flink;
|
|
||||||
while (EnumEntry != &TimerListHead)
|
|
||||||
{
|
|
||||||
MsgTimer = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
|
|
||||||
EnumEntry = EnumEntry->Flink;
|
|
||||||
|
|
||||||
if (MsgTimer->Msg.hwnd == hWnd &&
|
|
||||||
MsgTimer->Msg.wParam == (WPARAM)IDEvent &&
|
|
||||||
MsgTimer->ThreadID == ThreadID &&
|
|
||||||
(MsgTimer->Msg.message == WM_SYSTIMER) == SysTimer)
|
|
||||||
{
|
|
||||||
RemoveEntryList(&MsgTimer->ListEntry);
|
|
||||||
return MsgTimer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* NOTE: It doesn't kill the timer. It just removes them from the list.
|
|
||||||
*/
|
|
||||||
VOID FASTCALL
|
|
||||||
RemoveTimersThread(HANDLE ThreadID)
|
|
||||||
{
|
|
||||||
PMSG_TIMER_ENTRY MsgTimer;
|
|
||||||
PLIST_ENTRY EnumEntry;
|
|
||||||
|
|
||||||
IntLockTimerList();
|
|
||||||
|
|
||||||
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(&WindowLessTimersBitMap, ((UINT_PTR)MsgTimer->Msg.wParam) - 1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
RemoveEntryList(&MsgTimer->ListEntry);
|
|
||||||
ExFreePool(MsgTimer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IntUnLockTimerList();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* NOTE: It doesn't kill the timer. It just removes them from the list.
|
|
||||||
*/
|
|
||||||
VOID FASTCALL
|
|
||||||
RemoveTimersWindow(HWND Wnd)
|
|
||||||
{
|
|
||||||
PMSG_TIMER_ENTRY MsgTimer;
|
|
||||||
PLIST_ENTRY EnumEntry;
|
|
||||||
|
|
||||||
IntLockTimerList();
|
|
||||||
|
|
||||||
EnumEntry = TimerListHead.Flink;
|
|
||||||
while (EnumEntry != &TimerListHead)
|
|
||||||
{
|
|
||||||
MsgTimer = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
|
|
||||||
EnumEntry = EnumEntry->Flink;
|
|
||||||
|
|
||||||
if (MsgTimer->Msg.hwnd == Wnd)
|
|
||||||
{
|
|
||||||
RemoveEntryList(&MsgTimer->ListEntry);
|
|
||||||
ExFreePool(MsgTimer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IntUnLockTimerList();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
UINT_PTR FASTCALL
|
UINT_PTR FASTCALL
|
||||||
IntSetTimer(HWND hWnd, UINT_PTR nIDEvent, UINT uElapse, TIMERPROC lpTimerFunc, BOOL SystemTimer)
|
IntSetTimer(HWND Wnd, UINT_PTR IDEvent, UINT Elapse, TIMERPROC TimerFunc, BOOL SystemTimer)
|
||||||
{
|
{
|
||||||
PMSG_TIMER_ENTRY MsgTimer = NULL;
|
|
||||||
PMSG_TIMER_ENTRY NewTimer;
|
|
||||||
LARGE_INTEGER CurrentTime;
|
|
||||||
PWINDOW_OBJECT WindowObject;
|
PWINDOW_OBJECT WindowObject;
|
||||||
HANDLE ThreadID;
|
|
||||||
UINT_PTR Ret = 0;
|
UINT_PTR Ret = 0;
|
||||||
|
|
||||||
ThreadID = PsGetCurrentThreadId();
|
DPRINT("IntSetTimer wnd %x id %p elapse %u timerproc %p systemtimer %s\n",
|
||||||
KeQuerySystemTime(&CurrentTime);
|
Wnd, IDEvent, Elapse, TimerFunc, SystemTimer ? "TRUE" : "FALSE");
|
||||||
IntLockTimerList();
|
|
||||||
|
|
||||||
if((hWnd == NULL) && !SystemTimer)
|
if ((Wnd == NULL) && ! SystemTimer)
|
||||||
{
|
{
|
||||||
|
DPRINT("Window-less timer\n");
|
||||||
/* find a free, window-less timer id */
|
/* find a free, window-less timer id */
|
||||||
nIDEvent = RtlFindClearBitsAndSet(&WindowLessTimersBitMap, 1, HintIndex);
|
IntLockWindowlessTimerBitmap();
|
||||||
|
IDEvent = RtlFindClearBitsAndSet(&WindowLessTimersBitMap, 1, HintIndex);
|
||||||
|
|
||||||
if(nIDEvent == (UINT_PTR) -1)
|
if (IDEvent == (UINT_PTR) -1)
|
||||||
{
|
{
|
||||||
IntUnLockTimerList();
|
IntUnlockWindowlessTimerBitmap();
|
||||||
|
DPRINT1("Unable to find a free window-less timer id\n");
|
||||||
|
SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
HintIndex = ++nIDEvent;
|
HintIndex = ++IDEvent;
|
||||||
|
IntUnlockWindowlessTimerBitmap();
|
||||||
|
Ret = IDEvent;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WindowObject = IntGetWindowObject(hWnd);
|
WindowObject = IntGetWindowObject(Wnd);
|
||||||
if(!WindowObject)
|
if (! WindowObject)
|
||||||
{
|
{
|
||||||
IntUnLockTimerList();
|
DPRINT1("Invalid window handle\n");
|
||||||
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(WindowObject->OwnerThread != PsGetCurrentThread())
|
if (WindowObject->OwnerThread != PsGetCurrentThread())
|
||||||
{
|
{
|
||||||
IntUnLockTimerList();
|
|
||||||
IntReleaseWindowObject(WindowObject);
|
IntReleaseWindowObject(WindowObject);
|
||||||
|
DPRINT1("Trying to set timer for window in another thread (shatter attack?)\n");
|
||||||
SetLastWin32Error(ERROR_ACCESS_DENIED);
|
SetLastWin32Error(ERROR_ACCESS_DENIED);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
IntReleaseWindowObject(WindowObject);
|
IntReleaseWindowObject(WindowObject);
|
||||||
|
Ret = 1;
|
||||||
/* remove timer if already in the queue */
|
|
||||||
MsgTimer = IntRemoveTimer(hWnd, nIDEvent, ThreadID, SystemTimer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
|
|
||||||
/* Win NT/2k/XP */
|
/* Win NT/2k/XP */
|
||||||
if(uElapse > 0x7fffffff)
|
if (Elapse > 0x7fffffff)
|
||||||
uElapse = 1;
|
{
|
||||||
|
DPRINT("Adjusting uElapse\n");
|
||||||
|
Elapse = 1;
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
/* Win Server 2003 */
|
/* Win Server 2003 */
|
||||||
if(uElapse > 0x7fffffff)
|
if (Elapse > 0x7fffffff)
|
||||||
uElapse = 0x7fffffff;
|
{
|
||||||
|
DPRINT("Adjusting uElapse\n");
|
||||||
|
Elapse = 0x7fffffff;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Win 2k/XP */
|
/* Win 2k/XP */
|
||||||
if(uElapse < 10)
|
if (Elapse < 10)
|
||||||
uElapse = 10;
|
|
||||||
|
|
||||||
if(MsgTimer)
|
|
||||||
{
|
{
|
||||||
/* modify existing (removed) timer */
|
DPRINT("Adjusting uElapse\n");
|
||||||
NewTimer = MsgTimer;
|
Elapse = 10;
|
||||||
|
|
||||||
NewTimer->Period = uElapse;
|
|
||||||
NewTimer->Timeout.QuadPart = CurrentTime.QuadPart + (uElapse * 10000);
|
|
||||||
NewTimer->Msg.lParam = (LPARAM)lpTimerFunc;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (! MsqSetTimer(PsGetWin32Thread()->MessageQueue, Wnd,
|
||||||
|
IDEvent, Elapse, TimerFunc,
|
||||||
|
SystemTimer ? WM_SYSTIMER : WM_TIMER))
|
||||||
{
|
{
|
||||||
/* FIXME: use lookaside? */
|
DPRINT1("Failed to set timer in message queue\n");
|
||||||
NewTimer = ExAllocatePoolWithTag(PagedPool, sizeof(MSG_TIMER_ENTRY), TAG_TIMER);
|
SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
|
||||||
if(!NewTimer)
|
|
||||||
{
|
|
||||||
IntUnLockTimerList();
|
|
||||||
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
|
|
||||||
return 0;
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ret = nIDEvent; // FIXME - return lpTimerProc if it's not a system timer
|
|
||||||
|
|
||||||
if(IntInsertTimerAscendingOrder(NewTimer))
|
|
||||||
{
|
|
||||||
/* new timer is first in queue and expires first */
|
|
||||||
KeSetTimer(&Timer, NewTimer->Timeout, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
IntUnLockTimerList();
|
|
||||||
|
|
||||||
return Ret;
|
return Ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BOOL FASTCALL
|
BOOL FASTCALL
|
||||||
IntKillTimer(HWND hWnd, UINT_PTR uIDEvent, BOOL SystemTimer)
|
IntKillTimer(HWND Wnd, UINT_PTR IDEvent, BOOL SystemTimer)
|
||||||
{
|
{
|
||||||
PMSG_TIMER_ENTRY MsgTimer;
|
DPRINT("IntKillTimer wnd %x id %p systemtimer %s\n",
|
||||||
PWINDOW_OBJECT WindowObject;
|
Wnd, IDEvent, SystemTimer ? "TRUE" : "FALSE");
|
||||||
|
|
||||||
IntLockTimerList();
|
if (! MsqKillTimer(PsGetWin32Thread()->MessageQueue, Wnd,
|
||||||
|
IDEvent, SystemTimer ? WM_SYSTIMER : WM_TIMER))
|
||||||
|
{
|
||||||
|
DPRINT1("Unable to locate timer in message queue\n");
|
||||||
|
SetLastWin32Error(ERROR_INVALID_PARAMETER);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/* window-less timer? */
|
/* window-less timer? */
|
||||||
if((hWnd == NULL) && !SystemTimer)
|
if ((Wnd == NULL) && ! SystemTimer)
|
||||||
{
|
{
|
||||||
if(!RtlAreBitsSet(&WindowLessTimersBitMap, uIDEvent - 1, 1))
|
/* Release the id */
|
||||||
{
|
IntLockWindowlessTimerBitmap();
|
||||||
IntUnLockTimerList();
|
|
||||||
/* bit was not set */
|
|
||||||
/* FIXME: set the last error */
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
RtlClearBits(&WindowLessTimersBitMap, uIDEvent - 1, 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WindowObject = IntGetWindowObject(hWnd);
|
|
||||||
if(!WindowObject)
|
|
||||||
{
|
|
||||||
IntUnLockTimerList();
|
|
||||||
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
if(WindowObject->OwnerThread != PsGetCurrentThread())
|
|
||||||
{
|
|
||||||
IntUnLockTimerList();
|
|
||||||
IntReleaseWindowObject(WindowObject);
|
|
||||||
SetLastWin32Error(ERROR_ACCESS_DENIED);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
IntReleaseWindowObject(WindowObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
MsgTimer = IntRemoveTimer(hWnd, uIDEvent, PsGetCurrentThreadId(), SystemTimer);
|
ASSERT(RtlAreBitsSet(&WindowLessTimersBitMap, IDEvent - 1, 1));
|
||||||
|
RtlClearBits(&WindowLessTimersBitMap, IDEvent - 1, 1);
|
||||||
|
|
||||||
IntUnLockTimerList();
|
IntUnlockWindowlessTimerBitmap();
|
||||||
|
|
||||||
if(MsgTimer == NULL)
|
|
||||||
{
|
|
||||||
/* didn't find timer */
|
|
||||||
/* FIXME: set the last error */
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: use lookaside? */
|
|
||||||
ExFreePool(MsgTimer);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static VOID STDCALL
|
|
||||||
TimerThreadMain(PVOID StartContext)
|
|
||||||
{
|
|
||||||
NTSTATUS Status;
|
|
||||||
LARGE_INTEGER CurrentTime;
|
|
||||||
PLIST_ENTRY EnumEntry;
|
|
||||||
PMSG_TIMER_ENTRY MsgTimer;
|
|
||||||
PETHREAD Thread;
|
|
||||||
PETHREAD *ThreadsToDereference;
|
|
||||||
ULONG ThreadsToDereferenceCount, ThreadsToDereferencePos, i;
|
|
||||||
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
Status = KeWaitForSingleObject(&Timer,
|
|
||||||
Executive,
|
|
||||||
KernelMode,
|
|
||||||
FALSE,
|
|
||||||
NULL);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
DPRINT1("Error waiting in TimerThreadMain\n");
|
|
||||||
KEBUGCHECK(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
ThreadsToDereferenceCount = ThreadsToDereferencePos = 0;
|
|
||||||
|
|
||||||
IntLockTimerList();
|
|
||||||
|
|
||||||
KeQuerySystemTime(&CurrentTime);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ThreadsToDereference = (PETHREAD *)ExAllocatePoolWithTag(
|
|
||||||
NonPagedPool, ThreadsToDereferenceCount * sizeof(PETHREAD), TAG_TIMERTD);
|
|
||||||
|
|
||||||
EnumEntry = TimerListHead.Flink;
|
|
||||||
while (EnumEntry != &TimerListHead)
|
|
||||||
{
|
|
||||||
MsgTimer = CONTAINING_RECORD(EnumEntry, MSG_TIMER_ENTRY, ListEntry);
|
|
||||||
|
|
||||||
if (CurrentTime.QuadPart >= MsgTimer->Timeout.QuadPart)
|
|
||||||
{
|
|
||||||
EnumEntry = EnumEntry->Flink;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
MsqPostMessage(Thread->Tcb.Win32Thread->MessageQueue, &MsgTimer->Msg,
|
|
||||||
FALSE, QS_TIMER);
|
|
||||||
|
|
||||||
ThreadsToDereference[ThreadsToDereferencePos] = Thread;
|
|
||||||
++ThreadsToDereferencePos;
|
|
||||||
|
|
||||||
//set up next periodic timeout
|
|
||||||
//FIXME: is this calculation really necesary (and correct)? -Gunnar
|
|
||||||
do
|
|
||||||
{
|
|
||||||
MsgTimer->Timeout.QuadPart += (MsgTimer->Period * 10000);
|
|
||||||
}
|
|
||||||
while (MsgTimer->Timeout.QuadPart <= CurrentTime.QuadPart);
|
|
||||||
IntInsertTimerAscendingOrder(MsgTimer);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//set up next timeout from first entry (if any)
|
|
||||||
if (!IsListEmpty(&TimerListHead))
|
|
||||||
{
|
|
||||||
MsgTimer = CONTAINING_RECORD( TimerListHead.Flink, MSG_TIMER_ENTRY, ListEntry);
|
|
||||||
KeSetTimer(&Timer, MsgTimer->Timeout, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
IntUnLockTimerList();
|
|
||||||
|
|
||||||
for (i = 0; i < ThreadsToDereferencePos; i++)
|
|
||||||
ObDereferenceObject(ThreadsToDereference[i]);
|
|
||||||
|
|
||||||
ExFreePool(ThreadsToDereference);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NTSTATUS FASTCALL
|
NTSTATUS FASTCALL
|
||||||
InitTimerImpl(VOID)
|
InitTimerImpl(VOID)
|
||||||
{
|
{
|
||||||
NTSTATUS Status;
|
|
||||||
ULONG BitmapBytes;
|
ULONG BitmapBytes;
|
||||||
|
|
||||||
BitmapBytes = ROUND_UP(NUM_WINDOW_LESS_TIMERS, sizeof(ULONG) * 8) / 8;
|
|
||||||
|
|
||||||
InitializeListHead(&TimerListHead);
|
|
||||||
KeInitializeTimerEx(&Timer, SynchronizationTimer);
|
|
||||||
ExInitializeFastMutex(&Mutex);
|
ExInitializeFastMutex(&Mutex);
|
||||||
|
|
||||||
|
BitmapBytes = ROUND_UP(NUM_WINDOW_LESS_TIMERS, sizeof(ULONG) * 8) / 8;
|
||||||
WindowLessTimersBitMapBuffer = ExAllocatePoolWithTag(PagedPool, BitmapBytes, TAG_TIMERBMP);
|
WindowLessTimersBitMapBuffer = ExAllocatePoolWithTag(PagedPool, BitmapBytes, TAG_TIMERBMP);
|
||||||
RtlInitializeBitMap(&WindowLessTimersBitMap,
|
RtlInitializeBitMap(&WindowLessTimersBitMap,
|
||||||
WindowLessTimersBitMapBuffer,
|
WindowLessTimersBitMapBuffer,
|
||||||
BitmapBytes * 8);
|
BitmapBytes * 8);
|
||||||
|
|
||||||
//yes we need this, since ExAllocatePool isn't supposed to zero out allocated memory
|
/* yes we need this, since ExAllocatePool isn't supposed to zero out allocated memory */
|
||||||
RtlClearAllBits(&WindowLessTimersBitMap);
|
RtlClearAllBits(&WindowLessTimersBitMap);
|
||||||
|
|
||||||
Status = PsCreateSystemThread(&MsgTimerThreadHandle,
|
return STATUS_SUCCESS;
|
||||||
THREAD_ALL_ACCESS,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
&MsgTimerThreadId,
|
|
||||||
TimerThreadMain,
|
|
||||||
NULL);
|
|
||||||
return Status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
/* $Id: window.c,v 1.258 2004/12/25 20:30:50 navaraf Exp $
|
/* $Id: window.c,v 1.259 2004/12/29 19:55:01 gvg Exp $
|
||||||
*
|
*
|
||||||
* COPYRIGHT: See COPYING in the top level directory
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
* PROJECT: ReactOS kernel
|
* PROJECT: ReactOS kernel
|
||||||
|
@ -268,7 +268,7 @@ static LRESULT IntDestroyWindow(PWINDOW_OBJECT Window,
|
||||||
|
|
||||||
ASSERT(Window);
|
ASSERT(Window);
|
||||||
|
|
||||||
RemoveTimersWindow(Window->Self);
|
MsqRemoveTimersWindow(ThreadData->MessageQueue, Window->Self);
|
||||||
|
|
||||||
IntLockThreadWindows(Window->OwnerThread->Tcb.Win32Thread);
|
IntLockThreadWindows(Window->OwnerThread->Tcb.Win32Thread);
|
||||||
if(Window->Status & WINDOWSTATUS_DESTROYING)
|
if(Window->Status & WINDOWSTATUS_DESTROYING)
|
||||||
|
|
Loading…
Reference in a new issue