1 /* $Id: create.c,v 1.2 1999/12/14 18:35:19 phreak 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 static VOID
PiTimeoutThread( struct _KDPC
*dpc
, PVOID Context
, PVOID arg1
, PVOID arg2
)
48 // wake up the thread, and tell it it timed out
49 NTSTATUS Status
= STATUS_TIMEOUT
;
50 PsUnfreezeThread( (ETHREAD
*)Context
, &Status
);
53 VOID
PiBeforeBeginThread(VOID
)
55 DPRINT("PiBeforeBeginThread()\n");
56 //KeReleaseSpinLock(&PiThreadListLock, PASSIVE_LEVEL);
57 KeLowerIrql(PASSIVE_LEVEL
);
58 DPRINT("KeGetCurrentIrql() %d\n", KeGetCurrentIrql());
61 VOID
PsBeginThread(PKSTART_ROUTINE StartRoutine
, PVOID StartContext
)
65 // KeReleaseSpinLock(&PiThreadListLock,PASSIVE_LEVEL);
66 KeLowerIrql(PASSIVE_LEVEL
);
67 Ret
= StartRoutine(StartContext
);
68 PsTerminateSystemThread(Ret
);
72 VOID
PiDeleteThread(PVOID ObjectBody
)
75 DPRINT("PiDeleteThread(ObjectBody %x)\n",ObjectBody
);
77 KeAcquireSpinLock(&PiThreadListLock
, &oldIrql
);
78 ObDereferenceObject(((PETHREAD
)ObjectBody
)->ThreadsProcess
);
79 ((PETHREAD
)ObjectBody
)->ThreadsProcess
= NULL
;
81 RemoveEntryList(&((PETHREAD
)ObjectBody
)->Tcb
.ThreadListEntry
);
82 HalReleaseTask((PETHREAD
)ObjectBody
);
83 KeReleaseSpinLock(&PiThreadListLock
, oldIrql
);
86 VOID
PiCloseThread(PVOID ObjectBody
, ULONG HandleCount
)
88 DPRINT("PiCloseThread(ObjectBody %x)\n", ObjectBody
);
89 DPRINT("ObGetReferenceCount(ObjectBody) %d "
90 "ObGetHandleCount(ObjectBody) %d\n",
91 ObGetReferenceCount(ObjectBody
),
92 ObGetHandleCount(ObjectBody
));
95 NTSTATUS
PsInitializeThread(HANDLE ProcessHandle
,
98 ACCESS_MASK DesiredAccess
,
99 POBJECT_ATTRIBUTES ThreadAttributes
)
109 if (ProcessHandle
!= NULL
)
111 Status
= ObReferenceObjectByHandle(ProcessHandle
,
112 PROCESS_CREATE_THREAD
,
117 if (Status
!= STATUS_SUCCESS
)
119 DPRINT("Failed at %s:%d\n",__FILE__
,__LINE__
);
125 Process
= SystemProcess
;
126 ObReferenceObjectByPointer(Process
,
127 PROCESS_CREATE_THREAD
,
133 * Create and initialize thread
135 Thread
= ObCreateObject(ThreadHandle
,
139 DPRINT("Thread = %x\n",Thread
);
143 Thread
->Tcb
.State
= THREAD_STATE_SUSPENDED
;
144 Thread
->Tcb
.SuspendCount
= 0;
145 Thread
->Tcb
.FreezeCount
= 1;
146 InitializeListHead(&Thread
->Tcb
.ApcState
.ApcListHead
[0]);
147 InitializeListHead(&Thread
->Tcb
.ApcState
.ApcListHead
[1]);
148 Thread
->Tcb
.KernelApcDisable
= 1;
149 Thread
->Tcb
.WaitIrql
= PASSIVE_LEVEL
;
150 Thread
->ThreadsProcess
= Process
;
151 KeInitializeDpc( &Thread
->Tcb
.TimerDpc
, PiTimeoutThread
, Thread
);
152 Thread
->Tcb
.WaitBlockList
= NULL
;
154 KeInitializeDispatcherHeader(&Thread
->Tcb
.DispatcherHeader
,
159 InitializeListHead(&Thread
->IrpList
);
160 Thread
->Cid
.UniqueThread
= (HANDLE
)InterlockedIncrement(
161 &PiNextThreadUniqueId
);
162 Thread
->Cid
.UniqueProcess
= (HANDLE
)Thread
->ThreadsProcess
->UniqueProcessId
;
163 DPRINT("Thread->Cid.UniqueThread %d\n",Thread
->Cid
.UniqueThread
);
167 KeAcquireSpinLock(&PiThreadListLock
, &oldIrql
);
168 InsertTailList(&PiThreadListHead
, &Thread
->Tcb
.ThreadListEntry
);
169 KeReleaseSpinLock(&PiThreadListLock
, oldIrql
);
171 Thread
->Tcb
.BasePriority
= Thread
->ThreadsProcess
->Pcb
.BasePriority
;
172 Thread
->Tcb
.Priority
= Thread
->Tcb
.BasePriority
;
174 return(STATUS_SUCCESS
);
178 static NTSTATUS
PsCreateTeb (HANDLE ProcessHandle
,
181 PINITIAL_TEB InitialTeb
)
183 MEMORY_BASIC_INFORMATION Info
;
191 TebBase
= (PVOID
)0x7FFDE000;
196 /* The TEB must reside in user space */
197 Status
= NtAllocateVirtualMemory(ProcessHandle
,
203 if (NT_SUCCESS(Status
))
205 DPRINT ("TEB allocated at %x\n", TebBase
);
210 DPRINT ("TEB allocation failed! Status %x\n",Status
);
213 TebBase
= Info
.BaseAddress
- TebSize
;
216 DPRINT ("TebBase %p TebSize %lu\n", TebBase
, TebSize
);
218 /* set all pointers to and from the TEB */
219 Teb
.Tib
.Self
= TebBase
;
220 if (Thread
->ThreadsProcess
)
222 Teb
.Peb
= Thread
->ThreadsProcess
->Peb
; /* No PEB yet!! */
225 /* store stack information from InitialTeb */
226 if (InitialTeb
!= NULL
)
228 Teb
.Tib
.StackBase
= InitialTeb
->StackBase
;
229 Teb
.Tib
.StackLimit
= InitialTeb
->StackLimit
;
232 * I don't know if this is really stored in a WNT-TEB,
233 * but it's needed to free the thread stack. (Eric Kohl)
235 Teb
.StackCommit
= InitialTeb
->StackCommit
;
236 Teb
.StackCommitMax
= InitialTeb
->StackCommitMax
;
237 Teb
.StackReserved
= InitialTeb
->StackReserved
;
241 /* more initialization */
242 Teb
.Cid
.UniqueThread
= Thread
->Cid
.UniqueThread
;
243 Teb
.Cid
.UniqueProcess
= Thread
->Cid
.UniqueProcess
;
245 /* write TEB data into teb page */
246 Status
= NtWriteVirtualMemory(ProcessHandle
,
252 if (!NT_SUCCESS(Status
))
255 DPRINT ("Writing TEB failed!\n");
258 NtFreeVirtualMemory(ProcessHandle
,
266 /* FIXME: fs:[0] = TEB */
270 // *TebPtr = (PNT_TEB)TebBase;
273 DPRINT ("TEB allocated at %p\n", TebBase
);
279 NTSTATUS STDCALL
NtCreateThread (PHANDLE ThreadHandle
,
280 ACCESS_MASK DesiredAccess
,
281 POBJECT_ATTRIBUTES ObjectAttributes
,
282 HANDLE ProcessHandle
,
284 PCONTEXT ThreadContext
,
285 PINITIAL_TEB InitialTeb
,
286 BOOLEAN CreateSuspended
)
292 DPRINT("NtCreateThread(ThreadHandle %x, PCONTEXT %x)\n",
293 ThreadHandle
,ThreadContext
);
295 Status
= PsInitializeThread(ProcessHandle
,&Thread
,ThreadHandle
,
296 DesiredAccess
,ObjectAttributes
);
297 if (!NT_SUCCESS(Status
))
302 Status
= HalInitTaskWithContext(Thread
,ThreadContext
);
303 if (!NT_SUCCESS(Status
))
308 Status
= PsCreateTeb (ProcessHandle
,
312 if (!NT_SUCCESS(Status
))
317 /* Attention: TebBase is in user memory space */
318 // Thread->Tcb.Teb = TebBase;
320 Thread
->StartAddress
=NULL
;
327 if (!CreateSuspended
)
329 DPRINT("Not creating suspended\n");
330 PsUnfreezeThread(Thread
, NULL
);
332 DPRINT("Thread %x\n", Thread
);
333 DPRINT("ObGetReferenceCount(Thread) %d ObGetHandleCount(Thread) %x\n",
334 ObGetReferenceCount(Thread
), ObGetHandleCount(Thread
));
335 DPRINT("Finished PsCreateThread()\n");
336 return(STATUS_SUCCESS
);
340 NTSTATUS
PsCreateSystemThread(PHANDLE ThreadHandle
,
341 ACCESS_MASK DesiredAccess
,
342 POBJECT_ATTRIBUTES ObjectAttributes
,
343 HANDLE ProcessHandle
,
345 PKSTART_ROUTINE StartRoutine
,
348 * FUNCTION: Creates a thread which executes in kernel mode
350 * ThreadHandle (OUT) = Caller supplied storage for the returned thread
352 * DesiredAccess = Requested access to the thread
353 * ObjectAttributes = Object attributes (optional)
354 * ProcessHandle = Handle of process thread will run in
355 * NULL to use system process
356 * ClientId (OUT) = Caller supplied storage for the returned client id
357 * of the thread (optional)
358 * StartRoutine = Entry point for the thread
359 * StartContext = Argument supplied to the thread when it begins
361 * RETURNS: Success or failure status
367 DPRINT("PsCreateSystemThread(ThreadHandle %x, ProcessHandle %x)\n",
368 ThreadHandle
,ProcessHandle
);
370 Status
= PsInitializeThread(ProcessHandle
,&Thread
,ThreadHandle
,
371 DesiredAccess
,ObjectAttributes
);
372 if (!NT_SUCCESS(Status
))
377 Thread
->StartAddress
=StartRoutine
;
378 Status
= HalInitTask(Thread
,StartRoutine
,StartContext
);
379 if (!NT_SUCCESS(Status
))
386 *ClientId
=Thread
->Cid
;
389 PsUnfreezeThread(Thread
, NULL
);
391 return(STATUS_SUCCESS
);