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

📄 mt3_schedule.c

📁 小型操作系统,以VC为开发环境,需要boachs调试
💻 C
字号:
/***************************************************************************
**     File name   : mt3_schedule.c
**     Author      : x.cheng
**     Create date :
**
**	   Comment:
**        The scheduler function for process schedule
**
**     Revisions:
**     $Log: mt3_schedule.c,v $
**     Revision 1.2  2005/08/18 14:54:20  x.cheng
**     bug fix refreshqueue()
**
**     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\system.h"
#include "..\..\inc\spinlock.h"
#include "..\..\inc\pmm.h"
#include "..\..\inc\task.h"			//kernel\inc
#include "..\..\inc\pmm.h"
#include "..\..\inc\mts.h"
#include "..\..\inc\tui.h"

#include "..\inc\def_mts.h" 
#include "..\inc\def_sched.h"

/* debug preprocessor inst
	#ifdef _DEBUG__
	#ifdef _DEBUG_MTS__
				
	#endif
	#endif	
***************************/
/*****************global variable declaration***************/
//Current running task.
ts_Task *g_pstCurrentTask = NULL;
//IDLE task structure.
ts_Task *g_pstIdleTask = NULL;
//Ready-queue: tasks are ready for the CPU.
ts_QueueNode *g_pstReadyQueue = NULL;
//Wait-queue: tasks are waiting for I/O.
ts_QueueNode *g_pstWaitQueue = NULL;
//Zombie-queue: tasks are dying.
ts_QueueNode *g_pstZombieQueue = NULL;
/*************end*******************************************/

///////////////////////////////////////////////////////////////////
//! Spinlock to enable/disable scheduling.
DECLARE_SPINLOCK( stScheduleEnable );

//! inline function
// Disable the scheduling of the other tasks.
inline void vScheduleEnterCritialRegion( void )
{
	#ifdef _DEBUG__ 
	#ifdef _DEBUG_MTS__
//		kprintf("&stScheduleEnable= [%p], .ulLock= %ld\n", &stScheduleEnable, stScheduleEnable.ulLock);
//		HexDump(&stScheduleEnable, 16);
	#endif
	#endif
	if( SpinlockIsLocked( &stScheduleEnable ) ) {

	#ifdef _DEBUG__ 
	#ifdef _DEBUG_MTS__
		kprintf("%s(): deadlock at \"%s\"- %u line\n", __FUNCTION__, __FILE__, __LINE__);
	#endif
	#endif
	}
	SpinlockLock( &stScheduleEnable );
} 

//! inline function
// Enable scheduling for the other tasks.
inline void vScheduleLeaveCriticalRegion( void )
{
	SpinlockUnlock( &stScheduleEnable );
}

//! inline function
// Check if the scheduling is enabled.
inline int iScheduleIsDisable( void )
{
	return( SpinlockIsLocked(&stScheduleEnable) );
}
 
//! A flag to invoke a refresh of the task queues.
ts_Atomic stRefreshQueueFlag = TO_ATOMIC( 0 );

/************************************************************
*************************************************************
**      Function Name:			vMt3RefreshQueues()
**      Author:                 x.cheng
**
**      Comment:
**			Update all task queue
**
**      List of parameters:
**
**      Return value:   
**
**      Revisions:
**
*************************************************************
*************************************************************/
inline void vMt3RefreshQueues()
{
	ts_QueueNode *pstNode, *pstNodeNext;
	ts_Task *pstTask;
	int iCnt;

/*
#define queue_for_each_safe( pos, n, c, head ) \
	if( (head) != NULL ) \
		for( pos = (head), n = pos->next, \
			c = count_queue( &(head) ); \
			c--; \
			pos = n, n = pos->next )
*/
	// Look into the ready queue for the tasks that need to
	// be waked-up and to be killed.
	if ( NULL !=g_pstReadyQueue ) {
/*		//代替成下面的形式更安全
		for (pstNode=g_pstReadyQueue, iCnt=iCountQueueElement(ppstHeadNode);
			iCnt--; pstNode=pstNode->pstNext)
*/
		for (pstNode=g_pstReadyQueue, pstNodeNext=pstNode->pstNext, iCnt=iCountQueueElement(&g_pstReadyQueue);
			iCnt--; pstNode=pstNodeNext, pstNodeNext=pstNode->pstNext) {
			pstTask = (NULL != pstNode) ? pstNode->pvVal : NULL;
			if ( pstTask->ucState == TASK_STATE_WAIT ) {
				iMoveNodeBetweenQueue(&g_pstWaitQueue, &g_pstReadyQueue, pstNode);
			} else if ( pstTask->ucState == TASK_STATE_ZOMBIE ) {
				iMoveNodeBetweenQueue(&g_pstZombieQueue, &g_pstReadyQueue, pstNode);
				//wakeup_task( kpagd );
			}
		}
		
	}

	// Look into the wait queue for the tasks that need to
	// be waked-up and to be killed.
	if ( NULL !=g_pstWaitQueue ) {
/*		//代替成下面的形式更安全
		for (pstNode=g_pstReadyQueue, iCnt=iCountQueueElement(ppstHeadNode);
			iCnt--; pstNode=pstNode->pstNext)
*/
		for (pstNode=g_pstWaitQueue, pstNodeNext=pstNode->pstNext, iCnt=iCountQueueElement(&g_pstWaitQueue);
			iCnt--; pstNode=pstNodeNext, pstNodeNext=pstNode->pstNext) {
			pstTask = (NULL != pstNode) ? pstNode->pvVal : NULL;
			if ( pstTask->ucState == TASK_STATE_READY ) {
				iMoveNodeBetweenQueue(&g_pstReadyQueue, &g_pstWaitQueue, pstNode);
				pstTask->iCounter = (HIGH_PRIORITY << 1) + pstTask->iPriority;
			} else if ( pstTask->ucState == TASK_STATE_ZOMBIE ) {
				iMoveNodeBetweenQueue(&g_pstZombieQueue, &g_pstReadyQueue, pstNode);
				//wakeup_task( kpagd );
			}
		}
	}

	// Refresh done.
	SET_ATOMIC( &stRefreshQueueFlag, 0 );
}

