Skip to content

[WIP] Add native Windows back-end #166

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 109 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
109 commits
Select commit Hold shift + click to select a range
7c3574b
tests: cleanup: Avoid `.pop().unwrap()` in cross_process_sender_trans…
vvuk Sep 9, 2016
d3aeaa5
tests: Add variants of cross-process test, using `spawn()`
vvuk Sep 9, 2016
e38c40c
Add inception channel-in-channel multi-process transfer test
vvuk Dec 15, 2016
596e456
tests: Introduce `which` parameter in `get_channel_name_arg()` helper
antrik Jul 12, 2017
45f8264
tests: Move `get_channel_name_arg()` helper to `src/test.rs`
antrik Jul 12, 2017
5afef48
tests: Introduce `cross_process_embedded_senders_spawn()`
antrik Jul 12, 2017
e3e52a1
tests: cleanup: Streamline structure of `_server()` helpers
antrik Jul 12, 2017
a2529f8
tests: cleanup: Introduce a common `spawn_server()` helper function
antrik Jul 26, 2017
58733f6
tests: cleanup: Avoid need for separate `_server()` pseudo-tests
antrik Jul 26, 2017
1a2df12
Implement ipc-channel on Windows
vvuk Sep 9, 2016
5ceb216
appveyor.yml: Restore testing `inprocess` back-end, not only native one
antrik Nov 5, 2017
68f6b0c
tests: Split out SHM object equality check
antrik Sep 23, 2017
ca0eea6
windows: fix warning: `reader` doesn't need to be mutable
antrik Sep 23, 2017
774f9d0
windows: cleanup: Change suitable plain comments into doc comments
antrik Sep 23, 2017
7ee7690
windows: cleanup: Use more standard indentation for macro
antrik Sep 23, 2017
05fedf6
windows: Move out original handle in `to_receiver()` and `to_sender()`
antrik Sep 24, 2017
2df82b9
windows: Drop unnecessary `&mut self` in a few places
antrik Sep 24, 2017
93fd37e
windows: cleanup: Switch methods for a more logical order
antrik Sep 24, 2017
f9f1eb8
windows: Mark `notify_completion()` as unsafe
antrik Sep 24, 2017
c276d7f
windows: Widen too narrow `unsafe` block
antrik Sep 24, 2017
256e6b6
windows: Drop custom `GetMessageResult` type
antrik Sep 24, 2017
d65a927
windows: More defensive receive buffer handling
antrik Sep 24, 2017
524ef10
[RemoveMe] Temporarily disable most CI targets
antrik Sep 24, 2017
f3360f4
windows: Add explanation why the `ov` structure needs to be boxed
antrik Sep 27, 2017
34eb0c3
windows: Implement `Drop` for `MessageReader`
antrik Sep 27, 2017
c36e495
windows: Consume reader immediately when moving out handle
antrik Sep 28, 2017
ad35a32
windows: Take ownership of handle in `move_handle_to_process()`
antrik Sep 24, 2017
2776819
windows: Assert valid state before consuming receiver
antrik Sep 30, 2017
592e43c
windows: Don't duplicate handle when consuming receiver
antrik Sep 30, 2017
96f9cc2
windows: Remove bogus explicit `impl Send` for `OsIpcSender`
antrik Sep 24, 2017
6c0cd9c
windows: Add a comment explaining the `impl Send` on `OsIpcReceiver`
antrik Sep 30, 2017
ccbd2ee
windows: cleanup: Use enum rather than anonymous bool for blocking mo…
antrik Sep 30, 2017
7a6f069
windows: Improve placement of comments in `receive_message()`
antrik Oct 1, 2017
3fde2fc
windows: Add checks and warnings regarding dangers of `ov` and `read_…
antrik Oct 6, 2017
ec7419a
windows: Shrink unnecessarily wide `unsafe` block
antrik Oct 6, 2017
ce80862
windows: Minor comment fix
antrik Oct 6, 2017
5bebf06
windows: cleanup: More straightforward use of default match case
antrik Oct 6, 2017
40a58bb
windows: Take `WinHandle` rather than `HANDLE` in `write_msg()` and `…
antrik Oct 6, 2017
76334d3
windows: cleanup: Use helper variable consistently
antrik Oct 7, 2017
85f7396
windows: cleanup: Merge `write_msg()` functionality into `write_buf()`
antrik Oct 7, 2017
9962dc8
windows: Shrink an unnecessarily wide `unsafe` block
antrik Oct 7, 2017
f90bc92
windows: Fix overly eager size check
antrik Oct 7, 2017
a43c96c
windows: Fix another overly eager size check
antrik Oct 7, 2017
a51b7c3
windows: Revamp send buffer construction to minimise `unsafe`
antrik Oct 7, 2017
d02db85
windows: Remove trivial `MessageHeader::size()` helper
antrik Oct 7, 2017
9c2b758
windows: Turn `MessageHeader` into normal struct
antrik Oct 7, 2017
033cdd8
windows: Check for errors on SHM unmapping
antrik Oct 7, 2017
faee0c3
windows: Check for errors on file handle closing
antrik Oct 7, 2017
cf2bdac
windows: Add check to make sure we don't leak `OsOpaqueIpcChannel`
antrik Oct 7, 2017
d71a856
windows: Fix SHM mapping for areas larger than 2^32
antrik Oct 7, 2017
17d87bf
windows: Derive `PartialEq` on `WinError`
antrik Oct 7, 2017
628a724
windows: cleanup: Don't intersperse method impls with free-standing f…
antrik Oct 7, 2017
f59a916
windows: cleanup: `start_read()`: Use `match` for error handling
antrik Oct 8, 2017
9bd559b
windows: cleanup: `start_read()`: Consistenly use explicit `return`
antrik Oct 13, 2017
a46741e
windows: cleanup: `start_read()`: Merge handling of identical cases
antrik Oct 13, 2017
9493932
windows: cleanup: `start_read()`: Switch cases for more logical order
antrik Oct 13, 2017
36f16e7
windows: cleanup: `start_read()`: Construct a temporary `Result<>`
antrik Oct 13, 2017
37e67df
windows: cleanup: Drop redundant comment part
antrik Oct 8, 2017
c9b9ad2
windows: Fix misplaced comment
antrik Oct 8, 2017
897f7a2
windows: Drop bogus `Result<>` from `notify_completion()`
antrik Oct 8, 2017
421bafd
windows: Drop bogus comment
antrik Oct 16, 2017
629cb6d
windows: Introduce `MessageReader.fetch_async_result()` helper method
antrik Oct 16, 2017
dee8c98
windows: Move `Send` declaration from `OsIpcReceiver` to `MessageReader`
antrik May 10, 2018
d2d0e68
windows: cleanup: Consume reader in `read_raw_sized()`
antrik Oct 16, 2017
447be23
windows: Avoid code duplication in `read_raw_sized()`
antrik Oct 16, 2017
6b3064e
windows: Take `WinHandle` rather than `HANDLE` in `add_to_iocp()`
antrik Oct 19, 2017
d378a94
windows: Comment on boxing `OVERLAPPED` inside `OsIpcReceiver.accept()`
antrik Oct 21, 2017
66aded8
windows: cleanup: `OsIpcReceiver.accept()`: Unwrap handle at actual u…
antrik Oct 28, 2017
e9bca00
windows: Fix a misleading (outdated?) comment
antrik Oct 29, 2017
6f29e86
windows: cleanup: Use `if let` rather than `is_some()` + `unwrap()`
antrik Oct 29, 2017
0a52f80
windows: cleanup: More idiomatic search code
antrik Oct 29, 2017
62a7754
windows: cleanup: Use `if let` rather than one-arm `match`
antrik Oct 31, 2017
86c0891
windows: Don't explicitly set `ErrorKind::BrokenPipe` on closed sender
antrik Nov 5, 2017
d13aa7c
windows: cleanup: Use `while let` rather than `loop` + `match`
antrik Nov 12, 2017
4fb4e18
windows: refactor: More straightforward "closed" status handling
antrik Nov 12, 2017
9a56344
windows: Don't delay "sender closed" notification from `select()`
antrik Nov 13, 2017
5d164cd
windows: Handle channel closed events directly where possible
antrik Nov 13, 2017
7d6873d
windows: cleanup: Simplify control flow
antrik Apr 30, 2018
5ca5a0d
windows: Introduce `closed_readers` vector instead of `MessageReader.…
antrik Apr 29, 2018
15dd4f2
windows: cleanup: Rename `WinHandle.take()` to `take_raw()`
antrik Apr 29, 2018
eab8460
windows: cleanup: More idiomatic `for` loops
antrik Apr 29, 2018
9925e58
windows: cleanup: More idiomatic use of tuples
antrik Apr 29, 2018
41e3d29
windows: Use `WinHandle` in more places
antrik Apr 29, 2018
85f1eaa
windows: refactor: (Re-)introduce `WinHandle.take()` with expected me…
antrik Apr 29, 2018
ddb4515
windows: Use explicit `as_raw()` on WinHandle instead of `deref()`
antrik Apr 30, 2018
ec94c03
windows: cleanup: Simpler casting for `completion_key`
antrik Apr 30, 2018
c6c5048
windows: cleanup: Tighten scope of `nbytes` local variable
antrik May 1, 2018
27c77ec
windows: cleanup: Streamline handling of reader list in `select()`
antrik May 1, 2018
4a27fe4
windows: Fix `unsafe` coverage in `OsIpcReceiverSet.select()`
antrik May 1, 2018
a46804d
windows: cleanup: Be more explicit about completion key creation
antrik Apr 30, 2018
5732e83
windows: Rename `set_id` to `entry_id`
antrik Apr 30, 2018
4b6f122
windows: cleanup: More idiomatic handling of `io_err`
antrik May 5, 2018
b05b8a6
windows: cleanup: Pass status as a proper `Result<>`
antrik May 5, 2018
464f3a9
windows: cleanup: `match` on errors in `notify_completion()`
antrik May 5, 2018
7ebae59
windows: More defensive `read_in_progress` handling
antrik May 6, 2018
61c21db
windows: Make `MessageReader.ov` optional
antrik May 6, 2018
2963ea5
windows: Drop explicit `read_in_progress` flag
antrik May 6, 2018
7c1ccfa
windows: Avoid leaking unsafety outside `unsafe` blocks
antrik May 7, 2018
95589fa
windows: Clarify comment about `start_read()` for receivers in sets
antrik May 15, 2018
0ecf1cc
windows: Put `ov` and `buf` in the same `AliasedCell<>`
antrik May 14, 2018
33b15fc
windows: Don't ignore `CancelIoEx()` errors
antrik May 15, 2018
62f30b1
windows: Don't panic on unknown errors in `notify_completion()`
antrik May 15, 2018
ebdfe2b
windows: refactor: Split out `OsIpcReceiverSet.fetch_iocp_result()`
antrik May 19, 2018
f646ea2
windows: Make `cancel_io()` sound
antrik May 19, 2018
1e07510
[RemoveMe] Temporarily restore all CI targets using `unix` back-end
antrik May 30, 2018
a7d36e1
WIP: threaded fragment tests
antrik Jun 7, 2018
44f262c
windows: Properly hide all `win32-trace` code behind conditionals
antrik Jun 8, 2018
9a67245
windows: Introduce `MessageReader.get_raw_handle()` debug helper
antrik Jun 8, 2018
fac85e5
windows: Move `handle` into `AsyncData` as well
antrik May 21, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,13 @@ rust:

os:
- linux
- osx

env:
global:
- RUST_BACKTRACE=1
matrix:
- FEATURES="unstable"
- FEATURES="unstable force-inprocess"

matrix:
include:
- os: linux
env: FEATURES="unstable memfd"
- FEATURES="unstable memfd"

notifications:
webhooks: http://build.servo.org:54856/travis
Expand Down
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ force-inprocess = []
memfd = ["sc"]
unstable = []
async = ["futures"]
win32-trace = []

[dependencies]
bincode = "1"
Expand All @@ -30,3 +31,7 @@ futures = { version = "0.1", optional = true }

[dev-dependencies]
crossbeam = "0.2"

[target.'cfg(target_os = "windows")'.dependencies]
winapi = "0.2"
kernel32-sys = "0.2"
5 changes: 2 additions & 3 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ environment:
RUST_BACKTRACE: 1
matrix:
- TARGET: x86_64-pc-windows-msvc
- TARGET: i686-pc-windows-msvc
- TARGET: i686-pc-windows-gnu
FEATURES: "unstable"
install:
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe"
- rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
Expand All @@ -14,4 +13,4 @@ install:
build: false

test_script:
- 'cargo test --verbose --features "unstable"'
- cargo test --verbose --features "%FEATURES%"
8 changes: 7 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![cfg_attr(any(feature = "force-inprocess", target_os = "windows", target_os = "android", target_os = "ios"),
#![cfg_attr(any(feature = "force-inprocess", target_os = "android", target_os = "ios"),
feature(mpsc_select))]
#![cfg_attr(all(feature = "unstable", test), feature(specialization))]

Expand All @@ -18,6 +18,7 @@ extern crate bincode;
extern crate libc;
extern crate rand;
extern crate serde;

#[cfg(any(feature = "force-inprocess", target_os = "windows", target_os = "android", target_os = "ios"))]
extern crate uuid;
extern crate tempfile;
Expand All @@ -38,6 +39,11 @@ extern crate sc;
extern crate futures;


#[cfg(all(not(feature = "force-inprocess"), target_os = "windows"))]
extern crate winapi;
#[cfg(all(not(feature = "force-inprocess"), target_os = "windows"))]
extern crate kernel32;

pub mod ipc;
pub mod platform;
pub mod router;
Expand Down
11 changes: 9 additions & 2 deletions src/platform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,16 @@ mod os {
pub use super::macos::*;
}

#[cfg(any(feature = "force-inprocess", target_os = "windows", target_os = "android", target_os = "ios"))]
#[cfg(all(not(feature = "force-inprocess"), target_os = "windows"))]
mod windows;
#[cfg(all(not(feature = "force-inprocess"), target_os = "windows"))]
mod os {
pub use super::windows::*;
}

#[cfg(any(feature = "force-inprocess", target_os = "android", target_os = "ios"))]
mod inprocess;
#[cfg(any(feature = "force-inprocess", target_os = "windows", target_os = "android", target_os = "ios"))]
#[cfg(any(feature = "force-inprocess", target_os = "android", target_os = "ios"))]
mod os {
pub use super::inprocess::*;
}
Expand Down
156 changes: 151 additions & 5 deletions src/platform/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,15 @@ use std::sync::Arc;
use std::time::{Duration, Instant};
use std::thread;

#[cfg(not(any(feature = "force-inprocess", target_os = "android", target_os = "ios")))]
use libc;
use platform::{OsIpcSender, OsIpcOneShotServer};
#[cfg(not(any(feature = "force-inprocess", target_os = "windows", target_os = "android", target_os = "ios")))]
use libc::{kill, SIGSTOP, SIGCONT};
#[cfg(not(any(feature = "force-inprocess", target_os = "windows", target_os = "android", target_os = "ios")))]
use test::{fork, Wait};
#[cfg(not(any(feature = "force-inprocess", target_os = "android", target_os = "ios")))]
use test::{get_channel_name_arg, spawn_server};

#[test]
fn simple() {
Expand Down Expand Up @@ -173,9 +177,15 @@ fn with_n_fds(n: usize, size: usize) {
let (super_tx, super_rx) = platform::channel().unwrap();

let data: Vec<u8> = (0..size).map(|i| (i % 251) as u8).collect();
super_tx.send(&data[..], sender_fds, vec![]).unwrap();
let thread = {
let data = data.clone();
thread::spawn(move || {
super_tx.send(&data[..], sender_fds, vec![]).unwrap();
})
};
let (received_data, received_channels, received_shared_memory_regions) =
super_rx.recv().unwrap();
thread.join().unwrap();

assert_eq!(received_data.len(), data.len());
assert_eq!(&received_data[..], &data[..]);
Expand All @@ -196,7 +206,8 @@ fn with_n_fds(n: usize, size: usize) {

// These tests only apply to platforms that need fragmentation.
#[cfg(all(not(feature = "force-inprocess"), any(target_os = "linux",
target_os = "freebsd")))]
target_os = "freebsd",
target_os = "windows")))]
mod fragment_tests {
use platform;
use super::with_n_fds;
Expand Down Expand Up @@ -643,9 +654,32 @@ fn server_connect_first() {
(data, vec![], vec![]));
}

#[cfg(not(any(feature = "force-inprocess", target_os = "android", target_os = "ios")))]
#[test]
fn cross_process_spawn() {
let data: &[u8] = b"1234567";

let channel_name = get_channel_name_arg("server");
if let Some(channel_name) = channel_name {
let tx = OsIpcSender::connect(channel_name).unwrap();
tx.send(data, vec![], vec![]).unwrap();

unsafe { libc::exit(0); }
}

let (server, name) = OsIpcOneShotServer::new().unwrap();
let mut child_pid = spawn_server("cross_process_spawn", &[("server", &*name)]);

let (_, received_data, received_channels, received_shared_memory_regions) =
server.accept().unwrap();
child_pid.wait().expect("failed to wait on child");
assert_eq!((&received_data[..], received_channels, received_shared_memory_regions),
(data, vec![], vec![]));
}

#[cfg(not(any(feature = "force-inprocess", target_os = "windows", target_os = "android", target_os = "ios")))]
#[test]
fn cross_process() {
fn cross_process_fork() {
let (server, name) = OsIpcOneShotServer::new().unwrap();
let data: &[u8] = b"1234567";

Expand All @@ -661,9 +695,42 @@ fn cross_process() {
(data, vec![], vec![]));
}

#[cfg(not(any(feature = "force-inprocess", target_os = "android", target_os = "ios")))]
#[test]
fn cross_process_sender_transfer_spawn() {
let channel_name = get_channel_name_arg("server");
if let Some(channel_name) = channel_name {
let super_tx = OsIpcSender::connect(channel_name).unwrap();
let (sub_tx, sub_rx) = platform::channel().unwrap();
let data: &[u8] = b"foo";
super_tx.send(data, vec![OsIpcChannel::Sender(sub_tx)], vec![]).unwrap();
sub_rx.recv().unwrap();
let data: &[u8] = b"bar";
super_tx.send(data, vec![], vec![]).unwrap();

unsafe { libc::exit(0); }
}

let (server, name) = OsIpcOneShotServer::new().unwrap();
let mut child_pid = spawn_server("cross_process_sender_transfer_spawn", &[("server", &*name)]);

let (super_rx, _, mut received_channels, _) = server.accept().unwrap();
assert_eq!(received_channels.len(), 1);
let sub_tx = received_channels[0].to_sender();
let data: &[u8] = b"baz";
sub_tx.send(data, vec![], vec![]).unwrap();

let data: &[u8] = b"bar";
let (received_data, received_channels, received_shared_memory_regions) =
super_rx.recv().unwrap();
child_pid.wait().expect("failed to wait on child");
assert_eq!((&received_data[..], received_channels, received_shared_memory_regions),
(data, vec![], vec![]));
}

#[cfg(not(any(feature = "force-inprocess", target_os = "windows", target_os = "android", target_os = "ios")))]
#[test]
fn cross_process_sender_transfer() {
fn cross_process_sender_transfer_fork() {
let (server, name) = OsIpcOneShotServer::new().unwrap();

let child_pid = unsafe { fork(|| {
Expand All @@ -678,7 +745,7 @@ fn cross_process_sender_transfer() {

let (super_rx, _, mut received_channels, _) = server.accept().unwrap();
assert_eq!(received_channels.len(), 1);
let sub_tx = received_channels.pop().unwrap().to_sender();
let sub_tx = received_channels[0].to_sender();
let data: &[u8] = b"baz";
sub_tx.send(data, vec![], vec![]).unwrap();

Expand Down Expand Up @@ -968,3 +1035,82 @@ mod sync_test {
platform::OsIpcSender::test_not_sync();
}
}

// This test panics on Windows, because the other process will panic
// when it detects that it receives handles that are intended for another
// process. It's marked as ignore/known-fail on Windows for this reason.
//
// TODO -- this fails on OSX as well with a MACH_SEND_INVALID_RIGHT!
// Needs investigation. It may be a similar underlying issue, just done by
// the kernel instead of explicitly (ports in a message that's already
// buffered are intended for only one process).
#[cfg(not(any(feature = "force-inprocess", target_os = "android", target_os = "ios")))]
#[cfg_attr(any(target_os = "windows", target_os = "macos"), ignore)]
#[test]
fn cross_process_two_step_transfer_spawn() {
let cookie: &[u8] = b"cookie";

let channel_name = get_channel_name_arg("server");
if let Some(channel_name) = channel_name {
// connect by name to our other process
let super_tx = OsIpcSender::connect(channel_name).unwrap();

// create a channel for real communication between the two processes
let (sub_tx, sub_rx) = platform::channel().unwrap();

// send the other process the tx side, so it can send us the channels
super_tx.send(&[], vec![OsIpcChannel::Sender(sub_tx)], vec![]).unwrap();

// get two_rx from the other process
let (_, mut received_channels, _) = sub_rx.recv().unwrap();
assert_eq!(received_channels.len(), 1);
let two_rx = received_channels[0].to_receiver();

// get one_rx from two_rx's buffer
let (_, mut received_channels, _) = two_rx.recv().unwrap();
assert_eq!(received_channels.len(), 1);
let one_rx = received_channels[0].to_receiver();

// get a cookie from one_rx
let (data, _, _) = one_rx.recv().unwrap();
assert_eq!(&data[..], cookie);

// finally, send a cookie back
super_tx.send(&data, vec![], vec![]).unwrap();

// terminate
unsafe { libc::exit(0); }
}

// create channel 1
let (one_tx, one_rx) = platform::channel().unwrap();
// put data in channel 1's pipe
one_tx.send(cookie, vec![], vec![]).unwrap();

// create channel 2
let (two_tx, two_rx) = platform::channel().unwrap();
// put channel 1's rx end in channel 2's pipe
two_tx.send(&[], vec![OsIpcChannel::Receiver(one_rx)], vec![]).unwrap();

// create a one-shot server, and spawn another process
let (server, name) = OsIpcOneShotServer::new().unwrap();
let mut child_pid = spawn_server("cross_process_two_step_transfer_spawn",
&[("server", &*name)]);

// The other process will have sent us a transmit channel in received channels
let (super_rx, _, mut received_channels, _) = server.accept().unwrap();
assert_eq!(received_channels.len(), 1);
let sub_tx = received_channels[0].to_sender();

// Send the outer payload channel, so the server can use it to
// retrive the inner payload and the cookie
sub_tx.send(&[], vec![OsIpcChannel::Receiver(two_rx)], vec![]).unwrap();

// Then we wait for the cookie to make its way back to us
let (received_data, received_channels, received_shared_memory_regions) =
super_rx.recv().unwrap();
let child_exit_code = child_pid.wait().expect("failed to wait on child");
assert!(child_exit_code.success());
assert_eq!((&received_data[..], received_channels, received_shared_memory_regions),
(cookie, vec![], vec![]));
}
Loading