implement process_release/1, process_wait/2, process_wait/3, and process_kill/1
This commit is contained in:
@@ -4795,6 +4795,22 @@ impl Machine {
|
||||
try_or_throw!(self.machine_st, self.process_create());
|
||||
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||
}
|
||||
&Instruction::CallProcessWait => {
|
||||
try_or_throw!(self.machine_st, self.process_wait());
|
||||
step_or_fail!(self, self.machine_st.p += 1);
|
||||
}
|
||||
&Instruction::ExecuteProcessWait => {
|
||||
try_or_throw!(self.machine_st, self.process_wait());
|
||||
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||
}
|
||||
&Instruction::CallProcessKill => {
|
||||
try_or_throw!(self.machine_st, self.process_kill());
|
||||
step_or_fail!(self, self.machine_st.p += 1);
|
||||
}
|
||||
&Instruction::ExecuteProcessKill => {
|
||||
try_or_throw!(self.machine_st, self.process_kill());
|
||||
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||
}
|
||||
&Instruction::CallPid => {
|
||||
self.pid();
|
||||
step_or_fail!(self, self.machine_st.p += 1);
|
||||
|
||||
@@ -405,6 +405,17 @@ impl MachineState {
|
||||
[atom_as_cell((atom!("stream"))), cell(culprit)]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
}
|
||||
}
|
||||
ExistenceError::Process(culprit) => {
|
||||
let stub = functor!(
|
||||
atom!("existence_error"),
|
||||
[atom_as_cell((atom!("process"))), cell(culprit)]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
@@ -1003,6 +1014,7 @@ pub enum ExistenceError {
|
||||
},
|
||||
SourceSink(HeapCellValue),
|
||||
Stream(HeapCellValue),
|
||||
Process(HeapCellValue),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
||||
@@ -8616,6 +8616,142 @@ impl Machine {
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn process_wait(&mut self) -> CallResult {
|
||||
fn stub_gen() -> Vec<FunctorElement> {
|
||||
functor_stub(atom!("process_wait"), 2)
|
||||
}
|
||||
|
||||
// Pid
|
||||
let pid_r = self.deref_register(1);
|
||||
// Var | Status
|
||||
let status_r = self.deref_register(2);
|
||||
// timeout | 0
|
||||
let timeout_r = self.deref_register(3);
|
||||
|
||||
let Some(pid) = pid_r
|
||||
.to_fixnum()
|
||||
.and_then(|elem| elem.get_num().try_into().ok())
|
||||
else {
|
||||
let err = self
|
||||
.machine_st
|
||||
.existence_error(ExistenceError::Process(pid_r));
|
||||
return Err(self.machine_st.error_form(err, stub_gen()));
|
||||
};
|
||||
let Some(mut child) = self.machine_st.child_processes.remove(&pid) else {
|
||||
let err = self
|
||||
.machine_st
|
||||
.existence_error(ExistenceError::Process(pid_r));
|
||||
return Err(self.machine_st.error_form(err, stub_gen()));
|
||||
};
|
||||
|
||||
let status = if let Some(atom) = timeout_r.to_atom() {
|
||||
match atom {
|
||||
atom!("infinite") => child.wait().map(Some),
|
||||
_ => {
|
||||
panic!("Invalid Timeout value")
|
||||
}
|
||||
}
|
||||
} else if let Some(timeout) = timeout_r.to_fixnum() {
|
||||
if timeout.get_num() == 0 {
|
||||
child.try_wait()
|
||||
} else {
|
||||
panic!("Invalid Timeout value")
|
||||
}
|
||||
} else {
|
||||
panic!("Invalid Timeout value")
|
||||
};
|
||||
|
||||
match status {
|
||||
Ok(None) => {
|
||||
unify!(self.machine_st, status_r, atom_as_cell!(atom!("timeout")));
|
||||
Ok(())
|
||||
}
|
||||
Ok(Some(exit_status)) => {
|
||||
if let Some(exit_code) = exit_status.code() {
|
||||
let mut writer =
|
||||
Heap::functor_writer(functor!(atom!("exit"), [fixnum(exit_code)]));
|
||||
|
||||
match writer(&mut self.machine_st.heap) {
|
||||
Ok(loc) => {
|
||||
unify!(self.machine_st, status_r, loc);
|
||||
}
|
||||
Err(resource_err_loc) => {
|
||||
self.machine_st.throw_resource_error(resource_err_loc);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::process::ExitStatusExt;
|
||||
|
||||
if let Some(signal) = ExitStatusExt::signal(&exit_status) {
|
||||
let mut writer =
|
||||
Heap::functor_writer(functor!(atom!("signal"), [fixnum(signal)]));
|
||||
|
||||
match writer(&mut self.machine_st.heap) {
|
||||
Ok(loc) => {
|
||||
unify!(self.machine_st, status_r, loc);
|
||||
}
|
||||
Err(resource_err_loc) => {
|
||||
self.machine_st.throw_resource_error(resource_err_loc);
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
} else {
|
||||
unify!(self.machine_st, status_r, atom_as_cell!(atom!("unknown")));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
#[cfg(not(unix))]
|
||||
{
|
||||
unify!(self.machine_st, status_r, atom_as_cell!(atom!("unknown")));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
let perm_error = self.machine_st.permission_error(
|
||||
Permission::Modify,
|
||||
atom!("process"),
|
||||
stub_gen(),
|
||||
);
|
||||
Err(self.machine_st.error_form(perm_error, stub_gen()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn process_kill(&mut self) -> CallResult {
|
||||
fn stub_gen() -> Vec<FunctorElement> {
|
||||
functor_stub(atom!("process_kill"), 1)
|
||||
}
|
||||
|
||||
// Pid
|
||||
let pid_r = self.deref_register(1);
|
||||
let Some(pid) = pid_r
|
||||
.to_fixnum()
|
||||
.and_then(|elem| elem.get_num().try_into().ok())
|
||||
else {
|
||||
let err = self
|
||||
.machine_st
|
||||
.existence_error(ExistenceError::Process(pid_r));
|
||||
return Err(self.machine_st.error_form(err, stub_gen()));
|
||||
};
|
||||
let Some(mut child) = self.machine_st.child_processes.remove(&pid) else {
|
||||
let err = self
|
||||
.machine_st
|
||||
.existence_error(ExistenceError::Process(pid_r));
|
||||
return Err(self.machine_st.error_form(err, stub_gen()));
|
||||
};
|
||||
if child.kill().is_err() {
|
||||
let perm_error =
|
||||
self.machine_st
|
||||
.permission_error(Permission::Modify, atom!("process"), stub_gen());
|
||||
return Err(self.machine_st.error_form(perm_error, stub_gen()));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn chars_base64(&mut self) -> CallResult {
|
||||
let padding = cell_as_atom!(self.deref_register(3));
|
||||
|
||||
Reference in New Issue
Block a user