This commit was generated by cvs2svn to compensate for changes in r30,
[reactos.git] / reactos / ntoskrnl / ps / thread.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ps/thread.c
5 * PURPOSE: Thread managment
6 * PROGRAMMER: David Welch (welch@mcmail.com)
7 * REVISION HISTORY:
8 * 23/06/98: Created
9 */
10
11 /*
12 * NOTE:
13 *
14 * All of the routines that manipulate the thread queue synchronize on
15 * a single spinlock
16 *
17 */
18
19 /* INCLUDES ****************************************************************/
20
21 #include <windows.h>
22 #include <ddk/ntddk.h>
23 #include <internal/ke.h>
24 #include <internal/objmgr.h>
25 #include <internal/string.h>
26 #include <internal/hal.h>
27 #include <internal/psmgr.h>
28
29 #define NDEBUG
30 #include <internal/debug.h>
31
32 /* TYPES *******************************************************************/
33
34 /* GLOBALS ******************************************************************/
35
36 OBJECT_TYPE ThreadObjectType = {{NULL,0,0},
37 0,
38 0,
39 ULONG_MAX,
40 ULONG_MAX,
41 sizeof(ETHREAD),
42 0,
43 NULL,
44 NULL,
45 NULL,
46 NULL,
47 NULL,
48 NULL,
49 NULL,
50 NULL,
51 };
52
53 #define NR_THREAD_PRIORITY_LEVELS (32)
54
55 static KSPIN_LOCK ThreadListLock = {0,};
56
57 /*
58 * PURPOSE: List of all threads currently active
59 */
60 static LIST_ENTRY ThreadListHead = {NULL,NULL};
61
62 /*
63 * PURPOSE: List of threads associated with each priority level
64 */
65 static LIST_ENTRY PriorityListHead[NR_THREAD_PRIORITY_LEVELS]={{NULL,NULL},};
66 static BOOLEAN DoneInitYet = FALSE;
67
68 static PETHREAD CurrentThread = NULL;
69
70 static ULONG NextThreadUniqueId = 0;
71
72 /* FUNCTIONS ***************************************************************/
73
74 NTSTATUS ZwSetInformationThread(HANDLE ThreadHandle,
75 THREADINFOCLASS ThreadInformationClass,
76 PVOID ThreadInformation,
77 ULONG ThreadInformationLength)
78 {
79 UNIMPLEMENTED;
80 }
81
82 PKTHREAD KeGetCurrentThread(VOID)
83 {
84 return((PKTHREAD)CurrentThread);
85 }
86
87 PETHREAD PsGetCurrentThread(VOID)
88 {
89 return((PETHREAD)KeGetCurrentThread());
90 }
91
92 #if CAN_WE_DARE_TO_TRY_THIS
93 void PsDispatchThread(void)
94 {
95 int i;
96
97 for (i=0; i<NR_THREAD_PRIORITY_LEVELS; i++)
98 {
99 if (PsDispatchSpecificPriorityThread(i))
100 {
101 return;
102 }
103 }
104 }
105 #endif
106
107 void PsDispatchThread(void)
108 /*
109 * FUNCTION: Chooses a thread, possibly the current one if it is runnable
110 * and dispatches it
111 */
112 {
113 KIRQL irql;
114 PLIST_ENTRY current_entry;
115 PKTHREAD current;
116
117 if (!DoneInitYet)
118 {
119 return;
120 }
121
122 DPRINT("PsDispatchThread() Current %x\n",CurrentThread);
123
124 /*
125 * Bump overselves up to a higher IRQ level during this
126 */
127 KeAcquireSpinLock(&ThreadListLock,&irql);
128
129 /*
130 * If this was an involuntary reschedule then the current thread will still
131 * be eligible to run later
132 */
133 if (CurrentThread->Tcb.ThreadState==THREAD_STATE_RUNNING)
134 {
135 CurrentThread->Tcb.ThreadState=THREAD_STATE_RUNNABLE;
136 }
137
138 /*
139 * Simple round robin algorithm, iterate through and dispatch the first
140 * runnable thread
141 */
142 current = CONTAINING_RECORD(ThreadListHead.Flink,KTHREAD,Entry);
143 current_entry = ThreadListHead.Flink;
144
145 while (current_entry!=(&ThreadListHead))
146 {
147 DPRINT("Scanning %x ",current);
148 DPRINT("State %x Runnable %x\n",current->ThreadState,
149 THREAD_STATE_RUNNABLE);
150 if (current->ThreadState == THREAD_STATE_RUNNABLE &&
151 current != (PKTHREAD)CurrentThread)
152 {
153 DPRINT("Scheduling this one %x\n",current);
154 CurrentThread = current;
155 CurrentThread->Tcb.ThreadState = THREAD_STATE_RUNNING;
156 KeReleaseSpinLock(&ThreadListLock,irql);
157 HalTaskSwitch(current);
158 return;
159 }
160 current_entry = current->Entry.Flink;
161 current = CONTAINING_RECORD(current_entry,KTHREAD,Entry);
162 }
163
164 /*
165 * If there are no other threads then continue with the current one if
166 * possible
167 */
168 if (CurrentThread->Tcb.ThreadState == THREAD_STATE_RUNNABLE)
169 {
170 return;
171 }
172
173 /*
174 * Disaster
175 */
176 printk("Out of threads at %s:%d\n",__FILE__,__LINE__);
177 for(;;);
178 }
179
180 void PsInitThreadManagment(void)
181 /*
182 * FUNCTION: Initialize thread managment
183 */
184 {
185 PETHREAD first_thread;
186
187 InitializeListHead(&ThreadListHead);
188 KeInitializeSpinLock(&ThreadListLock);
189
190 ObRegisterType(OBJTYP_THREAD,&ThreadObjectType);
191
192 first_thread = ExAllocatePool(NonPagedPool,sizeof(ETHREAD));
193 first_thread->Tcb.ThreadState = THREAD_STATE_RUNNING;
194 HalInitFirstTask((PKTHREAD)first_thread);
195 ExInterlockedInsertHeadList(&ThreadListHead,&first_thread->Tcb.Entry,
196 &ThreadListLock);
197 CurrentThread = first_thread;
198
199 DoneInitYet = TRUE;
200 }
201
202 NTSTATUS PsWakeThread(PETHREAD Thread)
203 {
204 Thread->Tcb.ThreadState = THREAD_STATE_RUNNABLE;
205 return(STATUS_SUCCESS);
206 }
207
208 NTSTATUS PsSuspendThread(VOID)
209 /*
210 * FUNCTION: Suspend the current thread
211 */
212 {
213 KIRQL oldlvl;
214
215 DPRINT("suspending %x\n",CurrentThread);
216
217 /*
218 * NOTE: When we return from PsDispatchThread the spinlock will be
219 * released
220 */
221 CurrentThread->Tcb.ThreadState = THREAD_STATE_SUSPENDED;
222 PsDispatchThread();
223 return(STATUS_SUCCESS);
224 }
225
226
227
228 NTSTATUS PsTerminateSystemThread(NTSTATUS ExitStatus)
229 /*
230 * FUNCTION: Terminates the current thread
231 * ARGUMENTS:
232 * ExitStatus = Status to pass to the creater
233 * RETURNS: Doesn't
234 */
235 {
236 KIRQL oldlvl;
237
238 DPRINT("terminating %x\n",CurrentThread);
239 KeRaiseIrql(DISPATCH_LEVEL,&oldlvl);
240 CurrentThread->Tcb.ThreadState = THREAD_STATE_TERMINATED;
241 RemoveEntryList(&CurrentThread->Tcb.Entry);
242 PsDispatchThread();
243 for(;;);
244 }
245
246 NTSTATUS NtCreateThread(PHANDLE ThreadHandle,
247 ACCESS_MASK DesiredAccess,
248 POBJECT_ATTRIBUTES ObjectAttributes,
249 HANDLE ProcessHandle,
250 PCLIENT_ID Client,
251 PCONTEXT ThreadContext,
252 PINITIAL_TEB InitialTeb,
253 BOOLEAN CreateSuspended)
254 {
255 }
256
257 NTSTATUS PsCreateSystemThread(PHANDLE ThreadHandle,
258 ACCESS_MASK DesiredAccess,
259 POBJECT_ATTRIBUTES ObjectAttributes,
260 HANDLE ProcessHandle,
261 PCLIENT_ID ClientId,
262 PKSTART_ROUTINE StartRoutine,
263 PVOID StartContext)
264 /*
265 * FUNCTION: Creates a thread which executes in kernel mode
266 * ARGUMENTS:
267 * ThreadHandle (OUT) = Caller supplied storage for the returned thread
268 * handle
269 * DesiredAccess = Requested access to the thread
270 * ObjectAttributes = Object attributes (optional)
271 * ProcessHandle = Handle of process thread will run in
272 * NULL to use system process
273 * ClientId (OUT) = Caller supplied storage for the returned client id
274 * of the thread (optional)
275 * StartRoutine = Entry point for the thread
276 * StartContext = Argument supplied to the thread when it begins
277 * execution
278 * RETURNS: Success or failure status
279 */
280 {
281 PETHREAD thread;
282 ULONG ThreadId;
283 ULONG ProcessId;
284
285 thread = ObGenericCreateObject(ThreadHandle,0,NULL,OBJTYP_THREAD);
286 DPRINT("Allocating thread %x\n",thread);
287
288 thread->Tcb.ThreadState=THREAD_STATE_RUNNABLE;
289 thread->Tcb.BasePriority=0;
290 thread->Tcb.CurrentPriority=0;
291 thread->Tcb.ApcList=ExAllocatePool(NonPagedPool,sizeof(LIST_ENTRY));
292 InitializeListHead(thread->Tcb.ApcList);
293 HalInitTask(&(thread->Tcb),StartRoutine,StartContext);
294 InitializeListHead(&(thread->IrpList));
295 thread->Cid.UniqueThread=NextThreadUniqueId++;
296 // thread->Cid.ThreadId=InterlockedIncrement(&NextThreadUniqueId);
297 if (ClientId!=NULL)
298 {
299 *ClientId=thread->Cid;
300 }
301
302 if (ProcessHandle!=NULL)
303 {
304 thread->ThreadsProcess=ObGetObjectByHandle(ProcessHandle);
305 }
306 else
307 {
308 thread->ThreadsProcess=&SystemProcess;
309 }
310 thread->StartAddress=StartRoutine;
311
312
313 ExInterlockedInsertHeadList(&ThreadListHead,&thread->Tcb.Entry,
314 &ThreadListLock);
315 return(STATUS_SUCCESS);
316 }
317
318 LONG KeSetBasePriorityThread(PKTHREAD Thread, LONG Increment)
319 {
320 UNIMPLEMENTED;
321 }
322
323 KPRIORITY KeSetPriorityThread(PKTHREAD Thread, KPRIORITY Priority)
324 {
325 UNIMPLEMENTED;
326 }