Files
RedBear-OS/local/archived/patches-2026-06-migration/base/P15-7-init-service-timeout.patch
T
vasilito 89d1306c8d migrate: complete source ownership transition
- Create source symlinks for all 7 core components (kernel, relibc, base,
  bootloader, installer, redoxfs, userutils) pointing at local/sources/
- Create redoxfs and userutils fork repos from frozen 0.1.0 archives
- Fix relibc-tests recipes: replace patch commands with direct fork build
- Archive all 417 patch files to local/archived/patches-2026-06-migration/
- Full AGENTS.md rewrite: remove all 31 remaining stale patch references,
  update DURABILITY POLICY to describe git commit workflow, update WHERE TO
  LOOK table, fix build flow description, replace Recipe Patch Wiring section
  with Recipe Source Configuration
- Zero active patches = [...] arrays remain in any recipe.toml file
- All 13 remaining grep hits for 'patches' are TODO comments in WIP recipes
2026-05-29 22:42:42 +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(