1 /* $Id: create.c,v 1.57 2003/04/26 23:13:33 hyperion Exp $
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
;
44 #define MAX_THREAD_NOTIFY_ROUTINE_COUNT 8
46 static ULONG PiThreadNotifyRoutineCount
= 0;
47 static PCREATE_THREAD_NOTIFY_ROUTINE
48 PiThreadNotifyRoutine
[MAX_THREAD_NOTIFY_ROUTINE_COUNT
];
50 /* FUNCTIONS ***************************************************************/
53 PsAssignImpersonationToken(PETHREAD Thread
,
57 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
;
60 if (TokenHandle
!= NULL
)
62 Status
= ObReferenceObjectByHandle(TokenHandle
,
68 if (!NT_SUCCESS(Status
))
72 ImpersonationLevel
= Token
->ImpersonationLevel
;
77 ImpersonationLevel
= 0;
80 PsImpersonateClient(Thread
,
87 ObDereferenceObject(Token
);
89 return(STATUS_SUCCESS
);
97 Thread
= PsGetCurrentThread();
99 if (Thread
->ActiveImpersonationInfo
!= 0)
101 ObDereferenceObject(Thread
->ImpersonationInfo
->Token
);
102 Thread
->ActiveImpersonationInfo
= 0;
107 PsImpersonateClient(PETHREAD Thread
,
111 SECURITY_IMPERSONATION_LEVEL Level
)
115 if (Thread
->ActiveImpersonationInfo
!= 0)
117 Thread
->ActiveImpersonationInfo
= 0;
118 if (Thread
->ImpersonationInfo
->Token
!= NULL
)
120 ObDereferenceObject(Thread
->ImpersonationInfo
->Token
);
125 if (Thread
->ActiveImpersonationInfo
== 0 ||
126 Thread
->ImpersonationInfo
== NULL
)
128 Thread
->ImpersonationInfo
= ExAllocatePool(NonPagedPool
,
129 sizeof(PS_IMPERSONATION_INFO
));
131 Thread
->ImpersonationInfo
->Level
= Level
;
132 Thread
->ImpersonationInfo
->Unknown2
= c
;
133 Thread
->ImpersonationInfo
->Unknown1
= b
;
134 Thread
->ImpersonationInfo
->Token
= Token
;
135 ObReferenceObjectByPointer(Token
,
139 Thread
->ActiveImpersonationInfo
= 1;
143 PsReferenceEffectiveToken(PETHREAD Thread
,
144 PTOKEN_TYPE TokenType
,
146 PSECURITY_IMPERSONATION_LEVEL Level
)
151 if (Thread
->ActiveImpersonationInfo
== 0)
153 Process
= Thread
->ThreadsProcess
;
154 *TokenType
= TokenPrimary
;
156 Token
= Process
->Token
;
160 Token
= Thread
->ImpersonationInfo
->Token
;
161 *TokenType
= TokenImpersonation
;
162 *b
= Thread
->ImpersonationInfo
->Unknown2
;
163 *Level
= Thread
->ImpersonationInfo
->Level
;
169 NtImpersonateThread(IN HANDLE ThreadHandle
,
170 IN HANDLE ThreadToImpersonateHandle
,
171 IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService
)
174 PETHREAD ThreadToImpersonate
;
176 SECURITY_CLIENT_CONTEXT ClientContext
;
178 Status
= ObReferenceObjectByHandle(ThreadHandle
,
184 if (!NT_SUCCESS(Status
))
189 Status
= ObReferenceObjectByHandle(ThreadToImpersonateHandle
,
193 (PVOID
*)&ThreadToImpersonate
,
195 if (!NT_SUCCESS(Status
))
197 ObDereferenceObject(Thread
);
201 Status
= SeCreateClientSecurity(ThreadToImpersonate
,
202 SecurityQualityOfService
,
205 if (!NT_SUCCESS(Status
))
207 ObDereferenceObject(Thread
);
208 ObDereferenceObject(ThreadToImpersonate
);
212 SeImpersonateClient(&ClientContext
, Thread
);
213 if (ClientContext
.Token
!= NULL
)
215 ObDereferenceObject(ClientContext
.Token
);
217 return(STATUS_SUCCESS
);
221 NtOpenThreadToken(IN HANDLE ThreadHandle
,
222 IN ACCESS_MASK DesiredAccess
,
223 IN BOOLEAN OpenAsSelf
,
224 OUT PHANDLE TokenHandle
)
231 Status
= ObReferenceObjectByHandle(ThreadHandle
,
237 if (!NT_SUCCESS(Status
))
242 Token
= PsReferencePrimaryToken(Thread
->ThreadsProcess
);
243 SepCreateImpersonationTokenDacl(Token
);
245 return(STATUS_UNSUCCESSFUL
);
248 PACCESS_TOKEN STDCALL
249 PsReferenceImpersonationToken(PETHREAD Thread
,
252 SECURITY_IMPERSONATION_LEVEL
* Level
)
254 if (Thread
->ActiveImpersonationInfo
== 0)
259 *Level
= Thread
->ImpersonationInfo
->Level
;
260 *Unknown1
= Thread
->ImpersonationInfo
->Unknown1
;
261 *Unknown2
= Thread
->ImpersonationInfo
->Unknown2
;
262 ObReferenceObjectByPointer(Thread
->ImpersonationInfo
->Token
,
266 return(Thread
->ImpersonationInfo
->Token
);
270 PiBeforeBeginThread(CONTEXT c
)
272 KeLowerIrql(PASSIVE_LEVEL
);
276 PiDeleteThread(PVOID ObjectBody
)
281 Thread
= (PETHREAD
)ObjectBody
;
283 DPRINT("PiDeleteThread(ObjectBody %x)\n",ObjectBody
);
285 ObDereferenceObject(Thread
->ThreadsProcess
);
286 Thread
->ThreadsProcess
= NULL
;
288 KeAcquireSpinLock(&PiThreadListLock
, &oldIrql
);
290 for (i
= 0; i
< PiThreadNotifyRoutineCount
; i
++)
292 PiThreadNotifyRoutine
[i
](Thread
->Cid
.UniqueProcess
,
293 Thread
->Cid
.UniqueThread
,
297 RemoveEntryList(&Thread
->Tcb
.ThreadListEntry
);
298 KeReleaseSpinLock(&PiThreadListLock
, oldIrql
);
299 KeReleaseThread(Thread
);
300 DPRINT("PiDeleteThread() finished\n");
304 PsInitializeThread(HANDLE ProcessHandle
,
306 PHANDLE ThreadHandle
,
307 ACCESS_MASK DesiredAccess
,
308 POBJECT_ATTRIBUTES ThreadAttributes
,
320 if (ProcessHandle
!= NULL
)
322 Status
= ObReferenceObjectByHandle(ProcessHandle
,
323 PROCESS_CREATE_THREAD
,
328 if (Status
!= STATUS_SUCCESS
)
330 DPRINT("Failed at %s:%d\n",__FILE__
,__LINE__
);
333 DPRINT( "Creating thread in process %x\n", Process
);
337 Process
= PsInitialSystemProcess
;
338 ObReferenceObjectByPointer(Process
,
339 PROCESS_CREATE_THREAD
,
345 * Create and initialize thread
347 Status
= ObCreateObject(ThreadHandle
,
352 if (!NT_SUCCESS(Status
))
357 DPRINT("Thread = %x\n",Thread
);
361 KeInitializeThread(&Process
->Pcb
, &Thread
->Tcb
, First
);
362 Thread
->ThreadsProcess
= Process
;
364 * FIXME: What lock protects this?
366 InsertTailList(&Thread
->ThreadsProcess
->ThreadListHead
,
367 &Thread
->Tcb
.ProcessThreadListEntry
);
368 InitializeListHead(&Thread
->TerminationPortList
);
369 KeInitializeSpinLock(&Thread
->ActiveTimerListLock
);
370 InitializeListHead(&Thread
->IrpList
);
371 Thread
->Cid
.UniqueThread
= (HANDLE
)InterlockedIncrement(
372 (LONG
*)&PiNextThreadUniqueId
);
373 Thread
->Cid
.UniqueProcess
= (HANDLE
)Thread
->ThreadsProcess
->UniqueProcessId
;
374 Thread
->DeadThread
= 0;
375 Thread
->Win32Thread
= 0;
376 DPRINT("Thread->Cid.UniqueThread %d\n",Thread
->Cid
.UniqueThread
);
380 KeAcquireSpinLock(&PiThreadListLock
, &oldIrql
);
381 InsertTailList(&PiThreadListHead
, &Thread
->Tcb
.ThreadListEntry
);
382 KeReleaseSpinLock(&PiThreadListLock
, oldIrql
);
384 Thread
->Tcb
.BasePriority
= Thread
->ThreadsProcess
->Pcb
.BasePriority
;
385 Thread
->Tcb
.Priority
= Thread
->Tcb
.BasePriority
;
387 for (i
= 0; i
< PiThreadNotifyRoutineCount
; i
++)
389 PiThreadNotifyRoutine
[i
](Thread
->Cid
.UniqueProcess
,
390 Thread
->Cid
.UniqueThread
,
394 return(STATUS_SUCCESS
);
399 PsCreateTeb(HANDLE ProcessHandle
,
402 PUSER_STACK UserStack
)
404 MEMORY_BASIC_INFORMATION Info
;
413 TebBase
= (PVOID
)0x7FFDE000;
418 Status
= NtQueryVirtualMemory(ProcessHandle
,
420 MemoryBasicInformation
,
424 if (!NT_SUCCESS(Status
))
426 CPRINT("NtQueryVirtualMemory (Status %x)\n", Status
);
429 /* FIXME: Race between this and the above check */
430 if (Info
.State
== MEM_FREE
)
432 /* The TEB must reside in user space */
433 Status
= NtAllocateVirtualMemory(ProcessHandle
,
437 MEM_RESERVE
| MEM_COMMIT
,
439 if (NT_SUCCESS(Status
))
445 TebBase
= TebBase
- TebSize
;
448 DPRINT ("TebBase %p TebSize %lu\n", TebBase
, TebSize
);
450 /* set all pointers to and from the TEB */
451 Teb
.Tib
.Self
= TebBase
;
452 if (Thread
->ThreadsProcess
)
454 Teb
.Peb
= Thread
->ThreadsProcess
->Peb
; /* No PEB yet!! */
456 DPRINT("Teb.Peb %x\n", Teb
.Peb
);
458 /* store stack information from UserStack */
459 if(UserStack
!= NULL
)
461 /* fixed-size stack */
462 if(UserStack
->FixedStackBase
&& UserStack
->FixedStackLimit
)
464 Teb
.Tib
.StackBase
= UserStack
->FixedStackBase
;
465 Teb
.Tib
.StackLimit
= UserStack
->FixedStackLimit
;
466 Teb
.DeallocationStack
= UserStack
->FixedStackLimit
;
468 /* expandable stack */
471 Teb
.Tib
.StackBase
= UserStack
->ExpandableStackBase
;
472 Teb
.Tib
.StackLimit
= UserStack
->ExpandableStackLimit
;
473 Teb
.DeallocationStack
= UserStack
->ExpandableStackBottom
;
477 /* more initialization */
478 Teb
.Cid
.UniqueThread
= Thread
->Cid
.UniqueThread
;
479 Teb
.Cid
.UniqueProcess
= Thread
->Cid
.UniqueProcess
;
480 Teb
.CurrentLocale
= PsDefaultThreadLocaleId
;
482 /* Terminate the exception handler list */
483 Teb
.Tib
.ExceptionList
= (PVOID
)-1;
485 DPRINT("sizeof(TEB) %x\n", sizeof(TEB
));
487 /* write TEB data into teb page */
488 Status
= NtWriteVirtualMemory(ProcessHandle
,
494 if (!NT_SUCCESS(Status
))
497 DPRINT1 ("Writing TEB failed!\n");
500 NtFreeVirtualMemory(ProcessHandle
,
510 *TebPtr
= (PTEB
)TebBase
;
513 DPRINT("TEB allocated at %p\n", TebBase
);
519 LdrInitApcRundownRoutine(PKAPC Apc
)
525 LdrInitApcKernelRoutine(PKAPC Apc
,
526 PKNORMAL_ROUTINE
* NormalRoutine
,
527 PVOID
* NormalContext
,
528 PVOID
* SystemArgument1
,
529 PVOID
* SystemArgument2
)
535 NtCreateThread(PHANDLE ThreadHandle
,
536 ACCESS_MASK DesiredAccess
,
537 POBJECT_ATTRIBUTES ObjectAttributes
,
538 HANDLE ProcessHandle
,
540 PCONTEXT ThreadContext
,
541 PUSER_STACK UserStack
,
542 BOOLEAN CreateSuspended
)
549 DPRINT("NtCreateThread(ThreadHandle %x, PCONTEXT %x)\n",
550 ThreadHandle
,ThreadContext
);
552 Status
= PsInitializeThread(ProcessHandle
,
558 if (!NT_SUCCESS(Status
))
563 Status
= KiArchInitThreadWithContext(&Thread
->Tcb
, ThreadContext
);
564 if (!NT_SUCCESS(Status
))
569 Status
= PsCreateTeb(ProcessHandle
,
573 if (!NT_SUCCESS(Status
))
577 Thread
->Tcb
.Teb
= TebBase
;
579 Thread
->StartAddress
= NULL
;
583 *Client
= Thread
->Cid
;
587 * Maybe send a message to the process's debugger
589 DbgkCreateThread((PVOID
)ThreadContext
->Eip
);
592 * First, force the thread to be non-alertable for user-mode alerts.
594 Thread
->Tcb
.Alertable
= FALSE
;
597 * If the thread is to be created suspended then queue an APC to
598 * do the suspend before we run any userspace code.
602 PsSuspendThread(Thread
, NULL
);
606 * Queue an APC to the thread that will execute the ntdll startup
609 LdrInitApc
= ExAllocatePool(NonPagedPool
, sizeof(KAPC
));
610 KeInitializeApc(LdrInitApc
, &Thread
->Tcb
, 0, LdrInitApcKernelRoutine
,
611 LdrInitApcRundownRoutine
, LdrpGetSystemDllEntryPoint(),
613 KeInsertQueueApc(LdrInitApc
, NULL
, NULL
, UserMode
);
616 * Start the thread running and force it to execute the APC(s) we just
617 * queued before it runs anything else in user-mode.
619 Thread
->Tcb
.Alertable
= TRUE
;
620 Thread
->Tcb
.Alerted
[0] = 1;
621 PsUnblockThread(Thread
, NULL
);
623 return(STATUS_SUCCESS
);
628 PsCreateSystemThread(PHANDLE ThreadHandle
,
629 ACCESS_MASK DesiredAccess
,
630 POBJECT_ATTRIBUTES ObjectAttributes
,
631 HANDLE ProcessHandle
,
633 PKSTART_ROUTINE StartRoutine
,
636 * FUNCTION: Creates a thread which executes in kernel mode
638 * ThreadHandle (OUT) = Caller supplied storage for the returned thread
640 * DesiredAccess = Requested access to the thread
641 * ObjectAttributes = Object attributes (optional)
642 * ProcessHandle = Handle of process thread will run in
643 * NULL to use system process
644 * ClientId (OUT) = Caller supplied storage for the returned client id
645 * of the thread (optional)
646 * StartRoutine = Entry point for the thread
647 * StartContext = Argument supplied to the thread when it begins
649 * RETURNS: Success or failure status
655 DPRINT("PsCreateSystemThread(ThreadHandle %x, ProcessHandle %x)\n",
656 ThreadHandle
,ProcessHandle
);
658 Status
= PsInitializeThread(ProcessHandle
,
664 if (!NT_SUCCESS(Status
))
669 Thread
->StartAddress
= StartRoutine
;
670 Status
= KiArchInitThread(&Thread
->Tcb
, StartRoutine
, StartContext
);
671 if (!NT_SUCCESS(Status
))
676 if (ClientId
!= NULL
)
678 *ClientId
=Thread
->Cid
;
681 PsUnblockThread(Thread
, NULL
);
683 return(STATUS_SUCCESS
);
688 PsSetCreateThreadNotifyRoutine(IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine
)
690 if (PiThreadNotifyRoutineCount
>= MAX_THREAD_NOTIFY_ROUTINE_COUNT
)
691 return(STATUS_INSUFFICIENT_RESOURCES
);
693 PiThreadNotifyRoutine
[PiThreadNotifyRoutineCount
] = NotifyRoutine
;
694 PiThreadNotifyRoutineCount
++;
696 return(STATUS_SUCCESS
);