Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygencmdelay.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
1.7.6.1
|