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 static BOOLEAN ExpInitialized
= FALSE
;
82 /******************************************************************************/
85 ExpInitializeHandleTables(VOID
)
87 ExpHandleShortWait
.QuadPart
= -50000;
88 InitializeListHead(&ExpHandleTableHead
);
89 ExInitializeFastMutex(&ExpHandleTableListLock
);
91 ExpInitialized
= TRUE
;
95 ExCreateHandleTable(IN PEPROCESS QuotaProcess OPTIONAL
)
97 PHANDLE_TABLE HandleTable
;
106 if(QuotaProcess
!= NULL
)
108 /* FIXME - Charge process quota before allocating the handle table! */
111 /* allocate enough memory for the handle table and the lowest level */
112 HandleTable
= ExAllocatePoolWithTag(NonPagedPool
,
113 sizeof(HANDLE_TABLE
) + (N_TOPLEVEL_POINTERS
* sizeof(PHANDLE_TABLE_ENTRY
*)),
114 TAG('E', 'x', 'H', 't'));
115 if(HandleTable
!= NULL
)
117 /* initialize the handle table */
118 HandleTable
->Flags
= 0;
119 HandleTable
->HandleCount
= 0;
120 HandleTable
->Table
= (PHANDLE_TABLE_ENTRY
**)(HandleTable
+ 1);
121 HandleTable
->QuotaProcess
= QuotaProcess
;
122 HandleTable
->FirstFreeTableEntry
= -1; /* no entries freed so far */
123 HandleTable
->NextIndexNeedingPool
= 0; /* no entries freed so far, so we have to allocate already for the first handle */
124 HandleTable
->UniqueProcessId
= (QuotaProcess
? QuotaProcess
->UniqueProcessId
: NULL
);
126 ExInitializeResource(&HandleTable
->HandleTableLock
);
128 KeInitializeEvent(&HandleTable
->HandleContentionEvent
,
132 RtlZeroMemory(HandleTable
->Table
, N_TOPLEVEL_POINTERS
* sizeof(PHANDLE_TABLE_ENTRY
*));
134 /* during bootup KeGetCurrentThread() might be NULL, needs to be fixed... */
135 if(KeGetCurrentThread() != NULL
)
137 /* insert it into the global handle table list */
138 KeEnterCriticalRegion();
140 ExAcquireHandleTableListLock();
141 InsertTailList(&ExpHandleTableHead
,
142 &HandleTable
->HandleTableList
);
143 ExReleaseHandleTableListLock();
145 KeLeaveCriticalRegion();
149 InsertTailList(&ExpHandleTableHead
,
150 &HandleTable
->HandleTableList
);
155 /* FIXME - return the quota to the process */
162 ExLockHandleTableEntryNoDestructionCheck(IN PHANDLE_TABLE HandleTable
,
163 IN PHANDLE_TABLE_ENTRY Entry
)
165 ULONG_PTR Current
, New
;
169 DPRINT("Entering handle table entry 0x%p lock...\n", Entry
);
176 Current
= (volatile ULONG_PTR
)Entry
->u1
.Object
;
180 DPRINT("Attempted to lock empty handle table entry 0x%p or handle table shut down\n", Entry
);
184 if(!(Current
& EX_HANDLE_ENTRY_LOCKED
))
186 New
= Current
| EX_HANDLE_ENTRY_LOCKED
;
187 if(InterlockedCompareExchangePointer(&Entry
->u1
.Object
,
189 (PVOID
)Current
) == (PVOID
)Current
)
191 DPRINT("SUCCESS handle table 0x%p entry 0x%p lock\n", HandleTable
, Entry
);
192 /* we acquired the lock */
197 /* wait about 5ms at maximum so we don't wait forever in unfortunate
198 co-incidences where releasing the lock in another thread happens right
199 before we're waiting on the contention event to get pulsed, which might
200 never happen again... */
201 KeWaitForSingleObject(&HandleTable
->HandleContentionEvent
,
205 &ExpHandleShortWait
);
212 ExDestroyHandleTable(IN PHANDLE_TABLE HandleTable
,
213 IN PEX_DESTROY_HANDLE_CALLBACK DestroyHandleCallback OPTIONAL
,
214 IN PVOID Context OPTIONAL
)
216 PHANDLE_TABLE_ENTRY
**tlp
, **lasttlp
, *mlp
, *lastmlp
;
217 PEPROCESS QuotaProcess
;
223 KeEnterCriticalRegion();
225 /* ensure there's no other operations going by acquiring an exclusive lock */
226 ExAcquireHandleTableLockExclusive(HandleTable
);
228 ASSERT(!(HandleTable
->Flags
& EX_HANDLE_TABLE_CLOSING
));
230 HandleTable
->Flags
|= EX_HANDLE_TABLE_CLOSING
;
232 KePulseEvent(&HandleTable
->HandleContentionEvent
,
236 /* remove the handle table from the global handle table list */
237 ExAcquireHandleTableListLock();
238 RemoveEntryList(&HandleTable
->HandleTableList
);
239 ExReleaseHandleTableListLock();
241 /* call the callback function to cleanup the objects associated with the
243 if(DestroyHandleCallback
!= NULL
)
245 for(tlp
= HandleTable
->Table
, lasttlp
= HandleTable
->Table
+ N_TOPLEVEL_POINTERS
;
251 for(mlp
= *tlp
, lastmlp
= (*tlp
) + N_MIDDLELEVEL_POINTERS
;
257 PHANDLE_TABLE_ENTRY curee
, laste
;
259 for(curee
= *mlp
, laste
= *mlp
+ N_SUBHANDLE_ENTRIES
;
263 if(curee
->u1
.Object
!= NULL
&& ExLockHandleTableEntryNoDestructionCheck(HandleTable
, curee
))
265 DestroyHandleCallback(HandleTable
, curee
->u1
.Object
, curee
->u2
.GrantedAccess
, Context
);
266 ExUnlockHandleTableEntry(HandleTable
, curee
);
275 QuotaProcess
= HandleTable
->QuotaProcess
;
277 /* free the tables */
278 for(tlp
= HandleTable
->Table
, lasttlp
= HandleTable
->Table
+ N_TOPLEVEL_POINTERS
;
284 for(mlp
= *tlp
, lastmlp
= (*tlp
) + N_MIDDLELEVEL_POINTERS
;
292 if(QuotaProcess
!= NULL
)
294 /* FIXME - return the quota to the process */
301 if(QuotaProcess
!= NULL
)
303 /* FIXME - return the quota to the process */
308 ExReleaseHandleTableLock(HandleTable
);
310 KeLeaveCriticalRegion();
312 /* free the handle table */
313 ExDeleteResource(&HandleTable
->HandleTableLock
);
314 ExFreePool(HandleTable
);
316 if(QuotaProcess
!= NULL
)
318 /* FIXME - return the quota to the process */
323 ExDupHandleTable(IN PEPROCESS QuotaProcess OPTIONAL
,
324 IN PEX_DUPLICATE_HANDLE_CALLBACK DuplicateHandleCallback OPTIONAL
,
325 IN PVOID Context OPTIONAL
,
326 IN PHANDLE_TABLE SourceHandleTable
)
328 PHANDLE_TABLE HandleTable
;
332 ASSERT(SourceHandleTable
);
334 HandleTable
= ExCreateHandleTable(QuotaProcess
);
335 if(HandleTable
!= NULL
)
337 PHANDLE_TABLE_ENTRY
**tlp
, **srctlp
, **etlp
, *mlp
, *srcmlp
, *emlp
, stbl
, srcstbl
, estbl
;
342 /* make sure the other handle table isn't being changed during the duplication */
343 ExAcquireHandleTableLockShared(SourceHandleTable
);
345 /* allocate enough tables */
346 etlp
= SourceHandleTable
->Table
+ N_TOPLEVEL_POINTERS
;
347 for(srctlp
= SourceHandleTable
->Table
, tlp
= HandleTable
->Table
;
353 /* allocate middle level entry tables */
354 if(QuotaProcess
!= NULL
)
356 /* FIXME - Charge process quota before allocating the handle table! */
359 *tlp
= ExAllocatePoolWithTag(PagedPool
,
360 N_MIDDLELEVEL_POINTERS
* sizeof(PHANDLE_TABLE_ENTRY
),
361 TAG('E', 'x', 'H', 't'));
364 RtlZeroMemory(*tlp
, N_MIDDLELEVEL_POINTERS
* sizeof(PHANDLE_TABLE_ENTRY
));
368 emlp
= *srctlp
+ N_MIDDLELEVEL_POINTERS
;
369 for(srcmlp
= *srctlp
, mlp
= *tlp
;
375 /* allocate subhandle tables */
376 if(QuotaProcess
!= NULL
)
378 /* FIXME - Charge process quota before allocating the handle table! */
381 *mlp
= ExAllocatePoolWithTag(PagedPool
,
382 N_SUBHANDLE_ENTRIES
* sizeof(HANDLE_TABLE_ENTRY
),
383 TAG('E', 'x', 'H', 't'));
386 RtlZeroMemory(*mlp
, N_SUBHANDLE_ENTRIES
* sizeof(HANDLE_TABLE_ENTRY
));
390 goto freehandletable
;
402 DPRINT1("Failed to duplicate handle table 0x%p\n", SourceHandleTable
);
404 ExReleaseHandleTableLock(SourceHandleTable
);
406 ExDestroyHandleTable(HandleTable
,
409 /* allocate an empty handle table */
410 return ExCreateHandleTable(QuotaProcess
);
415 /* duplicate the handles */
416 HandleTable
->HandleCount
= SourceHandleTable
->HandleCount
;
417 HandleTable
->FirstFreeTableEntry
= SourceHandleTable
->FirstFreeTableEntry
;
418 HandleTable
->NextIndexNeedingPool
= SourceHandleTable
->NextIndexNeedingPool
;
420 /* make sure all tables are zeroed */
423 etlp
= SourceHandleTable
->Table
+ N_TOPLEVEL_POINTERS
;
424 for(srctlp
= SourceHandleTable
->Table
, tlp
= HandleTable
->Table
;
426 srctlp
++, tlp
++, tli
++)
430 ASSERT(*tlp
!= NULL
);
432 emlp
= *srctlp
+ N_MIDDLELEVEL_POINTERS
;
433 for(srcmlp
= *srctlp
, mlp
= *tlp
;
435 srcmlp
++, mlp
++, mli
++)
439 ASSERT(*mlp
!= NULL
);
441 /* walk all handle entries and duplicate them if wanted */
442 estbl
= *srcmlp
+ N_SUBHANDLE_ENTRIES
;
443 for(srcstbl
= *srcmlp
, stbl
= *mlp
;
445 srcstbl
++, stbl
++, eli
++)
447 /* try to duplicate the source handle */
448 if(srcstbl
->u1
.Object
!= NULL
&&
449 ExLockHandleTableEntry(SourceHandleTable
,
452 /* ask the caller if this handle should be duplicated */
453 if(DuplicateHandleCallback
!= NULL
&&
454 !DuplicateHandleCallback(HandleTable
,
458 /* free the entry and chain it into the free list */
459 HandleTable
->HandleCount
--;
460 stbl
->u1
.Object
= NULL
;
461 stbl
->u2
.NextFreeTableEntry
= HandleTable
->FirstFreeTableEntry
;
462 HandleTable
->FirstFreeTableEntry
= BUILD_HANDLE(tli
, mli
, eli
);
466 /* duplicate the handle and unlock it */
467 stbl
->u2
.GrantedAccess
= srcstbl
->u2
.GrantedAccess
;
468 stbl
->u1
.ObAttributes
= srcstbl
->u1
.ObAttributes
& ~EX_HANDLE_ENTRY_LOCKED
;
470 ExUnlockHandleTableEntry(SourceHandleTable
,
475 /* this is a free handle table entry, copy over the entire
485 /* release the source handle table */
486 ExReleaseHandleTableLock(SourceHandleTable
);
492 static PHANDLE_TABLE_ENTRY
493 ExpAllocateHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
496 PHANDLE_TABLE_ENTRY Entry
= NULL
;
502 ASSERT(KeGetCurrentThread() != NULL
);
504 DPRINT("HT[0x%p]: HandleCount: %d\n", HandleTable
, HandleTable
->HandleCount
);
506 if(HandleTable
->HandleCount
< EX_MAX_HANDLES
)
510 if(HandleTable
->FirstFreeTableEntry
!= -1)
512 /* there's a free handle entry we can just grab and use */
513 tli
= TLI_FROM_HANDLE(HandleTable
->FirstFreeTableEntry
);
514 mli
= MLI_FROM_HANDLE(HandleTable
->FirstFreeTableEntry
);
515 eli
= ELI_FROM_HANDLE(HandleTable
->FirstFreeTableEntry
);
517 /* the pointer should be valid in any way!!! */
518 ASSERT(HandleTable
->Table
[tli
]);
519 ASSERT(HandleTable
->Table
[tli
][mli
]);
521 Entry
= &HandleTable
->Table
[tli
][mli
][eli
];
523 *Handle
= HandleTable
->FirstFreeTableEntry
;
525 /* save the index to the next free handle (if available) */
526 HandleTable
->FirstFreeTableEntry
= Entry
->u2
.NextFreeTableEntry
;
527 Entry
->u2
.NextFreeTableEntry
= 0;
528 Entry
->u1
.Object
= NULL
;
530 HandleTable
->HandleCount
++;
534 /* we need to allocate a new subhandle table first */
535 PHANDLE_TABLE_ENTRY cure
, laste
, ntbl
, *nmtbl
;
537 BOOLEAN AllocatedMtbl
;
539 ASSERT(HandleTable
->NextIndexNeedingPool
<= N_MAX_HANDLE
);
541 /* the index of the next table to be allocated was saved in
542 NextIndexNeedingPool the last time a handle entry was allocated and
543 the subhandle entry list was full. the subhandle entry index of
544 NextIndexNeedingPool should be 0 here! */
545 tli
= TLI_FROM_HANDLE(HandleTable
->NextIndexNeedingPool
);
546 mli
= MLI_FROM_HANDLE(HandleTable
->NextIndexNeedingPool
);
547 DPRINT("HandleTable->NextIndexNeedingPool: 0x%x\n", HandleTable
->NextIndexNeedingPool
);
548 DPRINT("tli: 0x%x mli: 0x%x eli: 0x%x\n", tli
, mli
, ELI_FROM_HANDLE(HandleTable
->NextIndexNeedingPool
));
550 ASSERT(ELI_FROM_HANDLE(HandleTable
->NextIndexNeedingPool
) == 0);
552 DPRINT("HandleTable->Table[%d] == 0x%p\n", tli
, HandleTable
->Table
[tli
]);
554 /* allocate a middle level entry list if required */
555 nmtbl
= HandleTable
->Table
[tli
];
558 if(HandleTable
->QuotaProcess
!= NULL
)
560 /* FIXME - Charge process quota before allocating the handle table! */
563 nmtbl
= ExAllocatePoolWithTag(PagedPool
,
564 N_MIDDLELEVEL_POINTERS
* sizeof(PHANDLE_TABLE_ENTRY
),
565 TAG('E', 'x', 'H', 't'));
568 if(HandleTable
->QuotaProcess
!= NULL
)
570 /* FIXME - return the quota to the process */
576 /* clear the middle level entry list */
577 RtlZeroMemory(nmtbl
, N_MIDDLELEVEL_POINTERS
* sizeof(PHANDLE_TABLE_ENTRY
));
579 /* make sure the table was zeroed before we set one item */
582 /* note, don't set the the pointer in the top level list yet because we
583 might screw up lookups if allocating a subhandle entry table failed
584 and this newly allocated table might get freed again */
585 AllocatedMtbl
= TRUE
;
589 AllocatedMtbl
= FALSE
;
591 /* allocate a subhandle entry table in any case! */
592 ASSERT(nmtbl
[mli
] == NULL
);
595 DPRINT("HandleTable->Table[%d][%d] == 0x%p\n", tli
, mli
, nmtbl
[mli
]);
597 if(HandleTable
->QuotaProcess
!= NULL
)
599 /* FIXME - Charge process quota before allocating the handle table! */
602 ntbl
= ExAllocatePoolWithTag(PagedPool
,
603 N_SUBHANDLE_ENTRIES
* sizeof(HANDLE_TABLE_ENTRY
),
604 TAG('E', 'x', 'H', 't'));
607 if(HandleTable
->QuotaProcess
!= NULL
)
609 /* FIXME - Return process quota charged */
612 /* free the middle level entry list, if allocated, because it's empty and
618 if(HandleTable
->QuotaProcess
!= NULL
)
620 /* FIXME - Return process quota charged */
627 /* let's just use the very first entry */
629 Entry
->u1
.ObAttributes
= EX_HANDLE_ENTRY_LOCKED
;
630 Entry
->u2
.NextFreeTableEntry
= 0;
632 *Handle
= HandleTable
->NextIndexNeedingPool
;
634 HandleTable
->HandleCount
++;
636 /* set the FirstFreeTableEntry member to the second entry and chain the
638 HandleTable
->FirstFreeTableEntry
= HandleTable
->NextIndexNeedingPool
+ 1;
639 for(cure
= Entry
+ 1, laste
= Entry
+ N_SUBHANDLE_ENTRIES
, i
= HandleTable
->FirstFreeTableEntry
+ 1;
643 cure
->u1
.Object
= NULL
;
644 cure
->u2
.NextFreeTableEntry
= i
;
646 /* truncate the free entry list */
647 (cure
- 1)->u2
.NextFreeTableEntry
= -1;
649 /* save the pointers to the allocated list(s) */
650 InterlockedExchangePointer(&nmtbl
[mli
], ntbl
);
653 InterlockedExchangePointer(&HandleTable
->Table
[tli
], nmtbl
);
656 /* increment the NextIndexNeedingPool to the next index where we need to
657 allocate new memory */
658 HandleTable
->NextIndexNeedingPool
+= N_SUBHANDLE_ENTRIES
;
663 DPRINT1("Can't allocate any more handles in handle table 0x%p!\n", HandleTable
);
670 ExpFreeHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
671 IN PHANDLE_TABLE_ENTRY Entry
,
678 ASSERT(IS_VALID_EX_HANDLE(Handle
));
680 DPRINT("ExpFreeHandleTableEntry HT:0x%p Entry:0x%p\n", HandleTable
, Entry
);
682 /* automatically unlock the entry if currently locked. We however don't notify
683 anyone who waited on the handle because we're holding an exclusive lock after
684 all and these locks will fail then */
685 InterlockedExchangePointer(&Entry
->u1
.Object
, NULL
);
686 Entry
->u2
.NextFreeTableEntry
= HandleTable
->FirstFreeTableEntry
;
687 HandleTable
->FirstFreeTableEntry
= Handle
;
689 HandleTable
->HandleCount
--;
692 static PHANDLE_TABLE_ENTRY
693 ExpLookupHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
696 PHANDLE_TABLE_ENTRY Entry
= NULL
;
702 if(IS_VALID_EX_HANDLE(Handle
))
705 PHANDLE_TABLE_ENTRY
*mlp
;
707 tli
= TLI_FROM_HANDLE(Handle
);
708 mli
= MLI_FROM_HANDLE(Handle
);
709 eli
= ELI_FROM_HANDLE(Handle
);
711 mlp
= HandleTable
->Table
[tli
];
712 if(Handle
< HandleTable
->NextIndexNeedingPool
&&
713 mlp
!= NULL
&& mlp
[mli
] != NULL
&& mlp
[mli
][eli
].u1
.Object
!= NULL
)
715 Entry
= &mlp
[mli
][eli
];
716 DPRINT("handle lookup 0x%x -> entry 0x%p [HT:0x%p] ptr: 0x%p\n", Handle
, Entry
, HandleTable
, mlp
[mli
][eli
].u1
.Object
);
721 DPRINT("Looking up invalid handle 0x%x\n", Handle
);
728 ExLockHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
729 IN PHANDLE_TABLE_ENTRY Entry
)
731 ULONG_PTR Current
, New
;
735 DPRINT("Entering handle table entry 0x%p lock...\n", Entry
);
742 Current
= (volatile ULONG_PTR
)Entry
->u1
.Object
;
744 if(!Current
|| (HandleTable
->Flags
& EX_HANDLE_TABLE_CLOSING
))
746 DPRINT("Attempted to lock empty handle table entry 0x%p or handle table shut down\n", Entry
);
750 if(!(Current
& EX_HANDLE_ENTRY_LOCKED
))
752 New
= Current
| EX_HANDLE_ENTRY_LOCKED
;
753 if(InterlockedCompareExchangePointer(&Entry
->u1
.Object
,
755 (PVOID
)Current
) == (PVOID
)Current
)
757 DPRINT("SUCCESS handle table 0x%p entry 0x%p lock\n", HandleTable
, Entry
);
758 /* we acquired the lock */
763 /* wait about 5ms at maximum so we don't wait forever in unfortunate
764 co-incidences where releasing the lock in another thread happens right
765 before we're waiting on the contention event to get pulsed, which might
766 never happen again... */
767 KeWaitForSingleObject(&HandleTable
->HandleContentionEvent
,
771 &ExpHandleShortWait
);
778 ExUnlockHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
779 IN PHANDLE_TABLE_ENTRY Entry
)
781 ULONG_PTR Current
, New
;
788 DPRINT("ExUnlockHandleTableEntry HT:0x%p Entry:0x%p\n", HandleTable
, Entry
);
790 Current
= (volatile ULONG_PTR
)Entry
->u1
.Object
;
792 ASSERT(Current
& EX_HANDLE_ENTRY_LOCKED
);
794 New
= Current
& ~EX_HANDLE_ENTRY_LOCKED
;
796 InterlockedExchangePointer(&Entry
->u1
.Object
,
799 /* we unlocked the entry, pulse the contention event so threads who're waiting
800 on the release can continue */
801 KePulseEvent(&HandleTable
->HandleContentionEvent
,
807 ExCreateHandle(IN PHANDLE_TABLE HandleTable
,
808 IN PHANDLE_TABLE_ENTRY Entry
)
810 PHANDLE_TABLE_ENTRY NewHandleTableEntry
;
811 LONG Handle
= EX_INVALID_HANDLE
;
818 /* The highest bit in Entry->u1.Object has to be 1 so we make sure it's a
819 pointer to kmode memory. It will cleared though because it also indicates
821 ASSERT((ULONG_PTR
)Entry
->u1
.Object
& EX_HANDLE_ENTRY_LOCKED
);
823 KeEnterCriticalRegion();
824 ExAcquireHandleTableLockExclusive(HandleTable
);
826 NewHandleTableEntry
= ExpAllocateHandleTableEntry(HandleTable
,
828 if(NewHandleTableEntry
!= NULL
)
830 *NewHandleTableEntry
= *Entry
;
832 ExUnlockHandleTableEntry(HandleTable
,
833 NewHandleTableEntry
);
836 ExReleaseHandleTableLock(HandleTable
);
837 KeLeaveCriticalRegion();
843 ExDestroyHandle(IN PHANDLE_TABLE HandleTable
,
846 PHANDLE_TABLE_ENTRY HandleTableEntry
;
853 KeEnterCriticalRegion();
854 ExAcquireHandleTableLockExclusive(HandleTable
);
856 HandleTableEntry
= ExpLookupHandleTableEntry(HandleTable
,
859 if(HandleTableEntry
!= NULL
&& ExLockHandleTableEntry(HandleTable
, HandleTableEntry
))
861 /* free and automatically unlock the handle. However we don't need to pulse
862 the contention event since other locks on this entry will fail */
863 ExpFreeHandleTableEntry(HandleTable
,
869 ExReleaseHandleTableLock(HandleTable
);
870 KeLeaveCriticalRegion();
876 ExDestroyHandleByEntry(IN PHANDLE_TABLE HandleTable
,
877 IN PHANDLE_TABLE_ENTRY Entry
,
885 /* This routine requires the entry to be locked */
886 ASSERT((ULONG_PTR
)Entry
->u1
.Object
& EX_HANDLE_ENTRY_LOCKED
);
888 DPRINT("DestroyHandleByEntry HT:0x%p Entry:0x%p\n", HandleTable
, Entry
);
890 KeEnterCriticalRegion();
891 ExAcquireHandleTableLockExclusive(HandleTable
);
893 /* free and automatically unlock the handle. However we don't need to pulse
894 the contention event since other locks on this entry will fail */
895 ExpFreeHandleTableEntry(HandleTable
,
899 ExReleaseHandleTableLock(HandleTable
);
900 KeLeaveCriticalRegion();
904 ExMapHandleToPointer(IN PHANDLE_TABLE HandleTable
,
907 PHANDLE_TABLE_ENTRY HandleTableEntry
;
913 HandleTableEntry
= ExpLookupHandleTableEntry(HandleTable
,
915 if (HandleTableEntry
!= NULL
&& ExLockHandleTableEntry(HandleTable
, HandleTableEntry
))
917 DPRINT("ExMapHandleToPointer HT:0x%p Entry:0x%p locked\n", HandleTable
, HandleTableEntry
);
918 return HandleTableEntry
;
925 ExChangeHandle(IN PHANDLE_TABLE HandleTable
,
927 IN PEX_CHANGE_HANDLE_CALLBACK ChangeHandleCallback
,
930 PHANDLE_TABLE_ENTRY HandleTableEntry
;
936 ASSERT(ChangeHandleCallback
);
938 KeEnterCriticalRegion();
940 HandleTableEntry
= ExpLookupHandleTableEntry(HandleTable
,
943 if(HandleTableEntry
!= NULL
&& ExLockHandleTableEntry(HandleTable
, HandleTableEntry
))
945 Ret
= ChangeHandleCallback(HandleTable
,
949 ExUnlockHandleTableEntry(HandleTable
,
953 KeLeaveCriticalRegion();