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

📄 mt2_thread.c

📁 小型操作系统,以VC为开发环境,需要boachs调试
💻 C
字号:
/***************************************************************************
**     File name   : mt2_thread.c
**     Author      : x.cheng
**     Create date :
**
**	   Comment:
**        function for thread management
**
**     Revisions:
**     $Log: mt2_thread.c,v $
**     Revision 1.2  2005/07/27 07:19:35  x.cheng
**     bug fix - save father's privilege level to iPrivilege
**
**     Revision 1.1.1.1  2005/07/27 06:53:15  x.cheng
**     add into repositories
**
**
***************************************************************************/
#include "const.h"
#include "type.h"
#include "stdarg.h"
#include "stdlib.h"

#include "string.h"
#include "queue.h"
#include "..\..\inc\i386\page.h"		//kernel\inc\i386
#include "..\..\inc\i386\x86.h"
#include "..\..\inc\i386\system.h"
#include "..\..\inc\task.h"			//kernel\inc
#include "..\..\inc\mts.h"
#include "..\..\inc\tui.h" 
#include "..\..\inc\debug.h"

#define __USER_SPACE_ALLOCTOR__
#include "..\..\inc\vmm.h"
#define __MTS_SRC__
#include "..\inc\def_mts.h"
#include "..\inc\def_sched.h"


/* debug preprocessor instrument
	#ifdef _DEBUG__
	#ifdef _DEBUG_MTS__
				
	#endif
	#endif	
***************************/

