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)
14 * All of the routines that manipulate the thread queue synchronize on
19 /* INCLUDES ****************************************************************/
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>
30 #include <internal/debug.h>
32 /* TYPES *******************************************************************/
34 /* GLOBALS ******************************************************************/
36 OBJECT_TYPE ThreadObjectType
= {{NULL
,0,0},
53 #define NR_THREAD_PRIORITY_LEVELS (32)
55 static KSPIN_LOCK ThreadListLock
= {0,};
58 * PURPOSE: List of all threads currently active
60 static LIST_ENTRY ThreadListHead
= {NULL
,NULL
};
63 * PURPOSE: List of threads associated with each priority level
65 static LIST_ENTRY PriorityListHead
[NR_THREAD_PRIORITY_LEVELS
]={{NULL
,NULL
},};
66 static BOOLEAN DoneInitYet
= FALSE
;
68 static PETHREAD CurrentThread
= NULL
;
70 static ULONG NextThreadUniqueId
= 0;
72 /* FUNCTIONS ***************************************************************/
74 NTSTATUS
ZwSetInformationThread(HANDLE ThreadHandle
,
75 THREADINFOCLASS ThreadInformationClass
,
76 PVOID ThreadInformation
,
77 ULONG ThreadInformationLength
)
82 PKTHREAD
KeGetCurrentThread(VOID
)
84 return((PKTHREAD
)CurrentThread
);
87 PETHREAD
PsGetCurrentThread(VOID
)
89 return((PETHREAD
)KeGetCurrentThread());
92 #if CAN_WE_DARE_TO_TRY_THIS
93 void PsDispatchThread(void)
97 for (i
=0; i
<NR_THREAD_PRIORITY_LEVELS
; i
++)
99 if (PsDispatchSpecificPriorityThread(i
))
107 void PsDispatchThread(void)
109 * FUNCTION: Chooses a thread, possibly the current one if it is runnable
114 PLIST_ENTRY current_entry
;
122 DPRINT("PsDispatchThread() Current %x\n",CurrentThread
);
125 * Bump overselves up to a higher IRQ level during this
127 KeAcquireSpinLock(&ThreadListLock
,&irql
);
130 * If this was an involuntary reschedule then the current thread will still
131 * be eligible to run later
133 if (CurrentThread
->Tcb
.ThreadState
==THREAD_STATE_RUNNING
)
135 CurrentThread
->Tcb
.ThreadState
=THREAD_STATE_RUNNABLE
;
139 * Simple round robin algorithm, iterate through and dispatch the first
142 current
= CONTAINING_RECORD(ThreadListHead
.Flink
,KTHREAD
,Entry
);
143 current_entry
= ThreadListHead
.Flink
;
145 while (current_entry
!=(&ThreadListHead
))
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
)
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
);
160 current_entry
= current
->Entry
.Flink
;
161 current
= CONTAINING_RECORD(current_entry
,KTHREAD
,Entry
);
165 * If there are no other threads then continue with the current one if
168 if (CurrentThread
->Tcb
.ThreadState
== THREAD_STATE_RUNNABLE
)
176 printk("Out of threads at %s:%d\n",__FILE__
,__LINE__
);
180 void PsInitThreadManagment(void)
182 * FUNCTION: Initialize thread managment
185 PETHREAD first_thread
;
187 InitializeListHead(&ThreadListHead
);
188 KeInitializeSpinLock(&ThreadListLock
);
190 ObRegisterType(OBJTYP_THREAD
,&ThreadObjectType
);
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
,
197 CurrentThread
= first_thread
;
202 NTSTATUS
PsWakeThread(PETHREAD Thread
)
204 Thread
->Tcb
.ThreadState
= THREAD_STATE_RUNNABLE
;
205 return(STATUS_SUCCESS
);
208 NTSTATUS
PsSuspendThread(VOID
)
210 * FUNCTION: Suspend the current thread
215 DPRINT("suspending %x\n",CurrentThread
);
218 * NOTE: When we return from PsDispatchThread the spinlock will be
221 CurrentThread
->Tcb
.ThreadState
= THREAD_STATE_SUSPENDED
;
223 return(STATUS_SUCCESS
);
228 NTSTATUS
PsTerminateSystemThread(NTSTATUS ExitStatus
)
230 * FUNCTION: Terminates the current thread
232 * ExitStatus = Status to pass to the creater
238 DPRINT("terminating %x\n",CurrentThread
);
239 KeRaiseIrql(DISPATCH_LEVEL
,&oldlvl
);
240 CurrentThread
->Tcb
.ThreadState
= THREAD_STATE_TERMINATED
;
241 RemoveEntryList(&CurrentThread
->Tcb
.Entry
);
246 NTSTATUS
NtCreateThread(PHANDLE ThreadHandle
,
247 ACCESS_MASK DesiredAccess
,
248 POBJECT_ATTRIBUTES ObjectAttributes
,
249 HANDLE ProcessHandle
,
251 PCONTEXT ThreadContext
,
252 PINITIAL_TEB InitialTeb
,
253 BOOLEAN CreateSuspended
)
257 NTSTATUS
PsCreateSystemThread(PHANDLE ThreadHandle
,
258 ACCESS_MASK DesiredAccess
,
259 POBJECT_ATTRIBUTES ObjectAttributes
,
260 HANDLE ProcessHandle
,
262 PKSTART_ROUTINE StartRoutine
,
265 * FUNCTION: Creates a thread which executes in kernel mode
267 * ThreadHandle (OUT) = Caller supplied storage for the returned thread
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
278 * RETURNS: Success or failure status
285 thread
= ObGenericCreateObject(ThreadHandle
,0,NULL
,OBJTYP_THREAD
);
286 DPRINT("Allocating thread %x\n",thread
);
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);
299 *ClientId
=thread
->Cid
;
302 if (ProcessHandle
!=NULL
)
304 thread
->ThreadsProcess
=ObGetObjectByHandle(ProcessHandle
);
308 thread
->ThreadsProcess
=&SystemProcess
;
310 thread
->StartAddress
=StartRoutine
;
313 ExInterlockedInsertHeadList(&ThreadListHead
,&thread
->Tcb
.Entry
,
315 return(STATUS_SUCCESS
);
318 LONG
KeSetBasePriorityThread(PKTHREAD Thread
, LONG Increment
)
323 KPRIORITY
KeSetPriorityThread(PKTHREAD Thread
, KPRIORITY Priority
)