Exemplo n.º 1
0
/**
 *  태스크 2
 *      자신의 ID를 참고하여 특정 위치에 회전하는 바람개비를 출력
 */
void kTestTask2( void )
{
    int i = 0, iOffset;
    CHARACTER* pstScreen = ( CHARACTER* ) CONSOLE_VIDEOMEMORYADDRESS;
    TCB* pstRunningTask;
    char vcData[ 4 ] = { '-', '\\', '|', '/' };
    
    // 자신의 ID를 얻어서 화면 오프셋으로 사용
    pstRunningTask = kGetRunningTask();
    iOffset = ( pstRunningTask->stLink.qwID & 0xFFFFFFFF ) * 2;
    iOffset = CONSOLE_WIDTH * CONSOLE_HEIGHT - 
        ( iOffset % ( CONSOLE_WIDTH * CONSOLE_HEIGHT ) );

    while( 1 )
    {
        // 회전하는 바람개비를 표시
        pstScreen[ iOffset ].bCharactor = vcData[ i % 4 ];
        // 색깔 지정
        pstScreen[ iOffset ].bAttribute = ( iOffset % 15 ) + 1;
        i++;
        
        // 다른 태스크로 전환
        kSchedule();
    }
}
Exemplo n.º 2
0
// Task 2
// 		Along ID, print rotating character
void kTestTask2(void)
{
	int i = 0;
	int iOffset;
	CHARACTER * pstScreen = (CHARACTER *) CONSOLE_VIDEOMEMORYADDRESS;
	TCB * pstRunningTask;
	char vcData[4] = {'-', '\\', '|', '/'};
	
	// Get ID and use is as offset of monitor
	pstRunningTask = kGetRunningTask();
	iOffset = (pstRunningTask->stLink.qwID & 0xFFFFFFFF) * 2;
	iOffset = CONSOLE_WIDTH * CONSOLE_HEIGHT - (iOffset % (CONSOLE_WIDTH * CONSOLE_HEIGHT));
	
	while (1)
	{
		// Set rotating character
		pstScreen[iOffset].bCharactor = vcData[i % 4];
		// Set Color
		pstScreen[iOffset].bAttribute = (iOffset % 15) + 1;
		i++;
		
		// Switch task
		kSchedule();
	}
}
Exemplo n.º 3
0
/**
 *  태스크 1
 *      화면 테두리를 돌면서 문자를 출력
 */
