// ***************************************************************************** // * This file is part of the FreeFileSync project. It is distributed under * // * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 * // * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved * // ***************************************************************************** #include "process_priority.h" #include //setpriority using namespace zen; namespace { #if 0 //https://linux.die.net/man/2/getpriority //CPU priority from highest to lowest range: [-NZERO, NZERO -1] usually: [-20, 19] enum //with values from CentOS 7 { CPU_PRIO_VERYHIGH = -NZERO, CPU_PRIO_HIGH = -5, CPU_PRIO_NORMAL = 0, CPU_PRIO_LOW = 5, CPU_PRIO_VERYLOW = NZERO - 1, }; int getCpuPriority() //throw SysError { errno = 0; const int prio = getpriority(PRIO_PROCESS, 0 /* = the calling process */); if (prio == -1 && errno != 0) //"can legitimately return the value -1" THROW_LAST_SYS_ERROR("getpriority"); return prio; } //lowering is allowed, but increasing CPU prio requires admin rights >:( void setCpuPriority(int prio) //throw SysError { if (setpriority(PRIO_PROCESS, 0 /* = the calling process */, prio) != 0) THROW_LAST_SYS_ERROR("setpriority(" + numberTo(prio) + ')'); } #endif //--------------------------------------------------------------------------------------------------- //- required functions ioprio_get/ioprio_set are not part of glibc: https://linux.die.net/man/2/ioprio_set //- and probably never will: https://sourceware.org/bugzilla/show_bug.cgi?id=4464 //https://github.com/torvalds/linux/blob/master/include/uapi/linux/ioprio.h #define IOPRIO_CLASS_SHIFT 13 #define IOPRIO_PRIO_VALUE(prioclass, priolevel) \ (((prioclass) << IOPRIO_CLASS_SHIFT) | (priolevel)) #define IOPRIO_NORM 4 enum { IOPRIO_WHO_PROCESS = 1, IOPRIO_WHO_PGRP, IOPRIO_WHO_USER, }; enum { IOPRIO_CLASS_NONE = 0, IOPRIO_CLASS_RT = 1, IOPRIO_CLASS_BE = 2, IOPRIO_CLASS_IDLE = 3, }; int getIoPriority() //throw SysError { const int rv = ::syscall(SYS_ioprio_get, IOPRIO_WHO_PROCESS, ::getpid()); if (rv == -1) THROW_LAST_SYS_ERROR("ioprio_get"); //fix Linux kernel fuck up: bogus system default value if (rv == IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, IOPRIO_NORM)) return IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, IOPRIO_NORM); return rv; } void setIoPriority(int ioPrio) //throw SysError { if (::syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, ::getpid(), ioPrio) != 0) THROW_LAST_SYS_ERROR("ioprio_set(0x" + printNumber("%x", static_cast(ioPrio)) + ')'); } } struct SetProcessPriority::Impl { std::optional oldIoPrio; }; SetProcessPriority::SetProcessPriority(ProcessPriority prio) : //throw FileError pimpl_(new Impl) { if (prio == ProcessPriority::background) try { pimpl_->oldIoPrio = getIoPriority(); //throw SysError setIoPriority(IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 6 /*0 (highest) to 7 (lowest)*/)); //throw SysError //maybe even IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0) ? nope: "only served when no one else is using the disk" } catch (const SysError& e) { throw FileError(_("Cannot change process I/O priorities."), e.toString()); } } SetProcessPriority::~SetProcessPriority() { if (pimpl_->oldIoPrio) try { setIoPriority(*pimpl_->oldIoPrio); //throw SysError } catch (const SysError& e) { logExtraError(_("Cannot change process I/O priorities.") + L"\n\n" + e.toString()); } }