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.

1314 lines
34 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. procobj.c
  5. Abstract:
  6. This module implements the machine independent functions to manipulate
  7. the kernel process object. Functions are provided to initialize, attach,
  8. detach, exclude, include, and set the base priority of process objects.
  9. Author:
  10. David N. Cutler (davec) 7-Mar-1989
  11. Environment:
  12. Kernel mode only.
  13. Revision History:
  14. --*/
  15. #include "ki.h"
  16. #pragma alloc_text(PAGE, KeInitializeProcess)
  17. //
  18. // Define forward referenced function prototypes.
  19. //
  20. VOID
  21. KiAttachProcess (
  22. IN PRKTHREAD Thread,
  23. IN PRKPROCESS Process,
  24. IN KIRQL OldIrql,
  25. OUT PRKAPC_STATE SavedApcState
  26. );
  27. VOID
  28. KiMoveApcState (
  29. IN PKAPC_STATE Source,
  30. OUT PKAPC_STATE Destination
  31. );
  32. //
  33. // The following assert macro is used to check that an input process is
  34. // really a kprocess and not something else, like deallocated pool.
  35. //
  36. #define ASSERT_PROCESS(E) { \
  37. ASSERT((E)->Header.Type == ProcessObject); \
  38. }
  39. VOID
  40. KeInitializeProcess (
  41. IN PRKPROCESS Process,
  42. IN KPRIORITY BasePriority,
  43. IN KAFFINITY Affinity,
  44. IN ULONG_PTR DirectoryTableBase[2],
  45. IN BOOLEAN Enable
  46. )
  47. /*++
  48. Routine Description:
  49. This function initializes a kernel process object. The base priority,
  50. affinity, and page frame numbers for the process page table directory
  51. and hyper space are stored in the process object.
  52. N.B. It is assumed that the process object is zeroed.
  53. Arguments:
  54. Process - Supplies a pointer to a dispatcher object of type process.
  55. BasePriority - Supplies the base priority of the process.
  56. Affinity - Supplies the set of processors on which children threads
  57. of the process can execute.
  58. DirectoryTableBase - Supplies a pointer to an array whose fist element
  59. is the value that is to be loaded into the Directory Table Base
  60. register when a child thread is dispatched for execution and whose
  61. second element contains the page table entry that maps hyper space.
  62. Enable - Supplies a boolean value that determines the default
  63. handling of data alignment exceptions for child threads. A value
  64. of TRUE causes all data alignment exceptions to be automatically
  65. handled by the kernel. A value of FALSE causes all data alignment
  66. exceptions to be actually raised as exceptions.
  67. Return Value:
  68. None.
  69. --*/
  70. {
  71. PKNODE Node;
  72. UCHAR NodeNumber;
  73. ULONG i;
  74. //
  75. // Initialize the standard dispatcher object header and set the initial
  76. // signal state of the process object.
  77. //
  78. Process->Header.Type = ProcessObject;
  79. Process->Header.Size = sizeof(KPROCESS) / sizeof(LONG);
  80. InitializeListHead(&Process->Header.WaitListHead);
  81. //
  82. // Initialize the base priority, affinity, directory table base values,
  83. // autoalignment, and stack count.
  84. //
  85. // N.B. The distinguished value MAXSHORT is used to signify that no
  86. // threads have been created for the process.
  87. //
  88. Process->BasePriority = (SCHAR)BasePriority;
  89. Process->Affinity = Affinity;
  90. Process->AutoAlignment = Enable;
  91. Process->DirectoryTableBase[0] = DirectoryTableBase[0];
  92. Process->DirectoryTableBase[1] = DirectoryTableBase[1];
  93. Process->StackCount = MAXSHORT;
  94. //
  95. // Initialize the stack count, profile listhead, ready queue list head,
  96. // accumulated runtime, process quantum, thread quantum, and thread list
  97. // head.
  98. //
  99. InitializeListHead(&Process->ProfileListHead);
  100. InitializeListHead(&Process->ReadyListHead);
  101. InitializeListHead(&Process->ThreadListHead);
  102. Process->ThreadQuantum = THREAD_QUANTUM;
  103. //
  104. // Initialize the process state and set the thread processor selection
  105. // seed.
  106. //
  107. Process->State = ProcessInMemory;
  108. //
  109. // Set the ideal node for this process.
  110. //
  111. #if defined(KE_MULTINODE)
  112. if (KeNumberNodes > 1) {
  113. NodeNumber = (KeProcessNodeSeed + 1) % KeNumberNodes;
  114. KeProcessNodeSeed = NodeNumber;
  115. for (i = 0; i < KeNumberNodes; i++) {
  116. if (KeNodeBlock[NodeNumber]->ProcessorMask & Affinity) {
  117. break;
  118. }
  119. NodeNumber = (NodeNumber + 1) % KeNumberNodes;
  120. }
  121. } else {
  122. NodeNumber = 0;
  123. }
  124. Process->IdealNode = NodeNumber;
  125. Node = KeNodeBlock[NodeNumber];
  126. Process->ThreadSeed = KeFindNextRightSetAffinity(Node->Seed,
  127. Node->ProcessorMask & Affinity);
  128. Node->Seed = Process->ThreadSeed;
  129. #else
  130. Process->ThreadSeed = (UCHAR)KiQueryLowTickCount() % KeNumberProcessors;
  131. #endif
  132. //
  133. // Initialize IopmBase and Iopl flag for this process (i386 only)
  134. //
  135. #if defined(_X86_) || defined(_AMD64_)
  136. Process->IopmOffset = KiComputeIopmOffset(IO_ACCESS_MAP_NONE);
  137. #endif // defined(_X86_) || defined(_AMD64_)
  138. return;
  139. }
  140. VOID
  141. KeAttachProcess (
  142. IN PRKPROCESS Process
  143. )
  144. /*++
  145. Routine Description:
  146. This function attaches a thread to a target process' address space
  147. if, and only if, there is not already a process attached.
  148. Arguments:
  149. Process - Supplies a pointer to a dispatcher object of type process.
  150. Return Value:
  151. None.
  152. --*/
  153. {
  154. KIRQL OldIrql;
  155. PRKTHREAD Thread;
  156. ASSERT_PROCESS(Process);
  157. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  158. //
  159. // If the target process is not the current process, then attach the
  160. // target process.
  161. //
  162. Thread = KeGetCurrentThread();
  163. if (Thread->ApcState.Process != Process) {
  164. //
  165. // If the current thread is already attached or executing a DPC, then
  166. // bugcheck.
  167. //
  168. if ((Thread->ApcStateIndex != 0) ||
  169. (KeIsExecutingDpc() != FALSE)) {
  170. KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT,
  171. (ULONG_PTR)Process,
  172. (ULONG_PTR)Thread->ApcState.Process,
  173. (ULONG)Thread->ApcStateIndex,
  174. (ULONG)KeIsExecutingDpc());
  175. }
  176. //
  177. // Raise IRQL to dispatcher level and lock dispatcher database.
  178. //
  179. // N.B. The dispatcher lock is released ay the attach routine.
  180. //
  181. KiLockDispatcherDatabase(&OldIrql);
  182. KiAttachProcess(Thread, Process, OldIrql, &Thread->SavedApcState);
  183. }
  184. return;
  185. }
  186. LOGICAL
  187. KeForceAttachProcess (
  188. IN PRKPROCESS Process
  189. )
  190. /*++
  191. Routine Description:
  192. This function forces an attach of a thread to a target process' address
  193. space if the process is not current being swapped into or out of memory.
  194. N.B. This function is for use by memory management ONLY.
  195. Arguments:
  196. Process - Supplies a pointer to a dispatcher object of type process.
  197. Return Value:
  198. None.
  199. --*/
  200. {
  201. KIRQL OldIrql;
  202. PRKTHREAD Thread;
  203. ASSERT_PROCESS(Process);
  204. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  205. //
  206. // If the current thread is already attached or executing a DPC, then
  207. // bugcheck.
  208. //
  209. Thread = KeGetCurrentThread();
  210. if ((Thread->ApcStateIndex != 0) ||
  211. (KeIsExecutingDpc() != FALSE)) {
  212. KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT,
  213. (ULONG_PTR)Process,
  214. (ULONG_PTR)Thread->ApcState.Process,
  215. (ULONG)Thread->ApcStateIndex,
  216. (ULONG)KeIsExecutingDpc());
  217. }
  218. //
  219. // If the target process is not the current process, then attach the
  220. // target process if the process is not currently being swapped in or
  221. // out of memory.
  222. //
  223. if (Thread->ApcState.Process != Process) {
  224. //
  225. // Raise IRQL to dispatcher level and lock dispatcher database.
  226. //
  227. // If the target process is currently being swapped into or out of
  228. // memory, then return a value of FALSE. Otherwise, force the process
  229. // to be inswapped.
  230. //
  231. KiLockDispatcherDatabase(&OldIrql);
  232. if ((Process->State == ProcessInSwap) ||
  233. (Process->State == ProcessInTransition) ||
  234. (Process->State == ProcessOutTransition) ||
  235. (Process->State == ProcessOutSwap)) {
  236. KiUnlockDispatcherDatabase(OldIrql);
  237. return FALSE;
  238. } else {
  239. //
  240. // Force the process state to in memory and attach the target process.
  241. //
  242. // N.B. The dispatcher lock is released ay the attach routine.
  243. //
  244. Process->State = ProcessInMemory;
  245. KiAttachProcess(Thread, Process, OldIrql, &Thread->SavedApcState);
  246. }
  247. }
  248. return TRUE;
  249. }
  250. VOID
  251. KeStackAttachProcess (
  252. IN PRKPROCESS Process,
  253. OUT PRKAPC_STATE ApcState
  254. )
  255. /*++
  256. Routine Description:
  257. This function attaches a thread to a target process' address space
  258. and returns information about a previous attached process.
  259. Arguments:
  260. Process - Supplies a pointer to a dispatcher object of type process.
  261. Return Value:
  262. None.
  263. --*/
  264. {
  265. KIRQL OldIrql;
  266. PRKTHREAD Thread;
  267. ASSERT_PROCESS(Process);
  268. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  269. //
  270. // If the current thread is executing a DPC, then bug check.
  271. //
  272. Thread = KeGetCurrentThread();
  273. if (KeIsExecutingDpc() != FALSE) {
  274. KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT,
  275. (ULONG_PTR)Process,
  276. (ULONG_PTR)Thread->ApcState.Process,
  277. (ULONG)Thread->ApcStateIndex,
  278. (ULONG)KeIsExecutingDpc());
  279. }
  280. //
  281. // If the target process is not the current process, then attach the
  282. // target process. Otherwise, return a distinguished process value to
  283. // indicate that an attach was not performed.
  284. //
  285. if (Thread->ApcState.Process == Process) {
  286. ApcState->Process = (PRKPROCESS)1;
  287. } else {
  288. //
  289. // Raise IRQL to dispatcher level and lock dispatcher database.
  290. //
  291. // If the current thread is attached to a process, then save the
  292. // current APC state in the callers APC state structure. Otherwise,
  293. // save the current APC state in the saved APC state structure, and
  294. // return a NULL process pointer.
  295. //
  296. // N.B. The dispatcher lock is released ay the attach routine.
  297. //
  298. KiLockDispatcherDatabase(&OldIrql);
  299. if (Thread->ApcStateIndex != 0) {
  300. KiAttachProcess(Thread, Process, OldIrql, ApcState);
  301. } else {
  302. KiAttachProcess(Thread, Process, OldIrql, &Thread->SavedApcState);
  303. ApcState->Process = NULL;
  304. }
  305. }
  306. return;
  307. }
  308. VOID
  309. KeDetachProcess (
  310. VOID
  311. )
  312. /*++
  313. Routine Description:
  314. This function detaches a thread from another process' address space.
  315. Arguments:
  316. None.
  317. Return Value:
  318. None.
  319. --*/
  320. {
  321. KIRQL OldIrql;
  322. PKPROCESS Process;
  323. PKTHREAD Thread;
  324. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  325. //
  326. // If the current thread is attached to another process, then detach
  327. // it.
  328. //
  329. Thread = KeGetCurrentThread();
  330. if (Thread->ApcStateIndex != 0) {
  331. //
  332. // Raise IRQL to dispatcher level and lock dispatcher database.
  333. //
  334. KiLockDispatcherDatabase(&OldIrql);
  335. //
  336. // Test to determine if a kernel APC is pending.
  337. //
  338. // If a kernel APC is pending and the previous IRQL was less than
  339. // APC_LEVEL, then a kernel APC was queued by another processor just
  340. // after IRQL was raised to DISPATCH_LEVEL, but before the dispatcher
  341. // database was locked.
  342. //
  343. // N.B. that this can only happen in a multiprocessor system.
  344. //
  345. #if !defined(NT_UP)
  346. while (Thread->ApcState.KernelApcPending && (OldIrql < APC_LEVEL)) {
  347. //
  348. // Unlock the dispatcher database and lower IRQL to its previous
  349. // value. An APC interrupt will immediately occur which will result
  350. // in the delivery of the kernel APC if possible.
  351. //
  352. KiUnlockDispatcherDatabase(OldIrql);
  353. KiLockDispatcherDatabase(&OldIrql);
  354. }
  355. #endif
  356. //
  357. // If a kernel APC is in progress, the kernel APC is nbot empty, or
  358. // the user APC queues is not empty, then bug check.
  359. //
  360. #if DBG
  361. if ((Thread->ApcState.KernelApcInProgress) ||
  362. (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]) == FALSE) ||
  363. (IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]) == FALSE)) {
  364. KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT);
  365. }
  366. #endif
  367. //
  368. // Unbias current process stack count and check if the process should
  369. // be swapped out of memory.
  370. //
  371. Process = Thread->ApcState.Process;
  372. Process->StackCount -= 1;
  373. if ((Process->StackCount == 0) &&
  374. (IsListEmpty(&Process->ThreadListHead) == FALSE)) {
  375. Process->State = ProcessOutTransition;
  376. InterlockedPushEntrySingleList(&KiProcessOutSwapListHead,
  377. &Process->SwapListEntry);
  378. KiSetSwapEvent();
  379. }
  380. //
  381. // Restore APC state and check whether the kernel APC queue contains
  382. // an entry. If the kernel APC queue contains an entry then set kernel
  383. // APC pending and request a software interrupt at APC_LEVEL.
  384. //
  385. KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState);
  386. Thread->SavedApcState.Process = (PKPROCESS)NULL;
  387. Thread->ApcStatePointer[0] = &Thread->ApcState;
  388. Thread->ApcStatePointer[1] = &Thread->SavedApcState;
  389. Thread->ApcStateIndex = 0;
  390. if (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]) == FALSE) {
  391. Thread->ApcState.KernelApcPending = TRUE;
  392. KiRequestSoftwareInterrupt(APC_LEVEL);
  393. }
  394. //
  395. // Swap the address space back to the parent process.
  396. //
  397. KiSwapProcess(Thread->ApcState.Process, Process);
  398. //
  399. // Lower IRQL to its previous value and return.
  400. //
  401. KiUnlockDispatcherDatabase(OldIrql);
  402. }
  403. return;
  404. }
  405. VOID
  406. KeUnstackDetachProcess (
  407. IN PRKAPC_STATE ApcState
  408. )
  409. /*++
  410. Routine Description:
  411. This function detaches a thread from another process' address space
  412. and restores previous attach state.
  413. Arguments:
  414. ApcState - Supplies a pointer to an APC state structure that was returned
  415. from a previous call to stack attach process.
  416. Return Value:
  417. None.
  418. --*/
  419. {
  420. KIRQL OldIrql;
  421. PKPROCESS Process;
  422. PKTHREAD Thread;
  423. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  424. //
  425. // If the APC state has a distinguished process pointer value, then no
  426. // attach was performed on the paired call to stack attach process.
  427. //
  428. if (ApcState->Process != (PRKPROCESS)1) {
  429. //
  430. // Raise IRQL to dispatcher level and lock dispatcher database.
  431. //
  432. Thread = KeGetCurrentThread();
  433. KiLockDispatcherDatabase(&OldIrql);
  434. //
  435. // Test to determine if a kernel APC is pending.
  436. //
  437. // If a kernel APC is pending and the previous IRQL was less than
  438. // APC_LEVEL, then a kernel APC was queued by another processor just
  439. // after IRQL was raised to DISPATCH_LEVEL, but before the dispatcher
  440. // database was locked.
  441. //
  442. // N.B. that this can only happen in a multiprocessor system.
  443. //
  444. #if !defined(NT_UP)
  445. while (Thread->ApcState.KernelApcPending && (OldIrql < APC_LEVEL)) {
  446. //
  447. // Unlock the dispatcher database and lower IRQL to its previous
  448. // value. An APC interrupt will immediately occur which will result
  449. // in the delivery of the kernel APC if possible.
  450. //
  451. KiUnlockDispatcherDatabase(OldIrql);
  452. KiLockDispatcherDatabase(&OldIrql);
  453. }
  454. #endif
  455. //
  456. // If the APC state is the original APC state, a kernel APC is in
  457. // progress, the kernel APC is nbot empty, or the user APC queues is
  458. // not empty, then bug check.
  459. //
  460. if ((Thread->ApcStateIndex == 0) ||
  461. (Thread->ApcState.KernelApcInProgress) ||
  462. (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]) == FALSE) ||
  463. (IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]) == FALSE)) {
  464. KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT);
  465. }
  466. //
  467. // Unbias current process stack count and check if the process should
  468. // be swapped out of memory.
  469. //
  470. Process = Thread->ApcState.Process;
  471. Process->StackCount -= 1;
  472. if ((Process->StackCount == 0) &&
  473. (IsListEmpty(&Process->ThreadListHead) == FALSE)) {
  474. Process->State = ProcessOutTransition;
  475. InterlockedPushEntrySingleList(&KiProcessOutSwapListHead,
  476. &Process->SwapListEntry);
  477. KiSetSwapEvent();
  478. }
  479. //
  480. // Restore APC state and check whether the kernel APC queue contains
  481. // an entry. If the kernel APC queue contains an entry then set kernel
  482. // APC pending and request a software interrupt at APC_LEVEL.
  483. //
  484. if (ApcState->Process != NULL) {
  485. KiMoveApcState(ApcState, &Thread->ApcState);
  486. } else {
  487. KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState);
  488. Thread->SavedApcState.Process = (PKPROCESS)NULL;
  489. Thread->ApcStatePointer[0] = &Thread->ApcState;
  490. Thread->ApcStatePointer[1] = &Thread->SavedApcState;
  491. Thread->ApcStateIndex = 0;
  492. }
  493. if (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]) == FALSE) {
  494. Thread->ApcState.KernelApcPending = TRUE;
  495. KiRequestSoftwareInterrupt(APC_LEVEL);
  496. }
  497. //
  498. // Swap the address space back to the parent process.
  499. //
  500. KiSwapProcess(Thread->ApcState.Process, Process);
  501. //
  502. // Lower IRQL to its previous value and return.
  503. //
  504. KiUnlockDispatcherDatabase(OldIrql);
  505. }
  506. return;
  507. }
  508. LONG
  509. KeReadStateProcess (
  510. IN PRKPROCESS Process
  511. )
  512. /*++
  513. Routine Description:
  514. This function reads the current signal state of a process object.
  515. Arguments:
  516. Process - Supplies a pointer to a dispatcher object of type process.
  517. Return Value:
  518. The current signal state of the process object.
  519. --*/
  520. {
  521. ASSERT_PROCESS(Process);
  522. //
  523. // Return current signal state of process object.
  524. //
  525. return Process->Header.SignalState;
  526. }
  527. LONG
  528. KeSetProcess (
  529. IN PRKPROCESS Process,
  530. IN KPRIORITY Increment,
  531. IN BOOLEAN Wait
  532. )
  533. /*++
  534. Routine Description:
  535. This function sets the signal state of a proces object to Signaled
  536. and attempts to satisfy as many Waits as possible. The previous
  537. signal state of the process object is returned as the function value.
  538. Arguments:
  539. Process - Supplies a pointer to a dispatcher object of type process.
  540. Increment - Supplies the priority increment that is to be applied
  541. if setting the process causes a Wait to be satisfied.
  542. Wait - Supplies a boolean value that signifies whether the call to
  543. KeSetProcess will be immediately followed by a call to one of the
  544. kernel Wait functions.
  545. Return Value:
  546. The previous signal state of the process object.
  547. --*/
  548. {
  549. KIRQL OldIrql;
  550. LONG OldState;
  551. PRKTHREAD Thread;
  552. ASSERT_PROCESS(Process);
  553. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  554. //
  555. // Raise IRQL to dispatcher level and lock dispatcher database.
  556. //
  557. KiLockDispatcherDatabase(&OldIrql);
  558. //
  559. // If the previous state of the process object is Not-Signaled and
  560. // the wait queue is not empty, then satisfy as many Waits as
  561. // possible.
  562. //
  563. OldState = Process->Header.SignalState;
  564. Process->Header.SignalState = 1;
  565. if ((OldState == 0) && (!IsListEmpty(&Process->Header.WaitListHead))) {
  566. KiWaitTest(Process, Increment);
  567. }
  568. //
  569. // If the value of the Wait argument is TRUE, then return to the
  570. // caller with IRQL raised and the dispatcher database locked. Else
  571. // release the dispatcher database lock and lower IRQL to its
  572. // previous value.
  573. //
  574. if (Wait) {
  575. Thread = KeGetCurrentThread();
  576. Thread->WaitNext = Wait;
  577. Thread->WaitIrql = OldIrql;
  578. } else {
  579. KiUnlockDispatcherDatabase(OldIrql);
  580. }
  581. //
  582. // Return previous signal state of process object.
  583. //
  584. return OldState;
  585. }
  586. KAFFINITY
  587. KeSetAffinityProcess (
  588. IN PKPROCESS Process,
  589. IN KAFFINITY Affinity
  590. )
  591. /*++
  592. Routine Description:
  593. This function sets the affinity of a process to the specified value and
  594. also sets the affinity of each thread in the process to the specified
  595. value.
  596. Arguments:
  597. Process - Supplies a pointer to a dispatcher object of type process.
  598. Affinity - Supplies the new of set of processors on which the threads
  599. in the process can run.
  600. Return Value:
  601. The previous affinity of the specified process is returned as the function
  602. value.
  603. --*/
  604. {
  605. KLOCK_QUEUE_HANDLE LockHandle;
  606. PLIST_ENTRY NextEntry;
  607. KAFFINITY OldAffinity;
  608. PKTHREAD Thread;
  609. ASSERT_PROCESS(Process);
  610. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  611. //
  612. // Raise IRQL to SYNCH_LEVEL, acquire the process lock, and acquire the
  613. // dispatcher databack lock at SYNCH_LEVEL.
  614. //
  615. KeAcquireInStackQueuedSpinLockRaiseToSynch(&Process->ProcessLock, &LockHandle);
  616. KiLockDispatcherDatabaseAtSynchLevel();
  617. //
  618. // Capture the current affinity of the specified process and set the
  619. // affinity of the process and all of its threads to the specified
  620. // affinity.
  621. //
  622. OldAffinity = Process->Affinity;
  623. Process->Affinity = Affinity;
  624. NextEntry = Process->ThreadListHead.Flink;
  625. while (NextEntry != &Process->ThreadListHead) {
  626. Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry);
  627. KiSetAffinityThread(Thread, Affinity);
  628. NextEntry = NextEntry->Flink;
  629. }
  630. //
  631. // Unlock dispatcher database (restoring IRQL to SYNCH_LEVEL), unlock the
  632. // process lock, lower IRQL to its previous value, and return the previous process
  633. // affinity.
  634. //
  635. // N.B. The unlock of the dispatch database specifying SYNCH_LEVEL is to
  636. // make sure a dispatch interrupt is generated if necessary.
  637. //
  638. KiUnlockDispatcherDatabase(SYNCH_LEVEL);
  639. KeReleaseInStackQueuedSpinLock(&LockHandle);
  640. return OldAffinity;
  641. }
  642. KPRIORITY
  643. KeSetPriorityProcess (
  644. IN PKPROCESS Process,
  645. IN KPRIORITY NewBase
  646. )
  647. /*++
  648. Routine Description:
  649. This function set the base priority of a process to a new value
  650. and adjusts the priority and base priority of all child threads
  651. as appropriate.
  652. Arguments:
  653. Process - Supplies a pointer to a dispatcher object of type process.
  654. NewBase - Supplies the new base priority of the process.
  655. Return Value:
  656. The previous base priority of the process.
  657. --*/
  658. {
  659. KPRIORITY Adjustment;
  660. KLOCK_QUEUE_HANDLE LockHandle;
  661. PLIST_ENTRY NextEntry;
  662. KPRIORITY NewPriority;
  663. KPRIORITY OldBase;
  664. PKTHREAD Thread;
  665. ASSERT_PROCESS(Process);
  666. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  667. //
  668. // If the new priority is equal to the old priority, then do not change
  669. // the process priority and return the old priority.
  670. //
  671. // N.B. This check can be made without holding the dispatcher lock since
  672. // nothing needs to be protected, and any race condition that can exist
  673. // calling this routine exists with or without the lock being held.
  674. //
  675. if (Process->BasePriority == NewBase) {
  676. return NewBase;
  677. }
  678. //
  679. // Raise IRQL to SYNCH_LEVEL, acquire the process lock, and acquire the
  680. // dispatcher databack lock at SYNCH_LEVEL.
  681. //
  682. KeAcquireInStackQueuedSpinLockRaiseToSynch(&Process->ProcessLock, &LockHandle);
  683. KiLockDispatcherDatabaseAtSynchLevel();
  684. //
  685. // Save the current process base priority, set the new process base
  686. // priority, compute the adjustment value, and adjust the priority
  687. // and base priority of all child threads as appropriate.
  688. //
  689. OldBase = Process->BasePriority;
  690. Process->BasePriority = (SCHAR)NewBase;
  691. Adjustment = NewBase - OldBase;
  692. NextEntry = Process->ThreadListHead.Flink;
  693. if (NewBase >= LOW_REALTIME_PRIORITY) {
  694. while (NextEntry != &Process->ThreadListHead) {
  695. Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry);
  696. //
  697. // Compute the new base priority of the thread.
  698. //
  699. NewPriority = Thread->BasePriority + Adjustment;
  700. //
  701. // If the new base priority is outside the realtime class,
  702. // then limit the change to the realtime class.
  703. //
  704. if (NewPriority < LOW_REALTIME_PRIORITY) {
  705. NewPriority = LOW_REALTIME_PRIORITY;
  706. } else if (NewPriority > HIGH_PRIORITY) {
  707. NewPriority = HIGH_PRIORITY;
  708. }
  709. //
  710. // Set the base priority and the current priority of the
  711. // thread to the appropriate value.
  712. //
  713. // N.B. If priority saturation occured the last time the thread
  714. // base priority was set and the new process base priority
  715. // is not crossing from variable to realtime, then it is not
  716. // necessary to change the thread priority.
  717. //
  718. if ((Thread->Saturation == 0) || (OldBase < LOW_REALTIME_PRIORITY)) {
  719. if (Thread->Saturation > 0) {
  720. NewPriority = HIGH_PRIORITY;
  721. } else if (Thread->Saturation < 0) {
  722. NewPriority = LOW_REALTIME_PRIORITY;
  723. }
  724. Thread->BasePriority = (SCHAR)NewPriority;
  725. Thread->Quantum = Process->ThreadQuantum;
  726. Thread->DecrementCount = 0;
  727. Thread->PriorityDecrement = 0;
  728. KiSetPriorityThread(Thread, NewPriority);
  729. }
  730. NextEntry = NextEntry->Flink;
  731. }
  732. } else {
  733. while (NextEntry != &Process->ThreadListHead) {
  734. Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry);
  735. //
  736. // Compute the new base priority of the thread.
  737. //
  738. NewPriority = Thread->BasePriority + Adjustment;
  739. //
  740. // If the new base priority is outside the variable class,
  741. // then limit the change to the variable class.
  742. //
  743. if (NewPriority >= LOW_REALTIME_PRIORITY) {
  744. NewPriority = LOW_REALTIME_PRIORITY - 1;
  745. } else if (NewPriority <= LOW_PRIORITY) {
  746. NewPriority = 1;
  747. }
  748. //
  749. // Set the base priority and the current priority of the
  750. // thread to the computed value and reset the thread quantum.
  751. //
  752. // N.B. If priority saturation occured the last time the thread
  753. // base priority was set and the new process base priority
  754. // is not crossing from realtime to variable, then it is not
  755. // necessary to change the thread priority.
  756. //
  757. if ((Thread->Saturation == 0) || (OldBase >= LOW_REALTIME_PRIORITY)) {
  758. if (Thread->Saturation > 0) {
  759. NewPriority = LOW_REALTIME_PRIORITY - 1;
  760. } else if (Thread->Saturation < 0) {
  761. NewPriority = 1;
  762. }
  763. Thread->BasePriority = (SCHAR)NewPriority;
  764. Thread->Quantum = Process->ThreadQuantum;
  765. Thread->DecrementCount = 0;
  766. Thread->PriorityDecrement = 0;
  767. KiSetPriorityThread(Thread, NewPriority);
  768. }
  769. NextEntry = NextEntry->Flink;
  770. }
  771. }
  772. //
  773. // Unlock dispatcher database from SYNCH_LEVEL, unlock the process lock
  774. // and lower IRQL to its previous value, and return the previous process
  775. // base priority.
  776. //
  777. KiUnlockDispatcherDatabaseFromSynchLevel();
  778. KeReleaseInStackQueuedSpinLock(&LockHandle);
  779. return OldBase;
  780. }
  781. LOGICAL
  782. KeSetDisableQuantumProcess (
  783. IN PKPROCESS Process,
  784. IN LOGICAL Disable
  785. )
  786. /*++
  787. Routine Description:
  788. This function disables quantum runout for realtime threads in the
  789. specified process.
  790. Arguments:
  791. Process - Supplies a pointer to a dispatcher object of type process.
  792. Disable - Supplies a logical value that determines whether quantum
  793. runout for realtime threads in the specified process are disabled
  794. or enabled.
  795. Return Value:
  796. The previous value of the disable quantum state variable.
  797. --*/
  798. {
  799. LOGICAL DisableQuantum;
  800. ASSERT_PROCESS(Process);
  801. //
  802. // Capture the current state of the disable boost variable and set its
  803. // state to TRUE.
  804. //
  805. DisableQuantum = Process->DisableQuantum;
  806. Process->DisableQuantum = (BOOLEAN)Disable;
  807. //
  808. // Return the previous disable quantum state.
  809. //
  810. return DisableQuantum;
  811. }
  812. VOID
  813. KiAttachProcess (
  814. IN PRKTHREAD Thread,
  815. IN PKPROCESS Process,
  816. IN KIRQL OldIrql,
  817. OUT PRKAPC_STATE SavedApcState
  818. )
  819. /*++
  820. Routine Description:
  821. This function attaches a thread to a target process' address space.
  822. N.B. The dispatcher database lock must be held when this routine is
  823. called.
  824. Arguments:
  825. Thread - Supplies a pointer to a dispatcher object of type thread.
  826. Process - Supplies a pointer to a dispatcher object of type process.
  827. OldIrql - Supplies the previous IRQL.
  828. SavedApcState - Supplies a pointer to the APC state structure that receives
  829. the saved APC state.
  830. Return Value:
  831. None.
  832. --*/
  833. {
  834. PRKTHREAD OutThread;
  835. KAFFINITY Processor;
  836. PLIST_ENTRY NextEntry;
  837. KIRQL HighIrql;
  838. ASSERT(Process != Thread->ApcState.Process);
  839. //
  840. // Bias the stack count of the target process to signify that a
  841. // thread exists in that process with a stack that is resident.
  842. //
  843. Process->StackCount += 1;
  844. //
  845. // Save current APC state and initialize a new APC state.
  846. //
  847. KiMoveApcState(&Thread->ApcState, SavedApcState);
  848. InitializeListHead(&Thread->ApcState.ApcListHead[KernelMode]);
  849. InitializeListHead(&Thread->ApcState.ApcListHead[UserMode]);
  850. Thread->ApcState.Process = Process;
  851. Thread->ApcState.KernelApcInProgress = FALSE;
  852. Thread->ApcState.KernelApcPending = FALSE;
  853. Thread->ApcState.UserApcPending = FALSE;
  854. if (SavedApcState == &Thread->SavedApcState) {
  855. Thread->ApcStatePointer[0] = &Thread->SavedApcState;
  856. Thread->ApcStatePointer[1] = &Thread->ApcState;
  857. Thread->ApcStateIndex = 1;
  858. }
  859. //
  860. // If the target process is in memory, then immediately enter the
  861. // new address space by loading a new Directory Table Base. Otherwise,
  862. // insert the current thread in the target process ready list, inswap
  863. // the target process if necessary, select a new thread to run on the
  864. // the current processor and context switch to the new thread.
  865. //
  866. if (Process->State == ProcessInMemory) {
  867. //
  868. // It is possible that the process is in memory, but there exist
  869. // threads in the process ready list. This can happen when memory
  870. // management forces a process attach.
  871. //
  872. NextEntry = Process->ReadyListHead.Flink;
  873. while (NextEntry != &Process->ReadyListHead) {
  874. OutThread = CONTAINING_RECORD(NextEntry, KTHREAD, WaitListEntry);
  875. RemoveEntryList(NextEntry);
  876. OutThread->ProcessReadyQueue = FALSE;
  877. KiReadyThread(OutThread);
  878. NextEntry = Process->ReadyListHead.Flink;
  879. }
  880. KiSwapProcess(Process, SavedApcState->Process);
  881. KiUnlockDispatcherDatabase(OldIrql);
  882. } else {
  883. Thread->State = Ready;
  884. Thread->ProcessReadyQueue = TRUE;
  885. InsertTailList(&Process->ReadyListHead, &Thread->WaitListEntry);
  886. if (Process->State == ProcessOutOfMemory) {
  887. Process->State = ProcessInTransition;
  888. InterlockedPushEntrySingleList(&KiProcessInSwapListHead,
  889. &Process->SwapListEntry);
  890. KiSetSwapEvent();
  891. }
  892. //
  893. // Clear the active processor bit in the previous process and
  894. // set active processor bit in the process being attached to.
  895. //
  896. #if !defined(NT_UP)
  897. KiLockContextSwap(&HighIrql);
  898. Processor = KeGetCurrentPrcb()->SetMember;
  899. SavedApcState->Process->ActiveProcessors &= ~Processor;
  900. Process->ActiveProcessors |= Processor;
  901. KiUnlockContextSwap(HighIrql);
  902. #endif
  903. Thread->WaitIrql = OldIrql;
  904. KiSwapThread();
  905. }
  906. return;
  907. }
  908. VOID
  909. KiMoveApcState (
  910. IN PKAPC_STATE Source,
  911. OUT PKAPC_STATE Destination
  912. )
  913. /*++
  914. Routine Description:
  915. This function moves the APC state from the source structure to the
  916. destination structure and reinitializes list headers as appropriate.
  917. Arguments:
  918. Source - Supplies a pointer to the source APC state structure.
  919. Destination - Supplies a pointer to the destination APC state structure.
  920. Return Value:
  921. None.
  922. --*/
  923. {
  924. PLIST_ENTRY First;
  925. PLIST_ENTRY Last;
  926. //
  927. // Copy the APC state from the source to the destination.
  928. //
  929. *Destination = *Source;
  930. if (IsListEmpty(&Source->ApcListHead[KernelMode]) != FALSE) {
  931. InitializeListHead(&Destination->ApcListHead[KernelMode]);
  932. } else {
  933. First = Source->ApcListHead[KernelMode].Flink;
  934. Last = Source->ApcListHead[KernelMode].Blink;
  935. Destination->ApcListHead[KernelMode].Flink = First;
  936. Destination->ApcListHead[KernelMode].Blink = Last;
  937. First->Blink = &Destination->ApcListHead[KernelMode];
  938. Last->Flink = &Destination->ApcListHead[KernelMode];
  939. }
  940. if (IsListEmpty(&Source->ApcListHead[UserMode]) != FALSE) {
  941. InitializeListHead(&Destination->ApcListHead[UserMode]);
  942. } else {
  943. First = Source->ApcListHead[UserMode].Flink;
  944. Last = Source->ApcListHead[UserMode].Blink;
  945. Destination->ApcListHead[UserMode].Flink = First;
  946. Destination->ApcListHead[UserMode].Blink = Last;
  947. First->Blink = &Destination->ApcListHead[UserMode];
  948. Last->Flink = &Destination->ApcListHead[UserMode];
  949. }
  950. return;
  951. }