folk_runtime_fork/
runtime.rs1use std::os::unix::io::{FromRawFd, IntoRawFd};
4use std::sync::Arc;
5
6use anyhow::Result;
7use async_trait::async_trait;
8use folk_core::runtime::{Runtime, WorkerHandle};
9use folk_runtime_pipe::socket::create_socketpair;
10use tokio::net::UnixStream;
11use tokio::sync::Mutex;
12
13use crate::handle::ForkWorkerHandle;
14use crate::master::PreforkMaster;
15
16#[derive(Clone)]
18pub struct ForkConfig {
19 pub php: String,
20 pub script: String,
21 pub boot_timeout: std::time::Duration,
22}
23
24pub struct ForkRuntime {
26 _config: ForkConfig,
28 master: Mutex<Option<PreforkMaster>>,
29}
30
31impl ForkRuntime {
32 pub async fn new(config: ForkConfig) -> Result<Arc<Self>> {
34 let master = PreforkMaster::spawn(&config.php, &config.script, config.boot_timeout).await?;
35
36 Ok(Arc::new(Self {
37 _config: config,
38 master: Mutex::new(Some(master)),
39 }))
40 }
41}
42
43#[async_trait]
44#[allow(unsafe_code)]
45impl Runtime for ForkRuntime {
46 async fn spawn(&self) -> Result<Box<dyn WorkerHandle>> {
47 let (task_master, task_child) = create_socketpair()?;
48 let (ctrl_master, ctrl_child) = create_socketpair()?;
49
50 let child_pid = {
51 let mut master_guard = self.master.lock().await;
52 let master = master_guard
53 .as_mut()
54 .ok_or_else(|| anyhow::anyhow!("prefork master not running"))?;
55 master.fork_worker(&task_child, &ctrl_child).await?
56 };
57
58 drop(task_child);
60 drop(ctrl_child);
61
62 let task_stream = {
64 let std_sock =
65 unsafe { std::os::unix::net::UnixStream::from_raw_fd(task_master.into_raw_fd()) };
66 std_sock.set_nonblocking(true)?;
67 UnixStream::from_std(std_sock)?
68 };
69 let ctrl_stream = {
70 let std_sock =
71 unsafe { std::os::unix::net::UnixStream::from_raw_fd(ctrl_master.into_raw_fd()) };
72 std_sock.set_nonblocking(true)?;
73 UnixStream::from_std(std_sock)?
74 };
75
76 Ok(Box::new(ForkWorkerHandle::new(
77 child_pid,
78 task_stream,
79 ctrl_stream,
80 )))
81 }
82}