결론을 먼저 말씀드리면 프로세스가 죽게 됩니다.
플랫폼에 따라 다르지만, 이번 글에서는 설명을 위해 mbed os를 예로 들겠습니다.
mbed os에서 제공하는 기본 예제 코드입니다.
https://os.mbed.com/docs/mbed-os/v6.15/apis/scheduling-tutorials.html
/*
* Copyright (c) 2020 Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*/
#include "mbed.h"
DigitalOut led1(LED1);
InterruptIn sw(SW2);
EventQueue queue(32 * EVENTS_EVENT_SIZE);
Thread t;
void rise_handler(void)
{
queue.call(printf, "rise_handler in context %p\n", ThisThread::get_id());
// Toggle LED
led1 = !led1;
}
void fall_handler(void)
{
printf("rise_handler in context %p\n", ThisThread::get_id());
// Toggle LED
led1 = !led1;
}
int main()
{
// Start the event queue
t.start(callback(&queue, &EventQueue::dispatch_forever));
printf("Starting in context %p\r\n", ThisThread::get_id());
// The 'rise' handler will execute in IRQ context
sw.rise(rise_handler);
// The 'fall' handler will execute in the context of thread 't'
sw.fall(queue.event(fall_handler));
}
sw를 누르면 인터럽트가 발생하고, fall_handler 펑션이 인터럽트 핸들러로서, 콜백 함수로 등록됩니다.
근데 sw.fall(queue.event(fall_handler))를 실행함으로써 굳이 queue에 이벤트로 등록함을 알 수 있습니다. 이렇게 하는 이유는, printf를 fall_handler 안에서 호출하기 때문이죠. 만일 queue에 집어넣지 않고, sw.fall(fall_handler) 이런식으로 펑션이 직접 호출되게 했다면 프로세스가 죽습니다.
이유는 ISR에서 printf를 실행하기 때문입니다.
printf는 내부적으로 lock이 실행됩니다.
ISR에서 lock을 실행하면 스레드 레벨에서는 lock을 해제할 방법이 없습니다. 그렇기 때문에 문제가 생기지요. 커널은 이를 알고, 아예 런타임 에러를 내버립니다.
따라서 위 코드처럼 직접 ISR에서 lock등의 동기화 처리를 하지말고 이벤트처럼 처리해 다른 스레드에서 lock 작업을 하게끔 해야 합니다.
'OS' 카테고리의 다른 글
single core에서의 multi-threading (0) | 2022.01.24 |
---|---|
usb 연결시 커널 동작 (0) | 2021.12.06 |