Beispiel #1
0
/**
 *  스캔 코드를 내부적으로 사용하는 키 데이터로 바꾼 후 키 큐에 삽입
 */
BOOL kConvertScanCodeAndPutQueue( BYTE bScanCode )
{
    KEYDATA stData;
    BOOL bResult = FALSE;
    BOOL bPreviousInterrupt;

    // 스캔 코드를 키 데이터에 삽입
    stData.bScanCode = bScanCode;
    
    // 스캔 코드를 ASCII 코드와 키 상태로 변환하여 키 데이터에 삽입
    if( kConvertScanCodeToASCIICode( bScanCode, &( stData.bASCIICode ), 
            &( stData.bFlags ) ) == TRUE )
    {
        // 임계 영역 시작
        bPreviousInterrupt = kLockForSystemData();
        
        // 키 큐에 삽입
        bResult = kPutQueue( &gs_stKeyQueue, &stData );

        // 임계 영역 끝
        kUnlockForSystemData( bPreviousInterrupt );
    }
    
    return bResult;
}
Beispiel #2
0
/**
 *  인터럽트가 발생했을 때, 다른 태스크를 찾아 전환
 *      반드시 인터럽트나 예외가 발생했을 때 호출해야 함
 */
BOOL kScheduleInInterrupt( void )
{
    TCB* pstRunningTask, * pstNextTask;
    char* pcContextAddress;
    BOOL bPreviousFlag;
    
    // 임계 영역 시작
    bPreviousFlag = kLockForSystemData();
    
    // 전환할 태스크가 없으면 종료
    pstNextTask = kGetNextTaskToRun();
    if( pstNextTask == NULL )
    {
        // 임계 영역 끝
        kUnlockForSystemData( bPreviousFlag );
        return FALSE;
    }
    
    //==========================================================================
    //  태스크 전환 처리   
    //      인터럽트 핸들러에서 저장한 콘텍스트를 다른 콘텍스트로 덮어쓰는 방법으로 처리
    //==========================================================================
    pcContextAddress = ( char* ) IST_STARTADDRESS + IST_SIZE - sizeof( CONTEXT );
    
    // 현재 수행중인 태스크의 정보를 수정한 뒤 콘텍스트 전환
    pstRunningTask = gs_stScheduler.pstRunningTask;
    gs_stScheduler.pstRunningTask = pstNextTask;

    // 유휴 태스크에서 전환되었다면 사용한 Tick Count를 증가시킴
    if( ( pstRunningTask->qwFlags & TASK_FLAGS_IDLE ) == TASK_FLAGS_IDLE )
    {
        gs_stScheduler.qwSpendProcessorTimeInIdleTask += TASK_PROCESSORTIME;
    }    
    
    // 태스크 종료 플래그가 설정된 경우, 콘텍스트를 저장하지 않고 대기 리스트에만 삽입
    if( pstRunningTask->qwFlags & TASK_FLAGS_ENDTASK )
    {    
        kAddListToTail( &( gs_stScheduler.stWaitList ), pstRunningTask );
    }
    // 태스크가 종료되지 않으면 IST에 있는 콘텍스트를 복사하고, 현재 태스크를 준비 리스트로
    // 옮김
    else
    {
        kMemCpy( &( pstRunningTask->stContext ), pcContextAddress, sizeof( CONTEXT ) );
        kAddTaskToReadyList( pstRunningTask );
    }
    // 임계 영역 끝
    kUnlockForSystemData( bPreviousFlag );

    // 전환해서 실행할 태스크를 Running Task로 설정하고 콘텍스트를 IST에 복사해서
    // 자동으로 태스크 전환이 일어나도록 함
    kMemCpy( pcContextAddress, &( pstNextTask->stContext ), sizeof( CONTEXT ) );
    
    // 프로세서 사용 시간을 업데이트
    gs_stScheduler.iProcessorTime = TASK_PROCESSORTIME;
    return TRUE;
}
Beispiel #3
0
/**
 *  다른 태스크를 찾아서 전환
 *      인터럽트나 예외가 발생했을 때 호출하면 안됨
 */
