// Wait for non-locked serial, and retrieve it with acquire semantics. uint32_t SystemProperties::Serial(const prop_info* pi) { uint32_t serial = load_const_atomic(&pi->serial, memory_order_acquire); while (SERIAL_DIRTY(serial)) { __futex_wait(const_cast<_Atomic(uint_least32_t)*>(&pi->serial), serial, nullptr); serial = load_const_atomic(&pi->serial, memory_order_acquire); } return serial; }
// Wait for non-locked serial, and retrieve it with acquire semantics. unsigned int __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, NULL); serial = load_const_atomic(&pi->serial, memory_order_acquire); } return serial; }
int __system_property_read(const prop_info *pi, char *name, char *value) { if (__predict_false(compat_mode)) { return __system_property_read_compat(pi, name, value); } while (true) { uint32_t serial = __system_property_serial(pi); // acquire semantics size_t len = SERIAL_VALUE_LEN(serial); memcpy(value, pi->value, len + 1); // TODO: Fix the synchronization scheme here. // There is no fully supported way to implement this kind // of synchronization in C++11, since the memcpy races with // updates to pi, and the data being accessed is not atomic. // The following fence is unintuitive, but would be the // correct one if memcpy used memory_order_relaxed atomic accesses. // In practice it seems unlikely that the generated code would // would be any different, so this should be OK. atomic_thread_fence(memory_order_acquire); if (serial == load_const_atomic(&(pi->serial), memory_order_relaxed)) { if (name != 0) { strcpy(name, pi->name); } return len; } } }
bool SystemProperties::Wait(const prop_info* pi, uint32_t old_serial, uint32_t* new_serial_ptr, const timespec* relative_timeout) { // Are we waiting on the global serial or a specific serial? atomic_uint_least32_t* serial_ptr; if (pi == nullptr) { if (!initialized_) { return -1; } prop_area* serial_pa = contexts_->GetSerialPropArea(); if (serial_pa == nullptr) { return -1; } serial_ptr = serial_pa->serial(); } else { serial_ptr = const_cast<atomic_uint_least32_t*>(&pi->serial); } uint32_t new_serial; do { int rc; if ((rc = __futex_wait(serial_ptr, old_serial, relative_timeout)) != 0 && rc == -ETIMEDOUT) { return false; } new_serial = load_const_atomic(serial_ptr, memory_order_acquire); } while (new_serial == old_serial); *new_serial_ptr = new_serial; return true; }
void SystemProperties::ReadCallback(const prop_info* pi, void (*callback)(void* cookie, const char* name, const char* value, uint32_t serial), void* cookie) { // Read only properties don't need to copy the value to a temporary buffer, since it can never // change. if (is_read_only(pi->name)) { uint32_t serial = Serial(pi); if (pi->is_long()) { callback(cookie, pi->name, pi->long_value(), serial); } else { callback(cookie, pi->name, pi->value, serial); } return; } while (true) { uint32_t serial = Serial(pi); // acquire semantics size_t len = SERIAL_VALUE_LEN(serial); char value_buf[len + 1]; memcpy(value_buf, pi->value, len); value_buf[len] = '\0'; // TODO: see todo in Read function atomic_thread_fence(memory_order_acquire); if (serial == load_const_atomic(&(pi->serial), memory_order_relaxed)) { callback(cookie, pi->name, value_buf, serial); return; } } }
bool mb__system_property_wait(const prop_info* pi, uint32_t old_serial, uint32_t* new_serial_ptr, const timespec* relative_timeout) { // Are we waiting on the global serial or a specific serial? atomic_uint_least32_t* serial_ptr; if (pi == nullptr) { if (mb__system_property_area__ == nullptr) return -1; serial_ptr = mb__system_property_area__->serial(); } else { serial_ptr = const_cast<atomic_uint_least32_t*>(&pi->serial); } uint32_t new_serial; do { int rc; if ((rc = __futex_wait(serial_ptr, old_serial, relative_timeout)) != 0 && rc == -ETIMEDOUT) { return false; } new_serial = load_const_atomic(serial_ptr, memory_order_acquire); } while (new_serial == old_serial); *new_serial_ptr = new_serial; return true; }
void mb__system_property_read_callback(const prop_info* pi, void (*callback)(void* cookie, const char* name, const char* value, uint32_t serial), void* cookie) { #if MB_ENABLE_COMPAT_PROPERTIES // TODO (dimitry): do we need compat mode for this function? if (__predict_false(compat_mode)) { uint32_t serial = mb__system_property_serial_compat(pi); char name_buf[PROP_NAME_MAX]; char value_buf[PROP_VALUE_MAX]; mb__system_property_read_compat(pi, name_buf, value_buf); callback(cookie, name_buf, value_buf, serial); return; } #endif while (true) { uint32_t serial = mb__system_property_serial(pi); // acquire semantics size_t len = SERIAL_VALUE_LEN(serial); char value_buf[len + 1]; memcpy(value_buf, pi->value, len); value_buf[len] = '\0'; // 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, serial); return; } } }
int mb__system_property_read(const prop_info* pi, char* name, char* value) { #if MB_ENABLE_COMPAT_PROPERTIES if (__predict_false(compat_mode)) { return mb__system_property_read_compat(pi, name, value); } #endif while (true) { uint32_t serial = mb__system_property_serial(pi); // acquire semantics size_t len = SERIAL_VALUE_LEN(serial); memcpy(value, pi->value, len + 1); // TODO: Fix the synchronization scheme here. // There is no fully supported way to implement this kind // of synchronization in C++11, since the memcpy races with // updates to pi, and the data being accessed is not atomic. // The following fence is unintuitive, but would be the // correct one if memcpy used memory_order_relaxed atomic accesses. // In practice it seems unlikely that the generated code would // would be any different, so this should be OK. atomic_thread_fence(memory_order_acquire); if (serial == load_const_atomic(&(pi->serial), memory_order_relaxed)) { if (name != nullptr) { size_t namelen = strlcpy(name, pi->name, PROP_NAME_MAX); if (namelen >= PROP_NAME_MAX) { LOGE("The property name length for \"%s\" is >= %d;" " please use __system_property_read_callback" " to read this property. (the name is truncated to \"%s\")", pi->name, PROP_NAME_MAX - 1, name); } } return len; } } }
void* BBinder::findObject(const void* objectID) const { Extras* e = reinterpret_cast<Extras*>( load_const_atomic(&mExtras, std::memory_order_acquire)); if (!e) return NULL; AutoMutex _l(e->mLock); return e->mObjects.find(objectID); }
int SystemProperties::Read(const prop_info* pi, char* name, char* value) { while (true) { uint32_t serial = Serial(pi); // acquire semantics size_t len = SERIAL_VALUE_LEN(serial); memcpy(value, pi->value, len + 1); // TODO: Fix the synchronization scheme here. // There is no fully supported way to implement this kind // of synchronization in C++11, since the memcpy races with // updates to pi, and the data being accessed is not atomic. // The following fence is unintuitive, but would be the // correct one if memcpy used memory_order_relaxed atomic accesses. // In practice it seems unlikely that the generated code would // would be any different, so this should be OK. atomic_thread_fence(memory_order_acquire); if (serial == load_const_atomic(&(pi->serial), memory_order_relaxed)) { if (name != nullptr) { size_t namelen = strlcpy(name, pi->name, PROP_NAME_MAX); if (namelen >= PROP_NAME_MAX) { async_safe_format_log(ANDROID_LOG_ERROR, "libc", "The property name length for \"%s\" is >= %d;" " please use __system_property_read_callback" " to read this property. (the name is truncated to \"%s\")", pi->name, PROP_NAME_MAX - 1, name); } } if (is_read_only(pi->name) && pi->is_long()) { async_safe_format_log( ANDROID_LOG_ERROR, "libc", "The property \"%s\" has a value with length %zu that is too large for" " __system_property_get()/__system_property_read(); use" " __system_property_read_callback() instead.", pi->name, strlen(pi->long_value())); } return len; } } }