정보공간_1

[6기 강북 전영진] 리눅스 커널 심층 분석 #4 본문

IT 놀이터/Elite Member Tech & Talk

[6기 강북 전영진] 리눅스 커널 심층 분석 #4

알 수 없는 사용자 2014. 11. 28. 21:41

#Intro

안녕하세요. 강북멤버십 23-2기 전영진입니다.

 

이번엔 리눅스 인터럽트와 인터럽트 핸들러에 대해 소개하겠습니다.

 

#인터럽트

하드웨어는 인터럽트를 이용해 프로세서에 신호를 보냅니다.

예를 들어, 키보드를 누르게 되면 키보드 컨트롤러가 프로세서에 전기적 신호를 보내 운영체제에 알리게 되는데, 그 전기적 신호를 인터럽트라고 합니다.

인터럽트는 프로세스 클럭과 관계없이 아무 때나 발생 가능합니다.

 

인터럽트 동작 과정

1. 하드웨어로부터 나온 전기적 신호(인터럽트)는 인터럽트 컨트롤러에 전송.

2. 인터럽트 컨트롤러는 프로세서에 신호를 전달.

3. 신호를 감지하면 프로세서는 인터럽트 처리를 위해 현재 실행하던 일을 중단.

4. 운영체제에 인터럽트 발생 사실 전달.

5. 운영체제는 상황에 맞게 처리.

 

인터럽트 별로 고유 값을 할당이 가능하며, 그 값으로 운영체제는 인터럽트를 구별하고 인터럽트가 발생한 하드웨어가 어떤 것인지 식별할 수 있다. 이러한 인터럽트 값을 인터럽트 요청(IRQ, interrupt request)라인이라 부릅니다. IRQ라인에는 IRQ0, IRQ1 이러한 방법으로 번호가 붙어있습니다.

 

#인터럽트 핸들러

인터럽트 핸들러, 인터럽트 서비스 루틴 : 인터럽트를 처리하기 위해 커널이 실행하는 함수

각 장치 별로 인터럽트 핸들러가 있다.

리눅스의 인터럽트 핸들러는 일반적인 C함수입니다.

인터럽트 핸들러가 다른 커널 함수와의 차이점은 인터럽트가 발생했을 때 커널이 호출한다는 점과 인터럽트 컨텍스트라는 특별한 컨텍스트에서 실행된다는 점입니다.

이 컨텍스트에 잇는 코드를 실행 하는 동안 중단할 수 없기 때문에 이를 단위 컨텍스트라고 부르기도 합니다. 인터럽트는 언제라도 발생할 수 있기 때문에 중단된 코드를 빨리 실행하려면 핸들러의 속도가 빨라야 됩니다. 따라서 운영체제가 지체 없이 인터럽트를 처리하는 것도 중요하지만 인터럽트 핸들러의 실행시간이 가능한 짧은 것도 중요합니다.

 

#전반부 처리와 후반부 처리

빠른 실행 속도와 대량 작업 실행이라는 두 목적을 위해 인터럽트 처리는 두 부분으로 나눠져 있습니다. 전반부 처리는 인터럽트 핸들러가 담당하며, 인터럽트를 받은 즉시 실행되며 인터럽트 수신확인이나 하드웨어 재설정처럼 처리 시한이 중요한 작업만 빠르게 처리합니다. 나중에 할 수 있는 일은 후반부 처리로 지연 시킵니다. 후반부 처리에 대한 내용은 다음 포스팅 때 설명하겠습니다.

 

#인터럽트 핸들러 등록

인터럽트 해들러는 하드웨어를 관리하는 드라이버가 담당합니다. 각 장치별로 드라이버가 있으며, 인터럽트를 사용하는 장치라면 드라이버가 인터럽트 핸들러를 등록합니다.

 

드라이버는 <linux/interrupt.h>파일에 정의된 request_irq() 함수를 이용해 인터럽트를 활성화시키고 인터럽트 핸들러를 등록합니다.

 

