Use upper-case ASSERT macros.
[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.55 2004/10/22 20:30:47 ekohl 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 VOID
40 STDCALL
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 * @implemented
67 */
68 KPRIORITY
69 STDCALL
70 KeQueryPriorityThread (
71 IN PKTHREAD Thread
72 )
73 {
74 return Thread->Priority;
75 }
76
77 NTSTATUS
78 KeReleaseThread(PKTHREAD Thread)
79 /*
80 * FUNCTION: Releases the resource allocated for a thread by
81 * KeInitializeThread
82 * NOTE: The thread had better not be running when this is called
83 */
84 {
85 extern unsigned int init_stack;
86
87 /* FIXME - lock the process */
88 RemoveEntryList(&Thread->ThreadListEntry);
89
90 if (Thread->StackLimit != (ULONG)&init_stack)
91 {
92 MmLockAddressSpace(MmGetKernelAddressSpace());
93 MmFreeMemoryArea(MmGetKernelAddressSpace(),
94 (PVOID)Thread->StackLimit,
95 MM_STACK_SIZE,
96 KeFreeStackPage,
97 NULL);
98 MmUnlockAddressSpace(MmGetKernelAddressSpace());
99 }
100 Thread->StackLimit = 0;
101 Thread->InitialStack = NULL;
102 Thread->StackBase = NULL;
103 Thread->KernelStack = NULL;
104 return(STATUS_SUCCESS);
105 }
106
107 /*
108 * @implemented
109 */
110 BOOLEAN
111 STDCALL
112 KeSetKernelStackSwapEnable(
113 IN BOOLEAN Enable
114 )
115 {
116 PKTHREAD Thread;
117 BOOLEAN PreviousState;
118
119 Thread = KeGetCurrentThread();
120
121 /* Save Old State */
122 PreviousState = Thread->EnableStackSwap;
123
124 /* Set New State */
125 Thread->EnableStackSwap = Enable;
126
127 /* Return Old State */
128 return PreviousState;
129 }
130
131 VOID
132 KeInitializeThread(PKPROCESS Process, PKTHREAD Thread, BOOLEAN First)
133 /*
134 * FUNCTION: Initialize the microkernel state of the thread
135 */
136 {
137 PVOID KernelStack;
138 NTSTATUS Status;
139 extern unsigned int init_stack_top;
140 extern unsigned int init_stack;
141 PMEMORY_AREA StackArea;
142 ULONG i;
143 PHYSICAL_ADDRESS BoundaryAddressMultiple;
144
145 BoundaryAddressMultiple.QuadPart = 0;
146
147 KeInitializeDispatcherHeader(&Thread->DispatcherHeader,
148 InternalThreadType,
149 sizeof(ETHREAD),
150 FALSE);
151 InitializeListHead(&Thread->MutantListHead);
152 if (!First)
153 {
154 PFN_TYPE Page[MM_STACK_SIZE / PAGE_SIZE];
155 KernelStack = NULL;
156
157 MmLockAddressSpace(MmGetKernelAddressSpace());
158 Status = MmCreateMemoryArea(NULL,
159 MmGetKernelAddressSpace(),
160 MEMORY_AREA_KERNEL_STACK,
161 &KernelStack,
162 MM_STACK_SIZE,
163 0,
164 &StackArea,
165 FALSE,
166 FALSE,
167 BoundaryAddressMultiple);
168 MmUnlockAddressSpace(MmGetKernelAddressSpace());
169
170 if (!NT_SUCCESS(Status))
171 {
172 DPRINT1("Failed to create thread stack\n");
173 KEBUGCHECK(0);
174 }
175 for (i = 0; i < (MM_STACK_SIZE / PAGE_SIZE); i++)
176 {
177 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page[i]);
178 if (!NT_SUCCESS(Status))
179 {
180 KEBUGCHECK(0);
181 }
182 }
183 Status = MmCreateVirtualMapping(NULL,
184 KernelStack,
185 PAGE_READWRITE,
186 Page,
187 MM_STACK_SIZE / PAGE_SIZE);
188 if (!NT_SUCCESS(Status))
189 {
190 KEBUGCHECK(0);
191 }
192 Thread->InitialStack = (char*)KernelStack + MM_STACK_SIZE;
193 Thread->StackBase = (char*)KernelStack + MM_STACK_SIZE;
194 Thread->StackLimit = (ULONG)KernelStack;
195 Thread->KernelStack = (char*)KernelStack + MM_STACK_SIZE;
196 }
197 else
198 {
199 Thread->InitialStack = (PVOID)&init_stack_top;
200 Thread->StackBase = (PVOID)&init_stack_top;
201 Thread->StackLimit = (ULONG)&init_stack;
202 Thread->KernelStack = (PVOID)&init_stack_top;
203 }
204
205 /*
206 * Establish the pde's for the new stack and the thread structure within the
207 * address space of the new process. They are accessed while taskswitching or
208 * while handling page faults. At this point it isn't possible to call the
209 * page fault handler for the missing pde's.
210 */
211
212 MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread->StackLimit, MM_STACK_SIZE);
213 MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread, sizeof(ETHREAD));
214
215 /*
216 * The Native API function will initialize the TEB field later
217 */
218 Thread->Teb = NULL;
219 Thread->TlsArray = NULL;
220 Thread->DebugActive = 0;
221 Thread->State = THREAD_STATE_INITIALIZED;
222 Thread->Alerted[0] = 0;
223 Thread->Alerted[1] = 0;
224 Thread->Iopl = 0;
225 /*
226 * FIXME: Think how this might work
227 */
228 Thread->NpxState = 0;
229
230 Thread->Saturation = 0;
231 Thread->Priority = 0;
232 InitializeListHead(&Thread->ApcState.ApcListHead[0]);
233 InitializeListHead(&Thread->ApcState.ApcListHead[1]);
234 Thread->ApcState.Process = Process;
235 Thread->ApcState.KernelApcInProgress = 0;
236 Thread->ApcState.KernelApcPending = 0;
237 Thread->ApcState.UserApcPending = 0;
238 Thread->ContextSwitches = 0;
239 Thread->WaitStatus = STATUS_SUCCESS;
240 Thread->WaitIrql = 0;
241 Thread->WaitMode = 0;
242 Thread->WaitNext = 0;
243 Thread->WaitBlockList = NULL;
244 Thread->WaitListEntry.Flink = NULL;
245 Thread->WaitListEntry.Blink = NULL;
246 Thread->WaitTime = 0;
247 Thread->BasePriority = 0;
248 Thread->DecrementCount = 0;
249 Thread->PriorityDecrement = 0;
250 Thread->Quantum = 0;
251 memset(Thread->WaitBlock, 0, sizeof(KWAIT_BLOCK)*4);
252 Thread->LegoData = 0;
253
254 /*
255 * FIXME: Why this?
256 */
257 // Thread->KernelApcDisable = 1;
258 /*
259 It may be correct to have regular kmode APC disabled
260 until the thread has been fully created, BUT the problem is: they are
261 currently never enabled again! So until somone figures out how
262 this really work, I'm setting regular kmode APC's intially enabled.
263 -Gunnar
264
265 UPDATE: After enabling regular kmode APC's I have experienced random
266 crashes. I'm disabling it again, until we fix the APC implementation...
267 -Gunnar
268 */
269
270 Thread->KernelApcDisable = -1;
271
272
273 Thread->UserAffinity = Process->Affinity;
274 Thread->SystemAffinityActive = 0;
275 Thread->PowerState = 0;
276 Thread->NpxIrql = 0;
277 Thread->ServiceTable = KeServiceDescriptorTable;
278 Thread->Queue = NULL;
279 KeInitializeSpinLock(&Thread->ApcQueueLock);
280 memset(&Thread->Timer, 0, sizeof(KTIMER));
281 KeInitializeTimer(&Thread->Timer);
282 Thread->QueueListEntry.Flink = NULL;
283 Thread->QueueListEntry.Blink = NULL;
284 Thread->Affinity = Process->Affinity;
285 Thread->Preempted = 0;
286 Thread->ProcessReadyQueue = 0;
287 Thread->KernelStackResident = 1;
288 Thread->NextProcessor = 0;
289 Thread->CallbackStack = NULL;
290 Thread->Win32Thread = NULL;
291 Thread->TrapFrame = NULL;
292 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState;
293 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState;
294 Thread->EnableStackSwap = 0;
295 Thread->LargeStack = 0;
296 Thread->ResourceIndex = 0;
297 Thread->PreviousMode = KernelMode;
298 Thread->KernelTime = 0;
299 Thread->UserTime = 0;
300 memset(&Thread->SavedApcState, 0, sizeof(KAPC_STATE));
301
302 /* FIXME: is this correct? */
303 Thread->Alertable = 1;
304
305 Thread->ApcStateIndex = OriginalApcEnvironment;
306
307 /* FIXME: not all thread are ApcQueueable! */
308 Thread->ApcQueueable = TRUE;
309
310 Thread->AutoAlignment = 0;
311 KeInitializeApc(&Thread->SuspendApc,
312 Thread,
313 OriginalApcEnvironment,
314 PiSuspendThreadKernelRoutine,
315 PiSuspendThreadRundownRoutine,
316 PiSuspendThreadNormalRoutine,
317 KernelMode,
318 NULL);
319 KeInitializeSemaphore(&Thread->SuspendSemaphore, 0, 128);
320 InsertTailList(&Process->ThreadListHead,
321 &Thread->ThreadListEntry);
322 Thread->FreezeCount = 0;
323 Thread->SuspendCount = 0;
324
325 /*
326 * Do x86 specific part
327 */
328 }
329
330 VOID STDCALL
331 KeRescheduleThread(VOID)
332 {
333 PsDispatchThread(THREAD_STATE_READY);
334 }
335
336 /*
337 * @implemented
338 */
339 VOID
340 STDCALL
341 KeRevertToUserAffinityThread(VOID)
342 {
343 PKTHREAD CurrentThread;
344 CurrentThread = KeGetCurrentThread();
345
346 /* Return to User Affinity */
347 CurrentThread->Affinity = CurrentThread->UserAffinity;
348
349 /* Disable System Affinity */
350 CurrentThread->SystemAffinityActive = FALSE;
351 }
352
353 /*
354 * @implemented
355 */
356 CCHAR
357 STDCALL
358 KeSetIdealProcessorThread (
359 IN PKTHREAD Thread,
360 IN CCHAR Processor)
361 {
362 CCHAR PreviousIdealProcessor;
363
364 /* Save Old Ideal Processor */
365 PreviousIdealProcessor = Thread->IdealProcessor;
366
367 /* Set New Ideal Processor */
368 Thread->IdealProcessor = Processor;
369
370 /* Return Old Ideal Processor */
371 return PreviousIdealProcessor;
372 }
373
374 /*
375 * @implemented
376 */
377 VOID
378 STDCALL
379 KeSetSystemAffinityThread(IN KAFFINITY Affinity)
380 {
381 PKTHREAD CurrentThread;
382 CurrentThread = KeGetCurrentThread();
383
384 /* Set the System Affinity Specified */
385 CurrentThread->Affinity = Affinity;
386
387 /* Enable System Affinity */
388 CurrentThread->SystemAffinityActive = TRUE;
389 }
390
391 /*
392 * @implemented
393 */
394 VOID
395 STDCALL
396 KeTerminateThread(IN KPRIORITY Increment)
397 {
398 /* The Increment Argument seems to be ignored by NT and always 0 when called */
399
400 /* Call our own internal routine */
401 PsTerminateCurrentThread(0);
402 }