.
├── boot
│ ├── Entry.S
│ ├── Handler.c
│ ├── Main.c
│ └── main.h
├── hal
│ ├── HalInterrupt.h
│ ├── HalTimer.h
│ ├── HalUart.h
│ └── rvpb
│ ├── Interrupt.c
│ ├── Interrupt.h
│ ├── Regs.c
│ ├── Timer.c
│ ├── Timer.h
│ ├── Uart.c
│ └── Uart.h
├── include
│ ├── ARMv7AR.h
│ ├── memio.h
│ ├── MemoryMap.h
│ ├── stdarg.h
│ ├── stdbool.h
│ └── stdint.h
├── kernel
│ ├── event.c
│ ├── event.h
│ ├── Kernel.c
│ ├── Kernel.h
│ ├── msg.c
│ ├── msg.h
│ ├── synch.c
│ ├── synch.h
│ ├── task.c
│ └── task.h
├── lib
│ ├── armcpu.c
│ ├── armcpu.h
│ ├── stdio.c
│ ├── stdio.h
│ ├── stdlib.c
│ └── stdlib.h
├── Makefile
└── navilos.ld
현재 TEST 중인 QEMU 환경에서는 CORE가 1개로 실행 되기때문에 동기화 알고리즘을 사용을 억지로 실행 해볼 예정이다.
세마포어란 여러 쓰레드, RTOS 환경에서 TASK 들 끼리 같은 공유 자원(Share resource)을 사용할 때 서로 충돌을 방지하기 위해 사용하는 알고리즘이다.
즉 세마포어는 공유 자원에 화장실 처럼 칸막이와 문을 설치한 다음 그 문에 맞는 열쇠(sSem:코드)를 만들어
그 열쇠를 가지고 있는 Task 만이 공유자원을 사용할 수 있다.
예제코드에서는 binary 세마포어를 사용한다.
synch.c
Kernel_sem_init()
static int32_t sSemMax;
static int32_t sSem;
void Kernel_sem_init(int32_t max)
{
sSemMax = (max <= 0) ? DEF_SEM_MAX : max; //(max <= 0) 이 참이면 sSemMax에 DEF_SEM_MAX을 할당 아니면 max를 할당
sSem = sSemMax;
}
위에 언급한 열쇠의 갯수를 정한다.
만약 열쇠(sSem)의 갯수가 0 보다 작거나 같으면 MAX 값인 8로 설정한다.
Kernel_sem_check()
bool Kernel_sem_check(void)
{
if (sSem <= 0)
{
return false;
}
sSem--;
return true;
}
열쇠가 있는지 체크한다.
만약 열쇠가 없으면 false를 return 하여 열쇠가 없음을 알리고 만약 열쇠가 있으면 열쇠를 가지고 가기때문에
sSem-- 하여 열쇠를 -1 해주고 true를 return 한다.
Kernel_sem_realease()
void Kernel_sem_release(void)
{
if (sSem >= sSemMax)
{
sSem = sSemMax;
}
sSem++;
}
열쇠를 반납한다.
열쇠가 max값보다 크면 max 값과 동일하게 만든 후 +1을 한다.
Kernel_lock_sem()
void Kernel_lock_sem(void)
{
while(false == Kernel_sem_check())
{
Kernel_yield();
}
}
앞서 언급했던 kernel_sem_check에서 false를 return할 시 kernel_yield를 호출 하여 강제로 Context switching 한다.
kernel_unlock_sem()
void Kernel_unlock_sem(void)
{
Kernel_sem_release();
}
Kernel_sem_realese를 호출하여 lock 을 푼다.
Test_critical_section()
static uint32_t shared_value;
static void Test_critical_section(uint32_t p, uint32_t taskId)
{
Kernel_lock_sem();
debug_printf("section Task #%u Send=%u\n", taskId, p);
shared_value = p;
Kernel_yield();
delay(1000);
debug_printf("Recive Task #%u Shared Value=%u\n", taskId, shared_value);
Kernel_unlock_sem();
}
공유 자원을 전역변수로 선언하여 critical_section 함수 안에 활용한다.
함수 안에서는 세마포어 lock 을 사용한다음 debug_printf 를 활용하여 share_value값을 확인한다.
그 다음 kernel_yield를 호출하여 Context Switching을 한다.
이때 다른 Task에서 Critical_section을 호출하여 shared_value 값을 바꿀려고 해도 lock 이걸려있어 share_value 값을 바꾸지 못하고 다시 Context switching을 한다.
이번에 사용한 예제 코드의 알고리즘이다.
지금까지 사용했던 Task는 유지하고 Task#2 와 Task#3을 사용했다.
Task#2에서는 새로 추가된 semaphore 이벤트가 set 되었을 시 Critical Section에 진입하며
Task#3에서는 호출 될때마다 Critical Section에 진입한다.
여기서 주목할 block은 Critical Section인데 Task#2에서는 공유자원값을 5로 설정하고
Task#3에서는 공유자원 값을 3으로 설정한다.
아래 실제 Task#2, Task#3 코드이다.
void User_task2(void)
{
int32_t local = 0;
while(true)
{
debug_printf("User Task #2\n", &local);
KernelEventFlag_t handle_event = Kernel_wait_events(KernelEventFlag_Semaphore);
switch(handle_event)
{
case KernelEventFlag_Semaphore:
debug_printf("event semaphore\n");
Test_critical_section(5,2);
break;
}
delay(1000);
Kernel_yield();
}
}
void User_task3(void)
{
int32_t local = 0;
while(true)
{
debug_printf("User Task #3\n", &local);
Test_critical_section(3,3);
delay(1000);
Kernel_yield();
}
}
앞서 올린 순서도를 이해 했다면 위 코드는 어렵지 않을 것이다.
Uart.c
Interrupt_handler()
static void interrupt_handler(void)
{
uint8_t ch = Hal_uart_get_char();
Hal_uart_put_char(ch);
Hal_uart_put_char('\n');
Kernel_send_msg(KernelMsgQ_Task0,&ch,1);
Kernel_send_events(KernelEventFlag_UartIn);
if(ch =='s')
Kernel_send_events(KernelEventFlag_Semaphore);
}
Semaphore event는 interrupt에서 s라는 문자가 왔을 시 보낸다.
실행화면
Task#3에서 Critical Section에 진입하여 lock 걸고 Context switching 하였을 때
's' 문자를 입력하여 Tesk#2에서 Critical Section에 진입하여 Shared value 값을 5로 수정할려고 하였으나
lock으로 인해 변경하지 못하고 Context switching 하였으며
unlock 되자 Task#2에서 다시 진입하여 5로 변경 후 출력 되는 화면이다.
'Firmware > RTOS' 카테고리의 다른 글
임베디드 OS 개발 프로젝트 18(뮤텍스) - 마지막 장 (1) | 2020.03.26 |
---|---|
임베디드 OS 개발 프로젝트 16(메시징-2) (0) | 2020.03.16 |
임베디드 OS 개발 프로젝트 15(메시징) (0) | 2020.03.15 |
임베디드 OS 개발 프로젝트 14(Event 처리) (0) | 2020.03.11 |
임베디드 OS 개발 프로젝트 13(Context Switching - Priority) (0) | 2020.03.10 |