diff --git a/.cargo/config.toml b/.cargo/config.toml deleted file mode 100644 index fdec85a..0000000 --- a/.cargo/config.toml +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-FileCopyrightText: 2026 Qyriad -# -# SPDX-License-Identifier: EUPL-1.1 -# vim: tabstop=2 shiftwidth=0 noexpandtab - -[build] -rustflags = [ - "-C", "force-frame-pointers=yes", - "-C", "force-unwind-tables=yes", -] diff --git a/Cargo.toml b/Cargo.toml index 7408fb0..495e9e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,19 +47,3 @@ tap = "1.0.1" tracing = { version = "0.1.44", features = ["attributes"] } tracing-human-layer = "0.2.1" tracing-subscriber = { version = "0.3.22", default-features = false, features = ["std", "env-filter", "fmt", "ansi", "registry", "parking_lot"] } - -[profile.dev] -opt-level = 1 -lto = "thin" - -[profile.release] -debug = true -debug-assertions = true -lto = true - -[profile.dev.package."*"] -opt-level = 1 - -[profile.release.package."*"] -debug = true -debug-assertions = true diff --git a/default.nix b/default.nix index 697681f..d6a38de 100644 --- a/default.nix +++ b/default.nix @@ -9,11 +9,7 @@ in import src { inherit pkgs; }, }: let inherit (qpkgs) lib; - dynix = (qpkgs.callPackage ./package.nix { }) - .overrideAttrs (final: prev: { - dynixCommand = qpkgs.stdlib.mkStdenvPretty prev.dynixCommand; - dynixModules = qpkgs.stdlib.mkStdenvPretty prev.dynixModules; - }) + dynix = qpkgs.callPackage ./package.nix { } |> qpkgs.stdlib.mkStdenvPretty; byStdenv = lib.mapAttrs (stdenvName: stdenv: let withStdenv = dynix.override { clangStdenv = stdenv; }; diff --git a/flake.lock b/flake.lock index b1ccced..3173a57 100644 --- a/flake.lock +++ b/flake.lock @@ -3,11 +3,11 @@ "fenix": { "flake": false, "locked": { - "lastModified": 1774163246, - "narHash": "sha256-gzlqyLjP44LWraUd3Zn4xrQKOtK+zcBJ77pnsSUsxcM=", + "lastModified": 1773126504, + "narHash": "sha256-/iXlg2V5UMlgCmyRHkPHjlD6NdMfFOnwFMvH7REigD4=", "owner": "nix-community", "repo": "fenix", - "rev": "4cd28929c68cae521589bc21958d3793904ed1e2", + "rev": "64407ddb1932af06ed5cd711f6a2ed946b2548b9", "type": "github" }, "original": { @@ -37,11 +37,11 @@ "nixpkgs": { "flake": false, "locked": { - "lastModified": 1773840656, - "narHash": "sha256-9tpvMGFteZnd3gRQZFlRCohVpqooygFuy9yjuyRL2C0=", + "lastModified": 1772956932, + "narHash": "sha256-M0yS4AafhKxPPmOHGqIV0iKxgNO8bHDWdl1kOwGBwRY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "9cf7092bdd603554bd8b63c216e8943cf9b12512", + "rev": "608d0cadfed240589a7eea422407a547ad626a14", "type": "github" }, "original": { diff --git a/package.nix b/package.nix index fa07871..e5c4f98 100644 --- a/package.nix +++ b/package.nix @@ -7,23 +7,14 @@ clangStdenv, callPackage, linkFarm, - llvmPackages, rustHooks, rustPackages, versionCheckHook, - wrapBintoolsWith, }: lib.callWith' rustPackages ({ rustPlatform, cargo, }: let - # Use LLD for faster link times. - stdenv = clangStdenv.override { - cc = clangStdenv.cc.override { - bintools = wrapBintoolsWith { - bintools = llvmPackages.bintools; - }; - }; - }; + stdenv = clangStdenv; cargoToml = lib.importTOML ./Cargo.toml; cargoPackage = cargoToml.package; in stdenv.mkDerivation (finalAttrs: let diff --git a/shell.nix b/shell.nix index 39cd49f..37ad241 100644 --- a/shell.nix +++ b/shell.nix @@ -21,7 +21,7 @@ inherit (pkgs) lib; mkDevShell = dynix: qpkgs.callPackage dynix.mkDevShell { inherit fenixToolchain; }; - devShell = mkDevShell dynix |> qpkgs.stdlib.mkStdenvPretty; + devShell = mkDevShell dynix; byStdenv = lib.mapAttrs (lib.const mkDevShell) dynix.byStdenv; diff --git a/src/daemon.rs b/src/daemon.rs index 4272486..df477e5 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -1,5 +1,5 @@ use std::{ - env, io, + env, io, mem, ops::Deref, os::fd::{AsFd, BorrowedFd, IntoRawFd, OwnedFd, RawFd}, sync::{ @@ -26,7 +26,7 @@ use crate::{ use crate::{OwnedFdWithFlags, TokenFd}; -pub static UID: LazyLock = LazyLock::new(rustix::process::getuid); +pub static UID: LazyLock = LazyLock::new(|| rustix::process::getuid()); pub static USER_SOCKET_DIR: LazyLock<&'static Path> = LazyLock::new(|| { let dir: Box = env::var_os("XDG_RUNTIME_DIR") @@ -52,23 +52,19 @@ pub enum ConvenientAttrPath { } impl ConvenientAttrPath { - /// Not currently used, but here for completeness. - #[expect(dead_code)] pub fn clone_from_dotted(s: &str) -> Self { Self::Dotted(Box::from(s)) } - /// Not currently used, but here for completeness. - #[expect(dead_code)] pub fn clone_from_split(s: &[&str]) -> Self { - Self::from_str_iter(s.iter().map(Deref::deref)) + Self::from_str_iter(s.into_iter().map(Deref::deref)) } pub fn from_str_iter<'i, I>(iter: I) -> Self where I: Iterator, { - let boxed = iter.map(Box::from); + let boxed = iter.map(|s| Box::from(s)); Self::Split(Box::from_iter(boxed)) } @@ -139,6 +135,9 @@ pub struct Daemon { // Bijective mapping of [`mio::Token`]s to [`RawFd`]s. tokfd: BiHashMap, + + cmd_buffer: Vec, + next_timeout: Option, } /// `tokfd` handling. @@ -223,8 +222,6 @@ impl Daemon { .copied() } - /// Not currently used, but here for completeness. - #[expect(dead_code)] fn token_for_fd(&self, fd: RawFd) -> Option { self.tokfd .get2(&fd) @@ -258,10 +255,10 @@ impl Daemon { debug!("opened daemon to {:?} file descriptor {fd:?}", name); - let path = name - .as_ref() - .map(PathBuf::from) - .map(PathBuf::into_boxed_path); + let path = match &name { + Some(name) => Some(PathBuf::from(name).into_boxed_path()), + None => None, + }; Self { config_path, @@ -270,6 +267,8 @@ impl Daemon { poller, fd_info, tokfd: Default::default(), + cmd_buffer: Vec::with_capacity(1024), + next_timeout: TIMEOUT_NEVER, } } @@ -346,12 +345,16 @@ impl Daemon { /// Private helpers. impl Daemon { fn read_cmd(&mut self, fd: &BorrowedFd) -> Result<(), IoError> { - // FIXME: don't use a new allocation every time. - let mut cmd_buffer: Vec = Vec::with_capacity(1024); + if self.cmd_buffer.len() == self.cmd_buffer.capacity() { + self.cmd_buffer.reserve(1024); + } - let _count = rustix::io::read(fd, spare_capacity(&mut cmd_buffer)) + let _count = rustix::io::read(fd, spare_capacity(&mut self.cmd_buffer)) .tap_err(|e| error!("read() on daemon fd {fd:?} failed: {e}"))?; + // So that the loop doesn't borrow from `self`. + let mut cmd_buffer = mem::take(&mut self.cmd_buffer); + // The buffer might have existing data from the last read. let deserializer = serde_json::Deserializer::from_slice(&cmd_buffer); let stream: StreamDeserializer<_, DaemonCmd> = deserializer.into_iter(); @@ -359,13 +362,16 @@ impl Daemon { let cmd = match cmd { Ok(cmd) => cmd, Err(e) if e.is_eof() => { - warn!("Got EOF before a valid command"); - debug!("command buffer was: {:?}", cmd_buffer.as_bstr()); + self.next_timeout = Some(Duration::from_secs(4)); + warn!("Didn't get a valid daemon command; giving the other side 4 seconds..."); + let _ = mem::replace(&mut self.cmd_buffer, cmd_buffer); return Ok(()); }, Err(e) => { warn!("error deserializing command: {e}"); debug!("command buffer was: {:?}", cmd_buffer.as_bstr()); + cmd_buffer.clear(); + let _ = mem::replace(&mut self.cmd_buffer, cmd_buffer); // Don't propagate the error unless we have too many. self.fd_error_push(fd.as_raw_fd(), e.into()).tap_err(|e| { error!("Accumulated too many errors for daemon fd {fd:?}: {e}") @@ -379,6 +385,9 @@ impl Daemon { self.dispatch_cmd(cmd).unwrap_or_else(|e| todo!("{e}")); } + cmd_buffer.clear(); + let _ = mem::replace(&mut self.cmd_buffer, cmd_buffer); + Ok(()) } @@ -460,19 +469,25 @@ impl Daemon { } } - match self.poller.poll(&mut events, TIMEOUT_NEVER) { + if let Some(timeout) = self.next_timeout { + debug!( + "epoll_wait() with a timeout: {}", + humantime::format_duration(timeout), + ); + } + + match self.poller.poll(&mut events, self.next_timeout.take()) { Ok(_) => { trace!( "mio::Poller::poll() got events: {:?}", events.iter().size_hint().0, ); if events.is_empty() { - unreachable!( - "epoll_wait() with a \"forever\" timeout should never give empty events", - ); + warn!("timeout expired"); + self.cmd_buffer.clear(); + } else { + let _ = self.fd_error_pop(self.poller.as_raw_fd()); } - - let _ = self.fd_error_pop(self.poller.as_raw_fd()); }, Err(e) if e.kind() == IoErrorKind::Interrupted => { // EINTR is silly. diff --git a/src/daemon_io.rs b/src/daemon_io.rs index 9b319b0..891a518 100644 --- a/src/daemon_io.rs +++ b/src/daemon_io.rs @@ -130,7 +130,7 @@ impl From for OwnedFdWithFlags { impl Read for &OwnedFdWithFlags { fn read(&mut self, buf: &mut [u8]) -> Result { - debug_assert!(!buf.is_empty()); + debug_assert!(buf.len() > 0); loop { buf.fill(0); match rustix::io::read(self.as_ref_owned(), &mut *buf) { diff --git a/src/daemon_tokfd.rs b/src/daemon_tokfd.rs index e00f5f2..05d5ec9 100644 --- a/src/daemon_tokfd.rs +++ b/src/daemon_tokfd.rs @@ -52,7 +52,7 @@ impl FdInfo { match Self::guess_name(self.fd) { Ok(name) => { - let prev = self.name.set(name); + let prev = self.name.set(Box::from(name)); debug_assert_eq!(prev, Ok(())); }, Err(e) => { @@ -105,14 +105,13 @@ impl<'a> Display for FdInfoDisplay<'a> { } #[derive(Copy)] -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[non_exhaustive] pub enum FdKind { File, Socket, SockStream, Poller, - #[default] Unknown, } @@ -129,6 +128,12 @@ impl FdKind { } } +impl Default for FdKind { + fn default() -> FdKind { + FdKind::Unknown + } +} + #[derive(Copy)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct TokenFd { diff --git a/src/main.rs b/src/main.rs index e2c5214..a54078e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,7 +14,7 @@ use tracing_subscriber::{EnvFilter, layer::SubscriberExt}; fn main_wrapped() -> Result<(), Box> { // Default RUST_LOG to warn if it's not specified. - if env::var_os("RUST_LOG").is_none() { + if let None = env::var_os("RUST_LOG") { unsafe { env::set_var("RUST_LOG", "warn"); } diff --git a/src/nixcmd.rs b/src/nixcmd.rs index b5e2db5..980d8a0 100644 --- a/src/nixcmd.rs +++ b/src/nixcmd.rs @@ -5,27 +5,27 @@ #[allow(unused_imports)] use crate::prelude::*; -//#[derive(Debug, Clone, PartialEq, Hash)] -//pub(crate) struct NixEvalExpr { -// pub(crate) expr: E, -// pub(crate) attrpath: A, -//} -// -//impl NixEvalExpr -//where -// E: AsRef, -// A: AsRef, -//{ -// pub(crate) fn into_command(self) -> Command { -// let mut cmd = Command::new("nix-instantiate"); -// cmd.arg("--eval") -// .arg("--json") -// .arg("--strict") -// .arg("--expr") -// .arg(self.expr) -// .arg("-A") -// .arg(self.attrpath); -// -// cmd -// } -//} +#[derive(Debug, Clone, PartialEq, Hash)] +pub(crate) struct NixEvalExpr { + pub(crate) expr: E, + pub(crate) attrpath: A, +} + +impl NixEvalExpr +where + E: AsRef, + A: AsRef, +{ + pub(crate) fn into_command(self) -> Command { + let mut cmd = Command::new("nix-instantiate"); + cmd.arg("--eval") + .arg("--json") + .arg("--strict") + .arg("--expr") + .arg(self.expr) + .arg("-A") + .arg(self.attrpath); + + cmd + } +}