Silence some debug messages
[reactos.git] / reactos / ntoskrnl / ps / kill.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ps/kill.c
5 * PURPOSE: Thread Termination and Reaping
6 *
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
8 * David Welch (welch@cwcom.net)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* GLOBALS *******************************************************************/
18
19 PETHREAD PspReaperList = NULL;
20 WORK_QUEUE_ITEM PspReaperWorkItem;
21 BOOLEAN PspReaping = FALSE;
22 extern LIST_ENTRY PsActiveProcessHead;
23 extern FAST_MUTEX PspActiveProcessMutex;
24 extern PHANDLE_TABLE PspCidTable;
25
26 /* FUNCTIONS *****************************************************************/
27
28 VOID
29 STDCALL
30 PspReapRoutine(PVOID Context)
31 {
32 KIRQL OldIrql;
33 PETHREAD Thread, NewThread;
34
35 /* Acquire lock */
36 DPRINT("Evil reaper running!!\n");
37 OldIrql = KeAcquireDispatcherDatabaseLock();
38
39 /* Get the first Thread Entry */
40 Thread = PspReaperList;
41 PspReaperList = NULL;
42 DPRINT("PspReaperList: %x\n", Thread);
43
44 /* Check to see if the list is empty */
45 do {
46
47 /* Unlock the Dispatcher */
48 KeReleaseDispatcherDatabaseLock(OldIrql);
49
50 /* Is there a thread on the list? */
51 while (Thread) {
52
53 /* Get the next Thread */
54 DPRINT("Thread: %x\n", Thread);
55 DPRINT("Thread: %x\n", Thread->ReaperLink);
56 NewThread = Thread->ReaperLink;
57
58 /* Remove reference to current thread */
59 ObDereferenceObject(Thread);
60
61 /* Move to next Thread */
62 Thread = NewThread;
63 }
64
65 /* No more linked threads... Reacquire the Lock */
66 OldIrql = KeAcquireDispatcherDatabaseLock();
67
68 /* Now try to get a new thread from the list */
69 Thread = PspReaperList;
70 PspReaperList = NULL;
71 DPRINT("PspReaperList: %x\n", Thread);
72
73 /* Loop again if there is a new thread */
74 } while (Thread);
75
76 PspReaping = FALSE;
77 DPRINT("Done reaping\n");
78 KeReleaseDispatcherDatabaseLock(OldIrql);
79 }
80
81 VOID
82 STDCALL
83 PspKillMostProcesses(VOID)
84 {
85 PLIST_ENTRY current_entry;
86 PEPROCESS current;
87
88 ASSERT(PsGetCurrentProcessId() == PsInitialSystemProcess->UniqueProcessId);
89
90 /* Acquire the Active Process Lock */
91 ExAcquireFastMutex(&PspActiveProcessMutex);
92
93 /* Loop all processes on the list */
94 current_entry = PsActiveProcessHead.Flink;
95 while (current_entry != &PsActiveProcessHead)
96 {
97 current = CONTAINING_RECORD(current_entry, EPROCESS, ActiveProcessLinks);
98 current_entry = current_entry->Flink;
99
100 if (current->UniqueProcessId != PsInitialSystemProcess->UniqueProcessId)
101 {
102 /* Terminate all the Threads in this Process */
103 PspTerminateProcessThreads(current, STATUS_SUCCESS);
104 }
105 }
106
107 /* Release the lock */
108 ExReleaseFastMutex(&PspActiveProcessMutex);
109 }
110
111 VOID
112 STDCALL
113 PspTerminateProcessThreads(PEPROCESS Process,
114 NTSTATUS ExitStatus)
115 {
116 PLIST_ENTRY CurrentEntry;
117 PETHREAD Thread, CurrentThread = PsGetCurrentThread();
118
119 CurrentEntry = Process->ThreadListHead.Flink;
120 while (CurrentEntry != &Process->ThreadListHead) {
121
122 /* Get the Current Thread */
123 Thread = CONTAINING_RECORD(CurrentEntry, ETHREAD, ThreadListEntry);
124
125 /* Move to the Next Thread */
126 CurrentEntry = CurrentEntry->Flink;
127
128 /* Make sure it's not the one we're in */
129 if (Thread != CurrentThread) {
130
131 /* Make sure it didn't already terminate */
132 if (!Thread->Terminated) {
133
134 Thread->Terminated = TRUE;
135
136 /* Terminate it by APC */
137 PspTerminateThreadByPointer(Thread, ExitStatus);
138 }
139 }
140 }
141 }
142
143 VOID
144 STDCALL
145 PspDeleteProcess(PVOID ObjectBody)
146 {
147 PEPROCESS Process = (PEPROCESS)ObjectBody;
148
149 DPRINT("PiDeleteProcess(ObjectBody %x)\n", ObjectBody);
150
151 /* Remove it from the Active List */
152 ExAcquireFastMutex(&PspActiveProcessMutex);
153 RemoveEntryList(&Process->ActiveProcessLinks);
154 ExReleaseFastMutex(&PspActiveProcessMutex);
155
156 /* Delete the CID Handle */
157 if(Process->UniqueProcessId)
158 {
159 ExDestroyHandle(PspCidTable, Process->UniqueProcessId);
160 }
161
162 /* KDB hook */
163 KDB_DELETEPROCESS_HOOK(Process);
164
165 /* Dereference the Token */
166 SeDeassignPrimaryToken(Process);
167
168 /* Release Memory Information */
169 MmReleaseMmInfo(Process);
170
171 /* Delete the W32PROCESS structure if there's one associated */
172 if(Process->Win32Process != NULL) ExFreePool(Process->Win32Process);
173 }
174
175 VOID
176 STDCALL
177 PspDeleteThread(PVOID ObjectBody)
178 {
179 PETHREAD Thread = (PETHREAD)ObjectBody;
180 PEPROCESS Process = Thread->ThreadsProcess;
181
182 DPRINT("PiDeleteThread(ObjectBody 0x%x, process 0x%x)\n",ObjectBody, Thread->ThreadsProcess);
183
184 /* Deassociate the Process */
185 Thread->ThreadsProcess = NULL;
186
187 /* Delete the CID Handle */
188 if(Thread->Cid.UniqueThread)
189 {
190 ExDestroyHandle(PspCidTable, Thread->Cid.UniqueThread);
191 }
192
193 /* Free the W32THREAD structure if present */
194 if(Thread->Tcb.Win32Thread != NULL) ExFreePool (Thread->Tcb.Win32Thread);
195
196 /* Release the Kernel Stack */
197 MmDeleteKernelStack((PVOID)Thread->Tcb.StackLimit, FALSE);
198
199 /* Dereference the Process */
200 ObDereferenceObject(Process);
201 }
202
203 /*
204 * FUNCTION: Terminates the current thread
205 * See "Windows Internals" - Chapter 13, Page 50-53
206 */
207 VOID
208 STDCALL
209 PspExitThread(NTSTATUS ExitStatus)
210 {
211 PETHREAD CurrentThread;
212 BOOLEAN Last;
213 PEPROCESS CurrentProcess;
214 PTERMINATION_PORT TerminationPort;
215 PTEB Teb;
216 KIRQL oldIrql;
217 PLIST_ENTRY FirstEntry, CurrentEntry;
218 PKAPC Apc;
219
220 DPRINT("PspExitThread(ExitStatus %x), Current: 0x%x\n", ExitStatus, PsGetCurrentThread());
221
222 /* Get the Current Thread and Process */
223 CurrentThread = PsGetCurrentThread();
224 CurrentProcess = CurrentThread->ThreadsProcess;
225
226 /* Set the Exit Status and Exit Time */
227 CurrentThread->ExitStatus = ExitStatus;
228 KeQuerySystemTime(&CurrentThread->ExitTime);
229
230 /* Can't terminate a thread if it attached another process */
231 if (KeIsAttachedProcess()) {
232
233 KEBUGCHECKEX(INVALID_PROCESS_ATTACH_ATTEMPT, (ULONG) CurrentProcess,
234 (ULONG) CurrentThread->Tcb.ApcState.Process,
235 (ULONG) CurrentThread->Tcb.ApcStateIndex,
236 (ULONG) CurrentThread);
237 }
238
239 /* Lower to Passive Level */
240 KeLowerIrql(PASSIVE_LEVEL);
241
242 /* Lock the Process before we modify its thread entries */
243 PsLockProcess(CurrentProcess, FALSE);
244
245 /* wake up the thread so we don't deadlock on PsLockProcess */
246 KeForceResumeThread(&CurrentThread->Tcb);
247
248 /* Run Thread Notify Routines before we desintegrate the thread */
249 PspRunCreateThreadNotifyRoutines(CurrentThread, FALSE);
250
251 /* Remove the thread from the thread list of its process */
252 RemoveEntryList(&CurrentThread->ThreadListEntry);
253 Last = IsListEmpty(&CurrentProcess->ThreadListHead);
254
255 /* Set the last Thread Exit Status */
256 CurrentProcess->LastThreadExitStatus = ExitStatus;
257
258 if (Last) {
259
260 /* Save the Exit Time if not already done by NtTerminateProcess. This
261 happens when the last thread just terminates without explicitly
262 terminating the process. */
263 CurrentProcess->ExitTime = CurrentThread->ExitTime;
264 CurrentProcess->ExitStatus = ExitStatus;
265 }
266
267 /* Check if the process has a debug port */
268 if (CurrentProcess->DebugPort) {
269
270 /* Notify the Debug API. TODO */
271 //Last ? DbgkExitProcess(ExitStatus) : DbgkExitThread(ExitStatus);
272 }
273
274 /* Process the Termination Ports */
275 while ((TerminationPort = CurrentThread->TerminationPort)) {
276
277 DPRINT("TerminationPort: %p\n", TerminationPort);
278
279 /* Get the next one */
280 CurrentThread->TerminationPort = TerminationPort->Next;
281
282 /* Send the LPC Message */
283 LpcSendTerminationPort(TerminationPort->Port, CurrentThread->CreateTime);
284 ObDereferenceObject(TerminationPort->Port);
285
286 /* Free the Port */
287 ExFreePool(TerminationPort);
288 }
289
290 /* Rundown Win32 Structures */
291 PsTerminateWin32Thread(CurrentThread);
292 if (Last) PsTerminateWin32Process(CurrentProcess);
293
294 /* Rundown Registry Notifications. TODO (refers to NtChangeNotify, not Cm callbacks) */
295 //CmNotifyRunDown(CurrentThread);
296
297 /* Free the TEB */
298 if((Teb = CurrentThread->Tcb.Teb))
299 {
300 /* Clean up the stack first, if requested */
301 if (Teb->FreeStackOnTermination)
302 {
303 ULONG Dummy = 0;
304 ZwFreeVirtualMemory(NtCurrentProcess(),
305 &Teb->DeallocationStack,
306 &Dummy,
307 MEM_RELEASE);
308 }
309
310 DPRINT("Decommit teb at %p\n", Teb);
311 MmDeleteTeb(CurrentProcess, Teb);
312 CurrentThread->Tcb.Teb = NULL;
313 }
314
315 /* The last Thread shuts down the Process */
316 if (Last) PspExitProcess(CurrentProcess);
317
318 /* Unlock the Process */
319 PsUnlockProcess(CurrentProcess);
320
321 /* Cancel I/O for the thread. */
322 IoCancelThreadIo(CurrentThread);
323
324 /* Rundown Timers */
325 ExTimerRundown();
326 KeCancelTimer(&CurrentThread->Tcb.Timer);
327
328 /* If the Processor Control Block's NpxThread points to the current thread
329 * unset it.
330 */
331 KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
332 InterlockedCompareExchangePointer(&KeGetCurrentPrcb()->NpxThread,
333 NULL,
334 (PKPROCESS)CurrentThread);
335 KeLowerIrql(oldIrql);
336
337 /* Rundown Mutexes */
338 KeRundownThread();
339
340 /* Disable new APC Queuing, this is as far as we'll let them go */
341 KeDisableThreadApcQueueing(&CurrentThread->Tcb);
342
343 /* Flush the User APCs */
344 FirstEntry = KeFlushQueueApc(&CurrentThread->Tcb, UserMode);
345 if (FirstEntry != NULL)
346 {
347 CurrentEntry = FirstEntry;
348 do
349 {
350 /* Get the APC */
351 Apc = CONTAINING_RECORD(CurrentEntry, KAPC, ApcListEntry);
352
353 /* Move to the next one */
354 CurrentEntry = CurrentEntry->Flink;
355
356 /* Rundown the APC or de-allocate it */
357 if (Apc->RundownRoutine)
358 {
359 /* Call its own routine */
360 (Apc->RundownRoutine)(Apc);
361 }
362 else
363 {
364 /* Do it ourselves */
365 ExFreePool(Apc);
366 }
367 }
368 while (CurrentEntry != FirstEntry);
369 }
370
371 /* Call the Lego routine */
372 if (CurrentThread->Tcb.LegoData) PspRunLegoRoutine(&CurrentThread->Tcb);
373
374 /* Flush the APC queue, which should be empty */
375 if ((FirstEntry = KeFlushQueueApc(&CurrentThread->Tcb, KernelMode)))
376 {
377 /* Bugcheck time */
378 KEBUGCHECKEX(KERNEL_APC_PENDING_DURING_EXIT,
379 (ULONG_PTR)FirstEntry,
380 CurrentThread->Tcb.KernelApcDisable,
381 oldIrql,
382 0);
383 }
384
385 /* Terminate the Thread from the Scheduler */
386 KeTerminateThread(0);
387 DPRINT1("Unexpected return, CurrentThread %x PsGetCurrentThread() %x\n", CurrentThread, PsGetCurrentThread());
388 KEBUGCHECK(0);
389 }
390
391 VOID
392 STDCALL
393 PsExitSpecialApc(PKAPC Apc,
394 PKNORMAL_ROUTINE* NormalRoutine,
395 PVOID* NormalContext,
396 PVOID* SystemArgument1,
397 PVOID* SystemArguemnt2)
398 {
399 DPRINT("PsExitSpecialApc called: 0x%x (proc: 0x%x, '%.16s')\n",
400 PsGetCurrentThread(), PsGetCurrentProcess(), PsGetCurrentProcess()->ImageFileName);
401
402 /* Don't do anything unless we are in User-Mode */
403 if (Apc->SystemArgument2)
404 {
405 NTSTATUS ExitStatus = (NTSTATUS)Apc->NormalContext;
406
407 /* Free the APC */
408 ExFreePool(Apc);
409
410 /* Terminate the Thread */
411 PspExitThread(ExitStatus);
412
413 /* we should never reach this point! */
414 KEBUGCHECK(0);
415 }
416 }
417
418 VOID
419 STDCALL
420 PspExitNormalApc(PVOID NormalContext,
421 PVOID SystemArgument1,
422 PVOID SystemArgument2)
423 {
424 PKAPC Apc = (PKAPC)SystemArgument1;
425 PETHREAD Thread = PsGetCurrentThread();
426 NTSTATUS ExitStatus;
427
428 DPRINT("PspExitNormalApc called: 0x%x (proc: 0x%x, '%.16s')\n",
429 PsGetCurrentThread(), PsGetCurrentProcess(), PsGetCurrentProcess()->ImageFileName);
430
431 /* This should never happen */
432 ASSERT(!SystemArgument2);
433
434 /* If this is a system thread, we can safely kill it from Kernel-Mode */
435 if (PsIsSystemThread(Thread))
436 {
437 /* Get the Exit Status */
438 DPRINT1("Killing System Thread\n");
439 ExitStatus = (NTSTATUS)Apc->NormalContext;
440
441 /* Free the APC */
442 ExFreePool(Apc);
443
444 /* Exit the Thread */
445 PspExitThread(ExitStatus);
446 }
447
448 /* If we're here, this is not a System Thread, so kill it from User-Mode */
449 DPRINT("Initializing User-Mode APC\n");
450 KeInitializeApc(Apc,
451 &Thread->Tcb,
452 OriginalApcEnvironment,
453 PsExitSpecialApc,
454 NULL,
455 PspExitNormalApc,
456 UserMode,
457 NormalContext);
458
459 /* Now insert the APC with the User-Mode Flag */
460 KeInsertQueueApc(Apc, Apc, (PVOID)UserMode, 2);
461
462 /* Forcefully resume the thread */
463 KeForceResumeThread(&Thread->Tcb);
464 }
465
466 /*
467 * See "Windows Internals" - Chapter 13, Page 49
468 */
469 VOID
470 STDCALL
471 PspTerminateThreadByPointer(PETHREAD Thread,
472 NTSTATUS ExitStatus)
473 {
474 PKAPC Apc;
475
476 DPRINT("PspTerminatedThreadByPointer(Thread %x, ExitStatus %x)\n",
477 Thread, ExitStatus);
478
479 /* Check if we are already in the right context */
480 if (PsGetCurrentThread() == Thread) {
481
482 /* Directly terminate the thread */
483 PspExitThread(ExitStatus);
484
485 /* we should never reach this point! */
486 KEBUGCHECK(0);
487 }
488
489 /* Allocate the APC */
490 Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG_TERMINATE_APC);
491
492 /* Initialize a Kernel Mode APC to Kill the Thread */
493 KeInitializeApc(Apc,
494 &Thread->Tcb,
495 OriginalApcEnvironment,
496 PsExitSpecialApc,
497 NULL,
498 PspExitNormalApc,
499 KernelMode,
500 (PVOID)ExitStatus);
501
502 /* Insert it into the APC Queue */
503 KeInsertQueueApc(Apc,
504 Apc,
505 NULL,
506 2);
507
508 /* Forcefully resume the thread */
509 KeForceResumeThread(&Thread->Tcb);
510 }
511
512 NTSTATUS
513 STDCALL
514 PspExitProcess(PEPROCESS Process)
515 {
516 DPRINT("PspExitProcess 0x%x\n", Process);
517
518 PspRunCreateProcessNotifyRoutines(Process, FALSE);
519
520 PspDestroyQuotaBlock(Process);
521
522 /* close all handles associated with our process, this needs to be done
523 when the last thread still runs */
524 ObKillProcess(Process);
525
526 KeSetProcess(&Process->Pcb, IO_NO_INCREMENT);
527
528 return(STATUS_SUCCESS);
529 }
530
531 NTSTATUS
532 STDCALL
533 NtTerminateProcess(IN HANDLE ProcessHandle OPTIONAL,
534 IN NTSTATUS ExitStatus)
535 {
536 NTSTATUS Status;
537 PEPROCESS Process;
538 PETHREAD CurrentThread;
539 BOOLEAN KillByHandle;
540
541 PAGED_CODE();
542
543 DPRINT("NtTerminateProcess(ProcessHandle %x, ExitStatus %x)\n",
544 ProcessHandle, ExitStatus);
545
546 KillByHandle = (ProcessHandle != NULL);
547
548 /* Get the Process Object */
549 Status = ObReferenceObjectByHandle((KillByHandle ? ProcessHandle : NtCurrentProcess()),
550 PROCESS_TERMINATE,
551 PsProcessType,
552 KeGetPreviousMode(),
553 (PVOID*)&Process,
554 NULL);
555 if (!NT_SUCCESS(Status)) {
556
557 DPRINT1("Invalid handle to Process\n");
558 return(Status);
559 }
560
561 CurrentThread = PsGetCurrentThread();
562
563 PsLockProcess(Process, FALSE);
564
565 if(Process->ExitTime.QuadPart != 0)
566 {
567 PsUnlockProcess(Process);
568 ObDereferenceObject(Process);
569 return STATUS_PROCESS_IS_TERMINATING;
570 }
571
572 /* Terminate all the Process's Threads */
573 PspTerminateProcessThreads(Process, ExitStatus);
574
575 /* only kill the calling thread if it either passed a process handle or
576 NtCurrentProcess() */
577 if (KillByHandle) {
578
579 /* set the exit time as we're about to release the process lock before
580 we kill ourselves to prevent threads outside of our process trying
581 to kill us */
582 KeQuerySystemTime(&Process->ExitTime);
583 Process->ExitStatus = ExitStatus;
584
585 /* Only master thread remains... kill it off */
586 if (CurrentThread->ThreadsProcess == Process) {
587
588 /* mark our thread as terminating so attempts to terminate it, when
589 unlocking the process, fail */
590 CurrentThread->Terminated = TRUE;
591
592 PsUnlockProcess(Process);
593
594 /* we can safely dereference the process because the current thread
595 holds a reference to it until it gets reaped */
596 ObDereferenceObject(Process);
597
598 /* now the other threads get a chance to terminate, we don't wait but
599 just kill ourselves right now. The process will be run down when the
600 last thread terminates */
601
602 PspExitThread(ExitStatus);
603
604 /* we should never reach this point! */
605 KEBUGCHECK(0);
606 }
607 }
608
609 /* unlock and dereference the process so the threads can kill themselves */
610 PsUnlockProcess(Process);
611 ObDereferenceObject(Process);
612
613 return(STATUS_SUCCESS);
614 }
615
616 NTSTATUS
617 STDCALL
618 NtTerminateThread(IN HANDLE ThreadHandle,
619 IN NTSTATUS ExitStatus)
620 {
621 PETHREAD Thread;
622 NTSTATUS Status;
623
624 PAGED_CODE();
625
626 /* Handle the special NULL case */
627 if (!ThreadHandle)
628 {
629 /* Check if we're the only thread left */
630 if (IsListEmpty(&PsGetCurrentProcess()->Pcb.ThreadListHead))
631 {
632 /* This is invalid */
633 DPRINT1("Can't terminate self\n");
634 return STATUS_CANT_TERMINATE_SELF;
635 }
636 else
637 {
638 /* Use current handle */
639 ThreadHandle = NtCurrentThread();
640 }
641 }
642
643 /* Get the Thread Object */
644 Status = ObReferenceObjectByHandle(ThreadHandle,
645 THREAD_TERMINATE,
646 PsThreadType,
647 KeGetPreviousMode(),
648 (PVOID*)&Thread,
649 NULL);
650 if (!NT_SUCCESS(Status)) {
651
652 DPRINT1("Could not reference thread object\n");
653 return(Status);
654 }
655
656 /* Make sure this is not a system thread */
657 if (PsIsSystemThread(Thread)) {
658
659 DPRINT1("Trying to Terminate a system thread!\n");
660 ObDereferenceObject(Thread);
661 return STATUS_INVALID_PARAMETER;
662 }
663
664 /* Check to see if we're running in the same thread */
665 if (Thread != PsGetCurrentThread()) {
666
667 /* we need to lock the process to make sure it's not already terminating */
668 PsLockProcess(Thread->ThreadsProcess, FALSE);
669
670 /* This isn't our thread, terminate it if not already done */
671 if (!Thread->Terminated) {
672
673 Thread->Terminated = TRUE;
674
675 /* Terminate it */
676 PspTerminateThreadByPointer(Thread, ExitStatus);
677 }
678
679 PsUnlockProcess(Thread->ThreadsProcess);
680
681 /* Dereference the Thread and return */
682 ObDereferenceObject(Thread);
683
684 } else {
685
686 Thread->Terminated = TRUE;
687
688 /* it's safe to dereference thread, there's at least the keep-alive
689 reference which will be removed by the thread reaper causing the
690 thread to be finally destroyed */
691 ObDereferenceObject(Thread);
692
693 /* Terminate him, he's ours */
694 PspExitThread(ExitStatus);
695
696 /* We do never reach this point */
697 KEBUGCHECK(0);
698 }
699
700 return(STATUS_SUCCESS);
701 }
702
703 /*
704 * @implemented
705 */
706 NTSTATUS
707 STDCALL
708 PsTerminateSystemThread(NTSTATUS ExitStatus)
709 {
710 PETHREAD Thread = PsGetCurrentThread();
711
712 /* Make sure this is a system thread */
713 if (!PsIsSystemThread(Thread)) {
714
715 DPRINT1("Trying to Terminate a non-system thread!\n");
716 return STATUS_INVALID_PARAMETER;
717 }
718
719 /* Terminate it for real */
720 PspExitThread(ExitStatus);
721
722 /* we should never reach this point! */
723 KEBUGCHECK(0);
724
725 return(STATUS_SUCCESS);
726 }
727
728 NTSTATUS
729 STDCALL
730 NtRegisterThreadTerminatePort(HANDLE PortHandle)
731 {
732 NTSTATUS Status;
733 PTERMINATION_PORT TerminationPort;
734 PVOID TerminationLpcPort;
735 PETHREAD Thread;
736
737 PAGED_CODE();
738
739 /* Get the Port */
740 Status = ObReferenceObjectByHandle(PortHandle,
741 PORT_ALL_ACCESS,
742 LpcPortObjectType,
743 KeGetPreviousMode(),
744 &TerminationLpcPort,
745 NULL);
746 if (!NT_SUCCESS(Status)) {
747
748 DPRINT1("Failed to reference Port\n");
749 return(Status);
750 }
751
752 /* Allocate the Port and make sure it suceeded */
753 if((TerminationPort = ExAllocatePoolWithTag(NonPagedPool,
754 sizeof(PTERMINATION_PORT),
755 TAG('P', 's', 'T', '=')))) {
756
757 /* Associate the Port */
758 Thread = PsGetCurrentThread();
759 TerminationPort->Port = TerminationLpcPort;
760 DPRINT("TerminationPort: %p\n", TerminationPort);
761 TerminationPort->Next = Thread->TerminationPort;
762 Thread->TerminationPort = TerminationPort;
763 DPRINT("TerminationPort: %p\n", Thread->TerminationPort);
764
765 /* Return success */
766 return(STATUS_SUCCESS);
767
768 } else {
769
770 /* Dereference and Fail */
771 ObDereferenceObject(TerminationPort);
772 return(STATUS_INSUFFICIENT_RESOURCES);
773 }
774 }