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 /******************************************************************************/
83 ExpInitializeHandleTables(VOID
)
85 ExpHandleShortWait
.QuadPart
= -50000;
86 InitializeListHead(&ExpHandleTableHead
);
87 ExInitializeFastMutex(&ExpHandleTableListLock
);
91 ExCreateHandleTable(IN PEPROCESS QuotaProcess OPTIONAL
)
93 PHANDLE_TABLE HandleTable
;
97 if(QuotaProcess
!= NULL
)
99 /* FIXME - Charge process quota before allocating the handle table! */
102 /* allocate enough memory for the handle table and the lowest level */
103 HandleTable
= ExAllocatePoolWithTag(NonPagedPool
,
104 sizeof(HANDLE_TABLE
) + (N_TOPLEVEL_POINTERS
* sizeof(PHANDLE_TABLE_ENTRY
*)),
105 TAG('E', 'x', 'H', 't'));
106 if(HandleTable
!= NULL
)
108 /* initialize the handle table */
109 HandleTable
->Flags
= 0;
110 HandleTable
->HandleCount
= 0;
111 HandleTable
->Table
= (PHANDLE_TABLE_ENTRY
**)(HandleTable
+ 1);
112 HandleTable
->QuotaProcess
= QuotaProcess
;
113 HandleTable
->FirstFreeTableEntry
= -1; /* no entries freed so far */
114 HandleTable
->NextIndexNeedingPool
= 0; /* no entries freed so far, so we have to allocate already for the first handle */
115 HandleTable
->UniqueProcessId
= (QuotaProcess
? QuotaProcess
->UniqueProcessId
: NULL
);
117 ExInitializeResource(&HandleTable
->HandleTableLock
);
119 KeInitializeEvent(&HandleTable
->HandleContentionEvent
,
123 RtlZeroMemory(HandleTable
->Table
, N_TOPLEVEL_POINTERS
* sizeof(PHANDLE_TABLE_ENTRY
*));
125 /* during bootup KeGetCurrentThread() might be NULL, needs to be fixed... */
126 if(KeGetCurrentThread() != NULL
)
128 /* insert it into the global handle table list */
129 KeEnterCriticalRegion();
131 ExAcquireHandleTableListLock();
132 InsertTailList(&ExpHandleTableHead
,
133 &HandleTable
->HandleTableList
);
134 ExReleaseHandleTableListLock();
136 KeLeaveCriticalRegion();
140 InsertTailList(&ExpHandleTableHead
,
141 &HandleTable
->HandleTableList
);
146 /* FIXME - return the quota to the process */
153 ExLockHandleTableEntryNoDestructionCheck(IN PHANDLE_TABLE HandleTable
,
154 IN PHANDLE_TABLE_ENTRY Entry
)
156 ULONG_PTR Current
, New
;
160 DPRINT("Entering handle table entry 0x%x lock...\n", Entry
);
167 Current
= (volatile ULONG_PTR
)Entry
->u1
.Object
;
171 DPRINT("Attempted to lock empty handle table entry 0x%x or handle table shut down\n", Entry
);
175 if(!(Current
& EX_HANDLE_ENTRY_LOCKED
))
177 New
= Current
| EX_HANDLE_ENTRY_LOCKED
;
178 if(InterlockedCompareExchangePointer(&Entry
->u1
.Object
,
180 (PVOID
)Current
) == (PVOID
)Current
)
182 DPRINT("SUCCESS handle table 0x%x entry 0x%x lock\n", HandleTable
, Entry
);
183 /* we acquired the lock */
188 /* wait about 5ms at maximum so we don't wait forever in unfortunate
189 co-incidences where releasing the lock in another thread happens right
190 before we're waiting on the contention event to get pulsed, which might
191 never happen again... */
192 KeWaitForSingleObject(&HandleTable
->HandleContentionEvent
,
196 &ExpHandleShortWait
);
203 ExDestroyHandleTable(IN PHANDLE_TABLE HandleTable
,
204 IN PEX_DESTROY_HANDLE_CALLBACK DestroyHandleCallback OPTIONAL
,
205 IN PVOID Context OPTIONAL
)
207 PHANDLE_TABLE_ENTRY
**tlp
, **lasttlp
, *mlp
, *lastmlp
;
208 PEPROCESS QuotaProcess
;
214 KeEnterCriticalRegion();
216 /* ensure there's no other operations going by acquiring an exclusive lock */
217 ExAcquireHandleTableLockExclusive(HandleTable
);
219 ASSERT(!(HandleTable
->Flags
& EX_HANDLE_TABLE_CLOSING
));
221 HandleTable
->Flags
|= EX_HANDLE_TABLE_CLOSING
;
223 KePulseEvent(&HandleTable
->HandleContentionEvent
,
227 /* remove the handle table from the global handle table list */
228 ExAcquireHandleTableListLock();
229 RemoveEntryList(&HandleTable
->HandleTableList
);
230 ExReleaseHandleTableListLock();
232 /* call the callback function to cleanup the objects associated with the
234 if(DestroyHandleCallback
!= NULL
)
236 for(tlp
= HandleTable
->Table
, lasttlp
= HandleTable
->Table
+ N_TOPLEVEL_POINTERS
;
242 for(mlp
= *tlp
, lastmlp
= (*tlp
) + N_MIDDLELEVEL_POINTERS
;
248 PHANDLE_TABLE_ENTRY curee
, laste
;
250 for(curee
= *mlp
, laste
= *mlp
+ N_SUBHANDLE_ENTRIES
;
254 if(curee
->u1
.Object
!= NULL
&& ExLockHandleTableEntryNoDestructionCheck(HandleTable
, curee
))
256 DestroyHandleCallback(HandleTable
, curee
->u1
.Object
, curee
->u2
.GrantedAccess
, Context
);
257 ExUnlockHandleTableEntry(HandleTable
, curee
);
266 QuotaProcess
= HandleTable
->QuotaProcess
;
268 /* free the tables */
269 for(tlp
= HandleTable
->Table
, lasttlp
= HandleTable
->Table
+ N_TOPLEVEL_POINTERS
;
275 for(mlp
= *tlp
, lastmlp
= (*tlp
) + N_MIDDLELEVEL_POINTERS
;
283 if(QuotaProcess
!= NULL
)
285 /* FIXME - return the quota to the process */
292 if(QuotaProcess
!= NULL
)
294 /* FIXME - return the quota to the process */
299 ExReleaseHandleTableLock(HandleTable
);
301 KeLeaveCriticalRegion();
303 /* free the handle table */
304 ExDeleteResource(&HandleTable
->HandleTableLock
);
305 ExFreePool(HandleTable
);
307 if(QuotaProcess
!= NULL
)
309 /* FIXME - return the quota to the process */
314 ExDupHandleTable(IN PEPROCESS QuotaProcess OPTIONAL
,
315 IN PEX_DUPLICATE_HANDLE_CALLBACK DuplicateHandleCallback OPTIONAL
,
316 IN PVOID Context OPTIONAL
,
317 IN PHANDLE_TABLE SourceHandleTable
)
319 PHANDLE_TABLE HandleTable
;
323 ASSERT(SourceHandleTable
);
325 HandleTable
= ExCreateHandleTable(QuotaProcess
);
326 if(HandleTable
!= NULL
)
328 PHANDLE_TABLE_ENTRY
**tlp
, **srctlp
, **etlp
, *mlp
, *srcmlp
, *emlp
, stbl
, srcstbl
, estbl
;
333 /* make sure the other handle table isn't being changed during the duplication */
334 ExAcquireHandleTableLockShared(SourceHandleTable
);
336 /* allocate enough tables */
337 etlp
= SourceHandleTable
->Table
+ N_TOPLEVEL_POINTERS
;
338 for(srctlp
= SourceHandleTable
->Table
, tlp
= HandleTable
->Table
;
344 /* allocate middle level entry tables */
345 if(QuotaProcess
!= NULL
)
347 /* FIXME - Charge process quota before allocating the handle table! */
350 *tlp
= ExAllocatePoolWithTag(PagedPool
,
351 N_MIDDLELEVEL_POINTERS
* sizeof(PHANDLE_TABLE_ENTRY
),
352 TAG('E', 'x', 'H', 't'));
355 RtlZeroMemory(*tlp
, N_MIDDLELEVEL_POINTERS
* sizeof(PHANDLE_TABLE_ENTRY
));
359 emlp
= *srctlp
+ N_MIDDLELEVEL_POINTERS
;
360 for(srcmlp
= *srctlp
, mlp
= *tlp
;
366 /* allocate subhandle tables */
367 if(QuotaProcess
!= NULL
)
369 /* FIXME - Charge process quota before allocating the handle table! */
372 *mlp
= ExAllocatePoolWithTag(PagedPool
,
373 N_SUBHANDLE_ENTRIES
* sizeof(HANDLE_TABLE_ENTRY
),
374 TAG('E', 'x', 'H', 't'));
377 RtlZeroMemory(*mlp
, N_SUBHANDLE_ENTRIES
* sizeof(HANDLE_TABLE_ENTRY
));
381 goto freehandletable
;
393 DPRINT1("Failed to duplicate handle table 0x%x\n", SourceHandleTable
);
395 ExReleaseHandleTableLock(SourceHandleTable
);
397 ExDestroyHandleTable(HandleTable
,
400 /* allocate an empty handle table */
401 return ExCreateHandleTable(QuotaProcess
);
406 /* duplicate the handles */
407 HandleTable
->HandleCount
= SourceHandleTable
->HandleCount
;
408 HandleTable
->FirstFreeTableEntry
= SourceHandleTable
->FirstFreeTableEntry
;
409 HandleTable
->NextIndexNeedingPool
= SourceHandleTable
->NextIndexNeedingPool
;
411 /* make sure all tables are zeroed */
414 etlp
= SourceHandleTable
->Table
+ N_TOPLEVEL_POINTERS
;
415 for(srctlp
= SourceHandleTable
->Table
, tlp
= HandleTable
->Table
;
417 srctlp
++, tlp
++, tli
++)
421 ASSERT(*tlp
!= NULL
);
423 emlp
= *srctlp
+ N_MIDDLELEVEL_POINTERS
;
424 for(srcmlp
= *srctlp
, mlp
= *tlp
;
426 srcmlp
++, mlp
++, mli
++)
430 ASSERT(*mlp
!= NULL
);
432 /* walk all handle entries and duplicate them if wanted */
433 estbl
= *srcmlp
+ N_SUBHANDLE_ENTRIES
;
434 for(srcstbl
= *srcmlp
, stbl
= *mlp
;
436 srcstbl
++, stbl
++, eli
++)
438 /* try to duplicate the source handle */
439 if(srcstbl
->u1
.Object
!= NULL
&&
440 ExLockHandleTableEntry(SourceHandleTable
,
443 /* ask the caller if this handle should be duplicated */
444 if(DuplicateHandleCallback
!= NULL
&&
445 !DuplicateHandleCallback(HandleTable
,
449 /* free the entry and chain it into the free list */
450 HandleTable
->HandleCount
--;
451 stbl
->u1
.Object
= NULL
;
452 stbl
->u2
.NextFreeTableEntry
= HandleTable
->FirstFreeTableEntry
;
453 HandleTable
->FirstFreeTableEntry
= BUILD_HANDLE(tli
, mli
, eli
);
457 /* duplicate the handle and unlock it */
458 stbl
->u2
.GrantedAccess
= srcstbl
->u2
.GrantedAccess
;
459 stbl
->u1
.ObAttributes
= srcstbl
->u1
.ObAttributes
& ~EX_HANDLE_ENTRY_LOCKED
;
461 ExUnlockHandleTableEntry(SourceHandleTable
,
466 /* this is a free handle table entry, copy over the entire
476 /* release the source handle table */
477 ExReleaseHandleTableLock(SourceHandleTable
);
483 static PHANDLE_TABLE_ENTRY
484 ExpAllocateHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
487 PHANDLE_TABLE_ENTRY Entry
= NULL
;
493 ASSERT(KeGetCurrentThread() != NULL
);
495 DPRINT("HT[0x%x]: HandleCount: %d\n", HandleTable
, HandleTable
->HandleCount
);
497 if(HandleTable
->HandleCount
< EX_MAX_HANDLES
)
501 if(HandleTable
->FirstFreeTableEntry
!= -1)
503 /* there's a free handle entry we can just grab and use */
504 tli
= TLI_FROM_HANDLE(HandleTable
->FirstFreeTableEntry
);
505 mli
= MLI_FROM_HANDLE(HandleTable
->FirstFreeTableEntry
);
506 eli
= ELI_FROM_HANDLE(HandleTable
->FirstFreeTableEntry
);
508 /* the pointer should be valid in any way!!! */
509 ASSERT(HandleTable
->Table
[tli
]);
510 ASSERT(HandleTable
->Table
[tli
][mli
]);
512 Entry
= &HandleTable
->Table
[tli
][mli
][eli
];
514 *Handle
= HandleTable
->FirstFreeTableEntry
;
516 /* save the index to the next free handle (if available) */
517 HandleTable
->FirstFreeTableEntry
= Entry
->u2
.NextFreeTableEntry
;
518 Entry
->u2
.NextFreeTableEntry
= 0;
519 Entry
->u1
.Object
= NULL
;
521 HandleTable
->HandleCount
++;
525 /* we need to allocate a new subhandle table first */
526 PHANDLE_TABLE_ENTRY cure
, laste
, ntbl
, *nmtbl
;
528 BOOLEAN AllocatedMtbl
;
530 ASSERT(HandleTable
->NextIndexNeedingPool
<= N_MAX_HANDLE
);
532 /* the index of the next table to be allocated was saved in
533 NextIndexNeedingPool the last time a handle entry was allocated and
534 the subhandle entry list was full. the subhandle entry index of
535 NextIndexNeedingPool should be 0 here! */
536 tli
= TLI_FROM_HANDLE(HandleTable
->NextIndexNeedingPool
);
537 mli
= MLI_FROM_HANDLE(HandleTable
->NextIndexNeedingPool
);
538 DPRINT("HandleTable->NextIndexNeedingPool: 0x%x\n", HandleTable
->NextIndexNeedingPool
);
539 DPRINT("tli: 0x%x mli: 0x%x eli: 0x%x\n", tli
, mli
, ELI_FROM_HANDLE(HandleTable
->NextIndexNeedingPool
));
541 ASSERT(ELI_FROM_HANDLE(HandleTable
->NextIndexNeedingPool
) == 0);
543 DPRINT("HandleTable->Table[%d] == 0x%x\n", tli
, HandleTable
->Table
[tli
]);
545 /* allocate a middle level entry list if required */
546 nmtbl
= HandleTable
->Table
[tli
];
549 if(HandleTable
->QuotaProcess
!= NULL
)
551 /* FIXME - Charge process quota before allocating the handle table! */
554 nmtbl
= ExAllocatePoolWithTag(PagedPool
,
555 N_MIDDLELEVEL_POINTERS
* sizeof(PHANDLE_TABLE_ENTRY
),
556 TAG('E', 'x', 'H', 't'));
559 if(HandleTable
->QuotaProcess
!= NULL
)
561 /* FIXME - return the quota to the process */
567 /* clear the middle level entry list */
568 RtlZeroMemory(nmtbl
, N_MIDDLELEVEL_POINTERS
* sizeof(PHANDLE_TABLE_ENTRY
));
570 /* make sure the table was zeroed before we set one item */
573 /* note, don't set the the pointer in the top level list yet because we
574 might screw up lookups if allocating a subhandle entry table failed
575 and this newly allocated table might get freed again */
576 AllocatedMtbl
= TRUE
;
580 AllocatedMtbl
= FALSE
;
582 /* allocate a subhandle entry table in any case! */
583 ASSERT(nmtbl
[mli
] == NULL
);
586 DPRINT("HandleTable->Table[%d][%d] == 0x%x\n", tli
, mli
, nmtbl
[mli
]);
588 if(HandleTable
->QuotaProcess
!= NULL
)
590 /* FIXME - Charge process quota before allocating the handle table! */
593 ntbl
= ExAllocatePoolWithTag(PagedPool
,
594 N_SUBHANDLE_ENTRIES
* sizeof(HANDLE_TABLE_ENTRY
),
595 TAG('E', 'x', 'H', 't'));
598 if(HandleTable
->QuotaProcess
!= NULL
)
600 /* FIXME - Return process quota charged */
603 /* free the middle level entry list, if allocated, because it's empty and
609 if(HandleTable
->QuotaProcess
!= NULL
)
611 /* FIXME - Return process quota charged */
618 /* let's just use the very first entry */
620 Entry
->u1
.ObAttributes
= EX_HANDLE_ENTRY_LOCKED
;
621 Entry
->u2
.NextFreeTableEntry
= 0;
623 *Handle
= HandleTable
->NextIndexNeedingPool
;
625 HandleTable
->HandleCount
++;
627 /* set the FirstFreeTableEntry member to the second entry and chain the
629 HandleTable
->FirstFreeTableEntry
= HandleTable
->NextIndexNeedingPool
+ 1;
630 for(cure
= Entry
+ 1, laste
= Entry
+ N_SUBHANDLE_ENTRIES
, i
= HandleTable
->FirstFreeTableEntry
+ 1;
634 cure
->u1
.Object
= NULL
;
635 cure
->u2
.NextFreeTableEntry
= i
;
637 /* truncate the free entry list */
638 (cure
- 1)->u2
.NextFreeTableEntry
= -1;
640 /* save the pointers to the allocated list(s) */
641 InterlockedExchangePointer(&nmtbl
[mli
], ntbl
);
644 InterlockedExchangePointer(&HandleTable
->Table
[tli
], nmtbl
);
647 /* increment the NextIndexNeedingPool to the next index where we need to
648 allocate new memory */
649 HandleTable
->NextIndexNeedingPool
+= N_SUBHANDLE_ENTRIES
;
654 DPRINT1("Can't allocate any more handles in handle table 0x%x!\n", HandleTable
);
661 ExpFreeHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
662 IN PHANDLE_TABLE_ENTRY Entry
,
669 ASSERT(IS_VALID_EX_HANDLE(Handle
));
671 DPRINT("ExpFreeHandleTableEntry HT:0x%x Entry:0x%x\n", HandleTable
, Entry
);
673 /* automatically unlock the entry if currently locked. We however don't notify
674 anyone who waited on the handle because we're holding an exclusive lock after
675 all and these locks will fail then */
676 InterlockedExchangePointer(&Entry
->u1
.Object
, NULL
);
677 Entry
->u2
.NextFreeTableEntry
= HandleTable
->FirstFreeTableEntry
;
678 HandleTable
->FirstFreeTableEntry
= Handle
;
680 HandleTable
->HandleCount
--;
683 static PHANDLE_TABLE_ENTRY
684 ExpLookupHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
687 PHANDLE_TABLE_ENTRY Entry
= NULL
;
693 if(IS_VALID_EX_HANDLE(Handle
))
696 PHANDLE_TABLE_ENTRY
*mlp
;
698 tli
= TLI_FROM_HANDLE(Handle
);
699 mli
= MLI_FROM_HANDLE(Handle
);
700 eli
= ELI_FROM_HANDLE(Handle
);
702 mlp
= HandleTable
->Table
[tli
];
703 if(Handle
< HandleTable
->NextIndexNeedingPool
&&
704 mlp
!= NULL
&& mlp
[mli
] != NULL
&& mlp
[mli
][eli
].u1
.Object
!= NULL
)
706 Entry
= &mlp
[mli
][eli
];
707 DPRINT("handle lookup 0x%x -> entry 0x%x [HT:0x%x] ptr: 0x%x\n", Handle
, Entry
, HandleTable
, mlp
[mli
][eli
].u1
.Object
);
712 DPRINT("Looking up invalid handle 0x%x\n", Handle
);
719 ExLockHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
720 IN PHANDLE_TABLE_ENTRY Entry
)
722 ULONG_PTR Current
, New
;
726 DPRINT("Entering handle table entry 0x%x lock...\n", Entry
);
733 Current
= (volatile ULONG_PTR
)Entry
->u1
.Object
;
735 if(!Current
|| (HandleTable
->Flags
& EX_HANDLE_TABLE_CLOSING
))
737 DPRINT("Attempted to lock empty handle table entry 0x%x or handle table shut down\n", Entry
);
741 if(!(Current
& EX_HANDLE_ENTRY_LOCKED
))
743 New
= Current
| EX_HANDLE_ENTRY_LOCKED
;
744 if(InterlockedCompareExchangePointer(&Entry
->u1
.Object
,
746 (PVOID
)Current
) == (PVOID
)Current
)
748 DPRINT("SUCCESS handle table 0x%x entry 0x%x lock\n", HandleTable
, Entry
);
749 /* we acquired the lock */
754 /* wait about 5ms at maximum so we don't wait forever in unfortunate
755 co-incidences where releasing the lock in another thread happens right
756 before we're waiting on the contention event to get pulsed, which might
757 never happen again... */
758 KeWaitForSingleObject(&HandleTable
->HandleContentionEvent
,
762 &ExpHandleShortWait
);
769 ExUnlockHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
770 IN PHANDLE_TABLE_ENTRY Entry
)
772 ULONG_PTR Current
, New
;
779 DPRINT("ExUnlockHandleTableEntry HT:0x%x Entry:0x%x\n", HandleTable
, Entry
);
781 Current
= (volatile ULONG_PTR
)Entry
->u1
.Object
;
783 ASSERT(Current
& EX_HANDLE_ENTRY_LOCKED
);
785 New
= Current
& ~EX_HANDLE_ENTRY_LOCKED
;
787 InterlockedExchangePointer(&Entry
->u1
.Object
,
790 /* we unlocked the entry, pulse the contention event so threads who're waiting
791 on the release can continue */
792 KePulseEvent(&HandleTable
->HandleContentionEvent
,
798 ExCreateHandle(IN PHANDLE_TABLE HandleTable
,
799 IN PHANDLE_TABLE_ENTRY Entry
)
801 PHANDLE_TABLE_ENTRY NewHandleTableEntry
;
802 LONG Handle
= EX_INVALID_HANDLE
;
809 /* The highest bit in Entry->u1.Object has to be 1 so we make sure it's a
810 pointer to kmode memory. It will cleared though because it also indicates
812 ASSERT((ULONG_PTR
)Entry
->u1
.Object
& EX_HANDLE_ENTRY_LOCKED
);
814 KeEnterCriticalRegion();
815 ExAcquireHandleTableLockExclusive(HandleTable
);
817 NewHandleTableEntry
= ExpAllocateHandleTableEntry(HandleTable
,
819 if(NewHandleTableEntry
!= NULL
)
821 *NewHandleTableEntry
= *Entry
;
823 ExUnlockHandleTableEntry(HandleTable
,
824 NewHandleTableEntry
);
827 ExReleaseHandleTableLock(HandleTable
);
828 KeLeaveCriticalRegion();
834 ExDestroyHandle(IN PHANDLE_TABLE HandleTable
,
837 PHANDLE_TABLE_ENTRY HandleTableEntry
;
844 KeEnterCriticalRegion();
845 ExAcquireHandleTableLockExclusive(HandleTable
);
847 HandleTableEntry
= ExpLookupHandleTableEntry(HandleTable
,
850 if(HandleTableEntry
!= NULL
&& ExLockHandleTableEntry(HandleTable
, HandleTableEntry
))
852 /* free and automatically unlock the handle. However we don't need to pulse
853 the contention event since other locks on this entry will fail */
854 ExpFreeHandleTableEntry(HandleTable
,
860 ExReleaseHandleTableLock(HandleTable
);
861 KeLeaveCriticalRegion();
867 ExDestroyHandleByEntry(IN PHANDLE_TABLE HandleTable
,
868 IN PHANDLE_TABLE_ENTRY Entry
,
876 /* This routine requires the entry to be locked */
877 ASSERT((ULONG_PTR
)Entry
->u1
.Object
& EX_HANDLE_ENTRY_LOCKED
);
879 DPRINT("DestroyHandleByEntry HT:0x%x Entry:0x%x\n", HandleTable
, Entry
);
881 KeEnterCriticalRegion();
882 ExAcquireHandleTableLockExclusive(HandleTable
);
884 /* free and automatically unlock the handle. However we don't need to pulse
885 the contention event since other locks on this entry will fail */
886 ExpFreeHandleTableEntry(HandleTable
,
890 ExReleaseHandleTableLock(HandleTable
);
891 KeLeaveCriticalRegion();
895 ExMapHandleToPointer(IN PHANDLE_TABLE HandleTable
,
898 PHANDLE_TABLE_ENTRY HandleTableEntry
;
904 HandleTableEntry
= ExpLookupHandleTableEntry(HandleTable
,
906 if (HandleTableEntry
!= NULL
&& ExLockHandleTableEntry(HandleTable
, HandleTableEntry
))
908 DPRINT("ExMapHandleToPointer HT:0x%x Entry:0x%x locked\n", HandleTable
, HandleTableEntry
);
909 return HandleTableEntry
;
916 ExChangeHandle(IN PHANDLE_TABLE HandleTable
,
918 IN PEX_CHANGE_HANDLE_CALLBACK ChangeHandleCallback
,
921 PHANDLE_TABLE_ENTRY HandleTableEntry
;
927 ASSERT(ChangeHandleCallback
);
929 KeEnterCriticalRegion();
931 HandleTableEntry
= ExpLookupHandleTableEntry(HandleTable
,
934 if(HandleTableEntry
!= NULL
&& ExLockHandleTableEntry(HandleTable
, HandleTableEntry
))
936 Ret
= ChangeHandleCallback(HandleTable
,
940 ExUnlockHandleTableEntry(HandleTable
,
944 KeLeaveCriticalRegion();