- Rework MiSyncThreadProcessViews
[reactos.git] / reactos / 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 <internal/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 (!LOW_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 /* Make sure that we are in the right page directory (ReactOS Mm Hack) */
451 MiSyncThreadProcessViews(Thread);
452
453 /* Check if we're already in that process */
454 if (Thread->ApcState.Process == Process) return;
455
456 /* Check if a DPC is executing or if we're already attached */
457 if ((Thread->ApcStateIndex != OriginalApcEnvironment) ||
458 (KeIsExecutingDpc()))
459 {
460 /* Invalid attempt */
461 KEBUGCHECKEX(INVALID_PROCESS_ATTACH_ATTEMPT,
462 (ULONG_PTR)Process,
463 (ULONG_PTR)Thread->ApcState.Process,
464 Thread->ApcStateIndex,
465 KeIsExecutingDpc());
466 }
467 else
468 {
469 /* Acquire APC Lock */
470 KiAcquireApcLock(Thread, &ApcLock);
471
472 /* Acquire the dispatcher lock */
473 KiAcquireDispatcherLockAtDpcLevel();
474
475 /* Legit attach attempt: do it! */
476 KiAttachProcess(Thread, Process, &ApcLock, &Thread->SavedApcState);
477 }
478 }
479
480 /*
481 * @implemented
482 */
483 VOID
484 NTAPI
485 KeDetachProcess(VOID)
486 {
487 PKTHREAD Thread = KeGetCurrentThread();
488 KLOCK_QUEUE_HANDLE ApcLock;
489 PKPROCESS Process;
490 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
491
492 /* Check if it's attached */
493 if (Thread->ApcStateIndex == OriginalApcEnvironment) return;
494
495 /* Acquire APC Lock */
496 KiAcquireApcLock(Thread, &ApcLock);
497
498 /* Check for invalid attach attempts */
499 if ((Thread->ApcState.KernelApcInProgress) ||
500 !(IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) ||
501 !(IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])))
502 {
503 /* Crash the system */
504 KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT);
505 }
506
507 /* Get the process */
508 Process = Thread->ApcState.Process;
509
510 /* Acquire dispatcher lock */
511 KiAcquireDispatcherLockAtDpcLevel();
512
513 /* Decrease the stack count */
514 ASSERT(Process->StackCount != 0);
515 ASSERT(Process->State == ProcessInMemory);
516 Process->StackCount--;
517
518 /* Check if we can swap the process out */
519 if (!Process->StackCount)
520 {
521 /* FIXME: Swap the process out */
522 }
523
524 /* Release dispatcher lock */
525 KiReleaseDispatcherLockFromDpcLevel();
526
527 /* Restore the APC State */
528 KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState);
529 Thread->SavedApcState.Process = NULL;
530 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState;
531 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState;
532 Thread->ApcStateIndex = OriginalApcEnvironment;
533
534 /* Release lock */
535 KiReleaseApcLockFromDpcLevel(&ApcLock);
536
537 /* Swap Processes */
538 KiSwapProcess(Thread->ApcState.Process, Thread->ApcState.Process);
539
540 /* Exit the dispatcher */
541 KiExitDispatcher(ApcLock.OldIrql);
542
543 /* Check if we have pending APCs */
544 if (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]))
545 {
546 /* What do you know, we do! Request them to be delivered */
547 Thread->ApcState.KernelApcPending = TRUE;
548 HalRequestSoftwareInterrupt(APC_LEVEL);
549 }
550 }
551
552 /*
553 * @implemented
554 */
555 BOOLEAN
556 NTAPI
557 KeIsAttachedProcess(VOID)
558 {
559 /* Return the APC State */
560 return KeGetCurrentThread()->ApcStateIndex;
561 }
562
563 /*
564 * @implemented
565 */
566 VOID
567 NTAPI
568 KeStackAttachProcess(IN PKPROCESS Process,
569 OUT PRKAPC_STATE ApcState)
570 {
571 KLOCK_QUEUE_HANDLE ApcLock;
572 PKTHREAD Thread = KeGetCurrentThread();
573 ASSERT_PROCESS(Process);
574 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
575
576 /* Make sure that we are in the right page directory (ReactOS Mm Hack) */
577 MiSyncThreadProcessViews(Thread);
578
579 /* Crash system if DPC is being executed! */
580 if (KeIsExecutingDpc())
581 {
582 /* Executing a DPC, crash! */
583 KEBUGCHECKEX(INVALID_PROCESS_ATTACH_ATTEMPT,
584 (ULONG_PTR)Process,
585 (ULONG_PTR)Thread->ApcState.Process,
586 Thread->ApcStateIndex,
587 KeIsExecutingDpc());
588 }
589
590 /* Check if we are already in the target process */
591 if (Thread->ApcState.Process == Process)
592 {
593 /* Set magic value so we don't crash later when detaching */
594 ApcState->Process = (PKPROCESS)1;
595 return;
596 }
597
598 /* Acquire APC Lock */
599 KiAcquireApcLock(Thread, &ApcLock);
600
601 /* Acquire dispatcher lock */
602 KiAcquireDispatcherLockAtDpcLevel();
603
604 /* Check if the Current Thread is already attached */
605 if (Thread->ApcStateIndex != OriginalApcEnvironment)
606 {
607 /* We're already attached, so save the APC State into what we got */
608 KiAttachProcess(Thread, Process, &ApcLock, ApcState);
609 }
610 else
611 {
612 /* We're not attached, so save the APC State into SavedApcState */
613 KiAttachProcess(Thread, Process, &ApcLock, &Thread->SavedApcState);
614 ApcState->Process = NULL;
615 }
616 }
617
618 /*
619 * @implemented
620 */
621 VOID
622 NTAPI
623 KeUnstackDetachProcess(IN PRKAPC_STATE ApcState)
624 {
625 KLOCK_QUEUE_HANDLE ApcLock;
626 PKTHREAD Thread = KeGetCurrentThread();
627 PKPROCESS Process;
628 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
629
630 /* Check for magic value meaning we were already in the same process */
631 if (ApcState->Process == (PKPROCESS)1) return;
632
633 /* Loop to make sure no APCs are pending */
634 for (;;)
635 {
636 /* Acquire APC Lock */
637 KiAcquireApcLock(Thread, &ApcLock);
638
639 /* Check if a kernel APC is pending */
640 if (Thread->ApcState.KernelApcPending)
641 {
642 /* Check if kernel APC should be delivered */
643 if (!(Thread->KernelApcDisable) && (ApcLock.OldIrql <= APC_LEVEL))
644 {
645 /* Release the APC lock so that the APC can be delivered */
646 KiReleaseApcLock(&ApcLock);
647 continue;
648 }
649 }
650
651 /* Otherwise, break out */
652 break;
653 }
654
655 /*
656 * Check if the process isn't attacked, or has a Kernel APC in progress
657 * or has pending APC of any kind.
658 */
659 if ((Thread->ApcStateIndex == OriginalApcEnvironment) ||
660 (Thread->ApcState.KernelApcInProgress) ||
661 (!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) ||
662 (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])))
663 {
664 /* Bugcheck the system */
665 KEBUGCHECK(INVALID_PROCESS_DETACH_ATTEMPT);
666 }
667
668 /* Get the process */
669 Process = Thread->ApcState.Process;
670
671 /* Acquire dispatcher lock */
672 KiAcquireDispatcherLockAtDpcLevel();
673
674 /* Decrease the stack count */
675 ASSERT(Process->StackCount != 0);
676 ASSERT(Process->State == ProcessInMemory);
677 Process->StackCount--;
678
679 /* Check if we can swap the process out */
680 if (!Process->StackCount)
681 {
682 /* FIXME: Swap the process out */
683 }
684
685 /* Release dispatcher lock */
686 KiReleaseDispatcherLockFromDpcLevel();
687
688 /* Check if there's an APC state to restore */
689 if (ApcState->Process)
690 {
691 /* Restore the APC State */
692 KiMoveApcState(ApcState, &Thread->ApcState);
693 }
694 else
695 {
696 /* The ApcState parameter is useless, so use the saved data and reset it */
697 KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState);
698 Thread->SavedApcState.Process = NULL;
699 Thread->ApcStateIndex = OriginalApcEnvironment;
700 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState;
701 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState;
702 }
703
704 /* Release lock */
705 KiReleaseApcLockFromDpcLevel(&ApcLock);
706
707 /* Swap Processes */
708 KiSwapProcess(Thread->ApcState.Process, Thread->ApcState.Process);
709
710 /* Exit the dispatcher */
711 KiExitDispatcher(ApcLock.OldIrql);
712
713 /* Check if we have pending APCs */
714 if (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]))
715 {
716 /* What do you know, we do! Request them to be delivered */
717 Thread->ApcState.KernelApcPending = TRUE;
718 HalRequestSoftwareInterrupt(APC_LEVEL);
719 }
720 }
721
722 /*
723 * @implemented
724 */
725 BOOLEAN
726 NTAPI
727 KeAddSystemServiceTable(IN PULONG_PTR Base,
728 IN PULONG Count OPTIONAL,
729 IN ULONG Limit,
730 IN PUCHAR Number,
731 IN ULONG Index)
732 {
733 PAGED_CODE();
734
735 /* Check if descriptor table entry is free */
736 if ((Index > SSDT_MAX_ENTRIES - 1) ||
737 (KeServiceDescriptorTable[Index].Base) ||
738 (KeServiceDescriptorTableShadow[Index].Base))
739 {
740 /* It's not, fail */
741 return FALSE;
742 }
743
744 /* Initialize the shadow service descriptor table */
745 KeServiceDescriptorTableShadow[Index].Base = Base;
746 KeServiceDescriptorTableShadow[Index].Limit = Limit;
747 KeServiceDescriptorTableShadow[Index].Number = Number;
748 KeServiceDescriptorTableShadow[Index].Count = Count;
749 return TRUE;
750 }
751
752 /*
753 * @implemented
754 */
755 BOOLEAN
756 NTAPI
757 KeRemoveSystemServiceTable(IN ULONG Index)
758 {
759 PAGED_CODE();
760
761 /* Make sure the Index is valid */
762 if (Index > (SSDT_MAX_ENTRIES - 1)) return FALSE;
763
764 /* Is there a Normal Descriptor Table? */
765 if (!KeServiceDescriptorTable[Index].Base)
766 {
767 /* Not with the index, is there a shadow at least? */
768 if (!KeServiceDescriptorTableShadow[Index].Base) return FALSE;
769 }
770
771 /* Now clear from the Shadow Table. */
772 KeServiceDescriptorTableShadow[Index].Base = NULL;
773 KeServiceDescriptorTableShadow[Index].Number = NULL;
774 KeServiceDescriptorTableShadow[Index].Limit = 0;
775 KeServiceDescriptorTableShadow[Index].Count = NULL;
776
777 /* Check if we should clean from the Master one too */
778 if (Index == 1)
779 {
780 KeServiceDescriptorTable[Index].Base = NULL;
781 KeServiceDescriptorTable[Index].Number = NULL;
782 KeServiceDescriptorTable[Index].Limit = 0;
783 KeServiceDescriptorTable[Index].Count = NULL;
784 }
785
786 /* Return success */
787 return TRUE;
788 }
789 /* EOF */