diff --git a/src/ipc.rs b/src/ipc.rs index 5967ad9a..746e1363 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -353,8 +353,13 @@ where { /// Create an [IpcSender] connected to a previously defined [IpcOneShotServer]. /// + /// This function should not be called more than once per [IpcOneShotServer], + /// otherwise the behaviour is unpredictable. + /// See [issue 378](https://github.com/servo/ipc-channel/issues/378) for details. + /// /// [IpcSender]: struct.IpcSender.html /// [IpcOneShotServer]: struct.IpcOneShotServer.html + #[deprecated(since = "0.20.0", note = "please use `new_with_connector` instead")] pub fn connect(name: String) -> Result, io::Error> { Ok(IpcSender { os_sender: OsIpcSender::connect(name)?, @@ -871,6 +876,7 @@ impl IpcOneShotServer where T: for<'de> Deserialize<'de> + Serialize, { + #[deprecated(since = "0.20.0", note = "please use `new_with_connector` instead")] pub fn new() -> Result<(IpcOneShotServer, String), io::Error> { let (os_server, name) = OsIpcOneShotServer::new()?; Ok(( @@ -882,6 +888,20 @@ where )) } + pub fn new_with_connector() -> Result<(IpcOneShotServer, IpcConnector), io::Error> { + let (os_server, name) = OsIpcOneShotServer::new()?; + Ok(( + IpcOneShotServer { + os_server, + phantom: PhantomData, + }, + IpcConnector { + name, + phantom: PhantomData, + }, + )) + } + pub fn accept(self) -> Result<(IpcReceiver, T), bincode::Error> { let (os_receiver, ipc_message) = self.os_server.accept()?; Ok(( @@ -894,6 +914,25 @@ where } } +/// A means of connecting to an [IpcOneShotServer]. +/// [IpcOneShotServer]: struct.IpcOneShotServer.html +pub struct IpcConnector { + name: String, + phantom: PhantomData, +} + +impl IpcConnector +where + T: for<'de> Deserialize<'de> + Serialize, +{ + pub fn connect(self) -> Result, io::Error> { + Ok(IpcSender { + os_sender: OsIpcSender::connect(self.name)?, + phantom: PhantomData, + }) + } +} + /// Receiving end of a channel that does not used serialized messages. #[derive(Debug)] pub struct IpcBytesReceiver { diff --git a/src/test.rs b/src/test.rs index 83d01bec..20f086f5 100644 --- a/src/test.rs +++ b/src/test.rs @@ -265,6 +265,34 @@ fn cross_process_embedded_senders_fork() { assert_eq!(received_person, person); } +#[cfg(not(any( + feature = "force-inprocess", + target_os = "windows", + target_os = "android", + target_os = "ios" +)))] +#[test] +fn cross_process_embedded_senders_fork_with_connector() { + let person = ("Patrick Walton".to_owned(), 29); + let (server0, server0_connector) = IpcOneShotServer::new_with_connector().unwrap(); + let (server2, server2_connector) = IpcOneShotServer::new_with_connector().unwrap(); + let child_pid = unsafe { + fork(|| { + let (tx1, rx1): (IpcSender, IpcReceiver) = ipc::channel().unwrap(); + let tx0 = server0_connector.connect().unwrap(); + tx0.send(tx1).unwrap(); + rx1.recv().unwrap(); + let tx2: IpcSender = server2_connector.connect().unwrap(); + tx2.send(person.clone()).unwrap(); + }) + }; + let (_, tx1): (_, IpcSender) = server0.accept().unwrap(); + tx1.send(person.clone()).unwrap(); + let (_, received_person): (_, Person) = server2.accept().unwrap(); + child_pid.wait(); + assert_eq!(received_person, person); +} + #[test] fn router_simple_global() { // Note: All ROUTER operation need to run in a single test,