- Fixed WaitForInputIdle, finally!, passed all the wine tests for it.
- Moved Get/Peek message to the new all in one support routine.
- Foreground hook hits one out of five, this needs more research.
- Attempted to workout synchronizing issues with low level and regular hooks.

svn path=/trunk/; revision=49579
This commit is contained in:
James Tabor 2010-11-14 00:27:38 +00:00
parent ea5d462bdf
commit 31efb355c9
3 changed files with 138 additions and 155 deletions

View file

@ -103,6 +103,8 @@ Win32kProcessCallback(struct _EPROCESS *Process,
ExInitializeFastMutex(&Win32Process->DriverObjListLock); ExInitializeFastMutex(&Win32Process->DriverObjListLock);
Win32Process->KeyboardLayout = W32kGetDefaultKeyLayout(); Win32Process->KeyboardLayout = W32kGetDefaultKeyLayout();
EngCreateEvent((PEVENT *)&Win32Process->InputIdleEvent);
KeInitializeEvent(Win32Process->InputIdleEvent, NotificationEvent, FALSE);
if(Process->Peb != NULL) if(Process->Peb != NULL)
{ {
@ -118,6 +120,13 @@ Win32kProcessCallback(struct _EPROCESS *Process,
else else
{ {
DPRINT("Destroying W32 process PID:%d at IRQ level: %lu\n", Process->UniqueProcessId, KeGetCurrentIrql()); DPRINT("Destroying W32 process PID:%d at IRQ level: %lu\n", Process->UniqueProcessId, KeGetCurrentIrql());
Win32Process->W32PF_flags |= W32PF_TERMINATED;
if (Win32Process->InputIdleEvent)
{
EngFreeMem((PVOID)Win32Process->InputIdleEvent);
Win32Process->InputIdleEvent = NULL;
}
IntCleanupMenus(Process, Win32Process); IntCleanupMenus(Process, Win32Process);
IntCleanupCurIcons(Process, Win32Process); IntCleanupCurIcons(Process, Win32Process);
CleanupMonitorImpl(); CleanupMonitorImpl();

View file

@ -15,6 +15,8 @@
#define NDEBUG #define NDEBUG
#include <debug.h> #include <debug.h>
BOOLEAN NTAPI PsGetProcessExitProcessCalled(PEPROCESS Process);
#define PM_BADMSGFLAGS ~((QS_RAWINPUT << 16)|PM_QS_SENDMESSAGE|PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_QS_INPUT|PM_NOYIELD|PM_REMOVE) #define PM_BADMSGFLAGS ~((QS_RAWINPUT << 16)|PM_QS_SENDMESSAGE|PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_QS_INPUT|PM_NOYIELD|PM_REMOVE)
typedef struct typedef struct
@ -323,6 +325,52 @@ UnpackParam(LPARAM lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL No
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
} }
//
// Wakeup any thread/process waiting on idle input.
//
VOID FASTCALL
IdlePing(VOID)
{
PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
PUSER_MESSAGE_QUEUE ForegroundQueue;
PTHREADINFO pti, ptiForeground = NULL;
ForegroundQueue = IntGetFocusMessageQueue();
if (ForegroundQueue)
ptiForeground = ForegroundQueue->Thread->Tcb.Win32Thread;
pti = PsGetCurrentThreadWin32Thread();
if ( pti && pti->pDeskInfo && pti == ptiForeground )
{
if ( pti->fsHooks & HOOKID_TO_FLAG(WH_FOREGROUNDIDLE) ||
pti->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_FOREGROUNDIDLE) )
{
co_HOOK_CallHooks(WH_FOREGROUNDIDLE,HC_ACTION,0,0);
}
}
DPRINT("IdlePing ppi 0x%x\n",ppi);
if ( ppi && ppi->InputIdleEvent )
{
DPRINT("InputIdleEvent\n");
KeSetEvent( ppi->InputIdleEvent, IO_NO_INCREMENT, FALSE);
}
}
VOID FASTCALL
IdlePong(VOID)
{
PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
DPRINT("IdlePong ppi 0x%x\n",ppi);
if ( ppi && ppi->InputIdleEvent )
{
KeClearEvent(ppi->InputIdleEvent);
}
}
static VOID FASTCALL static VOID FASTCALL
IntCallWndProc( PWND Window, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) IntCallWndProc( PWND Window, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{ {
@ -856,6 +904,8 @@ co_IntPeekMessage( PUSER_MESSAGE Msg,
RemoveMessages = RemoveMsg & PM_REMOVE; RemoveMessages = RemoveMsg & PM_REMOVE;
IdlePong();
do do
{ {
KeQueryTickCount(&LargeTickCount); KeQueryTickCount(&LargeTickCount);
@ -944,10 +994,6 @@ co_IntPeekMessage( PUSER_MESSAGE Msg,
} }
while (TRUE); while (TRUE);
// The WH_GETMESSAGE hook enables an application to monitor messages about to
// be returned by the GetMessage or PeekMessage function.
co_HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, RemoveMsg & PM_REMOVE, (LPARAM)&Msg->Msg);
return TRUE; return TRUE;
} }
@ -1068,6 +1114,7 @@ co_IntWaitMessage( PWND Window,
{ {
return TRUE; return TRUE;
} }
/* Nothing found. Wait for new messages. */ /* Nothing found. Wait for new messages. */
Status = co_MsqWaitForNewMessages( ThreadQueue, Status = co_MsqWaitForNewMessages( ThreadQueue,
Window, Window,
@ -1094,9 +1141,9 @@ co_IntGetPeekMessage( PMSG pMsg,
UINT RemoveMsg, UINT RemoveMsg,
BOOL bGMSG ) BOOL bGMSG )
{ {
BOOL Present;
PWND Window; PWND Window;
USER_MESSAGE Msg; USER_MESSAGE Msg;
BOOL Present = FALSE;
if ( hWnd == HWND_TOPMOST || hWnd == HWND_BROADCAST ) if ( hWnd == HWND_TOPMOST || hWnd == HWND_BROADCAST )
hWnd = HWND_BOTTOM; hWnd = HWND_BOTTOM;
@ -1123,6 +1170,8 @@ co_IntGetPeekMessage( PMSG pMsg,
MsgFilterMax = 0; MsgFilterMax = 0;
} }
RtlZeroMemory(&Msg, sizeof(USER_MESSAGE));
do do
{ {
Present = co_IntPeekMessage( &Msg, Present = co_IntPeekMessage( &Msg,
@ -1132,33 +1181,40 @@ co_IntGetPeekMessage( PMSG pMsg,
RemoveMsg ); RemoveMsg );
if (Present) if (Present)
{ {
RtlCopyMemory( pMsg, &Msg.Msg, sizeof(MSG)); RtlCopyMemory( pMsg, &Msg.Msg, sizeof(MSG));
if (bGMSG) // The WH_GETMESSAGE hook enables an application to monitor messages about to
return (WM_QUIT != pMsg->message); // be returned by the GetMessage or PeekMessage function.
else
return TRUE; co_HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, RemoveMsg & PM_REMOVE, (LPARAM)pMsg);
if ( bGMSG )
return (WM_QUIT != pMsg->message);
} }
if ( bGMSG && !co_IntWaitMessage(Window, MsgFilterMin, MsgFilterMax) ) if ( bGMSG )
{ {
return -1; if ( !co_IntWaitMessage(Window, MsgFilterMin, MsgFilterMax) )
return -1;
} }
else else
{ {
if (!(RemoveMsg & PM_NOYIELD)) if (!(RemoveMsg & PM_NOYIELD))
{ {
// Yield this thread! IdlePing();
UserLeave(); // Yield this thread!
ZwYieldExecution(); UserLeave();
UserEnterExclusive(); ZwYieldExecution();
// Fall through to fail. UserEnterExclusive();
} // Fall through to exit.
IdlePong();
}
break;
} }
} }
while( bGMSG && !Present ); while( bGMSG && !Present );
return FALSE; return Present;
} }
BOOL FASTCALL BOOL FASTCALL
@ -2049,49 +2105,30 @@ NtUserGetMessage( PNTUSERGETMESSAGEINFO UnsafeInfo,
* retrieved. * retrieved.
*/ */
{ {
BOOL GotMessage;
NTUSERGETMESSAGEINFO Info; NTUSERGETMESSAGEINFO Info;
NTSTATUS Status; NTSTATUS Status;
/* FIXME: if initialization is removed, gcc complains that this may be used before initialization. Please review */ /* FIXME: if initialization is removed, gcc complains that this may be used before initialization. Please review */
PWND Window = NULL;
PMSGMEMORY MsgMemoryEntry; PMSGMEMORY MsgMemoryEntry;
PVOID UserMem; PVOID UserMem;
ULONG Size; ULONG Size;
USER_MESSAGE Msg; MSG Msg;
BOOL GotMessage;
if ( (MsgFilterMin|MsgFilterMax) & ~WM_MAXIMUM )
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
return FALSE;
}
DPRINT("Enter NtUserGetMessage\n");
UserEnterExclusive(); UserEnterExclusive();
/* Validate input */ RtlZeroMemory(&Msg, sizeof(MSG));
if (hWnd && !(Window = UserGetWindowObject(hWnd)))
{
UserLeave();
return -1;
}
// if (Window) UserRefObjectCo(Window, &Ref); GotMessage = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE, TRUE);
if (MsgFilterMax < MsgFilterMin)
{
MsgFilterMin = 0;
MsgFilterMax = 0;
}
do
{
GotMessage = co_IntPeekMessage(&Msg, Window, MsgFilterMin, MsgFilterMax, PM_REMOVE);
if (!GotMessage && !co_IntWaitMessage(Window, MsgFilterMin, MsgFilterMax))
{
UserLeave();
return -1;
}
}
while (! GotMessage);
UserLeave(); UserLeave();
Info.Msg = Msg.Msg; Info.Msg = Msg; //.Msg;
/* See if this message type is present in the table */ /* See if this message type is present in the table */
MsgMemoryEntry = FindMsgMemory(Info.Msg.message); MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
@ -2103,7 +2140,7 @@ NtUserGetMessage( PNTUSERGETMESSAGEINFO UnsafeInfo,
if (NULL == MsgMemoryEntry) if (NULL == MsgMemoryEntry)
{ {
/* Not present, no copying needed */ /* Not present, no copying needed */
Info.LParamSize = 0; UnsafeInfo->LParamSize = 0;
} }
else else
{ {
@ -2127,8 +2164,8 @@ NtUserGetMessage( PNTUSERGETMESSAGEINFO UnsafeInfo,
ProbeForWrite(UserMem, Size, 1); ProbeForWrite(UserMem, Size, 1);
RtlCopyMemory(UserMem, (PVOID)Info.Msg.lParam, Size); RtlCopyMemory(UserMem, (PVOID)Info.Msg.lParam, Size);
Info.LParamSize = Size; UnsafeInfo->LParamSize = Size;
Info.Msg.lParam = (LPARAM) UserMem; UnsafeInfo->Msg.lParam = (LPARAM) UserMem;
} }
} }
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
@ -2144,7 +2181,7 @@ NtUserGetMessage( PNTUSERGETMESSAGEINFO UnsafeInfo,
} }
_SEH2_END; _SEH2_END;
return (Info.Msg.message != WM_QUIT ); return GotMessage;
} }
@ -2163,10 +2200,10 @@ NtUserGetMessageX(PMSG pMsg,
return FALSE; return FALSE;
} }
RtlZeroMemory(&Msg, sizeof(MSG));
UserEnterExclusive(); UserEnterExclusive();
RtlZeroMemory(&Msg, sizeof(MSG));
Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE, TRUE); Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE, TRUE);
UserLeave(); UserLeave();
@ -2197,46 +2234,30 @@ NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
UINT RemoveMsg) UINT RemoveMsg)
{ {
NTSTATUS Status; NTSTATUS Status;
BOOL Ret;
NTUSERGETMESSAGEINFO Info; NTUSERGETMESSAGEINFO Info;
PWND Window;
PMSGMEMORY MsgMemoryEntry; PMSGMEMORY MsgMemoryEntry;
PVOID UserMem = NULL; PVOID UserMem = NULL;
ULONG Size; ULONG Size;
USER_MESSAGE Msg; MSG Msg;
BOOL Ret;
if ( RemoveMsg & PM_BADMSGFLAGS )
{
SetLastWin32Error(ERROR_INVALID_FLAGS);
return FALSE;
}
UserEnterExclusive(); UserEnterExclusive();
if (hWnd == (HWND)-1 || hWnd == (HWND)0x0000FFFF || hWnd == (HWND)0xFFFFFFFF) RtlZeroMemory(&Msg, sizeof(MSG));
hWnd = (HWND)1;
/* Validate input */ Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg, FALSE);
if (hWnd && hWnd != (HWND)1)
{
if (!(Window = UserGetWindowObject(hWnd)))
{
UserLeave();
return -1;
}
}
else
{
Window = (PWND)hWnd;
}
if (MsgFilterMax < MsgFilterMin)
{
MsgFilterMin = 0;
MsgFilterMax = 0;
}
Ret = co_IntPeekMessage(&Msg, Window, MsgFilterMin, MsgFilterMax, RemoveMsg);
UserLeave(); UserLeave();
if (Ret) if (Ret)
{ {
Info.Msg = Msg.Msg; Info.Msg = Msg;
/* See if this message type is present in the table */ /* See if this message type is present in the table */
MsgMemoryEntry = FindMsgMemory(Info.Msg.message); MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
@ -2248,7 +2269,7 @@ NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
if (NULL == MsgMemoryEntry) if (NULL == MsgMemoryEntry)
{ {
/* Not present, no copying needed */ /* Not present, no copying needed */
Info.LParamSize = 0; UnsafeInfo->LParamSize = 0;
} }
else else
{ {
@ -2272,8 +2293,8 @@ NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
ProbeForWrite(UserMem, Size, 1); ProbeForWrite(UserMem, Size, 1);
RtlCopyMemory(UserMem, (PVOID)Info.Msg.lParam, Size); RtlCopyMemory(UserMem, (PVOID)Info.Msg.lParam, Size);
Info.LParamSize = Size; UnsafeInfo->LParamSize = Size;
Info.Msg.lParam = (LPARAM) UserMem; UnsafeInfo->Msg.lParam = (LPARAM) UserMem;
} }
} }
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
@ -2308,10 +2329,10 @@ NtUserPeekMessageX( PMSG pMsg,
return FALSE; return FALSE;
} }
RtlZeroMemory(&Msg, sizeof(MSG));
UserEnterExclusive(); UserEnterExclusive();
RtlZeroMemory(&Msg, sizeof(MSG));
Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg, FALSE); Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg, FALSE);
UserLeave(); UserLeave();
@ -2665,10 +2686,10 @@ NtUserWaitForInputIdle( IN HANDLE hProcess,
{ {
PEPROCESS Process; PEPROCESS Process;
PPROCESSINFO W32Process; PPROCESSINFO W32Process;
PTHREADINFO pti;
NTSTATUS Status; NTSTATUS Status;
HANDLE Handles[2]; HANDLE Handles[3];
LARGE_INTEGER Timeout; LARGE_INTEGER Timeout;
ULONGLONG StartTime, Run, Elapsed = 0;
UserEnterExclusive(); UserEnterExclusive();
@ -2686,8 +2707,13 @@ NtUserWaitForInputIdle( IN HANDLE hProcess,
return WAIT_FAILED; return WAIT_FAILED;
} }
pti = PsGetCurrentThreadWin32Thread();
W32Process = (PPROCESSINFO)Process->Win32Process; W32Process = (PPROCESSINFO)Process->Win32Process;
if (!W32Process)
if ( PsGetProcessExitProcessCalled(Process) ||
!W32Process ||
pti->ppi == W32Process)
{ {
ObDereferenceObject(Process); ObDereferenceObject(Process);
UserLeave(); UserLeave();
@ -2695,10 +2721,9 @@ NtUserWaitForInputIdle( IN HANDLE hProcess,
return WAIT_FAILED; return WAIT_FAILED;
} }
EngCreateEvent((PEVENT *)&W32Process->InputIdleEvent);
Handles[0] = Process; Handles[0] = Process;
Handles[1] = W32Process->InputIdleEvent; Handles[1] = W32Process->InputIdleEvent;
Handles[2] = pti->MessageQueue->NewMessages; // pEventQueueServer; IntMsqSetWakeMask returns hEventQueueClient
if (!Handles[1]) if (!Handles[1])
{ {
@ -2707,16 +2732,15 @@ NtUserWaitForInputIdle( IN HANDLE hProcess,
return STATUS_SUCCESS; /* no event to wait on */ return STATUS_SUCCESS; /* no event to wait on */
} }
StartTime = EngGetTickCount(); if (dwMilliseconds != INFINITE)
Timeout.QuadPart = (LONGLONG) dwMilliseconds * (LONGLONG) -10000;
Run = dwMilliseconds;
DPRINT("WFII: ppi 0x%x\n",W32Process);
DPRINT("WFII: waiting for %p\n", Handles[1] ); DPRINT("WFII: waiting for %p\n", Handles[1] );
do do
{ {
Timeout.QuadPart = Run - Elapsed;
UserLeave(); UserLeave();
Status = KeWaitForMultipleObjects( 2, Status = KeWaitForMultipleObjects( 3,
Handles, Handles,
WaitAny, WaitAny,
UserRequest, UserRequest,
@ -2736,21 +2760,19 @@ NtUserWaitForInputIdle( IN HANDLE hProcess,
switch (Status) switch (Status)
{ {
case STATUS_WAIT_0: case STATUS_WAIT_0:
Status = WAIT_FAILED;
goto WaitExit; goto WaitExit;
case STATUS_WAIT_2: case STATUS_WAIT_2:
{ {
USER_MESSAGE Msg; USER_MESSAGE Msg;
co_IntPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE ); co_IntPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE );
break; DPRINT1("WFII: WAIT 2\n");
} }
break;
case STATUS_USER_APC:
case STATUS_ALERTED:
case STATUS_TIMEOUT: case STATUS_TIMEOUT:
DPRINT1("WFII: timeout\n"); DPRINT1("WFII: timeout\n");
Status = STATUS_TIMEOUT; case WAIT_FAILED:
goto WaitExit; goto WaitExit;
default: default:
@ -2758,24 +2780,10 @@ NtUserWaitForInputIdle( IN HANDLE hProcess,
Status = STATUS_SUCCESS; Status = STATUS_SUCCESS;
goto WaitExit; goto WaitExit;
} }
if (dwMilliseconds != INFINITE)
{
Elapsed = EngGetTickCount() - StartTime;
if (Elapsed > Run)
Status = STATUS_TIMEOUT;
break;
}
} }
while (1); while (TRUE);
WaitExit: WaitExit:
if (W32Process->InputIdleEvent)
{
EngFreeMem((PVOID)W32Process->InputIdleEvent);
W32Process->InputIdleEvent = NULL;
}
ObDereferenceObject(Process); ObDereferenceObject(Process);
UserLeave(); UserLeave();
return Status; return Status;

View file

@ -62,32 +62,6 @@ static PAGED_LOOKASIDE_LIST MessageLookasideList;
/* FUNCTIONS *****************************************************************/ /* FUNCTIONS *****************************************************************/
//
// Wakeup any thread/process waiting on idle input.
//
static VOID FASTCALL
IdlePing(VOID)
{
HWND hWnd;
PWND Window;
PPROCESSINFO W32d = PsGetCurrentProcessWin32Process();
hWnd = UserGetForegroundWindow();
Window = UserGetWindowObject(hWnd);
if (Window && Window->head.pti)
{
if (Window->head.pti->fsHooks & HOOKID_TO_FLAG(WH_FOREGROUNDIDLE))
{
co_HOOK_CallHooks(WH_FOREGROUNDIDLE,HC_ACTION,0,0);
}
}
if (W32d && W32d->InputIdleEvent)
KePulseEvent( W32d->InputIdleEvent, EVENT_INCREMENT, TRUE);
}
HANDLE FASTCALL HANDLE FASTCALL
IntMsqSetWakeMask(DWORD WakeMask) IntMsqSetWakeMask(DWORD WakeMask)
{ {
@ -578,8 +552,6 @@ co_MsqPeekHardwareMessage(PUSER_MESSAGE_QUEUE MessageQueue, PWND Window,
WaitObjects[0] = &HardwareMessageQueueLock; WaitObjects[0] = &HardwareMessageQueueLock;
do do
{ {
IdlePing();
UserLeaveCo(); UserLeaveCo();
WaitStatus = KeWaitForMultipleObjects(2, WaitObjects, WaitAny, UserRequest, WaitStatus = KeWaitForMultipleObjects(2, WaitObjects, WaitAny, UserRequest,
@ -1185,8 +1157,6 @@ co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
if(Block) if(Block)
{ {
IdlePing();
UserLeaveCo(); UserLeaveCo();
/* don't process messages sent to the thread */ /* don't process messages sent to the thread */
@ -1248,8 +1218,6 @@ co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
WaitObjects[1] = ThreadQueue->NewMessages; WaitObjects[1] = ThreadQueue->NewMessages;
do do
{ {
IdlePing();
UserLeaveCo(); UserLeaveCo();
WaitStatus = KeWaitForMultipleObjects(2, WaitObjects, WaitAny, UserRequest, WaitStatus = KeWaitForMultipleObjects(2, WaitObjects, WaitAny, UserRequest,
@ -1407,8 +1375,6 @@ co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue, PWND WndFilter,
PVOID WaitObjects[2] = {MessageQueue->NewMessages, &HardwareMessageEvent}; PVOID WaitObjects[2] = {MessageQueue->NewMessages, &HardwareMessageEvent};
NTSTATUS ret; NTSTATUS ret;
IdlePing(); // Going to wait so send Idle ping.
UserLeaveCo(); UserLeaveCo();
ret = KeWaitForMultipleObjects(2, ret = KeWaitForMultipleObjects(2,