Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenke_x.h
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/include/ke_x.h 00005 * PURPOSE: Internal Inlined Functions for the Kernel 00006 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 00007 */ 00008 00009 #ifndef _M_ARM 00010 FORCEINLINE 00011 KPROCESSOR_MODE 00012 KeGetPreviousMode(VOID) 00013 { 00014 /* Return the current mode */ 00015 return KeGetCurrentThread()->PreviousMode; 00016 } 00017 #endif 00018 00019 // 00020 // Enters a Guarded Region 00021 // 00022 #define KeEnterGuardedRegion() \ 00023 { \ 00024 PKTHREAD _Thread = KeGetCurrentThread(); \ 00025 \ 00026 /* Sanity checks */ \ 00027 ASSERT(KeGetCurrentIrql() <= APC_LEVEL); \ 00028 ASSERT(_Thread == KeGetCurrentThread()); \ 00029 ASSERT((_Thread->SpecialApcDisable <= 0) && \ 00030 (_Thread->SpecialApcDisable != -32768)); \ 00031 \ 00032 /* Disable Special APCs */ \ 00033 _Thread->SpecialApcDisable--; \ 00034 } 00035 00036 // 00037 // Leaves a Guarded Region 00038 // 00039 #define KeLeaveGuardedRegion() \ 00040 { \ 00041 PKTHREAD _Thread = KeGetCurrentThread(); \ 00042 \ 00043 /* Sanity checks */ \ 00044 ASSERT(KeGetCurrentIrql() <= APC_LEVEL); \ 00045 ASSERT(_Thread == KeGetCurrentThread()); \ 00046 ASSERT(_Thread->SpecialApcDisable < 0); \ 00047 \ 00048 /* Leave region and check if APCs are OK now */ \ 00049 if (!(++_Thread->SpecialApcDisable)) \ 00050 { \ 00051 /* Check for Kernel APCs on the list */ \ 00052 if (!IsListEmpty(&_Thread->ApcState. \ 00053 ApcListHead[KernelMode])) \ 00054 { \ 00055 /* Check for APC Delivery */ \ 00056 KiCheckForKernelApcDelivery(); \ 00057 } \ 00058 } \ 00059 } 00060 00061 // 00062 // Enters a Critical Region 00063 // 00064 #define KeEnterCriticalRegion() \ 00065 { \ 00066 PKTHREAD _Thread = KeGetCurrentThread(); \ 00067 \ 00068 /* Sanity checks */ \ 00069 ASSERT(_Thread == KeGetCurrentThread()); \ 00070 ASSERT((_Thread->KernelApcDisable <= 0) && \ 00071 (_Thread->KernelApcDisable != -32768)); \ 00072 \ 00073 /* Disable Kernel APCs */ \ 00074 _Thread->KernelApcDisable--; \ 00075 } 00076 00077 // 00078 // Leaves a Critical Region 00079 // 00080 #define KeLeaveCriticalRegion() \ 00081 { \ 00082 PKTHREAD _Thread = KeGetCurrentThread(); \ 00083 \ 00084 /* Sanity checks */ \ 00085 ASSERT(_Thread == KeGetCurrentThread()); \ 00086 ASSERT(_Thread->KernelApcDisable < 0); \ 00087 \ 00088 /* Enable Kernel APCs */ \ 00089 _Thread->KernelApcDisable++; \ 00090 \ 00091 /* Check if Kernel APCs are now enabled */ \ 00092 if (!(_Thread->KernelApcDisable)) \ 00093 { \ 00094 /* Check if we need to request an APC Delivery */ \ 00095 if (!(IsListEmpty(&_Thread->ApcState.ApcListHead[KernelMode])) && \ 00096 !(_Thread->SpecialApcDisable)) \ 00097 { \ 00098 /* Check for the right environment */ \ 00099 KiCheckForKernelApcDelivery(); \ 00100 } \ 00101 } \ 00102 } 00103 00104 #ifndef CONFIG_SMP 00105 00106 // 00107 // This routine protects against multiple CPU acquires, it's meaningless on UP. 00108 // 00109 FORCEINLINE 00110 VOID 00111 KiAcquireDispatcherObject(IN DISPATCHER_HEADER* Object) 00112 { 00113 UNREFERENCED_PARAMETER(Object); 00114 } 00115 00116 // 00117 // This routine protects against multiple CPU acquires, it's meaningless on UP. 00118 // 00119 FORCEINLINE 00120 VOID 00121 KiReleaseDispatcherObject(IN DISPATCHER_HEADER* Object) 00122 { 00123 UNREFERENCED_PARAMETER(Object); 00124 } 00125 00126 FORCEINLINE 00127 KIRQL 00128 KiAcquireDispatcherLock(VOID) 00129 { 00130 /* Raise to synch level */ 00131 return KfRaiseIrql(SYNCH_LEVEL); 00132 } 00133 00134 FORCEINLINE 00135 VOID 00136 KiReleaseDispatcherLock(IN KIRQL OldIrql) 00137 { 00138 /* Just exit the dispatcher */ 00139 KiExitDispatcher(OldIrql); 00140 } 00141 00142 FORCEINLINE 00143 VOID 00144 KiAcquireDispatcherLockAtDpcLevel(VOID) 00145 { 00146 /* This is a no-op at DPC Level for UP systems */ 00147 return; 00148 } 00149 00150 FORCEINLINE 00151 VOID 00152 KiReleaseDispatcherLockFromDpcLevel(VOID) 00153 { 00154 /* This is a no-op at DPC Level for UP systems */ 00155 return; 00156 } 00157 00158 // 00159 // This routine makes the thread deferred ready on the boot CPU. 00160 // 00161 FORCEINLINE 00162 VOID 00163 KiInsertDeferredReadyList(IN PKTHREAD Thread) 00164 { 00165 /* Set the thread to deferred state and boot CPU */ 00166 Thread->State = DeferredReady; 00167 Thread->DeferredProcessor = 0; 00168 00169 /* Make the thread ready immediately */ 00170 KiDeferredReadyThread(Thread); 00171 } 00172 00173 FORCEINLINE 00174 VOID 00175 KiRescheduleThread(IN BOOLEAN NewThread, 00176 IN ULONG Cpu) 00177 { 00178 /* This is meaningless on UP systems */ 00179 UNREFERENCED_PARAMETER(NewThread); 00180 UNREFERENCED_PARAMETER(Cpu); 00181 } 00182 00183 // 00184 // This routine protects against multiple CPU acquires, it's meaningless on UP. 00185 // 00186 FORCEINLINE 00187 VOID 00188 KiSetThreadSwapBusy(IN PKTHREAD Thread) 00189 { 00190 UNREFERENCED_PARAMETER(Thread); 00191 } 00192 00193 // 00194 // This routine protects against multiple CPU acquires, it's meaningless on UP. 00195 // 00196 FORCEINLINE 00197 VOID 00198 KiAcquirePrcbLock(IN PKPRCB Prcb) 00199 { 00200 UNREFERENCED_PARAMETER(Prcb); 00201 } 00202 00203 // 00204 // This routine protects against multiple CPU acquires, it's meaningless on UP. 00205 // 00206 FORCEINLINE 00207 VOID 00208 KiReleasePrcbLock(IN PKPRCB Prcb) 00209 { 00210 UNREFERENCED_PARAMETER(Prcb); 00211 } 00212 00213 // 00214 // This routine protects against multiple CPU acquires, it's meaningless on UP. 00215 // 00216 FORCEINLINE 00217 VOID 00218 KiAcquireThreadLock(IN PKTHREAD Thread) 00219 { 00220 UNREFERENCED_PARAMETER(Thread); 00221 } 00222 00223 // 00224 // This routine protects against multiple CPU acquires, it's meaningless on UP. 00225 // 00226 FORCEINLINE 00227 VOID 00228 KiReleaseThreadLock(IN PKTHREAD Thread) 00229 { 00230 UNREFERENCED_PARAMETER(Thread); 00231 } 00232 00233 // 00234 // This routine protects against multiple CPU acquires, it's meaningless on UP. 00235 // 00236 FORCEINLINE 00237 BOOLEAN 00238 KiTryThreadLock(IN PKTHREAD Thread) 00239 { 00240 UNREFERENCED_PARAMETER(Thread); 00241 return FALSE; 00242 } 00243 00244 FORCEINLINE 00245 VOID 00246 KiCheckDeferredReadyList(IN PKPRCB Prcb) 00247 { 00248 /* There are no deferred ready lists on UP systems */ 00249 UNREFERENCED_PARAMETER(Prcb); 00250 } 00251 00252 FORCEINLINE 00253 VOID 00254 KiRequestApcInterrupt(IN BOOLEAN NeedApc, 00255 IN UCHAR Processor) 00256 { 00257 /* We deliver instantly on UP */ 00258 UNREFERENCED_PARAMETER(NeedApc); 00259 UNREFERENCED_PARAMETER(Processor); 00260 } 00261 00262 FORCEINLINE 00263 PKSPIN_LOCK_QUEUE 00264 KiAcquireTimerLock(IN ULONG Hand) 00265 { 00266 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL); 00267 00268 /* Nothing to do on UP */ 00269 UNREFERENCED_PARAMETER(Hand); 00270 return NULL; 00271 } 00272 00273 FORCEINLINE 00274 VOID 00275 KiReleaseTimerLock(IN PKSPIN_LOCK_QUEUE LockQueue) 00276 { 00277 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL); 00278 00279 /* Nothing to do on UP */ 00280 UNREFERENCED_PARAMETER(LockQueue); 00281 } 00282 00283 #else 00284 00285 FORCEINLINE 00286 VOID 00287 KiAcquireDispatcherObject(IN DISPATCHER_HEADER* Object) 00288 { 00289 LONG OldValue; 00290 00291 /* Make sure we're at a safe level to touch the lock */ 00292 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL); 00293 00294 /* Start acquire loop */ 00295 do 00296 { 00297 /* Loop until the other CPU releases it */ 00298 while (TRUE) 00299 { 00300 /* Check if it got released */ 00301 OldValue = Object->Lock; 00302 if ((OldValue & KOBJECT_LOCK_BIT) == 0) break; 00303 00304 /* Let the CPU know that this is a loop */ 00305 YieldProcessor(); 00306 } 00307 00308 /* Try acquiring the lock now */ 00309 } while (InterlockedCompareExchange(&Object->Lock, 00310 OldValue | KOBJECT_LOCK_BIT, 00311 OldValue) != OldValue); 00312 } 00313 00314 FORCEINLINE 00315 VOID 00316 KiReleaseDispatcherObject(IN DISPATCHER_HEADER* Object) 00317 { 00318 /* Make sure we're at a safe level to touch the lock */ 00319 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL); 00320 00321 /* Release it */ 00322 InterlockedAnd(&Object->Lock, ~KOBJECT_LOCK_BIT); 00323 } 00324 00325 FORCEINLINE 00326 KIRQL 00327 KiAcquireDispatcherLock(VOID) 00328 { 00329 /* Raise to synchronization level and acquire the dispatcher lock */ 00330 return KeAcquireQueuedSpinLockRaiseToSynch(LockQueueDispatcherLock); 00331 } 00332 00333 FORCEINLINE 00334 VOID 00335 KiReleaseDispatcherLock(IN KIRQL OldIrql) 00336 { 00337 /* First release the lock */ 00338 KeReleaseQueuedSpinLockFromDpcLevel(&KeGetCurrentPrcb()-> 00339 LockQueue[LockQueueDispatcherLock]); 00340 00341 /* Then exit the dispatcher */ 00342 KiExitDispatcher(OldIrql); 00343 } 00344 00345 FORCEINLINE 00346 VOID 00347 KiAcquireDispatcherLockAtDpcLevel(VOID) 00348 { 00349 /* Acquire the dispatcher lock */ 00350 KeAcquireQueuedSpinLockAtDpcLevel(&KeGetCurrentPrcb()-> 00351 LockQueue[LockQueueDispatcherLock]); 00352 } 00353 00354 FORCEINLINE 00355 VOID 00356 KiReleaseDispatcherLockFromDpcLevel(VOID) 00357 { 00358 /* Release the dispatcher lock */ 00359 KeReleaseQueuedSpinLockFromDpcLevel(&KeGetCurrentPrcb()-> 00360 LockQueue[LockQueueDispatcherLock]); 00361 } 00362 00363 // 00364 // This routine inserts a thread into the deferred ready list of the current CPU 00365 // 00366 FORCEINLINE 00367 VOID 00368 KiInsertDeferredReadyList(IN PKTHREAD Thread) 00369 { 00370 PKPRCB Prcb = KeGetCurrentPrcb(); 00371 00372 /* Set the thread to deferred state and CPU */ 00373 Thread->State = DeferredReady; 00374 Thread->DeferredProcessor = Prcb->Number; 00375 00376 /* Add it on the list */ 00377 PushEntryList(&Prcb->DeferredReadyListHead, &Thread->SwapListEntry); 00378 } 00379 00380 FORCEINLINE 00381 VOID 00382 KiRescheduleThread(IN BOOLEAN NewThread, 00383 IN ULONG Cpu) 00384 { 00385 /* Check if a new thread needs to be scheduled on a different CPU */ 00386 if ((NewThread) && !(KeGetPcr()->Number == Cpu)) 00387 { 00388 /* Send an IPI to request delivery */ 00389 KiIpiSend(AFFINITY_MASK(Cpu), IPI_DPC); 00390 } 00391 } 00392 00393 // 00394 // This routine sets the current thread in a swap busy state, which ensure that 00395 // nobody else tries to swap it concurrently. 00396 // 00397 FORCEINLINE 00398 VOID 00399 KiSetThreadSwapBusy(IN PKTHREAD Thread) 00400 { 00401 /* Make sure nobody already set it */ 00402 ASSERT(Thread->SwapBusy == FALSE); 00403 00404 /* Set it ourselves */ 00405 Thread->SwapBusy = TRUE; 00406 } 00407 00408 // 00409 // This routine acquires the PRCB lock so that only one caller can touch 00410 // volatile PRCB data. 00411 // 00412 // Since this is a simple optimized spin-lock, it must only be acquired 00413 // at dispatcher level or higher! 00414 // 00415 FORCEINLINE 00416 VOID 00417 KiAcquirePrcbLock(IN PKPRCB Prcb) 00418 { 00419 /* Make sure we're at a safe level to touch the PRCB lock */ 00420 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL); 00421 00422 /* Start acquire loop */ 00423 for (;;) 00424 { 00425 /* Acquire the lock and break out if we acquired it first */ 00426 if (!InterlockedExchange((PLONG)&Prcb->PrcbLock, 1)) break; 00427 00428 /* Loop until the other CPU releases it */ 00429 do 00430 { 00431 /* Let the CPU know that this is a loop */ 00432 YieldProcessor(); 00433 } while (Prcb->PrcbLock); 00434 } 00435 } 00436 00437 // 00438 // This routine releases the PRCB lock so that other callers can touch 00439 // volatile PRCB data. 00440 // 00441 // Since this is a simple optimized spin-lock, it must be be only acquired 00442 // at dispatcher level or higher! 00443 // 00444 FORCEINLINE 00445 VOID 00446 KiReleasePrcbLock(IN PKPRCB Prcb) 00447 { 00448 /* Make sure we are above dispatch and the lock is acquired! */ 00449 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL); 00450 ASSERT(Prcb->PrcbLock != 0); 00451 00452 /* Release it */ 00453 InterlockedAnd((PLONG)&Prcb->PrcbLock, 0); 00454 } 00455 00456 // 00457 // This routine acquires the thread lock so that only one caller can touch 00458 // volatile thread data. 00459 // 00460 // Since this is a simple optimized spin-lock, it must be be only acquired 00461 // at dispatcher level or higher! 00462 // 00463 FORCEINLINE 00464 VOID 00465 KiAcquireThreadLock(IN PKTHREAD Thread) 00466 { 00467 /* Make sure we're at a safe level to touch the thread lock */ 00468 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL); 00469 00470 /* Start acquire loop */ 00471 for (;;) 00472 { 00473 /* Acquire the lock and break out if we acquired it first */ 00474 if (!InterlockedExchange((PLONG)&Thread->ThreadLock, 1)) break; 00475 00476 /* Loop until the other CPU releases it */ 00477 do 00478 { 00479 /* Let the CPU know that this is a loop */ 00480 YieldProcessor(); 00481 } while (Thread->ThreadLock); 00482 } 00483 } 00484 00485 // 00486 // This routine releases the thread lock so that other callers can touch 00487 // volatile thread data. 00488 // 00489 // Since this is a simple optimized spin-lock, it must be be only acquired 00490 // at dispatcher level or higher! 00491 // 00492 FORCEINLINE 00493 VOID 00494 KiReleaseThreadLock(IN PKTHREAD Thread) 00495 { 00496 /* Make sure we are still above dispatch */ 00497 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL); 00498 00499 /* Release it */ 00500 InterlockedAnd((PLONG)&Thread->ThreadLock, 0); 00501 } 00502 00503 FORCEINLINE 00504 BOOLEAN 00505 KiTryThreadLock(IN PKTHREAD Thread) 00506 { 00507 LONG Value; 00508 00509 /* If the lock isn't acquired, return false */ 00510 if (!Thread->ThreadLock) return FALSE; 00511 00512 /* Otherwise, try to acquire it and check the result */ 00513 Value = 1; 00514 Value = InterlockedExchange((PLONG)&Thread->ThreadLock, Value); 00515 00516 /* Return the lock state */ 00517 return (Value == TRUE); 00518 } 00519 00520 FORCEINLINE 00521 VOID 00522 KiCheckDeferredReadyList(IN PKPRCB Prcb) 00523 { 00524 /* Scan the deferred ready lists if required */ 00525 if (Prcb->DeferredReadyListHead.Next) KiProcessDeferredReadyList(Prcb); 00526 } 00527 00528 FORCEINLINE 00529 VOID 00530 KiRequestApcInterrupt(IN BOOLEAN NeedApc, 00531 IN UCHAR Processor) 00532 { 00533 /* Check if we need to request APC delivery */ 00534 if (NeedApc) 00535 { 00536 /* Check if it's on another CPU */ 00537 if (KeGetPcr()->Number != Processor) 00538 { 00539 /* Send an IPI to request delivery */ 00540 KiIpiSend(AFFINITY_MASK(Processor), IPI_APC); 00541 } 00542 else 00543 { 00544 /* Request a software interrupt */ 00545 HalRequestSoftwareInterrupt(APC_LEVEL); 00546 } 00547 } 00548 } 00549 00550 FORCEINLINE 00551 PKSPIN_LOCK_QUEUE 00552 KiAcquireTimerLock(IN ULONG Hand) 00553 { 00554 PKSPIN_LOCK_QUEUE LockQueue; 00555 ULONG LockIndex; 00556 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL); 00557 00558 /* Get the lock index */ 00559 LockIndex = Hand >> LOCK_QUEUE_TIMER_LOCK_SHIFT; 00560 LockIndex &= (LOCK_QUEUE_TIMER_TABLE_LOCKS - 1); 00561 00562 /* Now get the lock */ 00563 LockQueue = &KeGetCurrentPrcb()->LockQueue[LockQueueTimerTableLock + LockIndex]; 00564 00565 /* Acquire it and return */ 00566 KeAcquireQueuedSpinLockAtDpcLevel(LockQueue); 00567 return LockQueue; 00568 } 00569 00570 FORCEINLINE 00571 VOID 00572 KiReleaseTimerLock(IN PKSPIN_LOCK_QUEUE LockQueue) 00573 { 00574 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL); 00575 00576 /* Release the lock */ 00577 KeReleaseQueuedSpinLockFromDpcLevel(LockQueue); 00578 } 00579 00580 #endif 00581 00582 FORCEINLINE 00583 VOID 00584 KiAcquireApcLock(IN PKTHREAD Thread, 00585 IN PKLOCK_QUEUE_HANDLE Handle) 00586 { 00587 /* Acquire the lock and raise to synchronization level */ 00588 KeAcquireInStackQueuedSpinLockRaiseToSynch(&Thread->ApcQueueLock, Handle); 00589 } 00590 00591 FORCEINLINE 00592 VOID 00593 KiAcquireApcLockAtDpcLevel(IN PKTHREAD Thread, 00594 IN PKLOCK_QUEUE_HANDLE Handle) 00595 { 00596 /* Acquire the lock */ 00597 KeAcquireInStackQueuedSpinLockAtDpcLevel(&Thread->ApcQueueLock, Handle); 00598 } 00599 00600 FORCEINLINE 00601 VOID 00602 KiAcquireApcLockAtApcLevel(IN PKTHREAD Thread, 00603 IN PKLOCK_QUEUE_HANDLE Handle) 00604 { 00605 /* Acquire the lock */ 00606 KeAcquireInStackQueuedSpinLock(&Thread->ApcQueueLock, Handle); 00607 } 00608 00609 FORCEINLINE 00610 VOID 00611 KiReleaseApcLock(IN PKLOCK_QUEUE_HANDLE Handle) 00612 { 00613 /* Release the lock */ 00614 KeReleaseInStackQueuedSpinLock(Handle); 00615 } 00616 00617 FORCEINLINE 00618 VOID 00619 KiReleaseApcLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE Handle) 00620 { 00621 /* Release the lock */ 00622 KeReleaseInStackQueuedSpinLockFromDpcLevel(Handle); 00623 } 00624 00625 FORCEINLINE 00626 VOID 00627 KiAcquireProcessLock(IN PKPROCESS Process, 00628 IN PKLOCK_QUEUE_HANDLE Handle) 00629 { 00630 /* Acquire the lock and raise to synchronization level */ 00631 KeAcquireInStackQueuedSpinLockRaiseToSynch(&Process->ProcessLock, Handle); 00632 } 00633 00634 FORCEINLINE 00635 VOID 00636 KiReleaseProcessLock(IN PKLOCK_QUEUE_HANDLE Handle) 00637 { 00638 /* Release the lock */ 00639 KeReleaseInStackQueuedSpinLock(Handle); 00640 } 00641 00642 FORCEINLINE 00643 VOID 00644 KiReleaseProcessLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE Handle) 00645 { 00646 /* Release the lock */ 00647 KeReleaseInStackQueuedSpinLockFromDpcLevel(Handle); 00648 } 00649 00650 FORCEINLINE 00651 VOID 00652 KiAcquireDeviceQueueLock(IN PKDEVICE_QUEUE DeviceQueue, 00653 IN PKLOCK_QUEUE_HANDLE DeviceLock) 00654 { 00655 /* Check if we were called from a threaded DPC */ 00656 if (KeGetCurrentPrcb()->DpcThreadActive) 00657 { 00658 /* Lock the Queue, we're not at DPC level */ 00659 KeAcquireInStackQueuedSpinLock(&DeviceQueue->Lock, DeviceLock); 00660 } 00661 else 00662 { 00663 /* We must be at DPC level, acquire the lock safely */ 00664 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); 00665 KeAcquireInStackQueuedSpinLockAtDpcLevel(&DeviceQueue->Lock, 00666 DeviceLock); 00667 } 00668 } 00669 00670 FORCEINLINE 00671 VOID 00672 KiReleaseDeviceQueueLock(IN PKLOCK_QUEUE_HANDLE DeviceLock) 00673 { 00674 /* Check if we were called from a threaded DPC */ 00675 if (KeGetCurrentPrcb()->DpcThreadActive) 00676 { 00677 /* Unlock the Queue, we're not at DPC level */ 00678 KeReleaseInStackQueuedSpinLock(DeviceLock); 00679 } 00680 else 00681 { 00682 /* We must be at DPC level, release the lock safely */ 00683 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); 00684 KeReleaseInStackQueuedSpinLockFromDpcLevel(DeviceLock); 00685 } 00686 } 00687 00688 // 00689 // Satisfies the wait of any dispatcher object 00690 // 00691 #define KiSatisfyObjectWait(Object, Thread) \ 00692 { \ 00693 /* Special case for Mutants */ \ 00694 if ((Object)->Header.Type == MutantObject) \ 00695 { \ 00696 /* Decrease the Signal State */ \ 00697 (Object)->Header.SignalState--; \ 00698 \ 00699 /* Check if it's now non-signaled */ \ 00700 if (!(Object)->Header.SignalState) \ 00701 { \ 00702 /* Set the Owner Thread */ \ 00703 (Object)->OwnerThread = Thread; \ 00704 \ 00705 /* Disable APCs if needed */ \ 00706 Thread->KernelApcDisable = Thread->KernelApcDisable - \ 00707 (Object)->ApcDisable; \ 00708 \ 00709 /* Check if it's abandoned */ \ 00710 if ((Object)->Abandoned) \ 00711 { \ 00712 /* Unabandon it */ \ 00713 (Object)->Abandoned = FALSE; \ 00714 \ 00715 /* Return Status */ \ 00716 Thread->WaitStatus = STATUS_ABANDONED; \ 00717 } \ 00718 \ 00719 /* Insert it into the Mutant List */ \ 00720 InsertHeadList(Thread->MutantListHead.Blink, \ 00721 &(Object)->MutantListEntry); \ 00722 } \ 00723 } \ 00724 else if (((Object)->Header.Type & TIMER_OR_EVENT_TYPE) == \ 00725 EventSynchronizationObject) \ 00726 { \ 00727 /* Synchronization Timers and Events just get un-signaled */ \ 00728 (Object)->Header.SignalState = 0; \ 00729 } \ 00730 else if ((Object)->Header.Type == SemaphoreObject) \ 00731 { \ 00732 /* These ones can have multiple states, so we only decrease it */ \ 00733 (Object)->Header.SignalState--; \ 00734 } \ 00735 } 00736 00737 // 00738 // Satisfies the wait of a mutant dispatcher object 00739 // 00740 #define KiSatisfyMutantWait(Object, Thread) \ 00741 { \ 00742 /* Decrease the Signal State */ \ 00743 (Object)->Header.SignalState--; \ 00744 \ 00745 /* Check if it's now non-signaled */ \ 00746 if (!(Object)->Header.SignalState) \ 00747 { \ 00748 /* Set the Owner Thread */ \ 00749 (Object)->OwnerThread = Thread; \ 00750 \ 00751 /* Disable APCs if needed */ \ 00752 Thread->KernelApcDisable = Thread->KernelApcDisable - \ 00753 (Object)->ApcDisable; \ 00754 \ 00755 /* Check if it's abandoned */ \ 00756 if ((Object)->Abandoned) \ 00757 { \ 00758 /* Unabandon it */ \ 00759 (Object)->Abandoned = FALSE; \ 00760 \ 00761 /* Return Status */ \ 00762 Thread->WaitStatus = STATUS_ABANDONED; \ 00763 } \ 00764 \ 00765 /* Insert it into the Mutant List */ \ 00766 InsertHeadList(Thread->MutantListHead.Blink, \ 00767 &(Object)->MutantListEntry); \ 00768 } \ 00769 } 00770 00771 // 00772 // Satisfies the wait of any nonmutant dispatcher object 00773 // 00774 #define KiSatisfyNonMutantWait(Object) \ 00775 { \ 00776 if (((Object)->Header.Type & TIMER_OR_EVENT_TYPE) == \ 00777 EventSynchronizationObject) \ 00778 { \ 00779 /* Synchronization Timers and Events just get un-signaled */ \ 00780 (Object)->Header.SignalState = 0; \ 00781 } \ 00782 else if ((Object)->Header.Type == SemaphoreObject) \ 00783 { \ 00784 /* These ones can have multiple states, so we only decrease it */ \ 00785 (Object)->Header.SignalState--; \ 00786 } \ 00787 } 00788 00789 // 00790 // Recalculates the due time 00791 // 00792 FORCEINLINE 00793 PLARGE_INTEGER 00794 KiRecalculateDueTime(IN PLARGE_INTEGER OriginalDueTime, 00795 IN PLARGE_INTEGER DueTime, 00796 IN OUT PLARGE_INTEGER NewDueTime) 00797 { 00798 /* Don't do anything for absolute waits */ 00799 if (OriginalDueTime->QuadPart >= 0) return OriginalDueTime; 00800 00801 /* Otherwise, query the interrupt time and recalculate */ 00802 NewDueTime->QuadPart = KeQueryInterruptTime(); 00803 NewDueTime->QuadPart -= DueTime->QuadPart; 00804 return NewDueTime; 00805 } 00806 00807 // 00808 // Determines whether a thread should be added to the wait list 00809 // 00810 FORCEINLINE 00811 BOOLEAN 00812 KiCheckThreadStackSwap(IN PKTHREAD Thread, 00813 IN KPROCESSOR_MODE WaitMode) 00814 { 00815 /* Check the required conditions */ 00816 if ((WaitMode != KernelMode) && 00817 (Thread->EnableStackSwap) && 00818 (Thread->Priority >= (LOW_REALTIME_PRIORITY + 9))) 00819 { 00820 /* We are go for swap */ 00821 return TRUE; 00822 } 00823 else 00824 { 00825 /* Don't swap the thread */ 00826 return FALSE; 00827 } 00828 } 00829 00830 // 00831 // Adds a thread to the wait list 00832 // 00833 #define KiAddThreadToWaitList(Thread, Swappable) \ 00834 { \ 00835 /* Make sure it's swappable */ \ 00836 if (Swappable) \ 00837 { \ 00838 /* Insert it into the PRCB's List */ \ 00839 InsertTailList(&KeGetCurrentPrcb()->WaitListHead, \ 00840 &Thread->WaitListEntry); \ 00841 } \ 00842 } 00843 00844 // 00845 // Checks if a wait in progress should be interrupted by APCs or an alertable 00846 // state. 00847 // 00848 FORCEINLINE 00849 NTSTATUS 00850 KiCheckAlertability(IN PKTHREAD Thread, 00851 IN BOOLEAN Alertable, 00852 IN KPROCESSOR_MODE WaitMode) 00853 { 00854 /* Check if the wait is alertable */ 00855 if (Alertable) 00856 { 00857 /* It is, first check if the thread is alerted in this mode */ 00858 if (Thread->Alerted[WaitMode]) 00859 { 00860 /* It is, so bail out of the wait */ 00861 Thread->Alerted[WaitMode] = FALSE; 00862 return STATUS_ALERTED; 00863 } 00864 else if ((WaitMode != KernelMode) && 00865 (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) 00866 { 00867 /* It's isn't, but this is a user wait with queued user APCs */ 00868 Thread->ApcState.UserApcPending = TRUE; 00869 return STATUS_USER_APC; 00870 } 00871 else if (Thread->Alerted[KernelMode]) 00872 { 00873 /* It isn't that either, but we're alered in kernel mode */ 00874 Thread->Alerted[KernelMode] = FALSE; 00875 return STATUS_ALERTED; 00876 } 00877 } 00878 else if ((WaitMode != KernelMode) && (Thread->ApcState.UserApcPending)) 00879 { 00880 /* Not alertable, but this is a user wait with pending user APCs */ 00881 return STATUS_USER_APC; 00882 } 00883 00884 /* Otherwise, we're fine */ 00885 return STATUS_WAIT_0; 00886 } 00887 00888 ULONG 00889 FORCEINLINE 00890 KiComputeTimerTableIndex(IN ULONGLONG DueTime) 00891 { 00892 return (DueTime / KeMaximumIncrement) & (TIMER_TABLE_SIZE - 1); 00893 } 00894 00895 // 00896 // Called from KiCompleteTimer, KiInsertTreeTimer, KeSetSystemTime 00897 // to remove timer entries 00898 // See Windows HPI blog for more information. 00899 FORCEINLINE 00900 VOID 00901 KiRemoveEntryTimer(IN PKTIMER Timer) 00902 { 00903 ULONG Hand; 00904 PKTIMER_TABLE_ENTRY TableEntry; 00905 00906 /* Remove the timer from the timer list and check if it's empty */ 00907 Hand = Timer->Header.Hand; 00908 if (RemoveEntryList(&Timer->TimerListEntry)) 00909 { 00910 /* Get the respective timer table entry */ 00911 TableEntry = &KiTimerTableListHead[Hand]; 00912 if (&TableEntry->Entry == TableEntry->Entry.Flink) 00913 { 00914 /* Set the entry to an infinite absolute time */ 00915 TableEntry->Time.HighPart = 0xFFFFFFFF; 00916 } 00917 } 00918 00919 /* Clear the list entries on dbg builds so we can tell the timer is gone */ 00920 #if DBG 00921 Timer->TimerListEntry.Flink = NULL; 00922 Timer->TimerListEntry.Blink = NULL; 00923 #endif 00924 } 00925 00926 // 00927 // Called by Wait and Queue code to insert a timer for dispatching. 00928 // Also called by KeSetTimerEx to insert a timer from the caller. 00929 // 00930 FORCEINLINE 00931 VOID 00932 KxInsertTimer(IN PKTIMER Timer, 00933 IN ULONG Hand) 00934 { 00935 PKSPIN_LOCK_QUEUE LockQueue; 00936 00937 /* Acquire the lock and release the dispatcher lock */ 00938 LockQueue = KiAcquireTimerLock(Hand); 00939 KiReleaseDispatcherLockFromDpcLevel(); 00940 00941 /* Try to insert the timer */ 00942 if (KiInsertTimerTable(Timer, Hand)) 00943 { 00944 /* Complete it */ 00945 KiCompleteTimer(Timer, LockQueue); 00946 } 00947 else 00948 { 00949 /* Do nothing, just release the lock */ 00950 KiReleaseTimerLock(LockQueue); 00951 } 00952 } 00953 00954 // 00955 // Called by KeSetTimerEx and KiInsertTreeTimer to calculate Due Time 00956 // See the Windows HPI Blog for more information 00957 // 00958 FORCEINLINE 00959 BOOLEAN 00960 KiComputeDueTime(IN PKTIMER Timer, 00961 IN LARGE_INTEGER DueTime, 00962 OUT PULONG Hand) 00963 { 00964 LARGE_INTEGER InterruptTime, SystemTime, DifferenceTime; 00965 00966 /* Convert to relative time if needed */ 00967 Timer->Header.Absolute = FALSE; 00968 if (DueTime.HighPart >= 0) 00969 { 00970 /* Get System Time */ 00971 KeQuerySystemTime(&SystemTime); 00972 00973 /* Do the conversion */ 00974 DifferenceTime.QuadPart = SystemTime.QuadPart - DueTime.QuadPart; 00975 00976 /* Make sure it hasn't already expired */ 00977 Timer->Header.Absolute = TRUE; 00978 if (DifferenceTime.HighPart >= 0) 00979 { 00980 /* Cancel everything */ 00981 Timer->Header.SignalState = TRUE; 00982 Timer->Header.Hand = 0; 00983 Timer->DueTime.QuadPart = 0; 00984 *Hand = 0; 00985 return FALSE; 00986 } 00987 00988 /* Set the time as Absolute */ 00989 DueTime = DifferenceTime; 00990 } 00991 00992 /* Get the Interrupt Time */ 00993 InterruptTime.QuadPart = KeQueryInterruptTime(); 00994 00995 /* Recalculate due time */ 00996 Timer->DueTime.QuadPart = InterruptTime.QuadPart - DueTime.QuadPart; 00997 00998 /* Get the handle */ 00999 *Hand = KiComputeTimerTableIndex(Timer->DueTime.QuadPart); 01000 Timer->Header.Hand = (UCHAR)*Hand; 01001 Timer->Header.Inserted = TRUE; 01002 return TRUE; 01003 } 01004 01005 // 01006 // Called from Unlink and Queue Insert Code. 01007 // Also called by timer code when canceling an inserted timer. 01008 // Removes a timer from it's tree. 01009 // 01010 FORCEINLINE 01011 VOID 01012 KxRemoveTreeTimer(IN PKTIMER Timer) 01013 { 01014 ULONG Hand = Timer->Header.Hand; 01015 PKSPIN_LOCK_QUEUE LockQueue; 01016 PKTIMER_TABLE_ENTRY TimerEntry; 01017 01018 /* Acquire timer lock */ 01019 LockQueue = KiAcquireTimerLock(Hand); 01020 01021 /* Set the timer as non-inserted */ 01022 Timer->Header.Inserted = FALSE; 01023 01024 /* Remove it from the timer list */ 01025 if (RemoveEntryList(&Timer->TimerListEntry)) 01026 { 01027 /* Get the entry and check if it's empty */ 01028 TimerEntry = &KiTimerTableListHead[Hand]; 01029 if (IsListEmpty(&TimerEntry->Entry)) 01030 { 01031 /* Clear the time then */ 01032 TimerEntry->Time.HighPart = 0xFFFFFFFF; 01033 } 01034 } 01035 01036 /* Release the timer lock */ 01037 KiReleaseTimerLock(LockQueue); 01038 } 01039 01040 FORCEINLINE 01041 VOID 01042 KxSetTimerForThreadWait(IN PKTIMER Timer, 01043 IN LARGE_INTEGER Interval, 01044 OUT PULONG Hand) 01045 { 01046 ULONGLONG DueTime; 01047 LARGE_INTEGER InterruptTime, SystemTime, TimeDifference; 01048 01049 /* Check the timer's interval to see if it's absolute */ 01050 Timer->Header.Absolute = FALSE; 01051 if (Interval.HighPart >= 0) 01052 { 01053 /* Get the system time and calculate the relative time */ 01054 KeQuerySystemTime(&SystemTime); 01055 TimeDifference.QuadPart = SystemTime.QuadPart - Interval.QuadPart; 01056 Timer->Header.Absolute = TRUE; 01057 01058 /* Check if we've already expired */ 01059 if (TimeDifference.HighPart >= 0) 01060 { 01061 /* Reset everything */ 01062 Timer->DueTime.QuadPart = 0; 01063 *Hand = 0; 01064 Timer->Header.Hand = 0; 01065 return; 01066 } 01067 else 01068 { 01069 /* Update the interval */ 01070 Interval = TimeDifference; 01071 } 01072 } 01073 01074 /* Calculate the due time */ 01075 InterruptTime.QuadPart = KeQueryInterruptTime(); 01076 DueTime = InterruptTime.QuadPart - Interval.QuadPart; 01077 Timer->DueTime.QuadPart = DueTime; 01078 01079 /* Calculate the timer handle */ 01080 *Hand = KiComputeTimerTableIndex(DueTime); 01081 Timer->Header.Hand = (UCHAR)*Hand; 01082 } 01083 01084 #define KxDelayThreadWait() \ 01085 \ 01086 /* Setup the Wait Block */ \ 01087 Thread->WaitBlockList = TimerBlock; \ 01088 \ 01089 /* Setup the timer */ \ 01090 KxSetTimerForThreadWait(Timer, *Interval, &Hand); \ 01091 \ 01092 /* Save the due time for the caller */ \ 01093 DueTime.QuadPart = Timer->DueTime.QuadPart; \ 01094 \ 01095 /* Link the timer to this Wait Block */ \ 01096 TimerBlock->NextWaitBlock = TimerBlock; \ 01097 Timer->Header.WaitListHead.Flink = &TimerBlock->WaitListEntry; \ 01098 Timer->Header.WaitListHead.Blink = &TimerBlock->WaitListEntry; \ 01099 \ 01100 /* Clear wait status */ \ 01101 Thread->WaitStatus = STATUS_SUCCESS; \ 01102 \ 01103 /* Setup wait fields */ \ 01104 Thread->Alertable = Alertable; \ 01105 Thread->WaitReason = DelayExecution; \ 01106 Thread->WaitMode = WaitMode; \ 01107 \ 01108 /* Check if we can swap the thread's stack */ \ 01109 Thread->WaitListEntry.Flink = NULL; \ 01110 Swappable = KiCheckThreadStackSwap(Thread, WaitMode); \ 01111 \ 01112 /* Set the wait time */ \ 01113 Thread->WaitTime = KeTickCount.LowPart; 01114 01115 #define KxMultiThreadWait() \ 01116 /* Link wait block array to the thread */ \ 01117 Thread->WaitBlockList = WaitBlockArray; \ 01118 \ 01119 /* Reset the index */ \ 01120 Index = 0; \ 01121 \ 01122 /* Loop wait blocks */ \ 01123 do \ 01124 { \ 01125 /* Fill out the wait block */ \ 01126 WaitBlock = &WaitBlockArray[Index]; \ 01127 WaitBlock->Object = Object[Index]; \ 01128 WaitBlock->WaitKey = (USHORT)Index; \ 01129 WaitBlock->WaitType = WaitType; \ 01130 WaitBlock->Thread = Thread; \ 01131 \ 01132 /* Link to next block */ \ 01133 WaitBlock->NextWaitBlock = &WaitBlockArray[Index + 1]; \ 01134 Index++; \ 01135 } while (Index < Count); \ 01136 \ 01137 /* Link the last block */ \ 01138 WaitBlock->NextWaitBlock = WaitBlockArray; \ 01139 \ 01140 /* Set default wait status */ \ 01141 Thread->WaitStatus = STATUS_WAIT_0; \ 01142 \ 01143 /* Check if we have a timer */ \ 01144 if (Timeout) \ 01145 { \ 01146 /* Link to the block */ \ 01147 TimerBlock->NextWaitBlock = WaitBlockArray; \ 01148 \ 01149 /* Setup the timer */ \ 01150 KxSetTimerForThreadWait(Timer, *Timeout, &Hand); \ 01151 \ 01152 /* Save the due time for the caller */ \ 01153 DueTime.QuadPart = Timer->DueTime.QuadPart; \ 01154 \ 01155 /* Initialize the list */ \ 01156 InitializeListHead(&Timer->Header.WaitListHead); \ 01157 } \ 01158 \ 01159 /* Set wait settings */ \ 01160 Thread->Alertable = Alertable; \ 01161 Thread->WaitMode = WaitMode; \ 01162 Thread->WaitReason = WaitReason; \ 01163 \ 01164 /* Check if we can swap the thread's stack */ \ 01165 Thread->WaitListEntry.Flink = NULL; \ 01166 Swappable = KiCheckThreadStackSwap(Thread, WaitMode); \ 01167 \ 01168 /* Set the wait time */ \ 01169 Thread->WaitTime = KeTickCount.LowPart; 01170 01171 #define KxSingleThreadWait() \ 01172 /* Setup the Wait Block */ \ 01173 Thread->WaitBlockList = WaitBlock; \ 01174 WaitBlock->WaitKey = STATUS_SUCCESS; \ 01175 WaitBlock->Object = Object; \ 01176 WaitBlock->WaitType = WaitAny; \ 01177 \ 01178 /* Clear wait status */ \ 01179 Thread->WaitStatus = STATUS_SUCCESS; \ 01180 \ 01181 /* Check if we have a timer */ \ 01182 if (Timeout) \ 01183 { \ 01184 /* Setup the timer */ \ 01185 KxSetTimerForThreadWait(Timer, *Timeout, &Hand); \ 01186 \ 01187 /* Save the due time for the caller */ \ 01188 DueTime.QuadPart = Timer->DueTime.QuadPart; \ 01189 \ 01190 /* Pointer to timer block */ \ 01191 WaitBlock->NextWaitBlock = TimerBlock; \ 01192 TimerBlock->NextWaitBlock = WaitBlock; \ 01193 \ 01194 /* Link the timer to this Wait Block */ \ 01195 Timer->Header.WaitListHead.Flink = &TimerBlock->WaitListEntry; \ 01196 Timer->Header.WaitListHead.Blink = &TimerBlock->WaitListEntry; \ 01197 } \ 01198 else \ 01199 { \ 01200 /* No timer block, just ourselves */ \ 01201 WaitBlock->NextWaitBlock = WaitBlock; \ 01202 } \ 01203 \ 01204 /* Set wait settings */ \ 01205 Thread->Alertable = Alertable; \ 01206 Thread->WaitMode = WaitMode; \ 01207 Thread->WaitReason = WaitReason; \ 01208 \ 01209 /* Check if we can swap the thread's stack */ \ 01210 Thread->WaitListEntry.Flink = NULL; \ 01211 Swappable = KiCheckThreadStackSwap(Thread, WaitMode); \ 01212 \ 01213 /* Set the wait time */ \ 01214 Thread->WaitTime = KeTickCount.LowPart; 01215 01216 #define KxQueueThreadWait() \ 01217 /* Setup the Wait Block */ \ 01218 Thread->WaitBlockList = WaitBlock; \ 01219 WaitBlock->WaitKey = STATUS_SUCCESS; \ 01220 WaitBlock->Object = Queue; \ 01221 WaitBlock->WaitType = WaitAny; \ 01222 WaitBlock->Thread = Thread; \ 01223 \ 01224 /* Clear wait status */ \ 01225 Thread->WaitStatus = STATUS_SUCCESS; \ 01226 \ 01227 /* Check if we have a timer */ \ 01228 if (Timeout) \ 01229 { \ 01230 /* Setup the timer */ \ 01231 KxSetTimerForThreadWait(Timer, *Timeout, &Hand); \ 01232 \ 01233 /* Save the due time for the caller */ \ 01234 DueTime.QuadPart = Timer->DueTime.QuadPart; \ 01235 \ 01236 /* Pointer to timer block */ \ 01237 WaitBlock->NextWaitBlock = TimerBlock; \ 01238 TimerBlock->NextWaitBlock = WaitBlock; \ 01239 \ 01240 /* Link the timer to this Wait Block */ \ 01241 Timer->Header.WaitListHead.Flink = &TimerBlock->WaitListEntry; \ 01242 Timer->Header.WaitListHead.Blink = &TimerBlock->WaitListEntry; \ 01243 } \ 01244 else \ 01245 { \ 01246 /* No timer block, just ourselves */ \ 01247 WaitBlock->NextWaitBlock = WaitBlock; \ 01248 } \ 01249 \ 01250 /* Set wait settings */ \ 01251 Thread->Alertable = FALSE; \ 01252 Thread->WaitMode = WaitMode; \ 01253 Thread->WaitReason = WrQueue; \ 01254 \ 01255 /* Check if we can swap the thread's stack */ \ 01256 Thread->WaitListEntry.Flink = NULL; \ 01257 Swappable = KiCheckThreadStackSwap(Thread, WaitMode); \ 01258 \ 01259 /* Set the wait time */ \ 01260 Thread->WaitTime = KeTickCount.LowPart; 01261 01262 // 01263 // Unwaits a Thread 01264 // 01265 FORCEINLINE 01266 VOID 01267 KxUnwaitThread(IN DISPATCHER_HEADER *Object, 01268 IN KPRIORITY Increment) 01269 { 01270 PLIST_ENTRY WaitEntry, WaitList; 01271 PKWAIT_BLOCK WaitBlock; 01272 PKTHREAD WaitThread; 01273 ULONG WaitKey; 01274 01275 /* Loop the Wait Entries */ 01276 WaitList = &Object->WaitListHead; 01277 ASSERT(IsListEmpty(&Object->WaitListHead) == FALSE); 01278 WaitEntry = WaitList->Flink; 01279 do 01280 { 01281 /* Get the current wait block */ 01282 WaitBlock = CONTAINING_RECORD(WaitEntry, KWAIT_BLOCK, WaitListEntry); 01283 01284 /* Get the waiting thread */ 01285 WaitThread = WaitBlock->Thread; 01286 01287 /* Check the current Wait Mode */ 01288 if (WaitBlock->WaitType == WaitAny) 01289 { 01290 /* Use the actual wait key */ 01291 WaitKey = WaitBlock->WaitKey; 01292 } 01293 else 01294 { 01295 /* Otherwise, use STATUS_KERNEL_APC */ 01296 WaitKey = STATUS_KERNEL_APC; 01297 } 01298 01299 /* Unwait the thread */ 01300 KiUnwaitThread(WaitThread, WaitKey, Increment); 01301 01302 /* Next entry */ 01303 WaitEntry = WaitList->Flink; 01304 } while (WaitEntry != WaitList); 01305 } 01306 01307 // 01308 // Unwaits a Thread waiting on an event 01309 // 01310 FORCEINLINE 01311 VOID 01312 KxUnwaitThreadForEvent(IN PKEVENT Event, 01313 IN KPRIORITY Increment) 01314 { 01315 PLIST_ENTRY WaitEntry, WaitList; 01316 PKWAIT_BLOCK WaitBlock; 01317 PKTHREAD WaitThread; 01318 01319 /* Loop the Wait Entries */ 01320 WaitList = &Event->Header.WaitListHead; 01321 ASSERT(IsListEmpty(&Event->Header.WaitListHead) == FALSE); 01322 WaitEntry = WaitList->Flink; 01323 do 01324 { 01325 /* Get the current wait block */ 01326 WaitBlock = CONTAINING_RECORD(WaitEntry, KWAIT_BLOCK, WaitListEntry); 01327 01328 /* Get the waiting thread */ 01329 WaitThread = WaitBlock->Thread; 01330 01331 /* Check the current Wait Mode */ 01332 if (WaitBlock->WaitType == WaitAny) 01333 { 01334 /* Un-signal it */ 01335 Event->Header.SignalState = 0; 01336 01337 /* Un-signal the event and unwait the thread */ 01338 KiUnwaitThread(WaitThread, WaitBlock->WaitKey, Increment); 01339 break; 01340 } 01341 01342 /* Unwait the thread with STATUS_KERNEL_APC */ 01343 KiUnwaitThread(WaitThread, STATUS_KERNEL_APC, Increment); 01344 01345 /* Next entry */ 01346 WaitEntry = WaitList->Flink; 01347 } while (WaitEntry != WaitList); 01348 } 01349 01350 // 01351 // This routine queues a thread that is ready on the PRCB's ready lists. 01352 // If this thread cannot currently run on this CPU, then the thread is 01353 // added to the deferred ready list instead. 01354 // 01355 // This routine must be entered with the PRCB lock held and it will exit 01356 // with the PRCB lock released! 01357 // 01358 FORCEINLINE 01359 VOID 01360 KxQueueReadyThread(IN PKTHREAD Thread, 01361 IN PKPRCB Prcb) 01362 { 01363 BOOLEAN Preempted; 01364 KPRIORITY Priority; 01365 01366 /* Sanity checks */ 01367 ASSERT(Prcb == KeGetCurrentPrcb()); 01368 ASSERT(Thread->State == Running); 01369 ASSERT(Thread->NextProcessor == Prcb->Number); 01370 01371 /* Check if this thread is allowed to run in this CPU */ 01372 #ifdef CONFIG_SMP 01373 if ((Thread->Affinity) & (Prcb->SetMember)) 01374 #else 01375 if (TRUE) 01376 #endif 01377 { 01378 /* Set thread ready for execution */ 01379 Thread->State = Ready; 01380 01381 /* Save current priority and if someone had pre-empted it */ 01382 Priority = Thread->Priority; 01383 Preempted = Thread->Preempted; 01384 01385 /* We're not pre-empting now, and set the wait time */ 01386 Thread->Preempted = FALSE; 01387 Thread->WaitTime = KeTickCount.LowPart; 01388 01389 /* Sanity check */ 01390 ASSERT((Priority >= 0) && (Priority <= HIGH_PRIORITY)); 01391 01392 /* Insert this thread in the appropriate order */ 01393 Preempted ? InsertHeadList(&Prcb->DispatcherReadyListHead[Priority], 01394 &Thread->WaitListEntry) : 01395 InsertTailList(&Prcb->DispatcherReadyListHead[Priority], 01396 &Thread->WaitListEntry); 01397 01398 /* Update the ready summary */ 01399 Prcb->ReadySummary |= PRIORITY_MASK(Priority); 01400 01401 /* Sanity check */ 01402 ASSERT(Priority == Thread->Priority); 01403 01404 /* Release the PRCB lock */ 01405 KiReleasePrcbLock(Prcb); 01406 } 01407 else 01408 { 01409 /* Otherwise, prepare this thread to be deferred */ 01410 Thread->State = DeferredReady; 01411 Thread->DeferredProcessor = Prcb->Number; 01412 01413 /* Release the lock and defer scheduling */ 01414 KiReleasePrcbLock(Prcb); 01415 KiDeferredReadyThread(Thread); 01416 } 01417 } 01418 01419 // 01420 // This routine scans for an appropriate ready thread to select at the 01421 // given priority and for the given CPU. 01422 // 01423 FORCEINLINE 01424 PKTHREAD 01425 KiSelectReadyThread(IN KPRIORITY Priority, 01426 IN PKPRCB Prcb) 01427 { 01428 ULONG PrioritySet; 01429 LONG HighPriority; 01430 PLIST_ENTRY ListEntry; 01431 PKTHREAD Thread = NULL; 01432 01433 /* Save the current mask and get the priority set for the CPU */ 01434 PrioritySet = Prcb->ReadySummary >> Priority; 01435 if (!PrioritySet) goto Quickie; 01436 01437 /* Get the highest priority possible */ 01438 BitScanReverse((PULONG)&HighPriority, PrioritySet); 01439 ASSERT((PrioritySet & PRIORITY_MASK(HighPriority)) != 0); 01440 HighPriority += Priority; 01441 01442 /* Make sure the list isn't empty at the highest priority */ 01443 ASSERT(IsListEmpty(&Prcb->DispatcherReadyListHead[HighPriority]) == FALSE); 01444 01445 /* Get the first thread on the list */ 01446 ListEntry = Prcb->DispatcherReadyListHead[HighPriority].Flink; 01447 Thread = CONTAINING_RECORD(ListEntry, KTHREAD, WaitListEntry); 01448 01449 /* Make sure this thread is here for a reason */ 01450 ASSERT(HighPriority == Thread->Priority); 01451 ASSERT(Thread->Affinity & AFFINITY_MASK(Prcb->Number)); 01452 ASSERT(Thread->NextProcessor == Prcb->Number); 01453 01454 /* Remove it from the list */ 01455 if (RemoveEntryList(&Thread->WaitListEntry)) 01456 { 01457 /* The list is empty now, reset the ready summary */ 01458 Prcb->ReadySummary ^= PRIORITY_MASK(HighPriority); 01459 } 01460 01461 /* Sanity check and return the thread */ 01462 Quickie: 01463 ASSERT((Thread == NULL) || 01464 (Thread->BasePriority == 0) || 01465 (Thread->Priority != 0)); 01466 return Thread; 01467 } 01468 01469 // 01470 // This routine computes the new priority for a thread. It is only valid for 01471 // threads with priorities in the dynamic priority range. 01472 // 01473 FORCEINLINE 01474 SCHAR 01475 KiComputeNewPriority(IN PKTHREAD Thread, 01476 IN SCHAR Adjustment) 01477 { 01478 SCHAR Priority; 01479 01480 /* Priority sanity checks */ 01481 ASSERT((Thread->PriorityDecrement >= 0) && 01482 (Thread->PriorityDecrement <= Thread->Priority)); 01483 ASSERT((Thread->Priority < LOW_REALTIME_PRIORITY) ? 01484 TRUE : (Thread->PriorityDecrement == 0)); 01485 01486 /* Get the current priority */ 01487 Priority = Thread->Priority; 01488 if (Priority < LOW_REALTIME_PRIORITY) 01489 { 01490 /* Decrease priority by the priority decrement */ 01491 Priority -= (Thread->PriorityDecrement + Adjustment); 01492 01493 /* Don't go out of bounds */ 01494 if (Priority < Thread->BasePriority) Priority = Thread->BasePriority; 01495 01496 /* Reset the priority decrement */ 01497 Thread->PriorityDecrement = 0; 01498 } 01499 01500 /* Sanity check */ 01501 ASSERT((Thread->BasePriority == 0) || (Priority != 0)); 01502 01503 /* Return the new priority */ 01504 return Priority; 01505 } 01506 01507 // 01508 // Guarded Mutex Routines 01509 // 01510 FORCEINLINE 01511 VOID 01512 _KeInitializeGuardedMutex(OUT PKGUARDED_MUTEX GuardedMutex) 01513 { 01514 /* Setup the Initial Data */ 01515 GuardedMutex->Count = GM_LOCK_BIT; 01516 GuardedMutex->Owner = NULL; 01517 GuardedMutex->Contention = 0; 01518 01519 /* Initialize the Wait Gate */ 01520 KeInitializeGate(&GuardedMutex->Gate); 01521 } 01522 01523 FORCEINLINE 01524 VOID 01525 _KeAcquireGuardedMutexUnsafe(IN OUT PKGUARDED_MUTEX GuardedMutex) 01526 { 01527 PKTHREAD Thread = KeGetCurrentThread(); 01528 01529 /* Sanity checks */ 01530 ASSERT((KeGetCurrentIrql() == APC_LEVEL) || 01531 (Thread->SpecialApcDisable < 0) || 01532 (Thread->Teb == NULL) || 01533 (Thread->Teb >= (PTEB)MM_SYSTEM_RANGE_START)); 01534 ASSERT(GuardedMutex->Owner != Thread); 01535 01536 /* Remove the lock */ 01537 if (!InterlockedBitTestAndReset(&GuardedMutex->Count, GM_LOCK_BIT_V)) 01538 { 01539 /* The Guarded Mutex was already locked, enter contented case */ 01540 KiAcquireGuardedMutex(GuardedMutex); 01541 } 01542 01543 /* Set the Owner */ 01544 GuardedMutex->Owner = Thread; 01545 } 01546 01547 FORCEINLINE 01548 VOID 01549 _KeReleaseGuardedMutexUnsafe(IN OUT PKGUARDED_MUTEX GuardedMutex) 01550 { 01551 LONG OldValue, NewValue; 01552 01553 /* Sanity checks */ 01554 ASSERT((KeGetCurrentIrql() == APC_LEVEL) || 01555 (KeGetCurrentThread()->SpecialApcDisable < 0) || 01556 (KeGetCurrentThread()->Teb == NULL) || 01557 (KeGetCurrentThread()->Teb >= (PTEB)MM_SYSTEM_RANGE_START)); 01558 ASSERT(GuardedMutex->Owner == KeGetCurrentThread()); 01559 01560 /* Destroy the Owner */ 01561 GuardedMutex->Owner = NULL; 01562 01563 /* Add the Lock Bit */ 01564 OldValue = InterlockedExchangeAdd(&GuardedMutex->Count, GM_LOCK_BIT); 01565 ASSERT((OldValue & GM_LOCK_BIT) == 0); 01566 01567 /* Check if it was already locked, but not woken */ 01568 if ((OldValue) && !(OldValue & GM_LOCK_WAITER_WOKEN)) 01569 { 01570 /* Update the Oldvalue to what it should be now */ 01571 OldValue += GM_LOCK_BIT; 01572 01573 /* The mutex will be woken, minus one waiter */ 01574 NewValue = OldValue + GM_LOCK_WAITER_WOKEN - 01575 GM_LOCK_WAITER_INC; 01576 01577 /* Remove the Woken bit */ 01578 if (InterlockedCompareExchange(&GuardedMutex->Count, 01579 NewValue, 01580 OldValue) == OldValue) 01581 { 01582 /* Signal the Gate */ 01583 KeSignalGateBoostPriority(&GuardedMutex->Gate); 01584 } 01585 } 01586 } 01587 01588 FORCEINLINE 01589 VOID 01590 _KeAcquireGuardedMutex(IN PKGUARDED_MUTEX GuardedMutex) 01591 { 01592 PKTHREAD Thread = KeGetCurrentThread(); 01593 01594 /* Sanity checks */ 01595 ASSERT(KeGetCurrentIrql() <= APC_LEVEL); 01596 ASSERT(GuardedMutex->Owner != Thread); 01597 01598 /* Disable Special APCs */ 01599 KeEnterGuardedRegion(); 01600 01601 /* Remove the lock */ 01602 if (!InterlockedBitTestAndReset(&GuardedMutex->Count, GM_LOCK_BIT_V)) 01603 { 01604 /* The Guarded Mutex was already locked, enter contented case */ 01605 KiAcquireGuardedMutex(GuardedMutex); 01606 } 01607 01608 /* Set the Owner and Special APC Disable state */ 01609 GuardedMutex->Owner = Thread; 01610 GuardedMutex->SpecialApcDisable = Thread->SpecialApcDisable; 01611 } 01612 01613 FORCEINLINE 01614 VOID 01615 _KeReleaseGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex) 01616 { 01617 LONG OldValue, NewValue; 01618 01619 /* Sanity checks */ 01620 ASSERT(KeGetCurrentIrql() <= APC_LEVEL); 01621 ASSERT(GuardedMutex->Owner == KeGetCurrentThread()); 01622 ASSERT(KeGetCurrentThread()->SpecialApcDisable == 01623 GuardedMutex->SpecialApcDisable); 01624 01625 /* Destroy the Owner */ 01626 GuardedMutex->Owner = NULL; 01627 01628 /* Add the Lock Bit */ 01629 OldValue = InterlockedExchangeAdd(&GuardedMutex->Count, GM_LOCK_BIT); 01630 ASSERT((OldValue & GM_LOCK_BIT) == 0); 01631 01632 /* Check if it was already locked, but not woken */ 01633 if ((OldValue) && !(OldValue & GM_LOCK_WAITER_WOKEN)) 01634 { 01635 /* Update the Oldvalue to what it should be now */ 01636 OldValue += GM_LOCK_BIT; 01637 01638 /* The mutex will be woken, minus one waiter */ 01639 NewValue = OldValue + GM_LOCK_WAITER_WOKEN - 01640 GM_LOCK_WAITER_INC; 01641 01642 /* Remove the Woken bit */ 01643 if (InterlockedCompareExchange(&GuardedMutex->Count, 01644 NewValue, 01645 OldValue) == OldValue) 01646 { 01647 /* Signal the Gate */ 01648 KeSignalGateBoostPriority(&GuardedMutex->Gate); 01649 } 01650 } 01651 01652 /* Re-enable APCs */ 01653 KeLeaveGuardedRegion(); 01654 } 01655 01656 FORCEINLINE 01657 BOOLEAN 01658 _KeTryToAcquireGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex) 01659 { 01660 PKTHREAD Thread = KeGetCurrentThread(); 01661 01662 /* Block APCs */ 01663 KeEnterGuardedRegion(); 01664 01665 /* Remove the lock */ 01666 if (!InterlockedBitTestAndReset(&GuardedMutex->Count, GM_LOCK_BIT_V)) 01667 { 01668 /* Re-enable APCs */ 01669 KeLeaveGuardedRegion(); 01670 YieldProcessor(); 01671 01672 /* Return failure */ 01673 return FALSE; 01674 } 01675 01676 /* Set the Owner and APC State */ 01677 GuardedMutex->Owner = Thread; 01678 GuardedMutex->SpecialApcDisable = Thread->SpecialApcDisable; 01679 return TRUE; 01680 } 01681 01682 01683 FORCEINLINE 01684 VOID 01685 KiAcquireNmiListLock(OUT PKIRQL OldIrql) 01686 { 01687 KeAcquireSpinLock(&KiNmiCallbackListLock, OldIrql); 01688 } 01689 01690 FORCEINLINE 01691 VOID 01692 KiReleaseNmiListLock(IN KIRQL OldIrql) 01693 { 01694 KeReleaseSpinLock(&KiNmiCallbackListLock, OldIrql); 01695 } Generated on Sun May 27 2012 04:37:14 for ReactOS by
1.7.6.1
|