wait for lua child to exit before client exits
* handle sigchld with the self-pipe trick * use libc bindings to poll() to watch that and the socket simultaneously
This commit is contained in:
Generated
+19
@@ -40,6 +40,12 @@ version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "cfg_aliases"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.15.0"
|
||||
@@ -83,6 +89,7 @@ dependencies = [
|
||||
"fork",
|
||||
"libc",
|
||||
"mlua",
|
||||
"nix",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -119,6 +126,18 @@ dependencies = [
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.31.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d6d0705320c1e6ba1d912b5e37cf18071b6c2e9b7fa8215a1e8a7651966f5d3"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"cfg_aliases",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
|
||||
@@ -7,3 +7,4 @@ edition = "2024"
|
||||
fork = "0.7.0"
|
||||
libc = "0.2.186"
|
||||
mlua = { version = "0.11.6", features = ["lua53"] }
|
||||
nix = { version = "0.31.2", features = ["process"] }
|
||||
|
||||
+5
-3
@@ -7,7 +7,8 @@ use std::{
|
||||
SocketAddr
|
||||
},
|
||||
env,
|
||||
io::IoSlice
|
||||
io::IoSlice,
|
||||
process::exit
|
||||
};
|
||||
use std::os::linux::net::SocketAddrExt;
|
||||
|
||||
@@ -36,6 +37,7 @@ fn main() {
|
||||
let buf = IoSlice::new(&payload);
|
||||
sock.send_vectored_with_ancillary(&[buf], &mut ancillary).expect("send failed");
|
||||
|
||||
|
||||
println!("heyt");
|
||||
let mut buf = vec![0u8; 1];
|
||||
let _ = sock.recv(buf.as_mut_slice()).unwrap();
|
||||
exit(buf[0].into());
|
||||
}
|
||||
|
||||
+89
-16
@@ -3,11 +3,12 @@
|
||||
use mlua::Lua;
|
||||
use std::{
|
||||
env,
|
||||
io,
|
||||
io::IoSliceMut,
|
||||
io::Read,
|
||||
path::Path,
|
||||
process::exit,
|
||||
collections::HashMap
|
||||
collections::HashMap,
|
||||
os::fd::AsRawFd
|
||||
};
|
||||
|
||||
use std::os::unix::net::{
|
||||
@@ -18,8 +19,29 @@ use std::os::unix::net::{
|
||||
|
||||
};
|
||||
|
||||
use libc::WEXITSTATUS;
|
||||
use fork::{Fork, fork, waitpid};
|
||||
use libc::{
|
||||
WEXITSTATUS,
|
||||
pollfd,
|
||||
poll,
|
||||
POLLIN,
|
||||
c_void
|
||||
};
|
||||
use nix::sys::wait::{wait,WaitStatus};
|
||||
|
||||
use fork::{Fork, fork};
|
||||
|
||||
static mut sigchild_fd : i32 = -1;
|
||||
|
||||
extern "C" fn handle_sigchld(_: libc::c_int) {
|
||||
unsafe {
|
||||
if sigchild_fd >= 0 {
|
||||
let _ = libc::write(
|
||||
sigchild_fd,
|
||||
"\n".as_ptr() as * const c_void,
|
||||
1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fork_lua(lua : &Lua, args: Vec<String>, fds: Vec<i32>) -> Option<i32> {
|
||||
let pathname = &args[0];
|
||||
@@ -78,6 +100,14 @@ fn main() -> std::io::Result<()> {
|
||||
panic!("need to set LUAD_SOCKET_PATH env var");
|
||||
};
|
||||
|
||||
let Ok((mut sigchild_reader, sigchild_writer)) = std::io::pipe() else {
|
||||
panic!("failed to open pipe for sigchild")
|
||||
};
|
||||
|
||||
unsafe {
|
||||
sigchild_fd = sigchild_writer.as_raw_fd();
|
||||
libc::signal(libc::SIGCHLD, handle_sigchld as libc::sighandler_t);
|
||||
};
|
||||
let lua = unsafe { Lua::unsafe_new() };
|
||||
|
||||
let sock = UnixDatagram::bind(sock_path)?;
|
||||
@@ -89,6 +119,8 @@ fn main() -> std::io::Result<()> {
|
||||
// write the exit status back to the peer
|
||||
// this implies we need a map of child pid -> peer address
|
||||
|
||||
|
||||
|
||||
loop {
|
||||
let mut buf = [0u8; 1024];
|
||||
let mut bufs = [
|
||||
@@ -96,22 +128,63 @@ fn main() -> std::io::Result<()> {
|
||||
];
|
||||
let mut ancillary_buffer = [0; 128];
|
||||
let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
|
||||
match sock.recv_vectored_with_ancillary_from(&mut bufs, &mut ancillary) {
|
||||
Ok((size, truncated, peer)) => {
|
||||
let fds = read_ancillary_data(ancillary);
|
||||
let args = split_command(&buf[..size-1]);
|
||||
println!("args {:?} from {:?}", args, peer);
|
||||
if let Some(child) = fork_lua(&lua, args, fds) {
|
||||
println!("forked {child}");
|
||||
peers.insert(child, peer);
|
||||
}
|
||||
|
||||
let mut pollfds = [
|
||||
pollfd {
|
||||
fd: sock.as_raw_fd(),
|
||||
events: POLLIN,
|
||||
revents: 0,
|
||||
},
|
||||
Err(e) => {
|
||||
println!("error reading: {:?}", e);
|
||||
pollfd {
|
||||
fd: sigchild_reader.as_raw_fd(),
|
||||
events: POLLIN,
|
||||
revents: 0,
|
||||
}
|
||||
}
|
||||
];
|
||||
let n_ready = unsafe { poll(pollfds.as_mut_ptr(), 2, 10000) };
|
||||
if n_ready > 0 {
|
||||
println!("data! {n_ready}, {:?}, {:?}",
|
||||
pollfds[0].revents,
|
||||
pollfds[1].revents
|
||||
);
|
||||
if pollfds[0].revents > 0 {
|
||||
match sock.recv_vectored_with_ancillary_from(&mut bufs, &mut ancillary) {
|
||||
Ok((size, _truncated, peer)) => {
|
||||
let fds = read_ancillary_data(ancillary);
|
||||
let args = split_command(&buf[..size-1]);
|
||||
println!("args {:?} from {:?}", args, peer);
|
||||
if let Some(child) = fork_lua(&lua, args, fds) {
|
||||
println!("forked {child}");
|
||||
peers.insert(child, peer);
|
||||
}
|
||||
|
||||
},
|
||||
Err(e) => {
|
||||
println!("error reading: {:?}", e);
|
||||
}
|
||||
}
|
||||
};
|
||||
if pollfds[1].revents > 0 {
|
||||
println!("a child is done");
|
||||
let mut buf = [0u8;1];
|
||||
let _ = sigchild_reader.read(&mut buf);
|
||||
if let Ok(wstatus) = wait() {
|
||||
if let Some(pid) = wstatus.pid() {
|
||||
match peers.get(&pid.as_raw()) {
|
||||
Some(addr) => {
|
||||
println!("send exit bytes {:?}",
|
||||
sock.send_to_addr(b"\0\n\r\t", addr));
|
||||
},
|
||||
None => {
|
||||
println!("no peer for child");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
} else {
|
||||
println!("timeout");
|
||||
}
|
||||
|
||||
// // println!("parent {:?} {:?}", pid, result);
|
||||
// match waitpid(pid) {
|
||||
|
||||
Reference in New Issue
Block a user