28.2.1.1. px4::WorkItem 클래스 상속을 통한 Work Queue 스케줄링 메커니즘
PX4 운영체제 추상화 계층(OSAL)이 한정된 임베디드 리소스를 쥐어짜 내어 제공하는 가장 강력한 무기 중 하나인 비동기 워크 큐(Work Queue) 스케줄링 시스템에 탑승하기 위해, FlightModeManager 마이크로서비스 클래스는 자신의 C++ 뼈대에 **px4::WorkItem 추상 기초 클래스의 상속(Inheritance)**이라는 핵심적인 설계적 결단을 내린다.
1. 다중 상속 기반의 마이크로서비스 클래스 템플릿 구조
src/modules/flight_mode_manager/flight_mode_manager.hpp 헤더 파일을 조심스럽게 파헤쳐보면, FMM 구동계의 최상단 코어 클래스는 아래와 같이 두 개의 거대한 PX4 시스템 부모 클래스 템플릿들을 어깨에 짊어지고 다중 상속(Multiple Inheritance) 받아 탄생하는 것을 목격할 수 있다.
class FlightModeManager : public ModuleBase<FlightModeManager>, public ModuleParams, public px4::WorkItem
ModuleBase<FlightModeManager>상속: 이 C++ 템플릿 부모는 픽스호크 콘솔 셸(NuttShell/NSH) 환경 터미널에서 사용자가 타이핑하는flight_mode_manager start나status명령어 문자열 입력을 파싱하고, 백그라운드 데몬의 초기 램 메모리 셋업과 전단 라이프사이클을 책임지는 OS 친화적 시작 프로그램(Launcher) 규격 역할을 전담한다.ModuleParams상속: QGroundControl에서 내리는 외부 파라미터(Parameter) 값들의 런타임 콜백 갱신 동기화를 스레드 세이프하게 보장받기 위한 PX4 기본 파라미터 엔진 플러그인 클래스다.px4::WorkItem상속: 이 위대한 추상 부모 클래스가 바로 FMM 데몬 전체를 구시대적 무한 루프 악몽에서 구원하여 모던 이벤트 스케줄러로 인도해 준 핵심 커널 드라이버다. 이 클래스를 상속받는 순간 FMM은 평범하고 멍청한 C++ 객체에서 완전히 벗어나, NuttX RTOS 시스템 커널 워크 스케줄러가 스레드 풀 번호표를 직접 관장하는 **하나의 능동형 대기표(Ticket)를 가진 워크 아이템(Work Item Task)**으로 거듭나게 된다.
2. 아키텍처 인터페이스 강제: Run() 가상 함수(Virtual Function)의 절대적 오버라이딩
px4::WorkItem 부모 클래스는 자식 클래스인 FMM에게 자율성을 보장하는 대신 단 딱 하나의 피의 규율만을 엄격하게 강제한다. 바로 순수 가상 함수이자 진입점인 virtual void Run() = 0; 스코프를 반드시 자식의 몸통 내부에 구체적으로 구현(Override)하여 대령해 놓으라는 것이다.
이 강제로 뚫어놓은 Run() 함수야말로, OS 커널 워크 큐 스케줄러가 이벤트(예: 하위 EKF에서 상태 토픽 업데이트 수신)를 인지하고 잠자는 FMM 데몬을 마이크로초 단위로 깨울 때 커널 레벨에서 다이렉트로 무식하게 때려버리는(포인터 다형성 호출하는) 유일무이한 진입점(Entry Point)이자 심장 박동(Heartbeat) 트리거 함수가 된다.
FMM 모듈 내부에 존재하는 그 어떤 화려한 비행 궤적 로직이나, 복잡한 객체 지향 팩토리 태스크 스위칭 알고리즘도 모두가 결국 이 좁고 단일화된 Run() 함수의 중추 관문을 거쳐 출발하여 실행 트리(Execution Tree) 가지를 뻗어 나가야만 하는 병목적 절차 지향성을 수용하게 된다.
3. 커널 타스크 스케줄링 3대 트리거 유틸리티 메서드
px4::WorkItem 부모 기초 클래스로부터 상속 물려받아, FMM 데몬이 스스로의 작업 스케줄링 생명을 커널 스케줄러에게 밀고 당기며 통보할 때 자유자재로 꺼내 쓰는 핵심 스레드 제어 무기 메서드(Methods) 3인방은 다음과 같다.
ScheduleNow()메서드:
- 지금 당장 우선순위 불문하고 즉시 내
Run()메인 함수를 워크 큐 대기열 맨 앞줄에 새치기로 끼워 넣어 빨리 스케줄링 연산해 달라는 가장 강력한 긴급 호출 메서드다. uORB 데이터 버스를 폴링하던 중에 조종사의 즉각적인 킬-스위치 개입이나 오프보드 경로 변경 같은 비동기 이벤트가 수신되었을 때, 지연을 0으로 깎아내리기 위해 자신 스스로의 꼬리를 물고 리스케줄링(Self-Rescheduling) 목적으로 폭력적으로 사용한다.
ScheduleDelayed(uint32_t delay_us)메서드:
- FMM이 찰나의
Run()함수 실행 연산 사이클을 끝마치고 스레드 제어권을 리턴하여 깊은 잠에 빠지기 직전에 커널에 던지는 마지막 유언장과도 같다. “나 지금 CPU 넘겨주고 쉴 건데, 정확히 마이크로 타이머로 50밀리초(50000_us) 뒤에는 이벤트가 있든 없든 반드시 하드웨어 알람 울려서 다시 내Run()함수 좀 강제로 깨워줘“라고 스케줄러의 타임 알람보드를 세팅하는 약속 명령어다. 외부 토픽 이벤트 인터럽트가 혹여나 유실되어 들어오지 않더라도, FMM이 스스로 목숨을 연명하며 최소한의 비상 고도 보장 페일세이프 생존(Failsafe Survival Timeout) 주기 루프를 유지하기 위한 든든한 하드웨어 와치독(Watchdog) 보증 수표로 사용된다.
ScheduleClear()메서드:
- 과거 틱(Tick)에서 기존에 예약해 두었던 OS 워크 큐 모든 스케줄링 대기열 포인터와 타임아웃 알람을 커널에서 완전히 강제로 캔슬하고 파기(Revoke)해 버린다. 사용자의 콘솔 명령으로 데몬 모듈 자체가 아예 완전히 다운되어 종료(
flight_mode_manager stop명령어)될 때, 램 스레드 큐(Queue) 대기열에서 스스로의 찌꺼기 흔적을 단 한 바이트의 패닉 없이 깔끔하게 지워내고 메모리를 안전하게 수거당하기 위한 자폭 준비 호흡 정지 루틴으로 호출된다.