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

Commit 67a1c1a7 authored by Yurii Zubrytskyi's avatar Yurii Zubrytskyi
Browse files

Fix wait_until(infinity) for condition_variable

libcxx implements wait_until using wait_for, which in
its turn has to call a syscall that's basically wait_until,
causing a double conversion of the waiting time parameter.
Because of this, infinity detection code in those conversions
sometimes fail if the delat between the conversions is long
enough - causing a syscall error for 'invalid time'

This CL explicitly calls non-timed wait() instead.

Bug: 293223125
Bug: 292138960
Test: build + unit tests + presubmits
Change-Id: Id30fdfbe374b63fcaed627fcdf374f1e501a7807
parent 8b283287
Loading
Loading
Loading
Loading
+13 −2
Original line number Diff line number Diff line
@@ -315,11 +315,22 @@ private:
        std::unique_lock lock(mMutex);
        for (;;) {
            const TimePoint nextJobTs = mJobs.empty() ? kInfinityTs : mJobs.begin()->when;
            mCondition.wait_until(lock, nextJobTs, [this, oldNextJobTs = nextJobTs]() {
            auto conditionPredicate = [this, oldNextJobTs = nextJobTs]() {
                const auto now = Clock::now();
                const auto newFirstJobTs = !mJobs.empty() ? mJobs.begin()->when : kInfinityTs;
                return newFirstJobTs <= now || newFirstJobTs < oldNextJobTs || !mRunning;
            });
            };
            // libcxx's implementation of wait_until() 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 'infinity' 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.
            if (mJobs.empty()) {
                mCondition.wait(lock, conditionPredicate);
            } else {
                mCondition.wait_until(lock, nextJobTs, conditionPredicate);
            }
            if (!mRunning) {
                return;
            }