void kTestTask1( void )
{
    BYTE bData;
    int i = 0, iX = 0, iY = 0, iMargin;
    CHARACTER* pstScreen = ( CHARACTER* ) CONSOLE_VIDEOMEMORYADDRESS;
    TCB* pstRunningTask;
    
    // 자신의 ID를 얻어서 화면 오프셋으로 사용
    pstRunningTask = kGetRunningTask();
    iMargin = ( pstRunningTask->stLink.qwID & 0xFFFFFFFF ) % 10;
    
    // 화면 네 귀퉁이를 돌면서 문자 출력
    while( 1 )
    {
        switch( i )
        {
        case 0:
            iX++;
            if( iX >= ( CONSOLE_WIDTH - iMargin ) )
            {
                i = 1;
            }
            break;
            
        case 1:
            iY++;
            if( iY >= ( CONSOLE_HEIGHT - iMargin ) )
            {
                i = 2;
            }
            break;
            
        case 2:
            iX--;
            if( iX < iMargin )
            {
                i = 3;
            }
            break;
            
        case 3:
            iY--;
            if( iY < iMargin )
            {
                i = 0;
            }
            break;
        }
        
        // 문자 및 색깔 지정
        pstScreen[ iY * CONSOLE_WIDTH + iX ].bCharactor = bData;
        pstScreen[ iY * CONSOLE_WIDTH + iX ].bAttribute = bData & 0x0F;
        bData++;
        
        // 다른 태스크로 전환
        kSchedule();
    }
}
Exemplo n.º 4
0
// Task 1
// 		Print character around monitor
void kTestTask1(void)
{
	BYTE bData;
	int i = 0, iX = 0, iY = 0, iMargin;
	CHARACTER * pstScreen = (CHARACTER *)CONSOLE_VIDEOMEMORYADDRESS;
	TCB * pstRunningTask;
	
	// Get ID and use is as offset of monitor
	pstRunningTask = kGetRunningTask();
	iMargin = (pstRunningTask->stLink.qwID & 0xFFFFFFFF) % 10;
	
	while (1)
	{
		switch (i)
		{
		case 0:
			iX++;
			if ( iX >= (CONSOLE_WIDTH - iMargin) )
			{
				i = 1;
			}
			break;
		case 1:
			iY++;
			if ( iY >= (CONSOLE_HEIGHT - iMargin) )
			{
				i = 2;
			}
			break;
		case 2:
			iX--;
			if ( iX < iMargin )
			{
				i = 3;
			}
			break;
		case 3:
			iY--;
			if ( iY < iMargin )
			{
				i = 0;
			}
			break;
		}
		
		// Set characture and color
		pstScreen[iY * CONSOLE_WIDTH + iX].bCharactor = bData;
		pstScreen[iY * CONSOLE_WIDTH + iX].bAttribute = bData & 0x0F;
		bData++;
		
		// Switch task
		kSchedule();
	}
}
Exemplo n.º 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;
}
Exemplo n.º 6
0
/**
 *  getch() 함수의 구현
 */
BYTE kGetCh( void )
{
    KEYDATA stData;
    
    // 키가 눌러질때까지 대기함
    while( 1 )
    {
        // 키 큐에 데이터가 수신될 때까지 대기
        while( kGetKeyFromKeyQueue( &stData ) == FALSE )
        {
            kSchedule();
        }
        
        // 키가 눌렸다는 데이터가 수신되면 ASCII 코드를 반환
        if( stData.bFlags & KEY_FLAGS_DOWN )
        {
            return stData.bASCIICode;
        }
    }
}
Exemplo n.º 7
0
/**
 *  태스크 사이에서 사용하는 데이터를 위한 잠금 함수
 */
void kLock( MUTEX* pstMutex )
{
    // 이미 잠겨 있다면 내가 잠갔는지 확인하고 잠근 횟수를 증가시킨 뒤 종료
    if( kTestAndSet(&( pstMutex->bLockFlag ), 0, 1 ) == FALSE )
    {
        // 자신이 잠갔다면 횟수만 증가시킴
        if( pstMutex->qwTaskID == kGetRunningTask()->stLink.qwID ) 
        {
            pstMutex->dwLockCount++;
            return ;
        }
        
        // 자신이 아닌 경우는 잠긴 것이 해제될 때까지 대기
        while( kTestAndSet( &( pstMutex->bLockFlag ), 0, 1 ) == FALSE )
        {
            kSchedule();
        }
    }
       
    // 잠김 설정, 잠김 플래그는 위의 kTestAndSet() 함수에서 처리함
    pstMutex->dwLockCount = 1;
    pstMutex->qwTaskID = kGetRunningTask()->stLink.qwID;
}
Exemplo n.º 8
0
// 태스크 사이에서 사용하는 데이터를 위한 잠금 함수
void kLock(MUTEX* pstMutex)
{
	BYTE bCurrentAPICID;
	BOOL bInterruptFlag;

	// 인터럽트를 비활성화 
	bInterruptFlag = kSetInterruptFlag(FALSE);

	// 현재 코어의 로컬 APIC ID를 확인 
	bCurrentAPICID = kGetAPICID();

	// 이미 잠겨 있다면 내가 잠갔는지 확인하고 잠근 횟수를 증가시킨 뒤 종료 
	if(kTestAndSet(&(pstMutex->bLockFlag),0,1)==FALSE)
	{
		// 자신이 잠겼다면 횟수만 증가시킴 
		if(pstMutex->qwTaskID==kGetRunningTask(bCurrentAPICID)->stLink.qwID)
		{
			// 인터럽트를 복원 
			kSetInterruptFlag(bInterruptFlag);
			pstMutex->dwLockCount++;
			return;
		}

		// 자신이 아닌 경우는 잠긴 것이 해제될 때까지 대기 
		while(kTestAndSet(&(pstMutex->bLockFlag),0,1)==FALSE)
		{
			kSchedule();
		}
	}

	// 잠금 설정, 잠긴 플래그는 위의 kTestAndSet() 함수에서 처리함 	
	pstMutex->dwLockCount =1;
	pstMutex->qwTaskID=kGetRunningTask(bCurrentAPICID)->stLink.qwID;
	// 인터럽트를 복원 
	kSetInterruptFlag(bInterruptFlag);
}
Exemplo n.º 9
0
/**
 *  태스크를 종료
 */
