📄 ktmgr.cpp
字号:
lpKernelThread = (__KERNEL_THREAD_OBJECT*)ObjectManager.CreateObject(&ObjectManager,
NULL,
OBJECT_TYPE_KERNEL_THREAD);
if(NULL == lpKernelThread) //If failed to create the kernel thread object.
goto __TERMINAL;
if(!lpKernelThread->Initialize((__COMMON_OBJECT*)lpKernelThread)) //Failed to initialize.
goto __TERMINAL;
if(0 == dwStackSize) //If the dwStackSize is zero,then allocate the default size's
//stack.
dwStackSize = DEFAULT_STACK_SIZE;
else
{
if(dwStackSize < KMEM_MIN_ALOCATE_BLOCK) //If dwStackSize is too small.
dwStackSize = KMEM_MIN_ALOCATE_BLOCK;
}
lpStack = KMemAlloc(dwStackSize,KMEM_SIZE_TYPE_ANY);
if(NULL == lpStack) //Failed to create kernel thread stack.
goto __TERMINAL;
//The following code initializes the kernel thread object created just now.
lpKernelThread->dwThreadID = lpKernelThread->dwObjectID;
lpKernelThread->dwThreadStatus = dwStatus;
lpKernelThread->dwThreadPriority = dwPriority;
lpKernelThread->dwScheduleCounter = dwPriority; //***** CAUTION!!! *****
lpKernelThread->dwReturnValue = 0L;
lpKernelThread->dwTotalRunTime = 0L;
lpKernelThread->dwTotalMemSize = 0L;
lpKernelThread->lpCurrentDirectory = NULL; //Maybe updated in the future.
lpKernelThread->lpRootDirectory = NULL;
lpKernelThread->lpModuleDirectory = NULL;
lpKernelThread->bUsedMath = FALSE; //May be updated in the future.
lpKernelThread->dwStackSize = dwStackSize ? dwStackSize : DEFAULT_STACK_SIZE;
lpKernelThread->lpInitStackPointer = (LPVOID)((DWORD)lpStack + dwStackSize);
lpKernelThread->KernelThreadRoutine = lpStartRoutine; //Will be updated.
lpKernelThread->lpRoutineParam = lpRoutineParam;
lpKernelThread->ucMsgQueueHeader = 0;
lpKernelThread->ucMsgQueueTrial = 0;
lpKernelThread->ucCurrentMsgNum = 0;
lpKernelThread->dwLastError = 0L;
lpKernelThread->lpParentKernelThread = NULL; //Will be updated.
//
//The initializating value of Instruction Pointer Register is KernelThreadWrapper,
//this routine has a parameter,lpKernelThread,in order to pass this parameter to the
//routine,we must build the stack frame correctly.
//The following code is used to build the kernel thread's stack frame.
//It first 'push' the lpKernelThread into the stack,and substract 8 from the stack
//pointer's value to simulate a procedure call,then initializes the context of the
//kernel thread created just now by using INIT_KERNEL_THREAD_CONTEXT_X macros.
//
*(DWORD*)((DWORD)lpStack + dwStackSize - 4) = (DWORD)lpKernelThread; //"Push" the lpKernelThread into
//it's stack.
#ifdef __I386
INIT_KERNEL_THREAD_CONTEXT_I(&(lpKernelThread->KernelThreadContext), //Initialize context.
(DWORD)KernelThreadWrapper,
((DWORD)lpStack + dwStackSize - 8)) //Please notice the 8 is necessary.
#elif (defined(__ALPHA))
#elif (defined(__PPC))
#elif (defined(__SPARC))
#endif
if(KERNEL_THREAD_STATUS_READY == dwStatus) //Add into Ready Queue.
{
if(!lpMgr->lpReadyQueue->InsertIntoQueue((__COMMON_OBJECT*)lpMgr->lpReadyQueue,
(__COMMON_OBJECT*)lpKernelThread,dwPriority))
goto __TERMINAL;
}
else //Add into Suspended Queue.
{
if(!lpMgr->lpSuspendedQueue->InsertIntoQueue((__COMMON_OBJECT*)lpMgr->lpSuspendedQueue,
(__COMMON_OBJECT*)lpKernelThread,dwPriority))
goto __TERMINAL;
}
bSuccess = TRUE; //Now,the TRANSACTION of create a kernel thread is successfully.
__TERMINAL:
if(!bSuccess)
{
//First,release the resources created successfully.
if(NULL != lpKernelThread)
ObjectManager.DestroyObject(&ObjectManager,(__COMMON_OBJECT*)lpKernelThread);
if(NULL != lpStack)
KMemFree(lpStack,KMEM_SIZE_TYPE_ANY,0L);
return NULL;
}
else
return lpKernelThread;
}
//
//DestroyKernelThread's implementation.
//The routine do the following:
// 1. Check the status of the kernel thread object will be destroyed,if the
// status is KERNEL_THREAD_STATUS_TERMINAL,then does the rest steps,else,
// simple return;
// 2. Delete the kernel thread object from Terminal Queue;
// 3. Destroy the kernel thread object by calling DestroyObject.
//
static VOID DestroyKernelThread(__COMMON_OBJECT* lpThis,__COMMON_OBJECT* lpKernel)
{
__KERNEL_THREAD_OBJECT* lpKernelThread = NULL;
__KERNEL_THREAD_MANAGER* lpMgr = NULL;
__PRIORITY_QUEUE* lpTerminalQueue = NULL;
LPVOID lpStack = NULL;
if((NULL == lpThis) || (NULL == lpKernel)) //Parameter check.
return;
lpKernelThread = (__KERNEL_THREAD_OBJECT*)lpKernel;
lpMgr = (__KERNEL_THREAD_MANAGER*)lpThis;
if(KERNEL_THREAD_STATUS_TERMINAL != lpKernelThread->dwThreadStatus)
return;
lpTerminalQueue = lpMgr->lpTerminalQueue;
lpTerminalQueue->DeleteFromQueue((__COMMON_OBJECT*)lpTerminalQueue,
(__COMMON_OBJECT*)lpKernelThread); //Delete from terminal queue.
lpStack = lpKernelThread->lpInitStackPointer;
lpStack = (LPVOID)((DWORD)lpStack - lpKernelThread->dwStackSize);
KMemFree(lpStack,KMEM_SIZE_TYPE_ANY,0L); //Free the stack of the kernel thread.
ObjectManager.DestroyObject(&ObjectManager,
(__COMMON_OBJECT*)lpKernelThread);
}
//SuspendKernelThread's implementation.
static BOOL SuspendKernelThread(__COMMON_OBJECT* lpThis,__COMMON_OBJECT* lpKernelThread)
{
return FALSE;
}
//ResumeKernelThread's implementation.
static BOOL ResumeKernelThread(__COMMON_OBJECT* lpThis,__COMMON_OBJECT* lpKernelThread)
{
return FALSE;
}
//
//ScheduleFromProc's implementation.
//This routine do the following:
// 1. Save the current kernel's context into stack(current kernel thread's stack);
// 2. Copy the context of current kernel thread into current kernel thread's object;
// 3. Call ChangeContext to switch to the context of the current CPU to another kernel
// thread.
//Because this procedure is declared as naked,i.e,in the procedure's implementation,we
//can not use local variables,so,in order to make the implementation easy,we define
//another routine,called ChangeContext,to finish the rest task.
//
static VOID ChangeContext(); //This routine's implementation will be described in behind
//of ScheduleFromProc's implementation.
__declspec(naked) static VOID ScheduleFromProc(__KERNEL_THREAD_CONTEXT* lpContext)
{
#ifdef __I386__
__asm{
push ebp
mov ebp,esp
add ebp,0x08 //add ebp,0x04 ??????
push ebp //Save the ESP register.
sub ebp,0x08 //sub ebp,0x04 ??????
push eax
push ebx
push ecx
push edx
push esi
push edi
pushfd
} //Now,we have saved the current kernel's context into stack successfully.
#else
#endif
//The following code saves the current kernel thread's context into kernel thread object.
#ifdef __I386__
__asm{
mov eax,dword ptr [ebp + 0x08] //Now,the EAX register countains the lpContext.
mov ebp,esp
mov ebx,dword ptr [ebp]
mov dword ptr [eax + CONTEXT_OFFSET_EFLAGS],ebx //Save eflags.
add ebp,0x04
mov ebx,dword ptr [ebp]
mov dword ptr [eax + CONTEXT_OFFSET_EDI],ebx //Save EDI.
add ebp,0x04
mov ebx,dword ptr [ebp]
mov dword ptr [eax + CONTEXT_OFFSET_ESI],ebx //Save ESI.
add ebp,0x04
mov ebx,dword ptr [ebp]
mov dword ptr [eax + CONTEXT_OFFSET_EDX],ebx //Save EDX.
add ebp,0x04
mov ebx,dword ptr [ebp]
mov dword ptr [eax + CONTEXT_OFFSET_ECX],ebx //Save ECX.
add ebp,0x04
mov ebx,dword ptr [ebp]
mov dword ptr [eax + CONTEXT_OFFSET_EBX],ebx //Save EBX.
add ebp,0x04
mov ebx,dword ptr [EBP]
mov dword ptr [eax + CONTEXT_OFFSET_EAX],ebx //Save EAX.
add ebp,0x04
mov ebx,dword ptr [ebp]
mov dword ptr [eax + CONTEXT_OFFSET_ESP],ebx //Save ESP.
add ebp,0x04
mov ebx,dword ptr [ebp]
mov dword ptr [eax + CONTEXT_OFFSET_EBP],ebx //Save EBP.
add ebp,0x04
mov ebx,dword ptr [ebp]
mov dword ptr [eax + CONTEXT_OFFSET_EIP],ebx //Save EIP.
add ebp,0x04
} //Now,we have saved the current kernel thread's context into kernel thread object.
#else
#endif
ChangeContext(); //Call ChangeContext to re-schedule all kernel threads.
}
//
//The ChangeContext is a helper routine,it does the following:
// 1. Fetch a kernel thread whose status is READY from Ready Queue of Kernel Thread Manager;
// 2. Change the kernel thread's status to KERNEL_THREAD_STATUS_RUNNING;
// 3. Update the lpCurrentKernelThread to the kernel thread's base address;
// 4. Call the SwitchTo procedure to switch the control flow.
//
static VOID ChangeContext()
{
__KERNEL_THREAD_OBJECT* lpKernelThread = NULL;
__KERNEL_THREAD_CONTEXT* lpContext = NULL;
BYTE strThread[12];
DWORD dwThread = 0L;
DWORD dwFlags = 0L;
lpKernelThread = (__KERNEL_THREAD_OBJECT*)
KernelThreadManager.lpReadyQueue->GetHeaderElement(
(__COMMON_OBJECT*)KernelThreadManager.lpReadyQueue,
NULL);
if(NULL == lpKernelThread) //If this case occurs,the system may crash.
{
PrintLine("In ChangeContext routine.");
PrintLine(lpszCriticalMsg);
PrintLine("Current kernel thread: ");
strThread[0] = ' ';
strThread[1] = ' ';
strThread[2] = ' ';
strThread[3] = ' ';
dwThread = (DWORD)KernelThreadManager.lpCurrentKernelThread;
Hex2Str(dwThread,&strThread[4]);
PrintLine(strThread);
return;
}
lpContext = &lpKernelThread->KernelThreadContext;
//ENTER_CRITICAL_SECTION(); //Here,the interrupt must be disabled.
__ENTER_CRITICAL_SECTION(NULL,dwFlags)
lpKernelThread->dwThreadStatus = KERNEL_THREAD_STATUS_RUNNING;
KernelThreadManager.lpCurrentKernelThread = lpKernelThread;
SwitchTo(lpContext);
}
//ScheduleFromInt's implementation.
static VOID ScheduleFromInt(__COMMON_OBJECT* lpThis,LPVOID lpESP)
{
__KERNEL_THREAD_OBJECT* lpNextThread = NULL;
__KERNEL_THREAD_OBJECT* lpCurrentThread = NULL;
__KERNEL_THREAD_MANAGER* lpMgr = NULL;
__KERNEL_THREAD_CONTEXT* lpContext = NULL;
if((NULL == lpThis) || (NULL == lpESP)) //Parameters check.
return;
lpMgr = (__KERNEL_THREAD_MANAGER*)lpThis;
if(NULL == lpMgr->lpCurrentKernelThread) //The routine is called first time in the
//initialization process.
//In this case,the routine does not need
//to save the current kernel's context,
//it only fetch the first ready kernel thread
//from Ready Queue,and switch to this kernel
//thread.
{
lpNextThread = (__KERNEL_THREAD_OBJECT*)KernelThreadManager.lpReadyQueue->GetHeaderElement(
(__COMMON_OBJECT*)KernelThreadManager.lpReadyQueue,
NULL);
if(NULL == lpNextThread) //If this case is occurs,the system is crash.
{
PrintLine("In ScheduleFromInt,lpCurrentKernelThread == NULL.");
PrintLine(lpszCriticalMsg);
return;
}
//ENTER_CRITICAL_SECTION();
KernelThreadManager.lpCurrentKernelThread = lpNextThread; //Update the current kernel
//thread pointer.
lpNextThread->dwThreadStatus = KERNEL_THREAD_STATUS_RUNNING; //Update the status.
//LEAVE_CRITICAL_SECTION();
lpContext = &lpNextThread->KernelThreadContext;
SwitchTo(lpContext); //Switch to the next kernel thread.
}
else //The routine is called in the running process
//of a kernel thread.
//The current kernel thread is determind by
//lpCurrentKernelThread member of Kernel Thread
//Manager.
//In this case,the routine saves the current
//kernel thread's context,fetches the first
//ready kernel thread,and switch to this kernel
//thread.
{
lpCurrentThread = KernelThreadManager.lpCurrentKernelThread;
lpContext = &lpCurrentThread->KernelThreadContext;
SaveContext(lpContext,(DWORD*)lpESP); //Save the current kernel thread's context.
switch(lpCurrentThread->dwThreadStatus)
{
case KERNEL_THREAD_STATUS_BLOCKED: //If the current kernel thread's status is
//BLOCKED,it means that the kernel thread
//is waiting for some shared resources,before
//the thread be put into BLOCKED queue,a timer
//interrupt occurs,but the kernel thread's
//status has been modified to BLOCKED.
//In this case,the kernel thread should not
//be put into READY queue,only restore it's
//context to continue to run.
//ENTER_CRITICAL_SECTION();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -