implemented counting semaph for linux

This commit is contained in:
Robin Müller 2020-05-29 01:41:16 +02:00
parent 56498e5bc1
commit 671f298935
7 changed files with 155 additions and 20 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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,12 +117,12 @@ 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)
@ -125,3 +130,19 @@ void BinarySemaphore::initSemaphore() {
}
}
}
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;
}

View File

@ -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 <framework/returnvalues/HasReturnvaluesIF.h>
#include <framework/tasks/SemaphoreIF.h>
@ -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;
};

View File

@ -0,0 +1,54 @@
#include <framework/osal/linux/CountingSemaphore.h>
#include <framework/serviceinterface/ServiceInterfaceStream.h>
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;
}

View File

@ -0,0 +1,37 @@
#ifndef FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_
#define FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_
#include <framework/osal/linux/BinarySemaphore.h>
/**
* @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_ */

View File

@ -1,5 +1,6 @@
#include <framework/tasks/SemaphoreFactory.h>
#include <framework/osal/linux/BinarySemaphore.h>
#include <framework/osal/linux/CountingSemaphore.h>
#include <framework/serviceinterface/ServiceInterfaceStream.h>
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) {