장치들은 처리할 작업이 준비되었음을 컴퓨터 시스템의 다른 부분에 알리기 위해 여러가지 방법을 사용한다.
하드웨어와 소프트웨어 간의 비동기 통신을 효율적으로 처리하기 위해 IRQ가 필요하다. IRQ는 하드웨어 장치에서 이벤트가 발생했을 때 CPU가 이를 처리하도록 알려주는 역할을 한다.
IRQ 정보를 확인하기 위해 다음 명령어를 사용할 수 있다.
$ cat /proc/interrupts
또는
$ mpstat -A
handle_IPI는 ARM 아키텍처에서 다중 프로세서 간 인터럽트(IPI)를 처리하는 함수이다.
void handle_IPI(int ipinr, struct pt_regs *regs)
{
switch (ipinr) {
case IPI_TIMER:
tick_receive_broadcast();
break;
case IPI_RESCHEDULE:
scheduler_ipi();
break;
case IPI_CALL_FUNC:
generic_smp_call_function_interrupt();
break;
case IPI_CPU_STOP:
ipi_cpu_stop(cpu);
break;
case IPI_IRQ_WORK:
irq_work_run();
break;
case IPI_COMPLETION:
ipi_complete(cpu);
break;
}
}
IPI는 여러 프로세서 간에 특정 작업을 수행하도록 신호를 보낼 때 사용되며, 각 타입별로 다른 핸들러 함수가 호출된다.
- IPI_TIMER: 타이머 브로드캐스트 처리
- IPI_RESCHEDULE: 스케줄러 관련 작업
- IPI_CALL_FUNC: 함수 호출 인터럽트 처리
- IPI_CPU_STOP: CPU 중지
- IPI_IRQ_WORK: IRQ 관련 작업
- IPI_COMPLETION: 작업 완료 처리
/proc/interrupts 파일의 하단을 확인하여 인터럽트 정보를 확인할 수 있다.
$ cat /proc/interrupts
CPU0 CPU1 CPU2 CPU3
0: 21 0 0 0 IO-APIC-edge timer
1: 2 0 0 0 IO-APIC-edge i8042
5: 0 0 0 0 IO-APIC-edge parport0
8: 1 0 0 0 IO-APIC-edge rtc0
9: 0 0 0 0 IO-APIC-fasteoi acpi
12: 4 0 0 0 IO-APIC-edge i8042
136: 0 0 0 0 PCI-MSI-edge aerdrv, PCIe PME
137: 0 0 0 0 PCI-MSI-edge aerdrv, PCIe PME
138: 0 0 0 0 PCI-MSI-edge aerdrv, PCIe PME
139: 32 0 0 0 PCI-MSI-edge xhci_hcd
140: 2605695996 0 0 0 PCI-MSI-edge ahci
141: 1043038252 0 0 0 PCI-MSI-edge eth0
142: 632 0 0 0 PCI-MSI-edge snd_hda_intel
NMI: 101899 44420 43726 43594 Non-maskable interrupts
LOC: 689550845 368704910 297503411 268799403 Local timer interrupts
SPU: 0 0 0 0 Spurious interrupts
PMI: 101899 44420 43726 43594 Performance monitoring interrupts
IWI: 18206501 66200953 99879867 109191772 IRQ work interrupts
RTR: 2 0 0 0 APIC ICR read retries
RES: 135331614 39139837 38573153 34878201 Rescheduling interrupts
CAL: 797034 1942494 1710609 1713455 Function call interrupts
TLB: 128754559 65722910 58314646 59097716 TLB shootdowns
TRM: 0 0 0 0 Thermal event interrupts
THR: 0 0 0 0 Threshold APIC interrupts
MCE: 0 0 0 0 Machine check exceptions
MCP: 88994 88994 88994 88994 Machine check polls
ERR: 0
MIS: 0
hardIRQ, softIRQ
- hardware interrupt
- 하드웨어 에서 cpu나 메모리로 보내는 비동기 신호를 hard interrupt라고 한다.
- cpu가 수신한 후 interrupt handler를 실행한다.
- interrupt handler 는 중요한 작업과 빨리 끝내는 작업만 처리하여 software interrupt로 넘긴다.
- Top Half라고도 불린다.
- 발생 과정
- 외부 장치에 의해 interrupt 신호가 발생(예: 네트워크 카드에서 데이터 패킷 도착, 키보드 입력등)
- interrupt 신호가 interrupt controller 로 전달
- interrupt controller가 cpu 의 interrupt pin을 통해 cpu에 신호를 보냄
- cpu는 실행 중인 작업을 중단하고 다음 작업을 수행
- program counter와 stack register 등 현재 상태를 저장(컨텍스트 스위칭)
- interrupt vector table 을 참조하여 interrupt handler 를 호출
- software interrupt
- hardware interrupt handler나 프로세스 스케쥴러에 의해 생성되며 software system 자체에서 운영체제 커널로 보내는 인터럽트 신호를 soft interrupt라고 한다.
- Bottom Half라고도 불린다.
- 발생 과정
- 소프트웨어 프로그램이 interrupt 요청
- hardware interrupt 처리 루틴(예: 네트워크 데이터 처리) 에서 후속 작업을 위해 software interrupt 를 생성하거나 프로세스 스케쥴러가 트리거
- interrupt controller는 관여하지 않음
- cpu는 소프트웨어 명령어를 통해 interrupt 신호를 인지
- program counter 와 stack register 상태를 저장 (컨텍스트 스위칭)
- software interrupt handler 가 실행되어 interrupt 처리
- 소프트웨어 프로그램이 interrupt 요청
NMI란
NMI(Non-Maskable Interrupt)는 CPU가 특정 인터럽트를 무시할 수 없는 상황에서 처리해야 하는 인터럽트이다. 주로 치명적인 하드웨어 문제(예: 버스 오류, 타이머 오버플로우) 발생 시 사용된다. perf와 같은 도구는 NMI를 사용하여 시스템 성능 관련 데이터를 수집한다.
IRQ 마스킹(차단) 작동 방식
IRQ 마스킹은 CPU가 특정 시점에 인터럽트 요청(IRQ)를 무시하거나 일시적으로 처리하지 않도록 막는 작업이다.
다음은 각 아키텍처에서 IRQ를 활성화하는 로컬(코어 한정) 방식에 대한 예시이다. 이는 시스템이 효율적으로 인터럽트를 처리하거나 특정 코어만 인터럽트를 허용하도록 설계된 중요한 메커니즘을 보여준다.
- ARM: cpsie i → 간단한 명령으로 IRQ 활성화.
- ARM64: msr daifclr, #2 → DAIF 레지스터를 사용하여 좀 더 세밀하게 인터럽트 관리.
- x86: sti → IF 플래그로 모든 인터럽트를 관리하는 단일 접근 방식.
ARM 아키텍처 (arch/arm/include/asm/irqflags.h)
#define arch_local_irq_enable arch_local_irq_enable
static inline void arch_local_irq_enable(void)
{
asm volatile(
"cpsie i" /* 현재 코어만 활성화 (only current core) */
::: "memory", "cc");
}
- "cpsie i": 프로세서 상태 변경 명령 ("change processor state")
- i: IRQ(Interrupt Request) 비트를 설정해 인터럽트를 활성화
- arch_local_irq_enable: 현재 코어의 인터럽트를 활성화
- 현재 코어에서만 적용
- "memory", "cc"는 클로버(Constraint)로, 메모리 및 조건 플래그에 영향을 미친다는 것을 의미
ARM64 아키텍처 (arch/arm64/include/asm/irqflags.h)
static inline void arch_local_irq_enable(void)
{
asm volatile(
"msr daifclr, #2" /* 프로세서의 DAIF 레지스터에서 인터럽트 플래그를 클리어 */
::: "memory");
}
- "msr daifclr, #2": DAIF 레지스터를 조작하여 인터럽트를 활성화
- DAIF: **Debug, Asynchronous, IRQ, FIQ(특정 인터럽트 종류)**를 관리하는 레지스터
- #2: IRQ 비트를 선택적으로 클리어한다.
- ARM64는 DAIF 레지스터를 사용하여 다양한 인터럽트의 상태를 관리한다.
- 다른 종류의 인터럽트(FIQ 등)와 독립적으로 IRQ만 활성화할 수 있다.
x86 아키텍처 (arch/x86/include/asm/irqflags.h)
static inline notrace void arch_local_irq_enable(void)
{
native_irq_enable();
}
static inline void native_irq_enable(void)
{
asm volatile("sti" ::: "memory");
}
- "sti": CPU의 인터럽트를 활성화하는 어셈블리 명령어
- IF는 x86 CPU에서 인터럽트를 제어하는 주요 플래그
- 인터럽트 플래그를 설정하면, 모든 하드웨어 인터럽트를 처리할 준비가 된다.
- x86은 다른 아키텍처와 달리 IF 플래그 하나로 인터럽트를 관리한다.
IRQ Domain
IRQ 도메인은 하드웨어와 소프트웨어의 인터럽트 번호를 연결하는 매핑 시스템으로 서로 다른 INTC(Interrupt Controllers)와 대응된다.
CONFIG_IRQ_DOMAIN_DEBUG
- 이 옵션은 하드웨어 IRQ 번호와 Linux IRQ 번호 간의 매핑 관계를 표시
- 매핑 정보는 irq_domain_mapping 파일을 통해 debugfs에 노출된다.
RT 커널에서의 스레드화된 IRQ (Threaded IRQs in RT kernel)
IRQ를 커널 스레드로 처리한다는 것은, 일반적인 인터럽트 핸들러가 하드웨어 인터럽트 컨텍스트에서 실행되는 대신, 이를 커널 스레드로 실행하도록 변경하는 것을 의미한다.
전통적인 IRQ 처리 방식
- 일반 커널에서는 IRQ 처리 로직이 하드웨어 인터럽트 컨텍스트에서 실행됨
- 인터럽트 발생 → 커널이 IRQ 핸들러 실행
- 핸들러는 매우 짧은 시간 안에 실행을 끝내야 함. 긴 작업은 softIRQ, tasklet 또는 워크큐로 연기됨.
- IRQ 핸들러는 매우 높은 우선순위로 실행되어 다른 작업을 차단됨
- IRQ 핸들러 자체가 중단될 수 없음 (Non-Preemptive)
- 특정 상황에서 높은 지연(latency)을 유발
스레드화된 IRQ 처리 방식
Threaded IRQ는 IRQ 핸들러를 하드웨어 인터럽트 컨텍스트가 아닌 일반 커널 스레드에서 실행하는 방식이다.
- 인터럽트 발생 → **최소한의 하드웨어 인터럽트 핸들러(Top-Half)**가 실행됨
- 여기서 하드웨어 상태를 확인하거나 데이터 수신 등 기본 작업만 수행
- 이후 인터럽트 처리 작업을 커널 스레드(IRQ 스레드)로 전환
- 하드웨어 인터럽트 컨텍스트에서 벗어나 일반 스레드 컨텍스트에서 실행
- 이 IRQ 스레드는 일반 커널 스레드처럼 우선순위를 조정하거나 CPU affinity를 설정할 수 있음
Threaded IRQ의 장점은
- 우선순위 조정 가능
- CPU Affinity 설정 가능
- Preemptible (중단 가능)
- 낮은 지연
softIRQ
네트워크 디바이스의 경우 NIC(Network Interface Controller) 가 IRQ(Interrupt Request) 를 발생시켜 패킷이 도착했으며 처리가 준비되었음을 알리는 것이 일반적이다.
IRQ 핸들러가 linux 커널에 의해 실행되면 매우 높은 우선순위로 실행되며 추가적인 IRQ 생성이 차단되는 경우가 많다.
따라서 디바이스 드라이버의 IRQ 핸들러는 가능한 빨리 실행을 완료하고 시간이 오래 걸리는 작업은 이 컨텍스트 외부에서 실행하도록 연기해야한다.
이를 위해 softirq 시스템이 존재한다.
softIRQ는 hardIRQ의 연속 작업을 커널 레벨에서 처리하며, tasklet은 softIRQ를 기반으로 한 경량화된 작업 처리 단위
linux kernel의 softIRQ는 디바이스 드라이버의 IRQ 컨텍스트 외부에서 작업을 처리하기 위한 시스템이다. 네트워크 디바이스의 경우 softIRQ 시스템은 들어오는 패킷을 처리하는 역할을 한다.
softIRQ 시스템은 커널의 부팅 과정 초기 단계에서 초기화된다.
softirq
softirq 라이프 사이클
1. 부팅 과정에서 open
References
'System Programming > Operating System' 카테고리의 다른 글
[OS] I/O처리 방식: Non-Blocking (0) | 2024.12.03 |
---|---|
linux에서 process 간 통신 #1 program and process (1) | 2024.09.08 |