get process_create working and add tests

This commit is contained in:
Bennet Bleßmann
2025-07-26 18:21:00 +02:00
committed by Bennet Bleßmann
parent 1120bcde29
commit dc08a4ab11
14 changed files with 223 additions and 91 deletions

View File

@@ -4795,6 +4795,14 @@ impl Machine {
try_or_throw!(self.machine_st, self.process_create());
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
&Instruction::CallProcessId => {
try_or_throw!(self.machine_st, self.process_id());
step_or_fail!(self, self.machine_st.p += 1);
}
&Instruction::ExecuteProcessId => {
try_or_throw!(self.machine_st, self.process_id());
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);

View File

@@ -44,6 +44,7 @@ pub(crate) enum ValidType {
// PredicateIndicator,
// Variable
TcpListener,
Process,
}
impl ValidType {
@@ -67,6 +68,7 @@ impl ValidType {
// ValidType::PredicateIndicator => atom!("predicate_indicator"),
// ValidType::Variable => atom!("variable")
ValidType::TcpListener => atom!("tcp_listener"),
ValidType::Process => atom!("process"),
}
}
}

View File

@@ -20,11 +20,9 @@ use crate::parser::dashu::Integer;
use indexmap::IndexMap;
use std::collections::BTreeMap;
use std::convert::TryFrom;
use std::fmt;
use std::ops::{Index, IndexMut, Range};
use std::process::Child;
use std::sync::Arc;
pub(crate) type Registers = [HeapCellValue; MAX_ARITY + 1];
@@ -99,7 +97,6 @@ pub struct MachineState {
pub(crate) unify_fn: fn(&mut MachineState),
pub(crate) bind_fn: fn(&mut MachineState, Ref, HeapCellValue),
pub(crate) run_cleaners_fn: fn(&mut Machine) -> bool,
pub(crate) child_processes: BTreeMap<u32, Child>,
}
impl fmt::Debug for MachineState {

View File

@@ -19,7 +19,6 @@ use crate::types::*;
use indexmap::IndexSet;
use std::cmp::Ordering;
use std::collections::BTreeMap;
use std::convert::TryFrom;
impl MachineState {
@@ -68,7 +67,6 @@ impl MachineState {
unify_fn: MachineState::unify,
bind_fn: MachineState::bind,
run_cleaners_fn: |_| false,
child_processes: BTreeMap::new(),
}
}

View File

@@ -56,6 +56,7 @@ use std::net::{SocketAddr, ToSocketAddrs};
use std::net::{TcpListener, TcpStream};
use std::num::NonZeroU32;
use std::process;
use std::process::Child;
use std::process::Stdio;
#[cfg(feature = "http")]
use std::str::FromStr;
@@ -8496,16 +8497,13 @@ impl Machine {
match command.spawn() {
Ok(child) => {
let pid = child.id();
dbg!(pid);
self.machine_st.child_processes.insert(pid, child);
let child_process_alloc: TypedArenaPtr<Child> =
arena_alloc!(child, &mut self.machine_st.arena);
unify!(
self.machine_st,
pid_r,
fixnum_as_cell!(Fixnum::build_with(pid))
typed_arena_ptr_as_cell!(child_process_alloc)
);
Ok(())
@@ -8617,44 +8615,84 @@ impl Machine {
})
}
pub(crate) fn process_id(&mut self) -> CallResult {
fn stub_gen() -> Vec<FunctorElement> {
functor_stub(atom!("process_id"), 2)
}
// Process
let process_r = self.deref_register(1);
// Pid
let pid_r = self.deref_register(2);
let Some(ptr) = process_r.to_untyped_arena_ptr() else {
let err = self.machine_st.type_error(ValidType::Process, process_r);
return Err(self.machine_st.error_form(err, stub_gen()));
};
let process = match_untyped_arena_ptr!(ptr,
(ArenaHeaderTag::ChildProcess, child_process) => {
child_process
}
(ArenaHeaderTag::Dropped, _dropped) => {
let err = self.machine_st.existence_error(ExistenceError::Process(process_r));
return Err(self.machine_st.error_form(err, stub_gen()));
}
_ => {
let err = self.machine_st.type_error(ValidType::Process, process_r);
return Err(self.machine_st.error_form(err, stub_gen()));
}
);
self.machine_st.bind(
pid_r.as_var().unwrap(),
fixnum_as_cell!(Fixnum::build_with(process.id())),
);
Ok(())
}
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);
// Process
let process_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(child) = self.machine_st.child_processes.get_mut(&pid) else {
let err = self
.machine_st
.existence_error(ExistenceError::Process(pid_r));
let Some(ptr) = process_r.to_untyped_arena_ptr() else {
let err = self.machine_st.type_error(ValidType::Process, process_r);
return Err(self.machine_st.error_form(err, stub_gen()));
};
let mut process = match_untyped_arena_ptr!(ptr,
(ArenaHeaderTag::ChildProcess, child_process) => {
child_process
}
(ArenaHeaderTag::Dropped, _dropped) => {
let err = self.machine_st.existence_error(ExistenceError::Process(process_r));
return Err(self.machine_st.error_form(err, stub_gen()));
}
_ => {
let err = self.machine_st.type_error(ValidType::Process, process_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),
atom!("infinite") => process.wait().map(Some),
_ => {
panic!("Invalid Timeout value")
}
}
} else if let Some(timeout) = timeout_r.to_fixnum() {
if timeout.get_num() == 0 {
child.try_wait()
process.try_wait()
} else {
panic!("Invalid Timeout value")
}
@@ -8728,23 +8766,28 @@ impl Machine {
}
// 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));
let process_r = self.deref_register(1);
let Some(ptr) = process_r.to_untyped_arena_ptr() else {
let err = self.machine_st.type_error(ValidType::Process, process_r);
return Err(self.machine_st.error_form(err, stub_gen()));
};
let Some(child) = self.machine_st.child_processes.get_mut(&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 mut process = match_untyped_arena_ptr!(ptr,
(ArenaHeaderTag::ChildProcess, child_process) => {
child_process
}
(ArenaHeaderTag::Dropped, _dropped) => {
let err = self.machine_st.existence_error(ExistenceError::Process(process_r));
return Err(self.machine_st.error_form(err, stub_gen()));
}
_ => {
let err = self.machine_st.type_error(ValidType::Process, process_r);
return Err(self.machine_st.error_form(err, stub_gen()));
}
);
if process.kill().is_err() {
let perm_error =
self.machine_st
.permission_error(Permission::Modify, atom!("process"), stub_gen());
@@ -8758,18 +8801,23 @@ impl Machine {
functor_stub(atom!("process_release"), 1)
}
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()));
};
self.machine_st.child_processes.remove(&pid);
Ok(())
let process = self.deref_register(1);
if let Some(ptr) = process.to_untyped_arena_ptr() {
match_untyped_arena_ptr!(ptr,
(ArenaHeaderTag::ChildProcess, child_process) => {
child_process.drop_payload();
return Ok(());
}
_ => {
}
);
}
let err = self.machine_st.type_error(ValidType::Process, process);
Err(self.machine_st.error_form(err, stub_gen()))
}
#[inline(always)]