티스토리 뷰

심화

megaOS - 12. Flag

Just4Fun 2016. 11. 8. 21:08

앞의 글에서 설명한 Semaphore는 단순히 이벤트가 발생했다는 것만을 알려주기 위하여 사용된다면, 이번 글에서 다룰 flag는 이벤트의 종류를 세분화 하여 알려줄수 있는 기능을 지원한다.


예를 들어 다음과 같은 상황을 상상해 보자.

몇만톤급의 호화유람선의 진수식이 조선소에서 진행되고 있다.

유람선을 구매한 선사에서 사장, 부사장, 선장, 승무원 대표 이렇게 네명과,

배를 만든 조선회사의 사장, 부사장, 공장장, 사원대표 이렇게 네명을 포함하여 모두 여덟명의 주요 인사들 앞에 스위치가 하나씩 설치되어 있다.

이제 사회자의 진행에 따라 배를 바다에 띄우기 위하여 스위치를 누르라는 얘기를 하면 각자 스위치를 누를 것이다.

이러한 상황에서 양쪽 회사의 사장과 부사장들 네명 모두 스위치를 눌렀을 때 비로소 배가 바다에 들어가야지, 만일 아직 어느 한명이 스위치를 누르지도 않았는데 배가 바다로 들어가게 된다면 기분이 썩 좋지는 않을 것이다.

만약 스위치 여덟개가 모두 눌리워 질때까지 기다리게 만들었는데, 사원대표가 너무 긴장한 탓에 스위치를 누르지 않고 있어서 배가 바다에 들어가지 않고 있다면 이또한 난감한 일이라고 할 수 있겠다.

따라서, 순서와는 무관하지만 어쨋든 VIP 네명의 스위치가 모두 눌리워졌을때 비로소 어떤 일을 수행하도록 하고, 나머지 참가자들의 스위치가 눌리워지든지 말든지 무시하게 만드는게 가장 좋은 방법일 것이다.


또다른 예를 들면, 택시같은 경우 손님이 한명이 오든, 두명이 오든 일단 손님이 오면 무조건 목적지로 출발하여야 되는 경우도 있다.


위의 예에서와 같이 여러가지 각기 다른 이벤트가 모두 발생할 때까지 기다리거나, 아니면 어느 하나의 이벤트라도 발생하기만 하면 일을 수행할 수 있도록 하는 것이 flag의 주요 기능이다.


지금부터 megaOS에서 사용하는 flag를 만들어 보도록 하겠다.

먼저, os.h 에 다음과 같은 내용을 추가한다.

os_flag_mode는 이벤트를 기다릴때 어떤 조건으로 기다릴것인지 선택할 때 사용한다.  AND는 모든 이벤트가 발생할 때까지 기다릴 때 사용하고, OR는 어느 하나의 이벤트라도 발생하면 그 이벤트를 처리하겠다는 것을 의미 한다. CLR는 이벤트가 발생하여 처리하면, flag value를 0으로 초기화 시킬때 사용한다.

megaOS에서 지원하는 flag 이벤트는 8비트 값을 가진다.  즉, 8개까지의 이벤트를 처리할 수 있다는 뜻이다.


flag는 내부적으로 이벤트를 처리하기 위한 구조체를 사용하는데, 이 정보를 저장하기 위하여 TCB 구조체에 다음과 같은 항목을 추가하여야 한다.

    os_addr_t       wait_info;


kernel/os_flag.c 파일에 flag 기능을 만들어 보도록 하겠다.

flag_wait_info 구조체는 flag 내부에서 이벤트를 처리하기 위하여 사용된다.


flag를 생성하기 위한 os_flag_create()는 다음과 같다.


이벤트가 발생하였을 때 이를 알려주기 위한 os_flag_setbits()는 다음과 같다.

이벤트가 발생하면 5번줄에서처럼 flag의 value에 기록한다.

만약 이벤트를 기다리고 있는 타스크가 있다면 적절한 처리를 하고, 그렇지 않고 아무런 타스크도 이벤트를 기다리고 있지 않으면 그냥 빠져 나오게 된다.

13번 줄은 아직 이벤트를 기다리고 있는 타스크가 깨어날 조건이 되지 않는 경우에 이를 처리하기 위하여 임시로 타스크 링크를 저장하기 위하여 초기화 시켜 두는 것이다.

16~17은 이벤트를 기다리고 있는 타스크를 가지고 와서 어떤 조건의 이벤트를 기다리고 있는지 그 정보를 가지고 오는 것이다.

19번 줄은 이벤트를 기다리는 타스크의 flag 조건이 AND 인지 확인하는 것이고, 20번 줄은 OR 조건인지 검사하는 것이다.

조건을 만족하게 되면 타스크를 깨우게 하고 flag 내부 변수에 발생한 이벤트를 기록해두게 된다.  만약 CLR 조건이 설정되어 있다면 flag의 value를 0으로 초기화 시킨다.

30번 줄은 이벤트 조건이 아직 만족되지 않은 상황인 경우 임시로 holding list에 타스크를 링크 시켜둔다.

32번 줄은 flag list에 더이상 타스크가 연결되어 있지 않을때까지 다음 타스크에 대한 이벤트 조건을 계속 검사하도록 한다.

flag list에 연결되어 있던 모든 타스크들에 대한 이벤트 처리가 끝나고 나면 holding list에 임시로 연결되어 있는 타스크들이 있는지 확인한다.

