(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut ReadBuf<'_>,
)
| 220 | |
| 221 | impl AsyncRead for WasiStdinAsyncRead { |
| 222 | fn poll_read( |
| 223 | mut self: Pin<&mut Self>, |
| 224 | cx: &mut Context<'_>, |
| 225 | buf: &mut ReadBuf<'_>, |
| 226 | ) -> Poll<io::Result<()>> { |
| 227 | let g = GlobalStdin::get(); |
| 228 | |
| 229 | // Everything below is executed under the global stdin lock. It's not |
| 230 | // going to block below so that's semantically fine. Optimization-wise |
| 231 | // it's probably possible to move this within the loop around just a |
| 232 | // small part of reading/writing the state, but that was done |
| 233 | // historically and it resulted in lost wakeups with `Notify`, so this |
| 234 | // is conservatively hoisted up here. |
| 235 | let mut locked = g.state.lock().unwrap(); |
| 236 | |
| 237 | // Perform everything below in a `loop` to handle the case that a read |
| 238 | // was stolen by another thread, for example, or perhaps a spurious |
| 239 | // notification to `Notified`. |
| 240 | loop { |
| 241 | // If we were previously blocked on reading a "ready" notification, |
| 242 | // wait for that notification to complete. |
| 243 | if let Some(notified) = self.as_mut().notified_future() { |
| 244 | match notified.poll(cx) { |
| 245 | Poll::Ready(()) => self.set(WasiStdinAsyncRead::Ready), |
| 246 | Poll::Pending => break Poll::Pending, |
| 247 | } |
| 248 | } |
| 249 | |
| 250 | assert!(matches!(*self, WasiStdinAsyncRead::Ready)); |
| 251 | |
| 252 | // Once we're in the "ready" state then take a look at the global |
| 253 | // state of stdin. |
| 254 | match mem::replace(&mut *locked, StdinState::ReadRequested(buf.remaining())) { |
| 255 | // If data is available then drain what we can into `buf`. |
| 256 | StdinState::Data(mut data) => { |
| 257 | let size = data.len().min(buf.remaining()); |
| 258 | let bytes = data.split_to(size); |
| 259 | *locked = if data.is_empty() { |
| 260 | StdinState::ReadNotRequested |
| 261 | } else { |
| 262 | StdinState::Data(data) |
| 263 | }; |
| 264 | buf.put_slice(&bytes); |
| 265 | break Poll::Ready(Ok(())); |
| 266 | } |
| 267 | |
| 268 | // If stdin failed to be read then we fail with that error and |
| 269 | // transition to "closed" |
| 270 | StdinState::Error(e) => { |
| 271 | *locked = StdinState::Closed; |
| 272 | break Poll::Ready(Err(e)); |
| 273 | } |
| 274 | |
| 275 | // If stdin is closed, keep it closed. |
| 276 | StdinState::Closed => { |
| 277 | *locked = StdinState::Closed; |
| 278 | break Poll::Ready(Ok(())); |
| 279 | } |
nothing calls this directly
no test coverage detected