Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2517 lines
58 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. threadobj.c
  5. Abstract:
  6. This module implements the machine independent functions to manipulate
  7. the kernel thread object. Functions are provided to initialize, ready,
  8. alert, test alert, boost priority, enable APC queuing, disable APC
  9. queuing, confine, set affinity, set priority, suspend, resume, alert
  10. resume, terminate, read thread state, freeze, unfreeze, query data
  11. alignment handling mode, force resume, and enter and leave critical
  12. regions for thread objects.
  13. Author:
  14. David N. Cutler (davec) 4-Mar-1989
  15. Environment:
  16. Kernel mode only.
  17. Revision History:
  18. --*/
  19. #include "ki.h"
  20. #pragma alloc_text(INIT, KeInitializeThread)
  21. #pragma alloc_text(PAGE, KeInitThread)
  22. #pragma alloc_text(PAGE, KeUninitThread)
  23. //
  24. // The following assert macro is used to check that an input thread object is
  25. // really a kthread and not something else, like deallocated pool.
  26. //
  27. #define ASSERT_THREAD(E) { \
  28. ASSERT((E)->Header.Type == ThreadObject); \
  29. }
  30. NTSTATUS
  31. KeInitThread (
  32. IN PKTHREAD Thread,
  33. IN PVOID KernelStack OPTIONAL,
  34. IN PKSYSTEM_ROUTINE SystemRoutine,
  35. IN PKSTART_ROUTINE StartRoutine OPTIONAL,
  36. IN PVOID StartContext OPTIONAL,
  37. IN PCONTEXT ContextFrame OPTIONAL,
  38. IN PVOID Teb OPTIONAL,
  39. IN PKPROCESS Process
  40. )
  41. /*++
  42. Routine Description:
  43. This function initializes a thread object. The priority, affinity,
  44. and initial quantum are taken from the parent process object.
  45. N.B. This routine is carefully written so that if an access violation
  46. occurs while reading the specified context frame, then no kernel
  47. data structures will have been modified. It is the responsibility
  48. of the caller to handle the exception and provide necessary clean
  49. up.
  50. N.B. It is assumed that the thread object is zeroed.
  51. Arguments:
  52. Thread - Supplies a pointer to a dispatcher object of type thread.
  53. KernelStack - Supplies a pointer to the base of a kernel stack on which
  54. the context frame for the thread is to be constructed.
  55. SystemRoutine - Supplies a pointer to the system function that is to be
  56. called when the thread is first scheduled for execution.
  57. StartRoutine - Supplies an optional pointer to a function that is to be
  58. called after the system has finished initializing the thread. This
  59. parameter is specified if the thread is a system thread and will
  60. execute totally in kernel mode.
  61. StartContext - Supplies an optional pointer to an arbitrary data structure
  62. which will be passed to the StartRoutine as a parameter. This
  63. parameter is specified if the thread is a system thread and will
  64. execute totally in kernel mode.
  65. ContextFrame - Supplies an optional pointer a context frame which contains
  66. the initial user mode state of the thread. This parameter is specified
  67. if the thread is a user thread and will execute in user mode. If this
  68. parameter is not specified, then the Teb parameter is ignored.
  69. Teb - Supplies an optional pointer to the user mode thread environment
  70. block. This parameter is specified if the thread is a user thread and
  71. will execute in user mode. This parameter is ignored if the ContextFrame
  72. parameter is not specified.
  73. Process - Supplies a pointer to a control object of type process.
  74. Return Value:
  75. None.
  76. --*/
  77. {
  78. UCHAR IdealProcessor;
  79. ULONG Index;
  80. BOOLEAN KernelStackAllocated = FALSE;
  81. KAFFINITY PreferredSet;
  82. NTSTATUS Status = STATUS_SUCCESS;
  83. KAFFINITY TempSet;
  84. PKTIMER Timer;
  85. PKWAIT_BLOCK WaitBlock;
  86. //
  87. // Initialize the standard dispatcher object header and set the initial
  88. // state of the thread object.
  89. //
  90. Thread->Header.Type = ThreadObject;
  91. Thread->Header.Size = sizeof(KTHREAD) / sizeof(LONG);
  92. InitializeListHead(&Thread->Header.WaitListHead);
  93. //
  94. // Initialize the owned mutant listhead.
  95. //
  96. InitializeListHead(&Thread->MutantListHead);
  97. //
  98. // Initialize the thread field of all builtin wait blocks.
  99. //
  100. for (Index = 0; Index < (THREAD_WAIT_OBJECTS + 1); Index += 1) {
  101. Thread->WaitBlock[Index].Thread = Thread;
  102. }
  103. //
  104. // Initialize the alerted, preempted, debugactive, autoalignment,
  105. // kernel stack resident, enable kernel stack swap, and process
  106. // ready queue boolean values.
  107. //
  108. // N.B. Only nonzero values are initialized.
  109. //
  110. Thread->AutoAlignment = Process->AutoAlignment;
  111. Thread->EnableStackSwap = TRUE;
  112. Thread->KernelStackResident = TRUE;
  113. //
  114. // Set the system service table pointer to the address of the static
  115. // system service descriptor table. If the thread is later converted
  116. // to a Win32 thread this pointer will be change to a pointer to the
  117. // shadow system service descriptor table.
  118. //
  119. Thread->ServiceTable = (PVOID)&KeServiceDescriptorTable[0];
  120. //
  121. // Initialize the APC state pointers, the current APC state, the saved
  122. // APC state, and enable APC queuing.
  123. //
  124. Thread->ApcStatePointer[0] = &Thread->ApcState;
  125. Thread->ApcStatePointer[1] = &Thread->SavedApcState;
  126. InitializeListHead(&Thread->ApcState.ApcListHead[KernelMode]);
  127. InitializeListHead(&Thread->ApcState.ApcListHead[UserMode]);
  128. Thread->ApcState.Process = Process;
  129. Thread->ApcQueueable = TRUE;
  130. //
  131. // Initialize the kernel mode suspend APC and the suspend semaphore object.
  132. // and the builtin wait timeout timer object.
  133. //
  134. KeInitializeApc(&Thread->SuspendApc,
  135. Thread,
  136. OriginalApcEnvironment,
  137. (PKKERNEL_ROUTINE)KiSuspendNop,
  138. (PKRUNDOWN_ROUTINE)KiSuspendRundown,
  139. KiSuspendThread,
  140. KernelMode,
  141. NULL);
  142. KeInitializeSemaphore(&Thread->SuspendSemaphore, 0L, 2L);
  143. //
  144. // Initialize the builtin timer trimer wait wait block.
  145. //
  146. // N.B. This is the only time the wait block is initialized sincs this
  147. // information is constant.
  148. //
  149. Timer = &Thread->Timer;
  150. KeInitializeTimer(Timer);
  151. WaitBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
  152. WaitBlock->Object = Timer;
  153. WaitBlock->WaitKey = (CSHORT)STATUS_TIMEOUT;
  154. WaitBlock->WaitType = WaitAny;
  155. WaitBlock->WaitListEntry.Flink = &Timer->Header.WaitListHead;
  156. WaitBlock->WaitListEntry.Blink = &Timer->Header.WaitListHead;
  157. //
  158. // Initialize the APC queue spinlock.
  159. //
  160. KeInitializeSpinLock(&Thread->ApcQueueLock);
  161. //
  162. // Initialize the Thread Environment Block (TEB) pointer (can be NULL).
  163. //
  164. Thread->Teb = Teb;
  165. #if defined(NT_UP)
  166. IdealProcessor = 0;
  167. #else
  168. //
  169. // Initialize the ideal processor number for the thread.
  170. //
  171. // Set IdealProcessor to next processor this thread is allowed to
  172. // run on.
  173. //
  174. // Get a bit mask of the affinity of all processors with a smaller
  175. // number than the last processor assigned to this process.
  176. //
  177. IdealProcessor = Process->ThreadSeed;
  178. PreferredSet = Process->Affinity & KeActiveProcessors;
  179. //
  180. // If possible bias the ideal processor to a different SMT set than the
  181. // last thread.
  182. //
  183. #if defined(NT_SMT)
  184. TempSet = ~KiProcessorBlock[IdealProcessor]->MultiThreadProcessorSet;
  185. if ((PreferredSet & TempSet) != 0) {
  186. PreferredSet &= TempSet;
  187. }
  188. #endif
  189. //
  190. // For NUMA systems bias the ideal processor to the same node as other
  191. // threads in the process.
  192. //
  193. #if defined(KE_MULTINODE)
  194. TempSet = KeNodeBlock[Process->IdealNode]->ProcessorMask;
  195. if ((PreferredSet & TempSet) != 0) {
  196. PreferredSet &= TempSet;
  197. }
  198. #endif
  199. IdealProcessor = KeFindNextRightSetAffinity(IdealProcessor,
  200. PreferredSet);
  201. #endif
  202. //
  203. // Set the initial node which is used for stack allocation and delete.
  204. // This needs to be determined as it may not have been possible to put
  205. // the thread on its ideal node.
  206. //
  207. #if defined(KE_MULTINODE)
  208. for (Index = Process->IdealNode;
  209. (KeNodeBlock[Index]->ProcessorMask & AFFINITY_MASK(IdealProcessor)) == 0;
  210. Index = Index > 0 ? Index - 1 : KeNumberNodes - 1) {
  211. if (Process->IdealNode == Index) {
  212. //
  213. // This can only happen if we wrapped,... which can't happen.
  214. //
  215. Index = 0;
  216. break;
  217. }
  218. }
  219. Thread->InitialNode = (UCHAR)Index;
  220. #else
  221. Thread->InitialNode = 0;
  222. #endif
  223. //
  224. // Set the initial kernel stack and the initial thread context.
  225. //
  226. if (KernelStack == NULL) {
  227. //
  228. // Get a kernel stack for this thread.
  229. //
  230. KernelStack = MmCreateKernelStack(FALSE, Thread->InitialNode);
  231. if (KernelStack == NULL) {
  232. return STATUS_INSUFFICIENT_RESOURCES;
  233. }
  234. KernelStackAllocated = TRUE;
  235. }
  236. Thread->InitialStack = KernelStack;
  237. Thread->StackBase = KernelStack;
  238. Thread->StackLimit = (PVOID)((ULONG_PTR)KernelStack - KERNEL_STACK_SIZE);
  239. try {
  240. KiInitializeContextThread(Thread,
  241. SystemRoutine,
  242. StartRoutine,
  243. StartContext,
  244. ContextFrame);
  245. } except (EXCEPTION_EXECUTE_HANDLER) {
  246. if (KernelStackAllocated) {
  247. MmDeleteKernelStack(Thread->StackBase, FALSE);
  248. Thread->InitialStack = NULL;
  249. }
  250. return GetExceptionCode();
  251. }
  252. //
  253. // Set the base thread priority, the thread priority, the thread affinity,
  254. // the thread quantum, and the scheduling state.
  255. //
  256. Thread->State = Initialized;
  257. #if defined(NT_UP)
  258. Thread->IdealProcessor = 0;
  259. Thread->SoftAffinity = 1;
  260. #else
  261. Thread->IdealProcessor = IdealProcessor;
  262. #endif
  263. return STATUS_SUCCESS;
  264. }
  265. VOID
  266. KeUninitThread (
  267. IN PKTHREAD Thread
  268. )
  269. /*++
  270. Routine Description:
  271. This function frees the thread kernel stack and must be called before
  272. the thread is started.
  273. Arguments:
  274. Thread - Supplies a pointer to a dispatcher object of type thread.
  275. Return Value:
  276. None.
  277. --*/
  278. {
  279. MmDeleteKernelStack(Thread->StackBase, FALSE);
  280. Thread->InitialStack = NULL;
  281. return;
  282. }
  283. VOID
  284. KeStartThread (
  285. IN PKTHREAD Thread
  286. )
  287. /*++
  288. Routine Description:
  289. This function initializes remaining thread fields and inserts the thread
  290. in the thread's process list. From this point on the thread must run.
  291. Arguments:
  292. Thread - Supplies a pointer to a dispatcher object of type thread.
  293. Return Value:
  294. None.
  295. --*/
  296. {
  297. KLOCK_QUEUE_HANDLE LockHandle;
  298. PKPROCESS Process;
  299. //
  300. // Initialize the thread priority, affinity, and quantum.
  301. //
  302. Process = Thread->ApcState.Process;
  303. Thread->BasePriority = Process->BasePriority;
  304. Thread->Priority = Thread->BasePriority;
  305. Thread->Affinity = Process->Affinity;
  306. Thread->UserAffinity = Process->Affinity;
  307. Thread->SystemAffinityActive = FALSE;
  308. Thread->Quantum = Process->ThreadQuantum;
  309. Thread->DisableBoost = Process->DisableBoost;
  310. #if !defined(NT_UP)
  311. Thread->SoftAffinity =
  312. KiProcessorBlock[Thread->IdealProcessor]->ParentNode->ProcessorMask;
  313. #endif
  314. #if defined(_X86_)
  315. Thread->Iopl = Process->Iopl;
  316. #endif
  317. //
  318. // Raise IRQL to SYNCH_LEVEL, acquire the process lock, and acquire the
  319. // dispatcher databack lock at SYNCH_LEVEL.
  320. //
  321. KeAcquireInStackQueuedSpinLockRaiseToSynch(&Process->ProcessLock, &LockHandle);
  322. KiLockDispatcherDatabaseAtSynchLevel();
  323. //
  324. // Insert the thread in the process thread list, and increment the kernel
  325. // stack count.
  326. //
  327. // N.B. The distinguished value MAXSHORT is used to signify that no
  328. // threads have been created for a process.
  329. //
  330. InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry);
  331. if (Process->StackCount == MAXSHORT) {
  332. Process->StackCount = 1;
  333. } else {
  334. Process->StackCount += 1;
  335. }
  336. #if !defined(NT_UP)
  337. Process->ThreadSeed = Thread->IdealProcessor;
  338. #endif
  339. //
  340. // Unlock dispatcher database from SYNCH_LEVEL, unlock the process lock
  341. // and lower IRQL to its previous value.
  342. //
  343. KiUnlockDispatcherDatabaseFromSynchLevel();
  344. KeReleaseInStackQueuedSpinLock(&LockHandle);
  345. return;
  346. }
  347. NTSTATUS
  348. KeInitializeThread (
  349. IN PKTHREAD Thread,
  350. IN PVOID KernelStack OPTIONAL,
  351. IN PKSYSTEM_ROUTINE SystemRoutine,
  352. IN PKSTART_ROUTINE StartRoutine OPTIONAL,
  353. IN PVOID StartContext OPTIONAL,
  354. IN PCONTEXT ContextFrame OPTIONAL,
  355. IN PVOID Teb OPTIONAL,
  356. IN PKPROCESS Process
  357. )
  358. /*++
  359. Routine Description:
  360. This function initializes a thread object. The priority, affinity,
  361. and initial quantum are taken from the parent process object. The
  362. thread object is inserted at the end of the thread list for the
  363. parent process.
  364. N.B. This routine is carefully written so that if an access violation
  365. occurs while reading the specified context frame, then no kernel
  366. data structures will have been modified. It is the responsibility
  367. of the caller to handle the exception and provide necessary clean
  368. up.
  369. N.B. It is assumed that the thread object is zeroed.
  370. Arguments:
  371. Thread - Supplies a pointer to a dispatcher object of type thread.
  372. KernelStack - Supplies a pointer to the base of a kernel stack on which
  373. the context frame for the thread is to be constructed.
  374. SystemRoutine - Supplies a pointer to the system function that is to be
  375. called when the thread is first scheduled for execution.
  376. StartRoutine - Supplies an optional pointer to a function that is to be
  377. called after the system has finished initializing the thread. This
  378. parameter is specified if the thread is a system thread and will
  379. execute totally in kernel mode.
  380. StartContext - Supplies an optional pointer to an arbitrary data structure
  381. which will be passed to the StartRoutine as a parameter. This
  382. parameter is specified if the thread is a system thread and will
  383. execute totally in kernel mode.
  384. ContextFrame - Supplies an optional pointer a context frame which contains
  385. the initial user mode state of the thread. This parameter is specified
  386. if the thread is a user thread and will execute in user mode. If this
  387. parameter is not specified, then the Teb parameter is ignored.
  388. Teb - Supplies an optional pointer to the user mode thread environment
  389. block. This parameter is specified if the thread is a user thread and
  390. will execute in user mode. This parameter is ignored if the ContextFrame
  391. parameter is not specified.
  392. Process - Supplies a pointer to a control object of type process.
  393. Return Value:
  394. NTSTATUS - Status of operation
  395. --*/
  396. {
  397. NTSTATUS Status;
  398. Status = KeInitThread(Thread,
  399. KernelStack,
  400. SystemRoutine,
  401. StartRoutine,
  402. StartContext,
  403. ContextFrame,
  404. Teb,
  405. Process);
  406. if (!NT_SUCCESS(Status)) {
  407. return Status;
  408. }
  409. KeStartThread(Thread);
  410. return STATUS_SUCCESS;
  411. }
  412. BOOLEAN
  413. KeAlertThread (
  414. IN PKTHREAD Thread,
  415. IN KPROCESSOR_MODE AlertMode
  416. )
  417. /*++
  418. Routine Description:
  419. This function attempts to alert a thread and cause its execution to
  420. be continued if it is currently in an alertable Wait state. Otherwise
  421. it just sets the alerted variable for the specified processor mode.
  422. Arguments:
  423. Thread - Supplies a pointer to a dispatcher object of type thread.
  424. AlertMode - Supplies the processor mode for which the thread is
  425. to be alerted.
  426. Return Value:
  427. The previous state of the alerted variable for the specified processor
  428. mode.
  429. --*/
  430. {
  431. BOOLEAN Alerted;
  432. KLOCK_QUEUE_HANDLE LockHandle;
  433. ASSERT_THREAD(Thread);
  434. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  435. //
  436. // Raise IRQL to SYNCH_LEVEL, acquire the thread APC queue lock, and lock
  437. // the dispatcher database.
  438. //
  439. KeAcquireInStackQueuedSpinLockRaiseToSynch(&Thread->ApcQueueLock, &LockHandle);
  440. KiLockDispatcherDatabaseAtSynchLevel();
  441. //
  442. // Capture the current state of the alerted variable for the specified
  443. // processor mode.
  444. //
  445. Alerted = Thread->Alerted[AlertMode];
  446. //
  447. // If the alerted state for the specified processor mode is Not-Alerted,
  448. // then attempt to alert the thread.
  449. //
  450. if (Alerted == FALSE) {
  451. //
  452. // If the thread is currently in a Wait state, the Wait is alertable,
  453. // and the specified processor mode is less than or equal to the Wait
  454. // mode, then the thread is unwaited with a status of "alerted".
  455. //
  456. if ((Thread->State == Waiting) && (Thread->Alertable == TRUE) &&
  457. (AlertMode <= Thread->WaitMode)) {
  458. KiUnwaitThread(Thread, STATUS_ALERTED, ALERT_INCREMENT, NULL);
  459. } else {
  460. Thread->Alerted[AlertMode] = TRUE;
  461. }
  462. }
  463. //
  464. // Unlock the dispatcher database from SYNCH_LEVEL, unlock the thread APC
  465. // queue lock and lower IRQL to its previous value, and return the previous
  466. // alerted state for the specified mode.
  467. //
  468. KiUnlockDispatcherDatabaseFromSynchLevel();
  469. KeReleaseInStackQueuedSpinLock(&LockHandle);
  470. return Alerted;
  471. }
  472. ULONG
  473. KeAlertResumeThread (
  474. IN PKTHREAD Thread
  475. )
  476. /*++
  477. Routine Description:
  478. This function attempts to alert a thread in kernel mode and cause its
  479. execution to be continued if it is currently in an alertable Wait state.
  480. In addition, a resume operation is performed on the specified thread.
  481. Arguments:
  482. Thread - Supplies a pointer to a dispatcher object of type thread.
  483. Return Value:
  484. The previous suspend count.
  485. --*/
  486. {
  487. ULONG OldCount;
  488. KLOCK_QUEUE_HANDLE LockHandle;
  489. ASSERT_THREAD(Thread);
  490. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  491. //
  492. // Raise IRQL to SYNCH_LEVEL, acquire the thread APC queue lock, and lock
  493. // the dispatcher database.
  494. //
  495. KeAcquireInStackQueuedSpinLockRaiseToSynch(&Thread->ApcQueueLock, &LockHandle);
  496. KiLockDispatcherDatabaseAtSynchLevel();
  497. //
  498. // If the kernel mode alerted state is FALSE, then attempt to alert
  499. // the thread for kernel mode.
  500. //
  501. if (Thread->Alerted[KernelMode] == FALSE) {
  502. //
  503. // If the thread is currently in a Wait state and the Wait is alertable,
  504. // then the thread is unwaited with a status of "alerted". Else set the
  505. // kernel mode alerted variable.
  506. //
  507. if ((Thread->State == Waiting) && (Thread->Alertable == TRUE)) {
  508. KiUnwaitThread(Thread, STATUS_ALERTED, ALERT_INCREMENT, NULL);
  509. } else {
  510. Thread->Alerted[KernelMode] = TRUE;
  511. }
  512. }
  513. //
  514. // Capture the current suspend count.
  515. //
  516. OldCount = Thread->SuspendCount;
  517. //
  518. // If the thread is currently suspended, then decrement its suspend count.
  519. //
  520. if (OldCount != 0) {
  521. Thread->SuspendCount -= 1;
  522. //
  523. // If the resultant suspend count is zero and the freeze count is
  524. // zero, then resume the thread by releasing its suspend semaphore.
  525. //
  526. if ((Thread->SuspendCount == 0) && (Thread->FreezeCount == 0)) {
  527. Thread->SuspendSemaphore.Header.SignalState += 1;
  528. KiWaitTest(&Thread->SuspendSemaphore, RESUME_INCREMENT);
  529. }
  530. }
  531. //
  532. // Unlock the dispatcher database from SYNCH_LEVEL, unlock the thread APC
  533. // queue lock and lower IRQL to its previous value, and return the previous
  534. // suspend count.
  535. //
  536. KiUnlockDispatcherDatabaseFromSynchLevel();
  537. KeReleaseInStackQueuedSpinLock(&LockHandle);
  538. return OldCount;
  539. }
  540. VOID
  541. KeBoostPriorityThread (
  542. IN PKTHREAD Thread,
  543. IN KPRIORITY Increment
  544. )
  545. /*++
  546. Routine Description:
  547. This function boosts the priority of the specified thread using the
  548. same algorithm used when a thread gets a boost from a wait operation.
  549. Arguments:
  550. Thread - Supplies a pointer to a dispatcher object of type thread.
  551. Increment - Supplies the priority increment that is to be applied to
  552. the thread's priority.
  553. Return Value:
  554. None.
  555. --*/
  556. {
  557. KIRQL OldIrql;
  558. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  559. //
  560. // Raise IRQL to dispatcher level and lock dispatcher database.
  561. //
  562. KiLockDispatcherDatabase(&OldIrql);
  563. //
  564. // If the thread does not run at a realtime priority level, then boost
  565. // the thread priority.
  566. //
  567. if (Thread->Priority < LOW_REALTIME_PRIORITY) {
  568. KiBoostPriorityThread(Thread, Increment);
  569. }
  570. //
  571. // Unlock dispatcher database and lower IRQL to its previous
  572. // value.
  573. //
  574. KiUnlockDispatcherDatabase(OldIrql);
  575. return;
  576. }
  577. KAFFINITY
  578. KeConfineThread (
  579. VOID
  580. )
  581. /*++
  582. Routine Description:
  583. This function confines the execution of the current thread to the current
  584. processor.
  585. Arguments:
  586. Thread - Supplies a pointer to a dispatcher object of type thread.
  587. Return Value:
  588. The previous affinity value.
  589. --*/
  590. {
  591. KAFFINITY Affinity;
  592. KIRQL OldIrql;
  593. PKTHREAD Thread;
  594. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  595. //
  596. // Raise IRQL to dispatcher level and lock dispatcher database.
  597. //
  598. Thread = KeGetCurrentThread();
  599. KiLockDispatcherDatabase(&OldIrql);
  600. //
  601. // Capture the current affinity and compute new affinity value by
  602. // shifting a one bit left by the current processor number.
  603. //
  604. Affinity = Thread->Affinity;
  605. Thread->Affinity = AFFINITY_MASK(Thread->NextProcessor);
  606. //
  607. // Unlock dispatcher database and lower IRQL to its previous
  608. // value.
  609. //
  610. KiUnlockDispatcherDatabase(OldIrql);
  611. //
  612. // Return the previous affinity value.
  613. //
  614. return Affinity;
  615. }
  616. BOOLEAN
  617. KeDisableApcQueuingThread (
  618. IN PKTHREAD Thread
  619. )
  620. /*++
  621. Routine Description:
  622. This function disables the queuing of APC's to the specified thread.
  623. Arguments:
  624. Thread - Supplies a pointer to a dispatcher object of type thread.
  625. Return Value:
  626. The previous value of the APC queuing state variable.
  627. --*/
  628. {
  629. BOOLEAN ApcQueueable;
  630. KIRQL OldIrql;
  631. ASSERT_THREAD(Thread);
  632. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  633. //
  634. // Raise IRQL to dispatcher level and lock dispatcher database.
  635. //
  636. KiLockDispatcherDatabase(&OldIrql);
  637. //
  638. // Capture the current state of the APC queueable state variable and
  639. // set its state to FALSE.
  640. //
  641. ApcQueueable = Thread->ApcQueueable;
  642. Thread->ApcQueueable = FALSE;
  643. //
  644. // Unlock dispatcher database and lower IRQL to its previous
  645. // value.
  646. //
  647. KiUnlockDispatcherDatabase(OldIrql);
  648. //
  649. // Return the previous APC queueable state.
  650. //
  651. return ApcQueueable;
  652. }
  653. BOOLEAN
  654. KeEnableApcQueuingThread (
  655. IN PKTHREAD Thread
  656. )
  657. /*++
  658. Routine Description:
  659. This function enables the queuing of APC's to the specified thread.
  660. Arguments:
  661. Thread - Supplies a pointer to a dispatcher object of type thread.
  662. Return Value:
  663. The previous value of the APC queuing state variable.
  664. --*/
  665. {
  666. BOOLEAN ApcQueueable;
  667. KIRQL OldIrql;
  668. ASSERT_THREAD(Thread);
  669. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  670. //
  671. // Raise IRQL to dispatcher level and lock dispatcher database.
  672. //
  673. KiLockDispatcherDatabase(&OldIrql);
  674. //
  675. // Capture the current state of the APC queueable state variable and
  676. // set its state to TRUE.
  677. //
  678. ApcQueueable = Thread->ApcQueueable;
  679. Thread->ApcQueueable = TRUE;
  680. //
  681. // Unlock dispatcher database and lower IRQL to its previous
  682. // value.
  683. //
  684. KiUnlockDispatcherDatabase(OldIrql);
  685. //
  686. // Return previous APC queueable state.
  687. //
  688. return ApcQueueable;
  689. }
  690. ULONG
  691. KeForceResumeThread (
  692. IN PKTHREAD Thread
  693. )
  694. /*++
  695. Routine Description:
  696. This function forces resumption of thread execution if the thread is
  697. suspended. If the specified thread is not suspended, then no operation
  698. is performed.
  699. Arguments:
  700. Thread - Supplies a pointer to a dispatcher object of type thread.
  701. Return Value:
  702. The sum of the previous suspend count and the freeze count.
  703. --*/
  704. {
  705. ULONG OldCount;
  706. KIRQL OldIrql;
  707. ASSERT_THREAD(Thread);
  708. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  709. //
  710. // Raise IRQL to dispatcher level and lock dispatcher database.
  711. //
  712. KiLockDispatcherDatabase(&OldIrql);
  713. //
  714. // Capture the current suspend count.
  715. //
  716. OldCount = Thread->SuspendCount + Thread->FreezeCount;
  717. //
  718. // If the thread is currently suspended, then force resumption of
  719. // thread execution.
  720. //
  721. if (OldCount != 0) {
  722. Thread->FreezeCount = 0;
  723. Thread->SuspendCount = 0;
  724. Thread->SuspendSemaphore.Header.SignalState += 1;
  725. KiWaitTest(&Thread->SuspendSemaphore, RESUME_INCREMENT);
  726. }
  727. //
  728. // Unlock dispatcher database and lower IRQL to its previous
  729. // value.
  730. //
  731. KiUnlockDispatcherDatabase(OldIrql);
  732. //
  733. // Return the previous suspend count.
  734. //
  735. return OldCount;
  736. }
  737. VOID
  738. KeFreezeAllThreads (
  739. VOID
  740. )
  741. /*++
  742. Routine Description:
  743. This function suspends the execution of all thread in the current
  744. process except the current thread. If the freeze count overflows
  745. the maximum suspend count, then a condition is raised.
  746. Arguments:
  747. None.
  748. Return Value:
  749. None.
  750. --*/
  751. {
  752. PKTHREAD CurrentThread;
  753. PLIST_ENTRY ListHead;
  754. PLIST_ENTRY NextEntry;
  755. PKPROCESS Process;
  756. KLOCK_QUEUE_HANDLE ProcessHandle;
  757. PKTHREAD Thread;
  758. KLOCK_QUEUE_HANDLE ThreadHandle;
  759. ULONG OldCount;
  760. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  761. //
  762. // Set the address of the current thread object and the current process
  763. // object.
  764. //
  765. CurrentThread = KeGetCurrentThread();
  766. Process = CurrentThread->ApcState.Process;
  767. //
  768. // Raise IRQL to SYNCH_LEVEL and acquire the process lock.
  769. //
  770. KeAcquireInStackQueuedSpinLockRaiseToSynch(&Process->ProcessLock,
  771. &ProcessHandle);
  772. //
  773. // If the freeze count of the current thread is not zero, then there
  774. // is another thread that is trying to freeze this thread. Unlock the
  775. // the process lock and lower IRQL to its previous value, allow the
  776. // suspend APC to occur, then raise IRQL to SYNCH_LEVEL and lock the
  777. // process lock.
  778. //
  779. while (CurrentThread->FreezeCount != 0) {
  780. KeReleaseInStackQueuedSpinLock(&ProcessHandle);
  781. KeAcquireInStackQueuedSpinLockRaiseToSynch(&Process->ProcessLock,
  782. &ProcessHandle);
  783. }
  784. KeEnterCriticalRegion();
  785. //
  786. // Freeze all threads except the current thread.
  787. //
  788. ListHead = &Process->ThreadListHead;
  789. NextEntry = ListHead->Flink;
  790. do {
  791. //
  792. // Get the address of the next thread.
  793. //
  794. Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry);
  795. //
  796. // Acquire the thread APC queue lock and acquire the dispatcher
  797. // database lock.
  798. //
  799. KeAcquireInStackQueuedSpinLockAtDpcLevel(&Thread->ApcQueueLock,
  800. &ThreadHandle);
  801. KiLockDispatcherDatabaseAtSynchLevel();
  802. //
  803. // If the thread is not the current thread and APCs are queueable,
  804. // then attempt to suspend the thread.
  805. //
  806. if ((Thread != CurrentThread) && (Thread->ApcQueueable == TRUE)) {
  807. //
  808. // Increment the freeze count. If the thread was not previously
  809. // suspended, then queue the thread's suspend APC.
  810. //
  811. OldCount = Thread->FreezeCount;
  812. ASSERT(OldCount != MAXIMUM_SUSPEND_COUNT);
  813. Thread->FreezeCount += 1;
  814. if ((OldCount == 0) && (Thread->SuspendCount == 0)) {
  815. if (KiInsertQueueApc(&Thread->SuspendApc, RESUME_INCREMENT) == FALSE) {
  816. Thread->SuspendSemaphore.Header.SignalState -= 1;
  817. }
  818. }
  819. }
  820. //
  821. // Release the dispatcher database lock and the thread APC queue lock.
  822. //
  823. KiUnlockDispatcherDatabaseFromSynchLevel();
  824. KeReleaseInStackQueuedSpinLockFromDpcLevel(&ThreadHandle);
  825. NextEntry = NextEntry->Flink;
  826. } while (NextEntry != ListHead);
  827. //
  828. // Unlock the process lock and lower IRQL to its previous value.
  829. //
  830. KeReleaseInStackQueuedSpinLock(&ProcessHandle);
  831. return;
  832. }
  833. BOOLEAN
  834. KeQueryAutoAlignmentThread (
  835. IN PKTHREAD Thread
  836. )
  837. /*++
  838. Routine Description:
  839. This function returns the data alignment handling mode for the specified
  840. thread.
  841. Arguments:
  842. None.
  843. Return Value:
  844. A value of TRUE is returned if data alignment exceptions are being
  845. automatically handled by the kernel. Otherwise, a value of FALSE
  846. is returned.
  847. --*/
  848. {
  849. ASSERT_THREAD(Thread);
  850. //
  851. // Return the data alignment handling mode for the thread.
  852. //
  853. return Thread->AutoAlignment;
  854. }
  855. LONG
  856. KeQueryBasePriorityThread (
  857. IN PKTHREAD Thread
  858. )
  859. /*++
  860. Routine Description:
  861. This function returns the base priority increment of the specified
  862. thread.
  863. Arguments:
  864. Thread - Supplies a pointer to a dispatcher object of type thread.
  865. Return Value:
  866. The base priority increment of the specified thread.
  867. --*/
  868. {
  869. LONG Increment;
  870. KIRQL OldIrql;
  871. PKPROCESS Process;
  872. ASSERT_THREAD(Thread);
  873. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  874. //
  875. // Raise IRQL to dispatcher level and lock dispatcher database.
  876. //
  877. KiLockDispatcherDatabase(&OldIrql);
  878. //
  879. // If priority saturation occured the last time the thread base priority
  880. // was set, then return the saturation increment value. Otherwise, compute
  881. // the increment value as the difference between the thread base priority
  882. // and the process base priority.
  883. //
  884. Process = Thread->ApcStatePointer[0]->Process;
  885. Increment = Thread->BasePriority - Process->BasePriority;
  886. if (Thread->Saturation != 0) {
  887. Increment = ((HIGH_PRIORITY + 1) / 2) * Thread->Saturation;
  888. }
  889. //
  890. // Unlock dispatcher database and lower IRQL to its previous
  891. // value.
  892. //
  893. KiUnlockDispatcherDatabase(OldIrql);
  894. //
  895. // Return the previous thread base priority increment.
  896. //
  897. return Increment;
  898. }
  899. KPRIORITY
  900. KeQueryPriorityThread (
  901. IN PKTHREAD Thread
  902. )
  903. /*++
  904. Routine Description:
  905. This function returns the current priority of the specified thread.
  906. Arguments:
  907. Thread - Supplies a pointer to a dispatcher object of type thread.
  908. Return Value:
  909. The current priority of the specified thread.
  910. --*/
  911. {
  912. return Thread->Priority;
  913. }
  914. ULONG
  915. KeQueryRuntimeThread (
  916. IN PKTHREAD Thread,
  917. OUT PULONG UserTime
  918. )
  919. /*++
  920. Routine Description:
  921. This function returns the kernel and user runtime for the specified
  922. thread.
  923. Arguments:
  924. Thread - Supplies a pointer to a dispatcher object of type thread.
  925. UserTime - Supplies a pointer to a variable that receives the user
  926. runtime for the specified thread.
  927. Return Value:
  928. The kernel runtime for the specfied thread is returned.
  929. --*/
  930. {
  931. ASSERT_THREAD(Thread);
  932. *UserTime = Thread->UserTime;
  933. return Thread->KernelTime;
  934. }
  935. BOOLEAN
  936. KeReadStateThread (
  937. IN PKTHREAD Thread
  938. )
  939. /*++
  940. Routine Description:
  941. This function reads the current signal state of a thread object.
  942. Arguments:
  943. Thread - Supplies a pointer to a dispatcher object of type thread.
  944. Return Value:
  945. The current signal state of the thread object.
  946. --*/
  947. {
  948. ASSERT_THREAD(Thread);
  949. //
  950. // Return current signal state of thread object.
  951. //
  952. return (BOOLEAN)Thread->Header.SignalState;
  953. }
  954. VOID
  955. KeReadyThread (
  956. IN PKTHREAD Thread
  957. )
  958. /*++
  959. Routine Description:
  960. This function readies a thread for execution. If the thread's process
  961. is currently not in the balance set, then the thread is inserted in the
  962. thread's process' ready queue. Else if the thread is higher priority than
  963. another thread that is currently running on a processor then the thread
  964. is selected for execution on that processor. Else the thread is inserted
  965. in the dispatcher ready queue selected by its priority.
  966. Arguments:
  967. Thread - Supplies a pointer to a dispatcher object of type thread.
  968. Return Value:
  969. None.
  970. --*/
  971. {
  972. KIRQL OldIrql;
  973. ASSERT_THREAD(Thread);
  974. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  975. //
  976. // Raise IRQL to dispatcher level and lock dispatcher database.
  977. //
  978. KiLockDispatcherDatabase(&OldIrql);
  979. //
  980. // Ready the specified thread for execution.
  981. //
  982. KiReadyThread(Thread);
  983. //
  984. // Unlock dispatcher database and lower IRQL to its previous
  985. // value.
  986. //
  987. KiUnlockDispatcherDatabase(OldIrql);
  988. return;
  989. }
  990. ULONG
  991. KeResumeThread (
  992. IN PKTHREAD Thread
  993. )
  994. /*++
  995. Routine Description:
  996. This function resumes the execution of a suspended thread. If the
  997. specified thread is not suspended, then no operation is performed.
  998. Arguments:
  999. Thread - Supplies a pointer to a dispatcher object of type thread.
  1000. Return Value:
  1001. The previous suspend count.
  1002. --*/
  1003. {
  1004. ULONG OldCount;
  1005. KIRQL OldIrql;
  1006. ASSERT_THREAD(Thread);
  1007. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  1008. //
  1009. // Raise IRQL to dispatcher level and lock dispatcher database.
  1010. //
  1011. KiLockDispatcherDatabase(&OldIrql);
  1012. //
  1013. // Capture the current suspend count.
  1014. //
  1015. OldCount = Thread->SuspendCount;
  1016. //
  1017. // If the thread is currently suspended, then decrement its suspend count.
  1018. //
  1019. if (OldCount != 0) {
  1020. Thread->SuspendCount -= 1;
  1021. //
  1022. // If the resultant suspend count is zero and the freeze count is
  1023. // zero, then resume the thread by releasing its suspend semaphore.
  1024. //
  1025. if ((Thread->SuspendCount == 0) && (Thread->FreezeCount == 0)) {
  1026. Thread->SuspendSemaphore.Header.SignalState += 1;
  1027. KiWaitTest(&Thread->SuspendSemaphore, RESUME_INCREMENT);
  1028. }
  1029. }
  1030. //
  1031. // Unlock dispatcher database and lower IRQL to its previous
  1032. // value.
  1033. //
  1034. KiUnlockDispatcherDatabase(OldIrql);
  1035. //
  1036. // Return the previous suspend count.
  1037. //
  1038. return OldCount;
  1039. }
  1040. VOID
  1041. KeRevertToUserAffinityThread (
  1042. VOID
  1043. )
  1044. /*++
  1045. Routine Description:
  1046. This function setss the affinity of the current thread to its user
  1047. affinity.
  1048. Arguments:
  1049. None.
  1050. Return Value:
  1051. None.
  1052. --*/
  1053. {
  1054. PKTHREAD CurrentThread;
  1055. PKTHREAD NextThread;
  1056. KIRQL OldIrql;
  1057. PKPRCB Prcb;
  1058. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  1059. ASSERT(KeGetCurrentThread()->SystemAffinityActive != FALSE);
  1060. //
  1061. // Raise IRQL to dispatcher level and lock dispatcher database.
  1062. //
  1063. CurrentThread = KeGetCurrentThread();
  1064. KiLockDispatcherDatabase(&OldIrql);
  1065. //
  1066. // Set the current affinity to the user affinity.
  1067. //
  1068. // If the current processor is not in the new affinity set and another
  1069. // thread has not already been selected for execution on the current
  1070. // processor, then select a new thread for the current processor.
  1071. //
  1072. CurrentThread->Affinity = CurrentThread->UserAffinity;
  1073. CurrentThread->SystemAffinityActive = FALSE;
  1074. Prcb = KeGetCurrentPrcb();
  1075. if (((Prcb->SetMember & CurrentThread->Affinity) == 0) &&
  1076. (Prcb->NextThread == NULL)) {
  1077. NextThread = KiSelectNextThread(CurrentThread->NextProcessor);
  1078. NextThread->State = Standby;
  1079. Prcb->NextThread = NextThread;
  1080. }
  1081. //
  1082. // Unlock dispatcher database and lower IRQL to its previous value.
  1083. //
  1084. KiUnlockDispatcherDatabase(OldIrql);
  1085. return;
  1086. }
  1087. VOID
  1088. KeRundownThread (
  1089. )
  1090. /*++
  1091. Routine Description:
  1092. This function is called by the executive to rundown thread structures
  1093. which must be guarded by the dispatcher database lock and which must
  1094. be processed before actually terminating the thread. An example of such
  1095. a structure is the mutant ownership list that is anchored in the kernel
  1096. thread object.
  1097. Arguments:
  1098. None.
  1099. Return Value:
  1100. None.
  1101. --*/
  1102. {
  1103. PKMUTANT Mutant;
  1104. PLIST_ENTRY NextEntry;
  1105. KIRQL OldIrql;
  1106. PKTHREAD Thread;
  1107. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  1108. Thread = KeGetCurrentThread();
  1109. if (IsListEmpty (&Thread->MutantListHead)) {
  1110. return;
  1111. }
  1112. //
  1113. // Raise IRQL to dispatcher level and lock dispatcher database.
  1114. //
  1115. KiLockDispatcherDatabase(&OldIrql);
  1116. //
  1117. // Scan the list of owned mutant objects and release the mutant objects
  1118. // with an abandoned status. If the mutant is a kernel mutex, then bug
  1119. // check.
  1120. //
  1121. NextEntry = Thread->MutantListHead.Flink;
  1122. while (NextEntry != &Thread->MutantListHead) {
  1123. Mutant = CONTAINING_RECORD(NextEntry, KMUTANT, MutantListEntry);
  1124. if (Mutant->ApcDisable != 0) {
  1125. KeBugCheckEx(THREAD_TERMINATE_HELD_MUTEX,
  1126. (ULONG_PTR)Thread,
  1127. (ULONG_PTR)Mutant, 0, 0);
  1128. }
  1129. RemoveEntryList(&Mutant->MutantListEntry);
  1130. Mutant->Header.SignalState = 1;
  1131. Mutant->Abandoned = TRUE;
  1132. Mutant->OwnerThread = (PKTHREAD)NULL;
  1133. if (IsListEmpty(&Mutant->Header.WaitListHead) != TRUE) {
  1134. KiWaitTest(Mutant, MUTANT_INCREMENT);
  1135. }
  1136. NextEntry = Thread->MutantListHead.Flink;
  1137. }
  1138. //
  1139. // Release dispatcher database lock and lower IRQL to its previous value.
  1140. //
  1141. KiUnlockDispatcherDatabase(OldIrql);
  1142. return;
  1143. }
  1144. KAFFINITY
  1145. KeSetAffinityThread (
  1146. IN PKTHREAD Thread,
  1147. IN KAFFINITY Affinity
  1148. )
  1149. /*++
  1150. Routine Description:
  1151. This function sets the affinity of a specified thread to a new value.
  1152. Arguments:
  1153. Thread - Supplies a pointer to a dispatcher object of type thread.
  1154. Affinity - Supplies the new of set of processors on which the thread
  1155. can run.
  1156. Return Value:
  1157. The previous affinity of the specified thread.
  1158. --*/
  1159. {
  1160. KAFFINITY OldAffinity;
  1161. KIRQL OldIrql;
  1162. ASSERT_THREAD(Thread);
  1163. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  1164. //
  1165. // Raise IRQL to dispatcher level and lock dispatcher database.
  1166. //
  1167. KiLockDispatcherDatabase(&OldIrql);
  1168. //
  1169. // Set the thread affinity to the specified value.
  1170. //
  1171. OldAffinity = KiSetAffinityThread(Thread, Affinity);
  1172. //
  1173. // Unlock dispatcher database, lower IRQL to its previous value, and
  1174. // return the previous user affinity.
  1175. //
  1176. KiUnlockDispatcherDatabase(OldIrql);
  1177. return OldAffinity;
  1178. }
  1179. VOID
  1180. KeSetSystemAffinityThread (
  1181. IN KAFFINITY Affinity
  1182. )
  1183. /*++
  1184. Routine Description:
  1185. This function set the system affinity of the current thread.
  1186. Arguments:
  1187. Affinity - Supplies the new of set of processors on which the thread
  1188. can run.
  1189. Return Value:
  1190. None.
  1191. --*/
  1192. {
  1193. PKTHREAD CurrentThread;
  1194. PKTHREAD NextThread;
  1195. KIRQL OldIrql;
  1196. PKPRCB Prcb;
  1197. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  1198. ASSERT((Affinity & KeActiveProcessors) != 0);
  1199. //
  1200. // Raise IRQL to dispatcher level and lock dispatcher database.
  1201. //
  1202. CurrentThread = KeGetCurrentThread();
  1203. KiLockDispatcherDatabase(&OldIrql);
  1204. //
  1205. // Set the current affinity to the specified affinity.
  1206. //
  1207. // If the current processor is not in the new affinity set and another
  1208. // thread has not already been selected for execution on the current
  1209. // processor, then select a new thread for the current processor.
  1210. //
  1211. CurrentThread->Affinity = Affinity;
  1212. CurrentThread->SystemAffinityActive = TRUE;
  1213. Prcb = KeGetCurrentPrcb();
  1214. if (((Prcb->SetMember & CurrentThread->Affinity) == 0) &&
  1215. (Prcb->NextThread == NULL)) {
  1216. NextThread = KiSelectNextThread(CurrentThread->NextProcessor);
  1217. NextThread->State = Standby;
  1218. Prcb->NextThread = NextThread;
  1219. }
  1220. //
  1221. // Unlock dispatcher database and lower IRQL to its previous value.
  1222. //
  1223. KiUnlockDispatcherDatabase(OldIrql);
  1224. return;
  1225. }
  1226. LONG
  1227. KeSetBasePriorityThread (
  1228. IN PKTHREAD Thread,
  1229. IN LONG Increment
  1230. )
  1231. /*++
  1232. Routine Description:
  1233. This function sets the base priority of the specified thread to a
  1234. new value. The new base priority for the thread is the process base
  1235. priority plus the increment.
  1236. Arguments:
  1237. Thread - Supplies a pointer to a dispatcher object of type thread.
  1238. Increment - Supplies the base priority increment of the subject thread.
  1239. N.B. If the absolute value of the increment is such that saturation
  1240. of the base priority is forced, then subsequent changes to the
  1241. parent process base priority will not change the base priority
  1242. of the thread.
  1243. Return Value:
  1244. The previous base priority increment of the specified thread.
  1245. --*/
  1246. {
  1247. KPRIORITY NewBase;
  1248. KPRIORITY NewPriority;
  1249. KPRIORITY OldBase;
  1250. LONG OldIncrement;
  1251. KIRQL OldIrql;
  1252. PKPROCESS Process;
  1253. ASSERT_THREAD(Thread);
  1254. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  1255. //
  1256. // Raise IRQL to dispatcher level and lock dispatcher database.
  1257. //
  1258. KiLockDispatcherDatabase(&OldIrql);
  1259. //
  1260. // Capture the base priority of the specified thread and determine
  1261. // whether saturation if being forced.
  1262. //
  1263. Process = Thread->ApcStatePointer[0]->Process;
  1264. OldBase = Thread->BasePriority;
  1265. OldIncrement = OldBase - Process->BasePriority;
  1266. if (Thread->Saturation != 0) {
  1267. OldIncrement = ((HIGH_PRIORITY + 1) / 2) * Thread->Saturation;
  1268. }
  1269. Thread->Saturation = FALSE;
  1270. if (abs(Increment) >= (HIGH_PRIORITY + 1) / 2) {
  1271. Thread->Saturation = (Increment > 0) ? 1 : -1;
  1272. }
  1273. //
  1274. // Set the base priority of the specified thread. If the thread's process
  1275. // is in the realtime class, then limit the change to the realtime class.
  1276. // Otherwise, limit the change to the variable class.
  1277. //
  1278. NewBase = Process->BasePriority + Increment;
  1279. if (Process->BasePriority >= LOW_REALTIME_PRIORITY) {
  1280. if (NewBase < LOW_REALTIME_PRIORITY) {
  1281. NewBase = LOW_REALTIME_PRIORITY;
  1282. } else if (NewBase > HIGH_PRIORITY) {
  1283. NewBase = HIGH_PRIORITY;
  1284. }
  1285. //
  1286. // Set the new priority of the thread to the new base priority.
  1287. //
  1288. NewPriority = NewBase;
  1289. } else {
  1290. if (NewBase >= LOW_REALTIME_PRIORITY) {
  1291. NewBase = LOW_REALTIME_PRIORITY - 1;
  1292. } else if (NewBase <= LOW_PRIORITY) {
  1293. NewBase = 1;
  1294. }
  1295. //
  1296. // Compute the new thread priority. If the new priority is outside
  1297. // the variable class, then set the new priority to the highest
  1298. // variable priority.
  1299. //
  1300. if (Thread->Saturation != 0) {
  1301. NewPriority = NewBase;
  1302. } else {
  1303. NewPriority = Thread->Priority +
  1304. (NewBase - OldBase) - Thread->PriorityDecrement;
  1305. if (NewPriority >= LOW_REALTIME_PRIORITY) {
  1306. NewPriority = LOW_REALTIME_PRIORITY - 1;
  1307. }
  1308. }
  1309. }
  1310. //
  1311. // Set the new base priority and clear the priority decrement. If the
  1312. // new priority is not equal to the old priority, then set the new thread
  1313. // priority.
  1314. //
  1315. Thread->BasePriority = (SCHAR)NewBase;
  1316. Thread->DecrementCount = 0;
  1317. Thread->PriorityDecrement = 0;
  1318. if (NewPriority != Thread->Priority) {
  1319. Thread->Quantum = Process->ThreadQuantum;
  1320. KiSetPriorityThread(Thread, NewPriority);
  1321. }
  1322. //
  1323. // Unlock dispatcher database and lower IRQL to its previous
  1324. // value.
  1325. //
  1326. KiUnlockDispatcherDatabase(OldIrql);
  1327. //
  1328. // Return the previous thread base priority.
  1329. //
  1330. return OldIncrement;
  1331. }
  1332. LOGICAL
  1333. KeSetDisableBoostThread (
  1334. IN PKTHREAD Thread,
  1335. IN LOGICAL Disable
  1336. )
  1337. /*++
  1338. Routine Description:
  1339. This function disables priority boosts for the specified thread.
  1340. Arguments:
  1341. Thread - Supplies a pointer to a dispatcher object of type thread.
  1342. Disable - Supplies a logical value that determines whether priority
  1343. boosts for the thread are disabled or enabled.
  1344. Return Value:
  1345. The previous value of the disable boost state variable.
  1346. --*/
  1347. {
  1348. LOGICAL DisableBoost;
  1349. KIRQL OldIrql;
  1350. ASSERT_THREAD(Thread);
  1351. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  1352. //
  1353. // Raise IRQL to dispatcher level and lock dispatcher database.
  1354. //
  1355. KiLockDispatcherDatabase(&OldIrql);
  1356. //
  1357. // Capture the current state of the disable boost variable and set its
  1358. // state to TRUE.
  1359. //
  1360. DisableBoost = Thread->DisableBoost;
  1361. Thread->DisableBoost = (BOOLEAN)Disable;
  1362. //
  1363. // Unlock dispatcher database and lower IRQL to its previous
  1364. // value.
  1365. //
  1366. KiUnlockDispatcherDatabase(OldIrql);
  1367. //
  1368. // Return the previous disable boost state.
  1369. //
  1370. return DisableBoost;
  1371. }
  1372. CCHAR
  1373. KeSetIdealProcessorThread (
  1374. IN PKTHREAD Thread,
  1375. IN CCHAR Processor
  1376. )
  1377. /*++
  1378. Routine Description:
  1379. This function sets the ideal processor for the specified thread execution.
  1380. If the selected processor is greater than the number of processors in the
  1381. system, a processor is selected from the set of available processors.
  1382. Arguments:
  1383. Thread - Supplies a pointer to the thread whose ideal processor number is
  1384. set to the specfied value.
  1385. Processor - Supplies the number of the ideal processor.
  1386. Return Value:
  1387. The previous ideal processor number.
  1388. --*/
  1389. {
  1390. CCHAR OldProcessor;
  1391. KIRQL OldIrql;
  1392. PKPROCESS Process;
  1393. //
  1394. // Capture the previous ideal processor value, set the new ideal processor
  1395. // value, and return the old ideal processor value for the current thread.
  1396. //
  1397. ASSERT(Processor <= MAXIMUM_PROCESSORS);
  1398. KiLockDispatcherDatabase(&OldIrql);
  1399. OldProcessor = Thread->IdealProcessor;
  1400. if (Processor < KeNumberProcessors) {
  1401. Thread->IdealProcessor = Processor;
  1402. } else {
  1403. Process = Thread->ApcState.Process;
  1404. Thread->IdealProcessor =
  1405. KeFindNextRightSetAffinity(Process->ThreadSeed,
  1406. KeNodeBlock[Process->IdealNode]->ProcessorMask);
  1407. Process->ThreadSeed = Thread->IdealProcessor;
  1408. }
  1409. Thread->SoftAffinity =
  1410. KiProcessorBlock[Thread->IdealProcessor]->ParentNode->ProcessorMask;
  1411. //
  1412. // Unlock dispatcher database and lower IRQL to its previous value.
  1413. //
  1414. KiUnlockDispatcherDatabase(OldIrql);
  1415. return OldProcessor;
  1416. }
  1417. BOOLEAN
  1418. KeSetKernelStackSwapEnable (
  1419. IN BOOLEAN Enable
  1420. )
  1421. /*++
  1422. Routine Description:
  1423. This function sets the kernel stack swap enable value for the current
  1424. thread and returns the old swap enable value.
  1425. Arguments:
  1426. Enable - Supplies the new kernel stack swap enable value.
  1427. Return Value:
  1428. The previous kernel stack swap enable value.
  1429. --*/
  1430. {
  1431. BOOLEAN OldState;
  1432. PKTHREAD Thread;
  1433. //
  1434. // Capture the previous kernel stack swap enable value, set the new
  1435. // swap enable value, and return the old swap enable value for the
  1436. // current thread;
  1437. //
  1438. Thread = KeGetCurrentThread();
  1439. OldState = Thread->EnableStackSwap;
  1440. Thread->EnableStackSwap = Enable;
  1441. return OldState;
  1442. }
  1443. KPRIORITY
  1444. KeSetPriorityThread (
  1445. IN PKTHREAD Thread,
  1446. IN KPRIORITY Priority
  1447. )
  1448. /*++
  1449. Routine Description:
  1450. This function sets the priority of the specified thread to a new value.
  1451. If the new thread priority is lower than the old thread priority, then
  1452. resecheduling may take place if the thread is currently running on, or
  1453. about to run on, a processor.
  1454. Arguments:
  1455. Thread - Supplies a pointer to a dispatcher object of type thread.
  1456. Priority - Supplies the new priority of the subject thread.
  1457. Return Value:
  1458. The previous priority of the specified thread.
  1459. --*/
  1460. {
  1461. KIRQL OldIrql;
  1462. KPRIORITY OldPriority;
  1463. PKPROCESS Process;
  1464. ASSERT_THREAD(Thread);
  1465. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  1466. ASSERT(((Priority != 0) || (Thread->BasePriority == 0)) &&
  1467. (Priority <= HIGH_PRIORITY));
  1468. ASSERT(KeIsExecutingDpc() == FALSE);
  1469. //
  1470. // Raise IRQL to dispatcher level and lock dispatcher database.
  1471. //
  1472. KiLockDispatcherDatabase(&OldIrql);
  1473. //
  1474. // Capture the current thread priority, set the thread priority to the
  1475. // the new value, and replenish the thread quantum. It is assumed that
  1476. // the priority would not be set unless the thread had already lost it
  1477. // initial quantum.
  1478. //
  1479. OldPriority = Thread->Priority;
  1480. Thread->DecrementCount = 0;
  1481. Thread->PriorityDecrement = 0;
  1482. if (Priority != Thread->Priority) {
  1483. Process = Thread->ApcStatePointer[0]->Process;
  1484. Thread->Quantum = Process->ThreadQuantum;
  1485. KiSetPriorityThread(Thread, Priority);
  1486. }
  1487. //
  1488. // Unlock dispatcher database and lower IRQL to its previous
  1489. // value.
  1490. //
  1491. KiUnlockDispatcherDatabase(OldIrql);
  1492. //
  1493. // Return the previous thread priority.
  1494. //
  1495. return OldPriority;
  1496. }
  1497. ULONG
  1498. KeSuspendThread (
  1499. IN PKTHREAD Thread
  1500. )
  1501. /*++
  1502. Routine Description:
  1503. This function suspends the execution of a thread. If the suspend count
  1504. overflows the maximum suspend count, then a condition is raised.
  1505. Arguments:
  1506. Thread - Supplies a pointer to a dispatcher object of type thread.
  1507. Return Value:
  1508. The previous suspend count.
  1509. --*/
  1510. {
  1511. KLOCK_QUEUE_HANDLE LockHandle;
  1512. ULONG OldCount;
  1513. ASSERT_THREAD(Thread);
  1514. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  1515. //
  1516. // Raise IRQL to SYNCH_LEVEL, acquire the thread APC queue lock, and lock
  1517. // the dispatcher database.
  1518. //
  1519. KeAcquireInStackQueuedSpinLockRaiseToSynch(&Thread->ApcQueueLock, &LockHandle);
  1520. KiLockDispatcherDatabaseAtSynchLevel();
  1521. //
  1522. // Capture the current suspend count.
  1523. //
  1524. // If the suspend count is at its maximum value, then unlock the
  1525. // dispatcher database, unlock the thread APC queue lock, lower IRQL
  1526. // to its previous value, and raise an error condition.
  1527. //
  1528. OldCount = Thread->SuspendCount;
  1529. if (OldCount == MAXIMUM_SUSPEND_COUNT) {
  1530. KiUnlockDispatcherDatabaseFromSynchLevel();
  1531. KeReleaseInStackQueuedSpinLock(&LockHandle);
  1532. ExRaiseStatus(STATUS_SUSPEND_COUNT_EXCEEDED);
  1533. }
  1534. //
  1535. // Don't suspend the thread if APC queuing is disabled. In this case the
  1536. // thread is being deleted.
  1537. //
  1538. if (Thread->ApcQueueable == TRUE) {
  1539. //
  1540. // Increment the suspend count. If the thread was not previously
  1541. // suspended, then queue the thread's suspend APC.
  1542. //
  1543. Thread->SuspendCount += 1;
  1544. if ((OldCount == 0) && (Thread->FreezeCount == 0)) {
  1545. if (KiInsertQueueApc(&Thread->SuspendApc, RESUME_INCREMENT) == FALSE) {
  1546. Thread->SuspendSemaphore.Header.SignalState -= 1;
  1547. }
  1548. }
  1549. }
  1550. //
  1551. // Unlock the dispatcher database from SYNCH_LEVEL, unlock the thread APC
  1552. // queue lock and lower IRQL to its previous value, and return the old
  1553. // count.
  1554. //
  1555. KiUnlockDispatcherDatabaseFromSynchLevel();
  1556. KeReleaseInStackQueuedSpinLock(&LockHandle);
  1557. return OldCount;
  1558. }
  1559. VOID
  1560. KeTerminateThread (
  1561. IN KPRIORITY Increment
  1562. )
  1563. /*++
  1564. Routine Description:
  1565. This function terminates the execution of the current thread, sets the
  1566. signal state of the thread to Signaled, and attempts to satisfy as many
  1567. Waits as possible. The scheduling state of the thread is set to terminated,
  1568. and a new thread is selected to run on the current processor. There is no
  1569. return from this function.
  1570. Arguments:
  1571. None.
  1572. Return Value:
  1573. None.
  1574. --*/
  1575. {
  1576. KLOCK_QUEUE_HANDLE LockHandle;
  1577. PKPROCESS Process;
  1578. PKQUEUE Queue;
  1579. PKTHREAD Thread;
  1580. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  1581. //
  1582. // Raise IRQL to SYNCH_LEVEL, acquire the process lock, and acquire the
  1583. // dispatcher databack lock at SYNCH_LEVEL.
  1584. //
  1585. Thread = KeGetCurrentThread();
  1586. Process = Thread->ApcState.Process;
  1587. KeAcquireInStackQueuedSpinLockRaiseToSynch(&Process->ProcessLock, &LockHandle);
  1588. KiLockDispatcherDatabaseAtSynchLevel();
  1589. //
  1590. // Insert the thread in the reaper list.
  1591. //
  1592. // If a reaper thread is not currently active, then insert a work item in
  1593. // the hyper critical work queue.
  1594. //
  1595. // N.B. This code has knowledge of the reaper data structures and how
  1596. // worker threads are implemented.
  1597. //
  1598. // N.B. The dispatcher database lock is used to synchronize access to the
  1599. // reaper list.
  1600. //
  1601. ((PETHREAD)Thread)->ReaperLink = PsReaperList;
  1602. PsReaperList = (PETHREAD)Thread;
  1603. if (PsReaperActive == FALSE) {
  1604. PsReaperActive = TRUE;
  1605. KiInsertQueue(&ExWorkerQueue[HyperCriticalWorkQueue].WorkerQueue,
  1606. &PsReaperWorkItem.List,
  1607. FALSE);
  1608. }
  1609. //
  1610. // If the current thread is processing a queue entry, then remove
  1611. // the thread from the queue object thread list and attempt to
  1612. // activate another thread that is blocked on the queue object.
  1613. //
  1614. Queue = Thread->Queue;
  1615. if (Queue != NULL) {
  1616. RemoveEntryList(&Thread->QueueListEntry);
  1617. KiActivateWaiterQueue(Queue);
  1618. }
  1619. //
  1620. // Set the state of the current thread object to Signaled, and attempt
  1621. // to satisfy as many Waits as possible.
  1622. //
  1623. Thread->Header.SignalState = TRUE;
  1624. if (IsListEmpty(&Thread->Header.WaitListHead) != TRUE) {
  1625. KiWaitTest((PVOID)Thread, Increment);
  1626. }
  1627. //
  1628. // Remove thread from its parent process' thread list.
  1629. //
  1630. RemoveEntryList(&Thread->ThreadListEntry);
  1631. //
  1632. // Release the process lock, but don't lower the IRQL.
  1633. //
  1634. KeReleaseInStackQueuedSpinLockFromDpcLevel(&LockHandle);
  1635. //
  1636. // Set thread scheduling state to terminated, decrement the process'
  1637. // stack count, select a new thread to run on the current processor,
  1638. // and swap context to the new thread.
  1639. //
  1640. Thread->State = Terminated;
  1641. Process->StackCount -= 1;
  1642. if (Process->StackCount == 0) {
  1643. if (Process->ThreadListHead.Flink != &Process->ThreadListHead) {
  1644. Process->State = ProcessOutTransition;
  1645. InterlockedPushEntrySingleList(&KiProcessOutSwapListHead,
  1646. &Process->SwapListEntry);
  1647. KiSetSwapEvent();
  1648. }
  1649. }
  1650. //
  1651. // Rundown any architectural specific structures
  1652. //
  1653. KiRundownThread(Thread);
  1654. //
  1655. // Get off the processor for the last time.
  1656. //
  1657. KiSwapThread();
  1658. return;
  1659. }
  1660. BOOLEAN
  1661. KeTestAlertThread (
  1662. IN KPROCESSOR_MODE AlertMode
  1663. )
  1664. /*++
  1665. Routine Description:
  1666. This function tests to determine if the alerted variable for the
  1667. specified processor mode has a value of TRUE or whether a user mode
  1668. APC should be delivered to the current thread.
  1669. Arguments:
  1670. AlertMode - Supplies the processor mode which is to be tested
  1671. for an alerted condition.
  1672. Return Value:
  1673. The previous state of the alerted variable for the specified processor
  1674. mode.
  1675. --*/
  1676. {
  1677. BOOLEAN Alerted;
  1678. KLOCK_QUEUE_HANDLE LockHandle;
  1679. PKTHREAD Thread;
  1680. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  1681. //
  1682. // Raise IRQL to SYNCH_LEVEL, acquire the thread APC queue lock, and lock
  1683. // the dispatcher database.
  1684. //
  1685. Thread = KeGetCurrentThread();
  1686. KeAcquireInStackQueuedSpinLockRaiseToSynch(&Thread->ApcQueueLock, &LockHandle);
  1687. KiLockDispatcherDatabaseAtSynchLevel();
  1688. //
  1689. // If the current thread is alerted for the specified processor mode,
  1690. // then clear the alerted state. Else if the specified processor mode
  1691. // is user and the current thread's user mode APC queue contains an entry,
  1692. // then set user APC pending.
  1693. //
  1694. Alerted = Thread->Alerted[AlertMode];
  1695. if (Alerted == TRUE) {
  1696. Thread->Alerted[AlertMode] = FALSE;
  1697. } else if ((AlertMode == UserMode) &&
  1698. (IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]) != TRUE)) {
  1699. Thread->ApcState.UserApcPending = TRUE;
  1700. }
  1701. //
  1702. // Unlock the dispatcher database from SYNCH_LEVEL, unlock the thread APC
  1703. // queue lock and lower IRQL to its previous value, and return the previous
  1704. // alerted state for the specified mode.
  1705. //
  1706. KiUnlockDispatcherDatabaseFromSynchLevel();
  1707. KeReleaseInStackQueuedSpinLock(&LockHandle);
  1708. return Alerted;
  1709. }
  1710. VOID
  1711. KeThawAllThreads (
  1712. VOID
  1713. )
  1714. /*++
  1715. Routine Description:
  1716. This function resumes the execution of all suspended froozen threads
  1717. in the current process.
  1718. Arguments:
  1719. None.
  1720. Return Value:
  1721. None.
  1722. --*/
  1723. {
  1724. KLOCK_QUEUE_HANDLE LockHandle;
  1725. PLIST_ENTRY ListHead;
  1726. PLIST_ENTRY NextEntry;
  1727. PKPROCESS Process;
  1728. PKTHREAD Thread;
  1729. ULONG OldCount;
  1730. KIRQL OldIrql;
  1731. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  1732. //
  1733. // Raise IRQL to SYNCH_LEVEL, acquire the process lock, and acquire the
  1734. // dispatcher databack lock at SYNCH_LEVEL.
  1735. //
  1736. Process = KeGetCurrentThread()->ApcState.Process;
  1737. KeAcquireInStackQueuedSpinLockRaiseToSynch(&Process->ProcessLock, &LockHandle);
  1738. KiLockDispatcherDatabaseAtSynchLevel();
  1739. //
  1740. // Thaw the execution of all threads in the current process that have
  1741. // been frozzen.
  1742. //
  1743. ListHead = &Process->ThreadListHead;
  1744. NextEntry = ListHead->Flink;
  1745. do {
  1746. //
  1747. // Get the address of the next thread and thaw its execution if
  1748. // if was previously froozen.
  1749. //
  1750. Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry);
  1751. OldCount = Thread->FreezeCount;
  1752. if (OldCount != 0) {
  1753. Thread->FreezeCount -= 1;
  1754. //
  1755. // If the resultant suspend count is zero and the freeze count is
  1756. // zero, then resume the thread by releasing its suspend semaphore.
  1757. //
  1758. if ((Thread->SuspendCount == 0) && (Thread->FreezeCount == 0)) {
  1759. Thread->SuspendSemaphore.Header.SignalState += 1;
  1760. KiWaitTest(&Thread->SuspendSemaphore, RESUME_INCREMENT);
  1761. }
  1762. }
  1763. NextEntry = NextEntry->Flink;
  1764. } while (NextEntry != ListHead);
  1765. //
  1766. // Unlock dispatcher database from SYNCH_LEVEL, unlock the process lock
  1767. // and lower IRQL to its previous value.
  1768. //
  1769. KiUnlockDispatcherDatabaseFromSynchLevel();
  1770. KeReleaseInStackQueuedSpinLock(&LockHandle);
  1771. KeLeaveCriticalRegion();
  1772. return;
  1773. }