#include "generic_ftc_threading.h" #include #include #include #include #include #ifdef Q_OS_LINUX #include #endif Threading::~Threading() { if (m_threadLifetime != nullptr) { m_threadLifetime->stop(); m_threadLifetime.reset(); } setCleanupNeeded(false); { std::lock_guard l(m_conditionMutex); setRun(false); } if (!m_used) { } if (m_thread.joinable()) { m_condition.notify_all(); m_thread.join(); } } void Threading::preInit() const { m_partitionId = partitionId(); m_partitionType = partitionType(); const QString base(QStringLiteral("F%1%2").arg(m_partitionType.left(1)).arg(m_partitionId)); const int baseLen = base.length(); const int maxLen = 16 - 1 - baseLen; if (maxLen < 1) { Q_ASSERT(false); m_threadName = functionTopicName(); return; } const QString orgName(functionTopicName()); QString name; if (orgName.length() > maxLen) { QRegularExpression regexp(QStringLiteral("[A-Z][a-z]*")); auto matches = regexp.globalMatch(functionTopicName()); QStringList words; while (matches.hasNext()) { const auto word = matches.next().capturedTexts().join(QString()); words += word; } if (words.isEmpty()) { Q_ASSERT(false); m_threadName = functionTopicName(); return; } int wordsLeft = words.count(); if (wordsLeft < 1) { Q_ASSERT(false); m_threadName = functionTopicName(); return; } int bremse = 20; while (wordsLeft > 0) { if (bremse < 1) { Q_ASSERT(false); break; } bremse--; const int lenRest = maxLen - name.count(); if (lenRest < 1) { Q_ASSERT(false); m_threadName = functionTopicName(); return; } const int maxWordLen = lenRest / wordsLeft; if (words.isEmpty()) { Q_ASSERT(false); break; } name += words.takeFirst().leftRef(maxWordLen); wordsLeft--; } const int finalLeft = maxLen - name.count(); if (finalLeft < 0 || (finalLeft > 0 && functionTopicName().length() > maxLen)) { } } else { name = orgName; } m_threadName = QStringLiteral("%1%2[%3]").arg(base, name).arg(qrand(), 8, 16, QLatin1Char('0')); } const QString &Threading::threadName() const { if (m_threadName.isEmpty()) { Q_ASSERT(false); } return m_threadName; } const char *Threading::posixThreadName() const { if (m_posixThreadName.empty()) { m_posixThreadName = threadName().left(15).toStdString(); } return m_posixThreadName.c_str(); } void Threading::createThread() { if (!isRun()) { if (m_thread.joinable()) { m_condition.notify_all(); m_thread.join(); threadDone(); } m_alreadyThreaded = 0; setRun(true); m_thread = std::thread(&Threading::run, this, threadName()); #ifdef Q_OS_LINUX pthread_setname_np(m_thread.native_handle(), posixThreadName()); #endif } m_createThreadCalledBefore = true; } void Threading::runThread() { m_used = true; Q_ASSERT(m_createThreadCalledBefore); m_createThreadCalledBefore = false; { std::lock_guard l(m_conditionMutex); setWorkAvailable(true); } m_condition.notify_all(); if (!m_threadLifetime) { m_threadLifetime.reset(new QTimer); m_threadLifetime->setSingleShot(true); m_threadLifetime->setInterval(11*1000); QObject::connect(m_threadLifetime.get(), &QTimer::timeout, m_threadLifetime.get(), [this] { bool workAvailable = false; bool run = false; bool working = false; { std::lock_guard l(m_conditionMutex); workAvailable = isWorkAvailable(); run = isRun(); working = isWorking(); } if (workAvailable || working) { m_threadLifetime->start(); return; } m_threadLifetime->deleteLater(); m_threadLifetime = nullptr; if (!run) { Q_ASSERT(false); return; } { std::lock_guard l(m_conditionMutex); setRun(false); } m_condition.notify_all(); }); } m_threadLifetime->start(); } void Threading::run(const QString &threadName) { Q_ASSERT(m_alreadyThreaded == 0); m_alreadyThreaded = 1; const std::string _tn = threadName.toStdString(); const char *tn = _tn.c_str(); while (isRun()) { try { { std::unique_lock conditionLock(m_conditionMutex); m_condition.wait(conditionLock, [this]{ return (isWorkAvailable() || !isRun()); }); } cancellationPoint(); { std::lock_guard l(m_conditionMutex); setWorking(true); } work(); { std::lock_guard l(m_conditionMutex); setWorking(false); } cancellationPoint(); } catch (const CancelationPointReached &ex) { break; } catch (const std::exception &ex) { fprintf(stderr, "[!] Threading::run: exception: %s (%s)\n", ex.what(), tn); } catch(...) { fprintf(stderr, "[!] Threading::run: unknown exception occured (%s) !!!\n", tn); } } if (isCleanupNeeded()) { cleanupThread(); } else { } }