Example #1
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();
	}
}
Example #2
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();
    }
}
Example #3
0
// 태스크 사이에서 사용하는 데이터를 위한 잠근 해제 함수 
void kUnlock(MUTEX* pstMutex)
{
	BOOL bInterruptFlag;

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

	// 뮤텍스를 잠근 태스크가 아니면 실패 
	if((pstMutex->bLockFlag==FALSE)||(pstMutex->qwTaskID!=kGetRunningTask(kGetAPICID())->stLink.qwID))
	{
		// 인터럽트를 복원 
		kSetInterruptFlag(bInterruptFlag);
		return ;
	}

	// 뮤텍스를 중복으로 잠갔으면 잠긴 횟수만 감소 
	if(pstMutex->dwLockCount>1)
	{
		pstMutex->dwLockCount--;
	}
	else 
	{
		// 해제된 것으로 설정, 잠긴 플래그는 가장 나중에 해제해야함 
		pstMutex->qwTaskID = TASK_INVALIDID;
		pstMutex->dwLockCount = 0;
		pstMutex->bLockFlag=FALSE;
	}

	// 인터럽트를 복원 
	kSetInterruptFlag(bInterruptFlag);
}
Example #4
0
/**
 *  태스크 1
 *      화면 테두리를 돌면서 문자를 출력
 */
static void kTestTask1( void )
{
    BYTE bData;
    int i = 0, iX = 0, iY = 0, iMargin, j;
    CHARACTER* pstScreen = ( CHARACTER* ) CONSOLE_VIDEOMEMORYADDRESS;
    TCB* pstRunningTask;
    
    // 자신의 ID를 얻어서 화면 오프셋으로 사용
    pstRunningTask = kGetRunningTask();
    iMargin = ( pstRunningTask->stLink.qwID & 0xFFFFFFFF ) % 10;
    
    // 화면 네 귀퉁이를 돌면서 문자 출력
    for( j = 0 ; j < 20000 ; j++ )
    {
        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();
    }

    //kExitTask();
}
Example #5
0
/**
 *  Device Not Available 예외의 핸들러
 */
void kDeviceNotAvailableHandler( int iVectorNumber )
{
    TCB* pstFPUTask, * pstCurrentTask;
    QWORD qwLastFPUTaskID;
    BYTE bCurrentAPICID;

    //=========================================================================
    // FPU 예외가 발생했음을 알리려고 메시지를 출력하는 부분
    char vcBuffer[] = "[EXC:  , ]";
    static int g_iFPUInterruptCount = 0;

    // 예외 벡터를 화면 오른쪽 위에 2자리 정수로 출력
    vcBuffer[ 5 ] = '0' + iVectorNumber / 10;
    vcBuffer[ 6 ] = '0' + iVectorNumber % 10;
    // 발생한 횟수 출력
    vcBuffer[ 8 ] = '0' + g_iFPUInterruptCount;
    g_iFPUInterruptCount = ( g_iFPUInterruptCount + 1 ) % 10;
    kPrintStringXY( 0, 0, vcBuffer );    
    //=========================================================================
    
    // 현재 코어의 로컬 APIC ID를 확인
    bCurrentAPICID = kGetAPICID();
    
    // CR0 컨트롤 레지스터의 TS 비트를 0으로 설정
    kClearTS();

    // 이전에 FPU를 사용한 태스크가 있는지 확인하여, 있다면 FPU의 상태를 태스크에 저장
    qwLastFPUTaskID = kGetLastFPUUsedTaskID( bCurrentAPICID );
    pstCurrentTask = kGetRunningTask( bCurrentAPICID );
    
    // 이전에 FPU를 사용한 것이 자신이면 아무것도 안 함
    if( qwLastFPUTaskID == pstCurrentTask->stLink.qwID )
    {
        return ;
    }
    // FPU를 사용한 태스크가 있으면 FPU 상태를 저장
    else if( qwLastFPUTaskID != TASK_INVALIDID )
    {
        pstFPUTask = kGetTCBInTCBPool( GETTCBOFFSET( qwLastFPUTaskID ) );
        if( ( pstFPUTask != NULL ) && ( pstFPUTask->stLink.qwID == qwLastFPUTaskID ) )
        {
            kSaveFPUContext( pstFPUTask->vqwFPUContext );
        }
    }
    
    // 현재 태스크가 FPU를 사용한 적이 있는 지 확인하여 FPU를 사용한 적이 없다면 
    // 초기화하고, 사용한적이 있다면 저장된 FPU 콘텍스트를 복원
    if( pstCurrentTask->bFPUUsed == FALSE )
    {
        kInitializeFPU();
        pstCurrentTask->bFPUUsed = TRUE;
    }
    else
    {
        kLoadFPUContext( pstCurrentTask->vqwFPUContext );
    }
    
    // FPU를 사용한 태스크 ID를 현재 태스크로 변경
    kSetLastFPUUsedTaskID( bCurrentAPICID, pstCurrentTask->stLink.qwID );
}
Example #6
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();
	}
}
Example #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;
}
Example #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);
}
Example #9
0
/**
 *  공통으로 사용하는 예외 핸들러
 */
