많은 알토스가 제공하는 또 하나의 서비스는 시스템 안에서의 이벤트 관리 기능입니다. 이벤트는 본질적으로 부울 변수 값으로 되어 있는 플래그로 태스크들이 설정하거나 리셋할 수 있고 다른 태스크들은 그 값을 기다려서 사용할 수 있게됩니다. 사용자가 무선 바코드 스캐너의 방아쇠를 당기면 레이저 스캐닝 장치를 켜고 바코드를 인식하려는 태스크를 작동시켜야하는 것이죠. 이벤트는 이런 행동을 아주 쉽게 처리합니다. 사용자가 방아쇠를 당길 때 실행되는 인터럽트 루틴은 스캐닝 태스크가 기다리고 있는 이벤트를 설정합니다. 일반적인 운영체제의 의미에서의 이벤트가 익숙하다면 RTOS에서는 약간은 다른 의미를 지닌다는 것을 바로 알 수 있었을겁니다.
이벤트에 대한 일반적인 기능에 대해서 먼저 살펴봅시다.
- 하나 이상의 태스크들이 같은 이벤트를 기다릴 수 있고, RTOS는 이벤트가 발생 했을 때 그들 모두를 대기 상태에서 해제시킬 수 있습니다. 그리고 우선 순위에 따라 실행시키지요. 사용자가 방아쇠를 당겼다거나 라디오 태스크가 라디오 장치를 구동할 준비를 시작해야 한다고 생각해보면 이 태스크 역시 방아쇠를 당기는 이벤트를 기다려야 합니다. 스캐닝 태스크와 라디오 태스크 둘 다 방아쇠를 당기는 이벤트를 기다린다는 의미입니다.
- RTOS는 일반적으로 이벤트 그룹을 형성하고, 태스크들은 그룹 안의 어떤 이벤트도 기다릴 수 있습니다. 스캐너 키 패드에 있느 키를 사용자가 눌렀다는 것을 나타내는 이벤트는 방아쇠를 당기는 이벤트와 같은 그룹이 될 겁니다. 만약 라디오 태스크가 키나 방아쇠 모두에 대해서 깨어나야 한다고 가정하면 그렇게 할수도 있죠. 스캐닝 태스크는 방아쇠 이벤트에만 깨어나게 될겁니다.
- 다른 종류의 RTOS는 이벤트가 발생하고 그것을 기다리던 태스크가 대기 상태에서 해제된 후에 이벤트를 다시 리셋하는 문제에 대해서 각기 다른 방법으로 처리합니다. 어떤 RTOS들은 자동적으로 이벤트를 리셋합니다. 다른 RTOS들은 태스크가 그것을 해줘야하지요. 이벤트를 리셋하는 것은 매우 중요한 일인데 방아쇠를 당기는 이벤트가 리셋되지 않았다면 그 이벤트를 기다려야 하는 태스크는 영원히 다시 기다리는 상태로 돌아갈 수 없습니다.
이벤트를 사용하는 예제로 코드 AMX 시스템에서 가져온 함수들을 떠올려봅시다.
[태스크간 통신 방법에 대한 비교와 고찰]
지금까지 두 태스크나 인터럽트 루틴과 태스크 사이의 통신을 위해서 큐, 파이프, 메일박스, 세마포어 및 이벤트를 사용하는 방법에 대해서 쭈욱 이어왔습니다.
이것들을 한번 대놓고 비교해볼까요?
- 세마포은 일반적으로 가장 빠르고 간단한 방법입니다. 세마포어를 통해서 많은 정보가 전달 될 수는 없다는 반전도 있지만요. 세마포어는 그저 가질 수 있는지를 나타내는 1 비트 정도의 정보를 전달하는 것에 그칩니다.
- 이벤트는 세마포어 보다는 조금 더 복잡하고, 약간 더 많은 마이크로프로세서 시간을 소모합니다. 세마포어에 비해 이벤트가 가지는 장점은 태스크가 하나의 세마포어 만을 기다려야 하는 것과는 달리, 동시에 여러 개의 이벤트 중의 하나를 기다릴 수 있다는 것입니다. 또 다른 장점을 꺼내보자면 어떤 RTOS들은 이런 목적으로 이벤를 쉽게 사용할 수 있도록 한 반면에 세마포어는 사용하기가 불편하게 되어 있다는 것입니다.
- 큐는 태스크에서 태스크로 많은 정보를 전달할 수 있게 해줍니다. 태스크가 단지 하나의 큐나 메일박스, 파이프를 기다릴 수 있는 상황이라고 하더라도, 큐를 통해서 데이터를 보낼 수 있다는 사실은 이벤트보다는 훨씬 더 많은 유연성을 가집니다. 단점으로는 메시지를 큐에 넣거나 가져오는 자업은 더 많은 마이크로프로세서의 시간을 필요로 하고, 큐는 버그가 코드에 들어갈 더 많은 기회를 제공할 수 있다는 것입니다. 메일박스와 파이프 역시 같은 특징을 가지고 있고요.
[메모리 관리에 대한 얘기]
대부분의 RTOS는 어떤 종류의 메모리 관리 기능을 가지고 있습니다. 어떤 알토스는 C 라이브러리 함수인 malloc과 free 같은 기능을 제공하기도 하지만, 이런 함수들은 일반적으로 느리고 수행 시간을 예측하기 어려워서 실시간 시스템 엔지니어들은 종종 이런 함수들을 사용하는 것을 피합니다. 대신 그들은 고정된 크기의 버퍼를 할당하거나 해제하는 함수를 선호하고, 대부분의 RTOS는 이런 목적을 위해 빠르고 예측 가능한 함수를 제공합니다.
MultiTask! 시스템은 이런 관점에서는 매우 전형적인 RTOS입니다. 프로그래머는 각각 어떤 개수의 버퍼로 구성되어 있는 메모리 풀을 설정할 수 있습니다. 어떤 주어진 풀에서 모든 버퍼는 같은 크기를 가지고 있습니다. reqbuf와 getbuf 함수는 메모리 풀로부터 버퍼를 할당하는 기능을 하는데요. 각각 할당된 버퍼를 가리키는 포인터를 반환합니다. 두 함수의 유일한 차이는 가능한 메모리 버퍼가 없을 때, getbuf 함수는 태스크를 기다리게 하고, reqbuf는 즉시 NULL 포인터를 반환한다는 것입니다.
void *getbuf (unsigned int uPoolId, unsigned int uTimeout) ;
void *reqbuf (unsigned int uPoolId) ;
이들 함수에서 uPoolId 인수는 메모리 버퍼가 할당된 풀을 나타냅니다. getbuf 함수에서 uTimeout 인수는 가용한 메모리가 없을 때 얼마 동안 버퍼를 기다릴지를 나타낸다. 하나의 풀에 있는 버퍼는 모두 같은 크기를 가지고 있기 때문에, 반환되는 버퍼의 크기는 버퍼가 할당되는 풀에 따라 결정됩니다. 이들 함수를 호출하는 태스크는 각각의 풀에 있는 버퍼의 크기를 알고 있어야만 합니다.
relbuf 함수는 메모리 버퍼를 해제시킵니다.
void *reqbuf (unsigned int uPoolId, void *p_vBuffer) ;
rebuf는 p_vBuffer 가 실제로 uPoolId가 나타내는 풀에 있는 버퍼를 가리키는 지를 체크하지 않는다는 것을 주의해야 합니다. 프로그램이 잘못된 값을 p_vBuffer에 사용하면 결과는 재앙을 초래하게 되겠죠.
MultiTask! 시스템은 또한 메모리가 실제로 시스템에서 어디에 있는지 모르는 전형적인 RTOS입니다. 데스크톱 시스템과는 달리, 대부분의 임베디드 시스템에서는 운영체제가 아니라 응용 프로그램이 먼저 전체 시스템의 제어권을 가집니다. RTOS가 시작할 때는 어떤 메모리가 사용가능하고 어떤 메모리를 응용 프로그램에서 이미 사용하는지에 대해서 아무런 정보도 가지고 있지 못하고요. MultiTask!는 메모리 버퍼를 위한 풀을 관리할 것입니다. 그러나 먼저 메모리가 어디에 있는지 알려줘야 합니다. init_mem_pool 함수는 이런 일을 수행합니다.
uPoolId 인수는 getbuf, reqbuf, relbuf 를 호출할 때 사용하게 될 식별자입니다. p_vMemory 인수는 풀로 사용할 메모리 블록을 가리키는 포인터입니다. 포인터가 유효한 메모리를 가리키도록 해야만 합니다. uBufSize와 uBufCount 인수는 각각의 버퍼가 얼마나 크고 풀에 얼마나 많은 버퍼가 있는 지를 나타냅니다. uPoolType 인수는 이들 버퍼가 태스크에서 사용될지 인터럽트 루틴에서 사용될지를 나타냅니다. 이런 구분은 MultiTask!의 독특한 특성입니다. 여기서는 이 내용을 다루지는 않을겁니다. 어떻게 메로리 버퍼의 풀을 할당하는지에 대해서만 보여드립니다.
쉽게 메모리 낭비로 보이는 코드가 분명히 있습니다. 하지만 주어진 줄이 매우 작은 문자를 담고 있더라도 항상 40문자 모두를 버퍼에 할당하니까 이런 메모리 낭비는 고정된 크기의 버퍼를 사용해서 얻을 수 있는 향상된 속도에 대한 대가라고 할 수 있습니다. 빠른 속도의 메모리 루틴과 메모리의 효율적인 사용에 대한 절충으로, 보통 각각 다른 크기의 버퍼를 가지고 있는 3~4개 풀을 할당합니다. 작은 양의 메모리를 필요로 하는 태스크는 작은 크기의 버퍼를 가진 풀을 할당하고, 많은 양의 메모리를 필요로 하는 태스크는 커다란 크기의 버퍼를 가진 풀을 할당합니다.
'IT > 임베디드 시스템' 카테고리의 다른 글
RTOS를 이용한 기본적인 임베디드 시스템 설계 - 개요 (0) | 2020.06.09 |
---|---|
RTOS 내에서 인터럽트 루틴 규칙 (0) | 2020.06.09 |
타이머 함수 - 임베디드 시스템 시간 관리 함수 (0) | 2020.06.09 |
파이프 - 큐와 비슷하지만 다른 변형들 (0) | 2020.06.06 |
메시지큐 / 메일박스 : 또 다른 수단 (0) | 2020.06.06 |
댓글