Files
RedBear-OS/local/patches/base/P15-7-init-service-timeout.patch
T
vasilito cee25393d8 fix: boot process improvements — dependency cycle, INIT_NOTIFY, probing loop, and log spam fixes
- Fix P15-8-init-cycle-detection.patch: replace visiting+error with seen+silent-skip
  to eliminate 11 false-positive 'dependency cycle detected' errors on shared deps
- Fix P0-daemon-fix-init-notify-unwrap.patch: remove eprintln! for missing
  INIT_NOTIFY (expected for oneshot_async services, ~7 daemons affected)
- Fix driver-manager hotplug loop: add PERMANENTLY_SKIPPED static set shared
  between hotplug handler and DriverConfig::probe() to stop infinite re-probing
  of Fatal/NotSupported/deferred-exhausted device+driver pairs (e.g. ided)
- Fix driver-manager log_timeline: suppress repeated EPIPE/ENOENT errors with
  AtomicI32 dedup and AtomicBool one-shot guards for boot timeline JSON
- Add driver-manager SIGTERM handler, ACPI bus registration, --status mode,
  driver reap loop, graceful shutdown, and reduced deferred retries (30→3)
2026-05-17 12:34:02 +03:00

80 lines
3.5 KiB
Diff

--- a/init/src/service.rs
+++ b/init/src/service.rs
@@ -1,7 +1,7 @@
use std::collections::{BTreeMap, BTreeSet};
use std::ffi::OsString;
use std::io::Read;
-use std::os::fd::{AsRawFd, OwnedFd};
+use std::os::fd::{AsRawFd, OwnedFd, RawFd};
use std::os::unix::process::CommandExt;
use std::process::Command;
use std::{env, io};
@@ -11,6 +11,23 @@
use crate::color::{init_error, init_warn, status_fail};
use crate::script::subst_env;
+/// Default timeout in seconds for waiting for service readiness notification.
+/// Prevents boot from hanging indefinitely if a daemon fails to notify.
+const SERVICE_READY_TIMEOUT_SECS: u32 = 30;
+
+/// Wait for data to be available on a file descriptor, with a timeout.
+/// Returns true if data is ready, false if timed out.
+fn poll_fd_timeout(fd: RawFd, timeout_secs: u32) -> bool {
+ let mut pollfd = libc::pollfd {
+ fd,
+ events: libc::POLLIN,
+ revents: 0,
+ };
+ let timeout_ms = (timeout_secs as libc::c_int) * 1000;
+ let result = unsafe { libc::poll(&mut pollfd, 1, timeout_ms) };
+ result > 0
+}
+
#[derive(Clone, Debug, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Service {
@@ -75,16 +92,36 @@
let _ = unsafe { libc::close(write_raw) };
match &self.type_ {
- ServiceType::Notify => match read_pipe.read_exact(&mut [0]) {
- Ok(()) => {}
- Err(err) if err.kind() == io::ErrorKind::UnexpectedEof => {
- init_warn(&format!("{:?} exited without notifying readiness", command));
+ ServiceType::Notify => {
+ if !poll_fd_timeout(read_pipe.as_raw_fd(), SERVICE_READY_TIMEOUT_SECS) {
+ init_warn(&format!(
+ "{:?} timed out after {}s waiting for readiness",
+ command, SERVICE_READY_TIMEOUT_SECS
+ ));
+ let _ = child.kill();
+ let _ = child.wait();
+ return;
}
- Err(err) => {
- init_error(&format!("failed to wait for {:?}: {}", command, err));
+ match read_pipe.read_exact(&mut [0]) {
+ Ok(()) => {}
+ Err(err) if err.kind() == io::ErrorKind::UnexpectedEof => {
+ init_warn(&format!("{:?} exited without notifying readiness", command));
+ }
+ Err(err) => {
+ init_error(&format!("failed to wait for {:?}: {}", command, err));
+ }
}
- },
+ }
ServiceType::Scheme(scheme) => {
+ if !poll_fd_timeout(read_pipe.as_raw_fd(), SERVICE_READY_TIMEOUT_SECS) {
+ init_warn(&format!(
+ "{:?} timed out after {}s waiting for scheme registration",
+ command, SERVICE_READY_TIMEOUT_SECS
+ ));
+ let _ = child.kill();
+ let _ = child.wait();
+ return;
+ }
let mut new_fd = usize::MAX;
loop {
match syscall::call_ro(