Notification Chains
소개
리눅스 커널의 여러 하위시스템으로 구성된 거대한 [C](https://en.wikipedia.org/wiki/C_(programming_language))코드의 조각입니다. 각 서브 시스템은 다른 서브 시스템과 독립적인 고유한 목적을 가지고 있습니다. 그러나 종종 한 서브 시스템은 다른 서브 시스템에서 무언가를 알고 싶어합니다. 리눅스 커널에는 이 문제를 부분적으로 해결하는 것을 허용하는 특별한 메커니즘이 있습니다. 이 메커니즘의 이름은 notification chains
으로 이것의 주 목적은 다른 서브시스템을 위해 또 다른 서브시스템의 비동기 이벤트를 구독할 수 있는 방법을 제공하는 것입니다. 이 메커니즘은 커널 내부의 소통에만 사용되지만, 커널과 사용자 공간 간의 소통에는 또 다른 메커니즘이 있습니다.
notification chains
API와 이 API의 구현을 생각하기 전에, 이 책의 다른 파트에서 한 것처럼 이론적 측면에서 메커니즘을 살펴봅시다. notification chains
메커니즘과 관련된 모든 것은 include/linux/notifier.h헤더 파일 및 kernel/notifier.c소스코드 파일에 있습니다. 파일을 열어 살펴봅시다.
알림 체인 관련 데이터 구조체
관련 데이터 구조체에서 notification chains
메커니즘을 고려해봅시다. 위에서 쓴 것처럼, 메인 데이터 구조체는 include/linux/notifier.h헤더 파일에 있어야하므로 리눅스 커널은 특정 아키텍처에 의존하지 않는 일반 API를 제공합니다. 일반적으로, notification chains
메커니즘은 이벤트가 일어났을 때 수행되는 [callback](https://en.wikipedia.org/wiki/Callback_(computer_programming))함수의 리스트(chains
라 명명된 이유)를 나타냅니다.
이러한 모든 콜백 함수는 리눅스 커널에서 notifier_fn_t
형식으로 표시됩니다:
따라서 다음 세 가지 인자가 필요하다는 것을 알 수 있습니다:
nb
- 연결된 함수 포인터의 리스트(이제 볼 것입니다);action
- 이벤트 유형. 알림 체인은 여러 이벤트를 지원할 수 있으므로 다른 이벤트와 구별하려면 이 매개변수가 필요;data
- 제한 정보를 위한 저장공간. 실제로 이벤트에 대한 추가적인 데이터 제공을 허용함.
추가적으로 notifier_fn_t
이 정수값을 반환하는 것을 볼 수 있습니다. 이 정수 값은 다음 값중 하나일 수 있습니다:
NOTIFY_DONE
- 알림에 흥미가 없는 구독자;NOTIFY_OK
- 알림이 올바르게 처리됨;NOTIFY_BAD
- 무언가 잘못됨;NOTIFY_STOP
- 알림이 완료됐지만, 이벤트에 대해 더 이상 콜백을 호출하지 않아야 함.
이러한 모든 결과는 include/linux/notifier.h헤더 파일에서 매크로로 정의됩니다:
NOTIFY_STOP_MASK
에서 다음과 같이 표시됩니다:
매크로는 다음 알림 중에 콜백이 호출되지 않음을 의미합니다.
특정 이벤트에 대해 알림을 받으려는 리눅스 커널의 각 파트는 자체 notifier_fn_t
콜백 함수를 제공해야합니다. notification chains
메커니즘의 주 역할은 비동기 이벤트가 일어났을 때 특정 콜백을 호출하는 것입니다.
notification chains
의 주요 구성 요소는 notifier_block
구조체입니다:
include/linux/notifier.h파일에 정의되어 있습니다. 이 구조체는 콜백 함수notifier_call
에 대한 포인터, 다음 알림 콜백 및 처음으로 실행되는 높은 우선순위의 함수와 같은 콜백 함수 priority
에 대한 연결을 포함합니다.
리눅스 커널은 다음과 같은 네 가지 유형의 알림 체인을 제공합니다:
알리미 체인 차단;
SRCU 알리미 체인;
어토믹 알리미 체인;
가공되지 않은 알리미 체인.
이러한 유형의 알림 체인을 모두 순서대로 고려해봅시다:
첫 번째 경우는 blocking notifier chains
로, 콜백이 프로세스 컨텍스트에서 호출/실행됩니다. 이는 알림체인의 호출이 차단될 수 있다는 것을 의미합니다.
두 번째로 SRCU notifier chains
는 blocking notifier chains
의 다른 형식을 나타냅니다. 첫 번째 경우, 차단 알리미 체인은 rw_semaphore
동기화 기본을 사용해 체인 링크를 보호합니다. SRCU
알리미 체인은 프로세스 컨텍스트에서도 실행되지만, 읽기 측면에서 중요 섹션에서 차단할 수 있는 특별한 형식의 RCU메커니즘을 사용합니다.
세 번째 경우는 atomic notifier chains
으로 인터럽트 또는 어토믹 컨텍스트에서 실행되고 스핀락동기화 기본으로 보호됩니다. 마지막으로 raw notifier chains
는 콜백에 대한 잠금 제한 없이 알리미 체인의 특별한 유형을 제공합니다. 이는 보호가 호출자의 사이드 숄더에 달려 있음을 의미합니다. 이것은 매우 특정한 잠금 메커니즘으로 체인을 보호하려고 할 때 매우 유용합니다.
notifier_block
구조체의 구현을 살펴보면, 알림 체인 리스트에서 next
요소에 대한 포인터를 포함한 것을 볼 수 있지만, 헤드가 없습니다. 실제로 이러한 목록의 헤드는 별도의 구조체로 되어 있으며 알림 체인의 유형에 따라 다릅니다. 예시로 blocking notifier chains
대한 것입니다:
또는 atomic notification chains
에 대한 것입니다:
이제 우리는 notification chains
메커니즘에 관해 조금 알았고 API의 구현을 고려합시다.
알림 체인
일반적으로 발행/구독자 메커니즘에는 두 가지 측면이 있습니다. 한 측은 알림을 받고자 하고 다른 측은 이러한 알림을 생성합니다. 우리는 이 양 측면에서 알림 체인 메커니즘을 고려할 것입니다. 알림 체인의 다른 유형이 비슷하고 대부분 보호 메커니즘이 다르기 때문에 이 파트에서 blocking notification chains
을 고려할 것입니다.
알림 생성자가 알림을 생성하기 전에, 먼저 알림 체인의 헤드를 초기하해야 합니다. 예를 들어 커널 로드 가능 모듈과 관련된 알림 체인을 생각해봅시다. kernel/module.c소스 코드 파일을 보면, 다음 정의를 볼 수 있습니다:
알림 체인을 차단하는 로드 가능한 모둘을 위한 헤드를 정의합니다. BLOCKING_NOTIFIER_HEAD
매크로는 include/linux/notifier.h헤더 파일에서 정의되었으며 다음의 코드로 확장합니다:
따라서 알리미 체인을 차단하는 헤드의 이름의 이름을 얻고 읽기/쓰기 semaphore를 초기화하고 헤드를 NULL
로 설정하는 것을 볼 수 있습니다. BLOCKING_INIT_NOTIFIER_HEAD
매크로 외에도, 리눅스 커널에서 추가적으로 ATOMIC_INIT_NOTIFIER_HEAD
, RAW_INIT_NOTIFIER_HEAD
매크로와 어토믹 초기화를 위한 srcu_init_notifier
함수와 알림 체인의 다른 유형을 제공합니다.
알림 체인의 헤드를 초기화한 후에, 주어진 알림 체인에서 알림을 받길 원하는 서브시스템은 알림의 유형에 따른 특정 함수를 등록해야합니다. include/linux/notifier.h헤더 파일을 보면, 이에 대한 다음 네 가지 함수를 볼 수 있습니다:
위에서 이미 쓴 것처럼, 우리는 이 파트에서 알림 체인을 차단하는 것만 다루므로, blocking_notifier_chain_register
함수의 구현을 고려해봅시다. 이 함수의 구현은 kernel/notifier.c소스 코드 파일에 있으며 blocking_notifier_chain_register
이 두 가지 매개변수를 사용하는 것을 볼 수 있습니다:
nh
- 알림 체인의 헤드;nb
- 알림 디스크립터.
이제 blocking_notifier_chain_register
함수의 구현을 살펴봅시다:
우리가 보는 것처럼 동일한 소스 코드 파일에서 notifier_chain_register
함수의 결과를 반환하고 우리가 이해한 것처럼 이 함수는 우리를 위해 모든 기능을 수행합니다. notifier_chain_register
함수의 정의를 봅시다:
우리가 본 것처럼 blocking_notifier_chain_register
의 구현은 매우 간단합니다. 우선 현재 시스템 상태를 확인하는 검사가 있으며 재부팅 상태의 서브시스템이면 notifier_chain_register
를 호출합니다. 다른 방법으로 동일한 notifier_chain_register
의 호출을 수행하지만 우리가 본 것처럼 이 호출은 읽기/쓰기 세마포어로 보호됩니다. 이제 notifier_chain_register
함수의 구현을 봅시다:
이 함수는 새로운 notifier_block
(알림을 얻길 원하는 서브시스템에서 줌)을 알림 체인 리스트에 삽입합니다. 이벤트를 구독하는 것 외에도, 구독자는 unsubscribe
함수의 설정으로 특정 이벤트를 구독 취소 할 수 있습니다:
알림의 생산자가 구독자에게 이벤트에 대해 알리려고 할 때, *.notifier_call_chain
함수가 호출됩니다. 이미 알고 있듯이 각 알림 체인의 유형은 알림을 생성하는 자체 함수를 제공합니다:
blocking_notifier_call_chain
함수의 구현을 고려해봅시다. 이 함수는 kernel/notifier.c소스 코드 파일에서 정의되었습니다:
보시다시피 __blocking_notifier_call_chain
함수의 결과를 반환합니다. 우리가 볼 수 있듯이 blocking_notifer_call_chain
은 세 매개변수를 취합니다:
nh
- 알림 체인 리스트의 헤드;val
- 알림의 유형;v
- 처리기가 사용할 수 있는 입력 매개변수.
그러나 이 __blocking_notifier_call_chain
함수는 다섯 가지 매개변수를 취합니다:
호출되는 알리미 함수의 수와 전송되는 알림의 수는 nr_to_call
와 nr_calls
에 있습니다. 추측한 것처럼 __blocking_notifer_call_chain
함수와 다른 알림 유형을 위한 다른 함수의 주 목표는 이벤트가 일어났을 때 콜백 함수를 호출하는 것입니다. __blocking_notifier_call_chain
의 구현은 매우 간단합니다. 읽기/쓰기 세마포어로 보호되는 동일한 소스코드 파일에서 notifier_call_chain
함수를 호출합니다:
그리고 결과를 반환합니다. 이 경우 모든 작업은 notifier_call_chain
함수에 의해 수행됩니다. 이 함수의 주 목적은 등록된 알리미에게 비동기 이벤트에 관해 알려주는 것입니다:
그것이 전부입니다. 일반적으로 모든 것이 단순해 보입니다.
이제 로드 가능 모듈과 관련된 간단한 예를 생각해봅시다. kernel/module.c를 살펴볼 경우. 우리는 이미 이 파트에서 봤습니다:
kernel/module.c소스 코드 파일에 module_notify_list
의 정의가 있습니다. 아 정의는 커널 모듈의 차단 알리미 체인의 리스트의 헤드를 결정합니다. 다음과 같은 세 가지 이상의 이벤트가 있습니다:
MODULE_STATE_LIVE
MODULE_STATE_COMING
MODULE_STATE_GOING
리눅스 커널의 일부 하위시스템에 관심을 가질 수 있습니다. 예를 들어 커널 모듈 상태의 추적이 있습니다. atomic_notifier_chain_register
, blocking_notifier_chain_register
등의 직접 호출 대신, 대부분의 알림 체인은 그것들에 등록하는데 사용되는 래퍼의 모음과 함께 제공됩니다. 이러한 모듈 이벤트의 등록은 래퍼의 도움으로 진행됩니다:
kernel/tracepoint.c소스 코드 파일을 보면, 트레이스 포인트의 초기화가 이뤄지는 동의안 등록을 볼 수 있습니다:
tracepoint_module_nb
가 콜백 함수를 제공하는 곳:
MODULE_STATE_LIVE
, MODULE_STATE_COMING
또는 MODULE_STATE_GOING
중 하나의 이벤트가 일어났을 때. 예를 들어 MODULE_STATE_LIVE
MODULE_STATE_COMING
알림이 init_module 시스템 호출의 실행 중에 전달됩니다. 또는 예를 들어 MODULE_STATE_GOING
은 delete_module system call
의 실행 중에 전달됩니다:
따라서 이러한 시스템 호출 중 하나가 사용자 공간에서 호출되면, 리눅스 커널은 시스템 콜에 따르는 특정 알림을 보내고 tracepoint_module_notify
콜백 함수가 호출됩니다.
그것이 전부입니다.
Links
[C programming langauge](https://en.wikipedia.org/wiki/C_(programming_language))
Last updated