블로그 이전했습니다. https://jeongzero.oopy.io/
kernel of linux - interrupt(0)
본문 바로가기
컴퓨터 관련 과목/운영체제 & 커널

kernel of linux - interrupt(0)

728x90

1. 타이머


저번 시간에 스케줄링시 사용되는 timeslice에 대해서 학습하였다. 이번 시간에는 timeslice를 커널이 어떻게 관리를 하는지에 대해서 간략하게 설명하고, 인터럽트에대해서 학습할 것이다.

손목시계를 생각해보자. HZ란 1초동안 몇번 째깍 거렸나를 나타내는 지표이다. 1000HZ는 1초동안 천번 째깍거렸다는 의미이다. 이는 물리시간에 배우는 의미이고 컴퓨터적인 의미로 해석하면 다음과 같다

  • #define HZ 1000

매크로 상수로 선언된 해당 의미는 1초에 1000번 인터럽트가 걸린다는 의미이다. 일반적으로 대부분의 아키텍처에서는 HZ가 100으로 세팅되어 있다.

시스템이 부팅된후, 몇번 째깍째각 거렸는지를 jiffies 라고 한다. 이는 global 변수이다. 그럼 이 jiffies 변수에 들어있는 값을 이용해서 현재 부팅된후 얼마만큼의 시간이 흘렀는지를 알수가 있다. 만약 HZ가 100으로 설저되어있고, 부팅된후 jiffies에 274050이 들어있다면, 274050/100 = 약 2740 초가 흘렀다는걸 알수 있다는 소리이다.

그럼 왜 HZ가 필요할까? 음 생각해봤을때 예를 들어 10분뒤에 울리는 알람을 설정해놨다고 해보자. 현재 HZ는 100으로 세팅되어있다. 그럼 초당 100번의 인터럽트가 발생하게되고, 총 300번의 인터럽트 즉 3초가 지났을때 알람이 울릴것이다. 이런식으로 타이머 인터럽트를 설정한거같다

또한 전 시간에 설명한 timeslice와 관련된 이유도 포함된다. 각 task마다 가용시간을 할당받는다고 했는데, 이 할당받는 시간의 체크 단위를 HZ로 하게 되는것이다. 특정 task가 3초의 시간을 할당받았다고하면, 300번의 인터럽트가 발생했을때 완료가 되서 끝나거나 아니면 다시 대기 상태로 빠지게 될것이다. 이렇게 HZ의 단위로 계속해서 프로세스들이 돌아가며 작업을 할 수 있게 해주기 위해 계속해서 특정 시간마다 인터럽트를 걸어주는 것 이다.

2. Hardware Clocks and Timers


시간과 관련된 2가지가 있다. 하나는 Timer이고, 나머지는 RTC이다. 두개는 구분되어서 사용된다. RTC의 가장 큰 특징은, 내부의 충전된 배터리가 존재하기 때문에 컴퓨터 파워를 꺼도 계속 시간이 흐른다. 따라서 컴퓨터가 부팅시에 커널로부터 RTC(현재 시각)을 읽어올수 있다.

이러한 RTC와는 다르게 Timer는 현재시간을 알리는 목적이 아니라 주기적으로 CPU에게 인터럽트를 거는 역할로서, 프로그램적으로 인터럽트를 걸게 설정할수도 있다. 그렇다면 타이머 인터럽트가 어떻게 걸리는지를 살펴보자.

clock을 시간으로 비유할때 1번 째깍 거릴때마다 인터럽트가 걸린다고했다. 이렇게 인터럽트가 걸리면, 인터럽트 핸들러에 의해 do_time 함수가 안에서 jiffies 를 1 증가시킨다.

그리고 update_process_times() 함수가 호출되는데, 현재 동작하고 있는 프로세스의 PCB정보를 토대로 커널모드인지, 유저모드인지에 따라서 각 모드에서의 count를 증가시킨다. 이를 통해 count * HZ 계산을 해서 커널 모드에서 얼만큼의 시간을 사용했고, 유저모드에서 얼만큼의 시간을 사용했는지 알수있다. 그리고 이 두개를 합쳐서 해당 프로세스가 얼마만큼의 CPU를 사용했지를 알수있다. (해당 정보 역시 PCB에 존재)

타이머에 대한 설명은 여기까지만 하고 이제 인터럽트에 대해서 자세히 알아보자

3. Interrupt


인터럽트(interrupt, 문화어: 중단, 새치기)란 마이크로프로세서(CPU)가 프로그램을 실행하고 있을 때, 입출력 하드웨어 등의 장치나 또는 예외상황이 발생하여 처리가 필요할 경우에 마이크로프로세서에게 알려 처리할 수 있도록 하는 것을 말한다

https://ko.wikipedia.org/wiki/인터럽트

위 그림을 봐보자. 네모난 파란색 박스는 CPU 내부를 의미한다. 현재 CPU 명령어 사이클을 돌면서 fetch, decode, execution 등의 루틴이 돌아간다. 하나의 사이클이 끝나면 다음 명령어를 수행하기 위해 PC가 증가된다.

