커널

15. 라즈베리파이 - thread_info 구조체_preempt_count 필드

corin13 2025. 7. 13. 17:10

선점 관련. 0 아닌 상태에서는 선점 불가능한 프로세스가

 

컨텍스트

1.프로세스 컨텍스트

  • 특정 프로세스 또는 쓰레드가 CPU에서 실행될 해당 프로세스의 상태, 메모리, 레지스터, 시스템 리소스 사용 정보 포함
  • , 현재 실행 중인 프로세스의 실행 환경 전체를 의미 -> 프로세스의 집합 정도..?
  • 프로세스 관련 정보가 프로세스 컨텍스트고, 태스크에 관련된 정보가 다른 태스크로 넘어가기 위해 바뀌는 과정을 컨텍스트 스위치라 부름
  • 중요성 : 컨텍스트는 시스템에서 프로세스가 전환될 (Context Switch) 저장되고 복원됨. 이를 통해 다중 프로세스 시스템에서 프로세스가 마치 독립적인 환경에서 실행되는 것처럼 관리됨

2.인터럽트 컨텍스트

인터럽트 : ex) 키보드 누르기 -> 이때 기존 실행되던 것을 저장 -> 특별한 처리를 위한 루틴 진입 -> 다시 복귀

  • 시스템이 인터럽트 또는 예외 상황에 응답할 때의 실행 상황을 의미
  • 이때, 커널은 사용자 프로세스의 컨텍스트를 잠시 중단하고 인터럽트 처리 루틴을 실행ㄹ함
  • 인터럽트 컨텍스트는 프로세스 컨텍스트에 비해 훨씬 간소화되어 있으며, 전환 저장해야 하는 정보도 상대적으로 적음
  • 커널에서 인터럽트가 발생해서 인터럽트 서비스 루틴을 실행하는 동작을 인터럽트 컨텍스트라

프로세스 컨텍스트는 프로그램과 프로그램 사이에 일어남 -> 프로세스가 완전히 바뀜 -> 오버헤드

 

Preempt_count 값은 여러 상태를 나타낼 있음

  • 인터럽트 컨텍스트가 실행중이다 / 종료되었다
  • Soft IRQ 컨텍스트가 실행중이다 / 종료중이다
  • 프로세스 선점 스케줄링이 가능한가

 

인터럽트 컨텍스트 실행 표기

  • preempt_count 필드에 인터럽트가 실행 중인 상태를 나타내는 비트를 설정. 비트를 읽어 인터럽트 컨텍스트 유무 식벽
  • in_interrupt 함수를 통해 현재 실행 중인 코드가 인터럽트 컨텍스트 내에 있는지 알려줌

irq_enter에서 preempt_count 값을 0x10000 추가하는 부분이 있다 -> 부분에서 in_interrupt true 바뀐다

 

 

131 # define in_interrupt() (irq_count()) -> true == 인터럽트 컨텍스트

108 # define irq_count() (mmi_count() | hardirq_count() | softirq_count())

101 # define nmi_count() (prrempt_count & NIM_MASK)

102 # define hardirq_count() (preempt_count() & HARDIRQ_MASK)

 

preempt.h 열기

우측의 thread_info.h 활용하는 것을 있음

 

hardirq.h 열기

 

irq_enter() 부분의 preempt_count_add 부분에서 preempt_count 값이 바뀐다

 

linux/arch/arm64/include/asm/preempt.h preempt_count_add 부분

 

val 들어가는 값을 아래에 정의되어 있음

Hard IRQ중이면 필드를 0x10000으로 설정

 

인터럽트 컨텍스트가 종료하는 부분은?

 

irq_exit -> __irq_exit_rcu

 

__irq_exit_rcu 보면 660 sub하는 부분이 보임

 

linux/arch/arm64/include/asm/preempt.h 보면 더한 값을 다시 빼주는 있음

지금까지 인터럽트 컨텍스트가 실행중이다 / 종료되었다 부분을 확인한

 

이제 Soft IRQ 컨텍스트가 실행중이다 / 종료중이다를 확인할 차례

 

Soft IRQ?

  • 하드웨어 인터럽트는 즉각적인 처리가 필요한 작업에 사용되므로 우선순위가 높음
  • 소프트웨어 인터럽트는 하드웨어 인터럽트에 의해 예약된 작업을 나중에 처리하기 위해 발생하므로 우선순위가 상대적으로 낮음
  • 소프트웨어 인터럽트는 커널 스케줄링에 의해 관리됨
  • 급하면 Hard IRQ(하드웨어 인터럽트), 급하면 Soft IRQ(소프트웨어 인터럽트) 넘김

 

Soft IRQ중인지는 in_interrumpt() 아닌 in_softirq() 있음

-> true soft irq, 필드를 0x100으로 설정

 

softirq.c 열기

 

__do_softirq -> handle_softirqs

 

아래 부분에서 preempt_count값을 변화시킴

 

 

softirq_handle_begin -> __local_bh_disable_ip인데, 2번째 인자에 값이 들어감

 

__local_bh_disable_ip cnt 들어가게 되고, __preept_count_add(cnt) 통해 호출

 

preempt.h의

 

__preempt_count_add함수

 

값을 되돌리는 부분은 607, softirq_handle_end()

 

softirq_handle_end -> __local_bh_enable

__local_bh_enable 보면 값을 되돌리는 부분이 보임

__preempt_count_sub 부분

 

이렇게 Soft_IRQ 시작/종료부분을 확인함

 

마지막으로 프로세스 선점 스케줄링 가능 여부 확인하기

 

 

주석으로 preempt_count 값이 0이면 선점 가능, 0보다 작으면 버그라 적혀 있음

그러려면 need_resched count 0 되어야

 

30, set_preempt_need_resched

preempt.need_resched값을 0으로 설정 -> count 값도 0이면 선점 가능

 

35, clear_preempt_need_resched

preempt.need_resched값을 1 설정 -> count 값에 상관없이 0 아니므로 선점 불가능

 

core.c 열기

should_resched irq_disabled 조건으로 사용

 

 

should_resched

선점이 가능하면 1 반환함

 

core.c 돌아와서

7246, 1(선점 가능) && !irqs_disabled니까 인터럽트가 활성화중일 때만 선점 스케줄링 진행?

7247, 선점 스케줄링이 가능한 상태니까 스케줄러가 작업을 하도록 만드는 함수