diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index c4fd93720..cd0b87246 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -35,6 +35,7 @@ #include #ifdef Q_OS_WIN +#include #include #include #endif @@ -344,6 +345,9 @@ Session::Session(QObject *parent) return tmp; } ) +#if defined(Q_OS_WIN) + , m_OSMemoryPriority(BITTORRENT_KEY("OSMemoryPriority"), OSMemoryPriority::BelowNormal) +#endif , m_resumeFolderLock {new QFile {this}} , m_refreshTimer {new QTimer {this}} , m_seedingLimitTimer {new QTimer {this}} @@ -930,6 +934,10 @@ void Session::configureComponents() disableIPFilter(); m_IPFilteringConfigured = true; } + +#if defined(Q_OS_WIN) + applyOSMemoryPriority(); +#endif } void Session::initializeNativeSession() @@ -2753,6 +2761,59 @@ QStringList Session::bannedIPs() const return m_bannedIPs; } +#if defined(Q_OS_WIN) +OSMemoryPriority Session::getOSMemoryPriority() const +{ + return m_OSMemoryPriority; +} + +void Session::setOSMemoryPriority(const OSMemoryPriority priority) +{ + if (m_OSMemoryPriority == priority) + return; + + m_OSMemoryPriority = priority; + configureDeferred(); +} + +void Session::applyOSMemoryPriority() const +{ + using SETPROCESSINFORMATION = BOOL (WINAPI *)(HANDLE, PROCESS_INFORMATION_CLASS, LPVOID, DWORD); + const auto setProcessInformation = Utils::Misc::loadWinAPI("Kernel32.dll", "SetProcessInformation"); + if (!setProcessInformation) // only available on Windows >= 8 + return; + +#if (_WIN32_WINNT < _WIN32_WINNT_WIN8) + // this dummy struct is required to compile successfully when targeting older Windows version + struct MEMORY_PRIORITY_INFORMATION + { + ULONG MemoryPriority; + }; +#endif + + MEMORY_PRIORITY_INFORMATION prioInfo {}; + switch (getOSMemoryPriority()) { + case OSMemoryPriority::Normal: + default: + prioInfo.MemoryPriority = MEMORY_PRIORITY_NORMAL; + break; + case OSMemoryPriority::BelowNormal: + prioInfo.MemoryPriority = MEMORY_PRIORITY_BELOW_NORMAL; + break; + case OSMemoryPriority::Medium: + prioInfo.MemoryPriority = MEMORY_PRIORITY_MEDIUM; + break; + case OSMemoryPriority::Low: + prioInfo.MemoryPriority = MEMORY_PRIORITY_LOW; + break; + case OSMemoryPriority::VeryLow: + prioInfo.MemoryPriority = MEMORY_PRIORITY_VERY_LOW; + break; + } + setProcessInformation(::GetCurrentProcess(), ProcessMemoryPriority, &prioInfo, sizeof(prioInfo)); +} +#endif + int Session::maxConnectionsPerTorrent() const { return m_maxConnectionsPerTorrent; diff --git a/src/base/bittorrent/session.h b/src/base/bittorrent/session.h index 8b6571666..80586a954 100644 --- a/src/base/bittorrent/session.h +++ b/src/base/bittorrent/session.h @@ -132,6 +132,18 @@ namespace BitTorrent AntiLeech = 2 }; Q_ENUM_NS(SeedChokingAlgorithm) + +#if defined(Q_OS_WIN) + enum class OSMemoryPriority : int + { + Normal = 0, + BelowNormal = 1, + Medium = 2, + Low = 3, + VeryLow = 4 + }; + Q_ENUM_NS(OSMemoryPriority) +#endif } using namespace SessionSettingsEnums; @@ -387,6 +399,10 @@ namespace BitTorrent void setTrackerFilteringEnabled(bool enabled); QStringList bannedIPs() const; void setBannedIPs(const QStringList &newList); +#if defined(Q_OS_WIN) + OSMemoryPriority getOSMemoryPriority() const; + void setOSMemoryPriority(OSMemoryPriority priority); +#endif void startUpTorrents(); TorrentHandle *findTorrent(const InfoHash &hash) const; @@ -530,6 +546,9 @@ namespace BitTorrent void populateAdditionalTrackers(); void enableIPFilter(); void disableIPFilter(); +#if defined(Q_OS_WIN) + void applyOSMemoryPriority() const; +#endif bool addTorrent_impl(CreateTorrentParams params, const MagnetUri &magnetUri, TorrentInfo torrentInfo = TorrentInfo(), @@ -661,6 +680,9 @@ namespace BitTorrent CachedSettingValue m_isDisableAutoTMMWhenCategorySavePathChanged; CachedSettingValue m_isTrackerEnabled; CachedSettingValue m_bannedIPs; +#if defined(Q_OS_WIN) + CachedSettingValue m_OSMemoryPriority; +#endif // Order is important. This needs to be declared after its CachedSettingsValue // counterpart, because it uses it for initialization in the constructor diff --git a/src/gui/advancedsettings.cpp b/src/gui/advancedsettings.cpp index d4d69d52d..b36a7360f 100644 --- a/src/gui/advancedsettings.cpp +++ b/src/gui/advancedsettings.cpp @@ -61,6 +61,9 @@ enum AdvSettingsRows { // qBittorrent section QBITTORRENT_HEADER, +#if defined(Q_OS_WIN) + OS_MEMORY_PRIORITY, +#endif // network interface NETWORK_IFACE, //Optional network address @@ -151,6 +154,28 @@ void AdvancedSettings::saveAdvancedSettings() Preferences *const pref = Preferences::instance(); BitTorrent::Session *const session = BitTorrent::Session::instance(); +#if defined(Q_OS_WIN) + BitTorrent::OSMemoryPriority prio = BitTorrent::OSMemoryPriority::Normal; + switch (m_comboBoxOSMemoryPriority.currentIndex()) { + case 0: + default: + prio = BitTorrent::OSMemoryPriority::Normal; + break; + case 1: + prio = BitTorrent::OSMemoryPriority::BelowNormal; + break; + case 2: + prio = BitTorrent::OSMemoryPriority::Medium; + break; + case 3: + prio = BitTorrent::OSMemoryPriority::Low; + break; + case 4: + prio = BitTorrent::OSMemoryPriority::VeryLow; + break; + } + session->setOSMemoryPriority(prio); +#endif // Async IO threads session->setAsyncIOThreads(m_spinBoxAsyncIOThreads.value()); // File pool size @@ -321,6 +346,33 @@ void AdvancedSettings::loadAdvancedSettings() addRow(LIBTORRENT_HEADER, QString("%1").arg(tr("libtorrent Section")), labelLibtorrentLink); static_cast(cellWidget(LIBTORRENT_HEADER, PROPERTY))->setAlignment(Qt::AlignCenter | Qt::AlignVCenter); +#if defined(Q_OS_WIN) + m_comboBoxOSMemoryPriority.addItems({tr("Normal"), tr("Below normal"), tr("Medium"), tr("Low"), tr("Very low")}); + int OSMemoryPriorityIndex = 0; + switch (session->getOSMemoryPriority()) { + default: + case BitTorrent::OSMemoryPriority::Normal: + OSMemoryPriorityIndex = 0; + break; + case BitTorrent::OSMemoryPriority::BelowNormal: + OSMemoryPriorityIndex = 1; + break; + case BitTorrent::OSMemoryPriority::Medium: + OSMemoryPriorityIndex = 2; + break; + case BitTorrent::OSMemoryPriority::Low: + OSMemoryPriorityIndex = 3; + break; + case BitTorrent::OSMemoryPriority::VeryLow: + OSMemoryPriorityIndex = 4; + break; + } + m_comboBoxOSMemoryPriority.setCurrentIndex(OSMemoryPriorityIndex); + addRow(OS_MEMORY_PRIORITY, (tr("Process memory priority (Windows >= 8 only)") + + ' ' + makeLink("https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-memory_priority_information", "(?)")) + , &m_comboBoxOSMemoryPriority); +#endif + // Async IO threads m_spinBoxAsyncIOThreads.setMinimum(1); m_spinBoxAsyncIOThreads.setMaximum(1024); diff --git a/src/gui/advancedsettings.h b/src/gui/advancedsettings.h index 0a782a931..502b56320 100644 --- a/src/gui/advancedsettings.h +++ b/src/gui/advancedsettings.h @@ -71,6 +71,8 @@ private: // OS dependent settings #if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)) QCheckBox m_checkBoxUseIconTheme; +#elif defined(Q_OS_WIN) + QComboBox m_comboBoxOSMemoryPriority; #endif };