2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/procobj.c
5 * PURPOSE: Kernel Process Management and System Call Tables
6 * PROGRAMMERS: Alex Ionescu
10 /* INCLUDES ******************************************************************/
16 /* GLOBALS *******************************************************************/
18 LIST_ENTRY KiProcessListHead
;
19 LIST_ENTRY KiProcessInSwapListHead
, KiProcessOutSwapListHead
;
20 LIST_ENTRY KiStackInSwapListHead
;
23 KSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable
[SSDT_MAX_ENTRIES
];
24 KSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTableShadow
[SSDT_MAX_ENTRIES
];
26 PVOID KeUserApcDispatcher
;
27 PVOID KeUserCallbackDispatcher
;
28 PVOID KeUserExceptionDispatcher
;
29 PVOID KeRaiseUserExceptionDispatcher
;
31 /* PRIVATE FUNCTIONS *********************************************************/
35 KiAttachProcess(IN PKTHREAD Thread
,
37 IN PKLOCK_QUEUE_HANDLE ApcLock
,
38 IN PRKAPC_STATE SavedApcState
)
41 PLIST_ENTRY ListHead
, NextEntry
;
42 PKTHREAD CurrentThread
;
44 ASSERT(Process
!= Thread
->ApcState
.Process
);
46 /* Increase Stack Count */
47 ASSERT(Process
->StackCount
!= MAXULONG_PTR
);
48 Process
->StackCount
++;
50 /* Swap the APC Environment */
51 KiMoveApcState(&Thread
->ApcState
, SavedApcState
);
53 /* Reinitialize Apc State */
54 InitializeListHead(&Thread
->ApcState
.ApcListHead
[KernelMode
]);
55 InitializeListHead(&Thread
->ApcState
.ApcListHead
[UserMode
]);
56 Thread
->ApcState
.Process
= Process
;
57 Thread
->ApcState
.KernelApcInProgress
= FALSE
;
58 Thread
->ApcState
.KernelApcPending
= FALSE
;
59 Thread
->ApcState
.UserApcPending
= FALSE
;
61 /* Update Environment Pointers if needed*/
62 if (SavedApcState
== &Thread
->SavedApcState
)
64 Thread
->ApcStatePointer
[OriginalApcEnvironment
] = &Thread
->
66 Thread
->ApcStatePointer
[AttachedApcEnvironment
] = &Thread
->ApcState
;
67 Thread
->ApcStateIndex
= AttachedApcEnvironment
;
70 /* Check if the process is paged in */
71 if (Process
->State
== ProcessInMemory
)
73 /* Scan the ready list */
75 ListHead
= &Process
->ReadyListHead
;
76 NextEntry
= ListHead
->Flink
;
77 while (NextEntry
!= ListHead
)
80 CurrentThread
= CONTAINING_RECORD(NextEntry
, KTHREAD
, WaitListEntry
);
83 RemoveEntryList(NextEntry
);
84 CurrentThread
->ProcessReadyQueue
= FALSE
;
87 KiReadyThread(CurrentThread
);
89 /* Go to the next one */
90 NextEntry
= ListHead
->Flink
;
94 /* Release dispatcher lock */
95 KiReleaseDispatcherLockFromDpcLevel();
98 KiReleaseApcLockFromDpcLevel(ApcLock
);
101 KiSwapProcess(Process
, SavedApcState
->Process
);
103 /* Exit the dispatcher */
104 KiExitDispatcher(ApcLock
->OldIrql
);
108 DPRINT1("Errr. ReactOS doesn't support paging out processes yet...\n");
115 KeInitializeProcess(IN OUT PKPROCESS Process
,
116 IN KPRIORITY Priority
,
117 IN KAFFINITY Affinity
,
118 IN PULONG_PTR DirectoryTableBase
,
127 /* Initialize the Dispatcher Header */
128 Process
->Header
.Type
= ProcessObject
;
129 Process
->Header
.Size
= sizeof(KPROCESS
) / sizeof(ULONG
);
130 Process
->Header
.SignalState
= 0;
131 InitializeListHead(&(Process
->Header
.WaitListHead
));
133 /* Initialize Scheduler Data, Alignment Faults and Set the PDE */
134 Process
->Affinity
= Affinity
;
135 Process
->BasePriority
= (CHAR
)Priority
;
136 Process
->QuantumReset
= 6;
137 Process
->DirectoryTableBase
[0] = DirectoryTableBase
[0];
138 Process
->DirectoryTableBase
[1] = DirectoryTableBase
[1];
139 Process
->AutoAlignment
= Enable
;
141 Process
->IopmOffset
= KiComputeIopmOffset(IO_ACCESS_MAP_NONE
);
144 /* Initialize the lists */
145 InitializeListHead(&Process
->ThreadListHead
);
146 InitializeListHead(&Process
->ProfileListHead
);
147 InitializeListHead(&Process
->ReadyListHead
);
149 /* Initialize the current State */
150 Process
->State
= ProcessInMemory
;
152 /* Check how many Nodes there are on the system */
154 if (KeNumberNodes
> 1)
156 /* Set the new seed */
157 KeProcessNodeSeed
= (KeProcessNodeSeed
+ 1) / KeNumberNodes
;
158 IdealNode
= KeProcessNodeSeed
;
160 /* Loop every node */
163 /* Check if the affinity matches */
164 if (KeNodeBlock
[IdealNode
]->ProcessorMask
!= Affinity
) break;
166 /* No match, try next Ideal Node and increase node loop index */
170 /* Check if the Ideal Node is beyond the total number of nodes */
171 if (IdealNode
>= KeNumberNodes
)
173 /* Normalize the Ideal Node */
174 IdealNode
-= KeNumberNodes
;
176 } while (i
< KeNumberNodes
);
179 /* Set the ideal node and get the ideal node block */
180 Process
->IdealNode
= IdealNode
;
181 Node
= KeNodeBlock
[IdealNode
];
182 ASSERT(Node
->ProcessorMask
& Affinity
);
184 /* Find the matching affinity set to calculate the thread seed */
185 Affinity
&= Node
->ProcessorMask
;
186 Process
->ThreadSeed
= KeFindNextRightSetAffinity(Node
->Seed
,
188 Node
->Seed
= Process
->ThreadSeed
;
194 KeSetProcess(IN PKPROCESS Process
,
195 IN KPRIORITY Increment
,
200 ASSERT_PROCESS(Process
);
201 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
203 /* Lock Dispatcher */
204 OldIrql
= KiAcquireDispatcherLock();
207 OldState
= Process
->Header
.SignalState
;
209 /* Signal the Process */
210 Process
->Header
.SignalState
= TRUE
;
212 /* Check if was unsignaled and has waiters */
214 !(IsListEmpty(&Process
->Header
.WaitListHead
)))
216 /* Unwait the threads */
217 KxUnwaitThread(&Process
->Header
, Increment
);
220 /* Release Dispatcher Database */
221 KiReleaseDispatcherLock(OldIrql
);
223 /* Return the previous State */
229 KeSetQuantumProcess(IN PKPROCESS Process
,
232 KLOCK_QUEUE_HANDLE ProcessLock
;
233 PLIST_ENTRY NextEntry
, ListHead
;
235 ASSERT_PROCESS(Process
);
236 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
238 /* Lock the process */
239 KiAcquireProcessLock(Process
, &ProcessLock
);
241 /* Set new quantum */
242 Process
->QuantumReset
= Quantum
;
244 /* Loop all child threads */
245 ListHead
= &Process
->ThreadListHead
;
246 NextEntry
= ListHead
->Flink
;
247 while (ListHead
!= NextEntry
)
250 Thread
= CONTAINING_RECORD(NextEntry
, KTHREAD
, ThreadListEntry
);
253 Thread
->QuantumReset
= Quantum
;
255 /* Go to the next one */
256 NextEntry
= NextEntry
->Flink
;
260 KiReleaseProcessLock(&ProcessLock
);
265 KeSetAffinityProcess(IN PKPROCESS Process
,
266 IN KAFFINITY Affinity
)
269 KLOCK_QUEUE_HANDLE ProcessLock
;
270 PLIST_ENTRY NextEntry
, ListHead
;
271 KAFFINITY OldAffinity
;
273 ASSERT_PROCESS(Process
);
274 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL
);
275 ASSERT((Affinity
& KeActiveProcessors
) != 0);
277 /* Lock the process */
278 KiAcquireProcessLock(Process
, &ProcessLock
);
280 /* Acquire the dispatcher lock */
281 KiAcquireDispatcherLockAtDpcLevel();
283 /* Capture old affinity and update it */
284 OldAffinity
= Process
->Affinity
;
285 Process
->Affinity
= Affinity
;
287 /* Loop all child threads */
288 ListHead
= &Process
->ThreadListHead
;
289 NextEntry
= ListHead
->Flink
;
290 while (ListHead
!= NextEntry
)
293 Thread
= CONTAINING_RECORD(NextEntry
, KTHREAD
, ThreadListEntry
);
295 /* Set affinity on it */
296 KiSetAffinityThread(Thread
, Affinity
);
297 NextEntry
= NextEntry
->Flink
;
300 /* Release Dispatcher Database */
301 KiReleaseDispatcherLockFromDpcLevel();
303 /* Release the process lock */
304 KiReleaseProcessLockFromDpcLevel(&ProcessLock
);
305 KiExitDispatcher(ProcessLock
.OldIrql
);
307 /* Return previous affinity */
313 KeSetAutoAlignmentProcess(IN PKPROCESS Process
,
316 /* Set or reset the bit depending on what the enable flag says */
319 return InterlockedBitTestAndSet(&Process
->ProcessFlags
,
320 KPSF_AUTO_ALIGNMENT_BIT
);
324 return InterlockedBitTestAndReset(&Process
->ProcessFlags
,
325 KPSF_AUTO_ALIGNMENT_BIT
);
331 KeSetDisableBoostProcess(IN PKPROCESS Process
,
334 /* Set or reset the bit depending on what the disable flag says */
337 return InterlockedBitTestAndSet(&Process
->ProcessFlags
,
338 KPSF_DISABLE_BOOST_BIT
);
342 return InterlockedBitTestAndReset(&Process
->ProcessFlags
,
343 KPSF_DISABLE_BOOST_BIT
);
349 KeSetPriorityAndQuantumProcess(IN PKPROCESS Process
,
350 IN KPRIORITY Priority
,
351 IN UCHAR Quantum OPTIONAL
)
353 KLOCK_QUEUE_HANDLE ProcessLock
;
355 PLIST_ENTRY NextEntry
, ListHead
;
356 KPRIORITY NewPriority
, OldPriority
;
358 ASSERT_PROCESS(Process
);
359 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
361 /* Check if the process already has this priority */
362 if (Process
->BasePriority
== Priority
) return Process
->BasePriority
;
364 /* If the caller gave priority 0, normalize to 1 */
365 if (!Priority
) Priority
= LOW_PRIORITY
+ 1;
367 /* Lock the process */
368 KiAcquireProcessLock(Process
, &ProcessLock
);
370 /* Check if we are modifying the quantum too */
371 if (Quantum
) Process
->QuantumReset
= Quantum
;
373 /* Save the current base priority and update it */
374 OldPriority
= Process
->BasePriority
;
375 Process
->BasePriority
= (SCHAR
)Priority
;
377 /* Calculate the priority delta */
378 Delta
= Priority
- OldPriority
;
380 /* Set the list head and list entry */
381 ListHead
= &Process
->ThreadListHead
;
382 NextEntry
= ListHead
->Flink
;
384 /* Check if this is a real-time priority */
385 if (Priority
>= LOW_REALTIME_PRIORITY
)
387 /* Loop the thread list */
388 while (NextEntry
!= ListHead
)
391 Thread
= CONTAINING_RECORD(NextEntry
, KTHREAD
, ThreadListEntry
);
393 /* Update the quantum if we had one */
394 if (Quantum
) Thread
->QuantumReset
= Quantum
;
396 /* Acquire the thread lock */
397 KiAcquireThreadLock(Thread
);
399 /* Calculate the new priority */
400 NewPriority
= Thread
->BasePriority
+ Delta
;
401 if (NewPriority
< LOW_REALTIME_PRIORITY
)
403 /* We're in real-time range, don't let it go below */
404 NewPriority
= LOW_REALTIME_PRIORITY
;
406 else if (NewPriority
> HIGH_PRIORITY
)
408 /* We're going beyond the maximum priority, normalize */
409 NewPriority
= HIGH_PRIORITY
;
413 * If priority saturation occured or the old priority was still in
414 * the real-time range, don't do anything.
416 if (!(Thread
->Saturation
) || (OldPriority
< LOW_REALTIME_PRIORITY
))
418 /* Check if we had priority saturation */
419 if (Thread
->Saturation
> 0)
421 /* Boost priority to maximum */
422 NewPriority
= HIGH_PRIORITY
;
424 else if (Thread
->Saturation
< 0)
426 /* If we had negative saturation, set minimum priority */
427 NewPriority
= LOW_REALTIME_PRIORITY
;
430 /* Update priority and quantum */
431 Thread
->BasePriority
= (SCHAR
)NewPriority
;
432 Thread
->Quantum
= Thread
->QuantumReset
;
434 /* Disable decrements and update priority */
435 Thread
->PriorityDecrement
= 0;
436 KiSetPriorityThread(Thread
, NewPriority
);
439 /* Release the thread lock */
440 KiReleaseThreadLock(Thread
);
442 /* Go to the next thread */
443 NextEntry
= NextEntry
->Flink
;
448 /* Loop the thread list */
449 while (NextEntry
!= ListHead
)
452 Thread
= CONTAINING_RECORD(NextEntry
, KTHREAD
, ThreadListEntry
);
454 /* Update the quantum if we had one */
455 if (Quantum
) Thread
->QuantumReset
= Quantum
;
457 /* Lock the thread */
458 KiAcquireThreadLock(Thread
);
460 /* Calculate the new priority */
461 NewPriority
= Thread
->BasePriority
+ Delta
;
462 if (NewPriority
>= LOW_REALTIME_PRIORITY
)
464 /* We're not real-time range, don't let it enter RT range */
465 NewPriority
= LOW_REALTIME_PRIORITY
- 1;
467 else if (NewPriority
<= LOW_PRIORITY
)
469 /* We're going below the minimum priority, normalize */
474 * If priority saturation occured or the old priority was still in
475 * the real-time range, don't do anything.
477 if (!(Thread
->Saturation
) ||
478 (OldPriority
>= LOW_REALTIME_PRIORITY
))
480 /* Check if we had priority saturation */
481 if (Thread
->Saturation
> 0)
483 /* Boost priority to maximum */
484 NewPriority
= LOW_REALTIME_PRIORITY
- 1;
486 else if (Thread
->Saturation
< 0)
488 /* If we had negative saturation, set minimum priority */
492 /* Update priority and quantum */
493 Thread
->BasePriority
= (SCHAR
)NewPriority
;
494 Thread
->Quantum
= Thread
->QuantumReset
;
496 /* Disable decrements and update priority */
497 Thread
->PriorityDecrement
= 0;
498 KiSetPriorityThread(Thread
, NewPriority
);
501 /* Release the thread lock */
502 KiReleaseThreadLock(Thread
);
504 /* Go to the next thread */
505 NextEntry
= NextEntry
->Flink
;
509 /* Release Dispatcher Database */
510 KiReleaseDispatcherLockFromDpcLevel();
512 /* Release the process lock */
513 KiReleaseProcessLockFromDpcLevel(&ProcessLock
);
514 KiExitDispatcher(ProcessLock
.OldIrql
);
516 /* Return previous priority */
522 KeQueryValuesProcess(IN PKPROCESS Process
,
523 PPROCESS_VALUES Values
)
526 PLIST_ENTRY NextEntry
;
527 ULONG TotalKernel
, TotalUser
;
528 KLOCK_QUEUE_HANDLE ProcessLock
;
530 ASSERT_PROCESS(Process
);
531 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL
);
533 /* Lock the process */
534 KiAcquireProcessLock(Process
, &ProcessLock
);
536 /* Initialize user and kernel times */
537 TotalKernel
= Process
->KernelTime
;
538 TotalUser
= Process
->UserTime
;
540 /* Copy the IO_COUNTERS from the process */
541 EProcess
= (PEPROCESS
)Process
;
542 Values
->IoInfo
.ReadOperationCount
= EProcess
->ReadOperationCount
.QuadPart
;
543 Values
->IoInfo
.WriteOperationCount
= EProcess
->WriteOperationCount
.QuadPart
;
544 Values
->IoInfo
.OtherOperationCount
= EProcess
->OtherOperationCount
.QuadPart
;
545 Values
->IoInfo
.ReadTransferCount
= EProcess
->ReadTransferCount
.QuadPart
;
546 Values
->IoInfo
.WriteTransferCount
= EProcess
->WriteTransferCount
.QuadPart
;
547 Values
->IoInfo
.OtherTransferCount
= EProcess
->OtherTransferCount
.QuadPart
;
549 /* Loop all child threads and sum up their times */
550 for (NextEntry
= Process
->ThreadListHead
.Flink
;
551 NextEntry
!= &Process
->ThreadListHead
;
552 NextEntry
= NextEntry
->Flink
)
557 Thread
= CONTAINING_RECORD(NextEntry
, KTHREAD
, ThreadListEntry
);
560 TotalKernel
+= Thread
->KernelTime
;
561 TotalUser
+= Thread
->UserTime
;
564 /* Release the process lock */
565 KiReleaseProcessLock(&ProcessLock
);
567 /* Compute total times */
568 Values
->TotalKernelTime
.QuadPart
= TotalKernel
* (LONGLONG
)KeMaximumIncrement
;
569 Values
->TotalUserTime
.QuadPart
= TotalUser
* (LONGLONG
)KeMaximumIncrement
;
572 /* PUBLIC FUNCTIONS **********************************************************/
579 KeAttachProcess(IN PKPROCESS Process
)
581 KLOCK_QUEUE_HANDLE ApcLock
;
582 PKTHREAD Thread
= KeGetCurrentThread();
583 ASSERT_PROCESS(Process
);
584 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
586 /* Check if we're already in that process */
587 if (Thread
->ApcState
.Process
== Process
) return;
589 /* Check if a DPC is executing or if we're already attached */
590 if ((Thread
->ApcStateIndex
!= OriginalApcEnvironment
) ||
591 (KeIsExecutingDpc()))
593 /* Invalid attempt */
594 KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT
,
596 (ULONG_PTR
)Thread
->ApcState
.Process
,
597 Thread
->ApcStateIndex
,
602 /* Acquire APC Lock */
603 KiAcquireApcLock(Thread
, &ApcLock
);
605 /* Acquire the dispatcher lock */
606 KiAcquireDispatcherLockAtDpcLevel();
608 /* Legit attach attempt: do it! */
609 KiAttachProcess(Thread
, Process
, &ApcLock
, &Thread
->SavedApcState
);
618 KeDetachProcess(VOID
)
620 PKTHREAD Thread
= KeGetCurrentThread();
621 KLOCK_QUEUE_HANDLE ApcLock
;
623 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
625 /* Check if it's attached */
626 if (Thread
->ApcStateIndex
== OriginalApcEnvironment
) return;
628 /* Acquire APC Lock */
629 KiAcquireApcLock(Thread
, &ApcLock
);
631 /* Check for invalid attach attempts */
632 if ((Thread
->ApcState
.KernelApcInProgress
) ||
633 !(IsListEmpty(&Thread
->ApcState
.ApcListHead
[KernelMode
])) ||
634 !(IsListEmpty(&Thread
->ApcState
.ApcListHead
[UserMode
])))
636 /* Crash the system */
637 KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT
);
640 /* Get the process */
641 Process
= Thread
->ApcState
.Process
;
643 /* Acquire dispatcher lock */
644 KiAcquireDispatcherLockAtDpcLevel();
646 /* Decrease the stack count */
647 ASSERT(Process
->StackCount
!= 0);
648 ASSERT(Process
->State
== ProcessInMemory
);
649 Process
->StackCount
--;
651 /* Check if we can swap the process out */
652 if (!Process
->StackCount
)
654 /* FIXME: Swap the process out */
657 /* Release dispatcher lock */
658 KiReleaseDispatcherLockFromDpcLevel();
660 /* Restore the APC State */
661 KiMoveApcState(&Thread
->SavedApcState
, &Thread
->ApcState
);
662 Thread
->SavedApcState
.Process
= NULL
;
663 Thread
->ApcStatePointer
[OriginalApcEnvironment
] = &Thread
->ApcState
;
664 Thread
->ApcStatePointer
[AttachedApcEnvironment
] = &Thread
->SavedApcState
;
665 Thread
->ApcStateIndex
= OriginalApcEnvironment
;
668 KiReleaseApcLockFromDpcLevel(&ApcLock
);
671 KiSwapProcess(Thread
->ApcState
.Process
, Process
);
673 /* Exit the dispatcher */
674 KiExitDispatcher(ApcLock
.OldIrql
);
676 /* Check if we have pending APCs */
677 if (!(IsListEmpty(&Thread
->ApcState
.ApcListHead
[KernelMode
])))
679 /* What do you know, we do! Request them to be delivered */
680 Thread
->ApcState
.KernelApcPending
= TRUE
;
681 HalRequestSoftwareInterrupt(APC_LEVEL
);
690 KeIsAttachedProcess(VOID
)
692 /* Return the APC State */
693 return KeGetCurrentThread()->ApcStateIndex
;
701 KeStackAttachProcess(IN PKPROCESS Process
,
702 OUT PRKAPC_STATE ApcState
)
704 KLOCK_QUEUE_HANDLE ApcLock
;
705 PKTHREAD Thread
= KeGetCurrentThread();
706 ASSERT_PROCESS(Process
);
707 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
709 /* Crash system if DPC is being executed! */
710 if (KeIsExecutingDpc())
712 /* Executing a DPC, crash! */
713 KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT
,
715 (ULONG_PTR
)Thread
->ApcState
.Process
,
716 Thread
->ApcStateIndex
,
720 /* Check if we are already in the target process */
721 if (Thread
->ApcState
.Process
== Process
)
723 /* Set magic value so we don't crash later when detaching */
724 ApcState
->Process
= (PKPROCESS
)1;
728 /* Acquire APC Lock */
729 KiAcquireApcLock(Thread
, &ApcLock
);
731 /* Acquire dispatcher lock */
732 KiAcquireDispatcherLockAtDpcLevel();
734 /* Check if the Current Thread is already attached */
735 if (Thread
->ApcStateIndex
!= OriginalApcEnvironment
)
737 /* We're already attached, so save the APC State into what we got */
738 KiAttachProcess(Thread
, Process
, &ApcLock
, ApcState
);
742 /* We're not attached, so save the APC State into SavedApcState */
743 KiAttachProcess(Thread
, Process
, &ApcLock
, &Thread
->SavedApcState
);
744 ApcState
->Process
= NULL
;
753 KeUnstackDetachProcess(IN PRKAPC_STATE ApcState
)
755 KLOCK_QUEUE_HANDLE ApcLock
;
756 PKTHREAD Thread
= KeGetCurrentThread();
758 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
760 /* Check for magic value meaning we were already in the same process */
761 if (ApcState
->Process
== (PKPROCESS
)1) return;
763 /* Loop to make sure no APCs are pending */
766 /* Acquire APC Lock */
767 KiAcquireApcLock(Thread
, &ApcLock
);
769 /* Check if a kernel APC is pending */
770 if (Thread
->ApcState
.KernelApcPending
)
772 /* Check if kernel APC should be delivered */
773 if (!(Thread
->KernelApcDisable
) && (ApcLock
.OldIrql
<= APC_LEVEL
))
775 /* Release the APC lock so that the APC can be delivered */
776 KiReleaseApcLock(&ApcLock
);
781 /* Otherwise, break out */
786 * Check if the process isn't attacked, or has a Kernel APC in progress
787 * or has pending APC of any kind.
789 if ((Thread
->ApcStateIndex
== OriginalApcEnvironment
) ||
790 (Thread
->ApcState
.KernelApcInProgress
) ||
791 (!IsListEmpty(&Thread
->ApcState
.ApcListHead
[KernelMode
])) ||
792 (!IsListEmpty(&Thread
->ApcState
.ApcListHead
[UserMode
])))
794 /* Bugcheck the system */
795 KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT
);
798 /* Get the process */
799 Process
= Thread
->ApcState
.Process
;
801 /* Acquire dispatcher lock */
802 KiAcquireDispatcherLockAtDpcLevel();
804 /* Decrease the stack count */
805 ASSERT(Process
->StackCount
!= 0);
806 ASSERT(Process
->State
== ProcessInMemory
);
807 Process
->StackCount
--;
809 /* Check if we can swap the process out */
810 if (!Process
->StackCount
)
812 /* FIXME: Swap the process out */
815 /* Release dispatcher lock */
816 KiReleaseDispatcherLockFromDpcLevel();
818 /* Check if there's an APC state to restore */
819 if (ApcState
->Process
)
821 /* Restore the APC State */
822 KiMoveApcState(ApcState
, &Thread
->ApcState
);
826 /* The ApcState parameter is useless, so use the saved data and reset it */
827 KiMoveApcState(&Thread
->SavedApcState
, &Thread
->ApcState
);
828 Thread
->SavedApcState
.Process
= NULL
;
829 Thread
->ApcStateIndex
= OriginalApcEnvironment
;
830 Thread
->ApcStatePointer
[OriginalApcEnvironment
] = &Thread
->ApcState
;
831 Thread
->ApcStatePointer
[AttachedApcEnvironment
] = &Thread
->SavedApcState
;
835 KiReleaseApcLockFromDpcLevel(&ApcLock
);
838 KiSwapProcess(Thread
->ApcState
.Process
, Process
);
840 /* Exit the dispatcher */
841 KiExitDispatcher(ApcLock
.OldIrql
);
843 /* Check if we have pending APCs */
844 if (!(IsListEmpty(&Thread
->ApcState
.ApcListHead
[KernelMode
])))
846 /* What do you know, we do! Request them to be delivered */
847 Thread
->ApcState
.KernelApcPending
= TRUE
;
848 HalRequestSoftwareInterrupt(APC_LEVEL
);
857 KeQueryRuntimeProcess(IN PKPROCESS Process
,
860 ULONG TotalUser
, TotalKernel
;
861 KLOCK_QUEUE_HANDLE ProcessLock
;
862 PLIST_ENTRY NextEntry
, ListHead
;
865 ASSERT_PROCESS(Process
);
867 /* Initialize user and kernel times */
868 TotalUser
= Process
->UserTime
;
869 TotalKernel
= Process
->KernelTime
;
871 /* Lock the process */
872 KiAcquireProcessLock(Process
, &ProcessLock
);
874 /* Loop all child threads and sum up their times */
875 ListHead
= &Process
->ThreadListHead
;
876 NextEntry
= ListHead
->Flink
;
877 while (ListHead
!= NextEntry
)
880 Thread
= CONTAINING_RECORD(NextEntry
, KTHREAD
, ThreadListEntry
);
883 TotalKernel
+= Thread
->KernelTime
;
884 TotalUser
+= Thread
->UserTime
;
886 /* Go to the next one */
887 NextEntry
= NextEntry
->Flink
;
891 KiReleaseProcessLock(&ProcessLock
);
893 /* Return the user time */
894 *UserTime
= TotalUser
;
896 /* Return the kernel time */
905 KeAddSystemServiceTable(IN PULONG_PTR Base
,
906 IN PULONG Count OPTIONAL
,
913 /* Check if descriptor table entry is free */
914 if ((Index
> SSDT_MAX_ENTRIES
- 1) ||
915 (KeServiceDescriptorTable
[Index
].Base
) ||
916 (KeServiceDescriptorTableShadow
[Index
].Base
))
922 /* Initialize the shadow service descriptor table */
923 KeServiceDescriptorTableShadow
[Index
].Base
= Base
;
924 KeServiceDescriptorTableShadow
[Index
].Limit
= Limit
;
925 KeServiceDescriptorTableShadow
[Index
].Number
= Number
;
926 KeServiceDescriptorTableShadow
[Index
].Count
= Count
;
935 KeRemoveSystemServiceTable(IN ULONG Index
)
939 /* Make sure the Index is valid */
940 if (Index
> (SSDT_MAX_ENTRIES
- 1)) return FALSE
;
942 /* Is there a Normal Descriptor Table? */
943 if (!KeServiceDescriptorTable
[Index
].Base
)
945 /* Not with the index, is there a shadow at least? */
946 if (!KeServiceDescriptorTableShadow
[Index
].Base
) return FALSE
;
949 /* Now clear from the Shadow Table. */
950 KeServiceDescriptorTableShadow
[Index
].Base
= NULL
;
951 KeServiceDescriptorTableShadow
[Index
].Number
= NULL
;
952 KeServiceDescriptorTableShadow
[Index
].Limit
= 0;
953 KeServiceDescriptorTableShadow
[Index
].Count
= NULL
;
955 /* Check if we should clean from the Master one too */
958 KeServiceDescriptorTable
[Index
].Base
= NULL
;
959 KeServiceDescriptorTable
[Index
].Number
= NULL
;
960 KeServiceDescriptorTable
[Index
].Limit
= 0;
961 KeServiceDescriptorTable
[Index
].Count
= NULL
;