Thread/Process Termination/Repeaing Rewrite + Fixes
[reactos.git] / reactos / ntoskrnl / ps / thread.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ps/thread.c
6 * PURPOSE: Thread managment
7 *
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
9 * Phillip Susi
10 */
11
12 /*
13 * NOTE:
14 *
15 * All of the routines that manipulate the thread queue synchronize on
16 * a single spinlock
17 *
18 */
19
20 /* INCLUDES ****************************************************************/
21
22 #include <ntoskrnl.h>
23 #define NDEBUG
24 #include <internal/debug.h>
25
26 /* GLOBALS ******************************************************************/
27
28 extern LIST_ENTRY PsActiveProcessHead;
29 extern PEPROCESS PsIdleProcess;
30
31 POBJECT_TYPE EXPORTED PsThreadType = NULL;
32
33 extern PVOID Ki386InitialStackArray[MAXIMUM_PROCESSORS];
34 extern ULONG IdleProcessorMask;
35 extern LIST_ENTRY PriorityListHead[MAXIMUM_PRIORITY];
36
37
38 BOOLEAN DoneInitYet = FALSE;
39 static GENERIC_MAPPING PiThreadMapping = {STANDARD_RIGHTS_READ | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION,
40 STANDARD_RIGHTS_WRITE | THREAD_TERMINATE | THREAD_SUSPEND_RESUME | THREAD_ALERT |
41 THREAD_SET_INFORMATION | THREAD_SET_CONTEXT,
42 STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
43 THREAD_ALL_ACCESS};
44
45 /* FUNCTIONS ***************************************************************/
46
47 /*
48 * @implemented
49 */
50 PKTHREAD STDCALL KeGetCurrentThread(VOID)
51 {
52 #ifdef CONFIG_SMP
53 ULONG Flags;
54 PKTHREAD Thread;
55 Ke386SaveFlags(Flags);
56 Ke386DisableInterrupts();
57 Thread = KeGetCurrentPrcb()->CurrentThread;
58 Ke386RestoreFlags(Flags);
59 return Thread;
60 #else
61 return(KeGetCurrentPrcb()->CurrentThread);
62 #endif
63 }
64
65 /*
66 * @implemented
67 */
68 HANDLE STDCALL PsGetCurrentThreadId(VOID)
69 {
70 return(PsGetCurrentThread()->Cid.UniqueThread);
71 }
72
73 /*
74 * @implemented
75 */
76 ULONG
77 STDCALL
78 PsGetThreadFreezeCount(
79 PETHREAD Thread
80 )
81 {
82 return Thread->Tcb.FreezeCount;
83 }
84
85 /*
86 * @implemented
87 */
88 BOOLEAN
89 STDCALL
90 PsGetThreadHardErrorsAreDisabled(
91 PETHREAD Thread
92 )
93 {
94 return Thread->HardErrorsAreDisabled;
95 }
96
97 /*
98 * @implemented
99 */
100 HANDLE
101 STDCALL
102 PsGetThreadId(
103 PETHREAD Thread
104 )
105 {
106 return Thread->Cid.UniqueThread;
107 }
108
109 /*
110 * @implemented
111 */
112 PEPROCESS
113 STDCALL
114 PsGetThreadProcess(
115 PETHREAD Thread
116 )
117 {
118 return Thread->ThreadsProcess;
119 }
120
121 /*
122 * @implemented
123 */
124 HANDLE
125 STDCALL
126 PsGetThreadProcessId(
127 PETHREAD Thread
128 )
129 {
130 return Thread->Cid.UniqueProcess;
131 }
132
133 /*
134 * @implemented
135 */
136 HANDLE
137 STDCALL
138 PsGetThreadSessionId(
139 PETHREAD Thread
140 )
141 {
142 return (HANDLE)Thread->ThreadsProcess->SessionId;
143 }
144
145 /*
146 * @implemented
147 */
148 PTEB
149 STDCALL
150 PsGetThreadTeb(
151 PETHREAD Thread
152 )
153 {
154 return Thread->Tcb.Teb;
155 }
156
157 /*
158 * @implemented
159 */
160 PVOID
161 STDCALL
162 PsGetThreadWin32Thread(
163 PETHREAD Thread
164 )
165 {
166 return Thread->Tcb.Win32Thread;
167 }
168
169 /*
170 * @implemented
171 */
172 KPROCESSOR_MODE
173 STDCALL
174 PsGetCurrentThreadPreviousMode (
175 VOID
176 )
177 {
178 return (KPROCESSOR_MODE)PsGetCurrentThread()->Tcb.PreviousMode;
179 }
180
181 /*
182 * @implemented
183 */
184 PVOID
185 STDCALL
186 PsGetCurrentThreadStackBase (
187 VOID
188 )
189 {
190 return PsGetCurrentThread()->Tcb.StackBase;
191 }
192
193 /*
194 * @implemented
195 */
196 PVOID
197 STDCALL
198 PsGetCurrentThreadStackLimit (
199 VOID
200 )
201 {
202 return (PVOID)PsGetCurrentThread()->Tcb.StackLimit;
203 }
204
205 /*
206 * @implemented
207 */
208 BOOLEAN STDCALL
209 PsIsThreadTerminating(IN PETHREAD Thread)
210 {
211 return (Thread->HasTerminated ? TRUE : FALSE);
212 }
213
214 /*
215 * @implemented
216 */
217 BOOLEAN
218 STDCALL
219 PsIsSystemThread(PETHREAD Thread)
220 {
221 return (Thread->SystemThread ? TRUE: FALSE);
222 }
223
224 /*
225 * @implemented
226 */
227 BOOLEAN
228 STDCALL
229 PsIsThreadImpersonating(
230 PETHREAD Thread
231 )
232 {
233 return Thread->ActiveImpersonationInfo;
234 }
235
236 VOID PsDumpThreads(BOOLEAN IncludeSystem)
237 {
238 PLIST_ENTRY AThread, AProcess;
239 PEPROCESS Process;
240 PETHREAD Thread;
241 ULONG nThreads = 0;
242
243 AProcess = PsActiveProcessHead.Flink;
244 while(AProcess != &PsActiveProcessHead)
245 {
246 Process = CONTAINING_RECORD(AProcess, EPROCESS, ProcessListEntry);
247 /* FIXME - skip suspended, ... processes? */
248 if((Process != PsInitialSystemProcess) ||
249 (Process == PsInitialSystemProcess && IncludeSystem))
250 {
251 AThread = Process->ThreadListHead.Flink;
252 while(AThread != &Process->ThreadListHead)
253 {
254 Thread = CONTAINING_RECORD(AThread, ETHREAD, ThreadListEntry);
255
256 nThreads++;
257 DbgPrint("Thread->Tcb.State %d Affinity %08x Priority %d PID.TID %d.%d Name %.8s Stack: \n",
258 Thread->Tcb.State,
259 Thread->Tcb.Affinity,
260 Thread->Tcb.Priority,
261 Thread->ThreadsProcess->UniqueProcessId,
262 Thread->Cid.UniqueThread,
263 Thread->ThreadsProcess->ImageFileName);
264 if(Thread->Tcb.State == THREAD_STATE_READY ||
265 Thread->Tcb.State == THREAD_STATE_SUSPENDED ||
266 Thread->Tcb.State == THREAD_STATE_BLOCKED)
267 {
268 ULONG i = 0;
269 PULONG Esp = (PULONG)Thread->Tcb.KernelStack;
270 PULONG Ebp = (PULONG)Esp[4];
271 DbgPrint("Ebp 0x%.8X\n", Ebp);
272 while(Ebp != 0 && Ebp >= (PULONG)Thread->Tcb.StackLimit)
273 {
274 DbgPrint("%.8X %.8X%s", Ebp[0], Ebp[1], (i % 8) == 7 ? "\n" : " ");
275 Ebp = (PULONG)Ebp[0];
276 i++;
277 }
278 if((i % 8) != 0)
279 {
280 DbgPrint("\n");
281 }
282 }
283 AThread = AThread->Flink;
284 }
285 }
286 AProcess = AProcess->Flink;
287 }
288 }
289
290 VOID
291 PsFreezeAllThreads(PEPROCESS Process)
292 /*
293 * Used by the debugging code to freeze all the process's threads
294 * while the debugger is examining their state.
295 */
296 {
297 KIRQL oldIrql;
298 PLIST_ENTRY current_entry;
299 PETHREAD current;
300
301 oldIrql = KeAcquireDispatcherDatabaseLock();
302 current_entry = Process->ThreadListHead.Flink;
303 while (current_entry != &Process->ThreadListHead)
304 {
305 current = CONTAINING_RECORD(current_entry, ETHREAD,
306 ThreadListEntry);
307
308 /*
309 * We have to be careful here, we can't just set the freeze the
310 * thread inside kernel mode since it may be holding a lock.
311 */
312
313 current_entry = current_entry->Flink;
314 }
315
316 KeReleaseDispatcherDatabaseLock(oldIrql);
317 }
318
319 ULONG
320 PsEnumThreadsByProcess(PEPROCESS Process)
321 {
322 KIRQL oldIrql;
323 PLIST_ENTRY current_entry;
324 ULONG Count = 0;
325
326 oldIrql = KeAcquireDispatcherDatabaseLock();
327
328 current_entry = Process->ThreadListHead.Flink;
329 while (current_entry != &Process->ThreadListHead)
330 {
331 Count++;
332 current_entry = current_entry->Flink;
333 }
334
335 KeReleaseDispatcherDatabaseLock(oldIrql);
336 return Count;
337 }
338
339 /*
340 * @unimplemented
341 */
342 NTSTATUS
343 STDCALL
344 PsRemoveCreateThreadNotifyRoutine (
345 IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine
346 )
347 {
348 UNIMPLEMENTED;
349 return STATUS_NOT_IMPLEMENTED;
350 }
351
352 /*
353 * @unimplemented
354 */
355 ULONG
356 STDCALL
357 PsSetLegoNotifyRoutine(
358 PVOID LegoNotifyRoutine
359 )
360 {
361 UNIMPLEMENTED;
362 return 0;
363 }
364
365 /*
366 * @implemented
367 */
368 VOID
369 STDCALL
370 PsSetThreadHardErrorsAreDisabled(
371 PETHREAD Thread,
372 BOOLEAN HardErrorsAreDisabled
373 )
374 {
375 Thread->HardErrorsAreDisabled = HardErrorsAreDisabled;
376 }
377
378 /*
379 * @implemented
380 */
381 VOID
382 STDCALL
383 PsSetThreadWin32Thread(
384 PETHREAD Thread,
385 PVOID Win32Thread
386 )
387 {
388 Thread->Tcb.Win32Thread = Win32Thread;
389 }
390
391 VOID
392 PsApplicationProcessorInit(VOID)
393 {
394 KIRQL oldIrql;
395 oldIrql = KeAcquireDispatcherDatabaseLock();
396 IdleProcessorMask |= (1 << KeGetCurrentProcessorNumber());
397 KeReleaseDispatcherDatabaseLock(oldIrql);
398 }
399
400 VOID INIT_FUNCTION
401 PsPrepareForApplicationProcessorInit(ULONG Id)
402 {
403 PETHREAD IdleThread;
404 PKPRCB Prcb = ((PKPCR)((ULONG_PTR)KPCR_BASE + Id * PAGE_SIZE))->Prcb;
405
406 PsInitializeThread(PsIdleProcess,
407 &IdleThread,
408 NULL,
409 KernelMode,
410 FALSE);
411 IdleThread->Tcb.State = THREAD_STATE_RUNNING;
412 IdleThread->Tcb.FreezeCount = 0;
413 IdleThread->Tcb.Affinity = 1 << Id;
414 IdleThread->Tcb.UserAffinity = 1 << Id;
415 IdleThread->Tcb.Priority = LOW_PRIORITY;
416 IdleThread->Tcb.BasePriority = LOW_PRIORITY;
417 Prcb->IdleThread = &IdleThread->Tcb;
418 Prcb->CurrentThread = &IdleThread->Tcb;
419
420 Ki386InitialStackArray[Id] = (PVOID)IdleThread->Tcb.StackLimit;
421
422 DPRINT("IdleThread for Processor %d has PID %d\n",
423 Id, IdleThread->Cid.UniqueThread);
424 }
425
426 VOID INIT_FUNCTION
427 PsInitThreadManagment(VOID)
428 /*
429 * FUNCTION: Initialize thread managment
430 */
431 {
432 PETHREAD FirstThread;
433 ULONG i;
434
435 for (i=0; i < MAXIMUM_PRIORITY; i++)
436 {
437 InitializeListHead(&PriorityListHead[i]);
438 }
439
440 PsThreadType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
441
442 PsThreadType->Tag = TAG('T', 'H', 'R', 'T');
443 PsThreadType->TotalObjects = 0;
444 PsThreadType->TotalHandles = 0;
445 PsThreadType->PeakObjects = 0;
446 PsThreadType->PeakHandles = 0;
447 PsThreadType->PagedPoolCharge = 0;
448 PsThreadType->NonpagedPoolCharge = sizeof(ETHREAD);
449 PsThreadType->Mapping = &PiThreadMapping;
450 PsThreadType->Dump = NULL;
451 PsThreadType->Open = NULL;
452 PsThreadType->Close = NULL;
453 PsThreadType->Delete = PspDeleteThread;
454 PsThreadType->Parse = NULL;
455 PsThreadType->Security = NULL;
456 PsThreadType->QueryName = NULL;
457 PsThreadType->OkayToClose = NULL;
458 PsThreadType->Create = NULL;
459 PsThreadType->DuplicationNotify = NULL;
460
461 RtlInitUnicodeString(&PsThreadType->TypeName, L"Thread");
462
463 ObpCreateTypeObject(PsThreadType);
464
465 PsInitializeThread(NULL, &FirstThread, NULL, KernelMode, TRUE);
466 FirstThread->Tcb.State = THREAD_STATE_RUNNING;
467 FirstThread->Tcb.FreezeCount = 0;
468 FirstThread->Tcb.UserAffinity = (1 << 0); /* Set the affinity of the first thread to the boot processor */
469 FirstThread->Tcb.Affinity = (1 << 0);
470 KeGetCurrentPrcb()->CurrentThread = (PVOID)FirstThread;
471
472 DPRINT("FirstThread %x\n",FirstThread);
473
474 DoneInitYet = TRUE;
475
476 InitializeListHead(&PspReaperListHead);
477 ExInitializeWorkItem(&PspReaperWorkItem, PspReapRoutine, NULL);
478 }
479
480 /**********************************************************************
481 * NtOpenThread/4
482 *
483 * @implemented
484 */
485 NTSTATUS STDCALL
486 NtOpenThread(OUT PHANDLE ThreadHandle,
487 IN ACCESS_MASK DesiredAccess,
488 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
489 IN PCLIENT_ID ClientId OPTIONAL)
490 {
491 KPROCESSOR_MODE PreviousMode;
492 CLIENT_ID SafeClientId;
493 HANDLE hThread;
494 NTSTATUS Status = STATUS_SUCCESS;
495
496 PAGED_CODE();
497
498 PreviousMode = ExGetPreviousMode();
499
500 if(PreviousMode != KernelMode)
501 {
502 _SEH_TRY
503 {
504 ProbeForWrite(ThreadHandle,
505 sizeof(HANDLE),
506 sizeof(ULONG));
507 if(ClientId != NULL)
508 {
509 ProbeForRead(ClientId,
510 sizeof(CLIENT_ID),
511 sizeof(ULONG));
512 SafeClientId = *ClientId;
513 ClientId = &SafeClientId;
514 }
515 }
516 _SEH_HANDLE
517 {
518 Status = _SEH_GetExceptionCode();
519 }
520 _SEH_END;
521
522 if(!NT_SUCCESS(Status))
523 {
524 return Status;
525 }
526 }
527
528 if(!((ObjectAttributes == NULL) ^ (ClientId == NULL)))
529 {
530 DPRINT("NtOpenThread should be called with either ObjectAttributes or ClientId!\n");
531 return STATUS_INVALID_PARAMETER;
532 }
533
534 if(ClientId != NULL)
535 {
536 PETHREAD Thread;
537
538 Status = PsLookupThreadByThreadId(ClientId->UniqueThread,
539 &Thread);
540 if(NT_SUCCESS(Status))
541 {
542 Status = ObInsertObject(Thread,
543 NULL,
544 DesiredAccess,
545 0,
546 NULL,
547 &hThread);
548
549 ObDereferenceObject(Thread);
550 }
551 }
552 else
553 {
554 Status = ObOpenObjectByName(ObjectAttributes,
555 PsThreadType,
556 NULL,
557 PreviousMode,
558 DesiredAccess,
559 NULL,
560 &hThread);
561 }
562
563 if(NT_SUCCESS(Status))
564 {
565 _SEH_TRY
566 {
567 *ThreadHandle = hThread;
568 }
569 _SEH_HANDLE
570 {
571 Status = _SEH_GetExceptionCode();
572 }
573 _SEH_END;
574 }
575
576 return Status;
577 }
578
579 NTSTATUS STDCALL
580 NtYieldExecution(VOID)
581 {
582 KiDispatchThread(THREAD_STATE_READY);
583 return(STATUS_SUCCESS);
584 }
585
586
587 /*
588 * NOT EXPORTED
589 */
590 NTSTATUS STDCALL
591 NtTestAlert(VOID)
592 {
593 /* Check and Alert Thread if needed */
594 return KeTestAlertThread(ExGetPreviousMode()) ? STATUS_ALERTED : STATUS_SUCCESS;
595 }
596
597 VOID
598 KeSetPreviousMode (ULONG Mode)
599 {
600 PsGetCurrentThread()->Tcb.PreviousMode = (UCHAR)Mode;
601 }
602
603
604 /*
605 * @implemented
606 */
607 KPROCESSOR_MODE STDCALL
608 KeGetPreviousMode (VOID)
609 {
610 return (ULONG)PsGetCurrentThread()->Tcb.PreviousMode;
611 }
612
613
614 /*
615 * @implemented
616 */
617 KPROCESSOR_MODE STDCALL
618 ExGetPreviousMode (VOID)
619 {
620 return (KPROCESSOR_MODE)PsGetCurrentThread()->Tcb.PreviousMode;
621 }
622
623 /* EOF */