3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ke/kthread.c
6 * PURPOSE: Microkernel thread support
8 * PROGRAMMERS: David Welch (welch@cwcom.net)
11 /* INCLUDES *****************************************************************/
15 #include <internal/debug.h>
17 /* FUNCTIONS *****************************************************************/
24 Thread
= PsGetCurrentThread();
26 if (Thread
->Tcb
.ServiceTable
!= KeServiceDescriptorTableShadow
)
28 PsInitWin32Thread (Thread
);
30 Thread
->Tcb
.ServiceTable
= KeServiceDescriptorTableShadow
;
39 KeCapturePersistentThreadState(
40 IN PVOID CurrentThread
,
53 KeFreeStackPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
54 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
56 ASSERT(SwapEntry
== 0);
59 MmReleasePageMemoryConsumer(MC_NPPOOL
, Page
);
68 KeQueryPriorityThread (
72 return Thread
->Priority
;
85 /* Return the User Time */
86 *UserTime
= Thread
->UserTime
;
88 /* Return the Kernel Time */
89 return Thread
->KernelTime
;
93 KeReleaseThread(PKTHREAD Thread
)
95 * FUNCTION: Releases the resource allocated for a thread by
97 * NOTE: The thread had better not be running when this is called
100 extern unsigned int init_stack
;
102 /* FIXME - lock the process */
103 RemoveEntryList(&Thread
->ThreadListEntry
);
105 if (Thread
->StackLimit
!= (ULONG_PTR
)init_stack
)
107 MmLockAddressSpace(MmGetKernelAddressSpace());
108 MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(),
109 (PVOID
)Thread
->StackLimit
,
112 MmUnlockAddressSpace(MmGetKernelAddressSpace());
114 Thread
->StackLimit
= 0;
115 Thread
->InitialStack
= NULL
;
116 Thread
->StackBase
= NULL
;
117 Thread
->KernelStack
= NULL
;
118 return(STATUS_SUCCESS
);
126 KeSetKernelStackSwapEnable(
131 BOOLEAN PreviousState
;
133 Thread
= KeGetCurrentThread();
136 PreviousState
= Thread
->EnableStackSwap
;
139 Thread
->EnableStackSwap
= Enable
;
141 /* Return Old State */
142 return PreviousState
;
146 KeInitializeThread(PKPROCESS Process
, PKTHREAD Thread
, BOOLEAN First
)
148 * FUNCTION: Initialize the microkernel state of the thread
153 extern unsigned int init_stack_top
;
154 extern unsigned int init_stack
;
155 PMEMORY_AREA StackArea
;
157 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
159 BoundaryAddressMultiple
.QuadPart
= 0;
161 KeInitializeDispatcherHeader(&Thread
->DispatcherHeader
,
165 InitializeListHead(&Thread
->MutantListHead
);
168 PFN_TYPE Page
[MM_STACK_SIZE
/ PAGE_SIZE
];
171 MmLockAddressSpace(MmGetKernelAddressSpace());
172 Status
= MmCreateMemoryArea(NULL
,
173 MmGetKernelAddressSpace(),
174 MEMORY_AREA_KERNEL_STACK
,
181 BoundaryAddressMultiple
);
182 MmUnlockAddressSpace(MmGetKernelAddressSpace());
184 if (!NT_SUCCESS(Status
))
186 DPRINT1("Failed to create thread stack\n");
189 for (i
= 0; i
< (MM_STACK_SIZE
/ PAGE_SIZE
); i
++)
191 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Page
[i
]);
192 if (!NT_SUCCESS(Status
))
197 Status
= MmCreateVirtualMapping(NULL
,
201 MM_STACK_SIZE
/ PAGE_SIZE
);
202 if (!NT_SUCCESS(Status
))
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
;
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
;
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.
226 MmUpdatePageDir((PEPROCESS
)Process
, (PVOID
)Thread
->StackLimit
, MM_STACK_SIZE
);
227 MmUpdatePageDir((PEPROCESS
)Process
, (PVOID
)Thread
, sizeof(ETHREAD
));
230 * The Native API function will initialize the TEB field later
233 Thread
->TlsArray
= NULL
;
234 Thread
->DebugActive
= 0;
235 Thread
->State
= THREAD_STATE_INITIALIZED
;
236 Thread
->Alerted
[0] = 0;
237 Thread
->Alerted
[1] = 0;
240 * FIXME: Think how this might work
242 Thread
->NpxState
= 0;
244 Thread
->Saturation
= 0;
245 Thread
->Priority
= Process
->BasePriority
;
246 InitializeListHead(&Thread
->ApcState
.ApcListHead
[0]);
247 InitializeListHead(&Thread
->ApcState
.ApcListHead
[1]);
248 Thread
->ApcState
.Process
= Process
;
249 Thread
->ApcState
.KernelApcInProgress
= 0;
250 Thread
->ApcState
.KernelApcPending
= 0;
251 Thread
->ApcState
.UserApcPending
= 0;
252 Thread
->ContextSwitches
= 0;
253 Thread
->WaitStatus
= STATUS_SUCCESS
;
254 Thread
->WaitIrql
= PASSIVE_LEVEL
;
255 Thread
->WaitMode
= 0;
256 Thread
->WaitNext
= FALSE
;
257 Thread
->WaitBlockList
= NULL
;
258 Thread
->WaitListEntry
.Flink
= NULL
;
259 Thread
->WaitListEntry
.Blink
= NULL
;
260 Thread
->WaitTime
= 0;
261 Thread
->BasePriority
= Process
->BasePriority
;
262 Thread
->DecrementCount
= 0;
263 Thread
->PriorityDecrement
= 0;
264 Thread
->Quantum
= Process
->ThreadQuantum
;
265 memset(Thread
->WaitBlock
, 0, sizeof(KWAIT_BLOCK
)*4);
266 Thread
->LegoData
= 0;
267 Thread
->UserAffinity
= Process
->Affinity
;
268 Thread
->SystemAffinityActive
= 0;
269 Thread
->PowerState
= 0;
271 Thread
->ServiceTable
= KeServiceDescriptorTable
;
272 Thread
->Queue
= NULL
;
273 KeInitializeSpinLock(&Thread
->ApcQueueLock
);
274 memset(&Thread
->Timer
, 0, sizeof(KTIMER
));
275 KeInitializeTimer(&Thread
->Timer
);
276 Thread
->QueueListEntry
.Flink
= NULL
;
277 Thread
->QueueListEntry
.Blink
= NULL
;
278 Thread
->Affinity
= Process
->Affinity
;
279 Thread
->Preempted
= 0;
280 Thread
->ProcessReadyQueue
= 0;
281 Thread
->KernelStackResident
= 1;
282 Thread
->NextProcessor
= 0;
283 Thread
->CallbackStack
= NULL
;
284 Thread
->Win32Thread
= NULL
;
285 Thread
->TrapFrame
= NULL
;
286 Thread
->ApcStatePointer
[OriginalApcEnvironment
] = &Thread
->ApcState
;
287 Thread
->ApcStatePointer
[AttachedApcEnvironment
] = &Thread
->SavedApcState
;
288 Thread
->EnableStackSwap
= 0;
289 Thread
->LargeStack
= 0;
290 Thread
->ResourceIndex
= 0;
291 Thread
->PreviousMode
= KernelMode
;
292 Thread
->KernelTime
= 0;
293 Thread
->UserTime
= 0;
294 memset(&Thread
->SavedApcState
, 0, sizeof(KAPC_STATE
));
296 Thread
->ApcStateIndex
= OriginalApcEnvironment
;
297 Thread
->ApcQueueable
= TRUE
;
298 Thread
->AutoAlignment
= Process
->AutoAlignment
;
300 KeInitializeApc(&Thread
->SuspendApc
,
302 OriginalApcEnvironment
,
303 PiSuspendThreadKernelRoutine
,
304 PiSuspendThreadRundownRoutine
,
305 PiSuspendThreadNormalRoutine
,
308 KeInitializeSemaphore(&Thread
->SuspendSemaphore
, 0, 128);
310 InsertTailList(&Process
->ThreadListHead
,
311 &Thread
->ThreadListEntry
);
312 Thread
->FreezeCount
= 0;
313 Thread
->SuspendCount
= 0;
316 * Do x86 specific part
325 KeRevertToUserAffinityThread(VOID
)
328 PKTHREAD CurrentThread
;
331 oldIrql
= KeAcquireDispatcherDatabaseLock();
333 CurrentThread
= KeGetCurrentThread();
335 ASSERT(CurrentThread
->SystemAffinityActive
!= FALSE
);
337 /* Return to User Affinity */
338 CurrentThread
->Affinity
= CurrentThread
->UserAffinity
;
340 /* Disable System Affinity */
341 CurrentThread
->SystemAffinityActive
= FALSE
;
343 if (CurrentThread
->Affinity
& (1 << KeGetCurrentProcessorNumber()))
345 KeReleaseDispatcherDatabaseLock(oldIrql
);
349 CurrentThread
->WaitIrql
= oldIrql
;
350 PsDispatchThreadNoLock(THREAD_STATE_READY
);
351 KeLowerIrql(oldIrql
);
361 KeSetIdealProcessorThread (
365 CCHAR PreviousIdealProcessor
;
367 /* Save Old Ideal Processor */
368 PreviousIdealProcessor
= Thread
->IdealProcessor
;
370 /* Set New Ideal Processor */
371 Thread
->IdealProcessor
= Processor
;
373 /* Return Old Ideal Processor */
374 return PreviousIdealProcessor
;
382 KeSetSystemAffinityThread(IN KAFFINITY Affinity
)
385 PKTHREAD CurrentThread
;
388 oldIrql
= KeAcquireDispatcherDatabaseLock();
390 CurrentThread
= KeGetCurrentThread();
392 ASSERT(Affinity
& ((1 << KeNumberProcessors
) - 1));
394 /* Set the System Affinity Specified */
395 CurrentThread
->Affinity
= Affinity
;
397 /* Enable System Affinity */
398 CurrentThread
->SystemAffinityActive
= TRUE
;
400 if (Affinity
& (1 << KeGetCurrentProcessorNumber()))
402 KeReleaseDispatcherDatabaseLock(oldIrql
);
406 CurrentThread
->WaitIrql
= oldIrql
;
407 PsDispatchThreadNoLock(THREAD_STATE_READY
);
408 KeLowerIrql(oldIrql
);
418 KeTerminateThread(IN KPRIORITY Increment
)
420 /* The Increment Argument seems to be ignored by NT and always 0 when called */
422 /* Call our own internal routine */
423 PsTerminateCurrentThread(0);
429 NtDelayExecution(IN BOOLEAN Alertable
,
430 IN PLARGE_INTEGER DelayInterval
)
432 KPROCESSOR_MODE PreviousMode
;
433 LARGE_INTEGER SafeInterval
;
435 PreviousMode
= ExGetPreviousMode();
437 if(PreviousMode
!= KernelMode
)
439 NTSTATUS Status
= STATUS_SUCCESS
;
443 ProbeForRead(DelayInterval
,
444 sizeof(LARGE_INTEGER
),
446 /* make a copy on the kernel stack and let DelayInterval point to it so
447 we don't need to wrap KeDelayExecutionThread in SEH! */
448 SafeInterval
= *DelayInterval
;
449 DelayInterval
= &SafeInterval
;
453 Status
= _SEH_GetExceptionCode();
457 if(!NT_SUCCESS(Status
))
463 return KeDelayExecutionThread(PreviousMode
,