3 * Copyright (C) 2000 ReactOS Team
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.
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.
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.
21 * FILE: ntoskrnl/ke/kthread.c
22 * PURPOSE: Microkernel thread support
23 * PROGRAMMER: David Welch (welch@cwcom.net)
28 /* INCLUDES *****************************************************************/
32 #include <internal/debug.h>
34 /* FUNCTIONS *****************************************************************/
41 KeCapturePersistentThreadState(
42 IN PVOID CurrentThread
,
55 KeFreeStackPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
56 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
58 ASSERT(SwapEntry
== 0);
61 MmReleasePageMemoryConsumer(MC_NPPOOL
, Page
);
70 KeQueryPriorityThread (
74 return Thread
->Priority
;
78 KeReleaseThread(PKTHREAD Thread
)
80 * FUNCTION: Releases the resource allocated for a thread by
82 * NOTE: The thread had better not be running when this is called
85 extern unsigned int init_stack
;
87 /* FIXME - lock the process */
88 RemoveEntryList(&Thread
->ThreadListEntry
);
90 if (Thread
->StackLimit
!= (ULONG_PTR
)&init_stack
)
92 MmLockAddressSpace(MmGetKernelAddressSpace());
93 MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(),
94 (PVOID
)Thread
->StackLimit
,
97 MmUnlockAddressSpace(MmGetKernelAddressSpace());
99 Thread
->StackLimit
= 0;
100 Thread
->InitialStack
= NULL
;
101 Thread
->StackBase
= NULL
;
102 Thread
->KernelStack
= NULL
;
103 return(STATUS_SUCCESS
);
111 KeSetKernelStackSwapEnable(
116 BOOLEAN PreviousState
;
118 Thread
= KeGetCurrentThread();
121 PreviousState
= Thread
->EnableStackSwap
;
124 Thread
->EnableStackSwap
= Enable
;
126 /* Return Old State */
127 return PreviousState
;
131 KeInitializeThread(PKPROCESS Process
, PKTHREAD Thread
, BOOLEAN First
)
133 * FUNCTION: Initialize the microkernel state of the thread
138 extern unsigned int init_stack_top
;
139 extern unsigned int init_stack
;
140 PMEMORY_AREA StackArea
;
142 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
144 BoundaryAddressMultiple
.QuadPart
= 0;
146 KeInitializeDispatcherHeader(&Thread
->DispatcherHeader
,
150 InitializeListHead(&Thread
->MutantListHead
);
153 PFN_TYPE Page
[MM_STACK_SIZE
/ PAGE_SIZE
];
156 MmLockAddressSpace(MmGetKernelAddressSpace());
157 Status
= MmCreateMemoryArea(NULL
,
158 MmGetKernelAddressSpace(),
159 MEMORY_AREA_KERNEL_STACK
,
166 BoundaryAddressMultiple
);
167 MmUnlockAddressSpace(MmGetKernelAddressSpace());
169 if (!NT_SUCCESS(Status
))
171 DPRINT1("Failed to create thread stack\n");
174 for (i
= 0; i
< (MM_STACK_SIZE
/ PAGE_SIZE
); i
++)
176 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Page
[i
]);
177 if (!NT_SUCCESS(Status
))
182 Status
= MmCreateVirtualMapping(NULL
,
186 MM_STACK_SIZE
/ PAGE_SIZE
);
187 if (!NT_SUCCESS(Status
))
191 Thread
->InitialStack
= (PCHAR
)KernelStack
+ MM_STACK_SIZE
;
192 Thread
->StackBase
= (PCHAR
)KernelStack
+ MM_STACK_SIZE
;
193 Thread
->StackLimit
= (ULONG_PTR
)KernelStack
;
194 Thread
->KernelStack
= (PCHAR
)KernelStack
+ MM_STACK_SIZE
;
198 Thread
->InitialStack
= (PCHAR
)&init_stack_top
;
199 Thread
->StackBase
= (PCHAR
)&init_stack_top
;
200 Thread
->StackLimit
= (ULONG_PTR
)&init_stack
;
201 Thread
->KernelStack
= (PCHAR
)&init_stack_top
;
205 * Establish the pde's for the new stack and the thread structure within the
206 * address space of the new process. They are accessed while taskswitching or
207 * while handling page faults. At this point it isn't possible to call the
208 * page fault handler for the missing pde's.
211 MmUpdatePageDir((PEPROCESS
)Process
, (PVOID
)Thread
->StackLimit
, MM_STACK_SIZE
);
212 MmUpdatePageDir((PEPROCESS
)Process
, (PVOID
)Thread
, sizeof(ETHREAD
));
215 * The Native API function will initialize the TEB field later
218 Thread
->TlsArray
= NULL
;
219 Thread
->DebugActive
= 0;
220 Thread
->State
= THREAD_STATE_INITIALIZED
;
221 Thread
->Alerted
[0] = 0;
222 Thread
->Alerted
[1] = 0;
225 * FIXME: Think how this might work
227 Thread
->NpxState
= 0;
229 Thread
->Saturation
= 0;
230 Thread
->Priority
= Process
->BasePriority
;
231 InitializeListHead(&Thread
->ApcState
.ApcListHead
[0]);
232 InitializeListHead(&Thread
->ApcState
.ApcListHead
[1]);
233 Thread
->ApcState
.Process
= Process
;
234 Thread
->ApcState
.KernelApcInProgress
= 0;
235 Thread
->ApcState
.KernelApcPending
= 0;
236 Thread
->ApcState
.UserApcPending
= 0;
237 Thread
->ContextSwitches
= 0;
238 Thread
->WaitStatus
= STATUS_SUCCESS
;
239 Thread
->WaitIrql
= PASSIVE_LEVEL
;
240 Thread
->WaitMode
= 0;
241 Thread
->WaitNext
= FALSE
;
242 Thread
->WaitBlockList
= NULL
;
243 Thread
->WaitListEntry
.Flink
= NULL
;
244 Thread
->WaitListEntry
.Blink
= NULL
;
245 Thread
->WaitTime
= 0;
246 Thread
->BasePriority
= Process
->BasePriority
;
247 Thread
->DecrementCount
= 0;
248 Thread
->PriorityDecrement
= 0;
249 Thread
->Quantum
= Process
->ThreadQuantum
;
250 memset(Thread
->WaitBlock
, 0, sizeof(KWAIT_BLOCK
)*4);
251 Thread
->LegoData
= 0;
252 Thread
->UserAffinity
= Process
->Affinity
;
253 Thread
->SystemAffinityActive
= 0;
254 Thread
->PowerState
= 0;
256 Thread
->ServiceTable
= KeServiceDescriptorTable
;
257 Thread
->Queue
= NULL
;
258 KeInitializeSpinLock(&Thread
->ApcQueueLock
);
259 memset(&Thread
->Timer
, 0, sizeof(KTIMER
));
260 KeInitializeTimer(&Thread
->Timer
);
261 Thread
->QueueListEntry
.Flink
= NULL
;
262 Thread
->QueueListEntry
.Blink
= NULL
;
263 Thread
->Affinity
= Process
->Affinity
;
264 Thread
->Preempted
= 0;
265 Thread
->ProcessReadyQueue
= 0;
266 Thread
->KernelStackResident
= 1;
267 Thread
->NextProcessor
= 0;
268 Thread
->CallbackStack
= NULL
;
269 Thread
->Win32Thread
= NULL
;
270 Thread
->TrapFrame
= NULL
;
271 Thread
->ApcStatePointer
[OriginalApcEnvironment
] = &Thread
->ApcState
;
272 Thread
->ApcStatePointer
[AttachedApcEnvironment
] = &Thread
->SavedApcState
;
273 Thread
->EnableStackSwap
= 0;
274 Thread
->LargeStack
= 0;
275 Thread
->ResourceIndex
= 0;
276 Thread
->PreviousMode
= KernelMode
;
277 Thread
->KernelTime
= 0;
278 Thread
->UserTime
= 0;
279 memset(&Thread
->SavedApcState
, 0, sizeof(KAPC_STATE
));
281 Thread
->ApcStateIndex
= OriginalApcEnvironment
;
282 Thread
->ApcQueueable
= TRUE
;
283 Thread
->AutoAlignment
= Process
->AutoAlignment
;
285 KeInitializeApc(&Thread
->SuspendApc
,
287 OriginalApcEnvironment
,
288 PiSuspendThreadKernelRoutine
,
289 PiSuspendThreadRundownRoutine
,
290 PiSuspendThreadNormalRoutine
,
293 KeInitializeSemaphore(&Thread
->SuspendSemaphore
, 0, 128);
295 InsertTailList(&Process
->ThreadListHead
,
296 &Thread
->ThreadListEntry
);
297 Thread
->FreezeCount
= 0;
298 Thread
->SuspendCount
= 0;
301 * Do x86 specific part
310 KeRevertToUserAffinityThread(VOID
)
313 PKTHREAD CurrentThread
;
316 oldIrql
= KeAcquireDispatcherDatabaseLock();
318 CurrentThread
= KeGetCurrentThread();
320 ASSERT(CurrentThread
->SystemAffinityActive
!= FALSE
);
322 /* Return to User Affinity */
323 CurrentThread
->Affinity
= CurrentThread
->UserAffinity
;
325 /* Disable System Affinity */
326 CurrentThread
->SystemAffinityActive
= FALSE
;
328 if (CurrentThread
->Affinity
& (1 << KeGetCurrentProcessorNumber()))
330 KeReleaseDispatcherDatabaseLock(oldIrql
);
334 CurrentThread
->WaitIrql
= oldIrql
;
335 PsDispatchThreadNoLock(THREAD_STATE_READY
);
336 KeLowerIrql(oldIrql
);
346 KeSetIdealProcessorThread (
350 CCHAR PreviousIdealProcessor
;
352 /* Save Old Ideal Processor */
353 PreviousIdealProcessor
= Thread
->IdealProcessor
;
355 /* Set New Ideal Processor */
356 Thread
->IdealProcessor
= Processor
;
358 /* Return Old Ideal Processor */
359 return PreviousIdealProcessor
;
367 KeSetSystemAffinityThread(IN KAFFINITY Affinity
)
370 PKTHREAD CurrentThread
;
373 oldIrql
= KeAcquireDispatcherDatabaseLock();
375 CurrentThread
= KeGetCurrentThread();
377 ASSERT(Affinity
& ((1 << KeNumberProcessors
) - 1));
379 /* Set the System Affinity Specified */
380 CurrentThread
->Affinity
= Affinity
;
382 /* Enable System Affinity */
383 CurrentThread
->SystemAffinityActive
= TRUE
;
385 if (Affinity
& (1 << KeGetCurrentProcessorNumber()))
387 KeReleaseDispatcherDatabaseLock(oldIrql
);
391 CurrentThread
->WaitIrql
= oldIrql
;
392 PsDispatchThreadNoLock(THREAD_STATE_READY
);
393 KeLowerIrql(oldIrql
);
403 KeTerminateThread(IN KPRIORITY Increment
)
405 /* The Increment Argument seems to be ignored by NT and always 0 when called */
407 /* Call our own internal routine */
408 PsTerminateCurrentThread(0);