18.4.1.3 orb_advert_t 포인터 핸들의 반환과 모듈 내 전역 변수 유지 메커니즘
new uORBDeviceNode(...) 생성과 register_driver() VFS 마운트가 성공적으로 마무리되면, orb_advertise() 함수 체인은 길었던 여행을 마치고 드디어 사용자 코드(모듈)로 되돌아간다. 이때 반환되는 리턴 값의 타입이 바로 orb_advert_t 이다.
이 반환값은 단순히 성공과 실패를 알리는 정수(Integer)가 아니다. 이는 향후 1000Hz가 넘는 속도로 데이터를 퍼블리싱해야 하는 센서 드라이버에게 있어 가장 소중한 VIP 패스(Pass) 와도 같다.
1. orb_advert_t의 진정한 정체: 노드 메모리 주소(Pointer)
orb_advert_t의 정체를 알기 위해 C/C++ 헤더 파일을 파고들어가 보면, 이는 단순히 특정 구조체의 포인터를 가리키기 위해 typedef 된 포인터 제어 핸들(Handle) 타입임을 확인할 수 있다.
더 구체적으로 말하자면, 이 핸들의 알맹이는 방금 힙(Heap) 메모리에 할당했던 바로 그 uORBDeviceNode C++ 객체의 메모리 주소(Pointer) 이다!
사용자 모듈이 이 핸들을 쥐고 있다는 것은 무엇을 의미할까? 차후 데이터를 발행(orb_publish)하기 위해 커널의 /obj VFS 경로를 비싼 OS 시스템 콜(open())을 태워 다시 문자열 순회 검색하며 찾을 필요가 전혀 없다는 뜻이다. 커널 모드로 진입하기 전, 이미 사용자 스페이스(User space) 레벨에서 직접 해당 노드 객체의 메모리에 접근할 수 있는 프리패스 권한을 손에 넣은 것이다.
2. 정적(Static) 전역 변수를 활용한 생명 주기(Lifecycle) 관리
PX4의 센서 드라이버 소스 코드들을 살펴보면, orb_advert_t 타입의 변수들을 모듈 내의 최상단 정적(Static) 전역 변수나, 제어기 클래스(ModuleBase 상속)의 프라이빗(Private) 멤버 변수로 은밀하게 저장해 두는 패턴을 흔히 목격할 수 있다.
// 예시: 자이로스코프 데이터 퍼블리셔 핸들 보관
orb_advert_t _sensor_gyro_pub{nullptr};
// 초기화 타이밍
_sensor_gyro_pub = orb_advertise(ORB_ID(sensor_gyro), &gyro_data);
이렇게 모듈의 심장부에 전역적인 상태로 핸들을 꽉 쥐고(Cache) 유지하는 설계에는 치밀한 의도가 숨어있다.
- O(1) 퍼블리싱 성능 보장: 비행 제어기(Flight Controller)의 메인 루프 (Main Loop) 가 400Hz로 돌며
orb_publish(_sensor_gyro_pub, &gyro_data)를 호출할 때마다, 이 핸들 캐싱 덕분에 노드를 재검색하는 오버헤드 없이 곧바로 O(1) 상수 시간에write()함수로 바이패스(Bypass)된다. - 모듈 생존 주기와의 동기화 (RAII 호환): 모듈이
stop명령을 받고 종료(Teardown)되어야 할 때, 드라이버 파괴자(Destructor)는 이 쥐고 있던 전역 핸들을orb_unadvertise(_sensor_gyro_pub)에 넘겨주어, uORB 매니저가 메모리 누수(Memory Leak) 없이 깔끔하게 VFS 노드를 해제할 수 있도록 유도한다.
결론적으로 orb_advert_t는 단순한 식별자가 아니라, 최상위 제어 모듈과 최하단 디바이스 노드를 메모리 주소 기반의 O(1) 속도로 강력하게 결합(Coupling)시키는 초고속 통신의 탯줄 역할을 수행하는 메커니즘이다.