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

ke_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 doxygen 1.7.6.1

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