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 * ExSweepHandleTable (???)
15 * ExReferenceHandleDebugInfo
16 * ExSnapShotHandleTables
17 * ExpMoveFreeHandles (???)
20 /* INCLUDES *****************************************************************/
25 #include <internal/debug.h>
27 static LIST_ENTRY ExpHandleTableHead
;
28 static FAST_MUTEX ExpHandleTableListLock
;
29 static LARGE_INTEGER ExpHandleShortWait
;
31 #define ExAcquireHandleTableListLock() \
32 ExAcquireFastMutexUnsafe(&ExpHandleTableListLock)
34 #define ExReleaseHandleTableListLock() \
35 ExReleaseFastMutexUnsafe(&ExpHandleTableListLock)
37 #define ExAcquireHandleTableLockExclusive(HandleTable) \
38 ExAcquireResourceExclusiveLite(&(HandleTable)->HandleTableLock, TRUE)
40 #define ExAcquireHandleTableLockShared(HandleTable) \
41 ExAcquireResourceSharedLite(&(HandleTable)->HandleTableLock, TRUE)
43 #define ExReleaseHandleTableLock(HandleTable) \
44 ExReleaseResourceLite(&(HandleTable)->HandleTableLock)
48 8 bits: top level index
49 10 bits: middle level index
50 9 bits: sub handle index
52 #define N_TLI_BITS 8 /* top level index */
53 #define N_MLI_BITS 10 /* middle level index */
54 #define N_EI_BITS 9 /* sub handle index */
55 #define TLI_OFFSET (N_MLI_BITS + N_EI_BITS)
56 #define MLI_OFFSET N_EI_BITS
59 #define N_TOPLEVEL_POINTERS (1 << N_TLI_BITS)
60 #define N_MIDDLELEVEL_POINTERS (1 << N_MLI_BITS)
61 #define N_SUBHANDLE_ENTRIES (1 << N_EI_BITS)
62 #define EX_MAX_HANDLES (N_TOPLEVEL_POINTERS * N_MIDDLELEVEL_POINTERS * N_SUBHANDLE_ENTRIES)
64 #define VALID_HANDLE_MASK (((N_TOPLEVEL_POINTERS - 1) << TLI_OFFSET) | \
65 ((N_MIDDLELEVEL_POINTERS - 1) << MLI_OFFSET) | ((N_SUBHANDLE_ENTRIES - 1) << EI_OFFSET))
66 #define TLI_FROM_HANDLE(index) (ULONG)(((index) >> TLI_OFFSET) & (N_TOPLEVEL_POINTERS - 1))
67 #define MLI_FROM_HANDLE(index) (ULONG)(((index) >> MLI_OFFSET) & (N_MIDDLELEVEL_POINTERS - 1))
68 #define ELI_FROM_HANDLE(index) (ULONG)(((index) >> EI_OFFSET) & (N_SUBHANDLE_ENTRIES - 1))
70 #define N_MAX_HANDLE (N_TOPLEVEL_POINTERS * N_MIDDLELEVEL_POINTERS * N_SUBHANDLE_ENTRIES)
72 #define BUILD_HANDLE(tli, mli, eli) ((((tli) & (N_TOPLEVEL_POINTERS - 1)) << TLI_OFFSET) | \
73 (((mli) & (N_MIDDLELEVEL_POINTERS - 1)) << MLI_OFFSET) | (((eli) & (N_SUBHANDLE_ENTRIES - 1)) << EI_OFFSET))
75 #define IS_INVALID_EX_HANDLE(index) \
76 (((index) & ~VALID_HANDLE_MASK) != 0)
77 #define IS_VALID_EX_HANDLE(index) \
78 (((index) & ~VALID_HANDLE_MASK) == 0)
80 #define HANDLE_TO_EX_HANDLE(handle) \
81 (LONG)(((LONG)(handle) >> 2) - 1)
82 #define EX_HANDLE_TO_HANDLE(exhandle) \
83 (HANDLE)(((exhandle) + 1) << 2)
85 static BOOLEAN ExpInitialized
= FALSE
;
87 /******************************************************************************/
90 ExpInitializeHandleTables(VOID
)
92 ExpHandleShortWait
.QuadPart
= -50000;
93 InitializeListHead(&ExpHandleTableHead
);
94 ExInitializeFastMutex(&ExpHandleTableListLock
);
96 ExpInitialized
= TRUE
;
100 ExCreateHandleTable(IN PEPROCESS QuotaProcess OPTIONAL
)
102 PHANDLE_TABLE HandleTable
;
111 if(QuotaProcess
!= NULL
)
113 /* FIXME - Charge process quota before allocating the handle table! */
116 /* allocate enough memory for the handle table and the lowest level */
117 HandleTable
= ExAllocatePoolWithTag(NonPagedPool
,
118 sizeof(HANDLE_TABLE
) + (N_TOPLEVEL_POINTERS
* sizeof(PHANDLE_TABLE_ENTRY
*)),
119 TAG('E', 'x', 'H', 't'));
120 if(HandleTable
!= NULL
)
122 /* initialize the handle table */
123 HandleTable
->Flags
= 0;
124 HandleTable
->HandleCount
= 0;
125 HandleTable
->Table
= (PHANDLE_TABLE_ENTRY
**)(HandleTable
+ 1);
126 HandleTable
->QuotaProcess
= QuotaProcess
;
127 HandleTable
->FirstFreeTableEntry
= -1; /* no entries freed so far */
128 HandleTable
->NextIndexNeedingPool
= 0; /* no entries freed so far, so we have to allocate already for the first handle */
129 HandleTable
->UniqueProcessId
= (QuotaProcess
? QuotaProcess
->UniqueProcessId
: NULL
);
131 ExInitializeResource(&HandleTable
->HandleTableLock
);
133 KeInitializeEvent(&HandleTable
->HandleContentionEvent
,
137 RtlZeroMemory(HandleTable
->Table
, N_TOPLEVEL_POINTERS
* sizeof(PHANDLE_TABLE_ENTRY
*));
139 /* during bootup KeGetCurrentThread() might be NULL, needs to be fixed... */
140 if(KeGetCurrentThread() != NULL
)
142 /* insert it into the global handle table list */
143 KeEnterCriticalRegion();
145 ExAcquireHandleTableListLock();
146 InsertTailList(&ExpHandleTableHead
,
147 &HandleTable
->HandleTableList
);
148 ExReleaseHandleTableListLock();
150 KeLeaveCriticalRegion();
154 InsertTailList(&ExpHandleTableHead
,
155 &HandleTable
->HandleTableList
);
160 /* FIXME - return the quota to the process */
167 ExLockHandleTableEntryNoDestructionCheck(IN PHANDLE_TABLE HandleTable
,
168 IN PHANDLE_TABLE_ENTRY Entry
)
170 ULONG_PTR Current
, New
;
174 DPRINT("Entering handle table entry 0x%p lock...\n", Entry
);
181 Current
= (volatile ULONG_PTR
)Entry
->u1
.Object
;
185 DPRINT("Attempted to lock empty handle table entry 0x%p or handle table shut down\n", Entry
);
189 if(!(Current
& EX_HANDLE_ENTRY_LOCKED
))
191 New
= Current
| EX_HANDLE_ENTRY_LOCKED
;
192 if(InterlockedCompareExchangePointer(&Entry
->u1
.Object
,
194 (PVOID
)Current
) == (PVOID
)Current
)
196 DPRINT("SUCCESS handle table 0x%p entry 0x%p lock\n", HandleTable
, Entry
);
197 /* we acquired the lock */
202 /* wait about 5ms at maximum so we don't wait forever in unfortunate
203 co-incidences where releasing the lock in another thread happens right
204 before we're waiting on the contention event to get pulsed, which might
205 never happen again... */
206 KeWaitForSingleObject(&HandleTable
->HandleContentionEvent
,
210 &ExpHandleShortWait
);
217 ExDestroyHandleTable(IN PHANDLE_TABLE HandleTable
,
218 IN PEX_DESTROY_HANDLE_CALLBACK DestroyHandleCallback OPTIONAL
,
219 IN PVOID Context OPTIONAL
)
221 PHANDLE_TABLE_ENTRY
**tlp
, **lasttlp
, *mlp
, *lastmlp
;
222 PEPROCESS QuotaProcess
;
228 KeEnterCriticalRegion();
230 /* ensure there's no other operations going by acquiring an exclusive lock */
231 ExAcquireHandleTableLockExclusive(HandleTable
);
233 ASSERT(!(HandleTable
->Flags
& EX_HANDLE_TABLE_CLOSING
));
235 HandleTable
->Flags
|= EX_HANDLE_TABLE_CLOSING
;
237 KePulseEvent(&HandleTable
->HandleContentionEvent
,
241 /* remove the handle table from the global handle table list */
242 ExAcquireHandleTableListLock();
243 RemoveEntryList(&HandleTable
->HandleTableList
);
244 ExReleaseHandleTableListLock();
246 /* call the callback function to cleanup the objects associated with the
248 if(DestroyHandleCallback
!= NULL
)
250 for(tlp
= HandleTable
->Table
, lasttlp
= HandleTable
->Table
+ N_TOPLEVEL_POINTERS
;
256 for(mlp
= *tlp
, lastmlp
= (*tlp
) + N_MIDDLELEVEL_POINTERS
;
262 PHANDLE_TABLE_ENTRY curee
, laste
;
264 for(curee
= *mlp
, laste
= *mlp
+ N_SUBHANDLE_ENTRIES
;
268 if(curee
->u1
.Object
!= NULL
&& ExLockHandleTableEntryNoDestructionCheck(HandleTable
, curee
))
270 DestroyHandleCallback(HandleTable
, curee
->u1
.Object
, curee
->u2
.GrantedAccess
, Context
);
271 ExUnlockHandleTableEntry(HandleTable
, curee
);
280 QuotaProcess
= HandleTable
->QuotaProcess
;
282 /* free the tables */
283 for(tlp
= HandleTable
->Table
, lasttlp
= HandleTable
->Table
+ N_TOPLEVEL_POINTERS
;
289 for(mlp
= *tlp
, lastmlp
= (*tlp
) + N_MIDDLELEVEL_POINTERS
;
297 if(QuotaProcess
!= NULL
)
299 /* FIXME - return the quota to the process */
306 if(QuotaProcess
!= NULL
)
308 /* FIXME - return the quota to the process */
313 ExReleaseHandleTableLock(HandleTable
);
315 KeLeaveCriticalRegion();
317 /* free the handle table */
318 ExDeleteResource(&HandleTable
->HandleTableLock
);
319 ExFreePool(HandleTable
);
321 if(QuotaProcess
!= NULL
)
323 /* FIXME - return the quota to the process */
328 ExDupHandleTable(IN PEPROCESS QuotaProcess OPTIONAL
,
329 IN PEX_DUPLICATE_HANDLE_CALLBACK DuplicateHandleCallback OPTIONAL
,
330 IN PVOID Context OPTIONAL
,
331 IN PHANDLE_TABLE SourceHandleTable
)
333 PHANDLE_TABLE HandleTable
;
337 ASSERT(SourceHandleTable
);
339 HandleTable
= ExCreateHandleTable(QuotaProcess
);
340 if(HandleTable
!= NULL
)
342 PHANDLE_TABLE_ENTRY
**tlp
, **srctlp
, **etlp
, *mlp
, *srcmlp
, *emlp
, stbl
, srcstbl
, estbl
;
347 /* make sure the other handle table isn't being changed during the duplication */
348 ExAcquireHandleTableLockShared(SourceHandleTable
);
350 /* allocate enough tables */
351 etlp
= SourceHandleTable
->Table
+ N_TOPLEVEL_POINTERS
;
352 for(srctlp
= SourceHandleTable
->Table
, tlp
= HandleTable
->Table
;
358 /* allocate middle level entry tables */
359 if(QuotaProcess
!= NULL
)
361 /* FIXME - Charge process quota before allocating the handle table! */
364 *tlp
= ExAllocatePoolWithTag(PagedPool
,
365 N_MIDDLELEVEL_POINTERS
* sizeof(PHANDLE_TABLE_ENTRY
),
366 TAG('E', 'x', 'H', 't'));
369 RtlZeroMemory(*tlp
, N_MIDDLELEVEL_POINTERS
* sizeof(PHANDLE_TABLE_ENTRY
));
373 emlp
= *srctlp
+ N_MIDDLELEVEL_POINTERS
;
374 for(srcmlp
= *srctlp
, mlp
= *tlp
;
380 /* allocate subhandle tables */
381 if(QuotaProcess
!= NULL
)
383 /* FIXME - Charge process quota before allocating the handle table! */
386 *mlp
= ExAllocatePoolWithTag(PagedPool
,
387 N_SUBHANDLE_ENTRIES
* sizeof(HANDLE_TABLE_ENTRY
),
388 TAG('E', 'x', 'H', 't'));
391 RtlZeroMemory(*mlp
, N_SUBHANDLE_ENTRIES
* sizeof(HANDLE_TABLE_ENTRY
));
395 goto freehandletable
;
407 DPRINT1("Failed to duplicate handle table 0x%p\n", SourceHandleTable
);
409 ExReleaseHandleTableLock(SourceHandleTable
);
411 ExDestroyHandleTable(HandleTable
,
414 /* allocate an empty handle table */
415 return ExCreateHandleTable(QuotaProcess
);
420 /* duplicate the handles */
421 HandleTable
->HandleCount
= SourceHandleTable
->HandleCount
;
422 HandleTable
->FirstFreeTableEntry
= SourceHandleTable
->FirstFreeTableEntry
;
423 HandleTable
->NextIndexNeedingPool
= SourceHandleTable
->NextIndexNeedingPool
;
425 /* make sure all tables are zeroed */
428 etlp
= SourceHandleTable
->Table
+ N_TOPLEVEL_POINTERS
;
429 for(srctlp
= SourceHandleTable
->Table
, tlp
= HandleTable
->Table
;
431 srctlp
++, tlp
++, tli
++)
435 ASSERT(*tlp
!= NULL
);
437 emlp
= *srctlp
+ N_MIDDLELEVEL_POINTERS
;
438 for(srcmlp
= *srctlp
, mlp
= *tlp
;
440 srcmlp
++, mlp
++, mli
++)
444 ASSERT(*mlp
!= NULL
);
446 /* walk all handle entries and duplicate them if wanted */
447 estbl
= *srcmlp
+ N_SUBHANDLE_ENTRIES
;
448 for(srcstbl
= *srcmlp
, stbl
= *mlp
;
450 srcstbl
++, stbl
++, eli
++)
452 /* try to duplicate the source handle */
453 if(srcstbl
->u1
.Object
!= NULL
&&
454 ExLockHandleTableEntry(SourceHandleTable
,
457 /* ask the caller if this handle should be duplicated */
458 if(DuplicateHandleCallback
!= NULL
&&
459 !DuplicateHandleCallback(HandleTable
,
463 /* free the entry and chain it into the free list */
464 HandleTable
->HandleCount
--;
465 stbl
->u1
.Object
= NULL
;
466 stbl
->u2
.NextFreeTableEntry
= HandleTable
->FirstFreeTableEntry
;
467 HandleTable
->FirstFreeTableEntry
= BUILD_HANDLE(tli
, mli
, eli
);
471 /* duplicate the handle and unlock it */
472 stbl
->u2
.GrantedAccess
= srcstbl
->u2
.GrantedAccess
;
473 stbl
->u1
.ObAttributes
= srcstbl
->u1
.ObAttributes
& ~EX_HANDLE_ENTRY_LOCKED
;
475 ExUnlockHandleTableEntry(SourceHandleTable
,
480 /* this is a free handle table entry, copy over the entire
490 /* release the source handle table */
491 ExReleaseHandleTableLock(SourceHandleTable
);
497 static PHANDLE_TABLE_ENTRY
498 ExpAllocateHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
501 PHANDLE_TABLE_ENTRY Entry
= NULL
;
507 ASSERT(KeGetCurrentThread() != NULL
);
509 DPRINT("HT[0x%p]: HandleCount: %d\n", HandleTable
, HandleTable
->HandleCount
);
511 if(HandleTable
->HandleCount
< EX_MAX_HANDLES
)
515 if(HandleTable
->FirstFreeTableEntry
!= -1)
517 /* there's a free handle entry we can just grab and use */
518 tli
= TLI_FROM_HANDLE(HandleTable
->FirstFreeTableEntry
);
519 mli
= MLI_FROM_HANDLE(HandleTable
->FirstFreeTableEntry
);
520 eli
= ELI_FROM_HANDLE(HandleTable
->FirstFreeTableEntry
);
522 /* the pointer should be valid in any way!!! */
523 ASSERT(HandleTable
->Table
[tli
]);
524 ASSERT(HandleTable
->Table
[tli
][mli
]);
526 Entry
= &HandleTable
->Table
[tli
][mli
][eli
];
528 *Handle
= EX_HANDLE_TO_HANDLE(HandleTable
->FirstFreeTableEntry
);
530 /* save the index to the next free handle (if available) */
531 HandleTable
->FirstFreeTableEntry
= Entry
->u2
.NextFreeTableEntry
;
532 Entry
->u2
.NextFreeTableEntry
= 0;
533 Entry
->u1
.Object
= NULL
;
535 HandleTable
->HandleCount
++;
539 /* we need to allocate a new subhandle table first */
540 PHANDLE_TABLE_ENTRY cure
, laste
, ntbl
, *nmtbl
;
542 BOOLEAN AllocatedMtbl
;
544 ASSERT(HandleTable
->NextIndexNeedingPool
<= N_MAX_HANDLE
);
546 /* the index of the next table to be allocated was saved in
547 NextIndexNeedingPool the last time a handle entry was allocated and
548 the subhandle entry list was full. the subhandle entry index of
549 NextIndexNeedingPool should be 0 here! */
550 tli
= TLI_FROM_HANDLE(HandleTable
->NextIndexNeedingPool
);
551 mli
= MLI_FROM_HANDLE(HandleTable
->NextIndexNeedingPool
);
552 DPRINT("HandleTable->NextIndexNeedingPool: 0x%x\n", HandleTable
->NextIndexNeedingPool
);
553 DPRINT("tli: 0x%x mli: 0x%x eli: 0x%x\n", tli
, mli
, ELI_FROM_HANDLE(HandleTable
->NextIndexNeedingPool
));
555 ASSERT(ELI_FROM_HANDLE(HandleTable
->NextIndexNeedingPool
) == 0);
557 DPRINT("HandleTable->Table[%d] == 0x%p\n", tli
, HandleTable
->Table
[tli
]);
559 /* allocate a middle level entry list if required */
560 nmtbl
= HandleTable
->Table
[tli
];
563 if(HandleTable
->QuotaProcess
!= NULL
)
565 /* FIXME - Charge process quota before allocating the handle table! */
568 nmtbl
= ExAllocatePoolWithTag(PagedPool
,
569 N_MIDDLELEVEL_POINTERS
* sizeof(PHANDLE_TABLE_ENTRY
),
570 TAG('E', 'x', 'H', 't'));
573 if(HandleTable
->QuotaProcess
!= NULL
)
575 /* FIXME - return the quota to the process */
581 /* clear the middle level entry list */
582 RtlZeroMemory(nmtbl
, N_MIDDLELEVEL_POINTERS
* sizeof(PHANDLE_TABLE_ENTRY
));
584 /* make sure the table was zeroed before we set one item */
587 /* note, don't set the the pointer in the top level list yet because we
588 might screw up lookups if allocating a subhandle entry table failed
589 and this newly allocated table might get freed again */
590 AllocatedMtbl
= TRUE
;
594 AllocatedMtbl
= FALSE
;
596 /* allocate a subhandle entry table in any case! */
597 ASSERT(nmtbl
[mli
] == NULL
);
600 DPRINT("HandleTable->Table[%d][%d] == 0x%p\n", tli
, mli
, nmtbl
[mli
]);
602 if(HandleTable
->QuotaProcess
!= NULL
)
604 /* FIXME - Charge process quota before allocating the handle table! */
607 ntbl
= ExAllocatePoolWithTag(PagedPool
,
608 N_SUBHANDLE_ENTRIES
* sizeof(HANDLE_TABLE_ENTRY
),
609 TAG('E', 'x', 'H', 't'));
612 if(HandleTable
->QuotaProcess
!= NULL
)
614 /* FIXME - Return process quota charged */
617 /* free the middle level entry list, if allocated, because it's empty and
623 if(HandleTable
->QuotaProcess
!= NULL
)
625 /* FIXME - Return process quota charged */
632 /* let's just use the very first entry */
634 Entry
->u1
.ObAttributes
= EX_HANDLE_ENTRY_LOCKED
;
635 Entry
->u2
.NextFreeTableEntry
= 0;
637 *Handle
= EX_HANDLE_TO_HANDLE(HandleTable
->NextIndexNeedingPool
);
639 HandleTable
->HandleCount
++;
641 /* set the FirstFreeTableEntry member to the second entry and chain the
643 HandleTable
->FirstFreeTableEntry
= HandleTable
->NextIndexNeedingPool
+ 1;
644 for(cure
= Entry
+ 1, laste
= Entry
+ N_SUBHANDLE_ENTRIES
, i
= HandleTable
->FirstFreeTableEntry
+ 1;
648 cure
->u1
.Object
= NULL
;
649 cure
->u2
.NextFreeTableEntry
= i
;
651 /* truncate the free entry list */
652 (cure
- 1)->u2
.NextFreeTableEntry
= -1;
654 /* save the pointers to the allocated list(s) */
655 InterlockedExchangePointer(&nmtbl
[mli
], ntbl
);
658 InterlockedExchangePointer(&HandleTable
->Table
[tli
], nmtbl
);
661 /* increment the NextIndexNeedingPool to the next index where we need to
662 allocate new memory */
663 HandleTable
->NextIndexNeedingPool
+= N_SUBHANDLE_ENTRIES
;
668 DPRINT1("Can't allocate any more handles in handle table 0x%p!\n", HandleTable
);
675 ExpFreeHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
676 IN PHANDLE_TABLE_ENTRY Entry
,
683 ASSERT(IS_VALID_EX_HANDLE(Handle
));
685 DPRINT("ExpFreeHandleTableEntry HT:0x%p Entry:0x%p\n", HandleTable
, Entry
);
687 /* automatically unlock the entry if currently locked. We however don't notify
688 anyone who waited on the handle because we're holding an exclusive lock after
689 all and these locks will fail then */
690 InterlockedExchangePointer(&Entry
->u1
.Object
, NULL
);
691 Entry
->u2
.NextFreeTableEntry
= HandleTable
->FirstFreeTableEntry
;
692 HandleTable
->FirstFreeTableEntry
= Handle
;
694 HandleTable
->HandleCount
--;
697 static PHANDLE_TABLE_ENTRY
698 ExpLookupHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
701 PHANDLE_TABLE_ENTRY Entry
= NULL
;
707 if(IS_VALID_EX_HANDLE(Handle
))
710 PHANDLE_TABLE_ENTRY
*mlp
;
712 tli
= TLI_FROM_HANDLE(Handle
);
713 mli
= MLI_FROM_HANDLE(Handle
);
714 eli
= ELI_FROM_HANDLE(Handle
);
716 mlp
= HandleTable
->Table
[tli
];
717 if(Handle
< HandleTable
->NextIndexNeedingPool
&&
718 mlp
!= NULL
&& mlp
[mli
] != NULL
&& mlp
[mli
][eli
].u1
.Object
!= NULL
)
720 Entry
= &mlp
[mli
][eli
];
721 DPRINT("handle lookup 0x%x -> entry 0x%p [HT:0x%p] ptr: 0x%p\n", Handle
, Entry
, HandleTable
, mlp
[mli
][eli
].u1
.Object
);
726 DPRINT("Looking up invalid handle 0x%x\n", Handle
);
733 ExLockHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
734 IN PHANDLE_TABLE_ENTRY Entry
)
736 ULONG_PTR Current
, New
;
740 DPRINT("Entering handle table entry 0x%p lock...\n", Entry
);
747 Current
= (volatile ULONG_PTR
)Entry
->u1
.Object
;
749 if(!Current
|| (HandleTable
->Flags
& EX_HANDLE_TABLE_CLOSING
))
751 DPRINT("Attempted to lock empty handle table entry 0x%p or handle table shut down\n", Entry
);
755 if(!(Current
& EX_HANDLE_ENTRY_LOCKED
))
757 New
= Current
| EX_HANDLE_ENTRY_LOCKED
;
758 if(InterlockedCompareExchangePointer(&Entry
->u1
.Object
,
760 (PVOID
)Current
) == (PVOID
)Current
)
762 DPRINT("SUCCESS handle table 0x%p entry 0x%p lock\n", HandleTable
, Entry
);
763 /* we acquired the lock */
768 /* wait about 5ms at maximum so we don't wait forever in unfortunate
769 co-incidences where releasing the lock in another thread happens right
770 before we're waiting on the contention event to get pulsed, which might
771 never happen again... */
772 KeWaitForSingleObject(&HandleTable
->HandleContentionEvent
,
776 &ExpHandleShortWait
);
783 ExUnlockHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
784 IN PHANDLE_TABLE_ENTRY Entry
)
786 ULONG_PTR Current
, New
;
793 DPRINT("ExUnlockHandleTableEntry HT:0x%p Entry:0x%p\n", HandleTable
, Entry
);
795 Current
= (volatile ULONG_PTR
)Entry
->u1
.Object
;
797 ASSERT(Current
& EX_HANDLE_ENTRY_LOCKED
);
799 New
= Current
& ~EX_HANDLE_ENTRY_LOCKED
;
801 InterlockedExchangePointer(&Entry
->u1
.Object
,
804 /* we unlocked the entry, pulse the contention event so threads who're waiting
805 on the release can continue */
806 KePulseEvent(&HandleTable
->HandleContentionEvent
,
812 ExCreateHandle(IN PHANDLE_TABLE HandleTable
,
813 IN PHANDLE_TABLE_ENTRY Entry
)
815 PHANDLE_TABLE_ENTRY NewHandleTableEntry
;
816 HANDLE Handle
= NULL
;
823 /* The highest bit in Entry->u1.Object has to be 1 so we make sure it's a
824 pointer to kmode memory. It will cleared though because it also indicates
826 ASSERT((ULONG_PTR
)Entry
->u1
.Object
& EX_HANDLE_ENTRY_LOCKED
);
828 KeEnterCriticalRegion();
829 ExAcquireHandleTableLockExclusive(HandleTable
);
831 NewHandleTableEntry
= ExpAllocateHandleTableEntry(HandleTable
,
833 if(NewHandleTableEntry
!= NULL
)
835 *NewHandleTableEntry
= *Entry
;
837 ExUnlockHandleTableEntry(HandleTable
,
838 NewHandleTableEntry
);
841 ExReleaseHandleTableLock(HandleTable
);
842 KeLeaveCriticalRegion();
848 ExDestroyHandle(IN PHANDLE_TABLE HandleTable
,
851 PHANDLE_TABLE_ENTRY HandleTableEntry
;
859 ExHandle
= HANDLE_TO_EX_HANDLE(Handle
);
861 KeEnterCriticalRegion();
862 ExAcquireHandleTableLockExclusive(HandleTable
);
864 HandleTableEntry
= ExpLookupHandleTableEntry(HandleTable
,
867 if(HandleTableEntry
!= NULL
&& ExLockHandleTableEntry(HandleTable
, HandleTableEntry
))
869 /* free and automatically unlock the handle. However we don't need to pulse
870 the contention event since other locks on this entry will fail */
871 ExpFreeHandleTableEntry(HandleTable
,
877 ExReleaseHandleTableLock(HandleTable
);
878 KeLeaveCriticalRegion();
884 ExDestroyHandleByEntry(IN PHANDLE_TABLE HandleTable
,
885 IN PHANDLE_TABLE_ENTRY Entry
,
893 /* This routine requires the entry to be locked */
894 ASSERT((ULONG_PTR
)Entry
->u1
.Object
& EX_HANDLE_ENTRY_LOCKED
);
896 DPRINT("DestroyHandleByEntry HT:0x%p Entry:0x%p\n", HandleTable
, Entry
);
898 KeEnterCriticalRegion();
899 ExAcquireHandleTableLockExclusive(HandleTable
);
901 /* free and automatically unlock the handle. However we don't need to pulse
902 the contention event since other locks on this entry will fail */
903 ExpFreeHandleTableEntry(HandleTable
,
905 HANDLE_TO_EX_HANDLE(Handle
));
907 ExReleaseHandleTableLock(HandleTable
);
908 KeLeaveCriticalRegion();
912 ExMapHandleToPointer(IN PHANDLE_TABLE HandleTable
,
915 PHANDLE_TABLE_ENTRY HandleTableEntry
;
921 HandleTableEntry
= ExpLookupHandleTableEntry(HandleTable
,
922 HANDLE_TO_EX_HANDLE(Handle
));
923 if (HandleTableEntry
!= NULL
&& ExLockHandleTableEntry(HandleTable
, HandleTableEntry
))
925 DPRINT("ExMapHandleToPointer HT:0x%p Entry:0x%p locked\n", HandleTable
, HandleTableEntry
);
926 return HandleTableEntry
;
933 ExChangeHandle(IN PHANDLE_TABLE HandleTable
,
935 IN PEX_CHANGE_HANDLE_CALLBACK ChangeHandleCallback
,
938 PHANDLE_TABLE_ENTRY HandleTableEntry
;
944 ASSERT(ChangeHandleCallback
);
946 KeEnterCriticalRegion();
948 HandleTableEntry
= ExpLookupHandleTableEntry(HandleTable
,
949 HANDLE_TO_EX_HANDLE(Handle
));
951 if(HandleTableEntry
!= NULL
&& ExLockHandleTableEntry(HandleTable
, HandleTableEntry
))
953 Ret
= ChangeHandleCallback(HandleTable
,
957 ExUnlockHandleTableEntry(HandleTable
,
961 KeLeaveCriticalRegion();