Skip to content

Commit cb0af5e

Browse files
committed
Implement windows support
1 parent 52bae94 commit cb0af5e

File tree

26 files changed

+1260
-32
lines changed

26 files changed

+1260
-32
lines changed

.github/workflows/rust.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,35 @@ jobs:
101101
path: /tmp/logs
102102
name: tests-trace-${{ matrix.cgroups }}-${{ matrix.os }}
103103

104+
tests-windows:
105+
strategy:
106+
matrix:
107+
rust-target:
108+
- 'x86_64-pc-windows-gnu'
109+
- 'x86_64-pc-windows-msvc'
110+
runs-on: windows-latest
111+
steps:
112+
- uses: actions/checkout@v2
113+
- uses: actions-rs/toolchain@v1.0.6
114+
with:
115+
toolchain: stable
116+
override: true
117+
- name: Test
118+
run: powershell ci/windows.ps1
119+
timeout-minutes: 5
120+
env:
121+
CI_TARGET: ${{ matrix.rust-target }}
122+
- name: Collect logs
123+
if: always()
124+
run: |
125+
mkdir /tmp/logs
126+
cp ./strace* /tmp/logs
127+
- uses: actions/upload-artifact@v1
128+
if: always()
129+
with:
130+
path: /tmp/logs
131+
name: tests-trace
132+
104133
nightly-checks:
105134
runs-on: ubuntu-20.04
106135
steps:

Cargo.lock

Lines changed: 81 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,25 @@ futures-util = "0.3.12"
2020
tokio = { version = "1.1.0", features = ["net"] }
2121
tracing = "0.1.22"
2222
itoa = "0.4.7"
23+
serde = { version = "1.0.106", features = ["derive"] }
24+
thiserror = "1.0.19"
25+
anyhow = "1.0.32"
26+
futures-util = "0.3.6"
27+
once_cell = "1.4.1"
28+
backtrace = "0.3.46"
29+
30+
[target.'cfg(target_os="linux")'.dependencies]
31+
tiny-nix-ipc = { git = "https://github.com/myfreeweb/tiny-nix-ipc", features = ["ser_json", "zero_copy"] }
32+
procfs = "0.7.8"
33+
nix = {git = "https://github.com/nix-rust/nix"}
34+
libc = "0.2.68"
35+
errno = "0.2.5"
36+
serde_json = "1.0.51"
37+
tokio = { version = "0.3.2", features = ["net"] }
38+
39+
[target.'cfg(target_os="windows")'.dependencies]
40+
winapi = { version = "0.3.9", features = ["std", "processthreadsapi", "jobapi2", "errhandlingapi",
41+
"namedpipeapi", "fileapi", "synchapi", "winnt", "userenv", "handleapi", "securitybaseapi", "sddl"] }
2342

2443
[workspace]
2544
members = ["minion-ffi", ".", "minion-tests", "minion-cli"]

ci/windows.ps1

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
$ErrorActionPreference = "Stop"
2+
3+
Write-Output "::group::Info"
4+
Write-Output "Target: $env:CI_TARGET"
5+
Write-Output "::group::Preparing"
6+
rustup target add $env:CI_TARGET
7+
Write-Output @'
8+
[build]
9+
rustflags=["--cfg", "minion_ci"]
10+
'@ | Out-File -FilePath ./.cargo/config -Encoding 'utf8'
11+
12+
Write-Output "::group::Compiling tests"
13+
$env:RUSTC_BOOTSTRAP = 1
14+
cargo build -p minion-tests -Zunstable-options --out-dir=./out --target=$env:CI_TARGET
15+
16+
if ($LASTEXITCODE -ne 0) {
17+
throw "build failure"
18+
}
19+
20+
Write-Output "::group::Running tests"
21+
$env:RUST_BACKTRACE = 1
22+
./out/minion-tests.exe
23+
if ($LASTEXITCODE -ne 0) {
24+
throw "tests failed"
25+
}

