Skip to content

Commit 5b2e266

Browse files
committed
Revert Connection::open_{uni, bi} to named 'static futures
1 parent d19ffc3 commit 5b2e266

2 files changed

Lines changed: 74 additions & 39 deletions

File tree

quinn/src/connection.rs

Lines changed: 72 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use bytes::Bytes;
1414
use proto::{ConnectionError, ConnectionHandle, ConnectionStats, Dir, StreamEvent, StreamId};
1515
use rustc_hash::FxHashMap;
1616
use thiserror::Error;
17-
use tokio::sync::{mpsc, oneshot, Notify};
17+
use tokio::sync::{mpsc, oneshot};
1818
use tokio::time::{sleep_until, Instant as TokioInstant, Sleep};
1919
use tracing::debug_span;
2020
use udp::UdpState;
@@ -324,45 +324,22 @@ impl Connection {
324324
/// Streams are cheap and instantaneous to open unless blocked by flow control. As a
325325
/// consequence, the peer won't be notified that a stream has been opened until the stream is
326326
/// actually used.
327-
pub async fn open_uni(&self) -> Result<SendStream, ConnectionError> {
328-
let (id, is_0rtt) = self.open(Dir::Uni).await?;
329-
Ok(SendStream::new(self.0.clone(), id, is_0rtt))
327+
pub fn open_uni(&self) -> OpenUni {
328+
OpenUni {
329+
conn: Some(self.0.clone()),
330+
notify: self.0.lock("open_uni").stream_opening[Dir::Uni as usize].wait(),
331+
}
330332
}
331333

332334
/// Initiate a new outgoing bidirectional stream.
333335
///
334336
/// Streams are cheap and instantaneous to open unless blocked by flow control. As a
335337
/// consequence, the peer won't be notified that a stream has been opened until the stream is
336338
/// actually used.
337-
pub async fn open_bi(&self) -> Result<(SendStream, RecvStream), ConnectionError> {
338-
let (id, is_0rtt) = self.open(Dir::Bi).await?;
339-
Ok((
340-
SendStream::new(self.0.clone(), id, is_0rtt),
341-
RecvStream::new(self.0.clone(), id, is_0rtt),
342-
))
343-
}
344-
345-
async fn open(&self, dir: Dir) -> Result<(StreamId, bool), ConnectionError> {
346-
loop {
347-
let opening;
348-
{
349-
let mut conn = self.0.lock("open");
350-
if let Some(ref e) = conn.error {
351-
return Err(e.clone());
352-
}
353-
if let Some(id) = conn.inner.streams().open(dir) {
354-
let is_0rtt = conn.inner.side().is_client() && conn.inner.is_handshaking();
355-
return Ok((id, is_0rtt));
356-
}
357-
// Clone the `Arc<Notify>` so we can wait on the underlying `Notify` without holding
358-
// the lock. Store it in the outer scope to ensure it outlives the lock guard.
359-
opening = conn.stream_opening[dir as usize].clone();
360-
// Construct the future while the lock is held to ensure we can't miss a wakeup if
361-
// the `Notify` is signaled immediately after we release the lock. `await` it after
362-
// the lock guard is out of scope.
363-
opening.notified()
364-
}
365-
.await
339+
pub fn open_bi(&self) -> OpenBi {
340+
OpenBi {
341+
conn: Some(self.0.clone()),
342+
notify: self.0.lock("open_bi").stream_opening[Dir::Bi as usize].wait(),
366343
}
367344
}
368345

@@ -590,6 +567,63 @@ impl Clone for Connection {
590567
}
591568
}
592569

570+
/// Future produced by [`Connection::open_uni`]
571+
pub struct OpenUni {
572+
conn: Option<ConnectionRef>,
573+
notify: notify::Waiter,
574+
}
575+
576+
impl Future for OpenUni {
577+
type Output = Result<SendStream, ConnectionError>;
578+
fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
579+
let this = &mut *self;
580+
let (conn, id, is_0rtt) =
581+
ready!(poll_open(ctx, &mut this.conn, &mut this.notify, Dir::Uni)?);
582+
Poll::Ready(Ok(SendStream::new(conn, id, is_0rtt)))
583+
}
584+
}
585+
586+
/// Future produced by [`Connection::open_bi`]
587+
pub struct OpenBi {
588+
conn: Option<ConnectionRef>,
589+
notify: notify::Waiter,
590+
}
591+
592+
impl Future for OpenBi {
593+
type Output = Result<(SendStream, RecvStream), ConnectionError>;
594+
fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
595+
let this = &mut *self;
596+
let (conn, id, is_0rtt) =
597+
ready!(poll_open(ctx, &mut this.conn, &mut this.notify, Dir::Bi)?);
598+
599+
Poll::Ready(Ok((
600+
SendStream::new(conn.clone(), id, is_0rtt),
601+
RecvStream::new(conn, id, is_0rtt),
602+
)))
603+
}
604+
}
605+
606+
fn poll_open(
607+
ctx: &mut Context<'_>,
608+
conn_storage: &mut Option<ConnectionRef>,
609+
notify: &mut notify::Waiter,
610+
dir: Dir,
611+
) -> Poll<Result<(ConnectionRef, StreamId, bool), ConnectionError>> {
612+
let mut conn = conn_storage.as_ref().unwrap().lock("poll_open");
613+
if let Some(ref e) = conn.error {
614+
Poll::Ready(Err(e.clone()))
615+
} else if let Some(id) = conn.inner.streams().open(dir) {
616+
let is_0rtt = conn.inner.side().is_client() && conn.inner.is_handshaking();
617+
drop(conn); // Release the borrow so it can be passed to `RecvStream`
618+
let conn = conn_storage.take().expect("polled after completion");
619+
Poll::Ready(Ok((conn, id, is_0rtt)))
620+
} else {
621+
// `conn` lock ensures we don't race with readiness
622+
notify.register(ctx);
623+
Poll::Pending
624+
}
625+
}
626+
593627
/// A stream of unidirectional QUIC streams initiated by a remote peer.
594628
///
595629
/// Incoming streams are *always* opened in the same order that the peer created them, but data can
@@ -824,7 +858,7 @@ impl ConnectionRef {
824858
endpoint_events,
825859
blocked_writers: FxHashMap::default(),
826860
blocked_readers: FxHashMap::default(),
827-
stream_opening: [Arc::new(Notify::new()), Arc::new(Notify::new())],
861+
stream_opening: [NotifyOwned::new(), NotifyOwned::new()],
828862
incoming_uni_streams_reader: None,
829863
stream_incoming: [NotifyOwned::new(), NotifyOwned::new()],
830864
incoming_bi_streams_reader: None,
@@ -886,7 +920,7 @@ pub struct ConnectionInner {
886920
endpoint_events: mpsc::UnboundedSender<(ConnectionHandle, EndpointEvent)>,
887921
pub(crate) blocked_writers: FxHashMap<StreamId, Waker>,
888922
pub(crate) blocked_readers: FxHashMap<StreamId, Waker>,
889-
stream_opening: [Arc<Notify>; 2],
923+
stream_opening: [NotifyOwned; 2],
890924
incoming_uni_streams_reader: Option<Waker>,
891925
incoming_bi_streams_reader: Option<Waker>,
892926
stream_incoming: [NotifyOwned; 2],
@@ -1014,7 +1048,7 @@ impl ConnectionInner {
10141048
}
10151049
}
10161050
Stream(StreamEvent::Available { dir }) => {
1017-
self.stream_opening[dir as usize].notify_one();
1051+
self.stream_opening[dir as usize].notify_all();
10181052
}
10191053
Stream(StreamEvent::Finished { id }) => {
10201054
if let Some(finishing) = self.finishing.remove(&id) {
@@ -1106,8 +1140,8 @@ impl ConnectionInner {
11061140
for (_, reader) in self.blocked_readers.drain() {
11071141
reader.wake()
11081142
}
1109-
self.stream_opening[Dir::Uni as usize].notify_waiters();
1110-
self.stream_opening[Dir::Bi as usize].notify_waiters();
1143+
self.stream_opening[Dir::Uni as usize].notify_all();
1144+
self.stream_opening[Dir::Bi as usize].notify_all();
11111145
self.stream_incoming[Dir::Uni as usize].notify_all();
11121146
self.stream_incoming[Dir::Bi as usize].notify_all();
11131147
if let Some(x) = self.incoming_uni_streams_reader.take() {

quinn/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ pub use proto::{
7171

7272
pub use crate::connection::{
7373
AcceptBi, AcceptUni, Connecting, Connection, Datagrams, IncomingBiStreams, IncomingUniStreams,
74-
NewConnection, ReadDatagram, SendDatagramError, UnknownStream, ZeroRttAccepted,
74+
NewConnection, OpenBi, OpenUni, ReadDatagram, SendDatagramError, UnknownStream,
75+
ZeroRttAccepted,
7576
};
7677
pub use crate::endpoint::{Endpoint, Incoming};
7778
pub use crate::recv_stream::{ReadError, ReadExactError, ReadToEndError, RecvStream};

0 commit comments

Comments
 (0)