void kSchedule( void )
{
    TCB* pstRunningTask, * pstNextTask;
    BOOL bPreviousFlag;
    
    // 전환할 태스크가 있어야 함
    if( kGetReadyTaskCount() < 1 )
    {
        return ;
    }
    
    // 전환하는 도중 인터럽트가 발생하여 태스크 전환이 또 일어나면 곤란하므로 전환하는 
    // 동안 인터럽트가 발생하지 못하도록 설정
    // 임계 영역 시작
    bPreviousFlag = kLockForSystemData();
    
    // 실행할 다음 태스크를 얻음
    pstNextTask = kGetNextTaskToRun();
    if( pstNextTask == NULL )
    {
        // 임계 영역 끝
        kUnlockForSystemData( bPreviousFlag );
        return ;
    }
    
    // 현재 수행중인 태스크의 정보를 수정한 뒤 콘텍스트 전환
    pstRunningTask = gs_stScheduler.pstRunningTask; 
    gs_stScheduler.pstRunningTask = pstNextTask;
    
    // 유휴 태스크에서 전환되었다면 사용한 프로세서 시간을 증가시킴
    if( ( pstRunningTask->qwFlags & TASK_FLAGS_IDLE ) == TASK_FLAGS_IDLE )
    {
        gs_stScheduler.qwSpendProcessorTimeInIdleTask += 
            TASK_PROCESSORTIME - gs_stScheduler.iProcessorTime;
    }
    
    // 태스크 종료 플래그가 설정된 경우 콘텍스트를 저장할 필요가 없으므로, 대기 리스트에
    // 삽입하고 콘텍스트 전환
    if( pstRunningTask->qwFlags & TASK_FLAGS_ENDTASK )
    {
        kAddListToTail( &( gs_stScheduler.stWaitList ), pstRunningTask );
        kSwitchContext( NULL, &( pstNextTask->stContext ) );
    }
    else
    {
        kAddTaskToReadyList( pstRunningTask );
        kSwitchContext( &( pstRunningTask->stContext ), &( pstNextTask->stContext ) );
    }

    // 프로세서 사용 시간을 업데이트
    gs_stScheduler.iProcessorTime = TASK_PROCESSORTIME;

    // 임계 영역 끝
    kUnlockForSystemData( bPreviousFlag );
}
Beispiel #4
0
/**
 *  현재 수행 중인 태스크를 설정
 */
void kSetRunningTask( TCB* pstTask )
{
    BOOL bPreviousFlag;
    
    // 임계 영역 시작
    bPreviousFlag = kLockForSystemData();

    gs_stScheduler.pstRunningTask = pstTask;

    // 임계 영역 끝
    kUnlockForSystemData( bPreviousFlag );
}
Beispiel #5
0
/**
 *  태스크를 종료
 */
