2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ex/handle.c
5 * PURPOSE: Generic Executive Handle Tables
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Thomas Weidenmueller <w3seek@reactos.com>
10 /* INCLUDES ******************************************************************/
16 /* GLOBALS *******************************************************************/
18 LIST_ENTRY HandleTableListHead
;
19 EX_PUSH_LOCK HandleTableListLock
;
20 #define SizeOfHandle(x) (sizeof(HANDLE) * (x))
22 /* PRIVATE FUNCTIONS *********************************************************/
27 ExpInitializeHandleTables(VOID
)
29 /* Initialize the list of handle tables and the lock */
30 InitializeListHead(&HandleTableListHead
);
31 ExInitializePushLock(&HandleTableListLock
);
36 ExpLookupHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
41 PHANDLE_TABLE_ENTRY HandleArray
, Entry
;
44 /* Clear the tag bits */
47 /* Check if the handle is in the allocated range */
48 if (Handle
.Value
>= HandleTable
->NextHandleNeedingPool
)
53 /* Get the table code */
54 TableBase
= HandleTable
->TableCode
;
56 /* Extract the table level and actual table base */
57 TableLevel
= (ULONG
)(TableBase
& 3);
60 PointerArray
= (PVOID
*)TableBase
;
61 HandleArray
= (PHANDLE_TABLE_ENTRY
)TableBase
;
63 /* Check what level we're running at */
68 /* Get the mid level pointer array */
69 PointerArray
= PointerArray
[Handle
.HighIndex
];
74 /* Get the handle array */
75 HandleArray
= PointerArray
[Handle
.MidIndex
];
80 /* Get the entry using the low index */
81 Entry
= &HandleArray
[Handle
.LowIndex
];
92 /* Return the handle entry */
98 ExpAllocateTablePagedPool(IN PEPROCESS Process OPTIONAL
,
103 /* Do the allocation */
104 Buffer
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_OBJECT_TABLE
);
107 /* Clear the memory */
108 RtlZeroMemory(Buffer
, Size
);
110 /* Check if we have a process to charge quota */
113 /* FIXME: Charge quota */
117 /* Return the allocated memory */
123 ExpAllocateTablePagedPoolNoZero(IN PEPROCESS Process OPTIONAL
,
128 /* Do the allocation */
129 Buffer
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_OBJECT_TABLE
);
132 /* Check if we have a process to charge quota */
135 /* FIXME: Charge quota */
139 /* Return the allocated memory */
145 ExpFreeTablePagedPool(IN PEPROCESS Process OPTIONAL
,
149 /* Free the buffer */
150 ExFreePoolWithTag(Buffer
, TAG_OBJECT_TABLE
);
153 /* FIXME: Release quota */
159 ExpFreeLowLevelTable(IN PEPROCESS Process
,
160 IN PHANDLE_TABLE_ENTRY TableEntry
)
162 /* Check if we have an entry */
163 if (TableEntry
[0].Object
)
166 ExpFreeTablePagedPool(Process
,
167 TableEntry
[0].Object
,
169 sizeof(HANDLE_TABLE_ENTRY_INFO
));
173 ExpFreeTablePagedPool(Process
, TableEntry
, PAGE_SIZE
);
178 ExpFreeHandleTable(IN PHANDLE_TABLE HandleTable
)
180 PEPROCESS Process
= HandleTable
->QuotaProcess
;
182 ULONG_PTR TableCode
= HandleTable
->TableCode
;
183 ULONG_PTR TableBase
= TableCode
& ~3;
184 ULONG TableLevel
= (ULONG
)(TableCode
& 3);
185 PHANDLE_TABLE_ENTRY Level1
, *Level2
, **Level3
;
188 /* Check which level we're at */
191 /* Select the first level table base and just free it */
192 Level1
= (PVOID
)TableBase
;
193 ExpFreeLowLevelTable(Process
, Level1
);
195 else if (TableLevel
== 1)
197 /* Select the second level table base */
198 Level2
= (PVOID
)TableBase
;
200 /* Loop each mid level entry */
201 for (i
= 0; i
< MID_LEVEL_ENTRIES
; i
++)
203 /* Leave if we've reached the last entry */
204 if (!Level2
[i
]) break;
206 /* Free the second level table */
207 ExpFreeLowLevelTable(Process
, Level2
[i
]);
210 /* Free the second level table */
211 ExpFreeTablePagedPool(Process
, Level2
, PAGE_SIZE
);
215 /* Select the third level table base */
216 Level3
= (PVOID
)TableBase
;
218 /* Loop each high level entry */
219 for (i
= 0; i
< HIGH_LEVEL_ENTRIES
; i
++)
221 /* Leave if we've reached the last entry */
222 if (!Level3
[i
]) break;
224 /* Loop each mid level entry */
225 for (j
= 0; j
< MID_LEVEL_ENTRIES
; j
++)
227 /* Leave if we've reached the last entry */
228 if (!Level3
[i
][j
]) break;
230 /* Free the second level table */
231 ExpFreeLowLevelTable(Process
, Level3
[i
][j
]);
234 /* Free the third level table entry */
235 ExpFreeTablePagedPool(Process
, Level3
[i
], PAGE_SIZE
);
238 /* Free the third level table */
239 ExpFreeTablePagedPool(Process
,
241 SizeOfHandle(HIGH_LEVEL_ENTRIES
));
244 /* Free the actual table and check if we need to release quota */
245 ExFreePoolWithTag(HandleTable
, TAG_OBJECT_TABLE
);
254 ExpFreeHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
256 IN PHANDLE_TABLE_ENTRY HandleTableEntry
)
258 ULONG OldValue
, NewValue
, *Free
;
263 ASSERT(HandleTableEntry
->Object
== NULL
);
264 ASSERT(HandleTableEntry
== ExpLookupHandleTableEntry(HandleTable
, Handle
));
266 /* Decrement the handle count */
267 InterlockedDecrement(&HandleTable
->HandleCount
);
269 /* Mark the handle as free */
270 NewValue
= (ULONG
)Handle
.Value
& ~(SizeOfHandle(1) - 1);
272 /* Check if we're FIFO */
273 if (!HandleTable
->StrictFIFO
)
275 /* Select a lock index */
276 i
= (NewValue
>> 2) % 4;
278 /* Select which entry to use */
279 Free
= (HandleTable
->HandleTableLock
[i
].Locked
) ?
280 &HandleTable
->FirstFree
: &HandleTable
->LastFree
;
284 /* No need to worry about locking, take the last entry */
285 Free
= &HandleTable
->LastFree
;
288 /* Start value change loop */
291 /* Get the current value and write */
293 HandleTableEntry
->NextFreeTableEntry
= (ULONG
)OldValue
;
294 if (InterlockedCompareExchange((PLONG
) Free
, NewValue
, OldValue
) == OldValue
)
296 /* Break out, we're done. Make sure the handle value makes sense */
297 ASSERT((OldValue
& FREE_HANDLE_MASK
) <
298 HandleTable
->NextHandleNeedingPool
);
306 ExpAllocateHandleTable(IN PEPROCESS Process OPTIONAL
,
309 PHANDLE_TABLE HandleTable
;
310 PHANDLE_TABLE_ENTRY HandleTableTable
, HandleEntry
;
314 /* Allocate the table */
315 HandleTable
= ExAllocatePoolWithTag(PagedPool
,
316 sizeof(HANDLE_TABLE
),
318 if (!HandleTable
) return NULL
;
320 /* Check if we have a process */
323 /* FIXME: Charge quota */
326 /* Clear the table */
327 RtlZeroMemory(HandleTable
, sizeof(HANDLE_TABLE
));
329 /* Now allocate the first level structures */
330 HandleTableTable
= ExpAllocateTablePagedPoolNoZero(Process
, PAGE_SIZE
);
331 if (!HandleTableTable
)
333 /* Failed, free the table */
334 ExFreePoolWithTag(HandleTable
, TAG_OBJECT_TABLE
);
338 /* Write the pointer to our first level structures */
339 HandleTable
->TableCode
= (ULONG_PTR
)HandleTableTable
;
341 /* Initialize the first entry */
342 HandleEntry
= &HandleTableTable
[0];
343 HandleEntry
->NextFreeTableEntry
= -2;
344 HandleEntry
->Value
= 0;
346 /* Check if this is a new table */
349 /* Go past the root entry */
352 /* Loop every low level entry */
353 for (i
= 1; i
< (LOW_LEVEL_ENTRIES
- 1); i
++)
355 /* Set up the free data */
356 HandleEntry
->Value
= 0;
357 HandleEntry
->NextFreeTableEntry
= (i
+ 1) * SizeOfHandle(1);
359 /* Move to the next entry */
363 /* Terminate the last entry */
364 HandleEntry
->Value
= 0;
365 HandleEntry
->NextFreeTableEntry
= 0;
366 HandleTable
->FirstFree
= SizeOfHandle(1);
369 /* Set the next handle needing pool after our allocated page from above */
370 HandleTable
->NextHandleNeedingPool
= LOW_LEVEL_ENTRIES
* SizeOfHandle(1);
372 /* Setup the rest of the handle table data */
373 HandleTable
->QuotaProcess
= Process
;
374 HandleTable
->UniqueProcessId
= PsGetCurrentProcess()->UniqueProcessId
;
375 HandleTable
->Flags
= 0;
377 /* Loop all the handle table locks */
378 for (i
= 0; i
< 4; i
++)
380 /* Initialize the handle table lock */
381 ExInitializePushLock(&HandleTable
->HandleTableLock
[i
]);
384 /* Initialize the contention event lock and return the lock */
385 ExInitializePushLock(&HandleTable
->HandleContentionEvent
);
391 ExpAllocateLowLevelTable(IN PHANDLE_TABLE HandleTable
,
395 PHANDLE_TABLE_ENTRY Low
, HandleEntry
;
397 /* Allocate the low level table */
398 Low
= ExpAllocateTablePagedPoolNoZero(HandleTable
->QuotaProcess
,
400 if (!Low
) return NULL
;
402 /* Setup the initial entry */
403 HandleEntry
= &Low
[0];
404 HandleEntry
->NextFreeTableEntry
= -2;
405 HandleEntry
->Value
= 0;
407 /* Check if we're initializing */
410 /* Go to the next entry and the base entry */
412 Base
= HandleTable
->NextHandleNeedingPool
+ SizeOfHandle(2);
414 /* Loop each entry */
416 i
< Base
+ SizeOfHandle(LOW_LEVEL_ENTRIES
- 2);
417 i
+= SizeOfHandle(1))
419 /* Free this entry and move on to the next one */
420 HandleEntry
->NextFreeTableEntry
= i
;
421 HandleEntry
->Value
= 0;
425 /* Terminate the last entry */
426 HandleEntry
->NextFreeTableEntry
= 0;
427 HandleEntry
->Value
= 0;
430 /* Return the low level table */
436 ExpAllocateMidLevelTable(IN PHANDLE_TABLE HandleTable
,
438 OUT PHANDLE_TABLE_ENTRY
*LowTableEntry
)
440 PHANDLE_TABLE_ENTRY
*Mid
, Low
;
442 /* Allocate the mid level table */
443 Mid
= ExpAllocateTablePagedPool(HandleTable
->QuotaProcess
, PAGE_SIZE
);
444 if (!Mid
) return NULL
;
446 /* Allocate a new low level for it */
447 Low
= ExpAllocateLowLevelTable(HandleTable
, DoInit
);
450 /* We failed, free the mid table */
451 ExpFreeTablePagedPool(HandleTable
->QuotaProcess
, Mid
, PAGE_SIZE
);
455 /* Link the tables and return the pointer */
457 *LowTableEntry
= Low
;
463 ExpAllocateHandleTableEntrySlow(IN PHANDLE_TABLE HandleTable
,
467 PHANDLE_TABLE_ENTRY Low
= NULL
, *Mid
, **High
, *SecondLevel
, **ThirdLevel
;
468 ULONG NewFree
, FirstFree
;
470 ULONG_PTR TableCode
= HandleTable
->TableCode
;
471 ULONG_PTR TableBase
= TableCode
& ~3;
472 ULONG TableLevel
= (ULONG
)(TableCode
& 3);
475 /* Check how many levels we already have */
478 /* Allocate a mid level, since we only have a low level */
479 Mid
= ExpAllocateMidLevelTable(HandleTable
, DoInit
, &Low
);
480 if (!Mid
) return FALSE
;
482 /* Link up the tables */
484 Mid
[0] = (PVOID
)TableBase
;
486 /* Write the new level and attempt to change the table code */
487 TableBase
= ((ULONG_PTR
)Mid
) | 1;
488 Value
= InterlockedExchangePointer((PVOID
*)&HandleTable
->TableCode
, (PVOID
)TableBase
);
490 else if (TableLevel
== 1)
492 /* Setup the 2nd level table */
493 SecondLevel
= (PVOID
)TableBase
;
495 /* Get if the next index can fit in the table */
496 i
= HandleTable
->NextHandleNeedingPool
/
497 SizeOfHandle(LOW_LEVEL_ENTRIES
);
498 if (i
< MID_LEVEL_ENTRIES
)
500 /* We need to allocate a new table */
501 Low
= ExpAllocateLowLevelTable(HandleTable
, DoInit
);
502 if (!Low
) return FALSE
;
504 /* Update the table */
505 Value
= InterlockedExchangePointer((PVOID
*)&SecondLevel
[i
], Low
);
506 ASSERT(Value
== NULL
);
510 /* We need a new high level table */
511 High
= ExpAllocateTablePagedPool(HandleTable
->QuotaProcess
,
512 SizeOfHandle(HIGH_LEVEL_ENTRIES
));
513 if (!High
) return FALSE
;
515 /* Allocate a new mid level table as well */
516 Mid
= ExpAllocateMidLevelTable(HandleTable
, DoInit
, &Low
);
519 /* We failed, free the high level table as well */
520 ExpFreeTablePagedPool(HandleTable
->QuotaProcess
,
522 SizeOfHandle(HIGH_LEVEL_ENTRIES
));
526 /* Link up the tables */
527 High
[0] = (PVOID
)TableBase
;
530 /* Write the new table and change the table code */
531 TableBase
= ((ULONG_PTR
)High
) | 2;
532 Value
= InterlockedExchangePointer((PVOID
*)&HandleTable
->TableCode
,
536 else if (TableLevel
== 2)
538 /* Setup the 3rd level table */
539 ThirdLevel
= (PVOID
)TableBase
;
541 /* Get the index and check if it can fit */
542 i
= HandleTable
->NextHandleNeedingPool
/ SizeOfHandle(MAX_MID_INDEX
);
543 if (i
>= HIGH_LEVEL_ENTRIES
) return FALSE
;
545 /* Check if there's no mid-level table */
548 /* Allocate a new mid level table */
549 Mid
= ExpAllocateMidLevelTable(HandleTable
, DoInit
, &Low
);
550 if (!Mid
) return FALSE
;
552 /* Update the table pointer */
553 Value
= InterlockedExchangePointer((PVOID
*)&ThirdLevel
[i
], Mid
);
554 ASSERT(Value
== NULL
);
558 /* We have one, check at which index we should insert our entry */
559 Index
= (HandleTable
->NextHandleNeedingPool
/ SizeOfHandle(1)) -
561 j
= Index
/ LOW_LEVEL_ENTRIES
;
563 /* Allocate a new low level */
564 Low
= ExpAllocateLowLevelTable(HandleTable
, DoInit
);
565 if (!Low
) return FALSE
;
567 /* Update the table pointer */
568 Value
= InterlockedExchangePointer((PVOID
*)&ThirdLevel
[i
][j
], Low
);
569 ASSERT(Value
== NULL
);
574 /* Something is really broken */
578 /* Update the index of the next handle */
579 Index
= InterlockedExchangeAdd((PLONG
) &HandleTable
->NextHandleNeedingPool
,
580 SizeOfHandle(LOW_LEVEL_ENTRIES
));
582 /* Check if need to initialize the table */
585 /* Create a new index number */
586 Index
+= SizeOfHandle(1);
588 /* Start free index change loop */
591 /* Setup the first free index */
592 FirstFree
= HandleTable
->FirstFree
;
593 Low
[LOW_LEVEL_ENTRIES
- 1].NextFreeTableEntry
= FirstFree
;
595 /* Change the index */
596 NewFree
= InterlockedCompareExchange((PLONG
) &HandleTable
->FirstFree
,
599 if (NewFree
== FirstFree
) break;
609 ExpMoveFreeHandles(IN PHANDLE_TABLE HandleTable
)
613 /* Clear the last free index */
614 LastFree
= InterlockedExchange((PLONG
) &HandleTable
->LastFree
, 0);
616 /* Check if we had no index */
617 if (!LastFree
) return LastFree
;
619 /* Acquire the locks we need */
620 for (i
= 1; i
< 4; i
++)
622 /* Acquire this lock exclusively */
623 ExWaitOnPushLock(&HandleTable
->HandleTableLock
[i
]);
626 /* Check if we're not strict FIFO */
627 if (!HandleTable
->StrictFIFO
)
629 /* Update the first free index */
630 if (!InterlockedCompareExchange((PLONG
) &HandleTable
->FirstFree
, LastFree
, 0))
632 /* We're done, exit */
637 /* We are strict FIFO, we need to reverse the entries */
644 ExpAllocateHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
645 OUT PEXHANDLE NewHandle
)
647 ULONG OldValue
, NewValue
, NewValue1
;
648 PHANDLE_TABLE_ENTRY Entry
;
653 /* Start allocation loop */
656 /* Get the current link */
657 OldValue
= HandleTable
->FirstFree
;
660 /* No free entries remain, lock the handle table */
661 KeEnterCriticalRegion();
662 ExAcquirePushLockExclusive(&HandleTable
->HandleTableLock
[0]);
664 /* Check the value again */
665 OldValue
= HandleTable
->FirstFree
;
668 /* Another thread has already created a new level, bail out */
669 ExReleasePushLockExclusive(&HandleTable
->HandleTableLock
[0]);
670 KeLeaveCriticalRegion();
674 /* Now move any free handles */
675 OldValue
= ExpMoveFreeHandles(HandleTable
);
678 /* Another thread has already moved them, bail out */
679 ExReleasePushLockExclusive(&HandleTable
->HandleTableLock
[0]);
680 KeLeaveCriticalRegion();
684 /* We're the first one through, so do the actual allocation */
685 Result
= ExpAllocateHandleTableEntrySlow(HandleTable
, TRUE
);
687 /* Unlock the table and get the value now */
688 ExReleasePushLockExclusive(&HandleTable
->HandleTableLock
[0]);
689 KeLeaveCriticalRegion();
690 OldValue
= HandleTable
->FirstFree
;
692 /* Check if allocation failed */
695 /* Check if nobody else went through here */
698 /* We're still the only thread around, so fail */
699 NewHandle
->GenericHandleOverlay
= NULL
;
705 /* We made it, write the current value */
706 Handle
.Value
= (OldValue
& FREE_HANDLE_MASK
);
708 /* Lookup the entry for this handle */
709 Entry
= ExpLookupHandleTableEntry(HandleTable
, Handle
);
711 /* Get an available lock and acquire it */
712 i
= ((OldValue
& FREE_HANDLE_MASK
) >> 2) % 4;
713 KeEnterCriticalRegion();
714 ExAcquirePushLockShared(&HandleTable
->HandleTableLock
[i
]);
716 /* Check if the value changed after acquiring the lock */
717 if (OldValue
!= *(volatile ULONG
*)&HandleTable
->FirstFree
)
719 /* It did, so try again */
720 ExReleasePushLockShared(&HandleTable
->HandleTableLock
[i
]);
721 KeLeaveCriticalRegion();
725 /* Now get the next value and do the compare */
726 NewValue
= *(volatile ULONG
*)&Entry
->NextFreeTableEntry
;
727 NewValue1
= InterlockedCompareExchange((PLONG
) &HandleTable
->FirstFree
,
731 /* The change was done, so release the lock */
732 ExReleasePushLockShared(&HandleTable
->HandleTableLock
[i
]);
733 KeLeaveCriticalRegion();
735 /* Check if the compare was successful */
736 if (NewValue1
== OldValue
)
738 /* Make sure that the new handle is in range, and break out */
739 ASSERT((NewValue
& FREE_HANDLE_MASK
) <
740 HandleTable
->NextHandleNeedingPool
);
745 /* The compare failed, make sure we expected it */
746 ASSERT((NewValue1
& FREE_HANDLE_MASK
) !=
747 (OldValue
& FREE_HANDLE_MASK
));
751 /* Increase the number of handles */
752 InterlockedIncrement(&HandleTable
->HandleCount
);
754 /* Return the handle and the entry */
761 ExCreateHandleTable(IN PEPROCESS Process OPTIONAL
)
763 PHANDLE_TABLE HandleTable
;
766 /* Allocate the handle table */
767 HandleTable
= ExpAllocateHandleTable(Process
, TRUE
);
768 if (!HandleTable
) return NULL
;
770 /* Acquire the handle table lock */
771 KeEnterCriticalRegion();
772 ExAcquirePushLockExclusive(&HandleTableListLock
);
774 /* Insert it into the list */
775 InsertTailList(&HandleTableListHead
, &HandleTable
->HandleTableList
);
777 /* Release the lock */
778 ExReleasePushLockExclusive(&HandleTableListLock
);
779 KeLeaveCriticalRegion();
781 /* Return the handle table */
787 ExCreateHandle(IN PHANDLE_TABLE HandleTable
,
788 IN PHANDLE_TABLE_ENTRY HandleTableEntry
)
791 PHANDLE_TABLE_ENTRY NewEntry
;
794 /* Start with a clean handle */
795 Handle
.GenericHandleOverlay
= NULL
;
797 /* Allocate a new entry */
798 NewEntry
= ExpAllocateHandleTableEntry(HandleTable
, &Handle
);
801 /* Enter a critical region */
802 KeEnterCriticalRegion();
804 /* Write the entry */
805 *NewEntry
= *HandleTableEntry
;
807 /* Unlock it and leave the critical region */
808 ExUnlockHandleTableEntry(HandleTable
, NewEntry
);
809 KeLeaveCriticalRegion();
812 /* Return the handle value */
813 return Handle
.GenericHandleOverlay
;
818 ExpBlockOnLockedHandleEntry(IN PHANDLE_TABLE HandleTable
,
819 IN PHANDLE_TABLE_ENTRY HandleTableEntry
)
822 EX_PUSH_LOCK_WAIT_BLOCK WaitBlock
;
824 /* Block on the pushlock */
825 ExBlockPushLock(&HandleTable
->HandleContentionEvent
, &WaitBlock
);
827 /* Get the current value and check if it's been unlocked */
828 OldValue
= HandleTableEntry
->Value
;
829 if (!(OldValue
) || (OldValue
& EXHANDLE_TABLE_ENTRY_LOCK_BIT
))
831 /* Unblock the pushlock and return */
832 ExfUnblockPushLock(&HandleTable
->HandleContentionEvent
, &WaitBlock
);
836 /* Wait for it to be unblocked */
837 ExWaitForUnblockPushLock(&HandleTable
->HandleContentionEvent
,
844 ExpLockHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
845 IN PHANDLE_TABLE_ENTRY HandleTableEntry
)
847 LONG_PTR NewValue
, OldValue
;
850 ASSERT((KeGetCurrentThread()->CombinedApcDisable
!= 0) ||
851 (KeGetCurrentIrql() == APC_LEVEL
));
853 /* Start lock loop */
856 /* Get the current value and check if it's locked */
857 OldValue
= *(volatile LONG_PTR
*)&HandleTableEntry
->Object
;
858 if (OldValue
& EXHANDLE_TABLE_ENTRY_LOCK_BIT
)
860 /* It's not locked, remove the lock bit to lock it */
861 NewValue
= OldValue
& ~EXHANDLE_TABLE_ENTRY_LOCK_BIT
;
862 if (InterlockedCompareExchangePointer(&HandleTableEntry
->Object
,
864 (PVOID
)OldValue
) == (PVOID
)OldValue
)
866 /* We locked it, get out */
872 /* We couldn't lock it, bail out if it's been freed */
873 if (!OldValue
) return FALSE
;
876 /* It's locked, wait for it to be unlocked */
877 ExpBlockOnLockedHandleEntry(HandleTable
, HandleTableEntry
);
883 ExUnlockHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
884 IN PHANDLE_TABLE_ENTRY HandleTableEntry
)
890 ASSERT((KeGetCurrentThread()->CombinedApcDisable
!= 0) ||
891 (KeGetCurrentIrql() == APC_LEVEL
));
893 /* Set the lock bit and make sure it wasn't earlier */
894 OldValue
= InterlockedOr((PLONG
) &HandleTableEntry
->Value
,
895 EXHANDLE_TABLE_ENTRY_LOCK_BIT
);
896 ASSERT((OldValue
& EXHANDLE_TABLE_ENTRY_LOCK_BIT
) == 0);
898 /* Unblock any waiters */
899 ExfUnblockPushLock(&HandleTable
->HandleContentionEvent
, NULL
);
904 ExRemoveHandleTable(IN PHANDLE_TABLE HandleTable
)
908 /* Acquire the table lock */
909 KeEnterCriticalRegion();
910 ExAcquirePushLockExclusive(&HandleTableListLock
);
912 /* Remove the table and reset the list */
913 RemoveEntryList(&HandleTable
->HandleTableList
);
914 InitializeListHead(&HandleTable
->HandleTableList
);
916 /* Release the lock */
917 ExReleasePushLockExclusive(&HandleTableListLock
);
918 KeLeaveCriticalRegion();
923 ExDestroyHandleTable(IN PHANDLE_TABLE HandleTable
,
924 IN PVOID DestroyHandleProcedure OPTIONAL
)
928 /* Remove the handle from the list */
929 ExRemoveHandleTable(HandleTable
);
931 /* Check if we have a destroy callback */
932 if (DestroyHandleProcedure
)
938 /* Free the handle table */
939 ExpFreeHandleTable(HandleTable
);
944 ExDestroyHandle(IN PHANDLE_TABLE HandleTable
,
946 IN PHANDLE_TABLE_ENTRY HandleTableEntry OPTIONAL
)
952 /* Setup the actual handle value */
953 ExHandle
.GenericHandleOverlay
= Handle
;
955 /* Enter a critical region and check if we have to lookup the handle */
956 KeEnterCriticalRegion();
957 if (!HandleTableEntry
)
959 /* Lookup the entry */
960 HandleTableEntry
= ExpLookupHandleTableEntry(HandleTable
, ExHandle
);
962 /* Make sure that we found an entry, and that it's valid */
963 if (!(HandleTableEntry
) ||
964 !(HandleTableEntry
->Object
) ||
965 (HandleTableEntry
->NextFreeTableEntry
== -2))
967 /* Invalid handle, fail */
968 KeLeaveCriticalRegion();
973 if (!ExpLockHandleTableEntry(HandleTable
, HandleTableEntry
))
975 /* Couldn't lock, fail */
976 KeLeaveCriticalRegion();
982 /* Make sure the handle is locked */
983 ASSERT((HandleTableEntry
->Value
& EXHANDLE_TABLE_ENTRY_LOCK_BIT
) == 0);
986 /* Clear the handle */
987 Object
= InterlockedExchangePointer((PVOID
*)&HandleTableEntry
->Object
, NULL
);
990 ASSERT(Object
!= NULL
);
991 ASSERT((((ULONG_PTR
)Object
) & EXHANDLE_TABLE_ENTRY_LOCK_BIT
) == 0);
993 /* Unblock the pushlock */
994 ExfUnblockPushLock(&HandleTable
->HandleContentionEvent
, NULL
);
996 /* Free the actual entry */
997 ExpFreeHandleTableEntry(HandleTable
, ExHandle
, HandleTableEntry
);
999 /* If we got here, return success */
1000 KeLeaveCriticalRegion();
1006 ExMapHandleToPointer(IN PHANDLE_TABLE HandleTable
,
1010 PHANDLE_TABLE_ENTRY HandleTableEntry
;
1013 /* Set the handle value */
1014 ExHandle
.GenericHandleOverlay
= Handle
;
1016 /* Fail if we got an invalid index */
1017 if (!(ExHandle
.Index
& (LOW_LEVEL_ENTRIES
- 1))) return NULL
;
1020 HandleTableEntry
= ExpLookupHandleTableEntry(HandleTable
, ExHandle
);
1021 if (!HandleTableEntry
) return NULL
;
1024 if (!ExpLockHandleTableEntry(HandleTable
, HandleTableEntry
)) return NULL
;
1026 /* Return the entry */
1027 return HandleTableEntry
;
1032 ExDupHandleTable(IN PEPROCESS Process
,
1033 IN PHANDLE_TABLE HandleTable
,
1034 IN PEX_DUPLICATE_HANDLE_CALLBACK DupHandleProcedure
,
1037 PHANDLE_TABLE NewTable
;
1039 PHANDLE_TABLE_ENTRY HandleTableEntry
, NewEntry
;
1040 BOOLEAN Failed
= FALSE
;
1043 /* Allocate the duplicated copy */
1044 NewTable
= ExpAllocateHandleTable(Process
, FALSE
);
1045 if (!NewTable
) return NULL
;
1047 /* Loop each entry */
1048 while (NewTable
->NextHandleNeedingPool
<
1049 HandleTable
->NextHandleNeedingPool
)
1051 /* Insert it into the duplicated copy */
1052 if (!ExpAllocateHandleTableEntrySlow(NewTable
, FALSE
))
1054 /* Insert failed, free the new copy and return */
1055 ExpFreeHandleTable(NewTable
);
1060 /* Setup the initial handle table data */
1061 NewTable
->HandleCount
= 0;
1062 NewTable
->ExtraInfoPages
= 0;
1063 NewTable
->FirstFree
= 0;
1065 /* Setup the first handle value */
1066 Handle
.Value
= SizeOfHandle(1);
1068 /* Enter a critical region and lookup the new entry */
1069 KeEnterCriticalRegion();
1070 while ((NewEntry
= ExpLookupHandleTableEntry(NewTable
, Handle
)))
1072 /* Lookup the old entry */
1073 HandleTableEntry
= ExpLookupHandleTableEntry(HandleTable
, Handle
);
1075 /* Loop each entry */
1078 /* Check if it doesn't match the audit mask */
1079 if (!(HandleTableEntry
->Value
& Mask
))
1081 /* Free it since we won't use it */
1086 /* Lock the entry */
1087 if (!ExpLockHandleTableEntry(HandleTable
, HandleTableEntry
))
1089 /* Free it since we can't lock it, so we won't use it */
1094 /* Copy the handle value */
1095 *NewEntry
= *HandleTableEntry
;
1097 /* Call the duplicate callback */
1098 if (DupHandleProcedure(Process
,
1103 /* Clear failure flag */
1106 /* Lock the entry, increase the handle count */
1107 NewEntry
->Value
|= EXHANDLE_TABLE_ENTRY_LOCK_BIT
;
1108 NewTable
->HandleCount
++;
1112 /* Duplication callback refused, fail */
1118 /* Check if we failed earlier and need to free */
1121 /* Free this entry */
1122 NewEntry
->Object
= NULL
;
1123 NewEntry
->NextFreeTableEntry
= NewTable
->FirstFree
;
1124 NewTable
->FirstFree
= (ULONG
)Handle
.Value
;
1127 /* Increase the handle value and move to the next entry */
1128 Handle
.Value
+= SizeOfHandle(1);
1131 } while (Handle
.Value
% SizeOfHandle(LOW_LEVEL_ENTRIES
));
1133 /* We're done, skip the last entry */
1134 Handle
.Value
+= SizeOfHandle(1);
1137 /* Acquire the table lock and insert this new table into the list */
1138 ExAcquirePushLockExclusive(&HandleTableListLock
);
1139 InsertTailList(&HandleTableListHead
, &NewTable
->HandleTableList
);
1140 ExReleasePushLockExclusive(&HandleTableListLock
);
1142 /* Leave the critical region we entered previously and return the table */
1143 KeLeaveCriticalRegion();
1149 ExChangeHandle(IN PHANDLE_TABLE HandleTable
,
1151 IN PEX_CHANGE_HANDLE_CALLBACK ChangeRoutine
,
1152 IN ULONG_PTR Context
)
1155 PHANDLE_TABLE_ENTRY HandleTableEntry
;
1156 BOOLEAN Result
= FALSE
;
1159 /* Set the handle value */
1160 ExHandle
.GenericHandleOverlay
= Handle
;
1162 /* Find the entry for this handle */
1163 HandleTableEntry
= ExpLookupHandleTableEntry(HandleTable
, ExHandle
);
1165 /* Make sure that we found an entry, and that it's valid */
1166 if (!(HandleTableEntry
) ||
1167 !(HandleTableEntry
->Object
) ||
1168 (HandleTableEntry
->NextFreeTableEntry
== -2))
1170 /* It isn't, fail */
1174 /* Enter a critical region */
1175 KeEnterCriticalRegion();
1177 /* Try locking the handle entry */
1178 if (ExpLockHandleTableEntry(HandleTable
, HandleTableEntry
))
1180 /* Call the change routine and unlock the entry */
1181 Result
= ChangeRoutine(HandleTableEntry
, Context
);
1182 ExUnlockHandleTableEntry(HandleTable
, HandleTableEntry
);
1185 /* Leave the critical region and return the callback result */
1186 KeLeaveCriticalRegion();
1192 ExSweepHandleTable(IN PHANDLE_TABLE HandleTable
,
1193 IN PEX_SWEEP_HANDLE_CALLBACK EnumHandleProcedure
,
1197 PHANDLE_TABLE_ENTRY HandleTableEntry
;
1200 /* Set the initial value and loop the entries */
1201 Handle
.Value
= SizeOfHandle(1);
1202 while ((HandleTableEntry
= ExpLookupHandleTableEntry(HandleTable
, Handle
)))
1204 /* Loop each handle */
1207 /* Lock the entry */
1208 if (ExpLockHandleTableEntry(HandleTable
, HandleTableEntry
))
1210 /* Notify the callback routine */
1211 EnumHandleProcedure(HandleTableEntry
,
1212 Handle
.GenericHandleOverlay
,
1216 /* Go to the next handle and entry */
1217 Handle
.Value
+= SizeOfHandle(1);
1219 } while (Handle
.Value
% SizeOfHandle(LOW_LEVEL_ENTRIES
));
1221 /* Skip past the last entry */
1222 Handle
.Value
+= SizeOfHandle(1);
1231 ExEnumHandleTable(IN PHANDLE_TABLE HandleTable
,
1232 IN PEX_ENUM_HANDLE_CALLBACK EnumHandleProcedure
,
1233 IN OUT PVOID Context
,
1234 OUT PHANDLE EnumHandle OPTIONAL
)
1237 PHANDLE_TABLE_ENTRY HandleTableEntry
;
1238 BOOLEAN Result
= FALSE
;
1241 /* Enter a critical region */
1242 KeEnterCriticalRegion();
1244 /* Set the initial value and loop the entries */
1246 while ((HandleTableEntry
= ExpLookupHandleTableEntry(HandleTable
, Handle
)))
1248 /* Validate the entry */
1249 if ((HandleTableEntry
) &&
1250 (HandleTableEntry
->Object
) &&
1251 (HandleTableEntry
->NextFreeTableEntry
!= -2))
1253 /* Lock the entry */
1254 if (ExpLockHandleTableEntry(HandleTable
, HandleTableEntry
))
1256 /* Notify the callback routine */
1257 Result
= EnumHandleProcedure(HandleTableEntry
,
1258 Handle
.GenericHandleOverlay
,
1262 ExUnlockHandleTableEntry(HandleTable
, HandleTableEntry
);
1264 /* Was this the one looked for? */
1267 /* If so, return it if requested */
1268 if (EnumHandle
) *EnumHandle
= Handle
.GenericHandleOverlay
;
1274 /* Go to the next entry */
1275 Handle
.Value
+= SizeOfHandle(1);
1278 /* Leave the critical region and return callback result */
1279 KeLeaveCriticalRegion();