@@ -25,7 +25,7 @@ use std::{
25
25
atomic:: { AtomicBool , AtomicU16 , AtomicU64 , AtomicUsize , Ordering } ,
26
26
Arc , RwLock ,
27
27
} ,
28
- task:: { Context , Poll } ,
28
+ task:: { Context , Poll , Waker } ,
29
29
time:: { Duration , Instant } ,
30
30
} ;
31
31
@@ -1548,7 +1548,7 @@ impl Handle {
1548
1548
1549
1549
let ( actor_sender, actor_receiver) = mpsc:: channel ( 256 ) ;
1550
1550
let ( relay_actor_sender, relay_actor_receiver) = mpsc:: channel ( 256 ) ;
1551
- let ( relay_datagram_send_tx, relay_datagram_send_rx) = relay_datagram_sender ( ) ;
1551
+ let ( relay_datagram_send_tx, relay_datagram_send_rx) = relay_datagram_send_channel ( ) ;
1552
1552
let ( udp_disco_sender, mut udp_disco_receiver) = mpsc:: channel ( 256 ) ;
1553
1553
1554
1554
// load the node data
@@ -1743,27 +1743,17 @@ enum DiscoBoxError {
1743
1743
///
1744
1744
/// These includes the waker coordination required to support [`AsyncUdpSocket::try_send`]
1745
1745
/// and [`quinn::UdpPoller::poll_writable`].
1746
- ///
1747
- /// Note that this implementation has several bugs in them, but they have existed for rather
1748
- /// a while:
1749
- ///
1750
- /// - There can be multiple senders, which all have to be woken if they were blocked. But
1751
- /// only the last sender to install the waker is unblocked.
1752
- ///
1753
- /// - poll_writable may return blocking when it doesn't need to. Leaving the sender stuck
1754
- /// until another recv is called (which hopefully would happen soon given that the channel
1755
- /// is probably still rather full, but still).
1756
- fn relay_datagram_sender ( ) -> (
1746
+ fn relay_datagram_send_channel ( ) -> (
1757
1747
RelayDatagramSendChannelSender ,
1758
1748
RelayDatagramSendChannelReceiver ,
1759
1749
) {
1760
1750
let ( sender, receiver) = mpsc:: channel ( 256 ) ;
1761
- let waker = Arc :: new ( AtomicWaker :: new ( ) ) ;
1751
+ let wakers = Arc :: new ( std :: sync :: Mutex :: new ( Vec :: new ( ) ) ) ;
1762
1752
let tx = RelayDatagramSendChannelSender {
1763
1753
sender,
1764
- waker : waker . clone ( ) ,
1754
+ wakers : wakers . clone ( ) ,
1765
1755
} ;
1766
- let rx = RelayDatagramSendChannelReceiver { receiver, waker } ;
1756
+ let rx = RelayDatagramSendChannelReceiver { receiver, wakers } ;
1767
1757
( tx, rx)
1768
1758
}
1769
1759
@@ -1774,7 +1764,7 @@ fn relay_datagram_sender() -> (
1774
1764
#[ derive( Debug , Clone ) ]
1775
1765
struct RelayDatagramSendChannelSender {
1776
1766
sender : mpsc:: Sender < RelaySendItem > ,
1777
- waker : Arc < AtomicWaker > ,
1767
+ wakers : Arc < std :: sync :: Mutex < Vec < Waker > > > ,
1778
1768
}
1779
1769
1780
1770
impl RelayDatagramSendChannelSender {
@@ -1788,8 +1778,18 @@ impl RelayDatagramSendChannelSender {
1788
1778
fn poll_writable ( & self , cx : & mut Context ) -> Poll < io:: Result < ( ) > > {
1789
1779
match self . sender . capacity ( ) {
1790
1780
0 => {
1791
- self . waker . register ( cx. waker ( ) ) ;
1792
- Poll :: Pending
1781
+ let mut wakers = self . wakers . lock ( ) . expect ( "poisoned" ) ;
1782
+ if !wakers. iter ( ) . any ( |waker| waker. will_wake ( cx. waker ( ) ) ) {
1783
+ wakers. push ( cx. waker ( ) . clone ( ) ) ;
1784
+ }
1785
+ drop ( wakers) ;
1786
+ if self . sender . capacity ( ) != 0 {
1787
+ // We "risk" a spurious wake-up in this case, but rather that
1788
+ // than potentially skipping a receive.
1789
+ Poll :: Ready ( Ok ( ( ) ) )
1790
+ } else {
1791
+ Poll :: Pending
1792
+ }
1793
1793
}
1794
1794
_ => Poll :: Ready ( Ok ( ( ) ) ) ,
1795
1795
}
@@ -1803,13 +1803,14 @@ impl RelayDatagramSendChannelSender {
1803
1803
#[ derive( Debug ) ]
1804
1804
struct RelayDatagramSendChannelReceiver {
1805
1805
receiver : mpsc:: Receiver < RelaySendItem > ,
1806
- waker : Arc < AtomicWaker > ,
1806
+ wakers : Arc < std :: sync :: Mutex < Vec < Waker > > > ,
1807
1807
}
1808
1808
1809
1809
impl RelayDatagramSendChannelReceiver {
1810
1810
async fn recv ( & mut self ) -> Option < RelaySendItem > {
1811
1811
let item = self . receiver . recv ( ) . await ;
1812
- self . waker . wake ( ) ;
1812
+ let mut wakers = self . wakers . lock ( ) . expect ( "poisoned" ) ;
1813
+ wakers. drain ( ..) . for_each ( Waker :: wake) ;
1813
1814
item
1814
1815
}
1815
1816
}
0 commit comments