// 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;
    }
  }
}
Esempio n. 9
0
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;
    }
  }
}