하지만 만약 중간에 disk가 인터럽트를 걸었다고 가정해보자. 그렇게 되면, CPU 내부의 Interrupt request bit가 세팅되면서 현재 PC는 저장을 시키고, PC에 인터럽트 핸들러 주소가 들어가고, 그 주소가 fetch되면서 디스크를 서비스해주는 인터럽트 핸들러 루틴이 실행된다.

만약 인터럽트가 안걸리게 하고 싶을때도있다. 커널이 부팅될때 중간에 인터럽트가 들어와도 무시하고 부팅만 먼저 되게끔 하고 싶을때를 말한다. 따라서 이를 위한 내부적으로 소프트웨어 명령어가 존재하고 이는 Interrupt request bit을 disable 시키게 된다.

위에선 하나의 disk가 인터럽트를 건 상황이지만, 실제로는 수많은 디바이스들이 인터럽트를 요청할수 있다. 프린터, CD, 등등이 말이다.

따라서 여러 디바이스들이 각자 interrupt requet bit 을 세팅하는게 아니라, 중간에 Interrupt Controller를 두고 이놈이 여러 디바이스를 제어해서 대표적으로 interrupt request bit을 세팅하게 된다.

3.1 PIC (Programmable Interrupt Controller)


Interrupt Controller를 프로그램적으로 관리를 가능하게 해뒀기 때문에 이를 PIC라고 한다. 위 사진을 PIC라고 보면 될것이다.

우측 파란색 박스가 바로 PIC이다. PIC에는 여러 디바이스들이 물려있고, 디바이스들이 IRQ Lines를 통해 PIC에 연결되어 있다. IRQ(Interrupt Request)

때에 따라서 동시에 여러 디바이스들이 인터럽트를 요청할수 있다. 즉 서로 인터럽트 요청을 위한 경쟁을 하게 되고, PIC에서는 이러한 경쟁을 관리하기 위해 내부적으로 처리 로직이 존재한다.

우선 PIC에 IMR(Interrupt Mask Register)가 존재한다. 마스킹의 역할로, 0으로 세팅할경우 인터럽트 요청을 차단시킬수 있다. 만약 마스킹이 안되어있으면 요청은 그대로 전달되고, IRR(Interrupt Request Resiger)이 받게된다. IRR에서는 마스킹되지 않았던 요청을 그대로 받는다.

IRR에서 Priority Register 에서는 IRR에서 전달된 요청들중 어떤 놈의 요청을 제일먼저 처리해야할지 우선순위를 체크한다. 그리고 선정된 요청을 ISR(In Service Register) 에 전달한다. 여기에는 이제 실제 서비스해줄 요청이 담기고, 마지막으로 PIC에서는 해당 요청이 INTR에 전달되어 Interrupt request bit이 enable된다.

INTR 로 요청이 전달될때 어느 디바이스가 요청했는지의 정보를 vector에 담아서 같이 보낸다. 만약 디스크면 0, 프린트면 3 이런식으로 말이다. 사진 속 5번이 이에 대한 설명이다. IRQ Lines number를 vector로 변경시킨다는 의미이다.

여기서 INTR이 바로 좀 전 사진의 마름모 모양의 부분을 뜻한다.

이제 CPU에게 인터럽트 신호가 전달되었으면, PIC와 다른 디바이스들은 요청에 대한 응답(ACK)이 올때까지 Blocked 상태가 된다.

위 사진은 방금 설명한 그대로를 나타낸다. CPU 내부에 VECTOR, INTR이 들어가 있고, PIC가 외부에 존재한다. PIC에는 많은 IRQ 라인이 연결되어있는데, 하나의 IRQ에는 여러 디바이스들이 연결되어있다.

PIC로부터 선택된 인터럽트 요청과 해당 디바이스에 대한 Vector가 CPU로 전달되고, 이에대한 응답이 올때까지 PIC는 block 된다. ack가 온 뒤에, block이 풀리면서 다른 디바이스들의 요청이 처리된다.

3.2 Interrupt Handling in Multiprocessor


이번엔 멀티 프로세싱 상태의 인터럽트가 어떻게 동작하는지 살펴보자.

현재 CPU 가 2개 있고 각 CPU는 버스에 물려있다. 또한 모든 I/O 디바이스들은 Multi APIC에 연결되어 있다. APIC이란 Advanced PIC의 약자로 멀티프로세서를 위한 PIC을 의미한다. 또한 CPU에 달려있는 조그마한 Local APIC도 존재한다. 이 APIC에는 Timer device만 연결되어 있다.

좀더 큰 개념으로 봐보자. CPU는 실제 MMU와 연결되어있다. MMU는 Memory Management Unit으로 가상 메모리 주소를 실제 메모리 주소로 변환하며, 메모리 보호, 캐시 관리, 버스 중재 등의 역할을 진행한다.

