Skip to content

Commit

Permalink
Implement ipc-channel on Windows
Browse files Browse the repository at this point in the history
This implementation uses named pipes on Windows, with auto-generated uuid
names.  It takes advantage of DuplicateHandle to clone handles to target
processes when sending handles cross-process.  Shared memory is implemented
using anonymous file mappings.  select() and friends are implemented using
IO Completion Ports.
  • Loading branch information
vvuk authored and antrik committed Aug 16, 2017
1 parent 0480579 commit 309265a
Show file tree
Hide file tree
Showing 6 changed files with 1,538 additions and 21 deletions.
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ repository = "https://github.com/servo/ipc-channel"
force-inprocess = []
memfd = ["syscall"]
unstable = []
win32-trace = []

[dependencies]
bincode = "0.8"
Expand All @@ -27,3 +28,7 @@ syscall = { version = "0.2.1", optional = true }

[dev-dependencies]
crossbeam = "0.2"

[target.'cfg(target_os = "windows")'.dependencies]
winapi = "0.2"
kernel32-sys = "0.2"
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"),
#![cfg_attr(any(feature = "force-inprocess", target_os = "android"),
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"))]
extern crate uuid;
#[cfg(all(not(feature = "force-inprocess"), any(target_os = "linux",
Expand All @@ -32,6 +33,11 @@ extern crate fnv;
extern crate syscall;


#[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 @@ -43,9 +43,16 @@ mod os {
pub use super::macos::*;
}

#[cfg(any(feature = "force-inprocess", target_os = "windows", target_os = "android"))]
#[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"))]
mod inprocess;
#[cfg(any(feature = "force-inprocess", target_os = "windows", target_os = "android"))]
#[cfg(any(feature = "force-inprocess", target_os = "android"))]
mod os {
pub use super::inprocess::*;
}
Expand Down
25 changes: 16 additions & 9 deletions src/platform/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ use std::sync::Arc;
use std::time::{Duration, Instant};
use std::thread;

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

#[test]
Expand Down Expand Up @@ -200,7 +200,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 @@ -648,7 +649,7 @@ fn server_connect_first() {
(data, vec![], vec![]));
}

#[cfg(not(any(feature = "force-inprocess", target_os = "windows", target_os = "android")))]
#[cfg(not(any(feature = "force-inprocess", target_os = "android")))]
#[test]
fn cross_process_spawn() {
let data: &[u8] = b"1234567";
Expand Down Expand Up @@ -689,7 +690,7 @@ fn cross_process_fork() {
(data, vec![], vec![]));
}

#[cfg(not(any(feature = "force-inprocess", target_os = "windows", target_os = "android")))]
#[cfg(not(any(feature = "force-inprocess", target_os = "android")))]
#[test]
fn cross_process_sender_transfer_spawn() {
let channel_name = get_channel_name_arg("server");
Expand Down Expand Up @@ -916,10 +917,16 @@ mod sync_test {
}
}

// TODO -- this fails on OSX with a MACH_SEND_INVALID_RIGHT!
// Needs investigation.
#[cfg(not(any(feature = "force-inprocess", target_os = "windows", target_os = "android")))]
#[cfg_attr(target_os = "macos", ignore)]
// 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")))]
#[cfg_attr(any(target_os = "windows", target_os = "macos"), ignore)]
#[test]
fn cross_process_two_step_transfer_spawn() {
let cookie: &[u8] = b"cookie";
Expand Down
Loading

0 comments on commit 309265a

Please sign in to comment.