folk_runtime_pipe/
spawn.rs1use std::os::fd::{AsRawFd, FromRawFd, IntoRawFd};
4
5use anyhow::Result;
6use tokio::net::UnixStream;
7use tokio::process::Command;
8use tracing::debug;
9
10use crate::socket::create_socketpair;
11
12pub const TASK_FD: libc::c_int = 3;
14pub const CONTROL_FD: libc::c_int = 4;
15
16pub struct SpawnedWorker {
18 pub child: tokio::process::Child,
19 pub task_master: UnixStream,
20 pub control_master: UnixStream,
21}
22
23#[allow(unsafe_code)]
36pub fn spawn_worker(php: &str, script: &str) -> Result<SpawnedWorker> {
37 let (task_master_fd, task_child_fd) = create_socketpair()?;
38 let (ctrl_master_fd, ctrl_child_fd) = create_socketpair()?;
39
40 let task_child_raw = task_child_fd.as_raw_fd();
41 let ctrl_child_raw = ctrl_child_fd.as_raw_fd();
42
43 let mut cmd = Command::new(php);
44 cmd.arg(script)
45 .env("FOLK_RUNTIME", "pipe")
46 .env("FOLK_TASK_FD", TASK_FD.to_string())
47 .env("FOLK_CONTROL_FD", CONTROL_FD.to_string())
48 .stdin(std::process::Stdio::null())
49 .stdout(std::process::Stdio::piped())
50 .stderr(std::process::Stdio::piped());
51
52 unsafe {
55 cmd.pre_exec(move || {
56 if libc::dup2(task_child_raw, TASK_FD) < 0 {
57 return Err(std::io::Error::last_os_error());
58 }
59 if libc::dup2(ctrl_child_raw, CONTROL_FD) < 0 {
60 return Err(std::io::Error::last_os_error());
61 }
62
63 if task_child_raw != TASK_FD {
64 libc::close(task_child_raw);
65 }
66 if ctrl_child_raw != CONTROL_FD {
67 libc::close(ctrl_child_raw);
68 }
69
70 libc::fcntl(TASK_FD, libc::F_SETFD, 0);
71 libc::fcntl(CONTROL_FD, libc::F_SETFD, 0);
72
73 Ok(())
74 });
75 }
76
77 let child = cmd.spawn()?;
78
79 drop(task_child_fd);
80 drop(ctrl_child_fd);
81
82 let task_master = {
83 let std_sock =
84 unsafe { std::os::unix::net::UnixStream::from_raw_fd(task_master_fd.into_raw_fd()) };
85 std_sock.set_nonblocking(true)?;
86 UnixStream::from_std(std_sock)?
87 };
88
89 let control_master = {
90 let std_sock =
91 unsafe { std::os::unix::net::UnixStream::from_raw_fd(ctrl_master_fd.into_raw_fd()) };
92 std_sock.set_nonblocking(true)?;
93 UnixStream::from_std(std_sock)?
94 };
95
96 debug!(pid = ?child.id(), "worker spawned");
97
98 Ok(SpawnedWorker {
99 child,
100 task_master,
101 control_master,
102 })
103}