/************************************************************
*************************************************************
**      Function Name:			vMt3SwitchToTask()
**      Author:                 x.cheng
**
**      Comment:
**			This routine supplies to change the context of the tasks.
**
**      List of parameters:
**
**      Return value:   
**
**      Revisions:
**
*************************************************************
*************************************************************/
inline void vMt3SwitchToTask(ts_Task *pstPrevTask, ts_Task *pstNextTask)
{
	// Perform the context switch only if it is necessary.
	if( pstPrevTask != pstNextTask ) {
		// Update the page directory for kernel address
		// space only if the update counter is different
		// between the prev and next task. Because prev
		// was the running task it is the most recently
		// updated task. So we don't have to check if the
		// counter is 'less than' the next task. Better to
		// check only if they are different...
		if( pstNextTask->ulPdbrUpdateCounter != pstPrevTask->ulPdbrUpdateCounter ) {
			// Update the page directory for kernel address space
			// only if it is necessary.
			// This must be done to preserve coherency between
			// page directories of each task.
			if( pstNextTask->stTSS.cr3 != pstPrevTask->stTSS.cr3 ) {
				// Ok... we have to update now!
				memcpy( pulPdeOffset(pstNextTask->pulPdbr, KERNEL_VIRTUAL_START),
					pulPdeOffset(pstPrevTask->pulPdbr, KERNEL_VIRTUAL_START),
				( ulPdeIndex(PAGE_DIR_TABLE_START_ADDRESS) - ulPdeIndex(KERNEL_VIRTUAL_START) ) * sizeof(unsigned long) );

			}
			// Update the pdbr counter.
			pstNextTask->ulPdbrUpdateCounter = pstPrevTask->ulPdbrUpdateCounter;
		}
		// Perform the hardware task switch.
		vJumpToTss(pstNextTask->uiTssSelector);	//static inline funciton in io.h
	}

}
/************************************************************
*************************************************************
**      Function Name:			vMt3Schedule
**      Author:                 x.cheng
**
**      Comment:
**			multitask scheduler, 
**				This routine is called every time a task must be scheduled. 
**
**      List of parameters:
**
**      Return value:   
**
**      Revisions:
**
*************************************************************
*************************************************************/
void vMt3Schedule()
{
	int iMinCounter = INT_MAX;

	unsigned long ulFlags;
	ts_Task *pstPrevTask, *pstNextTask;
	ts_QueueNode *pstNode;
	int iCnt;

	#ifdef _DEBUG__
	#ifdef _DEBUG_MTS__
	SaveEflagsAndCli(ulFlags);
//	kprintf("%s: enter schedule...\n", __FUNCTION__);
	vDbgDummy();	//enter schedule....
	RestoreEflags(ulFlags);
	#endif
	#endif	

	if ( iScheduleIsDisable() ) {
		// can't switch to another task, return to the oringinal
		return;
	}
	SaveEflagsAndCli(ulFlags);

	// Update all the task queue if necessary.
	if ( READ_ATOMIC(&stRefreshQueueFlag) ) {
		vMt3RefreshQueues();
	}

	// Save the previous task.
	pstPrevTask = g_pstCurrentTask;
	// Set the idle task as the default candidate to run.
	g_pstCurrentTask = g_pstIdleTask;

	// The scheduler's body.
	pstPrevTask->iCounter = pstPrevTask->iPriority;

/*
#define queue_for_each( pos, c, head ) \
	if( (head) != NULL ) \
		for( pos = (head), c = 0, prefetch(pos->next); \
			(pos != (head)) || !(c); \
			pos = pos->next, prefetch(pos->next), ++c )
*/
	if ( NULL != g_pstReadyQueue ) {
		for( pstNode=g_pstReadyQueue, iCnt=0; (pstNode != g_pstReadyQueue)||!iCnt;
			 pstNode=pstNode->pstNext, iCnt++) {
			pstNextTask = (NULL != pstNode) ? pstNode->pvVal : NULL;
			if ( pstNextTask->iCounter < iMinCounter ) {
				g_pstCurrentTask = pstNextTask;
				iMinCounter = g_pstCurrentTask->iCounter;
			}
			if ( pstNextTask->iCounter > (HIGH_PRIORITY << 1) ) {
				(pstNextTask->iCounter) -- ;
			}
		}
	}

	#ifdef _DEBUG__
	#ifdef _DEBUG_MTS__
//	kprintf("pstPrevTask=(%p|%s), g_pstCurrentTask=(%p|%s)\n",
//		pstPrevTask, pstPrevTask->szName, g_pstCurrentTask, g_pstCurrentTask->szName);
	#endif
	#endif	
//	Mt5BrowserQueue(&g_pstZombieQueue, "Zombie");
//	Mt5BrowserQueue(&g_pstWaitQueue, "Wait");
//	Mt5BrowserQueue(&g_pstReadyQueue, "Ready");

	// Switch from the previous to the next process.
	vMt3SwitchToTask( pstPrevTask, g_pstCurrentTask);

	RestoreEflags(ulFlags);

}

⌨️ 快捷键说明

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