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.
19 /* $Id: kthread.c,v 1.49 2004/08/15 16:39:05 chorns Exp $
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 (
79 KeReleaseThread(PETHREAD Thread
)
81 * FUNCTION: Releases the resource allocated for a thread by
83 * NOTE: The thread had better not be running when this is called
86 extern unsigned int init_stack
;
88 if (Thread
->Tcb
.StackLimit
!= (ULONG
)&init_stack
)
90 MmLockAddressSpace(MmGetKernelAddressSpace());
91 MmFreeMemoryArea(MmGetKernelAddressSpace(),
92 (PVOID
)Thread
->Tcb
.StackLimit
,
96 MmUnlockAddressSpace(MmGetKernelAddressSpace());
98 Thread
->Tcb
.StackLimit
= 0;
99 Thread
->Tcb
.InitialStack
= NULL
;
100 Thread
->Tcb
.StackBase
= NULL
;
101 Thread
->Tcb
.KernelStack
= NULL
;
102 return(STATUS_SUCCESS
);
110 KeSetKernelStackSwapEnable(
119 KeInitializeThread(PKPROCESS Process
, PKTHREAD Thread
, BOOLEAN First
)
121 * FUNCTION: Initialize the microkernel state of the thread
126 extern unsigned int init_stack_top
;
127 extern unsigned int init_stack
;
128 PMEMORY_AREA StackArea
;
130 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
132 BoundaryAddressMultiple
.QuadPart
= 0;
134 KeInitializeDispatcherHeader(&Thread
->DispatcherHeader
,
138 InitializeListHead(&Thread
->MutantListHead
);
141 PFN_TYPE Page
[MM_STACK_SIZE
/ PAGE_SIZE
];
144 MmLockAddressSpace(MmGetKernelAddressSpace());
145 Status
= MmCreateMemoryArea(NULL
,
146 MmGetKernelAddressSpace(),
147 MEMORY_AREA_KERNEL_STACK
,
154 BoundaryAddressMultiple
);
155 MmUnlockAddressSpace(MmGetKernelAddressSpace());
157 if (!NT_SUCCESS(Status
))
159 DPRINT1("Failed to create thread stack\n");
162 for (i
= 0; i
< (MM_STACK_SIZE
/ PAGE_SIZE
); i
++)
164 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Page
[i
]);
165 if (!NT_SUCCESS(Status
))
170 Status
= MmCreateVirtualMapping(NULL
,
174 MM_STACK_SIZE
/ PAGE_SIZE
);
175 if (!NT_SUCCESS(Status
))
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
;
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
;
193 * The Native API function will initialize the TEB field later
196 Thread
->TlsArray
= NULL
;
197 Thread
->DebugActive
= 0;
198 Thread
->State
= THREAD_STATE_INITIALIZED
;
199 Thread
->Alerted
[0] = 0;
200 Thread
->Alerted
[1] = 0;
203 * FIXME: Think how this might work
205 Thread
->NpxState
= 0;
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;
228 memset(Thread
->WaitBlock
, 0, sizeof(KWAIT_BLOCK
)*4);
229 Thread
->LegoData
= 0;
234 // Thread->KernelApcDisable = 1;
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.
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...
247 Thread
->KernelApcDisable
= -1;
250 Thread
->UserAffinity
= Process
->Affinity
;
251 Thread
->SystemAffinityActive
= 0;
252 Thread
->PowerState
= 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
));
279 /* FIXME: is this correct? */
280 Thread
->Alertable
= 1;
282 Thread
->ApcStateIndex
= OriginalApcEnvironment
;
284 /* FIXME: not all thread are ApcQueueable! */
285 Thread
->ApcQueueable
= TRUE
;
287 Thread
->AutoAlignment
= 0;
288 KeInitializeApc(&Thread
->SuspendApc
,
290 OriginalApcEnvironment
,
291 PiSuspendThreadKernelRoutine
,
292 PiSuspendThreadRundownRoutine
,
293 PiSuspendThreadNormalRoutine
,
296 KeInitializeSemaphore(&Thread
->SuspendSemaphore
, 0, 128);
297 Thread
->ThreadListEntry
.Flink
= NULL
;
298 Thread
->ThreadListEntry
.Blink
= NULL
;
299 Thread
->FreezeCount
= 0;
300 Thread
->SuspendCount
= 0;
303 * Initialize ReactOS specific members
305 Thread
->ProcessThreadListEntry
.Flink
= NULL
;
306 Thread
->ProcessThreadListEntry
.Blink
= NULL
;
309 * Do x86 specific part
316 PsDispatchThread(THREAD_STATE_READY
);
324 KeRevertToUserAffinityThread(
336 KeSetIdealProcessorThread (
350 KeSetSystemAffinityThread(
351 IN KAFFINITY Affinity
363 IN KPRIORITY Increment