Skip to content

Commit

Permalink
Deprecate connect() in favour of IpcConnector
Browse files Browse the repository at this point in the history
Introduce IpcConnector as a means of forcing
at most one connect request to a one-shot server.

For a smooth upgrade experience, deprecate new()
and connect() in favour of new_with_connector()
and its connect() method, respectively.

new() will be deleted in a future release at
which point new_with_connector() could be renamed
new().

Note that new_with_connector() does not support
all the usecases of new(), but should be
sufficient for Servo. In particular, it does not
support launching a process passing the name of a
one-shot server to which the process may then
connect.

Ref: servo#378
  • Loading branch information
glyn committed Jan 23, 2025
1 parent b79cc38 commit af0b81f
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 0 deletions.
36 changes: 36 additions & 0 deletions src/ipc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ where
///
/// [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<IpcSender<T>, io::Error> {
Ok(IpcSender {
os_sender: OsIpcSender::connect(name)?,
Expand Down Expand Up @@ -875,6 +876,7 @@ impl<T> IpcOneShotServer<T>
where
T: for<'de> Deserialize<'de> + Serialize,
{
#[deprecated(since="0.20.0", note="please use `new_with_connector` instead")]
pub fn new() -> Result<(IpcOneShotServer<T>, String), io::Error> {
let (os_server, name) = OsIpcOneShotServer::new()?;
Ok((
Expand All @@ -886,6 +888,21 @@ where
))
}

pub fn new_with_connector() -> Result<(IpcOneShotServer<T>, IpcConnector<T>), 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>, T), bincode::Error> {
let (os_receiver, ipc_message) = self.os_server.accept()?;
Ok((
Expand All @@ -898,6 +915,25 @@ where
}
}

/// A means of connecting to an [IpcOneShotServer].
/// [IpcOneShotServer]: struct.IpcOneShotServer.html
pub struct IpcConnector<T> {
name: String,
phantom: PhantomData<T>,
}

impl<T> IpcConnector<T>
where
T: for<'de> Deserialize<'de> + Serialize,
{
pub fn connect(self) -> Result<IpcSender<T>, 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 {
Expand Down
28 changes: 28 additions & 0 deletions src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Person>, IpcReceiver<Person>) = ipc::channel().unwrap();
let tx0 = server0_connector.connect().unwrap();
tx0.send(tx1).unwrap();
rx1.recv().unwrap();
let tx2: IpcSender<Person> = server2_connector.connect().unwrap();
tx2.send(person.clone()).unwrap();
})
};
let (_, tx1): (_, IpcSender<Person>) = 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,
Expand Down

0 comments on commit af0b81f

Please sign in to comment.