BOOL kEndTask( QWORD qwTaskID )
{
    TCB* pstTarget;
    BYTE bPriority;
    BYTE bAPICID;
    
    // 태스크가 포함된 코어의 로컬 APIC ID를 찾은 후, 스핀락을 잠금
    if( kFindSchedulerOfTaskAndLock( qwTaskID, &bAPICID ) == FALSE )
    {
        return FALSE;
    }
    
    // 현재 실행중인 태스크이면 EndTask 비트를 설정하고 태스크를 전환
    pstTarget = gs_vstScheduler[ bAPICID ].pstRunningTask;
    if( pstTarget->stLink.qwID == qwTaskID )
    {
        pstTarget->qwFlags |= TASK_FLAGS_ENDTASK;
        SETPRIORITY( pstTarget->qwFlags, TASK_FLAGS_WAIT );
        
        // 임계 영역 끝
        kUnlockForSpinLock( &( gs_vstScheduler[ bAPICID ].stSpinLock ) );
        
        // 현재 스케줄러에서 실행중인 태스크의 경우만 아래를 적용
        if( kGetAPICID() == bAPICID )
        {
            kSchedule();

            // 태스크가 전환 되었으므로 아래 코드는 절대 실행되지 않음
            while( 1 ) 
            {
                ;
            }
        }
        
        return TRUE;
    }
    
    // 실행 중인 태스크가 아니면 준비 큐에서 직접 찾아서 대기 리스트에 연결
    // 준비 리스트에서 태스크를 찾지 못하면 직접 태스크를 찾아서 태스크 종료 비트를
    // 설정
    pstTarget = kRemoveTaskFromReadyList( bAPICID, qwTaskID );
    if( pstTarget == NULL )
    {
        // 태스크 ID로 직접 찾아서 설정
        pstTarget = kGetTCBInTCBPool( GETTCBOFFSET( qwTaskID ) );
        if( pstTarget != NULL )
        {
            pstTarget->qwFlags |= TASK_FLAGS_ENDTASK;
            SETPRIORITY( pstTarget->qwFlags, TASK_FLAGS_WAIT );
        }
        
        // 임계 영역 끝
        kUnlockForSpinLock( &( gs_vstScheduler[ bAPICID ].stSpinLock ) );
        return TRUE;
    }
    
    pstTarget->qwFlags |= TASK_FLAGS_ENDTASK;
    SETPRIORITY( pstTarget->qwFlags, TASK_FLAGS_WAIT );
    kAddListToTail( &( gs_vstScheduler[ bAPICID ].stWaitList ), pstTarget );
    
    // 임계 영역 끝
    kUnlockForSpinLock( &( gs_vstScheduler[ bAPICID ].stSpinLock ) );
    return TRUE;
}
Exemplo n.º 10
0
/**
 *  유휴 태스크
 *      대기 큐에 삭제 대기중인 태스크를 정리
 */
