1 /* $Id: create.c,v 1.10 2000/02/14 14:13:33 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 ***************************************************************/
46 NTSTATUS
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
);
85 VOID
PsRevertToSelf(PETHREAD Thread
)
87 if (Thread
->ActiveImpersonationInfo
!= 0)
89 Thread
->ActiveImpersonationInfo
= 0;
90 ObDereferenceObject(Thread
->ImpersonationInfo
->Token
);
94 VOID
PsImpersonateClient(PETHREAD Thread
,
98 SECURITY_IMPERSONATION_LEVEL Level
)
102 if (Thread
->ActiveImpersonationInfo
!= 0)
104 Thread
->ActiveImpersonationInfo
= 0;
105 if (Thread
->ImpersonationInfo
->Token
!= NULL
)
107 ObDereferenceObject(Thread
->ImpersonationInfo
->Token
);
112 if (Thread
->ActiveImpersonationInfo
== 0 ||
113 Thread
->ImpersonationInfo
== NULL
)
115 Thread
->ImpersonationInfo
= ExAllocatePool(NonPagedPool
,
116 sizeof(PS_IMPERSONATION_INFO
));
118 Thread
->ImpersonationInfo
->Level
= Level
;
119 Thread
->ImpersonationInfo
->Unknown2
= c
;
120 Thread
->ImpersonationInfo
->Unknown1
= b
;
121 Thread
->ImpersonationInfo
->Token
= Token
;
122 ObReferenceObjectByPointer(Token
,
126 Thread
->ActiveImpersonationInfo
= 1;
129 PACCESS_TOKEN
PsReferenceEffectiveToken(PETHREAD Thread
,
130 PTOKEN_TYPE TokenType
,
132 PSECURITY_IMPERSONATION_LEVEL Level
)
137 if (Thread
->ActiveImpersonationInfo
== 0)
139 Process
= Thread
->ThreadsProcess
;
140 *TokenType
= TokenPrimary
;
142 Token
= Process
->Token
;
146 Token
= Thread
->ImpersonationInfo
->Token
;
147 *TokenType
= TokenImpersonation
;
148 *b
= Thread
->ImpersonationInfo
->Unknown2
;
149 *Level
= Thread
->ImpersonationInfo
->Level
;
154 NTSTATUS STDCALL
NtImpersonateThread (IN HANDLE ThreadHandle
,
155 IN HANDLE ThreadToImpersonateHandle
,
156 IN PSECURITY_QUALITY_OF_SERVICE
157 SecurityQualityOfService
)
160 PETHREAD ThreadToImpersonate
;
164 Status
= ObReferenceObjectByHandle(ThreadHandle
,
170 if (!NT_SUCCESS(Status
))
175 Status
= ObReferenceObjectByHandle(ThreadToImpersonateHandle
,
179 (PVOID
*)&ThreadToImpersonate
,
181 if (!NT_SUCCESS(Status
))
183 ObDereferenceObject(Thread
);
187 Status
= SeCreateClientSecurity(ThreadToImpersonate
,
188 SecurityQualityOfService
,
191 if (!NT_SUCCESS(Status
))
193 ObDereferenceObject(Thread
);
194 ObDereferenceObject(ThreadToImpersonate
);
198 SeImpersonateClient(&b
, Thread
);
201 ObDereferenceObject(b
.Token
);
203 return(STATUS_SUCCESS
);
206 NTSTATUS STDCALL
NtOpenThreadToken(IN HANDLE ThreadHandle
,
207 IN ACCESS_MASK DesiredAccess
,
208 IN BOOLEAN OpenAsSelf
,
209 OUT PHANDLE TokenHandle
)
216 Status
= ObReferenceObjectByHandle(ThreadHandle
,
222 if (!NT_SUCCESS(Status
))
227 Token
= PsReferencePrimaryToken(Thread
->ThreadsProcess
);
228 SepCreateImpersonationTokenDacl(Token
);
230 return(STATUS_UNSUCCESSFUL
);
233 PACCESS_TOKEN
PsReferenceImpersonationToken(PETHREAD Thread
,
236 SECURITY_IMPERSONATION_LEVEL
*
239 if (Thread
->ActiveImpersonationInfo
== 0)
244 *Level
= Thread
->ImpersonationInfo
->Level
;
245 *Unknown1
= Thread
->ImpersonationInfo
->Unknown1
;
246 *Unknown2
= Thread
->ImpersonationInfo
->Unknown2
;
247 ObReferenceObjectByPointer(Thread
->ImpersonationInfo
->Token
,
251 return(Thread
->ImpersonationInfo
->Token
);
254 static VOID
PiTimeoutThread(struct _KDPC
*dpc
,
259 // wake up the thread, and tell it it timed out
260 NTSTATUS Status
= STATUS_TIMEOUT
;
262 DPRINT("PiTimeoutThread()\n");
264 KeRemoveAllWaitsThread((PETHREAD
)Context
, Status
);
267 VOID
PiBeforeBeginThread(VOID
)
269 DPRINT("PiBeforeBeginThread()\n");
270 //KeReleaseSpinLock(&PiThreadListLock, PASSIVE_LEVEL);
271 KeLowerIrql(PASSIVE_LEVEL
);
274 VOID
PsBeginThread(PKSTART_ROUTINE StartRoutine
, PVOID StartContext
)
278 // KeReleaseSpinLock(&PiThreadListLock,PASSIVE_LEVEL);
279 KeLowerIrql(PASSIVE_LEVEL
);
280 Ret
= StartRoutine(StartContext
);
281 PsTerminateSystemThread(Ret
);
285 VOID
PiDeleteThread(PVOID ObjectBody
)
289 DPRINT("PiDeleteThread(ObjectBody %x)\n",ObjectBody
);
291 KeAcquireSpinLock(&PiThreadListLock
, &oldIrql
);
292 DPRINT("Process %x(%d)\n", ((PETHREAD
)ObjectBody
)->ThreadsProcess
,
293 ObGetReferenceCount(((PETHREAD
)ObjectBody
)->ThreadsProcess
));
294 ObDereferenceObject(((PETHREAD
)ObjectBody
)->ThreadsProcess
);
295 ((PETHREAD
)ObjectBody
)->ThreadsProcess
= NULL
;
297 RemoveEntryList(&((PETHREAD
)ObjectBody
)->Tcb
.ThreadListEntry
);
298 HalReleaseTask((PETHREAD
)ObjectBody
);
299 KeReleaseSpinLock(&PiThreadListLock
, oldIrql
);
300 DPRINT("PiDeleteThread() finished\n");
303 VOID
PiCloseThread(PVOID ObjectBody
, ULONG HandleCount
)
305 DPRINT("PiCloseThread(ObjectBody %x)\n", ObjectBody
);
306 DPRINT("ObGetReferenceCount(ObjectBody) %d "
307 "ObGetHandleCount(ObjectBody) %d\n",
308 ObGetReferenceCount(ObjectBody
),
309 ObGetHandleCount(ObjectBody
));
312 NTSTATUS
PsInitializeThread(HANDLE ProcessHandle
,
314 PHANDLE ThreadHandle
,
315 ACCESS_MASK DesiredAccess
,
316 POBJECT_ATTRIBUTES ThreadAttributes
)
326 if (ProcessHandle
!= NULL
)
328 Status
= ObReferenceObjectByHandle(ProcessHandle
,
329 PROCESS_CREATE_THREAD
,
334 if (Status
!= STATUS_SUCCESS
)
336 DPRINT("Failed at %s:%d\n",__FILE__
,__LINE__
);
342 Process
= SystemProcess
;
343 ObReferenceObjectByPointer(Process
,
344 PROCESS_CREATE_THREAD
,
350 * Create and initialize thread
352 Thread
= ObCreateObject(ThreadHandle
,
356 DPRINT("Thread = %x\n",Thread
);
360 Thread
->Tcb
.State
= THREAD_STATE_SUSPENDED
;
361 Thread
->Tcb
.SuspendCount
= 0;
362 Thread
->Tcb
.FreezeCount
= 1;
363 InitializeListHead(&Thread
->Tcb
.ApcState
.ApcListHead
[0]);
364 InitializeListHead(&Thread
->Tcb
.ApcState
.ApcListHead
[1]);
365 Thread
->Tcb
.KernelApcDisable
= 1;
366 Thread
->Tcb
.WaitIrql
= PASSIVE_LEVEL
;
367 Thread
->ThreadsProcess
= Process
;
368 KeInitializeDpc(&Thread
->Tcb
.TimerDpc
, PiTimeoutThread
, Thread
);
369 Thread
->Tcb
.WaitBlockList
= NULL
;
370 InsertTailList(&Thread
->ThreadsProcess
->Pcb
.ThreadListHead
,
371 &Thread
->Tcb
.ProcessThreadListEntry
);
372 DPRINT1("Inserting %x into process %x list\n",
373 Thread
, Thread
->ThreadsProcess
);
374 KeInitializeDispatcherHeader(&Thread
->Tcb
.DispatcherHeader
,
379 InitializeListHead(&Thread
->IrpList
);
380 Thread
->Cid
.UniqueThread
= (HANDLE
)InterlockedIncrement(
381 &PiNextThreadUniqueId
);
382 Thread
->Cid
.UniqueProcess
= (HANDLE
)Thread
->ThreadsProcess
->UniqueProcessId
;
383 DPRINT("Thread->Cid.UniqueThread %d\n",Thread
->Cid
.UniqueThread
);
387 KeAcquireSpinLock(&PiThreadListLock
, &oldIrql
);
388 InsertTailList(&PiThreadListHead
, &Thread
->Tcb
.ThreadListEntry
);
389 KeReleaseSpinLock(&PiThreadListLock
, oldIrql
);
391 Thread
->Tcb
.BasePriority
= Thread
->ThreadsProcess
->Pcb
.BasePriority
;
392 Thread
->Tcb
.Priority
= Thread
->Tcb
.BasePriority
;
394 return(STATUS_SUCCESS
);
398 static NTSTATUS
PsCreateTeb (HANDLE ProcessHandle
,
401 PINITIAL_TEB InitialTeb
)
403 // MEMORY_BASIC_INFORMATION Info;
411 TebBase
= (PVOID
)0x7FFDE000;
416 /* The TEB must reside in user space */
417 Status
= NtAllocateVirtualMemory(ProcessHandle
,
423 if (NT_SUCCESS(Status
))
425 DPRINT ("TEB allocated at %x\n", TebBase
);
430 DPRINT ("TEB allocation failed! Status %x\n",Status
);
435 // TebBase = Info.BaseAddress - TebSize;
436 TebBase
= TebBase
- TebSize
;
439 DPRINT ("TebBase %p TebSize %lu\n", TebBase
, TebSize
);
441 /* set all pointers to and from the TEB */
442 Teb
.Tib
.Self
= TebBase
;
443 if (Thread
->ThreadsProcess
)
445 Teb
.Peb
= Thread
->ThreadsProcess
->Peb
; /* No PEB yet!! */
448 /* store stack information from InitialTeb */
449 if (InitialTeb
!= NULL
)
451 Teb
.Tib
.StackBase
= InitialTeb
->StackBase
;
452 Teb
.Tib
.StackLimit
= InitialTeb
->StackLimit
;
455 * I don't know if this is really stored in a WNT-TEB,
456 * but it's needed to free the thread stack. (Eric Kohl)
458 Teb
.StackCommit
= InitialTeb
->StackCommit
;
459 Teb
.StackCommitMax
= InitialTeb
->StackCommitMax
;
460 Teb
.StackReserved
= InitialTeb
->StackReserved
;
464 /* more initialization */
465 Teb
.Cid
.UniqueThread
= Thread
->Cid
.UniqueThread
;
466 Teb
.Cid
.UniqueProcess
= Thread
->Cid
.UniqueProcess
;
468 DPRINT("sizeof(NT_TEB) %x\n", sizeof(NT_TEB
));
470 /* write TEB data into teb page */
471 Status
= NtWriteVirtualMemory(ProcessHandle
,
477 if (!NT_SUCCESS(Status
))
480 DPRINT ("Writing TEB failed!\n");
483 NtFreeVirtualMemory(ProcessHandle
,
491 /* FIXME: fs:[0] = TEB */
495 // *TebPtr = (PNT_TEB)TebBase;
498 DPRINT ("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
;
552 if (!CreateSuspended
)
554 DPRINT("Not creating suspended\n");
555 PsUnfreezeThread(Thread
, NULL
);
557 DPRINT("Thread %x\n", Thread
);
558 DPRINT("ObGetReferenceCount(Thread) %d ObGetHandleCount(Thread) %x\n",
559 ObGetReferenceCount(Thread
), ObGetHandleCount(Thread
));
560 DPRINT("Finished PsCreateThread()\n");
561 return(STATUS_SUCCESS
);
565 NTSTATUS
PsCreateSystemThread(PHANDLE ThreadHandle
,
566 ACCESS_MASK DesiredAccess
,
567 POBJECT_ATTRIBUTES ObjectAttributes
,
568 HANDLE ProcessHandle
,
570 PKSTART_ROUTINE StartRoutine
,
573 * FUNCTION: Creates a thread which executes in kernel mode
575 * ThreadHandle (OUT) = Caller supplied storage for the returned thread
577 * DesiredAccess = Requested access to the thread
578 * ObjectAttributes = Object attributes (optional)
579 * ProcessHandle = Handle of process thread will run in
580 * NULL to use system process
581 * ClientId (OUT) = Caller supplied storage for the returned client id
582 * of the thread (optional)
583 * StartRoutine = Entry point for the thread
584 * StartContext = Argument supplied to the thread when it begins
586 * RETURNS: Success or failure status
592 DPRINT("PsCreateSystemThread(ThreadHandle %x, ProcessHandle %x)\n",
593 ThreadHandle
,ProcessHandle
);
595 Status
= PsInitializeThread(ProcessHandle
,&Thread
,ThreadHandle
,
596 DesiredAccess
,ObjectAttributes
);
597 if (!NT_SUCCESS(Status
))
602 Thread
->StartAddress
=StartRoutine
;
603 Status
= HalInitTask(Thread
,StartRoutine
,StartContext
);
604 if (!NT_SUCCESS(Status
))
611 *ClientId
=Thread
->Cid
;
614 PsUnfreezeThread(Thread
, NULL
);
616 return(STATUS_SUCCESS
);