BOOL kEndTask( QWORD qwTaskID )
{
    TCB* pstTarget;
    BYTE bPriority;
    BOOL bPreviousFlag;
    
    // 임계 영역 시작
    bPreviousFlag = kLockForSystemData();
    
    // 현재 실행중인 태스크이면 EndTask 비트를 설정하고 태스크를 전환
    pstTarget = gs_stScheduler.pstRunningTask;
    if( pstTarget->stLink.qwID == qwTaskID )
    {
        pstTarget->qwFlags |= TASK_FLAGS_ENDTASK;
        SETPRIORITY( pstTarget->qwFlags, TASK_FLAGS_WAIT );
        
        // 임계 영역 끝
        kUnlockForSystemData( bPreviousFlag );
        
        kSchedule();

        // 태스크가 전환 되었으므로 아래 코드는 절대 실행되지 않음
        while( 1 ) ;
    }
    // 실행 중인 태스크가 아니면 준비 큐에서 직접 찾아서 대기 리스트에 연결
    else
    {
        // 준비 리스트에서 태스크를 찾지 못하면 직접 태스크를 찾아서 태스크 종료 비트를
        // 설정
        pstTarget = kRemoveTaskFromReadyList( qwTaskID );
        if( pstTarget == NULL )
        {
            // 태스크 ID로 직접 찾아서 설정
            pstTarget = kGetTCBInTCBPool( GETTCBOFFSET( qwTaskID ) );
            if( pstTarget != NULL )
            {
                pstTarget->qwFlags |= TASK_FLAGS_ENDTASK;
                SETPRIORITY( pstTarget->qwFlags, TASK_FLAGS_WAIT );
            }
            // 임계 영역 끝
            kUnlockForSystemData( bPreviousFlag );
            return TRUE;
        }
        
        pstTarget->qwFlags |= TASK_FLAGS_ENDTASK;
        SETPRIORITY( pstTarget->qwFlags, TASK_FLAGS_WAIT );
        kAddListToTail( &( gs_stScheduler.stWaitList ), pstTarget );
    }
    // 임계 영역 끝
    kUnlockForSystemData( bPreviousFlag );
    return TRUE;
}
Beispiel #6
0
/**
 *  키 큐에서 데이터를 제거
 */
BOOL kGetKeyFromKeyQueue( KEYDATA* pstData )
{
    BOOL bResult;
    BOOL bPreviousInterrupt;
    
    // 임계 영역 시작
    bPreviousInterrupt = kLockForSystemData();

    bResult = kGetQueue( &gs_stKeyQueue, pstData );

    // 임계 영역 끝
    kUnlockForSystemData( bPreviousInterrupt );
    return bResult;
}
Beispiel #7
0
/**
 *  태스크를 생성
 *      태스크 ID에 따라서 스택 풀에서 스택 자동 할당
 */
TCB* kCreateTask( QWORD qwFlags, QWORD qwEntryPointAddress )
{
    TCB* pstTask;
    void* pvStackAddress;
    BOOL bPreviousFlag;
    
    // 임계 영역 시작
    bPreviousFlag = kLockForSystemData();    
    pstTask = kAllocateTCB();
    if( pstTask == NULL )
    {
        // 임계영역 끝
        kUnlockForSystemData( bPreviousFlag );
        return NULL;
    }
    // 임계 영역 끝
    kUnlockForSystemData( bPreviousFlag );
    
    // 태스크 ID로 스택 어드레스 계산, 하위 32비트가 스택 풀의 오프셋 역할 수행
    pvStackAddress = ( void* ) ( TASK_STACKPOOLADDRESS + ( TASK_STACKSIZE * 
            GETTCBOFFSET( pstTask->stLink.qwID ) ) );
    
    // TCB를 설정한 후 준비 리스트에 삽입하여 스케줄링될 수 있도록 함
    kSetUpTask( pstTask, qwFlags, qwEntryPointAddress, pvStackAddress, 
            TASK_STACKSIZE );

    // 임계 영역 시작
    bPreviousFlag = kLockForSystemData();
    
    // 태스크를 준비 리스트에 삽입
    kAddTaskToReadyList( pstTask );
    
    // 임계 영역 끝
    kUnlockForSystemData( bPreviousFlag );
    
    return pstTask;
}
Beispiel #8
0
/**
 *  현재 수행 중인 태스크를 반환
 */
TCB* kGetRunningTask( void )
{
    BOOL bPreviousFlag;
    TCB* pstRunningTask;
    
    // 임계 영역 시작
    bPreviousFlag = kLockForSystemData();
    
    pstRunningTask = gs_stScheduler.pstRunningTask;
    
    // 임계 영역 끝
    kUnlockForSystemData( bPreviousFlag );

    return pstRunningTask;
}
Beispiel #9
0
/**
 *  태스크의 우선 순위를 변경함
 */
