1 /* $Id: create.c,v 1.43 2002/02/08 02:57:07 chorns 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 #define MAX_THREAD_NOTIFY_ROUTINE_COUNT 8
45 static ULONG PiThreadNotifyRoutineCount
= 0;
46 static PCREATE_THREAD_NOTIFY_ROUTINE
47 PiThreadNotifyRoutine
[MAX_THREAD_NOTIFY_ROUTINE_COUNT
];
49 /* FUNCTIONS ***************************************************************/
52 PsAssignImpersonationToken(PETHREAD Thread
,
56 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
;
59 if (TokenHandle
!= NULL
)
61 Status
= ObReferenceObjectByHandle(TokenHandle
,
67 if (!NT_SUCCESS(Status
))
71 ImpersonationLevel
= Token
->ImpersonationLevel
;
76 ImpersonationLevel
= 0;
79 PsImpersonateClient(Thread
,
86 ObDereferenceObject(Token
);
88 return(STATUS_SUCCESS
);
96 Thread
= PsGetCurrentThread();
98 if (Thread
->ActiveImpersonationInfo
!= 0)
100 ObDereferenceObject(Thread
->ImpersonationInfo
->Token
);
101 Thread
->ActiveImpersonationInfo
= 0;
106 PsImpersonateClient(PETHREAD Thread
,
110 SECURITY_IMPERSONATION_LEVEL Level
)
114 if (Thread
->ActiveImpersonationInfo
!= 0)
116 Thread
->ActiveImpersonationInfo
= 0;
117 if (Thread
->ImpersonationInfo
->Token
!= NULL
)
119 ObDereferenceObject(Thread
->ImpersonationInfo
->Token
);
124 if (Thread
->ActiveImpersonationInfo
== 0 ||
125 Thread
->ImpersonationInfo
== NULL
)
127 Thread
->ImpersonationInfo
= ExAllocatePool(NonPagedPool
,
128 sizeof(PS_IMPERSONATION_INFO
));
130 Thread
->ImpersonationInfo
->Level
= Level
;
131 Thread
->ImpersonationInfo
->Unknown2
= c
;
132 Thread
->ImpersonationInfo
->Unknown1
= b
;
133 Thread
->ImpersonationInfo
->Token
= Token
;
134 ObReferenceObjectByPointer(Token
,
138 Thread
->ActiveImpersonationInfo
= 1;
142 PsReferenceEffectiveToken(PETHREAD Thread
,
143 PTOKEN_TYPE TokenType
,
145 PSECURITY_IMPERSONATION_LEVEL Level
)
150 if (Thread
->ActiveImpersonationInfo
== 0)
152 Process
= Thread
->ThreadsProcess
;
153 *TokenType
= TokenPrimary
;
155 Token
= Process
->Token
;
159 Token
= Thread
->ImpersonationInfo
->Token
;
160 *TokenType
= TokenImpersonation
;
161 *b
= Thread
->ImpersonationInfo
->Unknown2
;
162 *Level
= Thread
->ImpersonationInfo
->Level
;
168 NtImpersonateThread (IN HANDLE ThreadHandle
,
169 IN HANDLE ThreadToImpersonateHandle
,
170 IN PSECURITY_QUALITY_OF_SERVICE
171 SecurityQualityOfService
)
174 PETHREAD ThreadToImpersonate
;
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(&b
, Thread
);
215 ObDereferenceObject(b
.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 PiTimeoutThread(struct _KDPC
*dpc
,
275 // wake up the thread, and tell it it timed out
276 NTSTATUS Status
= STATUS_TIMEOUT
;
278 DPRINT("PiTimeoutThread()\n");
280 KeRemoveAllWaitsThread((PETHREAD
)Context
, Status
);
284 PiBeforeBeginThread(CONTEXT c
)
286 DPRINT("PiBeforeBeginThread(Eip %x)\n", c
.Eip
);
287 //KeReleaseSpinLock(&PiThreadListLock, PASSIVE_LEVEL);
288 KeLowerIrql(PASSIVE_LEVEL
);
293 PsBeginThread(PKSTART_ROUTINE StartRoutine
, PVOID StartContext
)
297 // KeReleaseSpinLock(&PiThreadListLock,PASSIVE_LEVEL);
298 KeLowerIrql(PASSIVE_LEVEL
);
299 Ret
= StartRoutine(StartContext
);
300 PsTerminateSystemThread(Ret
);
306 PiDeleteThread(PVOID ObjectBody
)
312 DPRINT("PiDeleteThread(ObjectBody %x)\n",ObjectBody
);
314 KeAcquireSpinLock(&PiThreadListLock
, &oldIrql
);
315 Thread
= (PETHREAD
)ObjectBody
;
317 for (i
= 0; i
< PiThreadNotifyRoutineCount
; i
++)
319 PiThreadNotifyRoutine
[i
](Thread
->Cid
.UniqueProcess
,
320 Thread
->Cid
.UniqueThread
,
324 DPRINT("Process %x(%d)\n",
325 Thread
->ThreadsProcess
,
326 ObGetReferenceCount(Thread
->ThreadsProcess
));
327 ObDereferenceObject(Thread
->ThreadsProcess
);
328 Thread
->ThreadsProcess
= NULL
;
330 RemoveEntryList(&Thread
->Tcb
.ThreadListEntry
);
331 HalReleaseTask(Thread
);
332 KeReleaseSpinLock(&PiThreadListLock
, oldIrql
);
333 DPRINT("PiDeleteThread() finished\n");
337 PiCloseThread(PVOID ObjectBody
,
340 DPRINT("PiCloseThread(ObjectBody %x)\n", ObjectBody
);
341 DPRINT("ObGetReferenceCount(ObjectBody) %d "
342 "ObGetHandleCount(ObjectBody) %d\n",
343 ObGetReferenceCount(ObjectBody
),
344 ObGetHandleCount(ObjectBody
));
348 PsInitializeThread(HANDLE ProcessHandle
,
350 PHANDLE ThreadHandle
,
351 ACCESS_MASK DesiredAccess
,
352 POBJECT_ATTRIBUTES ThreadAttributes
,
364 if (ProcessHandle
!= NULL
)
366 Status
= ObReferenceObjectByHandle(ProcessHandle
,
367 PROCESS_CREATE_THREAD
,
372 if (Status
!= STATUS_SUCCESS
)
374 DPRINT("Failed at %s:%d\n",__FILE__
,__LINE__
);
377 DPRINT( "Creating thread in process %x\n", Process
);
381 Process
= PsInitialSystemProcess
;
382 ObReferenceObjectByPointer(Process
,
383 PROCESS_CREATE_THREAD
,
389 * Create and initialize thread
391 Status
= ObCreateObject(ThreadHandle
,
396 if (!NT_SUCCESS(Status
))
401 DPRINT("Thread = %x\n",Thread
);
405 KeInitializeThread(&Process
->Pcb
, &Thread
->Tcb
, First
);
406 Thread
->ThreadsProcess
= Process
;
408 * FIXME: What lock protects this?
410 InsertTailList(&Thread
->ThreadsProcess
->ThreadListHead
,
411 &Thread
->Tcb
.ProcessThreadListEntry
);
412 InitializeListHead(&Thread
->TerminationPortList
);
413 KeInitializeSpinLock(&Thread
->ActiveTimerListLock
);
414 InitializeListHead(&Thread
->IrpList
);
415 Thread
->Cid
.UniqueThread
= (HANDLE
)InterlockedIncrement(
416 &PiNextThreadUniqueId
);
417 Thread
->Cid
.UniqueProcess
= (HANDLE
)Thread
->ThreadsProcess
->UniqueProcessId
;
418 Thread
->DeadThread
= 0;
419 Thread
->Win32Thread
= 0;
420 DPRINT("Thread->Cid.UniqueThread %d\n",Thread
->Cid
.UniqueThread
);
424 KeAcquireSpinLock(&PiThreadListLock
, &oldIrql
);
425 InsertTailList(&PiThreadListHead
, &Thread
->Tcb
.ThreadListEntry
);
426 KeReleaseSpinLock(&PiThreadListLock
, oldIrql
);
428 Thread
->Tcb
.BasePriority
= Thread
->ThreadsProcess
->Pcb
.BasePriority
;
429 Thread
->Tcb
.Priority
= Thread
->Tcb
.BasePriority
;
431 for (i
= 0; i
< PiThreadNotifyRoutineCount
; i
++)
433 PiThreadNotifyRoutine
[i
](Thread
->Cid
.UniqueProcess
,
434 Thread
->Cid
.UniqueThread
,
438 return(STATUS_SUCCESS
);
443 PsCreateTeb(HANDLE ProcessHandle
,
446 PINITIAL_TEB InitialTeb
)
448 MEMORY_BASIC_INFORMATION Info
;
457 TebBase
= (PVOID
)0x7FFDE000;
462 Status
= NtQueryVirtualMemory(ProcessHandle
,
464 MemoryBasicInformation
,
468 if (!NT_SUCCESS(Status
))
470 CPRINT("NtQueryVirtualMemory (Status %x)\n", Status
);
473 /* FIXME: Race between this and the above check */
474 if (Info
.State
== MEM_FREE
)
476 /* The TEB must reside in user space */
477 Status
= NtAllocateVirtualMemory(ProcessHandle
,
481 MEM_RESERVE
| MEM_COMMIT
,
483 if (NT_SUCCESS(Status
))
489 TebBase
= TebBase
- TebSize
;
492 DPRINT ("TebBase %p TebSize %lu\n", TebBase
, TebSize
);
494 /* set all pointers to and from the TEB */
495 Teb
.Tib
.Self
= TebBase
;
496 if (Thread
->ThreadsProcess
)
498 Teb
.Peb
= Thread
->ThreadsProcess
->Peb
; /* No PEB yet!! */
500 DPRINT("Teb.Peb %x\n", Teb
.Peb
);
502 /* store stack information from InitialTeb */
503 if (InitialTeb
!= NULL
)
505 Teb
.Tib
.StackBase
= InitialTeb
->StackBase
;
506 Teb
.Tib
.StackLimit
= InitialTeb
->StackLimit
;
507 Teb
.DeallocationStack
= InitialTeb
->StackAllocate
;
510 /* more initialization */
511 Teb
.Cid
.UniqueThread
= Thread
->Cid
.UniqueThread
;
512 Teb
.Cid
.UniqueProcess
= Thread
->Cid
.UniqueProcess
;
513 Teb
.CurrentLocale
= PsDefaultThreadLocaleId
;
515 DPRINT("sizeof(TEB) %x\n", sizeof(TEB
));
517 /* write TEB data into teb page */
518 Status
= NtWriteVirtualMemory(ProcessHandle
,
524 if (!NT_SUCCESS(Status
))
527 DPRINT1 ("Writing TEB failed!\n");
530 NtFreeVirtualMemory(ProcessHandle
,
540 *TebPtr
= (PTEB
)TebBase
;
543 DPRINT("TEB allocated at %p\n", TebBase
);
550 NtCreateThread (PHANDLE ThreadHandle
,
551 ACCESS_MASK DesiredAccess
,
552 POBJECT_ATTRIBUTES ObjectAttributes
,
553 HANDLE ProcessHandle
,
555 PCONTEXT ThreadContext
,
556 PINITIAL_TEB InitialTeb
,
557 BOOLEAN CreateSuspended
)
563 DPRINT("NtCreateThread(ThreadHandle %x, PCONTEXT %x)\n",
564 ThreadHandle
,ThreadContext
);
566 Status
= PsInitializeThread(ProcessHandle
,
572 if (!NT_SUCCESS(Status
))
577 Status
= Ke386InitThreadWithContext(&Thread
->Tcb
,
579 if (!NT_SUCCESS(Status
))
584 Status
= PsCreateTeb(ProcessHandle
,
588 if (!NT_SUCCESS(Status
))
593 /* Attention: TebBase is in user memory space */
594 Thread
->Tcb
.Teb
= TebBase
;
596 Thread
->StartAddress
=NULL
;
604 * Maybe send a message to the process's debugger
606 DbgkCreateThread((PVOID
)ThreadContext
->Eip
);
609 * Start the thread running
611 if (!CreateSuspended
)
613 DPRINT("Not creating suspended\n");
614 PsUnblockThread(Thread
, NULL
);
620 return(STATUS_SUCCESS
);
625 PsCreateSystemThread(PHANDLE ThreadHandle
,
626 ACCESS_MASK DesiredAccess
,
627 POBJECT_ATTRIBUTES ObjectAttributes
,
628 HANDLE ProcessHandle
,
630 PKSTART_ROUTINE StartRoutine
,
633 * FUNCTION: Creates a thread which executes in kernel mode
635 * ThreadHandle (OUT) = Caller supplied storage for the returned thread
637 * DesiredAccess = Requested access to the thread
638 * ObjectAttributes = Object attributes (optional)
639 * ProcessHandle = Handle of process thread will run in
640 * NULL to use system process
641 * ClientId (OUT) = Caller supplied storage for the returned client id
642 * of the thread (optional)
643 * StartRoutine = Entry point for the thread
644 * StartContext = Argument supplied to the thread when it begins
646 * RETURNS: Success or failure status
652 DPRINT("PsCreateSystemThread(ThreadHandle %x, ProcessHandle %x)\n",
653 ThreadHandle
,ProcessHandle
);
655 Status
= PsInitializeThread(ProcessHandle
,
661 if (!NT_SUCCESS(Status
))
666 Thread
->StartAddress
=StartRoutine
;
667 Status
= Ke386InitThread(&Thread
->Tcb
,
670 if (!NT_SUCCESS(Status
))
677 *ClientId
=Thread
->Cid
;
680 PsUnblockThread(Thread
, NULL
);
682 return(STATUS_SUCCESS
);
687 PsSetCreateThreadNotifyRoutine(IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine
)
689 if (PiThreadNotifyRoutineCount
>= MAX_THREAD_NOTIFY_ROUTINE_COUNT
)
690 return(STATUS_INSUFFICIENT_RESOURCES
);
692 PiThreadNotifyRoutine
[PiThreadNotifyRoutineCount
] = NotifyRoutine
;
693 PiThreadNotifyRoutineCount
++;
695 return(STATUS_SUCCESS
);