Clockevents framework
clockevents
프레임 워크 소개
clockevents
프레임 워크 소개이것은 리눅스 커널에서 타이머 및 시간 관리 관련 사항을 설명하는 chapter의 다섯 번째 부분입니다. 이 부분의 제목에서 알 수 있듯이 clockevents
프레임 워크가 논의됩니다. 우리는 이미 이 장의 두번째 부분에서 하나의 프레임 워크를 보았습니다. clocksource
프레임 워크였습니다. 이 두 프레임 워크는 모두 Linux 커널에서 시간을 유지하는 추상화를 나타냅니다.
처음에는 메모리를 새로 고치고 그것이 clocksource
프레임 워크와 그 목적이 무엇인지 기억하려고 노력하십시오. clocksource
프레임 워크의 주요 목표는 documentation에 설명 된대로 타임 라인
을 제공하는 것입니다. :
예를 들어 Linux 시스템에서
date
명령을 실행하면 clcok source를 읽어 정확한 시간을 결정합니다.
Linux 커널은 다양한 클럭 소스를 지원합니다. 이들 중 일부는 drivers/clocksource에서 찾을 수 있습니다. 예를 들어 오래된 좋은 1193182
Hz 주파수의 Intel 8253-프로그램 간격 타이머, 3579545
Hz 주파수의 ACPI PM 타이머 등. drivers/clocksource 디렉토리 외에도 각 아키텍처는 고유 한 아키텍처 별 클럭 소스를 제공 할 수 있습니다. 예를 들어 x86 아키텍처는 High Precision Event Timer를 제공하거나 powerpc에서는 timebase
레지스터를 통해 프로세서 타이머에 액세스 할 수 있습니다.
각 클럭 소스는 단조 원자 카운터를 제공합니다. 이미 쓴 것처럼 Linux 커널은 다양한 클럭 소스 세트를 지원하며 각 클럭 소스에는 frequency와 같은 자체 매개 변수가 있습니다. clocksource
프레임 워크의 주요 목표는 API를 제공하여 시스템에서 사용 가능한 최상의 클럭 소스, 즉 가장 높은 주파수를 가진 클럭 소스를 선택하는 것입니다. clocksource
프레임 워크의 추가 목표는 인간 단위로 클럭 소스가 제공하는 원자 카운터를 나타내는 것입니다. 이 시점에서, 나노 초는 Linux 커널에서 주어진 클럭 소스의 시간 값 단위로 선호되는 선택입니다.
include/linux/clocksource.h 에 정의 된 clocksource
구조로 표시되는 clocksource
프레임 워크는 클럭 소스의 이름, 시스템의 특정 클럭 소스 등급 (주파수가 높은 클럭 소스는 시스템에서 가장 높은 등급을 가짐), 시스템에 등록 된 모든 클럭 소스의 목록
과, enable
및 disable
필드는 클럭 소스를 활성화 및 비활성화하며, 클럭 소스의 원자 카운터 등을 반환해야하는 read
함수에 대한 포인터를 포함합니다.
또한 clocksource
구조는 mult
와 shift
라는 특정 클록 소스에 의해 인간 단위로 제공되는 원자 카운터의 변환에 필요한 두 개의 필드를 제공합니다.
ex) nanoseconds.
우리가 이미 알고 있듯이clocksource
구조 외에 clocksource
프레임 워크는 다른 주파수 스케일 팩터로 클록 소스를 등록하기 위한 API를 제공합니다.
클럭 소스 등록 취소 :
등
clocksource
프레임 워크 외에도 Linux 커널은 clockevents
프레임 워크를 제공합니다. documentation에 설명 된대로 :
클럭 이벤트는 클럭 소스의 개념적 역전입니다
의 주요 목표는 시계 이벤트 장치 또는 다른 말로 이벤트를 등록 할 수있는 장치를 관리하는 것입니다. 즉, interrupt 미래의 정해진 시점에 발생합니다.
이제 우리는 리눅스 커널의 clockevents
프레임 워크에 대해 조금 알고 있으며 이제는 API를 볼 차례입니다.
clockevents
프레임워크의 API
clockevents
프레임워크의 API클럭 이벤트 장치를 설명하는 주요 구조체는 clock_event_device
구조체입니다. 이 구조는 include/linux/clockchips.h 헤더 파일에 정의되어 있으며 거대한 필드 세트를 포함합니다. clocksource
구조뿐만 아니라 사람이 읽을 수 있는 시계 이벤트 장치 이름을 포함하는 name
필드가 있습니다 (예 : local APIC timer).
event_handler
, set_next_event
, next_event
의 주소는 인터럽트 핸들러 인 특정 시계 이벤트 장치에 대한 기능이며, 다음 이벤트의 설정자 및 로컬 다음 이벤트를 위한 스토리지 설정입니다. clock_event_device
구조의 또 다른 필드는 features
필드입니다. 그 가치는 다음과 같은 일반적인 기능 중 하나 일 수 있습니다.
여기서 CLOCK_EVT_FEAT_PERIODIC
은 이벤트를 주기적으로 생성하도록 프로그래밍 될 수있는 장치를 나타냅니다. CLOCK_EVT_FEAT_ONESHOT
는 이벤트를 한 번만 생성 할 수있는 장치를 나타냅니다. 이 두 기능 외에도 아키텍처 별 기능도 있습니다. 예를 들어 x86_64는 두 가지 추가 기능을 지원합니다.
첫 번째 CLOCK_EVT_FEAT_C3STOP
은 C3 상태에서 시계 이벤트 장치가 중지됨을 의미합니다. 또한 clock_event_device
구조에는 clocksource
구조뿐만 아니라 mult
및 shift
필드가 있습니다. clocksource
구조는 다른 필드도 포함하지만 나중에 고려할 것입니다.
clock_event_device
구조의 일부를 고려한 후, clockevents
프레임 워크의 API
를 살펴 볼 시간입니다. 시계 이벤트 장치를 사용하려면 먼저 clock_event_device 구조를 초기화하고 시계 이벤트 장치를 등록해야합니다. clockevents
프레임 워크는 클록 이벤트 장치의 등록을 위해 다음과 같은 API를 제공합니다.
이 함수는 kernel/time/clockevents.c 소스 코드 파일에 정의되어 있습니다. clockevents_register_device
함수는 하나의 매개 변수 만 사용합니다.
클럭 이벤트 장치를 나타내는
clock_event_device
구조의 주소.
따라서 클럭 이벤트 장치를 등록하려면 먼저 특정 클럭 이벤트 장치의 매개 변수로 clock_event_device
구조를 초기화해야합니다. 리눅스 커널 소스 코드에서 하나의 랜덤 클럭 이벤트 장치를 살펴봅시다. drivers/clocksource 디렉토리에서 찾거나 아키텍처 별 시계 이벤트 장치를 살펴보십시오. 예를 들어 at91sam926x 용 PIT (Periodic Interval Timer)를 예로 들어 보겠습니다. 구현은 drivers/ locksource에서 찾을 수 있습니다.
우선clock_event_device
구조의 초기화를 살펴 봅시다. 이것은 at91sam926x_pit_common_init
함수에서 발생합니다 :
여기서 우리는 at91sam926x_pit_common_init
가 하나의 매개 변수를 취한다는 것을 알 수 있습니다. at91sam926x
의 주기 이벤트 관련 정보를 포함하는 clock_event_device
구조체를 포함하는 pit_data
구조체에 대한 포인터 주기 간격 타이머. 처음에는 타이머 장치의 이름과 기능을 채 웁니다. 우리의 경우 우리가 이미 알고 있듯이 주기적으로 이벤트를 생성하도록 프로그래밍 될 수 있는 주기적인 타이머를 처리합니다.
다음 두 필드 인 shift
와 mult
는 우리에게 친숙합니다. 타이머 카운터를 나노초로 변환하는 데 사용됩니다. 그런 다음 타이머 등급을 100
으로 설정했습니다. 즉, 시스템에 등급이 높은 타이머가없는 경우이 타이머는 시간 표시에 사용됩니다. 다음 필드 인 cpumask
는 시스템에서 장치가 작동 할 프로세서를 나타냅니다. 우리의 경우 장치는 첫 번째 프로세서에서 작동합니다. include/linux/cpumask.h 헤더 파일에 정의 된 cpumask_of
매크로는 호출로 확장됩니다.
여기서 get_cpu_mask
는 주어진 cpu
번호를 포함하는 cpumask를 반환합니다. cpumasks
개념에 대한 자세한 내용은 Linux 커널의 CPU 마스크 부분에서 읽을 수 있습니다. 마지막 4 줄의 코드에서 시계 이벤트 장치 일시 중지 / 재개, 장치 종료 및 시계 이벤트 장치 상태 업데이트에 대한 콜백을 설정했습니다.
at91sam926x
주기 타이머 초기화를 완료 한 후 다음 함수를 호출하여 등록 할 수 있습니다.
이제 우리는 clockevent_register_device
함수의 구현을 고려할 수 있습니다. 위에서 이미 작성했듯이이 함수는 kernel/time/clockevents.c 소스 코드 파일 및 초기 이벤트 장치 상태의 초기화에서 시작합니다.
실제로 이벤트 장치는 다음 상태 중 하나 일 수 있습니다.
CLOCK_EVT_STATE_DETACHED
- 시계 이벤트 장치는clockevents
프레임 워크에서 사용되지 않습니다. 실제로 모든 시계 이벤트 장치의 초기 상태입니다.CLOCK_EVT_STATE_SHUTDOWN
- 시계 이벤트 장치의 전원이 꺼져 있습니다.CLOCK_EVT_STATE_PERIODIC
- 클록 이벤트 장치는 주기적으로 이벤트를 생성하도록 프로그래밍 될 수 있습니다.CLOCK_EVT_STATE_ONESHOT
- 클럭 이벤트 장치는 이벤트를 한 번만 생성하도록 프로그래밍 될 수 있습니다.CLOCK_EVT_STATE_ONESHOT_STOPPED
- 시계 이벤트 장치가 이벤트를 한 번만 생성하도록 프로그래밍되었으며 이제 일시적으로 중지되었습니다.
clock_event_set_state
함수의 구현은 매우 쉽습니다.
보시다시피, 주어진clock_event_device
구조체의 state_use_accessors
필드를 주어진 값으로 채웁니다. 이 경우에는 CLOCK_EVT_STATE_DETACHED
입니다. 실제로 모든 시계 이벤트 장치는 등록 중에 이 초기 상태를 갖습니다. clock_event_device
구조의 state_use_accessors
필드는 클럭 이벤트 장치의 현재 상태를 제공합니다.
주어진 clock_event_device
구조의 초기 상태를 설정 한 후 주어진 시계 이벤트 장치의 cpumask
가 0이 아닌지 확인합니다.
at91sam926x
주기 타이머의 cpumask
를 첫 번째 프로세서로 설정했음을 기억하십시오. 만약 cpumask
필드가 0이라면, 우리는 시스템에서 가능한 프로세서의 수를 확인하고 경고 메시지가 on보다 작 으면 인쇄합니다. 또한 주어진 클럭 이벤트 장치의 cpumask
를 현재 프로세서로 설정합니다. smp_processor_id
매크로가 어떻게 구현되는지에 관심이 있다면, 리눅스 커널 초기화 과정 장의 네 번째 part에서 더 자세히 읽을 수 있습니다.
이 검사 후 매크로 다음 호출에 의해 시계 이벤트 장치 등록의 실제 코드를 잠급니다.
또한 raw_spin_lock_irqsave
및 raw_spin_unlock_irqrestore
매크로는 로컬 인터럽트를 비활성화하지만 다른 프로세서의 인터럽트는 여전히 발생할 수 있습니다. 클록 이벤트 디바이스 목록에 새 클록 이벤트 디바이스를 추가하고 다른 클록 이벤트 디바이스에서 인터럽트가 발생하는 경우 잠재적 교착 상태를 방지하기 위해 이를 수행해야합니다.
raw_spin_lock_irqsave
와 raw_spin_unlock_irqrestore
매크로 사이에 다음과 같은 시계 이벤트 장치 등록 코드를 볼 수 있습니다.
우선, 주어진 clock 이벤트 장치를 clockevent_devices
로 표시되는 시계 이벤트 장치 목록에 추가합니다.
다음 단계에서 우리는 kernel/time/tick-common.c 소스 코드 파일에 정의 된tick_check_new_device
함수를 호출합니다. 소스코드 파일 및 검사는 새로운 등록 된 시계 이벤트 장치의 사용 여부를 확인합니다. tick_check_new_device
함수는 주어진 clock_event_device
가 tick_device
구조로 표시되는 현재 등록 된 틱 장치를 가져 와서 등급과 기능을 비교합니다. 실제로 CLOCK_EVT_STATE_ONESHOT
이 선호됩니다 :
새로 등록 된 시계 이벤트 장치가 이전 틱 장치보다 선호되는 경우 이전 및 새 등록 장치를 교환하고 새 장치를 설치합니다.
clockevents_exchange_device
기능이 해제되거나 다른 말로하면 clockevent_devices
목록에서 기존 시계 이벤트 장치가 삭제되었습니다. 다음 함수 인 tick_setup_device
는 이름에서 알 수 있듯이 새로운 틱 장치를 설정합니다. 이 기능은 새로 등록 된 시계 이벤트 장치의 모드를 확인하고 틱 장치 모드에 따라 tick_setup_periodic
함수 또는 tick_setup_oneshot
을 호출합니다.
이 함수는 모두 시계 이벤트 장치의 상태를 변경하기 위해 clockevents_switch_state
를 호출하고 다음 이벤트의 최대 및 최소 차이 현재 시간과 시간 사이의 델타를 기반으로 시계 이벤트 장치의 다음 이벤트를 설정하기 위해 clockevents_program_event
함수를 호출합니다. tick_setup_periodic
:
그리고tick_setup_oneshot_periodic
:
clockevents_switch_state
함수는 시계 이벤트 장치가 주어진 상태에 있지 않은지 확인하고 동일한 소스 코드 파일에서 __clockevents_switch_state
함수를 호출합니다.
__clockevents_switch_state
함수는 주어진 상태에 따라 특정 콜백을 호출합니다.
at91sam926x
주기 타이머의 경우 상태는CLOCK_EVT_FEAT_PERIODIC
입니다.
따라서pit_clkevt_set_periodic
콜백이 호출됩니다. at91sam926x 용 PIT (Periodic Interval Timer) 문서 를 읽으면 주기 간격 타이머 모드 레지스터
가 있음을 알 수 있습니다. 주기적 간격 타이머를 제어 할 수 있습니다.
다음과 같습니다.
PIV
또는 Periodic Interval Value
- 주기 간격 타이머의 기본 20 비트
카운터와 비교하여 값을 정의합니다. 비트가 1
이면 PITEN
또는 주기 간격 타이머 사용
, 비트가 1
이면 PITIEN
또는 주기 간격 타이머 인터럽트 사용
. 따라서 주기적 모드를 설정하려면 주기 간격 타이머 모드 레지스터에서 24 비트, 25 비트를 설정해야합니다. 그리고 우리는 pit_clkevt_set_periodic
기능에 그것을 하고 있습니다 :
AT91_PT_MR
, AT91_PT_PITEN
및 AT91_PIT_PITIEN
은 다음과 같이 선언됩니다.
새로운 시계 이벤트 장치의 설정이 끝나면 clockevents_register_device
기능으로 돌아갈 수 있습니다.
clockevents_register_device
함수의 마지막 함수는 다음과 같습니다.
함수는 해제 된 클럭 이벤트 장치를 포함하는 clockevents_released
목록을 확인합니다 ( clockevents_exchange_device
함수 호출 후 발생할 수 있음을 기억하십시오). 이 목록이 비어 있지 않으면 clock_events_released
목록에서 시계 이벤트 장치를 살펴보고 clockevent_devices
에서 삭제합니다.
그게 전부 입니다. 지금부터 새로운 시계 이벤트 장치를 등록했습니다. 따라서 clockevents
프레임 워크의 사용법은 간단하고 명확합니다. 아키텍처는 시계 이벤트 코어에 시계 이벤트 장치를 등록했습니다. clockevents
코어 사용자는 시계 이벤트 장치를 사용할 수 있습니다. clockevents
프레임 워크는 등록되거나 등록되지 않은 시계 이벤트 장치와 같은 다양한 시계 관련 관리 이벤트에 대한 알림 메커니즘을 제공하며 프로세서는 CPU hotplug 등을 지원하는 시스템에서 오프라인 상태입니다.
우리는 clockevents_register_device
함수의 구현만을 보았습니다. 그러나 일반적으로 시계 이벤트 계층 API는 작습니다. 클록 이벤트 장치 등록을위한 API 외에, 클록 이벤트 프레임 워크는 다음 이벤트 인터럽트, 클록 이벤트 장치 통지 서비스를 예약하고 클록 이벤트 장치의 일시 중단 및 재개를 지원하는 기능을 제공합니다.
clockevents
API에 대해 더 알고 싶다면 다음 소스 코드와 헤더 파일을 연구 할 수 있습니다. kernel/time/tick-common.c, kernel/time/clockevents.c 및 include/linux/clockchips.h.
결론
이것은 리눅스 커널에서 타이머와 타이머 관리 관련 사항을 설명하는 chapter의 다섯 번째 부분 입니다. 이전 부분에서는 타이머
개념에 대해 알게되었습니다. 이 부분에서 우리는 리눅스 커널에서 시간 관리 관련 내용을 계속 배웠고 또 다른 프레임 워크 인 clockevents
에 대해 조금 보았습니다.
질문이나 제안 사항이 있으면 Twitter 0xAX에 핑(Ping)을 보내거나 email을 보내거나 issue를 만드세요.
링크
Last updated