Little KDB update ;-) If you have any problems and/or questions let me know. I hope...
[reactos.git] / reactos / ntoskrnl / ke / kthread.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ke/kthread.c
6 * PURPOSE: Microkernel thread support
7 *
8 * PROGRAMMERS: David Welch (welch@cwcom.net)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* FUNCTIONS *****************************************************************/
18
19 VOID
20 KiServiceCheck (VOID)
21 {
22 PETHREAD Thread;
23
24 Thread = PsGetCurrentThread();
25
26 if (Thread->Tcb.ServiceTable != KeServiceDescriptorTableShadow)
27 {
28 PsInitWin32Thread (Thread);
29
30 Thread->Tcb.ServiceTable = KeServiceDescriptorTableShadow;
31 }
32 }
33
34 /*
35 * @unimplemented
36 */
37 VOID
38 STDCALL
39 KeCapturePersistentThreadState(
40 IN PVOID CurrentThread,
41 IN ULONG Setting1,
42 IN ULONG Setting2,
43 IN ULONG Setting3,
44 IN ULONG Setting4,
45 IN ULONG Setting5,
46 IN PVOID ThreadState
47 )
48 {
49 UNIMPLEMENTED;
50 }
51
52 VOID
53 KeFreeStackPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
54 PFN_TYPE Page, SWAPENTRY SwapEntry, BOOLEAN Dirty)
55 {
56 ASSERT(SwapEntry == 0);
57 if (Page != 0)
58 {
59 MmReleasePageMemoryConsumer(MC_NPPOOL, Page);
60 }
61 }
62
63 /*
64 * @implemented
65 */
66 KPRIORITY
67 STDCALL
68 KeQueryPriorityThread (
69 IN PKTHREAD Thread
70 )
71 {
72 return Thread->Priority;
73 }
74
75 /*
76 * @implemented
77 */
78 ULONG
79 STDCALL
80 KeQueryRuntimeThread(
81 IN PKTHREAD Thread,
82 OUT PULONG UserTime
83 )
84 {
85 /* Return the User Time */
86 *UserTime = Thread->UserTime;
87
88 /* Return the Kernel Time */
89 return Thread->KernelTime;
90 }
91
92 NTSTATUS
93 KeReleaseThread(PKTHREAD Thread)
94 /*
95 * FUNCTION: Releases the resource allocated for a thread by
96 * KeInitializeThread
97 * NOTE: The thread had better not be running when this is called
98 */
99 {
100 extern unsigned int init_stack;
101
102 /* FIXME - lock the process */
103 RemoveEntryList(&Thread->ThreadListEntry);
104
105 if (Thread->StackLimit != (ULONG_PTR)init_stack)
106 {
107 MmLockAddressSpace(MmGetKernelAddressSpace());
108 MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(),
109 (PVOID)Thread->StackLimit,
110 KeFreeStackPage,
111 NULL);
112 MmUnlockAddressSpace(MmGetKernelAddressSpace());
113 }
114 Thread->StackLimit = 0;
115 Thread->InitialStack = NULL;
116 Thread->StackBase = NULL;
117 Thread->KernelStack = NULL;
118 return(STATUS_SUCCESS);
119 }
120
121 /*
122 * @implemented
123 */
124 BOOLEAN
125 STDCALL
126 KeSetKernelStackSwapEnable(
127 IN BOOLEAN Enable
128 )
129 {
130 PKTHREAD Thread;
131 BOOLEAN PreviousState;
132
133 Thread = KeGetCurrentThread();
134
135 /* Save Old State */
136 PreviousState = Thread->EnableStackSwap;
137
138 /* Set New State */
139 Thread->EnableStackSwap = Enable;
140
141 /* Return Old State */
142 return PreviousState;
143 }
144
145 VOID
146 KeInitializeThread(PKPROCESS Process, PKTHREAD Thread, BOOLEAN First)
147 /*
148 * FUNCTION: Initialize the microkernel state of the thread
149 */
150 {
151 PVOID KernelStack;
152 NTSTATUS Status;
153 extern unsigned int init_stack_top;
154 extern unsigned int init_stack;
155 PMEMORY_AREA StackArea;
156 ULONG i;
157 PHYSICAL_ADDRESS BoundaryAddressMultiple;
158
159 BoundaryAddressMultiple.QuadPart = 0;
160
161 KeInitializeDispatcherHeader(&Thread->DispatcherHeader,
162 InternalThreadType,
163 sizeof(ETHREAD),
164 FALSE);
165 InitializeListHead(&Thread->MutantListHead);
166 if (!First)
167 {
168 PFN_TYPE Page[MM_STACK_SIZE / PAGE_SIZE];
169 KernelStack = NULL;
170
171 MmLockAddressSpace(MmGetKernelAddressSpace());
172 Status = MmCreateMemoryArea(NULL,
173 MmGetKernelAddressSpace(),
174 MEMORY_AREA_KERNEL_STACK,
175 &KernelStack,
176 MM_STACK_SIZE,
177 0,
178 &StackArea,
179 FALSE,
180 FALSE,
181 BoundaryAddressMultiple);
182 MmUnlockAddressSpace(MmGetKernelAddressSpace());
183
184 if (!NT_SUCCESS(Status))
185 {
186 DPRINT1("Failed to create thread stack\n");
187 KEBUGCHECK(0);
188 }
189 for (i = 0; i < (MM_STACK_SIZE / PAGE_SIZE); i++)
190 {
191 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page[i]);
192 if (!NT_SUCCESS(Status))
193 {
194 KEBUGCHECK(0);
195 }
196 }
197 Status = MmCreateVirtualMapping(NULL,
198 KernelStack,
199 PAGE_READWRITE,
200 Page,
201 MM_STACK_SIZE / PAGE_SIZE);
202 if (!NT_SUCCESS(Status))
203 {
204 KEBUGCHECK(0);
205 }
206 Thread->InitialStack = (PCHAR)KernelStack + MM_STACK_SIZE;
207 Thread->StackBase = (PCHAR)KernelStack + MM_STACK_SIZE;
208 Thread->StackLimit = (ULONG_PTR)KernelStack;
209 Thread->KernelStack = (PCHAR)KernelStack + MM_STACK_SIZE;
210 }
211 else
212 {
213 Thread->InitialStack = (PCHAR)init_stack_top;
214 Thread->StackBase = (PCHAR)init_stack_top;
215 Thread->StackLimit = (ULONG_PTR)init_stack;
216 Thread->KernelStack = (PCHAR)init_stack_top;
217 }
218
219 /*
220 * Establish the pde's for the new stack and the thread structure within the
221 * address space of the new process. They are accessed while taskswitching or
222 * while handling page faults. At this point it isn't possible to call the
223 * page fault handler for the missing pde's.
224 */
225
226 MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread->StackLimit, MM_STACK_SIZE);
227 MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread, sizeof(ETHREAD));
228
229 /*
230 * The Native API function will initialize the TEB field later
231 */
232 Thread->Teb = NULL;
233 Thread->TlsArray = NULL;
234 Thread->DebugActive = 0;
235 Thread->State = THREAD_STATE_INITIALIZED;
236 Thread->Alerted[0] = 0;
237 Thread->Alerted[1] = 0;
238 Thread->Iopl = 0;
239 Thread->NpxState = NPX_STATE_INVALID;
240
241 Thread->Saturation = 0;
242 Thread->Priority = Process->BasePriority;
243 InitializeListHead(&Thread->ApcState.ApcListHead[0]);
244 InitializeListHead(&Thread->ApcState.ApcListHead[1]);
245 Thread->ApcState.Process = Process;
246 Thread->ApcState.KernelApcInProgress = 0;
247 Thread->ApcState.KernelApcPending = 0;
248 Thread->ApcState.UserApcPending = 0;
249 Thread->ContextSwitches = 0;
250 Thread->WaitStatus = STATUS_SUCCESS;
251 Thread->WaitIrql = PASSIVE_LEVEL;
252 Thread->WaitMode = 0;
253 Thread->WaitNext = FALSE;
254 Thread->WaitBlockList = NULL;
255 Thread->WaitListEntry.Flink = NULL;
256 Thread->WaitListEntry.Blink = NULL;
257 Thread->WaitTime = 0;
258 Thread->BasePriority = Process->BasePriority;
259 Thread->DecrementCount = 0;
260 Thread->PriorityDecrement = 0;
261 Thread->Quantum = Process->ThreadQuantum;
262 RtlZeroMemory(Thread->WaitBlock, sizeof(KWAIT_BLOCK)*4);
263 Thread->LegoData = 0;
264 Thread->UserAffinity = Process->Affinity;
265 Thread->SystemAffinityActive = 0;
266 Thread->PowerState = 0;
267 Thread->NpxIrql = 0;
268 Thread->ServiceTable = KeServiceDescriptorTable;
269 Thread->Queue = NULL;
270 KeInitializeSpinLock(&Thread->ApcQueueLock);
271 RtlZeroMemory(&Thread->Timer, sizeof(KTIMER));
272 KeInitializeTimer(&Thread->Timer);
273 Thread->QueueListEntry.Flink = NULL;
274 Thread->QueueListEntry.Blink = NULL;
275 Thread->Affinity = Process->Affinity;
276 Thread->Preempted = 0;
277 Thread->ProcessReadyQueue = 0;
278 Thread->KernelStackResident = 1;
279 Thread->NextProcessor = 0;
280 Thread->CallbackStack = NULL;
281 Thread->Win32Thread = NULL;
282 Thread->TrapFrame = NULL;
283 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState;
284 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState;
285 Thread->EnableStackSwap = 0;
286 Thread->LargeStack = 0;
287 Thread->ResourceIndex = 0;
288 Thread->PreviousMode = KernelMode;
289 Thread->KernelTime = 0;
290 Thread->UserTime = 0;
291 RtlZeroMemory(&Thread->SavedApcState, sizeof(KAPC_STATE));
292
293 Thread->ApcStateIndex = OriginalApcEnvironment;
294 Thread->ApcQueueable = TRUE;
295 Thread->AutoAlignment = Process->AutoAlignment;
296
297 KeInitializeApc(&Thread->SuspendApc,
298 Thread,
299 OriginalApcEnvironment,
300 PiSuspendThreadKernelRoutine,
301 PiSuspendThreadRundownRoutine,
302 PiSuspendThreadNormalRoutine,
303 KernelMode,
304 NULL);
305 KeInitializeSemaphore(&Thread->SuspendSemaphore, 0, 128);
306
307 InsertTailList(&Process->ThreadListHead,
308 &Thread->ThreadListEntry);
309 Thread->FreezeCount = 0;
310 Thread->SuspendCount = 0;
311
312 /*
313 * Do x86 specific part
314 */
315 }
316
317 /*
318 * @implemented
319 */
320 VOID
321 STDCALL
322 KeRevertToUserAffinityThread(VOID)
323 {
324 #ifdef CONFIG_SMP
325 PKTHREAD CurrentThread;
326 KIRQL oldIrql;
327
328 oldIrql = KeAcquireDispatcherDatabaseLock();
329
330 CurrentThread = KeGetCurrentThread();
331
332 ASSERT(CurrentThread->SystemAffinityActive != FALSE);
333
334 /* Return to User Affinity */
335 CurrentThread->Affinity = CurrentThread->UserAffinity;
336
337 /* Disable System Affinity */
338 CurrentThread->SystemAffinityActive = FALSE;
339
340 if (CurrentThread->Affinity & (1 << KeGetCurrentProcessorNumber()))
341 {
342 KeReleaseDispatcherDatabaseLock(oldIrql);
343 }
344 else
345 {
346 CurrentThread->WaitIrql = oldIrql;
347 PsDispatchThreadNoLock(THREAD_STATE_READY);
348 KeLowerIrql(oldIrql);
349 }
350 #endif
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 #ifdef CONFIG_SMP
382 PKTHREAD CurrentThread;
383 KIRQL oldIrql;
384
385 oldIrql = KeAcquireDispatcherDatabaseLock();
386
387 CurrentThread = KeGetCurrentThread();
388
389 ASSERT(Affinity & ((1 << KeNumberProcessors) - 1));
390
391 /* Set the System Affinity Specified */
392 CurrentThread->Affinity = Affinity;
393
394 /* Enable System Affinity */
395 CurrentThread->SystemAffinityActive = TRUE;
396
397 if (Affinity & (1 << KeGetCurrentProcessorNumber()))
398 {
399 KeReleaseDispatcherDatabaseLock(oldIrql);
400 }
401 else
402 {
403 CurrentThread->WaitIrql = oldIrql;
404 PsDispatchThreadNoLock(THREAD_STATE_READY);
405 KeLowerIrql(oldIrql);
406 }
407 #endif
408 }
409
410 /*
411 * @implemented
412 */
413 VOID
414 STDCALL
415 KeTerminateThread(IN KPRIORITY Increment)
416 {
417 /* The Increment Argument seems to be ignored by NT and always 0 when called */
418
419 /* Call our own internal routine */
420 PsTerminateCurrentThread(0);
421 }
422
423
424 NTSTATUS
425 STDCALL
426 NtDelayExecution(IN BOOLEAN Alertable,
427 IN PLARGE_INTEGER DelayInterval)
428 {
429 KPROCESSOR_MODE PreviousMode;
430 LARGE_INTEGER SafeInterval;
431
432 PreviousMode = ExGetPreviousMode();
433
434 if(PreviousMode != KernelMode)
435 {
436 NTSTATUS Status = STATUS_SUCCESS;
437
438 _SEH_TRY
439 {
440 ProbeForRead(DelayInterval,
441 sizeof(LARGE_INTEGER),
442 sizeof(ULONG));
443 /* make a copy on the kernel stack and let DelayInterval point to it so
444 we don't need to wrap KeDelayExecutionThread in SEH! */
445 SafeInterval = *DelayInterval;
446 DelayInterval = &SafeInterval;
447 }
448 _SEH_HANDLE
449 {
450 Status = _SEH_GetExceptionCode();
451 }
452 _SEH_END;
453
454 if(!NT_SUCCESS(Status))
455 {
456 return Status;
457 }
458 }
459
460 return KeDelayExecutionThread(PreviousMode,
461 Alertable,
462 DelayInterval);
463 }