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
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 DirectoryTableBase
,
127 /* Initialize the Dispatcher Header */
128 KeInitializeDispatcherHeader(&Process
->Header
,
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 KeSetPriorityAndQuantumProcess(IN PKPROCESS Process
,
266 IN KPRIORITY Priority
,
267 IN UCHAR Quantum OPTIONAL
)
269 KLOCK_QUEUE_HANDLE ProcessLock
;
271 PLIST_ENTRY NextEntry
, ListHead
;
272 KPRIORITY NewPriority
, OldPriority
;
274 ASSERT_PROCESS(Process
);
275 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
277 /* Check if the process already has this priority */
278 if (Process
->BasePriority
== Priority
) return Process
->BasePriority
;
280 /* If the caller gave priority 0, normalize to 1 */
281 if (!Priority
) Priority
= LOW_PRIORITY
+ 1;
283 /* Lock the process */
284 KiAcquireProcessLock(Process
, &ProcessLock
);
286 /* Check if we are modifying the quantum too */
287 if (Quantum
) Process
->QuantumReset
= Quantum
;
289 /* Save the current base priority and update it */
290 OldPriority
= Process
->BasePriority
;
291 Process
->BasePriority
= (SCHAR
)Priority
;
293 /* Calculate the priority delta */
294 Delta
= Priority
- OldPriority
;
296 /* Set the list head and list entry */
297 ListHead
= &Process
->ThreadListHead
;
298 NextEntry
= ListHead
->Flink
;
300 /* Check if this is a real-time priority */
301 if (Priority
>= LOW_REALTIME_PRIORITY
)
303 /* Loop the thread list */
304 while (NextEntry
!= ListHead
)
307 Thread
= CONTAINING_RECORD(NextEntry
, KTHREAD
, ThreadListEntry
);
309 /* Update the quantum if we had one */
310 if (Quantum
) Thread
->QuantumReset
= Quantum
;
312 /* Acquire the thread lock */
313 KiAcquireThreadLock(Thread
);
315 /* Calculate the new priority */
316 NewPriority
= Thread
->BasePriority
+ Delta
;
317 if (NewPriority
< LOW_REALTIME_PRIORITY
)
319 /* We're in real-time range, don't let it go below */
320 NewPriority
= LOW_REALTIME_PRIORITY
;
322 else if (NewPriority
> HIGH_PRIORITY
)
324 /* We're going beyond the maximum priority, normalize */
325 NewPriority
= HIGH_PRIORITY
;
329 * If priority saturation occured or the old priority was still in
330 * the real-time range, don't do anything.
332 if (!(Thread
->Saturation
) || (OldPriority
< LOW_REALTIME_PRIORITY
))
334 /* Check if we had priority saturation */
335 if (Thread
->Saturation
> 0)
337 /* Boost priority to maximum */
338 NewPriority
= HIGH_PRIORITY
;
340 else if (Thread
->Saturation
< 0)
342 /* If we had negative saturation, set minimum priority */
343 NewPriority
= LOW_REALTIME_PRIORITY
;
346 /* Update priority and quantum */
347 Thread
->BasePriority
= (SCHAR
)NewPriority
;
348 Thread
->Quantum
= Thread
->QuantumReset
;
350 /* Disable decrements and update priority */
351 Thread
->PriorityDecrement
= 0;
352 KiSetPriorityThread(Thread
, NewPriority
);
355 /* Release the thread lock */
356 KiReleaseThreadLock(Thread
);
358 /* Go to the next thread */
359 NextEntry
= NextEntry
->Flink
;
364 /* Loop the thread list */
365 while (NextEntry
!= ListHead
)
368 Thread
= CONTAINING_RECORD(NextEntry
, KTHREAD
, ThreadListEntry
);
370 /* Update the quantum if we had one */
371 if (Quantum
) Thread
->QuantumReset
= Quantum
;
373 /* Lock the thread */
374 KiAcquireThreadLock(Thread
);
376 /* Calculate the new priority */
377 NewPriority
= Thread
->BasePriority
+ Delta
;
378 if (NewPriority
>= LOW_REALTIME_PRIORITY
)
380 /* We're not real-time range, don't let it enter RT range */
381 NewPriority
= LOW_REALTIME_PRIORITY
- 1;
383 else if (NewPriority
<= LOW_PRIORITY
)
385 /* We're going below the minimum priority, normalize */
390 * If priority saturation occured or the old priority was still in
391 * the real-time range, don't do anything.
393 if (!(Thread
->Saturation
) ||
394 (OldPriority
>= LOW_REALTIME_PRIORITY
))
396 /* Check if we had priority saturation */
397 if (Thread
->Saturation
> 0)
399 /* Boost priority to maximum */
400 NewPriority
= LOW_REALTIME_PRIORITY
- 1;
402 else if (Thread
->Saturation
< 0)
404 /* If we had negative saturation, set minimum priority */
408 /* Update priority and quantum */
409 Thread
->BasePriority
= (SCHAR
)NewPriority
;
410 Thread
->Quantum
= Thread
->QuantumReset
;
412 /* Disable decrements and update priority */
413 Thread
->PriorityDecrement
= 0;
414 KiSetPriorityThread(Thread
, NewPriority
);
417 /* Release the thread lock */
418 KiReleaseThreadLock(Thread
);
420 /* Go to the next thread */
421 NextEntry
= NextEntry
->Flink
;
425 /* Release Dispatcher Database */
426 KiReleaseDispatcherLockFromDpcLevel();
428 /* Release the process lock */
429 KiReleaseProcessLockFromDpcLevel(&ProcessLock
);
430 KiExitDispatcher(ProcessLock
.OldIrql
);
432 /* Return previous priority */
436 /* PUBLIC FUNCTIONS **********************************************************/
443 KeAttachProcess(IN PKPROCESS Process
)
445 KLOCK_QUEUE_HANDLE ApcLock
;
446 PKTHREAD Thread
= KeGetCurrentThread();
447 ASSERT_PROCESS(Process
);
448 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
450 /* Check if we're already in that process */
451 if (Thread
->ApcState
.Process
== Process
) return;
453 /* Check if a DPC is executing or if we're already attached */
454 if ((Thread
->ApcStateIndex
!= OriginalApcEnvironment
) ||
455 (KeIsExecutingDpc()))
457 /* Invalid attempt */
458 KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT
,
460 (ULONG_PTR
)Thread
->ApcState
.Process
,
461 Thread
->ApcStateIndex
,
466 /* Acquire APC Lock */
467 KiAcquireApcLock(Thread
, &ApcLock
);
469 /* Acquire the dispatcher lock */
470 KiAcquireDispatcherLockAtDpcLevel();
472 /* Legit attach attempt: do it! */
473 KiAttachProcess(Thread
, Process
, &ApcLock
, &Thread
->SavedApcState
);
482 KeDetachProcess(VOID
)
484 PKTHREAD Thread
= KeGetCurrentThread();
485 KLOCK_QUEUE_HANDLE ApcLock
;
487 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
489 /* Check if it's attached */
490 if (Thread
->ApcStateIndex
== OriginalApcEnvironment
) return;
492 /* Acquire APC Lock */
493 KiAcquireApcLock(Thread
, &ApcLock
);
495 /* Check for invalid attach attempts */
496 if ((Thread
->ApcState
.KernelApcInProgress
) ||
497 !(IsListEmpty(&Thread
->ApcState
.ApcListHead
[KernelMode
])) ||
498 !(IsListEmpty(&Thread
->ApcState
.ApcListHead
[UserMode
])))
500 /* Crash the system */
501 KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT
);
504 /* Get the process */
505 Process
= Thread
->ApcState
.Process
;
507 /* Acquire dispatcher lock */
508 KiAcquireDispatcherLockAtDpcLevel();
510 /* Decrease the stack count */
511 ASSERT(Process
->StackCount
!= 0);
512 ASSERT(Process
->State
== ProcessInMemory
);
513 Process
->StackCount
--;
515 /* Check if we can swap the process out */
516 if (!Process
->StackCount
)
518 /* FIXME: Swap the process out */
521 /* Release dispatcher lock */
522 KiReleaseDispatcherLockFromDpcLevel();
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
;
532 KiReleaseApcLockFromDpcLevel(&ApcLock
);
535 KiSwapProcess(Thread
->ApcState
.Process
, Process
);
537 /* Exit the dispatcher */
538 KiExitDispatcher(ApcLock
.OldIrql
);
540 /* Check if we have pending APCs */
541 if (!(IsListEmpty(&Thread
->ApcState
.ApcListHead
[KernelMode
])))
543 /* What do you know, we do! Request them to be delivered */
544 Thread
->ApcState
.KernelApcPending
= TRUE
;
545 HalRequestSoftwareInterrupt(APC_LEVEL
);
554 KeIsAttachedProcess(VOID
)
556 /* Return the APC State */
557 return KeGetCurrentThread()->ApcStateIndex
;
565 KeStackAttachProcess(IN PKPROCESS Process
,
566 OUT PRKAPC_STATE ApcState
)
568 KLOCK_QUEUE_HANDLE ApcLock
;
569 PKTHREAD Thread
= KeGetCurrentThread();
570 ASSERT_PROCESS(Process
);
571 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
573 /* Crash system if DPC is being executed! */
574 if (KeIsExecutingDpc())
576 /* Executing a DPC, crash! */
577 KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT
,
579 (ULONG_PTR
)Thread
->ApcState
.Process
,
580 Thread
->ApcStateIndex
,
584 /* Check if we are already in the target process */
585 if (Thread
->ApcState
.Process
== Process
)
587 /* Set magic value so we don't crash later when detaching */
588 ApcState
->Process
= (PKPROCESS
)1;
592 /* Acquire APC Lock */
593 KiAcquireApcLock(Thread
, &ApcLock
);
595 /* Acquire dispatcher lock */
596 KiAcquireDispatcherLockAtDpcLevel();
598 /* Check if the Current Thread is already attached */
599 if (Thread
->ApcStateIndex
!= OriginalApcEnvironment
)
601 /* We're already attached, so save the APC State into what we got */
602 KiAttachProcess(Thread
, Process
, &ApcLock
, ApcState
);
606 /* We're not attached, so save the APC State into SavedApcState */
607 KiAttachProcess(Thread
, Process
, &ApcLock
, &Thread
->SavedApcState
);
608 ApcState
->Process
= NULL
;
617 KeUnstackDetachProcess(IN PRKAPC_STATE ApcState
)
619 KLOCK_QUEUE_HANDLE ApcLock
;
620 PKTHREAD Thread
= KeGetCurrentThread();
622 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
624 /* Check for magic value meaning we were already in the same process */
625 if (ApcState
->Process
== (PKPROCESS
)1) return;
627 /* Loop to make sure no APCs are pending */
630 /* Acquire APC Lock */
631 KiAcquireApcLock(Thread
, &ApcLock
);
633 /* Check if a kernel APC is pending */
634 if (Thread
->ApcState
.KernelApcPending
)
636 /* Check if kernel APC should be delivered */
637 if (!(Thread
->KernelApcDisable
) && (ApcLock
.OldIrql
<= APC_LEVEL
))
639 /* Release the APC lock so that the APC can be delivered */
640 KiReleaseApcLock(&ApcLock
);
645 /* Otherwise, break out */
650 * Check if the process isn't attacked, or has a Kernel APC in progress
651 * or has pending APC of any kind.
653 if ((Thread
->ApcStateIndex
== OriginalApcEnvironment
) ||
654 (Thread
->ApcState
.KernelApcInProgress
) ||
655 (!IsListEmpty(&Thread
->ApcState
.ApcListHead
[KernelMode
])) ||
656 (!IsListEmpty(&Thread
->ApcState
.ApcListHead
[UserMode
])))
658 /* Bugcheck the system */
659 KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT
);
662 /* Get the process */
663 Process
= Thread
->ApcState
.Process
;
665 /* Acquire dispatcher lock */
666 KiAcquireDispatcherLockAtDpcLevel();
668 /* Decrease the stack count */
669 ASSERT(Process
->StackCount
!= 0);
670 ASSERT(Process
->State
== ProcessInMemory
);
671 Process
->StackCount
--;
673 /* Check if we can swap the process out */
674 if (!Process
->StackCount
)
676 /* FIXME: Swap the process out */
679 /* Release dispatcher lock */
680 KiReleaseDispatcherLockFromDpcLevel();
682 /* Check if there's an APC state to restore */
683 if (ApcState
->Process
)
685 /* Restore the APC State */
686 KiMoveApcState(ApcState
, &Thread
->ApcState
);
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
;
699 KiReleaseApcLockFromDpcLevel(&ApcLock
);
702 KiSwapProcess(Thread
->ApcState
.Process
, Process
);
704 /* Exit the dispatcher */
705 KiExitDispatcher(ApcLock
.OldIrql
);
707 /* Check if we have pending APCs */
708 if (!(IsListEmpty(&Thread
->ApcState
.ApcListHead
[KernelMode
])))
710 /* What do you know, we do! Request them to be delivered */
711 Thread
->ApcState
.KernelApcPending
= TRUE
;
712 HalRequestSoftwareInterrupt(APC_LEVEL
);
721 KeQueryRuntimeProcess(IN PKPROCESS Process
,
724 ULONG TotalUser
, TotalKernel
;
725 KLOCK_QUEUE_HANDLE ProcessLock
;
726 PLIST_ENTRY NextEntry
, ListHead
;
729 ASSERT_PROCESS(Process
);
731 /* Initialize user and kernel times */
732 TotalUser
= Process
->UserTime
;
733 TotalKernel
= Process
->KernelTime
;
735 /* Lock the process */
736 KiAcquireProcessLock(Process
, &ProcessLock
);
738 /* Loop all child threads and sum up their times */
739 ListHead
= &Process
->ThreadListHead
;
740 NextEntry
= ListHead
->Flink
;
741 while (ListHead
!= NextEntry
)
744 Thread
= CONTAINING_RECORD(NextEntry
, KTHREAD
, ThreadListEntry
);
747 TotalKernel
+= Thread
->KernelTime
;
748 TotalUser
+= Thread
->UserTime
;
750 /* Go to the next one */
751 NextEntry
= NextEntry
->Flink
;
755 KiReleaseProcessLock(&ProcessLock
);
757 /* Return the user time */
758 *UserTime
= TotalUser
;
760 /* Return the kernel time */
769 KeAddSystemServiceTable(IN PULONG_PTR Base
,
770 IN PULONG Count OPTIONAL
,
777 /* Check if descriptor table entry is free */
778 if ((Index
> SSDT_MAX_ENTRIES
- 1) ||
779 (KeServiceDescriptorTable
[Index
].Base
) ||
780 (KeServiceDescriptorTableShadow
[Index
].Base
))
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
;
799 KeRemoveSystemServiceTable(IN ULONG Index
)
803 /* Make sure the Index is valid */
804 if (Index
> (SSDT_MAX_ENTRIES
- 1)) return FALSE
;
806 /* Is there a Normal Descriptor Table? */
807 if (!KeServiceDescriptorTable
[Index
].Base
)
809 /* Not with the index, is there a shadow at least? */
810 if (!KeServiceDescriptorTableShadow
[Index
].Base
) return FALSE
;
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
;
819 /* Check if we should clean from the Master one too */
822 KeServiceDescriptorTable
[Index
].Base
= NULL
;
823 KeServiceDescriptorTable
[Index
].Number
= NULL
;
824 KeServiceDescriptorTable
[Index
].Limit
= 0;
825 KeServiceDescriptorTable
[Index
].Count
= NULL
;