QNX RTOS: 10-2. A Simple Resource Manager
2026. 1. 23. 17:41ㆍ운영체제/QNX
목표(Behavior)
클라이언트 관점에서 이 예제 리소스 매니저(Resource Manager)는 다음처럼 동작합니다.
- read() : 항상 0바이트 반환 (EOF처럼 동작, 실제 하드웨어 입력 없음)
- write() : 어떤 크기든 성공 처리 (데이터를 “받아주기만” 하는 형태)
- 그 외 동작(open/close/stat 등)은 프레임워크 기본(default) 동작을 따름
즉, “가짜 디바이스(dummy device)”를 만들어 /dev/example 같은 엔트리를 노출시키고, 최소한의 read/write만 커스터마이즈하는 전형적인 연습 구조입니다.
초기화 전체 흐름(One Big Picture)
초기화 단계는 크게 두 덩어리입니다.
- 구조체/테이블 준비(정적 설정)
- pathname space 등록 + 메시지 수신 루프(동작 시작)
스크립트 기준으로 단계는 다음 순서로 정리됩니다.
- Dispatch 구조체 생성(Dispatch structure)
- Connect 함수 테이블 설정(Connect function table)
- I/O 함수 테이블 설정(I/O function table)
- 디바이스 속성 설정(Device attributes, iofunc_attr_t)
- 리소스 매니저 속성/attach(attach to pathname space, secpol_resmgr_attach)
- Dispatch context 할당(Dispatch context, ctp)
- Receive loop: dispatch_block() + dispatch_handler() 반복
Step 1) Dispatch 생성: dispatch_create_channel()
하는 일
- 리소스 매니저가 메시지를 받기 위한 채널(Channel) 을 생성하고,
- 프레임워크가 사용할 dispatch 핸들(dpp) 을 확보합니다.
왜 필요한가
QNX의 RM은 “메시지 서버”입니다. 따라서 수신 엔드포인트(채널) 없이는 connect/read/write 메시지를 받을 수 없습니다.
파라미터 포인트
- channel ID를 -1로 주는 패턴: “새로 만들어 달라”는 의미로 많이 사용
- DISPATCH_FLAG_NOLOCK: 불필요한 락을 비활성화(스크립트 설명).
다만 멀티스레드/동시성 요구가 있으면 이 플래그 선택은 신중해야 합니다(이 강의는 단순 예제 전제).
Step 2~3) Connect/I-O 함수 테이블 설정
리소스 매니저 프레임워크는 “어떤 메시지 타입을 어떤 핸들러로 처리할지”를 테이블로 받습니다.
2) Connect 테이블(Connect messages)
- pathname 기반 호출이 들어올 때 처리
- 예: open(), (필요 시) unlink(), rename() 등
대부분의 단순 디바이스 RM은 보통 open만 의미 있게 다루고, unlink/rename은 파일시스템 성격이 있을 때 비중이 커집니다.
3) I/O 테이블(I/O messages)
- file descriptor 기반 호출 처리
- 예: _IO_READ, _IO_WRITE, _IO_CLOSE, _IO_DEVCTL 등
이 예제는 “read=0 bytes”, “write=always ok”가 목표이므로, 통상 read/write 핸들러만 override 하고 나머지는 default로 둡니다.
테이블 초기화 패턴 요지
스크립트에서는 “초기화 함수 호출 시 1번째/3번째 인자를 상수로 두고, connect 및 I/O 함수 포인터를 넣는다”는 식으로 설명합니다.
핵심은: 프레임워크 기본 핸들러를 깔고, 필요한 항목만 교체하는 구성입니다.
Step 4) Device attributes 설정: iofunc_attr_init()
하는 일
- 디바이스의 기본 속성(권한/타입/UID/GID 등)을 담는 attribute 구조체(iofunc_attr_t) 를 초기화합니다.
왜 필요한가
- attach 시에 “이 엔트리가 어떤 타입이며 권한이 무엇인지”를 RM 프레임워크가 알아야 합니다.
- 보통 stat(), 권한 체크, open 모드 체크 등이 이 정보에 의존합니다.
스크립트 포인트
- 권한을 옥탈(octal) 표기(예: 0666, 0644 등)로 넣는 전형적 패턴
- 예제에서는 device-specific 추가 데이터가 없어서 기본값 위주로 사용
- 필요하면 이 구조체를 확장(embedding)해서 사용자 데이터를 같이 들고 다니는 설계도 가능(실무에서는 흔함)
Step 5) Pathname space 등록: secpol_resmgr_attach()
하는 일
- /dev/example 같은 이름을 pathname space에 등록하여,
- 클라이언트가 open("/dev/example")로 접근할 수 있도록 “OS의 일부처럼 보이게” 만듭니다.
왜 secpol_* 인가
- 과거에는 resmgr_attach()를 썼고,
- 보안 정책(Security Policy)을 반영하기 위해 확장된 것이 secpol_resmgr_attach()라는 설명입니다.
주요 인자(스크립트 기준 의미)
- secpol_handle: 보통 NULL
- dpp: Step 1에서 받은 dispatch 포인터
- attr: RM attach용 추가 속성(대개 NULL)
- path: 등록할 경로(/dev/example)
- file_type: 보통 FILE_TYPE_ANY 같은 기본값
- flags: 0 또는 제어 플래그
- connect funcs, io funcs: Step 2~3에서 만든 테이블
- ioattr: Step 4의 디바이스 attribute 포인터
- perms_set: 보통 NULL이지만 “정책에 의해 속성이 변경되었는지” 알려주는 용도로 활용 가능
매우 중요한 실무 포인트(스크립트의 “piece of advice”)
- attach 전에 하드웨어 탐지(HW detect), 버퍼 할당(buffer allocation), 초기 설정(configuration)을 끝내라.
- 이유: attach 이후에는 클라이언트가 보게 되고(open 시도 등), “준비가 덜 된 상태의 RM”은 즉시 오류/레이스/불완전 상태를 노출할 수 있습니다.
구조체 라이프타임(lifetime) 주의
- secpol_resmgr_attach()는 connect/io/attr 구조체를 복사하지 않는다는 설명이 있습니다.
- 따라서 해당 구조체들은 RM이 살아있는 동안 계속 유효해야 합니다.
- 전역(global)로 두거나
- malloc() 등으로 할당해 “프로세스 생명주기 전체”를 보장해야 합니다.
권한(Privilege) 요구
- pathname space에 이름을 등록하는 행위는 특권이 필요할 수 있으며,
- 스크립트에서는 PROCMGR_AID_PATHSPACE 능력(Ability)이 필요하다고 언급합니다.
Step 6) Dispatch context 할당: dispatch_context_alloc()
하는 일
- 메시지 수신 루프에서 사용할 컨텍스트(ctp) 를 할당합니다.
- 이 컨텍스트는 수신 버퍼(receive buffer), rcvid 등 “현재 수신한 메시지 상태”를 들고 있으며,
- connect/I-O 핸들러로 전달되는 핵심 파라미터입니다.
즉, 핸들러 입장에서는 ctp를 통해:
- 어떤 요청인지(메시지 헤더/타입)
- 누가 보냈는지(rcvid)
- 수신 버퍼가 어디인지
등을 접근하게 됩니다.
Step 7) Receive loop: dispatch_block() + dispatch_handler()
역할 분담
- dispatch_block(ctp)
- 블로킹(blocking) 으로 메시지 도착을 기다림
- dispatch_handler(ctp)
- 도착한 메시지를 해석하여
- connect면 connect handler,
- I/O면 I/O handler로 디스패치(dispatch)
이 루프가 RM의 “서버로서의 생명”입니다.
전체를 구현 관점으로 축약한 체크리스트
- dpp = dispatch_create_channel(-1, DISPATCH_FLAG_NOLOCK)
- connect 테이블 초기화(최소 open)
- io 테이블 초기화(최소 read/write)
- iofunc_attr_init(&ioattr, mode, NULL, NULL)
- id = secpol_resmgr_attach(NULL, dpp, NULL, "/dev/example", FILE_TYPE_ANY, 0, &connect_funcs, &io_funcs, &ioattr, &perms_set)
- ctp = dispatch_context_alloc(dpp)
- while( (ctp = dispatch_block(ctp)) ) dispatch_handler(ctp);
'운영체제 > QNX' 카테고리의 다른 글
| QNX RTOS: 10-4. Handling read() and write() - write() (0) | 2026.01.23 |
|---|---|
| QNX RTOS: 10-3. Handling read() and write() - read() (0) | 2026.01.23 |
| QNX RTOS: 10-1. Overview of Resource Managers (0) | 2026.01.23 |
| QNX RTOS: 9-1. Images & Buildfiles (0) | 2026.01.02 |
| QNX RTOS: 8-6. Kernel Timeouts (0) | 2026.01.02 |