1 /* $Id: create.c,v 1.33 2001/06/16 14:11:15 ekohl 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/ob.h>
28 #include <internal/id.h>
29 #include <internal/dbg.h>
32 #include <internal/debug.h>
34 /* GLOBAL *******************************************************************/
36 static ULONG PiNextThreadUniqueId
= 0;
38 extern KSPIN_LOCK PiThreadListLock
;
39 extern ULONG PiNrThreads
;
41 extern LIST_ENTRY PiThreadListHead
;
43 /* FUNCTIONS ***************************************************************/
46 PsAssignImpersonationToken(PETHREAD Thread
,
50 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
;
53 if (TokenHandle
!= NULL
)
55 Status
= ObReferenceObjectByHandle(TokenHandle
,
61 if (!NT_SUCCESS(Status
))
65 ImpersonationLevel
= Token
->ImpersonationLevel
;
70 ImpersonationLevel
= 0;
73 PsImpersonateClient(Thread
,
80 ObDereferenceObject(Token
);
82 return(STATUS_SUCCESS
);
86 PsRevertToSelf(PETHREAD Thread
)
88 if (Thread
->ActiveImpersonationInfo
!= 0)
90 Thread
->ActiveImpersonationInfo
= 0;
91 ObDereferenceObject(Thread
->ImpersonationInfo
->Token
);
96 PsImpersonateClient(PETHREAD Thread
,
100 SECURITY_IMPERSONATION_LEVEL Level
)
104 if (Thread
->ActiveImpersonationInfo
!= 0)
106 Thread
->ActiveImpersonationInfo
= 0;
107 if (Thread
->ImpersonationInfo
->Token
!= NULL
)
109 ObDereferenceObject(Thread
->ImpersonationInfo
->Token
);
114 if (Thread
->ActiveImpersonationInfo
== 0 ||
115 Thread
->ImpersonationInfo
== NULL
)
117 Thread
->ImpersonationInfo
= ExAllocatePool(NonPagedPool
,
118 sizeof(PS_IMPERSONATION_INFO
));
120 Thread
->ImpersonationInfo
->Level
= Level
;
121 Thread
->ImpersonationInfo
->Unknown2
= c
;
122 Thread
->ImpersonationInfo
->Unknown1
= b
;
123 Thread
->ImpersonationInfo
->Token
= Token
;
124 ObReferenceObjectByPointer(Token
,
128 Thread
->ActiveImpersonationInfo
= 1;
132 PsReferenceEffectiveToken(PETHREAD Thread
,
133 PTOKEN_TYPE TokenType
,
135 PSECURITY_IMPERSONATION_LEVEL Level
)
140 if (Thread
->ActiveImpersonationInfo
== 0)
142 Process
= Thread
->ThreadsProcess
;
143 *TokenType
= TokenPrimary
;
145 Token
= Process
->Token
;
149 Token
= Thread
->ImpersonationInfo
->Token
;
150 *TokenType
= TokenImpersonation
;
151 *b
= Thread
->ImpersonationInfo
->Unknown2
;
152 *Level
= Thread
->ImpersonationInfo
->Level
;
158 NtImpersonateThread (IN HANDLE ThreadHandle
,
159 IN HANDLE ThreadToImpersonateHandle
,
160 IN PSECURITY_QUALITY_OF_SERVICE
161 SecurityQualityOfService
)
164 PETHREAD ThreadToImpersonate
;
168 Status
= ObReferenceObjectByHandle(ThreadHandle
,
174 if (!NT_SUCCESS(Status
))
179 Status
= ObReferenceObjectByHandle(ThreadToImpersonateHandle
,
183 (PVOID
*)&ThreadToImpersonate
,
185 if (!NT_SUCCESS(Status
))
187 ObDereferenceObject(Thread
);
191 Status
= SeCreateClientSecurity(ThreadToImpersonate
,
192 SecurityQualityOfService
,
195 if (!NT_SUCCESS(Status
))
197 ObDereferenceObject(Thread
);
198 ObDereferenceObject(ThreadToImpersonate
);
202 SeImpersonateClient(&b
, Thread
);
205 ObDereferenceObject(b
.Token
);
207 return(STATUS_SUCCESS
);
211 NtOpenThreadToken(IN HANDLE ThreadHandle
,
212 IN ACCESS_MASK DesiredAccess
,
213 IN BOOLEAN OpenAsSelf
,
214 OUT PHANDLE TokenHandle
)
221 Status
= ObReferenceObjectByHandle(ThreadHandle
,
227 if (!NT_SUCCESS(Status
))
232 Token
= PsReferencePrimaryToken(Thread
->ThreadsProcess
);
233 SepCreateImpersonationTokenDacl(Token
);
235 return(STATUS_UNSUCCESSFUL
);
238 PACCESS_TOKEN STDCALL
239 PsReferenceImpersonationToken(PETHREAD Thread
,
242 SECURITY_IMPERSONATION_LEVEL
* Level
)
244 if (Thread
->ActiveImpersonationInfo
== 0)
249 *Level
= Thread
->ImpersonationInfo
->Level
;
250 *Unknown1
= Thread
->ImpersonationInfo
->Unknown1
;
251 *Unknown2
= Thread
->ImpersonationInfo
->Unknown2
;
252 ObReferenceObjectByPointer(Thread
->ImpersonationInfo
->Token
,
256 return(Thread
->ImpersonationInfo
->Token
);
260 PiTimeoutThread(struct _KDPC
*dpc
,
265 // wake up the thread, and tell it it timed out
266 NTSTATUS Status
= STATUS_TIMEOUT
;
268 DPRINT("PiTimeoutThread()\n");
270 KeRemoveAllWaitsThread((PETHREAD
)Context
, Status
);
274 PiBeforeBeginThread(CONTEXT c
)
276 DPRINT("PiBeforeBeginThread(Eip %x)\n", c
.Eip
);
277 //KeReleaseSpinLock(&PiThreadListLock, PASSIVE_LEVEL);
278 KeLowerIrql(PASSIVE_LEVEL
);
283 PsBeginThread(PKSTART_ROUTINE StartRoutine
, PVOID StartContext
)
287 // KeReleaseSpinLock(&PiThreadListLock,PASSIVE_LEVEL);
288 KeLowerIrql(PASSIVE_LEVEL
);
289 Ret
= StartRoutine(StartContext
);
290 PsTerminateSystemThread(Ret
);
295 VOID
PiDeleteThread(PVOID ObjectBody
)
299 DPRINT("PiDeleteThread(ObjectBody %x)\n",ObjectBody
);
301 KeAcquireSpinLock(&PiThreadListLock
, &oldIrql
);
302 DPRINT("Process %x(%d)\n", ((PETHREAD
)ObjectBody
)->ThreadsProcess
,
303 ObGetReferenceCount(((PETHREAD
)ObjectBody
)->ThreadsProcess
));
304 ObDereferenceObject(((PETHREAD
)ObjectBody
)->ThreadsProcess
);
305 ((PETHREAD
)ObjectBody
)->ThreadsProcess
= NULL
;
307 RemoveEntryList(&((PETHREAD
)ObjectBody
)->Tcb
.ThreadListEntry
);
308 HalReleaseTask((PETHREAD
)ObjectBody
);
309 KeReleaseSpinLock(&PiThreadListLock
, oldIrql
);
310 DPRINT("PiDeleteThread() finished\n");
313 VOID
PiCloseThread(PVOID ObjectBody
, ULONG HandleCount
)
315 DPRINT("PiCloseThread(ObjectBody %x)\n", ObjectBody
);
316 DPRINT("ObGetReferenceCount(ObjectBody) %d "
317 "ObGetHandleCount(ObjectBody) %d\n",
318 ObGetReferenceCount(ObjectBody
),
319 ObGetHandleCount(ObjectBody
));
323 PsInitializeThread(HANDLE ProcessHandle
,
325 PHANDLE ThreadHandle
,
326 ACCESS_MASK DesiredAccess
,
327 POBJECT_ATTRIBUTES ThreadAttributes
,
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 &PiNextThreadUniqueId
);
391 Thread
->Cid
.UniqueProcess
= (HANDLE
)Thread
->ThreadsProcess
->UniqueProcessId
;
392 Thread
->DeadThread
= 0;
393 Thread
->Win32ThreadData
= 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
;
405 return(STATUS_SUCCESS
);
409 static NTSTATUS
PsCreateTeb (HANDLE ProcessHandle
,
412 PINITIAL_TEB InitialTeb
)
414 MEMORY_BASIC_INFORMATION Info
;
423 TebBase
= (PVOID
)0x7FFDE000;
428 Status
= NtQueryVirtualMemory(ProcessHandle
,
430 MemoryBasicInformation
,
434 if (!NT_SUCCESS(Status
))
436 DbgPrint("NtQueryVirtualMemory (Status %x)\n", Status
);
439 /* FIXME: Race between this and the above check */
440 if (Info
.State
== MEM_FREE
)
442 /* The TEB must reside in user space */
443 Status
= NtAllocateVirtualMemory(ProcessHandle
,
449 if (NT_SUCCESS(Status
))
455 TebBase
= TebBase
- TebSize
;
458 DPRINT ("TebBase %p TebSize %lu\n", TebBase
, TebSize
);
460 /* set all pointers to and from the TEB */
461 Teb
.Tib
.Self
= TebBase
;
462 if (Thread
->ThreadsProcess
)
464 Teb
.Peb
= Thread
->ThreadsProcess
->Peb
; /* No PEB yet!! */
466 DPRINT("Teb.Peb %x\n", Teb
.Peb
);
468 /* store stack information from InitialTeb */
469 if (InitialTeb
!= NULL
)
471 Teb
.Tib
.StackBase
= InitialTeb
->StackBase
;
472 Teb
.Tib
.StackLimit
= InitialTeb
->StackLimit
;
475 * I don't know if this is really stored in a WNT-TEB,
476 * but it's needed to free the thread stack. (Eric Kohl)
478 Teb
.StackCommit
= InitialTeb
->StackCommit
;
479 Teb
.StackCommitMax
= InitialTeb
->StackCommitMax
;
480 Teb
.StackReserve
= InitialTeb
->StackReserve
;
484 /* more initialization */
485 Teb
.Cid
.UniqueThread
= Thread
->Cid
.UniqueThread
;
486 Teb
.Cid
.UniqueProcess
= Thread
->Cid
.UniqueProcess
;
488 DPRINT("sizeof(NT_TEB) %x\n", sizeof(NT_TEB
));
490 /* write TEB data into teb page */
491 Status
= NtWriteVirtualMemory(ProcessHandle
,
497 if (!NT_SUCCESS(Status
))
500 DPRINT1 ("Writing TEB failed!\n");
503 NtFreeVirtualMemory(ProcessHandle
,
513 *TebPtr
= (PNT_TEB
)TebBase
;
516 DPRINT("TEB allocated at %p\n", TebBase
);
523 NtCreateThread (PHANDLE ThreadHandle
,
524 ACCESS_MASK DesiredAccess
,
525 POBJECT_ATTRIBUTES ObjectAttributes
,
526 HANDLE ProcessHandle
,
528 PCONTEXT ThreadContext
,
529 PINITIAL_TEB InitialTeb
,
530 BOOLEAN CreateSuspended
)
536 DPRINT("NtCreateThread(ThreadHandle %x, PCONTEXT %x)\n",
537 ThreadHandle
,ThreadContext
);
539 Status
= PsInitializeThread(ProcessHandle
,&Thread
,ThreadHandle
,
540 DesiredAccess
,ObjectAttributes
, FALSE
);
541 if (!NT_SUCCESS(Status
))
547 Status
= NtWriteVirtualMemory(ProcessHandle
,
548 (PVOID
)(((ULONG
)ThreadContext
->Esp
) - 8),
552 if (!NT_SUCCESS(Status
))
554 DPRINT1("NtWriteVirtualMemory failed\n");
557 ThreadContext
->Eip
= LdrpGetSystemDllEntryPoint
;
560 Status
= Ke386InitThreadWithContext(&Thread
->Tcb
, ThreadContext
);
561 if (!NT_SUCCESS(Status
))
566 Status
= PsCreateTeb (ProcessHandle
,
570 if (!NT_SUCCESS(Status
))
575 /* Attention: TebBase is in user memory space */
576 Thread
->Tcb
.Teb
= TebBase
;
578 Thread
->StartAddress
=NULL
;
586 * Maybe send a message to the process's debugger
588 DbgkCreateThread((PVOID
)ThreadContext
->Eip
);
591 * Start the thread running
593 if (!CreateSuspended
)
595 DPRINT("Not creating suspended\n");
596 PsUnblockThread(Thread
, NULL
);
602 return(STATUS_SUCCESS
);
607 PsCreateSystemThread(PHANDLE ThreadHandle
,
608 ACCESS_MASK DesiredAccess
,
609 POBJECT_ATTRIBUTES ObjectAttributes
,
610 HANDLE ProcessHandle
,
612 PKSTART_ROUTINE StartRoutine
,
615 * FUNCTION: Creates a thread which executes in kernel mode
617 * ThreadHandle (OUT) = Caller supplied storage for the returned thread
619 * DesiredAccess = Requested access to the thread
620 * ObjectAttributes = Object attributes (optional)
621 * ProcessHandle = Handle of process thread will run in
622 * NULL to use system process
623 * ClientId (OUT) = Caller supplied storage for the returned client id
624 * of the thread (optional)
625 * StartRoutine = Entry point for the thread
626 * StartContext = Argument supplied to the thread when it begins
628 * RETURNS: Success or failure status
634 DPRINT("PsCreateSystemThread(ThreadHandle %x, ProcessHandle %x)\n",
635 ThreadHandle
,ProcessHandle
);
637 Status
= PsInitializeThread(ProcessHandle
,&Thread
,ThreadHandle
,
638 DesiredAccess
,ObjectAttributes
, FALSE
);
639 if (!NT_SUCCESS(Status
))
644 Thread
->StartAddress
=StartRoutine
;
645 Status
= Ke386InitThread(&Thread
->Tcb
, StartRoutine
, StartContext
);
646 if (!NT_SUCCESS(Status
))
653 *ClientId
=Thread
->Cid
;
656 PsUnblockThread(Thread
, NULL
);
658 return(STATUS_SUCCESS
);