BOOL kChangePriority( QWORD qwTaskID, BYTE bPriority )
{
    TCB* pstTarget;
    BOOL bPreviousFlag;
    
    if( bPriority > TASK_MAXREADYLISTCOUNT )
    {
        return FALSE;
    }
    
    // 임계 영역 시작
    bPreviousFlag = kLockForSystemData();
    
    // 현재 실행중인 태스크이면 우선 순위만 변경
    // PIT 컨트롤러의 인터럽트(IRQ 0)가 발생하여 태스크 전환이 수행될 때 변경된 
    // 우선 순위의 리스트로 이동
    pstTarget = gs_stScheduler.pstRunningTask;
    if( pstTarget->stLink.qwID == qwTaskID )
    {
        SETPRIORITY( pstTarget->qwFlags, bPriority );
    }
    // 실행중인 태스크가 아니면 준비 리스트에서 찾아서 해당 우선 순위의 리스트로 이동
    else
    {
        // 준비 리스트에서 태스크를 찾지 못하면 직접 태스크를 찾아서 우선 순위를 설정
        pstTarget = kRemoveTaskFromReadyList( qwTaskID );
        if( pstTarget == NULL )
        {
            // 태스크 ID로 직접 찾아서 설정
            pstTarget = kGetTCBInTCBPool( GETTCBOFFSET( qwTaskID ) );
            if( pstTarget != NULL )
            {
                // 우선 순위를 설정
                SETPRIORITY( pstTarget->qwFlags, bPriority );
            }
        }
        else
        {
            // 우선 순위를 설정하고 준비 리스트에 다시 삽입
            SETPRIORITY( pstTarget->qwFlags, bPriority );
            kAddTaskToReadyList( pstTarget );
        }
    }
    // 임계 영역 끝
    kUnlockForSystemData( bPreviousFlag );
    return TRUE;    
}
Beispiel #10
0
BOOL kGetKeyFromKeyQueue( KEYDATA* pstData )
{
	BOOL bResult;
	BOOL bPreviousFlag;

	if( kIsQueueEmpty( &gs_stKeyQueue ) == TRUE )
	{
		return FALSE;
	}

	bPreviousFlag = kLockForSystemData();

	bResult = kGetQueue( &gs_stKeyQueue, pstData );

	kUnlockForSystemData( bPreviousFlag );
	return bResult;
}
Beispiel #11
0
BOOL kConvertScanCodeAndPutQueue( BYTE bScanCode )
{
	KEYDATA stData;
	BOOL bResult;
	BOOL bPreviousFlag;

	stData.bScanCode = bScanCode;

	if( kConvertScanCodeToASCIICode( bScanCode, &( stData.bASCIICode ), &( stData.bFlags ) ) )
	{
		bPreviousFlag = kLockForSystemData();
		bResult = kPutQueue( &gs_stKeyQueue, &stData );
		kUnlockForSystemData( bPreviousFlag );
	}

	return bResult;
}
Beispiel #12
0
/**
 *  전체 태스크의 수를 반환
 */ 
int kGetTaskCount( void )
{
    int iTotalCount;
    BOOL bPreviousFlag;
    
    // 준비 큐의 태스크 수를 구한 후, 대기 큐의 태스크 수와 현재 수행 중인 태스크 수를 더함
    iTotalCount = kGetReadyTaskCount();
    
    // 임계 영역 시작
    bPreviousFlag = kLockForSystemData();
    
    iTotalCount += kGetListCount( &( gs_stScheduler.stWaitList ) ) + 1;

    // 임계 영역 끝
    kUnlockForSystemData( bPreviousFlag );
    return iTotalCount;
}
Beispiel #13
0
/**
 *  준비 큐에 있는 모든 태스크의 수를 반환
 */
