19.5.2.2. poll() 반환값 분석 및 이벤트 발생 Topic 식별 분기문(Switch-case) 작성
거대한 다중 VFS 감시망 배열 객체를 구축하고 px4_poll() 명령을 때려 커널에 처박아 넣었다면, 이제 메인 스레드가 기나긴 블로킹(Blocking) 심연을 비집고 올라와 폭력적 인터럽트로 기상했을 때 일어나는 살벌한 사후 식별 처리(Post-processing)를 완벽히 통제 설계해야 한다.
만약 무거운 px4_poll이 poll_ret > 0을 반환하며 스레드를 살려냈다면, 이는 커널 스케줄러가 우리가 덫처럼 던져놓은 fds 구조체 배열 안에 등록된 통신 대기 N개의 감시 채널 중 **“최소 단 하나 이상(혹은 복수 동시 발생)”**에서 POLLIN 갱신 이벤트 플래그가 터졌음을 물리적으로 확실히 보장(Guarantee)하는 것이다.
하지만 OS 커널은 절대로 “주인님, 3번 방에서 데이터가 발생했습니다“라고 친절하고 우아하게 직접 텍스트로 말해주지 않는다. 우리는 배열의 각 슬롯 방 문을 하나하나 강제로 열어보고, 이벤트 반환 레지스터 값인 revents(Return Events) 마스크를 비트 마스킹(Bit-masking) 연산하여 “도대체 누구의 파이프에서 인터럽트가 터져서 내가 기상당했는가?“를 직접 역추적하는 무자비한 색출 작업이 뒤따라야만 한다.
1. revents 비트마스킹(Bit-masking)과 멀티 분기 색출의 아키텍처
아래 코드는 fds 감시망에서 자신이 기절을 깨고 일어난 그 파괴적 원인을 스스로 하나하나 찾아, 각각의 헬스 캐시 구조체로 데이터를 뽑아내는 극한의 분기 색출 설계 트랩이다.
// 2개의 채널, 1초 타임아웃 감시
int poll_ret = px4_poll(fds, 2, 1000);
if (poll_ret > 0) {
// ---- [인터럽트 멀티 기상 확정 대성공 구간] ----
// 1. [0번 슬롯 색출] sensor_test_data 파이프라인에서 새 패킷이 갱신되어 나부끼는가?
// revents(리턴된 이벤트) 레지스터 마스크와 내가 거론했던 POLLIN 마스크를 비트 AND(&) 연산으로 물리적 일치 여부를 파싱한다.
if (fds[0].revents & POLLIN) {
sensor_test_data_s sensor_data{};
orb_copy(ORB_ID(sensor_test_data), fds[0].fd, &sensor_data);
PX4_INFO("Event 0 Pipe Triggered: Extracted Custom Temp %.2f", (double)sensor_data.temperature);
// ... 여기서 뽑아낸 sensor_data를 글로벌 EKF 융합(Fusion) 객체에 변위로 저장 ...
}
// 2. [1번 슬롯 색출] vehicle_acceleration 코어 센서 파이프가 갱신되어 인터럽트를 터뜨렸는가?
if (fds[1].revents & POLLIN) {
vehicle_acceleration_s accel_data{};
orb_copy(ORB_ID(vehicle_acceleration), fds[1].fd, &accel_data);
PX4_INFO("Event 1 Pipe Triggered: Got System Accel X %.2f", (double)accel_data.xyz[0]);
// ... 여기서 뜯어온 가속도 3축 벡터 accel_data.xyz를 메인 항법 필터 행렬에 그대로 때려 넣음 ...
}
// 3. (생존자 방어) C 커널 버그나 물리적 렌더링 손상에 의한 VFS 에러 식별 분기
// 아주 드물지만 POLLIN 이외에 시스템이 토해내는 치명적인 파이프 에러(POLLERR, POLLHUP 등)가 메모리에 섞여 들어올 때를 무자비하게 색출
for (int i = 0; i < 2; i++) {
if (fds[i].revents & (POLLERR | POLLHUP | POLLNVAL)) {
PX4_WARN("Fatal Pipeline Memory Error systematically detected on FD slot %d! Discarding loop frame.", i);
}
}
}
2. 동시 다발적(Simultaneous) 이벤트 트리거의 완벽한 병렬 처리 철학
이 코드를 처음 마주할 때 학부생 초보자들은 이 분기문을 단순히 if ~ else if 문으로 무식하게 묶으려 들 것이다. 하지만 위 설계된 아키텍처 코드에서 fds[0] 구조체 검사와 fds[1] 구조체 검사가 전혀 상호 간섭하지 않는 독립적인 개별 if 블록으로 아주 치명적이고 노골적이게 분리되어 있음에 당신은 전율하며 주목해야 한다!
1000Hz 단위의 미친 속도로 돌아가는 픽스호크 실시간 펌웨어 멀티스레드 생태계 내부에서는, 불과 수십 마이크로초(us)의 찰나의 틱(Tick) 오차율 안에서, 0번 온도 센서 데몬과 1번 가속도계 보드가 VFS망에 동시에 데이터를 때려 부어버리는 완벽한 병렬 도착 충돌(Concurrent Arrival) 현상이 비일비재하게 일어난다.
만약 이 거대한 큐에서 초보자처럼 코드에 무지성으로 else if 구문을 써버리면, 우선순위가 높은 0번 버퍼 껍데기만 쏙 씹어 먹고 가장 중요한 1번 가속도 데이터는 읽지도 않은 채 링 버퍼에 그냥 처박아 쓰레기로 유기해 둔 채 다음 루프로 점프해 버리는, 메모리 I/O 락 꼬임과 핵심 연산 스킵(Skip)이라는 대추락 참사를 자초하게 된다.
따라서 100% 절대 불변의 철칙으로써, 당신의 데몬은 기절에서 기상하는 즉시 무조건 배열 내의 ’모든 감시 슬롯’을 전수 조사(Exhaustive Check)하는 브루트 포스 단일 루프를 태워, 발생한 모든 POLLIN 트리거들을 하나도 빠짐없이 모조리 일망타진해 빨아들이는 독립적 병렬 수집 로직(Independent Switch-Cases)을 반드시 구현해야만 한다. 이것이 커널 인터럽트를 미친 듯이 낚아채 반응하는 진정한 다중 토픽 멀티플렉싱(Multiplexing) 마에스트로 해커의 냉혹한 절대 철칙이다.