Skip to content
Snippets Groups Projects
Commit 6766f149 authored by Martyn Gigg's avatar Martyn Gigg Committed by Gigg, Martyn Anthony
Browse files

Add function to retrieve other process ids using psutil

Refs #0
parent d49f2ac2
No related branches found
No related tags found
No related merge requests found
...@@ -91,6 +91,7 @@ set ( QTIPLOT_SRCS src/ApplicationWindow.cpp ...@@ -91,6 +91,7 @@ set ( QTIPLOT_SRCS src/ApplicationWindow.cpp
src/PluginFit.cpp src/PluginFit.cpp
src/PolynomFitDialog.cpp src/PolynomFitDialog.cpp
src/PolynomialFit.cpp src/PolynomialFit.cpp
src/Process.cpp
src/ProjectRecovery.cpp src/ProjectRecovery.cpp
src/ProjectSaveView.cpp src/ProjectSaveView.cpp
src/ProjectSerialiser.cpp src/ProjectSerialiser.cpp
...@@ -291,6 +292,7 @@ set ( QTIPLOT_HDRS src/ApplicationWindow.h ...@@ -291,6 +292,7 @@ set ( QTIPLOT_HDRS src/ApplicationWindow.h
src/PluginFit.h src/PluginFit.h
src/PolynomFitDialog.h src/PolynomFitDialog.h
src/PolynomialFit.h src/PolynomialFit.h
src/Process.h
src/ProjectRecovery.h src/ProjectRecovery.h
src/ProjectSerialiser.h src/ProjectSerialiser.h
src/ProjectSaveView.h src/ProjectSaveView.h
......
// clang-format off
#include "MantidQtWidgets/Common/PythonThreading.h"
// clang-format on
#include "Process.h"
#include <iostream>
#include <stdexcept>
#include <QCoreApplication>
namespace {
class PyObjectNewReference {
public:
PyObjectNewReference(PyObject *object) : m_object(object) {}
~PyObjectNewReference() { Py_XDECREF(m_object); }
PyObjectNewReference(const PyObjectNewReference &) = delete;
PyObjectNewReference &operator=(const PyObjectNewReference &) = delete;
PyObjectNewReference(PyObjectNewReference &&) = default;
PyObjectNewReference &operator=(PyObjectNewReference &&) = default;
inline PyObject *ptr() const { return m_object; }
private:
PyObject *m_object;
};
/**
* @brief Retrieve a named attribute
* @param source The source object
* @param name The name of the attribute
* @return The attribute
* @throws std::runtime_error if an error occurs retrieving the attribute
*/
PyObjectNewReference attr(PyObject *source, const char *name) {
PyObjectNewReference attr(PyObject_GetAttrString(source, name));
if (attr.ptr()) {
return attr;
} else {
PyErr_Clear();
throw std::runtime_error(std::string("Process: No attribute ") + name +
" found");
}
}
/**
* @brief Call a named function with an check for errors
* @param source The source object
* @param name The name of the attribute to call
* @return The return value of the function
* @throws std::runtime_error if an error occurs retrieving the attribute
*/
PyObjectNewReference call(PyObject *source, const char *name) {
auto result = PyObject_CallFunction(attr(source, name).ptr(), nullptr);
if (result)
return PyObjectNewReference(result);
else {
PyErr_Clear();
throw std::runtime_error(std::string("Process: Error calling function ") +
name);
}
}
/**
* @return Return a pointer to the psutil module. A new reference is returned.
*/
PyObjectNewReference psutil() {
if (auto process = PyImport_ImportModule("psutil")) {
return PyObjectNewReference(process);
} else {
PyErr_Clear();
throw std::runtime_error("Python module psutil cannot be imported.");
}
}
} // namespace
namespace Process {
/**
* @brief Return a list of process IDs for other instances of this process.
* @return A list of other processes running. The PID for this process is
* removed from the list. An empty list is returned
* if no other processes are running.
* @throws std::runtime_error if the PID list cannot be determined
*/
std::vector<int64_t> otherInstancePIDs() {
ScopedPythonGIL lock;
const int64_t ourPID(QCoreApplication::applicationPid());
const PyObjectNewReference ourName(PyString_FromString(
QCoreApplication::applicationName().toLatin1().data()));
auto psutilModule(psutil());
auto processIter(call(psutilModule.ptr(), "process_iter"));
std::vector<int64_t> otherPIDs;
PyObject *item(nullptr);
while ((item = PyIter_Next(processIter.ptr()))) {
auto name = call(item, "name");
if (PyObject_RichCompareBool(name.ptr(), ourName.ptr(), Py_EQ)) {
auto pid = PyLong_AsLong(attr(item, "pid").ptr());
if (pid != ourPID) {
otherPIDs.emplace_back(pid);
}
}
Py_DECREF(item);
}
return otherPIDs;
}
} // namespace Process
#ifndef PROCESS_H_
#define PROCESS_H_
/*
Copyright &copy; 2008-18 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
National Laboratory & European Spallation Source
This file is part of Mantid.
Mantid is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
Mantid is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
File change history is stored at: <https://github.com/mantidproject/mantid>
Code Documentation is available at: <http://doxygen.mantidproject.org>
*/
#include <cstdint>
#include <vector>
/*
* A minimal wrapper around Python's psutil package to gather information
* about processes
*/
namespace Process {
std::vector<int64_t> otherInstancePIDs();
}
#endif // PROCESS_H_
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment