Actually check process when querying for completion
With --on-update=do-nothing, we need to know when the process is done before we can spawn a new one, but we never actually used to truly check the process, only the presence or absence of a spawned process. That process may have already completed, but because we don't wait on it when in do-nothing mode, there is no opportunity to notice this. So now we either actually check the completion status of the process (on Windows), or we expose the `done` mutex value on demand (Unix). Essentially this adds a way to check the completion status of the process without blocking (modulo a mutex lock on unix). Fixes #200
This commit is contained in:
parent
960bbbabbc
commit
71a178d4c2
|
@ -241,6 +241,13 @@ mod imp {
|
|||
.expect("poisoned cvar in process::wait");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_complete(&self) -> bool {
|
||||
*self
|
||||
.lock
|
||||
.lock()
|
||||
.expect("poisoned lock in process::is_complete")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -393,22 +400,37 @@ mod imp {
|
|||
}
|
||||
}
|
||||
|
||||
// Some(true) if complete, Some(false) if incomplete, None if timed out
|
||||
fn wait_for_completion(&self, timeout: DWORD) -> Option<bool> {
|
||||
let mut code: DWORD = 0;
|
||||
let mut key: ULONG_PTR = 0;
|
||||
let mut overlapped = mem::MaybeUninit::<LPOVERLAPPED>::uninit();
|
||||
|
||||
if 0 == unsafe {
|
||||
GetQueuedCompletionStatus(
|
||||
self.completion_port,
|
||||
&mut code,
|
||||
&mut key,
|
||||
overlapped.as_mut_ptr(),
|
||||
timeout,
|
||||
)
|
||||
} {
|
||||
// TODO: handle errors? how does that manifest for timeouts?
|
||||
None
|
||||
} else {
|
||||
Some(code == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO && (key as HANDLE) == self.job)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_complete(&self) -> bool {
|
||||
self.wait_for_completion(0).unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn wait(&self) {
|
||||
loop {
|
||||
let mut code: DWORD = 0;
|
||||
let mut key: ULONG_PTR = 0;
|
||||
let mut overlapped = mem::MaybeUninit::<LPOVERLAPPED>::uninit();
|
||||
unsafe {
|
||||
GetQueuedCompletionStatus(
|
||||
self.completion_port,
|
||||
&mut code,
|
||||
&mut key,
|
||||
overlapped.as_mut_ptr(),
|
||||
INFINITE,
|
||||
);
|
||||
}
|
||||
|
||||
if code == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO && (key as HANDLE) == self.job {
|
||||
if self.wait_for_completion(INFINITE).expect(
|
||||
"GetQueuedCompletionStatus passed INFINITE timeout but timed out anyway",
|
||||
) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -194,7 +194,10 @@ impl ExecHandler {
|
|||
.read()
|
||||
.expect("poisoned lock in has_running_process");
|
||||
|
||||
(*guard).is_some()
|
||||
(*guard)
|
||||
.as_ref()
|
||||
.map(|process| !process.is_complete())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -216,8 +219,15 @@ impl Handler for ExecHandler {
|
|||
// Only returns Err() on lock poisoning.
|
||||
fn on_update(&self, ops: &[PathOp]) -> Result<bool> {
|
||||
let signal = self.signal.unwrap_or(Signal::SIGTERM);
|
||||
let has_running_processes = self.has_running_process();
|
||||
|
||||
match (self.has_running_process(), self.args.on_busy_update) {
|
||||
log::debug!(
|
||||
"ON UPDATE: has_running_processes: {} --- on_busy_update: {:?}",
|
||||
has_running_processes,
|
||||
self.args.on_busy_update
|
||||
);
|
||||
|
||||
match (has_running_processes, self.args.on_busy_update) {
|
||||
// If nothing is running, start the command
|
||||
(false, _) => {
|
||||
self.spawn(ops)?;
|
||||
|
|
Loading…
Reference in New Issue