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