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;
|
||||
} 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
|
||||
{
|
||||
/* Reference counter, only access this variable with interlocked functions! */
|
||||
|
@ -55,6 +65,8 @@ typedef struct _USER_MESSAGE_QUEUE
|
|||
LIST_ENTRY NotifyMessagesListHead;
|
||||
/* Queue for hardware messages for the queue. */
|
||||
LIST_ENTRY HardwareMessagesListHead;
|
||||
/* List of timers, sorted on expiry time (earliest first) */
|
||||
LIST_ENTRY TimerListHead;
|
||||
/* Lock for the hardware message list. */
|
||||
KMUTEX HardwareLock;
|
||||
/* Lock for the queue. */
|
||||
|
@ -144,13 +156,12 @@ MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue);
|
|||
PUSER_MESSAGE_QUEUE FASTCALL
|
||||
MsqGetHardwareMessageQueue(VOID);
|
||||
NTSTATUS FASTCALL
|
||||
MsqWaitForNewMessage(PUSER_MESSAGE_QUEUE MessageQueue);
|
||||
NTSTATUS FASTCALL
|
||||
MsqInitializeImpl(VOID);
|
||||
BOOLEAN FASTCALL
|
||||
MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue);
|
||||
NTSTATUS FASTCALL
|
||||
MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue);
|
||||
MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue, HWND WndFilter,
|
||||
UINT MsgFilterMin, UINT MsgFilterMax);
|
||||
VOID FASTCALL
|
||||
MsqSendNotifyMessage(PUSER_MESSAGE_QUEUE MessageQueue,
|
||||
PUSER_SENT_MESSAGE_NOTIFY NotifyMessage);
|
||||
|
@ -248,6 +259,24 @@ IntMsqSetWakeMask(DWORD WakeMask);
|
|||
BOOL FASTCALL
|
||||
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 */
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -1,18 +1,8 @@
|
|||
#ifndef _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);
|
||||
VOID FASTCALL RemoveTimersThread(HANDLE ThreadID);
|
||||
VOID FASTCALL RemoveTimersWindow(HWND hWnd);
|
||||
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);
|
||||
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);
|
||||
|
||||
#endif /* _WIN32K_TIMER_H */
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* along with this program; if not, write to the Free Software
|
||||
* 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
|
||||
*/
|
||||
|
@ -184,7 +184,6 @@ Win32kThreadCallback (struct _ETHREAD *Thread,
|
|||
|
||||
Win32Thread->IsExiting = TRUE;
|
||||
HOOK_DestroyThreadHooks(Thread);
|
||||
RemoveTimersThread(Win32Thread->MessageQueue);
|
||||
UnregisterThreadHotKeys(Thread);
|
||||
DestroyThreadWindows(Thread);
|
||||
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
|
||||
* PROJECT: ReactOS kernel
|
||||
|
@ -240,7 +240,7 @@ NtUserCreateCaret(
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
IntRemoveTimer(hWnd, IDCARETTIMER, PsGetCurrentThreadId(), TRUE);
|
||||
IntKillTimer(hWnd, IDCARETTIMER, TRUE);
|
||||
|
||||
ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
|
||||
|
||||
|
@ -325,7 +325,7 @@ NtUserHideCaret(
|
|||
|
||||
if(ThreadQueue->CaretInfo->Visible)
|
||||
{
|
||||
IntRemoveTimer(hWnd, IDCARETTIMER, PsGetCurrentThreadId(), TRUE);
|
||||
IntKillTimer(hWnd, IDCARETTIMER, TRUE);
|
||||
|
||||
IntHideCaret(ThreadQueue->CaretInfo);
|
||||
ThreadQueue->CaretInfo->Visible = 0;
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* along with this program; if not, write to the Free Software
|
||||
* 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
|
||||
* PROJECT: ReactOS kernel
|
||||
|
@ -690,7 +690,14 @@ IntPeekMessage(PUSER_MESSAGE Msg,
|
|||
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)
|
||||
{
|
||||
|
@ -862,9 +869,9 @@ IntWaitMessage(HWND Wnd,
|
|||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* along with this program; if not, write to the Free Software
|
||||
* 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
|
||||
* PROJECT: ReactOS kernel
|
||||
|
@ -53,6 +53,7 @@ static KMUTEX HardwareMessageQueueLock;
|
|||
static KEVENT HardwareMessageEvent;
|
||||
|
||||
static PAGED_LOOKASIDE_LIST MessageLookasideList;
|
||||
static PAGED_LOOKASIDE_LIST TimerLookasideList;
|
||||
|
||||
#define IntLockSystemMessageQueue(OldIrql) \
|
||||
KeAcquireSpinLock(&SystemMessageQueueLock, &OldIrql)
|
||||
|
@ -145,6 +146,13 @@ MsqInitializeImpl(VOID)
|
|||
sizeof(USER_MESSAGE),
|
||||
0,
|
||||
256);
|
||||
ExInitializePagedLookasideList(&TimerLookasideList,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
sizeof(TIMER_ENTRY),
|
||||
0,
|
||||
64);
|
||||
|
||||
return(STATUS_SUCCESS);
|
||||
}
|
||||
|
@ -1195,16 +1203,29 @@ MsqFindMessage(IN PUSER_MESSAGE_QUEUE MessageQueue,
|
|||
}
|
||||
|
||||
NTSTATUS FASTCALL
|
||||
MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue)
|
||||
MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue, HWND WndFilter,
|
||||
UINT MsgFilterMin, UINT MsgFilterMax)
|
||||
{
|
||||
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,
|
||||
WaitObjects,
|
||||
WaitAny,
|
||||
Executive,
|
||||
UserMode,
|
||||
FALSE,
|
||||
NULL,
|
||||
Timeout,
|
||||
NULL));
|
||||
}
|
||||
|
||||
|
@ -1228,6 +1249,7 @@ MsqInitializeMessageQueue(struct _ETHREAD *Thread, PUSER_MESSAGE_QUEUE MessageQu
|
|||
InitializeListHead(&MessageQueue->PostedMessagesListHead);
|
||||
InitializeListHead(&MessageQueue->SentMessagesListHead);
|
||||
InitializeListHead(&MessageQueue->HardwareMessagesListHead);
|
||||
InitializeListHead(&MessageQueue->TimerListHead);
|
||||
InitializeListHead(&MessageQueue->DispatchingMessagesHead);
|
||||
InitializeListHead(&MessageQueue->LocalDispatchingMessagesHead);
|
||||
KeInitializeMutex(&MessageQueue->HardwareLock, 0);
|
||||
|
@ -1267,6 +1289,7 @@ MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
|
|||
{
|
||||
PLIST_ENTRY CurrentEntry;
|
||||
PUSER_MESSAGE CurrentMessage;
|
||||
PTIMER_ENTRY CurrentTimer;
|
||||
PUSER_SENT_MESSAGE CurrentSentMessage;
|
||||
|
||||
IntLockMessageQueue(MessageQueue);
|
||||
|
@ -1311,6 +1334,14 @@ MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
|
|||
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.
|
||||
ExitThread() was called in a SendMessage() umode callback */
|
||||
while (!IsListEmpty(&MessageQueue->LocalDispatchingMessagesHead))
|
||||
|
@ -1476,4 +1507,300 @@ MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue, ULONG Type, HWND hWnd)
|
|||
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 */
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* along with this program; if not, write to the Free Software
|
||||
* 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
|
||||
* PROJECT: ReactOS kernel
|
||||
|
@ -32,446 +32,165 @@
|
|||
|
||||
#include <w32k.h>
|
||||
|
||||
#define NDEBUG
|
||||
#undef NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
/* 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
|
||||
|
||||
static FAST_MUTEX Mutex;
|
||||
static LIST_ENTRY TimerListHead;
|
||||
static KTIMER Timer;
|
||||
static RTL_BITMAP WindowLessTimersBitMap;
|
||||
static PVOID WindowLessTimersBitMapBuffer;
|
||||
static ULONG HintIndex = 0;
|
||||
static HANDLE MsgTimerThreadHandle;
|
||||
static CLIENT_ID MsgTimerThreadId;
|
||||
|
||||
|
||||
#define IntLockTimerList() \
|
||||
#define IntLockWindowlessTimerBitmap() \
|
||||
ExAcquireFastMutex(&Mutex)
|
||||
|
||||
#define IntUnLockTimerList() \
|
||||
#define IntUnlockWindowlessTimerBitmap() \
|
||||
ExReleaseFastMutex(&Mutex)
|
||||
|
||||
/* 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
|
||||
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;
|
||||
HANDLE ThreadID;
|
||||
UINT_PTR Ret = 0;
|
||||
|
||||
ThreadID = PsGetCurrentThreadId();
|
||||
KeQuerySystemTime(&CurrentTime);
|
||||
IntLockTimerList();
|
||||
DPRINT("IntSetTimer wnd %x id %p elapse %u timerproc %p systemtimer %s\n",
|
||||
Wnd, IDEvent, Elapse, TimerFunc, SystemTimer ? "TRUE" : "FALSE");
|
||||
|
||||
if((hWnd == NULL) && !SystemTimer)
|
||||
if ((Wnd == NULL) && ! SystemTimer)
|
||||
{
|
||||
DPRINT("Window-less timer\n");
|
||||
/* 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;
|
||||
}
|
||||
|
||||
HintIndex = ++nIDEvent;
|
||||
HintIndex = ++IDEvent;
|
||||
IntUnlockWindowlessTimerBitmap();
|
||||
Ret = IDEvent;
|
||||
}
|
||||
else
|
||||
{
|
||||
WindowObject = IntGetWindowObject(hWnd);
|
||||
WindowObject = IntGetWindowObject(Wnd);
|
||||
if (! WindowObject)
|
||||
{
|
||||
IntUnLockTimerList();
|
||||
DPRINT1("Invalid window handle\n");
|
||||
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (WindowObject->OwnerThread != PsGetCurrentThread())
|
||||
{
|
||||
IntUnLockTimerList();
|
||||
IntReleaseWindowObject(WindowObject);
|
||||
DPRINT1("Trying to set timer for window in another thread (shatter attack?)\n");
|
||||
SetLastWin32Error(ERROR_ACCESS_DENIED);
|
||||
return 0;
|
||||
}
|
||||
IntReleaseWindowObject(WindowObject);
|
||||
|
||||
/* remove timer if already in the queue */
|
||||
MsgTimer = IntRemoveTimer(hWnd, nIDEvent, ThreadID, SystemTimer);
|
||||
Ret = 1;
|
||||
}
|
||||
|
||||
#if 1
|
||||
|
||||
/* Win NT/2k/XP */
|
||||
if(uElapse > 0x7fffffff)
|
||||
uElapse = 1;
|
||||
if (Elapse > 0x7fffffff)
|
||||
{
|
||||
DPRINT("Adjusting uElapse\n");
|
||||
Elapse = 1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* Win Server 2003 */
|
||||
if(uElapse > 0x7fffffff)
|
||||
uElapse = 0x7fffffff;
|
||||
if (Elapse > 0x7fffffff)
|
||||
{
|
||||
DPRINT("Adjusting uElapse\n");
|
||||
Elapse = 0x7fffffff;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Win 2k/XP */
|
||||
if(uElapse < 10)
|
||||
uElapse = 10;
|
||||
|
||||
if(MsgTimer)
|
||||
if (Elapse < 10)
|
||||
{
|
||||
/* modify existing (removed) timer */
|
||||
NewTimer = MsgTimer;
|
||||
|
||||
NewTimer->Period = uElapse;
|
||||
NewTimer->Timeout.QuadPart = CurrentTime.QuadPart + (uElapse * 10000);
|
||||
NewTimer->Msg.lParam = (LPARAM)lpTimerFunc;
|
||||
DPRINT("Adjusting uElapse\n");
|
||||
Elapse = 10;
|
||||
}
|
||||
else
|
||||
|
||||
if (! MsqSetTimer(PsGetWin32Thread()->MessageQueue, Wnd,
|
||||
IDEvent, Elapse, TimerFunc,
|
||||
SystemTimer ? WM_SYSTIMER : WM_TIMER))
|
||||
{
|
||||
/* FIXME: use lookaside? */
|
||||
NewTimer = ExAllocatePoolWithTag(PagedPool, sizeof(MSG_TIMER_ENTRY), TAG_TIMER);
|
||||
if(!NewTimer)
|
||||
{
|
||||
IntUnLockTimerList();
|
||||
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
|
||||
DPRINT1("Failed to set timer in message queue\n");
|
||||
SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
BOOL FASTCALL
|
||||
IntKillTimer(HWND hWnd, UINT_PTR uIDEvent, BOOL SystemTimer)
|
||||
IntKillTimer(HWND Wnd, UINT_PTR IDEvent, BOOL SystemTimer)
|
||||
{
|
||||
PMSG_TIMER_ENTRY MsgTimer;
|
||||
PWINDOW_OBJECT WindowObject;
|
||||
DPRINT("IntKillTimer wnd %x id %p systemtimer %s\n",
|
||||
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? */
|
||||
if((hWnd == NULL) && !SystemTimer)
|
||||
if ((Wnd == NULL) && ! SystemTimer)
|
||||
{
|
||||
if(!RtlAreBitsSet(&WindowLessTimersBitMap, uIDEvent - 1, 1))
|
||||
{
|
||||
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);
|
||||
}
|
||||
/* Release the id */
|
||||
IntLockWindowlessTimerBitmap();
|
||||
|
||||
MsgTimer = IntRemoveTimer(hWnd, uIDEvent, PsGetCurrentThreadId(), SystemTimer);
|
||||
ASSERT(RtlAreBitsSet(&WindowLessTimersBitMap, IDEvent - 1, 1));
|
||||
RtlClearBits(&WindowLessTimersBitMap, IDEvent - 1, 1);
|
||||
|
||||
IntUnLockTimerList();
|
||||
|
||||
if(MsgTimer == NULL)
|
||||
{
|
||||
/* didn't find timer */
|
||||
/* FIXME: set the last error */
|
||||
return FALSE;
|
||||
IntUnlockWindowlessTimerBitmap();
|
||||
}
|
||||
|
||||
/* FIXME: use lookaside? */
|
||||
ExFreePool(MsgTimer);
|
||||
|
||||
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
|
||||
InitTimerImpl(VOID)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
ULONG BitmapBytes;
|
||||
|
||||
BitmapBytes = ROUND_UP(NUM_WINDOW_LESS_TIMERS, sizeof(ULONG) * 8) / 8;
|
||||
|
||||
InitializeListHead(&TimerListHead);
|
||||
KeInitializeTimerEx(&Timer, SynchronizationTimer);
|
||||
ExInitializeFastMutex(&Mutex);
|
||||
|
||||
BitmapBytes = ROUND_UP(NUM_WINDOW_LESS_TIMERS, sizeof(ULONG) * 8) / 8;
|
||||
WindowLessTimersBitMapBuffer = ExAllocatePoolWithTag(PagedPool, BitmapBytes, TAG_TIMERBMP);
|
||||
RtlInitializeBitMap(&WindowLessTimersBitMap,
|
||||
WindowLessTimersBitMapBuffer,
|
||||
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);
|
||||
|
||||
Status = PsCreateSystemThread(&MsgTimerThreadHandle,
|
||||
THREAD_ALL_ACCESS,
|
||||
NULL,
|
||||
NULL,
|
||||
&MsgTimerThreadId,
|
||||
TimerThreadMain,
|
||||
NULL);
|
||||
return Status;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* along with this program; if not, write to the Free Software
|
||||
* 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
|
||||
* PROJECT: ReactOS kernel
|
||||
|
@ -268,7 +268,7 @@ static LRESULT IntDestroyWindow(PWINDOW_OBJECT Window,
|
|||
|
||||
ASSERT(Window);
|
||||
|
||||
RemoveTimersWindow(Window->Self);
|
||||
MsqRemoveTimersWindow(ThreadData->MessageQueue, Window->Self);
|
||||
|
||||
IntLockThreadWindows(Window->OwnerThread->Tcb.Win32Thread);
|
||||
if(Window->Status & WINDOWSTATUS_DESTROYING)
|
||||
|
|
Loading…
Reference in a new issue