Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c0ab3749 authored by youfa.song's avatar youfa.song Committed by youfa
Browse files

MediaMetrics: Fix wait_until(max) for condition_variable

As TimerClock is system_clock (which is not monotonic), libcxx's
implementation of condition_variable::wait_until(l, std::chrono::time_point)
recalculates the 'until' time into the wait duration and then goes back to the
absolute timestamp when calling pthread_cond_timedwait(); this back-and-forth
calculation sometimes loses the 'max' value because enough time passes in
between, and instead passes incorrect timestamp into the syscall, causing a
crash. Mitigating it by explicitly calling the non-timed wait here.

Change-Id: I1ee491cbf01c5943a3fc7e9e8e4632db1f506571
parent 677708a2
Loading
Loading
Loading
Loading
+11 −3
Original line number Original line Diff line number Diff line
@@ -81,9 +81,8 @@ private:
    void threadLoop() NO_THREAD_SAFETY_ANALYSIS { // thread safety doesn't cover unique_lock
    void threadLoop() NO_THREAD_SAFETY_ANALYSIS { // thread safety doesn't cover unique_lock
        std::unique_lock l(mLock);
        std::unique_lock l(mLock);
        while (!mQuit) {
        while (!mQuit) {
            auto sleepUntilTime = std::chrono::time_point<TimerClock>::max();
            if (!mMap.empty()) {
            if (!mMap.empty()) {
                sleepUntilTime = mMap.begin()->first;
                auto sleepUntilTime = mMap.begin()->first;
                const auto now = TimerClock::now();
                const auto now = TimerClock::now();
                if (sleepUntilTime <= now) {
                if (sleepUntilTime <= now) {
                    auto node = mMap.extract(mMap.begin()); // removes from mMap.
                    auto node = mMap.extract(mMap.begin()); // removes from mMap.
@@ -96,8 +95,17 @@ private:
                // of REALTIME specification, use kWakeupInterval to ensure minimum
                // of REALTIME specification, use kWakeupInterval to ensure minimum
                // granularity if suspended.
                // granularity if suspended.
                sleepUntilTime = std::min(sleepUntilTime, now + kWakeupInterval);
                sleepUntilTime = std::min(sleepUntilTime, now + kWakeupInterval);
            }
                mCondition.wait_until(l, sleepUntilTime);
                mCondition.wait_until(l, sleepUntilTime);
            } else {
                // As TimerClock is system_clock (which is not monotonic), libcxx's
                // implementation of condition_variable::wait_until(l, std::chrono::time_point)
                // recalculates the 'until' time into the wait duration and then goes back to the
                // absolute timestamp when calling pthread_cond_timedwait(); this back-and-forth
                // calculation sometimes loses the 'max' value because enough time passes in
                // between, and instead passes incorrect timestamp into the syscall, causing a
                // crash. Mitigating it by explicitly calling the non-timed wait here.
                mCondition.wait(l);
            }
        }
        }
    }
    }