2002-06-04 David Welch <welch@whitehall1-5.seh.ox.ac.uk>
[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.26 2002/06/04 15:26:56 dwelch 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 <ddk/ntddk.h>
31 #include <internal/ke.h>
32 #include <internal/ps.h>
33 #include <internal/id.h>
34 #include <internal/pool.h>
35
36 #define NDEBUG
37 #include <internal/debug.h>
38
39 /* EXTERN ********************************************************************/
40
41 //extern VOID
42 //PiTimeoutThread(struct _KDPC Dpc, PVOID Context, PVOID Arg1, PVOID Arg2);
43
44 /* FUNCTIONS *****************************************************************/
45
46 VOID
47 KeFreeStackPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
48 PHYSICAL_ADDRESS PhysAddr, SWAPENTRY SwapEntry, BOOLEAN Dirty)
49 {
50 assert(SwapEntry == 0);
51 if (PhysAddr.QuadPart != 0)
52 {
53 MmDereferencePage(PhysAddr);
54 }
55 }
56
57 NTSTATUS
58 KeReleaseThread(PETHREAD Thread)
59 /*
60 * FUNCTION: Releases the resource allocated for a thread by
61 * KeInitializeThread
62 * NOTE: The thread had better not be running when this is called
63 */
64 {
65 extern unsigned int init_stack;
66
67 if (Thread->Tcb.StackLimit != (ULONG)&init_stack)
68 {
69 MmLockAddressSpace(MmGetKernelAddressSpace());
70 MmFreeMemoryArea(MmGetKernelAddressSpace(),
71 (PVOID)Thread->Tcb.StackLimit,
72 MM_STACK_SIZE,
73 KeFreeStackPage,
74 NULL);
75 MmUnlockAddressSpace(MmGetKernelAddressSpace());
76 }
77 Thread->Tcb.StackLimit = 0;
78 Thread->Tcb.InitialStack = NULL;
79 Thread->Tcb.StackBase = NULL;
80 Thread->Tcb.KernelStack = NULL;
81 return(STATUS_SUCCESS);
82 }
83
84 VOID
85 KeInitializeThread(PKPROCESS Process, PKTHREAD Thread, BOOLEAN First)
86 /*
87 * FUNCTION: Initialize the microkernel state of the thread
88 */
89 {
90 PVOID KernelStack;
91 NTSTATUS Status;
92 extern unsigned int init_stack_top;
93 extern unsigned int init_stack;
94 PMEMORY_AREA StackArea;
95 ULONG i;
96
97 KeInitializeDispatcherHeader(&Thread->DispatcherHeader,
98 InternalThreadType,
99 sizeof(ETHREAD),
100 FALSE);
101 InitializeListHead(&Thread->MutantListHead);
102 if (!First)
103 {
104 KernelStack = NULL;
105
106 MmLockAddressSpace(MmGetKernelAddressSpace());
107 Status = MmCreateMemoryArea(NULL,
108 MmGetKernelAddressSpace(),
109 MEMORY_AREA_KERNEL_STACK,
110 &KernelStack,
111 MM_STACK_SIZE,
112 0,
113 &StackArea,
114 FALSE);
115 MmUnlockAddressSpace(MmGetKernelAddressSpace());
116
117 if (!NT_SUCCESS(Status))
118 {
119 DPRINT1("Failed to create thread stack\n");
120 KeBugCheck(0);
121 }
122 for (i = 0; i < (MM_STACK_SIZE / PAGESIZE); i++)
123 {
124 PHYSICAL_ADDRESS Page;
125 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page);
126 if (!NT_SUCCESS(Status))
127 {
128 KeBugCheck(0);
129 }
130 Status = MmCreateVirtualMapping(NULL,
131 KernelStack + (i * PAGESIZE),
132 PAGE_EXECUTE_READWRITE,
133 Page,
134 TRUE);
135 }
136 Thread->InitialStack = KernelStack + MM_STACK_SIZE;
137 Thread->StackBase = KernelStack + MM_STACK_SIZE;
138 Thread->StackLimit = (ULONG)KernelStack;
139 Thread->KernelStack = KernelStack + MM_STACK_SIZE;
140 }
141 else
142 {
143 Thread->InitialStack = (PVOID)&init_stack_top;
144 Thread->StackBase = (PVOID)&init_stack_top;
145 Thread->StackLimit = (ULONG)&init_stack;
146 Thread->KernelStack = (PVOID)&init_stack_top;
147 }
148
149 /*
150 * The Native API function will initialize the TEB field later
151 */
152 Thread->Teb = NULL;
153 Thread->TlsArray = NULL;
154 Thread->DebugActive = 0;
155 Thread->State = THREAD_STATE_BLOCKED;
156 Thread->Alerted[0] = 0;
157 Thread->Alerted[1] = 0;
158 Thread->Iopl = 0;
159 /*
160 * FIXME: Think how this might work
161 */
162 Thread->NpxState = 0;
163
164 Thread->Saturation = 0;
165 Thread->Priority = 0;
166 InitializeListHead(&Thread->ApcState.ApcListHead[0]);
167 InitializeListHead(&Thread->ApcState.ApcListHead[1]);
168 Thread->ApcState.Process = Process;
169 Thread->ApcState.KernelApcInProgress = 0;
170 Thread->ApcState.KernelApcPending = 0;
171 Thread->ApcState.UserApcPending = 0;
172 Thread->ContextSwitches = 0;
173 Thread->WaitStatus = STATUS_SUCCESS;
174 Thread->WaitIrql = 0;
175 Thread->WaitMode = 0;
176 Thread->WaitNext = 0;
177 Thread->WaitBlockList = NULL;
178 Thread->WaitListEntry.Flink = NULL;
179 Thread->WaitListEntry.Blink = NULL;
180 Thread->WaitTime = 0;
181 Thread->BasePriority = 0;
182 Thread->DecrementCount = 0;
183 Thread->PriorityDecrement = 0;
184 Thread->Quantum = 0;
185 memset(Thread->WaitBlock, 0, sizeof(KWAIT_BLOCK)*4);
186 Thread->LegoData = 0;
187 /*
188 * FIXME: Why this?
189 */
190 Thread->KernelApcDisable = 1;
191 Thread->UserAffinity = Process->Affinity;
192 Thread->SystemAffinityActive = 0;
193 Thread->Queue = NULL;
194 KeInitializeSpinLock(&Thread->ApcQueueLock);
195 memset(&Thread->Timer, 0, sizeof(KTIMER));
196 Thread->QueueListEntry.Flink = NULL;
197 Thread->QueueListEntry.Blink = NULL;
198 Thread->Affinity = Process->Affinity;
199 Thread->Preempted = 0;
200 Thread->ProcessReadyQueue = 0;
201 Thread->KernelStackResident = 1;
202 Thread->NextProcessor = 0;
203 Thread->CallbackStack = NULL;
204 Thread->Win32Thread = 0;
205 Thread->TrapFrame = NULL;
206 Thread->ApcStatePointer[0] = NULL;
207 Thread->ApcStatePointer[1] = NULL;
208 Thread->EnableStackSwap = 0;
209 Thread->LargeStack = 0;
210 Thread->ResourceIndex = 0;
211 Thread->PreviousMode = KernelMode;
212 Thread->KernelTime = 0;
213 Thread->UserTime = 0;
214 memset(&Thread->SavedApcState, 0, sizeof(KAPC_STATE));
215 Thread->Alertable = 1;
216 Thread->ApcStateIndex = 0;
217 Thread->ApcQueueable = 0;
218 Thread->AutoAlignment = 0;
219 KeInitializeApc(&Thread->SuspendApc,
220 Thread,
221 0,
222 PiSuspendThreadKernelRoutine,
223 PiSuspendThreadRundownRoutine,
224 PiSuspendThreadNormalRoutine,
225 KernelMode,
226 NULL);
227 KeInitializeSemaphore(&Thread->SuspendSemaphore, 0, 255);
228 Thread->ThreadListEntry.Flink = NULL;
229 Thread->ThreadListEntry.Blink = NULL;
230 Thread->FreezeCount = 0;
231 Thread->SuspendCount = 0;
232
233 /*
234 * Initialize ReactOS specific members
235 */
236 Thread->ProcessThreadListEntry.Flink = NULL;
237 Thread->ProcessThreadListEntry.Blink = NULL;
238 KeInitializeDpc(&Thread->TimerDpc,
239 (PKDEFERRED_ROUTINE)PiTimeoutThread,
240 Thread);
241 Thread->LastEip = 0;
242
243 /*
244 * Do x86 specific part
245 */
246 }
247