3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ps/thread.c
6 * PURPOSE: Thread managment
7 * PROGRAMMER: David Welch (welch@mcmail.com)
10 * 12/10/99: Phillip Susi: Thread priorities, and APC work
16 * All of the routines that manipulate the thread queue synchronize on
21 /* INCLUDES ****************************************************************/
23 #include <ddk/ntddk.h>
24 #include <internal/ke.h>
25 #include <internal/ob.h>
26 #include <internal/ps.h>
27 #include <internal/se.h>
28 #include <internal/id.h>
29 #include <internal/dbg.h>
30 #include <internal/ldr.h>
33 #include <internal/debug.h>
35 /* GLOBAL *******************************************************************/
37 static ULONG PiNextThreadUniqueId = 0;
39 extern KSPIN_LOCK PiThreadListLock;
40 extern ULONG PiNrThreads;
42 extern LIST_ENTRY PiThreadListHead;
45 #define MAX_THREAD_NOTIFY_ROUTINE_COUNT 8
47 static ULONG PiThreadNotifyRoutineCount = 0;
48 static PCREATE_THREAD_NOTIFY_ROUTINE
49 PiThreadNotifyRoutine[MAX_THREAD_NOTIFY_ROUTINE_COUNT];
50 #endif /* LIBCAPTIVE */
52 /* FUNCTIONS ***************************************************************/
57 PsAssignImpersonationToken(PETHREAD Thread,
61 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
64 if (TokenHandle != NULL)
66 Status = ObReferenceObjectByHandle(TokenHandle,
72 if (!NT_SUCCESS(Status))
76 ImpersonationLevel = Token->ImpersonationLevel;
81 ImpersonationLevel = 0;
84 PsImpersonateClient(Thread,
91 ObDereferenceObject(Token);
93 return(STATUS_SUCCESS);
101 Thread = PsGetCurrentThread();
103 if (Thread->ActiveImpersonationInfo != 0)
105 ObDereferenceObject(Thread->ImpersonationInfo->Token);
106 Thread->ActiveImpersonationInfo = 0;
111 PsImpersonateClient(PETHREAD Thread,
115 SECURITY_IMPERSONATION_LEVEL Level)
119 if (Thread->ActiveImpersonationInfo != 0)
121 Thread->ActiveImpersonationInfo = 0;
122 if (Thread->ImpersonationInfo->Token != NULL)
124 ObDereferenceObject(Thread->ImpersonationInfo->Token);
129 if (Thread->ActiveImpersonationInfo == 0 ||
130 Thread->ImpersonationInfo == NULL)
132 Thread->ImpersonationInfo = ExAllocatePool(NonPagedPool,
133 sizeof(PS_IMPERSONATION_INFO));
135 Thread->ImpersonationInfo->Level = Level;
136 Thread->ImpersonationInfo->Unknown2 = c;
137 Thread->ImpersonationInfo->Unknown1 = b;
138 Thread->ImpersonationInfo->Token = Token;
139 ObReferenceObjectByPointer(Token,
143 Thread->ActiveImpersonationInfo = 1;
147 PsReferenceEffectiveToken(PETHREAD Thread,
148 PTOKEN_TYPE TokenType,
150 PSECURITY_IMPERSONATION_LEVEL Level)
155 if (Thread->ActiveImpersonationInfo == 0)
157 Process = Thread->ThreadsProcess;
158 *TokenType = TokenPrimary;
160 Token = Process->Token;
164 Token = Thread->ImpersonationInfo->Token;
165 *TokenType = TokenImpersonation;
166 *b = Thread->ImpersonationInfo->Unknown2;
167 *Level = Thread->ImpersonationInfo->Level;
173 NtImpersonateThread(IN HANDLE ThreadHandle,
174 IN HANDLE ThreadToImpersonateHandle,
175 IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService)
178 PETHREAD ThreadToImpersonate;
180 SECURITY_CLIENT_CONTEXT ClientContext;
182 Status = ObReferenceObjectByHandle(ThreadHandle,
188 if (!NT_SUCCESS(Status))
193 Status = ObReferenceObjectByHandle(ThreadToImpersonateHandle,
197 (PVOID*)&ThreadToImpersonate,
199 if (!NT_SUCCESS(Status))
201 ObDereferenceObject(Thread);
205 Status = SeCreateClientSecurity(ThreadToImpersonate,
206 SecurityQualityOfService,
209 if (!NT_SUCCESS(Status))
211 ObDereferenceObject(Thread);
212 ObDereferenceObject(ThreadToImpersonate);
216 SeImpersonateClient(&ClientContext, Thread);
217 if (ClientContext.Token != NULL)
219 ObDereferenceObject(ClientContext.Token);
221 return(STATUS_SUCCESS);
225 NtOpenThreadToken(IN HANDLE ThreadHandle,
226 IN ACCESS_MASK DesiredAccess,
227 IN BOOLEAN OpenAsSelf,
228 OUT PHANDLE TokenHandle)
235 Status = ObReferenceObjectByHandle(ThreadHandle,
241 if (!NT_SUCCESS(Status))
246 Token = PsReferencePrimaryToken(Thread->ThreadsProcess);
247 SepCreateImpersonationTokenDacl(Token);
249 return(STATUS_UNSUCCESSFUL);
252 #endif /* LIBCAPTIVE */
254 PACCESS_TOKEN STDCALL
255 PsReferenceImpersonationToken(PETHREAD Thread,
258 SECURITY_IMPERSONATION_LEVEL* Level)
260 if (Thread->ActiveImpersonationInfo == 0)
269 #else /* !LIBCAPTIVE */
270 *Level = Thread->ImpersonationInfo->Level;
271 *Unknown1 = Thread->ImpersonationInfo->Unknown1;
272 *Unknown2 = Thread->ImpersonationInfo->Unknown2;
273 ObReferenceObjectByPointer(Thread->ImpersonationInfo->Token,
277 return(Thread->ImpersonationInfo->Token);
278 #endif /* LIBCAPTIVE */
284 PiBeforeBeginThread(CONTEXT c)
286 KeLowerIrql(PASSIVE_LEVEL);
290 PiDeleteThread(PVOID ObjectBody)
295 Thread = (PETHREAD)ObjectBody;
297 DPRINT("PiDeleteThread(ObjectBody %x)\n",ObjectBody);
299 ObDereferenceObject(Thread->ThreadsProcess);
300 Thread->ThreadsProcess = NULL;
302 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
304 for (i = 0; i < PiThreadNotifyRoutineCount; i++)
306 PiThreadNotifyRoutine[i](Thread->Cid.UniqueProcess,
307 Thread->Cid.UniqueThread,
311 RemoveEntryList(&Thread->Tcb.ThreadListEntry);
312 KeReleaseSpinLock(&PiThreadListLock, oldIrql);
313 KeReleaseThread(Thread);
314 DPRINT("PiDeleteThread() finished\n");
317 #endif /* LIBCAPTIVE */
320 PsInitializeThread(HANDLE ProcessHandle,
322 PHANDLE ThreadHandle,
323 ACCESS_MASK DesiredAccess,
324 POBJECT_ATTRIBUTES ThreadAttributes,
333 #endif /* LIBCAPTIVE */
338 if (ProcessHandle != NULL)
340 Status = ObReferenceObjectByHandle(ProcessHandle,
341 PROCESS_CREATE_THREAD,
346 if (Status != STATUS_SUCCESS)
348 DPRINT("Failed at %s:%d\n",__FILE__,__LINE__);
351 DPRINT( "Creating thread in process %x\n", Process );
355 Process = PsInitialSystemProcess;
356 ObReferenceObjectByPointer(Process,
357 PROCESS_CREATE_THREAD,
363 * Create and initialize thread
365 Status = ObCreateObject(ThreadHandle,
370 if (!NT_SUCCESS(Status))
375 DPRINT("Thread = %x\n",Thread);
379 KeInitializeThread(&Process->Pcb, &Thread->Tcb, First);
380 Thread->ThreadsProcess = Process;
382 * FIXME: What lock protects this?
384 InsertTailList(&Thread->ThreadsProcess->ThreadListHead,
385 &Thread->Tcb.ProcessThreadListEntry);
386 InitializeListHead(&Thread->TerminationPortList);
387 KeInitializeSpinLock(&Thread->ActiveTimerListLock);
388 InitializeListHead(&Thread->IrpList);
389 Thread->Cid.UniqueThread = (HANDLE)InterlockedIncrement(
390 (LONG *)&PiNextThreadUniqueId);
391 Thread->Cid.UniqueProcess = (HANDLE)Thread->ThreadsProcess->UniqueProcessId;
392 Thread->DeadThread = 0;
393 Thread->Win32Thread = 0;
394 DPRINT("Thread->Cid.UniqueThread %d\n",Thread->Cid.UniqueThread);
398 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
399 InsertTailList(&PiThreadListHead, &Thread->Tcb.ThreadListEntry);
400 KeReleaseSpinLock(&PiThreadListLock, oldIrql);
402 Thread->Tcb.BasePriority = Thread->ThreadsProcess->Pcb.BasePriority;
403 Thread->Tcb.Priority = Thread->Tcb.BasePriority;
406 for (i = 0; i < PiThreadNotifyRoutineCount; i++)
408 PiThreadNotifyRoutine[i](Thread->Cid.UniqueProcess,
409 Thread->Cid.UniqueThread,
412 #endif /* LIBCAPTIVE */
414 return(STATUS_SUCCESS);
420 PsCreateTeb(HANDLE ProcessHandle,
423 PUSER_STACK UserStack)
425 MEMORY_BASIC_INFORMATION Info;
434 TebBase = (PVOID)0x7FFDE000;
439 Status = NtQueryVirtualMemory(ProcessHandle,
441 MemoryBasicInformation,
445 if (!NT_SUCCESS(Status))
447 CPRINT("NtQueryVirtualMemory (Status %x)\n", Status);
450 /* FIXME: Race between this and the above check */
451 if (Info.State == MEM_FREE)
453 /* The TEB must reside in user space */
454 Status = NtAllocateVirtualMemory(ProcessHandle,
458 MEM_RESERVE | MEM_COMMIT,
460 if (NT_SUCCESS(Status))
466 TebBase = TebBase - TebSize;
469 DPRINT ("TebBase %p TebSize %lu\n", TebBase, TebSize);
471 RtlZeroMemory(&Teb, sizeof(TEB));
472 /* set all pointers to and from the TEB */
473 Teb.Tib.Self = TebBase;
474 if (Thread->ThreadsProcess)
476 Teb.Peb = Thread->ThreadsProcess->Peb; /* No PEB yet!! */
478 DPRINT("Teb.Peb %x\n", Teb.Peb);
480 /* store stack information from UserStack */
481 if(UserStack != NULL)
483 /* fixed-size stack */
484 if(UserStack->FixedStackBase && UserStack->FixedStackLimit)
486 Teb.Tib.StackBase = UserStack->FixedStackBase;
487 Teb.Tib.StackLimit = UserStack->FixedStackLimit;
488 Teb.DeallocationStack = UserStack->FixedStackLimit;
490 /* expandable stack */
493 Teb.Tib.StackBase = UserStack->ExpandableStackBase;
494 Teb.Tib.StackLimit = UserStack->ExpandableStackLimit;
495 Teb.DeallocationStack = UserStack->ExpandableStackBottom;
499 /* more initialization */
500 Teb.Cid.UniqueThread = Thread->Cid.UniqueThread;
501 Teb.Cid.UniqueProcess = Thread->Cid.UniqueProcess;
502 Teb.CurrentLocale = PsDefaultThreadLocaleId;
504 /* Terminate the exception handler list */
505 Teb.Tib.ExceptionList = (PVOID)-1;
507 DPRINT("sizeof(TEB) %x\n", sizeof(TEB));
509 /* write TEB data into teb page */
510 Status = NtWriteVirtualMemory(ProcessHandle,
516 if (!NT_SUCCESS(Status))
519 DPRINT1 ("Writing TEB failed!\n");
522 NtFreeVirtualMemory(ProcessHandle,
532 *TebPtr = (PTEB)TebBase;
535 DPRINT("TEB allocated at %p\n", TebBase);
541 LdrInitApcRundownRoutine(PKAPC Apc)
547 LdrInitApcKernelRoutine(PKAPC Apc,
548 PKNORMAL_ROUTINE* NormalRoutine,
549 PVOID* NormalContext,
550 PVOID* SystemArgument1,
551 PVOID* SystemArgument2)
557 NtCreateThread(PHANDLE ThreadHandle,
558 ACCESS_MASK DesiredAccess,
559 POBJECT_ATTRIBUTES ObjectAttributes,
560 HANDLE ProcessHandle,
562 PCONTEXT ThreadContext,
563 PUSER_STACK UserStack,
564 BOOLEAN CreateSuspended)
571 DPRINT("NtCreateThread(ThreadHandle %x, PCONTEXT %x)\n",
572 ThreadHandle,ThreadContext);
574 Status = PsInitializeThread(ProcessHandle,
580 if (!NT_SUCCESS(Status))
585 Status = KiArchInitThreadWithContext(&Thread->Tcb, ThreadContext);
586 if (!NT_SUCCESS(Status))
591 Status = PsCreateTeb(ProcessHandle,
595 if (!NT_SUCCESS(Status))
599 Thread->Tcb.Teb = TebBase;
601 Thread->StartAddress = NULL;
605 *Client = Thread->Cid;
609 * Maybe send a message to the process's debugger
611 DbgkCreateThread((PVOID)ThreadContext->Eip);
614 * First, force the thread to be non-alertable for user-mode alerts.
616 Thread->Tcb.Alertable = FALSE;
619 * If the thread is to be created suspended then queue an APC to
620 * do the suspend before we run any userspace code.
624 PsSuspendThread(Thread, NULL);
628 * Queue an APC to the thread that will execute the ntdll startup
631 LdrInitApc = ExAllocatePool(NonPagedPool, sizeof(KAPC));
632 KeInitializeApc(LdrInitApc, &Thread->Tcb, 0, LdrInitApcKernelRoutine,
633 LdrInitApcRundownRoutine, LdrpGetSystemDllEntryPoint(),
635 KeInsertQueueApc(LdrInitApc, NULL, NULL, UserMode);
638 * Start the thread running and force it to execute the APC(s) we just
639 * queued before it runs anything else in user-mode.
641 Thread->Tcb.Alertable = TRUE;
642 Thread->Tcb.Alerted[0] = 1;
643 PsUnblockThread(Thread, NULL);
645 return(STATUS_SUCCESS);
650 PsCreateSystemThread(PHANDLE ThreadHandle,
651 ACCESS_MASK DesiredAccess,
652 POBJECT_ATTRIBUTES ObjectAttributes,
653 HANDLE ProcessHandle,
655 PKSTART_ROUTINE StartRoutine,
658 * FUNCTION: Creates a thread which executes in kernel mode
660 * ThreadHandle (OUT) = Caller supplied storage for the returned thread
662 * DesiredAccess = Requested access to the thread
663 * ObjectAttributes = Object attributes (optional)
664 * ProcessHandle = Handle of process thread will run in
665 * NULL to use system process
666 * ClientId (OUT) = Caller supplied storage for the returned client id
667 * of the thread (optional)
668 * StartRoutine = Entry point for the thread
669 * StartContext = Argument supplied to the thread when it begins
671 * RETURNS: Success or failure status
677 DPRINT("PsCreateSystemThread(ThreadHandle %x, ProcessHandle %x)\n",
678 ThreadHandle,ProcessHandle);
680 Status = PsInitializeThread(ProcessHandle,
686 if (!NT_SUCCESS(Status))
691 Thread->StartAddress = StartRoutine;
692 Status = KiArchInitThread(&Thread->Tcb, StartRoutine, StartContext);
693 if (!NT_SUCCESS(Status))
698 if (ClientId != NULL)
700 *ClientId=Thread->Cid;
703 PsUnblockThread(Thread, NULL);
705 return(STATUS_SUCCESS);
710 PsSetCreateThreadNotifyRoutine(IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine)
712 if (PiThreadNotifyRoutineCount >= MAX_THREAD_NOTIFY_ROUTINE_COUNT)
713 return(STATUS_INSUFFICIENT_RESOURCES);
715 PiThreadNotifyRoutine[PiThreadNotifyRoutineCount] = NotifyRoutine;
716 PiThreadNotifyRoutineCount++;
718 return(STATUS_SUCCESS);
721 #endif /* LIBCAPTIVE */