📄 mt3_schedule.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 + -