Implement handle table management interface
This commit is contained in:
@@ -16,6 +16,7 @@ list(APPEND XTOSKRNL_SOURCE
|
||||
${XTOSKRNL_SOURCE_DIR}/ar/${ARCH}/traps.cc
|
||||
${XTOSKRNL_SOURCE_DIR}/ex/data.cc
|
||||
${XTOSKRNL_SOURCE_DIR}/ex/exports.cc
|
||||
${XTOSKRNL_SOURCE_DIR}/ex/handle.cc
|
||||
${XTOSKRNL_SOURCE_DIR}/ex/laslist.cc
|
||||
${XTOSKRNL_SOURCE_DIR}/ex/resource.cc
|
||||
${XTOSKRNL_SOURCE_DIR}/ex/rundown.cc
|
||||
|
||||
302
xtoskrnl/ex/handle.cc
Normal file
302
xtoskrnl/ex/handle.cc
Normal file
@@ -0,0 +1,302 @@
|
||||
/**
|
||||
* PROJECT: ExectOS
|
||||
* COPYRIGHT: See COPYING.md in the top level directory
|
||||
* FILE: xtoskrnl/ex/handle.cc
|
||||
* DESCRIPTION: Handle Table management interface
|
||||
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
|
||||
*/
|
||||
|
||||
#include <xtos.hh>
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves the extended information for a specific handle table entry.
|
||||
*
|
||||
* @param HandleTable
|
||||
* Supplies a pointer to the handle table containing the handle.
|
||||
*
|
||||
* @param Handle
|
||||
* Supplies the handle for which the extended information is requested.
|
||||
*
|
||||
* @param Locked
|
||||
* Specifies whether the handle table entry is currently locked by the caller.
|
||||
*
|
||||
* @return This routine returns a pointer to the handle table entry information, or NULL pointer if the table
|
||||
* does not support extra info pages or lookup fails.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTFASTCALL
|
||||
PHANDLE_TABLE_ENTRY_INFO
|
||||
EX::Handle::GetHandleInformation(IN PHANDLE_TABLE HandleTable,
|
||||
IN HANDLE Handle,
|
||||
IN BOOLEAN Locked)
|
||||
{
|
||||
PHANDLE_TABLE_ENTRY InfoStructure, TableEntry;
|
||||
PHANDLE_TABLE_ENTRY_INFO ResultInfo;
|
||||
EXHANDLE BaseHandle, ExHandle;
|
||||
|
||||
/* Initialize local state */
|
||||
ResultInfo = NULLPTR;
|
||||
TableEntry = NULLPTR;
|
||||
|
||||
/* Check if the handle table maintains extra information pages */
|
||||
if(HandleTable->ExtraInfoPages)
|
||||
{
|
||||
/* Check if the caller has not locked the entry */
|
||||
if(!Locked)
|
||||
{
|
||||
/* Acquire the lock */
|
||||
TableEntry = MapHandleToPointer(HandleTable, Handle);
|
||||
if(!TableEntry)
|
||||
{
|
||||
/* The handle is invalid or mapping failed, return NULL pointer */
|
||||
return NULLPTR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Isolate the base index of the handle table page */
|
||||
BaseHandle.GenericHandleOverlay = Handle;
|
||||
BaseHandle.Index &= ~(HANDLE_LOWLEVEL_COUNT - 1);
|
||||
|
||||
/* Fetch the base information structure */
|
||||
InfoStructure = LookupHandleTableEntry(HandleTable, BaseHandle);
|
||||
|
||||
/* Validate the retrieved structure */
|
||||
if(InfoStructure &&
|
||||
InfoStructure->NextFreeTableEntry == HANDLE_ADDITIONAL_INFO_SIGNATURE &&
|
||||
InfoStructure->InfoTable)
|
||||
{
|
||||
/* Decode the target index */
|
||||
ExHandle.GenericHandleOverlay = Handle;
|
||||
|
||||
/* Resolve the information entry pointer */
|
||||
ResultInfo = &InfoStructure->InfoTable[ExHandle.Index % HANDLE_LOWLEVEL_COUNT];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check if locked */
|
||||
if(TableEntry)
|
||||
{
|
||||
/* Release the lock */
|
||||
UnlockHandleTableEntry(HandleTable, TableEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the information pointer */
|
||||
return ResultInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquires the lock on a handle table entry, blocking the current thread if contention occurs.
|
||||
*
|
||||
* @param HandleTable
|
||||
* Supplies a pointer to the handle table containing the entry.
|
||||
*
|
||||
* @param HandleTableEntry
|
||||
* Supplies a pointer to the handle table entry to lock.
|
||||
*
|
||||
* @return This routine returns TRUE if the lock was successfully acquired, or FALSE otherwise.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
BOOLEAN
|
||||
EX::Handle::LockHandleTableEntry(IN PHANDLE_TABLE HandleTable,
|
||||
IN PHANDLE_TABLE_ENTRY HandleTableEntry)
|
||||
{
|
||||
LONG_PTR CurrentValue, NewValue, OldValue;
|
||||
KPUSH_LOCK_WAIT_BLOCK WaitBlock;
|
||||
|
||||
/* Enter a retry loop */
|
||||
while(TRUE)
|
||||
{
|
||||
/* Get the state of the entry */
|
||||
OldValue = *(VOLATILE LONG_PTR *)&HandleTableEntry->Value;
|
||||
|
||||
/* Check if the entry is currently unlocked */
|
||||
if(OldValue & EXHANDLE_TABLE_ENTRY_LOCK_BIT)
|
||||
{
|
||||
/* Clear the lock bit */
|
||||
NewValue = OldValue & ~EXHANDLE_TABLE_ENTRY_LOCK_BIT;
|
||||
|
||||
/* Attempt to apply the lock */
|
||||
if(RTL::Atomic::CompareExchangePointer((PVOID *)&HandleTableEntry->Value,
|
||||
(PVOID)NewValue, (PVOID)OldValue) == (PVOID)OldValue)
|
||||
{
|
||||
/* Lock acquired, return TRUE */
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check if the entry is completely empty */
|
||||
if(!OldValue)
|
||||
{
|
||||
/* Cannot proceed, return FALSE */
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* The entry is locked by another thread, block thread */
|
||||
KE::PushLock::BlockPushLock(&HandleTable->HandleContentionEvent, &WaitBlock);
|
||||
|
||||
/* Check if the entry was freed or unlocked */
|
||||
CurrentValue = *(VOLATILE LONG_PTR *)&HandleTableEntry->Value;
|
||||
if(!CurrentValue || (CurrentValue & EXHANDLE_TABLE_ENTRY_LOCK_BIT))
|
||||
{
|
||||
/* The state changed, abort the wait */
|
||||
KE::PushLock::UnblockPushLock(&HandleTable->HandleContentionEvent, &WaitBlock);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The entry is locked, commit to the wait state */
|
||||
KE::Dispatcher::WaitForSingleObject(&WaitBlock.WakeEvent, Executive, KernelMode, FALSE, NULLPTR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates a generic handle into a pointer to its underlying handle table entry.
|
||||
*
|
||||
* @param HandleTable
|
||||
* Supplies a pointer to the handle table performing the lookup.
|
||||
*
|
||||
* @param Handle
|
||||
* Supplies the structured handle to be translated.
|
||||
*
|
||||
* @return This routine returns a pointer to the corresponding handle table entry, or NULL pointer if the handle
|
||||
* is out of bounds or invalid.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
PHANDLE_TABLE_ENTRY
|
||||
EX::Handle::LookupHandleTableEntry(IN PHANDLE_TABLE HandleTable,
|
||||
IN EXHANDLE Handle)
|
||||
{
|
||||
PHANDLE_TABLE_ENTRY EntryTable;
|
||||
ULONG MaxHandle, TableLevel;
|
||||
ULONG_PTR Index, TableCode;
|
||||
PVOID *DirectoryTable;
|
||||
|
||||
/* Strip the tag bits */
|
||||
Handle.Value &= ~(ULONG_PTR)(HANDLE_VALUE_INCREMENT - 1);
|
||||
|
||||
/* Read the maximum handle value */
|
||||
MaxHandle = *(VOLATILE ULONG *)&HandleTable->NextHandleNeedingPool;
|
||||
if(Handle.Value >= MaxHandle)
|
||||
{
|
||||
/* Handle is out of bounds, return NULL pointer */
|
||||
return NULLPTR;
|
||||
}
|
||||
|
||||
/* Convert the raw handle value to an array index */
|
||||
Index = Handle.Value / HANDLE_VALUE_INCREMENT;
|
||||
|
||||
/* Read the table routing state */
|
||||
TableCode = *(VOLATILE ULONG_PTR *)&HandleTable->TableCode;
|
||||
|
||||
/* Extract the table depth level */
|
||||
TableLevel = (ULONG)(TableCode & HANDLE_LEVEL_CODE_MASK);
|
||||
|
||||
/* Validate the structural integrity of the table */
|
||||
if(TableLevel > 2)
|
||||
{
|
||||
/* Invalid table level, return NULL pointer */
|
||||
return NULLPTR;
|
||||
}
|
||||
|
||||
/* Isolate the base address of the table */
|
||||
DirectoryTable = (PVOID *)(TableCode & ~(ULONG_PTR)HANDLE_LEVEL_CODE_MASK);
|
||||
|
||||
/* Cascade through the directory levels */
|
||||
if(TableLevel == 2)
|
||||
{
|
||||
/* Resolve the highest level directory routing */
|
||||
DirectoryTable = (PVOID *)DirectoryTable[Index / (HANDLE_LOWLEVEL_COUNT * HANDLE_MIDLEVEL_COUNT)];
|
||||
}
|
||||
if(TableLevel >= 1)
|
||||
{
|
||||
/* Resolve the intermediate directory routing */
|
||||
DirectoryTable = (PVOID *)DirectoryTable[(Index / HANDLE_LOWLEVEL_COUNT) % HANDLE_MIDLEVEL_COUNT];
|
||||
}
|
||||
|
||||
/* Resolve the final entry page base */
|
||||
EntryTable = (PHANDLE_TABLE_ENTRY)DirectoryTable;
|
||||
|
||||
/* Return the memory location of the requested handle table entry */
|
||||
return &EntryTable[Index % HANDLE_LOWLEVEL_COUNT];
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a handle to its corresponding handle table entry and locks it.
|
||||
*
|
||||
* @param HandleTable
|
||||
* Supplies a pointer to the handle table where the lookup will be performed.
|
||||
*
|
||||
* @param Handle
|
||||
* Supplies the generic handle to map.
|
||||
*
|
||||
* @return This routine returns a pointer to the locked handle table entry on success, or NULL pointer on failure.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
PHANDLE_TABLE_ENTRY
|
||||
EX::Handle::MapHandleToPointer(IN PHANDLE_TABLE HandleTable,
|
||||
IN HANDLE Handle)
|
||||
{
|
||||
PHANDLE_TABLE_ENTRY TableEntry;
|
||||
EXHANDLE LocalHandle;
|
||||
|
||||
/* Assume failure initially */
|
||||
TableEntry = NULLPTR;
|
||||
|
||||
/* Overlay the generic handle */
|
||||
LocalHandle.GenericHandleOverlay = Handle;
|
||||
|
||||
/* Validate the handle index */
|
||||
if(LocalHandle.Index & (HANDLE_LOWLEVEL_COUNT - 1))
|
||||
{
|
||||
/* Lookup the handle table entry */
|
||||
TableEntry = LookupHandleTableEntry(HandleTable, LocalHandle);
|
||||
if(TableEntry)
|
||||
{
|
||||
/* Acquire the entry lock */
|
||||
if (!LockHandleTableEntry(HandleTable, TableEntry))
|
||||
{
|
||||
/* Lock acquisition failed, reset the pointer */
|
||||
TableEntry = NULLPTR;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the table entry pointer */
|
||||
return TableEntry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlocks a previously locked handle table entry and wakes up any threads waiting on the table's contention event.
|
||||
*
|
||||
* @param HandleTable
|
||||
* Supplies a pointer to the handle table containing the entry.
|
||||
*
|
||||
* @param HandleTableEntry
|
||||
* Supplies a pointer to the handle table entry to be unlocked.
|
||||
*
|
||||
* @return This routine does not return any value.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
VOID
|
||||
EX::Handle::UnlockHandleTableEntry(IN PHANDLE_TABLE HandleTable,
|
||||
IN PHANDLE_TABLE_ENTRY HandleTableEntry)
|
||||
{
|
||||
/* Unlock entry and signal the handle contention event */
|
||||
RTL::Atomic::Or64((VOLATILE PLONG_PTR)&HandleTableEntry->Value, (LONG_PTR)EXHANDLE_TABLE_ENTRY_LOCK_BIT);
|
||||
KE::PushLock::UnblockPushLock(&HandleTable->HandleContentionEvent, NULLPTR);
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <xtos.hh>
|
||||
|
||||
#include <ex/handle.hh>
|
||||
#include <ex/laslist.hh>
|
||||
#include <ex/resource.hh>
|
||||
#include <ex/rundown.hh>
|
||||
|
||||
37
xtoskrnl/includes/ex/handle.hh
Normal file
37
xtoskrnl/includes/ex/handle.hh
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* PROJECT: ExectOS
|
||||
* COPYRIGHT: See COPYING.md in the top level directory
|
||||
* FILE: xtoskrnl/includes/ex/handle.hh
|
||||
* DESCRIPTION: Handle Table management interface
|
||||
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef __XTOSKRNL_EX_HANDLE_HH
|
||||
#define __XTOSKRNL_EX_HANDLE_HH
|
||||
|
||||
#include <xtos.hh>
|
||||
|
||||
|
||||
/* Kernel Executive */
|
||||
namespace EX
|
||||
{
|
||||
class Handle
|
||||
{
|
||||
public:
|
||||
STATIC XTFASTCALL PHANDLE_TABLE_ENTRY_INFO GetHandleInformation(IN PHANDLE_TABLE HandleTable,
|
||||
IN HANDLE Handle,
|
||||
IN BOOLEAN Locked);
|
||||
STATIC XTAPI BOOLEAN LockHandleTableEntry(IN PHANDLE_TABLE HandleTable,
|
||||
IN PHANDLE_TABLE_ENTRY HandleTableEntry);
|
||||
STATIC XTAPI PHANDLE_TABLE_ENTRY MapHandleToPointer(IN PHANDLE_TABLE HandleTable,
|
||||
IN HANDLE Handle);
|
||||
STATIC XTAPI VOID UnlockHandleTableEntry(IN PHANDLE_TABLE HandleTable,
|
||||
IN PHANDLE_TABLE_ENTRY HandleTableEntry);
|
||||
|
||||
private:
|
||||
STATIC XTAPI PHANDLE_TABLE_ENTRY LookupHandleTableEntry(IN PHANDLE_TABLE HandleTable,
|
||||
IN EXHANDLE Handle);
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* __XTOSKRNL_EX_HANDLE_HH */
|
||||
Reference in New Issue
Block a user