Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenhandle.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: ntoskrnl/ex/init.c 00005 * PURPOSE: Generic Executive Handle Tables 00006 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 00007 * Thomas Weidenmueller <w3seek@reactos.com> 00008 */ 00009 00010 /* INCLUDES ******************************************************************/ 00011 00012 #include <ntoskrnl.h> 00013 #define NDEBUG 00014 #include <debug.h> 00015 00016 /* GLOBALS *******************************************************************/ 00017 00018 LIST_ENTRY HandleTableListHead; 00019 EX_PUSH_LOCK HandleTableListLock; 00020 #define SizeOfHandle(x) (sizeof(HANDLE) * (x)) 00021 00022 /* PRIVATE FUNCTIONS *********************************************************/ 00023 00024 VOID 00025 NTAPI 00026 INIT_FUNCTION 00027 ExpInitializeHandleTables(VOID) 00028 { 00029 /* Initialize the list of handle tables and the lock */ 00030 InitializeListHead(&HandleTableListHead); 00031 ExInitializePushLock(&HandleTableListLock); 00032 } 00033 00034 PHANDLE_TABLE_ENTRY 00035 NTAPI 00036 ExpLookupHandleTableEntry(IN PHANDLE_TABLE HandleTable, 00037 IN EXHANDLE LookupHandle) 00038 { 00039 ULONG TableLevel, NextHandle; 00040 ULONG_PTR i, j, k, TableBase; 00041 PHANDLE_TABLE_ENTRY Entry = NULL; 00042 EXHANDLE Handle = LookupHandle; 00043 PUCHAR Level1, Level2, Level3; 00044 00045 /* Clear the tag bits and check what the next handle is */ 00046 Handle.TagBits = 0; 00047 NextHandle = *(volatile ULONG*)&HandleTable->NextHandleNeedingPool; 00048 if (Handle.Value >= NextHandle) return NULL; 00049 00050 /* Get the table code */ 00051 TableBase = *(volatile ULONG_PTR*)&HandleTable->TableCode; 00052 00053 /* Extract the table level and actual table base */ 00054 TableLevel = (ULONG)(TableBase & 3); 00055 TableBase = TableBase - TableLevel; 00056 00057 /* Check what level we're running at */ 00058 switch (TableLevel) 00059 { 00060 /* Direct index */ 00061 case 0: 00062 00063 /* Use level 1 and just get the entry directly */ 00064 Level1 = (PUCHAR)TableBase; 00065 Entry = (PVOID)&Level1[Handle.Value * 00066 (sizeof(HANDLE_TABLE_ENTRY) / 00067 SizeOfHandle(1))]; 00068 break; 00069 00070 /* Nested index into mid level */ 00071 case 1: 00072 00073 /* Get the second table and index into it */ 00074 Level2 = (PUCHAR)TableBase; 00075 i = Handle.Value % SizeOfHandle(LOW_LEVEL_ENTRIES); 00076 00077 /* Substract this index, and get the next one */ 00078 Handle.Value -= i; 00079 j = Handle.Value / 00080 (SizeOfHandle(LOW_LEVEL_ENTRIES) / sizeof(PHANDLE_TABLE_ENTRY)); 00081 00082 /* Now get the next table and get the entry from it */ 00083 Level1 = (PUCHAR)*(PHANDLE_TABLE_ENTRY*)&Level2[j]; 00084 Entry = (PVOID)&Level1[i * 00085 (sizeof(HANDLE_TABLE_ENTRY) / 00086 SizeOfHandle(1))]; 00087 break; 00088 00089 /* Nested index into high level */ 00090 case 2: 00091 00092 /* Start with the 3rd level table */ 00093 Level3 = (PUCHAR)TableBase; 00094 i = Handle.Value % SizeOfHandle(LOW_LEVEL_ENTRIES); 00095 00096 /* Subtract this index and get the index for the next lower table */ 00097 Handle.Value -= i; 00098 k = Handle.Value / 00099 (SizeOfHandle(LOW_LEVEL_ENTRIES) / sizeof(PHANDLE_TABLE_ENTRY)); 00100 00101 /* Get the remaining index in the 2nd level table */ 00102 j = k % (MID_LEVEL_ENTRIES * sizeof(PHANDLE_TABLE_ENTRY)); 00103 00104 /* Get the remaining index, which is in the third table */ 00105 k -= j; 00106 k /= MID_LEVEL_ENTRIES; 00107 00108 /* Extract the table level for the handle in each table */ 00109 Level2 = (PUCHAR)*(PHANDLE_TABLE_ENTRY*)&Level3[k]; 00110 Level1 = (PUCHAR)*(PHANDLE_TABLE_ENTRY*)&Level2[j]; 00111 00112 /* Get the handle table entry */ 00113 Entry = (PVOID)&Level1[i * 00114 (sizeof(HANDLE_TABLE_ENTRY) / 00115 SizeOfHandle(1))]; 00116 00117 default: 00118 00119 /* All done */ 00120 break; 00121 } 00122 00123 /* Return the handle entry */ 00124 return Entry; 00125 } 00126 00127 PVOID 00128 NTAPI 00129 ExpAllocateTablePagedPool(IN PEPROCESS Process OPTIONAL, 00130 IN SIZE_T Size) 00131 { 00132 PVOID Buffer; 00133 00134 /* Do the allocation */ 00135 Buffer = ExAllocatePoolWithTag(PagedPool, Size, TAG_OBJECT_TABLE); 00136 if (Buffer) 00137 { 00138 /* Clear the memory */ 00139 RtlZeroMemory(Buffer, Size); 00140 00141 /* Check if we have a process to charge quota */ 00142 if (Process) 00143 { 00144 /* FIXME: Charge quota */ 00145 } 00146 } 00147 00148 /* Return the allocated memory */ 00149 return Buffer; 00150 } 00151 00152 PVOID 00153 NTAPI 00154 ExpAllocateTablePagedPoolNoZero(IN PEPROCESS Process OPTIONAL, 00155 IN SIZE_T Size) 00156 { 00157 PVOID Buffer; 00158 00159 /* Do the allocation */ 00160 Buffer = ExAllocatePoolWithTag(PagedPool, Size, TAG_OBJECT_TABLE); 00161 if (Buffer) 00162 { 00163 /* Check if we have a process to charge quota */ 00164 if (Process) 00165 { 00166 /* FIXME: Charge quota */ 00167 } 00168 } 00169 00170 /* Return the allocated memory */ 00171 return Buffer; 00172 } 00173 00174 VOID 00175 NTAPI 00176 ExpFreeTablePagedPool(IN PEPROCESS Process OPTIONAL, 00177 IN PVOID Buffer, 00178 IN SIZE_T Size) 00179 { 00180 /* Free the buffer */ 00181 ExFreePoolWithTag(Buffer, TAG_OBJECT_TABLE); 00182 if (Process) 00183 { 00184 /* FIXME: Release quota */ 00185 } 00186 } 00187 00188 VOID 00189 NTAPI 00190 ExpFreeLowLevelTable(IN PEPROCESS Process, 00191 IN PHANDLE_TABLE_ENTRY TableEntry) 00192 { 00193 /* Check if we have an entry */ 00194 if (TableEntry[0].Object) 00195 { 00196 /* Free the entry */ 00197 ExpFreeTablePagedPool(Process, 00198 TableEntry[0].Object, 00199 LOW_LEVEL_ENTRIES * 00200 sizeof(HANDLE_TABLE_ENTRY_INFO)); 00201 } 00202 00203 /* Free the table */ 00204 ExpFreeTablePagedPool(Process, TableEntry, PAGE_SIZE); 00205 } 00206 00207 VOID 00208 NTAPI 00209 ExpFreeHandleTable(IN PHANDLE_TABLE HandleTable) 00210 { 00211 PEPROCESS Process = HandleTable->QuotaProcess; 00212 ULONG i, j; 00213 ULONG_PTR TableCode = HandleTable->TableCode; 00214 ULONG_PTR TableBase = TableCode & ~3; 00215 ULONG TableLevel = (ULONG)(TableCode & 3); 00216 PHANDLE_TABLE_ENTRY Level1, *Level2, **Level3; 00217 PAGED_CODE(); 00218 00219 /* Check which level we're at */ 00220 if (!TableLevel) 00221 { 00222 /* Select the first level table base and just free it */ 00223 Level1 = (PVOID)TableBase; 00224 ExpFreeLowLevelTable(Process, Level1); 00225 } 00226 else if (TableLevel == 1) 00227 { 00228 /* Select the second level table base */ 00229 Level2 = (PVOID)TableBase; 00230 00231 /* Loop each mid level entry */ 00232 for (i = 0; i < MID_LEVEL_ENTRIES; i++) 00233 { 00234 /* Leave if we've reached the last entry */ 00235 if (!Level2[i]) break; 00236 00237 /* Free the second level table */ 00238 ExpFreeLowLevelTable(Process, Level2[i]); 00239 } 00240 00241 /* Free the second level table */ 00242 ExpFreeTablePagedPool(Process, Level2, PAGE_SIZE); 00243 } 00244 else 00245 { 00246 /* Select the third level table base */ 00247 Level3 = (PVOID)TableBase; 00248 00249 /* Loop each high level entry */ 00250 for (i = 0; i < HIGH_LEVEL_ENTRIES; i++) 00251 { 00252 /* Leave if we've reached the last entry */ 00253 if (!Level3[i]) break; 00254 00255 /* Loop each mid level entry */ 00256 for (j = 0; j < MID_LEVEL_ENTRIES; j++) 00257 { 00258 /* Leave if we've reached the last entry */ 00259 if (!Level3[i][j]) break; 00260 00261 /* Free the second level table */ 00262 ExpFreeLowLevelTable(Process, Level3[i][j]); 00263 } 00264 00265 /* Free the third level table entry */ 00266 ExpFreeTablePagedPool(Process, Level3[i], PAGE_SIZE); 00267 } 00268 00269 /* Free the third level table */ 00270 ExpFreeTablePagedPool(Process, 00271 Level3, 00272 SizeOfHandle(HIGH_LEVEL_ENTRIES)); 00273 } 00274 00275 /* Free the actual table and check if we need to release quota */ 00276 ExFreePoolWithTag(HandleTable, TAG_OBJECT_TABLE); 00277 if (Process) 00278 { 00279 /* FIXME: TODO */ 00280 } 00281 } 00282 00283 VOID 00284 NTAPI 00285 ExpFreeHandleTableEntry(IN PHANDLE_TABLE HandleTable, 00286 IN EXHANDLE Handle, 00287 IN PHANDLE_TABLE_ENTRY HandleTableEntry) 00288 { 00289 ULONG OldValue, NewValue, *Free; 00290 ULONG i; 00291 PAGED_CODE(); 00292 00293 /* Sanity checks */ 00294 ASSERT(HandleTableEntry->Object == NULL); 00295 ASSERT(HandleTableEntry == ExpLookupHandleTableEntry(HandleTable, Handle)); 00296 00297 /* Decrement the handle count */ 00298 InterlockedDecrement(&HandleTable->HandleCount); 00299 00300 /* Mark the handle as free */ 00301 NewValue = (ULONG)Handle.Value & ~(SizeOfHandle(1) - 1); 00302 00303 /* Check if we're FIFO */ 00304 if (!HandleTable->StrictFIFO) 00305 { 00306 /* Select a lock index */ 00307 i = (NewValue >> 2) % 4; 00308 00309 /* Select which entry to use */ 00310 Free = (HandleTable->HandleTableLock[i].Locked) ? 00311 &HandleTable->FirstFree : &HandleTable->LastFree; 00312 } 00313 else 00314 { 00315 /* No need to worry about locking, take the last entry */ 00316 Free = &HandleTable->LastFree; 00317 } 00318 00319 /* Start value change loop */ 00320 for (;;) 00321 { 00322 /* Get the current value and write */ 00323 OldValue = *Free; 00324 HandleTableEntry->NextFreeTableEntry = (ULONG)OldValue; 00325 if (InterlockedCompareExchange((PLONG) Free, NewValue, OldValue) == OldValue) 00326 { 00327 /* Break out, we're done. Make sure the handle value makes sense */ 00328 ASSERT((OldValue & FREE_HANDLE_MASK) < 00329 HandleTable->NextHandleNeedingPool); 00330 break; 00331 } 00332 } 00333 } 00334 00335 PHANDLE_TABLE 00336 NTAPI 00337 ExpAllocateHandleTable(IN PEPROCESS Process OPTIONAL, 00338 IN BOOLEAN NewTable) 00339 { 00340 PHANDLE_TABLE HandleTable; 00341 PHANDLE_TABLE_ENTRY HandleTableTable, HandleEntry; 00342 ULONG i; 00343 PAGED_CODE(); 00344 00345 /* Allocate the table */ 00346 HandleTable = ExAllocatePoolWithTag(PagedPool, 00347 sizeof(HANDLE_TABLE), 00348 TAG_OBJECT_TABLE); 00349 if (!HandleTable) return NULL; 00350 00351 /* Check if we have a process */ 00352 if (Process) 00353 { 00354 /* FIXME: Charge quota */ 00355 } 00356 00357 /* Clear the table */ 00358 RtlZeroMemory(HandleTable, sizeof(HANDLE_TABLE)); 00359 00360 /* Now allocate the first level structures */ 00361 HandleTableTable = ExpAllocateTablePagedPoolNoZero(Process, PAGE_SIZE); 00362 if (!HandleTableTable) 00363 { 00364 /* Failed, free the table */ 00365 ExFreePoolWithTag(HandleTable, TAG_OBJECT_TABLE); 00366 return NULL; 00367 } 00368 00369 /* Write the pointer to our first level structures */ 00370 HandleTable->TableCode = (ULONG_PTR)HandleTableTable; 00371 00372 /* Initialize the first entry */ 00373 HandleEntry = &HandleTableTable[0]; 00374 HandleEntry->NextFreeTableEntry = -2; 00375 HandleEntry->Value = 0; 00376 00377 /* Check if this is a new table */ 00378 if (NewTable) 00379 { 00380 /* Go past the root entry */ 00381 HandleEntry++; 00382 00383 /* Loop every low level entry */ 00384 for (i = 1; i < (LOW_LEVEL_ENTRIES - 1); i++) 00385 { 00386 /* Set up the free data */ 00387 HandleEntry->Value = 0; 00388 HandleEntry->NextFreeTableEntry = (i + 1) * SizeOfHandle(1); 00389 00390 /* Move to the next entry */ 00391 HandleEntry++; 00392 } 00393 00394 /* Terminate the last entry */ 00395 HandleEntry->Value = 0; 00396 HandleEntry->NextFreeTableEntry = 0; 00397 HandleTable->FirstFree = SizeOfHandle(1); 00398 } 00399 00400 /* Set the next handle needing pool after our allocated page from above */ 00401 HandleTable->NextHandleNeedingPool = LOW_LEVEL_ENTRIES * SizeOfHandle(1); 00402 00403 /* Setup the rest of the handle table data */ 00404 HandleTable->QuotaProcess = Process; 00405 HandleTable->UniqueProcessId = PsGetCurrentProcess()->UniqueProcessId; 00406 HandleTable->Flags = 0; 00407 00408 /* Loop all the handle table locks */ 00409 for (i = 0; i < 4; i++) 00410 { 00411 /* Initialize the handle table lock */ 00412 ExInitializePushLock(&HandleTable->HandleTableLock[i]); 00413 } 00414 00415 /* Initialize the contention event lock and return the lock */ 00416 ExInitializePushLock(&HandleTable->HandleContentionEvent); 00417 return HandleTable; 00418 } 00419 00420 PHANDLE_TABLE_ENTRY 00421 NTAPI 00422 ExpAllocateLowLevelTable(IN PHANDLE_TABLE HandleTable, 00423 IN BOOLEAN DoInit) 00424 { 00425 ULONG i, Base; 00426 PHANDLE_TABLE_ENTRY Low, HandleEntry; 00427 00428 /* Allocate the low level table */ 00429 Low = ExpAllocateTablePagedPoolNoZero(HandleTable->QuotaProcess, 00430 PAGE_SIZE); 00431 if (!Low) return NULL; 00432 00433 /* Setup the initial entry */ 00434 HandleEntry = &Low[0]; 00435 HandleEntry->NextFreeTableEntry = -2; 00436 HandleEntry->Value = 0; 00437 00438 /* Check if we're initializing */ 00439 if (DoInit) 00440 { 00441 /* Go to the next entry and the base entry */ 00442 HandleEntry++; 00443 Base = HandleTable->NextHandleNeedingPool + SizeOfHandle(2); 00444 00445 /* Loop each entry */ 00446 for (i = Base; 00447 i < Base + SizeOfHandle(LOW_LEVEL_ENTRIES - 2); 00448 i += SizeOfHandle(1)) 00449 { 00450 /* Free this entry and move on to the next one */ 00451 HandleEntry->NextFreeTableEntry = i; 00452 HandleEntry->Value = 0; 00453 HandleEntry++; 00454 } 00455 00456 /* Terminate the last entry */ 00457 HandleEntry->NextFreeTableEntry = 0; 00458 HandleEntry->Value = 0; 00459 } 00460 00461 /* Return the low level table */ 00462 return Low; 00463 } 00464 00465 PHANDLE_TABLE_ENTRY* 00466 NTAPI 00467 ExpAllocateMidLevelTable(IN PHANDLE_TABLE HandleTable, 00468 IN BOOLEAN DoInit, 00469 OUT PHANDLE_TABLE_ENTRY *LowTableEntry) 00470 { 00471 PHANDLE_TABLE_ENTRY *Mid, Low; 00472 00473 /* Allocate the mid level table */ 00474 Mid = ExpAllocateTablePagedPool(HandleTable->QuotaProcess, PAGE_SIZE); 00475 if (!Mid) return NULL; 00476 00477 /* Allocate a new low level for it */ 00478 Low = ExpAllocateLowLevelTable(HandleTable, DoInit); 00479 if (!Low) 00480 { 00481 /* We failed, free the mid table */ 00482 ExpFreeTablePagedPool(HandleTable->QuotaProcess, Mid, PAGE_SIZE); 00483 return NULL; 00484 } 00485 00486 /* Link the tables and return the pointer */ 00487 Mid[0] = Low; 00488 *LowTableEntry = Low; 00489 return Mid; 00490 } 00491 00492 BOOLEAN 00493 NTAPI 00494 ExpAllocateHandleTableEntrySlow(IN PHANDLE_TABLE HandleTable, 00495 IN BOOLEAN DoInit) 00496 { 00497 ULONG i, j, Index; 00498 PHANDLE_TABLE_ENTRY Low = NULL, *Mid, **High, *SecondLevel, **ThirdLevel; 00499 ULONG NewFree, FirstFree; 00500 PVOID Value; 00501 ULONG_PTR TableCode = HandleTable->TableCode; 00502 ULONG_PTR TableBase = TableCode & ~3; 00503 ULONG TableLevel = (ULONG)(TableCode & 3); 00504 PAGED_CODE(); 00505 00506 /* Check how many levels we already have */ 00507 if (!TableLevel) 00508 { 00509 /* Allocate a mid level, since we only have a low level */ 00510 Mid = ExpAllocateMidLevelTable(HandleTable, DoInit, &Low); 00511 if (!Mid) return FALSE; 00512 00513 /* Link up the tables */ 00514 Mid[1] = Mid[0]; 00515 Mid[0] = (PVOID)TableBase; 00516 00517 /* Write the new level and attempt to change the table code */ 00518 TableBase = ((ULONG_PTR)Mid) | 1; 00519 Value = InterlockedExchangePointer((PVOID*)&HandleTable->TableCode, (PVOID)TableBase); 00520 } 00521 else if (TableLevel == 1) 00522 { 00523 /* Setup the 2nd level table */ 00524 SecondLevel = (PVOID)TableBase; 00525 00526 /* Get if the next index can fit in the table */ 00527 i = HandleTable->NextHandleNeedingPool / 00528 SizeOfHandle(LOW_LEVEL_ENTRIES); 00529 if (i < MID_LEVEL_ENTRIES) 00530 { 00531 /* We need to allocate a new table */ 00532 Low = ExpAllocateLowLevelTable(HandleTable, DoInit); 00533 if (!Low) return FALSE; 00534 00535 /* Update the table */ 00536 Value = InterlockedExchangePointer((PVOID*)&SecondLevel[i], Low); 00537 ASSERT(Value == NULL); 00538 } 00539 else 00540 { 00541 /* We need a new high level table */ 00542 High = ExpAllocateTablePagedPool(HandleTable->QuotaProcess, 00543 SizeOfHandle(HIGH_LEVEL_ENTRIES)); 00544 if (!High) return FALSE; 00545 00546 /* Allocate a new mid level table as well */ 00547 Mid = ExpAllocateMidLevelTable(HandleTable, DoInit, &Low); 00548 if (!Mid) 00549 { 00550 /* We failed, free the high level table as welll */ 00551 ExpFreeTablePagedPool(HandleTable->QuotaProcess, 00552 High, 00553 SizeOfHandle(HIGH_LEVEL_ENTRIES)); 00554 return FALSE; 00555 } 00556 00557 /* Link up the tables */ 00558 High[0] = (PVOID)TableBase; 00559 High[1] = Mid; 00560 00561 /* Write the new table and change the table code */ 00562 TableBase = ((ULONG_PTR)High) | 2; 00563 Value = InterlockedExchangePointer((PVOID*)&HandleTable->TableCode, 00564 (PVOID)TableBase); 00565 } 00566 } 00567 else if (TableLevel == 2) 00568 { 00569 /* Setup the 3rd level table */ 00570 ThirdLevel = (PVOID)TableBase; 00571 00572 /* Get the index and check if it can fit */ 00573 i = HandleTable->NextHandleNeedingPool / SizeOfHandle(MAX_MID_INDEX); 00574 if (i >= HIGH_LEVEL_ENTRIES) return FALSE; 00575 00576 /* Check if there's no mid-level table */ 00577 if (!ThirdLevel[i]) 00578 { 00579 /* Allocate a new mid level table */ 00580 Mid = ExpAllocateMidLevelTable(HandleTable, DoInit, &Low); 00581 if (!Mid) return FALSE; 00582 00583 /* Update the table pointer */ 00584 Value = InterlockedExchangePointer((PVOID*)&ThirdLevel[i], Mid); 00585 ASSERT(Value == NULL); 00586 } 00587 else 00588 { 00589 /* We have one, check at which index we should insert our entry */ 00590 Index = (HandleTable->NextHandleNeedingPool / SizeOfHandle(1)) - 00591 i * MAX_MID_INDEX; 00592 j = Index / LOW_LEVEL_ENTRIES; 00593 00594 /* Allocate a new low level */ 00595 Low = ExpAllocateLowLevelTable(HandleTable, DoInit); 00596 if (!Low) return FALSE; 00597 00598 /* Update the table pointer */ 00599 Value = InterlockedExchangePointer((PVOID*)&ThirdLevel[i][j], Low); 00600 ASSERT(Value == NULL); 00601 } 00602 } 00603 00604 /* Update the index of the next handle */ 00605 Index = InterlockedExchangeAdd((PLONG) &HandleTable->NextHandleNeedingPool, 00606 SizeOfHandle(LOW_LEVEL_ENTRIES)); 00607 00608 /* Check if need to initialize the table */ 00609 if (DoInit) 00610 { 00611 /* Create a new index number */ 00612 Index += SizeOfHandle(1); 00613 00614 /* Start free index change loop */ 00615 for (;;) 00616 { 00617 /* Setup the first free index */ 00618 FirstFree = HandleTable->FirstFree; 00619 Low[LOW_LEVEL_ENTRIES - 1].NextFreeTableEntry = FirstFree; 00620 00621 /* Change the index */ 00622 NewFree = InterlockedCompareExchange((PLONG) &HandleTable->FirstFree, 00623 Index, 00624 FirstFree); 00625 if (NewFree == FirstFree) break; 00626 } 00627 } 00628 00629 /* All done */ 00630 return TRUE; 00631 } 00632 00633 ULONG 00634 NTAPI 00635 ExpMoveFreeHandles(IN PHANDLE_TABLE HandleTable) 00636 { 00637 ULONG LastFree, i; 00638 00639 /* Clear the last free index */ 00640 LastFree = InterlockedExchange((PLONG) &HandleTable->LastFree, 0); 00641 00642 /* Check if we had no index */ 00643 if (!LastFree) return LastFree; 00644 00645 /* Acquire the locks we need */ 00646 for (i = 1; i < 4; i++) 00647 { 00648 /* Acquire this lock exclusively */ 00649 ExWaitOnPushLock(&HandleTable->HandleTableLock[i]); 00650 } 00651 00652 /* Check if we're not strict FIFO */ 00653 if (!HandleTable->StrictFIFO) 00654 { 00655 /* Update the first free index */ 00656 if (!InterlockedCompareExchange((PLONG) &HandleTable->FirstFree, LastFree, 0)) 00657 { 00658 /* We're done, exit */ 00659 return LastFree; 00660 } 00661 } 00662 00663 /* We are strict FIFO, we need to reverse the entries */ 00664 ASSERT(FALSE); 00665 return LastFree; 00666 } 00667 00668 PHANDLE_TABLE_ENTRY 00669 NTAPI 00670 ExpAllocateHandleTableEntry(IN PHANDLE_TABLE HandleTable, 00671 OUT PEXHANDLE NewHandle) 00672 { 00673 ULONG OldValue, NewValue, NewValue1; 00674 PHANDLE_TABLE_ENTRY Entry; 00675 EXHANDLE Handle; 00676 BOOLEAN Result; 00677 ULONG i; 00678 00679 /* Start allocation loop */ 00680 for (;;) 00681 { 00682 /* Get the current link */ 00683 OldValue = HandleTable->FirstFree; 00684 while (!OldValue) 00685 { 00686 /* No free entries remain, lock the handle table */ 00687 KeEnterCriticalRegion(); 00688 ExAcquirePushLockExclusive(&HandleTable->HandleTableLock[0]); 00689 00690 /* Check the value again */ 00691 OldValue = HandleTable->FirstFree; 00692 if (OldValue) 00693 { 00694 /* Another thread has already created a new level, bail out */ 00695 ExReleasePushLockExclusive(&HandleTable->HandleTableLock[0]); 00696 KeLeaveCriticalRegion(); 00697 break; 00698 } 00699 00700 /* Now move any free handles */ 00701 OldValue = ExpMoveFreeHandles(HandleTable); 00702 if (OldValue) 00703 { 00704 /* Another thread has already moved them, bail out */ 00705 ExReleasePushLockExclusive(&HandleTable->HandleTableLock[0]); 00706 KeLeaveCriticalRegion(); 00707 break; 00708 } 00709 00710 /* We're the first one through, so do the actual allocation */ 00711 Result = ExpAllocateHandleTableEntrySlow(HandleTable, TRUE); 00712 00713 /* Unlock the table and get the value now */ 00714 ExReleasePushLockExclusive(&HandleTable->HandleTableLock[0]); 00715 KeLeaveCriticalRegion(); 00716 OldValue = HandleTable->FirstFree; 00717 00718 /* Check if allocation failed */ 00719 if (!Result) 00720 { 00721 /* Check if nobody else went through here */ 00722 if (!OldValue) 00723 { 00724 /* We're still the only thread around, so fail */ 00725 NewHandle->GenericHandleOverlay = NULL; 00726 return NULL; 00727 } 00728 } 00729 } 00730 00731 /* We made it, write the current value */ 00732 Handle.Value = (OldValue & FREE_HANDLE_MASK); 00733 00734 /* Lookup the entry for this handle */ 00735 Entry = ExpLookupHandleTableEntry(HandleTable, Handle); 00736 00737 /* Get an available lock and acquire it */ 00738 i = ((OldValue & FREE_HANDLE_MASK) >> 2) % 4; 00739 KeEnterCriticalRegion(); 00740 ExAcquirePushLockShared(&HandleTable->HandleTableLock[i]); 00741 00742 /* Check if the value changed after acquiring the lock */ 00743 if (OldValue != *(volatile ULONG*)&HandleTable->FirstFree) 00744 { 00745 /* It did, so try again */ 00746 ExReleasePushLockShared(&HandleTable->HandleTableLock[i]); 00747 KeLeaveCriticalRegion(); 00748 continue; 00749 } 00750 00751 /* Now get the next value and do the compare */ 00752 NewValue = *(volatile ULONG*)&Entry->NextFreeTableEntry; 00753 NewValue1 = InterlockedCompareExchange((PLONG) &HandleTable->FirstFree, 00754 NewValue, 00755 OldValue); 00756 00757 /* The change was done, so release the lock */ 00758 ExReleasePushLockShared(&HandleTable->HandleTableLock[i]); 00759 KeLeaveCriticalRegion(); 00760 00761 /* Check if the compare was successful */ 00762 if (NewValue1 == OldValue) 00763 { 00764 /* Make sure that the new handle is in range, and break out */ 00765 ASSERT((NewValue & FREE_HANDLE_MASK) < 00766 HandleTable->NextHandleNeedingPool); 00767 break; 00768 } 00769 else 00770 { 00771 /* The compare failed, make sure we expected it */ 00772 ASSERT((NewValue1 & FREE_HANDLE_MASK) != 00773 (OldValue & FREE_HANDLE_MASK)); 00774 } 00775 } 00776 00777 /* Increase the number of handles */ 00778 InterlockedIncrement(&HandleTable->HandleCount); 00779 00780 /* Return the handle and the entry */ 00781 *NewHandle = Handle; 00782 return Entry; 00783 } 00784 00785 PHANDLE_TABLE 00786 NTAPI 00787 ExCreateHandleTable(IN PEPROCESS Process OPTIONAL) 00788 { 00789 PHANDLE_TABLE HandleTable; 00790 PAGED_CODE(); 00791 00792 /* Allocate the handle table */ 00793 HandleTable = ExpAllocateHandleTable(Process, TRUE); 00794 if (!HandleTable) return NULL; 00795 00796 /* Acquire the handle table lock */ 00797 KeEnterCriticalRegion(); 00798 ExAcquirePushLockExclusive(&HandleTableListLock); 00799 00800 /* Insert it into the list */ 00801 InsertTailList(&HandleTableListHead, &HandleTable->HandleTableList); 00802 00803 /* Release the lock */ 00804 ExReleasePushLockExclusive(&HandleTableListLock); 00805 KeLeaveCriticalRegion(); 00806 00807 /* Return the handle table */ 00808 return HandleTable; 00809 } 00810 00811 HANDLE 00812 NTAPI 00813 ExCreateHandle(IN PHANDLE_TABLE HandleTable, 00814 IN PHANDLE_TABLE_ENTRY HandleTableEntry) 00815 { 00816 EXHANDLE Handle; 00817 PHANDLE_TABLE_ENTRY NewEntry; 00818 PAGED_CODE(); 00819 00820 /* Start with a clean handle */ 00821 Handle.GenericHandleOverlay = NULL; 00822 00823 /* Allocate a new entry */ 00824 NewEntry = ExpAllocateHandleTableEntry(HandleTable, &Handle); 00825 if (NewEntry) 00826 { 00827 /* Enter a critical region */ 00828 KeEnterCriticalRegion(); 00829 00830 /* Write the entry */ 00831 *NewEntry = *HandleTableEntry; 00832 00833 /* Unlock it and leave the critical region */ 00834 ExUnlockHandleTableEntry(HandleTable, NewEntry); 00835 KeLeaveCriticalRegion(); 00836 } 00837 00838 /* Return the handle value */ 00839 return Handle.GenericHandleOverlay; 00840 } 00841 00842 VOID 00843 NTAPI 00844 ExpBlockOnLockedHandleEntry(IN PHANDLE_TABLE HandleTable, 00845 IN PHANDLE_TABLE_ENTRY HandleTableEntry) 00846 { 00847 LONG_PTR OldValue; 00848 DEFINE_WAIT_BLOCK(WaitBlock); 00849 00850 /* Block on the pushlock */ 00851 ExBlockPushLock(&HandleTable->HandleContentionEvent, WaitBlock); 00852 00853 /* Get the current value and check if it's been unlocked */ 00854 OldValue = HandleTableEntry->Value; 00855 if (!(OldValue) || (OldValue & EXHANDLE_TABLE_ENTRY_LOCK_BIT)) 00856 { 00857 /* Unblock the pushlock and return */ 00858 ExfUnblockPushLock(&HandleTable->HandleContentionEvent, WaitBlock); 00859 } 00860 else 00861 { 00862 /* Wait for it to be unblocked */ 00863 ExWaitForUnblockPushLock(&HandleTable->HandleContentionEvent, 00864 WaitBlock); 00865 } 00866 } 00867 00868 BOOLEAN 00869 NTAPI 00870 ExpLockHandleTableEntry(IN PHANDLE_TABLE HandleTable, 00871 IN PHANDLE_TABLE_ENTRY HandleTableEntry) 00872 { 00873 LONG_PTR NewValue, OldValue; 00874 00875 /* Sanity check */ 00876 ASSERT((KeGetCurrentThread()->CombinedApcDisable != 0) || 00877 (KeGetCurrentIrql() == APC_LEVEL)); 00878 00879 /* Start lock loop */ 00880 for (;;) 00881 { 00882 /* Get the current value and check if it's locked */ 00883 OldValue = *(volatile LONG_PTR *)&HandleTableEntry->Object; 00884 if (OldValue & EXHANDLE_TABLE_ENTRY_LOCK_BIT) 00885 { 00886 /* It's not locked, remove the lock bit to lock it */ 00887 NewValue = OldValue & ~EXHANDLE_TABLE_ENTRY_LOCK_BIT; 00888 if (InterlockedCompareExchangePointer(&HandleTableEntry->Object, 00889 (PVOID)NewValue, 00890 (PVOID)OldValue) == (PVOID)OldValue) 00891 { 00892 /* We locked it, get out */ 00893 return TRUE; 00894 } 00895 } 00896 else 00897 { 00898 /* We couldn't lock it, bail out if it's been freed */ 00899 if (!OldValue) return FALSE; 00900 } 00901 00902 /* It's locked, wait for it to be unlocked */ 00903 ExpBlockOnLockedHandleEntry(HandleTable, HandleTableEntry); 00904 } 00905 } 00906 00907 VOID 00908 NTAPI 00909 ExUnlockHandleTableEntry(IN PHANDLE_TABLE HandleTable, 00910 IN PHANDLE_TABLE_ENTRY HandleTableEntry) 00911 { 00912 LONG_PTR OldValue; 00913 PAGED_CODE(); 00914 00915 /* Sanity check */ 00916 ASSERT((KeGetCurrentThread()->CombinedApcDisable != 0) || 00917 (KeGetCurrentIrql() == APC_LEVEL)); 00918 00919 /* Set the lock bit and make sure it wasn't earlier */ 00920 OldValue = InterlockedOr((PLONG) &HandleTableEntry->Value, 00921 EXHANDLE_TABLE_ENTRY_LOCK_BIT); 00922 ASSERT((OldValue & EXHANDLE_TABLE_ENTRY_LOCK_BIT) == 0); 00923 00924 /* Unblock any waiters */ 00925 ExfUnblockPushLock(&HandleTable->HandleContentionEvent, NULL); 00926 } 00927 00928 VOID 00929 NTAPI 00930 ExRemoveHandleTable(IN PHANDLE_TABLE HandleTable) 00931 { 00932 PAGED_CODE(); 00933 00934 /* Acquire the table lock */ 00935 KeEnterCriticalRegion(); 00936 ExAcquirePushLockExclusive(&HandleTableListLock); 00937 00938 /* Remove the table and reset the list */ 00939 RemoveEntryList(&HandleTable->HandleTableList); 00940 InitializeListHead(&HandleTable->HandleTableList); 00941 00942 /* Release the lock */ 00943 ExReleasePushLockExclusive(&HandleTableListLock); 00944 KeLeaveCriticalRegion(); 00945 } 00946 00947 VOID 00948 NTAPI 00949 ExDestroyHandleTable(IN PHANDLE_TABLE HandleTable, 00950 IN PVOID DestroyHandleProcedure OPTIONAL) 00951 { 00952 PAGED_CODE(); 00953 00954 /* Remove the handle from the list */ 00955 ExRemoveHandleTable(HandleTable); 00956 00957 /* Check if we have a desotry callback */ 00958 if (DestroyHandleProcedure) 00959 { 00960 /* FIXME: */ 00961 ASSERT(FALSE); 00962 } 00963 00964 /* Free the handle table */ 00965 ExpFreeHandleTable(HandleTable); 00966 } 00967 00968 BOOLEAN 00969 NTAPI 00970 ExDestroyHandle(IN PHANDLE_TABLE HandleTable, 00971 IN HANDLE Handle, 00972 IN PHANDLE_TABLE_ENTRY HandleTableEntry OPTIONAL) 00973 { 00974 EXHANDLE ExHandle; 00975 PVOID Object; 00976 PAGED_CODE(); 00977 00978 /* Setup the actual handle value */ 00979 ExHandle.GenericHandleOverlay = Handle; 00980 00981 /* Enter a critical region and check if we have to lookup the handle */ 00982 KeEnterCriticalRegion(); 00983 if (!HandleTableEntry) 00984 { 00985 /* Lookup the entry */ 00986 HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, ExHandle); 00987 00988 /* Make sure that we found an entry, and that it's valid */ 00989 if (!(HandleTableEntry) || 00990 !(HandleTableEntry->Object) || 00991 (HandleTableEntry->NextFreeTableEntry == -2)) 00992 { 00993 /* Invalid handle, fail */ 00994 KeLeaveCriticalRegion(); 00995 return FALSE; 00996 } 00997 00998 /* Lock the entry */ 00999 if (!ExpLockHandleTableEntry(HandleTable, HandleTableEntry)) 01000 { 01001 /* Couldn't lock, fail */ 01002 KeLeaveCriticalRegion(); 01003 return FALSE; 01004 } 01005 } 01006 else 01007 { 01008 /* Make sure the handle is locked */ 01009 ASSERT((HandleTableEntry->Value & EXHANDLE_TABLE_ENTRY_LOCK_BIT) == 0); 01010 } 01011 01012 /* Clear the handle */ 01013 Object = InterlockedExchangePointer((PVOID*)&HandleTableEntry->Object, NULL); 01014 01015 /* Sanity checks */ 01016 ASSERT(Object != NULL); 01017 ASSERT((((ULONG_PTR)Object) & EXHANDLE_TABLE_ENTRY_LOCK_BIT) == 0); 01018 01019 /* Unblock the pushlock */ 01020 ExfUnblockPushLock(&HandleTable->HandleContentionEvent, NULL); 01021 01022 /* Free the actual entry */ 01023 ExpFreeHandleTableEntry(HandleTable, ExHandle, HandleTableEntry); 01024 01025 /* If we got here, return success */ 01026 KeLeaveCriticalRegion(); 01027 return TRUE; 01028 } 01029 01030 PHANDLE_TABLE_ENTRY 01031 NTAPI 01032 ExMapHandleToPointer(IN PHANDLE_TABLE HandleTable, 01033 IN HANDLE Handle) 01034 { 01035 EXHANDLE ExHandle; 01036 PHANDLE_TABLE_ENTRY HandleTableEntry; 01037 PAGED_CODE(); 01038 01039 /* Set the handle value */ 01040 ExHandle.GenericHandleOverlay = Handle; 01041 01042 /* Fail if we got an invalid index */ 01043 if (!(ExHandle.Index & (LOW_LEVEL_ENTRIES - 1))) return NULL; 01044 01045 /* Do the lookup */ 01046 HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, ExHandle); 01047 if (!HandleTableEntry) return NULL; 01048 01049 /* Lock it */ 01050 if (!ExpLockHandleTableEntry(HandleTable, HandleTableEntry)) return NULL; 01051 01052 /* Return the entry */ 01053 return HandleTableEntry; 01054 } 01055 01056 PHANDLE_TABLE 01057 NTAPI 01058 ExDupHandleTable(IN PEPROCESS Process, 01059 IN PHANDLE_TABLE HandleTable, 01060 IN PEX_DUPLICATE_HANDLE_CALLBACK DupHandleProcedure, 01061 IN ULONG_PTR Mask) 01062 { 01063 PHANDLE_TABLE NewTable; 01064 EXHANDLE Handle; 01065 PHANDLE_TABLE_ENTRY HandleTableEntry, NewEntry; 01066 BOOLEAN Failed = FALSE; 01067 PAGED_CODE(); 01068 01069 /* Allocate the duplicated copy */ 01070 NewTable = ExpAllocateHandleTable(Process, FALSE); 01071 if (!NewTable) return NULL; 01072 01073 /* Loop each entry */ 01074 while (NewTable->NextHandleNeedingPool < 01075 HandleTable->NextHandleNeedingPool) 01076 { 01077 /* Insert it into the duplicated copy */ 01078 if (!ExpAllocateHandleTableEntrySlow(NewTable, FALSE)) 01079 { 01080 /* Insert failed, free the new copy and return */ 01081 ExpFreeHandleTable(NewTable); 01082 return NULL; 01083 } 01084 } 01085 01086 /* Setup the initial handle table data */ 01087 NewTable->HandleCount = 0; 01088 NewTable->ExtraInfoPages = 0; 01089 NewTable->FirstFree = 0; 01090 01091 /* Setup the first handle value */ 01092 Handle.Value = SizeOfHandle(1); 01093 01094 /* Enter a critical region and lookup the new entry */ 01095 KeEnterCriticalRegion(); 01096 while ((NewEntry = ExpLookupHandleTableEntry(NewTable, Handle))) 01097 { 01098 /* Lookup the old entry */ 01099 HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, Handle); 01100 01101 /* Loop each entry */ 01102 do 01103 { 01104 /* Check if it doesn't match the audit mask */ 01105 if (!(HandleTableEntry->Value & Mask)) 01106 { 01107 /* Free it since we won't use it */ 01108 Failed = TRUE; 01109 } 01110 else 01111 { 01112 /* Lock the entry */ 01113 if (!ExpLockHandleTableEntry(HandleTable, HandleTableEntry)) 01114 { 01115 /* Free it since we can't lock it, so we won't use it */ 01116 Failed = TRUE; 01117 } 01118 else 01119 { 01120 /* Copy the handle value */ 01121 *NewEntry = *HandleTableEntry; 01122 01123 /* Call the duplicate callback */ 01124 if (DupHandleProcedure(Process, 01125 HandleTable, 01126 HandleTableEntry, 01127 NewEntry)) 01128 { 01129 /* Clear failure flag */ 01130 Failed = FALSE; 01131 01132 /* Lock the entry, increase the handle count */ 01133 NewEntry->Value |= EXHANDLE_TABLE_ENTRY_LOCK_BIT; 01134 NewTable->HandleCount++; 01135 } 01136 else 01137 { 01138 /* Duplication callback refused, fail */ 01139 Failed = TRUE; 01140 } 01141 } 01142 } 01143 01144 /* Check if we failed earlier and need to free */ 01145 if (Failed) 01146 { 01147 /* Free this entry */ 01148 NewEntry->Object = NULL; 01149 NewEntry->NextFreeTableEntry = NewTable->FirstFree; 01150 NewTable->FirstFree = (ULONG)Handle.Value; 01151 } 01152 01153 /* Increase the handle value and move to the next entry */ 01154 Handle.Value += SizeOfHandle(1); 01155 NewEntry++; 01156 HandleTableEntry++; 01157 } while (Handle.Value % SizeOfHandle(LOW_LEVEL_ENTRIES)); 01158 01159 /* We're done, skip the last entry */ 01160 Handle.Value += SizeOfHandle(1); 01161 } 01162 01163 /* Acquire the table lock and insert this new table into the list */ 01164 ExAcquirePushLockExclusive(&HandleTableListLock); 01165 InsertTailList(&HandleTableListHead, &NewTable->HandleTableList); 01166 ExReleasePushLockExclusive(&HandleTableListLock); 01167 01168 /* Leave the critical region we entered previously and return the table */ 01169 KeLeaveCriticalRegion(); 01170 return NewTable; 01171 } 01172 01173 BOOLEAN 01174 NTAPI 01175 ExChangeHandle(IN PHANDLE_TABLE HandleTable, 01176 IN HANDLE Handle, 01177 IN PEX_CHANGE_HANDLE_CALLBACK ChangeRoutine, 01178 IN ULONG_PTR Context) 01179 { 01180 EXHANDLE ExHandle; 01181 PHANDLE_TABLE_ENTRY HandleTableEntry; 01182 BOOLEAN Result = FALSE; 01183 PAGED_CODE(); 01184 01185 /* Set the handle value */ 01186 ExHandle.GenericHandleOverlay = Handle; 01187 01188 /* Find the entry for this handle */ 01189 HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, ExHandle); 01190 01191 /* Make sure that we found an entry, and that it's valid */ 01192 if (!(HandleTableEntry) || 01193 !(HandleTableEntry->Object) || 01194 (HandleTableEntry->NextFreeTableEntry == -2)) 01195 { 01196 /* It isn't, fail */ 01197 return FALSE; 01198 } 01199 01200 /* Enter a critical region */ 01201 KeEnterCriticalRegion(); 01202 01203 /* Try locking the handle entry */ 01204 if (ExpLockHandleTableEntry(HandleTable, HandleTableEntry)) 01205 { 01206 /* Call the change routine and unlock the entry */ 01207 Result = ChangeRoutine(HandleTableEntry, Context); 01208 ExUnlockHandleTableEntry(HandleTable, HandleTableEntry); 01209 } 01210 01211 /* Leave the critical region and return the callback result */ 01212 KeLeaveCriticalRegion(); 01213 return Result; 01214 } 01215 01216 VOID 01217 NTAPI 01218 ExSweepHandleTable(IN PHANDLE_TABLE HandleTable, 01219 IN PEX_SWEEP_HANDLE_CALLBACK EnumHandleProcedure, 01220 IN PVOID Context) 01221 { 01222 EXHANDLE Handle; 01223 PHANDLE_TABLE_ENTRY HandleTableEntry; 01224 PAGED_CODE(); 01225 01226 /* Set the initial value and loop the entries */ 01227 Handle.Value = SizeOfHandle(1); 01228 while ((HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, Handle))) 01229 { 01230 /* Loop each handle */ 01231 do 01232 { 01233 /* Lock the entry */ 01234 if (ExpLockHandleTableEntry(HandleTable, HandleTableEntry)) 01235 { 01236 /* Notify the callback routine */ 01237 EnumHandleProcedure(HandleTableEntry, 01238 Handle.GenericHandleOverlay, 01239 Context); 01240 } 01241 01242 /* Go to the next handle and entry */ 01243 Handle.Value += SizeOfHandle(1); 01244 HandleTableEntry++; 01245 } while (Handle.Value % SizeOfHandle(LOW_LEVEL_ENTRIES)); 01246 01247 /* Skip past the last entry */ 01248 Handle.Value += SizeOfHandle(1); 01249 } 01250 } 01251 01252 /* 01253 * @implemented 01254 */ 01255 BOOLEAN 01256 NTAPI 01257 ExEnumHandleTable(IN PHANDLE_TABLE HandleTable, 01258 IN PEX_ENUM_HANDLE_CALLBACK EnumHandleProcedure, 01259 IN OUT PVOID Context, 01260 OUT PHANDLE EnumHandle OPTIONAL) 01261 { 01262 EXHANDLE Handle; 01263 PHANDLE_TABLE_ENTRY HandleTableEntry; 01264 BOOLEAN Result = FALSE; 01265 PAGED_CODE(); 01266 01267 /* Enter a critical region */ 01268 KeEnterCriticalRegion(); 01269 01270 /* Set the initial value and loop the entries */ 01271 Handle.Value = 0; 01272 while ((HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, Handle))) 01273 { 01274 /* Validate the entry */ 01275 if ((HandleTableEntry) && 01276 (HandleTableEntry->Object) && 01277 (HandleTableEntry->NextFreeTableEntry != -2)) 01278 { 01279 /* Lock the entry */ 01280 if (ExpLockHandleTableEntry(HandleTable, HandleTableEntry)) 01281 { 01282 /* Notify the callback routine */ 01283 Result = EnumHandleProcedure(HandleTableEntry, 01284 Handle.GenericHandleOverlay, 01285 Context); 01286 01287 /* Unlock it */ 01288 ExUnlockHandleTableEntry(HandleTable, HandleTableEntry); 01289 01290 /* Was this the one looked for? */ 01291 if (Result) 01292 { 01293 /* If so, return it if requested */ 01294 if (EnumHandle) *EnumHandle = Handle.GenericHandleOverlay; 01295 break; 01296 } 01297 } 01298 } 01299 01300 /* Go to the next entry */ 01301 Handle.Value += SizeOfHandle(1); 01302 } 01303 01304 /* Leave the critical region and return callback result */ 01305 KeLeaveCriticalRegion(); 01306 return Result; 01307 } Generated on Sun May 27 2012 04:24:28 for ReactOS by
1.7.6.1
|