2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ex/init.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 *********************************************************/
26 ExpInitializeHandleTables(VOID
)
28 /* Initialize the list of handle tables and the lock */
29 InitializeListHead(&HandleTableListHead
);
30 ExInitializePushLock((PULONG_PTR
)&HandleTableListLock
);
35 ExpLookupHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
36 IN EXHANDLE LookupHandle
)
38 ULONG i
, j
, k
, TableLevel
, NextHandle
;
40 PHANDLE_TABLE_ENTRY Entry
= NULL
;
41 EXHANDLE Handle
= LookupHandle
;
42 PUCHAR Level1
, Level2
, Level3
;
44 /* Clear the tag bits and check what the next handle is */
46 NextHandle
= *(volatile ULONG
*)&HandleTable
->NextHandleNeedingPool
;
47 if (Handle
.Value
>= NextHandle
) return NULL
;
49 /* Get the table code */
50 TableBase
= *(volatile ULONG_PTR
*)&HandleTable
->TableCode
;
52 /* Extract the table level and actual table base */
53 TableLevel
= (ULONG
)(TableBase
& 3);
54 TableBase
= TableBase
- TableLevel
;
56 /* Check what level we're running at */
62 /* Use level 1 and just get the entry directly */
63 Level1
= (PUCHAR
)TableBase
;
64 Entry
= (PVOID
)&Level1
[Handle
.Value
*
65 (sizeof(HANDLE_TABLE_ENTRY
) /
69 /* Nested index into mid level */
72 /* Get the second table and index into it */
73 Level2
= (PUCHAR
)TableBase
;
74 i
= Handle
.Value
% SizeOfHandle(LOW_LEVEL_ENTRIES
);
76 /* Substract this index, and get the next one */
79 (SizeOfHandle(LOW_LEVEL_ENTRIES
) / sizeof(PHANDLE_TABLE_ENTRY
));
81 /* Now get the next table and get the entry from it */
82 Level1
= (PUCHAR
)*(PHANDLE_TABLE_ENTRY
*)&Level2
[j
];
83 Entry
= (PVOID
)&Level1
[i
*
84 (sizeof(HANDLE_TABLE_ENTRY
) /
88 /* Nested index into high level */
91 /* Start with the 3rd level table */
92 Level3
= (PUCHAR
)TableBase
;
93 i
= Handle
.Value
% SizeOfHandle(LOW_LEVEL_ENTRIES
);
95 /* Subtract this index and get the index for the next lower table */
98 (SizeOfHandle(LOW_LEVEL_ENTRIES
) / sizeof(PHANDLE_TABLE_ENTRY
));
100 /* Get the remaining index in the 2nd level table */
101 j
= k
% (MID_LEVEL_ENTRIES
* sizeof(PHANDLE_TABLE_ENTRY
));
103 /* Get the remaining index, which is in the third table */
105 k
/= MID_LEVEL_ENTRIES
;
107 /* Extract the table level for the handle in each table */
108 Level2
= (PUCHAR
)*(PHANDLE_TABLE_ENTRY
*)&Level3
[k
];
109 Level1
= (PUCHAR
)*(PHANDLE_TABLE_ENTRY
*)&Level2
[j
];
111 /* Get the handle table entry */
112 Entry
= (PVOID
)&Level1
[i
*
113 (sizeof(HANDLE_TABLE_ENTRY
) /
122 /* Return the handle entry */
128 ExpAllocateTablePagedPool(IN PEPROCESS Process OPTIONAL
,
133 /* Do the allocation */
134 Buffer
= ExAllocatePoolWithTag(PagedPool
, Size
, 'btbO');
137 /* Clear the memory */
138 RtlZeroMemory(Buffer
, Size
);
140 /* Check if we have a process to charge quota */
143 /* FIXME: Charge quota */
147 /* Return the allocated memory */
153 ExpAllocateTablePagedPoolNoZero(IN PEPROCESS Process OPTIONAL
,
158 /* Do the allocation */
159 Buffer
= ExAllocatePoolWithTag(PagedPool
, Size
, 'btbO');
162 /* Check if we have a process to charge quota */
165 /* FIXME: Charge quota */
169 /* Return the allocated memory */
175 ExpFreeTablePagedPool(IN PEPROCESS Process OPTIONAL
,
179 /* Free the buffer */
183 /* FIXME: Release quota */
189 ExpFreeLowLevelTable(IN PEPROCESS Process
,
190 IN PHANDLE_TABLE_ENTRY TableEntry
)
192 /* Check if we have an entry */
193 if (TableEntry
[0].Object
)
196 ExpFreeTablePagedPool(Process
,
197 TableEntry
[0].Object
,
199 sizeof(HANDLE_TABLE_ENTRY_INFO
));
203 ExpFreeTablePagedPool(Process
, TableEntry
, PAGE_SIZE
);
208 ExpFreeHandleTable(IN PHANDLE_TABLE HandleTable
)
210 PEPROCESS Process
= HandleTable
->QuotaProcess
;
212 ULONG_PTR TableCode
= HandleTable
->TableCode
;
213 ULONG_PTR TableBase
= TableCode
& ~3;
214 ULONG TableLevel
= (ULONG
)(TableCode
& 3);
215 PHANDLE_TABLE_ENTRY Level1
, *Level2
, **Level3
;
218 /* Check which level we're at */
221 /* Select the first level table base and just free it */
222 Level1
= (PVOID
)TableBase
;
223 ExpFreeLowLevelTable(Process
, Level1
);
225 else if (TableLevel
== 1)
227 /* Select the second level table base */
228 Level2
= (PVOID
)TableBase
;
230 /* Loop each mid level entry */
231 for (i
= 0; i
< MID_LEVEL_ENTRIES
; i
++)
233 /* Leave if we've reached the last entry */
234 if (!Level2
[i
]) break;
236 /* Free the second level table */
237 ExpFreeLowLevelTable(Process
, Level2
[i
]);
240 /* Free the second level table */
241 ExpFreeTablePagedPool(Process
, Level2
, PAGE_SIZE
);
245 /* Select the third level table base */
246 Level3
= (PVOID
)TableBase
;
248 /* Loop each high level entry */
249 for (i
= 0; i
< HIGH_LEVEL_ENTRIES
; i
++)
251 /* Leave if we've reached the last entry */
252 if (!Level3
[i
]) break;
254 /* Loop each mid level entry */
255 for (j
= 0; j
< MID_LEVEL_ENTRIES
; j
++)
257 /* Leave if we've reached the last entry */
258 if (!Level3
[i
][j
]) break;
260 /* Free the second level table */
261 ExpFreeLowLevelTable(Process
, Level3
[i
][j
]);
264 /* Free the third level table entry */
265 ExpFreeTablePagedPool(Process
, Level3
[i
], PAGE_SIZE
);
268 /* Free the third level table */
269 ExpFreeTablePagedPool(Process
,
271 SizeOfHandle(HIGH_LEVEL_ENTRIES
));
274 /* Free the actual table and check if we need to release quota */
275 ExFreePool(HandleTable
);
284 ExpFreeHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
286 IN PHANDLE_TABLE_ENTRY HandleTableEntry
)
288 ULONG OldValue
, NewValue
, *Free
;
293 ASSERT(HandleTableEntry
->Object
== NULL
);
294 ASSERT(HandleTableEntry
== ExpLookupHandleTableEntry(HandleTable
, Handle
));
296 /* Decrement the handle count */
297 InterlockedDecrement(&HandleTable
->HandleCount
);
299 /* Mark the handle as free */
300 NewValue
= (ULONG
)Handle
.Value
& ~(SizeOfHandle(1) - 1);
302 /* Check if we're FIFO */
303 if (!HandleTable
->StrictFIFO
)
305 /* Select a lock index */
306 i
= (NewValue
>> 2) % 4;
308 /* Select which entry to use */
309 Free
= (HandleTable
->HandleTableLock
[i
].Locked
) ?
310 &HandleTable
->FirstFree
: &HandleTable
->LastFree
;
314 /* No need to worry about locking, take the last entry */
315 Free
= &HandleTable
->LastFree
;
318 /* Start value change loop */
321 /* Get the current value and write */
323 HandleTableEntry
->NextFreeTableEntry
= (ULONG
)OldValue
;
324 if (InterlockedCompareExchange((PLONG
) Free
, NewValue
, OldValue
) == OldValue
)
326 /* Break out, we're done. Make sure the handle value makes sense */
327 ASSERT((OldValue
& FREE_HANDLE_MASK
) <
328 HandleTable
->NextHandleNeedingPool
);
336 ExpAllocateHandleTable(IN PEPROCESS Process OPTIONAL
,
339 PHANDLE_TABLE HandleTable
;
340 PHANDLE_TABLE_ENTRY HandleTableTable
, HandleEntry
;
344 /* Allocate the table */
345 HandleTable
= ExAllocatePoolWithTag(PagedPool
,
346 sizeof(HANDLE_TABLE
),
348 if (!HandleTable
) return NULL
;
350 /* Check if we have a process */
353 /* FIXME: Charge quota */
356 /* Clear the table */
357 RtlZeroMemory(HandleTable
, sizeof(HANDLE_TABLE
));
359 /* Now allocate the first level structures */
360 HandleTableTable
= ExpAllocateTablePagedPoolNoZero(Process
, PAGE_SIZE
);
361 if (!HandleTableTable
)
363 /* Failed, free the table */
364 ExFreePool(HandleTable
);
368 /* Write the pointer to our first level structures */
369 HandleTable
->TableCode
= (ULONG_PTR
)HandleTableTable
;
371 /* Initialize the first entry */
372 HandleEntry
= &HandleTableTable
[0];
373 HandleEntry
->NextFreeTableEntry
= -2;
374 HandleEntry
->Value
= 0;
376 /* Check if this is a new table */
379 /* Go past the root entry */
382 /* Loop every low level entry */
383 for (i
= 1; i
< (LOW_LEVEL_ENTRIES
- 1); i
++)
385 /* Set up the free data */
386 HandleEntry
->Value
= 0;
387 HandleEntry
->NextFreeTableEntry
= (i
+ 1) * SizeOfHandle(1);
389 /* Move to the next entry */
393 /* Terminate the last entry */
394 HandleEntry
->Value
= 0;
395 HandleEntry
->NextFreeTableEntry
= 0;
396 HandleTable
->FirstFree
= SizeOfHandle(1);
399 /* Set the next handle needing pool after our allocated page from above */
400 HandleTable
->NextHandleNeedingPool
= LOW_LEVEL_ENTRIES
* SizeOfHandle(1);
402 /* Setup the rest of the handle table data */
403 HandleTable
->QuotaProcess
= Process
;
404 HandleTable
->UniqueProcessId
= PsGetCurrentProcess()->UniqueProcessId
;
405 HandleTable
->Flags
= 0;
407 /* Loop all the handle table locks */
408 for (i
= 0; i
< 4; i
++)
410 /* Initialize the handle table lock */
411 ExInitializePushLock((PULONG_PTR
)&HandleTable
->HandleTableLock
[i
]);
414 /* Initialize the contention event lock and return the lock */
415 ExInitializePushLock((PULONG_PTR
)&HandleTable
->HandleContentionEvent
);
421 ExpAllocateLowLevelTable(IN PHANDLE_TABLE HandleTable
,
425 PHANDLE_TABLE_ENTRY Low
, HandleEntry
;
427 /* Allocate the low level table */
428 Low
= ExpAllocateTablePagedPoolNoZero(HandleTable
->QuotaProcess
,
430 if (!Low
) return NULL
;
432 /* Setup the initial entry */
433 HandleEntry
= &Low
[0];
434 HandleEntry
->NextFreeTableEntry
= -2;
435 HandleEntry
->Value
= 0;
437 /* Check if we're initializing */
440 /* Go to the next entry and the base entry */
442 Base
= HandleTable
->NextHandleNeedingPool
+ SizeOfHandle(2);
444 /* Loop each entry */
446 i
< Base
+ SizeOfHandle(LOW_LEVEL_ENTRIES
- 2);
447 i
+= SizeOfHandle(1))
449 /* Free this entry and move on to the next one */
450 HandleEntry
->NextFreeTableEntry
= i
;
451 HandleEntry
->Value
= 0;
455 /* Terminate the last entry */
456 HandleEntry
->NextFreeTableEntry
= 0;
457 HandleEntry
->Value
= 0;
460 /* Return the low level table */
466 ExpAllocateMidLevelTable(IN PHANDLE_TABLE HandleTable
,
468 OUT PHANDLE_TABLE_ENTRY
*LowTableEntry
)
470 PHANDLE_TABLE_ENTRY
*Mid
, Low
;
472 /* Allocate the mid level table */
473 Mid
= ExpAllocateTablePagedPool(HandleTable
->QuotaProcess
, PAGE_SIZE
);
474 if (!Mid
) return NULL
;
476 /* Allocate a new low level for it */
477 Low
= ExpAllocateLowLevelTable(HandleTable
, DoInit
);
480 /* We failed, free the mid table */
481 ExpFreeTablePagedPool(HandleTable
->QuotaProcess
, Mid
, PAGE_SIZE
);
485 /* Link the tables and return the pointer */
487 *LowTableEntry
= Low
;
493 ExpAllocateHandleTableEntrySlow(IN PHANDLE_TABLE HandleTable
,
497 PHANDLE_TABLE_ENTRY Low
= NULL
, *Mid
, **High
, *SecondLevel
, **ThirdLevel
;
498 ULONG NewFree
, FirstFree
;
500 ULONG_PTR TableCode
= HandleTable
->TableCode
;
501 ULONG_PTR TableBase
= TableCode
& ~3;
502 ULONG TableLevel
= (ULONG
)(TableCode
& 3);
505 /* Check how many levels we already have */
508 /* Allocate a mid level, since we only have a low level */
509 Mid
= ExpAllocateMidLevelTable(HandleTable
, DoInit
, &Low
);
510 if (!Mid
) return FALSE
;
512 /* Link up the tables */
514 Mid
[0] = (PVOID
)TableBase
;
516 /* Write the new level and attempt to change the table code */
517 TableBase
= ((ULONG_PTR
)Mid
) | 1;
518 Value
= InterlockedExchangePointer((PVOID
*)&HandleTable
->TableCode
, (PVOID
)TableBase
);
520 else if (TableLevel
== 1)
522 /* Setup the 2nd level table */
523 SecondLevel
= (PVOID
)TableBase
;
525 /* Get if the next index can fit in the table */
526 i
= HandleTable
->NextHandleNeedingPool
/
527 SizeOfHandle(LOW_LEVEL_ENTRIES
);
528 if (i
< MID_LEVEL_ENTRIES
)
530 /* We need to allocate a new table */
531 Low
= ExpAllocateLowLevelTable(HandleTable
, DoInit
);
532 if (!Low
) return FALSE
;
534 /* Update the table */
535 Value
= InterlockedExchangePointer((PVOID
*)&SecondLevel
[i
], Low
);
536 ASSERT(Value
== NULL
);
540 /* We need a new high level table */
541 High
= ExpAllocateTablePagedPool(HandleTable
->QuotaProcess
,
542 SizeOfHandle(HIGH_LEVEL_ENTRIES
));
543 if (!High
) return FALSE
;
545 /* Allocate a new mid level table as well */
546 Mid
= ExpAllocateMidLevelTable(HandleTable
, DoInit
, &Low
);
549 /* We failed, free the high level table as welll */
550 ExpFreeTablePagedPool(HandleTable
->QuotaProcess
,
552 SizeOfHandle(HIGH_LEVEL_ENTRIES
));
556 /* Link up the tables */
557 High
[0] = (PVOID
)TableBase
;
560 /* Write the new table and change the table code */
561 TableBase
= ((ULONG_PTR
)High
) | 2;
562 Value
= InterlockedExchangePointer((PVOID
*)&HandleTable
->TableCode
,
566 else if (TableLevel
== 2)
568 /* Setup the 3rd level table */
569 ThirdLevel
= (PVOID
)TableBase
;
571 /* Get the index and check if it can fit */
572 i
= HandleTable
->NextHandleNeedingPool
/ SizeOfHandle(MAX_MID_INDEX
);
573 if (i
>= HIGH_LEVEL_ENTRIES
) return FALSE
;
575 /* Check if there's no mid-level table */
578 /* Allocate a new mid level table */
579 Mid
= ExpAllocateMidLevelTable(HandleTable
, DoInit
, &Low
);
580 if (!Mid
) return FALSE
;
582 /* Update the table pointer */
583 Value
= InterlockedExchangePointer((PVOID
*)&ThirdLevel
[i
], Mid
);
584 ASSERT(Value
== NULL
);
588 /* We have one, check at which index we should insert our entry */
589 Index
= (HandleTable
->NextHandleNeedingPool
/ SizeOfHandle(1)) -
591 j
= Index
/ LOW_LEVEL_ENTRIES
;
593 /* Allocate a new low level */
594 Low
= ExpAllocateLowLevelTable(HandleTable
, DoInit
);
595 if (!Low
) return FALSE
;
597 /* Update the table pointer */
598 Value
= InterlockedExchangePointer((PVOID
*)&ThirdLevel
[i
][j
], Low
);
599 ASSERT(Value
== NULL
);
603 /* Update the index of the next handle */
604 Index
= InterlockedExchangeAdd((PLONG
) &HandleTable
->NextHandleNeedingPool
,
605 SizeOfHandle(LOW_LEVEL_ENTRIES
));
607 /* Check if need to initialize the table */
610 /* Create a new index number */
611 Index
+= SizeOfHandle(1);
613 /* Start free index change loop */
616 /* Setup the first free index */
617 FirstFree
= HandleTable
->FirstFree
;
618 Low
[LOW_LEVEL_ENTRIES
- 1].NextFreeTableEntry
= FirstFree
;
620 /* Change the index */
621 NewFree
= InterlockedCompareExchange((PLONG
) &HandleTable
->FirstFree
,
624 if (NewFree
== FirstFree
) break;
634 ExpMoveFreeHandles(IN PHANDLE_TABLE HandleTable
)
638 /* Clear the last free index */
639 LastFree
= InterlockedExchange((PLONG
) &HandleTable
->LastFree
, 0);
641 /* Check if we had no index */
642 if (!LastFree
) return LastFree
;
644 /* Acquire the locks we need */
645 for (i
= 1; i
< 4; i
++)
647 /* Acquire this lock exclusively */
648 ExWaitOnPushLock(&HandleTable
->HandleTableLock
[i
]);
651 /* Check if we're not strict FIFO */
652 if (!HandleTable
->StrictFIFO
)
654 /* Update the first free index */
655 if (!InterlockedCompareExchange((PLONG
) &HandleTable
->FirstFree
, LastFree
, 0))
657 /* We're done, exit */
662 /* We are strict FIFO, we need to reverse the entries */
669 ExpAllocateHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
670 OUT PEXHANDLE NewHandle
)
672 ULONG OldValue
, NewValue
, NewValue1
;
673 PHANDLE_TABLE_ENTRY Entry
;
678 /* Start allocation loop */
681 /* Get the current link */
682 OldValue
= HandleTable
->FirstFree
;
685 /* No free entries remain, lock the handle table */
686 KeEnterCriticalRegion();
687 ExAcquirePushLockExclusive(&HandleTable
->HandleTableLock
[0]);
689 /* Check the value again */
690 OldValue
= HandleTable
->FirstFree
;
693 /* Another thread has already created a new level, bail out */
694 ExReleasePushLockExclusive(&HandleTable
->HandleTableLock
[0]);
695 KeLeaveCriticalRegion();
699 /* Now move any free handles */
700 OldValue
= ExpMoveFreeHandles(HandleTable
);
703 /* Another thread has already moved them, bail out */
704 ExReleasePushLockExclusive(&HandleTable
->HandleTableLock
[0]);
705 KeLeaveCriticalRegion();
709 /* We're the first one through, so do the actual allocation */
710 Result
= ExpAllocateHandleTableEntrySlow(HandleTable
, TRUE
);
712 /* Unlock the table and get the value now */
713 ExReleasePushLockExclusive(&HandleTable
->HandleTableLock
[0]);
714 KeLeaveCriticalRegion();
715 OldValue
= HandleTable
->FirstFree
;
717 /* Check if allocation failed */
720 /* Check if nobody else went through here */
723 /* We're still the only thread around, so fail */
724 NewHandle
->GenericHandleOverlay
= NULL
;
730 /* We made it, write the current value */
731 Handle
.Value
= (OldValue
& FREE_HANDLE_MASK
);
733 /* Lookup the entry for this handle */
734 Entry
= ExpLookupHandleTableEntry(HandleTable
, Handle
);
736 /* Get an available lock and acquire it */
737 i
= ((OldValue
& FREE_HANDLE_MASK
) >> 2) % 4;
738 KeEnterCriticalRegion();
739 ExAcquirePushLockShared(&HandleTable
->HandleTableLock
[i
]);
741 /* Check if the value changed after acquiring the lock */
742 if (OldValue
!= *(volatile ULONG
*)&HandleTable
->FirstFree
)
744 /* It did, so try again */
745 ExReleasePushLockShared(&HandleTable
->HandleTableLock
[i
]);
746 KeLeaveCriticalRegion();
750 /* Now get the next value and do the compare */
751 NewValue
= *(volatile ULONG
*)&Entry
->NextFreeTableEntry
;
752 NewValue1
= InterlockedCompareExchange((PLONG
) &HandleTable
->FirstFree
,
756 /* The change was done, so release the lock */
757 ExReleasePushLockShared(&HandleTable
->HandleTableLock
[i
]);
758 KeLeaveCriticalRegion();
760 /* Check if the compare was successful */
761 if (NewValue1
== OldValue
)
763 /* Make sure that the new handle is in range, and break out */
764 ASSERT((NewValue
& FREE_HANDLE_MASK
) <
765 HandleTable
->NextHandleNeedingPool
);
770 /* The compare failed, make sure we expected it */
771 ASSERT((NewValue1
& FREE_HANDLE_MASK
) !=
772 (OldValue
& FREE_HANDLE_MASK
));
776 /* Increase the number of handles */
777 InterlockedIncrement(&HandleTable
->HandleCount
);
779 /* Return the handle and the entry */
786 ExCreateHandleTable(IN PEPROCESS Process OPTIONAL
)
788 PHANDLE_TABLE HandleTable
;
791 /* Allocate the handle table */
792 HandleTable
= ExpAllocateHandleTable(Process
, TRUE
);
793 if (!HandleTable
) return NULL
;
795 /* Acquire the handle table lock */
796 KeEnterCriticalRegion();
797 ExAcquirePushLockExclusive(&HandleTableListLock
);
799 /* Insert it into the list */
800 InsertTailList(&HandleTableListHead
, &HandleTable
->HandleTableList
);
802 /* Release the lock */
803 ExReleasePushLockExclusive(&HandleTableListLock
);
804 KeLeaveCriticalRegion();
806 /* Return the handle table */
812 ExCreateHandle(IN PHANDLE_TABLE HandleTable
,
813 IN PHANDLE_TABLE_ENTRY HandleTableEntry
)
816 PHANDLE_TABLE_ENTRY NewEntry
;
819 /* Start with a clean handle */
820 Handle
.GenericHandleOverlay
= NULL
;
822 /* Allocate a new entry */
823 NewEntry
= ExpAllocateHandleTableEntry(HandleTable
, &Handle
);
826 /* Enter a critical region */
827 KeEnterCriticalRegion();
829 /* Write the entry */
830 *NewEntry
= *HandleTableEntry
;
832 /* Unlock it and leave the critical region */
833 ExUnlockHandleTableEntry(HandleTable
, NewEntry
);
834 KeLeaveCriticalRegion();
837 /* Return the handle value */
838 return Handle
.GenericHandleOverlay
;
843 ExpBlockOnLockedHandleEntry(IN PHANDLE_TABLE HandleTable
,
844 IN PHANDLE_TABLE_ENTRY HandleTableEntry
)
847 DEFINE_WAIT_BLOCK(WaitBlock
);
849 /* Block on the pushlock */
850 ExBlockPushLock(&HandleTable
->HandleContentionEvent
, WaitBlock
);
852 /* Get the current value and check if it's been unlocked */
853 OldValue
= HandleTableEntry
->Value
;
854 if (!(OldValue
) || (OldValue
& EXHANDLE_TABLE_ENTRY_LOCK_BIT
))
856 /* Unblock the pushlock and return */
857 ExfUnblockPushLock(&HandleTable
->HandleContentionEvent
, WaitBlock
);
861 /* Wait for it to be unblocked */
862 ExWaitForUnblockPushLock(&HandleTable
->HandleContentionEvent
,
869 ExpLockHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
870 IN PHANDLE_TABLE_ENTRY HandleTableEntry
)
872 LONG_PTR NewValue
, OldValue
;
875 ASSERT((KeGetCurrentThread()->CombinedApcDisable
!= 0) ||
876 (KeGetCurrentIrql() == APC_LEVEL
));
878 /* Start lock loop */
881 /* Get the current value and check if it's locked */
882 OldValue
= *(volatile LONG_PTR
*)&HandleTableEntry
->Object
;
883 if (OldValue
& EXHANDLE_TABLE_ENTRY_LOCK_BIT
)
885 /* It's not locked, remove the lock bit to lock it */
886 NewValue
= OldValue
& ~EXHANDLE_TABLE_ENTRY_LOCK_BIT
;
887 if (InterlockedCompareExchangePointer(&HandleTableEntry
->Object
,
889 (PVOID
)OldValue
) == (PVOID
)OldValue
)
891 /* We locked it, get out */
897 /* We couldn't lock it, bail out if it's been freed */
898 if (!OldValue
) return FALSE
;
901 /* It's locked, wait for it to be unlocked */
902 ExpBlockOnLockedHandleEntry(HandleTable
, HandleTableEntry
);
908 ExUnlockHandleTableEntry(IN PHANDLE_TABLE HandleTable
,
909 IN PHANDLE_TABLE_ENTRY HandleTableEntry
)
915 ASSERT((KeGetCurrentThread()->CombinedApcDisable
!= 0) ||
916 (KeGetCurrentIrql() == APC_LEVEL
));
918 /* Set the lock bit and make sure it wasn't earlier */
919 OldValue
= InterlockedOr((PLONG
) &HandleTableEntry
->Value
,
920 EXHANDLE_TABLE_ENTRY_LOCK_BIT
);
921 ASSERT((OldValue
& EXHANDLE_TABLE_ENTRY_LOCK_BIT
) == 0);
923 /* Unblock any waiters */
924 ExfUnblockPushLock(&HandleTable
->HandleContentionEvent
, NULL
);
929 ExRemoveHandleTable(IN PHANDLE_TABLE HandleTable
)
933 /* Acquire the table lock */
934 KeEnterCriticalRegion();
935 ExAcquirePushLockExclusive(&HandleTableListLock
);
937 /* Remove the table and reset the list */
938 RemoveEntryList(&HandleTable
->HandleTableList
);
939 InitializeListHead(&HandleTable
->HandleTableList
);
941 /* Release the lock */
942 ExReleasePushLockExclusive(&HandleTableListLock
);
943 KeLeaveCriticalRegion();
948 ExDestroyHandleTable(IN PHANDLE_TABLE HandleTable
,
949 IN PVOID DestroyHandleProcedure OPTIONAL
)
953 /* Remove the handle from the list */
954 ExRemoveHandleTable(HandleTable
);
956 /* Check if we have a desotry callback */
957 if (DestroyHandleProcedure
)
963 /* Free the handle table */
964 ExpFreeHandleTable(HandleTable
);
969 ExDestroyHandle(IN PHANDLE_TABLE HandleTable
,
971 IN PHANDLE_TABLE_ENTRY HandleTableEntry OPTIONAL
)
977 /* Setup the actual handle value */
978 ExHandle
.GenericHandleOverlay
= Handle
;
980 /* Enter a critical region and check if we have to lookup the handle */
981 KeEnterCriticalRegion();
982 if (!HandleTableEntry
)
984 /* Lookup the entry */
985 HandleTableEntry
= ExpLookupHandleTableEntry(HandleTable
, ExHandle
);
987 /* Make sure that we found an entry, and that it's valid */
988 if (!(HandleTableEntry
) ||
989 !(HandleTableEntry
->Object
) ||
990 (HandleTableEntry
->NextFreeTableEntry
== -2))
992 /* Invalid handle, fail */
993 KeLeaveCriticalRegion();
998 if (!ExpLockHandleTableEntry(HandleTable
, HandleTableEntry
))
1000 /* Couldn't lock, fail */
1001 KeLeaveCriticalRegion();
1007 /* Make sure the handle is locked */
1008 ASSERT((HandleTableEntry
->Value
& EXHANDLE_TABLE_ENTRY_LOCK_BIT
) == 0);
1011 /* Clear the handle */
1012 Object
= InterlockedExchangePointer((PVOID
*)&HandleTableEntry
->Object
, NULL
);
1015 ASSERT(Object
!= NULL
);
1016 ASSERT((((ULONG_PTR
)Object
) & EXHANDLE_TABLE_ENTRY_LOCK_BIT
) == 0);
1018 /* Unblock the pushlock */
1019 ExfUnblockPushLock(&HandleTable
->HandleContentionEvent
, NULL
);
1021 /* Free the actual entry */
1022 ExpFreeHandleTableEntry(HandleTable
, ExHandle
, HandleTableEntry
);
1024 /* If we got here, return success */
1025 KeLeaveCriticalRegion();
1031 ExMapHandleToPointer(IN PHANDLE_TABLE HandleTable
,
1035 PHANDLE_TABLE_ENTRY HandleTableEntry
;
1038 /* Set the handle value */
1039 ExHandle
.GenericHandleOverlay
= Handle
;
1041 /* Fail if we got an invalid index */
1042 if (!(ExHandle
.Index
& (LOW_LEVEL_ENTRIES
- 1))) return NULL
;
1045 HandleTableEntry
= ExpLookupHandleTableEntry(HandleTable
, ExHandle
);
1046 if (!HandleTableEntry
) return NULL
;
1049 if (!ExpLockHandleTableEntry(HandleTable
, HandleTableEntry
)) return NULL
;
1051 /* Return the entry */
1052 return HandleTableEntry
;
1057 ExDupHandleTable(IN PEPROCESS Process
,
1058 IN PHANDLE_TABLE HandleTable
,
1059 IN PEX_DUPLICATE_HANDLE_CALLBACK DupHandleProcedure
,
1062 PHANDLE_TABLE NewTable
;
1064 PHANDLE_TABLE_ENTRY HandleTableEntry
, NewEntry
;
1065 BOOLEAN Failed
= FALSE
;
1068 /* Allocate the duplicated copy */
1069 NewTable
= ExpAllocateHandleTable(Process
, FALSE
);
1070 if (!NewTable
) return NULL
;
1072 /* Loop each entry */
1073 while (NewTable
->NextHandleNeedingPool
<
1074 HandleTable
->NextHandleNeedingPool
)
1076 /* Insert it into the duplicated copy */
1077 if (!ExpAllocateHandleTableEntrySlow(NewTable
, FALSE
))
1079 /* Insert failed, free the new copy and return */
1080 ExpFreeHandleTable(NewTable
);
1085 /* Setup the initial handle table data */
1086 NewTable
->HandleCount
= 0;
1087 NewTable
->ExtraInfoPages
= 0;
1088 NewTable
->FirstFree
= 0;
1090 /* Setup the first handle value */
1091 Handle
.Value
= SizeOfHandle(1);
1093 /* Enter a critical region and lookup the new entry */
1094 KeEnterCriticalRegion();
1095 while ((NewEntry
= ExpLookupHandleTableEntry(NewTable
, Handle
)))
1097 /* Lookup the old entry */
1098 HandleTableEntry
= ExpLookupHandleTableEntry(HandleTable
, Handle
);
1100 /* Loop each entry */
1103 /* Check if it doesn't match the audit mask */
1104 if (!(HandleTableEntry
->Value
& Mask
))
1106 /* Free it since we won't use it */
1111 /* Lock the entry */
1112 if (!ExpLockHandleTableEntry(HandleTable
, HandleTableEntry
))
1114 /* Free it since we can't lock it, so we won't use it */
1119 /* Copy the handle value */
1120 *NewEntry
= *HandleTableEntry
;
1122 /* Call the duplicate callback */
1123 if (DupHandleProcedure(Process
,
1128 /* Clear failure flag */
1131 /* Lock the entry, increase the handle count */
1132 NewEntry
->Value
|= EXHANDLE_TABLE_ENTRY_LOCK_BIT
;
1133 NewTable
->HandleCount
++;
1137 /* Duplication callback refused, fail */
1143 /* Check if we failed earlier and need to free */
1146 /* Free this entry */
1147 NewEntry
->Object
= NULL
;
1148 NewEntry
->NextFreeTableEntry
= NewTable
->FirstFree
;
1149 NewTable
->FirstFree
= Handle
.Value
;
1152 /* Increase the handle value and move to the next entry */
1153 Handle
.Value
+= SizeOfHandle(1);
1156 } while (Handle
.Value
% SizeOfHandle(LOW_LEVEL_ENTRIES
));
1158 /* We're done, skip the last entry */
1159 Handle
.Value
+= SizeOfHandle(1);
1162 /* Acquire the table lock and insert this new table into the list */
1163 ExAcquirePushLockExclusive(&HandleTableListLock
);
1164 InsertTailList(&HandleTableListHead
, &NewTable
->HandleTableList
);
1165 ExReleasePushLockExclusive(&HandleTableListLock
);
1167 /* Leave the critical region we entered previously and return the table */
1168 KeLeaveCriticalRegion();
1174 ExChangeHandle(IN PHANDLE_TABLE HandleTable
,
1176 IN PEX_CHANGE_HANDLE_CALLBACK ChangeRoutine
,
1177 IN ULONG_PTR Context
)
1180 PHANDLE_TABLE_ENTRY HandleTableEntry
;
1181 BOOLEAN Result
= FALSE
;
1184 /* Set the handle value */
1185 ExHandle
.GenericHandleOverlay
= Handle
;
1187 /* Find the entry for this handle */
1188 HandleTableEntry
= ExpLookupHandleTableEntry(HandleTable
, ExHandle
);
1190 /* Make sure that we found an entry, and that it's valid */
1191 if (!(HandleTableEntry
) ||
1192 !(HandleTableEntry
->Object
) ||
1193 (HandleTableEntry
->NextFreeTableEntry
== -2))
1195 /* It isn't, fail */
1199 /* Enter a critical region */
1200 KeEnterCriticalRegion();
1202 /* Try locking the handle entry */
1203 if (ExpLockHandleTableEntry(HandleTable
, HandleTableEntry
))
1205 /* Call the change routine and unlock the entry */
1206 Result
= ChangeRoutine(HandleTableEntry
, Context
);
1207 ExUnlockHandleTableEntry(HandleTable
, HandleTableEntry
);
1210 /* Leave the critical region and return the callback result */
1211 KeLeaveCriticalRegion();
1217 ExSweepHandleTable(IN PHANDLE_TABLE HandleTable
,
1218 IN PEX_SWEEP_HANDLE_CALLBACK EnumHandleProcedure
,
1222 PHANDLE_TABLE_ENTRY HandleTableEntry
;
1225 /* Set the initial value and loop the entries */
1226 Handle
.Value
= SizeOfHandle(1);
1227 while ((HandleTableEntry
= ExpLookupHandleTableEntry(HandleTable
, Handle
)))
1229 /* Loop each handle */
1232 /* Lock the entry */
1233 if (ExpLockHandleTableEntry(HandleTable
, HandleTableEntry
))
1235 /* Notify the callback routine */
1236 EnumHandleProcedure(HandleTableEntry
,
1237 Handle
.GenericHandleOverlay
,
1241 /* Go to the next handle and entry */
1242 Handle
.Value
+= SizeOfHandle(1);
1244 } while (Handle
.Value
% SizeOfHandle(LOW_LEVEL_ENTRIES
));
1246 /* Skip past the last entry */
1247 Handle
.Value
+= SizeOfHandle(1);
1256 ExEnumHandleTable(IN PHANDLE_TABLE HandleTable
,
1257 IN PEX_ENUM_HANDLE_CALLBACK EnumHandleProcedure
,
1258 IN OUT PVOID Context
,
1259 OUT PHANDLE EnumHandle OPTIONAL
)
1262 PHANDLE_TABLE_ENTRY HandleTableEntry
;
1263 BOOLEAN Result
= FALSE
;
1266 /* Enter a critical region */
1267 KeEnterCriticalRegion();
1269 /* Set the initial value and loop the entries */
1271 while ((HandleTableEntry
= ExpLookupHandleTableEntry(HandleTable
, Handle
)))
1273 /* Validate the entry */
1274 if ((HandleTableEntry
) &&
1275 (HandleTableEntry
->Object
) &&
1276 (HandleTableEntry
->NextFreeTableEntry
!= -2))
1278 /* Lock the entry */
1279 if (ExpLockHandleTableEntry(HandleTable
, HandleTableEntry
))
1281 /* Notify the callback routine */
1282 Result
= EnumHandleProcedure(HandleTableEntry
,
1283 Handle
.GenericHandleOverlay
,
1287 ExUnlockHandleTableEntry(HandleTable
, HandleTableEntry
);
1289 /* Was this the one looked for? */
1292 /* If so, return it if requested */
1293 if (EnumHandle
) *EnumHandle
= Handle
.GenericHandleOverlay
;
1299 /* Go to the next entry */
1300 Handle
.Value
+= SizeOfHandle(1);
1303 /* Leave the critical region and return callback result */
1304 KeLeaveCriticalRegion();