유영창님의 리눅스 디바이스 드라이버를 보고 공부를 하고 있습니다.
인터럽트 사용 방법에서 다음과 같이 해야 한다고 되어있습니다.
unsigned long flags;
local_save_flags(flags);
local_irq_disable();
local_restore_flags(flags);
지금 개발중인 리눅스 인터럽트 코드를 보다
다음과 같이 되어 있는것을 발견 하였습니다.
local_irq_disable();
local_irq_enable();
아래 함수가 현재 프로세스의 상태를 저장한다고 설명 되어 있던데
local_save_flags(flags);
이 함수를 사용하지 않을경우 문제가 될까요?
문제가 된다면 어떤 문제가 발생할까요?
조언 부탁 드립니다.
댓글 9
-
백창우
2010.09.30 15:40
-
홍문화
2010.09.30 16:59
먼저 답변에 감사드립니다. ^^;
CS가 깨진다는 말씀이 중첩 인터럽트가 허용된다는 말씀 같은데
아래와 같이 되어 있다면 중첩 인터럽트가 허용되지 않는다는 말씀 이신지요?
local_save_flags(flags);
local_irq_disable();
...
local_save_flags(flags);
local_irq_disable();
...
local_restore_flags(flags);
... // CS
local_restore_flags(flags);
-
백창우
2010.09.30 17:29
아뇨. 그런 의미가 아니라....
main () {
...
local_irq_disable();
func();local_irq_enable();
}
만약 func()이 아래와 같이 되어 있다면 func()은 CS 내에서 호출할 수 없겠죠.
CS 보장이 안되니깐.
func() {
local_irq_disable();
...
local_irq_enable();
}
하지만 아래와 같이 되어 있다면 CS 내에 호출해도 괜찮습니다.
func() {
local_save_flags(flags);
local_irq_disable();
...
local_restore_flags(flags);}
결국
local_irq_disable();
...
local_irq_enable();
로써 CS의 처리는 해당 코드가 절대 interrupt disable 구간에서 호출되지 않는다는게 전재되어야만 가능합니다.
하지만 그러한 전재 조건을 가지는 코드는 그렇게 많지가 않죠.
그래서 int_save 더 많이 사용되는 것입니다.
-
홍문화
2010.09.30 18:05
친절한 설명에도 불구하고 시스템 프로그래밍에 입문한지 얼마 안 되어서 이해가 잘 안되네요. ㅜㅜ;
유저모드에서 쓰레드간의 CS는 뮤텍스와 같은 커널 자원으로 보호되는 것으로 알고 있습니다.
여기서 CS를 공유하는 주체가 어떤것인지요?
CS 처리와 IRQ 금지,해제의 관계가 이해가 안되네요. -
백창우
2010.09.30 18:46
쉽게 말씀드리죠.
uni-core processor 환경에서 interrupt disable을 하면 interrupt 발생이 불가능하여,
다른 task로 전환이 되지 않습니다.
물론 ISR도 수행되지 못하죠.
그래서 현재의 context만 코드를 수행하는 것을 보장할 수 있습니다.
일반적으로 우리는 이것을 두고 CS 구간이라고 이야기 하죠.
-
홍문화
2010.09.30 20:11
CS에 func();가 놓일 경우 local_irq_disable();는 현재 Task의 context로 복구가 되기 때문에 CS가 깨진다는
말씀 같습니다. 그래서 아래와 같이 해주면
local_save_flags(flags);
local_irq_disable();
이전 Task의 contex로 복구 되기 때문에 CS가 깨지지 않는다는 말씀으로 이해 됩니다.
-
이상철
2010.09.30 22:47
창우님이 설명한것에서 조금 더 보태면,
간단하게 가령 어떤 설계자가 인터럽트 핸들러를 설계 한다고 하죠.
여기서 이 설계자는 이 핸들러를 수행 하는중에는 반드시 인터럽트를 디스에이블 한 상태에서
수행을 해야 한다고 설계를 구상하고 핸들러를 작성 했다고 하죠.(중첩인트럽트 금지)
그런데 만약 이 핸들러 내부에서 func()라는 함수를 호출하고 돌아오면 인터럽트가 인에이블 되버릴 것입니다.
이런 경우는 설계자의 의도와 전혀 다르게 동작을 하게 되겠죠?
마찬가지로 단일 코어 시스템에서 인터럽트를 금지하고 그 안에 어떤 작업을 하는 경우는 그부분을 수행하는 동안
스케줄링이 일어나지 않을려고 해서 그렇게 했을 것입니다. 그런데 그렇게 설정한 영역안에 func()라는 함수를
호출하면 인터럽트가 인에이블 될 것입니다. 이렇게 될 경우 인터럽트가 발생 할 수 있고, 인터럽트가 발생할 경우
스케쥴러가 호출이 되므로 다른 태스크로 전환이 이루어질 가능성이 생긴 다는 거죠
그래서 local_irq_disable()과 local_irq_enable()만을 사용하지 않고, 창우님이 말씀하신대로 사용을 한다면 위와 같은
경우를 막을수가 있는거죠. 왜냐면 local_irq_disable()을 하기 전 상태로 복원을 하므로 위와 같은 문제가 발생 하지 않게
됩니다.
-
홍문화
2010.10.01 10:41
두분 모두 친절한 답변 감사드립니다.
창우님 책을 통해 리눅스 세계의 항해를 하는데 좋은 돛을 달았습니다. ^^;
이렇게 인터넷을 통해 간접적으로나마 저자를 뵙게되니 신기할 따름입니다. ㅋ
-
백창우
2010.10.01 14:58
반갑습니다. ^^
.
만약 아래와 같은 코드라면 critical section이 깨져버리는 문제가 발생합니다.
local_irq_disable();
...
local_irq_disable();
...
local_irq_enable();
... // critical section이 깨어짐
local_irq_enable();