From: Hwankyu Jhun Date: Thu, 22 Sep 2022 01:36:53 +0000 (+0000) Subject: Use malloc instead of std::vector X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fheads%2FRefs%2Ffor%2Ftizen;p=platform%2Fcore%2Fbase%2Fbundle.git Use malloc instead of std::vector To improve the performance of the parcel creation, the data_ variable of the parcel implementation is changed to uint8_t*. And, the DataCapacitor class is added to manage the allocated memory. While destroying the parcel instance, the allocated memory is set to the DataCapacitor object. Change-Id: Ia88815746d646ce089de802d89017c96cbc6b30d Signed-off-by: Hwankyu Jhun --- diff --git a/parcel/api/parcel.h b/parcel/api/parcel.h index 640b3b1..10dbaba 100644 --- a/parcel/api/parcel.h +++ b/parcel/api/parcel.h @@ -529,6 +529,32 @@ int parcel_get_raw(parcel_h parcel, void **raw, uint32_t *size); */ int parcel_set_byte_order(parcel_h parcle, bool big_endian); +/** + * @brief Gets the size of the data capacity of the parcel handle. + * @since_tizen 7.0 + * @param[in] parcel The parcel handle + * @param[out] size The size of the data capacity + * @return @c 0 on success, + * otherwise a negative error value + * @retval #PARCEL_ERROR_NONE Successful + * @retval #PARCEL_ERROR_INVALID_PARAMETER Invalid parameter + */ +int parcel_get_data_capacity(parcel_h parcel, size_t *size); + +/** + * @brief Sets the size of the data capacity of the parcel handle. + * @since_tizen 7.0 + * @remarks The raw data will be reallocated using the given size. + * @param[in] parcel The parcel handle + * @param[in] size The size of the data capacity + * @return @c 0 on success, + * otherwise a negative error value + * @retval #PARCEL_ERROR_NONE Successful + * @retval #PARCEL_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #PARCEL_ERROR_OUT_OF_MEMORY + */ +int parcel_set_data_capacity(parcel_h parcel, size_t size); + #ifdef __cplusplus } #endif diff --git a/parcel/parcel.cc b/parcel/parcel.cc index 2c3e13f..1fd9a03 100644 --- a/parcel/parcel.cc +++ b/parcel/parcel.cc @@ -16,6 +16,9 @@ #include +#include +#include + #include "parcel/common.hh" #include "parcel/log_private.hh" #include "parcel/parcel.hh" @@ -23,34 +26,106 @@ #include "parcel/parcelable.hh" namespace tizen_base { +namespace { + +constexpr const size_t kDataCapacity = 128; + +class DataCapacitor { + public: + DataCapacitor() { + data_ = static_cast(malloc(data_capacity_)); + if (data_ == nullptr) + data_capacity_ = 0; + } + + ~DataCapacitor() { + free(data_); + } + + void Set(uint8_t* data, size_t data_capacity) { + std::lock_guard lock(mutex_); + free(data_); + data_ = data; + data_capacity_ = data_capacity; + } -Parcel::Impl::Impl(Parcel* parent, bool big_endian) - : parent_(parent), big_endian_(big_endian) { + uint8_t* Detach(size_t* data_capacity) { + std::lock_guard lock(mutex_); + uint8_t* data = data_; + *data_capacity = data_capacity_; + data_ = nullptr; + data_capacity_ = 0; + return data; + } + + private: + uint8_t* data_; + size_t data_capacity_ = kDataCapacity; + std::recursive_mutex mutex_; +}; + +DataCapacitor capacitor; + +} // namespace + +Parcel::Impl::Impl(Parcel* parent, size_t data_capacity, bool big_endian) + : parent_(parent), data_capacity_(data_capacity), big_endian_(big_endian) { + size_t capacity = 0; + auto* data = capacitor.Detach(&capacity); + if (data != nullptr) { + if (data_capacity_ > capacity) { + data_ = static_cast(realloc(data, data_capacity_)); + if (data_ == nullptr) { + free(data); + throw std::bad_alloc(); + } + } else { + data_capacity_ = capacity; + data_ = data; + } + } else { + data_ = static_cast(malloc(data_capacity_)); + if (data_ == nullptr) + throw std::bad_alloc(); + } } -Parcel::Impl::~Impl() = default; +Parcel::Impl::~Impl() { + capacitor.Set(data_, data_capacity_); +} void Parcel::Impl::Write(const void* buf, uint32_t size) { - auto* p = reinterpret_cast(buf); - data_.insert(data_.end(), p, p + size); + if (data_size_ + size > data_capacity_) { + size_t new_size = (data_capacity_ + size) * 3 / 2; + uint8_t* data = static_cast(realloc(data_, new_size)); + if (data == nullptr) + throw std::bad_alloc(); + + data_ = data; + data_capacity_ = new_size; + } + + memcpy(data_ + data_size_, buf, size); + data_size_ += size; } int Parcel::Impl::Read(void* buf, uint32_t size) { - if (data_.size() == 0) + if (data_size_ == 0) return TIZEN_ERROR_NO_DATA; - if (reader_ + size > data_.size()) + if (reader_ + size > data_size_) return TIZEN_ERROR_ILLEGAL_BYTE_SEQ; - auto* p = reinterpret_cast(buf); - std::copy(&data_[reader_], &data_[reader_] + size, p); + memcpy(buf, data_ + reader_, size); reader_ += size; set_last_result(TIZEN_ERROR_NONE); return TIZEN_ERROR_NONE; } const std::vector& Parcel::Impl::GetRaw() { - return data_; + raw_.clear(); + raw_.assign(data_, data_ + data_size_); + return raw_; } void Parcel::Impl::ResetReader() { @@ -58,7 +133,7 @@ void Parcel::Impl::ResetReader() { } void Parcel::Impl::Clear() { - data_.clear(); + data_size_ = 0; reader_ = 0; } @@ -68,7 +143,7 @@ void Parcel::Impl::Reset(const void* buf, uint32_t size) { } bool Parcel::Impl::IsEmpty() { - return data_.size() == 0; + return data_size_ == 0; } void Parcel::Impl::WriteSize(uint32_t size) { @@ -80,20 +155,28 @@ void Parcel::Impl::WriteSize(uint32_t size) { template void Parcel::Impl::Write(T d) { + if (data_size_ + sizeof(T) > data_capacity_) { + size_t new_size = (data_capacity_ + sizeof(T)) * 3 / 2; + uint8_t* data = static_cast(realloc(data_, new_size)); + if (data == nullptr) + throw std::bad_alloc(); + + data_ = data; + data_capacity_ = new_size; + } + auto* p = reinterpret_cast(&d); - data_.insert(data_.end(), p, p + sizeof(T)); + memcpy(data_ + data_size_, p, sizeof(T)); + data_size_ += sizeof(T); } int Parcel::Impl::ReadSize(uint32_t* size) { - if (data_.size() == 0) + if (data_size_ == 0) return TIZEN_ERROR_NO_DATA; - if (reader_ + sizeof(uint32_t) > data_.size()) - return TIZEN_ERROR_ILLEGAL_BYTE_SEQ; - - auto* p = reinterpret_cast(size); - std::copy(&data_[reader_], &data_[reader_] + sizeof(uint32_t), p); - reader_ += sizeof(uint32_t); + int ret = Read(size); + if (ret != TIZEN_ERROR_NONE) + return ret; if (IsBigEndian()) *size = GUINT32_FROM_BE(*size); @@ -104,11 +187,11 @@ int Parcel::Impl::ReadSize(uint32_t* size) { template int Parcel::Impl::Read(T* d) { uint32_t size = sizeof(T); - if (reader_ + size > data_.size()) + if (reader_ + size > data_size_) return TIZEN_ERROR_ILLEGAL_BYTE_SEQ; auto* p = reinterpret_cast(d); - std::copy(&data_[reader_], &data_[reader_] + size, p); + memcpy(p, data_ + reader_, size); reader_ += size; return TIZEN_ERROR_NONE; } @@ -117,45 +200,113 @@ void Parcel::Impl::SetByteOrder(bool big_endian) { big_endian_ = big_endian; } -bool Parcel::Impl::IsBigEndian() { +bool Parcel::Impl::IsBigEndian() const { return big_endian_; } -Parcel::Parcel(bool big_endian) : impl_(new Impl(this, big_endian)) { +uint8_t* Parcel::Impl::GetData() const { + return data_; +} + +size_t Parcel::Impl::GetDataSize() const { + return data_size_; +} + +size_t Parcel::Impl::GetDataCapacity() const { + return data_capacity_; +} + +void Parcel::Impl::SetDataCapacity(size_t size) { + uint8_t* data = static_cast(realloc(data_, size)); + if (data == nullptr) + throw std::bad_alloc(); + + data_ = data; + data_capacity_ = size; +} + +Parcel::Parcel(bool big_endian) + : impl_(new Impl(this, kDataCapacity, big_endian)) { } Parcel::Parcel(const void* buf, uint32_t size, bool big_endian) - : impl_(new Impl(this, big_endian)) { + : impl_(new Impl(this, size, big_endian)) { impl_->Write(buf, size); } Parcel::~Parcel() = default; Parcel::Parcel(const Parcel& p) - : impl_(new Impl(this)) { + : impl_(new Impl(this, kDataCapacity)) { impl_->big_endian_ = p.impl_->big_endian_; - impl_->data_ = p.impl_->data_; + impl_->data_capacity_ = p.impl_->data_capacity_; + impl_->data_size_ = p.impl_->data_size_; + + uint8_t* data = static_cast( + realloc(impl_->data_, impl_->data_capacity_)); + if (data == nullptr) + throw std::bad_alloc(); + + impl_->data_ = data; + memcpy(impl_->data_, p.impl_->data_, impl_->data_size_); + impl_->reader_ = p.impl_->reader_; } Parcel& Parcel::operator = (const Parcel& p) { if (this != &p) { impl_->big_endian_ = p.impl_->big_endian_; - impl_->data_ = p.impl_->data_; + impl_->data_capacity_ = p.impl_->data_capacity_; + impl_->data_size_ = p.impl_->data_size_; + + uint8_t* data = static_cast( + realloc(impl_->data_, impl_->data_capacity_)); + if (data == nullptr) + throw std::bad_alloc(); + + impl_->data_ = data; + memcpy(impl_->data_, p.impl_->data_, impl_->data_size_); + impl_->reader_ = p.impl_->reader_; } return *this; } Parcel::Parcel(Parcel&& p) noexcept { - impl_ = std::move(p.impl_); - impl_->parent_ = this; + impl_->big_endian_ = p.impl_->big_endian_; + + impl_->data_size_ = p.impl_->data_size_; + p.impl_->data_size_ = 0; + + uint8_t* data = impl_->data_; + size_t data_capacity = impl_->data_capacity_; + + impl_->data_ = p.impl_->data_; + impl_->data_capacity_ = p.impl_->data_capacity_; + + p.impl_->data_ = data; + p.impl_->data_capacity_ = data_capacity; + + impl_->reader_ = p.impl_->reader_; + p.impl_->reader_ = 0; } Parcel& Parcel::operator = (Parcel&& p) noexcept { if (this != &p) { impl_->big_endian_ = p.impl_->big_endian_; - impl_->data_ = std::move(p.impl_->data_); + + impl_->data_size_ = p.impl_->data_size_; + p.impl_->data_size_ = 0; + + uint8_t* data = impl_->data_; + size_t data_capacity = impl_->data_capacity_; + + impl_->data_ = p.impl_->data_; + impl_->data_capacity_ = p.impl_->data_capacity_; + + p.impl_->data_ = data; + p.impl_->data_capacity_ = data_capacity; + impl_->reader_ = p.impl_->reader_; p.impl_->reader_ = 0; } @@ -394,4 +545,20 @@ void Parcel::SetByteOrder(bool big_endian) { impl_->SetByteOrder(big_endian); } +uint8_t* Parcel::GetData() const { + return impl_->GetData(); +} + +size_t Parcel::GetDataSize() const { + return impl_->GetDataSize(); +} + +size_t Parcel::GetDataCapacity() const { + return impl_->GetDataCapacity(); +} + +void Parcel::SetDataCapacity(size_t size) { + impl_->SetDataCapacity(size); +} + } // namespace tizen_base diff --git a/parcel/parcel.hh b/parcel/parcel.hh index 87af7d7..2ea3f38 100644 --- a/parcel/parcel.hh +++ b/parcel/parcel.hh @@ -378,6 +378,34 @@ class EXPORT Parcel final { */ void SetByteOrder(bool big_endian); + /** + * @brief Gets the raw data of the parcel. + * @since_tizen 7.0 + * @return The raw data + */ + uint8_t* GetData() const; + + /** + * @breif Gets the size of the raw data of the parcel. + * @since_tizen 7.0 + * @return The size of the raw data + */ + size_t GetDataSize() const; + + /** + * @brief Gets the size of the data capacity of the parcel. + * @since_tizen 7.0 + * @return The size of the data capacity + */ + size_t GetDataCapacity() const; + + /** + * @breif Sets the size of the data capacity of the parcel. + * @since_tizen 7.0 + * @param[in] size The size of the data capcity + */ + void SetDataCapacity(size_t size); + private: class Impl; std::unique_ptr impl_; diff --git a/parcel/parcel_implementation.hh b/parcel/parcel_implementation.hh index ed6c62f..502bc79 100644 --- a/parcel/parcel_implementation.hh +++ b/parcel/parcel_implementation.hh @@ -45,17 +45,24 @@ class Parcel::Impl { int Read(T* d); void SetByteOrder(bool big_endian); - bool IsBigEndian(); + bool IsBigEndian() const; + uint8_t* GetData() const; + size_t GetDataSize() const; + size_t GetDataCapacity() const; + void SetDataCapacity(size_t size); private: friend class Parcel; - explicit Impl(Parcel* parent, bool big_endian = false); + explicit Impl(Parcel* parent, size_t data_capacity, bool big_endian = false); private: Parcel* parent_; + size_t data_capacity_; bool big_endian_; - std::vector data_; + size_t data_size_ = 0; + uint8_t* data_ = nullptr; uint64_t reader_ = 0; + std::vector raw_; }; } // naemspace tizen_base diff --git a/parcel/stub.cc b/parcel/stub.cc index ce62584..f6b6299 100644 --- a/parcel/stub.cc +++ b/parcel/stub.cc @@ -15,6 +15,9 @@ */ #include "parcel/api/parcel.h" + +#include + #include "parcel/common.hh" #include "parcel/log_private.hh" #include "parcel/parcel.hh" @@ -386,9 +389,8 @@ extern "C" EXPORT int parcel_get_raw(parcel_h parcel, void** raw, } auto* h = static_cast(parcel); - auto& raw_data = h->GetRaw(); - *raw = reinterpret_cast(const_cast(&raw_data[0])); - *size = raw_data.size(); + *raw = reinterpret_cast(h->GetData()); + *size = h->GetDataSize(); return PARCEL_ERROR_NONE; } @@ -403,3 +405,33 @@ extern "C" EXPORT int parcel_set_byte_order(parcel_h parcel, h->SetByteOrder(big_endian); return PARCEL_ERROR_NONE; } + +extern "C" EXPORT int parcel_get_data_capacity(parcel_h parcel, + size_t* size) { + if (parcel == nullptr || size == nullptr) { + _E("Invalid parameter"); + return PARCEL_ERROR_INVALID_PARAMETER; + } + + auto* h = static_cast(parcel); + *size = h->GetDataCapacity(); + return PARCEL_ERROR_NONE; +} + +extern "C" EXPORT int parcel_set_data_capacity(parcel_h parcel, + size_t size) { + if (parcel == nullptr || size == 0) { + _E("Invalid parameter"); + return PARCEL_ERROR_INVALID_PARAMETER; + } + + auto* h = static_cast(parcel); + try { + h->SetDataCapacity(size); + } catch (const std::bad_alloc& e) { + _E("Exception occurs. error(%s)", e.what()); + return PARCEL_ERROR_OUT_OF_MEMORY; + } + + return PARCEL_ERROR_NONE; +} diff --git a/tests/parcel_unittests/test_parcel_cpp.cc b/tests/parcel_unittests/test_parcel_cpp.cc index ff52fb1..9236c94 100644 --- a/tests/parcel_unittests/test_parcel_cpp.cc +++ b/tests/parcel_unittests/test_parcel_cpp.cc @@ -187,7 +187,7 @@ TEST_F(ParcelCppTest, WriteCString_AND_ReadCString) { TEST_F(ParcelCppTest, GetRaw) { GetHandle().WriteInt32(0); auto& raw = GetHandle().GetRaw(); - ASSERT_EQ(raw.size(), sizeof(int32_t)); + ASSERT_EQ(raw.size(), sizeof(int)); } TEST_F(ParcelCppTest, ResetReader) {