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 ExAcquireHandleTableLockExclusive(HandleTable) \
37 ExAcquireResourceExclusiveLite(&(HandleTable)->HandleTableLock, TRUE)
39 #define ExAcquireHandleTableLockShared(HandleTable) \
40 ExAcquireResourceSharedLite(&(HandleTable)->HandleTableLock, TRUE)
42 #define ExReleaseHandleTableLock(HandleTable) \
43 ExReleaseResourceLite(&(HandleTable)->HandleTableLock)
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
->FirstFreeTableEntry
= -1; /* no entries freed so far */
127 HandleTable
->NextIndexNeedingPool
= 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
->HandleTableLock
);
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
;
176 KeEnterCriticalRegion();
178 /* ensure there's no other operations going by acquiring an exclusive lock */
179 ExAcquireHandleTableLockExclusive(HandleTable
);
181 ASSERT(!(HandleTable
->Flags
& EX_HANDLE_TABLE_CLOSING
));
183 HandleTable
->Flags
|= EX_HANDLE_TABLE_CLOSING
;
185 KePulseEvent(&HandleTable
->HandleContentionEvent
,
189 /* call the callback function to cleanup the objects associated with the
191 for(tlp
= HandleTable
->Table
, lasttlp
= HandleTable
->Table
+ N_TOPLEVEL_POINTERS
;
197 for(mlp
= *tlp
, lastmlp
= (*tlp
) + N_MIDDLELEVEL_POINTERS
;
203 PHANDLE_TABLE_ENTRY curee
, laste
;
205 for(curee
= *mlp
, laste
= *mlp
+ N_SUBHANDLE_ENTRIES
;
209 if(curee
->u1
.Object
!= NULL
&& SweepHandleCallback
!= NULL
)
211 curee
->u1
.ObAttributes
|= EX_HANDLE_ENTRY_LOCKED
;
212 SweepHandleCallback(HandleTable
, curee
->u1
.Object
, curee
->u2
.GrantedAccess
, Context
);
220 ExReleaseHandleTableLock(HandleTable
);
222 KeLeaveCriticalRegion();
226 ExDestroyHandleTable(IN PHANDLE_TABLE HandleTable
)
228 PHANDLE_TABLE_ENTRY
**tlp
, **lasttlp
, *mlp
, *lastmlp
;
229 PEPROCESS QuotaProcess
;
234 ASSERT(HandleTable
->Flags
& EX_HANDLE_TABLE_CLOSING
);
236 KeEnterCriticalRegion();
238 /* at this point the table should not be queried or altered anymore,
239 no locks should be necessary */
241 ASSERT(HandleTable
->Flags
& EX_HANDLE_TABLE_CLOSING
);
243 /* remove the handle table from the global handle table list */
244 ExAcquireHandleTableListLock();
245 RemoveEntryList(&HandleTable
->HandleTableList
);
246 ExReleaseHandleTableListLock();
248 QuotaProcess
= HandleTable
->QuotaProcess
;
250 /* free the tables */
251 for(tlp
= HandleTable
->Table
, lasttlp
= HandleTable
->Table
+ N_TOPLEVEL_POINTERS
;
257 for(mlp
= *tlp
, lastmlp
= (*tlp
) + N_MIDDLELEVEL_POINTERS
;
265 if(QuotaProcess
!= NULL
)
267 /* FIXME - return the quota to the process */
274 if(QuotaProcess
!= NULL
)
276 /* FIXME - return the quota to the process */
281 KeLeaveCriticalRegion();
283 /* free the handle table */
284 ExDeleteResource(&HandleTable
->HandleTableLock
);
285 ExFreePool(HandleTable
);
287 if(QuotaProcess
!= NULL
)
289 /* FIXME - return the quota to the process */
294 ExDupHandleTable(IN PEPROCESS QuotaProcess OPTIONAL
,
295 IN PEX_DUPLICATE_HANDLE_CALLBACK DuplicateHandleCallback OPTIONAL
,
296 IN PVOID Context OPTIONAL
,
297 IN PHANDLE_TABLE SourceHandleTable
)
299 PHANDLE_TABLE HandleTable
;
303 ASSERT(SourceHandleTable
);
305 HandleTable
= ExCreateHandleTable(QuotaProcess
);
306 if(HandleTable
!= NULL
)
308 PHANDLE_TABLE_ENTRY
**tlp
, **srctlp
, **etlp
, *mlp
, *srcmlp
, *emlp
, stbl
, srcstbl
, estbl
;
313 /* make sure the other handle table isn't being changed during the duplication */
314 ExAcquireHandleTableLockShared(SourceHandleTable
);
316 /* allocate enough tables */
317 etlp
= SourceHandleTable
->Table
+ N_TOPLEVEL_POINTERS
;
318 for(srctlp
= SourceHandleTable
->Table
, tlp
= HandleTable
->Table
;
324 /* allocate middle level entry tables */
325 if(QuotaProcess
!= NULL
)
327 /* FIXME - Charge process quota before allocating the handle table! */
330 *tlp
= ExAllocatePoolWithTag(PagedPool
,
331 N_MIDDLELEVEL_POINTERS
* sizeof(PHANDLE_TABLE_ENTRY
),
332 TAG('E', 'x', 'H', 't'));
335 RtlZeroMemory(*tlp
, N_MIDDLELEVEL_POINTERS
* sizeof(PHANDLE_TABLE_ENTRY
));
339 emlp
= *srctlp
+ N_MIDDLELEVEL_POINTERS
;
340 for(srcmlp
= *srctlp
, mlp
= *tlp
;
346 /* allocate subhandle tables */
347 if(QuotaProcess
!= NULL
)
349 /* FIXME - Charge process quota before allocating the handle table! */
352 *mlp
= ExAllocatePoolWithTag(PagedPool
,
353 N_SUBHANDLE_ENTRIES
* sizeof(HANDLE_TABLE_ENTRY
),
354 TAG('E', 'x', 'H', 't'));
357 RtlZeroMemory(*mlp
, N_SUBHANDLE_ENTRIES
* sizeof(HANDLE_TABLE_ENTRY
));
361 goto freehandletable
;
373 DPRINT1("Failed to duplicate handle table 0x%p\n", SourceHandleTable
);
375 ExReleaseHandleTableLock(SourceHandleTable
);
377 ExDestroyHandleTable(HandleTable
);
378 /* allocate an empty handle table */
379 return ExCreateHandleTable(QuotaProcess
);
384 /* duplicate the handles */
385 HandleTable
->HandleCount
= SourceHandleTable
->HandleCount
;
386 HandleTable
->FirstFreeTableEntry
= SourceHandleTable
->FirstFreeTableEntry
;
387 HandleTable
->NextIndexNeedingPool
= SourceHandleTable
->NextIndexNeedingPool
;
389 /* make sure all tables are zeroed */
392 etlp
= SourceHandleTable
->Table
+ N_TOPLEVEL_POINTERS
;
393 for(srctlp
= SourceHandleTable
->Table
, tlp
= HandleTable
->Table
;
395 srctlp
++, tlp
++, tli
++)
399 ASSERT(*tlp
!= NULL
);
401 emlp
= *srctlp
+ N_MIDDLELEVEL_POINTERS
;
402 for(srcmlp
= *srctlp
, mlp
= *tlp
;
404 srcmlp
++, mlp
++, mli
++)
408 ASSERT(*mlp
!= NULL
);
410 /* walk all handle entries and duplicate them if wanted */
411 estbl
= *srcmlp
+ N_SUBHANDLE_ENTRIES
;
412 for(srcstbl
= *srcmlp
, stbl
= *mlp
;
414 srcstbl
++, stbl
++, eli
++)
416 /* try to duplicate the source handle */
417 if(srcstbl
->u1
.Object
!= NULL
&&
418 ExLockHandleTableEntry(SourceHandleTable
,
421 /* ask the caller if this handle should be duplicated */
422 if(DuplicateHandleCallback
!= NULL
&&
423 !DuplicateHandleCallback(HandleTable
,
427 /* free the entry and chain it into the free list */
428 HandleTable
->HandleCount
--;
429 stbl
->u1
.Object
= NULL
;
430 stbl
->u2
.NextFreeTableEntry
= HandleTable
->FirstFreeTableEntry
;
431 HandleTable
->FirstFreeTableEntry
= BUILD_HANDLE(tli
, mli
, eli
);
435 /* duplicate the handle and unlock it */
436 stbl
->u2
.GrantedAccess
= srcstbl
->u2
.GrantedAccess
;
437 stbl
->u1
.ObAttributes
= srcstbl
->u1
.ObAttributes
& ~EX_HANDLE_ENTRY_LOCKED
;
439 ExUnlockHandleTableEntry(SourceHandleTable
,
444 /* this is a free handle table entry, copy over the entire
454 /* release the source handle table */
455 ExReleaseHandleTableLock(SourceHandleTable
);
461 static PHANDLE_TABLE_ENTRY
462 ExpAllocateHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
465 PHANDLE_TABLE_ENTRY Entry
= NULL
;
471 ASSERT(KeGetCurrentThread() != NULL
);
473 DPRINT("HT[0x%p]: HandleCount: %d\n", HandleTable
, HandleTable
->HandleCount
);
475 if(HandleTable
->HandleCount
< EX_MAX_HANDLES
)
479 if(HandleTable
->FirstFreeTableEntry
!= -1)
481 /* there's a free handle entry we can just grab and use */
482 tli
= TLI_FROM_HANDLE(HandleTable
->FirstFreeTableEntry
);
483 mli
= MLI_FROM_HANDLE(HandleTable
->FirstFreeTableEntry
);
484 eli
= ELI_FROM_HANDLE(HandleTable
->FirstFreeTableEntry
);
486 /* the pointer should be valid in any way!!! */
487 ASSERT(HandleTable
->Table
[tli
]);
488 ASSERT(HandleTable
->Table
[tli
][mli
]);
490 Entry
= &HandleTable
->Table
[tli
][mli
][eli
];
492 *Handle
= EX_HANDLE_TO_HANDLE(HandleTable
->FirstFreeTableEntry
);
494 /* save the index to the next free handle (if available) */
495 HandleTable
->FirstFreeTableEntry
= Entry
->u2
.NextFreeTableEntry
;
496 Entry
->u2
.NextFreeTableEntry
= 0;
497 Entry
->u1
.Object
= NULL
;
499 HandleTable
->HandleCount
++;
503 /* we need to allocate a new subhandle table first */
504 PHANDLE_TABLE_ENTRY cure
, laste
, ntbl
, *nmtbl
;
506 BOOLEAN AllocatedMtbl
;
508 ASSERT(HandleTable
->NextIndexNeedingPool
<= N_MAX_HANDLE
);
510 /* the index of the next table to be allocated was saved in
511 NextIndexNeedingPool the last time a handle entry was allocated and
512 the subhandle entry list was full. the subhandle entry index of
513 NextIndexNeedingPool should be 0 here! */
514 tli
= TLI_FROM_HANDLE(HandleTable
->NextIndexNeedingPool
);
515 mli
= MLI_FROM_HANDLE(HandleTable
->NextIndexNeedingPool
);
516 DPRINT("HandleTable->NextIndexNeedingPool: 0x%x\n", HandleTable
->NextIndexNeedingPool
);
517 DPRINT("tli: 0x%x mli: 0x%x eli: 0x%x\n", tli
, mli
, ELI_FROM_HANDLE(HandleTable
->NextIndexNeedingPool
));
519 ASSERT(ELI_FROM_HANDLE(HandleTable
->NextIndexNeedingPool
) == 0);
521 DPRINT("HandleTable->Table[%d] == 0x%p\n", tli
, HandleTable
->Table
[tli
]);
523 /* allocate a middle level entry list if required */
524 nmtbl
= HandleTable
->Table
[tli
];
527 if(HandleTable
->QuotaProcess
!= NULL
)
529 /* FIXME - Charge process quota before allocating the handle table! */
532 nmtbl
= ExAllocatePoolWithTag(PagedPool
,
533 N_MIDDLELEVEL_POINTERS
* sizeof(PHANDLE_TABLE_ENTRY
),
534 TAG('E', 'x', 'H', 't'));
537 if(HandleTable
->QuotaProcess
!= NULL
)
539 /* FIXME - return the quota to the process */
545 /* clear the middle level entry list */
546 RtlZeroMemory(nmtbl
, N_MIDDLELEVEL_POINTERS
* sizeof(PHANDLE_TABLE_ENTRY
));
548 /* make sure the table was zeroed before we set one item */
551 /* note, don't set the the pointer in the top level list yet because we
552 might screw up lookups if allocating a subhandle entry table failed
553 and this newly allocated table might get freed again */
554 AllocatedMtbl
= TRUE
;
558 AllocatedMtbl
= FALSE
;
560 /* allocate a subhandle entry table in any case! */
561 ASSERT(nmtbl
[mli
] == NULL
);
564 DPRINT("HandleTable->Table[%d][%d] == 0x%p\n", tli
, mli
, nmtbl
[mli
]);
566 if(HandleTable
->QuotaProcess
!= NULL
)
568 /* FIXME - Charge process quota before allocating the handle table! */
571 ntbl
= ExAllocatePoolWithTag(PagedPool
,
572 N_SUBHANDLE_ENTRIES
* sizeof(HANDLE_TABLE_ENTRY
),
573 TAG('E', 'x', 'H', 't'));
576 if(HandleTable
->QuotaProcess
!= NULL
)
578 /* FIXME - Return process quota charged */
581 /* free the middle level entry list, if allocated, because it's empty and
587 if(HandleTable
->QuotaProcess
!= NULL
)
589 /* FIXME - Return process quota charged */
596 /* let's just use the very first entry */
598 Entry
->u1
.ObAttributes
= EX_HANDLE_ENTRY_LOCKED
;
599 Entry
->u2
.NextFreeTableEntry
= 0;
601 *Handle
= EX_HANDLE_TO_HANDLE(HandleTable
->NextIndexNeedingPool
);
603 HandleTable
->HandleCount
++;
605 /* set the FirstFreeTableEntry member to the second entry and chain the
607 HandleTable
->FirstFreeTableEntry
= HandleTable
->NextIndexNeedingPool
+ 1;
608 for(cure
= Entry
+ 1, laste
= Entry
+ N_SUBHANDLE_ENTRIES
, i
= HandleTable
->FirstFreeTableEntry
+ 1;
612 cure
->u1
.Object
= NULL
;
613 cure
->u2
.NextFreeTableEntry
= i
;
615 /* truncate the free entry list */
616 (cure
- 1)->u2
.NextFreeTableEntry
= -1;
618 /* save the pointers to the allocated list(s) */
619 InterlockedExchangePointer(&nmtbl
[mli
], ntbl
);
622 InterlockedExchangePointer(&HandleTable
->Table
[tli
], nmtbl
);
625 /* increment the NextIndexNeedingPool to the next index where we need to
626 allocate new memory */
627 HandleTable
->NextIndexNeedingPool
+= N_SUBHANDLE_ENTRIES
;
632 DPRINT1("Can't allocate any more handles in handle table 0x%p!\n", HandleTable
);
639 ExpFreeHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
640 IN PHANDLE_TABLE_ENTRY Entry
,
647 ASSERT(IS_VALID_EX_HANDLE(Handle
));
649 DPRINT("ExpFreeHandleTableEntry HT:0x%p Entry:0x%p\n", HandleTable
, Entry
);
651 /* automatically unlock the entry if currently locked. We however don't notify
652 anyone who waited on the handle because we're holding an exclusive lock after
653 all and these locks will fail then */
654 InterlockedExchangePointer(&Entry
->u1
.Object
, NULL
);
655 Entry
->u2
.NextFreeTableEntry
= HandleTable
->FirstFreeTableEntry
;
656 HandleTable
->FirstFreeTableEntry
= Handle
;
658 HandleTable
->HandleCount
--;
661 static PHANDLE_TABLE_ENTRY
662 ExpLookupHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
665 PHANDLE_TABLE_ENTRY Entry
= NULL
;
671 if(IS_VALID_EX_HANDLE(Handle
))
674 PHANDLE_TABLE_ENTRY
*mlp
;
676 tli
= TLI_FROM_HANDLE(Handle
);
677 mli
= MLI_FROM_HANDLE(Handle
);
678 eli
= ELI_FROM_HANDLE(Handle
);
680 mlp
= HandleTable
->Table
[tli
];
681 if(Handle
< HandleTable
->NextIndexNeedingPool
&&
682 mlp
!= NULL
&& mlp
[mli
] != NULL
&& mlp
[mli
][eli
].u1
.Object
!= NULL
)
684 Entry
= &mlp
[mli
][eli
];
685 DPRINT("handle lookup 0x%x -> entry 0x%p [HT:0x%p] ptr: 0x%p\n", Handle
, Entry
, HandleTable
, mlp
[mli
][eli
].u1
.Object
);
690 DPRINT("Looking up invalid handle 0x%x\n", Handle
);
697 ExLockHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
698 IN PHANDLE_TABLE_ENTRY Entry
)
700 ULONG_PTR Current
, New
;
704 DPRINT("Entering handle table entry 0x%p lock...\n", Entry
);
711 Current
= (volatile ULONG_PTR
)Entry
->u1
.Object
;
713 if(!Current
|| (HandleTable
->Flags
& EX_HANDLE_TABLE_CLOSING
))
715 DPRINT("Attempted to lock empty handle table entry 0x%p or handle table shut down\n", Entry
);
719 if(!(Current
& EX_HANDLE_ENTRY_LOCKED
))
721 New
= Current
| EX_HANDLE_ENTRY_LOCKED
;
722 if(InterlockedCompareExchangePointer(&Entry
->u1
.Object
,
724 (PVOID
)Current
) == (PVOID
)Current
)
726 DPRINT("SUCCESS handle table 0x%p entry 0x%p lock\n", HandleTable
, Entry
);
727 /* we acquired the lock */
732 /* wait about 5ms at maximum so we don't wait forever in unfortunate
733 co-incidences where releasing the lock in another thread happens right
734 before we're waiting on the contention event to get pulsed, which might
735 never happen again... */
736 KeWaitForSingleObject(&HandleTable
->HandleContentionEvent
,
740 &ExpHandleShortWait
);
747 ExUnlockHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
748 IN PHANDLE_TABLE_ENTRY Entry
)
750 ULONG_PTR Current
, New
;
757 DPRINT("ExUnlockHandleTableEntry HT:0x%p Entry:0x%p\n", HandleTable
, Entry
);
759 Current
= (volatile ULONG_PTR
)Entry
->u1
.Object
;
761 ASSERT(Current
& EX_HANDLE_ENTRY_LOCKED
);
763 New
= Current
& ~EX_HANDLE_ENTRY_LOCKED
;
765 InterlockedExchangePointer(&Entry
->u1
.Object
,
768 /* we unlocked the entry, pulse the contention event so threads who're waiting
769 on the release can continue */
770 KePulseEvent(&HandleTable
->HandleContentionEvent
,
776 ExCreateHandle(IN PHANDLE_TABLE HandleTable
,
777 IN PHANDLE_TABLE_ENTRY Entry
)
779 PHANDLE_TABLE_ENTRY NewHandleTableEntry
;
780 HANDLE Handle
= NULL
;
787 /* The highest bit in Entry->u1.Object has to be 1 so we make sure it's a
788 pointer to kmode memory. It will cleared though because it also indicates
790 ASSERT((ULONG_PTR
)Entry
->u1
.Object
& EX_HANDLE_ENTRY_LOCKED
);
792 KeEnterCriticalRegion();
793 ExAcquireHandleTableLockExclusive(HandleTable
);
795 NewHandleTableEntry
= ExpAllocateHandleTableEntry(HandleTable
,
797 if(NewHandleTableEntry
!= NULL
)
799 *NewHandleTableEntry
= *Entry
;
801 ExUnlockHandleTableEntry(HandleTable
,
802 NewHandleTableEntry
);
805 ExReleaseHandleTableLock(HandleTable
);
806 KeLeaveCriticalRegion();
812 ExDestroyHandle(IN PHANDLE_TABLE HandleTable
,
815 PHANDLE_TABLE_ENTRY HandleTableEntry
;
823 ExHandle
= HANDLE_TO_EX_HANDLE(Handle
);
825 KeEnterCriticalRegion();
826 ExAcquireHandleTableLockExclusive(HandleTable
);
828 HandleTableEntry
= ExpLookupHandleTableEntry(HandleTable
,
831 if(HandleTableEntry
!= NULL
&& ExLockHandleTableEntry(HandleTable
, HandleTableEntry
))
833 /* free and automatically unlock the handle. However we don't need to pulse
834 the contention event since other locks on this entry will fail */
835 ExpFreeHandleTableEntry(HandleTable
,
841 ExReleaseHandleTableLock(HandleTable
);
842 KeLeaveCriticalRegion();
848 ExDestroyHandleByEntry(IN PHANDLE_TABLE HandleTable
,
849 IN PHANDLE_TABLE_ENTRY Entry
,
857 /* This routine requires the entry to be locked */
858 ASSERT((ULONG_PTR
)Entry
->u1
.Object
& EX_HANDLE_ENTRY_LOCKED
);
860 DPRINT("DestroyHandleByEntry HT:0x%p Entry:0x%p\n", HandleTable
, Entry
);
862 KeEnterCriticalRegion();
863 ExAcquireHandleTableLockExclusive(HandleTable
);
865 /* free and automatically unlock the handle. However we don't need to pulse
866 the contention event since other locks on this entry will fail */
867 ExpFreeHandleTableEntry(HandleTable
,
869 HANDLE_TO_EX_HANDLE(Handle
));
871 ExReleaseHandleTableLock(HandleTable
);
872 KeLeaveCriticalRegion();
876 ExMapHandleToPointer(IN PHANDLE_TABLE HandleTable
,
879 PHANDLE_TABLE_ENTRY HandleTableEntry
;
885 HandleTableEntry
= ExpLookupHandleTableEntry(HandleTable
,
886 HANDLE_TO_EX_HANDLE(Handle
));
887 if (HandleTableEntry
!= NULL
&& ExLockHandleTableEntry(HandleTable
, HandleTableEntry
))
889 DPRINT("ExMapHandleToPointer HT:0x%p Entry:0x%p locked\n", HandleTable
, HandleTableEntry
);
890 return HandleTableEntry
;
897 ExChangeHandle(IN PHANDLE_TABLE HandleTable
,
899 IN PEX_CHANGE_HANDLE_CALLBACK ChangeHandleCallback
,
902 PHANDLE_TABLE_ENTRY HandleTableEntry
;
908 ASSERT(ChangeHandleCallback
);
910 KeEnterCriticalRegion();
912 HandleTableEntry
= ExpLookupHandleTableEntry(HandleTable
,
913 HANDLE_TO_EX_HANDLE(Handle
));
915 if(HandleTableEntry
!= NULL
&& ExLockHandleTableEntry(HandleTable
, HandleTableEntry
))
917 Ret
= ChangeHandleCallback(HandleTable
,
921 ExUnlockHandleTableEntry(HandleTable
,
925 KeLeaveCriticalRegion();