linux error print handling improved

This commit is contained in:
Robin Müller 2021-06-03 12:29:06 +02:00
parent 6b9747ee0b
commit 3891014340
No known key found for this signature in database
GPG Key ID: 71B58F8A3CDFA9AC
13 changed files with 558 additions and 553 deletions

View File

@ -1,7 +1,7 @@
#include "MessageQueue.h" #include "MessageQueue.h"
#include "QueueMapManager.h" #include "QueueMapManager.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../serviceinterface/ServiceInterface.h"
#include "../../ipc/MutexFactory.h" #include "../../ipc/MutexFactory.h"
#include "../../ipc/MutexGuard.h" #include "../../ipc/MutexGuard.h"
@ -13,8 +13,9 @@ MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize):
auto result = QueueMapManager::instance()->addMessageQueue(this, &mqId); auto result = QueueMapManager::instance()->addMessageQueue(this, &mqId);
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MessageQueue::MessageQueue:" sif::error << "MessageQueue::MessageQueue: Could not be created" << std::endl;
<< " Could not be created" << std::endl; #else
sif::printError("MessageQueue::MessageQueue: Could not be created\n");
#endif #endif
} }
} }

View File

@ -1,4 +1,5 @@
#include "BinarySemaphore.h" #include "BinarySemaphore.h"
#include "unixUtility.h"
#include "../../serviceinterface/ServiceInterfacePrinter.h" #include "../../serviceinterface/ServiceInterfacePrinter.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../serviceinterface/ServiceInterfaceStream.h"
@ -8,154 +9,154 @@
BinarySemaphore::BinarySemaphore() { BinarySemaphore::BinarySemaphore() {
// Using unnamed semaphores for now // Using unnamed semaphores for now
initSemaphore(); initSemaphore();
} }
BinarySemaphore::~BinarySemaphore() { BinarySemaphore::~BinarySemaphore() {
sem_destroy(&handle); sem_destroy(&handle);
} }
BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) {
initSemaphore(); initSemaphore();
} }
BinarySemaphore& BinarySemaphore::operator =( BinarySemaphore& BinarySemaphore::operator =(
BinarySemaphore&& s) { BinarySemaphore&& s) {
initSemaphore(); initSemaphore();
return * this; return * this;
} }
ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType, ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType,
uint32_t timeoutMs) { uint32_t timeoutMs) {
int result = 0; int result = 0;
if(timeoutType == TimeoutType::POLLING) { if(timeoutType == TimeoutType::POLLING) {
result = sem_trywait(&handle); result = sem_trywait(&handle);
} }
else if(timeoutType == TimeoutType::BLOCKING) { else if(timeoutType == TimeoutType::BLOCKING) {
result = sem_wait(&handle); result = sem_wait(&handle);
} }
else if(timeoutType == TimeoutType::WAITING){ else if(timeoutType == TimeoutType::WAITING){
timespec timeOut; timespec timeOut;
clock_gettime(CLOCK_REALTIME, &timeOut); clock_gettime(CLOCK_REALTIME, &timeOut);
uint64_t nseconds = timeOut.tv_sec * 1000000000 + timeOut.tv_nsec; uint64_t nseconds = timeOut.tv_sec * 1000000000 + timeOut.tv_nsec;
nseconds += timeoutMs * 1000000; nseconds += timeoutMs * 1000000;
timeOut.tv_sec = nseconds / 1000000000; timeOut.tv_sec = nseconds / 1000000000;
timeOut.tv_nsec = nseconds - timeOut.tv_sec * 1000000000; timeOut.tv_nsec = nseconds - timeOut.tv_sec * 1000000000;
result = sem_timedwait(&handle, &timeOut); result = sem_timedwait(&handle, &timeOut);
if(result != 0 and errno == EINVAL) { if(result != 0 and errno == EINVAL) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "acquire", "sem_timedwait");
sif::debug << "BinarySemaphore::acquire: Invalid time value possible" }
<< std::endl; }
#endif if(result == 0) {
} return HasReturnvaluesIF::RETURN_OK;
} }
if(result == 0) {
return HasReturnvaluesIF::RETURN_OK;
}
switch(errno) { switch(errno) {
case(EAGAIN): case(EAGAIN):
// Operation could not be performed without blocking (for sem_trywait) // Operation could not be performed without blocking (for sem_trywait)
case(ETIMEDOUT): case(ETIMEDOUT): {
// Semaphore is 0 // Semaphore is 0
return SemaphoreIF::SEMAPHORE_TIMEOUT; utility::printUnixErrorGeneric(CLASS_NAME, "acquire", "ETIMEDOUT");
case(EINVAL): return SemaphoreIF::SEMAPHORE_TIMEOUT;
// Semaphore invalid }
return SemaphoreIF::SEMAPHORE_INVALID; case(EINVAL): {
case(EINTR): // Semaphore invalid
// Call was interrupted by signal handler utility::printUnixErrorGeneric(CLASS_NAME, "acquire", "EINVAL");
#if FSFW_CPP_OSTREAM_ENABLED == 1 return SemaphoreIF::SEMAPHORE_INVALID;
sif::debug << "BinarySemaphore::acquire: Signal handler interrupted." }
"Code " << strerror(errno) << std::endl; case(EINTR): {
#endif // Call was interrupted by signal handler
/* No break */ utility::printUnixErrorGeneric(CLASS_NAME, "acquire", "EINTR");
default: return HasReturnvaluesIF::RETURN_FAILED;
return HasReturnvaluesIF::RETURN_FAILED; }
} default:
return HasReturnvaluesIF::RETURN_FAILED;
}
} }
ReturnValue_t BinarySemaphore::release() { ReturnValue_t BinarySemaphore::release() {
return BinarySemaphore::release(&this->handle); return BinarySemaphore::release(&this->handle);
} }
ReturnValue_t BinarySemaphore::release(sem_t *handle) { ReturnValue_t BinarySemaphore::release(sem_t *handle) {
ReturnValue_t countResult = checkCount(handle, 1); ReturnValue_t countResult = checkCount(handle, 1);
if(countResult != HasReturnvaluesIF::RETURN_OK) { if(countResult != HasReturnvaluesIF::RETURN_OK) {
return countResult; return countResult;
} }
int result = sem_post(handle); int result = sem_post(handle);
if(result == 0) { if(result == 0) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
switch(errno) { switch(errno) {
case(EINVAL): case(EINVAL): {
// Semaphore invalid // Semaphore invalid
return SemaphoreIF::SEMAPHORE_INVALID; utility::printUnixErrorGeneric(CLASS_NAME, "release", "EINVAL");
case(EOVERFLOW): return SemaphoreIF::SEMAPHORE_INVALID;
// SEM_MAX_VALUE overflow. This should never happen }
default: case(EOVERFLOW): {
return HasReturnvaluesIF::RETURN_FAILED; // SEM_MAX_VALUE overflow. This should never happen
} utility::printUnixErrorGeneric(CLASS_NAME, "release", "EOVERFLOW");
return HasReturnvaluesIF::RETURN_FAILED;
}
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
} }
uint8_t BinarySemaphore::getSemaphoreCounter() const { uint8_t BinarySemaphore::getSemaphoreCounter() const {
// And another ugly cast :-D // And another ugly cast :-D
return getSemaphoreCounter(const_cast<sem_t*>(&this->handle)); return getSemaphoreCounter(const_cast<sem_t*>(&this->handle));
} }
uint8_t BinarySemaphore::getSemaphoreCounter(sem_t *handle) { uint8_t BinarySemaphore::getSemaphoreCounter(sem_t *handle) {
int value = 0; int value = 0;
int result = sem_getvalue(handle, &value); int result = sem_getvalue(handle, &value);
if (result == 0) { if (result == 0) {
return value; return value;
} }
else if(result != 0 and errno == EINVAL) { else if(result != 0 and errno == EINVAL) {
// Could be called from interrupt, use lightweight printf // Could be called from interrupt, use lightweight printf
sif::printError("BinarySemaphore::getSemaphoreCounter: " sif::printError("BinarySemaphore::getSemaphoreCounter: "
"Invalid semaphore\n"); "Invalid semaphore\n");
return 0; return 0;
} }
else { else {
// This should never happen. // This should never happen.
return 0; return 0;
} }
} }
void BinarySemaphore::initSemaphore(uint8_t initCount) { void BinarySemaphore::initSemaphore(uint8_t initCount) {
auto result = sem_init(&handle, true, initCount); auto result = sem_init(&handle, true, initCount);
if(result == -1) { if(result == -1) {
switch(errno) { switch(errno) {
case(EINVAL): case(EINVAL): {
// Value exceeds SEM_VALUE_MAX utility::printUnixErrorGeneric(CLASS_NAME, "initSemaphore", "EINVAL");
case(ENOSYS): { break;
// System does not support process-shared semaphores }
#if FSFW_CPP_OSTREAM_ENABLED == 1 case(ENOSYS): {
sif::error << "BinarySemaphore: Init failed with " // System does not support process-shared semaphores
<< strerror(errno) << std::endl; utility::printUnixErrorGeneric(CLASS_NAME, "initSemaphore", "ENOSYS");
#else break;
sif::printError("BinarySemaphore: Init failed with %s\n", }
strerror(errno)); }
#endif }
}
}
}
} }
ReturnValue_t BinarySemaphore::checkCount(sem_t* handle, uint8_t maxCount) { ReturnValue_t BinarySemaphore::checkCount(sem_t* handle, uint8_t maxCount) {
int value = getSemaphoreCounter(handle); int value = getSemaphoreCounter(handle);
if(value >= maxCount) { if(value >= maxCount) {
if(maxCount == 1 and value > 1) { if(maxCount == 1 and value > 1) {
// Binary Semaphore special case. // Binary Semaphore special case.
// This is a config error use lightweight printf is this is called // This is a config error use lightweight printf is this is called
// from an interrupt // from an interrupt
printf("BinarySemaphore::release: Value of binary semaphore greater" printf("BinarySemaphore::release: Value of binary semaphore greater than 1!\n");
" than 1!\n"); return HasReturnvaluesIF::RETURN_FAILED;
return HasReturnvaluesIF::RETURN_FAILED; }
} return SemaphoreIF::SEMAPHORE_NOT_OWNED;
return SemaphoreIF::SEMAPHORE_NOT_OWNED; }
} return HasReturnvaluesIF::RETURN_OK;
return HasReturnvaluesIF::RETURN_OK;
} }

View File

@ -76,6 +76,7 @@ public:
static ReturnValue_t checkCount(sem_t* handle, uint8_t maxCount); static ReturnValue_t checkCount(sem_t* handle, uint8_t maxCount);
protected: protected:
sem_t handle; sem_t handle;
static constexpr const char* CLASS_NAME = "BinarySemaphore";
}; };
#endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */ #endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */

View File

@ -15,6 +15,7 @@ target_sources(${LIB_FSFW_NAME}
TaskFactory.cpp TaskFactory.cpp
Timer.cpp Timer.cpp
tcpipHelpers.cpp tcpipHelpers.cpp
unixUtility.cpp
) )
find_package(Threads REQUIRED) find_package(Threads REQUIRED)

View File

@ -1,58 +1,70 @@
#include "../../osal/linux/CountingSemaphore.h" #include "CountingSemaphore.h"
#include "unixUtility.h"
#include "../../serviceinterface/ServiceInterface.h" #include "../../serviceinterface/ServiceInterface.h"
#include <errno.h> #include <errno.h>
CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount): CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount):
maxCount(maxCount), initCount(initCount) { maxCount(maxCount), initCount(initCount) {
if(initCount > maxCount) { if(initCount > maxCount) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "CountingSemaphoreUsingTask: Max count bigger than " sif::warning << "CountingSemaphoreUsingTask: Max count bigger than "
"intial cout. Setting initial count to max count." << std::endl; "intial cout. Setting initial count to max count" << std::endl;
#else
sif::printWarning("CountingSemaphoreUsingTask: Max count bigger than "
"intial cout. Setting initial count to max count\n");
#endif #endif
initCount = maxCount; initCount = maxCount;
} }
initSemaphore(initCount); initSemaphore(initCount);
} }
CountingSemaphore::CountingSemaphore(CountingSemaphore&& other): CountingSemaphore::CountingSemaphore(CountingSemaphore&& other):
maxCount(other.maxCount), initCount(other.initCount) { maxCount(other.maxCount), initCount(other.initCount) {
initSemaphore(initCount); initSemaphore(initCount);
} }
CountingSemaphore& CountingSemaphore::operator =( CountingSemaphore& CountingSemaphore::operator =(
CountingSemaphore&& other) { CountingSemaphore&& other) {
initSemaphore(other.initCount); initSemaphore(other.initCount);
return * this; return * this;
} }
ReturnValue_t CountingSemaphore::release() { ReturnValue_t CountingSemaphore::release() {
ReturnValue_t result = checkCount(&handle, maxCount); ReturnValue_t result = checkCount(&handle, maxCount);
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
return CountingSemaphore::release(&this->handle); return CountingSemaphore::release(&this->handle);
} }
ReturnValue_t CountingSemaphore::release(sem_t* handle) { ReturnValue_t CountingSemaphore::release(sem_t* handle) {
int result = sem_post(handle); int result = sem_post(handle);
if(result == 0) { if(result == 0) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
switch(errno) { switch(errno) {
case(EINVAL): case(EINVAL): {
// Semaphore invalid // Semaphore invalid
return SemaphoreIF::SEMAPHORE_INVALID; utility::printUnixErrorGeneric("CountingSemaphore", "release", "EINVAL");
case(EOVERFLOW): return SemaphoreIF::SEMAPHORE_INVALID;
// SEM_MAX_VALUE overflow. This should never happen }
default:
return HasReturnvaluesIF::RETURN_FAILED; case(EOVERFLOW): {
} // SEM_MAX_VALUE overflow. This should never happen
utility::printUnixErrorGeneric("CountingSemaphore", "release", "EOVERFLOW");
return SemaphoreIF::SEMAPHORE_INVALID;
}
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
} }
uint8_t CountingSemaphore::getMaxCount() const { uint8_t CountingSemaphore::getMaxCount() const {
return maxCount; return maxCount;
} }

View File

@ -1,4 +1,5 @@
#include "MessageQueue.h" #include "MessageQueue.h"
#include "unixUtility.h"
#include "../../serviceinterface/ServiceInterface.h" #include "../../serviceinterface/ServiceInterface.h"
#include "../../objectmanager/ObjectManagerIF.h" #include "../../objectmanager/ObjectManagerIF.h"
@ -13,7 +14,6 @@
MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize): MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize):
id(MessageQueueIF::NO_QUEUE),lastPartner(MessageQueueIF::NO_QUEUE), id(MessageQueueIF::NO_QUEUE),lastPartner(MessageQueueIF::NO_QUEUE),
defaultDestination(MessageQueueIF::NO_QUEUE), maxMessageSize(maxMessageSize) { defaultDestination(MessageQueueIF::NO_QUEUE), maxMessageSize(maxMessageSize) {
//debug << "MessageQueue::MessageQueue: Creating a queue" << std::endl;
mq_attr attributes; mq_attr attributes;
this->id = 0; this->id = 0;
//Set attributes //Set attributes
@ -30,7 +30,7 @@ MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize):
mode_t mode = S_IWUSR | S_IREAD | S_IWGRP | S_IRGRP | S_IROTH | S_IWOTH; mode_t mode = S_IWUSR | S_IREAD | S_IWGRP | S_IRGRP | S_IROTH | S_IWOTH;
mqd_t tempId = mq_open(name, oflag, mode, &attributes); mqd_t tempId = mq_open(name, oflag, mode, &attributes);
if (tempId == -1) { if (tempId == -1) {
handleError(&attributes, messageDepth); handleOpenError(&attributes, messageDepth);
} }
else { else {
//Successful mq_open call //Successful mq_open call
@ -41,101 +41,14 @@ MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize):
MessageQueue::~MessageQueue() { MessageQueue::~MessageQueue() {
int status = mq_close(this->id); int status = mq_close(this->id);
if(status != 0){ if(status != 0){
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "~MessageQueue", "close");
sif::error << "MessageQueue::Destructor: mq_close Failed with status: "
<< strerror(errno) <<std::endl;
#endif
} }
status = mq_unlink(name); status = mq_unlink(name);
if(status != 0){ if(status != 0){
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "~MessageQueue", "unlink");
sif::error << "MessageQueue::Destructor: mq_unlink Failed with status: "
<< strerror(errno) << std::endl;
#endif
} }
} }
ReturnValue_t MessageQueue::handleError(mq_attr* attributes,
uint32_t messageDepth) {
switch(errno) {
case(EINVAL): {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MessageQueue::MessageQueue: Invalid name or attributes"
" for message size" << std::endl;
#endif
size_t defaultMqMaxMsg = 0;
// Not POSIX conformant, but should work for all UNIX systems.
// Just an additional helpful printout :-)
if(std::ifstream("/proc/sys/fs/mqueue/msg_max",std::ios::in) >>
defaultMqMaxMsg and defaultMqMaxMsg < messageDepth) {
/*
See: https://www.man7.org/linux/man-pages/man3/mq_open.3.html
This happens if the msg_max value is not large enough
It is ignored if the executable is run in privileged mode.
Run the unlockRealtime script or grant the mode manually by using:
sudo setcap 'CAP_SYS_RESOURCE=+ep' <pathToBinary>
Persistent solution for session:
echo <newMsgMax> | sudo tee /proc/sys/fs/mqueue/msg_max
Permanent solution:
sudo nano /etc/sysctl.conf
Append at end: fs/mqueue/msg_max = <newMsgMaxLen>
Apply changes with: sudo sysctl -p
*/
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MessageQueue::MessageQueue: Default MQ size "
<< defaultMqMaxMsg << " is too small for requested size "
<< messageDepth << std::endl;
sif::error << "This error can be fixed by setting the maximum "
"allowed message size higher!" << std::endl;
#endif
}
break;
}
case(EEXIST): {
// An error occured during open
// We need to distinguish if it is caused by an already created queue
// There's another queue with the same name
// We unlink the other queue
int status = mq_unlink(name);
if (status != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "mq_unlink Failed with status: " << strerror(errno)
<< std::endl;
#endif
}
else {
// Successful unlinking, try to open again
mqd_t tempId = mq_open(name,
O_NONBLOCK | O_RDWR | O_CREAT | O_EXCL,
S_IWUSR | S_IREAD | S_IWGRP | S_IRGRP, attributes);
if (tempId != -1) {
//Successful mq_open
this->id = tempId;
return HasReturnvaluesIF::RETURN_OK;
}
}
break;
}
default: {
// Failed either the first time or the second time
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MessageQueue::MessageQueue: Creating Queue " << name
<< " failed with status: " << strerror(errno) << std::endl;
#else
sif::printError("MessageQueue::MessageQueue: Creating Queue %s"
" failed with status: %s\n", name, strerror(errno));
#endif
}
}
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, bool ignoreFault) { MessageQueueMessageIF* message, bool ignoreFault) {
return sendMessageFrom(sendTo, message, this->getId(), false); return sendMessageFrom(sendTo, message, this->getId(), false);
@ -204,7 +117,8 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
return MessageQueueIF::EMPTY; return MessageQueueIF::EMPTY;
case EBADF: { case EBADF: {
//mqdes doesn't represent a valid queue open for reading. //mqdes doesn't represent a valid queue open for reading.
return handleRecvError("EBADF"); utility::printUnixErrorGeneric(CLASS_NAME, "receiveMessage", "EBADF");
break;
} }
case EINVAL: { case EINVAL: {
/* /*
@ -216,7 +130,8 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
* queue, and the QNX extended option MQ_READBUF_DYNAMIC hasn't * queue, and the QNX extended option MQ_READBUF_DYNAMIC hasn't
* been set in the queue's mq_flags. * been set in the queue's mq_flags.
*/ */
return handleRecvError("EINVAL"); utility::printUnixErrorGeneric(CLASS_NAME, "receiveMessage", "EINVAL");
break;
} }
case EMSGSIZE: { case EMSGSIZE: {
/* /*
@ -228,23 +143,25 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
* given msg_len is too short for the message that would have * given msg_len is too short for the message that would have
* been received. * been received.
*/ */
return handleRecvError("EMSGSIZE"); utility::printUnixErrorGeneric(CLASS_NAME, "receiveMessage", "EMSGSIZE");
break;
} }
case EINTR: { case EINTR: {
//The operation was interrupted by a signal. //The operation was interrupted by a signal.
return handleRecvError("EINTR"); utility::printUnixErrorGeneric(CLASS_NAME, "receiveMessage", "EINTR");
break;
} }
case ETIMEDOUT: { case ETIMEDOUT: {
//The operation was interrupted by a signal. //The operation was interrupted by a signal.
return handleRecvError("ETIMEDOUT"); utility::printUnixErrorGeneric(CLASS_NAME, "receiveMessage", "ETIMEDOUT");
break;
} }
default: default:
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
return HasReturnvaluesIF::RETURN_FAILED;
} }
} }
@ -259,29 +176,27 @@ ReturnValue_t MessageQueue::flush(uint32_t* count) {
switch(errno){ switch(errno){
case EBADF: case EBADF:
//mqdes doesn't represent a valid message queue. //mqdes doesn't represent a valid message queue.
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "flush", "EBADF");
sif::error << "MessageQueue::flush configuration error, " break;
"called flush with an invalid queue ID" << std::endl;
#endif
/*NO BREAK*/ /*NO BREAK*/
case EINVAL: case EINVAL:
//mq_attr is NULL //mq_attr is NULL
utility::printUnixErrorGeneric(CLASS_NAME, "flush", "EINVAL");
break;
default: default:
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
return HasReturnvaluesIF::RETURN_FAILED;
} }
*count = attrib.mq_curmsgs; *count = attrib.mq_curmsgs;
attrib.mq_curmsgs = 0; attrib.mq_curmsgs = 0;
status = mq_setattr(id,&attrib,NULL); status = mq_setattr(id,&attrib,NULL);
if(status != 0){ if(status != 0){
switch(errno){ switch(errno) {
case EBADF: case EBADF:
//mqdes doesn't represent a valid message queue. //mqdes doesn't represent a valid message queue.
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "flush", "EBADF");
sif::error << "MessageQueue::flush configuration error, " break;
"called flush with an invalid queue ID" << std::endl;
#endif
/*NO BREAK*/
case EINVAL: case EINVAL:
/* /*
* This value indicates one of the following: * This value indicates one of the following:
@ -290,9 +205,12 @@ ReturnValue_t MessageQueue::flush(uint32_t* count) {
* mq_flags includes a 0 in the MQ_MULT_NOTIFY bit. Once * mq_flags includes a 0 in the MQ_MULT_NOTIFY bit. Once
* MQ_MULT_NOTIFY has been turned on, it may never be turned off. * MQ_MULT_NOTIFY has been turned on, it may never be turned off.
*/ */
utility::printUnixErrorGeneric(CLASS_NAME, "flush", "EINVAL");
break;
default: default:
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
return HasReturnvaluesIF::RETURN_FAILED;
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
@ -333,8 +251,9 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
bool ignoreFault) { bool ignoreFault) {
if(message == nullptr) { if(message == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MessageQueue::sendMessageFromMessageQueue: Message is " sif::error << "MessageQueue::sendMessageFromMessageQueue: Message is nullptr!" << std::endl;
"nullptr!" << std::endl; #else
sif::printError("MessageQueue::sendMessageFromMessageQueue: Message is nullptr!\n");
#endif #endif
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
@ -348,8 +267,7 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
if (result != 0) { if (result != 0) {
if(!ignoreFault){ if(!ignoreFault){
InternalErrorReporterIF* internalErrorReporter = InternalErrorReporterIF* internalErrorReporter =
objectManager->get<InternalErrorReporterIF>( objectManager->get<InternalErrorReporterIF>(objects::INTERNAL_ERROR_REPORTER);
objects::INTERNAL_ERROR_REPORTER);
if (internalErrorReporter != NULL) { if (internalErrorReporter != NULL) {
internalErrorReporter->queueMessageNotSent(); internalErrorReporter->queueMessageNotSent();
} }
@ -363,17 +281,20 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
case EBADF: { case EBADF: {
//mq_des doesn't represent a valid message queue descriptor, //mq_des doesn't represent a valid message queue descriptor,
//or mq_des wasn't opened for writing. //or mq_des wasn't opened for writing.
utility::printUnixErrorGeneric(CLASS_NAME, "sendMessageFromMessageQueue", "EBADF");
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MessageQueue::sendMessage: Configuration error, MQ" sif::warning << "mq_send to: " << sendTo << " sent from "
<< " destination invalid." << std::endl; << sentFrom << "failed" << std::endl;
sif::error << strerror(errno) << " in " #else
<<"mq_send to: " << sendTo << " sent from " sif::printWarning("mq_send to: %d sent from %d failed\n", sendTo, sentFrom);
<< sentFrom << std::endl;
#endif #endif
return DESTINATION_INVALID; return DESTINATION_INVALID;
} }
case EINTR: case EINTR:
//The call was interrupted by a signal. //The call was interrupted by a signal.
utility::printUnixErrorGeneric(CLASS_NAME, "sendMessageFromMessageQueue", "EINTR");
break;
case EINVAL: case EINVAL:
/* /*
* This value indicates one of the following: * This value indicates one of the following:
@ -384,36 +305,87 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
* - MQ_PRIO_RESTRICT is set in the mq_attr of mq_des, and * - MQ_PRIO_RESTRICT is set in the mq_attr of mq_des, and
* msg_prio is greater than the priority of the calling process. * msg_prio is greater than the priority of the calling process.
*/ */
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "sendMessageFromMessageQueue", "EINVAL");
sif::error << "MessageQueue::sendMessage: Configuration error " break;
<< strerror(errno) << " in mq_send" << std::endl;
#endif
/*NO BREAK*/
case EMSGSIZE: case EMSGSIZE:
// The msg_len is greater than the msgsize associated with // The msg_len is greater than the msgsize associated with
//the specified queue. //the specified queue.
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "sendMessageFromMessageQueue", "EMSGSIZE");
sif::error << "MessageQueue::sendMessage: Size error [" << break;
strerror(errno) << "] in mq_send" << std::endl;
#endif
/*NO BREAK*/
default: default:
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
return HasReturnvaluesIF::RETURN_FAILED;
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t MessageQueue::handleRecvError(const char * const failString) { ReturnValue_t MessageQueue::handleOpenError(mq_attr* attributes,
if(failString == nullptr) { uint32_t messageDepth) {
return HasReturnvaluesIF::RETURN_FAILED; switch(errno) {
} case(EINVAL): {
utility::printUnixErrorGeneric(CLASS_NAME, "MessageQueue", "EINVAL");
size_t defaultMqMaxMsg = 0;
// Not POSIX conformant, but should work for all UNIX systems.
// Just an additional helpful printout :-)
if(std::ifstream("/proc/sys/fs/mqueue/msg_max",std::ios::in) >>
defaultMqMaxMsg and defaultMqMaxMsg < messageDepth) {
/*
See: https://www.man7.org/linux/man-pages/man3/mq_open.3.html
This happens if the msg_max value is not large enough
It is ignored if the executable is run in privileged mode.
Run the unlockRealtime script or grant the mode manually by using:
sudo setcap 'CAP_SYS_RESOURCE=+ep' <pathToBinary>
Persistent solution for session:
echo <newMsgMax> | sudo tee /proc/sys/fs/mqueue/msg_max
Permanent solution:
sudo nano /etc/sysctl.conf
Append at end: fs/mqueue/msg_max = <newMsgMaxLen>
Apply changes with: sudo sysctl -p
*/
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MessageQueue::receiveMessage: " << failString << " error " sif::error << "MessageQueue::MessageQueue: Default MQ size " << defaultMqMaxMsg <<
<< strerror(errno) << std::endl; " is too small for requested size " << messageDepth << std::endl;
sif::error << "This error can be fixed by setting the maximum "
"allowed message size higher!" << std::endl;
#else #else
sif::printError("MessageQueue::receiveMessage: %s error %s\n", failString, sif::printError("MessageQueue::MessageQueue: Default MQ size %d is too small for"
strerror(errno)); "requested size %d\n");
sif::printError("This error can be fixes by setting the maximum allowed"
"message size higher!\n");
#endif #endif
}
break;
}
case(EEXIST): {
// An error occured during open.
// We need to distinguish if it is caused by an already created queue
// There's another queue with the same name
// We unlink the other queue
int status = mq_unlink(name);
if (status != 0) {
utility::printUnixErrorGeneric(CLASS_NAME, "MessageQueue", "EEXIST");
}
else {
// Successful unlinking, try to open again
mqd_t tempId = mq_open(name,
O_NONBLOCK | O_RDWR | O_CREAT | O_EXCL,
S_IWUSR | S_IREAD | S_IWGRP | S_IRGRP, attributes);
if (tempId != -1) {
//Successful mq_open
this->id = tempId;
return HasReturnvaluesIF::RETURN_OK;
}
}
break;
}
default: {
// Failed either the first time or the second time
utility::printUnixErrorGeneric(CLASS_NAME, "MessageQueue", "Unknown");
}
}
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }

View File

@ -181,8 +181,8 @@ private:
static uint16_t queueCounter; static uint16_t queueCounter;
const size_t maxMessageSize; const size_t maxMessageSize;
ReturnValue_t handleError(mq_attr* attributes, uint32_t messageDepth); static constexpr const char* CLASS_NAME = "MessageQueue";
ReturnValue_t handleRecvError(const char* const failString); ReturnValue_t handleOpenError(mq_attr* attributes, uint32_t messageDepth);
}; };
#endif /* FSFW_OSAL_LINUX_MESSAGEQUEUE_H_ */ #endif /* FSFW_OSAL_LINUX_MESSAGEQUEUE_H_ */

View File

@ -1,43 +1,34 @@
#include "Mutex.h" #include "Mutex.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "unixUtility.h"
#include "../../serviceinterface/ServiceInterface.h"
#include "../../timemanager/Clock.h" #include "../../timemanager/Clock.h"
uint8_t Mutex::count = 0;
#include <cstring> #include <cstring>
#include <errno.h> #include <errno.h>
uint8_t Mutex::count = 0;
Mutex::Mutex() { Mutex::Mutex() {
pthread_mutexattr_t mutexAttr; pthread_mutexattr_t mutexAttr;
int status = pthread_mutexattr_init(&mutexAttr); int status = pthread_mutexattr_init(&mutexAttr);
if (status != 0) { if (status != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric("Mutex", "Mutex", "pthread_mutexattr_init");
sif::error << "Mutex: Attribute init failed with: " << strerror(status) << std::endl;
#endif
} }
status = pthread_mutexattr_setprotocol(&mutexAttr, PTHREAD_PRIO_INHERIT); status = pthread_mutexattr_setprotocol(&mutexAttr, PTHREAD_PRIO_INHERIT);
if (status != 0) { if (status != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric("Mutex", "Mutex", "pthread_mutexattr_setprotocol");
sif::error << "Mutex: Attribute set PRIO_INHERIT failed with: " << strerror(status)
<< std::endl;
#endif
} }
status = pthread_mutex_init(&mutex, &mutexAttr); status = pthread_mutex_init(&mutex, &mutexAttr);
if (status != 0) { if (status != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric("Mutex", "Mutex", "pthread_mutex_init");
sif::error << "Mutex: creation with name, id " << mutex.__data.__count
<< ", " << " failed with " << strerror(status) << std::endl;
#endif
} }
// After a mutex attributes object has been used to initialize one or more // After a mutex attributes object has been used to initialize one or more
// mutexes, any function affecting the attributes object // mutexes, any function affecting the attributes object
// (including destruction) shall not affect any previously initialized mutexes. // (including destruction) shall not affect any previously initialized mutexes.
status = pthread_mutexattr_destroy(&mutexAttr); status = pthread_mutexattr_destroy(&mutexAttr);
if (status != 0) { if (status != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric("Mutex", "Mutex", "pthread_mutexattr_destroy");
sif::error << "Mutex: Attribute destroy failed with " << strerror(status) << std::endl;
#endif
} }
} }

View File

@ -1,7 +1,8 @@
#include "../../tasks/ExecutableObjectIF.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include <errno.h>
#include "PeriodicPosixTask.h" #include "PeriodicPosixTask.h"
#include "../../tasks/ExecutableObjectIF.h"
#include "../../serviceinterface/ServiceInterface.h"
#include <errno.h>
PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_, PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_,
size_t stackSize_, uint32_t period_, void(deadlineMissedFunc_)()): size_t stackSize_, uint32_t period_, void(deadlineMissedFunc_)()):
@ -28,6 +29,9 @@ ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure" sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
<< " it implements ExecutableObjectIF!" << std::endl; << " it implements ExecutableObjectIF!" << std::endl;
#else
sif::printError("PeriodicTask::addComponent: Invalid object. Make sure it"
"implements ExecutableObjectIF!\n");
#endif #endif
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
@ -44,9 +48,6 @@ ReturnValue_t PeriodicPosixTask::sleepFor(uint32_t ms) {
ReturnValue_t PeriodicPosixTask::startTask(void) { ReturnValue_t PeriodicPosixTask::startTask(void) {
started = true; started = true;
#if FSFW_CPP_OSTREAM_ENABLED == 1
//sif::info << stackSize << std::endl;
#endif
PosixThread::createTask(&taskEntryPoint,this); PosixThread::createTask(&taskEntryPoint,this);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }

View File

@ -1,4 +1,5 @@
#include "PosixThread.h" #include "PosixThread.h"
#include "unixUtility.h"
#include "../../serviceinterface/ServiceInterface.h" #include "../../serviceinterface/ServiceInterface.h"
@ -6,263 +7,240 @@
#include <errno.h> #include <errno.h>
PosixThread::PosixThread(const char* name_, int priority_, size_t stackSize_): PosixThread::PosixThread(const char* name_, int priority_, size_t stackSize_):
thread(0), priority(priority_), stackSize(stackSize_) { thread(0), priority(priority_), stackSize(stackSize_) {
name[0] = '\0'; name[0] = '\0';
std::strncat(name, name_, PTHREAD_MAX_NAMELEN - 1); std::strncat(name, name_, PTHREAD_MAX_NAMELEN - 1);
} }
PosixThread::~PosixThread() { PosixThread::~PosixThread() {
//No deletion and no free of Stack Pointer //No deletion and no free of Stack Pointer
} }
ReturnValue_t PosixThread::sleep(uint64_t ns) { ReturnValue_t PosixThread::sleep(uint64_t ns) {
//TODO sleep might be better with timer instead of sleep() //TODO sleep might be better with timer instead of sleep()
timespec time; timespec time;
time.tv_sec = ns/1000000000; time.tv_sec = ns/1000000000;
time.tv_nsec = ns - time.tv_sec*1e9; time.tv_nsec = ns - time.tv_sec*1e9;
//Remaining Time is not set here //Remaining Time is not set here
int status = nanosleep(&time,NULL); int status = nanosleep(&time,NULL);
if(status != 0){ if(status != 0){
switch(errno){ switch(errno){
case EINTR: case EINTR:
//The nanosleep() function was interrupted by a signal. //The nanosleep() function was interrupted by a signal.
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
case EINVAL: case EINVAL:
//The rqtp argument specified a nanosecond value less than zero or //The rqtp argument specified a nanosecond value less than zero or
// greater than or equal to 1000 million. // greater than or equal to 1000 million.
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
default: default:
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
void PosixThread::suspend() { void PosixThread::suspend() {
//Wait for SIGUSR1 //Wait for SIGUSR1
int caughtSig = 0; int caughtSig = 0;
sigset_t waitSignal; sigset_t waitSignal;
sigemptyset(&waitSignal); sigemptyset(&waitSignal);
sigaddset(&waitSignal, SIGUSR1); sigaddset(&waitSignal, SIGUSR1);
sigwait(&waitSignal, &caughtSig); sigwait(&waitSignal, &caughtSig);
if (caughtSig != SIGUSR1) { if (caughtSig != SIGUSR1) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "FixedTimeslotTask: Unknown Signal received: " << sif::error << "FixedTimeslotTask::suspend: Unknown Signal received: " << caughtSig <<
caughtSig << std::endl; std::endl;
#else
sif::printError("FixedTimeslotTask::suspend: Unknown Signal received: %d\n", caughtSig);
#endif #endif
} }
} }
void PosixThread::resume(){ void PosixThread::resume(){
/* Signal the thread to start. Makes sense to call kill to start or? ;) /* Signal the thread to start. Makes sense to call kill to start or? ;)
* *
* According to Posix raise(signal) will call pthread_kill(pthread_self(), sig), * According to Posix raise(signal) will call pthread_kill(pthread_self(), sig),
* but as the call must be done from the thread itsself this is not possible here * but as the call must be done from the thread itsself this is not possible here
*/ */
pthread_kill(thread,SIGUSR1); pthread_kill(thread,SIGUSR1);
} }
bool PosixThread::delayUntil(uint64_t* const prevoiusWakeTime_ms, bool PosixThread::delayUntil(uint64_t* const prevoiusWakeTime_ms,
const uint64_t delayTime_ms) { const uint64_t delayTime_ms) {
uint64_t nextTimeToWake_ms; uint64_t nextTimeToWake_ms;
bool shouldDelay = false; bool shouldDelay = false;
//Get current Time //Get current Time
const uint64_t currentTime_ms = getCurrentMonotonicTimeMs(); const uint64_t currentTime_ms = getCurrentMonotonicTimeMs();
/* Generate the tick time at which the task wants to wake. */ /* Generate the tick time at which the task wants to wake. */
nextTimeToWake_ms = (*prevoiusWakeTime_ms) + delayTime_ms; nextTimeToWake_ms = (*prevoiusWakeTime_ms) + delayTime_ms;
if (currentTime_ms < *prevoiusWakeTime_ms) { if (currentTime_ms < *prevoiusWakeTime_ms) {
/* The tick count has overflowed since this function was /* The tick count has overflowed since this function was
lasted called. In this case the only time we should ever lasted called. In this case the only time we should ever
actually delay is if the wake time has also overflowed, actually delay is if the wake time has also overflowed,
and the wake time is greater than the tick time. When this and the wake time is greater than the tick time. When this
is the case it is as if neither time had overflowed. */ is the case it is as if neither time had overflowed. */
if ((nextTimeToWake_ms < *prevoiusWakeTime_ms) if ((nextTimeToWake_ms < *prevoiusWakeTime_ms)
&& (nextTimeToWake_ms > currentTime_ms)) { && (nextTimeToWake_ms > currentTime_ms)) {
shouldDelay = true; shouldDelay = true;
} }
} else { } else {
/* The tick time has not overflowed. In this case we will /* The tick time has not overflowed. In this case we will
delay if either the wake time has overflowed, and/or the delay if either the wake time has overflowed, and/or the
tick time is less than the wake time. */ tick time is less than the wake time. */
if ((nextTimeToWake_ms < *prevoiusWakeTime_ms) if ((nextTimeToWake_ms < *prevoiusWakeTime_ms)
|| (nextTimeToWake_ms > currentTime_ms)) { || (nextTimeToWake_ms > currentTime_ms)) {
shouldDelay = true; shouldDelay = true;
} }
} }
/* Update the wake time ready for the next call. */ /* Update the wake time ready for the next call. */
(*prevoiusWakeTime_ms) = nextTimeToWake_ms; (*prevoiusWakeTime_ms) = nextTimeToWake_ms;
if (shouldDelay) { if (shouldDelay) {
uint64_t sleepTime = nextTimeToWake_ms - currentTime_ms; uint64_t sleepTime = nextTimeToWake_ms - currentTime_ms;
PosixThread::sleep(sleepTime * 1000000ull); PosixThread::sleep(sleepTime * 1000000ull);
return true; return true;
} }
//We are shifting the time in case the deadline was missed like rtems //We are shifting the time in case the deadline was missed like rtems
(*prevoiusWakeTime_ms) = currentTime_ms; (*prevoiusWakeTime_ms) = currentTime_ms;
return false; return false;
} }
uint64_t PosixThread::getCurrentMonotonicTimeMs(){ uint64_t PosixThread::getCurrentMonotonicTimeMs(){
timespec timeNow; timespec timeNow;
clock_gettime(CLOCK_MONOTONIC_RAW, &timeNow); clock_gettime(CLOCK_MONOTONIC_RAW, &timeNow);
uint64_t currentTime_ms = (uint64_t) timeNow.tv_sec * 1000 uint64_t currentTime_ms = (uint64_t) timeNow.tv_sec * 1000
+ timeNow.tv_nsec / 1000000; + timeNow.tv_nsec / 1000000;
return currentTime_ms; return currentTime_ms;
} }
void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) { void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
//sif::debug << "PosixThread::createTask" << std::endl; //sif::debug << "PosixThread::createTask" << std::endl;
#endif #endif
/* /*
* The attr argument points to a pthread_attr_t structure whose contents * The attr argument points to a pthread_attr_t structure whose contents
are used at thread creation time to determine attributes for the new are used at thread creation time to determine attributes for the new
thread; this structure is initialized using pthread_attr_init(3) and thread; this structure is initialized using pthread_attr_init(3) and
related functions. If attr is NULL, then the thread is created with related functions. If attr is NULL, then the thread is created with
default attributes. default attributes.
*/ */
pthread_attr_t attributes; pthread_attr_t attributes;
int status = pthread_attr_init(&attributes); int status = pthread_attr_init(&attributes);
if(status != 0){ if(status != 0){
utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_init");
}
void* stackPointer;
status = posix_memalign(&stackPointer, sysconf(_SC_PAGESIZE), stackSize);
if(status != 0) {
if(errno == ENOMEM) {
size_t stackMb = stackSize/10e6;
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Posix Thread attribute init failed with: " << sif::error << "PosixThread::createTask: Insufficient memory for"
strerror(status) << std::endl; " the requested " << stackMb << " MB" << std::endl;
#endif
}
void* stackPointer;
status = posix_memalign(&stackPointer, sysconf(_SC_PAGESIZE), stackSize);
if(status != 0){
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PosixThread::createTask: Stack init failed with: " <<
strerror(status) << std::endl;
#endif
if(errno == ENOMEM) {
size_t stackMb = stackSize/10e6;
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PosixThread::createTask: Insufficient memory for"
" the requested " << stackMb << " MB" << std::endl;
#else #else
sif::printError("PosixThread::createTask: Insufficient memory for " sif::printError("PosixThread::createTask: Insufficient memory for "
"the requested %lu MB\n", static_cast<unsigned long>(stackMb)); "the requested %lu MB\n", static_cast<unsigned long>(stackMb));
#endif #endif
} utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "ENOMEM");
else if(errno == EINVAL) { }
else if(errno == EINVAL) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PosixThread::createTask: Wrong alignment argument!" sif::error << "PosixThread::createTask: Wrong alignment argument!"
<< std::endl; << std::endl;
#else #else
sif::printError("PosixThread::createTask: " sif::printError("PosixThread::createTask: Wrong alignment argument!\n");
"Wrong alignment argument!\n");
#endif #endif
} utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "EINVAL");
return; }
} return;
}
status = pthread_attr_setstack(&attributes, stackPointer, stackSize); status = pthread_attr_setstack(&attributes, stackPointer, stackSize);
if(status != 0){ if(status != 0) {
utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_setstack");
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PosixThread::createTask: pthread_attr_setstack " sif::warning << "Make sure the specified stack size is valid and is "
" failed with: " << strerror(status) << std::endl; "larger than the minimum allowed stack size." << std::endl;
sif::error << "Make sure the specified stack size is valid and is " #else
"larger than the minimum allowed stack size." << std::endl; sif::printWarning("Make sure the specified stack size is valid and is "
"larger than the minimum allowed stack size.\n");
#endif #endif
} }
status = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED); status = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED);
if(status != 0){ if(status != 0){
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_setinheritsched");
sif::error << "Posix Thread attribute setinheritsched failed with: " << }
strerror(status) << std::endl;
#endif
}
#ifndef FSFW_USE_REALTIME_FOR_LINUX #ifndef FSFW_USE_REALTIME_FOR_LINUX
#error "Please define FSFW_USE_REALTIME_FOR_LINUX with either 0 or 1" #error "Please define FSFW_USE_REALTIME_FOR_LINUX with either 0 or 1"
#endif #endif
#if FSFW_USE_REALTIME_FOR_LINUX == 1 #if FSFW_USE_REALTIME_FOR_LINUX == 1
// FIFO -> This needs root privileges for the process // FIFO -> This needs root privileges for the process
status = pthread_attr_setschedpolicy(&attributes,SCHED_FIFO); status = pthread_attr_setschedpolicy(&attributes,SCHED_FIFO);
if(status != 0){ if(status != 0){
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_setschedpolicy");
sif::error << "Posix Thread attribute schedule policy failed with: " << }
strerror(status) << std::endl;
#endif
}
sched_param scheduleParams; sched_param scheduleParams;
scheduleParams.__sched_priority = priority; scheduleParams.__sched_priority = priority;
status = pthread_attr_setschedparam(&attributes, &scheduleParams); status = pthread_attr_setschedparam(&attributes, &scheduleParams);
if(status != 0){ if(status != 0){
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_setschedparam");
sif::error << "Posix Thread attribute schedule params failed with: " << }
strerror(status) << std::endl;
#endif #endif
} //Set Signal Mask for suspend until startTask is called
#endif sigset_t waitSignal;
//Set Signal Mask for suspend until startTask is called sigemptyset(&waitSignal);
sigset_t waitSignal; sigaddset(&waitSignal, SIGUSR1);
sigemptyset(&waitSignal); status = pthread_sigmask(SIG_BLOCK, &waitSignal, NULL);
sigaddset(&waitSignal, SIGUSR1); if(status != 0){
status = pthread_sigmask(SIG_BLOCK, &waitSignal, NULL); utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_sigmask");
if(status != 0){ }
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Posix Thread sigmask failed failed with: " <<
strerror(status) << " errno: " << strerror(errno) << std::endl;
#endif
}
status = pthread_create(&thread,&attributes,fnc_,arg_);
status = pthread_create(&thread,&attributes,fnc_,arg_); if(status != 0){
if(status != 0){ utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_create");
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PosixThread::createTask: Failed with: " << sif::error << "For FSFW_USE_REALTIME_FOR_LINUX == 1 make sure to call " <<
strerror(status) << std::endl; "\"all sudo setcap 'cap_sys_nice=eip'\" on the application or set "
sif::error << "For FSFW_USE_REALTIME_FOR_LINUX == 1 make sure to call " << "/etc/security/limit.conf" << std::endl;
"\"all sudo setcap 'cap_sys_nice=eip'\" on the application or set "
"/etc/security/limit.conf" << std::endl;
#else #else
sif::printError("PosixThread::createTask: Create failed with: %s\n", strerror(status)); sif::printError("For FSFW_USE_REALTIME_FOR_LINUX == 1 make sure to call "
sif::printError("For FSFW_USE_REALTIME_FOR_LINUX == 1 make sure to call " "\"all sudo setcap 'cap_sys_nice=eip'\" on the application or set "
"\"all sudo setcap 'cap_sys_nice=eip'\" on the application or set "
"/etc/security/limit.conf\n"); "/etc/security/limit.conf\n");
#endif #endif
} }
status = pthread_setname_np(thread,name); status = pthread_setname_np(thread,name);
if(status != 0){ if(status != 0){
utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_setname_np");
if(status == ERANGE) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PosixThread::createTask: setname failed with: " << sif::warning << "PosixThread::createTask: Task name length longer"
strerror(status) << std::endl; " than 16 chars. Truncating.." << std::endl;
#else
sif::printWarning("PosixThread::createTask: Task name length longer"
" than 16 chars. Truncating..\n");
#endif #endif
if(status == ERANGE) { name[15] = '\0';
#if FSFW_CPP_OSTREAM_ENABLED == 1 status = pthread_setname_np(thread,name);
sif::error << "PosixThread::createTask: Task name length longer" if(status != 0){
" than 16 chars. Truncating.." << std::endl; utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_setname_np");
#endif }
name[15] = '\0'; }
status = pthread_setname_np(thread,name); }
if(status != 0){
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PosixThread::createTask: Setting name"
" did not work.." << std::endl;
#endif
}
}
}
status = pthread_attr_destroy(&attributes); status = pthread_attr_destroy(&attributes);
if(status!=0){ if (status != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_destroy");
sif::error << "Posix Thread attribute destroy failed with: " << }
strerror(status) << std::endl;
#endif
}
} }

View File

@ -9,69 +9,71 @@
class PosixThread { class PosixThread {
public: public:
static constexpr uint8_t PTHREAD_MAX_NAMELEN = 16; static constexpr uint8_t PTHREAD_MAX_NAMELEN = 16;
PosixThread(const char* name_, int priority_, size_t stackSize_); PosixThread(const char* name_, int priority_, size_t stackSize_);
virtual ~PosixThread(); virtual ~PosixThread();
/** /**
* Set the Thread to sleep state * Set the Thread to sleep state
* @param ns Nanosecond sleep time * @param ns Nanosecond sleep time
* @return Returns Failed if sleep fails * @return Returns Failed if sleep fails
*/ */
static ReturnValue_t sleep(uint64_t ns); static ReturnValue_t sleep(uint64_t ns);
/** /**
* @brief Function to suspend the task until SIGUSR1 was received * @brief Function to suspend the task until SIGUSR1 was received
* *
* @details Will be called in the beginning to suspend execution until startTask() is called explicitly. * @details Will be called in the beginning to suspend execution until startTask() is called explicitly.
*/ */
void suspend(); void suspend();
/** /**
* @brief Function to allow a other thread to start the thread again from suspend state * @brief Function to allow a other thread to start the thread again from suspend state
* *
* @details Restarts the Thread after suspend call * @details Restarts the Thread after suspend call
*/ */
void resume(); void resume();
/** /**
* Delay function similar to FreeRtos delayUntil function * Delay function similar to FreeRtos delayUntil function
* *
* @param prevoiusWakeTime_ms Needs the previous wake time and returns the next wakeup time * @param prevoiusWakeTime_ms Needs the previous wake time and returns the next wakeup time
* @param delayTime_ms Time period to delay * @param delayTime_ms Time period to delay
* *
* @return False If deadline was missed; True if task was delayed * @return False If deadline was missed; True if task was delayed
*/ */
static bool delayUntil(uint64_t* const prevoiusWakeTime_ms, const uint64_t delayTime_ms); static bool delayUntil(uint64_t* const prevoiusWakeTime_ms, const uint64_t delayTime_ms);
/** /**
* Returns the current time in milliseconds from CLOCK_MONOTONIC * Returns the current time in milliseconds from CLOCK_MONOTONIC
* *
* @return current time in milliseconds from CLOCK_MONOTONIC * @return current time in milliseconds from CLOCK_MONOTONIC
*/ */
static uint64_t getCurrentMonotonicTimeMs(); static uint64_t getCurrentMonotonicTimeMs();
protected: protected:
pthread_t thread; pthread_t thread;
/** /**
* @brief Function that has to be called by derived class because the * @brief Function that has to be called by derived class because the
* derived class pointer has to be valid as argument. * derived class pointer has to be valid as argument.
* @details * @details
* This function creates a pthread with the given parameters. As the * This function creates a pthread with the given parameters. As the
* function requires a pointer to the derived object it has to be called * function requires a pointer to the derived object it has to be called
* after the this pointer of the derived object is valid. * after the this pointer of the derived object is valid.
* Sets the taskEntryPoint as function to be called by new a thread. * Sets the taskEntryPoint as function to be called by new a thread.
* @param fnc_ Function which will be executed by the thread. * @param fnc_ Function which will be executed by the thread.
* @param arg_ * @param arg_
* argument of the taskEntryPoint function, needs to be this pointer * argument of the taskEntryPoint function, needs to be this pointer
* of derived class * of derived class
*/ */
void createTask(void* (*fnc_)(void*),void* arg_); void createTask(void* (*fnc_)(void*),void* arg_);
private: private:
char name[PTHREAD_MAX_NAMELEN]; char name[PTHREAD_MAX_NAMELEN];
int priority; int priority;
size_t stackSize = 0; size_t stackSize = 0;
static constexpr const char* CLASS_NAME = "PosixThread";
}; };
#endif /* FRAMEWORK_OSAL_LINUX_POSIXTHREAD_H_ */ #endif /* FRAMEWORK_OSAL_LINUX_POSIXTHREAD_H_ */

View File

@ -0,0 +1,32 @@
#include "FSFWConfig.h"
#include "unixUtility.h"
#include "../../serviceinterface/ServiceInterface.h"
#include <cstring>
#include <errno.h>
void utility::printUnixErrorGeneric(const char* const className,
const char* const function, const char* const failString,
sif::OutputTypes outputType) {
if(className == nullptr or failString == nullptr or function == nullptr) {
return;
}
#if FSFW_VERBOSE_LEVEL >= 1
if(outputType == sif::OutputTypes::OUT_ERROR) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << className << "::" << function << ":" << failString << " error: "
<< strerror(errno) << std::endl;
#else
sif::printError("%s::%s: %s error: %s\n", className, function, failString, strerror(errno));
#endif
}
else {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << className << "::" << function << ":" << failString << " error: "
<< strerror(errno) << std::endl;
#else
sif::printWarning("%s::%s: %s error: %s\n", className, function, failString, strerror(errno));
#endif
}
#endif
}

13
osal/linux/unixUtility.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef FSFW_OSAL_LINUX_UNIXUTILITY_H_
#define FSFW_OSAL_LINUX_UNIXUTILITY_H_
#include "../../serviceinterface/serviceInterfaceDefintions.h"
namespace utility {
void printUnixErrorGeneric(const char* const className, const char* const function,
const char* const failString, sif::OutputTypes outputType = sif::OutputTypes::OUT_ERROR);
}
#endif /* FSFW_OSAL_LINUX_UNIXUTILITY_H_ */