mirror of
https://github.com/boostorg/process.git
synced 2026-01-20 04:42:24 +00:00
Compare commits
4 Commits
origin/xpr
...
suspend
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
89c5b589c3 | ||
|
|
4183c66490 | ||
|
|
9cdc1be868 | ||
|
|
b9cb5dc0ee |
@@ -12,6 +12,16 @@
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#if !defined(BOOST_PROCESS_V2_DISABLE_UNDOCUMENTED_API)
|
||||
extern "C"
|
||||
{
|
||||
|
||||
LONG WINAPI NtResumeProcess(HANDLE ProcessHandle);
|
||||
LONG WINAPI NtSuspendProcess(HANDLE ProcessHandle);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail
|
||||
@@ -113,6 +123,33 @@ void check_running_(HANDLE handle, error_code & ec, DWORD & exit_status)
|
||||
ec = detail::get_last_error();
|
||||
}
|
||||
|
||||
#if !defined(BOOST_PROCESS_V2_DISABLE_UNDOCUMENTED_API)
|
||||
void suspend_(HANDLE handle, error_code & ec)
|
||||
{
|
||||
auto nt_err = NtSuspendProcess(handle);
|
||||
if (nt_err > 0xC0000000)
|
||||
ec = detail::get_last_error();
|
||||
}
|
||||
|
||||
void resume_(HANDLE handle, error_code & ec)
|
||||
{
|
||||
|
||||
auto nt_err = NtResumeProcess(handle);
|
||||
if (nt_err > 0xC0000000)
|
||||
ec = detail::get_last_error();
|
||||
}
|
||||
#else
|
||||
void suspend_(HANDLE, error_code & ec)
|
||||
{
|
||||
ec.assign(ERROR_CALL_NOT_IMPLEMENTED, system_category());
|
||||
}
|
||||
|
||||
void resume_(HANDLE handle, error_code & ec)
|
||||
{
|
||||
|
||||
ec.assign(ERROR_CALL_NOT_IMPLEMENTED, system_category());
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
template struct basic_process_handle_win<>;
|
||||
|
||||
@@ -182,7 +182,42 @@ struct basic_process_handle_fd
|
||||
if (ec)
|
||||
detail::throw_error(ec, "request_exit");
|
||||
}
|
||||
|
||||
void suspend()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
error_code ec;
|
||||
suspend(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "suspend");
|
||||
}
|
||||
|
||||
void suspend(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
if (::kill(pid_, SIGCONT) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
void resume()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
error_code ec;
|
||||
resume(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "resume");
|
||||
}
|
||||
|
||||
void resume(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
if (::kill(pid_, SIGTERM) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
void terminate(native_exit_code_type &exit_status, error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
|
||||
@@ -211,6 +211,42 @@ struct basic_process_handle_fd_or_signal
|
||||
if (ec)
|
||||
detail::throw_error(ec, "request_exit");
|
||||
}
|
||||
|
||||
void suspend()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
error_code ec;
|
||||
suspend(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "suspend");
|
||||
}
|
||||
|
||||
void suspend(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
if (::kill(pid_, SIGCONT) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
void resume()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
error_code ec;
|
||||
resume(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "resume");
|
||||
}
|
||||
|
||||
void resume(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
if (::kill(pid_, SIGTERM) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
void terminate(native_exit_code_type &exit_status, error_code &ec)
|
||||
{
|
||||
|
||||
@@ -180,6 +180,50 @@ struct basic_process_handle_signal
|
||||
detail::throw_error(ec, "request_exit");
|
||||
}
|
||||
|
||||
void interrupt(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
if (::kill(pid_, SIGTERM) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
void suspend()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
error_code ec;
|
||||
suspend(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "suspend");
|
||||
}
|
||||
|
||||
void suspend(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
if (::kill(pid_, SIGCONT) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
void resume()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
error_code ec;
|
||||
resume(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "resume");
|
||||
}
|
||||
|
||||
void resume(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
if (::kill(pid_, SIGTERM) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
void terminate(native_exit_code_type &exit_status, error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
|
||||
@@ -32,6 +32,8 @@ BOOST_PROCESS_V2_DECL void terminate_if_running_(void * handle);
|
||||
BOOST_PROCESS_V2_DECL bool check_handle_(void* handle, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL bool check_pid_(pid_type pid_, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL void interrupt_(pid_type pid_, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL void suspend_(void * handle, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL void resume_(void * handle, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL void terminate_(void * handle, error_code & ec, native_exit_code_type & exit_code);
|
||||
BOOST_PROCESS_V2_DECL void request_exit_(pid_type pid_, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL void check_running_(void* handle, error_code & ec, native_exit_code_type & exit_status);
|
||||
@@ -176,6 +178,32 @@ struct basic_process_handle_win
|
||||
detail::throw_error(ec, "request_exit");
|
||||
}
|
||||
|
||||
void suspend(error_code &ec)
|
||||
{
|
||||
detail::suspend_(handle_.native_handle(), ec);
|
||||
}
|
||||
|
||||
void suspend()
|
||||
{
|
||||
error_code ec;
|
||||
suspend(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "suspend");
|
||||
}
|
||||
|
||||
void resume(error_code &ec)
|
||||
{
|
||||
detail::resume_(handle_.native_handle(), ec);
|
||||
}
|
||||
|
||||
void resume()
|
||||
{
|
||||
error_code ec;
|
||||
suspend(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "resume");
|
||||
}
|
||||
|
||||
void terminate(native_exit_code_type &exit_status, error_code &ec)
|
||||
{
|
||||
if (!detail::check_handle_(handle_.native_handle(), ec))
|
||||
|
||||
@@ -6,12 +6,21 @@
|
||||
#define BOOST_PROCESS_V2_IMPL_PID_IPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/last_error.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
#include <boost/process/v2/pid.hpp>
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
#include <windows.h>
|
||||
#include <tlhelp32.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
|
||||
#if (defined(__APPLE__) && defined(__MACH__))
|
||||
#include <sys/proc_info.h>
|
||||
#include <libproc.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
@@ -22,6 +31,220 @@ pid_type current_pid() {return ::GetCurrentProcessId();}
|
||||
pid_type current_pid() {return ::getpid();}
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
std::vector<pid_type> all_pids(error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
HANDLE hp = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (!hp)
|
||||
{
|
||||
ec = detail::get_last_error();
|
||||
return vec;
|
||||
}
|
||||
|
||||
PROCESSENTRY32 pe;
|
||||
pe.dwSize = sizeof(PROCESSENTRY32);
|
||||
if (Process32First(hp, &pe)) {
|
||||
do {
|
||||
vec.push_back(pe.th32ProcessID);
|
||||
} while (Process32Next(hp, &pe));
|
||||
}
|
||||
CloseHandle(hp);
|
||||
return vec;
|
||||
}
|
||||
|
||||
#elif (defined(__APPLE__) && defined(__MACH__))
|
||||
|
||||
std::vector<pid_type> all_pids(error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
vec.resize(proc_listpids(PROC_ALL_PIDS, 0, nullptr, 0));
|
||||
|
||||
if (proc_listpids(PROC_ALL_PIDS, 0, &vec[0], sizeof(pid_type) * vec))
|
||||
{
|
||||
ec = detail::get_last_error();
|
||||
return {};
|
||||
}
|
||||
|
||||
auto itr = std::partition(vec.begin(), vec.end(), [](pid_type pt) {return pt != 0;});
|
||||
vec.erase(itr, vec.end());
|
||||
return vec;
|
||||
}
|
||||
|
||||
#elif defined(__linux__)
|
||||
|
||||
std::vector<pid_type> all_pids(error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
DIR *proc = opendir("/proc");
|
||||
if (proc == nullptr)
|
||||
{
|
||||
ec = detail::get_last_error();
|
||||
return vec;
|
||||
}
|
||||
struct dirent *ent = nullptr;
|
||||
while ((ent = readdir(proc) != nullptr))
|
||||
{
|
||||
if (!isdigit(*ent->d_name))
|
||||
continue;
|
||||
vec.push_back(atoi(ent->d_name));
|
||||
}
|
||||
closedir(proc);
|
||||
return vec;
|
||||
}
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
|
||||
std::vector<pid_type> all_pids(error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
int cntp = 0;
|
||||
kinfo_proc *proc_info = kinfo_getallproc(&cntp);
|
||||
if (proc_info)
|
||||
{
|
||||
for (int i = 0; i < cntp; i++)
|
||||
vec.push_back(proc_info[i].ki_pid);
|
||||
free(proc_info);
|
||||
}
|
||||
else
|
||||
ec = detail::get_last_error();
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
#elif defined(__DragonFly__)
|
||||
|
||||
std::vector<pid_type> all_pids(error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
int cntp = 0;
|
||||
kinfo_proc *proc_info = nullptr;
|
||||
const char *nlistf, *memf;
|
||||
nlistf = memf = "/dev/null";
|
||||
kd = kvm_openfiles(nlistf, memf, nullptr, O_RDONLY, nullptr);
|
||||
if (!kd)
|
||||
{
|
||||
ec = detail::get_last_error();
|
||||
return vec;
|
||||
}
|
||||
|
||||
if ((proc_info = kvm_getprocs(kd, KERN_PROC_ALL, 0, &cntp)))
|
||||
{
|
||||
vec.reserve(cntp);
|
||||
for (int i = 0; i < cntp; i++)
|
||||
if (proc_info[i].kp_pid >= 0)
|
||||
vec.push_back(proc_info[i].kp_pid);
|
||||
}
|
||||
else
|
||||
ec = detail::get_last_error();
|
||||
|
||||
kvm_close(kd);
|
||||
return vec;
|
||||
}
|
||||
|
||||
#elif defined(__NetBSD__)
|
||||
|
||||
std::vector<pid_type> all_pids(error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
int cntp = 0;
|
||||
kinfo_proc2 *proc_info = nullptr;
|
||||
kd = kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr);
|
||||
if (!kd)
|
||||
{
|
||||
ec = detail::get_last_error();
|
||||
return vec;
|
||||
}
|
||||
if ((proc_info = kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2), &cntp)))
|
||||
{
|
||||
vec.reserve(cntp);
|
||||
for (int i = cntp - 1; i >= 0; i--) {
|
||||
vec.push_back(proc_info[i].p_pid);
|
||||
}
|
||||
}
|
||||
else
|
||||
ec = detail::get_last_error();
|
||||
kvm_close(kd);
|
||||
return vec;
|
||||
}
|
||||
|
||||
#elif defined(__OpenBSD__)
|
||||
|
||||
std::vector<pid_type> all_pids(error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
int cntp = 0;
|
||||
kinfo_proc *proc_info = nullptr;
|
||||
kd = kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr);
|
||||
|
||||
if (!kd)
|
||||
{
|
||||
ec = detail::get_last_error();
|
||||
return vec;
|
||||
}
|
||||
if ((proc_info = kvm_getprocs(kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), &cntp)))
|
||||
{
|
||||
vec.reserve(cntp);
|
||||
for (int i = 0; i < cntp; i++) {
|
||||
if (proc_info[i].kp_pid >= 0) {
|
||||
vec.push_back(proc_info[i].kp_pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
ec = detail::get_last_error();
|
||||
kvm_close(kd);
|
||||
return vec;
|
||||
}
|
||||
|
||||
#elif defined(__sun)
|
||||
|
||||
std::vector<pid_type> all_pids(error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
struct pid cur_pid;
|
||||
proc *proc_info = nullptr;
|
||||
kd = kvm_open(nullptr, nullptr, nullptr, O_RDONLY, nullptr);
|
||||
if (!kd)
|
||||
{
|
||||
ec = detail::get_last_error();
|
||||
return vec;
|
||||
}
|
||||
|
||||
while ((proc_info = kvm_nextproc(kd)))
|
||||
{
|
||||
if (kvm_kread(kd, (std::uintptr_t)proc_info->p_pidp, &cur_pid, sizeof(cur_pid)) != -1) {
|
||||
vec.insert(vec.begin(), cur_pid.pid_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
ec = detail::get_last_error();
|
||||
break;
|
||||
}
|
||||
}
|
||||
kvm_close(kd);
|
||||
return vec;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
#error "Platform not supported"
|
||||
|
||||
|
||||
#endif defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
|
||||
|
||||
std::vector<pid_type> all_pids()
|
||||
{
|
||||
error_code ec;
|
||||
auto res = all_pids(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "all_pids");
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#endif //BOOST_PROCESS_V2_IMPL_PID_IPP
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#define BOOST_PROCESS_V2_PID_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
@@ -31,6 +32,12 @@ typedef int pid_type;
|
||||
/// Get the process id of the current process.
|
||||
BOOST_PROCESS_V2_DECL pid_type current_pid();
|
||||
|
||||
/// List all available pids.
|
||||
BOOST_PROCESS_V2_DECL std::vector<pid_type> all_pids(error_code & ec);
|
||||
|
||||
/// List all available pids.
|
||||
BOOST_PROCESS_V2_DECL std::vector<pid_type> all_pids();
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
|
||||
@@ -214,6 +214,37 @@ struct basic_process
|
||||
process_handle_.request_exit(ec);
|
||||
}
|
||||
|
||||
/// Send the process a signal requesting it to stop. This may rely on undocmented functions.
|
||||
void suspend(error_code &ec)
|
||||
{
|
||||
process_handle_.suspend(ec);
|
||||
}
|
||||
|
||||
/// Send the process a signal requesting it to stop. This may rely on undocmented functions.
|
||||
void suspend()
|
||||
{
|
||||
error_code ec;
|
||||
suspend(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "suspend");
|
||||
}
|
||||
|
||||
|
||||
/// Send the process a signal requesting it to resume. This may rely on undocmented functions.
|
||||
void resume(error_code &ec)
|
||||
{
|
||||
process_handle_.resume(ec);
|
||||
}
|
||||
|
||||
/// Send the process a signal requesting it to resume. This may rely on undocmented functions.
|
||||
void resume()
|
||||
{
|
||||
error_code ec;
|
||||
suspend(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "resume");
|
||||
}
|
||||
|
||||
/// Throwing @overload void terminate(native_exit_code_type &exit_code, error_code & ec)
|
||||
void terminate()
|
||||
{
|
||||
|
||||
@@ -46,6 +46,7 @@ lib test_impl : test_impl.cpp filesystem :
|
||||
<link>static
|
||||
<target-os>windows:<source>shell32
|
||||
<target-os>windows:<source>user32
|
||||
<target-os>windows:<source>Ntdll
|
||||
;
|
||||
|
||||
test-suite standalone :
|
||||
|
||||
@@ -12,4 +12,8 @@ BOOST_AUTO_TEST_CASE(test_pid)
|
||||
{
|
||||
namespace bp2 = boost::process::v2;
|
||||
BOOST_CHECK_NE(bp2::current_pid(), static_cast<bp2::pid_type>(0));
|
||||
|
||||
auto all = bp2::all_pids();
|
||||
auto itr = std::find(all.begin(), all.end(), bp2::current_pid());
|
||||
BOOST_CHECK(itr != all.end());
|
||||
}
|
||||
@@ -149,6 +149,8 @@ BOOST_AUTO_TEST_CASE(terminate)
|
||||
|
||||
BOOST_CHECK_MESSAGE(!sh.empty(), sh);
|
||||
bpv::process proc(ctx, sh, {});
|
||||
proc.suspend();
|
||||
proc.resume();
|
||||
proc.terminate();
|
||||
proc.wait();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user