94b84007495e7abd44f790fe4ccf54fc40239bb2
[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: Terminating a thread
6 * PROGRAMMER: David Welch (welch@cwcom.net)
7 * UPDATE HISTORY:
8 * Created 22/05/98
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ddk/ntddk.h>
14 #include <internal/ps.h>
15 #include <internal/ke.h>
16 #include <internal/mm.h>
17 #include <internal/ob.h>
18
19 #define NDEBUG
20 #include <internal/debug.h>
21
22 /* GLOBALS *******************************************************************/
23
24 extern ULONG PiNrThreads;
25 extern ULONG PiNrRunnableThreads;
26 extern KSPIN_LOCK PiThreadListLock;
27 extern LIST_ENTRY PiThreadListHead;
28
29 /* FUNCTIONS *****************************************************************/
30
31 VOID PiTerminateProcessThreads(PEPROCESS Process, NTSTATUS ExitStatus)
32 {
33 KIRQL oldlvl;
34 PLIST_ENTRY current_entry;
35 PETHREAD current;
36
37 KeAcquireSpinLock(&PiThreadListLock, &oldlvl);
38
39 current_entry = PiThreadListHead.Flink;
40 while (current_entry != &PiThreadListHead)
41 {
42 current = CONTAINING_RECORD(current_entry,ETHREAD,Tcb.QueueListEntry);
43 if (current->ThreadsProcess == Process &&
44 current != PsGetCurrentThread())
45 {
46 KeReleaseSpinLock(&PiThreadListLock, oldlvl);
47 PsTerminateOtherThread(current, ExitStatus);
48 KeAcquireSpinLock(&PiThreadListLock, &oldlvl);
49 current_entry = PiThreadListHead.Flink;
50 }
51 current_entry = current_entry->Flink;
52 }
53
54 KeReleaseSpinLock(&PiThreadListLock, oldlvl);
55 }
56
57 VOID PsReapThreads(VOID)
58 {
59 PLIST_ENTRY current_entry;
60 PETHREAD current;
61 KIRQL oldIrql;
62
63 // DPRINT1("PsReapThreads()\n");
64
65 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
66
67 current_entry = PiThreadListHead.Flink;
68
69 while (current_entry != &PiThreadListHead)
70 {
71 current = CONTAINING_RECORD(current_entry, ETHREAD,
72 Tcb.ThreadListEntry);
73
74 current_entry = current_entry->Flink;
75
76 if (current->Tcb.State == THREAD_STATE_TERMINATED_1)
77 {
78 PEPROCESS Process = current->ThreadsProcess;
79 NTSTATUS Status = current->ExitStatus;
80
81 DPRINT("PsProcessType %x\n", PsProcessType);
82 ObReferenceObjectByPointer(Process,
83 0,
84 PsProcessType,
85 KernelMode);
86 DPRINT("Reaping thread %x\n", current);
87 DPRINT("Ref count %d\n", ObGetReferenceCount(Process));
88 current->Tcb.State = THREAD_STATE_TERMINATED_2;
89 RemoveEntryList(&current->Tcb.ProcessThreadListEntry);
90 KeReleaseSpinLock(&PiThreadListLock, oldIrql);
91 ObDereferenceObject(current);
92 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
93 if(IsListEmpty(&Process->Pcb.ThreadListHead))
94 {
95 /*
96 * TODO: Optimize this so it doesnt jerk the IRQL around so
97 * much :)
98 */
99 DPRINT("Last thread terminated, terminating process\n");
100 KeReleaseSpinLock(&PiThreadListLock, oldIrql);
101 PiTerminateProcess(Process, Status);
102 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
103 }
104 DPRINT("Ref count %d\n", ObGetReferenceCount(Process));
105 ObDereferenceObject(Process);
106 current_entry = PiThreadListHead.Flink;
107 }
108 }
109 KeReleaseSpinLock(&PiThreadListLock, oldIrql);
110 }
111
112 VOID PsTerminateCurrentThread(NTSTATUS ExitStatus)
113 /*
114 * FUNCTION: Terminates the current thread
115 */
116 {
117 KIRQL oldIrql;
118 PETHREAD CurrentThread;
119
120 CurrentThread = PsGetCurrentThread();
121
122 DPRINT("terminating %x\n",CurrentThread);
123 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
124
125 CurrentThread->ExitStatus = ExitStatus;
126
127 DPRINT("ObGetReferenceCount(CurrentThread) %d\n",
128 ObGetReferenceCount(CurrentThread));
129 DPRINT("ObGetHandleCount(CurrentThread) %x\n",
130 ObGetHandleCount(CurrentThread));
131
132 CurrentThread->Tcb.DispatcherHeader.SignalState = TRUE;
133 KeDispatcherObjectWake(&CurrentThread->Tcb.DispatcherHeader);
134
135 DPRINT("Type %x\n",
136 BODY_TO_HEADER(CurrentThread->ThreadsProcess)->ObjectType);
137
138 PsDispatchThreadNoLock(THREAD_STATE_TERMINATED_1);
139 KeBugCheck(0);
140 }
141
142 VOID PsTerminateOtherThread(PETHREAD Thread, NTSTATUS ExitStatus)
143 /*
144 * FUNCTION: Terminate a thread when calling from that thread's context
145 */
146 {
147 KIRQL oldIrql;
148
149 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
150 if (Thread->Tcb.State == THREAD_STATE_RUNNABLE)
151 {
152 RemoveEntryList(&Thread->Tcb.QueueListEntry);
153 }
154 RemoveEntryList(&Thread->Tcb.ProcessThreadListEntry);
155 Thread->Tcb.State = THREAD_STATE_TERMINATED_2;
156 Thread->Tcb.DispatcherHeader.SignalState = TRUE;
157 KeDispatcherObjectWake(&Thread->Tcb.DispatcherHeader);
158 KeReleaseSpinLock(&PiThreadListLock, oldIrql);
159 if (IsListEmpty(&Thread->ThreadsProcess->Pcb.ThreadListHead))
160 {
161 PiTerminateProcess(Thread->ThreadsProcess, ExitStatus);
162 }
163 ObDereferenceObject(Thread);
164 }
165
166 NTSTATUS STDCALL PiTerminateProcess(PEPROCESS Process,
167 NTSTATUS ExitStatus)
168 {
169 KIRQL oldlvl;
170
171 DPRINT("PsTerminateProcess(Process %x, ExitStatus %x)\n",
172 Process, ExitStatus);
173
174 if (Process->Pcb.ProcessState == PROCESS_STATE_TERMINATED)
175 {
176 return(STATUS_SUCCESS);
177 }
178
179 PiTerminateProcessThreads(Process, ExitStatus);
180 ObCloseAllHandles(Process);
181 KeRaiseIrql(DISPATCH_LEVEL, &oldlvl);
182 Process->Pcb.ProcessState = PROCESS_STATE_TERMINATED;
183 Process->Pcb.DispatcherHeader.SignalState = TRUE;
184 DPRINT("Type %x\n", BODY_TO_HEADER(Process)->ObjectType);
185 KeDispatcherObjectWake(&Process->Pcb.DispatcherHeader);
186 KeLowerIrql(oldlvl);
187 DPRINT("Type %x\n", BODY_TO_HEADER(Process)->ObjectType);
188 return(STATUS_SUCCESS);
189 }
190
191 NTSTATUS STDCALL NtTerminateProcess(IN HANDLE ProcessHandle,
192 IN NTSTATUS ExitStatus)
193 {
194 NTSTATUS Status;
195 PEPROCESS Process;
196
197 DPRINT("NtTerminateProcess(ProcessHandle %x, ExitStatus %x)\n",
198 ProcessHandle, ExitStatus);
199
200 Status = ObReferenceObjectByHandle(ProcessHandle,
201 PROCESS_TERMINATE,
202 PsProcessType,
203 UserMode,
204 (PVOID*)&Process,
205 NULL);
206 if (Status != STATUS_SUCCESS)
207 {
208 return(Status);
209 }
210
211 PiTerminateProcess(Process, ExitStatus);
212 if (PsGetCurrentThread()->ThreadsProcess == Process)
213 {
214 DPRINT("Type %x\n", BODY_TO_HEADER(Process)->ObjectType);
215 ObDereferenceObject(Process);
216 DPRINT("Type %x\n", BODY_TO_HEADER(Process)->ObjectType);
217 PsTerminateCurrentThread(ExitStatus);
218 }
219 ObDereferenceObject(Process);
220 return(STATUS_SUCCESS);
221 }
222
223
224 NTSTATUS STDCALL NtTerminateThread(IN HANDLE ThreadHandle,
225 IN NTSTATUS ExitStatus)
226 {
227 PETHREAD Thread;
228 NTSTATUS Status;
229
230 Status = ObReferenceObjectByHandle(ThreadHandle,
231 THREAD_TERMINATE,
232 PsThreadType,
233 UserMode,
234 (PVOID*)&Thread,
235 NULL);
236 if (Status != STATUS_SUCCESS)
237 {
238 return(Status);
239 }
240
241 ObDereferenceObject(Thread);
242
243 if (Thread == PsGetCurrentThread())
244 {
245 PsTerminateCurrentThread(ExitStatus);
246 }
247 else
248 {
249 PsTerminateOtherThread(Thread, ExitStatus);
250 }
251 return(STATUS_SUCCESS);
252 }
253
254
255 NTSTATUS PsTerminateSystemThread(NTSTATUS ExitStatus)
256 /*
257 * FUNCTION: Terminates the current thread
258 * ARGUMENTS:
259 * ExitStatus = Status to pass to the creater
260 * RETURNS: Doesn't
261 */
262 {
263 PsTerminateCurrentThread(ExitStatus);
264 return(STATUS_SUCCESS);
265 }
266
267
268 NTSTATUS STDCALL NtRegisterThreadTerminatePort(HANDLE TerminationPort)
269 {
270 UNIMPLEMENTED;
271 }