void kIdleTask( void )
{
    TCB* pstTask, * pstChildThread, * pstProcess;
    QWORD qwLastMeasureTickCount, qwLastSpendTickInIdleTask;
    QWORD qwCurrentMeasureTickCount, qwCurrentSpendTickInIdleTask;
    QWORD qwTaskID, qwChildThreadID;
    int i, iCount;
    void* pstThreadLink;
    BYTE bCurrentAPICID;
    BYTE bProcessAPICID;
    
    // 현재 코어의 로컬 APIC ID를 확인
    bCurrentAPICID = kGetAPICID();
    
    // 프로세서 사용량 계산을 위해 기준 정보를 저장
    qwLastSpendTickInIdleTask = 
        gs_vstScheduler[ bCurrentAPICID ].qwSpendProcessorTimeInIdleTask;
    qwLastMeasureTickCount = kGetTickCount();
    
    while( 1 )
    {
        // 현재 상태를 저장
        qwCurrentMeasureTickCount = kGetTickCount();
        qwCurrentSpendTickInIdleTask = 
            gs_vstScheduler[ bCurrentAPICID ].qwSpendProcessorTimeInIdleTask;
        
        // 프로세서 사용량을 계산
        // 100 - ( 유휴 태스크가 사용한 프로세서 시간 ) * 100 / ( 시스템 전체에서 
        // 사용한 프로세서 시간 )
        if( qwCurrentMeasureTickCount - qwLastMeasureTickCount == 0 )
        {
            gs_vstScheduler[ bCurrentAPICID ].qwProcessorLoad = 0;
        }
        else
        {
            gs_vstScheduler[ bCurrentAPICID ].qwProcessorLoad = 100 - 
                ( qwCurrentSpendTickInIdleTask - qwLastSpendTickInIdleTask ) * 
                100 /( qwCurrentMeasureTickCount - qwLastMeasureTickCount );
        }
        
        // 현재 상태를 이전 상태에 보관
        qwLastMeasureTickCount = qwCurrentMeasureTickCount;
        qwLastSpendTickInIdleTask = qwCurrentSpendTickInIdleTask;

        // 프로세서의 부하에 따라 쉬게 함
        kHaltProcessorByLoad( bCurrentAPICID );
        
        // 대기 큐에 대기중인 태스크가 있으면 태스크를 종료함
        if( kGetListCount( &( gs_vstScheduler[ bCurrentAPICID ].stWaitList ) ) 
                > 0 )
        {
            while( 1 )
            {
                // 임계 영역 시작
                kLockForSpinLock( &( gs_vstScheduler[ bCurrentAPICID ].stSpinLock ) );
                pstTask = kRemoveListFromHeader( 
                    &( gs_vstScheduler[ bCurrentAPICID ].stWaitList ) );
                // 임계 영역 끝
                kUnlockForSpinLock( &( gs_vstScheduler[ bCurrentAPICID ].stSpinLock ) );
                
                if( pstTask == NULL )
                {
                    break;
                }
                
                if( pstTask->qwFlags & TASK_FLAGS_PROCESS )
                {
                    // 프로세스를 종료할 때 자식 스레드가 존재하면 스레드를 모두 
                    // 종료하고, 다시 자식 스레드 리스트에 삽입
                    iCount = kGetListCount( &( pstTask->stChildThreadList ) );
                    for( i = 0 ; i < iCount ; i++ )
                    {
                        // 임계 영역 시작
                        kLockForSpinLock( 
                            &( gs_vstScheduler[ bCurrentAPICID ].stSpinLock ) );
                        // 스레드 링크의 어드레스에서 꺼내 스레드를 종료시킴
                        pstThreadLink = ( TCB* ) kRemoveListFromHeader( 
                                &( pstTask->stChildThreadList ) );
                        if( pstThreadLink == NULL )
                        {
                            // 임계 영역 끝
                            kUnlockForSpinLock( 
                                &( gs_vstScheduler[ bCurrentAPICID ].stSpinLock ) );
                            break;
                        }
                        
                        // 자식 스레드 리스트에 연결된 정보는 태스크 자료구조에 있는 
                        // stThreadLink의 시작 어드레스이므로, 태스크 자료구조의 시작
                        // 어드레스를 구하려면 별도의 계산이 필요함
                        pstChildThread = GETTCBFROMTHREADLINK( pstThreadLink );                        

                        // 다시 자식 스레드 리스트에 삽입하여 해당 스레드가 종료될 때
                        // 자식 스레드가 프로세스를 찾아 스스로 리스트에서 제거하도록 함
                        kAddListToTail( &( pstTask->stChildThreadList ),
                                &( pstChildThread->stThreadLink ) );
                        qwChildThreadID = pstChildThread->stLink.qwID;
                        // 임계 영역 끝
                        kUnlockForSpinLock( 
                            &( gs_vstScheduler[ bCurrentAPICID ].stSpinLock ) );
                        
                        // 자식 스레드를 찾아서 종료
                        kEndTask( qwChildThreadID );
                    }
                    
                    // 아직 자식 스레드가 남아있다면 자식 스레드가 다 종료될 때까지
                    // 기다려야 하므로 다시 대기 리스트에 삽입
                    if( kGetListCount( &( pstTask->stChildThreadList ) ) > 0 )
                    {
                        // 임계 영역 시작
                        kLockForSpinLock( 
                            &( gs_vstScheduler[ bCurrentAPICID ].stSpinLock ) );
                        kAddListToTail( 
                             &( gs_vstScheduler[ bCurrentAPICID ].stWaitList ), 
                             pstTask );
                        // 임계 영역 끝
                        kUnlockForSpinLock( 
                            &( gs_vstScheduler[ bCurrentAPICID ].stSpinLock ) );
                        continue;
                    }
                    // 프로세스를 종료해야 하므로 할당 받은 메모리 영역을 삭제
                    else
                    {
                        // 유저 레벨 프로세스라면 메모리를 할당 받았을 것이므로 할당
                        // 받은 메모리를 삭제
                        if( pstTask->qwFlags & TASK_FLAGS_USERLEVEL )
                        {
                            kFreeMemory( pstTask->pvMemoryAddress );
                        }
                    }
                }                
                else if( pstTask->qwFlags & TASK_FLAGS_THREAD )
                {
                    // 스레드라면 프로세스의 자식 스레드 리스트에서 제거
                    pstProcess = kGetProcessByThread( pstTask );
                    if( pstProcess != NULL )
                    {
                        // 프로세스 ID로 프로세스가 속한 스케줄러의 ID를 찾고 스핀락 잠금
                        if( kFindSchedulerOfTaskAndLock( pstProcess->stLink.qwID, 
                                &bProcessAPICID ) == TRUE )
                        {
                            kRemoveList( &( pstProcess->stChildThreadList ), 
                                         pstTask->stLink.qwID );
                            kUnlockForSpinLock( &( gs_vstScheduler[ 
                                bProcessAPICID ].stSpinLock ) );
                        }
                    }
                }
                
                // 여기까지 왔다면 태스크가 정상적으로 종료된 것이므로, 
                // 태스크 자료구조(TCB)와 스택을 반환
                qwTaskID = pstTask->stLink.qwID;

                // 스택을 반환
                kFreeMemory( pstTask->pvStackAddress );
                 
                // 태스크 자료구조(TCB)를 반환
                kFreeTCB( qwTaskID );                
                kPrintf( "IDLE: Task ID[0x%q] is completely ended.\n", 
                        qwTaskID );
            }
        }
        
        kSchedule();
    }
}
Exemplo n.º 11
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();
    }
}
Exemplo n.º 12
0
/**
 *  유휴 태스크
 *      대기 큐에 삭제 대기중인 태스크를 정리
 */