void kCommonExceptionHandler( int iVectorNumber, QWORD qwErrorCode )
{
    char vcBuffer[ 100 ];
    BYTE bAPICID;
    TCB* pstTask;
    
    // 현재 예외가 발생한 코어를 반환
    bAPICID = kGetAPICID();
    // 현재 코어에서 실행 중인 태스크를 반환
    pstTask = kGetRunningTask( bAPICID );
    
    // 메시지 출력
    kPrintStringXY( 0, 0, "====================================================" );
    kPrintStringXY( 0, 1, "                 Exception Occur~!!!!               " );
    // 예외 벡터와 코어 ID, 에러코드를 출력
    kSPrintf( vcBuffer,   "     Vector:%d     Core ID:0x%X     ErrorCode:0x%X  ", 
            iVectorNumber, bAPICID, qwErrorCode );            
    kPrintStringXY( 0, 2, vcBuffer );    
    // 태스크 ID를 출력
    kSPrintf( vcBuffer,   "                Task ID:0x%Q", pstTask->stLink.qwID );
    kPrintStringXY( 0, 3, vcBuffer );
    kPrintStringXY( 0, 4, "====================================================" );

    // 유저 레벨 태스크의 경우는 무한 루프를 수행하지 않고 태스크를 종료시키고 다른
    // 태스크로 전환
    if( pstTask->qwFlags & TASK_FLAGS_USERLEVEL )
    {
        // 태스크 종료
        kEndTask( pstTask->stLink.qwID );
        
        // 무한 루프 수행 
        // kEndTask() 함수에서 다른 태스크로 전환하므로 실제로 여기는 수행되지 않음
        while( 1 )
        {
            ;
        }
    }
    // 커널 레벨인 경우는 무한 루프 수행
    else
    {
        // 무한 루프 수행
        while( 1 )
        {
            ;
        }
    }
}
Example #10
0
/**
 *  태스크 사이에서 사용하는 데이터를 위한 잠금 해제 함수
 */
void kUnlock( MUTEX* pstMutex )
{
    // 뮤텍스를 잠근 태스크가 아니면 실패
    if( ( pstMutex->bLockFlag == FALSE ) ||
        ( pstMutex->qwTaskID != kGetRunningTask()->stLink.qwID ) )
    {
        return ;
    }
    
    // 뮤텍스를 중복으로 잠갔으면 잠긴 횟수만 감소
    if( pstMutex->dwLockCount > 1 )
    {
        pstMutex->dwLockCount--;
        return ;
    }
    
    // 해제된 것으로 설정, 잠김 플래그를 가장 나중에 해제해야 함
    pstMutex->qwTaskID = TASK_INVALIDID;
    pstMutex->dwLockCount = 0;
    pstMutex->bLockFlag = FALSE;
}
Example #11
0
/**
 *  태스크를 생성
 *      태스크 ID에 따라서 스택 풀에서 스택 자동 할당
 *      프로세스 및 스레드 모두 생성 가능
 *      bAffinity에 태스크를 수행하고 싶은 코어의 ID를 설정 가능
 */
