mirror of
https://github.com/PX4/PX4-Autopilot.git
synced 2026-07-24 15:27:41 +08:00
Two related thread-safety fixes for the cond_timedwait + set_absolute_time dance, both surfaced under TSan with multi-instance Mavlink and a fast sim clock advance: 1. Signal loss between releasing _timed_waits_mutex and entering pthread_cond_wait. set_absolute_time could have already broadcast to a waiter that hadn't actually started waiting yet, and the broadcast would be missed -> wait blocks forever. Fix: cond_timedwait uses pthread_cond_timedwait with a short wall-clock timeout (10 ms) and re-checks the timeout flag. Lost signals turn into a maximum of one loop iteration of latency. 2. ABBA between (passed_lock -> _timed_waits_mutex) used by cond_timedwait to mark `done`, and (passed_lock under _timed_waits_mutex) used by set_absolute_time to broadcast. TSan flagged the inversion immediately. Fix: split set_absolute_time into three phases. Phase 1 marks timed_outs and stages waiters onto a per-call signal_next list, under _timed_waits_mutex only. Phase 2 broadcasts to each waiter, outside _timed_waits_mutex but under a new _signaling_mutex held for the duration. Phase 3 clears _setting_time under the _timed_waits_mutex again. The waiter's "dance" (when it sees _setting_time still true on exit) acquires _signaling_mutex first, then _timed_waits_mutex, guaranteeing it cannot return — and let its stack-local passed_lock/passed_cond go out of scope — until set_absolute_time has finished signaling. The TimedWait::timeout flag also becomes std::atomic<bool> since it is now read by cond_timedwait without holding _timed_waits_mutex.