@@ -14,7 +14,7 @@ use bytes::Bytes;
1414use proto:: { ConnectionError , ConnectionHandle , ConnectionStats , Dir , StreamEvent , StreamId } ;
1515use rustc_hash:: FxHashMap ;
1616use thiserror:: Error ;
17- use tokio:: sync:: { mpsc, oneshot, Notify } ;
17+ use tokio:: sync:: { mpsc, oneshot} ;
1818use tokio:: time:: { sleep_until, Instant as TokioInstant , Sleep } ;
1919use tracing:: debug_span;
2020use 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 ( ) {
0 commit comments