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

thrdobj.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         ReactOS Kernel
00003  * LICENSE:         GPL - See COPYING in the top level directory
00004  * FILE:            ntoskrnl/ke/thrdobj.c
00005  * PURPOSE:         Implements routines to manage the Kernel Thread Object
00006  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
00007  */
00008 
00009 /* INCLUDES ******************************************************************/
00010 
00011 #include <ntoskrnl.h>
00012 #define NDEBUG
00013 #include <debug.h>
00014 
00015 extern EX_WORK_QUEUE ExWorkerQueue[MaximumWorkQueue];
00016 extern LIST_ENTRY PspReaperListHead;
00017 
00018 ULONG KiMask32Array[MAXIMUM_PRIORITY] =
00019 {
00020     0x1,        0x2,       0x4,       0x8,       0x10,       0x20,
00021     0x40,       0x80,      0x100,     0x200,     0x400,      0x800,
00022     0x1000,     0x2000,    0x4000,    0x8000,    0x10000,    0x20000,
00023     0x40000,    0x80000,   0x100000,  0x200000,  0x400000,   0x800000,
00024     0x1000000,  0x2000000, 0x4000000, 0x8000000, 0x10000000, 0x20000000,
00025     0x40000000, 0x80000000
00026 };
00027 
00028 /* FUNCTIONS *****************************************************************/
00029 
00030 UCHAR
00031 NTAPI
00032 KeFindNextRightSetAffinity(IN UCHAR Number,
00033                            IN ULONG Set)
00034 {
00035     ULONG Bit, Result;
00036     ASSERT(Set != 0);
00037 
00038     /* Calculate the mask */
00039     Bit = (AFFINITY_MASK(Number) - 1) & Set;
00040 
00041     /* If it's 0, use the one we got */
00042     if (!Bit) Bit = Set;
00043 
00044     /* Now find the right set and return it */
00045     BitScanReverse(&Result, Bit);
00046     return (UCHAR)Result;
00047 }
00048 
00049 BOOLEAN
00050 NTAPI
00051 KeReadStateThread(IN PKTHREAD Thread)
00052 {
00053     ASSERT_THREAD(Thread);
00054 
00055     /* Return signal state */
00056     return (BOOLEAN)Thread->Header.SignalState;
00057 }
00058 
00059 KPRIORITY
00060 NTAPI
00061 KeQueryBasePriorityThread(IN PKTHREAD Thread)
00062 {
00063     LONG BaseIncrement;
00064     KIRQL OldIrql;
00065     PKPROCESS Process;
00066     ASSERT_THREAD(Thread);
00067     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
00068 
00069     /* Raise IRQL to synch level */
00070     OldIrql = KeRaiseIrqlToSynchLevel();
00071 
00072     /* Lock the thread */
00073     KiAcquireThreadLock(Thread);
00074 
00075     /* Get the Process */
00076     Process = Thread->ApcStatePointer[0]->Process;
00077 
00078     /* Calculate the base increment */
00079     BaseIncrement = Thread->BasePriority - Process->BasePriority;
00080 
00081     /* If saturation occured, return the saturation increment instead */
00082     if (Thread->Saturation) BaseIncrement = (HIGH_PRIORITY + 1) / 2 *
00083                                             Thread->Saturation;
00084 
00085     /* Release thread lock */
00086     KiReleaseThreadLock(Thread);
00087 
00088     /* Lower IRQl and return Increment */
00089     KeLowerIrql(OldIrql);
00090     return BaseIncrement;
00091 }
00092 
00093 BOOLEAN
00094 NTAPI
00095 KeSetDisableBoostThread(IN OUT PKTHREAD Thread,
00096                         IN BOOLEAN Disable)
00097 {
00098     ASSERT_THREAD(Thread);
00099 
00100     /* Check if we're enabling or disabling */
00101     if (Disable)
00102     {
00103         /* Set the bit */
00104         return InterlockedBitTestAndSet(&Thread->ThreadFlags, 1);
00105     }
00106     else
00107     {
00108         /* Remove the bit */
00109         return InterlockedBitTestAndReset(&Thread->ThreadFlags, 1);
00110     }
00111 }
00112 
00113 VOID
00114 NTAPI
00115 KeReadyThread(IN PKTHREAD Thread)
00116 {
00117     KIRQL OldIrql;
00118     ASSERT_THREAD(Thread);
00119     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
00120 
00121     /* Lock the Dispatcher Database */
00122     OldIrql = KiAcquireDispatcherLock();
00123 
00124     /* Make the thread ready */
00125     KiReadyThread(Thread);
00126 
00127     /* Unlock dispatcher database */
00128     KiReleaseDispatcherLock(OldIrql);
00129 }
00130 
00131 ULONG
00132 NTAPI
00133 KeAlertResumeThread(IN PKTHREAD Thread)
00134 {
00135     ULONG PreviousCount;
00136     KLOCK_QUEUE_HANDLE ApcLock;
00137     ASSERT_THREAD(Thread);
00138     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
00139 
00140     /* Lock the Dispatcher Database and the APC Queue */
00141     KiAcquireApcLock(Thread, &ApcLock);
00142     KiAcquireDispatcherLockAtDpcLevel();
00143 
00144     /* Return if Thread is already alerted. */
00145     if (!Thread->Alerted[KernelMode])
00146     {
00147         /* If it's Blocked, unblock if it we should */
00148         if ((Thread->State == Waiting) && (Thread->Alertable))
00149         {
00150             /* Abort the wait */
00151             KiUnwaitThread(Thread, STATUS_ALERTED, THREAD_ALERT_INCREMENT);
00152         }
00153         else
00154         {
00155             /* If not, simply Alert it */
00156             Thread->Alerted[KernelMode] = TRUE;
00157         }
00158     }
00159 
00160     /* Save the old Suspend Count */
00161     PreviousCount = Thread->SuspendCount;
00162 
00163     /* If the thread is suspended, decrease one of the suspend counts */
00164     if (PreviousCount)
00165     {
00166         /* Decrease count. If we are now zero, unwait it completely */
00167         Thread->SuspendCount--;
00168         if (!(Thread->SuspendCount) && !(Thread->FreezeCount))
00169         {
00170             /* Signal and satisfy */
00171             Thread->SuspendSemaphore.Header.SignalState++;
00172             KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT);
00173         }
00174     }
00175 
00176     /* Release Locks and return the Old State */
00177     KiReleaseDispatcherLockFromDpcLevel();
00178     KiReleaseApcLockFromDpcLevel(&ApcLock);
00179     KiExitDispatcher(ApcLock.OldIrql);
00180     return PreviousCount;
00181 }
00182 
00183 BOOLEAN
00184 NTAPI
00185 KeAlertThread(IN PKTHREAD Thread,
00186               IN KPROCESSOR_MODE AlertMode)
00187 {
00188     BOOLEAN PreviousState;
00189     KLOCK_QUEUE_HANDLE ApcLock;
00190     ASSERT_THREAD(Thread);
00191     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
00192 
00193     /* Lock the Dispatcher Database and the APC Queue */
00194     KiAcquireApcLock(Thread, &ApcLock);
00195     KiAcquireDispatcherLockAtDpcLevel();
00196 
00197     /* Save the Previous State */
00198     PreviousState = Thread->Alerted[AlertMode];
00199 
00200     /* Check if it's already alerted */
00201     if (!PreviousState)
00202     {
00203         /* Check if the thread is alertable, and blocked in the given mode */
00204         if ((Thread->State == Waiting) &&
00205             (Thread->Alertable) &&
00206             (AlertMode <= Thread->WaitMode))
00207         {
00208             /* Abort the wait to alert the thread */
00209             KiUnwaitThread(Thread, STATUS_ALERTED, THREAD_ALERT_INCREMENT);
00210         }
00211         else
00212         {
00213             /* Otherwise, merely set the alerted state */
00214             Thread->Alerted[AlertMode] = TRUE;
00215         }
00216     }
00217 
00218     /* Release the Dispatcher Lock */
00219     KiReleaseDispatcherLockFromDpcLevel();
00220     KiReleaseApcLockFromDpcLevel(&ApcLock);
00221     KiExitDispatcher(ApcLock.OldIrql);
00222 
00223     /* Return the old state */
00224     return PreviousState;
00225 }
00226 
00227 VOID
00228 NTAPI
00229 KeBoostPriorityThread(IN PKTHREAD Thread,
00230                       IN KPRIORITY Increment)
00231 {
00232     KIRQL OldIrql;
00233     KPRIORITY Priority;
00234     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
00235 
00236     /* Lock the Dispatcher Database */
00237     OldIrql = KiAcquireDispatcherLock();
00238 
00239     /* Only threads in the dynamic range get boosts */
00240     if (Thread->Priority < LOW_REALTIME_PRIORITY)
00241     {
00242         /* Lock the thread */
00243         KiAcquireThreadLock(Thread);
00244         
00245         /* Check again, and make sure there's not already a boost */
00246         if ((Thread->Priority < LOW_REALTIME_PRIORITY) &&
00247             !(Thread->PriorityDecrement))
00248         {
00249             /* Compute the new priority and see if it's higher */
00250             Priority = Thread->BasePriority + Increment;
00251             if (Priority > Thread->Priority)
00252             {
00253                 if (Priority >= LOW_REALTIME_PRIORITY)
00254                 {
00255                     Priority = LOW_REALTIME_PRIORITY - 1;
00256                 }
00257 
00258                 /* Reset the quantum */
00259                 Thread->Quantum = Thread->QuantumReset;
00260 
00261                 /* Set the new Priority */
00262                 KiSetPriorityThread(Thread, Priority);
00263             }
00264         }
00265 
00266         /* Release thread lock */
00267         KiReleaseThreadLock(Thread);
00268     }
00269     
00270     /* Release the dispatcher lokc */
00271     KiReleaseDispatcherLock(OldIrql);
00272 }
00273 
00274 ULONG
00275 NTAPI
00276 KeForceResumeThread(IN PKTHREAD Thread)
00277 {
00278     KLOCK_QUEUE_HANDLE ApcLock;
00279     ULONG PreviousCount;
00280     ASSERT_THREAD(Thread);
00281     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
00282 
00283     /* Lock the APC Queue */
00284     KiAcquireApcLock(Thread, &ApcLock);
00285 
00286     /* Save the old Suspend Count */
00287     PreviousCount = Thread->SuspendCount + Thread->FreezeCount;
00288 
00289     /* If the thread is suspended, wake it up!!! */
00290     if (PreviousCount)
00291     {
00292         /* Unwait it completely */
00293         Thread->SuspendCount = 0;
00294         Thread->FreezeCount = 0;
00295 
00296         /* Lock the dispatcher */
00297         KiAcquireDispatcherLockAtDpcLevel();
00298 
00299         /* Signal and satisfy */
00300         Thread->SuspendSemaphore.Header.SignalState++;
00301         KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT);
00302 
00303         /* Release the dispatcher */
00304         KiReleaseDispatcherLockFromDpcLevel();
00305     }
00306 
00307     /* Release Lock and return the Old State */
00308     KiReleaseApcLockFromDpcLevel(&ApcLock);
00309     KiExitDispatcher(ApcLock.OldIrql);
00310     return PreviousCount;
00311 }
00312 
00313 VOID
00314 NTAPI
00315 KeFreezeAllThreads(VOID)
00316 {
00317     KLOCK_QUEUE_HANDLE LockHandle, ApcLock;
00318     PKTHREAD Current, CurrentThread = KeGetCurrentThread();
00319     PKPROCESS Process = CurrentThread->ApcState.Process;
00320     PLIST_ENTRY ListHead, NextEntry;
00321     LONG OldCount;
00322     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
00323 
00324     /* Lock the process */
00325     KiAcquireProcessLock(Process, &LockHandle);
00326 
00327     /* If someone is already trying to free us, try again */
00328     while (CurrentThread->FreezeCount)
00329     {
00330         /* Release and re-acquire the process lock so the APC will go through */
00331         KiReleaseProcessLock(&LockHandle);
00332         KiAcquireProcessLock(Process, &LockHandle);
00333     }
00334 
00335     /* Enter a critical region */
00336     KeEnterCriticalRegion();
00337 
00338     /* Loop the Process's Threads */
00339     ListHead = &Process->ThreadListHead;
00340     NextEntry = ListHead->Flink;
00341     do
00342     {
00343         /* Get the current thread */
00344         Current = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry);
00345 
00346         /* Lock it */
00347         KiAcquireApcLockAtDpcLevel(Current, &ApcLock);
00348 
00349         /* Make sure it's not ours, and check if APCs are enabled */
00350         if ((Current != CurrentThread) && (Current->ApcQueueable))
00351         {
00352             /* Sanity check */
00353             OldCount = Current->SuspendCount;
00354             ASSERT(OldCount != MAXIMUM_SUSPEND_COUNT);
00355 
00356             /* Increase the freeze count */
00357             Current->FreezeCount++;
00358 
00359             /* Make sure it wasn't already suspended */
00360             if (!(OldCount) && !(Current->SuspendCount))
00361             {
00362                 /* Did we already insert it? */
00363                 if (!Current->SuspendApc.Inserted)
00364                 {
00365                     /* Insert the APC */
00366                     Current->SuspendApc.Inserted = TRUE;
00367                     KiInsertQueueApc(&Current->SuspendApc, IO_NO_INCREMENT);
00368                 }
00369                 else
00370                 {
00371                     /* Lock the dispatcher */
00372                     KiAcquireDispatcherLockAtDpcLevel();
00373 
00374                     /* Unsignal the semaphore, the APC was already inserted */
00375                     Current->SuspendSemaphore.Header.SignalState--;
00376 
00377                     /* Release the dispatcher */
00378                     KiReleaseDispatcherLockFromDpcLevel();
00379                 }
00380             }
00381         }
00382 
00383         /* Release the APC lock */
00384         KiReleaseApcLockFromDpcLevel(&ApcLock);
00385 
00386         /* Move to the next thread */
00387         NextEntry = NextEntry->Flink;
00388     } while (NextEntry != ListHead);
00389 
00390     /* Release the process lock and exit the dispatcher */
00391     KiReleaseProcessLockFromDpcLevel(&LockHandle);
00392     KiExitDispatcher(LockHandle.OldIrql);
00393 }
00394 
00395 ULONG
00396 NTAPI
00397 KeResumeThread(IN PKTHREAD Thread)
00398 {
00399     KLOCK_QUEUE_HANDLE ApcLock;
00400     ULONG PreviousCount;
00401     ASSERT_THREAD(Thread);
00402     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
00403 
00404     /* Lock the APC Queue */
00405     KiAcquireApcLock(Thread, &ApcLock);
00406 
00407     /* Save the Old Count */
00408     PreviousCount = Thread->SuspendCount;
00409 
00410     /* Check if it existed */
00411     if (PreviousCount)
00412     {
00413         /* Decrease the suspend count */
00414         Thread->SuspendCount--;
00415 
00416         /* Check if the thrad is still suspended or not */
00417         if ((!Thread->SuspendCount) && (!Thread->FreezeCount))
00418         {
00419             /* Acquire the dispatcher lock */
00420             KiAcquireDispatcherLockAtDpcLevel();
00421 
00422             /* Signal the Suspend Semaphore */
00423             Thread->SuspendSemaphore.Header.SignalState++;
00424             KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT);
00425 
00426             /* Release the dispatcher lock */
00427             KiReleaseDispatcherLockFromDpcLevel();
00428         }
00429     }
00430 
00431     /* Release APC Queue lock and return the Old State */
00432     KiReleaseApcLockFromDpcLevel(&ApcLock);
00433     KiExitDispatcher(ApcLock.OldIrql);
00434     return PreviousCount;
00435 }
00436 
00437 VOID
00438 NTAPI
00439 KeRundownThread(VOID)
00440 {
00441     KIRQL OldIrql;
00442     PKTHREAD Thread = KeGetCurrentThread();
00443     PLIST_ENTRY NextEntry, ListHead;
00444     PKMUTANT Mutant;
00445     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
00446 
00447     /* Optimized path if nothing is on the list at the moment */
00448     if (IsListEmpty(&Thread->MutantListHead)) return;
00449 
00450     /* Lock the Dispatcher Database */
00451     OldIrql = KiAcquireDispatcherLock();
00452 
00453     /* Get the List Pointers */
00454     ListHead = &Thread->MutantListHead;
00455     NextEntry = ListHead->Flink;
00456     while (NextEntry != ListHead)
00457     {
00458         /* Get the Mutant */
00459         Mutant = CONTAINING_RECORD(NextEntry, KMUTANT, MutantListEntry);
00460 
00461         /* Make sure it's not terminating with APCs off */
00462         if (Mutant->ApcDisable)
00463         {
00464             /* Bugcheck the system */
00465             KeBugCheckEx(THREAD_TERMINATE_HELD_MUTEX,
00466                          (ULONG_PTR)Thread,
00467                          (ULONG_PTR)Mutant,
00468                          0,
00469                          0);
00470         }
00471 
00472         /* Now we can remove it */
00473         RemoveEntryList(&Mutant->MutantListEntry);
00474 
00475         /* Unconditionally abandon it */
00476         Mutant->Header.SignalState = 1;
00477         Mutant->Abandoned = TRUE;
00478         Mutant->OwnerThread = NULL;
00479 
00480         /* Check if the Wait List isn't empty */
00481         if (!IsListEmpty(&Mutant->Header.WaitListHead))
00482         {
00483             /* Wake the Mutant */
00484             KiWaitTest(&Mutant->Header, MUTANT_INCREMENT);
00485         }
00486 
00487         /* Move on */
00488         NextEntry = NextEntry->Flink;
00489     }
00490 
00491     /* Release the Lock */
00492     KiReleaseDispatcherLock(OldIrql);
00493 }
00494 
00495 VOID
00496 NTAPI
00497 KeStartThread(IN OUT PKTHREAD Thread)
00498 {
00499     KLOCK_QUEUE_HANDLE LockHandle;
00500 #ifdef CONFIG_SMP
00501     PKNODE Node;
00502     PKPRCB NodePrcb;
00503     ULONG Set, Mask;
00504 #endif
00505     UCHAR IdealProcessor = 0;
00506     PKPROCESS Process = Thread->ApcState.Process;
00507 
00508     /* Setup static fields from parent */
00509     Thread->DisableBoost = Process->DisableBoost;
00510 #if defined(_M_IX86)
00511     Thread->Iopl = Process->Iopl;
00512 #endif
00513     Thread->Quantum = Process->QuantumReset;
00514     Thread->QuantumReset = Process->QuantumReset;
00515     Thread->SystemAffinityActive = FALSE;
00516 
00517     /* Lock the process */
00518     KiAcquireProcessLock(Process, &LockHandle);
00519 
00520     /* Setup volatile data */
00521     Thread->Priority = Process->BasePriority;
00522     Thread->BasePriority = Process->BasePriority;
00523     Thread->Affinity = Process->Affinity;
00524     Thread->UserAffinity = Process->Affinity;
00525 
00526 #ifdef CONFIG_SMP
00527     /* Get the KNODE and its PRCB */
00528     Node = KeNodeBlock[Process->IdealNode];
00529     NodePrcb = KiProcessorBlock[Process->ThreadSeed];
00530 
00531     /* Calculate affinity mask */
00532     Set = ~NodePrcb->MultiThreadProcessorSet;
00533     Mask = (ULONG)(Node->ProcessorMask & Process->Affinity);
00534     Set &= Mask;
00535     if (Set) Mask = Set;
00536 
00537     /* Get the new thread seed */
00538     IdealProcessor = KeFindNextRightSetAffinity(Process->ThreadSeed, Mask);
00539     Process->ThreadSeed = IdealProcessor;
00540 
00541     /* Sanity check */
00542     ASSERT((Thread->UserAffinity & AFFINITY_MASK(IdealProcessor)));
00543 #endif
00544 
00545     /* Set the Ideal Processor */
00546     Thread->IdealProcessor = IdealProcessor;
00547     Thread->UserIdealProcessor = IdealProcessor;
00548 
00549     /* Lock the Dispatcher Database */
00550     KiAcquireDispatcherLockAtDpcLevel();
00551 
00552     /* Insert the thread into the process list */
00553     InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry);
00554 
00555     /* Increase the stack count */
00556     ASSERT(Process->StackCount != MAXULONG_PTR);
00557     Process->StackCount++;
00558 
00559     /* Release locks and return */
00560     KiReleaseDispatcherLockFromDpcLevel();
00561     KiReleaseProcessLock(&LockHandle);
00562 }
00563 
00564 VOID
00565 NTAPI
00566 KiSuspendRundown(IN PKAPC Apc)
00567 {
00568     /* Does nothing */
00569     UNREFERENCED_PARAMETER(Apc);
00570 }
00571 
00572 VOID
00573 NTAPI
00574 KiSuspendNop(IN PKAPC Apc,
00575              IN PKNORMAL_ROUTINE *NormalRoutine,
00576              IN PVOID *NormalContext,
00577              IN PVOID *SystemArgument1,
00578              IN PVOID *SystemArgument2)
00579 {
00580     /* Does nothing */
00581     UNREFERENCED_PARAMETER(Apc);
00582     UNREFERENCED_PARAMETER(NormalRoutine);
00583     UNREFERENCED_PARAMETER(NormalContext);
00584     UNREFERENCED_PARAMETER(SystemArgument1);
00585     UNREFERENCED_PARAMETER(SystemArgument2);
00586 }
00587 
00588 VOID
00589 NTAPI
00590 KiSuspendThread(IN PVOID NormalContext,
00591                 IN PVOID SystemArgument1,
00592                 IN PVOID SystemArgument2)
00593 {
00594     /* Non-alertable kernel-mode suspended wait */
00595     KeWaitForSingleObject(&KeGetCurrentThread()->SuspendSemaphore,
00596                           Suspended,
00597                           KernelMode,
00598                           FALSE,
00599                           NULL);
00600 }
00601 
00602 ULONG
00603 NTAPI
00604 KeSuspendThread(PKTHREAD Thread)
00605 {
00606     KLOCK_QUEUE_HANDLE ApcLock;
00607     ULONG PreviousCount;
00608     ASSERT_THREAD(Thread);
00609     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
00610 
00611     /* Lock the APC Queue */
00612     KiAcquireApcLock(Thread, &ApcLock);
00613 
00614     /* Save the Old Count */
00615     PreviousCount = Thread->SuspendCount;
00616 
00617     /* Handle the maximum */
00618     if (PreviousCount == MAXIMUM_SUSPEND_COUNT)
00619     {
00620         /* Raise an exception */
00621         KiReleaseApcLock(&ApcLock);
00622         RtlRaiseStatus(STATUS_SUSPEND_COUNT_EXCEEDED);
00623     }
00624 
00625     /* Should we bother to queue at all? */
00626     if (Thread->ApcQueueable)
00627     {
00628         /* Increment the suspend count */
00629         Thread->SuspendCount++;
00630 
00631         /* Check if we should suspend it */
00632         if (!(PreviousCount) && !(Thread->FreezeCount))
00633         {
00634             /* Is the APC already inserted? */
00635             if (!Thread->SuspendApc.Inserted)
00636             {
00637                 /* Not inserted, insert it */
00638                 Thread->SuspendApc.Inserted = TRUE;
00639                 KiInsertQueueApc(&Thread->SuspendApc, IO_NO_INCREMENT);
00640             }
00641             else
00642             {
00643                 /* Lock the dispatcher */
00644                 KiAcquireDispatcherLockAtDpcLevel();
00645 
00646                 /* Unsignal the semaphore, the APC was already inserted */
00647                 Thread->SuspendSemaphore.Header.SignalState--;
00648 
00649                 /* Release the dispatcher */
00650                 KiReleaseDispatcherLockFromDpcLevel();
00651             }
00652         }
00653     }
00654 
00655     /* Release Lock and return the Old State */
00656     KiReleaseApcLockFromDpcLevel(&ApcLock);
00657     KiExitDispatcher(ApcLock.OldIrql);
00658     return PreviousCount;
00659 }
00660 
00661 VOID
00662 NTAPI
00663 KeThawAllThreads(VOID)
00664 {
00665     KLOCK_QUEUE_HANDLE LockHandle, ApcLock;
00666     PKTHREAD Current, CurrentThread = KeGetCurrentThread();
00667     PKPROCESS Process = CurrentThread->ApcState.Process;
00668     PLIST_ENTRY ListHead, NextEntry;
00669     LONG OldCount;
00670     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
00671 
00672     /* Lock the process */
00673     KiAcquireProcessLock(Process, &LockHandle);
00674 
00675     /* Loop the Process's Threads */
00676     ListHead = &Process->ThreadListHead;
00677     NextEntry = ListHead->Flink;
00678     do
00679     {
00680         /* Get the current thread */
00681         Current = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry);
00682 
00683         /* Lock it */
00684         KiAcquireApcLockAtDpcLevel(Current, &ApcLock);
00685 
00686         /* Make sure we are frozen */
00687         OldCount = Current->FreezeCount;
00688         if (OldCount)
00689         {
00690             /* Decrease the freeze count */
00691             Current->FreezeCount--;
00692 
00693             /* Check if both counts are zero now */
00694             if (!(Current->SuspendCount) && (!Current->FreezeCount))
00695             {
00696                 /* Lock the dispatcher */
00697                 KiAcquireDispatcherLockAtDpcLevel();
00698 
00699                 /* Signal the suspend semaphore and wake it */
00700                 Current->SuspendSemaphore.Header.SignalState++;
00701                 KiWaitTest(&Current->SuspendSemaphore, 0);
00702 
00703                 /* Unlock the dispatcher */
00704                 KiReleaseDispatcherLockFromDpcLevel();
00705             }
00706         }
00707 
00708         /* Release the APC lock */
00709         KiReleaseApcLockFromDpcLevel(&ApcLock);
00710 
00711         /* Go to the next one */
00712         NextEntry = NextEntry->Flink;
00713     } while (NextEntry != ListHead);
00714 
00715     /* Release the process lock and exit the dispatcher */
00716     KiReleaseProcessLockFromDpcLevel(&LockHandle);
00717     KiExitDispatcher(LockHandle.OldIrql);
00718 
00719     /* Leave the critical region */
00720     KeLeaveCriticalRegion();
00721 }
00722 
00723 BOOLEAN
00724 NTAPI
00725 KeTestAlertThread(IN KPROCESSOR_MODE AlertMode)
00726 {
00727     PKTHREAD Thread = KeGetCurrentThread();
00728     BOOLEAN OldState;
00729     KLOCK_QUEUE_HANDLE ApcLock;
00730     ASSERT_THREAD(Thread);
00731     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
00732 
00733     /* Lock the Dispatcher Database and the APC Queue */
00734     KiAcquireApcLock(Thread, &ApcLock);
00735 
00736     /* Save the old State */
00737     OldState = Thread->Alerted[AlertMode];
00738 
00739     /* Check the Thread is alerted */
00740     if (OldState)
00741     {
00742         /* Disable alert for this mode */
00743         Thread->Alerted[AlertMode] = FALSE;
00744     }
00745     else if ((AlertMode != KernelMode) &&
00746              (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])))
00747     {
00748         /* If the mode is User and the Queue isn't empty, set Pending */
00749         Thread->ApcState.UserApcPending = TRUE;
00750     }
00751 
00752     /* Release Locks and return the Old State */
00753     KiReleaseApcLock(&ApcLock);
00754     return OldState;
00755 }
00756 
00757 NTSTATUS
00758 NTAPI
00759 KeInitThread(IN OUT PKTHREAD Thread,
00760              IN PVOID KernelStack,
00761              IN PKSYSTEM_ROUTINE SystemRoutine,
00762              IN PKSTART_ROUTINE StartRoutine,
00763              IN PVOID StartContext,
00764              IN PCONTEXT Context,
00765              IN PVOID Teb,
00766              IN PKPROCESS Process)
00767 {
00768     BOOLEAN AllocatedStack = FALSE;
00769     ULONG i;
00770     PKWAIT_BLOCK TimerWaitBlock;
00771     PKTIMER Timer;
00772     NTSTATUS Status;
00773 
00774     /* Initalize the Dispatcher Header */
00775     Thread->Header.Type = ThreadObject;
00776     Thread->Header.ThreadControlFlags = 0;
00777     Thread->Header.DebugActive = FALSE;
00778     Thread->Header.SignalState = 0;
00779     InitializeListHead(&(Thread->Header.WaitListHead));
00780 
00781     /* Initialize the Mutant List */
00782     InitializeListHead(&Thread->MutantListHead);
00783 
00784     /* Initialize the wait blocks */
00785     for (i = 0; i< (THREAD_WAIT_OBJECTS + 1); i++)
00786     {
00787         /* Put our pointer */
00788         Thread->WaitBlock[i].Thread = Thread;
00789     }
00790 
00791     /* Set swap settings */
00792     Thread->EnableStackSwap = TRUE;
00793     Thread->IdealProcessor = 1;
00794     Thread->SwapBusy = FALSE;
00795     Thread->KernelStackResident = TRUE;
00796     Thread->AdjustReason = AdjustNone;
00797 
00798     /* Initialize the lock */
00799     KeInitializeSpinLock(&Thread->ThreadLock);
00800 
00801     /* Setup the Service Descriptor Table for Native Calls */
00802     Thread->ServiceTable = KeServiceDescriptorTable;
00803 
00804     /* Setup APC Fields */
00805     InitializeListHead(&Thread->ApcState.ApcListHead[0]);
00806     InitializeListHead(&Thread->ApcState.ApcListHead[1]);
00807     Thread->ApcState.Process = Process;
00808     Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState;
00809     Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState;
00810     Thread->ApcStateIndex = OriginalApcEnvironment;
00811     Thread->ApcQueueable = TRUE;
00812     KeInitializeSpinLock(&Thread->ApcQueueLock);
00813 
00814     /* Initialize the Suspend APC */
00815     KeInitializeApc(&Thread->SuspendApc,
00816                     Thread,
00817                     OriginalApcEnvironment,
00818                     KiSuspendNop,
00819                     KiSuspendRundown,
00820                     KiSuspendThread,
00821                     KernelMode,
00822                     NULL);
00823 
00824     /* Initialize the Suspend Semaphore */
00825     KeInitializeSemaphore(&Thread->SuspendSemaphore, 0, 2);
00826 
00827     /* Setup the timer */
00828     Timer = &Thread->Timer;
00829     KeInitializeTimer(Timer);
00830     TimerWaitBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
00831     TimerWaitBlock->Object = Timer;
00832     TimerWaitBlock->WaitKey = STATUS_TIMEOUT;
00833     TimerWaitBlock->WaitType = WaitAny;
00834     TimerWaitBlock->NextWaitBlock = NULL;
00835 
00836     /* Link the two wait lists together */
00837     TimerWaitBlock->WaitListEntry.Flink = &Timer->Header.WaitListHead;
00838     TimerWaitBlock->WaitListEntry.Blink = &Timer->Header.WaitListHead;
00839 
00840     /* Set the TEB */
00841     Thread->Teb = Teb;
00842 
00843     /* Check if we have a kernel stack */
00844     if (!KernelStack)
00845     {
00846         /* We don't, allocate one */
00847         KernelStack = MmCreateKernelStack(FALSE, 0);
00848         if (!KernelStack) return STATUS_INSUFFICIENT_RESOURCES;
00849 
00850         /* Remember for later */
00851         AllocatedStack = TRUE;
00852     }
00853 
00854     /* Set the Thread Stacks */
00855     Thread->InitialStack = KernelStack;
00856     Thread->StackBase = KernelStack;
00857     Thread->StackLimit = (ULONG_PTR)KernelStack - KERNEL_STACK_SIZE;
00858     Thread->KernelStackResident = TRUE;
00859 
00860     /* Enter SEH to avoid crashes due to user mode */
00861     Status = STATUS_SUCCESS;
00862     _SEH2_TRY
00863     {
00864         /* Initalize the Thread Context */
00865         KiInitializeContextThread(Thread,
00866                                   SystemRoutine,
00867                                   StartRoutine,
00868                                   StartContext,
00869                                   Context);
00870     }
00871     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00872     {
00873         /* Set failure status */
00874         Status = STATUS_UNSUCCESSFUL;
00875 
00876         /* Check if a stack was allocated */
00877         if (AllocatedStack)
00878         {
00879             /* Delete the stack */
00880             MmDeleteKernelStack((PVOID)Thread->StackBase, FALSE);
00881             Thread->InitialStack = NULL;
00882         }
00883     }
00884     _SEH2_END;
00885 
00886     /* Set the Thread to initalized */
00887     Thread->State = Initialized;
00888     return Status;
00889 }
00890 
00891 VOID
00892 NTAPI
00893 KeInitializeThread(IN PKPROCESS Process,
00894                    IN OUT PKTHREAD Thread,
00895                    IN PKSYSTEM_ROUTINE SystemRoutine,
00896                    IN PKSTART_ROUTINE StartRoutine,
00897                    IN PVOID StartContext,
00898                    IN PCONTEXT Context,
00899                    IN PVOID Teb,
00900                    IN PVOID KernelStack)
00901 {
00902     /* Initialize and start the thread on success */
00903     if (NT_SUCCESS(KeInitThread(Thread,
00904                                 KernelStack,
00905                                 SystemRoutine,
00906                                 StartRoutine,
00907                                 StartContext,
00908                                 Context,
00909                                 Teb,
00910                                 Process)))
00911     {
00912         /* Start it */
00913         KeStartThread(Thread);
00914     }
00915 }
00916 
00917 VOID
00918 NTAPI
00919 KeUninitThread(IN PKTHREAD Thread)
00920 {
00921     /* Delete the stack */
00922     MmDeleteKernelStack((PVOID)Thread->StackBase, FALSE);
00923     Thread->InitialStack = NULL;
00924 }
00925 
00926 /* PUBLIC FUNCTIONS **********************************************************/
00927 
00928 /*
00929  * @unimplemented
00930  */
00931 VOID
00932 NTAPI
00933 KeCapturePersistentThreadState(IN PVOID CurrentThread,
00934                                IN ULONG Setting1,
00935                                IN ULONG Setting2,
00936                                IN ULONG Setting3,
00937                                IN ULONG Setting4,
00938                                IN ULONG Setting5,
00939                                IN PVOID ThreadState)
00940 {
00941     UNIMPLEMENTED;
00942 }
00943 
00944 /*
00945  * @implemented
00946  */
00947 #undef KeGetCurrentThread
00948 PKTHREAD
00949 NTAPI
00950 KeGetCurrentThread(VOID)
00951 {
00952     /* Return the current thread on this PCR */
00953     return _KeGetCurrentThread();
00954 }
00955 
00956 /*
00957  * @implemented
00958  */
00959 #undef KeGetPreviousMode
00960 UCHAR
00961 NTAPI
00962 KeGetPreviousMode(VOID)
00963 {
00964     /* Return the previous mode of this thread */
00965     return _KeGetPreviousMode();
00966 }
00967 
00968 /*
00969  * @implemented
00970  */
00971 ULONG
00972 NTAPI
00973 KeQueryRuntimeThread(IN PKTHREAD Thread,
00974                      OUT PULONG UserTime)
00975 {
00976     ASSERT_THREAD(Thread);
00977 
00978     /* Return the User Time */
00979     *UserTime = Thread->UserTime;
00980 
00981     /* Return the Kernel Time */
00982     return Thread->KernelTime;
00983 }
00984 
00985 /*
00986  * @implemented
00987  */
00988 BOOLEAN
00989 NTAPI
00990 KeSetKernelStackSwapEnable(IN BOOLEAN Enable)
00991 {
00992     BOOLEAN PreviousState;
00993     PKTHREAD Thread = KeGetCurrentThread();
00994 
00995     /* Save Old State */
00996     PreviousState = Thread->EnableStackSwap;
00997 
00998     /* Set New State */
00999     Thread->EnableStackSwap = Enable;
01000 
01001     /* Return Old State */
01002     return PreviousState;
01003 }
01004 
01005 /*
01006  * @implemented
01007  */
01008 KPRIORITY
01009 NTAPI
01010 KeQueryPriorityThread(IN PKTHREAD Thread)
01011 {
01012     ASSERT_THREAD(Thread);
01013 
01014     /* Return the current priority */
01015     return Thread->Priority;
01016 }
01017 
01018 /*
01019  * @implemented
01020  */
01021 VOID
01022 NTAPI
01023 KeRevertToUserAffinityThread(VOID)
01024 {
01025     KIRQL OldIrql;
01026     PKPRCB Prcb;
01027     PKTHREAD NextThread, CurrentThread = KeGetCurrentThread();
01028     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
01029     ASSERT(CurrentThread->SystemAffinityActive != FALSE);
01030 
01031     /* Lock the Dispatcher Database */
01032     OldIrql = KiAcquireDispatcherLock();
01033 
01034     /* Set the user affinity and processor and disable system affinity */
01035     CurrentThread->Affinity = CurrentThread->UserAffinity;
01036     CurrentThread->IdealProcessor = CurrentThread->UserIdealProcessor;
01037     CurrentThread->SystemAffinityActive = FALSE;
01038 
01039     /* Get the current PRCB and check if it doesn't match this affinity */
01040     Prcb = KeGetCurrentPrcb();
01041     if (!(Prcb->SetMember & CurrentThread->Affinity))
01042     {
01043         /* Lock the PRCB */
01044         KiAcquirePrcbLock(Prcb);
01045 
01046         /* Check if there's no next thread scheduled */
01047         if (!Prcb->NextThread)
01048         {
01049             /* Select a new thread and set it on standby */
01050             NextThread = KiSelectNextThread(Prcb);
01051             NextThread->State = Standby;
01052             Prcb->NextThread = NextThread;
01053         }
01054 
01055         /* Release the PRCB lock */
01056         KiReleasePrcbLock(Prcb);
01057     }
01058 
01059     /* Unlock dispatcher database */
01060     KiReleaseDispatcherLock(OldIrql);
01061 }
01062 
01063 /*
01064  * @implemented
01065  */
01066 UCHAR
01067 NTAPI
01068 KeSetIdealProcessorThread(IN PKTHREAD Thread,
01069                           IN UCHAR Processor)
01070 {
01071     CCHAR OldIdealProcessor;
01072     KIRQL OldIrql;
01073     ASSERT(Processor <= MAXIMUM_PROCESSORS);
01074 
01075     /* Lock the Dispatcher Database */
01076     OldIrql = KiAcquireDispatcherLock();
01077 
01078     /* Save Old Ideal Processor */
01079     OldIdealProcessor = Thread->UserIdealProcessor;
01080 
01081     /* Make sure a valid CPU was given */
01082     if (Processor < KeNumberProcessors)
01083     {
01084         /* Check if the user ideal CPU is in the affinity */
01085         if (Thread->Affinity & AFFINITY_MASK(Processor))
01086         {
01087             /* Set the ideal processor */
01088             Thread->IdealProcessor = Processor;
01089 
01090             /* Check if system affinity is used */
01091             if (!Thread->SystemAffinityActive)
01092             {
01093                 /* It's not, so update the user CPU too */
01094                 Thread->UserIdealProcessor = Processor;
01095             }
01096         }
01097     }
01098 
01099     /* Release dispatcher lock and return the old ideal CPU */
01100     KiReleaseDispatcherLock(OldIrql);
01101     return OldIdealProcessor;
01102 }
01103 
01104 /*
01105  * @implemented
01106  */
01107 VOID
01108 NTAPI
01109 KeSetSystemAffinityThread(IN KAFFINITY Affinity)
01110 {
01111     KIRQL OldIrql;
01112     PKPRCB Prcb;
01113     PKTHREAD NextThread, CurrentThread = KeGetCurrentThread();
01114     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
01115     ASSERT((Affinity & KeActiveProcessors) != 0);
01116 
01117     /* Lock the Dispatcher Database */
01118     OldIrql = KiAcquireDispatcherLock();
01119 
01120     /* Restore the affinity and enable system affinity */
01121     CurrentThread->Affinity = Affinity;
01122     CurrentThread->SystemAffinityActive = TRUE;
01123 
01124     /* Check if the ideal processor is part of the affinity */
01125 #ifdef CONFIG_SMP
01126     if (!(Affinity & AFFINITY_MASK(CurrentThread->IdealProcessor)))
01127     {
01128         ULONG AffinitySet, NodeMask;
01129 
01130         /* It's not! Get the PRCB */
01131         Prcb = KiProcessorBlock[CurrentThread->IdealProcessor];
01132 
01133         /* Calculate the affinity set */
01134         AffinitySet = KeActiveProcessors & Affinity;
01135         NodeMask = Prcb->ParentNode->ProcessorMask & AffinitySet;
01136         if (NodeMask)
01137         {
01138             /* Use the Node set instead */
01139             AffinitySet = NodeMask;
01140         }
01141 
01142         /* Calculate the ideal CPU from the affinity set */
01143         BitScanReverse(&NodeMask, AffinitySet);
01144         CurrentThread->IdealProcessor = (UCHAR)NodeMask;
01145     }
01146 #endif
01147 
01148     /* Get the current PRCB and check if it doesn't match this affinity */
01149     Prcb = KeGetCurrentPrcb();
01150     if (!(Prcb->SetMember & CurrentThread->Affinity))
01151     {
01152         /* Lock the PRCB */
01153         KiAcquirePrcbLock(Prcb);
01154 
01155         /* Check if there's no next thread scheduled */
01156         if (!Prcb->NextThread)
01157         {
01158             /* Select a new thread and set it on standby */
01159             NextThread = KiSelectNextThread(Prcb);
01160             NextThread->State = Standby;
01161             Prcb->NextThread = NextThread;
01162         }
01163 
01164         /* Release the PRCB lock */
01165         KiReleasePrcbLock(Prcb);
01166     }
01167 
01168     /* Unlock dispatcher database */
01169     KiReleaseDispatcherLock(OldIrql);
01170 }
01171 
01172 /*
01173  * @implemented
01174  */
01175 LONG
01176 NTAPI
01177 KeSetBasePriorityThread(IN PKTHREAD Thread,
01178                         IN LONG Increment)
01179 {
01180     KIRQL OldIrql;
01181     KPRIORITY OldBasePriority, Priority, BasePriority;
01182     LONG OldIncrement;
01183     PKPROCESS Process;
01184     ASSERT_THREAD(Thread);
01185     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
01186 
01187     /* Get the process */
01188     Process = Thread->ApcState.Process;
01189 
01190     /* Lock the Dispatcher Database */
01191     OldIrql = KiAcquireDispatcherLock();
01192 
01193     /* Lock the thread */
01194     KiAcquireThreadLock(Thread);
01195 
01196     /* Save the old base priority and increment */
01197     OldBasePriority = Thread->BasePriority;
01198     OldIncrement = OldBasePriority - Process->BasePriority;
01199 
01200     /* If priority saturation happened, use the saturated increment */
01201     if (Thread->Saturation) OldIncrement = (HIGH_PRIORITY + 1) / 2 *
01202                                             Thread->Saturation;
01203 
01204     /* Reset the saturation value */
01205     Thread->Saturation = 0;
01206 
01207     /* Now check if saturation is being used for the new value */
01208     if (abs(Increment) >= ((HIGH_PRIORITY + 1) / 2))
01209     {
01210         /* Check if we need positive or negative saturation */
01211         Thread->Saturation = (Increment > 0) ? 1 : -1;
01212     }
01213 
01214     /* Normalize the Base Priority */
01215     BasePriority = Process->BasePriority + Increment;
01216     if (Process->BasePriority >= LOW_REALTIME_PRIORITY)
01217     {
01218         /* Check if it's too low */
01219         if (BasePriority < LOW_REALTIME_PRIORITY)
01220         {
01221             /* Set it to the lowest real time level */
01222             BasePriority = LOW_REALTIME_PRIORITY;
01223         }
01224 
01225         /* Check if it's too high */
01226         if (BasePriority > HIGH_PRIORITY) BasePriority = HIGH_PRIORITY;
01227 
01228         /* We are at real time, so use the raw base priority */
01229         Priority = BasePriority;
01230     }
01231     else
01232     {
01233         /* Check if it's entering the real time range */
01234         if (BasePriority >= LOW_REALTIME_PRIORITY)
01235         {
01236             /* Set it to the highest dynamic level */
01237             BasePriority = LOW_REALTIME_PRIORITY - 1;
01238         }
01239 
01240         /* Check if it's too low and normalize it */
01241         if (BasePriority <= LOW_PRIORITY) BasePriority = 1;
01242 
01243         /* Check if Saturation is used */
01244         if (Thread->Saturation)
01245         {
01246             /* Use the raw base priority */
01247             Priority = BasePriority;
01248         }
01249         else
01250         {
01251             /* Otherwise, calculate the new priority */
01252             Priority = KiComputeNewPriority(Thread, 0);
01253             Priority += (BasePriority - OldBasePriority);
01254 
01255             /* Check if it entered the real-time range */
01256             if (Priority >= LOW_REALTIME_PRIORITY)
01257             {
01258                 /* Normalize it down to the highest dynamic priority */
01259                 Priority = LOW_REALTIME_PRIORITY - 1;
01260             }
01261             else if (Priority <= LOW_PRIORITY)
01262             {
01263                 /* It went too low, normalize it */
01264                 Priority = 1;
01265             }
01266         }
01267     }
01268 
01269     /* Finally set the new base priority */
01270     Thread->BasePriority = (SCHAR)BasePriority;
01271 
01272     /* Reset the decrements */
01273     Thread->PriorityDecrement = 0;
01274 
01275     /* Check if we're changing priority after all */
01276     if (Priority != Thread->Priority)
01277     {
01278         /* Reset the quantum and do the actual priority modification */
01279         Thread->Quantum = Thread->QuantumReset;
01280         KiSetPriorityThread(Thread, Priority);
01281     }
01282 
01283     /* Release thread lock */
01284     KiReleaseThreadLock(Thread);
01285 
01286     /* Release the dispatcher database and return old increment */
01287     KiReleaseDispatcherLock(OldIrql);
01288     return OldIncrement;
01289 }
01290 
01291 /*
01292  * @implemented
01293  */
01294 KAFFINITY
01295 NTAPI
01296 KeSetAffinityThread(IN PKTHREAD Thread,
01297                     IN KAFFINITY Affinity)
01298 {
01299     KIRQL OldIrql;
01300     KAFFINITY OldAffinity;
01301     ASSERT_THREAD(Thread);
01302     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
01303 
01304     /* Lock the dispatcher database */
01305     OldIrql = KiAcquireDispatcherLock();
01306 
01307     /* Call the internal function */
01308     OldAffinity = KiSetAffinityThread(Thread, Affinity);
01309 
01310     /* Release the dispatcher database and return old affinity */
01311     KiReleaseDispatcherLock(OldIrql);
01312     return OldAffinity;
01313 }
01314 
01315 /*
01316  * @implemented
01317  */
01318 KPRIORITY
01319 NTAPI
01320 KeSetPriorityThread(IN PKTHREAD Thread,
01321                     IN KPRIORITY Priority)
01322 {
01323     KIRQL OldIrql;
01324     KPRIORITY OldPriority;
01325     ASSERT_THREAD(Thread);
01326     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
01327     ASSERT((Priority <= HIGH_PRIORITY) && (Priority >= LOW_PRIORITY));
01328     ASSERT(KeIsExecutingDpc() == FALSE);
01329 
01330     /* Lock the Dispatcher Database */
01331     OldIrql = KiAcquireDispatcherLock();
01332 
01333     /* Lock the thread */
01334     KiAcquireThreadLock(Thread);
01335 
01336     /* Save the old Priority and reset decrement */
01337     OldPriority = Thread->Priority;
01338     Thread->PriorityDecrement = 0;
01339 
01340     /* Make sure that an actual change is being done */
01341     if (Priority != Thread->Priority)
01342     {
01343         /* Reset the quantum */
01344         Thread->Quantum = Thread->QuantumReset;
01345 
01346         /* Check if priority is being set too low and normalize if so */
01347         if ((Thread->BasePriority != 0) && !(Priority)) Priority = 1;
01348 
01349         /* Set the new Priority */
01350         KiSetPriorityThread(Thread, Priority);
01351     }
01352 
01353     /* Release thread lock */
01354     KiReleaseThreadLock(Thread);
01355 
01356     /* Release the dispatcher database */
01357     KiReleaseDispatcherLock(OldIrql);
01358 
01359     /* Return Old Priority */
01360     return OldPriority;
01361 }
01362 
01363 /*
01364  * @implemented
01365  */
01366 VOID
01367 NTAPI
01368 KeTerminateThread(IN KPRIORITY Increment)
01369 {
01370     PLIST_ENTRY *ListHead;
01371     PETHREAD Entry, SavedEntry;
01372     PETHREAD *ThreadAddr;
01373     KLOCK_QUEUE_HANDLE LockHandle;
01374     PKTHREAD Thread = KeGetCurrentThread();
01375     PKPROCESS Process = Thread->ApcState.Process;
01376     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
01377 
01378     /* Lock the process */
01379     KiAcquireProcessLock(Process, &LockHandle);
01380 
01381     /* Make sure we won't get Swapped */
01382     KiSetThreadSwapBusy(Thread);
01383 
01384     /* Save the Kernel and User Times */
01385     Process->KernelTime += Thread->KernelTime;
01386     Process->UserTime += Thread->UserTime;
01387 
01388     /* Get the current entry and our Port */
01389     Entry = (PETHREAD)PspReaperListHead.Flink;
01390     ThreadAddr = &((PETHREAD)Thread)->ReaperLink;
01391 
01392     /* Add it to the reaper's list */
01393     do
01394     {
01395         /* Get the list head */
01396         ListHead = &PspReaperListHead.Flink;
01397 
01398         /* Link ourselves */
01399         *ThreadAddr = Entry;
01400         SavedEntry = Entry;
01401 
01402         /* Now try to do the exchange */
01403         Entry = InterlockedCompareExchangePointer((PVOID*)ListHead,
01404                                                   ThreadAddr,
01405                                                   Entry);
01406 
01407         /* Break out if the change was succesful */
01408     } while (Entry != SavedEntry);
01409 
01410     /* Acquire the dispatcher lock */
01411     KiAcquireDispatcherLockAtDpcLevel();
01412 
01413     /* Check if the reaper wasn't active */
01414     if (!Entry)
01415     {
01416         /* Activate it as a work item, directly through its Queue */
01417         KiInsertQueue(&ExWorkerQueue[HyperCriticalWorkQueue].WorkerQueue,
01418                       &PspReaperWorkItem.List,
01419                       FALSE);
01420     }
01421 
01422     /* Check the thread has an associated queue */
01423     if (Thread->Queue)
01424     {
01425         /* Remove it from the list, and handle the queue */
01426         RemoveEntryList(&Thread->QueueListEntry);
01427         KiActivateWaiterQueue(Thread->Queue);
01428     }
01429 
01430     /* Signal the thread */
01431     Thread->Header.SignalState = TRUE;
01432     if (!IsListEmpty(&Thread->Header.WaitListHead))
01433     {
01434         /* Unwait the threads */
01435         KxUnwaitThread(&Thread->Header, Increment);
01436     }
01437 
01438     /* Remove the thread from the list */
01439     RemoveEntryList(&Thread->ThreadListEntry);
01440 
01441     /* Release the process lock */
01442     KiReleaseProcessLockFromDpcLevel(&LockHandle);
01443 
01444     /* Set us as terminated, decrease the Process's stack count */
01445     Thread->State = Terminated;
01446 
01447     /* Decrease stack count */
01448     ASSERT(Process->StackCount != 0);
01449     ASSERT(Process->State == ProcessInMemory);
01450     Process->StackCount--;
01451     if (!(Process->StackCount) && !(IsListEmpty(&Process->ThreadListHead)))
01452     {
01453         /* FIXME: Swap stacks */
01454     }
01455 
01456     /* Rundown arch-specific parts */
01457     KiRundownThread(Thread);
01458 
01459     /* Swap to a new thread */
01460     KiReleaseDispatcherLockFromDpcLevel();
01461     KiSwapThread(Thread, KeGetCurrentPrcb());
01462 }

Generated on Fri May 25 2012 04:35:56 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.