- Remove cid.c
[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 ApcEntry;
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 }
265
266 /* Check if the process has a debug port */
267 if (CurrentProcess->DebugPort) {
268
269 /* Notify the Debug API. TODO */
270 //Last ? DbgkExitProcess(ExitStatus) : DbgkExitThread(ExitStatus);
271 }
272
273 /* Process the Termination Ports */
274 while ((TerminationPort = CurrentThread->TerminationPort)) {
275
276 DPRINT("TerminationPort: %p\n", TerminationPort);
277
278 /* Get the next one */
279 CurrentThread->TerminationPort = TerminationPort->Next;
280
281 /* Send the LPC Message */
282 LpcSendTerminationPort(TerminationPort->Port, CurrentThread->CreateTime);
283
284 /* Free the Port */
285 ExFreePool(TerminationPort);
286 }
287
288 /* Rundown Win32 Structures */
289 PsTerminateWin32Thread(CurrentThread);
290 if (Last) PsTerminateWin32Process(CurrentProcess);
291
292 /* Rundown Registry Notifications. TODO (refers to NtChangeNotify, not Cm callbacks) */
293 //CmNotifyRunDown(CurrentThread);
294
295 /* Free the TEB */
296 if((Teb = CurrentThread->Tcb.Teb))
297 {
298 /* Clean up the stack first, if requested */
299 if (Teb->FreeStackOnTermination)
300 {
301 ULONG Dummy = 0;
302 ZwFreeVirtualMemory(NtCurrentProcess(),
303 &Teb->DeallocationStack,
304 &Dummy,
305 MEM_RELEASE);
306 }
307
308 DPRINT("Decommit teb at %p\n", Teb);
309 MmDeleteTeb(CurrentProcess, Teb);
310 CurrentThread->Tcb.Teb = NULL;
311 }
312
313 /* The last Thread shuts down the Process */
314 if (Last) PspExitProcess(CurrentProcess);
315
316 /* Unlock the Process */
317 PsUnlockProcess(CurrentProcess);
318
319 /* Cancel I/O for the thread. */
320 IoCancelThreadIo(CurrentThread);
321
322 /* Rundown Timers */
323 ExTimerRundown();
324 KeCancelTimer(&CurrentThread->Tcb.Timer);
325
326 /* If the Processor Control Block's NpxThread points to the current thread
327 * unset it.
328 */
329 KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
330 InterlockedCompareExchangePointer(&KeGetCurrentPrcb()->NpxThread,
331 NULL,
332 (PKPROCESS)CurrentThread);
333 KeLowerIrql(oldIrql);
334
335 /* Rundown Mutexes */
336 KeRundownThread();
337
338 /* Disable new APC Queuing, this is as far as we'll let them go */
339 KeDisableThreadApcQueueing(&CurrentThread->Tcb);
340
341 /* Flush the User APCs */
342 ApcEntry = KeFlushQueueApc(&CurrentThread->Tcb, UserMode);
343 while(ApcEntry)
344 {
345 /* Get the APC */
346 Apc = CONTAINING_RECORD(ApcEntry, KAPC, ApcListEntry);
347
348 /* Move to the next one */
349 ApcEntry = ApcEntry->Flink;
350
351 /* Rundown the APC or de-allocate it */
352 if (Apc->RundownRoutine)
353 {
354 /* Call its own routine */
355 (Apc->RundownRoutine)(Apc);
356 }
357 else
358 {
359 /* Do it ourselves */
360 ExFreePool(Apc);
361 }
362 }
363
364 /* Call the Lego routine */
365 if (CurrentThread->Tcb.LegoData) PspRunLegoRoutine(&CurrentThread->Tcb);
366
367 /* Flush the APC queue, which should be empty */
368 if ((ApcEntry = KeFlushQueueApc(&CurrentThread->Tcb, KernelMode)))
369 {
370 /* Bugcheck time */
371 KEBUGCHECKEX(KERNEL_APC_PENDING_DURING_EXIT,
372 (ULONG_PTR)ApcEntry,
373 CurrentThread->Tcb.KernelApcDisable,
374 oldIrql,
375 0);
376 }
377
378 /* Terminate the Thread from the Scheduler */
379 KeTerminateThread(0);
380 DPRINT1("Unexpected return, CurrentThread %x PsGetCurrentThread() %x\n", CurrentThread, PsGetCurrentThread());
381 KEBUGCHECK(0);
382 }
383
384 VOID
385 STDCALL
386 PsExitSpecialApc(PKAPC Apc,
387 PKNORMAL_ROUTINE* NormalRoutine,
388 PVOID* NormalContext,
389 PVOID* SystemArgument1,
390 PVOID* SystemArguemnt2)
391 {
392 DPRINT1("PsExitSpecialApc called: 0x%x (proc: 0x%x, '%.16s')\n",
393 PsGetCurrentThread(), PsGetCurrentProcess(), PsGetCurrentProcess()->ImageFileName);
394
395 /* Don't do anything unless we are in User-Mode */
396 if (Apc->SystemArgument2)
397 {
398 NTSTATUS ExitStatus = (NTSTATUS)Apc->NormalContext;
399
400 /* Free the APC */
401 ExFreePool(Apc);
402
403 /* Terminate the Thread */
404 PspExitThread(ExitStatus);
405
406 /* we should never reach this point! */
407 KEBUGCHECK(0);
408 }
409 }
410
411 VOID
412 STDCALL
413 PspExitNormalApc(PVOID NormalContext,
414 PVOID SystemArgument1,
415 PVOID SystemArgument2)
416 {
417 PKAPC Apc = (PKAPC)SystemArgument1;
418 PETHREAD Thread = PsGetCurrentThread();
419 NTSTATUS ExitStatus;
420
421 DPRINT1("PspExitNormalApc called: 0x%x (proc: 0x%x, '%.16s')\n",
422 PsGetCurrentThread(), PsGetCurrentProcess(), PsGetCurrentProcess()->ImageFileName);
423
424 /* This should never happen */
425 ASSERT(!SystemArgument2);
426
427 /* If this is a system thread, we can safely kill it from Kernel-Mode */
428 if (PsIsSystemThread(Thread))
429 {
430 /* Get the Exit Status */
431 DPRINT1("Killing System Thread\n");
432 ExitStatus = (NTSTATUS)Apc->NormalContext;
433
434 /* Free the APC */
435 ExFreePool(Apc);
436
437 /* Exit the Thread */
438 PspExitThread(ExitStatus);
439 }
440
441 /* If we're here, this is not a System Thread, so kill it from User-Mode */
442 DPRINT1("Initializing User-Mode APC\n");
443 KeInitializeApc(Apc,
444 &Thread->Tcb,
445 OriginalApcEnvironment,
446 PsExitSpecialApc,
447 NULL,
448 PspExitNormalApc,
449 UserMode,
450 NormalContext);
451
452 /* Now insert the APC with the User-Mode Flag */
453 KeInsertQueueApc(Apc, Apc, (PVOID)UserMode, 2);
454
455 /* Forcefully resume the thread */
456 KeForceResumeThread(&Thread->Tcb);
457 }
458
459 /*
460 * See "Windows Internals" - Chapter 13, Page 49
461 */
462 VOID
463 STDCALL
464 PspTerminateThreadByPointer(PETHREAD Thread,
465 NTSTATUS ExitStatus)
466 {
467 PKAPC Apc;
468
469 DPRINT("PspTerminatedThreadByPointer(Thread %x, ExitStatus %x)\n",
470 Thread, ExitStatus);
471
472 /* Check if we are already in the right context */
473 if (PsGetCurrentThread() == Thread) {
474
475 /* Directly terminate the thread */
476 PspExitThread(ExitStatus);
477
478 /* we should never reach this point! */
479 KEBUGCHECK(0);
480 }
481
482 /* Allocate the APC */
483 Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG_TERMINATE_APC);
484
485 /* Initialize a Kernel Mode APC to Kill the Thread */
486 KeInitializeApc(Apc,
487 &Thread->Tcb,
488 OriginalApcEnvironment,
489 PsExitSpecialApc,
490 NULL,
491 PspExitNormalApc,
492 KernelMode,
493 (PVOID)ExitStatus);
494
495 /* Insert it into the APC Queue */
496 KeInsertQueueApc(Apc,
497 Apc,
498 NULL,
499 2);
500
501 /* Forcefully resume the thread */
502 KeForceResumeThread(&Thread->Tcb);
503 }
504
505 NTSTATUS
506 STDCALL
507 PspExitProcess(PEPROCESS Process)
508 {
509 DPRINT("PspExitProcess 0x%x\n", Process);
510
511 PspRunCreateProcessNotifyRoutines(Process, FALSE);
512
513 PspDestroyQuotaBlock(Process);
514
515 /* close all handles associated with our process, this needs to be done
516 when the last thread still runs */
517 ObKillProcess(Process);
518
519 KeSetProcess(&Process->Pcb, IO_NO_INCREMENT);
520
521 return(STATUS_SUCCESS);
522 }
523
524 NTSTATUS
525 STDCALL
526 NtTerminateProcess(IN HANDLE ProcessHandle OPTIONAL,
527 IN NTSTATUS ExitStatus)
528 {
529 NTSTATUS Status;
530 PEPROCESS Process;
531 PETHREAD CurrentThread;
532 BOOLEAN KillByHandle;
533
534 PAGED_CODE();
535
536 DPRINT("NtTerminateProcess(ProcessHandle %x, ExitStatus %x)\n",
537 ProcessHandle, ExitStatus);
538
539 KillByHandle = (ProcessHandle != NULL);
540
541 /* Get the Process Object */
542 Status = ObReferenceObjectByHandle((KillByHandle ? ProcessHandle : NtCurrentProcess()),
543 PROCESS_TERMINATE,
544 PsProcessType,
545 KeGetPreviousMode(),
546 (PVOID*)&Process,
547 NULL);
548 if (!NT_SUCCESS(Status)) {
549
550 DPRINT1("Invalid handle to Process\n");
551 return(Status);
552 }
553
554 CurrentThread = PsGetCurrentThread();
555
556 PsLockProcess(Process, FALSE);
557
558 if(Process->ExitTime.QuadPart != 0)
559 {
560 PsUnlockProcess(Process);
561 ObDereferenceObject(Process);
562 return STATUS_PROCESS_IS_TERMINATING;
563 }
564
565 /* Terminate all the Process's Threads */
566 PspTerminateProcessThreads(Process, ExitStatus);
567
568 /* only kill the calling thread if it either passed a process handle or
569 NtCurrentProcess() */
570 if (KillByHandle) {
571
572 /* set the exit time as we're about to release the process lock before
573 we kill ourselves to prevent threads outside of our process trying
574 to kill us */
575 KeQuerySystemTime(&Process->ExitTime);
576
577 /* Only master thread remains... kill it off */
578 if (CurrentThread->ThreadsProcess == Process) {
579
580 /* mark our thread as terminating so attempts to terminate it, when
581 unlocking the process, fail */
582 CurrentThread->Terminated = TRUE;
583
584 PsUnlockProcess(Process);
585
586 /* we can safely dereference the process because the current thread
587 holds a reference to it until it gets reaped */
588 ObDereferenceObject(Process);
589
590 /* now the other threads get a chance to terminate, we don't wait but
591 just kill ourselves right now. The process will be run down when the
592 last thread terminates */
593
594 PspExitThread(ExitStatus);
595
596 /* we should never reach this point! */
597 KEBUGCHECK(0);
598 }
599 }
600
601 /* unlock and dereference the process so the threads can kill themselves */
602 PsUnlockProcess(Process);
603 ObDereferenceObject(Process);
604
605 return(STATUS_SUCCESS);
606 }
607
608 NTSTATUS
609 STDCALL
610 NtTerminateThread(IN HANDLE ThreadHandle,
611 IN NTSTATUS ExitStatus)
612 {
613 PETHREAD Thread;
614 NTSTATUS Status;
615
616 PAGED_CODE();
617
618 /* Handle the special NULL case */
619 if (!ThreadHandle)
620 {
621 /* Check if we're the only thread left */
622 if (IsListEmpty(&PsGetCurrentProcess()->Pcb.ThreadListHead))
623 {
624 /* This is invalid */
625 DPRINT1("Can't terminate self\n");
626 return STATUS_CANT_TERMINATE_SELF;
627 }
628 else
629 {
630 /* Use current handle */
631 ThreadHandle = NtCurrentThread();
632 }
633 }
634
635 /* Get the Thread Object */
636 Status = ObReferenceObjectByHandle(ThreadHandle,
637 THREAD_TERMINATE,
638 PsThreadType,
639 KeGetPreviousMode(),
640 (PVOID*)&Thread,
641 NULL);
642 if (!NT_SUCCESS(Status)) {
643
644 DPRINT1("Could not reference thread object\n");
645 return(Status);
646 }
647
648 /* Make sure this is not a system thread */
649 if (PsIsSystemThread(Thread)) {
650
651 DPRINT1("Trying to Terminate a system thread!\n");
652 ObDereferenceObject(Thread);
653 return STATUS_INVALID_PARAMETER;
654 }
655
656 /* Check to see if we're running in the same thread */
657 if (Thread != PsGetCurrentThread()) {
658
659 /* we need to lock the process to make sure it's not already terminating */
660 PsLockProcess(Thread->ThreadsProcess, FALSE);
661
662 /* This isn't our thread, terminate it if not already done */
663 if (!Thread->Terminated) {
664
665 Thread->Terminated = TRUE;
666
667 /* Terminate it */
668 PspTerminateThreadByPointer(Thread, ExitStatus);
669 }
670
671 PsUnlockProcess(Thread->ThreadsProcess);
672
673 /* Dereference the Thread and return */
674 ObDereferenceObject(Thread);
675
676 } else {
677
678 Thread->Terminated = TRUE;
679
680 /* it's safe to dereference thread, there's at least the keep-alive
681 reference which will be removed by the thread reaper causing the
682 thread to be finally destroyed */
683 ObDereferenceObject(Thread);
684
685 /* Terminate him, he's ours */
686 PspExitThread(ExitStatus);
687
688 /* We do never reach this point */
689 KEBUGCHECK(0);
690 }
691
692 return(STATUS_SUCCESS);
693 }
694
695 /*
696 * @implemented
697 */
698 NTSTATUS
699 STDCALL
700 PsTerminateSystemThread(NTSTATUS ExitStatus)
701 {
702 PETHREAD Thread = PsGetCurrentThread();
703
704 /* Make sure this is a system thread */
705 if (!PsIsSystemThread(Thread)) {
706
707 DPRINT1("Trying to Terminate a non-system thread!\n");
708 return STATUS_INVALID_PARAMETER;
709 }
710
711 /* Terminate it for real */
712 PspExitThread(ExitStatus);
713
714 /* we should never reach this point! */
715 KEBUGCHECK(0);
716
717 return(STATUS_SUCCESS);
718 }
719
720 NTSTATUS
721 STDCALL
722 NtRegisterThreadTerminatePort(HANDLE PortHandle)
723 {
724 NTSTATUS Status;
725 PTERMINATION_PORT TerminationPort;
726 PVOID TerminationLpcPort;
727 PETHREAD Thread;
728
729 PAGED_CODE();
730
731 /* Get the Port */
732 Status = ObReferenceObjectByHandle(PortHandle,
733 PORT_ALL_ACCESS,
734 LpcPortObjectType,
735 KeGetPreviousMode(),
736 &TerminationLpcPort,
737 NULL);
738 if (!NT_SUCCESS(Status)) {
739
740 DPRINT1("Failed to reference Port\n");
741 return(Status);
742 }
743
744 /* Allocate the Port and make sure it suceeded */
745 if((TerminationPort = ExAllocatePoolWithTag(NonPagedPool,
746 sizeof(PTERMINATION_PORT),
747 TAG('P', 's', 'T', '=')))) {
748
749 /* Associate the Port */
750 Thread = PsGetCurrentThread();
751 TerminationPort->Port = TerminationLpcPort;
752 DPRINT("TerminationPort: %p\n", TerminationPort);
753 TerminationPort->Next = Thread->TerminationPort;
754 Thread->TerminationPort = TerminationPort;
755 DPRINT("TerminationPort: %p\n", Thread->TerminationPort);
756
757 /* Return success */
758 return(STATUS_SUCCESS);
759
760 } else {
761
762 /* Dereference and Fail */
763 ObDereferenceObject(TerminationPort);
764 return(STATUS_INSUFFICIENT_RESOURCES);
765 }
766 }