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
;
22 POBJECT_TYPE EXPORTED PsThreadType
= NULL
;
24 /* FUNCTIONS ***************************************************************/
28 PspThreadSpecialApc(PKAPC Apc
,
29 PKNORMAL_ROUTINE
* NormalRoutine
,
31 PVOID
* SystemArgument1
,
32 PVOID
* SystemArgument2
)
39 PspUserThreadStartup(PKSTART_ROUTINE StartRoutine
,
43 PETHREAD Thread
= PsGetCurrentThread();
45 DPRINT("I am a new USER thread. This is my start routine: %p. This my context: %p."
46 "This is my IRQL: %d. This is my Thread Pointer: %x.\n", StartRoutine
,
47 StartContext
, KeGetCurrentIrql(), Thread
);
49 if (!Thread
->Terminated
) {
51 /* Allocate the APC */
52 ThreadApc
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(KAPC
), TAG('T', 'h', 'r','d'));
55 KeInitializeApc(ThreadApc
,
57 OriginalApcEnvironment
,
60 LdrpGetSystemDllEntryPoint(),
64 /* Insert it into the queue */
65 KeInsertQueueApc(ThreadApc
, NULL
, NULL
, IO_NO_INCREMENT
);
66 Thread
->Tcb
.ApcState
.UserApcPending
= TRUE
;
69 /* Go to Passive Level and notify debugger */
70 KeLowerIrql(PASSIVE_LEVEL
);
71 DbgkCreateThread(StartContext
);
76 PspSystemThreadStartup(PKSTART_ROUTINE StartRoutine
,
79 PETHREAD Thread
= PsGetCurrentThread();
81 /* Unlock the dispatcher Database */
82 KeLowerIrql(PASSIVE_LEVEL
);
84 /* Make sure it's not terminated by now */
85 if (!Thread
->Terminated
) {
88 (StartRoutine
)(StartContext
);
92 PspExitThread(STATUS_SUCCESS
);
97 PspCreateThread(OUT PHANDLE ThreadHandle
,
98 IN ACCESS_MASK DesiredAccess
,
99 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
100 IN HANDLE ProcessHandle
,
101 IN PEPROCESS TargetProcess
,
102 OUT PCLIENT_ID ClientId
,
103 IN PCONTEXT ThreadContext
,
104 IN PINITIAL_TEB InitialTeb
,
105 IN BOOLEAN CreateSuspended
,
106 IN PKSTART_ROUTINE StartRoutine OPTIONAL
,
107 IN PVOID StartContext OPTIONAL
)
114 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
118 /* Reference the Process by handle or pointer, depending on what we got */
119 DPRINT("PspCreateThread: %x, %x, %x\n", ProcessHandle
, TargetProcess
, ThreadContext
);
122 /* Normal thread or System Thread */
123 DPRINT("Referencing Parent Process\n");
124 Status
= ObReferenceObjectByHandle(ProcessHandle
,
125 PROCESS_CREATE_THREAD
,
132 /* System thread inside System Process, or Normal Thread with a bug */
135 /* Reference the Process by Pointer */
136 DPRINT("Referencing Parent System Process\n");
137 ObReferenceObject(TargetProcess
);
138 Process
= TargetProcess
;
139 Status
= STATUS_SUCCESS
;
143 /* Fake ObReference returning this */
144 Status
= STATUS_INVALID_HANDLE
;
148 /* Check for success */
149 if(!NT_SUCCESS(Status
)) {
151 DPRINT1("Invalid Process Handle, or no handle given\n");
155 /* Create Thread Object */
156 DPRINT("Creating Thread Object\n");
157 Status
= ObCreateObject(PreviousMode
,
167 /* Check for success */
168 if (!NT_SUCCESS(Status
)) {
170 /* Dereference the Process */
171 DPRINT1("Failed to Create Thread Object\n");
172 ObDereferenceObject(Process
);
176 /* Zero the Object entirely */
177 DPRINT("Cleaning Thread Object\n");
178 RtlZeroMemory(Thread
, sizeof(ETHREAD
));
180 /* Create Cid Handle */
181 DPRINT("Creating Thread Handle (CID)\n");
182 if (!(NT_SUCCESS(PsCreateCidHandle(Thread
, PsThreadType
, &Thread
->Cid
.UniqueThread
)))) {
184 DPRINT1("Failed to create Thread Handle (CID)\n");
185 ObDereferenceObject(Process
);
186 ObDereferenceObject(Thread
);
190 /* Initialize Lists */
191 DPRINT("Initialliazing Thread Lists and Locks\n");
192 InitializeListHead(&Thread
->LpcReplyChain
);
193 InitializeListHead(&Thread
->IrpList
);
194 InitializeListHead(&Thread
->ActiveTimerListHead
);
195 KeInitializeSpinLock(&Thread
->ActiveTimerListLock
);
198 DPRINT("Initialliazing Thread Semaphore\n");
199 KeInitializeSemaphore(&Thread
->LpcReplySemaphore
, 0, LONG_MAX
);
201 /* Allocate Stack for non-GUI Thread */
202 DPRINT("Initialliazing Thread Stack\n");
203 KernelStack
= MmCreateKernelStack(FALSE
);
205 /* Set the Process CID */
206 DPRINT("Initialliazing Thread PID and Parent Process\n");
207 Thread
->Cid
.UniqueProcess
= Process
->UniqueProcessId
;
208 Thread
->ThreadsProcess
= Process
;
210 /* Now let the kernel initialize the context */
213 /* User-mode Thread */
216 DPRINT("Initialliazing Thread PEB\n");
217 TebBase
= MmCreateTeb(Process
, &Thread
->Cid
, InitialTeb
);
219 /* Set the Start Addresses */
220 DPRINT("Initialliazing Thread Start Addresses :%x, %x\n", ThreadContext
->Eip
, ThreadContext
->Eax
);
221 Thread
->StartAddress
= (PVOID
)ThreadContext
->Eip
;
222 Thread
->Win32StartAddress
= (PVOID
)ThreadContext
->Eax
;
224 /* Let the kernel intialize the Thread */
225 DPRINT("Initialliazing Kernel Thread\n");
226 KeInitializeThread(&Process
->Pcb
,
228 PspUserThreadStartup
,
238 DPRINT("Initialliazing Thread Start Address :%x\n", StartRoutine
);
239 Thread
->StartAddress
= StartRoutine
;
240 Thread
->SystemThread
= TRUE
;
242 /* Let the kernel intialize the Thread */
243 DPRINT("Initialliazing Kernel Thread\n");
244 KeInitializeThread(&Process
->Pcb
,
246 PspSystemThreadStartup
,
255 * Insert the Thread into the Process's Thread List
256 * Note, this is the ETHREAD Thread List. It is removed in
257 * ps/kill.c!PspExitThread.
259 DPRINT("Inserting into Process Thread List \n");
260 InsertTailList(&Process
->ThreadListHead
, &Thread
->ThreadListEntry
);
262 /* Notify Thread Creation */
263 DPRINT("Running Thread Notify \n");
264 PspRunCreateThreadNotifyRoutines(Thread
, TRUE
);
266 /* FIXME: Use Lock */
267 DPRINT("Apcs Queueable: %d \n", Thread
->Tcb
.ApcQueueable
);
268 Thread
->Tcb
.ApcQueueable
= TRUE
;
270 /* Suspend the Thread if we have to */
271 if (CreateSuspended
) {
273 DPRINT("Suspending Thread\n");
274 KeSuspendThread(&Thread
->Tcb
);
277 /* Reference ourselves as a keep-alive */
278 ObReferenceObject(Thread
);
280 /* Insert the Thread into the Object Manager */
281 DPRINT("Inserting Thread\n");
282 Status
= ObInsertObject((PVOID
)Thread
,
289 /* Return Cid and Handle */
290 DPRINT("All worked great!\n");
291 if(NT_SUCCESS(Status
)) {
295 if(ClientId
!= NULL
) {
297 *ClientId
= Thread
->Cid
;
299 *ThreadHandle
= hThread
;
303 Status
= _SEH_GetExceptionCode();
308 /* FIXME: SECURITY */
310 /* Dispatch thread */
311 DPRINT("About to dispatch the thread: %x!\n", &Thread
->Tcb
);
312 OldIrql
= KeAcquireDispatcherDatabaseLock ();
313 KiUnblockThread(&Thread
->Tcb
, NULL
, 0);
314 ObDereferenceObject(Thread
);
315 KeReleaseDispatcherDatabaseLock(OldIrql
);
318 DPRINT("Returning\n");
327 PsCreateSystemThread(PHANDLE ThreadHandle
,
328 ACCESS_MASK DesiredAccess
,
329 POBJECT_ATTRIBUTES ObjectAttributes
,
330 HANDLE ProcessHandle
,
332 PKSTART_ROUTINE StartRoutine
,
335 PEPROCESS TargetProcess
= NULL
;
336 HANDLE Handle
= ProcessHandle
;
338 /* Check if we have a handle. If not, use the System Process */
339 if (!ProcessHandle
) {
342 TargetProcess
= PsInitialSystemProcess
;
345 /* Call the shared function */
346 return PspCreateThread(ThreadHandle
,
364 PsGetCurrentThreadId(VOID
)
366 return(PsGetCurrentThread()->Cid
.UniqueThread
);
374 PsGetThreadFreezeCount(PETHREAD Thread
)
376 return Thread
->Tcb
.FreezeCount
;
384 PsGetThreadHardErrorsAreDisabled(PETHREAD Thread
)
386 return Thread
->HardErrorsAreDisabled
;
394 PsGetThreadId(PETHREAD Thread
)
396 return Thread
->Cid
.UniqueThread
;
404 PsGetThreadProcess(PETHREAD Thread
)
406 return Thread
->ThreadsProcess
;
414 PsGetThreadProcessId(PETHREAD Thread
)
416 return Thread
->Cid
.UniqueProcess
;
424 PsGetThreadSessionId(PETHREAD Thread
)
426 return (HANDLE
)Thread
->ThreadsProcess
->Session
;
434 PsGetThreadTeb(PETHREAD Thread
)
436 return Thread
->Tcb
.Teb
;
444 PsGetThreadWin32Thread(PETHREAD Thread
)
446 return Thread
->Tcb
.Win32Thread
;
454 PsGetCurrentThreadPreviousMode(VOID
)
456 return (KPROCESSOR_MODE
)PsGetCurrentThread()->Tcb
.PreviousMode
;
464 PsGetCurrentThreadStackBase(VOID
)
466 return PsGetCurrentThread()->Tcb
.StackBase
;
474 PsGetCurrentThreadStackLimit(VOID
)
476 return (PVOID
)PsGetCurrentThread()->Tcb
.StackLimit
;
484 PsIsThreadTerminating(IN PETHREAD Thread
)
486 return (Thread
->Terminated
? TRUE
: FALSE
);
494 PsIsSystemThread(PETHREAD Thread
)
496 return (Thread
->SystemThread
? TRUE
: FALSE
);
504 PsIsThreadImpersonating(PETHREAD Thread
)
506 return Thread
->ActiveImpersonationInfo
;
514 PsSetThreadHardErrorsAreDisabled(PETHREAD Thread
,
515 BOOLEAN HardErrorsAreDisabled
)
517 Thread
->HardErrorsAreDisabled
= HardErrorsAreDisabled
;
525 PsSetThreadWin32Thread(PETHREAD Thread
,
528 Thread
->Tcb
.Win32Thread
= Win32Thread
;
533 NtCreateThread(OUT PHANDLE ThreadHandle
,
534 IN ACCESS_MASK DesiredAccess
,
535 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
536 IN HANDLE ProcessHandle
,
537 OUT PCLIENT_ID ClientId
,
538 IN PCONTEXT ThreadContext
,
539 IN PINITIAL_TEB InitialTeb
,
540 IN BOOLEAN CreateSuspended
)
542 INITIAL_TEB SafeInitialTeb
;
546 DPRINT("NtCreateThread(ThreadHandle %x, PCONTEXT %x)\n",
547 ThreadHandle
,ThreadContext
);
549 if(KeGetPreviousMode() != KernelMode
) {
553 ProbeForWrite(ThreadHandle
,
557 if(ClientId
!= NULL
) {
559 ProbeForWrite(ClientId
,
564 if(ThreadContext
!= NULL
) {
566 ProbeForRead(ThreadContext
,
572 DPRINT1("No context for User-Mode Thread!!\n");
573 return STATUS_INVALID_PARAMETER
;
576 ProbeForRead(InitialTeb
,
582 return _SEH_GetExceptionCode();
587 /* Use probed data for the Initial TEB */
588 SafeInitialTeb
= *InitialTeb
;
589 InitialTeb
= &SafeInitialTeb
;
591 /* Call the shared function */
592 return PspCreateThread(ThreadHandle
,
610 NtOpenThread(OUT PHANDLE ThreadHandle
,
611 IN ACCESS_MASK DesiredAccess
,
612 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
613 IN PCLIENT_ID ClientId OPTIONAL
)
615 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
616 CLIENT_ID SafeClientId
;
618 NTSTATUS Status
= STATUS_SUCCESS
;
623 /* Probe the paraemeters */
624 if(PreviousMode
!= KernelMode
)
628 ProbeForWrite(ThreadHandle
,
634 ProbeForRead(ClientId
,
638 SafeClientId
= *ClientId
;
639 ClientId
= &SafeClientId
;
644 Status
= _SEH_GetExceptionCode();
648 if(!NT_SUCCESS(Status
)) return Status
;
651 /* Open by name if one was given */
652 if (ObjectAttributes
->ObjectName
)
655 Status
= ObOpenObjectByName(ObjectAttributes
,
663 if (Status
!= STATUS_SUCCESS
)
665 DPRINT1("Could not open object by name\n");
673 /* Open by Thread ID */
674 if (ClientId
->UniqueProcess
)
676 /* Get the Process */
677 if (ClientId
->UniqueProcess
== (HANDLE
)-1) KEBUGCHECK(0);
678 DPRINT("Opening by Process ID: %x\n", ClientId
->UniqueProcess
);
679 Status
= PsLookupProcessThreadByCid(ClientId
,
685 /* Get the Process */
686 DPRINT("Opening by Thread ID: %x\n", ClientId
->UniqueThread
);
687 Status
= PsLookupThreadByThreadId(ClientId
->UniqueThread
,
691 if(!NT_SUCCESS(Status
))
693 DPRINT1("Failure to find Thread\n");
697 /* Open the Thread Object */
698 Status
= ObOpenObjectByPointer(Thread
,
699 ObjectAttributes
->Attributes
,
705 if(!NT_SUCCESS(Status
))
707 DPRINT1("Failure to open Thread\n");
710 /* Dereference the thread */
711 ObDereferenceObject(Thread
);
714 /* Write back the handle */
715 if(NT_SUCCESS(Status
))
719 *ThreadHandle
= hThread
;
723 Status
= _SEH_GetExceptionCode();
734 NtYieldExecution(VOID
)
736 KiDispatchThread(Ready
);
737 return(STATUS_SUCCESS
);
744 /* Check and Alert Thread if needed */
745 return KeTestAlertThread(ExGetPreviousMode()) ? STATUS_ALERTED
: STATUS_SUCCESS
;
753 ExGetPreviousMode (VOID
)
755 return (KPROCESSOR_MODE
)PsGetCurrentThread()->Tcb
.PreviousMode
;