Prevent WaitForProperty() from using ~100% of CPU time on 32bit builds

Since 'struct timespec' members (time_t and long) are both 32bit on
32bit systems, and std::chrono::{seconds,nanoseconds}::rep are both
>32bit, timespec members assigned in DurationToTimeSpec() can have a
negative value, especially when WaitForProperty() is called with the
default timeout value which is std::chrono::milliseconds::max().

Regarding functionality, passing a negative value to
__system_property_wait() is okay because WaitForProperty() still
waits for the property value (so unit tests are passing), but while
WaitForProperty() does that, the function, to be more exact,
SystemProperties::Wait() in bionic/, consumes ~100% of CPU time. This
happens because SystemProperties::Wait() which implements
__system_property_wait() has a tight while-loop with a __futex_wait()
call, and the futex call immediately returns EINVAL when the timespec
passed in has a negative value.

With this CL, WaitForProperty() will never pass a negative timespec
to __system_property_wait(), and therefore the __futex_wait() call
in bionic works as expected without consuming too much CPU time even
on 32bit systems.

Bug: None
Test: libbase_test32 still passes
Test: strace no longer shows repeated EINVALs from __futex_wait
Change-Id: Id1834fac8cd2876b02dbe4479bf3d3eda2fa7da1
This commit is contained in:
yusukes 2018-02-13 18:28:50 -08:00
parent fd01164a8d
commit d3b9404241
1 changed files with 2 additions and 1 deletions

View File

@ -23,6 +23,7 @@
#include <algorithm>
#include <chrono>
#include <limits>
#include <string>
#include <android-base/parseint.h>
@ -109,7 +110,7 @@ static void WaitForPropertyCallback(void* data_ptr, const char*, const char* val
static void DurationToTimeSpec(timespec& ts, const std::chrono::milliseconds d) {
auto s = std::chrono::duration_cast<std::chrono::seconds>(d);
auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(d - s);
ts.tv_sec = s.count();
ts.tv_sec = std::min<std::chrono::seconds::rep>(s.count(), std::numeric_limits<time_t>::max());
ts.tv_nsec = ns.count();
}