ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

handle.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.