diff --git a/core/src/bins/startd.rs b/core/src/bins/startd.rs index 487170b82..1d6fd5212 100644 --- a/core/src/bins/startd.rs +++ b/core/src/bins/startd.rs @@ -148,6 +148,15 @@ pub fn main(args: impl IntoIterator) { .build() .expect(&t!("bins.startd.failed-to-initialize-runtime")); let res = rt.block_on(async { + // Periodically wake a worker thread from a non-tokio OS thread to + // prevent tokio I/O driver starvation (all workers parked on + // condvar with no driver). See tokio-rs/tokio#4730. + let rt_handle = tokio::runtime::Handle::current(); + std::thread::spawn(move || loop { + std::thread::sleep(Duration::from_secs(30)); + rt_handle.spawn(async {}); + }); + let mut server = WebServer::new(Acceptor::new(WildcardListener::new(80)?), refresher()); match inner_main(&mut server, &config).await { Ok(a) => { diff --git a/core/src/util/logger.rs b/core/src/util/logger.rs index c2dceed54..eb76e8e82 100644 --- a/core/src/util/logger.rs +++ b/core/src/util/logger.rs @@ -26,6 +26,30 @@ impl<'a> MakeWriter<'a> for LogFile { struct TeeWriter<'a>(MutexGuard<'a, Option>); impl<'a> Write for TeeWriter<'a> { fn write(&mut self, buf: &[u8]) -> io::Result { + // Blocking file+stderr I/O on a tokio worker thread can + // starve the I/O driver (tokio-rs/tokio#4730). + // block_in_place tells the runtime to hand off driver + // duties before we block. Only available on the + // multi-thread runtime; falls back to a direct write on + // current-thread runtimes (CLI) or outside a runtime. + if matches!( + tokio::runtime::Handle::try_current().map(|h| h.runtime_flavor()), + Ok(tokio::runtime::RuntimeFlavor::MultiThread), + ) { + tokio::task::block_in_place(|| self.write_inner(buf)) + } else { + self.write_inner(buf) + } + } + fn flush(&mut self) -> io::Result<()> { + if let Some(f) = &mut *self.0 { + f.flush()?; + } + Ok(()) + } + } + impl<'a> TeeWriter<'a> { + fn write_inner(&mut self, buf: &[u8]) -> io::Result { let n = if let Some(f) = &mut *self.0 { f.write(buf)? } else { @@ -34,12 +58,6 @@ impl<'a> MakeWriter<'a> for LogFile { io::stderr().write_all(&buf[..n])?; Ok(n) } - fn flush(&mut self) -> io::Result<()> { - if let Some(f) = &mut *self.0 { - f.flush()?; - } - Ok(()) - } } Box::new(TeeWriter(f)) } else {