- In ExpReleaseOrWaitForKeyedEvent, always restore previous values for ETHREAD::KeyedWaitValue and ETHREAD::KeyedWaitChain, as these fields have alternative meanings outside of keyed events
- Add missing list walk in ExpReleaseOrWaitForKeyedEvent
- In Nt(WaitFor|Release)KeyedEvent, refuse keys that are not two-byte aligned as shown by Wine tests
- Don't forget to set KTHREAD::Process on thread creation
Fixes hang when running ntdll_winetest:om as well as failing tests.
ROSTESTS-118 #resolve

svn path=/trunk/; revision=66304
This commit is contained in:
Thomas Faber 2015-02-15 22:20:34 +00:00
parent 3ce6fcf3b2
commit 05b349a93c
3 changed files with 28 additions and 8 deletions

View file

@ -132,6 +132,7 @@ ExpReleaseOrWaitForKeyedEvent(
PLIST_ENTRY ListEntry, WaitListHead1, WaitListHead2;
NTSTATUS Status;
ULONG_PTR HashIndex;
PVOID PreviousKeyedWaitValue;
/* Get the current process */
CurrentProcess = KeGetCurrentProcess();
@ -167,6 +168,7 @@ ExpReleaseOrWaitForKeyedEvent(
be signaled by this thread or, when the wait is aborted due to thread
termination, then it first needs to acquire the list lock. */
Thread = CONTAINING_RECORD(ListEntry, ETHREAD, KeyedWaitChain);
ListEntry = ListEntry->Flink;
/* Check if this thread is a correct waiter */
if ((Thread->Tcb.Process == CurrentProcess) &&
@ -179,7 +181,10 @@ ExpReleaseOrWaitForKeyedEvent(
InitializeListHead(&Thread->KeyedWaitChain);
/* Wake the thread */
KeReleaseSemaphore(&Thread->KeyedWaitSemaphore, 0, 1, FALSE);
KeReleaseSemaphore(&Thread->KeyedWaitSemaphore,
IO_NO_INCREMENT,
1,
FALSE);
Thread = NULL;
/* Unlock the list. After this it is not safe to access Thread */
@ -193,7 +198,8 @@ ExpReleaseOrWaitForKeyedEvent(
/* Get the current thread */
CurrentThread = PsGetCurrentThread();
/* Set the wait key */
/* Set the wait key and remember the old value */
PreviousKeyedWaitValue = CurrentThread->KeyedWaitValue;
CurrentThread->KeyedWaitValue = KeyedWaitValue;
/* Initialize the wait semaphore */
@ -221,10 +227,11 @@ ExpReleaseOrWaitForKeyedEvent(
ExAcquirePushLockExclusive(&KeyedEvent->HashTable[HashIndex].Lock);
/* Check if the wait list entry is still in the list */
if (CurrentThread->KeyedWaitChain.Flink != &CurrentThread->KeyedWaitChain)
if (!IsListEmpty(&CurrentThread->KeyedWaitChain))
{
/* Remove the thread from the list */
RemoveEntryList(&CurrentThread->KeyedWaitChain);
InitializeListHead(&CurrentThread->KeyedWaitChain);
}
/* Unlock the list */
@ -232,6 +239,9 @@ ExpReleaseOrWaitForKeyedEvent(
KeLeaveCriticalRegion();
}
/* Restore the previous KeyedWaitValue, since this is a union member */
CurrentThread->KeyedWaitValue = PreviousKeyedWaitValue;
return Status;
}
@ -412,6 +422,12 @@ NtWaitForKeyedEvent(
NTSTATUS Status;
LARGE_INTEGER TimeoutCopy;
/* Key must always be two-byte aligned */
if ((ULONG_PTR)Key & 1)
{
return STATUS_INVALID_PARAMETER_1;
}
/* Check if the caller passed a timeout value and this is from user mode */
if ((Timeout != NULL) && (PreviousMode != KernelMode))
{
@ -472,6 +488,12 @@ NtReleaseKeyedEvent(
NTSTATUS Status;
LARGE_INTEGER TimeoutCopy;
/* Key must always be two-byte aligned */
if ((ULONG_PTR)Key & 1)
{
return STATUS_INVALID_PARAMETER_1;
}
/* Check if the caller passed a timeout value and this is from user mode */
if ((Timeout != NULL) && (PreviousMode != KernelMode))
{

View file

@ -838,8 +838,9 @@ KeInitThread(IN OUT PKTHREAD Thread,
TimerWaitBlock->WaitListEntry.Flink = &Timer->Header.WaitListHead;
TimerWaitBlock->WaitListEntry.Blink = &Timer->Header.WaitListHead;
/* Set the TEB */
/* Set the TEB and process */
Thread->Teb = Teb;
Thread->Process = Process;
/* Check if we have a kernel stack */
if (!KernelStack)

View file

@ -1080,8 +1080,5 @@ START_TEST(om)
test_query_object();
test_type_mismatch();
test_event();
if (winetest_interactive)
test_keyed_events();
else
skip("Skipping test_keyed_events(). ROSTESTS-118.\n");
test_keyed_events();
}