1 /* $Id: create.c,v 1.17 2000/06/27 19:20:45 dwelch 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>
27 #include <internal/string.h>
28 #include <internal/hal.h>
29 #include <internal/ps.h>
30 #include <internal/ob.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 /* FUNCTIONS ***************************************************************/
48 PsAssignImpersonationToken(PETHREAD Thread
,
52 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
;
55 if (TokenHandle
!= NULL
)
57 Status
= ObReferenceObjectByHandle(TokenHandle
,
63 if (!NT_SUCCESS(Status
))
67 ImpersonationLevel
= Token
->ImpersonationLevel
;
72 ImpersonationLevel
= 0;
75 PsImpersonateClient(Thread
,
82 ObDereferenceObject(Token
);
84 return(STATUS_SUCCESS
);
87 VOID STDCALL
PsRevertToSelf(PETHREAD Thread
)
89 if (Thread
->ActiveImpersonationInfo
!= 0)
91 Thread
->ActiveImpersonationInfo
= 0;
92 ObDereferenceObject(Thread
->ImpersonationInfo
->Token
);
96 VOID STDCALL
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;
131 PACCESS_TOKEN
PsReferenceEffectiveToken(PETHREAD Thread
,
132 PTOKEN_TYPE TokenType
,
134 PSECURITY_IMPERSONATION_LEVEL Level
)
139 if (Thread
->ActiveImpersonationInfo
== 0)
141 Process
= Thread
->ThreadsProcess
;
142 *TokenType
= TokenPrimary
;
144 Token
= Process
->Token
;
148 Token
= Thread
->ImpersonationInfo
->Token
;
149 *TokenType
= TokenImpersonation
;
150 *b
= Thread
->ImpersonationInfo
->Unknown2
;
151 *Level
= Thread
->ImpersonationInfo
->Level
;
156 NTSTATUS STDCALL
NtImpersonateThread (IN HANDLE ThreadHandle
,
157 IN HANDLE ThreadToImpersonateHandle
,
158 IN PSECURITY_QUALITY_OF_SERVICE
159 SecurityQualityOfService
)
162 PETHREAD ThreadToImpersonate
;
166 Status
= ObReferenceObjectByHandle(ThreadHandle
,
172 if (!NT_SUCCESS(Status
))
177 Status
= ObReferenceObjectByHandle(ThreadToImpersonateHandle
,
181 (PVOID
*)&ThreadToImpersonate
,
183 if (!NT_SUCCESS(Status
))
185 ObDereferenceObject(Thread
);
189 Status
= SeCreateClientSecurity(ThreadToImpersonate
,
190 SecurityQualityOfService
,
193 if (!NT_SUCCESS(Status
))
195 ObDereferenceObject(Thread
);
196 ObDereferenceObject(ThreadToImpersonate
);
200 SeImpersonateClient(&b
, Thread
);
203 ObDereferenceObject(b
.Token
);
205 return(STATUS_SUCCESS
);
208 NTSTATUS STDCALL
NtOpenThreadToken(IN HANDLE ThreadHandle
,
209 IN ACCESS_MASK DesiredAccess
,
210 IN BOOLEAN OpenAsSelf
,
211 OUT PHANDLE TokenHandle
)
218 Status
= ObReferenceObjectByHandle(ThreadHandle
,
224 if (!NT_SUCCESS(Status
))
229 Token
= PsReferencePrimaryToken(Thread
->ThreadsProcess
);
230 SepCreateImpersonationTokenDacl(Token
);
232 return(STATUS_UNSUCCESSFUL
);
235 PACCESS_TOKEN STDCALL
PsReferenceImpersonationToken(PETHREAD Thread
,
238 SECURITY_IMPERSONATION_LEVEL
*
241 if (Thread
->ActiveImpersonationInfo
== 0)
246 *Level
= Thread
->ImpersonationInfo
->Level
;
247 *Unknown1
= Thread
->ImpersonationInfo
->Unknown1
;
248 *Unknown2
= Thread
->ImpersonationInfo
->Unknown2
;
249 ObReferenceObjectByPointer(Thread
->ImpersonationInfo
->Token
,
253 return(Thread
->ImpersonationInfo
->Token
);
256 static VOID
PiTimeoutThread(struct _KDPC
*dpc
,
261 // wake up the thread, and tell it it timed out
262 NTSTATUS Status
= STATUS_TIMEOUT
;
264 DPRINT("PiTimeoutThread()\n");
266 KeRemoveAllWaitsThread((PETHREAD
)Context
, Status
);
269 VOID
PiBeforeBeginThread(CONTEXT c
)
271 DPRINT("PiBeforeBeginThread(Eip %x)\n", c
.Eip
);
272 //KeReleaseSpinLock(&PiThreadListLock, PASSIVE_LEVEL);
273 KeLowerIrql(PASSIVE_LEVEL
);
276 VOID
PsBeginThread(PKSTART_ROUTINE StartRoutine
, PVOID StartContext
)
280 // KeReleaseSpinLock(&PiThreadListLock,PASSIVE_LEVEL);
281 KeLowerIrql(PASSIVE_LEVEL
);
282 Ret
= StartRoutine(StartContext
);
283 PsTerminateSystemThread(Ret
);
287 VOID
PiDeleteThread(PVOID ObjectBody
)
291 DPRINT("PiDeleteThread(ObjectBody %x)\n",ObjectBody
);
293 KeAcquireSpinLock(&PiThreadListLock
, &oldIrql
);
294 DPRINT("Process %x(%d)\n", ((PETHREAD
)ObjectBody
)->ThreadsProcess
,
295 ObGetReferenceCount(((PETHREAD
)ObjectBody
)->ThreadsProcess
));
296 ObDereferenceObject(((PETHREAD
)ObjectBody
)->ThreadsProcess
);
297 ((PETHREAD
)ObjectBody
)->ThreadsProcess
= NULL
;
299 RemoveEntryList(&((PETHREAD
)ObjectBody
)->Tcb
.ThreadListEntry
);
300 HalReleaseTask((PETHREAD
)ObjectBody
);
301 KeReleaseSpinLock(&PiThreadListLock
, oldIrql
);
302 DPRINT("PiDeleteThread() finished\n");
305 VOID
PiCloseThread(PVOID ObjectBody
, ULONG HandleCount
)
307 DPRINT("PiCloseThread(ObjectBody %x)\n", ObjectBody
);
308 DPRINT("ObGetReferenceCount(ObjectBody) %d "
309 "ObGetHandleCount(ObjectBody) %d\n",
310 ObGetReferenceCount(ObjectBody
),
311 ObGetHandleCount(ObjectBody
));
314 NTSTATUS
PsInitializeThread(HANDLE ProcessHandle
,
316 PHANDLE ThreadHandle
,
317 ACCESS_MASK DesiredAccess
,
318 POBJECT_ATTRIBUTES ThreadAttributes
)
328 if (ProcessHandle
!= NULL
)
330 Status
= ObReferenceObjectByHandle(ProcessHandle
,
331 PROCESS_CREATE_THREAD
,
336 if (Status
!= STATUS_SUCCESS
)
338 DPRINT("Failed at %s:%d\n",__FILE__
,__LINE__
);
344 Process
= PsInitialSystemProcess
;
345 ObReferenceObjectByPointer(Process
,
346 PROCESS_CREATE_THREAD
,
352 * Create and initialize thread
354 Thread
= ObCreateObject(ThreadHandle
,
358 DPRINT("Thread = %x\n",Thread
);
362 Thread
->Tcb
.State
= THREAD_STATE_SUSPENDED
;
363 Thread
->Tcb
.SuspendCount
= 0;
364 Thread
->Tcb
.FreezeCount
= 1;
365 InitializeListHead(&Thread
->Tcb
.ApcState
.ApcListHead
[0]);
366 InitializeListHead(&Thread
->Tcb
.ApcState
.ApcListHead
[1]);
367 Thread
->Tcb
.KernelApcDisable
= 1;
368 Thread
->Tcb
.WaitIrql
= PASSIVE_LEVEL
;
369 Thread
->ThreadsProcess
= Process
;
370 KeInitializeDpc(&Thread
->Tcb
.TimerDpc
, PiTimeoutThread
, Thread
);
371 Thread
->Tcb
.WaitBlockList
= NULL
;
372 InsertTailList(&Thread
->ThreadsProcess
->Pcb
.ThreadListHead
,
373 &Thread
->Tcb
.ProcessThreadListEntry
);
374 InitializeListHead(&Thread
->TerminationPortList
);
375 KeInitializeDispatcherHeader(&Thread
->Tcb
.DispatcherHeader
,
379 KeInitializeSpinLock(&Thread
->ActiveTimerListLock
);
380 InitializeListHead(&Thread
->IrpList
);
381 Thread
->Cid
.UniqueThread
= (HANDLE
)InterlockedIncrement(
382 &PiNextThreadUniqueId
);
383 Thread
->Cid
.UniqueProcess
= (HANDLE
)Thread
->ThreadsProcess
->UniqueProcessId
;
384 DPRINT("Thread->Cid.UniqueThread %d\n",Thread
->Cid
.UniqueThread
);
388 KeAcquireSpinLock(&PiThreadListLock
, &oldIrql
);
389 InsertTailList(&PiThreadListHead
, &Thread
->Tcb
.ThreadListEntry
);
390 KeReleaseSpinLock(&PiThreadListLock
, oldIrql
);
392 Thread
->Tcb
.BasePriority
= Thread
->ThreadsProcess
->Pcb
.BasePriority
;
393 Thread
->Tcb
.Priority
= Thread
->Tcb
.BasePriority
;
395 return(STATUS_SUCCESS
);
399 static NTSTATUS
PsCreateTeb (HANDLE ProcessHandle
,
402 PINITIAL_TEB InitialTeb
)
404 // MEMORY_BASIC_INFORMATION Info;
412 TebBase
= (PVOID
)0x7FFDE000;
417 /* The TEB must reside in user space */
418 Status
= NtAllocateVirtualMemory(ProcessHandle
,
424 if (NT_SUCCESS(Status
))
426 // DPRINT1 ("TEB allocated at %x\n", TebBase);
431 DPRINT ("TEB allocation failed! Status %x\n",Status
);
436 // TebBase = Info.BaseAddress - TebSize;
437 TebBase
= TebBase
- TebSize
;
440 DPRINT ("TebBase %p TebSize %lu\n", TebBase
, TebSize
);
442 /* set all pointers to and from the TEB */
443 Teb
.Tib
.Self
= TebBase
;
444 if (Thread
->ThreadsProcess
)
446 Teb
.Peb
= Thread
->ThreadsProcess
->Peb
; /* No PEB yet!! */
448 // DPRINT1("Teb.Peb %x\n", Teb.Peb);
450 /* store stack information from InitialTeb */
451 if (InitialTeb
!= NULL
)
453 Teb
.Tib
.StackBase
= InitialTeb
->StackBase
;
454 Teb
.Tib
.StackLimit
= InitialTeb
->StackLimit
;
457 * I don't know if this is really stored in a WNT-TEB,
458 * but it's needed to free the thread stack. (Eric Kohl)
460 Teb
.StackCommit
= InitialTeb
->StackCommit
;
461 Teb
.StackCommitMax
= InitialTeb
->StackCommitMax
;
462 Teb
.StackReserved
= InitialTeb
->StackReserved
;
466 /* more initialization */
467 Teb
.Cid
.UniqueThread
= Thread
->Cid
.UniqueThread
;
468 Teb
.Cid
.UniqueProcess
= Thread
->Cid
.UniqueProcess
;
470 DPRINT("sizeof(NT_TEB) %x\n", sizeof(NT_TEB
));
472 /* write TEB data into teb page */
473 Status
= NtWriteVirtualMemory(ProcessHandle
,
479 if (!NT_SUCCESS(Status
))
482 DPRINT1 ("Writing TEB failed!\n");
485 NtFreeVirtualMemory(ProcessHandle
,
495 *TebPtr
= (PNT_TEB
)TebBase
;
498 // DPRINT1 ("TEB allocated at %p\n", TebBase);
504 NTSTATUS STDCALL
NtCreateThread (PHANDLE ThreadHandle
,
505 ACCESS_MASK DesiredAccess
,
506 POBJECT_ATTRIBUTES ObjectAttributes
,
507 HANDLE ProcessHandle
,
509 PCONTEXT ThreadContext
,
510 PINITIAL_TEB InitialTeb
,
511 BOOLEAN CreateSuspended
)
517 DPRINT("NtCreateThread(ThreadHandle %x, PCONTEXT %x)\n",
518 ThreadHandle
,ThreadContext
);
520 Status
= PsInitializeThread(ProcessHandle
,&Thread
,ThreadHandle
,
521 DesiredAccess
,ObjectAttributes
);
522 if (!NT_SUCCESS(Status
))
527 Status
= HalInitTaskWithContext(Thread
,ThreadContext
);
528 if (!NT_SUCCESS(Status
))
533 Status
= PsCreateTeb (ProcessHandle
,
537 if (!NT_SUCCESS(Status
))
542 /* Attention: TebBase is in user memory space */
543 Thread
->Tcb
.Teb
= TebBase
;
545 Thread
->StartAddress
=NULL
;
553 * Maybe send a message to the process's debugger
556 if (ParentProcess
->DebugPort
!= NULL
)
558 LPC_DBG_MESSAGE Message
;
562 Message
.Header
.MessageSize
= sizeof(LPC_DBG_MESSAGE
);
563 Message
.Header
.DataSize
= sizeof(LPC_DBG_MESSAGE
) -
564 sizeof(LPC_MESSAGE_HEADER
);
565 Message
.EventCode
= DBG_EVENT_CREATE_THREAD
;
566 Message
.Data
.CreateThread
.StartAddress
=
568 Message
.Data
.CreateProcess
.Base
= ImageBase
;
569 Message
.Data
.CreateProcess
.EntryPoint
= NULL
; //
571 Status
= LpcSendDebugMessagePort(ParentProcess
->DebugPort
,
576 if (!CreateSuspended
)
578 DPRINT("Not creating suspended\n");
579 PsUnfreezeThread(Thread
, NULL
);
581 DPRINT("Thread %x\n", Thread
);
582 DPRINT("ObGetReferenceCount(Thread) %d ObGetHandleCount(Thread) %x\n",
583 ObGetReferenceCount(Thread
), ObGetHandleCount(Thread
));
584 DPRINT("Finished PsCreateThread()\n");
585 return(STATUS_SUCCESS
);
589 NTSTATUS STDCALL
PsCreateSystemThread(PHANDLE ThreadHandle
,
590 ACCESS_MASK DesiredAccess
,
591 POBJECT_ATTRIBUTES ObjectAttributes
,
592 HANDLE ProcessHandle
,
594 PKSTART_ROUTINE StartRoutine
,
597 * FUNCTION: Creates a thread which executes in kernel mode
599 * ThreadHandle (OUT) = Caller supplied storage for the returned thread
601 * DesiredAccess = Requested access to the thread
602 * ObjectAttributes = Object attributes (optional)
603 * ProcessHandle = Handle of process thread will run in
604 * NULL to use system process
605 * ClientId (OUT) = Caller supplied storage for the returned client id
606 * of the thread (optional)
607 * StartRoutine = Entry point for the thread
608 * StartContext = Argument supplied to the thread when it begins
610 * RETURNS: Success or failure status
616 DPRINT("PsCreateSystemThread(ThreadHandle %x, ProcessHandle %x)\n",
617 ThreadHandle
,ProcessHandle
);
619 Status
= PsInitializeThread(ProcessHandle
,&Thread
,ThreadHandle
,
620 DesiredAccess
,ObjectAttributes
);
621 if (!NT_SUCCESS(Status
))
626 Thread
->StartAddress
=StartRoutine
;
627 Status
= HalInitTask(Thread
,StartRoutine
,StartContext
);
628 if (!NT_SUCCESS(Status
))
635 *ClientId
=Thread
->Cid
;
638 PsUnfreezeThread(Thread
, NULL
);
640 return(STATUS_SUCCESS
);