int kGetReadyTaskCount( void )
{
    int iTotalCount = 0;
    int i;
    BOOL bPreviousFlag;

    // 임계 영역 시작
    bPreviousFlag = kLockForSystemData();

    // 모든 준비 큐를 확인하여 태스크 개수를 구함
    for( i = 0 ; i < TASK_MAXREADYLISTCOUNT ; i++ )
    {
        iTotalCount += kGetListCount( &( gs_stScheduler.vstReadyList[ i ] ) );
    }
    
    // 임계 영역 끝
    kUnlockForSystemData( bPreviousFlag );
    return iTotalCount ;
}
Beispiel #14
0
/**
 *  키 큐에서 키 데이터를 제거
 */
BOOL kGetKeyFromKeyQueue( KEYDATA* pstData )
{
    BOOL bResult;
    BOOL bPreviousInterrupt;
    
    // 큐가 비었으면 키 데이터를 꺼낼 수 없음
    if( kIsQueueEmpty( &gs_stKeyQueue ) == TRUE )
    {
        return FALSE;
    }

    // 임계 영역 시작
    bPreviousInterrupt = kLockForSystemData();

    // 키 큐에서 키 데이터를 제거
    bResult = kGetQueue( &gs_stKeyQueue, pstData );

    // 임계 영역 끝
    kUnlockForSystemData( bPreviousInterrupt );
    return bResult;
}
Beispiel #15
0
/**
 *  유휴 태스크
 *      대기 큐에 삭제 대기중인 태스크를 정리
 */
void kIdleTask( void )
{
    TCB* pstTask;
    QWORD qwLastMeasureTickCount, qwLastSpendTickInIdleTask;
    QWORD qwCurrentMeasureTickCount, qwCurrentSpendTickInIdleTask;
    BOOL bPreviousFlag;
    QWORD qwTaskID;

    // 프로세서 사용량 계산을 위해 기준 정보를 저장
    qwLastSpendTickInIdleTask = gs_stScheduler.qwSpendProcessorTimeInIdleTask;
    qwLastMeasureTickCount = kGetTickCount();
    
    while( 1 )
    {
        // 현재 상태를 저장
        qwCurrentMeasureTickCount = kGetTickCount();
        qwCurrentSpendTickInIdleTask = gs_stScheduler.qwSpendProcessorTimeInIdleTask;
        
        // 프로세서 사용량을 계산
        // 100 - ( 유휴 태스크가 사용한 프로세서 시간 ) * 100 / ( 시스템 전체에서 
        // 사용한 프로세서 시간 )
        if( qwCurrentMeasureTickCount - qwLastMeasureTickCount == 0 )
        {
            gs_stScheduler.qwProcessorLoad = 0;
        }
        else
        {
            gs_stScheduler.qwProcessorLoad = 100 - 
                ( qwCurrentSpendTickInIdleTask - qwLastSpendTickInIdleTask ) * 
                100 /( qwCurrentMeasureTickCount - qwLastMeasureTickCount );
        }
        
        // 현재 상태를 이전 상태에 보관
        qwLastMeasureTickCount = qwCurrentMeasureTickCount;
        qwLastSpendTickInIdleTask = qwCurrentSpendTickInIdleTask;

        // 프로세서의 부하에 따라 쉬게 함
        kHaltProcessorByLoad();
        
        // 대기 큐에 대기중인 태스크가 있으면 태스크를 종료함
        if( kGetListCount( &( gs_stScheduler.stWaitList ) ) >= 0 )
        {
            while( 1 )
            {
                // 임계 영역 시작
                bPreviousFlag = kLockForSystemData();                
                pstTask = kRemoveListFromHeader( &( gs_stScheduler.stWaitList ) );
                if( pstTask == NULL )
                {
                    // 임계 영역 끝
                    kUnlockForSystemData( bPreviousFlag );
                    break;
                }
                qwTaskID = pstTask->stLink.qwID;
                kFreeTCB( qwTaskID );
                // 임계 영역 끝
                kUnlockForSystemData( bPreviousFlag );
                
                kPrintf( "IDLE: Task ID[0x%q] is completely ended.\n", 
                        qwTaskID );
            }
        }
        
        kSchedule();
    }
}