Merge "[569144] Fix FORTE_LINKED_STRINGDICT definition" into develop
diff --git a/src/arch/posix/forte_sem.cpp b/src/arch/posix/forte_sem.cpp
index ef7cefb..288d5c4 100644
--- a/src/arch/posix/forte_sem.cpp
+++ b/src/arch/posix/forte_sem.cpp
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2016, 2018 fortiss GmbH, TU Vienna/ACIN
+ * Copyright (c) 2016, 2020 fortiss GmbH, TU Vienna/ACIN, OFFIS e.V.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
@@ -10,12 +10,15 @@
* Alois Zoitl - initial API and implementation and/or initial documentation
* Peter Gsellmann, Martin Melik-Merkumians - adds timed wait and try and no wait
* and documentation
+ * Jörg Walter - make timed wait work withoout busy-loop, switch to binary
+ * semaphore
+ *
*******************************************************************************/
-#include <errno.h>
-#include <string.h>
-#include <sys/time.h>
-#include <time.h>
+#include <cerrno>
+#include <cstring>
+#include <ctime>
+#include <cassert>
#include "forte_sem.h"
#include "../devlog.h"
@@ -24,44 +27,102 @@
namespace forte {
namespace arch {
- CPThreadSemaphore::CPThreadSemaphore(unsigned int paInitialValue){
- if(-1 == sem_init(&mSemaphore, 0, paInitialValue)){
- DEVLOG_ERROR("Could not initialize suspend sempaphore: %s\n", strerror(errno));
+ CPThreadSemaphore::CPThreadSemaphore(bool paInitialValue)
+ : mPosted(paInitialValue)
+ {
+ pthread_condattr_t condAttr;
+
+ if (pthread_condattr_init(&condAttr) != 0) {
+ DEVLOG_ERROR("Could not initialize cv attributes\n");
+ }
+ if (pthread_condattr_setclock(&condAttr, CLOCK_MONOTONIC) != 0) {
+ DEVLOG_ERROR("Could not set cv clock\n");
+ }
+ if (pthread_cond_init(&mCond, &condAttr) != 0) {
+ DEVLOG_ERROR("Could not initialize condition variable\n");
+ }
+ pthread_condattr_destroy(&condAttr);
+
+ if (pthread_mutex_init(&mMutex, NULL) != 0) {
+ DEVLOG_ERROR("Could not initialize mutex\n");
}
}
+
CPThreadSemaphore::~CPThreadSemaphore(){
- sem_destroy(&mSemaphore);
+ pthread_cond_destroy(&mCond);
+ pthread_mutex_destroy(&mMutex);
}
+
void CPThreadSemaphore::inc(){
- sem_post(&mSemaphore);
+ pthread_mutex_lock(&mMutex);
+ mPosted = true;
+ pthread_cond_signal(&mCond);
+ pthread_mutex_unlock(&mMutex);
}
+
void CPThreadSemaphore::waitIndefinitely(){
- while((-1 == sem_wait(&mSemaphore)) && (errno == EINTR)); //handle interrupts from signals
+ pthread_mutex_lock(&mMutex);
+ while (!mPosted) {
+ pthread_cond_wait(&mCond, &mMutex);
+ }
+ mPosted = false;
+ pthread_mutex_unlock(&mMutex);
}
+
bool CPThreadSemaphore::timedWait(const TForteUInt64 paRelativeTimeout){
- timespec timeoutSpec = { static_cast<time_t>(paRelativeTimeout / scmSecondInNanoSeconds), static_cast<time_t>(paRelativeTimeout % scmSecondInNanoSeconds) };
+ pthread_mutex_lock(&mMutex);
+
+ if (mPosted) {
+ mPosted = false;
+ pthread_mutex_unlock(&mMutex);
+ return true;
+ }
+
+ timespec timeoutSpec = {
+ static_cast<time_t>(paRelativeTimeout / 1000000000ULL),
+ static_cast<time_t>(paRelativeTimeout % 1000000000ULL)
+ };
+
timespec currentTime = { 0, 0 };
clock_gettime(CLOCK_MONOTONIC, ¤tTime);
- timespec expectedAbsoluteTimeoutTime = {0, 0};
+ timespec expectedAbsoluteTimeoutTime = { 0, 0 };
timespecAdd(¤tTime, &timeoutSpec, &expectedAbsoluteTimeoutTime);
- do{
- if(0 == sem_trywait(&mSemaphore)){
- return true;
- }
- clock_gettime(CLOCK_MONOTONIC, ¤tTime);
+ int rc = 0;
+ while (!mPosted && rc == 0) {
+ rc = pthread_cond_timedwait(&mCond, &mMutex, &expectedAbsoluteTimeoutTime);
+ }
- } while(timespecLessThan(¤tTime, &expectedAbsoluteTimeoutTime));
- return false;
+ if (rc != 0 && rc != ETIMEDOUT) {
+ DEVLOG_ERROR("Unexpected error during condition variable wait: %i\n", rc);
+ }
+
+ assert(!(rc == 0 && !mPosted)
+ && (bool)"should have been posted when waiting successfully");
+
+ bool success = (mPosted && rc == 0);
+ if (success) {
+ mPosted = false;
+ }
+
+ pthread_mutex_unlock(&mMutex);
+ return success;
}
+
bool CPThreadSemaphore::tryNoWait(){
- return (0 == sem_trywait(&mSemaphore));
+ pthread_mutex_lock(&mMutex);
+
+ bool success = mPosted;
+ mPosted = false;
+
+ pthread_mutex_unlock(&mMutex);
+ return success;
}
} /* namespace arch */
} /* namespace forte */
diff --git a/src/arch/posix/forte_sem.h b/src/arch/posix/forte_sem.h
index 2ce6be9..a85ec20 100644
--- a/src/arch/posix/forte_sem.h
+++ b/src/arch/posix/forte_sem.h
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2016, 2018 fortiss GmbH, TU Vienna/ACIN
+ * Copyright (c) 2016, 2020 fortiss GmbH, TU Vienna/ACIN, OFFIS e.V.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
@@ -10,25 +10,28 @@
* Alois Zoitl - initial API and implementation and/or initial documentation
* Peter Gsellmann, Martin Melik-Merkumians - adds timed wait and try and no wait
* and documentation
+ * Jörg Walter - make timed wait work withoout busy-loop, switch to binary
+ * semaphore
+ *
*******************************************************************************/
#ifndef SRC_ARCH_POSIX_SEMAPHORE_H_
#define SRC_ARCH_POSIX_SEMAPHORE_H_
-#include <semaphore.h>
+#include <pthread.h>
#include "datatype.h"
namespace forte {
namespace arch {
- /*!\brief counting semaphore for syncing operation in FORTE
+ /*!\brief binary semaphore for syncing operation in FORTE
*
* The semaphore is initialized with the value given.
*/
class CPThreadSemaphore{
public:
- explicit CPThreadSemaphore(unsigned int paInitialValue = 0);
+ explicit CPThreadSemaphore(bool paInitialValue = false);
~CPThreadSemaphore();
/** @brief Unlocks (increments) the semaphore
@@ -55,8 +58,24 @@
bool tryNoWait();
private:
- sem_t mSemaphore;
- static const TForteUInt64 scmSecondInNanoSeconds = (TForteUInt64)1E9;
+ /* TODO: in C++11, this class should be properly made non-copyable since
+ * mutexes cannot be copied after initialisation
+
+ CPThreadSemaphore(const CPThreadSemaphore &) = delete;
+ CPThreadSemaphore &operator=(const CPThreadSemaphore &) = delete;
+ */
+ CPThreadSemaphore(const CPThreadSemaphore &);
+ CPThreadSemaphore &operator=(const CPThreadSemaphore &);
+
+ /* Implementation is based on POSIX condition variables instead of POSIX
+ * semaphores, because POSIX semaphores cannot safely wait without busy
+ * looping. Derived from https://stackoverflow.com/a/57496953 */
+
+ pthread_mutex_t mMutex;
+ pthread_cond_t mCond;
+
+ bool mPosted;
+
};
typedef CPThreadSemaphore CSemaphore;
diff --git a/src/com/mqtt_paho/MQTTHandler.cpp b/src/com/mqtt_paho/MQTTHandler.cpp
index 6041eac..0a476e3 100644
--- a/src/com/mqtt_paho/MQTTHandler.cpp
+++ b/src/com/mqtt_paho/MQTTHandler.cpp
@@ -35,7 +35,7 @@
MQTTStates MQTTHandler::smMQTTS_STATE = NOT_CONNECTED;
-forte::arch::CSemaphore MQTTHandler::mStateSemaphore = forte::arch::CSemaphore();
+forte::arch::CSemaphore MQTTHandler::mStateSemaphore;
bool MQTTHandler::mIsSemaphoreEmpty = true;
MQTTHandler::MQTTHandler(CDeviceExecution& paDeviceExecution) : CExternalEventHandler(paDeviceExecution) {