⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ktmgr.cpp

📁 C写的小型操作系统源码
💻 CPP
📖 第 1 页 / 共 4 页
字号:

	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 + -