void kIdleTask( void )
{
    TCB* pstTask, * pstChildThread, * pstProcess;
    QWORD qwLastMeasureTickCount, qwLastSpendTickInIdleTask;
    QWORD qwCurrentMeasureTickCount, qwCurrentSpendTickInIdleTask;
    int i, iCount;
    QWORD qwTaskID;
    void* pstThreadLink;
    
    // 프로세서 사용량 계산을 위해 기준 정보를 저장
    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 )
            {
                // 임계 영역 시작
                kLockForSpinLock( &( gs_stScheduler.stSpinLock ) );
                pstTask = kRemoveListFromHeader( &( gs_stScheduler.stWaitList ) );
                if( pstTask == NULL )
                {
                    // 임계 영역 끝
                    kUnlockForSpinLock( &( gs_stScheduler.stSpinLock ) );
                    break;
                }
                
                if( pstTask->qwFlags & TASK_FLAGS_PROCESS )
                {
                    // 프로세스를 종료할 때 자식 스레드가 존재하면 스레드를 모두 
                    // 종료하고, 다시 자식 스레드 리스트에 삽입
                    iCount = kGetListCount( &( pstTask->stChildThreadList ) );
                    for( i = 0 ; i < iCount ; i++ )
                    {
                        // 스레드 링크의 어드레스에서 꺼내 스레드를 종료시킴
                        pstThreadLink = ( TCB* ) kRemoveListFromHeader( 
                                &( pstTask->stChildThreadList ) );
                        if( pstThreadLink == NULL )
                        {
                            break;
                        }
                        
                        // 자식 스레드 리스트에 연결된 정보는 태스크 자료구조에 있는 
                        // stThreadLink의 시작 어드레스이므로, 태스크 자료구조의 시작
                        // 어드레스를 구하려면 별도의 계산이 필요함
                        pstChildThread = GETTCBFROMTHREADLINK( pstThreadLink );

                        // 다시 자식 스레드 리스트에 삽입하여 해당 스레드가 종료될 때
                        // 자식 스레드가 프로세스를 찾아 스스로 리스트에서 제거하도록 함
                        kAddListToTail( &( pstTask->stChildThreadList ),
                                &( pstChildThread->stThreadLink ) );

                        // 자식 스레드를 찾아서 종료
                        kEndTask( pstChildThread->stLink.qwID );
                    }
                    
                    // 아직 자식 스레드가 남아있다면 자식 스레드가 다 종료될 때까지
                    // 기다려야 하므로 다시 대기 리스트에 삽입
                    if( kGetListCount( &( pstTask->stChildThreadList ) ) > 0 )
                    {
                        kAddListToTail( &( gs_stScheduler.stWaitList ), pstTask );

                        // 임계 영역 끝
                        kUnlockForSpinLock( &( gs_stScheduler.stSpinLock ) );
                        continue;
                    }
                    // 프로세스를 종료해야 하므로 할당 받은 메모리 영역을 삭제
                    else
                    {
                        // TODO: 추후에 코드 삽입
                    }
                }                
                else if( pstTask->qwFlags & TASK_FLAGS_THREAD )
                {
                    // 스레드라면 프로세스의 자식 스레드 리스트에서 제거
                    pstProcess = kGetProcessByThread( pstTask );
                    if( pstProcess != NULL )
                    {
                        kRemoveList( &( pstProcess->stChildThreadList ), pstTask->stLink.qwID );
                    }
                }
                
                qwTaskID = pstTask->stLink.qwID;
                kFreeTCB( qwTaskID );
                // 임계 영역 끝
                kUnlockForSpinLock( &( gs_stScheduler.stSpinLock ) );
                
                kPrintf( "IDLE: Task ID[0x%q] is completely ended.\n", 
                        qwTaskID );
            }
        }
        
        kSchedule();
    }
}