From 374cd862b1d7953e8e0d50915c54dec2a6d65240 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 11 May 2020 12:46:38 +0200 Subject: [PATCH 1/2] added files for inspection --- ipc/MutexHelper.h | 20 +- storagemanager/LocalPool.h | 377 +++++------------------------ storagemanager/LocalPool.tpp | 260 ++++++++++++++++++++ storagemanager/PoolManager.h | 81 ++----- storagemanager/PoolManager.tpp | 42 ++++ storagemanager/StorageAccessor.cpp | 154 ++++++++++++ storagemanager/StorageAccessor.h | 174 +++++++++++++ storagemanager/StorageManagerIF.h | 23 +- 8 files changed, 743 insertions(+), 388 deletions(-) create mode 100644 storagemanager/LocalPool.tpp create mode 100644 storagemanager/PoolManager.tpp create mode 100644 storagemanager/StorageAccessor.cpp create mode 100644 storagemanager/StorageAccessor.h diff --git a/ipc/MutexHelper.h b/ipc/MutexHelper.h index f76ccec47..27c6c8178 100644 --- a/ipc/MutexHelper.h +++ b/ipc/MutexHelper.h @@ -6,19 +6,35 @@ class MutexHelper { public: + enum class MutexStates: uint8_t { + LOCKED, + UNLOCKED + }; + MutexHelper(MutexIF* mutex, uint32_t timeoutMs) : internalMutex(mutex) { ReturnValue_t status = mutex->lockMutex(timeoutMs); if(status != HasReturnvaluesIF::RETURN_OK){ sif::error << "MutexHelper: Lock of Mutex failed " << status << std::endl; + result = status; } + internalState = MutexStates::LOCKED; } - ~MutexHelper() { - internalMutex->unlockMutex(); + internalMutex->unlockMutex(); + } + + MutexStates getInternalState() const { + return internalState; + } + + ReturnValue_t getResult() const { + return result; } private: MutexIF* internalMutex; + MutexStates internalState = MutexStates::UNLOCKED; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; }; #endif /* FRAMEWORK_IPC_MUTEXHELPER_H_ */ diff --git a/storagemanager/LocalPool.h b/storagemanager/LocalPool.h index 5104be2ed..a63344581 100644 --- a/storagemanager/LocalPool.h +++ b/storagemanager/LocalPool.h @@ -1,15 +1,6 @@ #ifndef FRAMEWORK_STORAGEMANAGER_LOCALPOOL_H_ #define FRAMEWORK_STORAGEMANAGER_LOCALPOOL_H_ -/** - * @file LocalPool - * - * @date 02.02.2012 - * @author Bastian Baetz - * - * @brief This file contains the definition of the LocalPool class. - */ - #include #include #include @@ -39,7 +30,64 @@ public: * @brief This definition generally sets the number of different sized pools. * @details This must be less than the maximum number of pools (currently 0xff). */ -// static const uint32_t NUMBER_OF_POOLS; + // static const uint32_t NUMBER_OF_POOLS; + /** + * @brief This is the default constructor for a pool manager instance. + * @details By passing two arrays of size NUMBER_OF_POOLS, the constructor + * allocates memory (with \c new) for store and size_list. These + * regions are all set to zero on start up. + * @param setObjectId The object identifier to be set. This allows for + * multiple instances of LocalPool in the system. + * @param element_sizes An array of size NUMBER_OF_POOLS in which the size + * of a single element in each pool is determined. + * The sizes must be provided in ascending order. + * + * @param n_elements An array of size NUMBER_OF_POOLS in which the + * number of elements for each pool is determined. + * The position of these values correspond to those in + * element_sizes. + * @param registered Register the pool in object manager or not. Default is false (local pool). + * @param spillsToHigherPools + * A variable to determine whether higher n pools are used if the store is full. + */ + LocalPool(object_id_t setObjectId, + const uint16_t element_sizes[NUMBER_OF_POOLS], + const uint16_t n_elements[NUMBER_OF_POOLS], + bool registered = false, + bool spillsToHigherPools = false); + /** + * @brief In the LocalPool's destructor all allocated memory is freed. + */ + virtual ~LocalPool(void); + + /** + * Documentation: See StorageManagerIF.h + */ + ReturnValue_t addData(store_address_t* storageId, const uint8_t * data, + size_t size, bool ignoreFault = false) override; + ReturnValue_t getFreeElement(store_address_t* storageId,const size_t size, + uint8_t** p_data, bool ignoreFault = false) override; + ReturnValue_t getData(store_address_t packet_id, const uint8_t** packet_ptr, + size_t * size) override; + ReturnValue_t modifyData(store_address_t packet_id, uint8_t** packet_ptr, + size_t * size) override; + virtual ReturnValue_t deleteData(store_address_t) override; + virtual ReturnValue_t deleteData(uint8_t* ptr, size_t size, + store_address_t* storeId = NULL) override; + void clearStore() override; + ReturnValue_t initialize() override; +protected: + /** + * With this helper method, a free element of \c size is reserved. + * @param size The minimum packet size that shall be reserved. + * @param[out] address Storage ID of the reserved data. + * @return - #RETURN_OK on success, + * - the return codes of #getPoolIndex or #findEmpty otherwise. + */ + virtual ReturnValue_t reserveSpace(const uint32_t size, + store_address_t* address, bool ignoreFault); + + InternalErrorReporterIF *internalErrorReporter; private: /** * Indicates that this element is free. @@ -78,7 +126,7 @@ private: * @param data The data to be stored. * @param size The size of the data to be stored. */ - void write(store_address_t packet_id, const uint8_t* data, uint32_t size); + void write(store_address_t packet_id, const uint8_t* data, size_t size); /** * @brief A helper method to read the element size of a certain pool. * @param pool_index The pool in which to look. @@ -101,7 +149,8 @@ private: * @return - #RETURN_OK on success, * - #DATA_TOO_LARGE otherwise. */ - ReturnValue_t getPoolIndex(uint32_t packet_size, uint16_t* poolIndex, uint16_t startAtIndex = 0); + ReturnValue_t getPoolIndex(size_t packet_size, uint16_t* poolIndex, + uint16_t startAtIndex = 0); /** * @brief This helper method calculates the true array position in store * of a given packet id. @@ -121,310 +170,8 @@ private: * - #DATA_STORAGE_FULL if the store is full */ ReturnValue_t findEmpty(uint16_t pool_index, uint16_t* element); -protected: - /** - * With this helper method, a free element of \c size is reserved. - * @param size The minimum packet size that shall be reserved. - * @param[out] address Storage ID of the reserved data. - * @return - #RETURN_OK on success, - * - the return codes of #getPoolIndex or #findEmpty otherwise. - */ - virtual ReturnValue_t reserveSpace(const uint32_t size, store_address_t* address, bool ignoreFault); - - InternalErrorReporterIF *internalErrorReporter; -public: - /** - * @brief This is the default constructor for a pool manager instance. - * @details By passing two arrays of size NUMBER_OF_POOLS, the constructor - * allocates memory (with \c new) for store and size_list. These - * regions are all set to zero on start up. - * @param setObjectId The object identifier to be set. This allows for - * multiple instances of LocalPool in the system. - * @param element_sizes An array of size NUMBER_OF_POOLS in which the size - * of a single element in each pool is determined. - * The sizes must be provided in ascending order. - * - * @param n_elements An array of size NUMBER_OF_POOLS in which the - * number of elements for each pool is determined. - * The position of these values correspond to those in - * element_sizes. - * @param registered Register the pool in object manager or not. Default is false (local pool). - */ - LocalPool(object_id_t setObjectId, - const uint16_t element_sizes[NUMBER_OF_POOLS], - const uint16_t n_elements[NUMBER_OF_POOLS], - bool registered = false, - bool spillsToHigherPools = false); - /** - * @brief In the LocalPool's destructor all allocated memory is freed. - */ - virtual ~LocalPool(void); - ReturnValue_t addData(store_address_t* storageId, const uint8_t * data, - uint32_t size, bool ignoreFault = false); - - /** - * With this helper method, a free element of \c size is reserved. - * - * @param size The minimum packet size that shall be reserved. - * @return Returns the storage identifier within the storage or - * StorageManagerIF::INVALID_ADDRESS (in raw). - */ - ReturnValue_t getFreeElement(store_address_t* storageId, - const uint32_t size, uint8_t** p_data, bool ignoreFault = false); - ReturnValue_t getData(store_address_t packet_id, const uint8_t** packet_ptr, - uint32_t* size); - ReturnValue_t modifyData(store_address_t packet_id, uint8_t** packet_ptr, - uint32_t* size); - virtual ReturnValue_t deleteData(store_address_t); - virtual ReturnValue_t deleteData(uint8_t* ptr, uint32_t size, - store_address_t* storeId = NULL); - void clearStore(); - ReturnValue_t initialize(); }; -template -inline ReturnValue_t LocalPool::findEmpty(uint16_t pool_index, - uint16_t* element) { - ReturnValue_t status = DATA_STORAGE_FULL; - for (uint16_t foundElement = 0; foundElement < n_elements[pool_index]; - foundElement++) { - if (size_list[pool_index][foundElement] == STORAGE_FREE) { - *element = foundElement; - status = RETURN_OK; - break; - } - } - return status; -} - -template -inline void LocalPool::write(store_address_t packet_id, - const uint8_t* data, uint32_t size) { - uint8_t* ptr; - uint32_t packet_position = getRawPosition(packet_id); - - //check size? -> Not necessary, because size is checked before calling this function. - ptr = &store[packet_id.pool_index][packet_position]; - memcpy(ptr, data, size); - size_list[packet_id.pool_index][packet_id.packet_index] = size; -} - -//Returns page size of 0 in case store_index is illegal -template -inline uint32_t LocalPool::getPageSize(uint16_t pool_index) { - if (pool_index < NUMBER_OF_POOLS) { - return element_sizes[pool_index]; - } else { - return 0; - } -} - -template -inline ReturnValue_t LocalPool::getPoolIndex( - uint32_t packet_size, uint16_t* poolIndex, uint16_t startAtIndex) { - for (uint16_t n = startAtIndex; n < NUMBER_OF_POOLS; n++) { -// debug << "LocalPool " << getObjectId() << "::getPoolIndex: Pool: " << n << ", Element Size: " << element_sizes[n] << std::endl; - if (element_sizes[n] >= packet_size) { - *poolIndex = n; - return RETURN_OK; - } - } - return DATA_TOO_LARGE; -} - -template -inline uint32_t LocalPool::getRawPosition( - store_address_t packet_id) { - return packet_id.packet_index * element_sizes[packet_id.pool_index]; -} - -template -inline ReturnValue_t LocalPool::reserveSpace( - const uint32_t size, store_address_t* address, bool ignoreFault) { - ReturnValue_t status = getPoolIndex(size, &address->pool_index); - if (status != RETURN_OK) { - sif::error << "LocalPool( " << std::hex << getObjectId() << std::dec - << " )::reserveSpace: Packet too large." << std::endl; - return status; - } - status = findEmpty(address->pool_index, &address->packet_index); - while (status != RETURN_OK && spillsToHigherPools) { - status = getPoolIndex(size, &address->pool_index, address->pool_index + 1); - if (status != RETURN_OK) { - //We don't find any fitting pool anymore. - break; - } - status = findEmpty(address->pool_index, &address->packet_index); - } - if (status == RETURN_OK) { -// if (getObjectId() == objects::IPC_STORE && address->pool_index >= 3) { -// debug << "Reserve: Pool: " << std::dec << address->pool_index << " Index: " << address->packet_index << std::endl; -// } - - size_list[address->pool_index][address->packet_index] = size; - } else { - if (!ignoreFault) { - internalErrorReporter->storeFull(); - } -// error << "LocalPool( " << std::hex << getObjectId() << std::dec -// << " )::reserveSpace: Packet store is full." << std::endl; - } - return status; -} - -template -inline LocalPool::LocalPool(object_id_t setObjectId, - const uint16_t element_sizes[NUMBER_OF_POOLS], - const uint16_t n_elements[NUMBER_OF_POOLS], bool registered, bool spillsToHigherPools) : - SystemObject(setObjectId, registered), spillsToHigherPools(spillsToHigherPools), internalErrorReporter(NULL) { - for (uint16_t n = 0; n < NUMBER_OF_POOLS; n++) { - this->element_sizes[n] = element_sizes[n]; - this->n_elements[n] = n_elements[n]; - store[n] = new uint8_t[n_elements[n] * element_sizes[n]]; - size_list[n] = new uint32_t[n_elements[n]]; - memset(store[n], 0x00, (n_elements[n] * element_sizes[n])); - memset(size_list[n], STORAGE_FREE, (n_elements[n] * sizeof(**size_list))); //TODO checkme - } -} - -template -inline LocalPool::~LocalPool(void) { - for (uint16_t n = 0; n < NUMBER_OF_POOLS; n++) { - delete[] store[n]; - delete[] size_list[n]; - } -} - -template -inline ReturnValue_t LocalPool::addData( - store_address_t* storageId, const uint8_t* data, uint32_t size, bool ignoreFault) { - ReturnValue_t status = reserveSpace(size, storageId, ignoreFault); - if (status == RETURN_OK) { - write(*storageId, data, size); - } - return status; -} - -template -inline ReturnValue_t LocalPool::getFreeElement( - store_address_t* storageId, const uint32_t size, uint8_t** p_data, bool ignoreFault) { - ReturnValue_t status = reserveSpace(size, storageId, ignoreFault); - if (status == RETURN_OK) { - *p_data = &store[storageId->pool_index][getRawPosition(*storageId)]; - } else { - *p_data = NULL; - } - return status; -} - -template -inline ReturnValue_t LocalPool::getData( - store_address_t packet_id, const uint8_t** packet_ptr, uint32_t* size) { - uint8_t* tempData = NULL; - ReturnValue_t status = modifyData(packet_id, &tempData, size); - *packet_ptr = tempData; - return status; -} - -template -inline ReturnValue_t LocalPool::modifyData(store_address_t packet_id, - uint8_t** packet_ptr, uint32_t* size) { - ReturnValue_t status = RETURN_FAILED; - if (packet_id.pool_index >= NUMBER_OF_POOLS) { - return ILLEGAL_STORAGE_ID; - } - if ((packet_id.packet_index >= n_elements[packet_id.pool_index])) { - return ILLEGAL_STORAGE_ID; - } - if (size_list[packet_id.pool_index][packet_id.packet_index] - != STORAGE_FREE) { - uint32_t packet_position = getRawPosition(packet_id); - *packet_ptr = &store[packet_id.pool_index][packet_position]; - *size = size_list[packet_id.pool_index][packet_id.packet_index]; - status = RETURN_OK; - } else { - status = DATA_DOES_NOT_EXIST; - } - return status; -} - -template -inline ReturnValue_t LocalPool::deleteData( - store_address_t packet_id) { - -// if (getObjectId() == objects::IPC_STORE && packet_id.pool_index >= 3) { -// debug << "Delete: Pool: " << std::dec << packet_id.pool_index << " Index: " << packet_id.packet_index << std::endl; -// } - ReturnValue_t status = RETURN_OK; - uint32_t page_size = getPageSize(packet_id.pool_index); - if ((page_size != 0) - && (packet_id.packet_index < n_elements[packet_id.pool_index])) { - uint16_t packet_position = getRawPosition(packet_id); - uint8_t* ptr = &store[packet_id.pool_index][packet_position]; - memset(ptr, 0, page_size); - //Set free list - size_list[packet_id.pool_index][packet_id.packet_index] = STORAGE_FREE; - } else { - //pool_index or packet_index is too large - sif::error << "LocalPool:deleteData failed." << std::endl; - status = ILLEGAL_STORAGE_ID; - } - return status; -} - -template -inline void LocalPool::clearStore() { - for (uint16_t n = 0; n < NUMBER_OF_POOLS; n++) { - memset(size_list[n], STORAGE_FREE, (n_elements[n] * sizeof(**size_list)));//TODO checkme - } -} - -template -inline ReturnValue_t LocalPool::deleteData(uint8_t* ptr, - uint32_t size, store_address_t* storeId) { - store_address_t localId; - ReturnValue_t result = ILLEGAL_ADDRESS; - for (uint16_t n = 0; n < NUMBER_OF_POOLS; n++) { - //Not sure if new allocates all stores in order. so better be careful. - if ((store[n] <= ptr) && (&store[n][n_elements[n]*element_sizes[n]]) > ptr) { - localId.pool_index = n; - uint32_t deltaAddress = ptr - store[n]; - //Getting any data from the right "block" is ok. This is necessary, as IF's sometimes don't point to the first element of an object. - localId.packet_index = deltaAddress / element_sizes[n]; - result = deleteData(localId); -// if (deltaAddress % element_sizes[n] != 0) { -// error << "Pool::deleteData: address not aligned!" << std::endl; -// } - break; - } - } - if (storeId != NULL) { - *storeId = localId; - } - return result; -} - -template -inline ReturnValue_t LocalPool::initialize() { - ReturnValue_t result = SystemObject::initialize(); - if (result != RETURN_OK) { - return result; - } - internalErrorReporter = objectManager->get(objects::INTERNAL_ERROR_REPORTER); - if (internalErrorReporter == NULL){ - return RETURN_FAILED; - } - - //Check if any pool size is large than the maximum allowed. - for (uint8_t count = 0; count < NUMBER_OF_POOLS; count++) { - if (element_sizes[count] >= STORAGE_FREE) { - sif::error - << "LocalPool::initialize: Pool is too large! Max. allowed size is: " - << (STORAGE_FREE - 1) << std::endl; - return RETURN_FAILED; - } - } - return RETURN_OK; -} +#include #endif /* FRAMEWORK_STORAGEMANAGER_LOCALPOOL_H_ */ diff --git a/storagemanager/LocalPool.tpp b/storagemanager/LocalPool.tpp new file mode 100644 index 000000000..c46e1a8d1 --- /dev/null +++ b/storagemanager/LocalPool.tpp @@ -0,0 +1,260 @@ +#ifndef LOCALPOOL_TPP +#define LOCALPOOL_TPP + +template +inline LocalPool::LocalPool(object_id_t setObjectId, + const uint16_t element_sizes[NUMBER_OF_POOLS], + const uint16_t n_elements[NUMBER_OF_POOLS], bool registered, + bool spillsToHigherPools) : + SystemObject(setObjectId, registered), internalErrorReporter(nullptr), + spillsToHigherPools(spillsToHigherPools) +{ + for (uint16_t n = 0; n < NUMBER_OF_POOLS; n++) { + this->element_sizes[n] = element_sizes[n]; + this->n_elements[n] = n_elements[n]; + store[n] = new uint8_t[n_elements[n] * element_sizes[n]]; + size_list[n] = new uint32_t[n_elements[n]]; + memset(store[n], 0x00, (n_elements[n] * element_sizes[n])); + //TODO checkme + memset(size_list[n], STORAGE_FREE, (n_elements[n] * sizeof(**size_list))); + } +} + + +template +inline ReturnValue_t LocalPool::findEmpty(uint16_t pool_index, + uint16_t* element) { + ReturnValue_t status = DATA_STORAGE_FULL; + for (uint16_t foundElement = 0; foundElement < n_elements[pool_index]; + foundElement++) { + if (size_list[pool_index][foundElement] == STORAGE_FREE) { + *element = foundElement; + status = RETURN_OK; + break; + } + } + return status; +} + +template +inline void LocalPool::write(store_address_t packet_id, + const uint8_t* data, size_t size) { + uint8_t* ptr; + uint32_t packet_position = getRawPosition(packet_id); + + //check size? -> Not necessary, because size is checked before calling this function. + ptr = &store[packet_id.pool_index][packet_position]; + memcpy(ptr, data, size); + size_list[packet_id.pool_index][packet_id.packet_index] = size; +} + +//Returns page size of 0 in case store_index is illegal +template +inline uint32_t LocalPool::getPageSize(uint16_t pool_index) { + if (pool_index < NUMBER_OF_POOLS) { + return element_sizes[pool_index]; + } else { + return 0; + } +} + +template +inline ReturnValue_t LocalPool::getPoolIndex( + size_t packet_size, uint16_t* poolIndex, uint16_t startAtIndex) { + for (uint16_t n = startAtIndex; n < NUMBER_OF_POOLS; n++) { + //debug << "LocalPool " << getObjectId() << "::getPoolIndex: Pool: " << + // n << ", Element Size: " << element_sizes[n] << std::endl; + if (element_sizes[n] >= packet_size) { + *poolIndex = n; + return RETURN_OK; + } + } + return DATA_TOO_LARGE; +} + +template +inline uint32_t LocalPool::getRawPosition( + store_address_t packet_id) { + return packet_id.packet_index * element_sizes[packet_id.pool_index]; +} + +template +inline ReturnValue_t LocalPool::reserveSpace( + const uint32_t size, store_address_t* address, bool ignoreFault) { + ReturnValue_t status = getPoolIndex(size, &address->pool_index); + if (status != RETURN_OK) { + sif::error << "LocalPool( " << std::hex << getObjectId() << std::dec + << " )::reserveSpace: Packet too large." << std::endl; + return status; + } + status = findEmpty(address->pool_index, &address->packet_index); + while (status != RETURN_OK && spillsToHigherPools) { + status = getPoolIndex(size, &address->pool_index, address->pool_index + 1); + if (status != RETURN_OK) { + //We don't find any fitting pool anymore. + break; + } + status = findEmpty(address->pool_index, &address->packet_index); + } + if (status == RETURN_OK) { + // if (getObjectId() == objects::IPC_STORE && address->pool_index >= 3) { + // debug << "Reserve: Pool: " << std::dec << address->pool_index << + // " Index: " << address->packet_index << std::endl; + // } + + size_list[address->pool_index][address->packet_index] = size; + } else { + if (!ignoreFault and internalErrorReporter != nullptr) { + internalErrorReporter->storeFull(); + } + // error << "LocalPool( " << std::hex << getObjectId() << std::dec + // << " )::reserveSpace: Packet store is full." << std::endl; + } + return status; +} + +template +inline LocalPool::~LocalPool(void) { + for (uint16_t n = 0; n < NUMBER_OF_POOLS; n++) { + delete[] store[n]; + delete[] size_list[n]; + } +} + +template +inline ReturnValue_t LocalPool::addData(store_address_t* storageId, + const uint8_t* data, size_t size, bool ignoreFault) { + ReturnValue_t status = reserveSpace(size, storageId, ignoreFault); + if (status == RETURN_OK) { + write(*storageId, data, size); + } + return status; +} + +template +inline ReturnValue_t LocalPool::getFreeElement( + store_address_t* storageId, const size_t size, + uint8_t** p_data, bool ignoreFault) { + ReturnValue_t status = reserveSpace(size, storageId, ignoreFault); + if (status == RETURN_OK) { + *p_data = &store[storageId->pool_index][getRawPosition(*storageId)]; + } else { + *p_data = NULL; + } + return status; +} + +template +inline ReturnValue_t LocalPool::getData( + store_address_t packet_id, const uint8_t** packet_ptr, size_t* size) { + uint8_t* tempData = NULL; + ReturnValue_t status = modifyData(packet_id, &tempData, size); + *packet_ptr = tempData; + return status; +} + +template +inline ReturnValue_t LocalPool::modifyData( + store_address_t packet_id, uint8_t** packet_ptr, size_t* size) { + ReturnValue_t status = RETURN_FAILED; + if (packet_id.pool_index >= NUMBER_OF_POOLS) { + return ILLEGAL_STORAGE_ID; + } + if ((packet_id.packet_index >= n_elements[packet_id.pool_index])) { + return ILLEGAL_STORAGE_ID; + } + if (size_list[packet_id.pool_index][packet_id.packet_index] + != STORAGE_FREE) { + uint32_t packet_position = getRawPosition(packet_id); + *packet_ptr = &store[packet_id.pool_index][packet_position]; + *size = size_list[packet_id.pool_index][packet_id.packet_index]; + status = RETURN_OK; + } else { + status = DATA_DOES_NOT_EXIST; + } + return status; +} + +template +inline ReturnValue_t LocalPool::deleteData( + store_address_t packet_id) { + //if (getObjectId() == objects::IPC_STORE && packet_id.pool_index >= 3) { + // debug << "Delete: Pool: " << std::dec << packet_id.pool_index << " Index: " + // << packet_id.packet_index << std::endl; + //} + ReturnValue_t status = RETURN_OK; + uint32_t page_size = getPageSize(packet_id.pool_index); + if ((page_size != 0) + && (packet_id.packet_index < n_elements[packet_id.pool_index])) { + uint16_t packet_position = getRawPosition(packet_id); + uint8_t* ptr = &store[packet_id.pool_index][packet_position]; + memset(ptr, 0, page_size); + //Set free list + size_list[packet_id.pool_index][packet_id.packet_index] = STORAGE_FREE; + } else { + //pool_index or packet_index is too large + sif::error << "LocalPool:deleteData failed." << std::endl; + status = ILLEGAL_STORAGE_ID; + } + return status; +} + +template +inline void LocalPool::clearStore() { + for (uint16_t n = 0; n < NUMBER_OF_POOLS; n++) { + //TODO checkme + memset(size_list[n], STORAGE_FREE, (n_elements[n] * sizeof(**size_list))); + } +} + +template +inline ReturnValue_t LocalPool::deleteData(uint8_t* ptr, + size_t size, store_address_t* storeId) { + store_address_t localId; + ReturnValue_t result = ILLEGAL_ADDRESS; + for (uint16_t n = 0; n < NUMBER_OF_POOLS; n++) { + //Not sure if new allocates all stores in order. so better be careful. + if ((store[n] <= ptr) && (&store[n][n_elements[n]*element_sizes[n]]) > ptr) { + localId.pool_index = n; + uint32_t deltaAddress = ptr - store[n]; + // Getting any data from the right "block" is ok. + // This is necessary, as IF's sometimes don't point to the first + // element of an object. + localId.packet_index = deltaAddress / element_sizes[n]; + result = deleteData(localId); + //if (deltaAddress % element_sizes[n] != 0) { + // error << "Pool::deleteData: address not aligned!" << std::endl; + //} + break; + } + } + if (storeId != NULL) { + *storeId = localId; + } + return result; +} + +template +inline ReturnValue_t LocalPool::initialize() { + ReturnValue_t result = SystemObject::initialize(); + if (result != RETURN_OK) { + return result; + } + internalErrorReporter = objectManager->get( + objects::INTERNAL_ERROR_REPORTER); + if (internalErrorReporter == nullptr){ + return ObjectManagerIF::INTERNAL_ERR_REPORTER_UNINIT; + } + + //Check if any pool size is large than the maximum allowed. + for (uint8_t count = 0; count < NUMBER_OF_POOLS; count++) { + if (element_sizes[count] >= STORAGE_FREE) { + sif::error << "LocalPool::initialize: Pool is too large! " + "Max. allowed size is: " << (STORAGE_FREE - 1) << std::endl; + return StorageManagerIF::POOL_TOO_LARGE; + } + } + return RETURN_OK; +} + +#endif diff --git a/storagemanager/PoolManager.h b/storagemanager/PoolManager.h index 68a7addc1..41325273a 100644 --- a/storagemanager/PoolManager.h +++ b/storagemanager/PoolManager.h @@ -1,12 +1,3 @@ -/** - * @file PoolManager - * - * @date 02.02.2012 - * @author Bastian Baetz - * - * @brief This file contains the definition of the PoolManager class. - */ - #ifndef POOLMANAGER_H_ #define POOLMANAGER_H_ @@ -17,70 +8,36 @@ /** * @brief The PoolManager class provides an intermediate data storage with * a fixed pool size policy for inter-process communication. - * \details Uses local pool, but is thread-safe. + * @details Uses local pool calls but is thread safe by protecting the call + * with a lock. */ template class PoolManager : public LocalPool { -protected: - /** - * Overwritten for thread safety. - * Locks during execution. - */ - virtual ReturnValue_t reserveSpace(const uint32_t size, store_address_t* address, bool ignoreFault); - - /** - * \brief The mutex is created in the constructor and makes access mutual exclusive. - * \details Locking and unlocking is done during searching for free slots and deleting existing slots. - */ - MutexIF* mutex; public: - PoolManager( object_id_t setObjectId, const uint16_t element_sizes[NUMBER_OF_POOLS], const uint16_t n_elements[NUMBER_OF_POOLS] ); + PoolManager( object_id_t setObjectId, const uint16_t element_sizes[NUMBER_OF_POOLS], + const uint16_t n_elements[NUMBER_OF_POOLS] ); /** * @brief In the PoolManager's destructor all allocated memory is freed. */ - virtual ~PoolManager( void ); + virtual ~PoolManager(); + + ReturnValue_t deleteData(store_address_t) override; + ReturnValue_t deleteData(uint8_t* buffer, size_t size, + store_address_t* storeId = NULL) override; +protected: + ReturnValue_t reserveSpace(const uint32_t size, store_address_t* address, + bool ignoreFault) override; + /** - * Overwritten for thread safety. + * @brief The mutex is created in the constructor and makes + * access mutual exclusive. + * @details Locking and unlocking is done during searching for free slots + * and deleting existing slots. */ - virtual ReturnValue_t deleteData(store_address_t); - virtual ReturnValue_t deleteData(uint8_t* buffer, uint32_t size, store_address_t* storeId = NULL); + MutexIF* mutex; }; -template -inline ReturnValue_t PoolManager::reserveSpace(const uint32_t size, store_address_t* address, bool ignoreFault) { - MutexHelper mutexHelper(mutex,MutexIF::NO_TIMEOUT); - ReturnValue_t status = LocalPool::reserveSpace(size,address,ignoreFault); - return status; -} - -template -inline PoolManager::PoolManager(object_id_t setObjectId, - const uint16_t element_sizes[NUMBER_OF_POOLS], - const uint16_t n_elements[NUMBER_OF_POOLS]) : LocalPool(setObjectId, element_sizes, n_elements, true) { - mutex = MutexFactory::instance()->createMutex(); -} - -template -inline PoolManager::~PoolManager(void) { - MutexFactory::instance()->deleteMutex(mutex); -} - -template -inline ReturnValue_t PoolManager::deleteData( - store_address_t packet_id) { - // debug << "PoolManager( " << translateObject(getObjectId()) << " )::deleteData from store " << packet_id.pool_index << ". id is " << packet_id.packet_index << std::endl; - MutexHelper mutexHelper(mutex,MutexIF::NO_TIMEOUT); - ReturnValue_t status = LocalPool::deleteData(packet_id); - return status; -} - -template -inline ReturnValue_t PoolManager::deleteData(uint8_t* buffer, uint32_t size, - store_address_t* storeId) { - MutexHelper mutexHelper(mutex,MutexIF::NO_TIMEOUT); - ReturnValue_t status = LocalPool::deleteData(buffer, size, storeId); - return status; -} +#include "PoolManager.tpp" #endif /* POOLMANAGER_H_ */ diff --git a/storagemanager/PoolManager.tpp b/storagemanager/PoolManager.tpp new file mode 100644 index 000000000..0408d55b9 --- /dev/null +++ b/storagemanager/PoolManager.tpp @@ -0,0 +1,42 @@ +template +inline PoolManager::PoolManager(object_id_t setObjectId, + const uint16_t element_sizes[NUMBER_OF_POOLS], + const uint16_t n_elements[NUMBER_OF_POOLS]) : + LocalPool(setObjectId, element_sizes, n_elements, true) { + mutex = MutexFactory::instance()->createMutex(); +} + +template +inline PoolManager::~PoolManager(void) { + MutexFactory::instance()->deleteMutex(mutex); +} + +template +inline ReturnValue_t PoolManager::reserveSpace( + const uint32_t size, store_address_t* address, bool ignoreFault) { + MutexHelper mutexHelper(mutex,MutexIF::NO_TIMEOUT); + ReturnValue_t status = LocalPool::reserveSpace(size, + address,ignoreFault); + return status; +} + +template +inline ReturnValue_t PoolManager::deleteData( + store_address_t packet_id) { + // debug << "PoolManager( " << translateObject(getObjectId()) << + // " )::deleteData from store " << packet_id.pool_index << + // ". id is "<< packet_id.packet_index << std::endl; + MutexHelper mutexHelper(mutex,MutexIF::NO_TIMEOUT); + ReturnValue_t status = LocalPool::deleteData(packet_id); + return status; +} + +template +inline ReturnValue_t PoolManager::deleteData(uint8_t* buffer, + size_t size, store_address_t* storeId) { + MutexHelper mutexHelper(mutex,MutexIF::NO_TIMEOUT); + ReturnValue_t status = LocalPool::deleteData(buffer, + size, storeId); + return status; +} + diff --git a/storagemanager/StorageAccessor.cpp b/storagemanager/StorageAccessor.cpp new file mode 100644 index 000000000..a068d1694 --- /dev/null +++ b/storagemanager/StorageAccessor.cpp @@ -0,0 +1,154 @@ +//#include +// +//ConstStorageAccessor::ConstStorageAccessor(store_address_t storeId): storeId(storeId) {} +// +//ConstStorageAccessor::~ConstStorageAccessor() { +// if(deleteData and store != nullptr) { +// sif::debug << "deleting store data" << std::endl; +// store->deleteDataNonLocking(storeId); +// } +// if(mutexLock != nullptr) { +// sif::debug << "unlocking mutex lock" << std::endl; +// mutexLock.reset(); +// } +//} +// +//ConstStorageAccessor& ConstStorageAccessor::operator=( +// ConstStorageAccessor&& other) { +// constDataPointer = other.constDataPointer; +// storeId = other.storeId; +// store = other.store; +// size_ = other.size_; +// deleteData = other.deleteData; +// this->store = other.store; +// // Transfer ownership of the lock. +// mutexLock = std::move(other.mutexLock); +// // This prevents double deletion of the resource +// other.mutexLock = nullptr; +// // This prevent premature deletion +// other.store = nullptr; +// return *this; +//} +// +//StorageAccessor::StorageAccessor(store_address_t storeId): +// ConstStorageAccessor(storeId) { +//} +// +//StorageAccessor& StorageAccessor::operator =( +// StorageAccessor&& other) { +// // Call the parent move assignment and also assign own member. +// dataPointer = other.dataPointer; +// StorageAccessor::operator=(std::move(other)); +// return * this; +//} +// +//// Call the parent move ctor and also transfer own member. +//StorageAccessor::StorageAccessor(StorageAccessor&& other): +// ConstStorageAccessor(std::move(other)), dataPointer(other.dataPointer) { +//} +// +//ConstStorageAccessor::ConstStorageAccessor(ConstStorageAccessor&& other): +// constDataPointer(other.constDataPointer), storeId(other.storeId), +// size_(other.size_), store(other.store), deleteData(other.deleteData), +// internalState(other.internalState) { +// // Transfer ownership of the lock. +// mutexLock = std::move(other.mutexLock); +// // This prevents double deletion of the resource. Not strictly necessary, +// // from the testing I have conducted so far but I am not familiar enough +// // with move semantics so I will just set the other lock to nullptr for now. +// other.mutexLock = nullptr; +// // This prevent premature deletion +// other.store = nullptr; +//} +// +//const uint8_t* ConstStorageAccessor::data() const { +// return constDataPointer; +//} +// +//size_t ConstStorageAccessor::size() const { +// if(internalState == AccessState::UNINIT) { +// sif::warning << "StorageAccessor: Not initialized!" << std::endl; +// } +// return size_; +//} +// +//void ConstStorageAccessor::getDataCopy(uint8_t *pointer) { +// if(internalState == AccessState::UNINIT) { +// sif::warning << "StorageAccessor: Not initialized!" << std::endl; +// return; +// } +// std::copy(constDataPointer, constDataPointer + size_, pointer); +//} +// +//void ConstStorageAccessor::release() { +// deleteData = false; +//} +// +//ReturnValue_t ConstStorageAccessor::lock(MutexIF* mutex, uint32_t mutexTimeout) { +// if(mutexLock == nullptr) { +// mutexLock = std::unique_ptr(new MutexHelper(mutex, mutexTimeout)); +// return mutexLock.get()->getResult(); +// } +// else { +// sif::warning << "StorageAccessor: Attempted to lock twice. Check code!" << std::endl; +// return HasReturnvaluesIF::RETURN_FAILED; +// } +//} +// +//void ConstStorageAccessor::unlock() { +// if(mutexLock != nullptr) { +// mutexLock.reset(); +// } +//} +// +//store_address_t ConstStorageAccessor::getId() const { +// return storeId; +//} +// +//void ConstStorageAccessor::print() const { +// if(internalState == AccessState::UNINIT) { +// sif::warning << "StorageAccessor: Not initialized!" << std::endl; +// return; +// } +// sif::info << "StorageAccessor: Printing data: ["; +// for(uint16_t iPool = 0; iPool < size_; iPool++) { +// sif::info << std::hex << (int)constDataPointer[iPool]; +// if(iPool < size_ - 1){ +// sif::info << " , "; +// } +// } +// sif::info << " ] " << std::endl; +//} +// +//void ConstStorageAccessor::assignStore(StorageManagerIF* store) { +// internalState = AccessState::READ; +// this->store = store; +//} +// +// +//uint8_t* StorageAccessor::data() { +// if(internalState == AccessState::UNINIT) { +// sif::warning << "StorageAccessor: Not initialized!" << std::endl; +// } +// return dataPointer; +//} +// +//ReturnValue_t StorageAccessor::write(uint8_t *data, size_t size, +// uint16_t offset) { +// if(internalState == AccessState::UNINIT) { +// sif::warning << "StorageAccessor: Not initialized!" << std::endl; +// return HasReturnvaluesIF::RETURN_FAILED; +// } +// if(offset + size > size_) { +// sif::error << "StorageAccessor: Data too large for pool entry!" << std::endl; +// return HasReturnvaluesIF::RETURN_FAILED; +// } +// std::copy(data, data + size, dataPointer); +// return HasReturnvaluesIF::RETURN_OK; +//} +// +//void StorageAccessor::assignConstPointer() { +// constDataPointer = dataPointer; +//} +// +// diff --git a/storagemanager/StorageAccessor.h b/storagemanager/StorageAccessor.h new file mode 100644 index 000000000..d391c5c26 --- /dev/null +++ b/storagemanager/StorageAccessor.h @@ -0,0 +1,174 @@ +///** +// * @brief Helper classes to facilitate safe access to storages which is also +// * conforming to RAII principles +// * @details These helper can be used together with the +// * StorageManager classes to manage access to a storage. +// * It can take care of thread-safety while also providing +// * mechanisms to automatically clear storage data and unlocking the +// * pool. +// */ +//#ifndef TEST_PROTOTYPES_STORAGEACCESSOR_H_ +//#define TEST_PROTOTYPES_STORAGEACCESSOR_H_ +// +//#include +//#include +//#include +// +// +///** +// * @brief Accessor class which can be returned by pool managers +// * or passed and set by pool managers to have safe access to the pool +// * resources. +// */ +//class ConstStorageAccessor { +// //! StorageManager classes have exclusive access to private variables. +// template +// friend class PoolManager; +// template +// friend class LocalPool; +//public: +// /** +// * @brief Simple constructor which takes the store ID of the storage +// * entry to access. +// * @param storeId +// */ +// ConstStorageAccessor(store_address_t storeId); +// +// /** +// * @brief Move ctor and move assignment allow returning accessors as +// * a returnvalue. They prevent resource being free prematurely. +// * Refer to: https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/cpp/ +// * move-constructors-and-move-assignment-operators-cpp.md +// * @param +// * @return +// */ +// ConstStorageAccessor& operator= (ConstStorageAccessor&&); +// ConstStorageAccessor (ConstStorageAccessor&&); +// +// //! The copy ctor and copy assignemnt should be deleted implicitely +// //! according to https://foonathan.net/2019/02/special-member-functions/ +// //! but I still deleted them to make it more explicit. (remember rule of 5). +// ConstStorageAccessor& operator= (ConstStorageAccessor&) = delete; +// ConstStorageAccessor (ConstStorageAccessor&) = delete; +// +// /** +// * @brief The destructor in default configuration takes care of +// * deleting the accessed pool entry and unlocking the mutex +// */ +// virtual ~ConstStorageAccessor(); +// +// /** +// * @brief Returns a pointer to the read-only data +// * @return +// */ +// const uint8_t* data() const; +// +// /** +// * @brief Copies the read-only data to the supplied pointer +// * @param pointer +// */ +// void getDataCopy(uint8_t *pointer); +// +// /** +// * @brief Calling this will prevent the Accessor from deleting the data +// * when the destructor is called. +// */ +// void release(); +// /** +// * @brief Locks the supplied mutex. +// * @details +// * The mutex will be unlocked automatically +// * when this class is destroyed (for example when exiting the scope). +// * Only one mutex can be locked at a time! +// * @param mutex +// * @param mutexTimeout +// * @return +// */ +// ReturnValue_t lock(MutexIF* mutex, +// uint32_t mutexTimeout = MutexIF::NO_TIMEOUT); +// /** +// * @brief Unlocks the mutex (if one has been locked previously). +// * Unless this function is called, the mutex is unlocked +// * when the class exits the scope. +// */ +// void unlock(); +// +// +// /** +// * Get the size of the data +// * @return +// */ +// size_t size() const; +// +// /** +// * Get the storage ID. +// * @return +// */ +// store_address_t getId() const; +// +// void print() const; +//protected: +// const uint8_t* constDataPointer = nullptr; +// store_address_t storeId; +// size_t size_ = 0; +// //! Managing pool, has to assign itself. +// StorageManagerIF* store = nullptr; +// //! Unique pointer to the mutex lock instance. Is initialized by +// //! the pool manager. +// std::unique_ptr mutexLock = nullptr; +// bool deleteData = true; +// +// enum class AccessState { +// UNINIT, +// READ +// }; +// //! Internal state for safety reasons. +// AccessState internalState = AccessState::UNINIT; +// /** +// * Used by the pool manager instances to assign themselves to the +// * accessor. This is necessary to delete the data when the acessor +// * exits the scope ! The internal state will be considered read +// * when this function is called, so take care all data is set properly as +// * well. +// * @param +// */ +// void assignStore(StorageManagerIF*); +// +//}; +// +// +///** +// * @brief Child class for modifyable data. Also has a normal pointer member. +// */ +//class StorageAccessor: public ConstStorageAccessor { +// //! StorageManager classes have exclusive access to private variables. +// template +// friend class PoolManager; +// template +// friend class LocalPool; +//public: +// StorageAccessor(store_address_t storeId); +// /** +// * @brief Move ctor and move assignment allow returning accessors as +// * a returnvalue. They prevent resource being free prematurely. +// * Refer to: https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/cpp/ +// * move-constructors-and-move-assignment-operators-cpp.md +// * @param +// * @return +// */ +// StorageAccessor& operator= (StorageAccessor&&); +// StorageAccessor (StorageAccessor&&); +// +// ReturnValue_t write(uint8_t *data, size_t size, +// uint16_t offset); +// uint8_t* data(); +// +//private: +// //! Non-const pointer for modifyable data. +// uint8_t* dataPointer = nullptr; +// //! For modifyable data, the const pointer is assigned to the normal +// //! pointer by the pool manager so both access functions can be used safely +// void assignConstPointer(); +//}; +// +//#endif /* TEST_PROTOTYPES_STORAGEACCESSOR_H_ */ diff --git a/storagemanager/StorageManagerIF.h b/storagemanager/StorageManagerIF.h index 575e9caa4..d1f9cde5d 100644 --- a/storagemanager/StorageManagerIF.h +++ b/storagemanager/StorageManagerIF.h @@ -6,9 +6,9 @@ #include /** - * This union defines the type that identifies where a data packet is stored in the store. - * It comprises of a raw part to read it as raw value and a structured part to use it in - * pool-like stores. + * This union defines the type that identifies where a data packet is + * stored in the store. It comprises of a raw part to read it as raw value and + * a structured part to use it in pool-like stores. */ union store_address_t { /** @@ -71,6 +71,7 @@ public: static const ReturnValue_t ILLEGAL_STORAGE_ID = MAKE_RETURN_CODE(3); //!< This return code indicates that data was requested with an illegal storage ID. static const ReturnValue_t DATA_DOES_NOT_EXIST = MAKE_RETURN_CODE(4); //!< This return code indicates that the requested ID was valid, but no data is stored there. static const ReturnValue_t ILLEGAL_ADDRESS = MAKE_RETURN_CODE(5); + static const ReturnValue_t POOL_TOO_LARGE = MAKE_RETURN_CODE(6); //!< Pool size too large on initialization. static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::OBSW; static const Event GET_DATA_FAILED = MAKE_EVENT(0, SEVERITY::LOW); @@ -94,7 +95,8 @@ public: * @li RETURN_FAILED if data could not be added. * storageId is unchanged then. */ - virtual ReturnValue_t addData(store_address_t* storageId, const uint8_t * data, uint32_t size, bool ignoreFault = false) = 0; + virtual ReturnValue_t addData(store_address_t* storageId, + const uint8_t * data, size_t size, bool ignoreFault = false) = 0; /** * @brief With deleteData, the storageManager frees the memory region * identified by packet_id. @@ -105,14 +107,16 @@ public: */ virtual ReturnValue_t deleteData(store_address_t packet_id) = 0; /** - * @brief Another deleteData which uses the pointer and size of the stored data to delete the content. + * @brief Another deleteData which uses the pointer and size of the + * stored data to delete the content. * @param buffer Pointer to the data. * @param size Size of data to be stored. * @param storeId Store id of the deleted element (optional) * @return @li RETURN_OK on success. * @li failure code if deletion did not work */ - virtual ReturnValue_t deleteData(uint8_t* buffer, uint32_t size, store_address_t* storeId = NULL) = 0; + virtual ReturnValue_t deleteData(uint8_t* buffer, size_t size, + store_address_t* storeId = nullptr) = 0; /** * @brief getData returns an address to data and the size of the data * for a given packet_id. @@ -125,12 +129,12 @@ public: * (e.g. an illegal packet_id was passed). */ virtual ReturnValue_t getData(store_address_t packet_id, - const uint8_t** packet_ptr, uint32_t* size) = 0; + const uint8_t** packet_ptr, size_t* size) = 0; /** * Same as above, but not const and therefore modifiable. */ virtual ReturnValue_t modifyData(store_address_t packet_id, - uint8_t** packet_ptr, uint32_t* size) = 0; + uint8_t** packet_ptr, size_t* size) = 0; /** * This method reserves an element of \c size. * @@ -144,7 +148,8 @@ public: * @li RETURN_FAILED if data could not be added. * storageId is unchanged then. */ - virtual ReturnValue_t getFreeElement(store_address_t* storageId, const uint32_t size, uint8_t** p_data, bool ignoreFault = false ) = 0; + virtual ReturnValue_t getFreeElement(store_address_t* storageId, + const size_t size, uint8_t** p_data, bool ignoreFault = false ) = 0; /** * Clears the whole store. * Use with care! -- 2.34.1 From af901f795e0a8083be4d34c44b8bdc774b184989 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 11 May 2020 12:47:33 +0200 Subject: [PATCH 2/2] uncommented the accessors --- storagemanager/StorageAccessor.cpp | 308 ++++++++++++------------- storagemanager/StorageAccessor.h | 348 ++++++++++++++--------------- 2 files changed, 328 insertions(+), 328 deletions(-) diff --git a/storagemanager/StorageAccessor.cpp b/storagemanager/StorageAccessor.cpp index a068d1694..bbebd253b 100644 --- a/storagemanager/StorageAccessor.cpp +++ b/storagemanager/StorageAccessor.cpp @@ -1,154 +1,154 @@ -//#include -// -//ConstStorageAccessor::ConstStorageAccessor(store_address_t storeId): storeId(storeId) {} -// -//ConstStorageAccessor::~ConstStorageAccessor() { -// if(deleteData and store != nullptr) { -// sif::debug << "deleting store data" << std::endl; -// store->deleteDataNonLocking(storeId); -// } -// if(mutexLock != nullptr) { -// sif::debug << "unlocking mutex lock" << std::endl; -// mutexLock.reset(); -// } -//} -// -//ConstStorageAccessor& ConstStorageAccessor::operator=( -// ConstStorageAccessor&& other) { -// constDataPointer = other.constDataPointer; -// storeId = other.storeId; -// store = other.store; -// size_ = other.size_; -// deleteData = other.deleteData; -// this->store = other.store; -// // Transfer ownership of the lock. -// mutexLock = std::move(other.mutexLock); -// // This prevents double deletion of the resource -// other.mutexLock = nullptr; -// // This prevent premature deletion -// other.store = nullptr; -// return *this; -//} -// -//StorageAccessor::StorageAccessor(store_address_t storeId): -// ConstStorageAccessor(storeId) { -//} -// -//StorageAccessor& StorageAccessor::operator =( -// StorageAccessor&& other) { -// // Call the parent move assignment and also assign own member. -// dataPointer = other.dataPointer; -// StorageAccessor::operator=(std::move(other)); -// return * this; -//} -// -//// Call the parent move ctor and also transfer own member. -//StorageAccessor::StorageAccessor(StorageAccessor&& other): -// ConstStorageAccessor(std::move(other)), dataPointer(other.dataPointer) { -//} -// -//ConstStorageAccessor::ConstStorageAccessor(ConstStorageAccessor&& other): -// constDataPointer(other.constDataPointer), storeId(other.storeId), -// size_(other.size_), store(other.store), deleteData(other.deleteData), -// internalState(other.internalState) { -// // Transfer ownership of the lock. -// mutexLock = std::move(other.mutexLock); -// // This prevents double deletion of the resource. Not strictly necessary, -// // from the testing I have conducted so far but I am not familiar enough -// // with move semantics so I will just set the other lock to nullptr for now. -// other.mutexLock = nullptr; -// // This prevent premature deletion -// other.store = nullptr; -//} -// -//const uint8_t* ConstStorageAccessor::data() const { -// return constDataPointer; -//} -// -//size_t ConstStorageAccessor::size() const { -// if(internalState == AccessState::UNINIT) { -// sif::warning << "StorageAccessor: Not initialized!" << std::endl; -// } -// return size_; -//} -// -//void ConstStorageAccessor::getDataCopy(uint8_t *pointer) { -// if(internalState == AccessState::UNINIT) { -// sif::warning << "StorageAccessor: Not initialized!" << std::endl; -// return; -// } -// std::copy(constDataPointer, constDataPointer + size_, pointer); -//} -// -//void ConstStorageAccessor::release() { -// deleteData = false; -//} -// -//ReturnValue_t ConstStorageAccessor::lock(MutexIF* mutex, uint32_t mutexTimeout) { -// if(mutexLock == nullptr) { -// mutexLock = std::unique_ptr(new MutexHelper(mutex, mutexTimeout)); -// return mutexLock.get()->getResult(); -// } -// else { -// sif::warning << "StorageAccessor: Attempted to lock twice. Check code!" << std::endl; -// return HasReturnvaluesIF::RETURN_FAILED; -// } -//} -// -//void ConstStorageAccessor::unlock() { -// if(mutexLock != nullptr) { -// mutexLock.reset(); -// } -//} -// -//store_address_t ConstStorageAccessor::getId() const { -// return storeId; -//} -// -//void ConstStorageAccessor::print() const { -// if(internalState == AccessState::UNINIT) { -// sif::warning << "StorageAccessor: Not initialized!" << std::endl; -// return; -// } -// sif::info << "StorageAccessor: Printing data: ["; -// for(uint16_t iPool = 0; iPool < size_; iPool++) { -// sif::info << std::hex << (int)constDataPointer[iPool]; -// if(iPool < size_ - 1){ -// sif::info << " , "; -// } -// } -// sif::info << " ] " << std::endl; -//} -// -//void ConstStorageAccessor::assignStore(StorageManagerIF* store) { -// internalState = AccessState::READ; -// this->store = store; -//} -// -// -//uint8_t* StorageAccessor::data() { -// if(internalState == AccessState::UNINIT) { -// sif::warning << "StorageAccessor: Not initialized!" << std::endl; -// } -// return dataPointer; -//} -// -//ReturnValue_t StorageAccessor::write(uint8_t *data, size_t size, -// uint16_t offset) { -// if(internalState == AccessState::UNINIT) { -// sif::warning << "StorageAccessor: Not initialized!" << std::endl; -// return HasReturnvaluesIF::RETURN_FAILED; -// } -// if(offset + size > size_) { -// sif::error << "StorageAccessor: Data too large for pool entry!" << std::endl; -// return HasReturnvaluesIF::RETURN_FAILED; -// } -// std::copy(data, data + size, dataPointer); -// return HasReturnvaluesIF::RETURN_OK; -//} -// -//void StorageAccessor::assignConstPointer() { -// constDataPointer = dataPointer; -//} -// -// +#include + +ConstStorageAccessor::ConstStorageAccessor(store_address_t storeId): storeId(storeId) {} + +ConstStorageAccessor::~ConstStorageAccessor() { + if(deleteData and store != nullptr) { + sif::debug << "deleting store data" << std::endl; + store->deleteDataNonLocking(storeId); + } + if(mutexLock != nullptr) { + sif::debug << "unlocking mutex lock" << std::endl; + mutexLock.reset(); + } +} + +ConstStorageAccessor& ConstStorageAccessor::operator=( + ConstStorageAccessor&& other) { + constDataPointer = other.constDataPointer; + storeId = other.storeId; + store = other.store; + size_ = other.size_; + deleteData = other.deleteData; + this->store = other.store; + // Transfer ownership of the lock. + mutexLock = std::move(other.mutexLock); + // This prevents double deletion of the resource + other.mutexLock = nullptr; + // This prevent premature deletion + other.store = nullptr; + return *this; +} + +StorageAccessor::StorageAccessor(store_address_t storeId): + ConstStorageAccessor(storeId) { +} + +StorageAccessor& StorageAccessor::operator =( + StorageAccessor&& other) { + // Call the parent move assignment and also assign own member. + dataPointer = other.dataPointer; + StorageAccessor::operator=(std::move(other)); + return * this; +} + +// Call the parent move ctor and also transfer own member. +StorageAccessor::StorageAccessor(StorageAccessor&& other): + ConstStorageAccessor(std::move(other)), dataPointer(other.dataPointer) { +} + +ConstStorageAccessor::ConstStorageAccessor(ConstStorageAccessor&& other): + constDataPointer(other.constDataPointer), storeId(other.storeId), + size_(other.size_), store(other.store), deleteData(other.deleteData), + internalState(other.internalState) { + // Transfer ownership of the lock. + mutexLock = std::move(other.mutexLock); + // This prevents double deletion of the resource. Not strictly necessary, + // from the testing I have conducted so far but I am not familiar enough + // with move semantics so I will just set the other lock to nullptr for now. + other.mutexLock = nullptr; + // This prevent premature deletion + other.store = nullptr; +} + +const uint8_t* ConstStorageAccessor::data() const { + return constDataPointer; +} + +size_t ConstStorageAccessor::size() const { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + } + return size_; +} + +void ConstStorageAccessor::getDataCopy(uint8_t *pointer) { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + return; + } + std::copy(constDataPointer, constDataPointer + size_, pointer); +} + +void ConstStorageAccessor::release() { + deleteData = false; +} + +ReturnValue_t ConstStorageAccessor::lock(MutexIF* mutex, uint32_t mutexTimeout) { + if(mutexLock == nullptr) { + mutexLock = std::unique_ptr(new MutexHelper(mutex, mutexTimeout)); + return mutexLock.get()->getResult(); + } + else { + sif::warning << "StorageAccessor: Attempted to lock twice. Check code!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +void ConstStorageAccessor::unlock() { + if(mutexLock != nullptr) { + mutexLock.reset(); + } +} + +store_address_t ConstStorageAccessor::getId() const { + return storeId; +} + +void ConstStorageAccessor::print() const { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + return; + } + sif::info << "StorageAccessor: Printing data: ["; + for(uint16_t iPool = 0; iPool < size_; iPool++) { + sif::info << std::hex << (int)constDataPointer[iPool]; + if(iPool < size_ - 1){ + sif::info << " , "; + } + } + sif::info << " ] " << std::endl; +} + +void ConstStorageAccessor::assignStore(StorageManagerIF* store) { + internalState = AccessState::READ; + this->store = store; +} + + +uint8_t* StorageAccessor::data() { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + } + return dataPointer; +} + +ReturnValue_t StorageAccessor::write(uint8_t *data, size_t size, + uint16_t offset) { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + if(offset + size > size_) { + sif::error << "StorageAccessor: Data too large for pool entry!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + std::copy(data, data + size, dataPointer); + return HasReturnvaluesIF::RETURN_OK; +} + +void StorageAccessor::assignConstPointer() { + constDataPointer = dataPointer; +} + + diff --git a/storagemanager/StorageAccessor.h b/storagemanager/StorageAccessor.h index d391c5c26..f861a2cc9 100644 --- a/storagemanager/StorageAccessor.h +++ b/storagemanager/StorageAccessor.h @@ -1,174 +1,174 @@ -///** -// * @brief Helper classes to facilitate safe access to storages which is also -// * conforming to RAII principles -// * @details These helper can be used together with the -// * StorageManager classes to manage access to a storage. -// * It can take care of thread-safety while also providing -// * mechanisms to automatically clear storage data and unlocking the -// * pool. -// */ -//#ifndef TEST_PROTOTYPES_STORAGEACCESSOR_H_ -//#define TEST_PROTOTYPES_STORAGEACCESSOR_H_ -// -//#include -//#include -//#include -// -// -///** -// * @brief Accessor class which can be returned by pool managers -// * or passed and set by pool managers to have safe access to the pool -// * resources. -// */ -//class ConstStorageAccessor { -// //! StorageManager classes have exclusive access to private variables. -// template -// friend class PoolManager; -// template -// friend class LocalPool; -//public: -// /** -// * @brief Simple constructor which takes the store ID of the storage -// * entry to access. -// * @param storeId -// */ -// ConstStorageAccessor(store_address_t storeId); -// -// /** -// * @brief Move ctor and move assignment allow returning accessors as -// * a returnvalue. They prevent resource being free prematurely. -// * Refer to: https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/cpp/ -// * move-constructors-and-move-assignment-operators-cpp.md -// * @param -// * @return -// */ -// ConstStorageAccessor& operator= (ConstStorageAccessor&&); -// ConstStorageAccessor (ConstStorageAccessor&&); -// -// //! The copy ctor and copy assignemnt should be deleted implicitely -// //! according to https://foonathan.net/2019/02/special-member-functions/ -// //! but I still deleted them to make it more explicit. (remember rule of 5). -// ConstStorageAccessor& operator= (ConstStorageAccessor&) = delete; -// ConstStorageAccessor (ConstStorageAccessor&) = delete; -// -// /** -// * @brief The destructor in default configuration takes care of -// * deleting the accessed pool entry and unlocking the mutex -// */ -// virtual ~ConstStorageAccessor(); -// -// /** -// * @brief Returns a pointer to the read-only data -// * @return -// */ -// const uint8_t* data() const; -// -// /** -// * @brief Copies the read-only data to the supplied pointer -// * @param pointer -// */ -// void getDataCopy(uint8_t *pointer); -// -// /** -// * @brief Calling this will prevent the Accessor from deleting the data -// * when the destructor is called. -// */ -// void release(); -// /** -// * @brief Locks the supplied mutex. -// * @details -// * The mutex will be unlocked automatically -// * when this class is destroyed (for example when exiting the scope). -// * Only one mutex can be locked at a time! -// * @param mutex -// * @param mutexTimeout -// * @return -// */ -// ReturnValue_t lock(MutexIF* mutex, -// uint32_t mutexTimeout = MutexIF::NO_TIMEOUT); -// /** -// * @brief Unlocks the mutex (if one has been locked previously). -// * Unless this function is called, the mutex is unlocked -// * when the class exits the scope. -// */ -// void unlock(); -// -// -// /** -// * Get the size of the data -// * @return -// */ -// size_t size() const; -// -// /** -// * Get the storage ID. -// * @return -// */ -// store_address_t getId() const; -// -// void print() const; -//protected: -// const uint8_t* constDataPointer = nullptr; -// store_address_t storeId; -// size_t size_ = 0; -// //! Managing pool, has to assign itself. -// StorageManagerIF* store = nullptr; -// //! Unique pointer to the mutex lock instance. Is initialized by -// //! the pool manager. -// std::unique_ptr mutexLock = nullptr; -// bool deleteData = true; -// -// enum class AccessState { -// UNINIT, -// READ -// }; -// //! Internal state for safety reasons. -// AccessState internalState = AccessState::UNINIT; -// /** -// * Used by the pool manager instances to assign themselves to the -// * accessor. This is necessary to delete the data when the acessor -// * exits the scope ! The internal state will be considered read -// * when this function is called, so take care all data is set properly as -// * well. -// * @param -// */ -// void assignStore(StorageManagerIF*); -// -//}; -// -// -///** -// * @brief Child class for modifyable data. Also has a normal pointer member. -// */ -//class StorageAccessor: public ConstStorageAccessor { -// //! StorageManager classes have exclusive access to private variables. -// template -// friend class PoolManager; -// template -// friend class LocalPool; -//public: -// StorageAccessor(store_address_t storeId); -// /** -// * @brief Move ctor and move assignment allow returning accessors as -// * a returnvalue. They prevent resource being free prematurely. -// * Refer to: https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/cpp/ -// * move-constructors-and-move-assignment-operators-cpp.md -// * @param -// * @return -// */ -// StorageAccessor& operator= (StorageAccessor&&); -// StorageAccessor (StorageAccessor&&); -// -// ReturnValue_t write(uint8_t *data, size_t size, -// uint16_t offset); -// uint8_t* data(); -// -//private: -// //! Non-const pointer for modifyable data. -// uint8_t* dataPointer = nullptr; -// //! For modifyable data, the const pointer is assigned to the normal -// //! pointer by the pool manager so both access functions can be used safely -// void assignConstPointer(); -//}; -// -//#endif /* TEST_PROTOTYPES_STORAGEACCESSOR_H_ */ +/** + * @brief Helper classes to facilitate safe access to storages which is also + * conforming to RAII principles + * @details These helper can be used together with the + * StorageManager classes to manage access to a storage. + * It can take care of thread-safety while also providing + * mechanisms to automatically clear storage data and unlocking the + * pool. + */ +#ifndef TEST_PROTOTYPES_STORAGEACCESSOR_H_ +#define TEST_PROTOTYPES_STORAGEACCESSOR_H_ + +#include +#include +#include + + +/** + * @brief Accessor class which can be returned by pool managers + * or passed and set by pool managers to have safe access to the pool + * resources. + */ +class ConstStorageAccessor { + //! StorageManager classes have exclusive access to private variables. + template + friend class PoolManager; + template + friend class LocalPool; +public: + /** + * @brief Simple constructor which takes the store ID of the storage + * entry to access. + * @param storeId + */ + ConstStorageAccessor(store_address_t storeId); + + /** + * @brief Move ctor and move assignment allow returning accessors as + * a returnvalue. They prevent resource being free prematurely. + * Refer to: https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/cpp/ + * move-constructors-and-move-assignment-operators-cpp.md + * @param + * @return + */ + ConstStorageAccessor& operator= (ConstStorageAccessor&&); + ConstStorageAccessor (ConstStorageAccessor&&); + + //! The copy ctor and copy assignemnt should be deleted implicitely + //! according to https://foonathan.net/2019/02/special-member-functions/ + //! but I still deleted them to make it more explicit. (remember rule of 5). + ConstStorageAccessor& operator= (ConstStorageAccessor&) = delete; + ConstStorageAccessor (ConstStorageAccessor&) = delete; + + /** + * @brief The destructor in default configuration takes care of + * deleting the accessed pool entry and unlocking the mutex + */ + virtual ~ConstStorageAccessor(); + + /** + * @brief Returns a pointer to the read-only data + * @return + */ + const uint8_t* data() const; + + /** + * @brief Copies the read-only data to the supplied pointer + * @param pointer + */ + void getDataCopy(uint8_t *pointer); + + /** + * @brief Calling this will prevent the Accessor from deleting the data + * when the destructor is called. + */ + void release(); + /** + * @brief Locks the supplied mutex. + * @details + * The mutex will be unlocked automatically + * when this class is destroyed (for example when exiting the scope). + * Only one mutex can be locked at a time! + * @param mutex + * @param mutexTimeout + * @return + */ + ReturnValue_t lock(MutexIF* mutex, + uint32_t mutexTimeout = MutexIF::NO_TIMEOUT); + /** + * @brief Unlocks the mutex (if one has been locked previously). + * Unless this function is called, the mutex is unlocked + * when the class exits the scope. + */ + void unlock(); + + + /** + * Get the size of the data + * @return + */ + size_t size() const; + + /** + * Get the storage ID. + * @return + */ + store_address_t getId() const; + + void print() const; +protected: + const uint8_t* constDataPointer = nullptr; + store_address_t storeId; + size_t size_ = 0; + //! Managing pool, has to assign itself. + StorageManagerIF* store = nullptr; + //! Unique pointer to the mutex lock instance. Is initialized by + //! the pool manager. + std::unique_ptr mutexLock = nullptr; + bool deleteData = true; + + enum class AccessState { + UNINIT, + READ + }; + //! Internal state for safety reasons. + AccessState internalState = AccessState::UNINIT; + /** + * Used by the pool manager instances to assign themselves to the + * accessor. This is necessary to delete the data when the acessor + * exits the scope ! The internal state will be considered read + * when this function is called, so take care all data is set properly as + * well. + * @param + */ + void assignStore(StorageManagerIF*); + +}; + + +/** + * @brief Child class for modifyable data. Also has a normal pointer member. + */ +class StorageAccessor: public ConstStorageAccessor { + //! StorageManager classes have exclusive access to private variables. + template + friend class PoolManager; + template + friend class LocalPool; +public: + StorageAccessor(store_address_t storeId); + /** + * @brief Move ctor and move assignment allow returning accessors as + * a returnvalue. They prevent resource being free prematurely. + * Refer to: https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/cpp/ + * move-constructors-and-move-assignment-operators-cpp.md + * @param + * @return + */ + StorageAccessor& operator= (StorageAccessor&&); + StorageAccessor (StorageAccessor&&); + + ReturnValue_t write(uint8_t *data, size_t size, + uint16_t offset); + uint8_t* data(); + +private: + //! Non-const pointer for modifyable data. + uint8_t* dataPointer = nullptr; + //! For modifyable data, the const pointer is assigned to the normal + //! pointer by the pool manager so both access functions can be used safely + void assignConstPointer(); +}; + +#endif /* TEST_PROTOTYPES_STORAGEACCESSOR_H_ */ -- 2.34.1