Task Process/ Thread 같다 임베디드 OS에서는 Task Process/Thread 역할을 대신한다 모든 프로세스의 처리는 Task단위로 처리가되며 이러한 Task 관리하기위한 Task control block 등을 만들고 연결해주는 작업이 필요하다.

 

task 관리하기위해 OS tcb(task control block) 만들고 구조체를 가지고 task 관리를 진행한다.

 

1. TCB

TCB에는 보통 해당 task stack pointer, stack_base정보 등을 가지고 있어 task 주소 값을 있다. 그리고 OS입장에서는 이렇게 만들어진 여 TCB 배열 상태로가지고 있다가 처리한다. tcb 처리하는 방법은 tcb안에 bool 변수를 넣어 true/false 통해 동작하는 tcb인지 아닌지를 확인하는 방법이 있을 수도 있고

아니면 배열 idx 이용해서 동작하는 tcb 넣어줌으로써 처리할 수도 있다.

 

각각의 tcb 각자 자신과 연결된 task 관리하는 것이고 task 처리한다는 것은 하나의 context 처리하는 연결된 함수가 있으며 동작을 수행하는 것이다.

마치 new Thread.run({}); 같이 Thread 생성함과 동시에 함수 하나를 연결하고 동작하는 것과 같다.

위와 같이 OS TCB 배열을 가지고있으며 하나의 Task 생성되면 해당 Task 생성하고 주소 값을 미리 잡아둔 Task Stack 영역(TCB 배열) 지정한다.

Task Stack영역에 생성된 Task 올리는 것으로 Task TCB 연결한다고 보면된다. 그리고 Task 동작시키는 fucntion(보통 매개변수로 받음) 주소값을 TCB 배열의 PC값으로 올려준다.

 

이렇게 되면 TCB배열을 통해 Tcb0 스케줄러가 context 올려주면 (Process running status로바꾸는 것을 의미)

가장 먼저 Task Stack을통해 Task 접근하고 여기서 PC 레지스터를 통해 함수를 실행할 있다.

 

2. 스케줄러

스케줄러는 그대로 Task Context 올리는 역할을 하며 Tcb배열에 여러 개의 task 동시에 ON 어떤 tcb 먼저 올릴지를 관리한다.

이러한 방법으로는 round-robin, 최소 시간, task 처리시간, 우선순위 다양한 방법이존재한다.

스케줄러의 처리 방식은 만들고자하는 OS 성격에 따라 다르기 때문에 어떤 기능이 가장 좋다라고 뽑기는 어렵다.

 

결과적으로 스케줄러 함수는 tcb 배열에 ON task 먼저처리할 얘들을 줄세워서 return해주는 함수로 생각하면 된다.

 

3. Context Switch

가장 기초적으로 생각하면 번에 OS 처리할 있는 task 1개이다. 때문에 task 동시에 사용하는 느낌을 사용자에게 주거나 혹은 실시간으로 반영되는 여러 task들을 정상적으로 동시에 돌리기 위해서는 task들을 짧은 시간내에 번갈아가면서 context해줌으로써 OS 많은 task 실시간으로 처리할 있도록 해야한다.

 

이렇게 여러 task 계속 바꿔가며 처리하는 방법을 context switch라고하며 또한 만들고자 하는 OS 따라서 여러가지 알고리즘으로 구현할 있다.

가장 기본적으로는 시분할 시스템으로 일정 시간마다 context switch 발생 시키는 것이다.

 

이러한 방법은 timer delay 두고 반복문을 통해 스케줄러 함수를 호출하고 리턴받은 task 교체해주도록 구현하면 된다.

 

Context Switch 하기 위해서는 기존에 동작하고 있던 task 저장하고 task 올려주고 해당 동작이 끝나면 다시 기존 저장했던 기존 task 정보를 불러와 동작해야 한다.

 

이는 __attribuite__ { _asm__ } 통해 어셈블리어로 작성할 있으며 해당 과정은 단순히 PC값과 sp만을 저장하는 것이아니라 기존 task 사용하던 register정보도 저장해줘야한다. 만약 기존 task 계산기 동작을 수행하던 context switch 일어났는데 register값이 정상적으로 저장되지않아 새로운 task에서 해당 register 사용한다면 다시 기존 task 돌아왔을 기존 작업을 이어서 하는 것은 불가능하다.

 

그리고 register값을 저장하는 방법은 ((naked)) 이용해서 진행하는 것이 안전하다.

왜냐하면 어셈블리어로 작성을하더라도 컴파일러는 이를 한번 해석해서 데이터들을 저장, 처리하기위해 ldr, mov 등의 어셈블리어 구문들이 우리가 구현한 어셈블리어 사이사이에 추가되는데 기존 task에서 사용하던 register 이용해서 데이터를 저장 처리할 있다.

이렇게 되는 경우 기존 task에서 register에저장해둔 값이 날아가게되므로 컴파일러가 우리가 직접 구현한 어셈블리어 구문만 이용하도록 하기 위해 ((naked)) 사용하여 어셈블리어를 구현하는 것이 코드상 안전하다.

 

- ref

임베디드 OS 만들기

+ Recent posts