Skip to content

Commit

Permalink
Use tokio 1.10 for safety on windows
Browse files Browse the repository at this point in the history
  • Loading branch information
passcod committed Aug 13, 2021
1 parent b5599af commit c4d4b88
Show file tree
Hide file tree
Showing 4 changed files with 13 additions and 78 deletions.
15 changes: 5 additions & 10 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,13 @@ exclude = ["/bin", "/.github"]
[dependencies]
async-trait = { version = "0.1.50", optional = true }

[target.'cfg(unix)'.dependencies.nix]
version = "0.22.0"

[target.'cfg(unix)'.dependencies.tokio]
version = "1.9.0"
[dependencies.tokio]
version = "1.10.0"
features = ["macros", "process", "rt"]
optional = true

[target.'cfg(windows)'.dependencies.tokio]
version = "1.9.0"
features = ["macros", "process", "rt", "sync"]
optional = true
[target.'cfg(unix)'.dependencies.nix]
version = "0.22.0"

[target.'cfg(windows)'.dependencies.winapi]
version = "0.3.9"
Expand All @@ -48,7 +43,7 @@ default = []
with-tokio = ["async-trait", "tokio"]

[dev-dependencies]
tokio = { version = "1.9.0", features = ["io-util", "macros", "process", "rt", "rt-multi-thread", "time"] }
tokio = { version = "1.10.0", features = ["io-util", "macros", "process", "rt", "rt-multi-thread", "time"] }

[package.metadata.docs.rs]
all-features = true
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ dbg!(status);
```toml
[dependencies]
command-group = { version = "1.0.4", features = ["with-tokio"] }
tokio = { version = "1.9.0", features = ["full"] }
tokio = { version = "1.10.0", features = ["full"] }
```

```rust
Expand Down
2 changes: 2 additions & 0 deletions src/tokio/child.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,8 @@ impl AsyncGroupChild {
err.read_to_end(&mut stderr).await?;
}
(Some(mut out), Some(mut err)) => {
// TODO: replace with futures crate usage
// and drop macros feature from tokio
tokio::try_join!(out.read_to_end(&mut stdout), err.read_to_end(&mut stderr),)?;
}
}
Expand Down
72 changes: 5 additions & 67 deletions src/tokio/windows.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
use std::{
io::Result,
mem,
os::windows::io::AsRawHandle,
process::{Child as StdChild, ExitStatus},
};
use tokio::{
process::{Child, ChildStderr, ChildStdin, ChildStdout, Command},
sync::oneshot,
};
use winapi::um::{winbase::CREATE_SUSPENDED, winnt::HANDLE};
use std::io::Result;
use tokio::process::Command;
use winapi::um::winbase::CREATE_SUSPENDED;

use crate::{winres::*, AsyncCommandGroup, AsyncGroupChild};

Expand All @@ -17,64 +9,10 @@ impl AsyncCommandGroup for Command {
fn group_spawn(&mut self) -> Result<AsyncGroupChild> {
let (job, completion_port) = job_object()?;
self.creation_flags(CREATE_SUSPENDED);
let child = self.spawn()?;

// this is incredibly unsafe and also relies on:
// - tokio internals staying the same
// - rust layout optimiser not fucking us
// if https://github.com/tokio-rs/tokio/issues/3987 gets done, use it instead!

// we could use transmute_copy here, but I want to rely on the compiler telling me if the
// types change size to get at least maybe a smidge of a chance to catch internals changing.
let uninternal_child: TokioChild = unsafe { mem::transmute(child) };
let handle =
if let TokioChild {
child:
FusedChild::Child(ChildDropGuard {
inner: TokioImpChild { ref child, .. },
..
}),
..
} = uninternal_child
{
child.as_raw_handle()
} else {
panic!("child has exited but it has not even started // OR something unsafe is going on");
};
let child: Child = unsafe { mem::transmute(uninternal_child) };

assign_child(handle, job)?;
let child = self.spawn()?;
assign_child(child.raw_handle().expect("child has exited but it has not even started"), job)?;

Ok(AsyncGroupChild::new(child, job, completion_port))
}
}

struct TokioChild {
child: FusedChild,
_stdin: Option<ChildStdin>,
_stdout: Option<ChildStdout>,
_stderr: Option<ChildStderr>,
}

#[allow(dead_code)]
enum FusedChild {
Child(ChildDropGuard<TokioImpChild>),
Done(ExitStatus),
}

struct ChildDropGuard<T> {
inner: T,
_kill_on_drop: bool,
}

struct TokioImpChild {
child: StdChild,
_waiting: Option<Waiting>,
}

// the only reason why we need the sync feature:
struct Waiting {
_rx: oneshot::Receiver<()>,
_wait_object: HANDLE,
_tx: *mut Option<oneshot::Sender<()>>,
}

0 comments on commit c4d4b88

Please sign in to comment.