티스토리 뷰

심화

megaOS - 11. Semaphore

Just4Fun 2016. 11. 7. 21:40

간단한 임베디드 시스템이라면 앞에서 설명했던 counter만 가지고도 필요한 기능을 수행할 수 있겠지만, 일반적인 임베디드 시스템에서는 좀더 다양한 형태의 이벤트 처리 기능을 요구하게 된다.


인터럽트가 발생했을때 적절한 처리를 하도록 타스크에게 알려주기 위해서나, 타스크간의 정보 교환이 필요한 경우가 있는데 이를 동기화(Synchronization)라고 한다.


megaOS에서는 동기화 기능중 semaphore, flag, mailbox를 만들어 보도록 하겠다.


Synchronization을 지원하기 위해서 TCB 구조체에 sync_list를 추가하여야 한다.

당연히 os_task_create() 함수에서는 sync_list 초기화 코드도 추가하여야 한다.

이 부분은 이 글의 마지막 부분에 첨부되어 있는 소스를 참고하기 바란다.


이번 글에서는 동기화 기능의 첫번째로 semaphore에 대해서 설명하도록 하겠다.

Semaphore는 이벤트가 발생했는지만 알려주는 기능을 제공하는 아주 간단한 동기화 블럭이다.

Semaphore를 위해서 os.h 에 다음과 같은 코드를 추가한다.

count는 처리되지 않은 이벤트가 몇개나 있는지 기록해두기 위해서 사용된다.

sem_list는 이벤트를 기다리는 타스크를 연결시키기 위해서 사용된다.


Semaphore 기능을 만들기 위하여 kernel/os_semaphore.c 파일을 만들고 다음과 같은 코드를 추가한다.


먼저 만들 코드는 Semaphore를 생성하기 위한 os_semaphore_create()이다.

os_semaphore_create()의 입력 인자로 생성되는 semaphore의 초기값을 줄 수가 있다.  count에 그 초기값을 전달한다.  그 다음에는 sem_list를 초기화 한다.


생성된 semaphore를 처리할 때 사용하는 os_semaphore_wait()는 다음과 같다.

os_semaphore_wait()의 두번째 인자로 tick 카운터값이 들어오는데 이값이 0이면 이벤트가 발생할 때까지 무한히 기다리게 되고, 값이 0이 아닌값이 들어오면 해당 tick 시간만큼 이벤트를 기다린 후, 이벤트가 발생하지 않게 되면 timeout 에러가 발생하게 된다.


8~12는 이미 semaphore에 이벤트가 발생되어 있는 경우 이벤트 카운터 값을 하나 감소 시킨 후 바로 빠져 나오게 된다.

만약 이벤트가 발생되어 있지 않게 되면, tick 값에 따라 타이머 설정을 하기도 하고, 그냥 바로 sleep 상태로 들어가기도 한다.

24번은 semaphore 이벤트가 발생될 때, 이를 처리하기 위하여 타스크의 sync_link를 semaphore의 sem_list에 링크 시켜 놓도록 한다.

25번 줄에서 타스크 스위칭이 일어나게 된다.

이벤트가 발생하거나, timeout이 되면 25번줄에서부터 타스크가 다시 깨어나 동작이 되는데, 타이머를 설정하였다면, 타이머를 clear한다.

30번줄은 만약 이벤트를 기다리기 위해서 sleep 되었던 타스크가 다시 깨어날 때 그 이유가 DONE이 아니면 에러 상황이라고 판단하여 result를 false로 만들게 된다.


때로는 이벤트가 발생되어 있는지만 확인하고 싶을 때가 있다.  이를 위하여 os_semaphore_trywait()를 사용하면 된다.

이벤트가 발생되어 semaphore의 count에 어떤 값이 들어 있으면, 그 값을 하나 감소 시킨후 true를 리턴한다.  만약 이벤트가 발생되어 있지 않아 count가 0의 값을 가지고 있으면 false를 리턴하여 이벤트가 발생되지 않았음을 알려준다.


이벤트가 발생되어 이를 기다리는 타스크에게 이러한 사실을 알려주기 위하여 os_semaphore_post()를 사용한다.

5번줄은 이벤트가 발생했을 때 아무 타스크도 sem_list에 링크되어 있지 않으면 count값을 하나 증가 시켜 이벤트가 발생 되었음을 기록해 두게 된다.

그러나, 만약 이벤트가 발생했을 때 이미 어떤 타스크가 이 이벤트를 기다리고 있는 상황이라면 11~13에서와 같이 타스크의 wake_reason을 DONE으로 만들고 타스크를 깨워준다.



그럼, 실제로 semaphore를 이용한 이벤트 처리 기능을 시험해 보도록 하겠다.

Counter 글을 참고하여 UART 인터럽트에 대한 이벤트를 semaphore를 이용하여 처리하는 예제를 만들어 보겠다.

40번 줄에서 UART RX 이벤트를 처리하기 위한 uart 타스크를 생성한다.

20~21은 uart rx 인터럽트 핸들러를 등록하고, uart에서 rx 인터럽트를 발생 시키도록 한다.

23번 줄에서 uart_sem을 하나 만든다. 초기값으로 0을 넣어준다.

27번 줄은 UART RX 이벤트가 발생을 기다리게 해 놓는다. tick값을 0으로 주었기 때문에 UART 이벤트가 발생할 때까지 무한히 sleep 상태로 유지하게 된다.

만약 UART RX이벤트가 발생하면 29번 줄에서처럼 들어온 UART 데이터를 화면에 출력하도록 한다.

8번 줄은 UART로 데이터가 수신되면 UART RX 인터럽트가 발생하게 되고, UDR에서 수신된 데이터를 읽어 uart_data 변수에 저장해 놓는다.

15번 줄에서 UART RX 이벤트가 발생한것을 알려준다.


실제로 어떻게 동작되는지 보드에서 실행해 보고 그 결과를 확인해 본다.


만약 3초 동안 아무런 데이터가 들어오지 않을 경우, 다른 동작을 하고 싶은 경우 os_semaphore_wait(uart_sem, 3*OS_TICKS_PER_SEC) 이렇게 tick 값을 원하는 시간 만큼 설정해 주면 된다.


이렇게 수정하고 다시 실행해 보면 다음과 같은 결과를 볼 수 있다.

위의 그림에서 'b'를 입력한 후 3초 동안 아무런 데이터가 수신되지 않았을 때 timeout이 되었음을 알려주는 메시지가 출력되는 것을 볼 수 있다.



megaOS.zip



심화 과정 목차

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

megaOS - 13. Mailbox  (1) 2016.11.13
megaOS - 12. Flag  (0) 2016.11.08
megaOS - 10. System Timer  (0) 2016.10.31
megaOS - 9. Counter  (0) 2016.10.29
megaOS - 8. Interrupt  (0) 2016.10.29
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/05   »
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
글 보관함