tcrm_task/tasks/process/group/action/
pause.rs1use crate::tasks::process::group::builder::ProcessGroup;
2use crate::tasks::process::group::error::ProcessGroupError;
3
4impl ProcessGroup {
5 #[cfg(unix)]
22 pub fn pause_group(&self) -> Result<(), ProcessGroupError> {
23 use nix::sys::signal::{Signal, killpg};
24 use nix::unistd::Pid;
25 if let Some(pgid) = self.inner.process_group_id {
26 use nix::errno::Errno;
27 match killpg(Pid::from_raw(pgid), Signal::SIGSTOP) {
28 Ok(_) => Ok(()),
29 Err(e) => match e {
30 Errno::ESRCH => Ok(()), Errno::EPERM => Err(ProcessGroupError::SignalFailed(format!(
32 "Permission denied to pause process group {}",
33 pgid
34 ))),
35 _ => Err(ProcessGroupError::SignalFailed(format!(
36 "Failed to send SIGSTOP to process group {}: {}",
37 pgid, e
38 ))),
39 },
40 }
41 } else {
42 Err(ProcessGroupError::SignalFailed(
43 "No process group ID available".to_string(),
44 ))
45 }
46 }
47
48 #[cfg(windows)]
65 pub fn pause_group(&self) -> Result<(), ProcessGroupError> {
66 use crate::tasks::process::group::builder::SendHandle;
67 use windows::Win32::Foundation::CloseHandle;
68 use windows::Win32::System::Diagnostics::ToolHelp::{
69 CreateToolhelp32Snapshot, TH32CS_SNAPTHREAD, THREADENTRY32, Thread32First, Thread32Next,
70 };
71 use windows::Win32::System::JobObjects::{
72 JOBOBJECT_BASIC_PROCESS_ID_LIST, JobObjectBasicProcessIdList, QueryInformationJobObject,
73 };
74 use windows::Win32::System::Threading::{OpenThread, SuspendThread, THREAD_SUSPEND_RESUME};
75
76 if let Some(SendHandle(job_handle)) = &self.inner.job_handle {
77 unsafe {
78 let mut process_list = JOBOBJECT_BASIC_PROCESS_ID_LIST::default();
80 let mut returned_length = 0u32;
81
82 QueryInformationJobObject(
83 Some(*job_handle),
84 JobObjectBasicProcessIdList,
85 &mut process_list as *mut _ as *mut std::ffi::c_void,
86 std::mem::size_of::<JOBOBJECT_BASIC_PROCESS_ID_LIST>() as u32,
87 Some(&mut returned_length),
88 )
89 .map_err(|e| {
90 ProcessGroupError::SignalFailed(format!(
91 "Failed to query job object process list: {}",
92 e
93 ))
94 })?;
95
96 let mut suspended_count = 0;
97
98 for i in 0..process_list.NumberOfProcessIdsInList {
100 let pid = process_list.ProcessIdList[i as usize] as u32;
101
102 let snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0).map_err(|e| {
104 ProcessGroupError::SignalFailed(format!(
105 "Failed to create thread snapshot: {}",
106 e
107 ))
108 })?;
109
110 let mut thread_entry = THREADENTRY32 {
111 dwSize: std::mem::size_of::<THREADENTRY32>() as u32,
112 ..Default::default()
113 };
114
115 if Thread32First(snapshot, &mut thread_entry).is_ok() {
117 loop {
118 if thread_entry.th32OwnerProcessID == pid {
119 let thread_handle = OpenThread(
120 THREAD_SUSPEND_RESUME,
121 false,
122 thread_entry.th32ThreadID,
123 );
124 if let Ok(handle) = thread_handle {
125 SuspendThread(handle);
126 let _ = CloseHandle(handle);
127 suspended_count += 1;
128 }
129 }
130
131 if Thread32Next(snapshot, &mut thread_entry).is_err() {
132 break;
133 }
134 }
135 }
136
137 let _ = CloseHandle(snapshot);
138 }
139
140 if suspended_count > 0 {
141 Ok(())
142 } else {
143 Err(ProcessGroupError::SignalFailed(
144 "No threads were suspended in the job object".to_string(),
145 ))
146 }
147 }
148 } else {
149 Err(ProcessGroupError::SignalFailed(
150 "No Job Object handle available".to_string(),
151 ))
152 }
153 }
154
155 #[cfg(not(any(unix, windows)))]
157 pub fn pause_group(&self) -> Result<(), ProcessGroupError> {
158 Err(ProcessGroupError::UnsupportedPlatform(
159 "Process group pausing not available on this platform".to_string(),
160 ))
161 }
162}