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

cmdelay.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/config/cmdelay.c
00005  * PURPOSE:         Routines for handling delay close and allocate.
00006  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
00007  */
00008 
00009 /* INCLUDES ******************************************************************/
00010 
00011 #include <ntoskrnl.h>
00012 #define NDEBUG
00013 #include <debug.h>
00014 
00015 /* GLOBALS *******************************************************************/
00016 
00017 WORK_QUEUE_ITEM CmpDelayDerefKCBWorkItem;
00018 
00019 ULONG CmpDelayedCloseSize = 2048;
00020 ULONG CmpDelayedCloseElements;
00021 KGUARDED_MUTEX CmpDelayedCloseTableLock;
00022 BOOLEAN CmpDelayCloseWorkItemActive;
00023 WORK_QUEUE_ITEM CmpDelayCloseWorkItem;
00024 LIST_ENTRY CmpDelayedLRUListHead;
00025 ULONG CmpDelayCloseIntervalInSeconds = 5;
00026 KDPC CmpDelayCloseDpc;
00027 KTIMER CmpDelayCloseTimer;
00028 
00029 KGUARDED_MUTEX CmpDelayDerefKCBLock;
00030 BOOLEAN CmpDelayDerefKCBWorkItemActive;
00031 LIST_ENTRY CmpDelayDerefKCBListHead;
00032 ULONG CmpDelayDerefKCBIntervalInSeconds = 5;
00033 KDPC CmpDelayDerefKCBDpc;
00034 KTIMER CmpDelayDerefKCBTimer;
00035 
00036 /* FUNCTIONS *****************************************************************/
00037 
00038 VOID
00039 NTAPI
00040 CmpDelayCloseDpcRoutine(IN PKDPC Dpc,
00041                         IN PVOID DeferredContext,
00042                         IN PVOID SystemArgument1,
00043                         IN PVOID SystemArgument2)
00044 {
00045     /* Sanity check */
00046     ASSERT(CmpDelayCloseWorkItemActive);
00047 
00048     /* Queue the work item */
00049     ExQueueWorkItem(&CmpDelayCloseWorkItem, DelayedWorkQueue);
00050 }
00051 
00052 VOID
00053 NTAPI
00054 CmpDelayCloseWorker(IN PVOID Context)
00055 {
00056     PCM_DELAYED_CLOSE_ENTRY ListEntry;
00057     ULONG i, ConvKey;
00058     PAGED_CODE();
00059 
00060     /* Sanity check */
00061     ASSERT(CmpDelayCloseWorkItemActive);
00062 
00063     /* Lock the registry */
00064     CmpLockRegistry();
00065 
00066     /* Acquire the delayed close table lock */
00067     KeAcquireGuardedMutex(&CmpDelayedCloseTableLock);
00068 
00069     /* Iterate */
00070     for (i = 0; i < (CmpDelayedCloseSize >> 2); i++)
00071     {
00072         /* Break out of the loop if there is nothing to process */
00073         if (CmpDelayedCloseElements <= CmpDelayedCloseSize) break;
00074 
00075         /* Sanity check */
00076         ASSERT(!IsListEmpty(&CmpDelayedLRUListHead));
00077 
00078         /* Get the entry */
00079         ListEntry = CONTAINING_RECORD(CmpDelayedLRUListHead.Blink,
00080                                       CM_DELAYED_CLOSE_ENTRY,
00081                                       DelayedLRUList);
00082 
00083         /* Save the ConvKey value of the KCB */
00084         ConvKey = ListEntry->KeyControlBlock->ConvKey;
00085 
00086         /* Release the delayed close table lock */
00087         KeReleaseGuardedMutex(&CmpDelayedCloseTableLock);
00088 
00089         /* Acquire the KCB lock */
00090         CmpAcquireKcbLockExclusiveByKey(ConvKey);
00091 
00092         /* Reacquire the delayed close table lock */
00093         KeAcquireGuardedMutex(&CmpDelayedCloseTableLock);
00094 
00095         /* Get the entry */
00096         ListEntry = CONTAINING_RECORD(CmpDelayedLRUListHead.Blink,
00097                                       CM_DELAYED_CLOSE_ENTRY,
00098                                       DelayedLRUList);
00099 
00100         /* Is the entry we have still the first one? */
00101         if (CmpDelayedCloseElements <= CmpDelayedCloseSize)
00102         {
00103             /* No, someone already inserted an entry there */
00104             CmpReleaseKcbLockByKey(ConvKey);
00105             break;
00106         }
00107 
00108         /* Is it a different entry? */
00109         if (ConvKey != ListEntry->KeyControlBlock->ConvKey)
00110         {
00111             /* Release the delayed close table lock */
00112             KeReleaseGuardedMutex(&CmpDelayedCloseTableLock);
00113 
00114             /* Release the KCB lock */
00115             CmpReleaseKcbLockByKey(ConvKey);
00116 
00117             /* Reacquire the delayed close table lock */
00118             KeAcquireGuardedMutex(&CmpDelayedCloseTableLock);
00119 
00120             /* Iterate again */
00121             continue;
00122         }
00123 
00124         /* Remove it from the end of the list */
00125         ListEntry =
00126             (PCM_DELAYED_CLOSE_ENTRY)RemoveTailList(&CmpDelayedLRUListHead);
00127 
00128         /* Get the containing entry */
00129         ListEntry = CONTAINING_RECORD(ListEntry,
00130                                       CM_DELAYED_CLOSE_ENTRY,
00131                                       DelayedLRUList);
00132 
00133         /* Process the entry */
00134         if ((ListEntry->KeyControlBlock->RefCount) ||
00135             (ListEntry->KeyControlBlock->DelayedCloseIndex))
00136         {
00137             /* Add it to the beginning of the list */
00138             InsertHeadList(&CmpDelayedLRUListHead, &ListEntry->DelayedLRUList);
00139 
00140             /* Release the delayed close table lock */
00141             KeReleaseGuardedMutex(&CmpDelayedCloseTableLock);
00142         }
00143         else
00144         {
00145             /* Release the delayed close table lock */
00146             KeReleaseGuardedMutex(&CmpDelayedCloseTableLock);
00147 
00148             /* Zero out the DelayCloseEntry pointer */
00149             ListEntry->KeyControlBlock->DelayCloseEntry = NULL;
00150 
00151             /* Cleanup the KCB cache */
00152             CmpCleanUpKcbCacheWithLock(ListEntry->KeyControlBlock, FALSE);
00153 
00154             /* Free the delay item */
00155             CmpFreeDelayItem(ListEntry);
00156 
00157             /* Decrement delayed close elements count */
00158             InterlockedDecrement((PLONG)&CmpDelayedCloseElements);
00159         }
00160 
00161         /* Release the KCB lock */
00162         CmpReleaseKcbLockByKey(ConvKey);
00163 
00164         /* Reacquire the delayed close table lock */
00165         KeAcquireGuardedMutex(&CmpDelayedCloseTableLock);
00166     }
00167 
00168     if (CmpDelayedCloseElements <= CmpDelayedCloseSize)
00169     {
00170         /* We're not active anymore */
00171         CmpDelayCloseWorkItemActive = FALSE;
00172     }
00173     else
00174     {
00175         /* We didn't process all things, so reschedule for the next time */
00176         CmpArmDelayedCloseTimer();
00177     }
00178 
00179     /* Release the delayed close table lock */
00180     KeReleaseGuardedMutex(&CmpDelayedCloseTableLock);
00181 
00182     /* Unlock the registry */
00183     CmpUnlockRegistry();
00184 }
00185 
00186 VOID
00187 NTAPI
00188 INIT_FUNCTION
00189 CmpInitializeDelayedCloseTable(VOID)
00190 {
00191     
00192     /* Setup the delayed close lock */
00193     KeInitializeGuardedMutex(&CmpDelayedCloseTableLock);
00194     
00195     /* Setup the work item */
00196     ExInitializeWorkItem(&CmpDelayCloseWorkItem, CmpDelayCloseWorker, NULL);
00197     
00198     /* Setup the list head */
00199     InitializeListHead(&CmpDelayedLRUListHead);
00200     
00201     /* Setup the DPC and its timer */
00202     KeInitializeDpc(&CmpDelayCloseDpc, CmpDelayCloseDpcRoutine, NULL);
00203     KeInitializeTimer(&CmpDelayCloseTimer);
00204 }
00205 
00206 VOID
00207 NTAPI
00208 CmpDelayDerefKCBDpcRoutine(IN PKDPC Dpc,
00209                            IN PVOID DeferredContext,
00210                            IN PVOID SystemArgument1,
00211                            IN PVOID SystemArgument2)
00212 {
00213     /* Sanity check */
00214     ASSERT(CmpDelayDerefKCBWorkItemActive);
00215 
00216     /* Queue the work item */
00217     ExQueueWorkItem(&CmpDelayDerefKCBWorkItem, DelayedWorkQueue);
00218 }
00219 
00220 VOID
00221 NTAPI
00222 CmpDelayDerefKCBWorker(IN PVOID Context)
00223 {
00224     PCM_DELAY_DEREF_KCB_ITEM Entry;
00225     PAGED_CODE();
00226 
00227     /* Sanity check */
00228     ASSERT(CmpDelayDerefKCBWorkItemActive);
00229 
00230     /* Lock the registry and and list lock */
00231     CmpLockRegistry();
00232     KeAcquireGuardedMutex(&CmpDelayDerefKCBLock);
00233 
00234     /* Check if the list is empty */
00235     while (!IsListEmpty(&CmpDelayDerefKCBListHead))
00236     {
00237         /* Grab an entry */
00238         Entry = (PVOID)RemoveHeadList(&CmpDelayDerefKCBListHead);
00239         
00240         /* We can release the lock now */
00241         KeReleaseGuardedMutex(&CmpDelayDerefKCBLock);
00242         
00243         /* Now grab the actual entry */
00244         Entry = CONTAINING_RECORD(Entry, CM_DELAY_DEREF_KCB_ITEM, ListEntry);
00245         Entry->ListEntry.Flink = Entry->ListEntry.Blink = NULL;
00246         
00247         /* Dereference and free */
00248         CmpDereferenceKeyControlBlock(Entry->Kcb);
00249         CmpFreeDelayItem(Entry);
00250         
00251         /* Lock the list again */
00252         KeAcquireGuardedMutex(&CmpDelayDerefKCBLock);
00253     }
00254     
00255     /* We're done */
00256     CmpDelayDerefKCBWorkItemActive = FALSE;
00257     KeReleaseGuardedMutex(&CmpDelayDerefKCBLock);
00258     CmpUnlockRegistry();
00259 }
00260 
00261 VOID
00262 NTAPI
00263 INIT_FUNCTION
00264 CmpInitDelayDerefKCBEngine(VOID)
00265 {
00266     /* Initialize lock and list */
00267     KeInitializeGuardedMutex(&CmpDelayDerefKCBLock);
00268     InitializeListHead(&CmpDelayDerefKCBListHead);
00269 
00270     /* Setup the work item */
00271     ExInitializeWorkItem(&CmpDelayDerefKCBWorkItem,
00272                          CmpDelayDerefKCBWorker,
00273                          NULL);
00274 
00275     /* Setup the DPC and timer for it */
00276     KeInitializeDpc(&CmpDelayDerefKCBDpc, CmpDelayDerefKCBDpcRoutine, NULL);
00277     KeInitializeTimer(&CmpDelayDerefKCBTimer);
00278 }
00279 
00280 VOID
00281 NTAPI
00282 CmpDelayDerefKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb)
00283 {
00284     LONG OldRefCount, NewRefCount;
00285     LARGE_INTEGER Timeout;
00286     PCM_DELAY_DEREF_KCB_ITEM Entry;
00287     PAGED_CODE();
00288     CMTRACE(CM_REFERENCE_DEBUG,
00289             "%s - Dereferencing KCB: %p\n", __FUNCTION__, Kcb);
00290 
00291     /* Get the previous reference count */
00292     OldRefCount = *(PLONG)&Kcb->RefCount;
00293     NewRefCount = OldRefCount - 1;
00294     if (((NewRefCount & 0xFFFF) > 0) &&
00295         (InterlockedCompareExchange((PLONG)&Kcb->RefCount,
00296                                     NewRefCount,
00297                                     OldRefCount) == OldRefCount))
00298     {
00299         /* KCB still had references, so we're done */
00300         return;
00301     }
00302 
00303     /* Allocate a delay item */
00304     Entry = CmpAllocateDelayItem();
00305     if (!Entry) return;
00306 
00307     /* Set the KCB */
00308     Entry->Kcb = Kcb;
00309 
00310     /* Acquire the delayed deref table lock */
00311     KeAcquireGuardedMutex(&CmpDelayDerefKCBLock);
00312 
00313     /* Insert the entry into the list */
00314     InsertTailList(&CmpDelayDerefKCBListHead, &Entry->ListEntry);
00315 
00316     /* Check if we need to enable anything */
00317     if (!CmpDelayDerefKCBWorkItemActive)
00318     {
00319         /* Yes, we have no work item, setup the interval */
00320         CmpDelayDerefKCBWorkItemActive = TRUE;
00321         Timeout.QuadPart = CmpDelayDerefKCBIntervalInSeconds * -10000000;
00322         KeSetTimer(&CmpDelayDerefKCBTimer, Timeout, &CmpDelayDerefKCBDpc);
00323     }
00324 
00325     /* Release the table lock */
00326     KeReleaseGuardedMutex(&CmpDelayDerefKCBLock);
00327 }
00328 
00329 VOID
00330 NTAPI
00331 CmpArmDelayedCloseTimer(VOID)
00332 {
00333     LARGE_INTEGER Timeout;
00334     PAGED_CODE();
00335     
00336     /* Set the worker active */
00337     CmpDelayCloseWorkItemActive = TRUE;
00338 
00339     /* Setup the interval */
00340     Timeout.QuadPart = CmpDelayCloseIntervalInSeconds * -10000000;
00341     KeSetTimer(&CmpDelayCloseTimer, Timeout, &CmpDelayCloseDpc);
00342 }
00343 
00344 VOID
00345 NTAPI
00346 CmpAddToDelayedClose(IN PCM_KEY_CONTROL_BLOCK Kcb,
00347                      IN BOOLEAN LockHeldExclusively)
00348 {
00349     ULONG i;
00350     ULONG OldRefCount, NewRefCount;
00351     PCM_DELAYED_CLOSE_ENTRY Entry;
00352     PAGED_CODE();
00353 
00354     /* Sanity check */
00355     ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) ||
00356            (CmpTestRegistryLockExclusive() == TRUE));
00357 
00358     /* Make sure it's valid */
00359     if (Kcb->DelayedCloseIndex != CmpDelayedCloseSize) ASSERT(FALSE);
00360 
00361     /* Sanity checks */
00362     ASSERT(Kcb->RefCount == 0);
00363     ASSERT(IsListEmpty(&Kcb->KeyBodyListHead) == TRUE);
00364     for (i = 0; i < 4; i++) ASSERT(Kcb->KeyBodyArray[i] == NULL);
00365 
00366     /* Allocate a delay item */
00367     Entry = CmpAllocateDelayItem();
00368     if (!Entry)
00369     {
00370         /* Cleanup immediately */
00371         CmpCleanUpKcbCacheWithLock(Kcb, LockHeldExclusively);
00372         return;
00373     }
00374 
00375     /* Sanity check */
00376     if (Kcb->InDelayClose) ASSERT(FALSE);
00377 
00378     /* Get the previous reference count */
00379     OldRefCount = *(PLONG)&Kcb->InDelayClose;
00380     ASSERT(OldRefCount == 0);
00381 
00382     /* Write the new one */
00383     NewRefCount = 1;
00384     if (InterlockedCompareExchange((PLONG)&Kcb->InDelayClose,
00385                                    NewRefCount,
00386                                    OldRefCount) != OldRefCount)
00387     {
00388         /* Sanity check */
00389         ASSERT(FALSE);
00390     }
00391 
00392     /* Reset the delayed close index */
00393     Kcb->DelayedCloseIndex = 0;
00394 
00395     /* Set up the close entry */
00396     Kcb->DelayCloseEntry = Entry;
00397     Entry->KeyControlBlock = Kcb;
00398 
00399     /* Increase the number of elements */
00400     InterlockedIncrement((PLONG)&CmpDelayedCloseElements);
00401 
00402     /* Acquire the delayed close table lock */
00403     KeAcquireGuardedMutex(&CmpDelayedCloseTableLock);
00404 
00405     /* Insert the entry into the list */
00406     InsertHeadList(&CmpDelayedLRUListHead, &Entry->DelayedLRUList);
00407 
00408     /* Check if we need to enable anything */
00409     if ((CmpDelayedCloseElements > CmpDelayedCloseSize) &&
00410         !(CmpDelayCloseWorkItemActive))
00411     {
00412         /* Yes, we have too many elements to close, and no work item */
00413         CmpArmDelayedCloseTimer();
00414     }
00415 
00416     /* Release the table lock */
00417     KeReleaseGuardedMutex(&CmpDelayedCloseTableLock);
00418 }
00419 
00420 VOID
00421 NTAPI
00422 CmpRemoveFromDelayedClose(IN PCM_KEY_CONTROL_BLOCK Kcb)
00423 {
00424     PCM_DELAYED_CLOSE_ENTRY Entry;
00425     ULONG NewRefCount, OldRefCount;
00426     PAGED_CODE();
00427     
00428     /* Sanity checks */
00429     ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) ||
00430            (CmpTestRegistryLockExclusive() == TRUE));
00431     if (Kcb->DelayedCloseIndex == CmpDelayedCloseSize) ASSERT(FALSE);
00432     
00433     /* Get the entry and lock the table */
00434     Entry = Kcb->DelayCloseEntry;
00435     ASSERT(Entry);
00436     KeAcquireGuardedMutex(&CmpDelayedCloseTableLock);
00437     
00438     /* Remove the entry */
00439     RemoveEntryList(&Entry->DelayedLRUList);
00440     
00441     /* Release the lock */
00442     KeReleaseGuardedMutex(&CmpDelayedCloseTableLock);
00443     
00444     /* Free the entry */
00445     CmpFreeDelayItem(Entry);
00446     
00447     /* Reduce the number of elements */
00448     InterlockedDecrement((PLONG)&CmpDelayedCloseElements);
00449     
00450     /* Sanity check */
00451     if (!Kcb->InDelayClose) ASSERT(FALSE);
00452     
00453     /* Get the previous reference count */
00454     OldRefCount = *(PLONG)&Kcb->InDelayClose;
00455     ASSERT(OldRefCount == 1);
00456     
00457     /* Write the new one */
00458     NewRefCount = 0;
00459     if (InterlockedCompareExchange((PLONG)&Kcb->InDelayClose,
00460                                    NewRefCount,
00461                                    OldRefCount) != OldRefCount)
00462     {
00463         /* Sanity check */
00464         ASSERT(FALSE);
00465     }
00466     
00467     /* Remove the link to the entry */
00468     Kcb->DelayCloseEntry = NULL;
00469     
00470     /* Set new delay size and remove the delete flag */
00471     Kcb->DelayedCloseIndex = CmpDelayedCloseSize;
00472 }

Generated on Sun May 27 2012 04:37:07 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.