/************************************************************
*************************************************************
**      Function Name:			pstMt2CreateThread
**      Author:                 x.cheng
**
**      Comment:
**			reate a new thread of a process.
**
**      List of parameters:
**			pvRoutine - The address of the entry point for the thread.
**			szName	- The name of the new task
**
**      Return value:   
**          A pointer to the new-created thread structure.
**			error: NULL If an error occurs (in particular out-of-memory)
**
**      Revisions:
**			This routine must be executed in mutual exclusion, because if
**		the current task is killed during the thread creation, the
**		space allocated before will be lost.
*************************************************************
*************************************************************/
ts_Task* pstMt2CreateThread(void *pvRoutine, char *szName)
{
	ts_Task* pstNewThread, *pstFatherProcess;
	int iPrivilege;

	if ( NULL==g_pstCurrentTask )
		return NULL;

	#ifdef _DEBUG__
	#ifdef _DEBUG_MTS__
		kprintf("create thread, name= %s, routine at= %p\n", szName, pvRoutine);
		Mt5BrowserQueue(&g_pstWaitQueue, "Wait");
	#endif 
	#endif	
	
	vScheduleEnterCritialRegion();

	// --- Create the task structure ------------------------------ //
	//!
	//! IA-32 Intel(R) Architecture Software Developer's Manual
	//! Volume 3: System Programming Guide - Chapter 6 - reports:
	//!
	//! "If paging is used, care should be taken to avoid placing a
	//! page boundary within the part of the TSS that the processor
	//! reads during a task switch (the first 104 bytes). If a page
	//! boundary is placed within this part of the TSS, the pages on
	//! either side of the boundary must be present at the same time
	//! and contiguous in physical memory.
	//! 
	//! 在发生任务切换的时候,CPU 总是读TSS段开始的物理地址连续的104个字节,
	//! 在读取这些字节的时候,可能并不使用分页转换。因此如果分配的给TSS
	//! 的物理内存不连续(跨页)的话,则为将来的任务切换埋下了隐患...
	pstNewThread = pvVmmKeAlignMalloc( PAGE_SIZE, sizeof(ts_Task), GFP_KERNEL );
		//pstNewTask的地址总是在PAGE_SIZE界上开始,比如0xD0001000
	if (pstNewThread == NULL) {
		//out of virtua memory
	#ifdef _DEBUG__
	#ifdef _DEBUG_MTS__
		kprintf("%s: cannot allocate task structure for '%s'\n", __FUNCTION__, szName);
	#endif 
	#endif	
		vScheduleLeaveCriticalRegion();
		return NULL;
	}
	
	// Add the task into the zombie queue, so if the current task
	// is killed the space allocated until now can be freed by the
	// kpager daemon.
	iAddQueueNode(&g_pstZombieQueue, pstNewThread);
	pstNewThread->ucState = TASK_STATE_NEW;

	// Create the kernel(Ring0) stack.
	pstNewThread->ulRing0Stack = (unsigned long)pvVmmKeMalloc(TASK_KERNEL_STACK_SIZE, GFP_KERNEL);
	if ( NULL == pstNewThread->ulRing0Stack ) {
	#ifdef _DEBUG__
	#ifdef _DEBUG_MTS__
		kprintf("%s: cannot allocate Ring0 stack for '%s'\n", __FUNCTION__, szName);
	#endif
	#endif
		vVmmKeFree(pstNewThread);
		vScheduleLeaveCriticalRegion();
		return NULL;
	}
	#ifdef _DEBUG__
	#ifdef _DEBUG_MTS__
		kprintf("%s: pstNewThread->ulRing0Stack =%p\n", __FUNCTION__, pstNewThread->ulRing0Stack);
	#endif
	#endif

	
	// Zero the stack..
	memset( (void *)pstNewThread->ulRing0Stack, 0, TASK_KERNEL_STACK_SIZE);
	
	// Setup the privileged stack in tss.
	// when switch to ring0, stack is different with ring3(user mode) one.
	pstNewThread->stTSS.ss0 = KERNEL_STACK;
	pstNewThread->stTSS.esp0 = ulAlignDown(
		(unsigned long)(pstNewThread->ulRing0Stack) + TASK_KERNEL_STACK_SIZE - sizeof(unsigned long),	sizeof(unsigned long) );

	#ifdef _DEBUG__
	#ifdef _DEBUG_MTS__
		kprintf("%s: pstNewThread->stTSS.esp0  =%p\n", __FUNCTION__, pstNewThread->stTSS.esp0 );
		kprintf("sizeof(ts_TSS_IO)=%x, &pstNewThread->stTSS=%p, ACS_TSSSEG=%x\n", sizeof(ts_TSS_IO),
				&pstNewThread->stTSS, ACS_TSSSEG);
	#endif
	#endif

	
	// Setup the TSS
	pstNewThread->uiTssSelector = uiSetupGdtEntry(sizeof(ts_TSS_IO), (unsigned long)&pstNewThread->stTSS, ACS_TSSSEG, 0);
	if ( NULL == pstNewThread->uiTssSelector ) {
	#ifdef _DEBUG__
	#ifdef _DEBUG_MTS__
		kprintf("%s: out of GDT entrys!!!can't create task '%s'\n", __FUNCTION__, szName);
	#endif
	#endif
		vVmmKeFree(pstNewThread);
		vVmmKeFree( (void *)pstNewThread->ulRing0Stack );
		vScheduleLeaveCriticalRegion();

		return NULL;
	}
	#ifdef _DEBUG__
	#ifdef _DEBUG_MTS__
		kprintf("%s: pstNewThread->uiTssSelector  =%x\n", __FUNCTION__, pstNewThread->uiTssSelector );
	#endif
	#endif

	// set the task type
	pstNewThread->stFlags.Type = TASK_TYPE_THREAD;
	// get father's privilege level(KERNEL_PRIVILEGE or USER_PRIVILEGE)
	iPrivilege = pstNewThread->iPrivilege = g_pstCurrentTask->iPrivilege;

	// Get the first process between all the parents of the
	// current thread. This is necessary to setup properly
	// the user space. Remember that every thread share the
	// same address space.
	pstFatherProcess = g_pstCurrentTask;
	#ifdef _DEBUG__
	#ifdef _DEBUG_MTS__
		kprintf("pstFatherProcess at %p, ->szName= %s, ->stFlags.Type= %d\n", pstFatherProcess, pstFatherProcess->szName,pstFatherProcess->stFlags.Type);
		vDbgDummy();
	#endif
	#endif
	while( pstFatherProcess->stFlags.Type == TASK_TYPE_THREAD ) {
		pstFatherProcess = pstFatherProcess->pstFather;
	}
	
	// Setup the thread heap equal to the father's heap.
	pstNewThread->ulHeapStart = pstFatherProcess->ulHeapStart;
	pstNewThread->ulHeapSize = pstFatherProcess->ulHeapSize;

	// Setup the task address space.
	pstNewThread->stTSS.cr3 = pstFatherProcess->stTSS.cr3;
	#ifdef _DEBUG__
	#ifdef _DEBUG_MTS__
	kprintf("pstNewThread->stTSS.cr3 = %08x\n", pstNewThread->stTSS.cr3);
	vDbgDummy();	//dummy function for break point assertion...
	#endif
	#endif

	// Get the same page directory of the father.
	pstNewThread->pulPdbr = pstFatherProcess->pulPdbr;
	// Get the same pdbr counter of the father.
	pstNewThread->ulPdbrUpdateCounter = pstFatherProcess->ulPdbrUpdateCounter;

	//create the task stack
	pstNewThread->stTSS.ss = (iPrivilege == KERNEL_PRIVILEGE) ? KERNEL_STACK : USER_STACK | 3;
	if ( KERNEL_PRIVILEGE == iPrivilege ) {
		pstNewThread->stTSS.esp = (unsigned long)pulMt5SetupStack( pstNewThread->stTSS.esp0+sizeof(unsigned long) );

	} else {
		// Put the thread's stack in the heap.
		//pstNewThread->ulRing3Stack = (unsigned long) umalloc( STACK_SIZE );
		//未完待续...
		PANIC();
	}
	#ifdef _DEBUG__
	#ifdef _DEBUG_MTS__
	kprintf("pstNewThread->stTSS.ss = %04x\tpstNewThread->stTSS.esp = %08x\n", pstNewThread->stTSS.ss, pstNewThread->stTSS.esp);
	vDbgDummy();	//dummy function for break point assertion...
	#endif
	#endif

	//setup the io port mapping
	pstNewThread->stTSS.uiIoMapAddr = sizeof(ts_TSS);
	memsetl( pstNewThread->stTSS.aulIoMap, 0xFFFFFFFF, IO_MAP_SIZE);

	// Setup general registers.
	if ( iPrivilege == KERNEL_PRIVILEGE ) {
		pstNewThread->stTSS.ds = pstNewThread->stTSS.es = 
		pstNewThread->stTSS.fs = pstNewThread->stTSS.gs = KERNEL_DATA;
	} else {
		pstNewThread->stTSS.ds = pstNewThread->stTSS.es = 
		pstNewThread->stTSS.fs = pstNewThread->stTSS.gs = USER_DATA | 3;
	}

	// setup the eflags register.
	pstNewThread->stTSS.eflags = EFLAGS_IOPL0 | EFLAGS_IF | 0x02;

	// setup the starting address(program counter).
	pstNewThread->stTSS.cs = (iPrivilege == KERNEL_PRIVILEGE) ? KERNEL_CODE : USER_CODE | 3;
	pstNewThread->stTSS.eip = (unsigned long)pvRoutine;

	// store the process's name
	strncpy( pstNewThread->szName, szName, sizeof(pstNewThread->szName)-2 );
	// Set the process credentials.
	pstNewThread->iPid = iMt5GeneratePid();
		//id setup...

	// set the parent
	pstNewThread->pstFather = g_pstCurrentTask;

	// set the console
	pstNewThread->iConsole = g_pstCurrentTask->iConsole;
	// set the priority
	pstNewThread->iPriority = pstNewThread->iCounter = HIGH_PRIORITY;

	// insert the task to the ready queue.
	iRemoveQueueNode(&g_pstZombieQueue, pstNewThread);
	iAddQueueNode(&g_pstReadyQueue, pstNewThread);
	pstNewThread->ucState = TASK_STATE_READY;

	#ifdef _DEBUG__
	#ifdef _DEBUG_MTS__
	Mt5BrowserQueue(&g_pstZombieQueue, "Zombie");
	Mt5BrowserQueue(&g_pstWaitQueue, "Wait");
	Mt5BrowserQueue(&g_pstReadyQueue, "Ready");
	#endif
	#endif

	vScheduleLeaveCriticalRegion();

	// This is a little trick... Because we exit
	// from a very long critical region we call
	// the scheduler to enforce a new task selection.
	vMt3Schedule();

	return (pstNewThread);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -