mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 19:22:58 +00:00
- Completely reimplement NtWaitForMultipleObjects:
- Check for invalid Objectcount and wait type - Don't use 2.6KB of stack space (kernel threads only get 4...) - Don't call ObReferenceObjectByHandle since it does a lot of superflous checks, continous locking/unlocking and makes us extremly slow for a large wait and also doesn't give us the full flexibility we need. - Detect if a Waitall is being done with the same object duplicated. - Protect wait with SEH. - General fixes for all NtWaitXXX: - Use DefaultObject from Object Header and remove all previous associated hacks, including the IO_TYPE hack. The DefaultObject will either be NULL, an offset to an internal Object Event, or a pointer to a default event. We handle all three. - Guard the KeWaitXXX call with SEH since it can raise exceptions. - Fix all object type intiailizers regarding DefaultObject. svn path=/trunk/; revision=17179
This commit is contained in:
parent
a6b3bd07b6
commit
4c1eb86320
12 changed files with 350 additions and 271 deletions
|
@ -91,7 +91,6 @@ ExpInitializeCallbacks(VOID)
|
||||||
ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(CALLBACK_OBJECT);
|
ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(CALLBACK_OBJECT);
|
||||||
ObjectTypeInitializer.GenericMapping = ExpCallbackMapping;
|
ObjectTypeInitializer.GenericMapping = ExpCallbackMapping;
|
||||||
ObjectTypeInitializer.PoolType = NonPagedPool;
|
ObjectTypeInitializer.PoolType = NonPagedPool;
|
||||||
ObjectTypeInitializer.UseDefaultObject = TRUE;
|
|
||||||
|
|
||||||
Status = ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ExCallbackObjectType);
|
Status = ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ExCallbackObjectType);
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,6 @@ ExpInitializeEventImplementation(VOID)
|
||||||
ObjectTypeInitializer.GenericMapping = ExpEventMapping;
|
ObjectTypeInitializer.GenericMapping = ExpEventMapping;
|
||||||
ObjectTypeInitializer.PoolType = NonPagedPool;
|
ObjectTypeInitializer.PoolType = NonPagedPool;
|
||||||
ObjectTypeInitializer.ValidAccessMask = EVENT_ALL_ACCESS;
|
ObjectTypeInitializer.ValidAccessMask = EVENT_ALL_ACCESS;
|
||||||
ObjectTypeInitializer.UseDefaultObject = TRUE;
|
|
||||||
ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ExEventObjectType);
|
ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ExEventObjectType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,6 @@ ExpInitializeMutantImplementation(VOID)
|
||||||
ObjectTypeInitializer.PoolType = NonPagedPool;
|
ObjectTypeInitializer.PoolType = NonPagedPool;
|
||||||
ObjectTypeInitializer.DeleteProcedure = ExpDeleteMutant;
|
ObjectTypeInitializer.DeleteProcedure = ExpDeleteMutant;
|
||||||
ObjectTypeInitializer.ValidAccessMask = MUTANT_ALL_ACCESS;
|
ObjectTypeInitializer.ValidAccessMask = MUTANT_ALL_ACCESS;
|
||||||
ObjectTypeInitializer.UseDefaultObject = TRUE;
|
|
||||||
ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ExMutantObjectType);
|
ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ExMutantObjectType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,6 @@ ExpInitializeProfileImplementation(VOID)
|
||||||
ObjectTypeInitializer.PoolType = NonPagedPool;
|
ObjectTypeInitializer.PoolType = NonPagedPool;
|
||||||
ObjectTypeInitializer.DeleteProcedure = ExpDeleteProfile;
|
ObjectTypeInitializer.DeleteProcedure = ExpDeleteProfile;
|
||||||
ObjectTypeInitializer.ValidAccessMask = STANDARD_RIGHTS_ALL;
|
ObjectTypeInitializer.ValidAccessMask = STANDARD_RIGHTS_ALL;
|
||||||
ObjectTypeInitializer.UseDefaultObject = TRUE;
|
|
||||||
ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ExProfileObjectType);
|
ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ExProfileObjectType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -133,7 +133,6 @@ ExpWin32kInit(VOID)
|
||||||
ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
|
ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
|
||||||
ObjectTypeInitializer.GenericMapping = ExpWindowStationMapping;
|
ObjectTypeInitializer.GenericMapping = ExpWindowStationMapping;
|
||||||
ObjectTypeInitializer.PoolType = NonPagedPool;
|
ObjectTypeInitializer.PoolType = NonPagedPool;
|
||||||
ObjectTypeInitializer.UseDefaultObject = TRUE;
|
|
||||||
ObjectTypeInitializer.OpenProcedure = ExpWinStaObjectOpen;
|
ObjectTypeInitializer.OpenProcedure = ExpWinStaObjectOpen;
|
||||||
ObjectTypeInitializer.DeleteProcedure = ExpWinStaObjectDelete;
|
ObjectTypeInitializer.DeleteProcedure = ExpWinStaObjectDelete;
|
||||||
ObjectTypeInitializer.ParseProcedure = ExpWinStaObjectParse;
|
ObjectTypeInitializer.ParseProcedure = ExpWinStaObjectParse;
|
||||||
|
|
|
@ -8,6 +8,13 @@ extern LARGE_INTEGER ExpTimeZoneBias;
|
||||||
extern ULONG ExpTimeZoneId;
|
extern ULONG ExpTimeZoneId;
|
||||||
extern POBJECT_TYPE ExEventPairObjectType;
|
extern POBJECT_TYPE ExEventPairObjectType;
|
||||||
|
|
||||||
|
#define EX_OBJ_TO_HDR(eob) ((POBJECT_HEADER)((ULONG_PTR)(eob) & \
|
||||||
|
~(EX_HANDLE_ENTRY_PROTECTFROMCLOSE | EX_HANDLE_ENTRY_INHERITABLE | \
|
||||||
|
EX_HANDLE_ENTRY_AUDITONCLOSE)))
|
||||||
|
#define EX_HTE_TO_HDR(hte) ((POBJECT_HEADER)((ULONG_PTR)((hte)->u1.Object) & \
|
||||||
|
~(EX_HANDLE_ENTRY_PROTECTFROMCLOSE | EX_HANDLE_ENTRY_INHERITABLE | \
|
||||||
|
EX_HANDLE_ENTRY_AUDITONCLOSE)))
|
||||||
|
|
||||||
/* INITIALIZATION FUNCTIONS *************************************************/
|
/* INITIALIZATION FUNCTIONS *************************************************/
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
|
|
|
@ -18,8 +18,6 @@
|
||||||
#include <ndk/ntndk.h>
|
#include <ndk/ntndk.h>
|
||||||
#include <ndk/sysguid.h>
|
#include <ndk/sysguid.h>
|
||||||
#include <ndk/asm.h>
|
#include <ndk/asm.h>
|
||||||
#undef IO_TYPE_FILE
|
|
||||||
#define IO_TYPE_FILE 0x0F5L /* Temp Hack */
|
|
||||||
|
|
||||||
/* FIXME: Temporary until CC Ros is gone */
|
/* FIXME: Temporary until CC Ros is gone */
|
||||||
#include <ccros.h>
|
#include <ccros.h>
|
||||||
|
|
|
@ -217,6 +217,7 @@ IoInit (VOID)
|
||||||
ObjectTypeInitializer.DeleteProcedure = IopDeleteFile;
|
ObjectTypeInitializer.DeleteProcedure = IopDeleteFile;
|
||||||
ObjectTypeInitializer.SecurityProcedure = IopSecurityFile;
|
ObjectTypeInitializer.SecurityProcedure = IopSecurityFile;
|
||||||
ObjectTypeInitializer.QueryNameProcedure = IopQueryNameFile;
|
ObjectTypeInitializer.QueryNameProcedure = IopQueryNameFile;
|
||||||
|
ObjectTypeInitializer.UseDefaultObject = FALSE;
|
||||||
ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &IoFileObjectType);
|
ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &IoFileObjectType);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -225,22 +225,6 @@ KeWaitForSingleObject(PVOID Object,
|
||||||
/* Get the Current Object */
|
/* Get the Current Object */
|
||||||
CurrentObject = (PDISPATCHER_HEADER)Object;
|
CurrentObject = (PDISPATCHER_HEADER)Object;
|
||||||
|
|
||||||
/* FIXME:
|
|
||||||
* Temporary hack until my Object Manager re-write. Basically some objects, like
|
|
||||||
* the File Object, but also LPCs and others, are actually waitable on their event.
|
|
||||||
* The Object Manager sets this up in The ObjectTypeInformation->DefaultObject member,
|
|
||||||
* by using pretty much the same kind of hack as us. Normal objects point to themselves
|
|
||||||
* in that pointer. Then, NtWaitForXXX will populate the WaitList that gets sent to us by
|
|
||||||
* using ->DefaultObject, so the proper actual objects will be sent to us. Until then however,
|
|
||||||
* I will keep this hack here, since there's no need to make an interim hack until the rewrite
|
|
||||||
* -- Alex Ionescu 24/02/05
|
|
||||||
*/
|
|
||||||
if (CurrentObject->Type == IO_TYPE_FILE) {
|
|
||||||
|
|
||||||
DPRINT1("Hack used: %x\n", &((PFILE_OBJECT)CurrentObject)->Event);
|
|
||||||
CurrentObject = (PDISPATCHER_HEADER)(&((PFILE_OBJECT)CurrentObject)->Event);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if the Object is Signaled */
|
/* Check if the Object is Signaled */
|
||||||
if (KiIsObjectSignaled(CurrentObject, CurrentThread)) {
|
if (KiIsObjectSignaled(CurrentObject, CurrentThread)) {
|
||||||
|
|
||||||
|
@ -441,21 +425,6 @@ KeWaitForMultipleObjects(ULONG Count,
|
||||||
/* Get the Current Object */
|
/* Get the Current Object */
|
||||||
CurrentObject = (PDISPATCHER_HEADER)Object[WaitIndex];
|
CurrentObject = (PDISPATCHER_HEADER)Object[WaitIndex];
|
||||||
|
|
||||||
/* FIXME:
|
|
||||||
* Temporary hack until my Object Manager re-write. Basically some objects, like
|
|
||||||
* the File Object, but also LPCs and others, are actually waitable on their event.
|
|
||||||
* The Object Manager sets this up in The ObjectTypeInformation->DefaultObject member,
|
|
||||||
* by using pretty much the same kind of hack as us. Normal objects point to themselves
|
|
||||||
* in that pointer. Then, NtWaitForXXX will populate the WaitList that gets sent to us by
|
|
||||||
* using ->DefaultObject, so the proper actual objects will be sent to us. Until then however,
|
|
||||||
* I will keep this hack here, since there's no need to make an interim hack until the rewrite
|
|
||||||
* -- Alex Ionescu 24/02/05
|
|
||||||
*/
|
|
||||||
if (CurrentObject->Type == IO_TYPE_FILE) {
|
|
||||||
|
|
||||||
CurrentObject = (PDISPATCHER_HEADER)(&((PFILE_OBJECT)CurrentObject)->Event);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if the Object is Signaled */
|
/* Check if the Object is Signaled */
|
||||||
if (KiIsObjectSignaled(CurrentObject, CurrentThread)) {
|
if (KiIsObjectSignaled(CurrentObject, CurrentThread)) {
|
||||||
|
|
||||||
|
@ -807,31 +776,6 @@ KiIsObjectSignaled(PDISPATCHER_HEADER Object,
|
||||||
return (!Object->SignalState <= 0);
|
return (!Object->SignalState <= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL
|
|
||||||
inline
|
|
||||||
FASTCALL
|
|
||||||
KiIsObjectWaitable(PVOID Object)
|
|
||||||
{
|
|
||||||
POBJECT_HEADER Header;
|
|
||||||
Header = BODY_TO_HEADER(Object);
|
|
||||||
|
|
||||||
if (Header->Type == ExEventObjectType ||
|
|
||||||
Header->Type == IoCompletionType ||
|
|
||||||
Header->Type == ExMutantObjectType ||
|
|
||||||
Header->Type == ExSemaphoreObjectType ||
|
|
||||||
Header->Type == ExTimerType ||
|
|
||||||
Header->Type == PsProcessType ||
|
|
||||||
Header->Type == PsThreadType ||
|
|
||||||
Header->Type == IoFileObjectType) {
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
inline
|
inline
|
||||||
FASTCALL
|
FASTCALL
|
||||||
|
|
|
@ -33,13 +33,6 @@
|
||||||
#define NDEBUG
|
#define NDEBUG
|
||||||
#include <internal/debug.h>
|
#include <internal/debug.h>
|
||||||
|
|
||||||
#define EX_OBJ_TO_HDR(eob) ((POBJECT_HEADER)((ULONG_PTR)(eob) & \
|
|
||||||
~(EX_HANDLE_ENTRY_PROTECTFROMCLOSE | EX_HANDLE_ENTRY_INHERITABLE | \
|
|
||||||
EX_HANDLE_ENTRY_AUDITONCLOSE)))
|
|
||||||
#define EX_HTE_TO_HDR(hte) ((POBJECT_HEADER)((ULONG_PTR)((hte)->u1.Object) & \
|
|
||||||
~(EX_HANDLE_ENTRY_PROTECTFROMCLOSE | EX_HANDLE_ENTRY_INHERITABLE | \
|
|
||||||
EX_HANDLE_ENTRY_AUDITONCLOSE)))
|
|
||||||
|
|
||||||
#define GENERIC_ANY (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL)
|
#define GENERIC_ANY (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL)
|
||||||
|
|
||||||
/* GLOBALS *****************************************************************/
|
/* GLOBALS *****************************************************************/
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* FILE: ntoskrnl/ob/wait.c
|
* FILE: ntoskrnl/ob/wait.c
|
||||||
* PURPOSE: Handles Waiting on Objects
|
* PURPOSE: Handles Waiting on Objects
|
||||||
*
|
*
|
||||||
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net) - Created file
|
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
|
||||||
* David Welch (welch@mcmail.com)
|
* David Welch (welch@mcmail.com)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -14,188 +14,322 @@
|
||||||
#define NDEBUG
|
#define NDEBUG
|
||||||
#include <internal/debug.h>
|
#include <internal/debug.h>
|
||||||
|
|
||||||
|
#define TAG_WAIT TAG('W', 'a', 'i', 't')
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
BOOL inline FASTCALL KiIsObjectWaitable(PVOID Object);
|
NTSTATUS
|
||||||
|
STDCALL
|
||||||
NTSTATUS STDCALL
|
|
||||||
NtWaitForMultipleObjects(IN ULONG ObjectCount,
|
NtWaitForMultipleObjects(IN ULONG ObjectCount,
|
||||||
IN PHANDLE ObjectsArray,
|
IN PHANDLE HandleArray,
|
||||||
IN WAIT_TYPE WaitType,
|
IN WAIT_TYPE WaitType,
|
||||||
IN BOOLEAN Alertable,
|
IN BOOLEAN Alertable,
|
||||||
IN PLARGE_INTEGER TimeOut OPTIONAL)
|
IN PLARGE_INTEGER TimeOut OPTIONAL)
|
||||||
{
|
{
|
||||||
KWAIT_BLOCK WaitBlockArray[MAXIMUM_WAIT_OBJECTS];
|
PKWAIT_BLOCK WaitBlockArray = NULL;
|
||||||
HANDLE SafeObjectsArray[MAXIMUM_WAIT_OBJECTS];
|
HANDLE Handles[MAXIMUM_WAIT_OBJECTS];
|
||||||
PVOID ObjectPtrArray[MAXIMUM_WAIT_OBJECTS];
|
PVOID Objects[MAXIMUM_WAIT_OBJECTS];
|
||||||
ULONG i, j;
|
PVOID WaitObjects[MAXIMUM_WAIT_OBJECTS];
|
||||||
KPROCESSOR_MODE PreviousMode;
|
ULONG i = 0, ReferencedObjects = 0, j;
|
||||||
LARGE_INTEGER SafeTimeOut;
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||||
NTSTATUS Status = STATUS_SUCCESS;
|
LARGE_INTEGER SafeTimeOut;
|
||||||
|
BOOLEAN LockInUse;
|
||||||
|
PHANDLE_TABLE_ENTRY HandleEntry;
|
||||||
|
POBJECT_HEADER ObjectHeader;
|
||||||
|
PHANDLE_TABLE HandleTable;
|
||||||
|
ACCESS_MASK GrantedAccess;
|
||||||
|
LONG ExHandle;
|
||||||
|
PVOID DefaultObject;
|
||||||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
DPRINT("NtWaitForMultipleObjects(ObjectCount %lu ObjectsArray[] %x, Alertable %d, "
|
DPRINT("NtWaitForMultipleObjects(ObjectCount %lu HandleArray[] %x, Alertable %d, "
|
||||||
"TimeOut %x)\n", ObjectCount,ObjectsArray,Alertable,TimeOut);
|
"TimeOut %x)\n", ObjectCount, HandleArray, Alertable, TimeOut);
|
||||||
|
|
||||||
PreviousMode = ExGetPreviousMode();
|
/* Enter a critical region since we'll play with handles */
|
||||||
|
LockInUse = TRUE;
|
||||||
|
KeEnterCriticalRegion();
|
||||||
|
|
||||||
if (ObjectCount > MAXIMUM_WAIT_OBJECTS)
|
/* Check for valid Object Count */
|
||||||
return STATUS_UNSUCCESSFUL;
|
if ((ObjectCount > MAXIMUM_WAIT_OBJECTS) || !ObjectCount)
|
||||||
if (0 == ObjectCount)
|
{
|
||||||
return STATUS_INVALID_PARAMETER;
|
Status = STATUS_INVALID_PARAMETER_1;
|
||||||
|
DPRINT1("No object count, or too many objects\n");
|
||||||
|
goto Quickie;
|
||||||
|
}
|
||||||
|
|
||||||
if(PreviousMode != KernelMode)
|
/* Check for valid Wait Type */
|
||||||
{
|
if ((WaitType != WaitAll) && (WaitType != WaitAny))
|
||||||
_SEH_TRY
|
{
|
||||||
{
|
Status = STATUS_INVALID_PARAMETER_3;
|
||||||
ProbeForRead(ObjectsArray,
|
DPRINT1("Invalid wait type\n");
|
||||||
ObjectCount * sizeof(ObjectsArray[0]),
|
goto Quickie;
|
||||||
sizeof(ULONG));
|
}
|
||||||
/* make a copy so we don't have to guard with SEH later and keep track of
|
|
||||||
what objects we referenced in case dereferencing pointers suddenly fails */
|
|
||||||
RtlCopyMemory(SafeObjectsArray, ObjectsArray, ObjectCount * sizeof(ObjectsArray[0]));
|
|
||||||
ObjectsArray = SafeObjectsArray;
|
|
||||||
|
|
||||||
if(TimeOut != NULL)
|
/* Capture arguments */
|
||||||
{
|
_SEH_TRY
|
||||||
ProbeForRead(TimeOut,
|
{
|
||||||
sizeof(LARGE_INTEGER),
|
if(PreviousMode != KernelMode)
|
||||||
sizeof(ULONG));
|
{
|
||||||
/* make a local copy of the timeout on the stack */
|
ProbeForRead(HandleArray,
|
||||||
SafeTimeOut = *TimeOut;
|
ObjectCount * sizeof(HANDLE),
|
||||||
TimeOut = &SafeTimeOut;
|
sizeof(HANDLE));
|
||||||
}
|
|
||||||
}
|
if(TimeOut)
|
||||||
_SEH_HANDLE
|
{
|
||||||
{
|
ProbeForRead(TimeOut,
|
||||||
Status = _SEH_GetExceptionCode();
|
sizeof(LARGE_INTEGER),
|
||||||
}
|
sizeof(ULONG));
|
||||||
_SEH_END;
|
|
||||||
|
|
||||||
if(!NT_SUCCESS(Status))
|
/* Make a local copy of the timeout on the stack */
|
||||||
{
|
SafeTimeOut = *TimeOut;
|
||||||
return Status;
|
TimeOut = &SafeTimeOut;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* reference all objects */
|
/*
|
||||||
for (i = 0; i < ObjectCount; i++)
|
* Make a copy so we don't have to guard with SEH later and keep
|
||||||
{
|
* track of what objects we referenced if dereferencing pointers
|
||||||
Status = ObReferenceObjectByHandle(ObjectsArray[i],
|
* suddenly fails
|
||||||
SYNCHRONIZE,
|
*/
|
||||||
NULL,
|
RtlCopyMemory(Handles,
|
||||||
PreviousMode,
|
HandleArray,
|
||||||
&ObjectPtrArray[i],
|
ObjectCount * sizeof(HANDLE));
|
||||||
NULL);
|
}
|
||||||
if (!NT_SUCCESS(Status) || !KiIsObjectWaitable(ObjectPtrArray[i]))
|
_SEH_HANDLE
|
||||||
{
|
{
|
||||||
if (NT_SUCCESS(Status))
|
Status = _SEH_GetExceptionCode();
|
||||||
{
|
}
|
||||||
DPRINT1("Waiting for object type '%wZ' is not supported\n",
|
_SEH_END;
|
||||||
&BODY_TO_HEADER(ObjectPtrArray[i])->Type->Name);
|
|
||||||
Status = STATUS_INVALID_HANDLE;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
/* dereference all referenced objects */
|
|
||||||
for (j = 0; j < i; j++)
|
|
||||||
{
|
|
||||||
ObDereferenceObject(ObjectPtrArray[j]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return(Status);
|
if(!NT_SUCCESS(Status)) goto Quickie;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Status = KeWaitForMultipleObjects(ObjectCount,
|
/* Check if we can use the internal Wait Array */
|
||||||
ObjectPtrArray,
|
if (ObjectCount > THREAD_WAIT_OBJECTS)
|
||||||
WaitType,
|
{
|
||||||
UserRequest,
|
/* Allocate from Pool */
|
||||||
PreviousMode,
|
WaitBlockArray = ExAllocatePoolWithTag(NonPagedPool,
|
||||||
Alertable,
|
ObjectCount * sizeof(KWAIT_BLOCK),
|
||||||
TimeOut,
|
TAG_WAIT);
|
||||||
WaitBlockArray);
|
}
|
||||||
|
|
||||||
/* dereference all objects */
|
/* Start the loop */
|
||||||
for (i = 0; i < ObjectCount; i++)
|
do
|
||||||
{
|
{
|
||||||
ObDereferenceObject(ObjectPtrArray[i]);
|
/* Use the right Executive Handle */
|
||||||
}
|
if(ObIsKernelHandle(Handles[i], PreviousMode))
|
||||||
|
{
|
||||||
|
/* Use the System Handle Table and decode */
|
||||||
|
HandleTable = ObpKernelHandleTable;
|
||||||
|
ExHandle = HANDLE_TO_EX_HANDLE(ObKernelHandleToHandle(Handles[i]));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Use the Process' Handle table and get the Ex Handle */
|
||||||
|
HandleTable = PsGetCurrentProcess()->ObjectTable;
|
||||||
|
ExHandle = HANDLE_TO_EX_HANDLE(Handles[i]);
|
||||||
|
}
|
||||||
|
|
||||||
return(Status);
|
/* Get a pointer to it */
|
||||||
|
if (!(HandleEntry = ExMapHandleToPointer(HandleTable, ExHandle)))
|
||||||
|
{
|
||||||
|
DPRINT1("Invalid handle\n");
|
||||||
|
Status = STATUS_INVALID_HANDLE;
|
||||||
|
goto Quickie;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for synchronize access */
|
||||||
|
GrantedAccess = HandleEntry->u2.GrantedAccess;
|
||||||
|
if ((PreviousMode != KernelMode) && (!(GrantedAccess & SYNCHRONIZE)))
|
||||||
|
{
|
||||||
|
/* Unlock the entry and fail */
|
||||||
|
ExUnlockHandleTableEntry(HandleTable, HandleEntry);
|
||||||
|
Status = STATUS_ACCESS_DENIED;
|
||||||
|
DPRINT1("Handle doesn't have SYNCH access\n");
|
||||||
|
goto Quickie;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the Object Header */
|
||||||
|
ObjectHeader = EX_HTE_TO_HDR(HandleEntry);
|
||||||
|
|
||||||
|
/* Get default Object */
|
||||||
|
DefaultObject = ObjectHeader->Type->DefaultObject;
|
||||||
|
|
||||||
|
/* Check if it's the internal offset */
|
||||||
|
if ((LONG_PTR)DefaultObject >= 0)
|
||||||
|
{
|
||||||
|
/* Increase reference count */
|
||||||
|
InterlockedIncrement(&ObjectHeader->PointerCount);
|
||||||
|
ReferencedObjects++;
|
||||||
|
|
||||||
|
/* Save the Object and Wait Object, this is a relative offset */
|
||||||
|
Objects[i] = &ObjectHeader->Body;
|
||||||
|
WaitObjects[i] = (PVOID)((ULONG_PTR)&ObjectHeader->Body +
|
||||||
|
(ULONG_PTR)DefaultObject);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* This is our internal Object */
|
||||||
|
ReferencedObjects++;
|
||||||
|
Objects[i] = NULL;
|
||||||
|
WaitObjects[i] = DefaultObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unlock the Handle Table Entry */
|
||||||
|
ExUnlockHandleTableEntry(HandleTable, HandleEntry);
|
||||||
|
|
||||||
|
/* Keep looping */
|
||||||
|
i++;
|
||||||
|
} while (i < ObjectCount);
|
||||||
|
|
||||||
|
/* For a Waitall, we can't have the same object more then once */
|
||||||
|
if (WaitType == WaitAll)
|
||||||
|
{
|
||||||
|
/* Start the loop */
|
||||||
|
do
|
||||||
|
{
|
||||||
|
/* Check the current and forward object */
|
||||||
|
for (i = 0, j = i + 1; j < ObjectCount; j++)
|
||||||
|
{
|
||||||
|
/* Make sure they don't match */
|
||||||
|
if (WaitObjects[i] == WaitObjects[j])
|
||||||
|
{
|
||||||
|
/* Fail */
|
||||||
|
Status = STATUS_INVALID_PARAMETER_MIX;
|
||||||
|
DPRINT1("Objects duplicated with WaitAll\n");
|
||||||
|
goto Quickie;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keep looping */
|
||||||
|
i++;
|
||||||
|
} while (i < ObjectCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now we can finally wait. Use SEH since it can raise an exception */
|
||||||
|
_SEH_TRY
|
||||||
|
{
|
||||||
|
/* We're done playing with handles */
|
||||||
|
LockInUse = FALSE;
|
||||||
|
KeLeaveCriticalRegion();
|
||||||
|
|
||||||
|
/* Do the kernel wait */
|
||||||
|
Status = KeWaitForMultipleObjects(ObjectCount,
|
||||||
|
WaitObjects,
|
||||||
|
WaitType,
|
||||||
|
UserRequest,
|
||||||
|
PreviousMode,
|
||||||
|
Alertable,
|
||||||
|
TimeOut,
|
||||||
|
WaitBlockArray);
|
||||||
|
}
|
||||||
|
_SEH_HANDLE
|
||||||
|
{
|
||||||
|
Status = _SEH_GetExceptionCode();
|
||||||
|
}
|
||||||
|
_SEH_END;
|
||||||
|
|
||||||
|
Quickie:
|
||||||
|
/* First derefence */
|
||||||
|
while (ReferencedObjects)
|
||||||
|
{
|
||||||
|
ReferencedObjects--;
|
||||||
|
if (Objects[ReferencedObjects])
|
||||||
|
{
|
||||||
|
ObDereferenceObject(Objects[ReferencedObjects]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free wait block array */
|
||||||
|
if (WaitBlockArray) ExFreePool(WaitBlockArray);
|
||||||
|
|
||||||
|
/* Re-enable APCs if needed */
|
||||||
|
if (LockInUse) KeLeaveCriticalRegion();
|
||||||
|
|
||||||
|
/* Return status */
|
||||||
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @implemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
NTSTATUS STDCALL
|
NTSTATUS
|
||||||
|
STDCALL
|
||||||
NtWaitForSingleObject(IN HANDLE ObjectHandle,
|
NtWaitForSingleObject(IN HANDLE ObjectHandle,
|
||||||
IN BOOLEAN Alertable,
|
IN BOOLEAN Alertable,
|
||||||
IN PLARGE_INTEGER TimeOut OPTIONAL)
|
IN PLARGE_INTEGER TimeOut OPTIONAL)
|
||||||
{
|
{
|
||||||
PVOID ObjectPtr;
|
PVOID Object, WaitableObject;
|
||||||
KPROCESSOR_MODE PreviousMode;
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||||
LARGE_INTEGER SafeTimeOut;
|
LARGE_INTEGER SafeTimeOut;
|
||||||
NTSTATUS Status = STATUS_SUCCESS;
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
DPRINT("NtWaitForSingleObject(ObjectHandle %x, Alertable %d, TimeOut %x)\n",
|
DPRINT("NtWaitForSingleObject(ObjectHandle %x, Alertable %d, TimeOut %x)\n",
|
||||||
ObjectHandle,Alertable,TimeOut);
|
ObjectHandle,Alertable,TimeOut);
|
||||||
|
|
||||||
PreviousMode = ExGetPreviousMode();
|
/* Capture timeout */
|
||||||
|
if(TimeOut && PreviousMode != KernelMode)
|
||||||
|
{
|
||||||
|
_SEH_TRY
|
||||||
|
{
|
||||||
|
ProbeForRead(TimeOut,
|
||||||
|
sizeof(LARGE_INTEGER),
|
||||||
|
sizeof(ULONG));
|
||||||
|
/* Make a copy on the stack */
|
||||||
|
SafeTimeOut = *TimeOut;
|
||||||
|
TimeOut = &SafeTimeOut;
|
||||||
|
}
|
||||||
|
_SEH_HANDLE
|
||||||
|
{
|
||||||
|
Status = _SEH_GetExceptionCode();
|
||||||
|
}
|
||||||
|
_SEH_END;
|
||||||
|
|
||||||
if(TimeOut != NULL && PreviousMode != KernelMode)
|
if(!NT_SUCCESS(Status)) return Status;
|
||||||
{
|
}
|
||||||
_SEH_TRY
|
|
||||||
{
|
|
||||||
ProbeForRead(TimeOut,
|
|
||||||
sizeof(LARGE_INTEGER),
|
|
||||||
sizeof(ULONG));
|
|
||||||
/* make a copy on the stack */
|
|
||||||
SafeTimeOut = *TimeOut;
|
|
||||||
TimeOut = &SafeTimeOut;
|
|
||||||
}
|
|
||||||
_SEH_HANDLE
|
|
||||||
{
|
|
||||||
Status = _SEH_GetExceptionCode();
|
|
||||||
}
|
|
||||||
_SEH_END;
|
|
||||||
|
|
||||||
if(!NT_SUCCESS(Status))
|
/* Get the Object */
|
||||||
{
|
Status = ObReferenceObjectByHandle(ObjectHandle,
|
||||||
return Status;
|
SYNCHRONIZE,
|
||||||
}
|
NULL,
|
||||||
}
|
PreviousMode,
|
||||||
|
&Object,
|
||||||
|
NULL);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* Get the Waitable Object */
|
||||||
|
WaitableObject = BODY_TO_HEADER(Object)->Type->DefaultObject;
|
||||||
|
|
||||||
Status = ObReferenceObjectByHandle(ObjectHandle,
|
/* Is it an offset for internal objects? */
|
||||||
SYNCHRONIZE,
|
if ((LONG_PTR)WaitableObject >= 0)
|
||||||
NULL,
|
{
|
||||||
PreviousMode,
|
/* Turn it into a pointer */
|
||||||
&ObjectPtr,
|
WaitableObject = (PVOID)((ULONG_PTR)Object +
|
||||||
NULL);
|
(ULONG_PTR)WaitableObject);
|
||||||
if (!NT_SUCCESS(Status))
|
}
|
||||||
{
|
|
||||||
return(Status);
|
|
||||||
}
|
|
||||||
if (!KiIsObjectWaitable(ObjectPtr))
|
|
||||||
{
|
|
||||||
DPRINT1("Waiting for object type '%wZ' is not supported\n",
|
|
||||||
&BODY_TO_HEADER(ObjectPtr)->Type->Name);
|
|
||||||
Status = STATUS_INVALID_HANDLE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Status = KeWaitForSingleObject(ObjectPtr,
|
|
||||||
UserRequest,
|
|
||||||
PreviousMode,
|
|
||||||
Alertable,
|
|
||||||
TimeOut);
|
|
||||||
}
|
|
||||||
|
|
||||||
ObDereferenceObject(ObjectPtr);
|
/* Now wait. Also SEH this since it can also raise an exception */
|
||||||
|
_SEH_TRY
|
||||||
|
{
|
||||||
|
Status = KeWaitForSingleObject(WaitableObject,
|
||||||
|
UserRequest,
|
||||||
|
PreviousMode,
|
||||||
|
Alertable,
|
||||||
|
TimeOut);
|
||||||
|
}
|
||||||
|
_SEH_HANDLE
|
||||||
|
{
|
||||||
|
Status = _SEH_GetExceptionCode();
|
||||||
|
}
|
||||||
|
_SEH_END;
|
||||||
|
|
||||||
return(Status);
|
/* Dereference the Object */
|
||||||
|
ObDereferenceObject(Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the status */
|
||||||
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
STDCALL
|
STDCALL
|
||||||
NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal,
|
NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal,
|
||||||
|
@ -204,15 +338,17 @@ NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal,
|
||||||
IN PLARGE_INTEGER TimeOut OPTIONAL)
|
IN PLARGE_INTEGER TimeOut OPTIONAL)
|
||||||
{
|
{
|
||||||
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||||
PDISPATCHER_HEADER Header;
|
POBJECT_TYPE Type;
|
||||||
PVOID SignalObj;
|
PVOID SignalObj;
|
||||||
PVOID WaitObj;
|
PVOID WaitObj;
|
||||||
|
PVOID WaitableObject;
|
||||||
LARGE_INTEGER SafeTimeOut;
|
LARGE_INTEGER SafeTimeOut;
|
||||||
OBJECT_HANDLE_INFORMATION HandleInfo;
|
OBJECT_HANDLE_INFORMATION HandleInfo;
|
||||||
NTSTATUS Status = STATUS_SUCCESS;
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
/* Capture timeout */
|
/* Capture timeout */
|
||||||
if(!TimeOut && PreviousMode != KernelMode)
|
DPRINT("NtSignalAndWaitForSingleObject\n");
|
||||||
|
if(TimeOut && PreviousMode != KernelMode)
|
||||||
{
|
{
|
||||||
_SEH_TRY
|
_SEH_TRY
|
||||||
{
|
{
|
||||||
|
@ -257,58 +393,65 @@ NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal,
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: Use DefaultObject from ObjectHeader */
|
/* Get the real waitable object */
|
||||||
Header = (PDISPATCHER_HEADER)SignalObj;
|
WaitableObject = BODY_TO_HEADER(WaitObj)->Type->DefaultObject;
|
||||||
|
|
||||||
/* Check dispatcher type */
|
/* Handle internal offset */
|
||||||
/* FIXME: Check Object Type instead! */
|
if ((LONG_PTR)WaitableObject >= 0)
|
||||||
switch (Header->Type)
|
|
||||||
{
|
{
|
||||||
case EventNotificationObject:
|
/* Get real pointer */
|
||||||
case EventSynchronizationObject:
|
WaitableObject = (PVOID)((ULONG_PTR)WaitObj +
|
||||||
/* Set the Event */
|
(ULONG_PTR)WaitableObject);
|
||||||
/* FIXME: Check permissions */
|
}
|
||||||
KeSetEvent(SignalObj, EVENT_INCREMENT, TRUE);
|
|
||||||
break;
|
/* Check Signal Object Type */
|
||||||
|
Type = BODY_TO_HEADER(WaitObj)->Type;
|
||||||
case MutantObject:
|
if (Type == ExEventObjectType)
|
||||||
/* Release the Mutant. This can raise an exception*/
|
{
|
||||||
_SEH_TRY
|
/* Set the Event */
|
||||||
{
|
/* FIXME: Check permissions */
|
||||||
KeReleaseMutant(SignalObj, MUTANT_INCREMENT, FALSE, TRUE);
|
KeSetEvent(SignalObj, EVENT_INCREMENT, TRUE);
|
||||||
}
|
}
|
||||||
_SEH_HANDLE
|
else if (Type == ExMutantObjectType)
|
||||||
{
|
{
|
||||||
Status = _SEH_GetExceptionCode();
|
/* Release the Mutant. This can raise an exception*/
|
||||||
goto Quickie;
|
_SEH_TRY
|
||||||
}
|
{
|
||||||
_SEH_END;
|
KeReleaseMutant(SignalObj, MUTANT_INCREMENT, FALSE, TRUE);
|
||||||
break;
|
}
|
||||||
|
_SEH_HANDLE
|
||||||
case SemaphoreObject:
|
{
|
||||||
/* Release the Semaphore. This can raise an exception*/
|
Status = _SEH_GetExceptionCode();
|
||||||
/* FIXME: Check permissions */
|
|
||||||
_SEH_TRY
|
|
||||||
{
|
|
||||||
KeReleaseSemaphore(SignalObj, SEMAPHORE_INCREMENT, 1, TRUE);
|
|
||||||
}
|
|
||||||
_SEH_HANDLE
|
|
||||||
{
|
|
||||||
Status = _SEH_GetExceptionCode();
|
|
||||||
goto Quickie;
|
|
||||||
}
|
|
||||||
_SEH_END;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
Status = STATUS_OBJECT_TYPE_MISMATCH;
|
|
||||||
goto Quickie;
|
goto Quickie;
|
||||||
|
}
|
||||||
|
_SEH_END;
|
||||||
|
}
|
||||||
|
else if (Type == ExSemaphoreObjectType)
|
||||||
|
{
|
||||||
|
/* Release the Semaphore. This can raise an exception*/
|
||||||
|
/* FIXME: Check permissions */
|
||||||
|
_SEH_TRY
|
||||||
|
{
|
||||||
|
KeReleaseSemaphore(SignalObj, SEMAPHORE_INCREMENT, 1, TRUE);
|
||||||
|
}
|
||||||
|
_SEH_HANDLE
|
||||||
|
{
|
||||||
|
Status = _SEH_GetExceptionCode();
|
||||||
|
goto Quickie;
|
||||||
|
}
|
||||||
|
_SEH_END;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Status = STATUS_OBJECT_TYPE_MISMATCH;
|
||||||
|
DPRINT1("Waiting on invalid object type\n");
|
||||||
|
goto Quickie;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now wait. Also SEH this since it can also raise an exception */
|
/* Now wait. Also SEH this since it can also raise an exception */
|
||||||
_SEH_TRY
|
_SEH_TRY
|
||||||
{
|
{
|
||||||
Status = KeWaitForSingleObject(WaitObj,
|
Status = KeWaitForSingleObject(WaitableObject,
|
||||||
UserRequest,
|
UserRequest,
|
||||||
PreviousMode,
|
PreviousMode,
|
||||||
Alertable,
|
Alertable,
|
||||||
|
|
|
@ -97,7 +97,6 @@ PsInitThreadManagment(VOID)
|
||||||
ObjectTypeInitializer.GenericMapping = PiThreadMapping;
|
ObjectTypeInitializer.GenericMapping = PiThreadMapping;
|
||||||
ObjectTypeInitializer.PoolType = NonPagedPool;
|
ObjectTypeInitializer.PoolType = NonPagedPool;
|
||||||
ObjectTypeInitializer.ValidAccessMask = THREAD_ALL_ACCESS;
|
ObjectTypeInitializer.ValidAccessMask = THREAD_ALL_ACCESS;
|
||||||
ObjectTypeInitializer.UseDefaultObject = TRUE;
|
|
||||||
ObjectTypeInitializer.DeleteProcedure = PspDeleteThread;
|
ObjectTypeInitializer.DeleteProcedure = PspDeleteThread;
|
||||||
ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &PsThreadType);
|
ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &PsThreadType);
|
||||||
|
|
||||||
|
@ -138,7 +137,6 @@ PsInitProcessManagment(VOID)
|
||||||
ObjectTypeInitializer.GenericMapping = PiProcessMapping;
|
ObjectTypeInitializer.GenericMapping = PiProcessMapping;
|
||||||
ObjectTypeInitializer.PoolType = NonPagedPool;
|
ObjectTypeInitializer.PoolType = NonPagedPool;
|
||||||
ObjectTypeInitializer.ValidAccessMask = PROCESS_ALL_ACCESS;
|
ObjectTypeInitializer.ValidAccessMask = PROCESS_ALL_ACCESS;
|
||||||
ObjectTypeInitializer.UseDefaultObject = TRUE;
|
|
||||||
ObjectTypeInitializer.DeleteProcedure = PspDeleteProcess;
|
ObjectTypeInitializer.DeleteProcedure = PspDeleteProcess;
|
||||||
ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &PsProcessType);
|
ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &PsProcessType);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue