db48805c8cd6410e3f3f188cdf886a264ed0aa02
[reactos.git] / reactos / ntoskrnl / ps / thread.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ps/thread.c
5 * PURPOSE: Process Manager: Thread Management
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Thomas Weidenmueller (w3seek@reactos.org)
8 */
9
10 /* INCLUDES ****************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <internal/debug.h>
15
16 /* GLOBALS ******************************************************************/
17
18 extern BOOLEAN CcPfEnablePrefetcher;
19 extern ULONG MmReadClusterSize;
20 POBJECT_TYPE PsThreadType = NULL;
21
22 /* PRIVATE FUNCTIONS *********************************************************/
23
24 VOID
25 NTAPI
26 PspUserThreadStartup(IN PKSTART_ROUTINE StartRoutine,
27 IN PVOID StartContext)
28 {
29 PETHREAD Thread;
30 PTEB Teb;
31 BOOLEAN DeadThread = FALSE;
32 KIRQL OldIrql;
33 PAGED_CODE();
34 PSTRACE(PS_THREAD_DEBUG,
35 "StartRoutine: %p StartContext: %p\n", StartRoutine, StartContext);
36
37 /* Go to Passive Level */
38 KeLowerIrql(PASSIVE_LEVEL);
39 Thread = PsGetCurrentThread();
40
41 /* Check if the thread is dead */
42 if (Thread->DeadThread)
43 {
44 /* Remember that we're dead */
45 DeadThread = TRUE;
46 }
47 else
48 {
49 /* Get the Locale ID and save Preferred Proc */
50 Teb = NtCurrentTeb();
51 Teb->CurrentLocale = MmGetSessionLocaleId();
52 Teb->IdealProcessor = Thread->Tcb.IdealProcessor;
53 }
54
55 /* Check if this is a dead thread, or if we're hiding */
56 if (!(Thread->DeadThread) && !(Thread->HideFromDebugger))
57 {
58 /* We're not, so notify the debugger */
59 DbgkCreateThread(StartContext);
60 }
61
62 /* Make sure we're not already dead */
63 if (!DeadThread)
64 {
65 /* Check if the Prefetcher is enabled */
66 if (CcPfEnablePrefetcher)
67 {
68 /* FIXME: Prepare to prefetch this process */
69 }
70
71 /* Raise to APC */
72 KeRaiseIrql(APC_LEVEL, &OldIrql);
73
74 /* Queue the User APC */
75 KiInitializeUserApc(NULL,
76 (PVOID)((ULONG_PTR)Thread->Tcb.InitialStack -
77 sizeof(KTRAP_FRAME) -
78 SIZEOF_FX_SAVE_AREA),
79 PspSystemDllEntryPoint,
80 NULL,
81 PspSystemDllBase,
82 NULL);
83
84 /* Lower it back to passive */
85 KeLowerIrql(PASSIVE_LEVEL);
86 }
87 else
88 {
89 /* We're dead, kill us now */
90 PspTerminateThreadByPointer(Thread,
91 STATUS_THREAD_IS_TERMINATING,
92 TRUE);
93 }
94
95 /* Do we have a cookie set yet? */
96 if (!SharedUserData->Cookie)
97 {
98 LARGE_INTEGER SystemTime;
99 ULONG NewCookie;
100 PKPRCB Prcb;
101
102 /* Generate a new cookie */
103 KeQuerySystemTime(&SystemTime);
104 Prcb = KeGetCurrentPrcb();
105 NewCookie = Prcb->MmPageFaultCount ^ Prcb->InterruptTime ^
106 SystemTime.u.LowPart ^ SystemTime.u.HighPart ^
107 (ULONG)&SystemTime;
108
109 /* Set the new cookie*/
110 InterlockedCompareExchange((LONG*)&SharedUserData->Cookie,
111 NewCookie,
112 0);
113 }
114 }
115
116 _SEH_FILTER(PspUnhandledExceptionInSystemThread)
117 {
118 PEXCEPTION_POINTERS ExceptionPointers= _SEH_GetExceptionPointers();
119
120 /* Print debugging information */
121 DPRINT1("PS: Unhandled Kernel Mode Exception Pointers = 0x%p\n",
122 ExceptionPointers);
123 DPRINT1("Code %x Addr %p Info0 %p Info1 %p Info2 %p Info3 %p\n",
124 ExceptionPointers->ExceptionRecord->ExceptionCode,
125 ExceptionPointers->ExceptionRecord->ExceptionAddress,
126 ExceptionPointers->ExceptionRecord->ExceptionInformation[0],
127 ExceptionPointers->ExceptionRecord->ExceptionInformation[1],
128 ExceptionPointers->ExceptionRecord->ExceptionInformation[2],
129 ExceptionPointers->ExceptionRecord->ExceptionInformation[3]);
130
131 /* Bugcheck the system */
132 KeBugCheckEx(0x7E,
133 ExceptionPointers->ExceptionRecord->ExceptionCode,
134 (ULONG_PTR)ExceptionPointers->ExceptionRecord->ExceptionAddress,
135 (ULONG_PTR)ExceptionPointers->ExceptionRecord,
136 (ULONG_PTR)ExceptionPointers->ContextRecord);
137 return 0;
138 }
139
140 VOID
141 NTAPI
142 PspSystemThreadStartup(IN PKSTART_ROUTINE StartRoutine,
143 IN PVOID StartContext)
144 {
145 PETHREAD Thread;
146 PSTRACE(PS_THREAD_DEBUG,
147 "StartRoutine: %p StartContext: %p\n", StartRoutine, StartContext);
148
149 /* Unlock the dispatcher Database */
150 KeLowerIrql(PASSIVE_LEVEL);
151 Thread = PsGetCurrentThread();
152
153 /* Make sure the thread isn't gone */
154 _SEH_TRY
155 {
156 if (!(Thread->Terminated) && !(Thread->DeadThread))
157 {
158 /* Call it the Start Routine */
159 StartRoutine(StartContext);
160 }
161 }
162 _SEH_EXCEPT(PspUnhandledExceptionInSystemThread)
163 {
164 /* Bugcheck if we got here */
165 KeBugCheck(KMODE_EXCEPTION_NOT_HANDLED);
166 }
167 _SEH_END;
168
169 /* Exit the thread */
170 PspTerminateThreadByPointer(Thread, STATUS_SUCCESS, TRUE);
171 }
172
173 NTSTATUS
174 NTAPI
175 PspCreateThread(OUT PHANDLE ThreadHandle,
176 IN ACCESS_MASK DesiredAccess,
177 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
178 IN HANDLE ProcessHandle,
179 IN PEPROCESS TargetProcess,
180 OUT PCLIENT_ID ClientId,
181 IN PCONTEXT ThreadContext,
182 IN PINITIAL_TEB InitialTeb,
183 IN BOOLEAN CreateSuspended,
184 IN PKSTART_ROUTINE StartRoutine OPTIONAL,
185 IN PVOID StartContext OPTIONAL)
186 {
187 HANDLE hThread;
188 PEPROCESS Process;
189 PETHREAD Thread;
190 PTEB TebBase = NULL;
191 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
192 NTSTATUS Status, AccessStatus;
193 HANDLE_TABLE_ENTRY CidEntry;
194 ACCESS_STATE LocalAccessState;
195 PACCESS_STATE AccessState = &LocalAccessState;
196 AUX_DATA AuxData;
197 BOOLEAN Result, SdAllocated;
198 PSECURITY_DESCRIPTOR SecurityDescriptor;
199 SECURITY_SUBJECT_CONTEXT SubjectContext;
200 PAGED_CODE();
201 PSTRACE(PS_THREAD_DEBUG,
202 "ThreadContext: %p TargetProcess: %p ProcessHandle: %p\n",
203 ThreadContext, TargetProcess, ProcessHandle);
204
205 /* If we were called from PsCreateSystemThread, then we're kernel mode */
206 if (StartRoutine) PreviousMode = KernelMode;
207
208 /* Reference the Process by handle or pointer, depending on what we got */
209 if (ProcessHandle)
210 {
211 /* Normal thread or System Thread */
212 Status = ObReferenceObjectByHandle(ProcessHandle,
213 PROCESS_CREATE_THREAD,
214 PsProcessType,
215 PreviousMode,
216 (PVOID*)&Process,
217 NULL);
218 PSREFTRACE(Process);
219 }
220 else
221 {
222 /* System thread inside System Process, or Normal Thread with a bug */
223 if (StartRoutine)
224 {
225 /* Reference the Process by Pointer */
226 ObReferenceObject(TargetProcess);
227 Process = TargetProcess;
228 Status = STATUS_SUCCESS;
229 }
230 else
231 {
232 /* Fake ObReference returning this */
233 Status = STATUS_INVALID_HANDLE;
234 }
235 }
236
237 /* Check for success */
238 if (!NT_SUCCESS(Status)) return Status;
239
240 /* Also make sure that User-Mode isn't trying to create a system thread */
241 if ((PreviousMode != KernelMode) && (Process == PsInitialSystemProcess))
242 {
243 /* Fail */
244 ObDereferenceObject(Process);
245 return STATUS_INVALID_HANDLE;
246 }
247
248 /* Create Thread Object */
249 Status = ObCreateObject(PreviousMode,
250 PsThreadType,
251 ObjectAttributes,
252 PreviousMode,
253 NULL,
254 sizeof(ETHREAD),
255 0,
256 0,
257 (PVOID*)&Thread);
258 if (!NT_SUCCESS(Status))
259 {
260 /* We failed; dereference the process and exit */
261 ObDereferenceObject(Process);
262 return Status;
263 }
264
265 /* Zero the Object entirely */
266 RtlZeroMemory(Thread, sizeof(ETHREAD));
267
268 /* Initialize rundown protection */
269 ExInitializeRundownProtection(&Thread->RundownProtect);
270
271 /* Initialize exit code */
272 Thread->ExitStatus = STATUS_PENDING;
273
274 /* Set the Process CID */
275 Thread->ThreadsProcess = Process;
276 Thread->Cid.UniqueProcess = Process->UniqueProcessId;
277
278 /* Create Cid Handle */
279 CidEntry.Object = Thread;
280 CidEntry.GrantedAccess = 0;
281 Thread->Cid.UniqueThread = ExCreateHandle(PspCidTable, &CidEntry);
282 if (!Thread->Cid.UniqueThread)
283 {
284 /* We couldn't create the CID, dereference the thread and fail */
285 ObDereferenceObject(Thread);
286 return STATUS_INSUFFICIENT_RESOURCES;
287 }
288
289 /* Save the read cluster size */
290 Thread->ReadClusterSize = MmReadClusterSize;
291
292 /* Initialize the LPC Reply Semaphore */
293 KeInitializeSemaphore(&Thread->LpcReplySemaphore, 0, 1);
294
295 /* Initialize the list heads and locks */
296 InitializeListHead(&Thread->LpcReplyChain);
297 InitializeListHead(&Thread->IrpList);
298 InitializeListHead(&Thread->PostBlockList);
299 InitializeListHead(&Thread->ActiveTimerListHead);
300 KeInitializeSpinLock(&Thread->ActiveTimerListLock);
301
302 /* Acquire rundown protection */
303 if (!ExAcquireRundownProtection (&Process->RundownProtect))
304 {
305 /* Fail */
306 ObDereferenceObject(Thread);
307 return STATUS_PROCESS_IS_TERMINATING;
308 }
309
310 /* Now let the kernel initialize the context */
311 if (ThreadContext)
312 {
313 /* User-mode Thread, create Teb */
314 TebBase = MmCreateTeb(Process, &Thread->Cid, InitialTeb);
315 if (!TebBase)
316 {
317 /* Failed to create the TEB. Release rundown and dereference */
318 ExReleaseRundownProtection(&Process->RundownProtect);
319 ObDereferenceObject(Thread);
320 return STATUS_INSUFFICIENT_RESOURCES;
321 }
322
323 /* Set the Start Addresses */
324 #if defined(_M_IX86)
325 Thread->StartAddress = (PVOID)ThreadContext->Eip;
326 Thread->Win32StartAddress = (PVOID)ThreadContext->Eax;
327 #elif defined(_M_PPC)
328 Thread->StartAddress = (PVOID)ThreadContext->Dr0;
329 Thread->Win32StartAddress = (PVOID)ThreadContext->Gpr3;
330 #elif defined(_M_MIPS)
331 for (;;);
332 #else
333 #error Unknown architecture
334 #endif
335
336 /* Let the kernel intialize the Thread */
337 Status = KeInitThread(&Thread->Tcb,
338 NULL,
339 PspUserThreadStartup,
340 NULL,
341 Thread->StartAddress,
342 ThreadContext,
343 TebBase,
344 &Process->Pcb);
345 }
346 else
347 {
348 /* System Thread */
349 Thread->StartAddress = StartRoutine;
350 PspSetCrossThreadFlag(Thread, CT_SYSTEM_THREAD_BIT);
351
352 /* Let the kernel intialize the Thread */
353 Status = KeInitThread(&Thread->Tcb,
354 NULL,
355 PspSystemThreadStartup,
356 StartRoutine,
357 StartContext,
358 NULL,
359 NULL,
360 &Process->Pcb);
361 }
362
363 /* Check if we failed */
364 if (!NT_SUCCESS(Status))
365 {
366 /* Delete the TEB if we had done */
367 if (TebBase) MmDeleteTeb(Process, TebBase);
368
369 /* Release rundown and dereference */
370 ExReleaseRundownProtection(&Process->RundownProtect);
371 ObDereferenceObject(Thread);
372 return Status;
373 }
374
375 /* Lock the process */
376 KeEnterCriticalRegion();
377 ExAcquirePushLockExclusive(&Process->ProcessLock);
378
379 /* Make sure the proces didn't just die on us */
380 if (Process->ProcessDelete) goto Quickie;
381
382 /* Check if the thread was ours, terminated and it was user mode */
383 if ((Thread->Terminated) &&
384 (ThreadContext) &&
385 (Thread->ThreadsProcess == Process))
386 {
387 /* Cleanup, we don't want to start it up and context switch */
388 goto Quickie;
389 }
390
391 /*
392 * Insert the Thread into the Process's Thread List
393 * Note, this is the ETHREAD Thread List. It is removed in
394 * ps/kill.c!PspExitThread.
395 */
396 InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry);
397 Process->ActiveThreads++;
398
399 /* Start the thread */
400 KeStartThread(&Thread->Tcb);
401
402 /* Release the process lock */
403 ExReleasePushLockExclusive(&Process->ProcessLock);
404 KeLeaveCriticalRegion();
405
406 /* Release rundown */
407 ExReleaseRundownProtection(&Process->RundownProtect);
408
409 /* Notify WMI */
410 //WmiTraceProcess(Process, TRUE);
411 //WmiTraceThread(Thread, InitialTeb, TRUE);
412
413 /* Notify Thread Creation */
414 PspRunCreateThreadNotifyRoutines(Thread, TRUE);
415
416 /* Reference ourselves as a keep-alive */
417 ObReferenceObjectEx(Thread, 2);
418
419 /* Suspend the Thread if we have to */
420 if (CreateSuspended) KeSuspendThread(&Thread->Tcb);
421
422 /* Check if we were already terminated */
423 if (Thread->Terminated) KeForceResumeThread(&Thread->Tcb);
424
425 /* Create an access state */
426 Status = SeCreateAccessStateEx(NULL,
427 ThreadContext ?
428 PsGetCurrentProcess() : Process,
429 &LocalAccessState,
430 &AuxData,
431 DesiredAccess,
432 &PsThreadType->TypeInfo.GenericMapping);
433 if (!NT_SUCCESS(Status))
434 {
435 /* Access state failed, thread is dead */
436 PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
437
438 /* If we were suspended, wake it up */
439 if (CreateSuspended) KeResumeThread(&Thread->Tcb);
440
441 /* Dispatch thread */
442 KeReadyThread(&Thread->Tcb);
443
444 /* Dereference completely to kill it */
445 ObDereferenceObjectEx(Thread, 2);
446 return Status;
447 }
448
449 /* Insert the Thread into the Object Manager */
450 Status = ObInsertObject(Thread,
451 AccessState,
452 DesiredAccess,
453 0,
454 NULL,
455 &hThread);
456
457 /* Delete the access state if we had one */
458 if (AccessState) SeDeleteAccessState(AccessState);
459
460 /* Check for success */
461 if (NT_SUCCESS(Status))
462 {
463 /* Wrap in SEH to protect against bad user-mode pointers */
464 _SEH_TRY
465 {
466 /* Return Cid and Handle */
467 if (ClientId) *ClientId = Thread->Cid;
468 *ThreadHandle = hThread;
469 }
470 _SEH_HANDLE
471 {
472 /* Get the exception code */
473 Status = _SEH_GetExceptionCode();
474
475 /* Thread insertion failed, thread is dead */
476 PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
477
478 /* If we were suspended, wake it up */
479 if (CreateSuspended) KeResumeThread(&Thread->Tcb);
480
481 /* Dispatch thread */
482 KeReadyThread(&Thread->Tcb);
483
484 /* Dereference it, leaving only the keep-alive */
485 ObDereferenceObject(Thread);
486
487 /* Close its handle, killing it */
488 ObCloseHandle(ThreadHandle, PreviousMode);
489 }
490 _SEH_END;
491 if (!NT_SUCCESS(Status)) return Status;
492 }
493 else
494 {
495 /* Thread insertion failed, thread is dead */
496 PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
497
498 /* If we were suspended, wake it up */
499 if (CreateSuspended) KeResumeThread(&Thread->Tcb);
500 }
501
502 /* Get the create time */
503 KeQuerySystemTime(&Thread->CreateTime);
504 ASSERT(!(Thread->CreateTime.HighPart & 0xF0000000));
505
506 /* Make sure the thread isn't dead */
507 if (!Thread->DeadThread)
508 {
509 /* Get the thread's SD */
510 Status = ObGetObjectSecurity(Thread,
511 &SecurityDescriptor,
512 &SdAllocated);
513 if (!NT_SUCCESS(Status))
514 {
515 /* Thread insertion failed, thread is dead */
516 PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
517
518 /* If we were suspended, wake it up */
519 if (CreateSuspended) KeResumeThread(&Thread->Tcb);
520
521 /* Dispatch thread */
522 KeReadyThread(&Thread->Tcb);
523
524 /* Dereference it, leaving only the keep-alive */
525 ObDereferenceObject(Thread);
526
527 /* Close its handle, killing it */
528 ObCloseHandle(ThreadHandle, PreviousMode);
529 return Status;
530 }
531
532 /* Create the subject context */
533 SubjectContext.ProcessAuditId = Process;
534 SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process);
535 SubjectContext.ClientToken = NULL;
536
537 /* Do the access check */
538 Result = SeAccessCheck(SecurityDescriptor,
539 &SubjectContext,
540 FALSE,
541 MAXIMUM_ALLOWED,
542 0,
543 NULL,
544 &PsThreadType->TypeInfo.GenericMapping,
545 PreviousMode,
546 &Thread->GrantedAccess,
547 &AccessStatus);
548
549 /* Dereference the token and let go the SD */
550 ObFastDereferenceObject(&Process->Token,
551 SubjectContext.PrimaryToken);
552 ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated);
553
554 /* Remove access if it failed */
555 if (!Result) Process->GrantedAccess = 0;
556
557 /* Set least some minimum access */
558 Thread->GrantedAccess |= (THREAD_TERMINATE |
559 THREAD_SET_INFORMATION |
560 THREAD_QUERY_INFORMATION);
561 }
562 else
563 {
564 /* Set the thread access mask to maximum */
565 Thread->GrantedAccess = THREAD_ALL_ACCESS;
566 }
567
568 /* Dispatch thread */
569 KeReadyThread(&Thread->Tcb);
570
571 /* Dereference it, leaving only the keep-alive */
572 ObDereferenceObject(Thread);
573
574 /* Return */
575 return Status;
576
577 /* Most annoying failure case ever, where we undo almost all manually */
578 Quickie:
579 /* When we get here, the process is locked, unlock it */
580 ExReleasePushLockExclusive(&Process->ProcessLock);
581
582 /* Uninitailize it */
583 KeUninitThread(&Thread->Tcb);
584
585 /* If we had a TEB, delete it */
586 if (TebBase) MmDeleteTeb(Process, TebBase);
587
588 /* Release rundown protection, which we also hold */
589 ExReleaseRundownProtection(&Process->RundownProtect);
590
591 /* Dereference the thread and return failure */
592 ObDereferenceObject(Thread);
593 return STATUS_PROCESS_IS_TERMINATING;
594 }
595
596 /* PUBLIC FUNCTIONS **********************************************************/
597
598 /*
599 * @implemented
600 */
601 NTSTATUS
602 NTAPI
603 PsCreateSystemThread(OUT PHANDLE ThreadHandle,
604 IN ACCESS_MASK DesiredAccess,
605 IN POBJECT_ATTRIBUTES ObjectAttributes,
606 IN HANDLE ProcessHandle,
607 IN PCLIENT_ID ClientId,
608 IN PKSTART_ROUTINE StartRoutine,
609 IN PVOID StartContext)
610 {
611 PEPROCESS TargetProcess = NULL;
612 HANDLE Handle = ProcessHandle;
613 PAGED_CODE();
614 PSTRACE(PS_THREAD_DEBUG,
615 "ProcessHandle: %p StartRoutine: %p StartContext: %p\n",
616 ProcessHandle, StartRoutine, StartContext);
617
618 /* Check if we have a handle. If not, use the System Process */
619 if (!ProcessHandle)
620 {
621 Handle = NULL;
622 TargetProcess = PsInitialSystemProcess;
623 }
624
625 /* Call the shared function */
626 return PspCreateThread(ThreadHandle,
627 DesiredAccess,
628 ObjectAttributes,
629 Handle,
630 TargetProcess,
631 ClientId,
632 NULL,
633 NULL,
634 FALSE,
635 StartRoutine,
636 StartContext);
637 }
638
639 /*
640 * @implemented
641 */
642 NTSTATUS
643 NTAPI
644 PsLookupThreadByThreadId(IN HANDLE ThreadId,
645 OUT PETHREAD *Thread)
646 {
647 PHANDLE_TABLE_ENTRY CidEntry;
648 PETHREAD FoundThread;
649 NTSTATUS Status = STATUS_INVALID_PARAMETER;
650 PAGED_CODE();
651 PSTRACE(PS_THREAD_DEBUG, "ThreadId: %p\n", ThreadId);
652 KeEnterCriticalRegion();
653
654 /* Get the CID Handle Entry */
655 CidEntry = ExMapHandleToPointer(PspCidTable, ThreadId);
656 if (CidEntry)
657 {
658 /* Get the Process */
659 FoundThread = CidEntry->Object;
660
661 /* Make sure it's really a process */
662 if (FoundThread->Tcb.DispatcherHeader.Type == ThreadObject)
663 {
664 /* Safe Reference and return it */
665 if (ObReferenceObjectSafe(FoundThread))
666 {
667 *Thread = FoundThread;
668 Status = STATUS_SUCCESS;
669 }
670 }
671
672 /* Unlock the Entry */
673 ExUnlockHandleTableEntry(PspCidTable, CidEntry);
674 }
675
676 /* Return to caller */
677 KeLeaveCriticalRegion();
678 return Status;
679 }
680
681 /*
682 * @implemented
683 */
684 HANDLE
685 NTAPI
686 PsGetCurrentThreadId(VOID)
687 {
688 return PsGetCurrentThread()->Cid.UniqueThread;
689 }
690
691 /*
692 * @implemented
693 */
694 ULONG
695 NTAPI
696 PsGetThreadFreezeCount(IN PETHREAD Thread)
697 {
698 return Thread->Tcb.FreezeCount;
699 }
700
701 /*
702 * @implemented
703 */
704 BOOLEAN
705 NTAPI
706 PsGetThreadHardErrorsAreDisabled(IN PETHREAD Thread)
707 {
708 return Thread->HardErrorsAreDisabled ? TRUE : FALSE;
709 }
710
711 /*
712 * @implemented
713 */
714 HANDLE
715 NTAPI
716 PsGetThreadId(IN PETHREAD Thread)
717 {
718 return Thread->Cid.UniqueThread;
719 }
720
721 /*
722 * @implemented
723 */
724 PEPROCESS
725 NTAPI
726 PsGetThreadProcess(IN PETHREAD Thread)
727 {
728 return Thread->ThreadsProcess;
729 }
730
731 /*
732 * @implemented
733 */
734 HANDLE
735 NTAPI
736 PsGetThreadProcessId(IN PETHREAD Thread)
737 {
738 return Thread->Cid.UniqueProcess;
739 }
740
741 /*
742 * @implemented
743 */
744 HANDLE
745 NTAPI
746 PsGetThreadSessionId(IN PETHREAD Thread)
747 {
748 return (HANDLE)Thread->ThreadsProcess->Session;
749 }
750
751 /*
752 * @implemented
753 */
754 PTEB
755 NTAPI
756 PsGetThreadTeb(IN PETHREAD Thread)
757 {
758 return Thread->Tcb.Teb;
759 }
760
761 /*
762 * @implemented
763 */
764 PVOID
765 NTAPI
766 PsGetThreadWin32Thread(IN PETHREAD Thread)
767 {
768 return Thread->Tcb.Win32Thread;
769 }
770
771 /*
772 * @implemented
773 */
774 KPROCESSOR_MODE
775 NTAPI
776 PsGetCurrentThreadPreviousMode(VOID)
777 {
778 return (KPROCESSOR_MODE)PsGetCurrentThread()->Tcb.PreviousMode;
779 }
780
781 /*
782 * @implemented
783 */
784 PVOID
785 NTAPI
786 PsGetCurrentThreadStackBase(VOID)
787 {
788 return PsGetCurrentThread()->Tcb.StackBase;
789 }
790
791 /*
792 * @implemented
793 */
794 PVOID
795 NTAPI
796 PsGetCurrentThreadStackLimit(VOID)
797 {
798 return (PVOID)PsGetCurrentThread()->Tcb.StackLimit;
799 }
800
801 /*
802 * @implemented
803 */
804 BOOLEAN
805 NTAPI
806 PsIsThreadTerminating(IN PETHREAD Thread)
807 {
808 return Thread->Terminated ? TRUE : FALSE;
809 }
810
811 /*
812 * @implemented
813 */
814 BOOLEAN
815 NTAPI
816 PsIsSystemThread(IN PETHREAD Thread)
817 {
818 return Thread->SystemThread ? TRUE: FALSE;
819 }
820
821 /*
822 * @implemented
823 */
824 BOOLEAN
825 NTAPI
826 PsIsThreadImpersonating(IN PETHREAD Thread)
827 {
828 return Thread->ActiveImpersonationInfo ? TRUE : FALSE;
829 }
830
831 /*
832 * @implemented
833 */
834 VOID
835 NTAPI
836 PsSetThreadHardErrorsAreDisabled(IN PETHREAD Thread,
837 IN BOOLEAN HardErrorsAreDisabled)
838 {
839 Thread->HardErrorsAreDisabled = HardErrorsAreDisabled;
840 }
841
842 /*
843 * @implemented
844 */
845 struct _W32THREAD*
846 NTAPI
847 PsGetCurrentThreadWin32Thread(VOID)
848 {
849 return PsGetCurrentThread()->Tcb.Win32Thread;
850 }
851
852 /*
853 * @implemented
854 */
855 VOID
856 NTAPI
857 PsSetThreadWin32Thread(IN PETHREAD Thread,
858 IN PVOID Win32Thread)
859 {
860 Thread->Tcb.Win32Thread = Win32Thread;
861 }
862
863 NTSTATUS
864 NTAPI
865 NtCreateThread(OUT PHANDLE ThreadHandle,
866 IN ACCESS_MASK DesiredAccess,
867 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
868 IN HANDLE ProcessHandle,
869 OUT PCLIENT_ID ClientId,
870 IN PCONTEXT ThreadContext,
871 IN PINITIAL_TEB InitialTeb,
872 IN BOOLEAN CreateSuspended)
873 {
874 INITIAL_TEB SafeInitialTeb;
875 NTSTATUS Status = STATUS_SUCCESS;
876 PAGED_CODE();
877 PSTRACE(PS_THREAD_DEBUG,
878 "ProcessHandle: %p Context: %p\n", ProcessHandle, ThreadContext);
879
880 /* Check if this was from user-mode */
881 if (KeGetPreviousMode() != KernelMode)
882 {
883 /* Make sure that we got a context */
884 if (!ThreadContext) return STATUS_INVALID_PARAMETER;
885
886 /* Protect checks */
887 _SEH_TRY
888 {
889 /* Make sure the handle pointer we got is valid */
890 ProbeForWriteHandle(ThreadHandle);
891
892 /* Check if the caller wants a client id */
893 if(ClientId)
894 {
895 /* Make sure we can write to it */
896 ProbeForWrite(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));
897 }
898
899 /* Make sure that the entire context is readable */
900 ProbeForRead(ThreadContext, sizeof(CONTEXT), sizeof(ULONG));
901
902 /* Check the Initial TEB */
903 ProbeForRead(InitialTeb, sizeof(INITIAL_TEB), sizeof(ULONG));
904 SafeInitialTeb = *InitialTeb;
905 }
906 _SEH_HANDLE
907 {
908 Status = _SEH_GetExceptionCode();
909 }
910 _SEH_END;
911 if (!NT_SUCCESS(Status)) return Status;
912 }
913 else
914 {
915 /* Use the Initial TEB as is */
916 SafeInitialTeb = *InitialTeb;
917 }
918
919 /* Call the shared function */
920 return PspCreateThread(ThreadHandle,
921 DesiredAccess,
922 ObjectAttributes,
923 ProcessHandle,
924 NULL,
925 ClientId,
926 ThreadContext,
927 &SafeInitialTeb,
928 CreateSuspended,
929 NULL,
930 NULL);
931 }
932
933 /*
934 * @implemented
935 */
936 NTSTATUS
937 NTAPI
938 NtOpenThread(OUT PHANDLE ThreadHandle,
939 IN ACCESS_MASK DesiredAccess,
940 IN POBJECT_ATTRIBUTES ObjectAttributes,
941 IN PCLIENT_ID ClientId OPTIONAL)
942 {
943 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
944 CLIENT_ID SafeClientId;
945 ULONG Attributes = 0;
946 HANDLE hThread = NULL;
947 NTSTATUS Status = STATUS_SUCCESS;
948 PETHREAD Thread;
949 BOOLEAN HasObjectName = FALSE;
950 ACCESS_STATE AccessState;
951 AUX_DATA AuxData;
952 PAGED_CODE();
953 PSTRACE(PS_THREAD_DEBUG,
954 "ClientId: %p ObjectAttributes: %p\n", ClientId, ObjectAttributes);
955
956 /* Check if we were called from user mode */
957 if (PreviousMode != KernelMode)
958 {
959 /* Enter SEH for probing */
960 _SEH_TRY
961 {
962 /* Probe the thread handle */
963 ProbeForWriteHandle(ThreadHandle);
964
965 /* Check for a CID structure */
966 if (ClientId)
967 {
968 /* Probe and capture it */
969 ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));
970 SafeClientId = *ClientId;
971 ClientId = &SafeClientId;
972 }
973
974 /*
975 * Just probe the object attributes structure, don't capture it
976 * completely. This is done later if necessary
977 */
978 ProbeForRead(ObjectAttributes,
979 sizeof(OBJECT_ATTRIBUTES),
980 sizeof(ULONG));
981 HasObjectName = (ObjectAttributes->ObjectName != NULL);
982 Attributes = ObjectAttributes->Attributes;
983 }
984 _SEH_HANDLE
985 {
986 /* Get the exception code */
987 Status = _SEH_GetExceptionCode();
988 }
989 _SEH_END;
990 if (!NT_SUCCESS(Status)) return Status;
991 }
992 else
993 {
994 /* Otherwise just get the data directly */
995 HasObjectName = (ObjectAttributes->ObjectName != NULL);
996 Attributes = ObjectAttributes->Attributes;
997 }
998
999 /* Can't pass both, fail */
1000 if ((HasObjectName) && (ClientId)) return STATUS_INVALID_PARAMETER_MIX;
1001
1002 /* Create an access state */
1003 Status = SeCreateAccessState(&AccessState,
1004 &AuxData,
1005 DesiredAccess,
1006 &PsProcessType->TypeInfo.GenericMapping);
1007 if (!NT_SUCCESS(Status)) return Status;
1008
1009 /* Check if this is a debugger */
1010 if (SeSinglePrivilegeCheck(SeDebugPrivilege, PreviousMode))
1011 {
1012 /* Did he want full access? */
1013 if (AccessState.RemainingDesiredAccess & MAXIMUM_ALLOWED)
1014 {
1015 /* Give it to him */
1016 AccessState.PreviouslyGrantedAccess |= THREAD_ALL_ACCESS;
1017 }
1018 else
1019 {
1020 /* Otherwise just give every other access he could want */
1021 AccessState.PreviouslyGrantedAccess |=
1022 AccessState.RemainingDesiredAccess;
1023 }
1024
1025 /* The caller desires nothing else now */
1026 AccessState.RemainingDesiredAccess = 0;
1027 }
1028
1029 /* Open by name if one was given */
1030 if (HasObjectName)
1031 {
1032 /* Open it */
1033 Status = ObOpenObjectByName(ObjectAttributes,
1034 PsThreadType,
1035 PreviousMode,
1036 &AccessState,
1037 0,
1038 NULL,
1039 &hThread);
1040
1041 /* Get rid of the access state */
1042 SeDeleteAccessState(&AccessState);
1043 }
1044 else if (ClientId)
1045 {
1046 /* Open by Thread ID */
1047 if (ClientId->UniqueProcess)
1048 {
1049 /* Get the Process */
1050 Status = PsLookupProcessThreadByCid(ClientId, NULL, &Thread);
1051 }
1052 else
1053 {
1054 /* Get the Process */
1055 Status = PsLookupThreadByThreadId(ClientId->UniqueThread, &Thread);
1056 }
1057
1058 /* Check if we didn't find anything */
1059 if (!NT_SUCCESS(Status))
1060 {
1061 /* Get rid of the access state and return */
1062 SeDeleteAccessState(&AccessState);
1063 return Status;
1064 }
1065
1066 /* Open the Thread Object */
1067 Status = ObOpenObjectByPointer(Thread,
1068 Attributes,
1069 &AccessState,
1070 0,
1071 PsThreadType,
1072 PreviousMode,
1073 &hThread);
1074
1075 /* Delete the access state and dereference the thread */
1076 SeDeleteAccessState(&AccessState);
1077 ObDereferenceObject(Thread);
1078 }
1079 else
1080 {
1081 /* Neither an object name nor a client id was passed */
1082 return STATUS_INVALID_PARAMETER_MIX;
1083 }
1084
1085 /* Check for success */
1086 if (NT_SUCCESS(Status))
1087 {
1088 /* Protect against bad user-mode pointers */
1089 _SEH_TRY
1090 {
1091 /* Write back the handle */
1092 *ThreadHandle = hThread;
1093 }
1094 _SEH_HANDLE
1095 {
1096 /* Get the exception code */
1097 Status = _SEH_GetExceptionCode();
1098 }
1099 _SEH_END;
1100 }
1101
1102 /* Return status */
1103 return Status;
1104 }
1105
1106 /* EOF */