TCB* kCreateTask( QWORD qwFlags, void* pvMemoryAddress, QWORD qwMemorySize, 
                  QWORD qwEntryPointAddress, BYTE bAffinity )
{
    TCB* pstTask, * pstProcess;
    void* pvStackAddress;
    BYTE bCurrentAPICID;
    
    // 현재 코어의 로컬 APIC ID를 확인
    bCurrentAPICID = kGetAPICID();
    
    // 태스크 자료구조 할당
    pstTask = kAllocateTCB();
    if( pstTask == NULL )
    {
        return NULL;
    }
    
    // 동적 메모리 영역에서 스택 할당
    pvStackAddress = kAllocateMemory( TASK_STACKSIZE );
    if( pvStackAddress == NULL )
    {
        kFreeTCB( pstTask->stLink.qwID );
        return NULL;
    }

    // 임계 영역 시작
    kLockForSpinLock( &( gs_vstScheduler[ bCurrentAPICID ].stSpinLock ) );
    
    // 현재 프로세스 또는 스레드가 속한 프로세스를 검색
    pstProcess = kGetProcessByThread( kGetRunningTask( bCurrentAPICID ) );
    // 만약 프로세스가 없다면 아무런 작업도 하지 않음
    if( pstProcess == NULL )
    {
        kFreeTCB( pstTask->stLink.qwID );
        kFreeMemory( pvStackAddress );
        // 임계 영역 끝
        kUnlockForSpinLock( &( gs_vstScheduler[ bCurrentAPICID ].stSpinLock ) );
        return NULL;
    }

    // 스레드를 생성하는 경우라면 내가 속한 프로세스의 자식 스레드 리스트에 연결함
    if( qwFlags & TASK_FLAGS_THREAD )
    {
        // 현재 스레드의 프로세스를 찾아서 생성할 스레드에 프로세스 정보를 상속
        pstTask->qwParentProcessID = pstProcess->stLink.qwID;
        pstTask->pvMemoryAddress = pstProcess->pvMemoryAddress;
        pstTask->qwMemorySize = pstProcess->qwMemorySize;
        
        // 부모 프로세스의 자식 스레드 리스트에 추가
        kAddListToTail( &( pstProcess->stChildThreadList ), &( pstTask->stThreadLink ) );
    }
    // 프로세스는 파라미터로 넘어온 값을 그대로 설정
    else
    {
        pstTask->qwParentProcessID = pstProcess->stLink.qwID;
        pstTask->pvMemoryAddress = pvMemoryAddress;
        pstTask->qwMemorySize = qwMemorySize;
    }
    
    // 스레드의 ID를 태스크 ID와 동일하게 설정
    pstTask->stThreadLink.qwID = pstTask->stLink.qwID;    
    // 임계 영역 끝
    kUnlockForSpinLock( &( gs_vstScheduler[ bCurrentAPICID ].stSpinLock ) );
    
    
    // TCB를 설정한 후 준비 리스트에 삽입하여 스케줄링될 수 있도록 함
    kSetUpTask( pstTask, qwFlags, qwEntryPointAddress, pvStackAddress, 
            TASK_STACKSIZE );

    // 자식 스레드 리스트를 초기화
    kInitializeList( &( pstTask->stChildThreadList ) );
    
    // FPU 사용 여부를 사용하지 않은 것으로 초기화
    pstTask->bFPUUsed = FALSE;
    
    // 현재 코어의 로컬 APIC ID를 태스크에 설정
    pstTask->bAPICID = bCurrentAPICID;
    
    // 프로세서 친화도(Affinity)를 설정
    pstTask->bAffinity = bAffinity;

    // 부하 분산을 고려하여 스케줄러에 태스크를 추가 
    kAddTaskToSchedulerWithLoadBalancing( pstTask );
    return pstTask;
}
Example #12
0
/**
 *  태스크를 생성
 *      태스크 ID에 따라서 스택 풀에서 스택 자동 할당
 *      프로세스 및 스레드 모두 생성 가능
 */
