windows-nt/Source/XPSP1/NT/base/ntos/rtl/handle.c
2020-09-26 16:20:57 +08:00

232 lines
6.2 KiB
C

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
handle.c
Abstract:
This module contains a simple handle allocator for use by the Local and
Global memory allocators.
Author:
Steve Wood (stevewo) 25-Jul-1991
Revision History:
--*/
#include "ntrtlp.h"
void
RtlInitializeHandleTable(
IN ULONG MaximumNumberOfHandles,
IN ULONG SizeOfHandleTableEntry,
OUT PRTL_HANDLE_TABLE HandleTable
)
{
RtlZeroMemory( HandleTable, sizeof( *HandleTable ) );
HandleTable->MaximumNumberOfHandles = MaximumNumberOfHandles;
HandleTable->SizeOfHandleTableEntry = SizeOfHandleTableEntry;
return;
}
NTSTATUS
RtlDestroyHandleTable(
IN OUT PRTL_HANDLE_TABLE HandleTable
)
{
NTSTATUS Status;
PVOID BaseAddress;
SIZE_T ReserveSize;
BaseAddress = HandleTable->CommittedHandles;
ReserveSize = (PUCHAR)(HandleTable->MaxReservedHandles) -
(PUCHAR)(HandleTable->CommittedHandles);
Status = NtFreeVirtualMemory( NtCurrentProcess(),
&BaseAddress,
&ReserveSize,
MEM_RELEASE
);
return Status;
}
PRTL_HANDLE_TABLE_ENTRY
RtlAllocateHandle(
IN PRTL_HANDLE_TABLE HandleTable,
OUT PULONG HandleIndex OPTIONAL
)
{
NTSTATUS Status;
PVOID BaseAddress;
ULONG n;
SIZE_T ReserveSize;
SIZE_T CommitSize;
PRTL_HANDLE_TABLE_ENTRY p, *pp;
if (HandleTable->FreeHandles == NULL) {
try {
if (HandleTable->UnCommittedHandles == NULL) {
ReserveSize = HandleTable->MaximumNumberOfHandles *
HandleTable->SizeOfHandleTableEntry;
BaseAddress = NULL;
Status = NtAllocateVirtualMemory( NtCurrentProcess(),
&BaseAddress,
0,
&ReserveSize,
MEM_RESERVE,
PAGE_READWRITE
);
if (NT_SUCCESS( Status )) {
HandleTable->CommittedHandles = (PRTL_HANDLE_TABLE_ENTRY)BaseAddress;
HandleTable->UnCommittedHandles = (PRTL_HANDLE_TABLE_ENTRY)BaseAddress;
HandleTable->MaxReservedHandles = (PRTL_HANDLE_TABLE_ENTRY)
((PCHAR)BaseAddress + ReserveSize);
}
}
else {
Status = STATUS_SUCCESS;
}
if (NT_SUCCESS( Status )) {
p = HandleTable->UnCommittedHandles;
if (p >= HandleTable->MaxReservedHandles) {
Status = STATUS_NO_MEMORY;
}
else {
CommitSize = PAGE_SIZE;
Status = NtAllocateVirtualMemory( NtCurrentProcess(),
(PVOID *)&p,
0,
&CommitSize,
MEM_COMMIT,
PAGE_READWRITE
);
if (NT_SUCCESS( Status )) {
HandleTable->UnCommittedHandles = (PRTL_HANDLE_TABLE_ENTRY)
((PCH)p + CommitSize);
}
}
}
}
except( EXCEPTION_EXECUTE_HANDLER ) {
Status = GetExceptionCode();
}
if (!NT_SUCCESS( Status )) {
return NULL;
}
pp = &HandleTable->FreeHandles;
while (p < HandleTable->UnCommittedHandles) {
*pp = p;
pp = &p->NextFree;
p = (PRTL_HANDLE_TABLE_ENTRY)((PUCHAR)p + HandleTable->SizeOfHandleTableEntry);
}
}
//
// Remove handle table entry from head of free list.
//
p = HandleTable->FreeHandles;
HandleTable->FreeHandles = p->NextFree;
//
// Clear free list link field, which also leaves the handle allocated bit
// clear. This allows the caller to mark it is allocated after they are
// done filling in their portion.
//
p->NextFree = NULL;
//
// If requested, return the index of this handle table entry
//
if (ARGUMENT_PRESENT( HandleIndex )) {
*HandleIndex = (ULONG) (((PCHAR)p - (PCHAR)HandleTable->CommittedHandles) /
HandleTable->SizeOfHandleTableEntry);
}
//
// Return a pointer to the handle table entry.
//
return p;
}
BOOLEAN
RtlFreeHandle(
IN PRTL_HANDLE_TABLE HandleTable,
IN PRTL_HANDLE_TABLE_ENTRY Handle
)
{
#if DBG
if (!RtlIsValidHandle( HandleTable, Handle )) {
DbgPrint( "RTL: RtlFreeHandle( %lx ) - invalid handle\n", Handle );
if (NtCurrentPeb()->BeingDebugged) {
DbgBreakPoint();
}
return FALSE;
}
#endif
RtlZeroMemory( Handle, HandleTable->SizeOfHandleTableEntry );
Handle->NextFree = HandleTable->FreeHandles;
HandleTable->FreeHandles = Handle;
return TRUE;
}
BOOLEAN
RtlIsValidHandle(
IN PRTL_HANDLE_TABLE HandleTable,
IN PRTL_HANDLE_TABLE_ENTRY Handle
)
{
if (Handle == NULL ||
Handle < HandleTable->CommittedHandles ||
Handle >= HandleTable->UnCommittedHandles ||
(ULONG_PTR)Handle & (HandleTable->SizeOfHandleTableEntry - 1) ||
!(Handle->Flags & RTL_HANDLE_ALLOCATED)
) {
return FALSE;
}
else {
return TRUE;
}
}
BOOLEAN
RtlIsValidIndexHandle(
IN PRTL_HANDLE_TABLE HandleTable,
IN ULONG HandleIndex,
OUT PRTL_HANDLE_TABLE_ENTRY *Handle
)
{
PRTL_HANDLE_TABLE_ENTRY p;
p = (PRTL_HANDLE_TABLE_ENTRY)
((PCHAR)HandleTable->CommittedHandles + (HandleIndex * HandleTable->SizeOfHandleTableEntry));
if (RtlIsValidHandle( HandleTable, p )) {
*Handle = p;
return TRUE;
}
else {
return FALSE;
}
}