forgot this file
[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 ExInitializeWorkItem(&PspReaperWorkItem, PspReapRoutine, NULL);
477 }
478
479 /**********************************************************************
480 * NtOpenThread/4
481 *
482 * @implemented
483 */
484 NTSTATUS STDCALL
485 NtOpenThread(OUT PHANDLE ThreadHandle,
486 IN ACCESS_MASK DesiredAccess,
487 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
488 IN PCLIENT_ID ClientId OPTIONAL)
489 {
490 KPROCESSOR_MODE PreviousMode;
491 CLIENT_ID SafeClientId;
492 HANDLE hThread;
493 NTSTATUS Status = STATUS_SUCCESS;
494
495 PAGED_CODE();
496
497 PreviousMode = ExGetPreviousMode();
498
499 if(PreviousMode != KernelMode)
500 {
501 _SEH_TRY
502 {
503 ProbeForWrite(ThreadHandle,
504 sizeof(HANDLE),
505 sizeof(ULONG));
506 if(ClientId != NULL)
507 {
508 ProbeForRead(ClientId,
509 sizeof(CLIENT_ID),
510 sizeof(ULONG));
511 SafeClientId = *ClientId;
512 ClientId = &SafeClientId;
513 }
514 }
515 _SEH_HANDLE
516 {
517 Status = _SEH_GetExceptionCode();
518 }
519 _SEH_END;
520
521 if(!NT_SUCCESS(Status))
522 {
523 return Status;
524 }
525 }
526
527 if(!((ObjectAttributes == NULL) ^ (ClientId == NULL)))
528 {
529 DPRINT("NtOpenThread should be called with either ObjectAttributes or ClientId!\n");
530 return STATUS_INVALID_PARAMETER;
531 }
532
533 if(ClientId != NULL)
534 {
535 PETHREAD Thread;
536
537 Status = PsLookupThreadByThreadId(ClientId->UniqueThread,
538 &Thread);
539 if(NT_SUCCESS(Status))
540 {
541 Status = ObInsertObject(Thread,
542 NULL,
543 DesiredAccess,
544 0,
545 NULL,
546 &hThread);
547
548 ObDereferenceObject(Thread);
549 }
550 }
551 else
552 {
553 Status = ObOpenObjectByName(ObjectAttributes,
554 PsThreadType,
555 NULL,
556 PreviousMode,
557 DesiredAccess,
558 NULL,
559 &hThread);
560 }
561
562 if(NT_SUCCESS(Status))
563 {
564 _SEH_TRY
565 {
566 *ThreadHandle = hThread;
567 }
568 _SEH_HANDLE
569 {
570 Status = _SEH_GetExceptionCode();
571 }
572 _SEH_END;
573 }
574
575 return Status;
576 }
577
578 NTSTATUS STDCALL
579 NtYieldExecution(VOID)
580 {
581 KiDispatchThread(THREAD_STATE_READY);
582 return(STATUS_SUCCESS);
583 }
584
585
586 /*
587 * NOT EXPORTED
588 */
589 NTSTATUS STDCALL
590 NtTestAlert(VOID)
591 {
592 /* Check and Alert Thread if needed */
593 return KeTestAlertThread(ExGetPreviousMode()) ? STATUS_ALERTED : STATUS_SUCCESS;
594 }
595
596 VOID
597 KeSetPreviousMode (ULONG Mode)
598 {
599 PsGetCurrentThread()->Tcb.PreviousMode = (UCHAR)Mode;
600 }
601
602
603 /*
604 * @implemented
605 */
606 KPROCESSOR_MODE STDCALL
607 KeGetPreviousMode (VOID)
608 {
609 return (ULONG)PsGetCurrentThread()->Tcb.PreviousMode;
610 }
611
612
613 /*
614 * @implemented
615 */
616 KPROCESSOR_MODE STDCALL
617 ExGetPreviousMode (VOID)
618 {
619 return (KPROCESSOR_MODE)PsGetCurrentThread()->Tcb.PreviousMode;
620 }
621
622 /* EOF */