minion-ffi/src/lib.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#![cfg_attr(minion_nightly, warn(unsafe_op_in_unsafe_fn))]
33
use minion::{self};
44
use std::{
5-
ffi::{CStr, OsStr, OsString},
5+
ffi::{CStr, OsString},
66
mem::{self},
77
os::raw::c_char,
88
sync::Arc,
@@ -42,11 +42,23 @@ pub enum WaitOutcome {
4242

4343
/// # Safety
4444
/// `buf` must be valid, readable pointer
45+
#[cfg(target_os = "linux")]
4546
unsafe fn get_string(buf: *const c_char) -> OsString {
4647
use std::os::unix::ffi::OsStrExt;
4748
let buf = unsafe { CStr::from_ptr(buf) };
4849
let buf = buf.to_bytes();
49-
let s = OsStr::from_bytes(buf);
50+
let s = std::ffi::OsStr::from_bytes(buf);
51+
s.to_os_string()
52+
}
53+
/// # Safety
54+
/// `buf` must be valid, readable pointer
55+
#[cfg(target_os = "windows")]
56+
unsafe fn get_string(buf: *const c_char) -> OsString {
57+
use std::os::windows::ffi::OsStringExt;
58+
let buf = unsafe { CStr::from_ptr(buf) };
59+
let buf = buf.to_bytes();
60+
assert!(buf.len() % 2 == 0);
61+
let s = OsString::from_wide(unsafe { buf.align_to::<u16>().1 });
5062
s.to_os_string()
5163
}
5264

minion-tests/Cargo.toml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,13 @@ edition = "2018"
88
once_cell = "1.5.2"
99
minion = {path = ".."}
1010
clap = "2.33.3"
11-
nix = "0.19.1"
1211
tempfile = "3.2.0"
1312
tokio = { version = "1.1.0", features = ["macros", "rt"] }
1413
tracing-subscriber = "0.2.15"
14+
tracing-subscriber = "0.2.15"
15+
16+
[target.'cfg(target_os="linux")'.dependencies]
17+
nix = "0.17.0"
18+
19+
[target.'cfg(target_os="windows")'.dependencies]
20+
winapi = { version = "0.3.9", features = ["processthreadsapi"] }

minion-tests/src/tests/simple.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,18 @@ impl crate::TestCase for TTlFork {
5050
(TODO: verify this is not wall-clock time limit)"
5151
}
5252
fn test(&self) -> ! {
53+
#[cfg(target_os = "linux")]
54+
nix::unistd::fork().unwrap();
55+
#[cfg(target_os = "winfows")]
5356
unsafe {
54-
nix::unistd::fork().unwrap();
57+
winapi::um::processthreadsapi::CreateThread(
58+
std::ptr::null_mut(),
59+
0,
60+
exceed_time_limit,
61+
self,
62+
0,
63+
std::ptr::null_mut(),
64+
);
5565
}
5666
exceed_time_limit()
5767
}
@@ -73,7 +83,12 @@ impl crate::TestCase for TIdle {
7383
checks that it still will be killed"
7484
}
7585
fn test(&self) -> ! {
86+
#[cfg(target_os = "linux")]
7687
nix::unistd::sleep(1_000_000_000);
88+
#[cfg(target_os = "windows")]
89+
unsafe {
90+
winapi::um::synchapi::Sleep(1_000_000_000);
91+
};
7792
std::process::exit(0)
7893
}
7994
fn check(&self, cp: crate::CompletedChild, _: &dyn Sandbox) {
@@ -149,6 +164,7 @@ impl crate::TestCase for TSecurity {
149164
fn description(&self) -> &'static str {
150165
"verifies that isolated program can not make certain bad things"
151166
}
167+
#[cfg(target_os = "linux")]
152168
fn test(&self) -> ! {
153169
// Check we can not read pid1's environment.
154170
let err = std::fs::read("/proc/1/environ").unwrap_err();
@@ -166,6 +182,12 @@ impl crate::TestCase for TSecurity {
166182
assert!(matches!(err, nix::Error::Sys(nix::errno::Errno::EPERM)));
167183
std::process::exit(24)
168184
}
185+
186+
#[cfg(target_os = "windows")]
187+
fn test(&self) -> ! {
188+
std::process::exit(24)
189+
}
190+
169191
fn check(&self, mut cp: crate::CompletedChild, _sb: &dyn Sandbox) {
170192
super::assert_exit_code(cp.by_ref(), minion::ExitCode(24));
171193
super::assert_empty(cp.stdout);

minion-tests/src/worker.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ async fn inner_main(test_cases: &[&'static dyn TestCase]) {
5858
}
5959

6060
pub fn main(test_cases: &[&'static dyn TestCase]) {
61+
tracing_subscriber::fmt().pretty().init();
6162
let rt = tokio::runtime::Builder::new_current_thread()
6263
.enable_all()
6364
.build()

rustfmt.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
unstable_features = true
2-
imports_granularity = "Crate"
2+
imports_granularity = "Crate"

src/erased.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub trait Sandbox: std::fmt::Debug + Send + Sync + 'static {
1818
}
1919

2020
impl<S: crate::Sandbox> Sandbox for S {
21-
fn id(&self) -> String {
21+
fn id(&self) -> &str {
2222
self.id()
2323
}
2424
fn check_cpu_tle(&self) -> anyhow::Result<bool> {
@@ -107,7 +107,11 @@ pub type ChildProcessOptions = crate::ChildProcessOptions<dyn Sandbox>;
107107

108108
/// Returns backend instance
109109
pub fn setup() -> anyhow::Result<Box<dyn Backend>> {
110-
Ok(Box::new(crate::linux::LinuxBackend::new(
110+
#[cfg(target_os = "linux")]
111+
return Ok(Box::new(crate::linux::LinuxBackend::new(
111112
crate::linux::Settings::new(),
112-
)?))
113+
)?));
114+
115+
#[cfg(target_os = "windows")]
116+
return Ok(Box::new(crate::windows::WindowsBackend::new()));
113117
}

0 commit comments

Comments
 (0)