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