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