인터럽트 중첩 관련해서 몇가지 질문이 있습니다.
(1) 프로세스가 실행 중에 인터럽트가 발생하면
현재 CPU 레지스터들을, 지금까지 실행중이던 프로세스에 할당되어 있는 커널 스택(혹은 인터럽트 스택)에 저장하고
인터럽트 핸들러를 실행하잖아요.
서로 다른 인터럽트가 계속 떠서 인터럽트가 중첩되면
인터럽트 핸들러가 실행중일 때 레지스터들도 또 백업해놓아야 할 것 같은데
(처음에 실행중이었던) 인터럽트된 그 프로세스에 할당되어 있는 커널 스택에 계속 저장되나요?
프로세스가 실행중이던 상태(레지스터)를 백업해놓는 곳은 그 프로세스에 할당되어 있는 커널 스택인데
인터럽트가 실행중이던 상태(레지스터)를 백업해놓는 곳도 (인터럽트된) 프로세스에 할당되어 있는 커널 스택인가요?
다시 말하면,
A 프로세스 -> I 인터럽트 -> J 인터럽트 -> K 인터럽트
이렇게 중첩되었다면
A 프로세스가 중단될 시점의 레지스터 백업 데이터와
I 프로세스가 중단될 시점의 레지스터 백업 데이터와
J 프로세스가 중단될 시점의 레지스터 백업 데이터가
모두 A 프로세스에 할당되어 있는 커널 스택에 저장되는지 입니다.
커널 스택이 아니라 인터럽트 스택을 사용하는 경우와 사용하지 않는 경우가 다르면
구분해서 설명 부탁드립니다.
커널 스택은 프로세"스"마다 할당되어 있고 인터럽트 스택은 프로세"서"마다 할당되어 있는 거죠?
(2) 프로세스가 리스케줄링 되는 대표적인 경우는
프로세스가 이벤트를 기다리기 위해 프로세스 스스로 대기 상태로 진입하는 경우와
타이머 인터럽트 핸들러에서 스케줄링하는 경우죠?
그러면
A 프로세스가 실행 중일 때 I 인터럽트가 발생했고
I 인터럽트 핸들러가 실행 중일 때 타이머 인터럽트가 발생해서
I 인터럽트 핸들러가 실행을 중단하고 타이머 인터럽트 핸들러로 넘어갔습니다.
이 때, 스케줄링이 일어날 수 있나요?
스케줄링이 일어나서 다른 프로세스가 A 프로세스를 선점해버리면 안될 것 같은데
스케줄링이 일어나지 않도록 되어 있나요?
같은 맥락에서,
I 인터럽트 핸들러가 실행을 마치고 복귀할 때,
반드시 처음 인터럽트 되었던 A 프로세스로만 복귀하나요?
다른 프로세스로 복귀되는 경우가 없을까요?
감사합니다.
댓글 4
-
문c(문영일)
2019.04.05 23:26
-
무명
2019.04.07 05:08
답변 정말 감사드립니다.
몇가지만 더 질문드려도 될까요?
그러면 동일한 irq가 아니어도
어떠한 irq 끼리도 중첩을 지원하지 않나요??
타이머 인터럽트도 중첩되지 않구요?
위의 (1)번 답변에서,
그러면 fiq가 irq를 중단시키고 실행되었을 때
irq가 실행중이던 상태를 백업해놓아야 할텐데
그곳은 (인터럽트된) 프로세스에 할당되어 있는 커널 스택인가요? (ARM 32bit 기준으로)
혹시 x86 x64 등에서
인터럽트가 중첩되면
인터럽트가 실행중이던 상태(레지스터)를 백업해놓는 곳은 (인터럽트된) 프로세스에 할당되어 있는 커널 스택인가요?
위의 (2)번 답변에서
인터럽트 복귀하면서
마지막 인터럽트 복귀 시점에서
리턴 함수를 호출하고
리스케줄링을 할 수는 있는데요
제 질문 포인트는
타이머 인터럽트가 다른 인터럽트를 중단하고 실행되었을 때에도
타이머 인터럽트 핸들러에서 리스케줄링 하는 경우가 있는지 궁금해서요
왜냐하면 타이머 인터럽트 핸들러가 I 인터럽트를 중단하고 실행되어
(A 프로세스 -> I 인터럽트 -> 타이머 인터럽트)
타이머 인터럽트가 리스케줄링을 한다면
A 프로세스가 B 프로세스로 바뀌어서
타이머 인터럽트가 종료되는 시점에서
A 프로세스의 커널 스택에 저장된 I 인터럽트 핸들러에서 백업한 레지스터 정보들을 현재 B 프로세스에서는 못찾을 거 같아서요. -
문c(문영일)
2019.04.07 14:30
x86과 달리 arm은 fiq를 제외하고 어떠한 irq 끼리도 중첩(nested)을 하지 않습니다.
인터럽트를 처리하기 위한 별도의 스택을 갖지 않는 arm 리눅스의 경우 nested irq를처리할 방법이 없습니다. (펌웨어 레벨은 가능합니다.)
arm64 리눅스의 경우 cpu별로 irq 전용 스택을 가지고 있어 nested irq의 구현은
가능한 상태지만, 아직 구현된 상태가 아닙니다.arm32에서는 역시 타이머 인터럽트도 중첩되지 않습니다.
(1)번 답변과 관련하여 네 프로세스에 할당된 커널 스택입니다. (arm32 기준)
x86_64를 분석하지 않아 정확히는 모르지만 x86은 nested nmi의 처리가 기본일 겁니다.
이렇게 nested를 지원하려면 기본적으로 커널 전용 스택 또는 인터럽트 전용 스택이 있어야 합니다.(2)번 답변과 관련하여 nested irq가 지원하지 않기 때문에 Task A에서 발생한
인터럽트에 대한 콜 스택은 모두 제거된 상태에서 Task B로 스위칭됩니다.감사합니다.
-
무명
2019.04.08 08:50
궁금한 부분이 모두 해결되었습니다.
정말 감사드립니다.
.
안녕하세요? 문c 블로그(http://jake.dothome.co.kr)의 문영일입니다.
ARM. ARM64 아키텍처에 한해 답변을 드립니다.
답변을 드리기 전에 간단히 ARM 인터럽트의 핸들러를 제외한 부분을 먼저 설명 드립니다.
ARM 아키텍처는 nested irq를 허용하나 ARM 리눅스 커널은 irq 끼리
nested irq를 지원하지 않습니다.
(fiq만 irq보다 우선 처리됩니다.)
irq 처리(핸들러의 호출)가 완료되고, local cpu의 인터럽트를 enable 하자마자 인터럽트
컨트롤러를 통해 pending 된 irq 들 중 가장 높은 priority irq가 새로 진입할 수 있습니다.
유저로 복귀 전까지 local cpu 인터럽트만 enable 되어 있으면
pendign irq 들이 계속 인터럽트될 수 있습니다.
모든 인터럽트 들이 종료된 경우 마지막으로 pending work(task preemption, signal, ...)을
처리하고, 유저로 복귀합니다. 복귀할 때 원래 preemption 되었던 Task A로 갈 수도 있고,
task preemption 되어 Task B로 복귀할 수도 있습니다.
-------------------------------------------
질문들에 번호별로 답변을 드려봅니다.
(1)
태스크(thread)마다 커널 스택과 유저 스택이 만들어지자나요?
ARM32의 경우 인터럽트 발생 시 태스크(thread)에 해당하는 커널 스택을 이용합니다.
ARM64의 경우 인터럽트 발생 시 cpu 마다 존재하는 인터럽트 전용 스택을 이용합니다.
(2)
언급하신 것들은 중요한 리스케줄링 포인트입니다.
또한 리스케줄링 되는 이유로 소소한 것을 다음과 같이 더 추가할 수 있습니다.
- preemption point에서 리스케줄
- TIF_NEED_RESCHED 플래그가 설정된 경우 모든 인터럽트의 종료 전에 리스케줄
- 로드밸런스에 의한 태스크 무빙에 의한 리스케줄
- IPI 호출에 의한 리스케줄
당연히 인터럽트 종료 시 원래 Task A가 아닌 선점된 Task B로 스케줄될 수 있습니다.
위와 같은 점들을 고려해서 정확히 분석해보시면 좋은 결과가 있을 것 같습니다.
감사합니다.