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
;
23 POBJECT_TYPE EXPORTED PsThreadType
= NULL
;
25 /* FUNCTIONS ***************************************************************/
29 PspThreadSpecialApc(PKAPC Apc
,
30 PKNORMAL_ROUTINE
* NormalRoutine
,
32 PVOID
* SystemArgument1
,
33 PVOID
* SystemArgument2
)
40 PspUserThreadStartup(PKSTART_ROUTINE StartRoutine
,
44 PETHREAD Thread
= PsGetCurrentThread();
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
);
50 if (!Thread
->Terminated
) {
52 /* Allocate the APC */
53 ThreadApc
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(KAPC
), TAG('T', 'h', 'r','d'));
56 KeInitializeApc(ThreadApc
,
58 OriginalApcEnvironment
,
61 PspSystemDllEntryPoint
,
65 /* Insert it into the queue */
66 KeInsertQueueApc(ThreadApc
, NULL
, NULL
, IO_NO_INCREMENT
);
67 Thread
->Tcb
.ApcState
.UserApcPending
= TRUE
;
70 /* Go to Passive Level and notify debugger */
71 KeLowerIrql(PASSIVE_LEVEL
);
72 DbgkCreateThread(StartContext
);
77 PspSystemThreadStartup(PKSTART_ROUTINE StartRoutine
,
80 PETHREAD Thread
= PsGetCurrentThread();
82 /* Unlock the dispatcher Database */
83 KeLowerIrql(PASSIVE_LEVEL
);
85 /* Make sure it's not terminated by now */
86 if (!Thread
->Terminated
) {
89 (StartRoutine
)(StartContext
);
93 PspExitThread(STATUS_SUCCESS
);
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
)
115 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
119 /* Reference the Process by handle or pointer, depending on what we got */
120 DPRINT("PspCreateThread: %x, %x, %x\n", ProcessHandle
, TargetProcess
, ThreadContext
);
123 /* Normal thread or System Thread */
124 DPRINT("Referencing Parent Process\n");
125 Status
= ObReferenceObjectByHandle(ProcessHandle
,
126 PROCESS_CREATE_THREAD
,
133 /* System thread inside System Process, or Normal Thread with a bug */
136 /* Reference the Process by Pointer */
137 DPRINT("Referencing Parent System Process\n");
138 ObReferenceObject(TargetProcess
);
139 Process
= TargetProcess
;
140 Status
= STATUS_SUCCESS
;
144 /* Fake ObReference returning this */
145 Status
= STATUS_INVALID_HANDLE
;
149 /* Check for success */
150 if(!NT_SUCCESS(Status
)) {
152 DPRINT1("Invalid Process Handle, or no handle given\n");
156 /* Create Thread Object */
157 DPRINT("Creating Thread Object\n");
158 Status
= ObCreateObject(PreviousMode
,
168 /* Check for success */
169 if (!NT_SUCCESS(Status
)) {
171 /* Dereference the Process */
172 DPRINT1("Failed to Create Thread Object\n");
173 ObDereferenceObject(Process
);
177 /* Zero the Object entirely */
178 DPRINT("Cleaning Thread Object\n");
179 RtlZeroMemory(Thread
, sizeof(ETHREAD
));
181 /* Create Cid Handle */
182 DPRINT("Creating Thread Handle (CID)\n");
183 if (!(NT_SUCCESS(PsCreateCidHandle(Thread
, PsThreadType
, &Thread
->Cid
.UniqueThread
)))) {
185 DPRINT1("Failed to create Thread Handle (CID)\n");
186 ObDereferenceObject(Process
);
187 ObDereferenceObject(Thread
);
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
);
199 DPRINT("Initialliazing Thread Semaphore\n");
200 KeInitializeSemaphore(&Thread
->LpcReplySemaphore
, 0, MAXLONG
);
202 /* Allocate Stack for non-GUI Thread */
203 DPRINT("Initialliazing Thread Stack\n");
204 KernelStack
= MmCreateKernelStack(FALSE
);
206 /* Set the Process CID */
207 DPRINT("Initialliazing Thread PID and Parent Process\n");
208 Thread
->Cid
.UniqueProcess
= Process
->UniqueProcessId
;
209 Thread
->ThreadsProcess
= Process
;
211 /* Now let the kernel initialize the context */
214 /* User-mode Thread */
217 DPRINT("Initialliazing Thread PEB\n");
218 TebBase
= MmCreateTeb(Process
, &Thread
->Cid
, InitialTeb
);
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
;
225 /* Let the kernel intialize the Thread */
226 DPRINT("Initialliazing Kernel Thread\n");
227 KeInitializeThread(&Process
->Pcb
,
229 PspUserThreadStartup
,
239 DPRINT("Initialliazing Thread Start Address :%x\n", StartRoutine
);
240 Thread
->StartAddress
= StartRoutine
;
241 Thread
->SystemThread
= TRUE
;
243 /* Let the kernel intialize the Thread */
244 DPRINT("Initialliazing Kernel Thread\n");
245 KeInitializeThread(&Process
->Pcb
,
247 PspSystemThreadStartup
,
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.
260 DPRINT("Inserting into Process Thread List \n");
261 InsertTailList(&Process
->ThreadListHead
, &Thread
->ThreadListEntry
);
263 /* Notify Thread Creation */
264 DPRINT("Running Thread Notify \n");
265 PspRunCreateThreadNotifyRoutines(Thread
, TRUE
);
267 /* FIXME: Use Lock */
268 DPRINT("Apcs Queueable: %d \n", Thread
->Tcb
.ApcQueueable
);
269 Thread
->Tcb
.ApcQueueable
= TRUE
;
271 /* Suspend the Thread if we have to */
272 if (CreateSuspended
) {
274 DPRINT("Suspending Thread\n");
275 KeSuspendThread(&Thread
->Tcb
);
278 /* Reference ourselves as a keep-alive */
279 ObReferenceObject(Thread
);
281 /* Insert the Thread into the Object Manager */
282 DPRINT("Inserting Thread\n");
283 Status
= ObInsertObject((PVOID
)Thread
,
290 /* Return Cid and Handle */
291 DPRINT("All worked great!\n");
292 if(NT_SUCCESS(Status
)) {
296 if(ClientId
!= NULL
) {
298 *ClientId
= Thread
->Cid
;
300 *ThreadHandle
= hThread
;
304 Status
= _SEH_GetExceptionCode();
309 /* FIXME: SECURITY */
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
);
319 DPRINT("Returning\n");
328 PsCreateSystemThread(PHANDLE ThreadHandle
,
329 ACCESS_MASK DesiredAccess
,
330 POBJECT_ATTRIBUTES ObjectAttributes
,
331 HANDLE ProcessHandle
,
333 PKSTART_ROUTINE StartRoutine
,
336 PEPROCESS TargetProcess
= NULL
;
337 HANDLE Handle
= ProcessHandle
;
339 /* Check if we have a handle. If not, use the System Process */
340 if (!ProcessHandle
) {
343 TargetProcess
= PsInitialSystemProcess
;
346 /* Call the shared function */
347 return PspCreateThread(ThreadHandle
,
365 PsGetCurrentThreadId(VOID
)
367 return(PsGetCurrentThread()->Cid
.UniqueThread
);
375 PsGetThreadFreezeCount(PETHREAD Thread
)
377 return Thread
->Tcb
.FreezeCount
;
385 PsGetThreadHardErrorsAreDisabled(PETHREAD Thread
)
387 return Thread
->HardErrorsAreDisabled
;
395 PsGetThreadId(PETHREAD Thread
)
397 return Thread
->Cid
.UniqueThread
;
405 PsGetThreadProcess(PETHREAD Thread
)
407 return Thread
->ThreadsProcess
;
415 PsGetThreadProcessId(PETHREAD Thread
)
417 return Thread
->Cid
.UniqueProcess
;
425 PsGetThreadSessionId(PETHREAD Thread
)
427 return (HANDLE
)Thread
->ThreadsProcess
->Session
;
435 PsGetThreadTeb(PETHREAD Thread
)
437 return Thread
->Tcb
.Teb
;
445 PsGetThreadWin32Thread(PETHREAD Thread
)
447 return Thread
->Tcb
.Win32Thread
;
455 PsGetCurrentThreadPreviousMode(VOID
)
457 return (KPROCESSOR_MODE
)PsGetCurrentThread()->Tcb
.PreviousMode
;
465 PsGetCurrentThreadStackBase(VOID
)
467 return PsGetCurrentThread()->Tcb
.StackBase
;
475 PsGetCurrentThreadStackLimit(VOID
)
477 return (PVOID
)PsGetCurrentThread()->Tcb
.StackLimit
;
485 PsIsThreadTerminating(IN PETHREAD Thread
)
487 return (Thread
->Terminated
? TRUE
: FALSE
);
495 PsIsSystemThread(PETHREAD Thread
)
497 return (Thread
->SystemThread
? TRUE
: FALSE
);
505 PsIsThreadImpersonating(PETHREAD Thread
)
507 return Thread
->ActiveImpersonationInfo
;
515 PsSetThreadHardErrorsAreDisabled(PETHREAD Thread
,
516 BOOLEAN HardErrorsAreDisabled
)
518 Thread
->HardErrorsAreDisabled
= HardErrorsAreDisabled
;
526 PsSetThreadWin32Thread(PETHREAD Thread
,
529 Thread
->Tcb
.Win32Thread
= Win32Thread
;
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
)
543 INITIAL_TEB SafeInitialTeb
;
547 DPRINT("NtCreateThread(ThreadHandle %x, PCONTEXT %x)\n",
548 ThreadHandle
,ThreadContext
);
550 if(KeGetPreviousMode() != KernelMode
) {
554 ProbeForWrite(ThreadHandle
,
558 if(ClientId
!= NULL
) {
560 ProbeForWrite(ClientId
,
565 if(ThreadContext
!= NULL
) {
567 ProbeForRead(ThreadContext
,
573 DPRINT1("No context for User-Mode Thread!!\n");
574 return STATUS_INVALID_PARAMETER
;
577 ProbeForRead(InitialTeb
,
583 return _SEH_GetExceptionCode();
588 /* Use probed data for the Initial TEB */
589 SafeInitialTeb
= *InitialTeb
;
590 InitialTeb
= &SafeInitialTeb
;
592 /* Call the shared function */
593 return PspCreateThread(ThreadHandle
,
611 NtOpenThread(OUT PHANDLE ThreadHandle
,
612 IN ACCESS_MASK DesiredAccess
,
613 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
614 IN PCLIENT_ID ClientId OPTIONAL
)
616 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
617 CLIENT_ID SafeClientId
;
619 NTSTATUS Status
= STATUS_SUCCESS
;
624 /* Probe the paraemeters */
625 if(PreviousMode
!= KernelMode
)
629 ProbeForWrite(ThreadHandle
,
635 ProbeForRead(ClientId
,
639 SafeClientId
= *ClientId
;
640 ClientId
= &SafeClientId
;
645 Status
= _SEH_GetExceptionCode();
649 if(!NT_SUCCESS(Status
)) return Status
;
652 /* Open by name if one was given */
653 if (ObjectAttributes
->ObjectName
)
656 Status
= ObOpenObjectByName(ObjectAttributes
,
664 if (Status
!= STATUS_SUCCESS
)
666 DPRINT1("Could not open object by name\n");
674 /* Open by Thread ID */
675 if (ClientId
->UniqueProcess
)
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
,
686 /* Get the Process */
687 DPRINT("Opening by Thread ID: %x\n", ClientId
->UniqueThread
);
688 Status
= PsLookupThreadByThreadId(ClientId
->UniqueThread
,
692 if(!NT_SUCCESS(Status
))
694 DPRINT1("Failure to find Thread\n");
698 /* Open the Thread Object */
699 Status
= ObOpenObjectByPointer(Thread
,
700 ObjectAttributes
->Attributes
,
706 if(!NT_SUCCESS(Status
))
708 DPRINT1("Failure to open Thread\n");
711 /* Dereference the thread */
712 ObDereferenceObject(Thread
);
715 /* Write back the handle */
716 if(NT_SUCCESS(Status
))
720 *ThreadHandle
= hThread
;
724 Status
= _SEH_GetExceptionCode();
735 NtYieldExecution(VOID
)
737 KiDispatchThread(Ready
);
738 return(STATUS_SUCCESS
);
745 /* Check and Alert Thread if needed */
746 return KeTestAlertThread(ExGetPreviousMode()) ? STATUS_ALERTED
: STATUS_SUCCESS
;
754 ExGetPreviousMode (VOID
)
756 return (KPROCESSOR_MODE
)PsGetCurrentThread()->Tcb
.PreviousMode
;