From c353bef3d1902229be40118ce6b52770e5346787 Mon Sep 17 00:00:00 2001 From: Cástor Muñoz Date: Fri, 5 Feb 2016 00:03:09 +0100 Subject: rbutil: add function to suspend/resume processes Change-Id: I99cfaaa4f853930cea88184496e91589b42859f3 --- rbutil/rbutilqt/base/utils.cpp | 122 +++++++++++++++++++++++++++++++++++++++++ rbutil/rbutilqt/base/utils.h | 1 + 2 files changed, 123 insertions(+) (limited to 'rbutil/rbutilqt') 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 > 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 Utils::suspendProcess(QList pidlist, bool suspend) +{ + QList 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 > findRunningProcess(QStringList names); + static QList suspendProcess(QList pidlist, bool suspend); static bool ejectDevice(QString device); }; -- cgit v1.2.3