즉 관리의 역할이므로 MMU에서는 CPU에서 전달된 주소가 low addreass(가령 0 ~ 7777xxx)이면 해당 주소는 메모리인것을 파악하고 메모리 버스를 통해 메모리에 전달한다. 만약 high address(가령 7777xxx ~ 7777777)이면 I/O 와 관련된 주소인것을 파악하고 I/O버스로 보낸다.

I/O 버스에는 실제 I/O 디바이스들이 물리는데, I/O interface card 형태로 직접 물릴수도 있고, PIC를 거쳐서 물릴수도 있다.

interface 는 요런거를 말하는거 같다. I/O interface card는 모두 동일한 포맷으로 규격화가 되어있다. 만약 디스크라고 하면

  • address 레지스터 : 디스크로 가는 섹터 주소
  • data 레지스터 : 디스크에 쓰거나 읽을 데이터
  • 보조레지스터인
    • control : cpu가 디스크를 read하고 싶은지 write하고 싶은지, 등에 대한 정보들
    • status : 디스크가 바쁜지 놀고있는지 등에 대한 상태정보
  • ROM
    • vendor id : 제조 회사 정보
    • device is : 해당 디바이스 정보
    • interrupt line

I/O 디바이스들이 I/O interface 로 직접 물릴수도 있고, PIC를 통해 물릴수도 있다.

이번엔 멀티 프로세싱 상황에서 좀더 자세히 알아보자. 멀티 프로세싱은 크게 2가지 종류가 있다.

  1. SMP (대칭형 멀티 프로세싱)

    SMP는 모든 프로세스가 메모리 버스, I/O 버스, 데이터 버스를 공유하며 하나의 운영체제가 모든 프로세스를 관리한다. 따라서 자원들이 서로 공유됨에 따라 동기화가 매우 중요하다.

  1. AMP (비 대칭형 멀티 프로세싱)

    AMP는 각 프로세스가 특정된 업무를 맡아서 한다. 이는 Mast-Slave 형태라고 부르며, 주 프로세스가 전체 시스템을 통제하고, 다른 프로세스들은 Master의 통제하에 동작된다.

이 개념을 토대로 아래 그림을 봐보자.

SMP에서는 모든 버스를 공유한다고 했다. 현재 Disk에서 인터럽트 요청이 오면, 해당 시그널은 APIC으로 전달된다. 헌데 현재 CPU가 4개나 있다. 이 중 어떤 CPU에게 요청을 해야할까?

아키텍처마다 다르지만 IRQ를 분배하는 알고리즘은 대부분 비슷하다. IRQ를 어떤 CPU에게 전달할꺼인지에 대한 방법은 크게 2가지가 있다.

  1. Static distribution

    말그대로 Static하게 설정된 table에 따라서 요청을 CPU에 분배한다

  1. Dynamic distribution

    동적으로 그때마다 우선순위 같은거에 따라 분배한다

    현재 우선순위가 가장 낮은 프로세스를 돌리고 있는 CPU에게 인터럽트 요청을 준다. 하지만 만약 running중인 프로세스의 우선순위가 동일한 cpu가 존재하면, Arbitration 알고리즘이 적용된다.

    해당 알고리즘에는, 모든 CPU가 카운터를 가지고, 현재 인터럽트 요청을 처리하는 CPU의 카운터는 0으로 만든다. 그러면서 다른 cpu들의 카운터는 1 증가가 된다. 이에따라 카운터의 숫자가 높은 CPU일 수록 인터럽트 처리를 자기는 안하고 남들한테 떠넘기는 놈이라고 판명할수 있다.

    그리고 이제 다음 IRQ 요청이 오면, CPU들의 카운터를 보고 가장 높은 놈에게 처리해달라고 요청한다.

    이번엔 AMP 를 봐보자. 위에서 간략하게 설명한것처럼 AMP는 Master - Slave 구조로써 Master CPU만 OS Kernel이 존재하게 된다. 따라서 Master CPU 만이 I/O 를 처리할수 있고, Slave에서 I/O를 하기 위해선 무조건 Master에게 요청을 보내서 부탁해야한다.

    SMP에서는 각 CPU들이 자원을 공유하기 때문에 상호배제의 원칙이 철저히 보장되야한다. 따라서 매우 복잡하다. 하지만 AMP는 Master-Slave 구조이기 때문에 모든 시스템 콜이 마치 한줄로 수행되므로 상호배제를 신경쓸 필요가 없다. 따라서 아키텍쳐 디자인이 SMP보다 매우 간단하다.

    이런 이유때문에 1997?8? 년까지는 멀티프로세싱이다 하면 AMP 프로세싱 구조로 통용되었다. 하지만 Slave의 요청이 많아지면 많은 과부하가 걸렸으며, Master CPU가 고장나버리면 아무것도 할수없는 상황이 벌어지기 때문에 신뢰성, 가용성, 성능 등의 많은 문제로 AMP 구조는 더이상 사용되지 않으며, SMP 구조가 최근까지 사용되고 있다.

    4. 정리


    간단하게 인터럽트가 컴퓨터에서 어떻게 처리되며, AMP, SMP의 차이를 알수있는 내용이였다

728x90