From e3449e7fd9062a7d163be87c1a41519d3752373e Mon Sep 17 00:00:00 2001 From: Filip Tibell Date: Sun, 20 Aug 2023 20:51:42 -0500 Subject: [PATCH] Run process.spawn on separate thread, if possible --- src/lune/builtins/process/mod.rs | 50 ++++++++++++++++++++------------ tests/process/spawn.luau | 5 ---- 2 files changed, 32 insertions(+), 23 deletions(-) diff --git a/src/lune/builtins/process/mod.rs b/src/lune/builtins/process/mod.rs index 8c36235..70d51fe 100644 --- a/src/lune/builtins/process/mod.rs +++ b/src/lune/builtins/process/mod.rs @@ -1,12 +1,13 @@ use std::{ env::{self, consts}, path, - process::Stdio, + process::{ExitStatus, Stdio}, }; use dunce::canonicalize; use mlua::prelude::*; use os_str_bytes::RawOsString; +use tokio::task; use crate::lune::{scheduler::Scheduler, util::TableBuilder}; @@ -163,29 +164,20 @@ async fn process_spawn<'lua>( lua: &'static Lua, (program, args, options): (String, Option>, ProcessSpawnOptions), ) -> LuaResult> { - let inherit_stdio = options.inherit_stdio; - // Spawn the child process - let child = options - .into_command(program, args) - .stdin(Stdio::null()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn()?; - // Inherit the output and stderr if wanted - let result = if inherit_stdio { - pipe_and_inherit_child_process_stdio(child).await - } else { - let output = child.wait_with_output().await?; - Ok((output.status, output.stdout, output.stderr)) - }; - // Extract result - let (status, stdout, stderr) = result?; + // Spawn the new process in the background, + // letting the tokio runtime place it on a + // different thread if necessary, and wait + let (status, stdout, stderr) = task::spawn(spawn_command(program, args, options)) + .await + .into_lua_err()??; + // NOTE: If an exit code was not given by the child process, // we default to 1 if it yielded any error output, otherwise 0 let code = status.code().unwrap_or(match stderr.is_empty() { true => 0, false => 1, }); + // Construct and return a readonly lua table with results TableBuilder::new(lua)? .with_value("ok", code == 0)? @@ -194,3 +186,25 @@ async fn process_spawn<'lua>( .with_value("stderr", lua.create_string(&stderr)?)? .build_readonly() } + +async fn spawn_command( + program: String, + args: Option>, + options: ProcessSpawnOptions, +) -> LuaResult<(ExitStatus, Vec, Vec)> { + let inherit_stdio = options.inherit_stdio; + + let child = options + .into_command(program, args) + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn()?; + + if inherit_stdio { + pipe_and_inherit_child_process_stdio(child).await + } else { + let output = child.wait_with_output().await?; + Ok((output.status, output.stdout, output.stderr)) + } +} diff --git a/tests/process/spawn.luau b/tests/process/spawn.luau index a6ab966..c3537df 100644 --- a/tests/process/spawn.luau +++ b/tests/process/spawn.luau @@ -83,11 +83,6 @@ assert(#homeDir1 > 0, "Home dir from echo was empty") assert(#homeDir2 > 0, "Home dir from pwd was empty") assert(homeDir1 == homeDir2, "Home dirs did not match when performing tilde substitution") --- FIXME: The below tests with sleeping do not work properly and block --- indefinitely, causing cargo test to timeout, for now we error prematurely - -error("FIXME") - --[[ Spawning a process should not block any lua thread(s)