Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenprocobj.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: ntoskrnl/ke/process.c 00005 * PURPOSE: Kernel Process Management and System Call Tables 00006 * PROGRAMMERS: Alex Ionescu 00007 * Gregor Anich 00008 */ 00009 00010 /* INCLUDES ******************************************************************/ 00011 00012 #include <ntoskrnl.h> 00013 #define NDEBUG 00014 #include <debug.h> 00015 00016 /* GLOBALS *******************************************************************/ 00017 00018 LIST_ENTRY KiProcessListHead; 00019 LIST_ENTRY KiProcessInSwapListHead, KiProcessOutSwapListHead; 00020 LIST_ENTRY KiStackInSwapListHead; 00021 KEVENT KiSwapEvent; 00022 00023 KSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable[SSDT_MAX_ENTRIES]; 00024 KSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTableShadow[SSDT_MAX_ENTRIES]; 00025 00026 PVOID KeUserApcDispatcher; 00027 PVOID KeUserCallbackDispatcher; 00028 PVOID KeUserExceptionDispatcher; 00029 PVOID KeRaiseUserExceptionDispatcher; 00030 00031 /* PRIVATE FUNCTIONS *********************************************************/ 00032 00033 VOID 00034 NTAPI 00035 KiAttachProcess(IN PKTHREAD Thread, 00036 IN PKPROCESS Process, 00037 IN PKLOCK_QUEUE_HANDLE ApcLock, 00038 IN PRKAPC_STATE SavedApcState) 00039 { 00040 #if 0 00041 PLIST_ENTRY ListHead, NextEntry; 00042 PKTHREAD CurrentThread; 00043 #endif 00044 ASSERT(Process != Thread->ApcState.Process); 00045 00046 /* Increase Stack Count */ 00047 ASSERT(Process->StackCount != MAXULONG_PTR); 00048 Process->StackCount++; 00049 00050 /* Swap the APC Environment */ 00051 KiMoveApcState(&Thread->ApcState, SavedApcState); 00052 00053 /* Reinitialize Apc State */ 00054 InitializeListHead(&Thread->ApcState.ApcListHead[KernelMode]); 00055 InitializeListHead(&Thread->ApcState.ApcListHead[UserMode]); 00056 Thread->ApcState.Process = Process; 00057 Thread->ApcState.KernelApcInProgress = FALSE; 00058 Thread->ApcState.KernelApcPending = FALSE; 00059 Thread->ApcState.UserApcPending = FALSE; 00060 00061 /* Update Environment Pointers if needed*/ 00062 if (SavedApcState == &Thread->SavedApcState) 00063 { 00064 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread-> 00065 SavedApcState; 00066 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->ApcState; 00067 Thread->ApcStateIndex = AttachedApcEnvironment; 00068 } 00069 00070 /* Check if the process is paged in */ 00071 if (Process->State == ProcessInMemory) 00072 { 00073 /* Scan the ready list */ 00074 #if 0 00075 ListHead = &Process->ReadyListHead; 00076 NextEntry = ListHead->Flink; 00077 while (NextEntry != ListHead) 00078 { 00079 /* Get the thread */ 00080 CurrentThread = CONTAINING_RECORD(NextEntry, KTHREAD, WaitListEntry); 00081 00082 /* Remove it */ 00083 RemoveEntryList(NextEntry); 00084 CurrentThread->ProcessReadyQueue = FALSE; 00085 00086 /* Mark it ready */ 00087 KiReadyThread(CurrentThread); 00088 00089 /* Go to the next one */ 00090 NextEntry = ListHead->Flink; 00091 } 00092 #endif 00093 00094 /* Release dispatcher lock */ 00095 KiReleaseDispatcherLockFromDpcLevel(); 00096 00097 /* Release lock */ 00098 KiReleaseApcLockFromDpcLevel(ApcLock); 00099 00100 /* Swap Processes */ 00101 KiSwapProcess(Process, SavedApcState->Process); 00102 00103 /* Exit the dispatcher */ 00104 KiExitDispatcher(ApcLock->OldIrql); 00105 } 00106 else 00107 { 00108 DPRINT1("Errr. ReactOS doesn't support paging out processes yet...\n"); 00109 ASSERT(FALSE); 00110 } 00111 } 00112 00113 VOID 00114 NTAPI 00115 KeInitializeProcess(IN OUT PKPROCESS Process, 00116 IN KPRIORITY Priority, 00117 IN KAFFINITY Affinity, 00118 IN PULONG_PTR DirectoryTableBase, 00119 IN BOOLEAN Enable) 00120 { 00121 #ifdef CONFIG_SMP 00122 ULONG i = 0; 00123 UCHAR IdealNode = 0; 00124 PKNODE Node; 00125 #endif 00126 00127 /* Initialize the Dispatcher Header */ 00128 Process->Header.Type = ProcessObject; 00129 Process->Header.Size = sizeof(KPROCESS) / sizeof(ULONG); 00130 Process->Header.SignalState = 0; 00131 InitializeListHead(&(Process->Header.WaitListHead)); 00132 00133 /* Initialize Scheduler Data, Alignment Faults and Set the PDE */ 00134 Process->Affinity = Affinity; 00135 Process->BasePriority = (CHAR)Priority; 00136 Process->QuantumReset = 6; 00137 Process->DirectoryTableBase[0] = DirectoryTableBase[0]; 00138 Process->DirectoryTableBase[1] = DirectoryTableBase[1]; 00139 Process->AutoAlignment = Enable; 00140 #if defined(_M_IX86) 00141 Process->IopmOffset = KiComputeIopmOffset(IO_ACCESS_MAP_NONE); 00142 #endif 00143 00144 /* Initialize the lists */ 00145 InitializeListHead(&Process->ThreadListHead); 00146 InitializeListHead(&Process->ProfileListHead); 00147 InitializeListHead(&Process->ReadyListHead); 00148 00149 /* Initialize the current State */ 00150 Process->State = ProcessInMemory; 00151 00152 /* Check how many Nodes there are on the system */ 00153 #ifdef CONFIG_SMP 00154 if (KeNumberNodes > 1) 00155 { 00156 /* Set the new seed */ 00157 KeProcessNodeSeed = (KeProcessNodeSeed + 1) / KeNumberNodes; 00158 IdealNode = KeProcessNodeSeed; 00159 00160 /* Loop every node */ 00161 do 00162 { 00163 /* Check if the affinity matches */ 00164 if (KeNodeBlock[IdealNode]->ProcessorMask != Affinity) break; 00165 00166 /* No match, try next Ideal Node and increase node loop index */ 00167 IdealNode++; 00168 i++; 00169 00170 /* Check if the Ideal Node is beyond the total number of nodes */ 00171 if (IdealNode >= KeNumberNodes) 00172 { 00173 /* Normalize the Ideal Node */ 00174 IdealNode -= KeNumberNodes; 00175 } 00176 } while (i < KeNumberNodes); 00177 } 00178 00179 /* Set the ideal node and get the ideal node block */ 00180 Process->IdealNode = IdealNode; 00181 Node = KeNodeBlock[IdealNode]; 00182 ASSERT(Node->ProcessorMask & Affinity); 00183 00184 /* Find the matching affinity set to calculate the thread seed */ 00185 Affinity &= Node->ProcessorMask; 00186 Process->ThreadSeed = KeFindNextRightSetAffinity(Node->Seed, 00187 (ULONG)Affinity); 00188 Node->Seed = Process->ThreadSeed; 00189 #endif 00190 } 00191 00192 ULONG 00193 NTAPI 00194 KeSetProcess(IN PKPROCESS Process, 00195 IN KPRIORITY Increment, 00196 IN BOOLEAN InWait) 00197 { 00198 KIRQL OldIrql; 00199 ULONG OldState; 00200 ASSERT_PROCESS(Process); 00201 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 00202 00203 /* Lock Dispatcher */ 00204 OldIrql = KiAcquireDispatcherLock(); 00205 00206 /* Get Old State */ 00207 OldState = Process->Header.SignalState; 00208 00209 /* Signal the Process */ 00210 Process->Header.SignalState = TRUE; 00211 00212 /* Check if was unsignaled and has waiters */ 00213 if (!(OldState) && 00214 !(IsListEmpty(&Process->Header.WaitListHead))) 00215 { 00216 /* Unwait the threads */ 00217 KxUnwaitThread(&Process->Header, Increment); 00218 } 00219 00220 /* Release Dispatcher Database */ 00221 KiReleaseDispatcherLock(OldIrql); 00222 00223 /* Return the previous State */ 00224 return OldState; 00225 } 00226 00227 VOID 00228 NTAPI 00229 KeSetQuantumProcess(IN PKPROCESS Process, 00230 IN UCHAR Quantum) 00231 { 00232 KLOCK_QUEUE_HANDLE ProcessLock; 00233 PLIST_ENTRY NextEntry, ListHead; 00234 PKTHREAD Thread; 00235 ASSERT_PROCESS(Process); 00236 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 00237 00238 /* Lock the process */ 00239 KiAcquireProcessLock(Process, &ProcessLock); 00240 00241 /* Set new quantum */ 00242 Process->QuantumReset = Quantum; 00243 00244 /* Loop all child threads */ 00245 ListHead = &Process->ThreadListHead; 00246 NextEntry = ListHead->Flink; 00247 while (ListHead != NextEntry) 00248 { 00249 /* Get the thread */ 00250 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry); 00251 00252 /* Set quantum */ 00253 Thread->QuantumReset = Quantum; 00254 00255 /* Go to the next one */ 00256 NextEntry = NextEntry->Flink; 00257 } 00258 00259 /* Release lock */ 00260 KiReleaseProcessLock(&ProcessLock); 00261 } 00262 00263 KAFFINITY 00264 NTAPI 00265 KeSetAffinityProcess(IN PKPROCESS Process, 00266 IN KAFFINITY Affinity) 00267 { 00268 00269 KLOCK_QUEUE_HANDLE ProcessLock; 00270 PLIST_ENTRY NextEntry, ListHead; 00271 KAFFINITY OldAffinity; 00272 PKTHREAD Thread; 00273 ASSERT_PROCESS(Process); 00274 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); 00275 ASSERT((Affinity & KeActiveProcessors) != 0); 00276 00277 /* Lock the process */ 00278 KiAcquireProcessLock(Process, &ProcessLock); 00279 00280 /* Acquire the dispatcher lock */ 00281 KiAcquireDispatcherLockAtDpcLevel(); 00282 00283 /* Capture old affinity and update it */ 00284 OldAffinity = Process->Affinity; 00285 Process->Affinity = Affinity; 00286 00287 /* Loop all child threads */ 00288 ListHead = &Process->ThreadListHead; 00289 NextEntry = ListHead->Flink; 00290 while (ListHead != NextEntry) 00291 { 00292 /* Get the thread */ 00293 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry); 00294 00295 /* Set affinity on it */ 00296 KiSetAffinityThread(Thread, Affinity); 00297 NextEntry = NextEntry->Flink; 00298 } 00299 00300 /* Release Dispatcher Database */ 00301 KiReleaseDispatcherLockFromDpcLevel(); 00302 00303 /* Release the process lock */ 00304 KiReleaseProcessLockFromDpcLevel(&ProcessLock); 00305 KiExitDispatcher(ProcessLock.OldIrql); 00306 00307 /* Return previous affinity */ 00308 return OldAffinity; 00309 } 00310 00311 BOOLEAN 00312 NTAPI 00313 KeSetAutoAlignmentProcess(IN PKPROCESS Process, 00314 IN BOOLEAN Enable) 00315 { 00316 /* Set or reset the bit depending on what the enable flag says */ 00317 if (Enable) 00318 { 00319 return InterlockedBitTestAndSet(&Process->ProcessFlags, 00320 KPSF_AUTO_ALIGNMENT_BIT); 00321 } 00322 else 00323 { 00324 return InterlockedBitTestAndReset(&Process->ProcessFlags, 00325 KPSF_AUTO_ALIGNMENT_BIT); 00326 } 00327 } 00328 00329 BOOLEAN 00330 NTAPI 00331 KeSetDisableBoostProcess(IN PKPROCESS Process, 00332 IN BOOLEAN Disable) 00333 { 00334 /* Set or reset the bit depending on what the disable flag says */ 00335 if (Disable) 00336 { 00337 return InterlockedBitTestAndSet(&Process->ProcessFlags, 00338 KPSF_DISABLE_BOOST_BIT); 00339 } 00340 else 00341 { 00342 return InterlockedBitTestAndReset(&Process->ProcessFlags, 00343 KPSF_DISABLE_BOOST_BIT); 00344 } 00345 } 00346 00347 KPRIORITY 00348 NTAPI 00349 KeSetPriorityAndQuantumProcess(IN PKPROCESS Process, 00350 IN KPRIORITY Priority, 00351 IN UCHAR Quantum OPTIONAL) 00352 { 00353 KLOCK_QUEUE_HANDLE ProcessLock; 00354 KPRIORITY Delta; 00355 PLIST_ENTRY NextEntry, ListHead; 00356 KPRIORITY NewPriority, OldPriority; 00357 PKTHREAD Thread; 00358 ASSERT_PROCESS(Process); 00359 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 00360 00361 /* Check if the process already has this priority */ 00362 if (Process->BasePriority == Priority) return Process->BasePriority; 00363 00364 /* If the caller gave priority 0, normalize to 1 */ 00365 if (!Priority) Priority = LOW_PRIORITY + 1; 00366 00367 /* Lock the process */ 00368 KiAcquireProcessLock(Process, &ProcessLock); 00369 00370 /* Check if we are modifying the quantum too */ 00371 if (Quantum) Process->QuantumReset = Quantum; 00372 00373 /* Save the current base priority and update it */ 00374 OldPriority = Process->BasePriority; 00375 Process->BasePriority = (SCHAR)Priority; 00376 00377 /* Calculate the priority delta */ 00378 Delta = Priority - OldPriority; 00379 00380 /* Set the list head and list entry */ 00381 ListHead = &Process->ThreadListHead; 00382 NextEntry = ListHead->Flink; 00383 00384 /* Check if this is a real-time priority */ 00385 if (Priority >= LOW_REALTIME_PRIORITY) 00386 { 00387 /* Loop the thread list */ 00388 while (NextEntry != ListHead) 00389 { 00390 /* Get the thread */ 00391 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry); 00392 00393 /* Update the quantum if we had one */ 00394 if (Quantum) Thread->QuantumReset = Quantum; 00395 00396 /* Acquire the thread lock */ 00397 KiAcquireThreadLock(Thread); 00398 00399 /* Calculate the new priority */ 00400 NewPriority = Thread->BasePriority + Delta; 00401 if (NewPriority < LOW_REALTIME_PRIORITY) 00402 { 00403 /* We're in real-time range, don't let it go below */ 00404 NewPriority = LOW_REALTIME_PRIORITY; 00405 } 00406 else if (NewPriority > HIGH_PRIORITY) 00407 { 00408 /* We're going beyond the maximum priority, normalize */ 00409 NewPriority = HIGH_PRIORITY; 00410 } 00411 00412 /* 00413 * If priority saturation occured or the old priority was still in 00414 * the real-time range, don't do anything. 00415 */ 00416 if (!(Thread->Saturation) || (OldPriority < LOW_REALTIME_PRIORITY)) 00417 { 00418 /* Check if we had priority saturation */ 00419 if (Thread->Saturation > 0) 00420 { 00421 /* Boost priority to maximum */ 00422 NewPriority = HIGH_PRIORITY; 00423 } 00424 else if (Thread->Saturation < 0) 00425 { 00426 /* If we had negative saturation, set minimum priority */ 00427 NewPriority = LOW_REALTIME_PRIORITY; 00428 } 00429 00430 /* Update priority and quantum */ 00431 Thread->BasePriority = (SCHAR)NewPriority; 00432 Thread->Quantum = Thread->QuantumReset; 00433 00434 /* Disable decrements and update priority */ 00435 Thread->PriorityDecrement = 0; 00436 KiSetPriorityThread(Thread, NewPriority); 00437 } 00438 00439 /* Release the thread lock */ 00440 KiReleaseThreadLock(Thread); 00441 00442 /* Go to the next thread */ 00443 NextEntry = NextEntry->Flink; 00444 } 00445 } 00446 else 00447 { 00448 /* Loop the thread list */ 00449 while (NextEntry != ListHead) 00450 { 00451 /* Get the thread */ 00452 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry); 00453 00454 /* Update the quantum if we had one */ 00455 if (Quantum) Thread->QuantumReset = Quantum; 00456 00457 /* Lock the thread */ 00458 KiAcquireThreadLock(Thread); 00459 00460 /* Calculate the new priority */ 00461 NewPriority = Thread->BasePriority + Delta; 00462 if (NewPriority >= LOW_REALTIME_PRIORITY) 00463 { 00464 /* We're not real-time range, don't let it enter RT range */ 00465 NewPriority = LOW_REALTIME_PRIORITY - 1; 00466 } 00467 else if (NewPriority <= LOW_PRIORITY) 00468 { 00469 /* We're going below the minimum priority, normalize */ 00470 NewPriority = 1; 00471 } 00472 00473 /* 00474 * If priority saturation occured or the old priority was still in 00475 * the real-time range, don't do anything. 00476 */ 00477 if (!(Thread->Saturation) || 00478 (OldPriority >= LOW_REALTIME_PRIORITY)) 00479 { 00480 /* Check if we had priority saturation */ 00481 if (Thread->Saturation > 0) 00482 { 00483 /* Boost priority to maximum */ 00484 NewPriority = LOW_REALTIME_PRIORITY - 1; 00485 } 00486 else if (Thread->Saturation < 0) 00487 { 00488 /* If we had negative saturation, set minimum priority */ 00489 NewPriority = 1; 00490 } 00491 00492 /* Update priority and quantum */ 00493 Thread->BasePriority = (SCHAR)NewPriority; 00494 Thread->Quantum = Thread->QuantumReset; 00495 00496 /* Disable decrements and update priority */ 00497 Thread->PriorityDecrement = 0; 00498 KiSetPriorityThread(Thread, NewPriority); 00499 } 00500 00501 /* Release the thread lock */ 00502 KiReleaseThreadLock(Thread); 00503 00504 /* Go to the next thread */ 00505 NextEntry = NextEntry->Flink; 00506 } 00507 } 00508 00509 /* Release Dispatcher Database */ 00510 KiReleaseDispatcherLockFromDpcLevel(); 00511 00512 /* Release the process lock */ 00513 KiReleaseProcessLockFromDpcLevel(&ProcessLock); 00514 KiExitDispatcher(ProcessLock.OldIrql); 00515 00516 /* Return previous priority */ 00517 return OldPriority; 00518 } 00519 00520 /* PUBLIC FUNCTIONS **********************************************************/ 00521 00522 /* 00523 * @implemented 00524 */ 00525 VOID 00526 NTAPI 00527 KeAttachProcess(IN PKPROCESS Process) 00528 { 00529 KLOCK_QUEUE_HANDLE ApcLock; 00530 PKTHREAD Thread = KeGetCurrentThread(); 00531 ASSERT_PROCESS(Process); 00532 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 00533 00534 /* Check if we're already in that process */ 00535 if (Thread->ApcState.Process == Process) return; 00536 00537 /* Check if a DPC is executing or if we're already attached */ 00538 if ((Thread->ApcStateIndex != OriginalApcEnvironment) || 00539 (KeIsExecutingDpc())) 00540 { 00541 /* Invalid attempt */ 00542 KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT, 00543 (ULONG_PTR)Process, 00544 (ULONG_PTR)Thread->ApcState.Process, 00545 Thread->ApcStateIndex, 00546 KeIsExecutingDpc()); 00547 } 00548 else 00549 { 00550 /* Acquire APC Lock */ 00551 KiAcquireApcLock(Thread, &ApcLock); 00552 00553 /* Acquire the dispatcher lock */ 00554 KiAcquireDispatcherLockAtDpcLevel(); 00555 00556 /* Legit attach attempt: do it! */ 00557 KiAttachProcess(Thread, Process, &ApcLock, &Thread->SavedApcState); 00558 } 00559 } 00560 00561 /* 00562 * @implemented 00563 */ 00564 VOID 00565 NTAPI 00566 KeDetachProcess(VOID) 00567 { 00568 PKTHREAD Thread = KeGetCurrentThread(); 00569 KLOCK_QUEUE_HANDLE ApcLock; 00570 PKPROCESS Process; 00571 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 00572 00573 /* Check if it's attached */ 00574 if (Thread->ApcStateIndex == OriginalApcEnvironment) return; 00575 00576 /* Acquire APC Lock */ 00577 KiAcquireApcLock(Thread, &ApcLock); 00578 00579 /* Check for invalid attach attempts */ 00580 if ((Thread->ApcState.KernelApcInProgress) || 00581 !(IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) || 00582 !(IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) 00583 { 00584 /* Crash the system */ 00585 KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT); 00586 } 00587 00588 /* Get the process */ 00589 Process = Thread->ApcState.Process; 00590 00591 /* Acquire dispatcher lock */ 00592 KiAcquireDispatcherLockAtDpcLevel(); 00593 00594 /* Decrease the stack count */ 00595 ASSERT(Process->StackCount != 0); 00596 ASSERT(Process->State == ProcessInMemory); 00597 Process->StackCount--; 00598 00599 /* Check if we can swap the process out */ 00600 if (!Process->StackCount) 00601 { 00602 /* FIXME: Swap the process out */ 00603 } 00604 00605 /* Release dispatcher lock */ 00606 KiReleaseDispatcherLockFromDpcLevel(); 00607 00608 /* Restore the APC State */ 00609 KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState); 00610 Thread->SavedApcState.Process = NULL; 00611 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState; 00612 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState; 00613 Thread->ApcStateIndex = OriginalApcEnvironment; 00614 00615 /* Release lock */ 00616 KiReleaseApcLockFromDpcLevel(&ApcLock); 00617 00618 /* Swap Processes */ 00619 KiSwapProcess(Thread->ApcState.Process, Process); 00620 00621 /* Exit the dispatcher */ 00622 KiExitDispatcher(ApcLock.OldIrql); 00623 00624 /* Check if we have pending APCs */ 00625 if (!(IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]))) 00626 { 00627 /* What do you know, we do! Request them to be delivered */ 00628 Thread->ApcState.KernelApcPending = TRUE; 00629 HalRequestSoftwareInterrupt(APC_LEVEL); 00630 } 00631 } 00632 00633 /* 00634 * @implemented 00635 */ 00636 BOOLEAN 00637 NTAPI 00638 KeIsAttachedProcess(VOID) 00639 { 00640 /* Return the APC State */ 00641 return KeGetCurrentThread()->ApcStateIndex; 00642 } 00643 00644 /* 00645 * @implemented 00646 */ 00647 VOID 00648 NTAPI 00649 KeStackAttachProcess(IN PKPROCESS Process, 00650 OUT PRKAPC_STATE ApcState) 00651 { 00652 KLOCK_QUEUE_HANDLE ApcLock; 00653 PKTHREAD Thread = KeGetCurrentThread(); 00654 ASSERT_PROCESS(Process); 00655 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 00656 00657 /* Crash system if DPC is being executed! */ 00658 if (KeIsExecutingDpc()) 00659 { 00660 /* Executing a DPC, crash! */ 00661 KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT, 00662 (ULONG_PTR)Process, 00663 (ULONG_PTR)Thread->ApcState.Process, 00664 Thread->ApcStateIndex, 00665 KeIsExecutingDpc()); 00666 } 00667 00668 /* Check if we are already in the target process */ 00669 if (Thread->ApcState.Process == Process) 00670 { 00671 /* Set magic value so we don't crash later when detaching */ 00672 ApcState->Process = (PKPROCESS)1; 00673 return; 00674 } 00675 00676 /* Acquire APC Lock */ 00677 KiAcquireApcLock(Thread, &ApcLock); 00678 00679 /* Acquire dispatcher lock */ 00680 KiAcquireDispatcherLockAtDpcLevel(); 00681 00682 /* Check if the Current Thread is already attached */ 00683 if (Thread->ApcStateIndex != OriginalApcEnvironment) 00684 { 00685 /* We're already attached, so save the APC State into what we got */ 00686 KiAttachProcess(Thread, Process, &ApcLock, ApcState); 00687 } 00688 else 00689 { 00690 /* We're not attached, so save the APC State into SavedApcState */ 00691 KiAttachProcess(Thread, Process, &ApcLock, &Thread->SavedApcState); 00692 ApcState->Process = NULL; 00693 } 00694 } 00695 00696 /* 00697 * @implemented 00698 */ 00699 VOID 00700 NTAPI 00701 KeUnstackDetachProcess(IN PRKAPC_STATE ApcState) 00702 { 00703 KLOCK_QUEUE_HANDLE ApcLock; 00704 PKTHREAD Thread = KeGetCurrentThread(); 00705 PKPROCESS Process; 00706 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 00707 00708 /* Check for magic value meaning we were already in the same process */ 00709 if (ApcState->Process == (PKPROCESS)1) return; 00710 00711 /* Loop to make sure no APCs are pending */ 00712 for (;;) 00713 { 00714 /* Acquire APC Lock */ 00715 KiAcquireApcLock(Thread, &ApcLock); 00716 00717 /* Check if a kernel APC is pending */ 00718 if (Thread->ApcState.KernelApcPending) 00719 { 00720 /* Check if kernel APC should be delivered */ 00721 if (!(Thread->KernelApcDisable) && (ApcLock.OldIrql <= APC_LEVEL)) 00722 { 00723 /* Release the APC lock so that the APC can be delivered */ 00724 KiReleaseApcLock(&ApcLock); 00725 continue; 00726 } 00727 } 00728 00729 /* Otherwise, break out */ 00730 break; 00731 } 00732 00733 /* 00734 * Check if the process isn't attacked, or has a Kernel APC in progress 00735 * or has pending APC of any kind. 00736 */ 00737 if ((Thread->ApcStateIndex == OriginalApcEnvironment) || 00738 (Thread->ApcState.KernelApcInProgress) || 00739 (!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) || 00740 (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) 00741 { 00742 /* Bugcheck the system */ 00743 KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT); 00744 } 00745 00746 /* Get the process */ 00747 Process = Thread->ApcState.Process; 00748 00749 /* Acquire dispatcher lock */ 00750 KiAcquireDispatcherLockAtDpcLevel(); 00751 00752 /* Decrease the stack count */ 00753 ASSERT(Process->StackCount != 0); 00754 ASSERT(Process->State == ProcessInMemory); 00755 Process->StackCount--; 00756 00757 /* Check if we can swap the process out */ 00758 if (!Process->StackCount) 00759 { 00760 /* FIXME: Swap the process out */ 00761 } 00762 00763 /* Release dispatcher lock */ 00764 KiReleaseDispatcherLockFromDpcLevel(); 00765 00766 /* Check if there's an APC state to restore */ 00767 if (ApcState->Process) 00768 { 00769 /* Restore the APC State */ 00770 KiMoveApcState(ApcState, &Thread->ApcState); 00771 } 00772 else 00773 { 00774 /* The ApcState parameter is useless, so use the saved data and reset it */ 00775 KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState); 00776 Thread->SavedApcState.Process = NULL; 00777 Thread->ApcStateIndex = OriginalApcEnvironment; 00778 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState; 00779 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState; 00780 } 00781 00782 /* Release lock */ 00783 KiReleaseApcLockFromDpcLevel(&ApcLock); 00784 00785 /* Swap Processes */ 00786 KiSwapProcess(Thread->ApcState.Process, Process); 00787 00788 /* Exit the dispatcher */ 00789 KiExitDispatcher(ApcLock.OldIrql); 00790 00791 /* Check if we have pending APCs */ 00792 if (!(IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]))) 00793 { 00794 /* What do you know, we do! Request them to be delivered */ 00795 Thread->ApcState.KernelApcPending = TRUE; 00796 HalRequestSoftwareInterrupt(APC_LEVEL); 00797 } 00798 } 00799 00800 /* 00801 * @implemented 00802 */ 00803 ULONG 00804 NTAPI 00805 KeQueryRuntimeProcess(IN PKPROCESS Process, 00806 OUT PULONG UserTime) 00807 { 00808 ULONG TotalUser, TotalKernel; 00809 KLOCK_QUEUE_HANDLE ProcessLock; 00810 PLIST_ENTRY NextEntry, ListHead; 00811 PKTHREAD Thread; 00812 00813 ASSERT_PROCESS(Process); 00814 00815 /* Initialize user and kernel times */ 00816 TotalUser = Process->UserTime; 00817 TotalKernel = Process->KernelTime; 00818 00819 /* Lock the process */ 00820 KiAcquireProcessLock(Process, &ProcessLock); 00821 00822 /* Loop all child threads and sum up their times */ 00823 ListHead = &Process->ThreadListHead; 00824 NextEntry = ListHead->Flink; 00825 while (ListHead != NextEntry) 00826 { 00827 /* Get the thread */ 00828 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry); 00829 00830 /* Sum up times */ 00831 TotalKernel += Thread->KernelTime; 00832 TotalUser += Thread->UserTime; 00833 00834 /* Go to the next one */ 00835 NextEntry = NextEntry->Flink; 00836 } 00837 00838 /* Release lock */ 00839 KiReleaseProcessLock(&ProcessLock); 00840 00841 /* Return the user time */ 00842 *UserTime = TotalUser; 00843 00844 /* Return the kernel time */ 00845 return TotalKernel; 00846 } 00847 00848 /* 00849 * @implemented 00850 */ 00851 BOOLEAN 00852 NTAPI 00853 KeAddSystemServiceTable(IN PULONG_PTR Base, 00854 IN PULONG Count OPTIONAL, 00855 IN ULONG Limit, 00856 IN PUCHAR Number, 00857 IN ULONG Index) 00858 { 00859 PAGED_CODE(); 00860 00861 /* Check if descriptor table entry is free */ 00862 if ((Index > SSDT_MAX_ENTRIES - 1) || 00863 (KeServiceDescriptorTable[Index].Base) || 00864 (KeServiceDescriptorTableShadow[Index].Base)) 00865 { 00866 /* It's not, fail */ 00867 return FALSE; 00868 } 00869 00870 /* Initialize the shadow service descriptor table */ 00871 KeServiceDescriptorTableShadow[Index].Base = Base; 00872 KeServiceDescriptorTableShadow[Index].Limit = Limit; 00873 KeServiceDescriptorTableShadow[Index].Number = Number; 00874 KeServiceDescriptorTableShadow[Index].Count = Count; 00875 return TRUE; 00876 } 00877 00878 /* 00879 * @implemented 00880 */ 00881 BOOLEAN 00882 NTAPI 00883 KeRemoveSystemServiceTable(IN ULONG Index) 00884 { 00885 PAGED_CODE(); 00886 00887 /* Make sure the Index is valid */ 00888 if (Index > (SSDT_MAX_ENTRIES - 1)) return FALSE; 00889 00890 /* Is there a Normal Descriptor Table? */ 00891 if (!KeServiceDescriptorTable[Index].Base) 00892 { 00893 /* Not with the index, is there a shadow at least? */ 00894 if (!KeServiceDescriptorTableShadow[Index].Base) return FALSE; 00895 } 00896 00897 /* Now clear from the Shadow Table. */ 00898 KeServiceDescriptorTableShadow[Index].Base = NULL; 00899 KeServiceDescriptorTableShadow[Index].Number = NULL; 00900 KeServiceDescriptorTableShadow[Index].Limit = 0; 00901 KeServiceDescriptorTableShadow[Index].Count = NULL; 00902 00903 /* Check if we should clean from the Master one too */ 00904 if (Index == 1) 00905 { 00906 KeServiceDescriptorTable[Index].Base = NULL; 00907 KeServiceDescriptorTable[Index].Number = NULL; 00908 KeServiceDescriptorTable[Index].Limit = 0; 00909 KeServiceDescriptorTable[Index].Count = NULL; 00910 } 00911 00912 /* Return success */ 00913 return TRUE; 00914 } 00915 /* EOF */ Generated on Thu May 24 2012 04:37:53 for ReactOS by
1.7.6.1
|