Add __system_property_wait and return the serial in __system_property_read_callback.
In order to implement android::base::WaitForProperty well, we need a way to
wait not for *any* property to change (__system_property_wait_any), but to
specifically wait for the property represented by a given `prop_info` to
change.
The android::base::WaitForProperty implementation, like attempts to cache
system properties in the past, also needs a way to keep serials and values
in sync, but the existing functions don't provide a cheap way to get a
consistent snapshot. Change the __system_property_read_callback callback's
type to include the serial corresponding to the given value.
Add a test, slightly clean up some of the existing tests (and name them to
include the names of the functions they're testing, in our usual style).
Bug: http://b/35201172
Test: ran tests
Change-Id: Ibc8ebe2e88eef1e333a1bd3dd7f68135f1ba7fb5
diff --git a/libc/bionic/system_properties.cpp b/libc/bionic/system_properties.cpp
index a62ce14..32d1e31 100644
--- a/libc/bionic/system_properties.cpp
+++ b/libc/bionic/system_properties.cpp
@@ -1102,7 +1102,7 @@
return fsetxattr_failed ? -2 : 0;
}
-unsigned int __system_property_area_serial() {
+uint32_t __system_property_area_serial() {
prop_area* pa = __system_property_area__;
if (!pa) {
return -1;
@@ -1163,8 +1163,10 @@
}
void __system_property_read_callback(const prop_info* pi,
- void (*callback)(void* cookie, const char* name,
- const char* value),
+ void (*callback)(void* cookie,
+ const char* name,
+ const char* value,
+ uint32_t serial),
void* cookie) {
while (true) {
uint32_t serial = __system_property_serial(pi); // acquire semantics
@@ -1177,7 +1179,7 @@
// TODO: see todo in __system_property_read function
atomic_thread_fence(memory_order_acquire);
if (serial == load_const_atomic(&(pi->serial), memory_order_relaxed)) {
- callback(cookie, pi->name, value_buf);
+ callback(cookie, pi->name, value_buf, serial);
return;
}
}
@@ -1329,30 +1331,34 @@
}
// Wait for non-locked serial, and retrieve it with acquire semantics.
-unsigned int __system_property_serial(const prop_info* pi) {
+uint32_t __system_property_serial(const prop_info* pi) {
uint32_t serial = load_const_atomic(&pi->serial, memory_order_acquire);
while (SERIAL_DIRTY(serial)) {
- __futex_wait(const_cast<volatile void*>(reinterpret_cast<const void*>(&pi->serial)), serial,
- nullptr);
+ __futex_wait(const_cast<_Atomic(uint_least32_t)*>(&pi->serial), serial, nullptr);
serial = load_const_atomic(&pi->serial, memory_order_acquire);
}
return serial;
}
-unsigned int __system_property_wait_any(unsigned int serial) {
+uint32_t __system_property_wait_any(uint32_t old_serial) {
prop_area* pa = __system_property_area__;
- uint32_t my_serial;
+ if (!pa) return 0;
- if (!pa) {
- return 0;
- }
-
+ uint32_t new_serial;
do {
- __futex_wait(pa->serial(), serial, nullptr);
- my_serial = atomic_load_explicit(pa->serial(), memory_order_acquire);
- } while (my_serial == serial);
+ __futex_wait(pa->serial(), old_serial, nullptr);
+ new_serial = atomic_load_explicit(pa->serial(), memory_order_acquire);
+ } while (new_serial == old_serial);
+ return new_serial;
+}
- return my_serial;
+uint32_t __system_property_wait(const prop_info* pi, uint32_t old_serial) {
+ uint32_t new_serial;
+ do {
+ __futex_wait(const_cast<_Atomic(uint_least32_t)*>(&pi->serial), old_serial, nullptr);
+ new_serial = load_const_atomic(&pi->serial, memory_order_acquire);
+ } while (new_serial == old_serial);
+ return new_serial;
}
const prop_info* __system_property_find_nth(unsigned n) {