2004-08-15 Casper S. Hornstrup <chorns@users.sourceforge.net>
[reactos.git] / reactos / ntoskrnl / ke / kthread.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2000 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: kthread.c,v 1.49 2004/08/15 16:39:05 chorns Exp $
20 *
21 * FILE: ntoskrnl/ke/kthread.c
22 * PURPOSE: Microkernel thread support
23 * PROGRAMMER: David Welch (welch@cwcom.net)
24 * UPDATE HISTORY:
25 * Created 22/05/98
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include <ntoskrnl.h>
31 #define NDEBUG
32 #include <internal/debug.h>
33
34 /* FUNCTIONS *****************************************************************/
35
36 /*
37 * @unimplemented
38 */
39 STDCALL
40 VOID
41 KeCapturePersistentThreadState(
42 IN PVOID CurrentThread,
43 IN ULONG Setting1,
44 IN ULONG Setting2,
45 IN ULONG Setting3,
46 IN ULONG Setting4,
47 IN ULONG Setting5,
48 IN PVOID ThreadState
49 )
50 {
51 UNIMPLEMENTED;
52 }
53
54 VOID
55 KeFreeStackPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
56 PFN_TYPE Page, SWAPENTRY SwapEntry, BOOLEAN Dirty)
57 {
58 assert(SwapEntry == 0);
59 if (Page != 0)
60 {
61 MmReleasePageMemoryConsumer(MC_NPPOOL, Page);
62 }
63 }
64
65 /*
66 * @unimplemented
67 */
68 STDCALL
69 KPRIORITY
70 KeQueryPriorityThread (
71 IN PKTHREAD Thread
72 )
73 {
74 UNIMPLEMENTED;
75 return 0;
76 }
77
78 NTSTATUS
79 KeReleaseThread(PETHREAD Thread)
80 /*
81 * FUNCTION: Releases the resource allocated for a thread by
82 * KeInitializeThread
83 * NOTE: The thread had better not be running when this is called
84 */
85 {
86 extern unsigned int init_stack;
87
88 if (Thread->Tcb.StackLimit != (ULONG)&init_stack)
89 {
90 MmLockAddressSpace(MmGetKernelAddressSpace());
91 MmFreeMemoryArea(MmGetKernelAddressSpace(),
92 (PVOID)Thread->Tcb.StackLimit,
93 MM_STACK_SIZE,
94 KeFreeStackPage,
95 NULL);
96 MmUnlockAddressSpace(MmGetKernelAddressSpace());
97 }
98 Thread->Tcb.StackLimit = 0;
99 Thread->Tcb.InitialStack = NULL;
100 Thread->Tcb.StackBase = NULL;
101 Thread->Tcb.KernelStack = NULL;
102 return(STATUS_SUCCESS);
103 }
104
105 /*
106 * @unimplemented
107 */
108 STDCALL
109 BOOLEAN
110 KeSetKernelStackSwapEnable(
111 IN BOOLEAN Enable
112 )
113 {
114 UNIMPLEMENTED;
115 return FALSE;
116 }
117
118 VOID
119 KeInitializeThread(PKPROCESS Process, PKTHREAD Thread, BOOLEAN First)
120 /*
121 * FUNCTION: Initialize the microkernel state of the thread
122 */
123 {
124 PVOID KernelStack;
125 NTSTATUS Status;
126 extern unsigned int init_stack_top;
127 extern unsigned int init_stack;
128 PMEMORY_AREA StackArea;
129 ULONG i;
130 PHYSICAL_ADDRESS BoundaryAddressMultiple;
131
132 BoundaryAddressMultiple.QuadPart = 0;
133
134 KeInitializeDispatcherHeader(&Thread->DispatcherHeader,
135 InternalThreadType,
136 sizeof(ETHREAD),
137 FALSE);
138 InitializeListHead(&Thread->MutantListHead);
139 if (!First)
140 {
141 PFN_TYPE Page[MM_STACK_SIZE / PAGE_SIZE];
142 KernelStack = NULL;
143
144 MmLockAddressSpace(MmGetKernelAddressSpace());
145 Status = MmCreateMemoryArea(NULL,
146 MmGetKernelAddressSpace(),
147 MEMORY_AREA_KERNEL_STACK,
148 &KernelStack,
149 MM_STACK_SIZE,
150 0,
151 &StackArea,
152 FALSE,
153 FALSE,
154 BoundaryAddressMultiple);
155 MmUnlockAddressSpace(MmGetKernelAddressSpace());
156
157 if (!NT_SUCCESS(Status))
158 {
159 DPRINT1("Failed to create thread stack\n");
160 KEBUGCHECK(0);
161 }
162 for (i = 0; i < (MM_STACK_SIZE / PAGE_SIZE); i++)
163 {
164 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page[i]);
165 if (!NT_SUCCESS(Status))
166 {
167 KEBUGCHECK(0);
168 }
169 }
170 Status = MmCreateVirtualMapping(NULL,
171 KernelStack,
172 PAGE_READWRITE,
173 Page,
174 MM_STACK_SIZE / PAGE_SIZE);
175 if (!NT_SUCCESS(Status))
176 {
177 KEBUGCHECK(0);
178 }
179 Thread->InitialStack = (char*)KernelStack + MM_STACK_SIZE;
180 Thread->StackBase = (char*)KernelStack + MM_STACK_SIZE;
181 Thread->StackLimit = (ULONG)KernelStack;
182 Thread->KernelStack = (char*)KernelStack + MM_STACK_SIZE;
183 }
184 else
185 {
186 Thread->InitialStack = (PVOID)&init_stack_top;
187 Thread->StackBase = (PVOID)&init_stack_top;
188 Thread->StackLimit = (ULONG)&init_stack;
189 Thread->KernelStack = (PVOID)&init_stack_top;
190 }
191
192 /*
193 * The Native API function will initialize the TEB field later
194 */
195 Thread->Teb = NULL;
196 Thread->TlsArray = NULL;
197 Thread->DebugActive = 0;
198 Thread->State = THREAD_STATE_INITIALIZED;
199 Thread->Alerted[0] = 0;
200 Thread->Alerted[1] = 0;
201 Thread->Iopl = 0;
202 /*
203 * FIXME: Think how this might work
204 */
205 Thread->NpxState = 0;
206
207 Thread->Saturation = 0;
208 Thread->Priority = 0;
209 InitializeListHead(&Thread->ApcState.ApcListHead[0]);
210 InitializeListHead(&Thread->ApcState.ApcListHead[1]);
211 Thread->ApcState.Process = Process;
212 Thread->ApcState.KernelApcInProgress = 0;
213 Thread->ApcState.KernelApcPending = 0;
214 Thread->ApcState.UserApcPending = 0;
215 Thread->ContextSwitches = 0;
216 Thread->WaitStatus = STATUS_SUCCESS;
217 Thread->WaitIrql = 0;
218 Thread->WaitMode = 0;
219 Thread->WaitNext = 0;
220 Thread->WaitBlockList = NULL;
221 Thread->WaitListEntry.Flink = NULL;
222 Thread->WaitListEntry.Blink = NULL;
223 Thread->WaitTime = 0;
224 Thread->BasePriority = 0;
225 Thread->DecrementCount = 0;
226 Thread->PriorityDecrement = 0;
227 Thread->Quantum = 0;
228 memset(Thread->WaitBlock, 0, sizeof(KWAIT_BLOCK)*4);
229 Thread->LegoData = 0;
230
231 /*
232 * FIXME: Why this?
233 */
234 // Thread->KernelApcDisable = 1;
235 /*
236 It may be correct to have regular kmode APC disabled
237 until the thread has been fully created, BUT the problem is: they are
238 currently never enabled again! So until somone figures out how
239 this really work, I'm setting regular kmode APC's intially enabled.
240 -Gunnar
241
242 UPDATE: After enabling regular kmode APC's I have experienced random
243 crashes. I'm disabling it again, until we fix the APC implementation...
244 -Gunnar
245 */
246
247 Thread->KernelApcDisable = -1;
248
249
250 Thread->UserAffinity = Process->Affinity;
251 Thread->SystemAffinityActive = 0;
252 Thread->PowerState = 0;
253 Thread->NpxIrql = 0;
254 Thread->ServiceTable = KeServiceDescriptorTable;
255 Thread->Queue = NULL;
256 KeInitializeSpinLock(&Thread->ApcQueueLock);
257 memset(&Thread->Timer, 0, sizeof(KTIMER));
258 KeInitializeTimer(&Thread->Timer);
259 Thread->QueueListEntry.Flink = NULL;
260 Thread->QueueListEntry.Blink = NULL;
261 Thread->Affinity = Process->Affinity;
262 Thread->Preempted = 0;
263 Thread->ProcessReadyQueue = 0;
264 Thread->KernelStackResident = 1;
265 Thread->NextProcessor = 0;
266 Thread->CallbackStack = NULL;
267 Thread->Win32Thread = 0;
268 Thread->TrapFrame = NULL;
269 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState;
270 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState;
271 Thread->EnableStackSwap = 0;
272 Thread->LargeStack = 0;
273 Thread->ResourceIndex = 0;
274 Thread->PreviousMode = KernelMode;
275 Thread->KernelTime = 0;
276 Thread->UserTime = 0;
277 memset(&Thread->SavedApcState, 0, sizeof(KAPC_STATE));
278
279 /* FIXME: is this correct? */
280 Thread->Alertable = 1;
281
282 Thread->ApcStateIndex = OriginalApcEnvironment;
283
284 /* FIXME: not all thread are ApcQueueable! */
285 Thread->ApcQueueable = TRUE;
286
287 Thread->AutoAlignment = 0;
288 KeInitializeApc(&Thread->SuspendApc,
289 Thread,
290 OriginalApcEnvironment,
291 PiSuspendThreadKernelRoutine,
292 PiSuspendThreadRundownRoutine,
293 PiSuspendThreadNormalRoutine,
294 KernelMode,
295 NULL);
296 KeInitializeSemaphore(&Thread->SuspendSemaphore, 0, 128);
297 Thread->ThreadListEntry.Flink = NULL;
298 Thread->ThreadListEntry.Blink = NULL;
299 Thread->FreezeCount = 0;
300 Thread->SuspendCount = 0;
301
302 /*
303 * Initialize ReactOS specific members
304 */
305 Thread->ProcessThreadListEntry.Flink = NULL;
306 Thread->ProcessThreadListEntry.Blink = NULL;
307
308 /*
309 * Do x86 specific part
310 */
311 }
312
313 VOID STDCALL
314 KeRescheduleThread()
315 {
316 PsDispatchThread(THREAD_STATE_READY);
317 }
318
319 /*
320 * @unimplemented
321 */
322 STDCALL
323 VOID
324 KeRevertToUserAffinityThread(
325 VOID
326 )
327 {
328 UNIMPLEMENTED;
329 }
330
331 /*
332 * @unimplemented
333 */
334 STDCALL
335 CCHAR
336 KeSetIdealProcessorThread (
337 IN PKTHREAD Thread,
338 IN CCHAR Processor
339 )
340 {
341 UNIMPLEMENTED;
342 return 0;
343 }
344
345 /*
346 * @unimplemented
347 */
348 STDCALL
349 VOID
350 KeSetSystemAffinityThread(
351 IN KAFFINITY Affinity
352 )
353 {
354 UNIMPLEMENTED;
355 }
356
357 /*
358 * @unimplemented
359 */
360 STDCALL
361 VOID
362 KeTerminateThread(
363 IN KPRIORITY Increment
364 )
365 {
366 UNIMPLEMENTED;
367 }