summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCástor Muñoz <cmvidal@gmail.com>2016-02-05 00:03:09 +0100
committerFranklin Wei <franklin@rockbox.org>2019-10-28 00:09:35 -0400
commitc353bef3d1902229be40118ce6b52770e5346787 (patch)
treecf2332df652aaf071e2402b1ecc2557aa859c119
parent9f7968efdd31e0b3753c698676fbbd92339320d9 (diff)
downloadrockbox-c353bef3d1902229be40118ce6b52770e5346787.tar.gz
rockbox-c353bef3d1902229be40118ce6b52770e5346787.tar.bz2
rockbox-c353bef3d1902229be40118ce6b52770e5346787.zip
rbutil: add function to suspend/resume processes
Change-Id: I99cfaaa4f853930cea88184496e91589b42859f3
-rw-r--r--rbutil/rbutilqt/base/utils.cpp122
-rw-r--r--rbutil/rbutilqt/base/utils.h1
2 files changed, 123 insertions, 0 deletions
diff --git a/rbutil/rbutilqt/base/utils.cpp b/rbutil/rbutilqt/base/utils.cpp
index f58d8c34e3..099f9c7742 100644
--- a/rbutil/rbutilqt/base/utils.cpp
+++ b/rbutil/rbutilqt/base/utils.cpp
@@ -764,6 +764,128 @@ QMap<QString, QList<int> > Utils::findRunningProcess(QStringList names)
}
+/** Suspends/resumes processes
+ * @param pidlist a list of PIDs to suspend/resume
+ * @param suspend processes are suspended if true, or resumed when false
+ * @return a list of PIDs successfully suspended/resumed
+ */
+QList<int> Utils::suspendProcess(QList<int> pidlist, bool suspend)
+{
+ QList<int> result;
+#if defined(Q_OS_WIN32)
+ // Enable debug privilege
+ HANDLE hToken = NULL;
+ LUID seDebugValue;
+ TOKEN_PRIVILEGES tNext, tPrev;
+ DWORD sPrev;
+ if(LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &seDebugValue)) {
+ if(OpenProcessToken(GetCurrentProcess(),
+ TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
+ memset(&tNext, 0, sizeof(tNext));
+ tNext.PrivilegeCount = 1;
+ tNext.Privileges[0].Luid = seDebugValue;
+ tNext.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ if(!AdjustTokenPrivileges(hToken, FALSE, &tNext, sizeof(tNext),
+ &tPrev, &sPrev) || GetLastError() != 0) {
+ CloseHandle(hToken);
+ hToken = NULL;
+ LOG_ERROR() << "AdjustTokenPrivileges(next) error" << GetLastError();
+ }
+ }
+ else {
+ LOG_ERROR() << "OpenProcessToken error" << GetLastError();
+ }
+ }
+ else {
+ LOG_ERROR() << "LookupPrivilegeValue error" << GetLastError();
+ }
+
+ // Suspend/resume threads
+ for(int i = 0; i < pidlist.size(); i++) {
+ HANDLE hdl = INVALID_HANDLE_VALUE;
+ THREADENTRY32 entry;
+ int n_fails = 0;
+
+ hdl = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
+ if(hdl == INVALID_HANDLE_VALUE) {
+ LOG_ERROR() << "CreateToolhelp32Snapshot error" << GetLastError();
+ continue;
+ }
+ entry.dwSize = sizeof(THREADENTRY32);
+ if(!Thread32First(hdl, &entry)) {
+ LOG_ERROR() << "Process32First error" << GetLastError();
+ CloseHandle(hdl);
+ continue;
+ }
+
+ do {
+ if(entry.th32OwnerProcessID != (DWORD)(pidlist[i]))
+ continue;
+ HANDLE thr = OpenThread(THREAD_SUSPEND_RESUME,
+ FALSE, entry.th32ThreadID);
+ if(!thr) {
+ LOG_ERROR() << "OpenThread" << entry.th32ThreadID
+ << "error" << GetLastError();
+ n_fails++;
+ continue;
+ }
+ if(suspend) {
+ // Execution of the specified thread is suspended and
+ // the thread's suspend count is incremented.
+ if(SuspendThread(thr) == (DWORD)(-1)) {
+ LOG_ERROR() << "SuspendThread" << entry.th32ThreadID
+ << "error" << GetLastError();
+ n_fails++;
+ }
+ }
+ else {
+ // Decrements a thread's suspend count. When the
+ // suspend count is decremented to zero, the
+ // execution of the thread is resumed.
+ if(ResumeThread(thr) == (DWORD)(-1)) {
+ LOG_ERROR() << "ResumeThread" << entry.th32ThreadID
+ << "error" << GetLastError();
+ n_fails++;
+ }
+ }
+ CloseHandle(thr);
+ } while(Thread32Next(hdl, &entry));
+ if (!n_fails)
+ result.append(pidlist[i]);
+ CloseHandle(hdl);
+ }
+
+ // Restore previous debug privilege
+ if (hToken) {
+ if(!AdjustTokenPrivileges(hToken, FALSE,
+ &tPrev, sPrev, NULL, NULL) || GetLastError() != 0) {
+ LOG_ERROR() << "AdjustTokenPrivileges(prev) error" << GetLastError();
+ }
+ CloseHandle(hToken);
+ }
+#endif
+#if defined(Q_OS_MACX)
+ int signal = suspend ? SIGSTOP : SIGCONT;
+ for(int i = 0; i < pidlist.size(); i++) {
+ pid_t pid = pidlist[i];
+ if(kill(pid, signal) != 0) {
+ LOG_ERROR() << "kill signal" << signal
+ << "for PID" << pid << "error:" << errno;
+ }
+ else {
+ result.append(pidlist[i]);
+ }
+ }
+#endif
+#if defined(Q_OS_LINUX)
+ // not implemented for Linux!
+#endif
+ LOG_INFO() << (suspend ? "Suspending" : "Resuming")
+ << "PIDs" << pidlist << "result" << result;
+ return result;
+}
+
+
/** Eject device from PC.
* Request the OS to eject the player.
* @param device mountpoint of the device
diff --git a/rbutil/rbutilqt/base/utils.h b/rbutil/rbutilqt/base/utils.h
index 7dfd797cbd..ca9c1d61af 100644
--- a/rbutil/rbutilqt/base/utils.h
+++ b/rbutil/rbutilqt/base/utils.h
@@ -55,6 +55,7 @@ public:
static QString resolveDevicename(QString path);
static QString resolveMountPoint(QString device);
static QMap<QString, QList<int> > findRunningProcess(QStringList names);
+ static QList<int> suspendProcess(QList<int> pidlist, bool suspend);
static bool ejectDevice(QString device);
};