IT/Linux Kernel

디버깅을 통해 배우는 리눅스 커널의 구조와 원리 1, 도서 공부하기 31 - ksoftirqd 스레드에 대해서

변화의 물결1 2025. 6. 27. 00:05

 

 

 

안녕하세요.

 

Soft IRQ를 알아가면서 필요한 ksoftirqd에 대해서 알아보도록 하겠습니다.

 


 

 

1. ksoftirqd 스레드에 대해서

 

  percpu 타입의 프로세스이며 ksoftirqd 스레드는 CPU 코어의 개수만큼 생성돼서 정해진 CPU 내에서만 실행됩니다.

  ksoftirqd 프로세스는 커널 스레드로 Soft IRQ 서비스를 레벨에서 처리하는 역할입니다.

 

 라즈베리 파이에서 ksoftirqd를 확인할 수 있습니다.

 

pi# ps axl | grep ksoftirq

  

코어가 4개인 시스템인 것을 알 수 있으며 ksoftirqd/[CPU 번호] 같은 규칙으로 이름을 생성됩니다.

 

 

 

 ksoftirqd 스레드는 swawn_ksoftirqd()함수 내 smpboot_register_percpu_thread() 함수를 호출할 때 ksoftirqd 스레드를 생성합니다.

 

 736번 줄에서 smpboot_register_percpu_thread() 함수를 호출할 때 ksoftirqd 스레드를 생성합니다.

 ksoftirqd 스레드가 실행되면 run_ksoftirqd() 함수가 실행된다는 것은 이전 내용에 확인했습니다.

  

linux# vim kernel/softirq.c

 

 

 

 

 참고로 ksoftirqd 같은 percpu 타입의 스레드는 smp 핫플러그 스레드로 등록해서 실행됩니다. 커널에서 시스템 부하가 줄어들었을 때는 여러 개의 CPU가 동작할 필요가 없습니다.

  smboot를 관리하는 함수는 smboot_thread_fn()인데, 이 부분은 책 부분의 내용을 넘어간다고 하여 책 저자의 블로그를 참조하라고 나와 있습니다.

 

 

 

책에 있는 링크는 접속이 되지 않고, 다른 링크가 있어 참고 삼아 남겨 놓습니다.

https://austindhkim.tistory.com/200

 

 

2. run_ksoftirqd() 함수 확인

 

 ksoftirqd 프로세스가 실행될 때 호출 되는 핸들러 함수입니다.

 650번 줄에서 local_softirq_pending() 함수를 호출해서  Soft IRQ 서비스를 호출 점검하고 요청이 있으면 __do_softirq() 함수를 호출해서 Soft IRQ 서비스 핸들러를 실행합니다.

 

 

  

 ksoftirqd 스레드를 제어하는 ksoftirqd_should_run() 함수도 보면, local_softirq_pending() 함수를 호출해서 Soft IRQ 서비스 요청이 있으면 true, 없으면 false를 반환합니다.

 

 

  

3. Soft IRQ 컨텍스트에 대해

 

 Soft IRQ 컨텍스트는 Soft IRQ와 컨텍스트의 합성어입니다. 컨텍스트는 레지스터 세트로 실행 그 자체라고 인터럽트 관련 글에서 보았습니다.

 

 결국, 리눅스 커널에서는 Soft IRQ 서비스를 실행 중인 상태를 Soft IRQ 컨텍스트라고 정의할 수 있습니다.

 

1) Soft IRQ 컨텍스트의 시작점 확인

 

 Soft IRQ 컨텍스트는 __do_softirq() 함수에서 Soft IRQ 서비스 핸들러를 실행하기 전에 활성화된다고 볼 수 있습니다. 어느 코드에서 Soft IRQ 컨텍스트를 활성화하는지 알아봅니다.

 

__do_softirq() 함수의 코드를 Soft IRQ 관점에서 보면 아래와 같은 흐름을 볼 수 있습니다.

 

 269번 줄은 Soft IRQ 컨텍스트 활성화

 292번 줄은 Soft IRQ 서비스 핸들러 실행

 318번 줄은 Soft IRQ 컨텍스트 비활성화

 

그렇기 때문에 Soft IRQ 컨텍스트 활성화되는 시점이라고 한다면, __do_softirq() 함수에서 Soft IRQ 서비스를 실행하기 전이라고 할 수 있습니다.

 

 

 

2) Soft IRQ 컨텍스트는 언제 시작하는 확인

 

 위에서 본 코드에서 활성화하고 비활성화하는 코드를 확인했습니다. 그중에 SOFTIRQ_OFFSET를 확인해 볼 필요가 있습니다.

 

 SOFTIRQ_OFFSET은 (1UL << SOFTIRQ_SHIFT)로 되어 있습니다.

 매크로를 조금 따라가 가보면, SOFTIRQ_SHIFT 플래그는 8이 되므로 1 << 8 연산결과인 0x100(256)이 됩니다.

 

linux# vim include/linux/preempt.h

 

 

 

 다시 돌아와서 softirq.c 파일을 보면,

 

 Soft IRQ 컨텍스트의 시작은 __local_bh_disable_ip() 함수에서 설정합니다.

 

 124번 줄을 보면 __preempt_count_add() 함수 인자로 cnt를 그래도 전달하는데, cnt는 SOFTIRQ_OFFSET 플래그입니다.

 

 

 

 __preempt_count_add() 함수를 보면 *preempt_count_ptr() 함수의 매개변수인 val을 더하는 연산을 수행합니다.

 

linux# vim include/asm-generic/preempt.h

 

 

 

 *preempt_count_ptr()를 따라가 보면, current_thread_info() 함수를 통해 프로세스의 스택 최상단 주소에 있는 thread_info 구조체의 preempt_count 필드에 접근한다는 것을 알 수 있습니다.

 thread_info 관련 내용을 하면서 보았던 내용이라 낯설지는 않을 겁니다.

 

 

 

Soft IRQ 컨텍스트를 비활성화할 때는 __local_bh_enable() 함수를 호출합니다.  

 

 

 

 여기서는 __preempt_count_sub() 함수를 호출해서 preempt_count 필드의 값을 val만큼 뺍니다. 함수를 호출할 때 SOFTIRQ_OFFSET 플래그를 전달할 때 0x100을 thread_info의 preempt_count 필드에 추가했던 것을 빼는 연산을 수행합니다.

 

 

 

 Soft IRQ 컨텍스트 관점에서 보면 preempt_count 필드에 SOFTIRQ_OFFSET 플래그인 0x100을 포함하고 있으면 현재 프로세스는 Soft IRQ 컨텍스트라고 해석할 수 있습니다.

 

 

 in_interrupt() 함수처럼 in_softirq() 함수를 통해 현재 실행 중인 코드가 Soft IRQ 컨텍스트인지 판단할 수 있습니다. 함수 구현은 아래와 같습니다.

 

linux# vim include/linux/preempt.h

 

 

 

 

 

감사합니다.

 

 

<참고 자료>

1. [도서] 디버깅을 통해 배우는 리눅스 커널의 구조와 원리 p490~502, wikibook

 

 

 

반응형