Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

procobj.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 procobj.c 00008 00009 Abstract: 00010 00011 This module implements the machine independent functions to manipulate 00012 the kernel process object. Functions are provided to initialize, attach, 00013 detach, exclude, include, and set the base priority of process objects. 00014 00015 Author: 00016 00017 David N. Cutler (davec) 7-Mar-1989 00018 00019 Environment: 00020 00021 Kernel mode only. 00022 00023 Revision History: 00024 00025 --*/ 00026 00027 #include "ki.h" 00028 00029 #ifdef ALLOC_PRAGMA 00030 #pragma alloc_text(PAGE, KeInitializeProcess) 00031 #endif 00032 00033 00034 // 00035 // Define forward referenced function prototypes. 00036 // 00037 00038 VOID 00039 KiAttachProcess ( 00040 IN PRKTHREAD Thread, 00041 IN PRKPROCESS Process, 00042 IN KIRQL OldIrql, 00043 OUT PRKAPC_STATE SavedApcState 00044 ); 00045 00046 VOID 00047 KiMoveApcState ( 00048 IN PKAPC_STATE Source, 00049 OUT PKAPC_STATE Destination 00050 ); 00051 00052 // 00053 // The following assert macro is used to check that an input process is 00054 // really a kprocess and not something else, like deallocated pool. 00055 // 00056 00057 #define ASSERT_PROCESS(E) { \ 00058 ASSERT((E)->Header.Type == ProcessObject); \ 00059 } 00060 00061 00062 VOID 00063 KeInitializeProcess ( 00064 IN PRKPROCESS Process, 00065 IN KPRIORITY BasePriority, 00066 IN KAFFINITY Affinity, 00067 IN ULONG_PTR DirectoryTableBase[2], 00068 IN BOOLEAN Enable 00069 ) 00070 00071 /*++ 00072 00073 Routine Description: 00074 00075 This function initializes a kernel process object. The base priority, 00076 affinity, and page frame numbers for the process page table directory 00077 and hyper space are stored in the process object. 00078 00079 N.B. It is assumed that the process object is zeroed. 00080 00081 Arguments: 00082 00083 Process - Supplies a pointer to a dispatcher object of type process. 00084 00085 BasePriority - Supplies the base priority of the process. 00086 00087 Affinity - Supplies the set of processors on which children threads 00088 of the process can execute. 00089 00090 DirectoryTableBase - Supplies a pointer to an array whose fist element 00091 is the value that is to be loaded into the Directory Table Base 00092 register when a child thread is dispatched for execution and whose 00093 second element contains the page table entry that maps hyper space. 00094 00095 Enable - Supplies a boolean value that determines the default 00096 handling of data alignment exceptions for child threads. A value 00097 of TRUE causes all data alignment exceptions to be automatically 00098 handled by the kernel. A value of FALSE causes all data alignment 00099 exceptions to be actually raised as exceptions. 00100 00101 Return Value: 00102 00103 None. 00104 00105 --*/ 00106 00107 { 00108 00109 // 00110 // Initialize the standard dispatcher object header and set the initial 00111 // signal state of the process object. 00112 // 00113 00114 Process->Header.Type = ProcessObject; 00115 Process->Header.Size = sizeof(KPROCESS) / sizeof(LONG); 00116 InitializeListHead(&Process->Header.WaitListHead); 00117 00118 // 00119 // Initialize the base priority, affinity, directory table base values, 00120 // autoalignment, and stack count. 00121 // 00122 // N.B. The distinguished value MAXSHORT is used to signify that no 00123 // threads have been created for the process. 00124 // 00125 00126 Process->BasePriority = (SCHAR)BasePriority; 00127 Process->Affinity = Affinity; 00128 Process->AutoAlignment = Enable; 00129 Process->DirectoryTableBase[0] = DirectoryTableBase[0]; 00130 Process->DirectoryTableBase[1] = DirectoryTableBase[1]; 00131 Process->StackCount = MAXSHORT; 00132 00133 // 00134 // Initialize the stack count, profile listhead, ready queue list head, 00135 // accumulated runtime, process quantum, thread quantum, and thread list 00136 // head. 00137 // 00138 00139 InitializeListHead(&Process->ProfileListHead); 00140 InitializeListHead(&Process->ReadyListHead); 00141 InitializeListHead(&Process->ThreadListHead); 00142 Process->ThreadQuantum = THREAD_QUANTUM; 00143 00144 // 00145 // Initialize the process state and set the thread processor selection 00146 // seed. 00147 // 00148 00149 Process->State = ProcessInMemory; 00150 Process->ThreadSeed = (UCHAR)KiQueryLowTickCount(); 00151 00152 // 00153 // Initialize IopmBase and Iopl flag for this process (i386 only) 00154 // 00155 00156 #ifdef i386 00157 00158 Process->IopmOffset = KiComputeIopmOffset(IO_ACCESS_MAP_NONE); 00159 00160 #endif 00161 00162 return; 00163 } 00164 00165 VOID 00166 KeAttachProcess ( 00167 IN PRKPROCESS Process 00168 ) 00169 00170 /*++ 00171 00172 Routine Description: 00173 00174 This function attaches a thread to a target process' address space 00175 if, and only if, there is not already a process attached. 00176 00177 Arguments: 00178 00179 Process - Supplies a pointer to a dispatcher object of type process. 00180 00181 Return Value: 00182 00183 None. 00184 00185 --*/ 00186 00187 { 00188 00189 KIRQL OldIrql; 00190 PRKTHREAD Thread; 00191 00192 ASSERT_PROCESS(Process); 00193 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); 00194 00195 // 00196 // Raise IRQL to dispatcher level and lock dispatcher database. 00197 // 00198 00199 Thread = KeGetCurrentThread(); 00200 KiLockDispatcherDatabase(&OldIrql); 00201 00202 // 00203 // If the target process is the current process, then return immediately. 00204 // Otherwise, check whether there is a process address space attached or 00205 // the thread is executing a DPC. If either condition is true, then call 00206 // bug check. Otherwise, attach the target process. 00207 // 00208 00209 if (Thread->ApcState.Process == Process) { 00210 KiUnlockDispatcherDatabase(OldIrql); 00211 00212 } else if ((Thread->ApcStateIndex != 0) || 00213 (KeIsExecutingDpc() != FALSE)) { 00214 KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT, 00215 (ULONG_PTR)Process, 00216 (ULONG_PTR)Thread->ApcState.Process, 00217 (ULONG)Thread->ApcStateIndex, 00218 (ULONG)KeIsExecutingDpc()); 00219 00220 } else { 00221 KiAttachProcess(Thread, Process, OldIrql, &Thread->SavedApcState); 00222 } 00223 00224 return; 00225 } 00226 00227 LOGICAL 00228 KeForceAttachProcess ( 00229 IN PRKPROCESS Process 00230 ) 00231 00232 /*++ 00233 00234 Routine Description: 00235 00236 This function forces an attach of a thread to a target process' address 00237 space if the process is not current being swapped into or out of memory. 00238 00239 N.B. This function is for use by memory management ONLY. 00240 00241 Arguments: 00242 00243 Process - Supplies a pointer to a dispatcher object of type process. 00244 00245 Return Value: 00246 00247 None. 00248 00249 --*/ 00250 00251 { 00252 00253 KIRQL OldIrql; 00254 PRKTHREAD Thread; 00255 00256 ASSERT_PROCESS(Process); 00257 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); 00258 00259 // 00260 // Raise IRQL to dispatcher level and lock dispatcher database. 00261 // 00262 00263 Thread = KeGetCurrentThread(); 00264 KiLockDispatcherDatabase(&OldIrql); 00265 00266 // 00267 // Check whether there is already a process address space attached or 00268 // the thread is executing a DPC. If either condition is true, then call 00269 // bug check. 00270 // 00271 00272 if ((Thread->ApcStateIndex != 0) || 00273 (KeIsExecutingDpc() != FALSE)) { 00274 KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT, 00275 (ULONG_PTR)Process, 00276 (ULONG_PTR)Thread->ApcState.Process, 00277 (ULONG)Thread->ApcStateIndex, 00278 (ULONG)KeIsExecutingDpc()); 00279 } 00280 00281 // 00282 // If the target process is not the current process, then attach the target 00283 // process if the process is not currently being swapped in or out of memory. 00284 // 00285 00286 if (Thread->ApcState.Process == Process) { 00287 KiUnlockDispatcherDatabase(OldIrql); 00288 00289 } else { 00290 00291 // 00292 // If the target process is currently being swapped into or out of memory, 00293 // then return a value of FALSE. Otherwise, force the process to be inswapped. 00294 // 00295 00296 if ((Process->State == ProcessInSwap) || Process->State == ProcessOutSwap) { 00297 KiUnlockDispatcherDatabase(OldIrql); 00298 return FALSE; 00299 00300 } else { 00301 00302 // 00303 // If the target process is in transition, then remove it from its 00304 // transition list. 00305 // 00306 00307 if (Process->State == ProcessInTransition) { 00308 RemoveEntryList(&Process->SwapListEntry); 00309 } 00310 00311 // 00312 // Force the process state to in memory and attach the target process. 00313 // 00314 00315 Process->State = ProcessInMemory; 00316 KiAttachProcess(Thread, Process, OldIrql, &Thread->SavedApcState); 00317 } 00318 } 00319 00320 return TRUE; 00321 } 00322 00323 VOID 00324 KeStackAttachProcess ( 00325 IN PRKPROCESS Process, 00326 OUT PRKAPC_STATE ApcState 00327 ) 00328 00329 /*++ 00330 00331 Routine Description: 00332 00333 This function attaches a thread to a target process' address space 00334 and returns information about a previous attached process. 00335 00336 Arguments: 00337 00338 Process - Supplies a pointer to a dispatcher object of type process. 00339 00340 Return Value: 00341 00342 None. 00343 00344 --*/ 00345 00346 { 00347 00348 KIRQL OldIrql; 00349 PRKTHREAD Thread; 00350 00351 ASSERT_PROCESS(Process); 00352 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); 00353 00354 // 00355 // Raise IRQL to dispatcher level and lock dispatcher database. 00356 // 00357 00358 Thread = KeGetCurrentThread(); 00359 KiLockDispatcherDatabase(&OldIrql); 00360 00361 // 00362 // If the current thread is executing a DPC, then bug check. 00363 // 00364 00365 if (KeIsExecutingDpc() != FALSE) { 00366 KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT, 00367 (ULONG_PTR)Process, 00368 (ULONG_PTR)Thread->ApcState.Process, 00369 (ULONG)Thread->ApcStateIndex, 00370 (ULONG)KeIsExecutingDpc()); 00371 } 00372 00373 // 00374 // If the target process is not the current process, then attach the target 00375 // process. Otherwise, return a distinguished process value to indicate that 00376 // an attach was not performed. 00377 // 00378 00379 if (Thread->ApcState.Process == Process) { 00380 KiUnlockDispatcherDatabase(OldIrql); 00381 ApcState->Process = (PRKPROCESS)1; 00382 00383 } else { 00384 00385 // 00386 // If the current thread is attached to a process, then save the current 00387 // APC state in the callers APC state structure. Otherwise, save the 00388 // current APC state in the saved APC state structure, and return a NULL 00389 // process pointer. 00390 // 00391 00392 if (Thread->ApcStateIndex != 0) { 00393 KiAttachProcess(Thread, Process, OldIrql, ApcState); 00394 00395 } else { 00396 KiAttachProcess(Thread, Process, OldIrql, &Thread->SavedApcState); 00397 ApcState->Process = NULL; 00398 } 00399 } 00400 00401 return; 00402 } 00403 00404 VOID 00405 KeDetachProcess ( 00406 VOID 00407 ) 00408 00409 /*++ 00410 00411 Routine Description: 00412 00413 This function detaches a thread from another process' address space. 00414 00415 Arguments: 00416 00417 None. 00418 00419 Return Value: 00420 00421 None. 00422 00423 --*/ 00424 00425 { 00426 00427 KIRQL OldIrql; 00428 PKPROCESS Process; 00429 PKTHREAD Thread; 00430 00431 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); 00432 00433 // 00434 // Raise IRQL to dispatcher level and lock dispatcher database. 00435 // 00436 00437 Thread = KeGetCurrentThread(); 00438 KiLockDispatcherDatabase(&OldIrql); 00439 00440 // 00441 // If the current thread is attached to another process, then detach 00442 // it. 00443 // 00444 00445 if (Thread->ApcStateIndex != 0) { 00446 00447 // 00448 // Check if a kernel APC is in progress, the kernel APC queue is 00449 // not empty, or the user APC queue is not empty. If any of these 00450 // conditions are true, then call bug check. 00451 // 00452 00453 #if DBG 00454 00455 if ((Thread->ApcState.KernelApcInProgress) || 00456 (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]) == FALSE) || 00457 (IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]) == FALSE)) { 00458 KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT); 00459 } 00460 00461 #endif 00462 00463 // 00464 // Unbias current process stack count and check if the process should 00465 // be swapped out of memory. 00466 // 00467 00468 Process = Thread->ApcState.Process; 00469 Process->StackCount -= 1; 00470 if ((Process->StackCount == 0) && 00471 (IsListEmpty(&Process->ThreadListHead) == FALSE)) { 00472 Process->State = ProcessInTransition; 00473 InsertTailList(&KiProcessOutSwapListHead, &Process->SwapListEntry); 00474 KiSwapEvent.Header.SignalState = 1; 00475 if (IsListEmpty(&KiSwapEvent.Header.WaitListHead) == FALSE) { 00476 KiWaitTest(&KiSwapEvent, BALANCE_INCREMENT); 00477 } 00478 } 00479 00480 // 00481 // Restore APC state and check whether the kernel APC queue contains 00482 // an entry. If the kernel APC queue contains an entry then set kernel 00483 // APC pending and request a software interrupt at APC_LEVEL. 00484 // 00485 00486 KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState); 00487 Thread->SavedApcState.Process = (PKPROCESS)NULL; 00488 Thread->ApcStatePointer[0] = &Thread->ApcState; 00489 Thread->ApcStatePointer[1] = &Thread->SavedApcState; 00490 Thread->ApcStateIndex = 0; 00491 if (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]) == FALSE) { 00492 Thread->ApcState.KernelApcPending = TRUE; 00493 KiRequestSoftwareInterrupt(APC_LEVEL); 00494 } 00495 00496 // 00497 // Swap the address space back to the parent process. 00498 // 00499 00500 KiSwapProcess(Thread->ApcState.Process, Process); 00501 } 00502 00503 // 00504 // Lower IRQL to its previous value and return. 00505 // 00506 00507 KiUnlockDispatcherDatabase(OldIrql); 00508 return; 00509 } 00510 00511 VOID 00512 KeUnstackDetachProcess ( 00513 IN PRKAPC_STATE ApcState 00514 ) 00515 00516 /*++ 00517 00518 Routine Description: 00519 00520 This function detaches a thread from another process' address space 00521 and restores previous attach state. 00522 00523 Arguments: 00524 00525 ApcState - Supplies a pointer to an APC state structure that was returned 00526 from a previous call to stack attach process. 00527 00528 Return Value: 00529 00530 None. 00531 00532 --*/ 00533 00534 { 00535 00536 KIRQL OldIrql; 00537 PKPROCESS Process; 00538 PKTHREAD Thread; 00539 00540 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); 00541 00542 // 00543 // Raise IRQL to dispatcher level and lock dispatcher database. 00544 // 00545 00546 Thread = KeGetCurrentThread(); 00547 KiLockDispatcherDatabase(&OldIrql); 00548 00549 // 00550 // If the APC state has a distinguished process pointer value, then no 00551 // attach was performed on the paired call to stack attach process. 00552 // 00553 00554 if (ApcState->Process != (PRKPROCESS)1) { 00555 00556 // 00557 // If the current thread is not attached to another process, a kernel 00558 // APC is in progress, or either the kernel or user mode APC queues 00559 // are not empty, then call bug check. 00560 // 00561 00562 if ((Thread->ApcStateIndex == 0) || 00563 (Thread->ApcState.KernelApcInProgress) || 00564 (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]) == FALSE) || 00565 (IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]) == FALSE)) { 00566 KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT); 00567 } 00568 00569 // 00570 // Unbias current process stack count and check if the process should 00571 // be swapped out of memory. 00572 // 00573 00574 Process = Thread->ApcState.Process; 00575 Process->StackCount -= 1; 00576 if ((Process->StackCount == 0) && 00577 (IsListEmpty(&Process->ThreadListHead) == FALSE)) { 00578 Process->State = ProcessInTransition; 00579 InsertTailList(&KiProcessOutSwapListHead, &Process->SwapListEntry); 00580 KiSwapEvent.Header.SignalState = 1; 00581 if (IsListEmpty(&KiSwapEvent.Header.WaitListHead) == FALSE) { 00582 KiWaitTest(&KiSwapEvent, BALANCE_INCREMENT); 00583 } 00584 } 00585 00586 // 00587 // Restore APC state and check whether the kernel APC queue contains 00588 // an entry. If the kernel APC queue contains an entry then set kernel 00589 // APC pending and request a software interrupt at APC_LEVEL. 00590 // 00591 00592 if (ApcState->Process != NULL) { 00593 KiMoveApcState(ApcState, &Thread->ApcState); 00594 00595 } else { 00596 KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState); 00597 Thread->SavedApcState.Process = (PKPROCESS)NULL; 00598 Thread->ApcStatePointer[0] = &Thread->ApcState; 00599 Thread->ApcStatePointer[1] = &Thread->SavedApcState; 00600 Thread->ApcStateIndex = 0; 00601 } 00602 00603 if (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]) == FALSE) { 00604 Thread->ApcState.KernelApcPending = TRUE; 00605 KiRequestSoftwareInterrupt(APC_LEVEL); 00606 } 00607 00608 // 00609 // Swap the address space back to the parent process. 00610 // 00611 00612 KiSwapProcess(Thread->ApcState.Process, Process); 00613 } 00614 00615 // 00616 // Lower IRQL to its previous value and return. 00617 // 00618 00619 KiUnlockDispatcherDatabase(OldIrql); 00620 return; 00621 } 00622 00623 LONG 00624 KeReadStateProcess ( 00625 IN PRKPROCESS Process 00626 ) 00627 00628 /*++ 00629 00630 Routine Description: 00631 00632 This function reads the current signal state of a process object. 00633 00634 Arguments: 00635 00636 Process - Supplies a pointer to a dispatcher object of type process. 00637 00638 Return Value: 00639 00640 The current signal state of the process object. 00641 00642 --*/ 00643 00644 { 00645 00646 ASSERT_PROCESS(Process); 00647 00648 // 00649 // Return current signal state of process object. 00650 // 00651 00652 return Process->Header.SignalState; 00653 } 00654 00655 LONG 00656 KeSetProcess ( 00657 IN PRKPROCESS Process, 00658 IN KPRIORITY Increment, 00659 IN BOOLEAN Wait 00660 ) 00661 00662 /*++ 00663 00664 Routine Description: 00665 00666 This function sets the signal state of a proces object to Signaled 00667 and attempts to satisfy as many Waits as possible. The previous 00668 signal state of the process object is returned as the function value. 00669 00670 Arguments: 00671 00672 Process - Supplies a pointer to a dispatcher object of type process. 00673 00674 Increment - Supplies the priority increment that is to be applied 00675 if setting the process causes a Wait to be satisfied. 00676 00677 Wait - Supplies a boolean value that signifies whether the call to 00678 KeSetProcess will be immediately followed by a call to one of the 00679 kernel Wait functions. 00680 00681 Return Value: 00682 00683 The previous signal state of the process object. 00684 00685 --*/ 00686 00687 { 00688 00689 KIRQL OldIrql; 00690 LONG OldState; 00691 PRKTHREAD Thread; 00692 00693 ASSERT_PROCESS(Process); 00694 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); 00695 00696 // 00697 // Raise IRQL to dispatcher level and lock dispatcher database. 00698 // 00699 00700 KiLockDispatcherDatabase(&OldIrql); 00701 00702 // 00703 // If the previous state of the process object is Not-Signaled and 00704 // the wait queue is not empty, then satisfy as many Waits as 00705 // possible. 00706 // 00707 00708 OldState = Process->Header.SignalState; 00709 Process->Header.SignalState = 1; 00710 if ((OldState == 0) && (!IsListEmpty(&Process->Header.WaitListHead))) { 00711 KiWaitTest(Process, Increment); 00712 } 00713 00714 // 00715 // If the value of the Wait argument is TRUE, then return to the 00716 // caller with IRQL raised and the dispatcher database locked. Else 00717 // release the dispatcher database lock and lower IRQL to its 00718 // previous value. 00719 // 00720 00721 if (Wait) { 00722 Thread = KeGetCurrentThread(); 00723 Thread->WaitNext = Wait; 00724 Thread->WaitIrql = OldIrql; 00725 00726 } else { 00727 KiUnlockDispatcherDatabase(OldIrql); 00728 } 00729 00730 // 00731 // Return previous signal state of process object. 00732 // 00733 00734 return OldState; 00735 } 00736 00737 KPRIORITY 00738 KeSetPriorityProcess ( 00739 IN PKPROCESS Process, 00740 IN KPRIORITY NewBase 00741 ) 00742 00743 /*++ 00744 00745 Routine Description: 00746 00747 This function set the base priority of a process to a new value 00748 and adjusts the priority and base priority of all child threads 00749 as appropriate. 00750 00751 Arguments: 00752 00753 Process - Supplies a pointer to a dispatcher object of type process. 00754 00755 NewBase - Supplies the new base priority of the process. 00756 00757 Return Value: 00758 00759 The previous base priority of the process. 00760 00761 --*/ 00762 00763 { 00764 00765 KPRIORITY Adjustment; 00766 PLIST_ENTRY NextEntry; 00767 KPRIORITY NewPriority; 00768 KIRQL OldIrql; 00769 KPRIORITY OldBase; 00770 PKTHREAD Thread; 00771 00772 ASSERT_PROCESS(Process); 00773 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); 00774 00775 // 00776 // Raise IRQL to dispatcher level and lock dispatcher database. 00777 // 00778 00779 KiLockDispatcherDatabase(&OldIrql); 00780 00781 // 00782 // Save the current process base priority, set the new process base 00783 // priority, compute the adjustment value, and adjust the priority 00784 // and base priority of all child threads as appropriate. 00785 // 00786 00787 OldBase = Process->BasePriority; 00788 Process->BasePriority = (SCHAR)NewBase; 00789 Adjustment = NewBase - OldBase; 00790 NextEntry = Process->ThreadListHead.Flink; 00791 if (NewBase >= LOW_REALTIME_PRIORITY) { 00792 while (NextEntry != &Process->ThreadListHead) { 00793 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry); 00794 00795 // 00796 // Compute the new base priority of the thread. 00797 // 00798 00799 NewPriority = Thread->BasePriority + Adjustment; 00800 00801 // 00802 // If the new base priority is outside the realtime class, 00803 // then limit the change to the realtime class. 00804 // 00805 00806 if (NewPriority < LOW_REALTIME_PRIORITY) { 00807 NewPriority = LOW_REALTIME_PRIORITY; 00808 00809 } else if (NewPriority > HIGH_PRIORITY) { 00810 NewPriority = HIGH_PRIORITY; 00811 } 00812 00813 // 00814 // Set the base priority and the current priority of the 00815 // thread to the appropriate value. 00816 // 00817 // N.B. If priority saturation occured the last time the thread 00818 // base priority was set and the new process base priority 00819 // is not crossing from variable to realtime, then it is not 00820 // necessary to change the thread priority. 00821 // 00822 00823 if ((Thread->Saturation == 0) || (OldBase < LOW_REALTIME_PRIORITY)) { 00824 if (Thread->Saturation > 0) { 00825 NewPriority = HIGH_PRIORITY; 00826 00827 } else if (Thread->Saturation < 0) { 00828 NewPriority = LOW_REALTIME_PRIORITY; 00829 } 00830 00831 Thread->BasePriority = (SCHAR)NewPriority; 00832 Thread->Quantum = Process->ThreadQuantum; 00833 Thread->DecrementCount = 0; 00834 Thread->PriorityDecrement = 0; 00835 KiSetPriorityThread(Thread, NewPriority); 00836 } 00837 00838 NextEntry = NextEntry->Flink; 00839 } 00840 00841 } else { 00842 while (NextEntry != &Process->ThreadListHead) { 00843 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry); 00844 00845 // 00846 // Compute the new base priority of the thread. 00847 // 00848 00849 NewPriority = Thread->BasePriority + Adjustment; 00850 00851 // 00852 // If the new base priority is outside the variable class, 00853 // then limit the change to the variable class. 00854 // 00855 00856 if (NewPriority >= LOW_REALTIME_PRIORITY) { 00857 NewPriority = LOW_REALTIME_PRIORITY - 1; 00858 00859 } else if (NewPriority <= LOW_PRIORITY) { 00860 NewPriority = 1; 00861 } 00862 00863 // 00864 // Set the base priority and the current priority of the 00865 // thread to the computed value and reset the thread quantum. 00866 // 00867 // N.B. If priority saturation occured the last time the thread 00868 // base priority was set and the new process base priority 00869 // is not crossing from realtime to variable, then it is not 00870 // necessary to change the thread priority. 00871 // 00872 00873 if ((Thread->Saturation == 0) || (OldBase >= LOW_REALTIME_PRIORITY)) { 00874 if (Thread->Saturation > 0) { 00875 NewPriority = LOW_REALTIME_PRIORITY - 1; 00876 00877 } else if (Thread->Saturation < 0) { 00878 NewPriority = 1; 00879 } 00880 00881 Thread->BasePriority = (SCHAR)NewPriority; 00882 Thread->Quantum = Process->ThreadQuantum; 00883 Thread->DecrementCount = 0; 00884 Thread->PriorityDecrement = 0; 00885 KiSetPriorityThread(Thread, NewPriority); 00886 } 00887 00888 NextEntry = NextEntry->Flink; 00889 } 00890 } 00891 00892 // 00893 // Unlock dispatcher database and lower IRQL to its previous 00894 // value. 00895 // 00896 00897 KiUnlockDispatcherDatabase(OldIrql); 00898 00899 // 00900 // Return previous process base priority 00901 // 00902 00903 return OldBase; 00904 } 00905 00906 LOGICAL 00907 KeSetDisableQuantumProcess ( 00908 IN PKPROCESS Process, 00909 IN LOGICAL Disable 00910 ) 00911 00912 /*++ 00913 00914 Routine Description: 00915 00916 This function disables quantum runout for realtime threads in the 00917 specified process. 00918 00919 Arguments: 00920 00921 Process - Supplies a pointer to a dispatcher object of type process. 00922 00923 Disable - Supplies a logical value that determines whether quantum 00924 runout for realtime threads in the specified process are disabled 00925 or enabled. 00926 00927 Return Value: 00928 00929 The previous value of the disable quantum state variable. 00930 00931 --*/ 00932 00933 { 00934 00935 LOGICAL DisableQuantum; 00936 00937 ASSERT_PROCESS(Process); 00938 00939 // 00940 // Capture the current state of the disable boost variable and set its 00941 // state to TRUE. 00942 // 00943 00944 DisableQuantum = Process->DisableQuantum; 00945 Process->DisableQuantum = (BOOLEAN)Disable; 00946 00947 // 00948 // Return the previous disable quantum state. 00949 // 00950 00951 return DisableQuantum; 00952 } 00953 00954 VOID 00955 KiAttachProcess ( 00956 IN PRKTHREAD Thread, 00957 IN PKPROCESS Process, 00958 IN KIRQL OldIrql, 00959 OUT PRKAPC_STATE SavedApcState 00960 ) 00961 00962 /*++ 00963 00964 Routine Description: 00965 00966 This function attaches a thread to a target process' address space. 00967 00968 N.B. The dispatcher database lock must be held when this routine is 00969 called. 00970 00971 Arguments: 00972 00973 Thread - Supplies a pointer to a dispatcher object of type thread. 00974 00975 Process - Supplies a pointer to a dispatcher object of type process. 00976 00977 OldIrql - Supplies the previous IRQL. 00978 00979 SavedApcState - Supplies a pointer to the APC state structure that receives 00980 the saved APC state. 00981 00982 Return Value: 00983 00984 None. 00985 00986 --*/ 00987 00988 { 00989 00990 PRKTHREAD OutThread; 00991 KAFFINITY Processor; 00992 PLIST_ENTRY NextEntry; 00993 KIRQL HighIrql; 00994 00995 ASSERT(Process != Thread->ApcState.Process); 00996 00997 // 00998 // Bias the stack count of the target process to signify that a 00999 // thread exists in that process with a stack that is resident. 01000 // 01001 01002 Process->StackCount += 1; 01003 01004 // 01005 // Save current APC state and initialize a new APC state. 01006 // 01007 01008 KiMoveApcState(&Thread->ApcState, SavedApcState); 01009 InitializeListHead(&Thread->ApcState.ApcListHead[KernelMode]); 01010 InitializeListHead(&Thread->ApcState.ApcListHead[UserMode]); 01011 Thread->ApcState.Process = Process; 01012 Thread->ApcState.KernelApcInProgress = FALSE; 01013 Thread->ApcState.KernelApcPending = FALSE; 01014 Thread->ApcState.UserApcPending = FALSE; 01015 if (SavedApcState == &Thread->SavedApcState) { 01016 Thread->ApcStatePointer[0] = &Thread->SavedApcState; 01017 Thread->ApcStatePointer[1] = &Thread->ApcState; 01018 Thread->ApcStateIndex = 1; 01019 } 01020 01021 // 01022 // If the target process is in memory, then immediately enter the 01023 // new address space by loading a new Directory Table Base. Otherwise, 01024 // insert the current thread in the target process ready list, inswap 01025 // the target process if necessary, select a new thread to run on the 01026 // the current processor and context switch to the new thread. 01027 // 01028 01029 if (Process->State == ProcessInMemory) { 01030 01031 // 01032 // It is possible that the process is in memory, but there exist 01033 // threads in the process ready list. This can happen when memory 01034 // management forces a process attach. 01035 // 01036 01037 NextEntry = Process->ReadyListHead.Flink; 01038 while (NextEntry != &Process->ReadyListHead) { 01039 OutThread = CONTAINING_RECORD(NextEntry, KTHREAD, WaitListEntry); 01040 RemoveEntryList(NextEntry); 01041 OutThread->ProcessReadyQueue = FALSE; 01042 KiReadyThread(OutThread); 01043 NextEntry = Process->ReadyListHead.Flink; 01044 } 01045 01046 KiSwapProcess(Process, SavedApcState->Process); 01047 KiUnlockDispatcherDatabase(OldIrql); 01048 01049 } else { 01050 Thread->State = Ready; 01051 Thread->ProcessReadyQueue = TRUE; 01052 InsertTailList(&Process->ReadyListHead, &Thread->WaitListEntry); 01053 if (Process->State == ProcessOutOfMemory) { 01054 Process->State = ProcessInTransition; 01055 InsertTailList(&KiProcessInSwapListHead, &Process->SwapListEntry); 01056 KiSwapEvent.Header.SignalState = 1; 01057 if (IsListEmpty(&KiSwapEvent.Header.WaitListHead) == FALSE) { 01058 KiWaitTest(&KiSwapEvent, BALANCE_INCREMENT); 01059 } 01060 } 01061 01062 // 01063 // Clear the active processor bit in the previous process and 01064 // set active processor bit in the process being attached to. 01065 // 01066 01067 #if !defined(NT_UP) 01068 01069 KiLockContextSwap(&HighIrql); 01070 Processor = KeGetCurrentPrcb()->SetMember; 01071 SavedApcState->Process->ActiveProcessors &= ~Processor; 01072 Process->ActiveProcessors |= Processor; 01073 01074 #if defined(_ALPHA_) 01075 01076 Process->RunOnProcessors |= Processor; 01077 01078 #endif 01079 01080 KiUnlockContextSwap(HighIrql); 01081 01082 #endif 01083 01084 Thread->WaitIrql = OldIrql; 01085 KiSwapThread(); 01086 } 01087 01088 return; 01089 } 01090 01091 VOID 01092 KiMoveApcState ( 01093 IN PKAPC_STATE Source, 01094 OUT PKAPC_STATE Destination 01095 ) 01096 01097 /*++ 01098 01099 Routine Description: 01100 01101 This function moves the APC state from the source structure to the 01102 destination structure and reinitializes list headers as appropriate. 01103 01104 Arguments: 01105 01106 Source - Supplies a pointer to the source APC state structure. 01107 01108 Destination - Supplies a pointer to the destination APC state structure. 01109 01110 01111 Return Value: 01112 01113 None. 01114 01115 --*/ 01116 01117 { 01118 01119 PLIST_ENTRY First; 01120 PLIST_ENTRY Last; 01121 01122 // 01123 // Copy the APC state from the source to the destination. 01124 // 01125 01126 *Destination = *Source; 01127 if (IsListEmpty(&Source->ApcListHead[KernelMode]) != FALSE) { 01128 InitializeListHead(&Destination->ApcListHead[KernelMode]); 01129 01130 } else { 01131 First = Source->ApcListHead[KernelMode].Flink; 01132 Last = Source->ApcListHead[KernelMode].Blink; 01133 Destination->ApcListHead[KernelMode].Flink = First; 01134 Destination->ApcListHead[KernelMode].Blink = Last; 01135 First->Blink = &Destination->ApcListHead[KernelMode]; 01136 Last->Flink = &Destination->ApcListHead[KernelMode]; 01137 } 01138 01139 if (IsListEmpty(&Source->ApcListHead[UserMode]) != FALSE) { 01140 InitializeListHead(&Destination->ApcListHead[UserMode]); 01141 01142 } else { 01143 First = Source->ApcListHead[UserMode].Flink; 01144 Last = Source->ApcListHead[UserMode].Blink; 01145 Destination->ApcListHead[UserMode].Flink = First; 01146 Destination->ApcListHead[UserMode].Blink = Last; 01147 First->Blink = &Destination->ApcListHead[UserMode]; 01148 Last->Flink = &Destination->ApcListHead[UserMode]; 01149 } 01150 01151 return; 01152 } 01153 

Generated on Sat May 15 19:41:26 2004 for test by doxygen 1.3.7