-
-
하드웨어에 인터럽트 가 발생하면,하드웨어의컨트롤러에서 물리적인 전기 신호 형태의 인터럽트 를 버스를 통해인터럽트 컨트롤러로 전달한다. -
인터럽트 컨트롤러는 여러 디바이스로부터 오는 인터럽트 신호를 모아CPU의 인터럽트 라인 이 활성화 됐다면CPU에게 인터럽트 를 보낸다.인터럽트 컨트롤러의 존재 이유는, 오직 하나의 인터럽트 핀을 가짐으로써 둘 이상의 디바이스에서 동시에 인터럽트 를 보내면 인터럽트 를 소실할 가능성이 있는CPU의 한계를 극복하기 위함이다.인터럽트 컨트롤러에는 여러 개의 핀이 있고, 동시에 인터럽트 가 발생해도 우선순위에 따라 인터럽트 를 처리한다.
-
CPU가 인터럽트 신호를 받으면, 인터럽트 시스템 을 비활성화 한다. 그다음, 현재 실행 중인 명령어를 끝마치고, 기존의 Program Counter 값을 스택 에 저장한다. 이때 인터럽트 가 커널의 수행을 방해했다면 저장하는 스택은 커널 스택 이 될 것이고, 사용자 프로세스의 수행을 방해했다면 사용자 스택 이 될 것이다. -
CPU는 인터럽트 벡터 테이블 을 참고하여 해당 인터럽트 라인 의 위치를 알아낸다. 그 후 알아낸 인터럽트 라인 의 위치로 분기한다.- 이때,
CPU가 커널 모드 로 진입하는 정확한 시점은 언제일까?
인터럽트 벡터 테이블 은 보통 커널 영역의 첫 번째 주소 번지부터 벡터 형태로 저장되어있으며 이 벡터 테이블 에 접근하기 위해 커널 영역으로 들어가기에
CPU가 벡터 테이블 에 접근하는 순간 유저 모드 에서 커널 모드 로 전환된다. - 이때,
-
인터럽트 라인 의 초기 진입 위치에는 어셈블리 코드가 있다. 이 코드는 IRQ 번호를 저장하고 인터럽트 가 중단시킨 작업의 레지스터 값들을 스택 에 저장한다. 그다음 커널은
do_IRQ()를 호출한다. -
do_IRQ()함수는 이전에 저장한 IRQ 번호를 이용해 인터럽트 라인 을 알아내고, 자신이 해당 인터럽트 를 인지했다는 것을 인터럽트 를 보낸하드웨어에게 알린다. 그리고 해당 인터럽트 라인 을 비활성화시켜 같은 인터럽트 의 재진입을 막는다. -
do_IRQ()함수는 해당 인터럽트 라인 에 유효한 핸들러 가 있는지 확인하고,handle_IRQ_event()함수를 실행함으로써 인터럽트 핸들러 를 실행한다. -
handle_IRQ_event()함수는CPU가 처음 인터럽트 를 받았을 때 인터럽트 시스템 을 비활성화하였으므로, 핸들러 함수 인자에IRQF_DISABLED플래그가 있지 않다면 다시 인터럽트 시스템 을 활성화해야 한다.IRQF_DISABLED인자가 지정된 상태라면 모든 인터럽트 가 비활성화된 상태에서 핸들러 를 실행한다. -
인터럽트 라인 에 해당하는 모든 핸들러 를 실행한 후,
handle_IRQ_event()함수는 다시 인터럽트 를 비활성화하고do_IRQ()함수로 반환한다. -
do_IRQ()함수로 반환 후 다시 초기 진입 위치로 돌아가서ret_from_intr()함수가 실행된다.ret_from_intr()함수는 초기 진입 코드와 마찬가지로 어셈블리 로 작성되어 있다. 이 함수는need_resched변수가 설정되어 있는지 확인하여 그에 따라 스케줄링 작업을 시행한다.- 인터럽트 가 사용자 프로세스를 중단한 경우
schedule()함수 호출
- 인터럽트 가 커널 자체를 중단한 경우
preempt_count값이 0인 경우에만schedule()함수 호출그 외의 경우에는 커널을 선점하는 것이 안전하지 않기 때문이다.
- 인터럽트 가 사용자 프로세스를 중단한 경우
-
schedule() 함수가 반환된 이후, 또는 대기 중인 프로세스가 없는 경우 레지스터에 저장했던 이전 작업의 문맥 을 복구하여 중단했던 작업을 계속 진행한다.
-
-
- 전역 cli() 함수 는
clear interrupt로 시스템 모든 프로세스의 인터럽트 를 비활성화시키는 함수이다. 이 함수의 주 사용처는 공유 데이터 에 대한 접근을 제한하기 위함이었지만 이를 위한 목적으로 전체 인터럽트_ 를 비활성화시키는 것은 시스템 성능에 엄청난 bottleneck 이었기에 이 함수를 제거해 몇 가지 이점을 얻었다.- 드라이버 개발자는 잠금 구현을 위해
cli()함수를 사용하지 않고 목적에 맞게 잠금 을 구현하게 되었다. - 2.5 버전 개발 과정에서
cli()함수와 같은 인터럽트 시스템의 중복된 코드를 비롯한 많은 코드를 정리하여 이해하기 쉽고 간단한 코드가 만들어졌다.
- 드라이버 개발자는 잠금 구현을 위해
- 전역 cli() 함수 는
-
-
인터럽트 핸들러 는
운영체제에 필요한 부분이나 실행할 때 몇 가지 제약이 있다.- 비동기적으로 실행되므로, 다른 인터럽트 핸들러 를 포함한 다른 중요한 코드를 중단시킬 수 있다.
- 최선의 경우
IRQF_DISABLED플래그가 설정되지 않으면 처리 중인 인터럽트 를 비활성화시킨 상태에서 실행되고, 최악의 경우IRQF_DISABLED플래그가 설정되었다면 현재 프로세서 의 모든 인터럽트 를 비활성화시킨 상태에서 실행된다. - 프로세스 컨텍스트 가 아닌 인터럽트 컨텍스트 에서 실행되어 휴면 상태 가 될 수 없기에 사용할 수 있는 함수에 제약이 있어 할 수 있는 일에 제약을 받는다.
하드웨어를 다루기 때문에 처리 시간이 중요하다.
-
위의 문제점을 해소하기 위해 최대한 인터럽트 핸들러 에서 중요한 몇 가지 기준의 작업들을 전반부 에서 처리하고 나머지 거의 모든 일을 후반부 처리에서 해결하는 것이 이상적이다.
- 전반부 에서 인터럽트 핸들러 가 처리할 고려 사항들
- 실행 시간에 민감한 작업
하드웨어와 관련된 작업- 다른 인터럽트 가 방해해서는 안 되는 작업
- 이외에 작업은 후반부 에서 처리한다.
대부분 상황에서 인터럽트 핸들러 가 종료된 직후에 후반부 처리가 실행된다. 그러나 후반부 처리의 핵심은 모든 인터럽트 가 활성화된 상태에서 후반부 처리를 한다는 것이다. 전반부 와 후반부 를 구분해 인터럽트 비활성화 시간을 최소화하여 시스템 지연시간 을 줄일 수 있다.
- 전반부 에서 인터럽트 핸들러 가 처리할 고려 사항들
-
-
-
- 컴파일 시 정적으로 할당되어 동적으로 등록하거나 제거할 수 없다.
- 인터럽트 컨텍스트 에서 실행되어 하드웨어 인터럽트 가 아니라면 선점할 수 없다.
- 하나의 프로세서 에서 같은 유형의
softirq가 동시 실행할 수 있다. - 최소한의 직렬화만 제공해 적절한 락이 필요하다.
-
softirq기반으로 만들어졌다.softirq와는 다르게 동적으로 할당된다.- 인터페이스가 간단하며, 락 사용 제한이
softirq에 비해 유연하다. - 인터럽트 컨텍스트 에서 실행되어 휴면 상태 가 될 수 없다.
- 하나의 프로세서 에서 둘 이상이 동시에 실행되지 않는다.
-
- 지연작업을 커널 스레드 형태로 처리한다.
- 프로세스 컨텍스트 에서 실행되어 휴면 상태 가 될 수 있으며 스케줄링 의 대상이다.
-
어떤 상황에 좋을까?
-
softirq
- 충분히 스레드화되어 깊은 부분까지 프로세서별로 변수를 구분해 사용하는 상황
- 실행 시간에 아주 민감하고 사용빈도가 높은 경우
-
tasklet
- 충분히 스레드화되어 있지 않은 상황
- 간단한 인터페이스를 가지며 동시에 실행되지 않기에 구현 작업이 더 쉽다.
- 대부분 상황에서
softirq보다 우선으로 고려된다.
-
workqueue
- 지연 작업을 프로세스 컨텍스트 에서 실행해야 한다면 사용
- 커널 스레드 를 사용하기에 컨텍스트 전환 비용이 필요하며 휴면 상태 가 필요 없다면 굳이 사용할 이유는 없다.
-
-