18.4.1.2 신규 토픽 등록 시 `new uORBDeviceNode()` 동적 할당 및 `register_driver()` VFS 등록 과정

18.4.1.2 신규 토픽 등록 시 new uORBDeviceNode() 동적 할당 및 register_driver() VFS 등록 과정

앞 절에서 살펴본 orb_advertise() 콜 스택의 종착지는 결국 uORB 시스템에 새로운 생명을 불어넣는 “노드 생성 메커니즘“이다. uORB::Manager가 전달받은 메타데이터(Metadata)와 인스턴스 번호를 바탕으로, 시스템 메모리 공간에 물리적인 데이터 파이프라인(Pipeline)을 구축하는 과정을 심도 있게 해부해 보자.

1. new uORBDeviceNode(): 힙(Heap) 메모리 상의 파이프라인 건설

uORBDeviceMaster 트리의 관리자에 의해 새로 토픽을 개설해야 한다는 결정이 내려지면, 지체 없이 new uORBDeviceNode(...) 생성자가 호출된다. 이 단 한 줄의 C++ 동적 할당 코드 이면에서는 엄청난 일들이 벌어진다.

  1. 객체 메모리 할당: 커널의 힙(Heap) 공간에서 uORBDeviceNode 클래스 크기만큼의 메모리 블록이 확보된다.
  2. 링 버퍼(Ring Buffer) 초기화: 객체가 생성되면서 이 객체의 심장부라 할 수 있는 데이터 링 버퍼가 동시에 초기화된다. 버퍼의 크기는 메타데이터에 명시된 단일 메시지 크기(o_size)에, 큐 스케일링 설정(History Queue Size)을 곱한 만큼의 바이트 연속 공간으로 잡힌다.
  3. 동기화 원시 타입(Primitive) 세팅: 이 노드에 향후 다수의 구독자와 발행자가 동시에 접근할 것을 대비하여, 내부적으로 데이터 경합을 막을 잠금 장치(Spinlock / Semaphores)와 세대 카운터(Generation Counter)가 모두 0으로 초기화된다.
  4. 연결 리스트(Linked-list) 삽입: 18.3.3.3절에서 살펴보았던 마스터 객체의 전역 단일 연결 리스트(_node_list)의 꼬리에 방금 태어난 자신(this)을 매달아, 앞으로 누구나 검색 쿼리를 날렸을 때 자신이 발견될 수 있도록 호적에 등록한다.

2. register_driver(): VFS 세계로의 데뷔

C++ 객체가 메모리에 올라왔다고 해서 다른 태스크나 프로세스들이 이 노드를 즉시 볼 수 있는 것은 아니다. POSIX 표준 호환성을 유지하기 위해서는 운영체제의 가상 파일 시스템(VFS) 상에 문자 디바이스(Character Device)의 형태로 노출되어야만 한다.

uORBDeviceNode는 탄생 직후, 자신이 상속받은 부모 클래스인 cdev::CDevinit() 메서드를 통해 초기화를 완료한 뒤, 마침내 NuttX 커널 API인 register_driver()를 타격한다.

이 함수가 호출될 때 두 가지 핵심 정보가 커널로 넘어간다.

  1. 사전에 규칙에 따라 합성해 둔 고유 절대 경로 문자열 (예: "/obj/sensor_accel0")
  2. 이 노드에 대한 표준 입출력 요청(open, close, read, write, ioctl, poll)이 들어왔을 때 실행되어야 할 C++ 멤버 함수들의 주소를 매핑해 놓은 파일 오퍼레이션(file_operations vtable) 포인터

register_driver() 시스템 콜이 에러 없이 리턴되는 순간, 비로소 이 sensor_accel0 노드는 RTOS 내의 모든 스레드(Thread)들이 접근할 수 있는 완전한 형태의 공용 파이프(Public Pipe)로 공식 승격된다. C++ 객체 지향 세계와 C 언어 기반의 커널 VFS 세계가 하나로 연결되는 가장 짜릿한 순간이다.