Merge 14551:14980 from trunk
[reactos.git] / reactos / ntoskrnl / ps / thread.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ps/thread.c
5 * PURPOSE: Thread managment
6 *
7 * PROGRAMMERS: David Welch (welch@mcmail.com)
8 * Phillip Susi
9 */
10
11 /* INCLUDES ****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* GLOBALS ******************************************************************/
18
19 extern LIST_ENTRY PsActiveProcessHead;
20 extern PEPROCESS PsIdleProcess;
21
22 POBJECT_TYPE EXPORTED PsThreadType = NULL;
23
24 /* FUNCTIONS ***************************************************************/
25
26 VOID
27 STDCALL
28 PspThreadSpecialApc(PKAPC Apc,
29 PKNORMAL_ROUTINE* NormalRoutine,
30 PVOID* NormalContext,
31 PVOID* SystemArgument1,
32 PVOID* SystemArgument2)
33 {
34 ExFreePool(Apc);
35 }
36
37 VOID
38 STDCALL
39 PspUserThreadStartup(PKSTART_ROUTINE StartRoutine,
40 PVOID StartContext)
41 {
42 PKAPC ThreadApc;
43 PETHREAD Thread = PsGetCurrentThread();
44
45 DPRINT("I am a new USER thread. This is my start routine: %p. This my context: %p."
46 "This is my IRQL: %d. This is my Thread Pointer: %x.\n", StartRoutine,
47 StartContext, KeGetCurrentIrql(), Thread);
48
49 if (!Thread->HasTerminated) {
50
51 /* Allocate the APC */
52 ThreadApc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG('T', 'h', 'r','d'));
53
54 /* Initialize it */
55 KeInitializeApc(ThreadApc,
56 &Thread->Tcb,
57 OriginalApcEnvironment,
58 PspThreadSpecialApc,
59 NULL,
60 LdrpGetSystemDllEntryPoint(),
61 UserMode,
62 NULL);
63
64 /* Insert it into the queue */
65 KeInsertQueueApc(ThreadApc, NULL, NULL, IO_NO_INCREMENT);
66 Thread->Tcb.ApcState.UserApcPending = TRUE;
67 }
68
69 /* Go to Passive Level and notify debugger */
70 KeLowerIrql(PASSIVE_LEVEL);
71 DbgkCreateThread(StartContext);
72 }
73
74 VOID
75 STDCALL
76 PspSystemThreadStartup(PKSTART_ROUTINE StartRoutine,
77 PVOID StartContext)
78 {
79 PETHREAD Thread = PsGetCurrentThread();
80
81 /* Unlock the dispatcher Database */
82 KeLowerIrql(PASSIVE_LEVEL);
83
84 /* Make sure it's not terminated by now */
85 if (!Thread->HasTerminated) {
86
87 /* Call it */
88 (StartRoutine)(StartContext);
89 }
90
91 /* Exit the thread */
92 PspExitThread(STATUS_SUCCESS);
93 }
94
95 NTSTATUS
96 STDCALL
97 PspCreateThread(OUT PHANDLE ThreadHandle,
98 IN ACCESS_MASK DesiredAccess,
99 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
100 IN HANDLE ProcessHandle,
101 IN PEPROCESS TargetProcess,
102 OUT PCLIENT_ID ClientId,
103 IN PCONTEXT ThreadContext,
104 IN PINITIAL_TEB InitialTeb,
105 IN BOOLEAN CreateSuspended,
106 IN PKSTART_ROUTINE StartRoutine OPTIONAL,
107 IN PVOID StartContext OPTIONAL)
108 {
109 HANDLE hThread;
110 PEPROCESS Process;
111 PETHREAD Thread;
112 PTEB TebBase;
113 KIRQL OldIrql;
114 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
115 NTSTATUS Status;
116 PVOID KernelStack;
117
118 /* Reference the Process by handle or pointer, depending on what we got */
119 DPRINT("PspCreateThread: %x, %x, %x\n", ProcessHandle, TargetProcess, ThreadContext);
120 if (ProcessHandle) {
121
122 /* Normal thread or System Thread */
123 DPRINT("Referencing Parent Process\n");
124 Status = ObReferenceObjectByHandle(ProcessHandle,
125 PROCESS_CREATE_THREAD,
126 PsProcessType,
127 PreviousMode,
128 (PVOID*)&Process,
129 NULL);
130 } else {
131
132 /* System thread inside System Process, or Normal Thread with a bug */
133 if (StartRoutine) {
134
135 /* Reference the Process by Pointer */
136 DPRINT("Referencing Parent System Process\n");
137 ObReferenceObject(TargetProcess);
138 Process = TargetProcess;
139 Status = STATUS_SUCCESS;
140
141 } else {
142
143 /* Fake ObReference returning this */
144 Status = STATUS_INVALID_HANDLE;
145 }
146 }
147
148 /* Check for success */
149 if(!NT_SUCCESS(Status)) {
150
151 DPRINT1("Invalid Process Handle, or no handle given\n");
152 return(Status);
153 }
154
155 /* Create Thread Object */
156 DPRINT("Creating Thread Object\n");
157 Status = ObCreateObject(PreviousMode,
158 PsThreadType,
159 ObjectAttributes,
160 KernelMode,
161 NULL,
162 sizeof(ETHREAD),
163 0,
164 0,
165 (PVOID*)&Thread);
166
167 /* Check for success */
168 if (!NT_SUCCESS(Status)) {
169
170 /* Dereference the Process */
171 DPRINT1("Failed to Create Thread Object\n");
172 ObDereferenceObject(Process);
173 return(Status);
174 }
175
176 /* Zero the Object entirely */
177 DPRINT("Cleaning Thread Object\n");
178 RtlZeroMemory(Thread, sizeof(ETHREAD));
179
180 /* Create Cid Handle */
181 DPRINT("Creating Thread Handle (CID)\n");
182 if (!(NT_SUCCESS(PsCreateCidHandle(Thread, PsThreadType, &Thread->Cid.UniqueThread)))) {
183
184 DPRINT1("Failed to create Thread Handle (CID)\n");
185 ObDereferenceObject(Process);
186 ObDereferenceObject(Thread);
187 return Status;
188 }
189
190 /* Initialize Lists */
191 DPRINT("Initialliazing Thread Lists and Locks\n");
192 InitializeListHead(&Thread->LpcReplyChain);
193 InitializeListHead(&Thread->IrpList);
194 InitializeListHead(&Thread->ActiveTimerListHead);
195 KeInitializeSpinLock(&Thread->ActiveTimerListLock);
196
197 /* Initialize LPC */
198 DPRINT("Initialliazing Thread Semaphore\n");
199 KeInitializeSemaphore(&Thread->LpcReplySemaphore, 0, LONG_MAX);
200
201 /* Allocate Stack for non-GUI Thread */
202 DPRINT("Initialliazing Thread Stack\n");
203 KernelStack = MmCreateKernelStack(FALSE);
204
205 /* Set the Process CID */
206 DPRINT("Initialliazing Thread PID and Parent Process\n");
207 Thread->Cid.UniqueProcess = Process->UniqueProcessId;
208 Thread->ThreadsProcess = Process;
209
210 /* Now let the kernel initialize the context */
211 if (ThreadContext) {
212
213 /* User-mode Thread */
214
215 /* Create Teb */
216 DPRINT("Initialliazing Thread PEB\n");
217 TebBase = MmCreateTeb(Process, &Thread->Cid, InitialTeb);
218
219 /* Set the Start Addresses */
220 DPRINT("Initialliazing Thread Start Addresses :%x, %x\n", ThreadContext->Eip, ThreadContext->Eax);
221 Thread->StartAddress = (PVOID)ThreadContext->Eip;
222 Thread->Win32StartAddress = (PVOID)ThreadContext->Eax;
223
224 /* Let the kernel intialize the Thread */
225 DPRINT("Initialliazing Kernel Thread\n");
226 KeInitializeThread(&Process->Pcb,
227 &Thread->Tcb,
228 PspUserThreadStartup,
229 NULL,
230 NULL,
231 ThreadContext,
232 TebBase,
233 KernelStack);
234
235 } else {
236
237 /* System Thread */
238 DPRINT("Initialliazing Thread Start Address :%x\n", StartRoutine);
239 Thread->StartAddress = StartRoutine;
240 Thread->SystemThread = TRUE;
241
242 /* Let the kernel intialize the Thread */
243 DPRINT("Initialliazing Kernel Thread\n");
244 KeInitializeThread(&Process->Pcb,
245 &Thread->Tcb,
246 PspSystemThreadStartup,
247 StartRoutine,
248 StartContext,
249 NULL,
250 NULL,
251 KernelStack);
252 }
253
254 /*
255 * Insert the Thread into the Process's Thread List
256 * Note, this is the ETHREAD Thread List. It is removed in
257 * ps/kill.c!PspExitThread.
258 */
259 DPRINT("Inserting into Process Thread List \n");
260 InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry);
261
262 /* Notify Thread Creation */
263 DPRINT("Running Thread Notify \n");
264 PspRunCreateThreadNotifyRoutines(Thread, TRUE);
265
266 /* FIXME: Use Lock */
267 DPRINT("Apcs Queueable: %d \n", Thread->Tcb.ApcQueueable);
268 Thread->Tcb.ApcQueueable = TRUE;
269
270 /* Suspend the Thread if we have to */
271 if (CreateSuspended) {
272
273 DPRINT("Suspending Thread\n");
274 KeSuspendThread(&Thread->Tcb);
275 }
276
277 /* Reference ourselves as a keep-alive */
278 ObReferenceObject(Thread);
279
280 /* Insert the Thread into the Object Manager */
281 DPRINT("Inserting Thread\n");
282 Status = ObInsertObject((PVOID)Thread,
283 NULL,
284 DesiredAccess,
285 0,
286 NULL,
287 &hThread);
288
289 /* Return Cid and Handle */
290 DPRINT("All worked great!\n");
291 if(NT_SUCCESS(Status)) {
292
293 _SEH_TRY {
294
295 if(ClientId != NULL) {
296
297 *ClientId = Thread->Cid;
298 }
299 *ThreadHandle = hThread;
300
301 } _SEH_HANDLE {
302
303 Status = _SEH_GetExceptionCode();
304
305 } _SEH_END;
306 }
307
308 /* FIXME: SECURITY */
309
310 /* Dispatch thread */
311 DPRINT("About to dispatch the thread: %x!\n", &Thread->Tcb);
312 OldIrql = KeAcquireDispatcherDatabaseLock ();
313 KiUnblockThread(&Thread->Tcb, NULL, 0);
314 ObDereferenceObject(Thread);
315 KeReleaseDispatcherDatabaseLock(OldIrql);
316
317 /* Return */
318 DPRINT("Returning\n");
319 return Status;
320 }
321
322 /*
323 * @implemented
324 */
325 NTSTATUS
326 STDCALL
327 PsCreateSystemThread(PHANDLE ThreadHandle,
328 ACCESS_MASK DesiredAccess,
329 POBJECT_ATTRIBUTES ObjectAttributes,
330 HANDLE ProcessHandle,
331 PCLIENT_ID ClientId,
332 PKSTART_ROUTINE StartRoutine,
333 PVOID StartContext)
334 {
335 PEPROCESS TargetProcess = NULL;
336 HANDLE Handle = ProcessHandle;
337
338 /* Check if we have a handle. If not, use the System Process */
339 if (!ProcessHandle) {
340
341 Handle = NULL;
342 TargetProcess = PsInitialSystemProcess;
343 }
344
345 /* Call the shared function */
346 return PspCreateThread(ThreadHandle,
347 DesiredAccess,
348 ObjectAttributes,
349 Handle,
350 TargetProcess,
351 ClientId,
352 NULL,
353 NULL,
354 FALSE,
355 StartRoutine,
356 StartContext);
357 }
358
359 /*
360 * @implemented
361 */
362 HANDLE
363 STDCALL
364 PsGetCurrentThreadId(VOID)
365 {
366 return(PsGetCurrentThread()->Cid.UniqueThread);
367 }
368
369 /*
370 * @implemented
371 */
372 ULONG
373 STDCALL
374 PsGetThreadFreezeCount(PETHREAD Thread)
375 {
376 return Thread->Tcb.FreezeCount;
377 }
378
379 /*
380 * @implemented
381 */
382 BOOLEAN
383 STDCALL
384 PsGetThreadHardErrorsAreDisabled(PETHREAD Thread)
385 {
386 return Thread->HardErrorsAreDisabled;
387 }
388
389 /*
390 * @implemented
391 */
392 HANDLE
393 STDCALL
394 PsGetThreadId(PETHREAD Thread)
395 {
396 return Thread->Cid.UniqueThread;
397 }
398
399 /*
400 * @implemented
401 */
402 PEPROCESS
403 STDCALL
404 PsGetThreadProcess(PETHREAD Thread)
405 {
406 return Thread->ThreadsProcess;
407 }
408
409 /*
410 * @implemented
411 */
412 HANDLE
413 STDCALL
414 PsGetThreadProcessId(PETHREAD Thread)
415 {
416 return Thread->Cid.UniqueProcess;
417 }
418
419 /*
420 * @implemented
421 */
422 HANDLE
423 STDCALL
424 PsGetThreadSessionId(PETHREAD Thread)
425 {
426 return (HANDLE)Thread->ThreadsProcess->SessionId;
427 }
428
429 /*
430 * @implemented
431 */
432 PTEB
433 STDCALL
434 PsGetThreadTeb(PETHREAD Thread)
435 {
436 return Thread->Tcb.Teb;
437 }
438
439 /*
440 * @implemented
441 */
442 PVOID
443 STDCALL
444 PsGetThreadWin32Thread(PETHREAD Thread)
445 {
446 return Thread->Tcb.Win32Thread;
447 }
448
449 /*
450 * @implemented
451 */
452 KPROCESSOR_MODE
453 STDCALL
454 PsGetCurrentThreadPreviousMode(VOID)
455 {
456 return (KPROCESSOR_MODE)PsGetCurrentThread()->Tcb.PreviousMode;
457 }
458
459 /*
460 * @implemented
461 */
462 PVOID
463 STDCALL
464 PsGetCurrentThreadStackBase(VOID)
465 {
466 return PsGetCurrentThread()->Tcb.StackBase;
467 }
468
469 /*
470 * @implemented
471 */
472 PVOID
473 STDCALL
474 PsGetCurrentThreadStackLimit(VOID)
475 {
476 return (PVOID)PsGetCurrentThread()->Tcb.StackLimit;
477 }
478
479 /*
480 * @implemented
481 */
482 BOOLEAN
483 STDCALL
484 PsIsThreadTerminating(IN PETHREAD Thread)
485 {
486 return (Thread->HasTerminated ? TRUE : FALSE);
487 }
488
489 /*
490 * @implemented
491 */
492 BOOLEAN
493 STDCALL
494 PsIsSystemThread(PETHREAD Thread)
495 {
496 return (Thread->SystemThread ? TRUE: FALSE);
497 }
498
499 /*
500 * @implemented
501 */
502 BOOLEAN
503 STDCALL
504 PsIsThreadImpersonating(PETHREAD Thread)
505 {
506 return Thread->ActiveImpersonationInfo;
507 }
508
509 /*
510 * @implemented
511 */
512 VOID
513 STDCALL
514 PsSetThreadHardErrorsAreDisabled(PETHREAD Thread,
515 BOOLEAN HardErrorsAreDisabled)
516 {
517 Thread->HardErrorsAreDisabled = HardErrorsAreDisabled;
518 }
519
520 /*
521 * @implemented
522 */
523 VOID
524 STDCALL
525 PsSetThreadWin32Thread(PETHREAD Thread,
526 PVOID Win32Thread)
527 {
528 Thread->Tcb.Win32Thread = Win32Thread;
529 }
530
531 NTSTATUS
532 STDCALL
533 NtCreateThread(OUT PHANDLE ThreadHandle,
534 IN ACCESS_MASK DesiredAccess,
535 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
536 IN HANDLE ProcessHandle,
537 OUT PCLIENT_ID ClientId,
538 IN PCONTEXT ThreadContext,
539 IN PINITIAL_TEB InitialTeb,
540 IN BOOLEAN CreateSuspended)
541 {
542 INITIAL_TEB SafeInitialTeb;
543
544 PAGED_CODE();
545
546 DPRINT("NtCreateThread(ThreadHandle %x, PCONTEXT %x)\n",
547 ThreadHandle,ThreadContext);
548
549 if(KeGetPreviousMode() != KernelMode) {
550
551 _SEH_TRY {
552
553 ProbeForWrite(ThreadHandle,
554 sizeof(HANDLE),
555 sizeof(ULONG));
556
557 if(ClientId != NULL) {
558
559 ProbeForWrite(ClientId,
560 sizeof(CLIENT_ID),
561 sizeof(ULONG));
562 }
563
564 if(ThreadContext != NULL) {
565
566 ProbeForRead(ThreadContext,
567 sizeof(CONTEXT),
568 sizeof(ULONG));
569
570 } else {
571
572 DPRINT1("No context for User-Mode Thread!!\n");
573 return STATUS_INVALID_PARAMETER;
574 }
575
576 ProbeForRead(InitialTeb,
577 sizeof(INITIAL_TEB),
578 sizeof(ULONG));
579
580 } _SEH_HANDLE {
581
582 return _SEH_GetExceptionCode();
583
584 } _SEH_END;
585 }
586
587 /* Use probed data for the Initial TEB */
588 SafeInitialTeb = *InitialTeb;
589 InitialTeb = &SafeInitialTeb;
590
591 /* Call the shared function */
592 return PspCreateThread(ThreadHandle,
593 DesiredAccess,
594 ObjectAttributes,
595 ProcessHandle,
596 NULL,
597 ClientId,
598 ThreadContext,
599 InitialTeb,
600 CreateSuspended,
601 NULL,
602 NULL);
603 }
604
605 /*
606 * @implemented
607 */
608 NTSTATUS
609 STDCALL
610 NtOpenThread(OUT PHANDLE ThreadHandle,
611 IN ACCESS_MASK DesiredAccess,
612 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
613 IN PCLIENT_ID ClientId OPTIONAL)
614 {
615 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
616 CLIENT_ID SafeClientId;
617 HANDLE hThread = 0;
618 NTSTATUS Status = STATUS_SUCCESS;
619 PETHREAD Thread;
620
621 PAGED_CODE();
622
623 /* Probe the paraemeters */
624 if(PreviousMode != KernelMode)
625 {
626 _SEH_TRY
627 {
628 ProbeForWrite(ThreadHandle,
629 sizeof(HANDLE),
630 sizeof(ULONG));
631
632 if(ClientId != NULL)
633 {
634 ProbeForRead(ClientId,
635 sizeof(CLIENT_ID),
636 sizeof(ULONG));
637
638 SafeClientId = *ClientId;
639 ClientId = &SafeClientId;
640 }
641 }
642 _SEH_HANDLE
643 {
644 Status = _SEH_GetExceptionCode();
645 }
646 _SEH_END;
647
648 if(!NT_SUCCESS(Status)) return Status;
649 }
650
651 /* Open by name if one was given */
652 if (ObjectAttributes->ObjectName)
653 {
654 /* Open it */
655 Status = ObOpenObjectByName(ObjectAttributes,
656 PsThreadType,
657 NULL,
658 PreviousMode,
659 DesiredAccess,
660 NULL,
661 hThread);
662
663 if (Status != STATUS_SUCCESS)
664 {
665 DPRINT1("Could not open object by name\n");
666 }
667
668 /* Return Status */
669 return(Status);
670 }
671 else if (ClientId)
672 {
673 /* Open by Thread ID */
674 if (ClientId->UniqueProcess)
675 {
676 /* Get the Process */
677 if (ClientId->UniqueProcess == (HANDLE)-1) KEBUGCHECK(0);
678 DPRINT("Opening by Process ID: %x\n", ClientId->UniqueProcess);
679 Status = PsLookupProcessThreadByCid(ClientId,
680 NULL,
681 &Thread);
682 }
683 else
684 {
685 /* Get the Process */
686 DPRINT("Opening by Thread ID: %x\n", ClientId->UniqueThread);
687 Status = PsLookupThreadByThreadId(ClientId->UniqueThread,
688 &Thread);
689 }
690
691 if(!NT_SUCCESS(Status))
692 {
693 DPRINT1("Failure to find Thread\n");
694 return Status;
695 }
696
697 /* Open the Thread Object */
698 Status = ObOpenObjectByPointer(Thread,
699 ObjectAttributes->Attributes,
700 NULL,
701 DesiredAccess,
702 PsThreadType,
703 PreviousMode,
704 hThread);
705 if(!NT_SUCCESS(Status))
706 {
707 DPRINT1("Failure to open Thread\n");
708 }
709
710 /* Dereference the thread */
711 ObDereferenceObject(Thread);
712 }
713
714 /* Write back the handle */
715 if(NT_SUCCESS(Status))
716 {
717 _SEH_TRY
718 {
719 *ThreadHandle = hThread;
720 }
721 _SEH_HANDLE
722 {
723 Status = _SEH_GetExceptionCode();
724 }
725 _SEH_END;
726 }
727
728 /* Return status */
729 return Status;
730 }
731
732 NTSTATUS
733 STDCALL
734 NtYieldExecution(VOID)
735 {
736 KiDispatchThread(Ready);
737 return(STATUS_SUCCESS);
738 }
739
740 NTSTATUS
741 STDCALL
742 NtTestAlert(VOID)
743 {
744 /* Check and Alert Thread if needed */
745 return KeTestAlertThread(ExGetPreviousMode()) ? STATUS_ALERTED : STATUS_SUCCESS;
746 }
747
748 /*
749 * @implemented
750 */
751 KPROCESSOR_MODE
752 STDCALL
753 ExGetPreviousMode (VOID)
754 {
755 return (KPROCESSOR_MODE)PsGetCurrentThread()->Tcb.PreviousMode;
756 }
757
758 /* EOF */