@@ -2116,7 +2116,7 @@ impl RelayDatagramSendChannelReceiver {
2116
2116
struct RelayDatagramRecvQueue {
2117
2117
queue : ConcurrentQueue < RelayRecvDatagram > ,
2118
2118
recv_waker : AtomicWaker ,
2119
- send_waker : AtomicWaker ,
2119
+ send_wakers : ConcurrentQueue < Waker > ,
2120
2120
}
2121
2121
2122
2122
impl RelayDatagramRecvQueue {
@@ -2125,7 +2125,7 @@ impl RelayDatagramRecvQueue {
2125
2125
Self {
2126
2126
queue : ConcurrentQueue :: bounded ( 512 ) ,
2127
2127
recv_waker : AtomicWaker :: new ( ) ,
2128
- send_waker : AtomicWaker :: new ( ) ,
2128
+ send_wakers : ConcurrentQueue :: unbounded ( ) ,
2129
2129
}
2130
2130
}
2131
2131
@@ -2142,14 +2142,42 @@ impl RelayDatagramRecvQueue {
2142
2142
} )
2143
2143
}
2144
2144
2145
+ /// Polls for whether the queue has free slots for sending items.
2146
+ ///
2147
+ /// If the queue has free slots, this returns [`Poll::Ready`].
2148
+ /// If the queue is full, [`Poll::Pending`] is returned and the waker
2149
+ /// is stored and woken once the queue has free slots.
2150
+ ///
2151
+ /// This can be called from multiple tasks concurrently. If a slot becomes
2152
+ /// available, all stored wakers will be woken simultaneously.
2153
+ /// This also means that even if [`Poll::Ready`] is returned, it is not
2154
+ /// guaranteed that [`Self::try_send`] will return `Ok` on the next call,
2155
+ /// because another send task could have used the slot already.
2145
2156
fn poll_send_ready ( & self , cx : & mut Context < ' _ > ) -> Poll < Result < ( ) > > {
2146
2157
if self . queue . is_closed ( ) {
2147
2158
Poll :: Ready ( Err ( anyhow ! ( "Queue closed" ) ) )
2148
2159
} else if !self . queue . is_full ( ) {
2149
2160
Poll :: Ready ( Ok ( ( ) ) )
2150
2161
} else {
2151
- self . send_waker . register ( cx. waker ( ) ) ;
2152
- Poll :: Pending
2162
+ match self . send_wakers . push ( cx. waker ( ) . clone ( ) ) {
2163
+ Ok ( ( ) ) => Poll :: Pending ,
2164
+ Err ( concurrent_queue:: PushError :: Full ( _) ) => {
2165
+ unreachable ! ( "Send waker queue is unbounded" )
2166
+ }
2167
+ Err ( concurrent_queue:: PushError :: Closed ( _) ) => {
2168
+ Poll :: Ready ( Err ( anyhow ! ( "Queue closed" ) ) )
2169
+ }
2170
+ }
2171
+ }
2172
+ }
2173
+
2174
+ async fn send_ready ( & self ) -> Result < ( ) > {
2175
+ std:: future:: poll_fn ( |cx| self . poll_send_ready ( cx) ) . await
2176
+ }
2177
+
2178
+ fn wake_senders ( & self ) {
2179
+ while let Ok ( waker) = self . send_wakers . pop ( ) {
2180
+ waker. wake ( ) ;
2153
2181
}
2154
2182
}
2155
2183
@@ -2168,28 +2196,28 @@ impl RelayDatagramRecvQueue {
2168
2196
fn poll_recv ( & self , cx : & mut Context ) -> Poll < Result < RelayRecvDatagram > > {
2169
2197
match self . queue . pop ( ) {
2170
2198
Ok ( value) => {
2171
- self . send_waker . wake ( ) ;
2199
+ self . wake_senders ( ) ;
2172
2200
Poll :: Ready ( Ok ( value) )
2173
2201
}
2174
2202
Err ( concurrent_queue:: PopError :: Empty ) => {
2175
2203
self . recv_waker . register ( cx. waker ( ) ) ;
2176
2204
2177
2205
match self . queue . pop ( ) {
2178
2206
Ok ( value) => {
2179
- self . send_waker . wake ( ) ;
2180
2207
self . recv_waker . take ( ) ;
2208
+ self . wake_senders ( ) ;
2181
2209
Poll :: Ready ( Ok ( value) )
2182
2210
}
2183
2211
Err ( concurrent_queue:: PopError :: Empty ) => Poll :: Pending ,
2184
2212
Err ( concurrent_queue:: PopError :: Closed ) => {
2185
2213
self . recv_waker . take ( ) ;
2186
- self . send_waker . wake ( ) ;
2214
+ self . wake_senders ( ) ;
2187
2215
Poll :: Ready ( Err ( anyhow ! ( "Queue closed" ) ) )
2188
2216
}
2189
2217
}
2190
2218
}
2191
2219
Err ( concurrent_queue:: PopError :: Closed ) => {
2192
- self . send_waker . wake ( ) ;
2220
+ self . wake_senders ( ) ;
2193
2221
Poll :: Ready ( Err ( anyhow ! ( "Queue closed" ) ) )
2194
2222
}
2195
2223
}
0 commit comments