[CMAKE/NTOSKRNL]
[reactos.git] / ntoskrnl / ke / procobj.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/process.c
5 * PURPOSE: Kernel Process Management and System Call Tables
6 * PROGRAMMERS: Alex Ionescu
7 * Gregor Anich
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS *******************************************************************/
17
18 LIST_ENTRY KiProcessListHead;
19 LIST_ENTRY KiProcessInSwapListHead, KiProcessOutSwapListHead;
20 LIST_ENTRY KiStackInSwapListHead;
21 KEVENT KiSwapEvent;
22
23 KSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable[SSDT_MAX_ENTRIES];
24 KSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTableShadow[SSDT_MAX_ENTRIES];
25
26 PVOID KeUserApcDispatcher;
27 PVOID KeUserCallbackDispatcher;
28 PVOID KeUserExceptionDispatcher;
29 PVOID KeRaiseUserExceptionDispatcher;
30
31 /* PRIVATE FUNCTIONS *********************************************************/
32
33 VOID
34 NTAPI
35 KiAttachProcess(IN PKTHREAD Thread,
36 IN PKPROCESS Process,
37 IN PKLOCK_QUEUE_HANDLE ApcLock,
38 IN PRKAPC_STATE SavedApcState)
39 {
40 #if 0
41 PLIST_ENTRY ListHead, NextEntry;
42 PKTHREAD CurrentThread;
43 #endif
44 ASSERT(Process != Thread->ApcState.Process);
45
46 /* Increase Stack Count */
47 ASSERT(Process->StackCount != MAXULONG_PTR);
48 Process->StackCount++;
49
50 /* Swap the APC Environment */
51 KiMoveApcState(&Thread->ApcState, SavedApcState);
52
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;
60
61 /* Update Environment Pointers if needed*/
62 if (SavedApcState == &Thread->SavedApcState)
63 {
64 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->
65 SavedApcState;
66 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->ApcState;
67 Thread->ApcStateIndex = AttachedApcEnvironment;
68 }
69
70 /* Check if the process is paged in */
71 if (Process->State == ProcessInMemory)
72 {
73 /* Scan the ready list */
74 #if 0
75 ListHead = &Process->ReadyListHead;
76 NextEntry = ListHead->Flink;
77 while (NextEntry != ListHead)
78 {
79 /* Get the thread */
80 CurrentThread = CONTAINING_RECORD(NextEntry, KTHREAD, WaitListEntry);
81
82 /* Remove it */
83 RemoveEntryList(NextEntry);
84 CurrentThread->ProcessReadyQueue = FALSE;
85
86 /* Mark it ready */
87 KiReadyThread(CurrentThread);
88
89 /* Go to the next one */
90 NextEntry = ListHead->Flink;
91 }
92 #endif
93
94 /* Release dispatcher lock */
95 KiReleaseDispatcherLockFromDpcLevel();
96
97 /* Release lock */
98 KiReleaseApcLockFromDpcLevel(ApcLock);
99
100 /* Swap Processes */
101 KiSwapProcess(Process, SavedApcState->Process);
102
103 /* Exit the dispatcher */
104 KiExitDispatcher(ApcLock->OldIrql);
105 }
106 else
107 {
108 DPRINT1("Errr. ReactOS doesn't support paging out processes yet...\n");
109 ASSERT(FALSE);
110 }
111 }
112
113 VOID
114 NTAPI
115 KeInitializeProcess(IN OUT PKPROCESS Process,
116 IN KPRIORITY Priority,
117 IN KAFFINITY Affinity,
118 IN PULONG DirectoryTableBase,
119 IN BOOLEAN Enable)
120 {
121 #ifdef CONFIG_SMP
122 ULONG i = 0;
123 UCHAR IdealNode = 0;
124 PKNODE Node;
125 #endif
126
127 /* Initialize the Dispatcher Header */
128 KeInitializeDispatcherHeader(&Process->Header,
129 ProcessObject,
130 sizeof(KPROCESS),
131 FALSE);
132
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;
140 #if defined(_M_IX86)
141 Process->IopmOffset = KiComputeIopmOffset(IO_ACCESS_MAP_NONE);
142 #endif
143
144 /* Initialize the lists */
145 InitializeListHead(&Process->ThreadListHead);
146 InitializeListHead(&Process->ProfileListHead);
147 InitializeListHead(&Process->ReadyListHead);
148
149 /* Initialize the current State */
150 Process->State = ProcessInMemory;
151
152 /* Check how many Nodes there are on the system */
153 #ifdef CONFIG_SMP
154 if (KeNumberNodes > 1)
155 {
156 /* Set the new seed */
157 KeProcessNodeSeed = (KeProcessNodeSeed + 1) / KeNumberNodes;
158 IdealNode = KeProcessNodeSeed;
159
160 /* Loop every node */
161 do
162 {
163 /* Check if the affinity matches */
164 if (KeNodeBlock[IdealNode]->ProcessorMask != Affinity) break;
165
166 /* No match, try next Ideal Node and increase node loop index */
167 IdealNode++;
168 i++;
169
170 /* Check if the Ideal Node is beyond the total number of nodes */
171 if (IdealNode >= KeNumberNodes)
172 {
173 /* Normalize the Ideal Node */
174 IdealNode -= KeNumberNodes;
175 }
176 } while (i < KeNumberNodes);
177 }
178
179 /* Set the ideal node and get the ideal node block */
180 Process->IdealNode = IdealNode;
181 Node = KeNodeBlock[IdealNode];
182 ASSERT(Node->ProcessorMask & Affinity);
183
184 /* Find the matching affinity set to calculate the thread seed */
185 Affinity &= Node->ProcessorMask;
186 Process->ThreadSeed = KeFindNextRightSetAffinity(Node->Seed,
187 (ULONG)Affinity);
188 Node->Seed = Process->ThreadSeed;
189 #endif
190 }
191
192 ULONG
193 NTAPI
194 KeSetProcess(IN PKPROCESS Process,
195 IN KPRIORITY Increment,
196 IN BOOLEAN InWait)
197 {
198 KIRQL OldIrql;
199 ULONG OldState;
200 ASSERT_PROCESS(Process);
201 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
202
203 /* Lock Dispatcher */
204 OldIrql = KiAcquireDispatcherLock();
205
206 /* Get Old State */
207 OldState = Process->Header.SignalState;
208
209 /* Signal the Process */
210 Process->Header.SignalState = TRUE;
211
212 /* Check if was unsignaled and has waiters */
213 if (!(OldState) &&
214 !(IsListEmpty(&Process->Header.WaitListHead)))
215 {
216 /* Unwait the threads */
217 KxUnwaitThread(&Process->Header, Increment);
218 }
219
220 /* Release Dispatcher Database */
221 KiReleaseDispatcherLock(OldIrql);
222
223 /* Return the previous State */
224 return OldState;
225 }
226
227 VOID
228 NTAPI
229 KeSetQuantumProcess(IN PKPROCESS Process,
230 IN UCHAR Quantum)
231 {
232 KLOCK_QUEUE_HANDLE ProcessLock;
233 PLIST_ENTRY NextEntry, ListHead;
234 PKTHREAD Thread;
235 ASSERT_PROCESS(Process);
236 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
237
238 /* Lock the process */
239 KiAcquireProcessLock(Process, &ProcessLock);
240
241 /* Set new quantum */
242 Process->QuantumReset = Quantum;
243
244 /* Loop all child threads */
245 ListHead = &Process->ThreadListHead;
246 NextEntry = ListHead->Flink;
247 while (ListHead != NextEntry)
248 {
249 /* Get the thread */
250 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry);
251
252 /* Set quantum */
253 Thread->QuantumReset = Quantum;
254
255 /* Go to the next one */
256 NextEntry = NextEntry->Flink;
257 }
258
259 /* Release lock */
260 KiReleaseProcessLock(&ProcessLock);
261 }
262
263 KPRIORITY
264 NTAPI
265 KeSetPriorityAndQuantumProcess(IN PKPROCESS Process,
266 IN KPRIORITY Priority,
267 IN UCHAR Quantum OPTIONAL)
268 {
269 KLOCK_QUEUE_HANDLE ProcessLock;
270 KPRIORITY Delta;
271 PLIST_ENTRY NextEntry, ListHead;
272 KPRIORITY NewPriority, OldPriority;
273 PKTHREAD Thread;
274 ASSERT_PROCESS(Process);
275 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
276
277 /* Check if the process already has this priority */
278 if (Process->BasePriority == Priority) return Process->BasePriority;
279
280 /* If the caller gave priority 0, normalize to 1 */
281 if (!Priority) Priority = LOW_PRIORITY + 1;
282
283 /* Lock the process */
284 KiAcquireProcessLock(Process, &ProcessLock);
285
286 /* Check if we are modifying the quantum too */
287 if (Quantum) Process->QuantumReset = Quantum;
288
289 /* Save the current base priority and update it */
290 OldPriority = Process->BasePriority;
291 Process->BasePriority = (SCHAR)Priority;
292
293 /* Calculate the priority delta */
294 Delta = Priority - OldPriority;
295
296 /* Set the list head and list entry */
297 ListHead = &Process->ThreadListHead;
298 NextEntry = ListHead->Flink;
299
300 /* Check if this is a real-time priority */
301 if (Priority >= LOW_REALTIME_PRIORITY)
302 {
303 /* Loop the thread list */
304 while (NextEntry != ListHead)
305 {
306 /* Get the thread */
307 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry);
308
309 /* Update the quantum if we had one */
310 if (Quantum) Thread->QuantumReset = Quantum;
311
312 /* Acquire the thread lock */
313 KiAcquireThreadLock(Thread);
314
315 /* Calculate the new priority */
316 NewPriority = Thread->BasePriority + Delta;
317 if (NewPriority < LOW_REALTIME_PRIORITY)
318 {
319 /* We're in real-time range, don't let it go below */
320 NewPriority = LOW_REALTIME_PRIORITY;
321 }
322 else if (NewPriority > HIGH_PRIORITY)
323 {
324 /* We're going beyond the maximum priority, normalize */
325 NewPriority = HIGH_PRIORITY;
326 }
327
328 /*
329 * If priority saturation occured or the old priority was still in
330 * the real-time range, don't do anything.
331 */
332 if (!(Thread->Saturation) || (OldPriority < LOW_REALTIME_PRIORITY))
333 {
334 /* Check if we had priority saturation */
335 if (Thread->Saturation > 0)
336 {
337 /* Boost priority to maximum */
338 NewPriority = HIGH_PRIORITY;
339 }
340 else if (Thread->Saturation < 0)
341 {
342 /* If we had negative saturation, set minimum priority */
343 NewPriority = LOW_REALTIME_PRIORITY;
344 }
345
346 /* Update priority and quantum */
347 Thread->BasePriority = (SCHAR)NewPriority;
348 Thread->Quantum = Thread->QuantumReset;
349
350 /* Disable decrements and update priority */
351 Thread->PriorityDecrement = 0;
352 KiSetPriorityThread(Thread, NewPriority);
353 }
354
355 /* Release the thread lock */
356 KiReleaseThreadLock(Thread);
357
358 /* Go to the next thread */
359 NextEntry = NextEntry->Flink;
360 }
361 }
362 else
363 {
364 /* Loop the thread list */
365 while (NextEntry != ListHead)
366 {
367 /* Get the thread */
368 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry);
369
370 /* Update the quantum if we had one */
371 if (Quantum) Thread->QuantumReset = Quantum;
372
373 /* Lock the thread */
374 KiAcquireThreadLock(Thread);
375
376 /* Calculate the new priority */
377 NewPriority = Thread->BasePriority + Delta;
378 if (NewPriority >= LOW_REALTIME_PRIORITY)
379 {
380 /* We're not real-time range, don't let it enter RT range */
381 NewPriority = LOW_REALTIME_PRIORITY - 1;
382 }
383 else if (NewPriority <= LOW_PRIORITY)
384 {
385 /* We're going below the minimum priority, normalize */
386 NewPriority = 1;
387 }
388
389 /*
390 * If priority saturation occured or the old priority was still in
391 * the real-time range, don't do anything.
392 */
393 if (!(Thread->Saturation) ||
394 (OldPriority >= LOW_REALTIME_PRIORITY))
395 {
396 /* Check if we had priority saturation */
397 if (Thread->Saturation > 0)
398 {
399 /* Boost priority to maximum */
400 NewPriority = LOW_REALTIME_PRIORITY - 1;
401 }
402 else if (Thread->Saturation < 0)
403 {
404 /* If we had negative saturation, set minimum priority */
405 NewPriority = 1;
406 }
407
408 /* Update priority and quantum */
409 Thread->BasePriority = (SCHAR)NewPriority;
410 Thread->Quantum = Thread->QuantumReset;
411
412 /* Disable decrements and update priority */
413 Thread->PriorityDecrement = 0;
414 KiSetPriorityThread(Thread, NewPriority);
415 }
416
417 /* Release the thread lock */
418 KiReleaseThreadLock(Thread);
419
420 /* Go to the next thread */
421 NextEntry = NextEntry->Flink;
422 }
423 }
424
425 /* Release Dispatcher Database */
426 KiReleaseDispatcherLockFromDpcLevel();
427
428 /* Release the process lock */
429 KiReleaseProcessLockFromDpcLevel(&ProcessLock);
430 KiExitDispatcher(ProcessLock.OldIrql);
431
432 /* Return previous priority */
433 return OldPriority;
434 }
435
436 /* PUBLIC FUNCTIONS **********************************************************/
437
438 /*
439 * @implemented
440 */
441 VOID
442 NTAPI
443 KeAttachProcess(IN PKPROCESS Process)
444 {
445 KLOCK_QUEUE_HANDLE ApcLock;
446 PKTHREAD Thread = KeGetCurrentThread();
447 ASSERT_PROCESS(Process);
448 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
449
450 /* Check if we're already in that process */
451 if (Thread->ApcState.Process == Process) return;
452
453 /* Check if a DPC is executing or if we're already attached */
454 if ((Thread->ApcStateIndex != OriginalApcEnvironment) ||
455 (KeIsExecutingDpc()))
456 {
457 /* Invalid attempt */
458 KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT,
459 (ULONG_PTR)Process,
460 (ULONG_PTR)Thread->ApcState.Process,
461 Thread->ApcStateIndex,
462 KeIsExecutingDpc());
463 }
464 else
465 {
466 /* Acquire APC Lock */
467 KiAcquireApcLock(Thread, &ApcLock);
468
469 /* Acquire the dispatcher lock */
470 KiAcquireDispatcherLockAtDpcLevel();
471
472 /* Legit attach attempt: do it! */
473 KiAttachProcess(Thread, Process, &ApcLock, &Thread->SavedApcState);
474 }
475 }
476
477 /*
478 * @implemented
479 */
480 VOID
481 NTAPI
482 KeDetachProcess(VOID)
483 {
484 PKTHREAD Thread = KeGetCurrentThread();
485 KLOCK_QUEUE_HANDLE ApcLock;
486 PKPROCESS Process;
487 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
488
489 /* Check if it's attached */
490 if (Thread->ApcStateIndex == OriginalApcEnvironment) return;
491
492 /* Acquire APC Lock */
493 KiAcquireApcLock(Thread, &ApcLock);
494
495 /* Check for invalid attach attempts */
496 if ((Thread->ApcState.KernelApcInProgress) ||
497 !(IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) ||
498 !(IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])))
499 {
500 /* Crash the system */
501 KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT);
502 }
503
504 /* Get the process */
505 Process = Thread->ApcState.Process;
506
507 /* Acquire dispatcher lock */
508 KiAcquireDispatcherLockAtDpcLevel();
509
510 /* Decrease the stack count */
511 ASSERT(Process->StackCount != 0);
512 ASSERT(Process->State == ProcessInMemory);
513 Process->StackCount--;
514
515 /* Check if we can swap the process out */
516 if (!Process->StackCount)
517 {
518 /* FIXME: Swap the process out */
519 }
520
521 /* Release dispatcher lock */
522 KiReleaseDispatcherLockFromDpcLevel();
523
524 /* Restore the APC State */
525 KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState);
526 Thread->SavedApcState.Process = NULL;
527 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState;
528 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState;
529 Thread->ApcStateIndex = OriginalApcEnvironment;
530
531 /* Release lock */
532 KiReleaseApcLockFromDpcLevel(&ApcLock);
533
534 /* Swap Processes */
535 KiSwapProcess(Thread->ApcState.Process, Process);
536
537 /* Exit the dispatcher */
538 KiExitDispatcher(ApcLock.OldIrql);
539
540 /* Check if we have pending APCs */
541 if (!(IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])))
542 {
543 /* What do you know, we do! Request them to be delivered */
544 Thread->ApcState.KernelApcPending = TRUE;
545 HalRequestSoftwareInterrupt(APC_LEVEL);
546 }
547 }
548
549 /*
550 * @implemented
551 */
552 BOOLEAN
553 NTAPI
554 KeIsAttachedProcess(VOID)
555 {
556 /* Return the APC State */
557 return KeGetCurrentThread()->ApcStateIndex;
558 }
559
560 /*
561 * @implemented
562 */
563 VOID
564 NTAPI
565 KeStackAttachProcess(IN PKPROCESS Process,
566 OUT PRKAPC_STATE ApcState)
567 {
568 KLOCK_QUEUE_HANDLE ApcLock;
569 PKTHREAD Thread = KeGetCurrentThread();
570 ASSERT_PROCESS(Process);
571 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
572
573 /* Crash system if DPC is being executed! */
574 if (KeIsExecutingDpc())
575 {
576 /* Executing a DPC, crash! */
577 KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT,
578 (ULONG_PTR)Process,
579 (ULONG_PTR)Thread->ApcState.Process,
580 Thread->ApcStateIndex,
581 KeIsExecutingDpc());
582 }
583
584 /* Check if we are already in the target process */
585 if (Thread->ApcState.Process == Process)
586 {
587 /* Set magic value so we don't crash later when detaching */
588 ApcState->Process = (PKPROCESS)1;
589 return;
590 }
591
592 /* Acquire APC Lock */
593 KiAcquireApcLock(Thread, &ApcLock);
594
595 /* Acquire dispatcher lock */
596 KiAcquireDispatcherLockAtDpcLevel();
597
598 /* Check if the Current Thread is already attached */
599 if (Thread->ApcStateIndex != OriginalApcEnvironment)
600 {
601 /* We're already attached, so save the APC State into what we got */
602 KiAttachProcess(Thread, Process, &ApcLock, ApcState);
603 }
604 else
605 {
606 /* We're not attached, so save the APC State into SavedApcState */
607 KiAttachProcess(Thread, Process, &ApcLock, &Thread->SavedApcState);
608 ApcState->Process = NULL;
609 }
610 }
611
612 /*
613 * @implemented
614 */
615 VOID
616 NTAPI
617 KeUnstackDetachProcess(IN PRKAPC_STATE ApcState)
618 {
619 KLOCK_QUEUE_HANDLE ApcLock;
620 PKTHREAD Thread = KeGetCurrentThread();
621 PKPROCESS Process;
622 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
623
624 /* Check for magic value meaning we were already in the same process */
625 if (ApcState->Process == (PKPROCESS)1) return;
626
627 /* Loop to make sure no APCs are pending */
628 for (;;)
629 {
630 /* Acquire APC Lock */
631 KiAcquireApcLock(Thread, &ApcLock);
632
633 /* Check if a kernel APC is pending */
634 if (Thread->ApcState.KernelApcPending)
635 {
636 /* Check if kernel APC should be delivered */
637 if (!(Thread->KernelApcDisable) && (ApcLock.OldIrql <= APC_LEVEL))
638 {
639 /* Release the APC lock so that the APC can be delivered */
640 KiReleaseApcLock(&ApcLock);
641 continue;
642 }
643 }
644
645 /* Otherwise, break out */
646 break;
647 }
648
649 /*
650 * Check if the process isn't attacked, or has a Kernel APC in progress
651 * or has pending APC of any kind.
652 */
653 if ((Thread->ApcStateIndex == OriginalApcEnvironment) ||
654 (Thread->ApcState.KernelApcInProgress) ||
655 (!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) ||
656 (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])))
657 {
658 /* Bugcheck the system */
659 KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT);
660 }
661
662 /* Get the process */
663 Process = Thread->ApcState.Process;
664
665 /* Acquire dispatcher lock */
666 KiAcquireDispatcherLockAtDpcLevel();
667
668 /* Decrease the stack count */
669 ASSERT(Process->StackCount != 0);
670 ASSERT(Process->State == ProcessInMemory);
671 Process->StackCount--;
672
673 /* Check if we can swap the process out */
674 if (!Process->StackCount)
675 {
676 /* FIXME: Swap the process out */
677 }
678
679 /* Release dispatcher lock */
680 KiReleaseDispatcherLockFromDpcLevel();
681
682 /* Check if there's an APC state to restore */
683 if (ApcState->Process)
684 {
685 /* Restore the APC State */
686 KiMoveApcState(ApcState, &Thread->ApcState);
687 }
688 else
689 {
690 /* The ApcState parameter is useless, so use the saved data and reset it */
691 KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState);
692 Thread->SavedApcState.Process = NULL;
693 Thread->ApcStateIndex = OriginalApcEnvironment;
694 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState;
695 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState;
696 }
697
698 /* Release lock */
699 KiReleaseApcLockFromDpcLevel(&ApcLock);
700
701 /* Swap Processes */
702 KiSwapProcess(Thread->ApcState.Process, Process);
703
704 /* Exit the dispatcher */
705 KiExitDispatcher(ApcLock.OldIrql);
706
707 /* Check if we have pending APCs */
708 if (!(IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])))
709 {
710 /* What do you know, we do! Request them to be delivered */
711 Thread->ApcState.KernelApcPending = TRUE;
712 HalRequestSoftwareInterrupt(APC_LEVEL);
713 }
714 }
715
716 /*
717 * @implemented
718 */
719 ULONG
720 NTAPI
721 KeQueryRuntimeProcess(IN PKPROCESS Process,
722 OUT PULONG UserTime)
723 {
724 ULONG TotalUser, TotalKernel;
725 KLOCK_QUEUE_HANDLE ProcessLock;
726 PLIST_ENTRY NextEntry, ListHead;
727 PKTHREAD Thread;
728
729 ASSERT_PROCESS(Process);
730
731 /* Initialize user and kernel times */
732 TotalUser = Process->UserTime;
733 TotalKernel = Process->KernelTime;
734
735 /* Lock the process */
736 KiAcquireProcessLock(Process, &ProcessLock);
737
738 /* Loop all child threads and sum up their times */
739 ListHead = &Process->ThreadListHead;
740 NextEntry = ListHead->Flink;
741 while (ListHead != NextEntry)
742 {
743 /* Get the thread */
744 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry);
745
746 /* Sum up times */
747 TotalKernel += Thread->KernelTime;
748 TotalUser += Thread->UserTime;
749
750 /* Go to the next one */
751 NextEntry = NextEntry->Flink;
752 }
753
754 /* Release lock */
755 KiReleaseProcessLock(&ProcessLock);
756
757 /* Return the user time */
758 *UserTime = TotalUser;
759
760 /* Return the kernel time */
761 return TotalKernel;
762 }
763
764 /*
765 * @implemented
766 */
767 BOOLEAN
768 NTAPI
769 KeAddSystemServiceTable(IN PULONG_PTR Base,
770 IN PULONG Count OPTIONAL,
771 IN ULONG Limit,
772 IN PUCHAR Number,
773 IN ULONG Index)
774 {
775 PAGED_CODE();
776
777 /* Check if descriptor table entry is free */
778 if ((Index > SSDT_MAX_ENTRIES - 1) ||
779 (KeServiceDescriptorTable[Index].Base) ||
780 (KeServiceDescriptorTableShadow[Index].Base))
781 {
782 /* It's not, fail */
783 return FALSE;
784 }
785
786 /* Initialize the shadow service descriptor table */
787 KeServiceDescriptorTableShadow[Index].Base = Base;
788 KeServiceDescriptorTableShadow[Index].Limit = Limit;
789 KeServiceDescriptorTableShadow[Index].Number = Number;
790 KeServiceDescriptorTableShadow[Index].Count = Count;
791 return TRUE;
792 }
793
794 /*
795 * @implemented
796 */
797 BOOLEAN
798 NTAPI
799 KeRemoveSystemServiceTable(IN ULONG Index)
800 {
801 PAGED_CODE();
802
803 /* Make sure the Index is valid */
804 if (Index > (SSDT_MAX_ENTRIES - 1)) return FALSE;
805
806 /* Is there a Normal Descriptor Table? */
807 if (!KeServiceDescriptorTable[Index].Base)
808 {
809 /* Not with the index, is there a shadow at least? */
810 if (!KeServiceDescriptorTableShadow[Index].Base) return FALSE;
811 }
812
813 /* Now clear from the Shadow Table. */
814 KeServiceDescriptorTableShadow[Index].Base = NULL;
815 KeServiceDescriptorTableShadow[Index].Number = NULL;
816 KeServiceDescriptorTableShadow[Index].Limit = 0;
817 KeServiceDescriptorTableShadow[Index].Count = NULL;
818
819 /* Check if we should clean from the Master one too */
820 if (Index == 1)
821 {
822 KeServiceDescriptorTable[Index].Base = NULL;
823 KeServiceDescriptorTable[Index].Number = NULL;
824 KeServiceDescriptorTable[Index].Limit = 0;
825 KeServiceDescriptorTable[Index].Count = NULL;
826 }
827
828 /* Return success */
829 return TRUE;
830 }
831 /* EOF */