diff --git a/src/librssguard/CMakeLists.txt b/src/librssguard/CMakeLists.txt index 9f37a150f..fff20a1cf 100644 --- a/src/librssguard/CMakeLists.txt +++ b/src/librssguard/CMakeLists.txt @@ -243,6 +243,8 @@ set(SOURCES miscellaneous/templates.h miscellaneous/textfactory.cpp miscellaneous/textfactory.h + miscellaneous/thread.cpp + miscellaneous/thread.h network-web/adblock/adblockdialog.cpp network-web/adblock/adblockdialog.h network-web/adblock/adblockicon.cpp diff --git a/src/librssguard/core/feeddownloader.cpp b/src/librssguard/core/feeddownloader.cpp index 4f5392950..1cd11688d 100644 --- a/src/librssguard/core/feeddownloader.cpp +++ b/src/librssguard/core/feeddownloader.cpp @@ -10,6 +10,7 @@ #include "exceptions/filteringexception.h" #include "miscellaneous/application.h" #include "miscellaneous/settings.h" +#include "miscellaneous/thread.h" #include "services/abstract/cacheforserviceroot.h" #include "services/abstract/feed.h" #include "services/abstract/labelsnode.h" @@ -17,7 +18,6 @@ #include #include #include -#include #include FeedDownloader::FeedDownloader() @@ -47,7 +47,7 @@ void FeedDownloader::synchronizeAccountCaches(const QList& for (CacheForServiceRoot* cache : caches) { qDebugNN << LOGSEC_FEEDDOWNLOADER << "Synchronizing cache back to server on thread" - << QUOTE_W_SPACE_DOT(QThread::currentThreadId()); + << QUOTE_W_SPACE_DOT(getThreadID()); cache->saveAllCachedData(false); if (m_stopCacheSynchronization) { @@ -77,7 +77,7 @@ void FeedDownloader::updateFeeds(const QList& feeds) { } else { qDebugNN << LOGSEC_FEEDDOWNLOADER << "Starting feed updates from worker in thread" - << QUOTE_W_SPACE_DOT(QThread::currentThreadId()); + << QUOTE_W_SPACE_DOT(getThreadID()); // Job starts now. emit updateStarted(); @@ -155,6 +155,9 @@ void FeedDownloader::updateFeeds(const QList& feeds) { std::function func = [=](const FeedUpdateRequest& fd) -> FeedUpdateResult { + #if defined(Q_OS_LINUX) + setThreadPriority(Priority::LOWEST); + #endif return updateThreadedFeed(fd); }; @@ -220,7 +223,7 @@ void FeedDownloader::updateOneFeed(ServiceRoot* acc, acc->itemChanged({feed}); } - qlonglong thread_id = qlonglong(QThread::currentThreadId()); + qlonglong thread_id = getThreadID(); qDebugNN << LOGSEC_FEEDDOWNLOADER << "Downloading new messages for feed ID" << QUOTE_W_SPACE(feed->customId()) << "URL:" << QUOTE_W_SPACE(feed->source()) << "title:" << QUOTE_W_SPACE(feed->title()) << "in thread " @@ -435,7 +438,7 @@ void FeedDownloader::updateOneFeed(ServiceRoot* acc, void FeedDownloader::finalizeUpdate() { qDebugNN << LOGSEC_FEEDDOWNLOADER << "Finished feed updates in thread" - << QUOTE_W_SPACE_DOT(QThread::currentThreadId()); + << QUOTE_W_SPACE_DOT(getThreadID()); m_feeds.clear(); diff --git a/src/librssguard/database/databasecleaner.cpp b/src/librssguard/database/databasecleaner.cpp index d4b3dec9f..e183d1d94 100644 --- a/src/librssguard/database/databasecleaner.cpp +++ b/src/librssguard/database/databasecleaner.cpp @@ -4,14 +4,14 @@ #include "database/databasequeries.h" #include "miscellaneous/application.h" +#include "miscellaneous/thread.h" #include -#include DatabaseCleaner::DatabaseCleaner(QObject* parent) : QObject(parent) {} void DatabaseCleaner::purgeDatabaseData(CleanerOrders which_data) { - qDebugNN << LOGSEC_DB << "Performing database cleanup in thread:" << QUOTE_W_SPACE_DOT(QThread::currentThreadId()); + qDebugNN << LOGSEC_DB << "Performing database cleanup in thread:" << QUOTE_W_SPACE_DOT(getThreadID()); // Inform everyone about the start of the process. emit purgeStarted(); diff --git a/src/librssguard/database/databasedriver.cpp b/src/librssguard/database/databasedriver.cpp index a570830e9..3134b716e 100644 --- a/src/librssguard/database/databasedriver.cpp +++ b/src/librssguard/database/databasedriver.cpp @@ -5,6 +5,7 @@ #include "definitions/definitions.h" #include "exceptions/applicationexception.h" #include "miscellaneous/iofactory.h" +#include "miscellaneous/thread.h" #include #include @@ -14,7 +15,7 @@ DatabaseDriver::DatabaseDriver(QObject* parent) : QObject(parent) {} QSqlDatabase DatabaseDriver::threadSafeConnection(const QString& connection_name, DesiredStorageType desired_type) { - qlonglong thread_id = qlonglong(QThread::currentThreadId()); + qlonglong thread_id = getThreadID(); bool is_main_thread = QThread::currentThread() == qApp->thread(); QSqlDatabase database = diff --git a/src/librssguard/gui/dialogs/formmain.cpp b/src/librssguard/gui/dialogs/formmain.cpp index 93edb13ab..545e5e03a 100644 --- a/src/librssguard/gui/dialogs/formmain.cpp +++ b/src/librssguard/gui/dialogs/formmain.cpp @@ -27,6 +27,7 @@ #include "miscellaneous/iconfactory.h" #include "miscellaneous/mutex.h" #include "miscellaneous/settings.h" +#include "miscellaneous/thread.h" #include "network-web/adblock/adblockicon.h" #include "network-web/adblock/adblockmanager.h" #include "network-web/webfactory.h" @@ -38,7 +39,6 @@ #include #include #include -#include #include #include #include @@ -54,7 +54,7 @@ FormMain::FormMain(QWidget* parent, Qt::WindowFlags f) : QMainWindow(parent, f), m_ui(new Ui::FormMain), m_trayMenu(nullptr), m_statusBar(nullptr) { qDebugNN << LOGSEC_GUI - << "Creating main application form in thread:" << QUOTE_W_SPACE_DOT(QThread::currentThreadId()); + << "Creating main application form in thread:" << QUOTE_W_SPACE_DOT(getThreadID()); // setAttribute(Qt::WA_WindowPropagation, true); m_ui->setupUi(this); qApp->setMainForm(this); diff --git a/src/librssguard/gui/webviewers/qtextbrowser/textbrowserviewer.cpp b/src/librssguard/gui/webviewers/qtextbrowser/textbrowserviewer.cpp index 10c5c15af..d42710166 100644 --- a/src/librssguard/gui/webviewers/qtextbrowser/textbrowserviewer.cpp +++ b/src/librssguard/gui/webviewers/qtextbrowser/textbrowserviewer.cpp @@ -42,7 +42,7 @@ TextBrowserViewer::TextBrowserViewer(QWidget* parent) setDocument(m_document.data()); m_resourceDownloader->moveToThread(m_resourceDownloaderThread); - m_resourceDownloaderThread->start(); + m_resourceDownloaderThread->start(QThread::LowPriority); connect(this, &TextBrowserViewer::reloadDocument, this, [this]() { const auto scr = verticalScrollBarPosition(); diff --git a/src/librssguard/miscellaneous/application.cpp b/src/librssguard/miscellaneous/application.cpp index 5001525ec..47aa0aaa7 100644 --- a/src/librssguard/miscellaneous/application.cpp +++ b/src/librssguard/miscellaneous/application.cpp @@ -1157,6 +1157,12 @@ void Application::setupWorkHorsePool() { m_workHorsePool->setMaxThreadCount((std::min)(MAX_THREADPOOL_THREADS, 2 * ideal_th_count)); } +#if QT_VERSION_MAJOR == 6 + // Avoid competing with interactive processes/threads by running the + // worker pool at a very low priority + m_workHorsePool->setThreadPriority(QThread::LowestPriority); +#endif + // NOTE: Do not expire threads so that their IDs are not reused. // This fixes cross-thread QSqlDatabase access. m_workHorsePool->setExpiryTimeout(-1); diff --git a/src/librssguard/miscellaneous/feedreader.cpp b/src/librssguard/miscellaneous/feedreader.cpp index d17fda1eb..9c6fd7fc1 100644 --- a/src/librssguard/miscellaneous/feedreader.cpp +++ b/src/librssguard/miscellaneous/feedreader.cpp @@ -128,7 +128,7 @@ void FeedReader::initializeFeedDownloader() { connect(m_feedDownloader, &FeedDownloader::updateStarted, this, &FeedReader::feedUpdatesStarted); connect(m_feedDownloader, &FeedDownloader::updateFinished, qApp->feedUpdateLock(), &Mutex::unlock); - m_feedDownloaderThread->start(); + m_feedDownloaderThread->start(QThread::LowPriority); } } diff --git a/src/librssguard/miscellaneous/thread.cpp b/src/librssguard/miscellaneous/thread.cpp new file mode 100644 index 000000000..3b9b4a12e --- /dev/null +++ b/src/librssguard/miscellaneous/thread.cpp @@ -0,0 +1,67 @@ +// For license of this file, see /LICENSE.md. + +#include "definitions/definitions.h" +#include "miscellaneous/thread.h" + +#include + +#if defined(Q_OS_LINUX) +#include +#include +#include +#endif + +// Returns the thread ID of the caller +qlonglong getThreadID() { + #if defined(Q_OS_LINUX) + return qlonglong(gettid()); + #else + return qlonglong(QThread::currentThreadId()); + #endif +} + +#if defined(Q_OS_LINUX) +// On Linux QThread priorities do nothing with the default scheduler SCHED_OTHER +// Set the nice value manually in this case until Qt supports nice values +void setThreadPriority(Priority prio) { + int current_policy = sched_getscheduler(0); + if (current_policy != -1) { + // If the current scheduling policy is neither of these the QThread priority should be working + if (current_policy != SCHED_BATCH && current_policy != SCHED_OTHER) { + return; + } + + // Set the scheduler to SCHED_BATCH if needed, indicating that this process is non-interactive + if (current_policy == SCHED_OTHER) { + struct sched_param p = {0}; + if (sched_setscheduler(0, SCHED_BATCH, &p) != 0) { + qDebugNN << "Setting the scheduler to SCHED_BATCH for thread" + << QUOTE_W_SPACE(getThreadID()) + << "failed with error" << QUOTE_W_SPACE_DOT(errno); + // We can still try to set the nice value + } + } + + errno = 0; // Clear errno since -1 is a legitimate return value + int current_priority = getpriority(PRIO_PROCESS, 0); + if (errno != 0) { + qDebugNN << "Getting the priority for thread" + << QUOTE_W_SPACE(getThreadID()) + << "failed with error" << QUOTE_W_SPACE_DOT(errno); + } else { + if (current_priority != prio) { + setpriority(PRIO_PROCESS, 0, prio); + if (errno != 0) { + qDebugNN << "Setting the priority for thread" + << QUOTE_W_SPACE(getThreadID()) + << "failed with error" << QUOTE_W_SPACE_DOT(errno); + } + } + } + } else { + qDebugNN << "Getting the priority for thread" + << QUOTE_W_SPACE(getThreadID()) + << "failed with error" << QUOTE_W_SPACE_DOT(errno); + } +} +#endif diff --git a/src/librssguard/miscellaneous/thread.h b/src/librssguard/miscellaneous/thread.h new file mode 100644 index 000000000..fe76b6618 --- /dev/null +++ b/src/librssguard/miscellaneous/thread.h @@ -0,0 +1,19 @@ +// For license of this file, see /LICENSE.md. + +#ifndef THREAD_H +#define THREAD_H + +qlonglong getThreadID(); + +#if defined(Q_OS_LINUX) +// Values corresponding to nice values +enum Priority { + LOWEST = 19, + LOW = 10, + NORMAL = 0 +}; + +void setThreadPriority(Priority); +#endif + +#endif // THREAD_H diff --git a/src/librssguard/network-web/adblock/adblockmanager.cpp b/src/librssguard/network-web/adblock/adblockmanager.cpp index dcb49c45a..64955ae55 100644 --- a/src/librssguard/network-web/adblock/adblockmanager.cpp +++ b/src/librssguard/network-web/adblock/adblockmanager.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include #include