TCB* kCreateTask( QWORD qwFlags, void* pvMemoryAddress, QWORD qwMemorySize, 
                  QWORD qwEntryPointAddress )
{
    TCB* pstTask, * pstProcess;
    void* pvStackAddress;
    
    // 임계 영역 시작
    kLockForSpinLock( &( gs_stScheduler.stSpinLock ) );
    
    pstTask = kAllocateTCB();
    if( pstTask == NULL )
    {
        // 임계영역 끝
        kUnlockForSpinLock( &( gs_stScheduler.stSpinLock ) );
        return NULL;
    }

    // 현재 프로세스 또는 스레드가 속한 프로세스를 검색
    pstProcess = kGetProcessByThread( kGetRunningTask() );
    // 만약 프로세스가 없다면 아무런 작업도 하지 않음
    if( pstProcess == NULL )
    {
        kFreeTCB( pstTask->stLink.qwID );
        // 임계 영역 끝
        kUnlockForSpinLock( &( gs_stScheduler.stSpinLock ) );
        return NULL;
    }

    // 스레드를 생성하는 경우라면 내가 속한 프로세스의 자식 스레드 리스트에 연결함
    if( qwFlags & TASK_FLAGS_THREAD )
    {
        // 현재 스레드의 프로세스를 찾아서 생성할 스레드에 프로세스 정보를 상속
        pstTask->qwParentProcessID = pstProcess->stLink.qwID;
        pstTask->pvMemoryAddress = pstProcess->pvMemoryAddress;
        pstTask->qwMemorySize = pstProcess->qwMemorySize;
        
        // 부모 프로세스의 자식 스레드 리스트에 추가
        kAddListToTail( &( pstProcess->stChildThreadList ), &( pstTask->stThreadLink ) );
    }
    // 프로세스는 파라미터로 넘어온 값을 그대로 설정
    else
    {
        pstTask->qwParentProcessID = pstProcess->stLink.qwID;
        pstTask->pvMemoryAddress = pvMemoryAddress;
        pstTask->qwMemorySize = qwMemorySize;
    }
    
    // 스레드의 ID를 태스크 ID와 동일하게 설정
    pstTask->stThreadLink.qwID = pstTask->stLink.qwID;    
    // 임계 영역 끝
    kUnlockForSpinLock( &( gs_stScheduler.stSpinLock ) );
    
    // 태스크 ID로 스택 어드레스 계산, 하위 32비트가 스택 풀의 오프셋 역할 수행
    pvStackAddress = ( void* ) ( TASK_STACKPOOLADDRESS + ( TASK_STACKSIZE * 
            GETTCBOFFSET( pstTask->stLink.qwID ) ) );
    
    // TCB를 설정한 후 준비 리스트에 삽입하여 스케줄링될 수 있도록 함
    kSetUpTask( pstTask, qwFlags, qwEntryPointAddress, pvStackAddress, 
            TASK_STACKSIZE );

    // 자식 스레드 리스트를 초기화
    kInitializeList( &( pstTask->stChildThreadList ) );
    
    // FPU 사용 여부를 사용하지 않은 것으로 초기화
    pstTask->bFPUUsed = FALSE;

    // 임계 영역 시작
    kLockForSpinLock( &( gs_stScheduler.stSpinLock ) );
    // 태스크를 준비 리스트에 삽입
    kAddTaskToReadyList( pstTask );
    // 임계 영역 끝
    kUnlockForSpinLock( &( gs_stScheduler.stSpinLock ) );
    
    return pstTask;
}