mirror of
https://github.com/reactos/reactos.git
synced 2024-07-07 21:25:05 +00:00
WaitForMultipleObjects: WaitAll waits were buggy
Many small fixes and cleanups svn path=/trunk/; revision=4205
This commit is contained in:
parent
3013b90260
commit
5852f3f492
|
@ -33,6 +33,9 @@ static BOOLEAN WaitSet = FALSE;
|
||||||
static KIRQL oldlvl = PASSIVE_LEVEL;
|
static KIRQL oldlvl = PASSIVE_LEVEL;
|
||||||
static PKTHREAD Owner = NULL;
|
static PKTHREAD Owner = NULL;
|
||||||
|
|
||||||
|
#define KeDispatcherObjectWakeOne(hdr) KeDispatcherObjectWakeOneOrAll(hdr, FALSE)
|
||||||
|
#define KeDispatcherObjectWakeAll(hdr) KeDispatcherObjectWakeOneOrAll(hdr, TRUE)
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
VOID KeInitializeDispatcherHeader(DISPATCHER_HEADER* Header,
|
VOID KeInitializeDispatcherHeader(DISPATCHER_HEADER* Header,
|
||||||
|
@ -85,16 +88,15 @@ VOID KeReleaseDispatcherDatabaseLock(BOOLEAN Wait)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static VOID KiSideEffectsBeforeWake(DISPATCHER_HEADER* hdr,
|
static BOOLEAN
|
||||||
PKTHREAD Thread,
|
KiSideEffectsBeforeWake(DISPATCHER_HEADER * hdr,
|
||||||
PBOOLEAN Abandoned)
|
PKTHREAD Thread)
|
||||||
/*
|
/*
|
||||||
* FUNCTION: Perform side effects on object before a wait for a thread is
|
* FUNCTION: Perform side effects on object before a wait for a thread is
|
||||||
* satisfied
|
* satisfied
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
if (Abandoned != NULL)
|
BOOLEAN Abandoned = FALSE;
|
||||||
*Abandoned = FALSE;
|
|
||||||
|
|
||||||
switch (hdr->Type)
|
switch (hdr->Type)
|
||||||
{
|
{
|
||||||
|
@ -133,14 +135,12 @@ static VOID KiSideEffectsBeforeWake(DISPATCHER_HEADER* hdr,
|
||||||
{
|
{
|
||||||
if (Thread == NULL)
|
if (Thread == NULL)
|
||||||
{
|
{
|
||||||
DPRINT1("Thread == NULL!\n");
|
DPRINT("Thread == NULL!\n");
|
||||||
KeBugCheck(0);
|
KeBugCheck(0);
|
||||||
}
|
}
|
||||||
if (Abandoned != NULL)
|
Abandoned = Mutex->Abandoned;
|
||||||
*Abandoned = Mutex->Abandoned;
|
|
||||||
if (Thread != NULL)
|
if (Thread != NULL)
|
||||||
InsertTailList(&Thread->MutantListHead,
|
InsertTailList(&Thread->MutantListHead, &Mutex->MutantListEntry);
|
||||||
&Mutex->MutantListEntry);
|
|
||||||
Mutex->OwnerThread = Thread;
|
Mutex->OwnerThread = Thread;
|
||||||
Mutex->Abandoned = FALSE;
|
Mutex->Abandoned = FALSE;
|
||||||
}
|
}
|
||||||
|
@ -148,20 +148,17 @@ static VOID KiSideEffectsBeforeWake(DISPATCHER_HEADER* hdr,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
DbgPrint("(%s:%d) Dispatcher object %x has unknown type\n",
|
DbgPrint("(%s:%d) Dispatcher object %x has unknown type\n", __FILE__, __LINE__, hdr);
|
||||||
__FILE__,__LINE__,hdr);
|
|
||||||
KeBugCheck(0);
|
KeBugCheck(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Abandoned;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOLEAN
|
static BOOLEAN
|
||||||
KiIsObjectSignalled(DISPATCHER_HEADER* hdr,
|
KiIsObjectSignalled(DISPATCHER_HEADER * hdr,
|
||||||
PKTHREAD Thread,
|
PKTHREAD Thread)
|
||||||
PBOOLEAN Abandoned)
|
|
||||||
{
|
{
|
||||||
if (Abandoned != NULL)
|
|
||||||
*Abandoned = FALSE;
|
|
||||||
|
|
||||||
if (hdr->Type == InternalMutexType)
|
if (hdr->Type == InternalMutexType)
|
||||||
{
|
{
|
||||||
PKMUTEX Mutex;
|
PKMUTEX Mutex;
|
||||||
|
@ -169,29 +166,24 @@ KiIsObjectSignalled(DISPATCHER_HEADER* hdr,
|
||||||
Mutex = CONTAINING_RECORD(hdr, KMUTEX, Header);
|
Mutex = CONTAINING_RECORD(hdr, KMUTEX, Header);
|
||||||
|
|
||||||
assert(hdr->SignalState <= 1);
|
assert(hdr->SignalState <= 1);
|
||||||
if ((hdr->SignalState < 1 && Mutex->OwnerThread == Thread) ||
|
|
||||||
hdr->SignalState == 1)
|
if ((hdr->SignalState < 1 && Mutex->OwnerThread == Thread) || hdr->SignalState == 1)
|
||||||
{
|
{
|
||||||
KiSideEffectsBeforeWake(hdr,
|
return (TRUE);
|
||||||
Thread,
|
|
||||||
Abandoned);
|
|
||||||
return(TRUE);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return(FALSE);
|
return (FALSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hdr->SignalState <= 0)
|
if (hdr->SignalState <= 0)
|
||||||
{
|
{
|
||||||
return(FALSE);
|
return (FALSE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
KiSideEffectsBeforeWake(hdr,
|
return (TRUE);
|
||||||
Thread,
|
|
||||||
Abandoned);
|
|
||||||
return(TRUE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,155 +214,113 @@ VOID KeRemoveAllWaitsThread(PETHREAD Thread, NTSTATUS WaitStatus)
|
||||||
KeReleaseDispatcherDatabaseLock(FALSE);
|
KeReleaseDispatcherDatabaseLock(FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOLEAN KeDispatcherObjectWakeAll(DISPATCHER_HEADER* hdr)
|
static BOOLEAN
|
||||||
|
KeDispatcherObjectWakeOneOrAll(DISPATCHER_HEADER * hdr,
|
||||||
|
BOOLEAN WakeAll)
|
||||||
{
|
{
|
||||||
PKWAIT_BLOCK current;
|
PKWAIT_BLOCK Waiter;
|
||||||
PLIST_ENTRY current_entry;
|
PKWAIT_BLOCK WaiterHead;
|
||||||
PKWAIT_BLOCK PrevBlock;
|
PLIST_ENTRY EnumEntry;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
BOOLEAN Abandoned;
|
BOOLEAN Abandoned;
|
||||||
|
BOOLEAN AllSignaled;
|
||||||
|
BOOLEAN WakedAny = FALSE;
|
||||||
|
|
||||||
DPRINT("KeDispatcherObjectWakeAll(hdr %x)\n",hdr);
|
DPRINT("KeDispatcherObjectWakeOnOrAll(hdr %x)\n", hdr);
|
||||||
|
DPRINT ("hdr->WaitListHead.Flink %x hdr->WaitListHead.Blink %x\n",
|
||||||
|
hdr->WaitListHead.Flink, hdr->WaitListHead.Blink);
|
||||||
|
|
||||||
if (IsListEmpty(&hdr->WaitListHead))
|
if (IsListEmpty(&hdr->WaitListHead))
|
||||||
{
|
{
|
||||||
return(FALSE);
|
return (FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!IsListEmpty(&hdr->WaitListHead))
|
//enum waiters for this dispatcher object
|
||||||
|
EnumEntry = hdr->WaitListHead.Flink;
|
||||||
|
while (EnumEntry != &hdr->WaitListHead && (WakeAll || !WakedAny))
|
||||||
{
|
{
|
||||||
current_entry = RemoveHeadList(&hdr->WaitListHead);
|
WaiterHead = CONTAINING_RECORD(EnumEntry, KWAIT_BLOCK, WaitListEntry);
|
||||||
current = CONTAINING_RECORD(current_entry,
|
DPRINT("current_entry %x current %x\n", EnumEntry, WaiterHead);
|
||||||
KWAIT_BLOCK,
|
EnumEntry = EnumEntry->Flink;
|
||||||
WaitListEntry);
|
assert(WaiterHead->Thread->WaitBlockList != NULL);
|
||||||
DPRINT("Waking %x\n",current->Thread);
|
|
||||||
if (current->WaitType == WaitAny)
|
Abandoned = FALSE;
|
||||||
|
|
||||||
|
if (WaiterHead->WaitType == WaitAny)
|
||||||
{
|
{
|
||||||
DPRINT("WaitAny: Remove all wait blocks.\n");
|
DPRINT("WaitAny: Remove all wait blocks.\n");
|
||||||
for(PrevBlock = current->Thread->WaitBlockList; PrevBlock;
|
for (Waiter = WaiterHead->Thread->WaitBlockList; Waiter; Waiter = Waiter->NextWaitBlock)
|
||||||
PrevBlock = PrevBlock->NextWaitBlock)
|
|
||||||
{
|
{
|
||||||
if (PrevBlock != current)
|
RemoveEntryList(&Waiter->WaitListEntry);
|
||||||
RemoveEntryList(&PrevBlock->WaitListEntry);
|
|
||||||
}
|
}
|
||||||
current->Thread->WaitBlockList = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DPRINT("WaitAll: Remove the current wait block only.\n");
|
|
||||||
|
|
||||||
PrevBlock = current->Thread->WaitBlockList;
|
WaiterHead->Thread->WaitBlockList = NULL;
|
||||||
if (PrevBlock == current)
|
|
||||||
{
|
/*
|
||||||
DPRINT( "WaitAll: Current block is list head.\n" );
|
* If a WakeAll KiSideEffectsBeforeWake(hdr,.. will be called several times,
|
||||||
current->Thread->WaitBlockList = current->NextWaitBlock;
|
* but thats ok since WakeAll objects has no sideeffects.
|
||||||
|
*/
|
||||||
|
Abandoned = KiSideEffectsBeforeWake(hdr, WaiterHead->Thread) ? TRUE : Abandoned;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DPRINT( "WaitAll: Current block is not list head.\n" );
|
DPRINT("WaitAll: All WaitAll objects must be signaled.\n");
|
||||||
while (PrevBlock && PrevBlock->NextWaitBlock != current)
|
|
||||||
|
AllSignaled = TRUE;
|
||||||
|
|
||||||
|
//all WaitAll obj. for thread need to be signaled to satisfy a wake
|
||||||
|
for (Waiter = WaiterHead->Thread->WaitBlockList; Waiter; Waiter = Waiter->NextWaitBlock)
|
||||||
{
|
{
|
||||||
PrevBlock = PrevBlock->NextWaitBlock;
|
//no need to check hdr since it has to be signaled
|
||||||
}
|
if (Waiter->WaitType == WaitAll && Waiter->Object != hdr)
|
||||||
if (PrevBlock)
|
|
||||||
{
|
{
|
||||||
PrevBlock->NextWaitBlock = current->NextWaitBlock;
|
if (!KiIsObjectSignalled(Waiter->Object, Waiter->Thread))
|
||||||
}
|
|
||||||
current->NextWaitBlock = NULL;
|
|
||||||
/* if the last block is the timeout block then remove this block */
|
|
||||||
PrevBlock = current->Thread->WaitBlockList;
|
|
||||||
if (PrevBlock == ¤t->Thread->WaitBlock[3] && PrevBlock->NextWaitBlock == NULL)
|
|
||||||
{
|
{
|
||||||
RemoveEntryList(¤t->Thread->WaitBlock[3].WaitListEntry);
|
AllSignaled = FALSE;
|
||||||
current->Thread->WaitBlockList = NULL;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
KiSideEffectsBeforeWake(hdr, current->Thread, &Abandoned);
|
|
||||||
Status = current->WaitKey;
|
if (AllSignaled)
|
||||||
|
{
|
||||||
|
for (Waiter = WaiterHead->Thread->WaitBlockList; Waiter; Waiter = Waiter->NextWaitBlock)
|
||||||
|
{
|
||||||
|
RemoveEntryList(&Waiter->WaitListEntry);
|
||||||
|
|
||||||
|
if (Waiter->WaitType == WaitAll)
|
||||||
|
{
|
||||||
|
Abandoned = KiSideEffectsBeforeWake(Waiter->Object, Waiter->Thread)
|
||||||
|
? TRUE : Abandoned;
|
||||||
|
}
|
||||||
|
|
||||||
|
//no WaitAny objects can possibly be signaled since we are here
|
||||||
|
assert(!(Waiter->WaitType == WaitAny
|
||||||
|
&& KiIsObjectSignalled(Waiter->Object, Waiter->Thread)));
|
||||||
|
}
|
||||||
|
|
||||||
|
WaiterHead->Thread->WaitBlockList = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WaiterHead->Thread->WaitBlockList == NULL)
|
||||||
|
{
|
||||||
|
Status = WaiterHead->WaitKey;
|
||||||
if (Abandoned)
|
if (Abandoned)
|
||||||
Status += STATUS_ABANDONED_WAIT_0;
|
|
||||||
if (current->Thread->WaitBlockList == NULL)
|
|
||||||
{
|
{
|
||||||
PsUnblockThread(CONTAINING_RECORD(current->Thread,ETHREAD,Tcb),
|
DPRINT("Abandoned mutex among objects");
|
||||||
&Status);
|
Status += STATUS_ABANDONED_WAIT_0;
|
||||||
|
}
|
||||||
|
|
||||||
|
WakedAny = TRUE;
|
||||||
|
DPRINT("Waking %x status = %x\n", WaiterHead->Thread, Status);
|
||||||
|
PsUnblockThread(CONTAINING_RECORD(WaiterHead->Thread, ETHREAD, Tcb), &Status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return(TRUE);
|
|
||||||
|
return WakedAny;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOLEAN KeDispatcherObjectWakeOne(DISPATCHER_HEADER* hdr)
|
|
||||||
{
|
|
||||||
PKWAIT_BLOCK current;
|
|
||||||
PLIST_ENTRY current_entry;
|
|
||||||
PKWAIT_BLOCK PrevBlock;
|
|
||||||
NTSTATUS Status;
|
|
||||||
BOOLEAN Abandoned;
|
|
||||||
|
|
||||||
DPRINT("KeDispatcherObjectWakeOn(hdr %x)\n",hdr);
|
|
||||||
DPRINT("hdr->WaitListHead.Flink %x hdr->WaitListHead.Blink %x\n",
|
|
||||||
hdr->WaitListHead.Flink,hdr->WaitListHead.Blink);
|
|
||||||
if (IsListEmpty(&(hdr->WaitListHead)))
|
|
||||||
{
|
|
||||||
return(FALSE);
|
|
||||||
}
|
|
||||||
current_entry = RemoveHeadList(&(hdr->WaitListHead));
|
|
||||||
current = CONTAINING_RECORD(current_entry,KWAIT_BLOCK,
|
|
||||||
WaitListEntry);
|
|
||||||
DPRINT("current_entry %x current %x\n",current_entry,current);
|
|
||||||
|
|
||||||
if (current->WaitType == WaitAny)
|
|
||||||
{
|
|
||||||
DPRINT("WaitAny: Remove all wait blocks.\n");
|
|
||||||
for( PrevBlock = current->Thread->WaitBlockList; PrevBlock; PrevBlock = PrevBlock->NextWaitBlock )
|
|
||||||
if( PrevBlock != current )
|
|
||||||
RemoveEntryList( &(PrevBlock->WaitListEntry) );
|
|
||||||
current->Thread->WaitBlockList = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DPRINT("WaitAll: Remove the current wait block only.\n");
|
|
||||||
|
|
||||||
PrevBlock = current->Thread->WaitBlockList;
|
|
||||||
if (PrevBlock == current)
|
|
||||||
{
|
|
||||||
DPRINT( "WaitAll: Current block is list head.\n" );
|
|
||||||
current->Thread->WaitBlockList = current->NextWaitBlock;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DPRINT( "WaitAll: Current block is not list head.\n" );
|
|
||||||
while ( PrevBlock && PrevBlock->NextWaitBlock != current)
|
|
||||||
{
|
|
||||||
PrevBlock = PrevBlock->NextWaitBlock;
|
|
||||||
}
|
|
||||||
if (PrevBlock)
|
|
||||||
{
|
|
||||||
PrevBlock->NextWaitBlock = current->NextWaitBlock;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
current->NextWaitBlock = NULL;
|
|
||||||
/* if the last block is the timeout block then remove this block */
|
|
||||||
PrevBlock = current->Thread->WaitBlockList;
|
|
||||||
if (PrevBlock == ¤t->Thread->WaitBlock[3] && PrevBlock->NextWaitBlock == NULL)
|
|
||||||
{
|
|
||||||
RemoveEntryList(¤t->Thread->WaitBlock[3].WaitListEntry);
|
|
||||||
current->Thread->WaitBlockList = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DPRINT("Waking %x\n",current->Thread);
|
|
||||||
KiSideEffectsBeforeWake(hdr, current->Thread, &Abandoned);
|
|
||||||
Status = current->WaitKey;
|
|
||||||
if (Abandoned)
|
|
||||||
Status += STATUS_ABANDONED_WAIT_0;
|
|
||||||
if (current->Thread->WaitBlockList == NULL)
|
|
||||||
{
|
|
||||||
PsUnblockThread(CONTAINING_RECORD(current->Thread,ETHREAD,Tcb),
|
|
||||||
&Status);
|
|
||||||
}
|
|
||||||
return(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOLEAN KeDispatcherObjectWake(DISPATCHER_HEADER* hdr)
|
BOOLEAN KeDispatcherObjectWake(DISPATCHER_HEADER* hdr)
|
||||||
/*
|
/*
|
||||||
|
@ -446,103 +396,14 @@ KeWaitForSingleObject(PVOID Object,
|
||||||
* RETURNS: Status
|
* RETURNS: Status
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
DISPATCHER_HEADER* hdr = (DISPATCHER_HEADER *)Object;
|
return KeWaitForMultipleObjects(1,
|
||||||
PKTHREAD CurrentThread;
|
&Object,
|
||||||
NTSTATUS Status;
|
WaitAny,
|
||||||
KIRQL WaitIrql;
|
WaitReason,
|
||||||
BOOLEAN Abandoned;
|
WaitMode,
|
||||||
|
Alertable,
|
||||||
CurrentThread = KeGetCurrentThread();
|
Timeout,
|
||||||
WaitIrql = KeGetCurrentIrql();
|
NULL);
|
||||||
|
|
||||||
/*
|
|
||||||
* Set up the timeout
|
|
||||||
* FIXME: Check for zero timeout
|
|
||||||
*/
|
|
||||||
if (Timeout != NULL)
|
|
||||||
{
|
|
||||||
KeInitializeTimer(&CurrentThread->Timer);
|
|
||||||
KeSetTimer(&CurrentThread->Timer, *Timeout, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
KeAcquireDispatcherDatabaseLock(FALSE);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If we are going to wait alertably and a user apc is pending
|
|
||||||
* then return
|
|
||||||
*/
|
|
||||||
if (Alertable && KiTestAlert())
|
|
||||||
{
|
|
||||||
KeReleaseDispatcherDatabaseLock(FALSE);
|
|
||||||
return(STATUS_USER_APC);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the object is signalled
|
|
||||||
*/
|
|
||||||
if (KiIsObjectSignalled(hdr, CurrentThread, &Abandoned))
|
|
||||||
{
|
|
||||||
if (Timeout != NULL)
|
|
||||||
{
|
|
||||||
KeCancelTimer(&CurrentThread->Timer);
|
|
||||||
}
|
|
||||||
KeReleaseDispatcherDatabaseLock(FALSE);
|
|
||||||
if (Abandoned == TRUE)
|
|
||||||
return(STATUS_ABANDONED_WAIT_0);
|
|
||||||
return(STATUS_WAIT_0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if we have already timed out
|
|
||||||
*/
|
|
||||||
if (Timeout != NULL &&
|
|
||||||
KiIsObjectSignalled(&CurrentThread->Timer.Header, CurrentThread, NULL))
|
|
||||||
{
|
|
||||||
KeCancelTimer(&CurrentThread->Timer);
|
|
||||||
KeReleaseDispatcherDatabaseLock(FALSE);
|
|
||||||
return(STATUS_TIMEOUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set up for a wait
|
|
||||||
*/
|
|
||||||
CurrentThread->WaitStatus = STATUS_UNSUCCESSFUL;
|
|
||||||
/* Append wait block to the KTHREAD wait block list */
|
|
||||||
CurrentThread->WaitBlockList = &CurrentThread->WaitBlock[0];
|
|
||||||
CurrentThread->WaitBlock[0].Object = Object;
|
|
||||||
CurrentThread->WaitBlock[0].Thread = CurrentThread;
|
|
||||||
CurrentThread->WaitBlock[0].WaitKey = STATUS_WAIT_0;
|
|
||||||
CurrentThread->WaitBlock[0].WaitType = WaitAny;
|
|
||||||
InsertTailList(&hdr->WaitListHead,
|
|
||||||
&CurrentThread->WaitBlock[0].WaitListEntry);
|
|
||||||
if (Timeout != NULL)
|
|
||||||
{
|
|
||||||
CurrentThread->WaitBlock[0].NextWaitBlock =
|
|
||||||
&CurrentThread->WaitBlock[3];
|
|
||||||
CurrentThread->WaitBlock[3].Object = (PVOID)&CurrentThread->Timer;
|
|
||||||
CurrentThread->WaitBlock[3].Thread = CurrentThread;
|
|
||||||
CurrentThread->WaitBlock[3].WaitKey = STATUS_TIMEOUT;
|
|
||||||
CurrentThread->WaitBlock[3].WaitType = WaitAny;
|
|
||||||
CurrentThread->WaitBlock[3].NextWaitBlock = NULL;
|
|
||||||
InsertTailList(&CurrentThread->Timer.Header.WaitListHead,
|
|
||||||
&CurrentThread->WaitBlock[3].WaitListEntry);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CurrentThread->WaitBlock[0].NextWaitBlock = NULL;
|
|
||||||
}
|
|
||||||
PsBlockThread(&Status, (UCHAR)Alertable, WaitMode, TRUE, WaitIrql);
|
|
||||||
} while (Status == STATUS_KERNEL_APC);
|
|
||||||
|
|
||||||
if (Timeout != NULL)
|
|
||||||
{
|
|
||||||
KeCancelTimer(&CurrentThread->Timer);
|
|
||||||
}
|
|
||||||
|
|
||||||
DPRINT("Returning from KeWaitForSingleObject()\n");
|
|
||||||
return(Status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -556,7 +417,7 @@ KeWaitForMultipleObjects(ULONG Count,
|
||||||
PLARGE_INTEGER Timeout,
|
PLARGE_INTEGER Timeout,
|
||||||
PKWAIT_BLOCK WaitBlockArray)
|
PKWAIT_BLOCK WaitBlockArray)
|
||||||
{
|
{
|
||||||
DISPATCHER_HEADER* hdr;
|
DISPATCHER_HEADER *hdr;
|
||||||
PKWAIT_BLOCK blk;
|
PKWAIT_BLOCK blk;
|
||||||
PKTHREAD CurrentThread;
|
PKTHREAD CurrentThread;
|
||||||
ULONG CountSignaled;
|
ULONG CountSignaled;
|
||||||
|
@ -566,9 +427,8 @@ KeWaitForMultipleObjects(ULONG Count,
|
||||||
BOOLEAN Abandoned;
|
BOOLEAN Abandoned;
|
||||||
|
|
||||||
DPRINT("Entering KeWaitForMultipleObjects(Count %lu Object[] %p) "
|
DPRINT("Entering KeWaitForMultipleObjects(Count %lu Object[] %p) "
|
||||||
"PsGetCurrentThread() %x\n",Count,Object,PsGetCurrentThread());
|
"PsGetCurrentThread() %x\n", Count, Object, PsGetCurrentThread());
|
||||||
|
|
||||||
CountSignaled = 0;
|
|
||||||
CurrentThread = KeGetCurrentThread();
|
CurrentThread = KeGetCurrentThread();
|
||||||
WaitIrql = KeGetCurrentIrql();
|
WaitIrql = KeGetCurrentIrql();
|
||||||
|
|
||||||
|
@ -579,9 +439,8 @@ KeWaitForMultipleObjects(ULONG Count,
|
||||||
{
|
{
|
||||||
if (Count > THREAD_WAIT_OBJECTS)
|
if (Count > THREAD_WAIT_OBJECTS)
|
||||||
{
|
{
|
||||||
DbgPrint("(%s:%d) Too many objects!\n",
|
DPRINT("(%s:%d) Too many objects!\n", __FILE__, __LINE__);
|
||||||
__FILE__,__LINE__);
|
return (STATUS_UNSUCCESSFUL);
|
||||||
return(STATUS_UNSUCCESSFUL);
|
|
||||||
}
|
}
|
||||||
WaitBlockArray = &CurrentThread->WaitBlock[0];
|
WaitBlockArray = &CurrentThread->WaitBlock[0];
|
||||||
}
|
}
|
||||||
|
@ -589,16 +448,15 @@ KeWaitForMultipleObjects(ULONG Count,
|
||||||
{
|
{
|
||||||
if (Count > EX_MAXIMUM_WAIT_OBJECTS)
|
if (Count > EX_MAXIMUM_WAIT_OBJECTS)
|
||||||
{
|
{
|
||||||
DbgPrint("(%s:%d) Too many objects!\n",
|
DPRINT("(%s:%d) Too many objects!\n", __FILE__, __LINE__);
|
||||||
__FILE__,__LINE__);
|
return (STATUS_UNSUCCESSFUL);
|
||||||
return(STATUS_UNSUCCESSFUL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up the timeout if required
|
* Set up the timeout if required
|
||||||
*/
|
*/
|
||||||
if (Timeout != NULL)
|
if (Timeout != NULL && Timeout->QuadPart != 0)
|
||||||
{
|
{
|
||||||
KeInitializeTimer(&CurrentThread->Timer);
|
KeInitializeTimer(&CurrentThread->Timer);
|
||||||
KeSetTimer(&CurrentThread->Timer, *Timeout, NULL);
|
KeSetTimer(&CurrentThread->Timer, *Timeout, NULL);
|
||||||
|
@ -615,55 +473,85 @@ KeWaitForMultipleObjects(ULONG Count,
|
||||||
if (Alertable && KiTestAlert())
|
if (Alertable && KiTestAlert())
|
||||||
{
|
{
|
||||||
KeReleaseDispatcherDatabaseLock(FALSE);
|
KeReleaseDispatcherDatabaseLock(FALSE);
|
||||||
return(STATUS_USER_APC);
|
return (STATUS_USER_APC);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if the wait is already satisfied
|
* Check if the wait is (already) satisfied
|
||||||
*/
|
*/
|
||||||
|
CountSignaled = 0;
|
||||||
|
Abandoned = FALSE;
|
||||||
for (i = 0; i < Count; i++)
|
for (i = 0; i < Count; i++)
|
||||||
{
|
{
|
||||||
hdr = (DISPATCHER_HEADER *)Object[i];
|
hdr = (DISPATCHER_HEADER *) Object[i];
|
||||||
|
|
||||||
if (KiIsObjectSignalled(hdr, CurrentThread, &Abandoned))
|
if (KiIsObjectSignalled(hdr, CurrentThread))
|
||||||
{
|
{
|
||||||
CountSignaled++;
|
CountSignaled++;
|
||||||
|
|
||||||
if (WaitType == WaitAny)
|
if (WaitType == WaitAny)
|
||||||
{
|
{
|
||||||
if (Timeout != NULL)
|
Abandoned = KiSideEffectsBeforeWake(hdr, CurrentThread) ? TRUE : Abandoned;
|
||||||
|
|
||||||
|
if (Timeout != NULL && Timeout->QuadPart != 0)
|
||||||
{
|
{
|
||||||
KeCancelTimer(&CurrentThread->Timer);
|
KeCancelTimer(&CurrentThread->Timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
KeReleaseDispatcherDatabaseLock(FALSE);
|
KeReleaseDispatcherDatabaseLock(FALSE);
|
||||||
DPRINT("One object is already signaled!\n");
|
|
||||||
|
DPRINT("One object is (already) signaled!\n");
|
||||||
if (Abandoned == TRUE)
|
if (Abandoned == TRUE)
|
||||||
return(STATUS_ABANDONED_WAIT_0 + i);
|
{
|
||||||
return(STATUS_WAIT_0 + i);
|
return (STATUS_ABANDONED_WAIT_0 + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (STATUS_WAIT_0 + i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Abandoned = FALSE;
|
||||||
if ((WaitType == WaitAll) && (CountSignaled == Count))
|
if ((WaitType == WaitAll) && (CountSignaled == Count))
|
||||||
{
|
{
|
||||||
if (Timeout != NULL)
|
for (i = 0; i < Count; i++)
|
||||||
|
{
|
||||||
|
hdr = (DISPATCHER_HEADER *) Object[i];
|
||||||
|
Abandoned = KiSideEffectsBeforeWake(hdr, CurrentThread) ? TRUE : Abandoned;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Timeout != NULL && Timeout->QuadPart != 0)
|
||||||
{
|
{
|
||||||
KeCancelTimer(&CurrentThread->Timer);
|
KeCancelTimer(&CurrentThread->Timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
KeReleaseDispatcherDatabaseLock(FALSE);
|
KeReleaseDispatcherDatabaseLock(FALSE);
|
||||||
DPRINT("All objects are already signaled!\n");
|
DPRINT("All objects are (already) signaled!\n");
|
||||||
return(STATUS_WAIT_0);
|
|
||||||
|
if (Abandoned == TRUE)
|
||||||
|
{
|
||||||
|
return (STATUS_ABANDONED_WAIT_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (STATUS_WAIT_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//zero timeout is used for testing if the object(s) can be immediately acquired
|
||||||
|
if (Timeout != NULL && Timeout->QuadPart == 0)
|
||||||
|
{
|
||||||
|
KeReleaseDispatcherDatabaseLock(FALSE);
|
||||||
|
return STATUS_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if we have already timed out
|
* Check if we have already timed out
|
||||||
*/
|
*/
|
||||||
if (Timeout != NULL &&
|
if (Timeout != NULL && KiIsObjectSignalled(&CurrentThread->Timer.Header, CurrentThread))
|
||||||
KiIsObjectSignalled(&CurrentThread->Timer.Header, CurrentThread, NULL))
|
|
||||||
{
|
{
|
||||||
|
KiSideEffectsBeforeWake(&CurrentThread->Timer.Header, CurrentThread);
|
||||||
KeCancelTimer(&CurrentThread->Timer);
|
KeCancelTimer(&CurrentThread->Timer);
|
||||||
KeReleaseDispatcherDatabaseLock(FALSE);
|
KeReleaseDispatcherDatabaseLock(FALSE);
|
||||||
return(STATUS_TIMEOUT);
|
return (STATUS_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Append wait block to the KTHREAD wait block list */
|
/* Append wait block to the KTHREAD wait block list */
|
||||||
|
@ -673,14 +561,16 @@ KeWaitForMultipleObjects(ULONG Count,
|
||||||
* Set up the wait
|
* Set up the wait
|
||||||
*/
|
*/
|
||||||
CurrentThread->WaitStatus = STATUS_UNSUCCESSFUL;
|
CurrentThread->WaitStatus = STATUS_UNSUCCESSFUL;
|
||||||
|
|
||||||
for (i = 0; i < Count; i++)
|
for (i = 0; i < Count; i++)
|
||||||
{
|
{
|
||||||
hdr = (DISPATCHER_HEADER *)Object[i];
|
hdr = (DISPATCHER_HEADER *) Object[i];
|
||||||
|
|
||||||
blk->Object = Object[i];
|
blk->Object = Object[i];
|
||||||
blk->Thread = CurrentThread;
|
blk->Thread = CurrentThread;
|
||||||
blk->WaitKey = STATUS_WAIT_0 + i;
|
blk->WaitKey = STATUS_WAIT_0 + i;
|
||||||
blk->WaitType = WaitType;
|
blk->WaitType = WaitType;
|
||||||
|
|
||||||
if (i == (Count - 1))
|
if (i == (Count - 1))
|
||||||
{
|
{
|
||||||
if (Timeout != NULL)
|
if (Timeout != NULL)
|
||||||
|
@ -697,23 +587,27 @@ KeWaitForMultipleObjects(ULONG Count,
|
||||||
blk->NextWaitBlock = blk + 1;
|
blk->NextWaitBlock = blk + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//add wait block to disp. obj. wait list
|
||||||
InsertTailList(&hdr->WaitListHead, &blk->WaitListEntry);
|
InsertTailList(&hdr->WaitListHead, &blk->WaitListEntry);
|
||||||
|
|
||||||
blk = blk->NextWaitBlock;
|
blk = blk->NextWaitBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Timeout != NULL)
|
if (Timeout != NULL)
|
||||||
{
|
{
|
||||||
CurrentThread->WaitBlock[3].Object = (PVOID)&CurrentThread->Timer;
|
CurrentThread->WaitBlock[3].Object = (PVOID) & CurrentThread->Timer;
|
||||||
CurrentThread->WaitBlock[3].Thread = CurrentThread;
|
CurrentThread->WaitBlock[3].Thread = CurrentThread;
|
||||||
CurrentThread->WaitBlock[3].WaitKey = STATUS_TIMEOUT;
|
CurrentThread->WaitBlock[3].WaitKey = STATUS_TIMEOUT;
|
||||||
CurrentThread->WaitBlock[3].WaitType = WaitAny;
|
CurrentThread->WaitBlock[3].WaitType = WaitAny;
|
||||||
CurrentThread->WaitBlock[3].NextWaitBlock = NULL;
|
CurrentThread->WaitBlock[3].NextWaitBlock = NULL;
|
||||||
|
|
||||||
InsertTailList(&CurrentThread->Timer.Header.WaitListHead,
|
InsertTailList(&CurrentThread->Timer.Header.WaitListHead,
|
||||||
&CurrentThread->WaitBlock[3].WaitListEntry);
|
&CurrentThread->WaitBlock[3].WaitListEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
PsBlockThread(&Status, Alertable, WaitMode, TRUE, WaitIrql);
|
PsBlockThread(&Status, Alertable, WaitMode, TRUE, WaitIrql);
|
||||||
} while(Status == STATUS_KERNEL_APC);
|
}
|
||||||
|
while (Status == STATUS_KERNEL_APC);
|
||||||
|
|
||||||
if (Timeout != NULL)
|
if (Timeout != NULL)
|
||||||
{
|
{
|
||||||
|
@ -721,7 +615,7 @@ KeWaitForMultipleObjects(ULONG Count,
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINT("Returning from KeWaitForMultipleObjects()\n");
|
DPRINT("Returning from KeWaitForMultipleObjects()\n");
|
||||||
return(Status);
|
return (Status);
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID KeInitializeDispatcher(VOID)
|
VOID KeInitializeDispatcher(VOID)
|
||||||
|
@ -732,7 +626,7 @@ VOID KeInitializeDispatcher(VOID)
|
||||||
NTSTATUS STDCALL
|
NTSTATUS STDCALL
|
||||||
NtWaitForMultipleObjects(IN ULONG Count,
|
NtWaitForMultipleObjects(IN ULONG Count,
|
||||||
IN HANDLE Object [],
|
IN HANDLE Object [],
|
||||||
IN CINT WaitType,
|
IN WAIT_TYPE WaitType,
|
||||||
IN BOOLEAN Alertable,
|
IN BOOLEAN Alertable,
|
||||||
IN PLARGE_INTEGER Time)
|
IN PLARGE_INTEGER Time)
|
||||||
{
|
{
|
||||||
|
@ -740,6 +634,7 @@ NtWaitForMultipleObjects(IN ULONG Count,
|
||||||
PVOID ObjectPtrArray[EX_MAXIMUM_WAIT_OBJECTS];
|
PVOID ObjectPtrArray[EX_MAXIMUM_WAIT_OBJECTS];
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
ULONG i, j;
|
ULONG i, j;
|
||||||
|
KPROCESSOR_MODE WaitMode;
|
||||||
|
|
||||||
DPRINT("NtWaitForMultipleObjects(Count %lu Object[] %x, Alertable %d, "
|
DPRINT("NtWaitForMultipleObjects(Count %lu Object[] %x, Alertable %d, "
|
||||||
"Time %x)\n", Count,Object,Alertable,Time);
|
"Time %x)\n", Count,Object,Alertable,Time);
|
||||||
|
@ -747,13 +642,15 @@ NtWaitForMultipleObjects(IN ULONG Count,
|
||||||
if (Count > EX_MAXIMUM_WAIT_OBJECTS)
|
if (Count > EX_MAXIMUM_WAIT_OBJECTS)
|
||||||
return STATUS_UNSUCCESSFUL;
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
|
||||||
|
WaitMode = ExGetPreviousMode();
|
||||||
|
|
||||||
/* reference all objects */
|
/* reference all objects */
|
||||||
for (i = 0; i < Count; i++)
|
for (i = 0; i < Count; i++)
|
||||||
{
|
{
|
||||||
Status = ObReferenceObjectByHandle(Object[i],
|
Status = ObReferenceObjectByHandle(Object[i],
|
||||||
SYNCHRONIZE,
|
SYNCHRONIZE,
|
||||||
NULL,
|
NULL,
|
||||||
UserMode,
|
WaitMode,
|
||||||
&ObjectPtrArray[i],
|
&ObjectPtrArray[i],
|
||||||
NULL);
|
NULL);
|
||||||
if (Status != STATUS_SUCCESS)
|
if (Status != STATUS_SUCCESS)
|
||||||
|
@ -772,7 +669,7 @@ NtWaitForMultipleObjects(IN ULONG Count,
|
||||||
ObjectPtrArray,
|
ObjectPtrArray,
|
||||||
WaitType,
|
WaitType,
|
||||||
UserRequest,
|
UserRequest,
|
||||||
UserMode,
|
WaitMode,
|
||||||
Alertable,
|
Alertable,
|
||||||
Time,
|
Time,
|
||||||
WaitBlockArray);
|
WaitBlockArray);
|
||||||
|
@ -794,14 +691,17 @@ NtWaitForSingleObject(IN HANDLE Object,
|
||||||
{
|
{
|
||||||
PVOID ObjectPtr;
|
PVOID ObjectPtr;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
|
KPROCESSOR_MODE WaitMode;
|
||||||
|
|
||||||
DPRINT("NtWaitForSingleObject(Object %x, Alertable %d, Time %x)\n",
|
DPRINT("NtWaitForSingleObject(Object %x, Alertable %d, Time %x)\n",
|
||||||
Object,Alertable,Time);
|
Object,Alertable,Time);
|
||||||
|
|
||||||
|
WaitMode = ExGetPreviousMode();
|
||||||
|
|
||||||
Status = ObReferenceObjectByHandle(Object,
|
Status = ObReferenceObjectByHandle(Object,
|
||||||
SYNCHRONIZE,
|
SYNCHRONIZE,
|
||||||
NULL,
|
NULL,
|
||||||
UserMode,
|
WaitMode,
|
||||||
&ObjectPtr,
|
&ObjectPtr,
|
||||||
NULL);
|
NULL);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
|
@ -810,8 +710,8 @@ NtWaitForSingleObject(IN HANDLE Object,
|
||||||
}
|
}
|
||||||
|
|
||||||
Status = KeWaitForSingleObject(ObjectPtr,
|
Status = KeWaitForSingleObject(ObjectPtr,
|
||||||
UserMode,
|
UserRequest,
|
||||||
UserMode,
|
WaitMode,
|
||||||
Alertable,
|
Alertable,
|
||||||
Time);
|
Time);
|
||||||
|
|
||||||
|
@ -827,17 +727,17 @@ NtSignalAndWaitForSingleObject(IN HANDLE SignalObject,
|
||||||
IN BOOLEAN Alertable,
|
IN BOOLEAN Alertable,
|
||||||
IN PLARGE_INTEGER Time)
|
IN PLARGE_INTEGER Time)
|
||||||
{
|
{
|
||||||
KPROCESSOR_MODE ProcessorMode;
|
KPROCESSOR_MODE WaitMode;
|
||||||
DISPATCHER_HEADER* hdr;
|
DISPATCHER_HEADER* hdr;
|
||||||
PVOID SignalObj;
|
PVOID SignalObj;
|
||||||
PVOID WaitObj;
|
PVOID WaitObj;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
|
|
||||||
ProcessorMode = ExGetPreviousMode();
|
WaitMode = ExGetPreviousMode();
|
||||||
Status = ObReferenceObjectByHandle(SignalObject,
|
Status = ObReferenceObjectByHandle(SignalObject,
|
||||||
0,
|
0,
|
||||||
NULL,
|
NULL,
|
||||||
ProcessorMode,
|
WaitMode,
|
||||||
&SignalObj,
|
&SignalObj,
|
||||||
NULL);
|
NULL);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
|
@ -848,7 +748,7 @@ NtSignalAndWaitForSingleObject(IN HANDLE SignalObject,
|
||||||
Status = ObReferenceObjectByHandle(WaitObject,
|
Status = ObReferenceObjectByHandle(WaitObject,
|
||||||
SYNCHRONIZE,
|
SYNCHRONIZE,
|
||||||
NULL,
|
NULL,
|
||||||
ProcessorMode,
|
WaitMode,
|
||||||
&WaitObj,
|
&WaitObj,
|
||||||
NULL);
|
NULL);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
|
@ -887,7 +787,7 @@ NtSignalAndWaitForSingleObject(IN HANDLE SignalObject,
|
||||||
|
|
||||||
Status = KeWaitForSingleObject(WaitObj,
|
Status = KeWaitForSingleObject(WaitObj,
|
||||||
UserRequest,
|
UserRequest,
|
||||||
ProcessorMode,
|
WaitMode,
|
||||||
Alertable,
|
Alertable,
|
||||||
Time);
|
Time);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue