diff options
author | 2023-08-01 15:55:05 -0700 | |
---|---|---|
committer | 2023-08-01 15:55:05 -0700 | |
commit | 67a1c1a79e4f2373b57a5c4c7173bb383ef75066 (patch) | |
tree | 59047d4a2c6323a941d50628113a168af995a2a6 | |
parent | 8b2832873705d7d7c72d6082806ef5be524619f2 (diff) |
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
-rw-r--r-- | services/incremental/ServiceWrappers.cpp | 15 |
1 files changed, 13 insertions, 2 deletions
diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp index ce3d51483d73..2a2fa7adf5cb 100644 --- a/services/incremental/ServiceWrappers.cpp +++ b/services/incremental/ServiceWrappers.cpp @@ -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; } |