타스크들이 holding list에 연결되어 있다면 다시 원래대로 flag list에 연결시켜 주게 된다.


필요한 경우 flag value에 이미 설정되어 있는 비트값을 지우고 싶을때가 있게 된다.

이를 위하여 os_flag_maskbits()를 사용하면 된다.


현재까지 발생된 이벤트가 조건에 맞는지 확인할 때 사용하기 위한 os_flag_poll()이 있다.

원하는 조건이 맞으면 리턴값으로 flag value를 리턴하고, 만약 조건에 맞는 이벤트가 아직 발생하지 않은 경우라면 0을 리턴한다.


마지막으로 flag 이벤트를 기다리기 위해서 os_flag_wait()를 사용한다.

8번 줄은 이벤트를 기다리려고 하였는데 이미 발생한 상태인지 확인해 보는 것이다. os_flag_poll()의 리턴값이 0이 아니라는것은 원하는 이벤트가 발생했다는 뜻이므로 바로 이벤트를 처리하면 된다.


만일 이벤트가 발생하지 않은 상태라면 이벤트를 기다리기 위한 조건을 설정해 두어야 한다.

17번 줄의 all_mask에는 OR mode일때 0을 쓰고, 그렇지 않으면 입력으로 들어온 이벤트 패턴 비트값을 기록해 둔다.

18번 줄의 any_mask에는 OR mode일때 입력 패턴값을 기록하고, AND mode일 경우 0을 써놓게 된다.

19번 줄에서는 이벤트가 발생하면 자동으로 value를 Clear 시킬것인지를 기록해 두는 것이다.

20번 줄은 os_flag_wait()의 리턴값으로 사용하기 위한 value_out을 0으로 초기화 시켜 놓는 것이다.

이렇게 이벤트 조건을 모두 설정하고 난 후 그 정보를 TCB 구조체의 wait_info에 저장해 둔다.

Tick 값이 설정되어 있으면 타이머를 구동시켜 timeout 조건으로 깨어 날 수 있도록 하고, tick값이 0이면 이벤트가 발생할 때까지 무한히 기다리도록 만든다.


설정해 둔 이벤트가 발생하거나, timeout이 되어서 깨어나게 되면 그 결과를 value_out값을 이용하여 알려주게 된다.

리턴값이 0이 되면 timeout이 발생했다는 뜻이 된다.


이제, 지금까지 구현한 flag를 이용하여 예제 코드를 만들어 제대로 동작되는지 확인해 보도록 하겠다.

예제 코드를 설명하면 다음과 같다.

main_task()에서 odd_task와 even_task를 각각 만든다.

각 타스크는 각기 하나의 flag를 생성 시킨다.

odd_task는 38번 줄에서처럼 AND mode로 설정하여 1,3,5값이 모두 들어올때까지 기다리도록 만들고,

even_task는 51번 줄에서처럼 OR mode로 설정하여 0,2,4 중에 하나라도 들어오면 되도록 만들었다.

두개의 타스크 모두 tick 값을 0으로 주었기 때문에 이벤트가 발생할때까지 기다리도록 되어 있다.

UART를 통하여 데이터가 수신되면 uart_isr에서 수신된 데이터를 uart_data에 저장한 다음, uart_dsr에서 수신된 uart_data를 화면에 출력하고, 들어온 값이 0~7 사이의 값인 경우 홀수이면 odd_flag에 값을 알려주고, 짝수이면 even_flag에 값을 쓴다.


위의 예제를 실제 보드에서 실행하여 결과를 확인해 보도록 하겠다.

위의 그림은 0,2,4,6을 차례로 입력하였을 때 나타난 결과를 보여준다.

0,2,4 어느 하나의 이벤트가 발생하더라도 바로 even_task가 실행된것을 볼 수 있다.

그러나 6을 눌렀을때는 아무런 변화가 없다.  하지만 even_flag의 value에는 그 값이 기록되기는 한다.


위의 그림은 5,7,1,3이 차례로 입력 되었을 때의 결과를 보여주고 있다.  1,3,5에 해당하는 이벤트가 모두 발생하였을때 비로소 odd_task가 실행되는것을 알 수 있다.


이제, odd_task에서 3초 동안 이벤트가 발생하지 않은 경우 이를 처리하는 방법에 대해서 알아 보도록 하겠다.

위의 코드처럼 수정한 후 다시 실행 시키면 다음과 같은 결과를 볼 수 있다.


5,7,1까지 입력한 후 3초의 시간이 경과되어 timeout 상황이 발생하였다.  odd_flag의 value값을 읽어 보면 5,7,1에 해당되는 이벤트는 발생 되었음을 알 수 있다.  따라서 필요한 경우 발생한 이벤트에 대해서만 추가적인 동작을 수행할 수 있다.

마지막으로 3을 누르게 되면 즉각 odd_task의 이벤트가 발생한 것을 알려주게 된다.

이벤트가 발생하면 value 값을 clear하도록 만들었으므로 다음 timeout이 발생했을때의 odd_flag의 value는 0으로 초기화 되어 있음을 알 수 있다.




megaOS.zip


심화 과정 목차

'심화' 카테고리의 다른 글

User Interface - UART 특수키 처리  (0) 2017.06.24
megaOS - 13. Mailbox  (1) 2016.11.13
megaOS - 11. Semaphore  (0) 2016.11.07
megaOS - 10. System Timer  (0) 2016.10.31
megaOS - 9. Counter  (0) 2016.10.29
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함