diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..fdec85a --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,10 @@ +# 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 495e9e4..7408fb0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,3 +47,19 @@ 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 d6a38de..697681f 100644 --- a/default.nix +++ b/default.nix @@ -9,7 +9,11 @@ in import src { inherit pkgs; }, }: let inherit (qpkgs) lib; - dynix = qpkgs.callPackage ./package.nix { } + dynix = (qpkgs.callPackage ./package.nix { }) + .overrideAttrs (final: prev: { + dynixCommand = qpkgs.stdlib.mkStdenvPretty prev.dynixCommand; + dynixModules = qpkgs.stdlib.mkStdenvPretty prev.dynixModules; + }) |> qpkgs.stdlib.mkStdenvPretty; byStdenv = lib.mapAttrs (stdenvName: stdenv: let withStdenv = dynix.override { clangStdenv = stdenv; }; diff --git a/flake.lock b/flake.lock index 3173a57..b1ccced 100644 --- a/flake.lock +++ b/flake.lock @@ -3,11 +3,11 @@ "fenix": { "flake": false, "locked": { - "lastModified": 1773126504, - "narHash": "sha256-/iXlg2V5UMlgCmyRHkPHjlD6NdMfFOnwFMvH7REigD4=", + "lastModified": 1774163246, + "narHash": "sha256-gzlqyLjP44LWraUd3Zn4xrQKOtK+zcBJ77pnsSUsxcM=", "owner": "nix-community", "repo": "fenix", - "rev": "64407ddb1932af06ed5cd711f6a2ed946b2548b9", + "rev": "4cd28929c68cae521589bc21958d3793904ed1e2", "type": "github" }, "original": { @@ -37,11 +37,11 @@ "nixpkgs": { "flake": false, "locked": { - "lastModified": 1772956932, - "narHash": "sha256-M0yS4AafhKxPPmOHGqIV0iKxgNO8bHDWdl1kOwGBwRY=", + "lastModified": 1773840656, + "narHash": "sha256-9tpvMGFteZnd3gRQZFlRCohVpqooygFuy9yjuyRL2C0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "608d0cadfed240589a7eea422407a547ad626a14", + "rev": "9cf7092bdd603554bd8b63c216e8943cf9b12512", "type": "github" }, "original": { diff --git a/package.nix b/package.nix index e5c4f98..fa07871 100644 --- a/package.nix +++ b/package.nix @@ -7,14 +7,23 @@ clangStdenv, callPackage, linkFarm, + llvmPackages, rustHooks, rustPackages, versionCheckHook, + wrapBintoolsWith, }: lib.callWith' rustPackages ({ rustPlatform, cargo, }: let - stdenv = clangStdenv; + # Use LLD for faster link times. + stdenv = clangStdenv.override { + cc = clangStdenv.cc.override { + bintools = wrapBintoolsWith { + bintools = llvmPackages.bintools; + }; + }; + }; cargoToml = lib.importTOML ./Cargo.toml; cargoPackage = cargoToml.package; in stdenv.mkDerivation (finalAttrs: let diff --git a/shell.nix b/shell.nix index 37ad241..39cd49f 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; + devShell = mkDevShell dynix |> qpkgs.stdlib.mkStdenvPretty; byStdenv = lib.mapAttrs (lib.const mkDevShell) dynix.byStdenv; diff --git a/src/daemon.rs b/src/daemon.rs index df477e5..4272486 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -1,5 +1,5 @@ use std::{ - env, io, mem, + env, io, 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,19 +52,23 @@ 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.into_iter().map(Deref::deref)) + Self::from_str_iter(s.iter().map(Deref::deref)) } pub fn from_str_iter<'i, I>(iter: I) -> Self where I: Iterator, { - let boxed = iter.map(|s| Box::from(s)); + let boxed = iter.map(Box::from); Self::Split(Box::from_iter(boxed)) } @@ -135,9 +139,6 @@ pub struct Daemon { // Bijective mapping of [`mio::Token`]s to [`RawFd`]s. tokfd: BiHashMap, - - cmd_buffer: Vec, - next_timeout: Option, } /// `tokfd` handling. @@ -222,6 +223,8 @@ 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) @@ -255,10 +258,10 @@ impl Daemon { debug!("opened daemon to {:?} file descriptor {fd:?}", name); - let path = match &name { - Some(name) => Some(PathBuf::from(name).into_boxed_path()), - None => None, - }; + let path = name + .as_ref() + .map(PathBuf::from) + .map(PathBuf::into_boxed_path); Self { config_path, @@ -267,8 +270,6 @@ impl Daemon { poller, fd_info, tokfd: Default::default(), - cmd_buffer: Vec::with_capacity(1024), - next_timeout: TIMEOUT_NEVER, } } @@ -345,16 +346,12 @@ impl Daemon { /// Private helpers. impl Daemon { fn read_cmd(&mut self, fd: &BorrowedFd) -> Result<(), IoError> { - if self.cmd_buffer.len() == self.cmd_buffer.capacity() { - self.cmd_buffer.reserve(1024); - } + // FIXME: don't use a new allocation every time. + let mut cmd_buffer: Vec = Vec::with_capacity(1024); - let _count = rustix::io::read(fd, spare_capacity(&mut self.cmd_buffer)) + let _count = rustix::io::read(fd, spare_capacity(&mut 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(); @@ -362,16 +359,13 @@ impl Daemon { let cmd = match cmd { Ok(cmd) => cmd, Err(e) if e.is_eof() => { - 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); + warn!("Got EOF before a valid command"); + debug!("command buffer was: {:?}", cmd_buffer.as_bstr()); 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}") @@ -385,9 +379,6 @@ 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(()) } @@ -469,25 +460,19 @@ impl Daemon { } } - 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()) { + match self.poller.poll(&mut events, TIMEOUT_NEVER) { Ok(_) => { trace!( "mio::Poller::poll() got events: {:?}", events.iter().size_hint().0, ); if events.is_empty() { - warn!("timeout expired"); - self.cmd_buffer.clear(); - } else { - let _ = self.fd_error_pop(self.poller.as_raw_fd()); + unreachable!( + "epoll_wait() with a \"forever\" timeout should never give empty events", + ); } + + 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 891a518..9b319b0 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.len() > 0); + debug_assert!(!buf.is_empty()); 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 05d5ec9..e00f5f2 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(Box::from(name)); + let prev = self.name.set(name); debug_assert_eq!(prev, Ok(())); }, Err(e) => { @@ -105,13 +105,14 @@ impl<'a> Display for FdInfoDisplay<'a> { } #[derive(Copy)] -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] #[non_exhaustive] pub enum FdKind { File, Socket, SockStream, Poller, + #[default] Unknown, } @@ -128,12 +129,6 @@ 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 a54078e..e2c5214 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 let None = env::var_os("RUST_LOG") { + if env::var_os("RUST_LOG").is_none() { unsafe { env::set_var("RUST_LOG", "warn"); } diff --git a/src/nixcmd.rs b/src/nixcmd.rs index 980d8a0..b5e2db5 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 +// } +//}