1 /*
2     SPDX-FileCopyrightText: 2007 John Tapsell <tapsell@kde.org>
3 
4     SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #ifndef PROCESSES_H_
8 #define PROCESSES_H_
9 
10 #include "process.h"
11 #include <QHash>
12 #include <QObject>
13 #include <QVariant>
14 
15 namespace KSysGuard
16 {
17 /**
18  * This class retrieves the processes currently running in an OS independent way.
19  *
20  * To use, do something like:
21  *
22  * \code
23  *   #include "processes.h>
24  *   #include "process.h>
25  *
26  *   KSysGuard::Processes *processes = new KSysGuard::Processes()
27  *   QHash<long, Process *> processlist = processes->getProcesses();
28  *   foreach( Process * process, processlist) {
29  *     kDebug() << "Process with pid " << process->pid() << " is called " << process->name;
30  *   }
31  *   delete processes;
32  *   processes = NULL;
33  * \endcode
34  *
35  * @author John Tapsell <tapsell@kde.org>
36  */
37 #ifdef Q_WS_WIN
38 class Processes : public QObject
39 #else
40 class Q_DECL_EXPORT Processes : public QObject
41 #endif
42 {
43     Q_OBJECT
44 
45 public:
46     Processes(const QString &hostname = QString(), QObject *parent = nullptr);
47     ~Processes() override;
48     enum UpdateFlag {
49         StandardInformation = 1,
50         IOStatistics = 2,
51         XMemory = 4,
52         Smaps = 8,
53     };
54     Q_DECLARE_FLAGS(UpdateFlags, UpdateFlag)
55 
56     enum Error { Unknown = 0, InvalidPid, InvalidParameter, InsufficientPermissions, ProcessDoesNotExistOrZombie, NotSupported, NoError };
57 
58     /**
59      *  Update all the process information.  After calling this, /proc or equivalent is scanned and
60      *  the signals processChanged, etc  are emitted.
61      *
62      *  Set updateDuration to whatever time period that you update, in milliseconds.
63      *  For example, if you update every 2000ms, set this to 2000.  That way it won't update
64      *  more often than needed.
65      */
66     void updateAllProcesses(long updateDurationMS = 0, Processes::UpdateFlags updateFlags = {});
67 
68     /**
69      *  Return information for one specific process.  Call getProcess(0) to get the
70      *  fake process used as the top most parent for all processes.
71      *  This doesn't fetch any new information and so returns almost instantly.
72      *  Call updateAllProcesses() to actually fetch the process information.
73      */
74     Process *getProcess(long pid) const;
75 
76     /**
77      *  Get the error code for the last command that failed.
78      */
79     Error lastError() const;
80 
81     /**
82      *  Kill the specified process.  You may not have the privilege to kill the process.
83      *  The process may also chose to ignore the command.  Send the SIGKILL signal to kill
84      *  the process immediately.  You may lose any unsaved data.
85      *
86      *  @returns Successful or not in killing the process
87      */
88     bool killProcess(long pid);
89 
90     /**
91      *  Send the specified named POSIX signal to the process given.
92      *
93      *  For example, to indicate for process 324 to STOP do:
94      *  \code
95      *    #include <signals.h>
96      *     ...
97      *
98      *    KSysGuard::Processes::sendSignal(23, SIGSTOP);
99      *  \endcode
100      *
101      */
102     bool sendSignal(long pid, int sig);
103 
104     /**
105      *  Set the priority for a process.  This is from 19 (very nice, lowest priority) to
106      *    -20 (highest priority).  The default value for a process is 0.
107      *
108      *  @return false if you do not have permission to set the priority
109      */
110     bool setNiceness(long pid, int priority);
111 
112     /**
113      *  Set the scheduler for a process.  This is defined according to POSIX.1-2001
114      *  See "man sched_setscheduler" for more information.
115      *
116      *  @p priorityClass One of SCHED_FIFO, SCHED_RR, SCHED_OTHER, and SCHED_BATCH
117      *  @p priority Set to 0 for SCHED_OTHER and SCHED_BATCH.  Between 1 and 99 for SCHED_FIFO and SCHED_RR
118      *  @return false if you do not have permission to set the priority
119      */
120     bool setScheduler(long pid, KSysGuard::Process::Scheduler priorityClass, int priority);
121 
122     /**
123      *  Set the io priority for a process.  This is from 7 (very nice, lowest io priority) to
124      *  0 (highest priority).  The default value is determined as: io_nice = (cpu_nice + 20) / 5.
125      *
126      *  @return false if you do not have permission to set the priority
127      */
128     bool setIoNiceness(long pid, KSysGuard::Process::IoPriorityClass priorityClass, int priority);
129 
130     /**
131      *  Returns true if ionice is supported on this system
132      */
133     bool supportsIoNiceness();
134 
135     /**
136      *  Return the internal pointer of all the processes.  The order of the processes
137      *  is guaranteed to never change.  Call updateAllProcesses() first to actually
138      *  update the information.
139      */
140     const QList<Process *> &getAllProcesses() const;
141 
142     /**
143      *  Return the number of processes.  Call updateAllProcesses() to actually
144      *  update the information.
145      *
146      *  This is equivalent to getAllProcesses().count()
147      */
148     int processCount() const;
149 
150     /**
151      *  Return the total amount of physical memory in KB.  This is fast (just a system call)
152      *  Returns 0 on error
153      */
154     long long totalPhysicalMemory();
155 
156     /**
157      *  Return the number of processor cores enabled.
158      *  (A system can disable processors.  Disabled processors are not counted here).
159      *  This is fast (just a system call) */
160     long numberProcessorCores();
161 
162     /** Update/add process for given pid immediately */
163     bool updateOrAddProcess(long pid);
164 
165     /** Whether we can get historic process and system data */
166     bool isHistoryAvailable() const;
167 
168     /** Stop using historical data and use the most recent up-to-date data */
169     void useCurrentData();
170 
171     /** Return a list of end times and intervals for all the available history */
172     QList<QPair<QDateTime, uint>> historiesAvailable() const;
173 
174     /** Use historical process data closest to the given date-time.
175      *  Returns false if it is outside the range available or there is a problem
176      *  getting the data. */
177     bool setViewingTime(const QDateTime &when);
178     QDateTime viewingTime() const;
179     bool loadHistoryFile(const QString &filename);
180     QString historyFileName() const;
181 
182 public Q_SLOTS:
183     /** The abstract processes has updated its list of processes */
184     void processesUpdated();
185     void processUpdated(long pid, const Process::Updates &changes);
186 
187 Q_SIGNALS:
188     /** The data for a process has changed.
189      *  if @p onlyTotalCpu is set, only the total cpu usage has been updated.
190      *  process->changes  contains a bit field indicating what has changed since the last time this was emitted
191      *  for this process
192      */
193     void processChanged(KSysGuard::Process *process, bool onlyTotalCpu);
194 
195     /**
196      *  This indicates we are about to add a process in the model.
197      *  The process already has the pid, ppid and tree_parent set up.
198      */
199     void beginAddProcess(KSysGuard::Process *process);
200 
201     /**
202      *  We have finished inserting a process
203      */
204     void endAddProcess();
205     /**
206      *  This indicates we are about to remove a process in the model.  Emit the appropriate signals
207      */
208 
209     void beginRemoveProcess(KSysGuard::Process *process);
210 
211     /**
212      *  We have finished removing a process
213      */
214     void endRemoveProcess();
215 
216     /**
217      *  This indicates we are about move a process from one parent to another.
218      */
219     void beginMoveProcess(KSysGuard::Process *process, KSysGuard::Process *new_parent);
220 
221     /**
222      *  We have finished moving the process
223      */
224     void endMoveProcess();
225 
226     void updated();
227 
228 protected:
229     class Private;
230     Private *d;
231 
232 private:
233     inline void deleteProcess(long pid);
234     bool updateProcess(Process *process, long ppid);
235     bool updateProcessInfo(Process *ps);
236     bool addProcess(long pid, long ppid);
237 
238 Q_SIGNALS:
239     /** For a remote machine, we rely on being able to communicate with ksysguardd.
240      *  This must be dealt with by the program including this widget.  It must listen to our
241      *  'runCommand' signal, and run the given command, with the given id. */
242     void runCommand(const QString &command, int id);
243 
244 public:
245     /** For a remote machine, we rely on being able to communicate with ksysguardd.
246      *  The programming using this must call this slot when an answer is received from ksysguardd,
247      *  in response to a runCommand request.  The id identifies the answer */
248     void answerReceived(int id, const QList<QByteArray> &answer);
249 };
250 Q_DECLARE_OPERATORS_FOR_FLAGS(Processes::UpdateFlags)
251 }
252 
253 #endif
254