본문 바로가기

임베디드

[RTOS 개발하기] 임베디드 OS 개발 프로젝트ch.9

https://www.yes24.com/Product/Goods/84909414

 

임베디드 OS 개발 프로젝트 - 예스24

나만의 임베디드 운영체제를 만들어 보자.이 책은 펌웨어 개발 과정을 실시간 운영체제(RTOS)를 만들어 가며 설명한다. 임베디드 운영체제를 개발 환경 구성에서 시작해 최종적으로 RTOS를 만드는

www.yes24.com

 

공부 목적으로 이만우님의 저서 "임베디드 OS 개발 프로젝트"를 따라가며, RTOS "Navilos"를 개발하는 포스트입니다. 모든 내용은 "임베디드 OS 개발 프로젝트"에 포함되어 있습니다.

개발 목적

임베디드 시스템에 많이 사용되는 RTOS를 직접 개발해 보며 다음과 같은 지식을 학습하고자 합니다.
 - RTOS의 핵심 개념에 대해 학습한다.
 - 운영체제 핵심 기능을 설계해 보며 학습한다.
 - 펌웨어에 대한 진입장벽을 낮춘다.
 -  ARM 아키텍처에 대해 학습한다.
 - 하드웨어에 대한 지식을 학습한다.(펌웨어가 어떻게 하드웨어를 제어하는지)


이번 챕터는 스케줄러를 만들 예정입니다.

 

스케줄러란?

다음에 실행할 태스크가 무엇인지 골라주는 것입니다.

스케줄러를 얼마나 효율적으로 만드는지에 따라 RTOS의 성능이 좌우됩니다.

 

해당 프로젝트에선 라운드 로빈 알고리즘을 통해 스케줄러를 설계하겠습니다. 주의할 점은 인덱스가 최댓값에 이르면 다시 0이 되어야 합니다.

 

스케줄러 역시 태스크 관련 작업이므로 task.c에 라운드 로빈 알고리즘을 적용한 스케줄러를 추가하겠습니다.

//task.c 스케줄러 추가
#include "stdint.h"
#include "stdbool.h"

#include "ARMv7AR.h"
#include "task.h"

static KernelTcb_t      sTask_list[MAX_TASK_NUM];
static uint32_t         sAllocated_tcb_index;

static uint32_t         sCurrent_tcb_index;
static KernelTcb_t*     Scheduler_round_robin_algorithm(void);

void Kernel_task_init(void){
        sAllocated_tcb_index = 0;

        for(uint32_t i = 0; i < MAX_TASK_NUM; i++){
                sTask_list[i].stack_base = (uint8_t*)(TASK_STACK_START + (i * USR_TASK_STACK_SIZE));
                sTask_list[i].sp = (uint32_t)sTask_list[i].stack_base + USR_TASK_STACK_SIZE - 4;

                sTask_list[i].sp -= sizeof(KernelTaskContext_t);
                kernelTaskContext_t* ctx = (KernelTaskContext_t*)sTask_list[i].sp;
                ctx->pc = 0;
                ctx->spsr = ARM_MODE_BIT_SYS;
        }
}

uint32_t Kernel_task_create(KernelTaskFunc_t startFunc){
        KernelTcb_t* new_tcb = &sTask_list[sAllocated_tcb_index++];

        if (sAllocated_tcb_index > MAX_TASK_NUM){
                return NOT_ENOUGH_TASK_NUM;
        }

        KernelTaskContext_t* ctx = (KernelTaskContext_t*)new_tcb->sp;
        ctx->pc = (uint32_t)startFunc;

        return (sAllocated_tcb_index - 1);
}

static KernelTcb_t* Scheduler_round_robin_algorithm(void){
        sCurrent_tcb_index++;
        sCurrent_tcb_idx %= sAllocated_tcb_index;

        return &sTask_list[sCurrent_tcb_index];
}

sCurrent_tcb_index라는 변수를 만들어 현재 실행 중인 태스크의 컨텍스트 블록 인덱스를 저장합니다.

라운드 로빈 스케줄러 구현은 이걸로 끝입니다. 이렇게 만든 알고리즘 코드를 컨텍스트 스위칭에 적용하면 됩니다.


우선순위 스케줄러

이번 프로젝트에선 우선순위 스케줄러를 만들지는 않을 것입니다. 에뮬레이터라는 QEMU의 제약으로 적당한 테스트 케이스를 만들기 어렵기 때문입니다.

 

우선순위 스케줄러 구현

우선순위 스케줄러엔 태스크의 우선순위가 있고, 그에 맞게 다음 동작할 태스크를 선택하는 것입니다. 이를 구현하려면 태스크 컨트롤 블록에 우선순위를 부여해야 합니다. 태스크를 생성할 때 개발자가 적당한 우선순위를 지정해 주어야 합니다.

typedef struct KernelTcb_t{
	uint32_t sp;
	uint8_t* stack_base;
	uint32_t priority;
} KernelTcb_t;
uint32_t Kernel_task_create(KernelTaskFunc_t startFunc, uint32_t priority){
	KernelTcb_t* new_tcb = &sTask_list[sAllocated_tcb_index++];
	
	if(sAllocated_tcb_index > MAX_TASK_NUM){
		return NOT_ENOUGH_TASK_NUM;
	}
	
	new_tcb->priority = priority;
	
	KernelTaskContext_t* ctx = (KernelTaskContext_t*)new_tcb->sp;
	ctx->pc = (uint32_t)startFunc;
	
	return (sAllocated_tcb_index - 1);
}

이렇게 자료구조와 Kernel_task_create()를 확장하여 우선순위를 부여할 수 있습니다.

static KernelTcb_t* Scheduler_priority_algorithm(void){
	for(uint32_t i = 0; i < sAllocated_tcb_index; i++){
		KernelTcb_t* pNextTcb = &sTask_list[i];
		if(pNextTcb != sCurrent){
			if(pNextTcb->priority <= sCurrent->priority){
				return pNextTcb;
			}
		}
	}
	return sCurrent_tcb;
}

현재 우선순위보다 우선순위가 높거나 같은 태스크가 있으면 다음에 실행할 태스크로 선택하는 방식으로 구현할 수 있습니다.

 


마치며

라운드 로빈 알고리즘을 적용한 스케줄러를 추가했고, 우선순위 스케줄러의 구현 방식을 공부했습니다. 테스트는 컨텍스트 스위칭까지 구현한 뒤 진행하도록 하겠습니다. 챕터 8에서 구현한 태스크를 이번에 적용한 스케줄러를 기반으로 컨텍스트 스위칭을 하는 것입니다.

이번 챕터를 통해 어렵게 느껴졌던 스케줄링 개념이 더욱 친근해진 것 같습니다.

 


참고

RealViewPB 데이터시트 https://developer.arm.com/documentation/dui0417/d/?lang=en

 

Documentation – Arm Developer

 

developer.arm.com

 

저자 이만우님 깃허브 https://github.com/navilera/Navilos

 

GitHub - navilera/Navilos: RTOS for various embedded platform

RTOS for various embedded platform. Contribute to navilera/Navilos development by creating an account on GitHub.

github.com