2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ps/thread.c
5 * PURPOSE: Thread managment
7 * PROGRAMMERS: David Welch (welch@mcmail.com)
11 /* INCLUDES ****************************************************************/
15 #include <internal/debug.h>
17 /* GLOBALS ******************************************************************/
19 extern LIST_ENTRY PsActiveProcessHead
;
20 extern PEPROCESS PsIdleProcess
;
21 extern PVOID PspSystemDllEntryPoint
;
22 extern PHANDLE_TABLE PspCidTable
;
24 POBJECT_TYPE EXPORTED PsThreadType
= NULL
;
26 /* FUNCTIONS ***************************************************************/
30 PspThreadSpecialApc(PKAPC Apc
,
31 PKNORMAL_ROUTINE
* NormalRoutine
,
33 PVOID
* SystemArgument1
,
34 PVOID
* SystemArgument2
)
41 PspUserThreadStartup(PKSTART_ROUTINE StartRoutine
,
45 PETHREAD Thread
= PsGetCurrentThread();
47 DPRINT("I am a new USER thread. This is my start routine: %p. This my context: %p."
48 "This is my IRQL: %d. This is my Thread Pointer: %x.\n", StartRoutine
,
49 StartContext
, KeGetCurrentIrql(), Thread
);
51 if (!Thread
->Terminated
) {
53 /* Allocate the APC */
54 ThreadApc
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(KAPC
), TAG('T', 'h', 'r','d'));
57 KeInitializeApc(ThreadApc
,
59 OriginalApcEnvironment
,
62 PspSystemDllEntryPoint
,
66 /* Insert it into the queue */
67 KeInsertQueueApc(ThreadApc
, NULL
, NULL
, IO_NO_INCREMENT
);
68 Thread
->Tcb
.ApcState
.UserApcPending
= TRUE
;
71 /* Go to Passive Level and notify debugger */
72 KeLowerIrql(PASSIVE_LEVEL
);
73 DbgkCreateThread(StartContext
);
78 PspSystemThreadStartup(PKSTART_ROUTINE StartRoutine
,
81 PETHREAD Thread
= PsGetCurrentThread();
83 /* Unlock the dispatcher Database */
84 KeLowerIrql(PASSIVE_LEVEL
);
86 /* Make sure it's not terminated by now */
87 if (!Thread
->Terminated
) {
90 (StartRoutine
)(StartContext
);
94 PspExitThread(STATUS_SUCCESS
);
99 PspCreateThread(OUT PHANDLE ThreadHandle
,
100 IN ACCESS_MASK DesiredAccess
,
101 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
102 IN HANDLE ProcessHandle
,
103 IN PEPROCESS TargetProcess
,
104 OUT PCLIENT_ID ClientId
,
105 IN PCONTEXT ThreadContext
,
106 IN PINITIAL_TEB InitialTeb
,
107 IN BOOLEAN CreateSuspended
,
108 IN PKSTART_ROUTINE StartRoutine OPTIONAL
,
109 IN PVOID StartContext OPTIONAL
)
116 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
118 HANDLE_TABLE_ENTRY CidEntry
;
121 /* Reference the Process by handle or pointer, depending on what we got */
122 DPRINT("PspCreateThread: %x, %x, %x\n", ProcessHandle
, TargetProcess
, ThreadContext
);
125 /* Normal thread or System Thread */
126 DPRINT("Referencing Parent Process\n");
127 Status
= ObReferenceObjectByHandle(ProcessHandle
,
128 PROCESS_CREATE_THREAD
,
135 /* System thread inside System Process, or Normal Thread with a bug */
138 /* Reference the Process by Pointer */
139 DPRINT("Referencing Parent System Process\n");
140 ObReferenceObject(TargetProcess
);
141 Process
= TargetProcess
;
142 Status
= STATUS_SUCCESS
;
146 /* Fake ObReference returning this */
147 Status
= STATUS_INVALID_HANDLE
;
151 /* Check for success */
152 if(!NT_SUCCESS(Status
)) {
154 DPRINT1("Invalid Process Handle, or no handle given\n");
158 /* Create Thread Object */
159 DPRINT("Creating Thread Object\n");
160 Status
= ObCreateObject(PreviousMode
,
170 /* Check for success */
171 if (!NT_SUCCESS(Status
)) {
173 /* Dereference the Process */
174 DPRINT1("Failed to Create Thread Object\n");
175 ObDereferenceObject(Process
);
179 /* Zero the Object entirely */
180 DPRINT("Cleaning Thread Object\n");
181 RtlZeroMemory(Thread
, sizeof(ETHREAD
));
183 /* Create Cid Handle */
184 DPRINT("Creating Thread Handle (CID)\n");
185 CidEntry
.u1
.Object
= Thread
;
186 CidEntry
.u2
.GrantedAccess
= 0;
187 Thread
->Cid
.UniqueThread
= ExCreateHandle(PspCidTable
, &CidEntry
);
188 if (!Thread
->Cid
.UniqueThread
) {
190 DPRINT1("Failed to create Thread Handle (CID)\n");
191 ObDereferenceObject(Process
);
192 ObDereferenceObject(Thread
);
193 return STATUS_INSUFFICIENT_RESOURCES
;
196 /* Initialize Lists */
197 DPRINT("Initialliazing Thread Lists and Locks\n");
198 InitializeListHead(&Thread
->LpcReplyChain
);
199 InitializeListHead(&Thread
->IrpList
);
200 InitializeListHead(&Thread
->ActiveTimerListHead
);
201 KeInitializeSpinLock(&Thread
->ActiveTimerListLock
);
204 DPRINT("Initialliazing Thread Semaphore\n");
205 KeInitializeSemaphore(&Thread
->LpcReplySemaphore
, 0, MAXLONG
);
207 /* Allocate Stack for non-GUI Thread */
208 DPRINT("Initialliazing Thread Stack\n");
209 KernelStack
= MmCreateKernelStack(FALSE
);
211 /* Set the Process CID */
212 DPRINT("Initialliazing Thread PID and Parent Process\n");
213 Thread
->Cid
.UniqueProcess
= Process
->UniqueProcessId
;
214 Thread
->ThreadsProcess
= Process
;
216 /* Now let the kernel initialize the context */
219 /* User-mode Thread */
222 DPRINT("Initialliazing Thread PEB\n");
223 TebBase
= MmCreateTeb(Process
, &Thread
->Cid
, InitialTeb
);
225 /* Set the Start Addresses */
226 DPRINT("Initialliazing Thread Start Addresses :%x, %x\n", ThreadContext
->Eip
, ThreadContext
->Eax
);
227 Thread
->StartAddress
= (PVOID
)ThreadContext
->Eip
;
228 Thread
->Win32StartAddress
= (PVOID
)ThreadContext
->Eax
;
230 /* Let the kernel intialize the Thread */
231 DPRINT("Initialliazing Kernel Thread\n");
232 KeInitializeThread(&Process
->Pcb
,
234 PspUserThreadStartup
,
244 DPRINT("Initialliazing Thread Start Address :%x\n", StartRoutine
);
245 Thread
->StartAddress
= StartRoutine
;
246 Thread
->SystemThread
= TRUE
;
248 /* Let the kernel intialize the Thread */
249 DPRINT("Initialliazing Kernel Thread\n");
250 KeInitializeThread(&Process
->Pcb
,
252 PspSystemThreadStartup
,
261 * Insert the Thread into the Process's Thread List
262 * Note, this is the ETHREAD Thread List. It is removed in
263 * ps/kill.c!PspExitThread.
265 DPRINT("Inserting into Process Thread List \n");
266 InsertTailList(&Process
->ThreadListHead
, &Thread
->ThreadListEntry
);
268 /* Notify Thread Creation */
269 DPRINT("Running Thread Notify \n");
270 PspRunCreateThreadNotifyRoutines(Thread
, TRUE
);
272 /* FIXME: Use Lock */
273 DPRINT("Apcs Queueable: %d \n", Thread
->Tcb
.ApcQueueable
);
274 Thread
->Tcb
.ApcQueueable
= TRUE
;
276 /* Suspend the Thread if we have to */
277 if (CreateSuspended
) {
279 DPRINT("Suspending Thread\n");
280 KeSuspendThread(&Thread
->Tcb
);
283 /* Reference ourselves as a keep-alive */
284 ObReferenceObject(Thread
);
286 /* Insert the Thread into the Object Manager */
287 DPRINT("Inserting Thread\n");
288 Status
= ObInsertObject((PVOID
)Thread
,
295 /* Return Cid and Handle */
296 DPRINT("All worked great!\n");
297 if(NT_SUCCESS(Status
)) {
301 if(ClientId
!= NULL
) {
303 *ClientId
= Thread
->Cid
;
305 *ThreadHandle
= hThread
;
309 Status
= _SEH_GetExceptionCode();
314 /* FIXME: SECURITY */
316 /* Dispatch thread */
317 DPRINT("About to dispatch the thread: %x!\n", &Thread
->Tcb
);
318 OldIrql
= KeAcquireDispatcherDatabaseLock ();
319 KiUnblockThread(&Thread
->Tcb
, NULL
, 0);
320 ObDereferenceObject(Thread
);
321 KeReleaseDispatcherDatabaseLock(OldIrql
);
324 DPRINT("Returning\n");
333 PsCreateSystemThread(PHANDLE ThreadHandle
,
334 ACCESS_MASK DesiredAccess
,
335 POBJECT_ATTRIBUTES ObjectAttributes
,
336 HANDLE ProcessHandle
,
338 PKSTART_ROUTINE StartRoutine
,
341 PEPROCESS TargetProcess
= NULL
;
342 HANDLE Handle
= ProcessHandle
;
344 /* Check if we have a handle. If not, use the System Process */
345 if (!ProcessHandle
) {
348 TargetProcess
= PsInitialSystemProcess
;
351 /* Call the shared function */
352 return PspCreateThread(ThreadHandle
,
370 PsLookupThreadByThreadId(IN HANDLE ThreadId
,
371 OUT PETHREAD
*Thread
)
373 PHANDLE_TABLE_ENTRY CidEntry
;
374 PETHREAD FoundThread
;
375 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
378 /* Get the CID Handle Entry */
379 if ((CidEntry
= ExMapHandleToPointer(PspCidTable
,
382 /* Get the Process */
383 FoundThread
= CidEntry
->u1
.Object
;
385 /* Make sure it's really a process */
386 if (FoundThread
->Tcb
.DispatcherHeader
.Type
== ThreadObject
)
388 /* Reference and return it */
389 ObReferenceObject(FoundThread
);
390 *Thread
= FoundThread
;
391 Status
= STATUS_SUCCESS
;
394 /* Unlock the Entry */
395 ExUnlockHandleTableEntry(PspCidTable
, CidEntry
);
398 /* Return to caller */
407 PsGetCurrentThreadId(VOID
)
409 return(PsGetCurrentThread()->Cid
.UniqueThread
);
417 PsGetThreadFreezeCount(PETHREAD Thread
)
419 return Thread
->Tcb
.FreezeCount
;
427 PsGetThreadHardErrorsAreDisabled(PETHREAD Thread
)
429 return Thread
->HardErrorsAreDisabled
;
437 PsGetThreadId(PETHREAD Thread
)
439 return Thread
->Cid
.UniqueThread
;
447 PsGetThreadProcess(PETHREAD Thread
)
449 return Thread
->ThreadsProcess
;
457 PsGetThreadProcessId(PETHREAD Thread
)
459 return Thread
->Cid
.UniqueProcess
;
467 PsGetThreadSessionId(PETHREAD Thread
)
469 return (HANDLE
)Thread
->ThreadsProcess
->Session
;
477 PsGetThreadTeb(PETHREAD Thread
)
479 return Thread
->Tcb
.Teb
;
487 PsGetThreadWin32Thread(PETHREAD Thread
)
489 return Thread
->Tcb
.Win32Thread
;
497 PsGetCurrentThreadPreviousMode(VOID
)
499 return (KPROCESSOR_MODE
)PsGetCurrentThread()->Tcb
.PreviousMode
;
507 PsGetCurrentThreadStackBase(VOID
)
509 return PsGetCurrentThread()->Tcb
.StackBase
;
517 PsGetCurrentThreadStackLimit(VOID
)
519 return (PVOID
)PsGetCurrentThread()->Tcb
.StackLimit
;
527 PsIsThreadTerminating(IN PETHREAD Thread
)
529 return (Thread
->Terminated
? TRUE
: FALSE
);
537 PsIsSystemThread(PETHREAD Thread
)
539 return (Thread
->SystemThread
? TRUE
: FALSE
);
547 PsIsThreadImpersonating(PETHREAD Thread
)
549 return Thread
->ActiveImpersonationInfo
;
557 PsSetThreadHardErrorsAreDisabled(PETHREAD Thread
,
558 BOOLEAN HardErrorsAreDisabled
)
560 Thread
->HardErrorsAreDisabled
= HardErrorsAreDisabled
;
568 PsSetThreadWin32Thread(PETHREAD Thread
,
571 Thread
->Tcb
.Win32Thread
= Win32Thread
;
576 NtCreateThread(OUT PHANDLE ThreadHandle
,
577 IN ACCESS_MASK DesiredAccess
,
578 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
579 IN HANDLE ProcessHandle
,
580 OUT PCLIENT_ID ClientId
,
581 IN PCONTEXT ThreadContext
,
582 IN PINITIAL_TEB InitialTeb
,
583 IN BOOLEAN CreateSuspended
)
585 INITIAL_TEB SafeInitialTeb
;
589 DPRINT("NtCreateThread(ThreadHandle %x, PCONTEXT %x)\n",
590 ThreadHandle
,ThreadContext
);
592 if(KeGetPreviousMode() != KernelMode
) {
596 ProbeForWrite(ThreadHandle
,
600 if(ClientId
!= NULL
) {
602 ProbeForWrite(ClientId
,
607 if(ThreadContext
!= NULL
) {
609 ProbeForRead(ThreadContext
,
615 DPRINT1("No context for User-Mode Thread!!\n");
616 return STATUS_INVALID_PARAMETER
;
619 ProbeForRead(InitialTeb
,
625 return _SEH_GetExceptionCode();
630 /* Use probed data for the Initial TEB */
631 SafeInitialTeb
= *InitialTeb
;
632 InitialTeb
= &SafeInitialTeb
;
634 /* Call the shared function */
635 return PspCreateThread(ThreadHandle
,
653 NtOpenThread(OUT PHANDLE ThreadHandle
,
654 IN ACCESS_MASK DesiredAccess
,
655 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
656 IN PCLIENT_ID ClientId OPTIONAL
)
658 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
659 CLIENT_ID SafeClientId
;
661 NTSTATUS Status
= STATUS_SUCCESS
;
666 /* Probe the paraemeters */
667 if(PreviousMode
!= KernelMode
)
671 ProbeForWrite(ThreadHandle
,
677 ProbeForRead(ClientId
,
681 SafeClientId
= *ClientId
;
682 ClientId
= &SafeClientId
;
687 Status
= _SEH_GetExceptionCode();
691 if(!NT_SUCCESS(Status
)) return Status
;
694 /* Open by name if one was given */
695 if (ObjectAttributes
->ObjectName
)
698 Status
= ObOpenObjectByName(ObjectAttributes
,
706 if (Status
!= STATUS_SUCCESS
)
708 DPRINT1("Could not open object by name\n");
716 /* Open by Thread ID */
717 if (ClientId
->UniqueProcess
)
719 /* Get the Process */
720 DPRINT("Opening by Process ID: %x\n", ClientId
->UniqueProcess
);
721 Status
= PsLookupProcessThreadByCid(ClientId
,
727 /* Get the Process */
728 DPRINT("Opening by Thread ID: %x\n", ClientId
->UniqueThread
);
729 Status
= PsLookupThreadByThreadId(ClientId
->UniqueThread
,
733 if(!NT_SUCCESS(Status
))
735 DPRINT1("Failure to find Thread\n");
739 /* Open the Thread Object */
740 Status
= ObOpenObjectByPointer(Thread
,
741 ObjectAttributes
->Attributes
,
747 if(!NT_SUCCESS(Status
))
749 DPRINT1("Failure to open Thread\n");
752 /* Dereference the thread */
753 ObDereferenceObject(Thread
);
756 /* Write back the handle */
757 if(NT_SUCCESS(Status
))
761 *ThreadHandle
= hThread
;
765 Status
= _SEH_GetExceptionCode();
776 NtYieldExecution(VOID
)
778 KiDispatchThread(Ready
);
779 return(STATUS_SUCCESS
);
786 /* Check and Alert Thread if needed */
787 return KeTestAlertThread(ExGetPreviousMode()) ? STATUS_ALERTED
: STATUS_SUCCESS
;
795 ExGetPreviousMode (VOID
)
797 return (KPROCESSOR_MODE
)PsGetCurrentThread()->Tcb
.PreviousMode
;