summaryrefslogtreecommitdiffstats
path: root/private/ntos/ex/handle.c
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/ex/handle.c
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/ex/handle.c')
-rw-r--r--private/ntos/ex/handle.c1520
1 files changed, 1520 insertions, 0 deletions
diff --git a/private/ntos/ex/handle.c b/private/ntos/ex/handle.c
new file mode 100644
index 000000000..53fb66944
--- /dev/null
+++ b/private/ntos/ex/handle.c
@@ -0,0 +1,1520 @@
+/*++
+
+Copyright (c) 1989-1995 Microsoft Corporation
+
+Module Name:
+
+ handle.c
+
+Abstract:
+
+ This module implements a set of functions for supporting handles.
+
+Author:
+
+ Steve Wood (stevewo) 25-Apr-1989
+ David N. Cutler (davec) 17-May-1995 (rewrite)
+
+Revision History:
+
+--*/
+
+#include "exp.h"
+#pragma hdrstop
+
+//
+// Define global values for the default initial handle entry table size and
+// the default size to grow the handle entry table.
+//
+
+USHORT ExpDefaultHandleTableSize;
+USHORT ExpDefaultHandleTableGrowth;
+
+//
+// Decline global structures that link all handle tables together.
+//
+
+ERESOURCE HandleTableListLock;
+LIST_ENTRY HandleTableListHead;
+
+//
+// Define forward referenced prototypes.
+//
+
+PHANDLE_TABLE
+ExpAllocateHandleTable(
+ IN PEPROCESS Process,
+ IN ULONG CountToGrowBy
+ );
+
+PHANDLE_ENTRY
+ExpAllocateHandleTableEntries(
+ IN PHANDLE_TABLE HandleTable,
+ IN PVOID OldTableEntries,
+ IN ULONG OldCountEntries,
+ IN ULONG NewCountEntries
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT, ExInitializeHandleTablePackage)
+#pragma alloc_text(PAGE, ExChangeHandle)
+#pragma alloc_text(PAGE, ExCreateHandle)
+#pragma alloc_text(PAGE, ExCreateHandleTable)
+#pragma alloc_text(PAGE, ExDestroyHandle)
+#pragma alloc_text(PAGE, ExDestroyHandleTable)
+#pragma alloc_text(PAGE, ExDupHandleTable)
+#pragma alloc_text(PAGE, ExEnumHandleTable)
+#pragma alloc_text(PAGE, ExMapHandleToPointer)
+#pragma alloc_text(PAGE, ExRemoveHandleTable)
+#pragma alloc_text(PAGE, ExSnapShotHandleTables)
+#pragma alloc_text(PAGE, ExpAllocateHandleTable)
+#pragma alloc_text(PAGE, ExpAllocateHandleTableEntries)
+#endif
+
+VOID
+ExInitializeHandleTablePackage(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function initializes static data structures required to support
+ handle table.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ MM_SYSTEMSIZE SystemSize;
+
+ //
+ // Get the configuration size of the host system and set the initial
+ // and growth default sizes for handle table as appropriate.
+ //
+ // N.B. The initial sizes are set such that otimal use of pool block
+ // storage can be obtained.
+ //
+
+ SystemSize = MmQuerySystemSize();
+ if (SystemSize == MmSmallSystem) {
+ ExpDefaultHandleTableSize = 7;
+ ExpDefaultHandleTableGrowth = 8;
+
+ } else {
+ ExpDefaultHandleTableSize = 15;
+ ExpDefaultHandleTableGrowth = 16;
+ }
+
+ //
+ // Initialize the handle table synchronization resource and listhead.
+ //
+
+ InitializeListHead(&HandleTableListHead);
+ ExInitializeResource(&HandleTableListLock);
+ return;
+}
+
+VOID
+FASTCALL
+ExAcquireHandleTableExclusive(
+ IN PHANDLE_TABLE HandleTable
+ )
+
+/*++
+
+Routine Description:
+
+ This routine acquires the specified handle table for exclusive access.
+
+ N.B. This routine uses fast locking.
+
+Arguments:
+
+ HandleTable - Supplies a pointer to the handle table that is acquired
+ for exclusive access.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ HANDLE_SYNCH Current;
+ HANDLE_SYNCH NewState;
+
+ ASSERT(KeIsExecutingDpc() == FALSE);
+
+ do {
+
+ //
+ // Capture the current state of handle table ownership and initialize
+ // the proposed new state value.
+ //
+ // If the handle table is not owned, then attempt to grant exclusive
+ // ownership. Otherwise, the handle table is owned either shared or
+ // exclusive and the calling thread must wait for exclusive access.
+ //
+
+ NewState.Value = Current.Value = *((volatile ULONGLONG *)&HandleTable->State.Value);
+ if (Current.u.OwnerCount == 0) {
+ NewState.u.OwnerCount = (ULONG)PsGetCurrentThread();
+ if (ExInterlockedCompareExchange64(&HandleTable->State.Value,
+ &NewState.Value,
+ &Current.Value,
+ &HandleTable->SpinLock) == Current.Value) {
+ break;
+ }
+
+ } else {
+
+ ASSERT((PETHREAD)(HandleTable->State.u.OwnerCount) != PsGetCurrentThread());
+
+ NewState.u.NumberOfExclusiveWaiters += 1;
+ if (ExInterlockedCompareExchange64(&HandleTable->State.Value,
+ &NewState.Value,
+ &Current.Value,
+ &HandleTable->SpinLock) == Current.Value) {
+
+ KeWaitForSingleObject(&HandleTable->ExclusiveWaiters,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ break;
+ }
+ }
+
+ } while (TRUE);
+
+ return;
+}
+
+VOID
+FASTCALL
+ExAcquireHandleTableShared(
+ IN PHANDLE_TABLE HandleTable
+ )
+
+/*++
+
+Routine Description:
+
+ This routine acquires the specified handle table for shared access.
+
+ N.B. This routines uses fast locking.
+
+Arguments:
+
+ HandleTable - Supplies a pointer to the handle table that is acquired
+ for shared access.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ HANDLE_SYNCH Current;
+ HANDLE_SYNCH NewState;
+
+ ASSERT(KeIsExecutingDpc() == FALSE);
+
+ do {
+
+ //
+ // Capture the current state of handle table ownership and initialize
+ // the proposed new state value.
+ //
+ // If the handle table is not owned or is owned shared, then attempt
+ // to grant shared ownership. Otherwise, the handle table is owned
+ // exclusive and the calling thread must wait for shared access.
+ //
+ // N.B. Shared access is granted if shared access is already granted
+ // regardless of exclusive waiters.
+ //
+
+ NewState.Value = Current.Value = *((volatile ULONGLONG *)&HandleTable->State.Value);
+ if ((Current.u.OwnerCount == 0) ||
+ ((Current.u.OwnerCount & 1) != 0)) {
+ NewState.u.OwnerCount = (NewState.u.OwnerCount + 2) | 1;
+ if (ExInterlockedCompareExchange64(&HandleTable->State.Value,
+ &NewState.Value,
+ &Current.Value,
+ &HandleTable->SpinLock) == Current.Value) {
+ break;
+ }
+
+ } else {
+ NewState.u.NumberOfSharedWaiters += 1;
+ if (ExInterlockedCompareExchange64(&HandleTable->State.Value,
+ &NewState.Value,
+ &Current.Value,
+ &HandleTable->SpinLock) == Current.Value) {
+
+ KeWaitForSingleObject(&HandleTable->SharedWaiters,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ break;
+ }
+ }
+
+ } while (TRUE);
+
+ return;
+}
+
+VOID
+FASTCALL
+ExReleaseHandleTableExclusive(
+ IN PHANDLE_TABLE HandleTable
+ )
+
+/*++
+
+Routine Description:
+
+ This routine releases exclusive access to the specified handle table
+ for the current thread.
+
+ N.B. This routine uses fast locking.
+
+Arguments:
+
+ HandleTable - Supplies a pointer to the handle table to release.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ HANDLE_SYNCH Current;
+ HANDLE_SYNCH NewState;
+ ULONG Number;
+
+ ASSERT(KeIsExecutingDpc() == FALSE);
+
+ ASSERT(((PETHREAD)HandleTable->State.u.OwnerCount == PsGetCurrentThread()) ||
+ (HandleTable->State.u.OwnerCount == 2));
+
+ do {
+
+ //
+ // Capture the current state of handle table ownership and initialize
+ // the proposed new state value.
+ //
+ // If there are shared waiters, then attempt to grant shared access to
+ // the handle table. Otherwise, it there are exclusive waiters, then
+ // attempt to grant exclusive access to the handle table. Otherwise,
+ // clear ownership of the handle table.
+ //
+
+ NewState.Value = Current.Value = *((volatile ULONGLONG *)&HandleTable->State.Value);
+ if ((Number = Current.u.NumberOfSharedWaiters) != 0) {
+ NewState.u.NumberOfSharedWaiters = 0;
+ NewState.u.OwnerCount = (Number * 2) | 1;
+ if (ExInterlockedCompareExchange64(&HandleTable->State.Value,
+ &NewState.Value,
+ &Current.Value,
+ &HandleTable->SpinLock) == Current.Value) {
+
+ KeReleaseSemaphore(&HandleTable->SharedWaiters, 0, Number, FALSE);
+ break;
+ }
+
+ } else if (Current.u.NumberOfExclusiveWaiters != 0) {
+ NewState.u.OwnerCount = 2;
+ NewState.u.NumberOfExclusiveWaiters -= 1;
+ if (ExInterlockedCompareExchange64(&HandleTable->State.Value,
+ &NewState.Value,
+ &Current.Value,
+ &HandleTable->SpinLock) == Current.Value) {
+
+ KeSetEventBoostPriority(&HandleTable->ExclusiveWaiters,
+ (PRKTHREAD *)&HandleTable->State.u.OwnerCount);
+
+ break;
+ }
+
+ } else {
+ NewState.u.OwnerCount = 0;
+ if (ExInterlockedCompareExchange64(&HandleTable->State.Value,
+ &NewState.Value,
+ &Current.Value,
+ &HandleTable->SpinLock) == Current.Value) {
+
+ break;
+ }
+ }
+
+ } while (TRUE);
+
+ return;
+}
+
+VOID
+FASTCALL
+ExReleaseHandleTableShared(
+ IN PHANDLE_TABLE HandleTable
+ )
+
+/*++
+
+Routine Description:
+
+ This routine releases shared access to the specified handle table for
+ the current thread.
+
+ N.B. This routine uses fast locking.
+
+Arguments:
+
+ HandleTable - Supplies a pointer to the handle table to release.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ HANDLE_SYNCH Current;
+ HANDLE_SYNCH NewState;
+ ULONG Number;
+
+ ASSERT(KeIsExecutingDpc() == FALSE);
+
+ ASSERT((HandleTable->State.u.OwnerCount & 1) == 1);
+
+ do {
+
+ //
+ // Capture the current state of handle table ownership and initialize
+ // the proposed new state value.
+ //
+ // If there are exclusive waiters, then attempt to grant exclusive
+ // access to the handle table. Otherwise, clear ownership of the
+ // handle table (it is not possible to have shared waiters).
+ //
+
+ NewState.Value = Current.Value = *((volatile ULONGLONG *)&HandleTable->State.Value);
+ if (Current.u.OwnerCount != 3) {
+ NewState.u.OwnerCount -= 2;
+ if (ExInterlockedCompareExchange64(&HandleTable->State.Value,
+ &NewState.Value,
+ &Current.Value,
+ &HandleTable->SpinLock) == Current.Value) {
+
+ break;
+ }
+
+ } else if (Current.u.NumberOfExclusiveWaiters != 0) {
+ NewState.u.OwnerCount = 2;
+ NewState.u.NumberOfExclusiveWaiters -= 1;
+ if (ExInterlockedCompareExchange64(&HandleTable->State.Value,
+ &NewState.Value,
+ &Current.Value,
+ &HandleTable->SpinLock) == Current.Value) {
+
+ KeSetEventBoostPriority(&HandleTable->ExclusiveWaiters,
+ (PRKTHREAD *)&HandleTable->State.u.OwnerCount);
+
+ break;
+ }
+
+ } else {
+ NewState.u.OwnerCount = 0;
+ if (ExInterlockedCompareExchange64(&HandleTable->State.Value,
+ &NewState.Value,
+ &Current.Value,
+ &HandleTable->SpinLock) == Current.Value) {
+
+ break;
+ }
+ }
+
+ } while (TRUE);
+
+ return;
+}
+
+BOOLEAN
+ExChangeHandle(
+ IN PHANDLE_TABLE HandleTable,
+ IN HANDLE Handle,
+ IN PEX_CHANGE_HANDLE_ROUTINE ChangeRoutine,
+ IN ULONG Parameter
+ )
+
+/*++
+
+Routine Description:
+
+ This function provides the capability to change the contents of the
+ handle entry corrsponding to the specified handle.
+
+Arguments:
+
+ HandleTable - Supplies a pointer to a handle table.
+
+ Handle - Supplies the handle for the handle entry that is changed.
+
+ ChangeRoutine - Supplies a pointer to a function that is called to
+ perform the change.
+
+ Parameter - Supplies an uninterpreted parameter that is passed to
+ the change routine.
+
+Return Value:
+
+ If the operation was successfully performed, then a value of TRUE
+ is returned. Otherwise, a value of FALSE is returned.
+
+--*/
+
+{
+
+ PHANDLE_ENTRY HandleEntry;
+ BOOLEAN ReturnValue;
+ PHANDLE_ENTRY TableBound;
+ PHANDLE_ENTRY TableEntries;
+ ULONG TableIndex;
+
+ PAGED_CODE();
+
+ ASSERT(HandleTable != NULL);
+
+ //
+ // Lock the handle table exclusive and check if the handle is valid.
+ //
+
+ ReturnValue = FALSE;
+ TableIndex = HANDLE_TO_INDEX(Handle);
+ ExLockHandleTableExclusive(HandleTable);
+ TableBound = HandleTable->TableBound;
+ TableEntries = HandleTable->TableEntries;
+ if (TableIndex < (ULONG)(TableBound - TableEntries)) {
+
+ //
+ // Compute the address of the handle entry and call the change
+ // handle function if the handle entry is not free.
+ //
+
+ HandleEntry = &TableEntries[TableIndex];
+ if (ExIsEntryUsed(TableEntries, TableBound, HandleEntry)) {
+ ReturnValue = (*ChangeRoutine)(HandleEntry, Parameter);
+ }
+ }
+
+ ExUnlockHandleTableExclusive(HandleTable);
+ return ReturnValue;
+}
+
+HANDLE
+ExCreateHandle(
+ IN PHANDLE_TABLE HandleTable,
+ IN PHANDLE_ENTRY HandleEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This function create a handle entry in the specified handle table and
+ returns a handle for the entry. If there is insufficient room in the
+ handle table for a new entry, then the handle table is expanded if
+ possible.
+
+Arguments:
+
+ HandleTable - Supplies a pointer to a handle table
+
+ HandleEntry - Supplies a poiner to the handle entry for which a
+ handle entry is created.
+
+Return Value:
+
+ If the handle entry is successfully created, then value of the created
+ handle is returned as the function value. Otherwise, a value of NULL is
+ returned.
+
+--*/
+
+{
+
+ PLIST_ENTRY FreeEntry;
+ ULONG NewCountEntries;
+ PHANDLE_ENTRY NewEntry;
+ ULONG OldCountEntries;
+ PHANDLE_ENTRY TableEntries;
+ ULONG TableIndex;
+
+ PAGED_CODE();
+
+ ASSERT(HandleTable != NULL);
+ ASSERT(HandleEntry != NULL);
+
+ //
+ // Lock the handle table exclusive and allocate a free handle entry.
+ //
+
+ ExLockHandleTableExclusive(HandleTable);
+ TableEntries = HandleTable->TableEntries;
+ if (IsListEmpty(&TableEntries->ListEntry)) {
+
+ //
+ // There are no free entries in the handle entry table. Attempt
+ // to grow the size of the handle entry table.
+ //
+
+ OldCountEntries = HandleTable->TableBound - TableEntries;
+ NewCountEntries = OldCountEntries + HandleTable->CountToGrowBy;
+ if (ExpAllocateHandleTableEntries(HandleTable,
+ TableEntries,
+ OldCountEntries,
+ NewCountEntries) == NULL) {
+
+ ExUnlockHandleTableExclusive(HandleTable);
+ return NULL;
+
+ } else {
+ TableEntries = HandleTable->TableEntries;
+ }
+ }
+
+ //
+ // Remove the first entry from the free list, initialize the handle
+ // entry, unlock the handle table, and return the handle value.
+ //
+ // N.B. The LIFO/FIFO discipline for handle table entires is maintained
+ // at the point handles are destroyed.
+ //
+
+ FreeEntry = TableEntries->ListEntry.Flink;
+ RemoveEntryList(FreeEntry);
+ NewEntry = CONTAINING_RECORD(FreeEntry, HANDLE_ENTRY, ListEntry);
+ HandleTable->HandleCount += 1;
+ NewEntry->Object = HandleEntry->Object;
+ NewEntry->Attributes = HandleEntry->Attributes;
+ ExUnlockHandleTableExclusive(HandleTable);
+ TableIndex = NewEntry - TableEntries;
+ return INDEX_TO_HANDLE(TableIndex);
+}
+
+PHANDLE_TABLE
+ExCreateHandleTable(
+ IN PEPROCESS Process OPTIONAL,
+ IN ULONG CountEntries,
+ IN ULONG CountToGrowBy
+ )
+
+/*++
+
+Routine Description:
+
+ This function creates a handle table and allocates the specified count
+ of initial handle entries.
+
+Arguments:
+
+ Process - Supplies an optional pointer to the process against which quota
+ will be charged.
+
+ CountEntries - Supplies the initial number of handle entries to allocate.
+
+ CountToGrowBy - Supplies the number of handle entries to grow the handle
+ entry table by when it becomes full.
+
+Return Value:
+
+ If a handle table is successfully created, then the address of the
+ handle table is returned as the function value. Otherwize, a value
+ NULL is returned.
+
+--*/
+
+{
+
+ PHANDLE_TABLE HandleTable;
+
+ PAGED_CODE();
+
+ //
+ // If the number of initial handle entries or the number to grow by
+ // are not specified, then use the system default value.
+ //
+
+ if ((CountEntries <= 1) || (CountEntries > MAXUSHORT)) {
+ CountEntries = ExpDefaultHandleTableSize;
+ }
+
+ if ((CountToGrowBy <= 1) || (CountToGrowBy > MAXUSHORT)) {
+ CountToGrowBy = ExpDefaultHandleTableGrowth;
+ }
+
+ //
+ // Allocate and initialize a handle table descriptor.
+ //
+
+ HandleTable = ExpAllocateHandleTable(Process, CountToGrowBy);
+
+ //
+ // If the handle table descriptor was successfully allocated, then
+ // allocate the initial handle entry table.
+ //
+
+ if (HandleTable != NULL) {
+ if (ExpAllocateHandleTableEntries(HandleTable,
+ NULL,
+ 0,
+ CountEntries) == NULL) {
+
+ ExDestroyHandleTable(HandleTable, NULL);
+ HandleTable = NULL;
+ }
+ }
+
+ return HandleTable;
+}
+
+BOOLEAN
+ExDestroyHandle(
+ IN PHANDLE_TABLE HandleTable,
+ IN HANDLE Handle,
+ IN BOOLEAN TableLocked
+ )
+
+/*++
+
+Routine Description:
+
+ This function removes a handle from a handle table.
+
+Arguments:
+
+ HandleTable - Supplies a pointer to a handle table
+
+ Handle - Supplies the handle value of the entry to remove.
+
+ TableLocked - Supplies a boolean value that determines whether the
+ handle table is already locked.
+
+Return Value:
+
+ If the specified handle is successfully removed, then a value of
+ TRUE is returned. Otherwise, a value of FALSE is returned.
+
+--*/
+
+{
+
+ PHANDLE_ENTRY HandleEntry;
+ BOOLEAN ResultValue;
+ PHANDLE_ENTRY TableBound;
+ PHANDLE_ENTRY TableEntries;
+ ULONG TableIndex;
+
+ PAGED_CODE();
+
+ ASSERT(HandleTable != NULL);
+
+ //
+ // If the handle table is not already locked, then lock the handle
+ // table exclussive.
+ //
+
+ ResultValue = FALSE;
+ TableIndex = HANDLE_TO_INDEX(Handle);
+ if (TableLocked == FALSE) {
+ ExLockHandleTableExclusive(HandleTable);
+ }
+
+ TableBound = HandleTable->TableBound;
+ TableEntries = HandleTable->TableEntries;
+ if (TableIndex < (ULONG)(TableBound - TableEntries)) {
+
+ //
+ // Compute the address of the handle entry and check if the handle
+ // is is use.
+ //
+
+ HandleEntry = &TableEntries[TableIndex];
+ if (ExIsEntryUsed(TableEntries, TableBound, HandleEntry)) {
+
+ //
+ // Insert the handle entry in the free list according to the
+ // discipline associated with the handle table and decrement
+ // the number of handles.
+ //
+
+ HandleTable->HandleCount -= 1;
+ if (HandleTable->LifoOrder != FALSE) {
+ InsertHeadList(&TableEntries->ListEntry, &HandleEntry->ListEntry);
+
+ } else {
+ InsertTailList(&TableEntries->ListEntry, &HandleEntry->ListEntry);
+ }
+
+ ResultValue = TRUE;
+ }
+ }
+
+ //
+ // Unlock the handle table if is was locked.
+ //
+
+ if (TableLocked == FALSE) {
+ ExUnlockHandleTableExclusive(HandleTable);
+ }
+
+ return ResultValue;
+}
+
+VOID
+ExRemoveHandleTable(
+ IN PHANDLE_TABLE HandleTable
+ )
+
+/*++
+
+Routine Description:
+
+ This function removes the specified handle table from the list of
+ handle tables. Used by PS and ATOM packages to make sure their
+ handle tables are not in the list enumerated by the ExSnapShotHandleTables
+ routine and the !handle debugger extension.
+
+Arguments:
+
+ HandleTable - Supplies a pointer to a handle table
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PAGED_CODE();
+
+ ASSERT(HandleTable != NULL);
+
+ //
+ // Remove the handle table from the handle table list.
+ //
+
+ KeEnterCriticalRegion();
+ ExAcquireResourceExclusive(&HandleTableListLock, TRUE);
+ if (!IsListEmpty(&HandleTable->ListEntry)) {
+ RemoveEntryList(&HandleTable->ListEntry);
+ InitializeListHead(&HandleTable->ListEntry);
+ }
+ ExReleaseResource(&HandleTableListLock);
+ KeLeaveCriticalRegion();
+ return;
+}
+
+VOID
+ExDestroyHandleTable(
+ IN PHANDLE_TABLE HandleTable,
+ IN EX_DESTROY_HANDLE_ROUTINE DestroyHandleProcedure OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This function destroys the specified handle table.
+
+Arguments:
+
+ HandleTable - Supplies a pointer to a handle table
+
+ DestroyHandleProcedure - Supplies a pointer to a function to call for
+ each valid handle entry in the handle table.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG CountEntries;
+ PHANDLE_ENTRY HandleEntry;
+ PEPROCESS Process;
+ PHANDLE_ENTRY TableBound;
+ PHANDLE_ENTRY TableEntries;
+ ULONG TableIndex;
+
+ PAGED_CODE();
+
+ ASSERT(HandleTable != NULL);
+
+ //
+ // Remove the handle table from the handle table list.
+ //
+
+ ExRemoveHandleTable(HandleTable);
+
+ //
+ // If a handle entry table has been allocated, then scan all of
+ // handle entries, call the destroy handle function, if specfied,
+ // free the allocated pool, and return pool quota as appropriate.
+ //
+
+ Process = HandleTable->QuotaProcess;
+ TableBound = HandleTable->TableBound;
+ TableEntries = HandleTable->TableEntries;
+ if (TableEntries != NULL) {
+ if (ARGUMENT_PRESENT(DestroyHandleProcedure)) {
+ HandleEntry = &TableEntries[1];
+ while (HandleEntry < TableBound) {
+ if (ExIsEntryUsed(TableEntries, TableBound, HandleEntry)) {
+ TableIndex = HandleEntry - TableEntries;
+ (*DestroyHandleProcedure)(INDEX_TO_HANDLE(TableIndex),
+ HandleEntry);
+ }
+
+ HandleEntry += 1;
+ }
+ }
+
+ ExFreePool(TableEntries);
+ if (Process != NULL) {
+ CountEntries = TableBound - TableEntries;
+ PsReturnPoolQuota(Process,
+ PagedPool,
+ CountEntries * sizeof(HANDLE_ENTRY));
+ }
+ }
+
+ //
+ // Free the allocated pool and return pool quota as appropriate.
+ //
+
+ ExFreePool(HandleTable);
+ if (Process != NULL) {
+ PsReturnPoolQuota(Process,
+ NonPagedPool,
+ sizeof(HANDLE_TABLE));
+
+ }
+
+ return;
+}
+
+PHANDLE_TABLE
+ExDupHandleTable(
+ IN PEPROCESS Process OPTIONAL,
+ IN PHANDLE_TABLE OldHandleTable,
+ IN EX_DUPLICATE_HANDLE_ROUTINE DupHandleProcedure OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This function creates a duplicate copy of the specified handle table.
+
+Arguments:
+
+ Process - Supplies an optional to the process to charge quota to.
+
+ OldHandleTable - Supplies a pointer to a handle table.
+
+ DupHandleProcedure - Supplies an optional pointer to a function to call
+ for each valid handle in the duplicated handle table.
+
+Return Value:
+
+ If the specified handle table is successfully duplicated, then the
+ address of the new handle table is returned as the function value.
+ Otherwize, a value NULL is returned.
+
+--*/
+
+{
+
+ PLIST_ENTRY FreeHead;
+ PHANDLE_TABLE NewHandleTable;
+ PHANDLE_ENTRY NewHandleEntry;
+ PHANDLE_ENTRY NewTableEntries;
+ PHANDLE_ENTRY OldHandleEntry;
+ ULONG OldCountEntries;
+ PHANDLE_ENTRY OldTableBound;
+ PHANDLE_ENTRY OldTableEntries;
+
+ PAGED_CODE();
+
+ ASSERT(OldHandleTable != NULL);
+
+ //
+ // Lock the old handle table exclusive and allocate and initialize
+ // a handle table descriptor.
+ //
+
+ ExLockHandleTableExclusive(OldHandleTable);
+ NewHandleTable = ExpAllocateHandleTable(Process,
+ OldHandleTable->CountToGrowBy);
+
+ //
+ // If the new handle table descriptor was successfully allocated, then
+ // the allocate the handle entry table.
+ //
+
+ if (NewHandleTable != NULL) {
+ OldTableBound = OldHandleTable->TableBound;
+ OldTableEntries = OldHandleTable->TableEntries;
+ OldCountEntries = OldTableBound - OldTableEntries;
+ if (ExpAllocateHandleTableEntries(NewHandleTable,
+ OldTableEntries,
+ 0,
+ OldCountEntries) == NULL) {
+
+ ExDestroyHandleTable(NewHandleTable, NULL);
+ NewHandleTable = NULL;
+
+ } else {
+
+ //
+ // Scan through the old handle table and either duplicate the
+ // associated entry or insert it in the free list.
+ //
+
+ NewTableEntries = NewHandleTable->TableEntries;
+ FreeHead = &NewTableEntries->ListEntry;
+ OldHandleEntry = &OldTableEntries[1];
+ NewHandleEntry = &NewTableEntries[1];
+ while (OldHandleEntry < OldTableBound) {
+ if (ExIsEntryFree(OldTableEntries, OldTableBound, OldHandleEntry)) {
+ InsertTailList(FreeHead, &NewHandleEntry->ListEntry);
+
+ } else {
+ NewHandleEntry->Object = OldHandleEntry->Object;
+ NewHandleEntry->Attributes = OldHandleEntry->Attributes;
+ if (ARGUMENT_PRESENT(DupHandleProcedure)) {
+ if ((*DupHandleProcedure)(Process, NewHandleEntry)) {
+ NewHandleTable->HandleCount += 1;
+
+ } else {
+ InsertTailList(FreeHead, &NewHandleEntry->ListEntry);
+ }
+
+ } else {
+ NewHandleTable->HandleCount += 1;
+ }
+ }
+
+ NewHandleEntry += 1;
+ OldHandleEntry += 1;
+ }
+ }
+ }
+
+ ExUnlockHandleTableExclusive(OldHandleTable);
+ return NewHandleTable;
+}
+
+BOOLEAN
+ExEnumHandleTable(
+ IN PHANDLE_TABLE HandleTable,
+ IN EX_ENUMERATE_HANDLE_ROUTINE EnumHandleProcedure,
+ IN PVOID EnumParameter,
+ OUT PHANDLE Handle OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This function enumerates all the valid handles in a handle table.
+ For each valid handle in the handle table, the specified eumeration
+ function is called. If the enumeration function returns TRUE, then
+ the enumeration is stopped, the current handle is returned to the
+ caller via the optional Handle parameter, and this function returns
+ TRUE to indicated that the enumeration stopped at a specific handle.
+
+Arguments:
+
+ HandleTable - Supplies a pointer to a handle table.
+
+ EnumHandleProcedure - Supplies a pointer to a fucntion to call for
+ each valid handle in the enumerated handle table.
+
+ EnumParameter - Supplies an uninterpreted 32-bit value that is passed
+ to the EnumHandleProcedure each time it is called.
+
+ Handle - Supplies an optional pointer a variable that receives the
+ Handle value that the enumeration stopped at. Contents of the
+ variable only valid if this function returns TRUE.
+
+Return Value:
+
+ If the enumeration stopped at a specific handle, then a value of TRUE
+ is returned. Otherwise, a value of FALSE is returned.
+
+--*/
+
+{
+
+ PHANDLE_ENTRY HandleEntry;
+ BOOLEAN ResultValue;
+ PHANDLE_ENTRY TableEntries;
+ PHANDLE_ENTRY TableBound;
+ ULONG TableIndex;
+
+ PAGED_CODE();
+
+ ASSERT(HandleTable != NULL);
+
+ //
+ // Lock the handle table exclusive and enumerate the handle entries.
+ //
+
+ ResultValue = FALSE;
+ ExLockHandleTableShared(HandleTable);
+ TableBound = HandleTable->TableBound;
+ TableEntries = HandleTable->TableEntries;
+ HandleEntry = &TableEntries[1];
+ while (HandleEntry < TableBound) {
+ if (ExIsEntryUsed(TableEntries, TableBound, HandleEntry)) {
+ TableIndex = HandleEntry - TableEntries;
+ if ((*EnumHandleProcedure)(HandleEntry,
+ INDEX_TO_HANDLE(TableIndex),
+ EnumParameter)) {
+
+ if (ARGUMENT_PRESENT(Handle)) {
+ *Handle = INDEX_TO_HANDLE(TableIndex);
+ }
+
+ ResultValue = TRUE;
+ break;
+ }
+ }
+
+ HandleEntry += 1;
+ }
+
+ ExUnlockHandleTableShared(HandleTable);
+ return ResultValue;
+}
+
+PHANDLE_ENTRY
+ExMapHandleToPointer(
+ IN PHANDLE_TABLE HandleTable,
+ IN HANDLE Handle,
+ IN BOOLEAN Shared
+ )
+
+/*++
+
+Routine Description:
+
+ This function maps a handle to a pointer to a handle entry. If the
+ map operation is successful, then this function returns with the
+ handle table locked.
+
+Arguments:
+
+ HandleTable - Supplies a pointer to a handle table.
+
+ Handle - Supplies the handle to be mapped to a handle entry.
+
+ Shared - Supplies a boolean value that determines whether the handle
+ table is locked for shared (TRUE) or exclusive (FALSE) access.
+
+Return Value:
+
+ If the handle was successfully mapped to a pointer to a handle entry,
+ then the address of the handle entry is returned as the function value
+ with the handle table locked. Otherwise, a value of NULL is returned with
+ the handle table unlocked.
+
+--*/
+
+{
+
+ PHANDLE_ENTRY HandleEntry;
+ PHANDLE_ENTRY TableBound;
+ PHANDLE_ENTRY TableEntries;
+ ULONG TableIndex;
+
+ PAGED_CODE();
+
+ ASSERT(HandleTable != NULL);
+
+ //
+ // Lock the handle table exclusive or shared and check if the handle
+ // if valid.
+ //
+
+ TableIndex = HANDLE_TO_INDEX(Handle);
+ if (Shared != FALSE) {
+ ExLockHandleTableShared(HandleTable);
+
+ } else {
+ ExLockHandleTableExclusive(HandleTable);
+ }
+
+ TableBound = HandleTable->TableBound;
+ TableEntries = HandleTable->TableEntries;
+ if (TableIndex < (ULONG)(TableBound - TableEntries)) {
+ HandleEntry = &TableEntries[TableIndex];
+ if (ExIsEntryUsed(TableEntries, TableBound, HandleEntry)) {
+ return HandleEntry;
+ }
+ }
+
+ if (Shared != FALSE) {
+ ExUnlockHandleTableShared(HandleTable);
+
+ } else {
+ ExUnlockHandleTableExclusive(HandleTable);
+ }
+
+ return NULL;
+}
+
+NTSTATUS
+ExSnapShotHandleTables(
+ IN PEX_SNAPSHOT_HANDLE_ENTRY SnapShotHandleEntry,
+ IN OUT PSYSTEM_HANDLE_INFORMATION HandleInformation,
+ IN ULONG Length,
+ IN OUT PULONG RequiredLength
+ )
+
+/*++
+
+Routine Description:
+
+ This function sets the handle allocation algorithm for the specified
+ handle table.
+
+Arguments:
+
+ ...
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PHANDLE_ENTRY HandleEntry;
+ PSYSTEM_HANDLE_TABLE_ENTRY_INFO HandleEntryInfo;
+ PHANDLE_TABLE HandleTable;
+ PLIST_ENTRY NextEntry;
+ NTSTATUS Status;
+ PHANDLE_ENTRY TableBound;
+ PHANDLE_ENTRY TableEntries;
+ ULONG TableIndex;
+
+ PAGED_CODE();
+
+ //
+ // Lock the handle table list exclusive and traverse the list of
+ // handle tables.
+ //
+
+ KeEnterCriticalRegion();
+ ExAcquireResourceExclusive(&HandleTableListLock, TRUE);
+ try {
+ HandleEntryInfo = &HandleInformation->Handles[0];
+ NextEntry = HandleTableListHead.Flink;
+ while (NextEntry != &HandleTableListHead) {
+
+ //
+ // Get the address of the next handle table, lock the handle
+ // table exclusive, and scan the list of handle entries.
+ //
+
+ HandleTable = CONTAINING_RECORD(NextEntry, HANDLE_TABLE, ListEntry);
+ ExLockHandleTableExclusive(HandleTable);
+ TableBound = HandleTable->TableBound;
+ TableEntries = HandleTable->TableEntries;
+ HandleEntry = &TableEntries[1];
+ try {
+ for (HandleEntry = &TableEntries[1];
+ HandleEntry < TableBound;
+ HandleEntry++) {
+ if (ExIsEntryUsed(TableEntries, TableBound, HandleEntry)) {
+ HandleInformation->NumberOfHandles += 1;
+ TableIndex = HandleEntry - TableEntries;
+ Status = (*SnapShotHandleEntry)(&HandleEntryInfo,
+ HandleTable->UniqueProcessId,
+ HandleEntry,
+ INDEX_TO_HANDLE(TableIndex),
+ Length,
+ RequiredLength);
+ }
+ }
+
+ } finally {
+ ExUnlockHandleTableExclusive(HandleTable);
+ }
+
+ NextEntry = NextEntry->Flink;
+ }
+
+ } finally {
+ ExReleaseResource(&HandleTableListLock);
+ KeLeaveCriticalRegion();
+ }
+
+ return Status;
+}
+
+PHANDLE_TABLE
+ExpAllocateHandleTable(
+ IN PEPROCESS Process OPTIONAL,
+ IN ULONG CountToGrowBy
+ )
+
+/*++
+
+Routine Description:
+
+ This function allocates and initializes a new handle table descriptor.
+
+Arguments:
+
+ Process - Supplies an optional pointer to a process to charge quota
+ against.
+
+ CountToGrowBy - Supplies the number of handle entries to grow the
+ handle table by.
+
+Return Value:
+
+ If a handle is successfully allocated, then the address of the handle
+ table is returned as the function value. Otherwise, NULL is returned.
+
+--*/
+
+{
+
+ PHANDLE_TABLE HandleTable;
+
+ PAGED_CODE();
+
+ //
+ // Allocate handle table from nonpaged pool.
+ //
+
+ HandleTable =
+ (PHANDLE_TABLE)ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(HANDLE_TABLE),
+ 'btbO');
+
+ //
+ // If the allocation is successful, then attempt to charge quota as
+ // appropriate and initialize the handle tabel descriptor.
+ //
+
+ if (HandleTable != NULL) {
+ if (ARGUMENT_PRESENT(Process)) {
+ try {
+ PsChargePoolQuota(Process,
+ NonPagedPool,
+ sizeof(HANDLE_TABLE));
+
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+ ExFreePool(HandleTable);
+ return NULL;
+ }
+ }
+
+ //
+ // Initialize the handle table access synchronization information.
+ //
+
+ HandleTable->State.u.OwnerCount = 0;
+ HandleTable->State.u.NumberOfSharedWaiters = 0;
+ HandleTable->State.u.NumberOfExclusiveWaiters = 0;
+ KeInitializeSpinLock(&HandleTable->SpinLock);
+ KeInitializeSemaphore(&HandleTable->SharedWaiters, 0, MAXLONG);
+ KeInitializeEvent(&HandleTable->ExclusiveWaiters,
+ SynchronizationEvent,
+ FALSE);
+
+ //
+ // Initialize the handle table descriptor.
+ //
+
+ HandleTable->LifoOrder = FALSE;
+ HandleTable->UniqueProcessId = PsGetCurrentProcess()->UniqueProcessId;
+ HandleTable->TableEntries = NULL;
+ HandleTable->TableBound = NULL;
+ HandleTable->QuotaProcess = Process;
+ HandleTable->HandleCount = 0;
+ HandleTable->CountToGrowBy = (USHORT)CountToGrowBy;
+
+ //
+ // Insert the handle table in the handle table list.
+ //
+
+ KeEnterCriticalRegion();
+ ExAcquireResourceExclusive(&HandleTableListLock, TRUE);
+ InsertTailList(&HandleTableListHead, &HandleTable->ListEntry);
+ ExReleaseResource(&HandleTableListLock);
+ KeLeaveCriticalRegion();
+ }
+
+ return HandleTable;
+}
+
+PHANDLE_ENTRY
+ExpAllocateHandleTableEntries(
+ IN PHANDLE_TABLE HandleTable,
+ IN PHANDLE_ENTRY OldTableEntries,
+ IN ULONG OldCountEntries,
+ IN ULONG NewCountEntries
+ )
+
+/*++
+
+Routine Description:
+
+ This function allocates and initializes a new set of free handle
+ table entries.
+
+Arguments:
+
+ HandleTable - Supplies a pointer to a handle table descriptor.
+
+ OldTableEntries - Supplies a pointer to the old set of handle table
+ entries.
+
+ OldCountEntries - Supplies the previous count of table entries.
+
+ NewCountEntries - Supplies the desired count of table entries.
+
+Return Value:
+
+ If a new set of handle entries is successfully allocated, then the
+ address of the handle entries is returned as the function value.
+ Otherwise, NULL is returned.
+
+--*/
+
+{
+
+ PHANDLE_ENTRY FreeEntry;
+ PLIST_ENTRY FreeHead;
+ ULONG NewCountBytes;
+ PHANDLE_ENTRY NewTableBound;
+ PHANDLE_ENTRY NewTableEntries;
+ LONG OldCountBytes;
+ PEPROCESS Process;
+ BOOLEAN Status;
+
+ PAGED_CODE();
+
+ ASSERT(NewCountEntries > OldCountEntries);
+
+ //
+ // Compute the old and new sizes for the handle entry table and
+ // allocate a new handle entry table.
+ //
+
+ OldCountBytes = OldCountEntries * sizeof(HANDLE_ENTRY);
+ NewCountBytes = NewCountEntries * sizeof(HANDLE_ENTRY);
+ NewTableEntries = (PHANDLE_ENTRY)ExAllocatePoolWithTag(PagedPool,
+ NewCountBytes,
+ 'btbO');
+
+ //
+ // If the allocation is successful, then attempt to charge quota as
+ // appropriate and initialize the free list of handle entries.
+ //
+
+ if (NewTableEntries != NULL) {
+ Process = HandleTable->QuotaProcess;
+ if (Process != NULL) {
+ try {
+ PsChargePoolQuota(Process,
+ PagedPool,
+ NewCountBytes - OldCountBytes);
+
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+ ExFreePool(NewTableEntries);
+ return NULL;
+ }
+ }
+
+ //
+ // Initialize the free listhead.
+ //
+
+ FreeHead = &NewTableEntries->ListEntry;
+ InitializeListHead(FreeHead);
+
+ //
+ // If a new handle table is being created or an existing handle
+ // table is being extended, then initialize the free entry list
+ // allocated in the extension.
+ //
+
+ NewTableBound = &NewTableEntries[NewCountEntries];
+ if ((OldTableEntries == NULL) || (OldCountEntries != 0)) {
+ if (OldCountEntries == 0) {
+ FreeEntry = &NewTableEntries[1];
+
+ } else {
+ FreeEntry = &NewTableEntries[OldCountEntries];
+ }
+
+ do {
+ InsertTailList(FreeHead, &FreeEntry->ListEntry);
+ FreeEntry += 1;
+ } while (FreeEntry < NewTableBound);
+
+ //
+ // If there is an old handle entry table, then move the old
+ // handle entires to the new handle entry table and free the
+ // old handle entry table.
+ //
+
+ if (OldTableEntries != NULL) {
+ RtlMoveMemory(&NewTableEntries[1],
+ &OldTableEntries[1],
+ OldCountBytes - sizeof(HANDLE_ENTRY));
+
+ ExFreePool(OldTableEntries);
+ }
+ }
+
+ //
+ // Set the new count of table entries, the new table bound, and
+ // the address of the new table entries.
+ //
+
+ HandleTable->TableBound = NewTableBound;
+ HandleTable->TableEntries = NewTableEntries;
+ }
+
+ return NewTableEntries;
+}