File indexing completed on 2024-04-28 05:31:36

0001 /*
0002     SPDX-FileCopyrightText: 2019 David Edmundson <davidedmundson@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 #include "extended_process_list.h"
0007 
0008 #include <KLocalizedString>
0009 #include <KPluginFactory>
0010 #include <KPluginMetaData>
0011 #include <KUser>
0012 
0013 #include "process.h"
0014 #include "process_attribute.h"
0015 #include "process_data_provider.h"
0016 #include "processcore_debug.h"
0017 
0018 using namespace KSysGuard;
0019 
0020 class Q_DECL_HIDDEN ExtendedProcesses::Private
0021 {
0022 public:
0023     Private(ExtendedProcesses *q);
0024     void loadPlugins();
0025 
0026     ExtendedProcesses *q;
0027     QList<ProcessAttribute *> m_coreAttributes;
0028     QList<ProcessDataProvider *> m_providers;
0029     QHash<K_UID, KUser> m_userCache;
0030 };
0031 
0032 enum GroupPolicy { Accumulate, Average, ForwardFirstEntry };
0033 
0034 template<class T>
0035 class ProcessSensor : public KSysGuard::ProcessAttribute
0036 {
0037 public:
0038     ProcessSensor(ExtendedProcesses *parent,
0039                   const QString &id,
0040                   const QString &name,
0041                   std::function<T(KSysGuard::Process *)> extractFunc,
0042                   KSysGuard::Process::Change changeFlag = KSysGuard::Process::Nothing,
0043                   GroupPolicy groupPolicy = Accumulate)
0044         : KSysGuard::ProcessAttribute(id, name, parent)
0045         , m_extractFunc(extractFunc)
0046         , m_changeFlag(changeFlag)
0047         , m_groupPolicy(groupPolicy)
0048     {
0049         if (m_changeFlag != 0) {
0050             connect(parent, &ExtendedProcesses::processChanged, this, [this](KSysGuard::Process *process) {
0051                 if (!process->changes().testFlag(m_changeFlag)) {
0052                     return;
0053                 }
0054                 Q_EMIT dataChanged(process);
0055             });
0056         }
0057     }
0058 
0059     QVariant data(KSysGuard::Process *process) const override
0060     {
0061         return QVariant::fromValue(m_extractFunc(process));
0062     }
0063 
0064     QVariant cgroupData(KSysGuard::CGroup *cgroup, const QList<KSysGuard::Process *> &groupProcesses) const override
0065     {
0066         switch (m_groupPolicy) {
0067         case Accumulate:
0068             return ProcessAttribute::cgroupData(cgroup, groupProcesses);
0069         case Average:
0070             return ProcessAttribute::cgroupData(cgroup, groupProcesses).toDouble() / groupProcesses.size();
0071         case ForwardFirstEntry:
0072             return groupProcesses.isEmpty() ? QVariant() : data(groupProcesses.first());
0073         }
0074         Q_UNREACHABLE();
0075     }
0076 
0077 private:
0078     std::function<T(KSysGuard::Process *)> m_extractFunc;
0079     KSysGuard::Process::Change m_changeFlag;
0080     GroupPolicy m_groupPolicy = Accumulate;
0081 };
0082 
0083 ExtendedProcesses::Private::Private(ExtendedProcesses *_q)
0084     : q(_q)
0085 {
0086 }
0087 
0088 ExtendedProcesses::ExtendedProcesses(QObject *parent)
0089     : Processes(QString(), parent)
0090     , d(new Private(this))
0091 {
0092     d->loadPlugins();
0093 
0094     auto pidSensor =
0095         new ProcessSensor<qlonglong>(this, QStringLiteral("pid"), i18n("PID"), &KSysGuard::Process::pid, KSysGuard::Process::Status, ForwardFirstEntry);
0096     pidSensor->setDescription(i18n("The unique Process ID that identifies this process."));
0097     d->m_coreAttributes << pidSensor;
0098 
0099     auto parentPidSensor = new ProcessSensor<qlonglong>(this,
0100                                                         QStringLiteral("parentPid"),
0101                                                         i18n("Parent PID"),
0102                                                         &KSysGuard::Process::parentPid,
0103                                                         Process::Nothing,
0104                                                         ForwardFirstEntry);
0105     d->m_coreAttributes << parentPidSensor;
0106 
0107     auto loginSensor =
0108         new ProcessSensor<QString>(this, QStringLiteral("login"), i18n("Login"), &KSysGuard::Process::login, KSysGuard::Process::Login, ForwardFirstEntry);
0109     loginSensor->setDescription(i18n("The user who owns this process."));
0110     d->m_coreAttributes << loginSensor;
0111 
0112     auto uidSensor =
0113         new ProcessSensor<qlonglong>(this, QStringLiteral("uid"), i18n("UID"), &KSysGuard::Process::uid, KSysGuard::Process::Uids, ForwardFirstEntry);
0114     d->m_coreAttributes << uidSensor;
0115 
0116     auto userNameSensor = new ProcessSensor<QString>(
0117         this,
0118         QStringLiteral("username"),
0119         i18n("Username"),
0120         [this](KSysGuard::Process *p) {
0121             const K_UID uid = p->uid();
0122             auto userIt = d->m_userCache.find(uid);
0123             if (userIt == d->m_userCache.end()) {
0124                 userIt = d->m_userCache.insert(uid, KUser(uid));
0125             }
0126             return userIt->loginName();
0127         },
0128         KSysGuard::Process::Uids,
0129         ForwardFirstEntry);
0130     d->m_coreAttributes << userNameSensor;
0131 
0132     auto canUserLoginSensor = new ProcessSensor<bool>(
0133         this,
0134         QStringLiteral("canUserLogin"),
0135         i18n("Can Login"),
0136         [this](KSysGuard::Process *p) {
0137             const K_UID uid = p->uid();
0138             if (uid == 65534) { // special value meaning nobody
0139                 return false;
0140             }
0141             auto userIt = d->m_userCache.find(uid);
0142             if (userIt == d->m_userCache.end()) {
0143                 userIt = d->m_userCache.insert(uid, KUser(uid));
0144             }
0145 
0146             if (!userIt->isValid()) {
0147                 // For some reason the user isn't recognised.  This might happen under certain security situations.
0148                 // Just return true to be safe
0149                 return true;
0150             }
0151             const QString shell = userIt->shell();
0152             if (shell == QLatin1String("/bin/false")) { // FIXME - add in any other shells it could be for false
0153                 return false;
0154             }
0155             return true;
0156         },
0157         KSysGuard::Process::Uids,
0158         ForwardFirstEntry);
0159     d->m_coreAttributes << canUserLoginSensor;
0160 
0161     auto euidSensor =
0162         new ProcessSensor<qlonglong>(this, QStringLiteral("euid"), i18n("EUID"), &KSysGuard::Process::euid, KSysGuard::Process::Uids, ForwardFirstEntry);
0163     d->m_coreAttributes << euidSensor;
0164 
0165     auto suidSensor =
0166         new ProcessSensor<qlonglong>(this, QStringLiteral("suid"), i18n("suid"), &KSysGuard::Process::suid, KSysGuard::Process::Uids, ForwardFirstEntry);
0167     d->m_coreAttributes << suidSensor;
0168 
0169     auto fsuidSensor =
0170         new ProcessSensor<qlonglong>(this, QStringLiteral("fsuid"), i18n("fsuid"), &KSysGuard::Process::fsuid, KSysGuard::Process::Uids, ForwardFirstEntry);
0171     d->m_coreAttributes << fsuidSensor;
0172 
0173     auto gidSensor =
0174         new ProcessSensor<qlonglong>(this, QStringLiteral("gid"), i18n("gid"), &KSysGuard::Process::gid, KSysGuard::Process::Gids, ForwardFirstEntry);
0175     d->m_coreAttributes << gidSensor;
0176 
0177     auto egidSensor =
0178         new ProcessSensor<qlonglong>(this, QStringLiteral("egid"), i18n("egid"), &KSysGuard::Process::egid, KSysGuard::Process::Gids, ForwardFirstEntry);
0179     d->m_coreAttributes << egidSensor;
0180 
0181     auto sgidSensor =
0182         new ProcessSensor<qlonglong>(this, QStringLiteral("sgid"), i18n("sgid"), &KSysGuard::Process::sgid, KSysGuard::Process::Gids, ForwardFirstEntry);
0183     d->m_coreAttributes << sgidSensor;
0184 
0185     auto fsgidSensor =
0186         new ProcessSensor<qlonglong>(this, QStringLiteral("fsgid"), i18n("fsgid"), &KSysGuard::Process::fsgid, KSysGuard::Process::Gids, ForwardFirstEntry);
0187     d->m_coreAttributes << fsgidSensor;
0188 
0189     auto tracerpidSensor = new ProcessSensor<qlonglong>(this,
0190                                                         QStringLiteral("tracerpid"),
0191                                                         i18n("Tracer Pid"),
0192                                                         &KSysGuard::Process::tracerpid,
0193                                                         Process::Nothing,
0194                                                         ForwardFirstEntry);
0195     d->m_coreAttributes << tracerpidSensor;
0196 
0197     auto ttySensor =
0198         new ProcessSensor<QByteArray>(this, QStringLiteral("tty"), i18n("tty"), &KSysGuard::Process::tty, KSysGuard::Process::Tty, ForwardFirstEntry);
0199     ttySensor->setDescription(i18n("The controlling terminal on which this process is running."));
0200     d->m_coreAttributes << ttySensor;
0201 
0202     auto userTimeSensor = new ProcessSensor<qlonglong>(this, QStringLiteral("userTime"), i18n("User Time"), &KSysGuard::Process::userTime);
0203     userTimeSensor->setUnit(KSysGuard::UnitTicks);
0204     d->m_coreAttributes << userTimeSensor;
0205 
0206     auto sysTimeSensor = new ProcessSensor<qlonglong>(this, QStringLiteral("sysTime"), i18n("System Time"), &KSysGuard::Process::sysTime);
0207     sysTimeSensor->setUnit(KSysGuard::UnitTicks);
0208     d->m_coreAttributes << sysTimeSensor;
0209 
0210     auto timeSensor = new ProcessSensor<qlonglong>(this, QStringLiteral("totalTime"), i18n("Total Time"), [](KSysGuard::Process *p) {
0211         return p->userTime() + p->sysTime();
0212     });
0213     timeSensor->setShortName(i18n("Time"));
0214     timeSensor->setUnit(KSysGuard::UnitTicks);
0215     timeSensor->setDescription(i18n("The total user and system time that this process has been running for"));
0216     d->m_coreAttributes << timeSensor;
0217 
0218     auto startTimeSensor = new ProcessSensor<qlonglong>(this,
0219                                                         QStringLiteral("startTime"),
0220                                                         i18n("Start Time"),
0221                                                         &KSysGuard::Process::startTime,
0222                                                         Process::Nothing,
0223                                                         ForwardFirstEntry); // Is this correct for apps?
0224     startTimeSensor->setUnit(KSysGuard::UnitBootTimestamp);
0225     d->m_coreAttributes << startTimeSensor;
0226 
0227     const int maximumCpuPercent = 100 * numberProcessorCores();
0228 
0229     auto userUsageSensor =
0230         new ProcessSensor<int>(this, QStringLiteral("userUsage"), i18n("User CPU Usage"), &KSysGuard::Process::userUsage, KSysGuard::Process::Usage);
0231     userUsageSensor->setShortName(i18n("User CPU"));
0232     userUsageSensor->setMin(0);
0233     userUsageSensor->setMax(maximumCpuPercent);
0234     userUsageSensor->setUnit(KSysGuard::UnitPercent);
0235     d->m_coreAttributes << userUsageSensor;
0236 
0237     auto sysUsageSensor =
0238         new ProcessSensor<int>(this, QStringLiteral("sysUsage"), i18n("System CPU Usage"), &KSysGuard::Process::sysUsage, KSysGuard::Process::Usage);
0239     sysUsageSensor->setShortName(i18n("System CPU"));
0240     sysUsageSensor->setMin(0);
0241     sysUsageSensor->setMax(maximumCpuPercent);
0242     sysUsageSensor->setUnit(KSysGuard::UnitPercent);
0243     d->m_coreAttributes << sysUsageSensor;
0244 
0245     auto usageSensor = new ProcessSensor<int>(
0246         this,
0247         QStringLiteral("usage"),
0248         i18n("Total CPU Usage"),
0249         [](KSysGuard::Process *p) {
0250             return p->userUsage() + p->sysUsage();
0251         },
0252         KSysGuard::Process::Usage,
0253         Accumulate);
0254     usageSensor->setShortName(i18n("CPU"));
0255     usageSensor->setMin(0);
0256     usageSensor->setMax(maximumCpuPercent);
0257     usageSensor->setUnit(KSysGuard::UnitPercent);
0258     usageSensor->setDescription(i18n("The current total CPU usage of the process."));
0259     d->m_coreAttributes << usageSensor;
0260 
0261     auto totalUserUsageSensor = new ProcessSensor<int>(this,
0262                                                        QStringLiteral("totalUserUsage"),
0263                                                        i18n("Group User CPU Usage"),
0264                                                        &KSysGuard::Process::totalUserUsage,
0265                                                        KSysGuard::Process::TotalUsage,
0266                                                        Average);
0267     totalUserUsageSensor->setDescription(i18n("The amount of userspace CPU used by this process and all its children."));
0268     totalUserUsageSensor->setMin(0);
0269     totalUserUsageSensor->setMax(maximumCpuPercent);
0270     totalUserUsageSensor->setUnit(KSysGuard::UnitPercent);
0271     d->m_coreAttributes << totalUserUsageSensor;
0272 
0273     auto totalSysUsageSensor = new ProcessSensor<int>(this,
0274                                                       QStringLiteral("totalSysUsage"),
0275                                                       i18n("Group System CPU Usage"),
0276                                                       &KSysGuard::Process::totalSysUsage,
0277                                                       KSysGuard::Process::TotalUsage,
0278                                                       Average);
0279     totalUserUsageSensor->setDescription(i18n("The amount of system CPU used by this process and all its children."));
0280     totalSysUsageSensor->setMin(0);
0281     totalSysUsageSensor->setMax(maximumCpuPercent);
0282     totalSysUsageSensor->setUnit(KSysGuard::UnitPercent);
0283     d->m_coreAttributes << totalSysUsageSensor;
0284 
0285     auto totalUsageSensor = new ProcessSensor<int>(
0286         this,
0287         QStringLiteral("totalUsage"),
0288         i18n("Group Total CPU Usage"),
0289         [](KSysGuard::Process *p) {
0290             return p->totalUserUsage() + p->totalSysUsage();
0291         },
0292         KSysGuard::Process::TotalUsage,
0293         Average);
0294     totalUsageSensor->setShortName(i18n("Group CPU"));
0295     totalUserUsageSensor->setDescription(i18n("The total amount of CPU used by this process and all its children."));
0296     totalUsageSensor->setMin(0);
0297     totalUsageSensor->setMax(maximumCpuPercent);
0298     totalUsageSensor->setUnit(KSysGuard::UnitPercent);
0299     d->m_coreAttributes << totalUsageSensor;
0300 
0301     auto niceLevelSensor =
0302         new ProcessSensor<int>(this, QStringLiteral("niceLevel"), i18n("Nice Level"), &KSysGuard::Process::niceLevel, KSysGuard::Process::NiceLevels);
0303     niceLevelSensor->setDescription(i18n(
0304         "The priority with which this process is being run. For the normal scheduler, this ranges from 19 (very nice, least priority) to -19 (top priority)."));
0305     d->m_coreAttributes << niceLevelSensor;
0306 
0307     auto schedulerSensor =
0308         new ProcessSensor<uint>(this, QStringLiteral("scheduler"), i18n("Scheduler"), &KSysGuard::Process::scheduler, KSysGuard::Process::NiceLevels);
0309     d->m_coreAttributes << schedulerSensor;
0310 
0311     auto ioPriorityClassSensor = new ProcessSensor<uint>(this,
0312                                                          QStringLiteral("ioPriorityClass"),
0313                                                          i18n("IO Priority Class"),
0314                                                          &KSysGuard::Process::ioPriorityClass,
0315                                                          KSysGuard::Process::NiceLevels);
0316     d->m_coreAttributes << ioPriorityClassSensor;
0317 
0318     auto ioniceLevelSensor =
0319         new ProcessSensor<int>(this, QStringLiteral("ioniceLevel"), i18n("IO Nice Level"), &KSysGuard::Process::ioniceLevel, KSysGuard::Process::NiceLevels);
0320     ioniceLevelSensor->setUnit(KSysGuard::UnitNone);
0321     d->m_coreAttributes << ioniceLevelSensor;
0322 
0323     auto vmSizeSensor = new ProcessSensor<qlonglong>(this, QStringLiteral("vmSize"), i18n("VM Size"), &KSysGuard::Process::vmSize, KSysGuard::Process::VmSize);
0324     vmSizeSensor->setUnit(KSysGuard::UnitKiloByte);
0325     vmSizeSensor->setMin(0);
0326     vmSizeSensor->setMax(totalPhysicalMemory());
0327     vmSizeSensor->setDescription(
0328         i18n("This is the amount of virtual memory space that the process is using, included shared libraries, graphics memory, files on disk, and so on. This "
0329              "number is almost meaningless."));
0330     d->m_coreAttributes << vmSizeSensor;
0331 
0332     auto vmRSSSensor =
0333         new ProcessSensor<qlonglong>(this, QStringLiteral("vmRSS"), i18n("RSS Memory Usage"), &KSysGuard::Process::vmRSS, KSysGuard::Process::VmRSS);
0334     vmRSSSensor->setUnit(KSysGuard::UnitKiloByte);
0335     vmRSSSensor->setMin(0);
0336     vmRSSSensor->setMax(totalPhysicalMemory());
0337     vmRSSSensor->setDescription(
0338         i18n("This is the amount of physical memory that this process is using and includes the amount of memory used by shared libraries."));
0339 
0340     auto vmURSSSensor =
0341         new ProcessSensor<qlonglong>(this, QStringLiteral("vmURSS"), i18n("Private Memory Usage"), &KSysGuard::Process::vmURSS, KSysGuard::Process::VmURSS);
0342     vmURSSSensor->setUnit(KSysGuard::UnitKiloByte);
0343     vmURSSSensor->setShortName(i18n("Private"));
0344     vmURSSSensor->setMin(0);
0345     vmURSSSensor->setMax(totalPhysicalMemory());
0346     vmURSSSensor->setDescription(
0347         i18n("This is the amount of physical memory that this process is using by itself, and approximates the Private memory usage of the process. It does "
0348              "not include any swapped out memory, nor the code size of its shared libraries."));
0349     d->m_coreAttributes << vmURSSSensor;
0350 
0351     auto sharedMemorySensor = new ProcessSensor<qlonglong>(
0352         this,
0353         QStringLiteral("vmShared"),
0354         i18n("Shared Memory Usage"),
0355         [](KSysGuard::Process *p) -> qlonglong {
0356             if (p->vmRSS() - p->vmURSS() < 0 || p->vmURSS() == -1) {
0357                 return 0;
0358             }
0359             return (qlonglong)(p->vmRSS() - p->vmURSS());
0360         },
0361         KSysGuard::Process::VmRSS);
0362     d->m_coreAttributes << sharedMemorySensor;
0363     sharedMemorySensor->setShortName(i18n("Shared"));
0364     sharedMemorySensor->setDescription(
0365         i18n("This is approximately the amount of real physical memory that this process's shared libraries are using. This memory is shared among all "
0366              "processes that use this library."));
0367     sharedMemorySensor->setUnit(KSysGuard::UnitKiloByte);
0368     sharedMemorySensor->setMin(0);
0369     sharedMemorySensor->setMax(totalPhysicalMemory());
0370 
0371     auto vmPSSSensor = new ProcessSensor<qlonglong>(this, QStringLiteral("vmPSS"), i18n("Memory Usage"), &KSysGuard::Process::vmPSS, KSysGuard::Process::VmPSS);
0372     vmPSSSensor->setShortName(i18n("Memory"));
0373     vmPSSSensor->setUnit(KSysGuard::UnitKiloByte);
0374     vmPSSSensor->setMin(0);
0375     vmPSSSensor->setMax(totalPhysicalMemory());
0376     vmPSSSensor->setRequiredUpdateFlags(Processes::Smaps);
0377     vmPSSSensor->setDescription(
0378         i18n("This is an approximation of the real amount of physical memory that this process is using. It is calculated by dividing the process' shared "
0379              "memory usage by the amount of processes sharing that memory, then adding the process' private memory."));
0380     d->m_coreAttributes << vmPSSSensor;
0381 
0382     auto nameSensor =
0383         new ProcessSensor<QString>(this, QStringLiteral("name"), i18n("Name"), &KSysGuard::Process::name, KSysGuard::Process::Name, ForwardFirstEntry);
0384     nameSensor->setDescription(i18n("The process name."));
0385     d->m_coreAttributes << nameSensor;
0386 
0387     auto commandSensor = new ProcessSensor<QString>(this,
0388                                                     QStringLiteral("command"),
0389                                                     i18n("Command"),
0390                                                     &KSysGuard::Process::command,
0391                                                     KSysGuard::Process::Command,
0392                                                     ForwardFirstEntry);
0393     commandSensor->setDescription(i18n("The command with which this process was launched."));
0394     d->m_coreAttributes << commandSensor;
0395 
0396     auto statusSensor =
0397         new ProcessSensor<QString>(this, QStringLiteral("status"), i18n("Status"), &KSysGuard::Process::translatedStatus, KSysGuard::Process::Status);
0398     d->m_coreAttributes << statusSensor;
0399 
0400     auto ioCharactersReadSensor = new ProcessSensor<qlonglong>(this,
0401                                                                QStringLiteral("ioCharactersRead"),
0402                                                                i18n("IO Characters Read"),
0403                                                                &KSysGuard::Process::ioCharactersRead,
0404                                                                KSysGuard::Process::IO);
0405     ioCharactersReadSensor->setUnit(KSysGuard::UnitByte);
0406     ioCharactersReadSensor->setRequiredUpdateFlags(Processes::IOStatistics);
0407     d->m_coreAttributes << ioCharactersReadSensor;
0408 
0409     auto ioCharactersWrittenSensor = new ProcessSensor<qlonglong>(this,
0410                                                                   QStringLiteral("ioCharactersWritten"),
0411                                                                   i18n("IO Characters Written"),
0412                                                                   &KSysGuard::Process::ioCharactersWritten,
0413                                                                   KSysGuard::Process::IO);
0414     ioCharactersWrittenSensor->setUnit(KSysGuard::UnitByte);
0415     ioCharactersWrittenSensor->setRequiredUpdateFlags(Processes::IOStatistics);
0416     d->m_coreAttributes << ioCharactersWrittenSensor;
0417 
0418     auto ioReadSyscallsSensor = new ProcessSensor<qlonglong>(this,
0419                                                              QStringLiteral("ioReadSyscalls"),
0420                                                              i18n("IO Read Syscalls"),
0421                                                              &KSysGuard::Process::ioReadSyscalls,
0422                                                              KSysGuard::Process::IO);
0423     ioReadSyscallsSensor->setUnit(KSysGuard::UnitRate);
0424     ioReadSyscallsSensor->setRequiredUpdateFlags(Processes::IOStatistics);
0425     d->m_coreAttributes << ioReadSyscallsSensor;
0426 
0427     auto ioReadSyscallsRateSensor = new ProcessSensor<qlonglong>(this,
0428                                                                  QStringLiteral("ioReadSyscallsRate"),
0429                                                                  i18n("IO Read Syscalls Rate"),
0430                                                                  &KSysGuard::Process::ioReadSyscallsRate,
0431                                                                  KSysGuard::Process::IO);
0432     ioReadSyscallsRateSensor->setUnit(KSysGuard::UnitRate);
0433     ioReadSyscallsRateSensor->setRequiredUpdateFlags(Processes::IOStatistics);
0434     d->m_coreAttributes << ioReadSyscallsSensor;
0435 
0436     auto ioWriteSyscallsSensor = new ProcessSensor<qlonglong>(this,
0437                                                               QStringLiteral("ioWriteSyscalls"),
0438                                                               i18n("IO Write Syscalls"),
0439                                                               &KSysGuard::Process::ioWriteSyscalls,
0440                                                               KSysGuard::Process::IO);
0441     ioWriteSyscallsSensor->setUnit(KSysGuard::UnitRate);
0442     ioWriteSyscallsSensor->setRequiredUpdateFlags(Processes::IOStatistics);
0443     d->m_coreAttributes << ioWriteSyscallsSensor;
0444 
0445     auto ioWriteSyscallsRateSensor = new ProcessSensor<qlonglong>(this,
0446                                                                   QStringLiteral("ioReadSyscallsRate"),
0447                                                                   i18n("IO Write Syscalls Rate"),
0448                                                                   &KSysGuard::Process::ioWriteSyscallsRate,
0449                                                                   KSysGuard::Process::IO);
0450     ioWriteSyscallsRateSensor->setUnit(KSysGuard::UnitRate);
0451     ioWriteSyscallsRateSensor->setRequiredUpdateFlags(Processes::IOStatistics);
0452     d->m_coreAttributes << ioWriteSyscallsRateSensor;
0453 
0454     auto ioCharactersActuallyReadSensor = new ProcessSensor<qlonglong>(this,
0455                                                                        QStringLiteral("ioCharactersActuallyRead"),
0456                                                                        i18n("IO Characters Actually Read"),
0457                                                                        &KSysGuard::Process::ioCharactersActuallyRead,
0458                                                                        KSysGuard::Process::IO);
0459     ioCharactersActuallyReadSensor->setUnit(KSysGuard::UnitByte);
0460     ioCharactersActuallyReadSensor->setRequiredUpdateFlags(Processes::IOStatistics);
0461     d->m_coreAttributes << ioCharactersActuallyReadSensor;
0462 
0463     auto ioCharactersReadRateSensor = new ProcessSensor<qlonglong>(this,
0464                                                                    QStringLiteral("ioCharactersReadRate"),
0465                                                                    i18n("IO Characters Read Rate"),
0466                                                                    &KSysGuard::Process::ioCharactersReadRate,
0467                                                                    KSysGuard::Process::IO);
0468     ioCharactersReadRateSensor->setDescription(i18n("The read rate for all of a process' IO, including disk cache and other nonphysical IO."));
0469     ioCharactersReadRateSensor->setUnit(KSysGuard::UnitByteRate);
0470     ioCharactersReadRateSensor->setRequiredUpdateFlags(Processes::IOStatistics);
0471     d->m_coreAttributes << ioCharactersReadRateSensor;
0472 
0473     auto ioCharactersWrittenRateSensor = new ProcessSensor<qlonglong>(this,
0474                                                                       QStringLiteral("ioCharactersWrittenRate"),
0475                                                                       i18n("IO Characters Written Rate"),
0476                                                                       &KSysGuard::Process::ioCharactersWrittenRate,
0477                                                                       KSysGuard::Process::IO);
0478     ioCharactersWrittenRateSensor->setDescription(i18n("The write rate for all of a process' IO, including disk cache and other nonphysical IO."));
0479     ioCharactersWrittenRateSensor->setUnit(KSysGuard::UnitByteRate);
0480     ioCharactersWrittenRateSensor->setRequiredUpdateFlags(Processes::IOStatistics);
0481     d->m_coreAttributes << ioCharactersWrittenRateSensor;
0482 
0483     auto ioCharactersActuallyReadRateSensor = new ProcessSensor<qlonglong>(this,
0484                                                                            QStringLiteral("ioCharactersActuallyReadRate"),
0485                                                                            i18n("Disk Read Rate"),
0486                                                                            &KSysGuard::Process::ioCharactersActuallyReadRate,
0487                                                                            KSysGuard::Process::IO);
0488     ioCharactersActuallyReadRateSensor->setUnit(KSysGuard::UnitByteRate);
0489     ioCharactersActuallyReadRateSensor->setShortName(i18n("Read"));
0490     ioCharactersActuallyReadRateSensor->setDescription(i18n("The rate of data being read from disk."));
0491     ioCharactersActuallyReadRateSensor->setRequiredUpdateFlags(Processes::IOStatistics);
0492     d->m_coreAttributes << ioCharactersActuallyReadRateSensor;
0493 
0494     auto ioCharactersActuallyWrittenRateSensor = new ProcessSensor<qlonglong>(this,
0495                                                                               QStringLiteral("ioCharactersActuallyWrittenRate"),
0496                                                                               i18n("Disk Write Rate"),
0497                                                                               &KSysGuard::Process::ioCharactersActuallyWrittenRate,
0498                                                                               KSysGuard::Process::IO);
0499     ioCharactersActuallyWrittenRateSensor->setUnit(KSysGuard::UnitByteRate);
0500     ioCharactersActuallyWrittenRateSensor->setShortName(i18n("Write"));
0501     ioCharactersActuallyWrittenRateSensor->setDescription(i18n("The rate of data being written to the disk."));
0502     ioCharactersActuallyWrittenRateSensor->setRequiredUpdateFlags(Processes::IOStatistics);
0503     d->m_coreAttributes << ioCharactersActuallyWrittenRateSensor;
0504 
0505     auto numThreadsSensor = new ProcessSensor<int>(this,
0506                                                    QStringLiteral("numThreads"),
0507                                                    i18n("Threads"),
0508                                                    &KSysGuard::Process::numThreads,
0509                                                    KSysGuard::Process::NumThreads,
0510                                                    ForwardFirstEntry);
0511     d->m_coreAttributes << numThreadsSensor;
0512 
0513     connect(this, &KSysGuard::Processes::beginRemoveProcess, this, [this](KSysGuard::Process *process) {
0514         const auto attrs = attributes();
0515         for (auto a : attrs) {
0516             a->clearData(process);
0517         }
0518     });
0519 
0520     connect(this, &KSysGuard::Processes::updated, this, [this]() {
0521         for (auto p : std::as_const(d->m_providers)) {
0522             if (p->enabled()) {
0523                 p->update();
0524             }
0525         }
0526     });
0527 }
0528 
0529 ExtendedProcesses::~ExtendedProcesses()
0530 {
0531 }
0532 
0533 QList<ProcessAttribute *> ExtendedProcesses::attributes() const
0534 {
0535     return d->m_coreAttributes + extendedAttributes();
0536 }
0537 
0538 QList<ProcessAttribute *> ExtendedProcesses::extendedAttributes() const
0539 {
0540     QList<ProcessAttribute *> rc;
0541     for (auto p : std::as_const(d->m_providers)) {
0542         rc << p->attributes();
0543     }
0544     return rc;
0545 }
0546 
0547 void ExtendedProcesses::Private::loadPlugins()
0548 {
0549     const QList<KPluginMetaData> listMetaData = KPluginMetaData::findPlugins(QStringLiteral("ksysguard/process"));
0550     // instantiate all plugins
0551     for (const auto &pluginMetaData : listMetaData) {
0552         qCDebug(LIBKSYSGUARD_PROCESSCORE) << "loading plugin" << pluginMetaData.name();
0553         auto provider = KPluginFactory::instantiatePlugin<ProcessDataProvider>(pluginMetaData, q);
0554         if (!provider.plugin) {
0555             qCCritical(LIBKSYSGUARD_PROCESSCORE) << "failed to instantiate ProcessDataProvider" << pluginMetaData.name();
0556             continue;
0557         }
0558         m_providers << provider.plugin;
0559     }
0560 }
0561 
0562 QSharedPointer<ExtendedProcesses> ExtendedProcesses::instance()
0563 {
0564     static QWeakPointer<ExtendedProcesses> instance;
0565     auto processes = instance.lock();
0566     if (!processes) {
0567         processes = QSharedPointer<ExtendedProcesses>(new ExtendedProcesses, [](ExtendedProcesses *p) {
0568             delete p;
0569         });
0570         instance = processes;
0571     }
0572     return processes;
0573 }