18.4.1.1 `orb_advertise()` API 호출부터 `uORBManager::orb_advertise_multi()`까지의 콜 스택 추적

18.4.1.1 orb_advertise() API 호출부터 uORBManager::orb_advertise_multi()까지의 콜 스택 추적

센서 드라이버나 제어 모듈을 개발할 때 가장 흔하게 접하게 되는 코드는 바로 데이터를 내보내기 위한 첫 단추인 orb_advertise() 함수이다. 사용자는 이 함수를 단순한 C API처럼 호출하지만, 그 이면에는 C++ 객체 지향 구조로 짜인 방대한 uORB 매니저 프레임워크로의 진입(Entry) 과정이 숨겨져 있다.

이 절에서는 가장 외곽의 사용자 단(User-space) API가 어떻게 가장 깊숙한 플랫폼 코어 로직으로 전달되는지 그 콜 스택(Call Stack)의 여정을 단계별로 추적해 본다.

1. 단계: 외곽 C API 래퍼 (Wrapper)

사용자가 orb_advertise(ORB_ID(sensor_accel), &data)를 호출하면, 이는 가장 먼저 src/modules/uORB/uORB.cpp 파일에 정의된 외곽 래퍼 함수에 도달한다.

이 함수의 내부 구현은 매우 단순하다. 구형 C 언어 스타일의 API 인터페이스를 제공하기 위해 껍데기만 씌워 놓은 것으로, 즉시 다중 인스턴스를 지원하는 확장 함수인 orb_advertise_multi()로 모든 책임을 넘긴다. 이때 기본 인스턴스 번호를 의미하는 nullptr 포인터가 함께 인자로 전달된다. (즉, “인스턴스 번호는 네가 알아서 첫 번째 남는 번호로 찾아줘“라는 의미다).

2. 단계: 싱글톤 uORB::Manager 획득

orb_advertise_multi() C 함수 내부로 진입하면 이제 멈춰있던 톱니바퀴가 본격적으로 돌아가기 시작한다. 먼저 전역 상태를 관리하는 컨트롤 타워에 접근해야 하므로, uORB::Manager::get_instance()를 호출한다.

이 함수는 더블 체크 락킹(Double-checked locking) 패턴을 이용하여 안전하게 싱글톤 매니저 객체의 메모리 주소를 반환한다. 시스템 부팅 후 아직 매니저가 초기화되지 않았다면 이 시점에서 치명적 오류(Fatal Error)를 발생시킨다.

3. 단계: uORBManager::orb_advertise_multi()로의 본류 진입

인스턴스 캐스팅이 끝나면, 마침내 C 알고리즘에서 C++ 멤버 함수로의 컨텍스트 전환이 일어난다. 바로 uORB::Manager 클래스의 핵심 메서드인 orb_advertise_multi() 안으로 떨어지게 되는 것이다.

이 메서드가 호출되면서 넘어오는 핵심 인자는 세 가지이다.

  1. meta: 사용할 토픽의 구조와 크기가 담긴 orb_metadata 포인터 (예: &__orb_sensor_accel)
  2. data: 최초로 링 버퍼에 써넣을 초기 데이터의 포인터 (생략 가능)
  3. instance: 발급받을 인스턴스 번호가 저장될 정수 포인터 주소

4. 단계: 매니저 내부의 데이터 릴레이 (Relay)

uORBManager::orb_advertise_multi() 내부 로직은 다시 크게 두 갈래로 나뉜다.

  • 먼저 자신이 소유하고 있는 _device_master (노드 리스트 관리자) 객체에게 지시를 내려 “이 메타데이터에 맞는 새로운 노드를 VFS(/obj/...)에 마운트(Mount)하고 메모리 힙에 할당하라“는 명령을 내린다.
  • 노드 생성이 성공적으로 끝나 VFS 경로가 확보되면, (만약 사용자가 data 포인터를 넘겼다면) 곧바로 해당 노드의 write() 오퍼레이션을 강제 호출하여 초기 데이터를 집어넣고 구독자들에게 이벤트 기상(Wake-up) 트리거를 날린다.

마침내 생성된 노드의 핸들(디바이스 포인터를 타입 캐스팅한 orb_advert_t)이 역순으로 콜 스택을 거슬러 올라가 사용자에게 반환되며 기나긴 여정이 종료된다. 사용자는 이 반환된 고유 핸들을 쥐고 비행 루프 속에서 마음껏 퍼블리싱(orb_publish)을 수행할 수 있게 된다.