From 671f298935a640e33274e1a5fd52339e790068b6 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 01:41:16 +0200 Subject: [PATCH] implemented counting semaph for linux --- osal/FreeRTOS/CountingSemaphore.cpp | 10 ++++++ osal/FreeRTOS/CountingSemaphore.h | 1 + osal/linux/BinarySemaphore.cpp | 43 +++++++++++++++++------ osal/linux/BinarySemaphore.h | 23 +++++++++--- osal/linux/CountingSemaphore.cpp | 54 +++++++++++++++++++++++++++++ osal/linux/CountingSemaphore.h | 37 ++++++++++++++++++++ osal/linux/SemaphoreFactory.cpp | 7 ++-- 7 files changed, 155 insertions(+), 20 deletions(-) create mode 100644 osal/linux/CountingSemaphore.cpp create mode 100644 osal/linux/CountingSemaphore.h diff --git a/osal/FreeRTOS/CountingSemaphore.cpp b/osal/FreeRTOS/CountingSemaphore.cpp index a23f32a0..c838f3e2 100644 --- a/osal/FreeRTOS/CountingSemaphore.cpp +++ b/osal/FreeRTOS/CountingSemaphore.cpp @@ -10,6 +10,12 @@ extern "C" { // free FreeRTOSConfig.h file. CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount): maxCount(maxCount), initCount(initCount) { + if(initCount > maxCount) { + sif::error << "CountingSemaphoreUsingTask: Max count bigger than " + "intial cout. Setting initial count to max count." << std::endl; + initCount = maxCount; + } + handle = xSemaphoreCreateCounting(maxCount, initCount); if(handle == nullptr) { sif::error << "CountingSemaphore: Creation failure" << std::endl; @@ -33,3 +39,7 @@ CountingSemaphore& CountingSemaphore::operator =( return * this; } + +uint8_t CountingSemaphore::getMaxCount() const { + return maxCount; +} diff --git a/osal/FreeRTOS/CountingSemaphore.h b/osal/FreeRTOS/CountingSemaphore.h index bed3c726..dca3ab0e 100644 --- a/osal/FreeRTOS/CountingSemaphore.h +++ b/osal/FreeRTOS/CountingSemaphore.h @@ -25,6 +25,7 @@ public: /* Same API as binary semaphore otherwise. acquire() can be called * until there are not semaphores left and release() can be called * until maxCount is reached. */ + uint8_t getMaxCount() const; private: const uint8_t maxCount; uint8_t initCount = 0; diff --git a/osal/linux/BinarySemaphore.cpp b/osal/linux/BinarySemaphore.cpp index ed1045e0..7c76a5c4 100644 --- a/osal/linux/BinarySemaphore.cpp +++ b/osal/linux/BinarySemaphore.cpp @@ -30,7 +30,7 @@ ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { if(timeoutMs == SemaphoreIF::NO_TIMEOUT) { result = sem_trywait(&handle); } - if(timeoutMs == SemaphoreIF::MAX_TIMEOUT) { + else if(timeoutMs == SemaphoreIF::MAX_TIMEOUT) { result = sem_wait(&handle); } else if(timeoutMs > SemaphoreIF::NO_TIMEOUT){ @@ -50,7 +50,7 @@ ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { return HasReturnvaluesIF::RETURN_OK; } - switch(result) { + switch(errno) { case(EAGAIN): // Operation could not be performed without blocking (for sem_trywait) case(ETIMEDOUT): @@ -61,8 +61,8 @@ ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { return SemaphoreIF::SEMAPHORE_INVALID; case(EINTR): // Call was interrupted by signal handler - sif::debug << "BinarySemaphore::acquire: Signal handler interrupted" - << std::endl; + sif::debug << "BinarySemaphore::acquire: Signal handler interrupted." + "Code " << strerror(errno) << std::endl; /* No break */ default: return HasReturnvaluesIF::RETURN_FAILED; @@ -70,10 +70,15 @@ ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { } ReturnValue_t BinarySemaphore::release() { - return release(&this->handle); + return BinarySemaphore::release(&this->handle); } ReturnValue_t BinarySemaphore::release(sem_t *handle) { + ReturnValue_t countResult = checkCount(handle, 1); + if(countResult != HasReturnvaluesIF::RETURN_OK) { + return countResult; + } + int result = sem_post(handle); if(result == 0) { return HasReturnvaluesIF::RETURN_OK; @@ -102,8 +107,8 @@ uint8_t BinarySemaphore::getSemaphoreCounter(sem_t *handle) { return value; } else if(result != 0 and errno == EINVAL) { - sif::debug << "BInarySemaphore::getSemaphoreCounter: Invalid" - " Semaphore." << std::endl; + // Could be called from interrupt, use lightweight printf + printf("BinarySemaphore::getSemaphoreCounter: Invalid semaphore\n"); return 0; } else { @@ -112,16 +117,32 @@ uint8_t BinarySemaphore::getSemaphoreCounter(sem_t *handle) { } } -void BinarySemaphore::initSemaphore() { - auto result = sem_init(&handle, true, 1); +void BinarySemaphore::initSemaphore(uint8_t initCount) { + auto result = sem_init(&handle, true, initCount); if(result == -1) { switch(errno) { case(EINVAL): - // Value excees SEM_VALUE_MAX + // Value exceeds SEM_VALUE_MAX case(ENOSYS): // System does not support process-shared semaphores sif::error << "BinarySemaphore: Init failed with" << strerror(errno) - << std::endl; + << std::endl; } } } + +ReturnValue_t BinarySemaphore::checkCount(sem_t* handle, uint8_t maxCount) { + int value = getSemaphoreCounter(handle); + if(value >= maxCount) { + if(maxCount == 1 and value > 1) { + // Binary Semaphore special case. + // This is a config error use lightweight printf is this is called + // from an interrupt + printf("BinarySemaphore::release: Value of binary semaphore greater" + " than 1!\n"); + return HasReturnvaluesIF::RETURN_FAILED; + } + return SemaphoreIF::SEMAPHORE_NOT_OWNED; + } + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/osal/linux/BinarySemaphore.h b/osal/linux/BinarySemaphore.h index d18b3eaa..7836cd41 100644 --- a/osal/linux/BinarySemaphore.h +++ b/osal/linux/BinarySemaphore.h @@ -1,5 +1,5 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ -#define FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ +#ifndef FRAMEWORK_OSAL_LINUX_BINARYSEMPAHORE_H_ +#define FRAMEWORK_OSAL_LINUX_BINARYSEMPAHORE_H_ #include #include @@ -35,10 +35,11 @@ public: //! @brief Destructor virtual ~BinarySemaphore(); - void initSemaphore(); + void initSemaphore(uint8_t initCount = 1); uint8_t getSemaphoreCounter() const override; static uint8_t getSemaphoreCounter(sem_t* handle); + /** * Take the binary semaphore. * If the semaphore has already been taken, the task will be blocked @@ -57,10 +58,22 @@ public: * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is * already available. */ - ReturnValue_t release() override; - + virtual ReturnValue_t release() override; + /** + * This static function can be used to release a semaphore by providing + * its handle. + * @param handle + * @return + */ static ReturnValue_t release(sem_t* handle); + /** Checks the validity of the semaphore count against a specified + * known maxCount + * @param handle + * @param maxCount + * @return + */ + static ReturnValue_t checkCount(sem_t* handle, uint8_t maxCount); protected: sem_t handle; }; diff --git a/osal/linux/CountingSemaphore.cpp b/osal/linux/CountingSemaphore.cpp new file mode 100644 index 00000000..dfc4d801 --- /dev/null +++ b/osal/linux/CountingSemaphore.cpp @@ -0,0 +1,54 @@ +#include +#include + +CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount): + maxCount(maxCount), initCount(initCount) { + if(initCount > maxCount) { + sif::error << "CountingSemaphoreUsingTask: Max count bigger than " + "intial cout. Setting initial count to max count." << std::endl; + initCount = maxCount; + } + + initSemaphore(initCount); +} + +CountingSemaphore::CountingSemaphore(CountingSemaphore&& other): + maxCount(other.maxCount), initCount(other.initCount) { + initSemaphore(initCount); +} + +CountingSemaphore& CountingSemaphore::operator =( + CountingSemaphore&& other) { + initSemaphore(other.initCount); + return * this; +} + +ReturnValue_t CountingSemaphore::release() { + ReturnValue_t result = checkCount(&handle, maxCount); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return CountingSemaphore::release(&this->handle); +} + +ReturnValue_t CountingSemaphore::release(sem_t* handle) { + int result = sem_post(handle); + if(result == 0) { + return HasReturnvaluesIF::RETURN_OK; + } + + switch(errno) { + case(EINVAL): + // Semaphore invalid + return SemaphoreIF::SEMAPHORE_INVALID; + case(EOVERFLOW): + // SEM_MAX_VALUE overflow. This should never happen + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +uint8_t CountingSemaphore::getMaxCount() const { + return maxCount; +} + diff --git a/osal/linux/CountingSemaphore.h b/osal/linux/CountingSemaphore.h new file mode 100644 index 00000000..ba606595 --- /dev/null +++ b/osal/linux/CountingSemaphore.h @@ -0,0 +1,37 @@ +#ifndef FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_ +#define FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_ +#include + +/** + * @brief Counting semaphores, which can be acquired more than once. + * @details + * See: https://www.freertos.org/CreateCounting.html + * API of counting semaphores is almost identical to binary semaphores, + * so we just inherit from binary semaphore and provide the respective + * constructors. + */ +class CountingSemaphore: public BinarySemaphore { +public: + CountingSemaphore(const uint8_t maxCount, uint8_t initCount); + //! @brief Copy ctor, disabled + CountingSemaphore(const CountingSemaphore&) = delete; + //! @brief Copy assignment, disabled + CountingSemaphore& operator=(const CountingSemaphore&) = delete; + //! @brief Move ctor + CountingSemaphore (CountingSemaphore &&); + //! @brief Move assignment + CountingSemaphore & operator=(CountingSemaphore &&); + + ReturnValue_t release() override; + static ReturnValue_t release(sem_t* sem); + /* Same API as binary semaphore otherwise. acquire() can be called + * until there are not semaphores left and release() can be called + * until maxCount is reached. */ + + uint8_t getMaxCount() const; +private: + const uint8_t maxCount; + uint8_t initCount = 0; +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ */ diff --git a/osal/linux/SemaphoreFactory.cpp b/osal/linux/SemaphoreFactory.cpp index 8d29ffe3..5aec84ea 100644 --- a/osal/linux/SemaphoreFactory.cpp +++ b/osal/linux/SemaphoreFactory.cpp @@ -1,5 +1,6 @@ #include #include +#include #include const uint32_t SemaphoreIF::NO_TIMEOUT = 0; @@ -25,11 +26,9 @@ SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t arguments) { return new BinarySemaphore(); } -SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t count, +SemaphoreIF* SemaphoreFactory::createCountingSemaphore(const uint8_t maxCount, uint8_t initCount, uint32_t arguments) { - sif::error << "Counting Semaphore not implemented for " - "Linux yet" << std::endl; - return nullptr; + return new CountingSemaphore(maxCount, initCount); } void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) {