mirror of
https://github.com/PX4/PX4-Autopilot.git
synced 2026-07-24 15:27:41 +08:00
Two related fixes for HRT callout queue corruption under lockstep SIH: 1. WorkQueue::Run() popped a WorkItem, released the work-queue lock, then called work->Run(). If another thread called Deinit on the item in that window, wq->Remove was a no-op (item already popped) and Deinit returned while Run() was still executing. Run() could then call ScheduleDelayed → hrt_call_after on an object that the caller of Deinit has since destructed and reused via placement new — the hrt_call metadata ends up living inside another object's fields, which later overwrite the flink pointer and tear the hrt callout queue. Fix: WorkItem carries a _run_in_progress atomic flag set by WorkQueue::Run around work->Run(). Deinit spins on that flag after wq->Remove so it cannot return while a Run() is still executing. WorkQueue captures its worker tid in the constructor (the ctor runs on the worker thread) so Deinit can skip the self-wait when called from inside Run() itself (e.g. should_exit() paths that invoke ScheduleClear). 2. _hrt_lock was a px4_sem_t and hrt_call_invoke unlocked around the callback so callbacks could re-enter hrt_call_*. That also exposed the queue to other threads mid-invocation. Switch _hrt_lock to a PTHREAD_MUTEX_RECURSIVE pthread_mutex and hold it across the callback — matches NuttX's enter_critical_section() nesting semantics, lets callbacks reschedule themselves safely, and prevents concurrent queue manipulation. Together these eliminate the HRT queue tearing observed in the SIH-at-20x MAVSDK integration soak (torn flink chains with the tail unreachable from the head; orphan nodes pointing into reused memory).