3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ex/handle.c
6 * PURPOSE: Generic Executive Handle Tables
8 * PROGRAMMERS: Thomas Weidenmueller <w3seek@reactos.com>
12 * - the last entry of a subhandle list should be reserved for auditing
14 * ExReferenceHandleDebugInfo
15 * ExSnapShotHandleTables
16 * ExpMoveFreeHandles (???)
19 /* INCLUDES *****************************************************************/
24 #include <internal/debug.h>
26 static LIST_ENTRY ExpHandleTableHead
;
27 static FAST_MUTEX ExpHandleTableListLock
;
28 static LARGE_INTEGER ExpHandleShortWait
;
30 #define ExAcquireHandleTableListLock() \
31 ExAcquireFastMutexUnsafe(&ExpHandleTableListLock)
33 #define ExReleaseHandleTableListLock() \
34 ExReleaseFastMutexUnsafe(&ExpHandleTableListLock)
36 #define ExAcquireHandleLockExclusive(HandleTable) \
37 ExAcquireResourceExclusiveLite(&(HandleTable)->HandleLock, TRUE)
39 #define ExAcquireHandleLockShared(HandleTable) \
40 ExAcquireResourceSharedLite(&(HandleTable)->HandleLock, TRUE)
42 #define ExReleaseHandleLock(HandleTable) \
43 ExReleaseResourceLite(&(HandleTable)->HandleLock)
47 8 bits: top level index
48 10 bits: middle level index
49 9 bits: sub handle index
51 #define N_TLI_BITS 8 /* top level index */
52 #define N_MLI_BITS 10 /* middle level index */
53 #define N_EI_BITS 9 /* sub handle index */
54 #define TLI_OFFSET (N_MLI_BITS + N_EI_BITS)
55 #define MLI_OFFSET N_EI_BITS
58 #define N_TOPLEVEL_POINTERS (1 << N_TLI_BITS)
59 #define N_MIDDLELEVEL_POINTERS (1 << N_MLI_BITS)
60 #define N_SUBHANDLE_ENTRIES (1 << N_EI_BITS)
61 #define EX_MAX_HANDLES (N_TOPLEVEL_POINTERS * N_MIDDLELEVEL_POINTERS * N_SUBHANDLE_ENTRIES)
63 #define VALID_HANDLE_MASK (((N_TOPLEVEL_POINTERS - 1) << TLI_OFFSET) | \
64 ((N_MIDDLELEVEL_POINTERS - 1) << MLI_OFFSET) | ((N_SUBHANDLE_ENTRIES - 1) << EI_OFFSET))
65 #define TLI_FROM_HANDLE(index) (ULONG)(((index) >> TLI_OFFSET) & (N_TOPLEVEL_POINTERS - 1))
66 #define MLI_FROM_HANDLE(index) (ULONG)(((index) >> MLI_OFFSET) & (N_MIDDLELEVEL_POINTERS - 1))
67 #define ELI_FROM_HANDLE(index) (ULONG)(((index) >> EI_OFFSET) & (N_SUBHANDLE_ENTRIES - 1))
69 #define N_MAX_HANDLE (N_TOPLEVEL_POINTERS * N_MIDDLELEVEL_POINTERS * N_SUBHANDLE_ENTRIES)
71 #define BUILD_HANDLE(tli, mli, eli) ((((tli) & (N_TOPLEVEL_POINTERS - 1)) << TLI_OFFSET) | \
72 (((mli) & (N_MIDDLELEVEL_POINTERS - 1)) << MLI_OFFSET) | (((eli) & (N_SUBHANDLE_ENTRIES - 1)) << EI_OFFSET))
74 #define IS_INVALID_EX_HANDLE(index) \
75 (((index) & ~VALID_HANDLE_MASK) != 0)
76 #define IS_VALID_EX_HANDLE(index) \
77 (((index) & ~VALID_HANDLE_MASK) == 0)
79 #define HANDLE_TO_EX_HANDLE(handle) \
80 (LONG)(((LONG)(handle) >> 2) - 1)
81 #define EX_HANDLE_TO_HANDLE(exhandle) \
82 (HANDLE)(((exhandle) + 1) << 2)
84 static BOOLEAN ExpInitialized
= FALSE
;
86 /******************************************************************************/
89 ExpInitializeHandleTables(VOID
)
91 ExpHandleShortWait
.QuadPart
= -50000;
92 InitializeListHead(&ExpHandleTableHead
);
93 ExInitializeFastMutex(&ExpHandleTableListLock
);
95 ExpInitialized
= TRUE
;
99 ExCreateHandleTable(IN PEPROCESS QuotaProcess OPTIONAL
)
101 PHANDLE_TABLE HandleTable
;
110 if(QuotaProcess
!= NULL
)
112 /* FIXME - Charge process quota before allocating the handle table! */
115 /* allocate enough memory for the handle table and the lowest level */
116 HandleTable
= ExAllocatePoolWithTag(NonPagedPool
,
117 sizeof(HANDLE_TABLE
) + (N_TOPLEVEL_POINTERS
* sizeof(PHANDLE_TABLE_ENTRY
*)),
118 TAG('E', 'x', 'H', 't'));
119 if(HandleTable
!= NULL
)
121 /* initialize the handle table */
122 HandleTable
->Flags
= 0;
123 HandleTable
->HandleCount
= 0;
124 HandleTable
->Table
= (PHANDLE_TABLE_ENTRY
**)(HandleTable
+ 1);
125 HandleTable
->QuotaProcess
= QuotaProcess
;
126 HandleTable
->FirstFree
= -1; /* no entries freed so far */
127 HandleTable
->NextHandleNeedingPool
= 0; /* no entries freed so far, so we have to allocate already for the first handle */
128 HandleTable
->UniqueProcessId
= (QuotaProcess
? QuotaProcess
->UniqueProcessId
: NULL
);
130 ExInitializeResource(&HandleTable
->HandleLock
);
132 KeInitializeEvent(&HandleTable
->HandleContentionEvent
,
136 RtlZeroMemory(HandleTable
->Table
, N_TOPLEVEL_POINTERS
* sizeof(PHANDLE_TABLE_ENTRY
*));
138 /* during bootup KeGetCurrentThread() might be NULL, needs to be fixed... */
139 if(KeGetCurrentThread() != NULL
)
141 /* insert it into the global handle table list */
142 KeEnterCriticalRegion();
144 ExAcquireHandleTableListLock();
145 InsertTailList(&ExpHandleTableHead
,
146 &HandleTable
->HandleTableList
);
147 ExReleaseHandleTableListLock();
149 KeLeaveCriticalRegion();
153 InsertTailList(&ExpHandleTableHead
,
154 &HandleTable
->HandleTableList
);
159 /* FIXME - return the quota to the process */
166 ExSweepHandleTable(IN PHANDLE_TABLE HandleTable
,
167 IN PEX_SWEEP_HANDLE_CALLBACK SweepHandleCallback OPTIONAL
,
168 IN PVOID Context OPTIONAL
)
170 PHANDLE_TABLE_ENTRY
**tlp
, **lasttlp
, *mlp
, *lastmlp
;
177 KeEnterCriticalRegion();
179 /* ensure there's no other operations going by acquiring an exclusive lock */
180 ExAcquireHandleLockExclusive(HandleTable
);
182 ASSERT(!(HandleTable
->Flags
& EX_HANDLE_TABLE_CLOSING
));
184 HandleTable
->Flags
|= EX_HANDLE_TABLE_CLOSING
;
186 KePulseEvent(&HandleTable
->HandleContentionEvent
,
190 /* call the callback function to cleanup the objects associated with the
192 for(tlp
= HandleTable
->Table
, lasttlp
= HandleTable
->Table
+ N_TOPLEVEL_POINTERS
;
198 for(mlp
= *tlp
, lastmlp
= (*tlp
) + N_MIDDLELEVEL_POINTERS
;
204 PHANDLE_TABLE_ENTRY curee
, laste
;
206 for(curee
= *mlp
, laste
= *mlp
+ N_SUBHANDLE_ENTRIES
;
210 if(curee
->Object
!= NULL
&& SweepHandleCallback
!= NULL
)
212 curee
->ObAttributes
|= EX_HANDLE_ENTRY_LOCKED
;
213 SweepHandleCallback(curee
, EX_HANDLE_TO_HANDLE(ExHandle
), Context
);
227 ExReleaseHandleLock(HandleTable
);
229 KeLeaveCriticalRegion();
233 ExDestroyHandleTable(IN PHANDLE_TABLE HandleTable
)
235 PHANDLE_TABLE_ENTRY
**tlp
, **lasttlp
, *mlp
, *lastmlp
;
236 PEPROCESS QuotaProcess
;
241 ASSERT(HandleTable
->Flags
& EX_HANDLE_TABLE_CLOSING
);
243 KeEnterCriticalRegion();
245 /* at this point the table should not be queried or altered anymore,
246 no locks should be necessary */
248 ASSERT(HandleTable
->Flags
& EX_HANDLE_TABLE_CLOSING
);
250 /* remove the handle table from the global handle table list */
251 ExAcquireHandleTableListLock();
252 RemoveEntryList(&HandleTable
->HandleTableList
);
253 ExReleaseHandleTableListLock();
255 QuotaProcess
= HandleTable
->QuotaProcess
;
257 /* free the tables */
258 for(tlp
= HandleTable
->Table
, lasttlp
= HandleTable
->Table
+ N_TOPLEVEL_POINTERS
;
264 for(mlp
= *tlp
, lastmlp
= (*tlp
) + N_MIDDLELEVEL_POINTERS
;
272 if(QuotaProcess
!= NULL
)
274 /* FIXME - return the quota to the process */
281 if(QuotaProcess
!= NULL
)
283 /* FIXME - return the quota to the process */
288 KeLeaveCriticalRegion();
290 /* free the handle table */
291 ExDeleteResource(&HandleTable
->HandleLock
);
292 ExFreePool(HandleTable
);
294 if(QuotaProcess
!= NULL
)
296 /* FIXME - return the quota to the process */
301 ExDupHandleTable(IN PEPROCESS QuotaProcess OPTIONAL
,
302 IN PEX_DUPLICATE_HANDLE_CALLBACK DuplicateHandleCallback OPTIONAL
,
303 IN PVOID Context OPTIONAL
,
304 IN PHANDLE_TABLE SourceHandleTable
)
306 PHANDLE_TABLE HandleTable
;
310 ASSERT(SourceHandleTable
);
312 HandleTable
= ExCreateHandleTable(QuotaProcess
);
313 if(HandleTable
!= NULL
)
315 PHANDLE_TABLE_ENTRY
**tlp
, **srctlp
, **etlp
, *mlp
, *srcmlp
, *emlp
, stbl
, srcstbl
, estbl
;
320 /* make sure the other handle table isn't being changed during the duplication */
321 ExAcquireHandleLockShared(SourceHandleTable
);
323 /* allocate enough tables */
324 etlp
= SourceHandleTable
->Table
+ N_TOPLEVEL_POINTERS
;
325 for(srctlp
= SourceHandleTable
->Table
, tlp
= HandleTable
->Table
;
331 /* allocate middle level entry tables */
332 if(QuotaProcess
!= NULL
)
334 /* FIXME - Charge process quota before allocating the handle table! */
337 *tlp
= ExAllocatePoolWithTag(PagedPool
,
338 N_MIDDLELEVEL_POINTERS
* sizeof(PHANDLE_TABLE_ENTRY
),
339 TAG('E', 'x', 'H', 't'));
342 RtlZeroMemory(*tlp
, N_MIDDLELEVEL_POINTERS
* sizeof(PHANDLE_TABLE_ENTRY
));
346 emlp
= *srctlp
+ N_MIDDLELEVEL_POINTERS
;
347 for(srcmlp
= *srctlp
, mlp
= *tlp
;
353 /* allocate subhandle tables */
354 if(QuotaProcess
!= NULL
)
356 /* FIXME - Charge process quota before allocating the handle table! */
359 *mlp
= ExAllocatePoolWithTag(PagedPool
,
360 N_SUBHANDLE_ENTRIES
* sizeof(HANDLE_TABLE_ENTRY
),
361 TAG('E', 'x', 'H', 't'));
364 RtlZeroMemory(*mlp
, N_SUBHANDLE_ENTRIES
* sizeof(HANDLE_TABLE_ENTRY
));
368 goto freehandletable
;
380 DPRINT1("Failed to duplicate handle table 0x%p\n", SourceHandleTable
);
382 ExReleaseHandleLock(SourceHandleTable
);
384 ExDestroyHandleTable(HandleTable
);
385 /* allocate an empty handle table */
386 return ExCreateHandleTable(QuotaProcess
);
391 /* duplicate the handles */
392 HandleTable
->HandleCount
= SourceHandleTable
->HandleCount
;
393 HandleTable
->FirstFree
= SourceHandleTable
->FirstFree
;
394 HandleTable
->NextHandleNeedingPool
= SourceHandleTable
->NextHandleNeedingPool
;
396 /* make sure all tables are zeroed */
399 etlp
= SourceHandleTable
->Table
+ N_TOPLEVEL_POINTERS
;
400 for(srctlp
= SourceHandleTable
->Table
, tlp
= HandleTable
->Table
;
402 srctlp
++, tlp
++, tli
++)
406 ASSERT(*tlp
!= NULL
);
408 emlp
= *srctlp
+ N_MIDDLELEVEL_POINTERS
;
409 for(srcmlp
= *srctlp
, mlp
= *tlp
;
411 srcmlp
++, mlp
++, mli
++)
415 ASSERT(*mlp
!= NULL
);
417 /* walk all handle entries and duplicate them if wanted */
418 estbl
= *srcmlp
+ N_SUBHANDLE_ENTRIES
;
419 for(srcstbl
= *srcmlp
, stbl
= *mlp
;
421 srcstbl
++, stbl
++, eli
++)
423 /* try to duplicate the source handle */
424 if(srcstbl
->Object
!= NULL
&&
425 ExLockHandleTableEntry(SourceHandleTable
,
428 /* ask the caller if this handle should be duplicated */
429 if(DuplicateHandleCallback
!= NULL
&&
430 !DuplicateHandleCallback(HandleTable
,
434 /* free the entry and chain it into the free list */
435 HandleTable
->HandleCount
--;
437 stbl
->NextFreeTableEntry
= HandleTable
->FirstFree
;
438 HandleTable
->FirstFree
= BUILD_HANDLE(tli
, mli
, eli
);
442 /* duplicate the handle and unlock it */
443 stbl
->GrantedAccess
= srcstbl
->GrantedAccess
;
444 stbl
->ObAttributes
= srcstbl
->ObAttributes
& ~EX_HANDLE_ENTRY_LOCKED
;
446 ExUnlockHandleTableEntry(SourceHandleTable
,
451 /* this is a free handle table entry, copy over the entire
461 /* release the source handle table */
462 ExReleaseHandleLock(SourceHandleTable
);
468 static PHANDLE_TABLE_ENTRY
469 ExpAllocateHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
472 PHANDLE_TABLE_ENTRY Entry
= NULL
;
478 ASSERT(KeGetCurrentThread() != NULL
);
480 DPRINT("HT[0x%p]: HandleCount: %d\n", HandleTable
, HandleTable
->HandleCount
);
482 if(HandleTable
->HandleCount
< EX_MAX_HANDLES
)
486 if(HandleTable
->FirstFree
!= -1)
488 /* there's a free handle entry we can just grab and use */
489 tli
= TLI_FROM_HANDLE(HandleTable
->FirstFree
);
490 mli
= MLI_FROM_HANDLE(HandleTable
->FirstFree
);
491 eli
= ELI_FROM_HANDLE(HandleTable
->FirstFree
);
493 /* the pointer should be valid in any way!!! */
494 ASSERT(HandleTable
->Table
[tli
]);
495 ASSERT(HandleTable
->Table
[tli
][mli
]);
497 Entry
= &HandleTable
->Table
[tli
][mli
][eli
];
499 *Handle
= EX_HANDLE_TO_HANDLE(HandleTable
->FirstFree
);
501 /* save the index to the next free handle (if available) */
502 HandleTable
->FirstFree
= Entry
->NextFreeTableEntry
;
503 Entry
->NextFreeTableEntry
= 0;
504 Entry
->Object
= NULL
;
506 HandleTable
->HandleCount
++;
510 /* we need to allocate a new subhandle table first */
511 PHANDLE_TABLE_ENTRY cure
, laste
, ntbl
, *nmtbl
;
513 BOOLEAN AllocatedMtbl
;
515 ASSERT(HandleTable
->NextHandleNeedingPool
<= N_MAX_HANDLE
);
517 /* the index of the next table to be allocated was saved in
518 NextHandleNeedingPool the last time a handle entry was allocated and
519 the subhandle entry list was full. the subhandle entry index of
520 NextHandleNeedingPool should be 0 here! */
521 tli
= TLI_FROM_HANDLE(HandleTable
->NextHandleNeedingPool
);
522 mli
= MLI_FROM_HANDLE(HandleTable
->NextHandleNeedingPool
);
523 DPRINT("HandleTable->NextHandleNeedingPool: 0x%x\n", HandleTable
->NextHandleNeedingPool
);
524 DPRINT("tli: 0x%x mli: 0x%x eli: 0x%x\n", tli
, mli
, ELI_FROM_HANDLE(HandleTable
->NextHandleNeedingPool
));
526 ASSERT(ELI_FROM_HANDLE(HandleTable
->NextHandleNeedingPool
) == 0);
528 DPRINT("HandleTable->Table[%d] == 0x%p\n", tli
, HandleTable
->Table
[tli
]);
530 /* allocate a middle level entry list if required */
531 nmtbl
= HandleTable
->Table
[tli
];
534 if(HandleTable
->QuotaProcess
!= NULL
)
536 /* FIXME - Charge process quota before allocating the handle table! */
539 nmtbl
= ExAllocatePoolWithTag(PagedPool
,
540 N_MIDDLELEVEL_POINTERS
* sizeof(PHANDLE_TABLE_ENTRY
),
541 TAG('E', 'x', 'H', 't'));
544 if(HandleTable
->QuotaProcess
!= NULL
)
546 /* FIXME - return the quota to the process */
552 /* clear the middle level entry list */
553 RtlZeroMemory(nmtbl
, N_MIDDLELEVEL_POINTERS
* sizeof(PHANDLE_TABLE_ENTRY
));
555 /* make sure the table was zeroed before we set one item */
558 /* note, don't set the the pointer in the top level list yet because we
559 might screw up lookups if allocating a subhandle entry table failed
560 and this newly allocated table might get freed again */
561 AllocatedMtbl
= TRUE
;
565 AllocatedMtbl
= FALSE
;
567 /* allocate a subhandle entry table in any case! */
568 ASSERT(nmtbl
[mli
] == NULL
);
571 DPRINT("HandleTable->Table[%d][%d] == 0x%p\n", tli
, mli
, nmtbl
[mli
]);
573 if(HandleTable
->QuotaProcess
!= NULL
)
575 /* FIXME - Charge process quota before allocating the handle table! */
578 ntbl
= ExAllocatePoolWithTag(PagedPool
,
579 N_SUBHANDLE_ENTRIES
* sizeof(HANDLE_TABLE_ENTRY
),
580 TAG('E', 'x', 'H', 't'));
583 if(HandleTable
->QuotaProcess
!= NULL
)
585 /* FIXME - Return process quota charged */
588 /* free the middle level entry list, if allocated, because it's empty and
594 if(HandleTable
->QuotaProcess
!= NULL
)
596 /* FIXME - Return process quota charged */
603 /* let's just use the very first entry */
605 Entry
->ObAttributes
= EX_HANDLE_ENTRY_LOCKED
;
606 Entry
->NextFreeTableEntry
= 0;
608 *Handle
= EX_HANDLE_TO_HANDLE(HandleTable
->NextHandleNeedingPool
);
610 HandleTable
->HandleCount
++;
612 /* set the FirstFree member to the second entry and chain the
614 HandleTable
->FirstFree
= HandleTable
->NextHandleNeedingPool
+ 1;
615 for(cure
= Entry
+ 1, laste
= Entry
+ N_SUBHANDLE_ENTRIES
, i
= HandleTable
->FirstFree
+ 1;
620 cure
->NextFreeTableEntry
= i
;
622 /* truncate the free entry list */
623 (cure
- 1)->NextFreeTableEntry
= -1;
625 /* save the pointers to the allocated list(s) */
626 (void)InterlockedExchangePointer(&nmtbl
[mli
], ntbl
);
629 (void)InterlockedExchangePointer(&HandleTable
->Table
[tli
], nmtbl
);
632 /* increment the NextHandleNeedingPool to the next index where we need to
633 allocate new memory */
634 HandleTable
->NextHandleNeedingPool
+= N_SUBHANDLE_ENTRIES
;
639 DPRINT1("Can't allocate any more handles in handle table 0x%p!\n", HandleTable
);
646 ExpFreeHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
647 IN PHANDLE_TABLE_ENTRY Entry
,
654 ASSERT(IS_VALID_EX_HANDLE(Handle
));
656 DPRINT("ExpFreeHandleTableEntry HT:0x%p Entry:0x%p\n", HandleTable
, Entry
);
658 /* automatically unlock the entry if currently locked. We however don't notify
659 anyone who waited on the handle because we're holding an exclusive lock after
660 all and these locks will fail then */
661 (void)InterlockedExchangePointer(&Entry
->Object
, NULL
);
662 Entry
->NextFreeTableEntry
= HandleTable
->FirstFree
;
663 HandleTable
->FirstFree
= Handle
;
665 HandleTable
->HandleCount
--;
668 static PHANDLE_TABLE_ENTRY
669 ExpLookupHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
672 PHANDLE_TABLE_ENTRY Entry
= NULL
;
678 if(IS_VALID_EX_HANDLE(Handle
))
681 PHANDLE_TABLE_ENTRY
*mlp
;
683 tli
= TLI_FROM_HANDLE(Handle
);
684 mli
= MLI_FROM_HANDLE(Handle
);
685 eli
= ELI_FROM_HANDLE(Handle
);
687 mlp
= HandleTable
->Table
[tli
];
688 if(Handle
< HandleTable
->NextHandleNeedingPool
&&
689 mlp
!= NULL
&& mlp
[mli
] != NULL
&& mlp
[mli
][eli
].Object
!= NULL
)
691 Entry
= &mlp
[mli
][eli
];
692 DPRINT("handle lookup 0x%x -> entry 0x%p [HT:0x%p] ptr: 0x%p\n", Handle
, Entry
, HandleTable
, mlp
[mli
][eli
].Object
);
697 DPRINT("Looking up invalid handle 0x%x\n", Handle
);
704 ExLockHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
705 IN PHANDLE_TABLE_ENTRY Entry
)
707 ULONG_PTR Current
, New
;
711 DPRINT("Entering handle table entry 0x%p lock...\n", Entry
);
718 Current
= (volatile ULONG_PTR
)Entry
->Object
;
720 if(!Current
|| (HandleTable
->Flags
& EX_HANDLE_TABLE_CLOSING
))
722 DPRINT("Attempted to lock empty handle table entry 0x%p or handle table shut down\n", Entry
);
726 if(!(Current
& EX_HANDLE_ENTRY_LOCKED
))
728 New
= Current
| EX_HANDLE_ENTRY_LOCKED
;
729 if(InterlockedCompareExchangePointer(&Entry
->Object
,
731 (PVOID
)Current
) == (PVOID
)Current
)
733 DPRINT("SUCCESS handle table 0x%p entry 0x%p lock\n", HandleTable
, Entry
);
734 /* we acquired the lock */
739 /* wait about 5ms at maximum so we don't wait forever in unfortunate
740 co-incidences where releasing the lock in another thread happens right
741 before we're waiting on the contention event to get pulsed, which might
742 never happen again... */
743 KeWaitForSingleObject(&HandleTable
->HandleContentionEvent
,
747 &ExpHandleShortWait
);
754 ExUnlockHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
755 IN PHANDLE_TABLE_ENTRY Entry
)
757 ULONG_PTR Current
, New
;
764 DPRINT("ExUnlockHandleTableEntry HT:0x%p Entry:0x%p\n", HandleTable
, Entry
);
766 Current
= (volatile ULONG_PTR
)Entry
->Object
;
768 ASSERT(Current
& EX_HANDLE_ENTRY_LOCKED
);
770 New
= Current
& ~EX_HANDLE_ENTRY_LOCKED
;
772 (void)InterlockedExchangePointer(&Entry
->Object
,
775 /* we unlocked the entry, pulse the contention event so threads who're waiting
776 on the release can continue */
777 KePulseEvent(&HandleTable
->HandleContentionEvent
,
783 ExCreateHandle(IN PHANDLE_TABLE HandleTable
,
784 IN PHANDLE_TABLE_ENTRY Entry
)
786 PHANDLE_TABLE_ENTRY NewHandleTableEntry
;
787 HANDLE Handle
= NULL
;
794 /* The highest bit in Entry->Object has to be 1 so we make sure it's a
795 pointer to kmode memory. It will cleared though because it also indicates
797 ASSERT((ULONG_PTR
)Entry
->Object
& EX_HANDLE_ENTRY_LOCKED
);
799 KeEnterCriticalRegion();
800 ExAcquireHandleLockExclusive(HandleTable
);
802 NewHandleTableEntry
= ExpAllocateHandleTableEntry(HandleTable
,
804 if(NewHandleTableEntry
!= NULL
)
806 *NewHandleTableEntry
= *Entry
;
808 ExUnlockHandleTableEntry(HandleTable
,
809 NewHandleTableEntry
);
812 ExReleaseHandleLock(HandleTable
);
813 KeLeaveCriticalRegion();
819 ExDestroyHandle(IN PHANDLE_TABLE HandleTable
,
822 PHANDLE_TABLE_ENTRY HandleTableEntry
;
830 ExHandle
= HANDLE_TO_EX_HANDLE(Handle
);
832 KeEnterCriticalRegion();
833 ExAcquireHandleLockExclusive(HandleTable
);
835 HandleTableEntry
= ExpLookupHandleTableEntry(HandleTable
,
838 if(HandleTableEntry
!= NULL
&& ExLockHandleTableEntry(HandleTable
, HandleTableEntry
))
840 /* free and automatically unlock the handle. However we don't need to pulse
841 the contention event since other locks on this entry will fail */
842 ExpFreeHandleTableEntry(HandleTable
,
848 ExReleaseHandleLock(HandleTable
);
849 KeLeaveCriticalRegion();
855 ExDestroyHandleByEntry(IN PHANDLE_TABLE HandleTable
,
856 IN PHANDLE_TABLE_ENTRY Entry
,
864 /* This routine requires the entry to be locked */
865 ASSERT((ULONG_PTR
)Entry
->Object
& EX_HANDLE_ENTRY_LOCKED
);
867 DPRINT("DestroyHandleByEntry HT:0x%p Entry:0x%p\n", HandleTable
, Entry
);
869 KeEnterCriticalRegion();
870 ExAcquireHandleLockExclusive(HandleTable
);
872 /* free and automatically unlock the handle. However we don't need to pulse
873 the contention event since other locks on this entry will fail */
874 ExpFreeHandleTableEntry(HandleTable
,
876 HANDLE_TO_EX_HANDLE(Handle
));
878 ExReleaseHandleLock(HandleTable
);
879 KeLeaveCriticalRegion();
883 ExMapHandleToPointer(IN PHANDLE_TABLE HandleTable
,
886 PHANDLE_TABLE_ENTRY HandleTableEntry
;
892 HandleTableEntry
= ExpLookupHandleTableEntry(HandleTable
,
893 HANDLE_TO_EX_HANDLE(Handle
));
894 if (HandleTableEntry
!= NULL
&& ExLockHandleTableEntry(HandleTable
, HandleTableEntry
))
896 DPRINT("ExMapHandleToPointer HT:0x%p Entry:0x%p locked\n", HandleTable
, HandleTableEntry
);
897 return HandleTableEntry
;
904 ExChangeHandle(IN PHANDLE_TABLE HandleTable
,
906 IN PEX_CHANGE_HANDLE_CALLBACK ChangeHandleCallback
,
909 PHANDLE_TABLE_ENTRY HandleTableEntry
;
915 ASSERT(ChangeHandleCallback
);
917 KeEnterCriticalRegion();
919 HandleTableEntry
= ExpLookupHandleTableEntry(HandleTable
,
920 HANDLE_TO_EX_HANDLE(Handle
));
922 if(HandleTableEntry
!= NULL
&& ExLockHandleTableEntry(HandleTable
, HandleTableEntry
))
924 Ret
= ChangeHandleCallback(HandleTable
,
928 ExUnlockHandleTableEntry(HandleTable
,
932 KeLeaveCriticalRegion();