- fixed handle table structures
- implement generic executive handle tables (since there don't exist
documents that describe the parameters of most of these functions (which
are kernel internal only), i made them up as required)
- adjusted OB's handle manager to use ex handle tables
- adjusted the client id manager to use ex handle tables
Modified: trunk/reactos/config
Modified: trunk/reactos/include/ddk/kefuncs.h
Modified: trunk/reactos/include/ntos/obtypes.h
Modified: trunk/reactos/ntoskrnl/Makefile
Added: trunk/reactos/ntoskrnl/ex/handle.c
Modified: trunk/reactos/ntoskrnl/ex/init.c
Modified: trunk/reactos/ntoskrnl/ex/sysinfo.c
Modified: trunk/reactos/ntoskrnl/ex/work.c
Modified: trunk/reactos/ntoskrnl/include/internal/ex.h
Modified: trunk/reactos/ntoskrnl/include/internal/ob.h
Modified: trunk/reactos/ntoskrnl/include/internal/ps.h
Modified: trunk/reactos/ntoskrnl/io/iomgr.c
Modified: trunk/reactos/ntoskrnl/io/pnpmgr.c
Modified: trunk/reactos/ntoskrnl/lpc/close.c
Modified: trunk/reactos/ntoskrnl/ob/handle.c
Modified: trunk/reactos/ntoskrnl/ob/object.c
Modified: trunk/reactos/ntoskrnl/ps/cid.c
Modified: trunk/reactos/ntoskrnl/ps/create.c
Modified: trunk/reactos/ntoskrnl/ps/idle.c
Modified: trunk/reactos/ntoskrnl/ps/kill.c
Modified: trunk/reactos/ntoskrnl/ps/process.c
Modified: trunk/reactos/ntoskrnl/ps/psmgr.c
Modified: trunk/reactos/ntoskrnl/ps/thread.c
Modified: trunk/reactos/subsys/win32k/misc/object.c
_____
Modified: trunk/reactos/config
--- trunk/reactos/config 2005-03-13 13:59:06 UTC (rev 14006)
+++ trunk/reactos/config 2005-03-13 14:21:47 UTC (rev 14007)
@@ -15,22 +15,22 @@
# be optimized for.
#
-OARCH := i486
+OARCH := i586
#
# Whether to compile in the kernel debugger
#
-KDBG := 0
+KDBG := 1
#
# Whether to compile for debugging
#
-DBG := 0
+DBG := 1
#
# Whether to compile with optimizations
#
-OPTIMIZED := 0
+OPTIMIZED := 1
#
# Whether to compile a multiprocessor or single processor version
_____
Modified: trunk/reactos/include/ddk/kefuncs.h
--- trunk/reactos/include/ddk/kefuncs.h 2005-03-13 13:59:06 UTC (rev
14006)
+++ trunk/reactos/include/ddk/kefuncs.h 2005-03-13 14:21:47 UTC (rev
14007)
@@ -42,6 +42,15 @@
#ifndef __USE_W32API
+static __inline
+VOID
+KeMemoryBarrier(
+ VOID)
+{
+ volatile LONG Barrier;
+ __asm__ __volatile__ ("xchg %%eax, %0" : : "m" (Barrier) :
"%eax");
+}
+
VOID STDCALL KeAcquireSpinLockAtDpcLevel (IN PKSPIN_LOCK
SpinLock);
#define KefAcquireSpinLockAtDpcLevel KeAcquireSpinLockAtDpcLevel
_____
Modified: trunk/reactos/include/ntos/obtypes.h
--- trunk/reactos/include/ntos/obtypes.h 2005-03-13 13:59:06 UTC
(rev 14006)
+++ trunk/reactos/include/ntos/obtypes.h 2005-03-13 14:21:47 UTC
(rev 14007)
@@ -87,18 +87,42 @@
PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
+typedef struct _HANDLE_TABLE_ENTRY_INFO {
+ ULONG AuditMask;
+} HANDLE_TABLE_ENTRY_INFO, *PHANDLE_TABLE_ENTRY_INFO;
+
+typedef struct _HANDLE_TABLE_ENTRY {
+ union {
+ PVOID Object;
+ ULONG_PTR ObAttributes;
+ PHANDLE_TABLE_ENTRY_INFO InfoTable;
+ ULONG_PTR Value;
+ } u1;
+ union {
+ ULONG GrantedAccess;
+ USHORT GrantedAccessIndex;
+ LONG NextFreeTableEntry;
+ } u2;
+} HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;
+
#endif /* __USE_W32API */
typedef struct _HANDLE_TABLE
{
- LIST_ENTRY ListHead;
- KSPIN_LOCK ListLock;
-} HANDLE_TABLE;
+ ULONG Flags;
+ LONG HandleCount;
+ PHANDLE_TABLE_ENTRY **Table;
+ PEPROCESS QuotaProcess;
+ HANDLE UniqueProcessId;
+ LONG FirstFreeTableEntry;
+ LONG NextIndexNeedingPool;
+ ERESOURCE HandleTableLock;
+ LIST_ENTRY HandleTableList;
+ KEVENT HandleContentionEvent;
+} HANDLE_TABLE, *PHANDLE_TABLE;
#ifndef __USE_W32API
-typedef struct _HANDLE_TABLE *PHANDLE_TABLE;
-
/*
* FIXME: These will eventually become centerfold in the compliant Ob
Manager
* For now, they are only here so Device Map is properly defined before
the header
_____
Modified: trunk/reactos/ntoskrnl/Makefile
--- trunk/reactos/ntoskrnl/Makefile 2005-03-13 13:59:06 UTC (rev
14006)
+++ trunk/reactos/ntoskrnl/Makefile 2005-03-13 14:21:47 UTC (rev
14007)
@@ -239,6 +239,7 @@
ex/event.o \
ex/evtpair.o \
ex/fmutex.o \
+ ex/handle.o \
ex/hashtab.o \
ex/init.o \
ex/interlck.o \
_____
Added: trunk/reactos/ntoskrnl/ex/handle.c
--- trunk/reactos/ntoskrnl/ex/handle.c 2005-03-13 13:59:06 UTC (rev
14006)
+++ trunk/reactos/ntoskrnl/ex/handle.c 2005-03-13 14:21:47 UTC (rev
14007)
@@ -0,0 +1,949 @@
+/* $Id:$
+ *
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * FILE: ntoskrnl/ex/handle.c
+ * PURPOSE: Generic Executive Handle Tables
+ *
+ * PROGRAMMERS: Thomas Weidenmueller <w3seek(a)reactos.com>
+ *
+ * TODO:
+ *
+ * - the last entry of a subhandle list should be reserved for
auditing
+ *
+ * ExSweepHandleTable (???)
+ * ExReferenceHandleDebugInfo
+ * ExSnapShotHandleTables
+ * ExpMoveFreeHandles (???)
+ */
+
+/* INCLUDES
*****************************************************************/
+
+#include <ntoskrnl.h>
+
+#define NDEBUG
+#include <internal/debug.h>
+
+static LIST_ENTRY ExpHandleTableHead;
+static FAST_MUTEX ExpHandleTableListLock;
+static LARGE_INTEGER ExpHandleShortWait;
+
+#define ExAcquireHandleTableListLock()
\
+ ExAcquireFastMutexUnsafe(&ExpHandleTableListLock)
+
+#define ExReleaseHandleTableListLock()
\
+ ExReleaseFastMutexUnsafe(&ExpHandleTableListLock)
+
+#define ExAcquireHandleTableLockExclusive(HandleTable)
\
+ ExAcquireResourceExclusiveLite(&(HandleTable)->HandleTableLock, TRUE)
+
+#define ExAcquireHandleTableLockShared(HandleTable)
\
+ ExAcquireResourceSharedLite(&(HandleTable)->HandleTableLock, TRUE)
+
+#define ExReleaseHandleTableLock(HandleTable)
\
+ ExReleaseResourceLite(&(HandleTable)->HandleTableLock)
+
+/*
+ 5 bits: reserved
+ 8 bits: top level index
+ 10 bits: middle level index
+ 9 bits: sub handle index
+*/
+#define N_TLI_BITS 8 /* top level index */
+#define N_MLI_BITS 10 /* middle level index */
+#define N_EI_BITS 9 /* sub handle index */
+#define TLI_OFFSET (N_MLI_BITS + N_EI_BITS)
+#define MLI_OFFSET N_EI_BITS
+#define EI_OFFSET 0
+
+#define N_TOPLEVEL_POINTERS (1 << N_TLI_BITS)
+#define N_MIDDLELEVEL_POINTERS (1 << N_MLI_BITS)
+#define N_SUBHANDLE_ENTRIES (1 << N_EI_BITS)
+#define EX_MAX_HANDLES (N_TOPLEVEL_POINTERS * N_MIDDLELEVEL_POINTERS *
N_SUBHANDLE_ENTRIES)
+
+#define VALID_HANDLE_MASK (((N_TOPLEVEL_POINTERS - 1) << TLI_OFFSET) |
\
+ ((N_MIDDLELEVEL_POINTERS - 1) << MLI_OFFSET) | ((N_SUBHANDLE_ENTRIES
- 1) << EI_OFFSET))
+#define TLI_FROM_HANDLE(index) (ULONG)(((index) >> TLI_OFFSET) &
(N_TOPLEVEL_POINTERS - 1))
+#define MLI_FROM_HANDLE(index) (ULONG)(((index) >> MLI_OFFSET) &
(N_MIDDLELEVEL_POINTERS - 1))
+#define ELI_FROM_HANDLE(index) (ULONG)(((index) >> EI_OFFSET) &
(N_SUBHANDLE_ENTRIES - 1))
+
+#define N_MAX_HANDLE (N_TOPLEVEL_POINTERS * N_MIDDLELEVEL_POINTERS *
N_SUBHANDLE_ENTRIES)
+
+#define BUILD_HANDLE(tli, mli, eli) ((((tli) & (N_TOPLEVEL_POINTERS -
1)) << TLI_OFFSET) | \
+ (((mli) & (N_MIDDLELEVEL_POINTERS - 1)) << MLI_OFFSET) | (((eli) &
(N_SUBHANDLE_ENTRIES - 1)) << EI_OFFSET))
+
+#define IS_INVALID_EX_HANDLE(index)
\
+ (((index) & ~VALID_HANDLE_MASK) != 0)
+#define IS_VALID_EX_HANDLE(index)
\
+ (((index) & ~VALID_HANDLE_MASK) == 0)
+
+/**********************************************************************
********/
+
+VOID
+ExpInitializeHandleTables(VOID)
+{
+ ExpHandleShortWait.QuadPart = -50000;
+ InitializeListHead(&ExpHandleTableHead);
+ ExInitializeFastMutex(&ExpHandleTableListLock);
+}
+
+PHANDLE_TABLE
+ExCreateHandleTable(IN PEPROCESS QuotaProcess OPTIONAL)
+{
+ PHANDLE_TABLE HandleTable;
+
+ PAGED_CODE();
+
+ if(QuotaProcess != NULL)
+ {
+ /* FIXME - Charge process quota before allocating the handle table!
*/
+ }
+
+ /* allocate enough memory for the handle table and the lowest level
*/
+ HandleTable = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(HANDLE_TABLE) +
(N_TOPLEVEL_POINTERS * sizeof(PHANDLE_TABLE_ENTRY*)),
+ TAG('E', 'x', 'H',
't'));
+ if(HandleTable != NULL)
+ {
+ /* initialize the handle table */
+ HandleTable->Flags = 0;
+ HandleTable->HandleCount = 0;
+ HandleTable->Table = (PHANDLE_TABLE_ENTRY**)(HandleTable + 1);
+ HandleTable->QuotaProcess = QuotaProcess;
+ HandleTable->FirstFreeTableEntry = -1; /* no entries freed so far
*/
+ HandleTable->NextIndexNeedingPool = 0; /* no entries freed so far,
so we have to allocate already for the first handle */
+ HandleTable->UniqueProcessId = (QuotaProcess ?
QuotaProcess->UniqueProcessId : PsGetCurrentProcessId());
+
+ ExInitializeResource(&HandleTable->HandleTableLock);
+
+ KeInitializeEvent(&HandleTable->HandleContentionEvent,
+ NotificationEvent,
+ FALSE);
+
+ RtlZeroMemory(HandleTable->Table, N_TOPLEVEL_POINTERS *
sizeof(PHANDLE_TABLE_ENTRY*));
+
+ /* during bootup KeGetCurrentThread() might be NULL, needs to be
fixed... */
+ if(KeGetCurrentThread() != NULL)
+ {
+ /* insert it into the global handle table list */
+ KeEnterCriticalRegion();
+
+ ExAcquireHandleTableListLock();
+ InsertTailList(&ExpHandleTableHead,
+ &HandleTable->HandleTableList);
+ ExReleaseHandleTableListLock();
+
+ KeLeaveCriticalRegion();
+ }
+ else
+ {
+ InsertTailList(&ExpHandleTableHead,
+ &HandleTable->HandleTableList);
+ }
+ }
+ else
+ {
+ /* FIXME - return the quota to the process */
+ }
+
+ return HandleTable;
+}
+
+static BOOLEAN
+ExLockHandleTableEntryNoDestructionCheck(IN PHANDLE_TABLE HandleTable,
+ IN PHANDLE_TABLE_ENTRY Entry)
+{
+ ULONG_PTR Current, New;
+
+ PAGED_CODE();
+
+ DPRINT("Entering handle table entry 0x%x lock...\n", Entry);
+
+ ASSERT(HandleTable);
+ ASSERT(Entry);
+
+ for(;;)
+ {
+ Current = (volatile ULONG_PTR)Entry->u1.Object;
+
+ if(!Current)
+ {
+ DPRINT("Attempted to lock empty handle table entry 0x%x or handle
table shut down\n", Entry);
+ break;
+ }
+
+ if(!(Current & EX_HANDLE_ENTRY_LOCKED))
+ {
+ New = Current | EX_HANDLE_ENTRY_LOCKED;
+ if(InterlockedCompareExchangePointer(&Entry->u1.Object,
+ (PVOID)New,
+ (PVOID)Current) ==
(PVOID)Current)
+ {
+ DPRINT("SUCCESS handle table 0x%x entry 0x%x lock\n",
HandleTable, Entry);
+ /* we acquired the lock */
+ return TRUE;
+ }
+ }
+
+ /* wait about 5ms at maximum so we don't wait forever in
unfortunate
+ co-incidences where releasing the lock in another thread happens
right
+ before we're waiting on the contention event to get pulsed,
which might
+ never happen again... */
+ KeWaitForSingleObject(&HandleTable->HandleContentionEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ &ExpHandleShortWait);
+ }
+
+ return FALSE;
+}
+
+VOID
+ExDestroyHandleTable(IN PHANDLE_TABLE HandleTable,
+ IN PEX_DESTROY_HANDLE_CALLBACK
DestroyHandleCallback OPTIONAL,
+ IN PVOID Context OPTIONAL)
+{
+ PHANDLE_TABLE_ENTRY **tlp, **lasttlp, *mlp, *lastmlp;
+ PEPROCESS QuotaProcess;
+
+ PAGED_CODE();
+
+ ASSERT(HandleTable);
+
+ KeEnterCriticalRegion();
+
+ /* ensure there's no other operations going by acquiring an exclusive
lock */
+ ExAcquireHandleTableLockExclusive(HandleTable);
+
+ ASSERT(!(HandleTable->Flags & EX_HANDLE_TABLE_CLOSING));
+
+ HandleTable->Flags |= EX_HANDLE_TABLE_CLOSING;
+
+ KePulseEvent(&HandleTable->HandleContentionEvent,
+ EVENT_INCREMENT,
+ FALSE);
+
+ /* remove the handle table from the global handle table list */
+ ExAcquireHandleTableListLock();
+ RemoveEntryList(&HandleTable->HandleTableList);
+ ExReleaseHandleTableListLock();
+
+ /* call the callback function to cleanup the objects associated with
the
+ handle table */
+ if(DestroyHandleCallback != NULL)
+ {
+ for(tlp = HandleTable->Table, lasttlp = HandleTable->Table +
N_TOPLEVEL_POINTERS;
+ tlp != lasttlp;
+ tlp++)
+ {
+ if((*tlp) != NULL)
+ {
+ for(mlp = *tlp, lastmlp = (*tlp) + N_MIDDLELEVEL_POINTERS;
+ mlp != lastmlp;
+ mlp++)
+ {
+ if((*mlp) != NULL)
+ {
+ PHANDLE_TABLE_ENTRY curee, laste;
+
+ for(curee = *mlp, laste = *mlp + N_SUBHANDLE_ENTRIES;
+ curee != laste;
+ curee++)
+ {
+ if(curee->u1.Object != NULL &&
ExLockHandleTableEntryNoDestructionCheck(HandleTable, curee))
+ {
+ DestroyHandleCallback(HandleTable, curee->u1.Object,
curee->u2.GrantedAccess, Context);
+ ExUnlockHandleTableEntry(HandleTable, curee);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ QuotaProcess = HandleTable->QuotaProcess;
+
+ /* free the tables */
+ for(tlp = HandleTable->Table, lasttlp = HandleTable->Table +
N_TOPLEVEL_POINTERS;
+ tlp != lasttlp;
+ tlp++)
+ {
+ if((*tlp) != NULL)
+ {
+ for(mlp = *tlp, lastmlp = (*tlp) + N_MIDDLELEVEL_POINTERS;
+ mlp != lastmlp;
+ mlp++)
+ {
+ if((*mlp) != NULL)
+ {
+ ExFreePool(*mlp);
+
+ if(QuotaProcess != NULL)
+ {
+ /* FIXME - return the quota to the process */
+ }
+ }
+ }
+
+ ExFreePool(*tlp);
+
+ if(QuotaProcess != NULL)
+ {
+ /* FIXME - return the quota to the process */
+ }
+ }
+ }
+
+ ExReleaseHandleTableLock(HandleTable);
+
+ KeLeaveCriticalRegion();
+
+ /* free the handle table */
+ ExDeleteResource(&HandleTable->HandleTableLock);
+ ExFreePool(HandleTable);
+
+ if(QuotaProcess != NULL)
+ {
+ /* FIXME - return the quota to the process */
+ }
+}
+
+PHANDLE_TABLE
+ExDupHandleTable(IN PEPROCESS QuotaProcess OPTIONAL,
+ IN PEX_DUPLICATE_HANDLE_CALLBACK
DuplicateHandleCallback OPTIONAL,
+ IN PVOID Context OPTIONAL,
+ IN PHANDLE_TABLE SourceHandleTable)
+{
+ PHANDLE_TABLE HandleTable;
+
+ PAGED_CODE();
+
+ ASSERT(SourceHandleTable);
+
+ HandleTable = ExCreateHandleTable(QuotaProcess);
+ if(HandleTable != NULL)
+ {
+ PHANDLE_TABLE_ENTRY **tlp, **srctlp, **etlp, *mlp, *srcmlp, *emlp,
stbl, srcstbl, estbl;
+ LONG tli, mli, eli;
+
+ tli = mli = eli = 0;
+
+ /* make sure the other handle table isn't being changed during the
duplication */
+ ExAcquireHandleTableLockShared(SourceHandleTable);
+
+ /* allocate enough tables */
+ etlp = SourceHandleTable->Table + N_TOPLEVEL_POINTERS;
+ for(srctlp = SourceHandleTable->Table, tlp = HandleTable->Table;
+ srctlp != etlp;
+ srctlp++, tlp++)
+ {
+ if(*srctlp != NULL)
+ {
+ /* allocate middle level entry tables */
+ if(QuotaProcess != NULL)
+ {
+ /* FIXME - Charge process quota before allocating the handle
table! */
+ }
+
+ *tlp = ExAllocatePoolWithTag(PagedPool,
+ N_MIDDLELEVEL_POINTERS *
sizeof(PHANDLE_TABLE_ENTRY),
+ TAG('E', 'x', 'H',
't'));
+ if(*tlp != NULL)
+ {
+ RtlZeroMemory(*tlp, N_MIDDLELEVEL_POINTERS *
sizeof(PHANDLE_TABLE_ENTRY));
+
+ KeMemoryBarrier();
+
+ emlp = *srctlp + N_MIDDLELEVEL_POINTERS;
+ for(srcmlp = *srctlp, mlp = *tlp;
+ srcmlp != emlp;
+ srcmlp++, mlp++)
+ {
+ if(*srcmlp != NULL)
+ {
+ /* allocate subhandle tables */
+ if(QuotaProcess != NULL)
+ {
+ /* FIXME - Charge process quota before allocating the
handle table! */
+ }
+
+ *mlp = ExAllocatePoolWithTag(PagedPool,
+ N_SUBHANDLE_ENTRIES *
sizeof(HANDLE_TABLE_ENTRY),
+ TAG('E', 'x', 'H',
't'));
+ if(*mlp != NULL)
+ {
+ RtlZeroMemory(*mlp, N_SUBHANDLE_ENTRIES *
sizeof(HANDLE_TABLE_ENTRY));
+ }
+ else
+ {
+ goto freehandletable;
+ }
+ }
+ else
+ {
+ *mlp = NULL;
+ }
+ }
+ }
+ else
+ {
+freehandletable:
+ DPRINT1("Failed to duplicate handle table 0x%x\n",
SourceHandleTable);
+
+ ExReleaseHandleTableLock(SourceHandleTable);
+
+ ExDestroyHandleTable(HandleTable,
+ NULL,
+ NULL);
+ /* allocate an empty handle table */
+ return ExCreateHandleTable(QuotaProcess);
+ }
+ }
+ }
+
+ /* duplicate the handles */
+ HandleTable->HandleCount = SourceHandleTable->HandleCount;
+ HandleTable->FirstFreeTableEntry =
SourceHandleTable->FirstFreeTableEntry;
+ HandleTable->NextIndexNeedingPool =
SourceHandleTable->NextIndexNeedingPool;
+
+ /* make sure all tables are zeroed */
+ KeMemoryBarrier();
+
+ etlp = SourceHandleTable->Table + N_TOPLEVEL_POINTERS;
+ for(srctlp = SourceHandleTable->Table, tlp = HandleTable->Table;
+ srctlp != etlp;
+ srctlp++, tlp++, tli++)
+ {
+ if(*srctlp != NULL)
+ {
+ ASSERT(*tlp != NULL);
+
+ emlp = *srctlp + N_MIDDLELEVEL_POINTERS;
+ for(srcmlp = *srctlp, mlp = *tlp;
+ srcmlp != emlp;
+ srcmlp++, mlp++, mli++)
+ {
+ if(*srcmlp != NULL)
+ {
+ ASSERT(*mlp != NULL);
+
+ /* walk all handle entries and duplicate them if wanted */
+ estbl = *srcmlp + N_SUBHANDLE_ENTRIES;
+ for(srcstbl = *srcmlp, stbl = *mlp;
+ srcstbl != estbl;
+ srcstbl++, stbl++, eli++)
+ {
+ /* try to duplicate the source handle */
+ if(srcstbl->u1.Object != NULL &&
+ ExLockHandleTableEntry(SourceHandleTable,
+ srcstbl))
+ {
+ /* ask the caller if this handle should be duplicated
*/
+ if(DuplicateHandleCallback != NULL &&
+ !DuplicateHandleCallback(HandleTable,
+ srcstbl,
+ Context))
+ {
+ /* free the entry and chain it into the free list */
+ HandleTable->HandleCount--;
+ stbl->u1.Object = NULL;
+ stbl->u2.NextFreeTableEntry =
HandleTable->FirstFreeTableEntry;
+ HandleTable->FirstFreeTableEntry = BUILD_HANDLE(tli,
mli, eli);
+ }
+ else
+ {
+ /* duplicate the handle and unlock it */
+ stbl->u2.GrantedAccess = srcstbl->u2.GrantedAccess;
+ stbl->u1.ObAttributes = srcstbl->u1.ObAttributes &
~EX_HANDLE_ENTRY_LOCKED;
+ }
+ ExUnlockHandleTableEntry(SourceHandleTable,
+ srcstbl);
+ }
+ else
+ {
+ /* this is a free handle table entry, copy over the
entire
+ structure as-is */
+ *stbl = *srcstbl;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* release the source handle table */
+ ExReleaseHandleTableLock(SourceHandleTable);
+ }
+
+ return HandleTable;
+}
+
+static PHANDLE_TABLE_ENTRY
+ExpAllocateHandleTableEntry(IN PHANDLE_TABLE HandleTable,
+ OUT PLONG Handle)
+{
+ PHANDLE_TABLE_ENTRY Entry = NULL;
+
+ PAGED_CODE();
+
+ ASSERT(HandleTable);
+ ASSERT(Handle);
+ ASSERT(KeGetCurrentThread() != NULL);
+
+ DPRINT("HT[0x%x]: HandleCount: %d\n", HandleTable,
HandleTable->HandleCount);
+
+ if(HandleTable->HandleCount < EX_MAX_HANDLES)
+ {
+ ULONG tli, mli, eli;
+
+ if(HandleTable->FirstFreeTableEntry != -1)
+ {
+ /* there's a free handle entry we can just grab and use */
+ tli = TLI_FROM_HANDLE(HandleTable->FirstFreeTableEntry);
+ mli = MLI_FROM_HANDLE(HandleTable->FirstFreeTableEntry);
+ eli = ELI_FROM_HANDLE(HandleTable->FirstFreeTableEntry);
+
+ /* the pointer should be valid in any way!!! */
+ ASSERT(HandleTable->Table[tli]);
+ ASSERT(HandleTable->Table[tli][mli]);
+
+ Entry = &HandleTable->Table[tli][mli][eli];
+
+ *Handle = HandleTable->FirstFreeTableEntry;
+
+ /* save the index to the next free handle (if available) */
+ HandleTable->FirstFreeTableEntry = Entry->u2.NextFreeTableEntry;
+ Entry->u2.NextFreeTableEntry = 0;
+ Entry->u1.Object = NULL;
+
+ HandleTable->HandleCount++;
+ }
+ else
+ {
+ /* we need to allocate a new subhandle table first */
+ PHANDLE_TABLE_ENTRY cure, laste, ntbl, *nmtbl;
+ ULONG i;
+ BOOLEAN AllocatedMtbl;
+
+ ASSERT(HandleTable->NextIndexNeedingPool <= N_MAX_HANDLE);
+
+ /* the index of the next table to be allocated was saved in
+ NextIndexNeedingPool the last time a handle entry was
allocated and
+ the subhandle entry list was full. the subhandle entry index
of
+ NextIndexNeedingPool should be 0 here! */
+ tli = TLI_FROM_HANDLE(HandleTable->NextIndexNeedingPool);
+ mli = MLI_FROM_HANDLE(HandleTable->NextIndexNeedingPool);
+ DPRINT("HandleTable->NextIndexNeedingPool: 0x%x\n",
HandleTable->NextIndexNeedingPool);
+ DPRINT("tli: 0x%x mli: 0x%x eli: 0x%x\n", tli, mli,
ELI_FROM_HANDLE(HandleTable->NextIndexNeedingPool));
+
+ ASSERT(ELI_FROM_HANDLE(HandleTable->NextIndexNeedingPool) == 0);
+
+ DPRINT("HandleTable->Table[%d] == 0x%x\n", tli,
HandleTable->Table[tli]);
+
+ /* allocate a middle level entry list if required */
+ nmtbl = HandleTable->Table[tli];
+ if(nmtbl == NULL)
+ {
+ if(HandleTable->QuotaProcess != NULL)
+ {
+ /* FIXME - Charge process quota before allocating the handle
table! */
+ }
+
+ nmtbl = ExAllocatePoolWithTag(PagedPool,
+ N_MIDDLELEVEL_POINTERS *
sizeof(PHANDLE_TABLE_ENTRY),
+ TAG('E', 'x', 'H',
't'));
+ if(nmtbl == NULL)
+ {
+ if(HandleTable->QuotaProcess != NULL)
+ {
+ /* FIXME - return the quota to the process */
+ }
+
+ return NULL;
+ }
+
+ /* clear the middle level entry list */
+ RtlZeroMemory(nmtbl, N_MIDDLELEVEL_POINTERS *
sizeof(PHANDLE_TABLE_ENTRY));
+
+ /* make sure the table was zeroed before we set one item */
+ KeMemoryBarrier();
+
+ /* note, don't set the the pointer in the top level list yet
because we
+ might screw up lookups if allocating a subhandle entry table
failed
+ and this newly allocated table might get freed again */
+ AllocatedMtbl = TRUE;
+ }
+ else
+ {
+ AllocatedMtbl = FALSE;
+
+ /* allocate a subhandle entry table in any case! */
+ ASSERT(nmtbl[mli] == NULL);
+ }
+
+ DPRINT("HandleTable->Table[%d][%d] == 0x%x\n", tli, mli,
nmtbl[mli]);
+
+ if(HandleTable->QuotaProcess != NULL)
+ {
+ /* FIXME - Charge process quota before allocating the handle
table! */
+ }
+
+ ntbl = ExAllocatePoolWithTag(PagedPool,
+ N_SUBHANDLE_ENTRIES *
sizeof(HANDLE_TABLE_ENTRY),
+ TAG('E', 'x', 'H',
't'));
+ if(ntbl == NULL)
+ {
+ if(HandleTable->QuotaProcess != NULL)
+ {
+ /* FIXME - Return process quota charged */
+ }
+
+ /* free the middle level entry list, if allocated, because it's
empty and
+ unused */
+ if(AllocatedMtbl)
+ {
+ ExFreePool(nmtbl);
+
+ if(HandleTable->QuotaProcess != NULL)
+ {
+ /* FIXME - Return process quota charged */
+ }
+ }
+
+ return NULL;
+ }
+
+ /* let's just use the very first entry */
+ Entry = ntbl;
+ Entry->u1.ObAttributes = EX_HANDLE_ENTRY_LOCKED;
+ Entry->u2.NextFreeTableEntry = 0;
+
+ *Handle = HandleTable->NextIndexNeedingPool;
+
+ HandleTable->HandleCount++;
+
+ /* set the FirstFreeTableEntry member to the second entry and
chain the
+ free entries */
+ HandleTable->FirstFreeTableEntry =
HandleTable->NextIndexNeedingPool + 1;
+ for(cure = Entry + 1, laste = Entry + N_SUBHANDLE_ENTRIES, i =
HandleTable->FirstFreeTableEntry + 1;
+ cure != laste;
+ cure++, i++)
+ {
+ cure->u1.Object = NULL;
+ cure->u2.NextFreeTableEntry = i;
+ }
+ /* truncate the free entry list */
+ (cure - 1)->u2.NextFreeTableEntry = -1;
+
+ /* save the pointers to the allocated list(s) */
+ InterlockedExchangePointer(&nmtbl[mli], ntbl);
+ if(AllocatedMtbl)
+ {
+ InterlockedExchangePointer(&HandleTable->Table[tli], nmtbl);
+ }
+
+ /* increment the NextIndexNeedingPool to the next index where we
need to
+ allocate new memory */
+ HandleTable->NextIndexNeedingPool += N_SUBHANDLE_ENTRIES;
+ }
+ }
+ else
+ {
+ DPRINT1("Can't allocate any more handles in handle table 0x%x!\n",
HandleTable);
+ }
+
+ return Entry;
+}
+
+static VOID
+ExpFreeHandleTableEntry(IN PHANDLE_TABLE HandleTable,
+ IN PHANDLE_TABLE_ENTRY Entry,
+ IN LONG Handle)
+{
+ PAGED_CODE();
+
+ ASSERT(HandleTable);
+ ASSERT(Entry);
+ ASSERT(IS_VALID_EX_HANDLE(Handle));
+
+ DPRINT("ExpFreeHandleTableEntry HT:0x%x Entry:0x%x\n", HandleTable,
Entry);
+
+ /* automatically unlock the entry if currently locked. We however
don't notify
+ anyone who waited on the handle because we're holding an exclusive
lock after
+ all and these locks will fail then */
+ InterlockedExchangePointer(&Entry->u1.Object, NULL);
+ Entry->u2.NextFreeTableEntry = HandleTable->FirstFreeTableEntry;
+ HandleTable->FirstFreeTableEntry = Handle;
+
+ HandleTable->HandleCount--;
+}
+
+static PHANDLE_TABLE_ENTRY
+ExpLookupHandleTableEntry(IN PHANDLE_TABLE HandleTable,
+ IN LONG Handle)
+{
+ PHANDLE_TABLE_ENTRY Entry = NULL;
+
+ PAGED_CODE();
+
+ ASSERT(HandleTable);
+
+ if(IS_VALID_EX_HANDLE(Handle))
+ {
+ ULONG tli, mli, eli;
+ PHANDLE_TABLE_ENTRY *mlp;
+
+ tli = TLI_FROM_HANDLE(Handle);
+ mli = MLI_FROM_HANDLE(Handle);
+ eli = ELI_FROM_HANDLE(Handle);
+
+ mlp = HandleTable->Table[tli];
+ if(Handle < HandleTable->NextIndexNeedingPool &&
+ mlp != NULL && mlp[mli] != NULL && mlp[mli][eli].u1.Object !=
NULL)
+ {
+ Entry = &mlp[mli][eli];
+ DPRINT("handle lookup 0x%x -> entry 0x%x [HT:0x%x] ptr: 0x%x\n",
Handle, Entry, HandleTable, mlp[mli][eli].u1.Object);
+ }
+ }
+ else
+ {
+ DPRINT("Looking up invalid handle 0x%x\n", Handle);
+ }
+
+ return Entry;
+}
+
+BOOLEAN
+ExLockHandleTableEntry(IN PHANDLE_TABLE HandleTable,
+ IN PHANDLE_TABLE_ENTRY Entry)
+{
+ ULONG_PTR Current, New;
+
+ PAGED_CODE();
+
+ DPRINT("Entering handle table entry 0x%x lock...\n", Entry);
+
+ ASSERT(HandleTable);
+ ASSERT(Entry);
+
+ for(;;)
+ {
+ Current = (volatile ULONG_PTR)Entry->u1.Object;
+
+ if(!Current || (HandleTable->Flags & EX_HANDLE_TABLE_CLOSING))
+ {
+ DPRINT("Attempted to lock empty handle table entry 0x%x or handle
table shut down\n", Entry);
+ break;
+ }
+
+ if(!(Current & EX_HANDLE_ENTRY_LOCKED))
+ {
+ New = Current | EX_HANDLE_ENTRY_LOCKED;
+ if(InterlockedCompareExchangePointer(&Entry->u1.Object,
+ (PVOID)New,
+ (PVOID)Current) ==
(PVOID)Current)
+ {
+ DPRINT("SUCCESS handle table 0x%x entry 0x%x lock\n",
HandleTable, Entry);
+ /* we acquired the lock */
+ return TRUE;
+ }
+ }
+
+ /* wait about 5ms at maximum so we don't wait forever in
unfortunate
+ co-incidences where releasing the lock in another thread happens
right
+ before we're waiting on the contention event to get pulsed,
which might
+ never happen again... */
+ KeWaitForSingleObject(&HandleTable->HandleContentionEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ &ExpHandleShortWait);
+ }
+
+ return FALSE;
+}
+
+VOID
+ExUnlockHandleTableEntry(IN PHANDLE_TABLE HandleTable,
+ IN PHANDLE_TABLE_ENTRY Entry)
+{
+ ULONG_PTR Current, New;
+
+ PAGED_CODE();
+
+ ASSERT(HandleTable);
+ ASSERT(Entry);
+
+ DPRINT("ExUnlockHandleTableEntry HT:0x%x Entry:0x%x\n", HandleTable,
Entry);
+
+ Current = (volatile ULONG_PTR)Entry->u1.Object;
+
+ ASSERT(Current & EX_HANDLE_ENTRY_LOCKED);
+
+ New = Current & ~EX_HANDLE_ENTRY_LOCKED;
+
+ InterlockedExchangePointer(&Entry->u1.Object,
+ (PVOID)New);
+
+ /* we unlocked the entry, pulse the contention event so threads
who're waiting
+ on the release can continue */
+ KePulseEvent(&HandleTable->HandleContentionEvent,
+ EVENT_INCREMENT,
+ FALSE);
+}
+
+LONG
+ExCreateHandle(IN PHANDLE_TABLE HandleTable,
+ IN PHANDLE_TABLE_ENTRY Entry)
+{
+ PHANDLE_TABLE_ENTRY NewHandleTableEntry;
+ LONG Handle = EX_INVALID_HANDLE;
+
+ PAGED_CODE();
+
+ ASSERT(HandleTable);
+ ASSERT(Entry);
+
+ /* The highest bit in Entry->u1.Object has to be 1 so we make sure
it's a
+ pointer to kmode memory. It will cleared though because it also
indicates
+ the lock */
+ ASSERT((ULONG_PTR)Entry->u1.Object & EX_HANDLE_ENTRY_LOCKED);
+
+ KeEnterCriticalRegion();
+ ExAcquireHandleTableLockExclusive(HandleTable);
+
+ NewHandleTableEntry = ExpAllocateHandleTableEntry(HandleTable,
+ &Handle);
+ if(NewHandleTableEntry != NULL)
+ {
+ *NewHandleTableEntry = *Entry;
+
+ ExUnlockHandleTableEntry(HandleTable,
+ NewHandleTableEntry);
+ }
+
+ ExReleaseHandleTableLock(HandleTable);
+ KeLeaveCriticalRegion();
+
+ return Handle;
+}
+
+BOOLEAN
+ExDestroyHandle(IN PHANDLE_TABLE HandleTable,
+ IN LONG Handle)
+{
+ PHANDLE_TABLE_ENTRY HandleTableEntry;
+ BOOLEAN Ret = FALSE;
+
+ PAGED_CODE();
+
+ ASSERT(HandleTable);
+
+ KeEnterCriticalRegion();
+ ExAcquireHandleTableLockExclusive(HandleTable);
+
+ HandleTableEntry = ExpLookupHandleTableEntry(HandleTable,
+ Handle);
+
+ if(HandleTableEntry != NULL && ExLockHandleTableEntry(HandleTable,
HandleTableEntry))
+ {
+ /* free and automatically unlock the handle. However we don't need
to pulse
+ the contention event since other locks on this entry will fail
*/
+ ExpFreeHandleTableEntry(HandleTable,
+ HandleTableEntry,
+ Handle);
+ Ret = TRUE;
+ }
+
+ ExReleaseHandleTableLock(HandleTable);
+ KeLeaveCriticalRegion();
+
+ return Ret;
+}
+
+VOID
+ExDestroyHandleByEntry(IN PHANDLE_TABLE HandleTable,
+ IN PHANDLE_TABLE_ENTRY Entry,
+ IN LONG Handle)
+{
+ PAGED_CODE();
+
+ ASSERT(HandleTable);
+ ASSERT(Entry);
+
+ /* This routine requires the entry to be locked */
+ ASSERT((ULONG_PTR)Entry->u1.Object & EX_HANDLE_ENTRY_LOCKED);
+
+ DPRINT("DestroyHandleByEntry HT:0x%x Entry:0x%x\n", HandleTable,
Entry);
+
[truncated at 1000 lines; 2866 more skipped]