mirror of
https://github.com/SpaceManiac/SpacemanDMM.git
synced 2025-12-23 05:36:47 +00:00
Codify launched subprocess state machine
This commit is contained in:
parent
93cde34a78
commit
a2eece17a8
1 changed files with 61 additions and 21 deletions
|
|
@ -5,41 +5,67 @@ use std::sync::{Arc, Mutex};
|
|||
use super::SequenceNumber;
|
||||
use super::dap_types::{ExitedEvent, TerminatedEvent};
|
||||
|
||||
// active --kill--> killed: emit Terminated, send SIGKILL
|
||||
// active --detach--> detached: emit Terminated
|
||||
// active --exit--> exited: emit Terminated + Exited
|
||||
// killed --exit--> exited: emit Exited
|
||||
// detached --exit--> exited: emit Exited
|
||||
// exited --kill--> exited: no-op
|
||||
// exited --detach--> exited: no-op
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
enum State {
|
||||
Active,
|
||||
Killed,
|
||||
Detached,
|
||||
Exited,
|
||||
}
|
||||
|
||||
// TODO: This code currently emits the Terminated event in order to cover for
|
||||
// no actual debugging taking place. When debugging is implemented, that event
|
||||
// should be moved to be
|
||||
|
||||
pub struct Launched {
|
||||
handle: raw::Handle,
|
||||
seq: Arc<SequenceNumber>,
|
||||
mutex: Arc<Mutex<bool>>, // TODO: AtomicBool instead?
|
||||
mutex: Arc<Mutex<State>>,
|
||||
}
|
||||
|
||||
impl Launched {
|
||||
pub fn new(seq: Arc<SequenceNumber>, mut child: std::process::Child) -> std::io::Result<Launched> {
|
||||
let mutex = Arc::new(Mutex::new(State::Active));
|
||||
let handle = raw::from(&child);
|
||||
|
||||
let seq2 = seq.clone();
|
||||
let mutex = Arc::new(Mutex::new(false));
|
||||
let mutex2 = mutex.clone();
|
||||
|
||||
std::thread::Builder::new()
|
||||
.name("launched debuggee manager thread".to_owned())
|
||||
.spawn(move || {
|
||||
eprintln!("[launched] child started");
|
||||
let code = match child.wait() {
|
||||
let wait = child.wait();
|
||||
// lock as soon as possible to minimize risk of shenanigans
|
||||
let mut state = mutex2.lock().expect("launched mutex poisoned");
|
||||
let code = match wait {
|
||||
Ok(status) => {
|
||||
let code = status.code();
|
||||
eprintln!("[launched] child exited with code {:?}", code);
|
||||
eprintln!("[launched] child exited in state {:?} with code {:?}", *state, code);
|
||||
code.unwrap_or(-1)
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("[launched] wait() errored: {:?}", e);
|
||||
Err(err) => {
|
||||
eprintln!("[launched] wait() errored in state {:?}: {:?}", *state, err);
|
||||
-1
|
||||
}
|
||||
};
|
||||
*mutex2.lock().unwrap() = true;
|
||||
seq2.issue_event(TerminatedEvent::default());
|
||||
if let State::Active = *state {
|
||||
seq2.issue_event(TerminatedEvent::default());
|
||||
}
|
||||
*state = State::Exited;
|
||||
seq2.issue_event(ExitedEvent {
|
||||
exitCode: code as i64,
|
||||
});
|
||||
eprintln!("launched - exited issued");
|
||||
})?;
|
||||
|
||||
Ok(Launched {
|
||||
handle,
|
||||
seq,
|
||||
|
|
@ -48,22 +74,36 @@ impl Launched {
|
|||
}
|
||||
|
||||
pub fn kill(self) -> std::io::Result<()> {
|
||||
eprintln!("launched - kill called");
|
||||
if *self.mutex.lock().unwrap() {
|
||||
// don't kill if the wait() has completed
|
||||
eprintln!("launched - kill short circuiting");
|
||||
return Ok(());
|
||||
}
|
||||
eprintln!("[launched] killing child process");
|
||||
match unsafe { raw::kill(self.handle) } {
|
||||
true => Ok(()),
|
||||
false => Err(std::io::Error::last_os_error()),
|
||||
let mut state = self.mutex.lock().expect("launched mutex poisoned");
|
||||
match *state {
|
||||
State::Active => {
|
||||
eprintln!("[launched] killing child process");
|
||||
self.seq.issue_event(TerminatedEvent::default());
|
||||
*state = State::Killed;
|
||||
match unsafe { raw::kill(self.handle) } {
|
||||
true => Ok(()),
|
||||
false => Err(std::io::Error::last_os_error()),
|
||||
}
|
||||
}
|
||||
other => {
|
||||
eprintln!("[launched] kill no-op in state {:?}", other);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn detach(self) {
|
||||
eprintln!("[launched] detaching softly");
|
||||
self.seq.issue_event(TerminatedEvent::default());
|
||||
let mut state = self.mutex.lock().expect("launched mutex poisoned");
|
||||
match *state {
|
||||
State::Active => {
|
||||
eprintln!("[launched] detaching from child process");
|
||||
self.seq.issue_event(TerminatedEvent::default());
|
||||
*state = State::Detached;
|
||||
}
|
||||
other => {
|
||||
eprintln!("[launched] detach no-op in state {:?}", other);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue