2020-12-14 21:46:33 +01:00
|
|
|
#include "BinarySemaphore.h"
|
2021-01-09 16:06:54 +01:00
|
|
|
#include "../../serviceinterface/ServiceInterfacePrinter.h"
|
2020-09-18 13:15:14 +02:00
|
|
|
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
|
|
|
|
2021-01-09 16:06:54 +01:00
|
|
|
#include <time.h>
|
2020-09-18 13:15:14 +02:00
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
2021-01-09 16:06:54 +01:00
|
|
|
|
2020-09-18 13:15:14 +02:00
|
|
|
|
|
|
|
BinarySemaphore::BinarySemaphore() {
|
|
|
|
// Using unnamed semaphores for now
|
|
|
|
initSemaphore();
|
|
|
|
}
|
|
|
|
|
|
|
|
BinarySemaphore::~BinarySemaphore() {
|
|
|
|
sem_destroy(&handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) {
|
|
|
|
initSemaphore();
|
|
|
|
}
|
|
|
|
|
|
|
|
BinarySemaphore& BinarySemaphore::operator =(
|
|
|
|
BinarySemaphore&& s) {
|
|
|
|
initSemaphore();
|
|
|
|
return * this;
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType,
|
|
|
|
uint32_t timeoutMs) {
|
|
|
|
int result = 0;
|
|
|
|
if(timeoutType == TimeoutType::POLLING) {
|
|
|
|
result = sem_trywait(&handle);
|
|
|
|
}
|
|
|
|
else if(timeoutType == TimeoutType::BLOCKING) {
|
|
|
|
result = sem_wait(&handle);
|
|
|
|
}
|
|
|
|
else if(timeoutType == TimeoutType::WAITING){
|
|
|
|
timespec timeOut;
|
|
|
|
clock_gettime(CLOCK_REALTIME, &timeOut);
|
|
|
|
uint64_t nseconds = timeOut.tv_sec * 1000000000 + timeOut.tv_nsec;
|
|
|
|
nseconds += timeoutMs * 1000000;
|
|
|
|
timeOut.tv_sec = nseconds / 1000000000;
|
|
|
|
timeOut.tv_nsec = nseconds - timeOut.tv_sec * 1000000000;
|
|
|
|
result = sem_timedwait(&handle, &timeOut);
|
|
|
|
if(result != 0 and errno == EINVAL) {
|
2021-01-03 14:16:52 +01:00
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2020-09-18 13:15:14 +02:00
|
|
|
sif::debug << "BinarySemaphore::acquire: Invalid time value possible"
|
|
|
|
<< std::endl;
|
2021-01-03 13:58:18 +01:00
|
|
|
#endif
|
2020-09-18 13:15:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if(result == 0) {
|
|
|
|
return HasReturnvaluesIF::RETURN_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(errno) {
|
|
|
|
case(EAGAIN):
|
|
|
|
// Operation could not be performed without blocking (for sem_trywait)
|
|
|
|
case(ETIMEDOUT):
|
|
|
|
// Semaphore is 0
|
|
|
|
return SemaphoreIF::SEMAPHORE_TIMEOUT;
|
|
|
|
case(EINVAL):
|
|
|
|
// Semaphore invalid
|
|
|
|
return SemaphoreIF::SEMAPHORE_INVALID;
|
|
|
|
case(EINTR):
|
|
|
|
// Call was interrupted by signal handler
|
2021-01-03 14:16:52 +01:00
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2020-09-18 13:15:14 +02:00
|
|
|
sif::debug << "BinarySemaphore::acquire: Signal handler interrupted."
|
|
|
|
"Code " << strerror(errno) << std::endl;
|
2021-01-03 13:58:18 +01:00
|
|
|
#endif
|
2020-09-18 13:15:14 +02:00
|
|
|
/* No break */
|
|
|
|
default:
|
|
|
|
return HasReturnvaluesIF::RETURN_FAILED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t BinarySemaphore::release() {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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 BinarySemaphore::getSemaphoreCounter() const {
|
|
|
|
// And another ugly cast :-D
|
|
|
|
return getSemaphoreCounter(const_cast<sem_t*>(&this->handle));
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t BinarySemaphore::getSemaphoreCounter(sem_t *handle) {
|
|
|
|
int value = 0;
|
|
|
|
int result = sem_getvalue(handle, &value);
|
|
|
|
if (result == 0) {
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
else if(result != 0 and errno == EINVAL) {
|
|
|
|
// Could be called from interrupt, use lightweight printf
|
2021-01-12 13:18:18 +01:00
|
|
|
sif::printError("BinarySemaphore::getSemaphoreCounter: "
|
2021-01-09 16:06:54 +01:00
|
|
|
"Invalid semaphore\n");
|
2020-09-18 13:15:14 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// This should never happen.
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BinarySemaphore::initSemaphore(uint8_t initCount) {
|
|
|
|
auto result = sem_init(&handle, true, initCount);
|
|
|
|
if(result == -1) {
|
|
|
|
switch(errno) {
|
|
|
|
case(EINVAL):
|
|
|
|
// Value exceeds SEM_VALUE_MAX
|
2021-01-09 16:06:54 +01:00
|
|
|
case(ENOSYS): {
|
|
|
|
// System does not support process-shared semaphores
|
2021-01-03 14:16:52 +01:00
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2021-01-09 16:06:54 +01:00
|
|
|
sif::error << "BinarySemaphore: Init failed with "
|
|
|
|
<< strerror(errno) << std::endl;
|
|
|
|
#else
|
2021-01-12 13:18:18 +01:00
|
|
|
sif::printError("BinarySemaphore: Init failed with %s\n",
|
2021-01-09 16:06:54 +01:00
|
|
|
strerror(errno));
|
2021-01-03 13:58:18 +01:00
|
|
|
#endif
|
2020-09-18 13:15:14 +02:00
|
|
|
}
|
2021-01-09 16:06:54 +01:00
|
|
|
}
|
2020-09-18 13:15:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|