// request_irq : 지정한 인터럽트를 할당

Int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev)

첫번째 irq 인자 : 할당할 인터럽트를 지정

두번째 handler 인자 : 터럽트를 처리할 실제 인터럽트 핼들러를 가리키는 함수 포인터

세번째 flag 인자

-      인터럽트 핸들러 플래그

IRQF_DISABLED : 인터럽트 핸들러를 실행하는 동안 모든 인터럽트를 비활성화.

IRQF_SAMPLE_RANDOM : 인터럽트를 커널의 엔트로피 저장소에 활용할지를 지정.

IRQF_TIMER : 핸들러가 시스템 타이머를 위한 인터럽트를 처리.

IRQF_SHARED : 여러 인터럽트 핸들러가 같은 인터럽트를 공유가능.

네번째 name 인자 : 인터럽트를 사용하는 장비의 ASCII 형식의 이름.

다섯번째 dev 인자 : 인터럽트를 공유할 때 사용.

 

#인터럽트 핸들러 해제

드라이버를 제거하면 인터럽트 핸들러를 해제하고 필요한 경우 인터럽트 라인을 비활성화해야합니다.

Void free_irq(unsigned int irq, void *dev)

 

#인터럽트 컨텍스트

인터럽트 핸들러를 실행하는 동안 커널은 인터럽트 컨텍스트 상태가 됩니다.

커널이 프로세스 컨텍스트에 있을 때 current 매크로는 관련 태스크를 가리킵니다.

(프로세스 컨텍스트 : 커널 동작 상태 중 하나로 시스템 호출을 실행하거나 커널 스레드를 실행할 때와 같이 프로세스 대신에 커널이 실행되는 상태)

그리고 프로세스 컨텍스트에 있는 커널과 프로세스는 묶여있어 프로세스 컨텍스트는 휴면 상태가 되거나 스케줄러를 호출 할 수 있습니다.

반면에 인터럽트 컨텍스트는 프로세스와 묶여 있지 않아, 휴면상태가 될 수 없습니다. 따라서 특정 함수가 휴면상태가 될 수 있는 함수라면 인터럽트 핸들러에서는 함수를 호출할 수 없습니다. 또한 인터럽트 핸들러는 다른 코드를 중단시키므로 인터럽트 컨텍스트에서는 실행 시간이 아주 중요합니다. 고로 인터럽트 핸들러에서는 가능한 최대한 많은 작업을 빼내어 보다 편한 시간에 실행하는 후반부 처리에서 수행해야 합니다.

 

#인터럽트 제어

리눅스 커널에는 시스템의 인터럽트 상태를 조정하는 인터페이스가 있습니다.

이 인터페이스를 사용하면 현재 프로세서의 인터럽트 시스템을 비활성화하거나 전체 시스템의 특정 인터럽트를 막을 수 있습니다.  이런 함수는 모두 아키텍처 의존적이며 <asm/system.h> <asm/irq.h>파일에 들어 있습니다.

인터럽트 시스템을 제어하는 이유 : 동기화를 제공하기 위해서 시스템을 제어.

인터럽트를 비활성화 시키면 인터럽트 핸들러가 선점되지 않으며, 커널 선점 또한 막습니다.

인터럽트 전달을 막거나 커널 선점을 막는다고 해서 다른 프로세스가 동시에 접근할 수 있는 것을 막을 수 있는 것은 아닙니다. 리눅스는 다중 프로세서를 지원하므로 공유 데이터에 접근에 제어하는 잠근 장치가 필요한데 그에 대한 해결책으로 인터럽트를 비활성화 시킴으로써 인터럽트 핸들러의 동시 접근을 막을 수 있습니다.

 

#인터럽트 제어 방법

 

 

이번 포스팅은 리눅스 커널 인터럽트와 인터럽트 핸들러에 대해 살펴 보았는데,
다음 포스팅에서는 리눅스 커널 인터럽트 후반부 처리에 대해 살펴 보겠습니다.
(Linux kernel development. 3/E 참조)