Compare commits

..

No commits in common. "420fac5f18c44b6b06c1ab5bb94cb84e658b8556" and "ac53850fd17068a21617db184bda04df75c750b3" have entirely different histories.

11 changed files with 83 additions and 102 deletions

View file

@ -1,10 +0,0 @@
# SPDX-FileCopyrightText: 2026 Qyriad <qyriad@qyriad.me>
#
# SPDX-License-Identifier: EUPL-1.1
# vim: tabstop=2 shiftwidth=0 noexpandtab
[build]
rustflags = [
"-C", "force-frame-pointers=yes",
"-C", "force-unwind-tables=yes",
]

View file

@ -47,19 +47,3 @@ tap = "1.0.1"
tracing = { version = "0.1.44", features = ["attributes"] } tracing = { version = "0.1.44", features = ["attributes"] }
tracing-human-layer = "0.2.1" tracing-human-layer = "0.2.1"
tracing-subscriber = { version = "0.3.22", default-features = false, features = ["std", "env-filter", "fmt", "ansi", "registry", "parking_lot"] } 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

View file

@ -9,11 +9,7 @@
in import src { inherit pkgs; }, in import src { inherit pkgs; },
}: let }: let
inherit (qpkgs) lib; 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; |> qpkgs.stdlib.mkStdenvPretty;
byStdenv = lib.mapAttrs (stdenvName: stdenv: let byStdenv = lib.mapAttrs (stdenvName: stdenv: let
withStdenv = dynix.override { clangStdenv = stdenv; }; withStdenv = dynix.override { clangStdenv = stdenv; };

12
flake.lock generated
View file

@ -3,11 +3,11 @@
"fenix": { "fenix": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1774163246, "lastModified": 1773126504,
"narHash": "sha256-gzlqyLjP44LWraUd3Zn4xrQKOtK+zcBJ77pnsSUsxcM=", "narHash": "sha256-/iXlg2V5UMlgCmyRHkPHjlD6NdMfFOnwFMvH7REigD4=",
"owner": "nix-community", "owner": "nix-community",
"repo": "fenix", "repo": "fenix",
"rev": "4cd28929c68cae521589bc21958d3793904ed1e2", "rev": "64407ddb1932af06ed5cd711f6a2ed946b2548b9",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -37,11 +37,11 @@
"nixpkgs": { "nixpkgs": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1773840656, "lastModified": 1772956932,
"narHash": "sha256-9tpvMGFteZnd3gRQZFlRCohVpqooygFuy9yjuyRL2C0=", "narHash": "sha256-M0yS4AafhKxPPmOHGqIV0iKxgNO8bHDWdl1kOwGBwRY=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "9cf7092bdd603554bd8b63c216e8943cf9b12512", "rev": "608d0cadfed240589a7eea422407a547ad626a14",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -7,23 +7,14 @@
clangStdenv, clangStdenv,
callPackage, callPackage,
linkFarm, linkFarm,
llvmPackages,
rustHooks, rustHooks,
rustPackages, rustPackages,
versionCheckHook, versionCheckHook,
wrapBintoolsWith,
}: lib.callWith' rustPackages ({ }: lib.callWith' rustPackages ({
rustPlatform, rustPlatform,
cargo, cargo,
}: let }: let
# Use LLD for faster link times. stdenv = clangStdenv;
stdenv = clangStdenv.override {
cc = clangStdenv.cc.override {
bintools = wrapBintoolsWith {
bintools = llvmPackages.bintools;
};
};
};
cargoToml = lib.importTOML ./Cargo.toml; cargoToml = lib.importTOML ./Cargo.toml;
cargoPackage = cargoToml.package; cargoPackage = cargoToml.package;
in stdenv.mkDerivation (finalAttrs: let in stdenv.mkDerivation (finalAttrs: let

View file

@ -21,7 +21,7 @@
inherit (pkgs) lib; inherit (pkgs) lib;
mkDevShell = dynix: qpkgs.callPackage dynix.mkDevShell { inherit fenixToolchain; }; 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; byStdenv = lib.mapAttrs (lib.const mkDevShell) dynix.byStdenv;

View file

@ -1,5 +1,5 @@
use std::{ use std::{
env, io, env, io, mem,
ops::Deref, ops::Deref,
os::fd::{AsFd, BorrowedFd, IntoRawFd, OwnedFd, RawFd}, os::fd::{AsFd, BorrowedFd, IntoRawFd, OwnedFd, RawFd},
sync::{ sync::{
@ -26,7 +26,7 @@ use crate::{
use crate::{OwnedFdWithFlags, TokenFd}; use crate::{OwnedFdWithFlags, TokenFd};
pub static UID: LazyLock<Uid> = LazyLock::new(rustix::process::getuid); pub static UID: LazyLock<Uid> = LazyLock::new(|| rustix::process::getuid());
pub static USER_SOCKET_DIR: LazyLock<&'static Path> = LazyLock::new(|| { pub static USER_SOCKET_DIR: LazyLock<&'static Path> = LazyLock::new(|| {
let dir: Box<Path> = env::var_os("XDG_RUNTIME_DIR") let dir: Box<Path> = env::var_os("XDG_RUNTIME_DIR")
@ -52,23 +52,19 @@ pub enum ConvenientAttrPath {
} }
impl ConvenientAttrPath { impl ConvenientAttrPath {
/// Not currently used, but here for completeness.
#[expect(dead_code)]
pub fn clone_from_dotted(s: &str) -> Self { pub fn clone_from_dotted(s: &str) -> Self {
Self::Dotted(Box::from(s)) Self::Dotted(Box::from(s))
} }
/// Not currently used, but here for completeness.
#[expect(dead_code)]
pub fn clone_from_split(s: &[&str]) -> Self { 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 pub fn from_str_iter<'i, I>(iter: I) -> Self
where where
I: Iterator<Item = &'i str>, I: Iterator<Item = &'i str>,
{ {
let boxed = iter.map(Box::from); let boxed = iter.map(|s| Box::from(s));
Self::Split(Box::from_iter(boxed)) Self::Split(Box::from_iter(boxed))
} }
@ -139,6 +135,9 @@ pub struct Daemon {
// Bijective mapping of [`mio::Token`]s to [`RawFd`]s. // Bijective mapping of [`mio::Token`]s to [`RawFd`]s.
tokfd: BiHashMap<TokenFd>, tokfd: BiHashMap<TokenFd>,
cmd_buffer: Vec<u8>,
next_timeout: Option<Duration>,
} }
/// `tokfd` handling. /// `tokfd` handling.
@ -223,8 +222,6 @@ impl Daemon {
.copied() .copied()
} }
/// Not currently used, but here for completeness.
#[expect(dead_code)]
fn token_for_fd(&self, fd: RawFd) -> Option<Token> { fn token_for_fd(&self, fd: RawFd) -> Option<Token> {
self.tokfd self.tokfd
.get2(&fd) .get2(&fd)
@ -258,10 +255,10 @@ impl Daemon {
debug!("opened daemon to {:?} file descriptor {fd:?}", name); debug!("opened daemon to {:?} file descriptor {fd:?}", name);
let path = name let path = match &name {
.as_ref() Some(name) => Some(PathBuf::from(name).into_boxed_path()),
.map(PathBuf::from) None => None,
.map(PathBuf::into_boxed_path); };
Self { Self {
config_path, config_path,
@ -270,6 +267,8 @@ impl Daemon {
poller, poller,
fd_info, fd_info,
tokfd: Default::default(), tokfd: Default::default(),
cmd_buffer: Vec::with_capacity(1024),
next_timeout: TIMEOUT_NEVER,
} }
} }
@ -346,12 +345,16 @@ impl Daemon {
/// Private helpers. /// Private helpers.
impl Daemon { impl Daemon {
fn read_cmd(&mut self, fd: &BorrowedFd) -> Result<(), IoError> { fn read_cmd(&mut self, fd: &BorrowedFd) -> Result<(), IoError> {
// FIXME: don't use a new allocation every time. if self.cmd_buffer.len() == self.cmd_buffer.capacity() {
let mut cmd_buffer: Vec<u8> = Vec::with_capacity(1024); 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}"))?; .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. // The buffer might have existing data from the last read.
let deserializer = serde_json::Deserializer::from_slice(&cmd_buffer); let deserializer = serde_json::Deserializer::from_slice(&cmd_buffer);
let stream: StreamDeserializer<_, DaemonCmd> = deserializer.into_iter(); let stream: StreamDeserializer<_, DaemonCmd> = deserializer.into_iter();
@ -359,13 +362,16 @@ impl Daemon {
let cmd = match cmd { let cmd = match cmd {
Ok(cmd) => cmd, Ok(cmd) => cmd,
Err(e) if e.is_eof() => { Err(e) if e.is_eof() => {
warn!("Got EOF before a valid command"); self.next_timeout = Some(Duration::from_secs(4));
debug!("command buffer was: {:?}", cmd_buffer.as_bstr()); 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(()); return Ok(());
}, },
Err(e) => { Err(e) => {
warn!("error deserializing command: {e}"); warn!("error deserializing command: {e}");
debug!("command buffer was: {:?}", cmd_buffer.as_bstr()); 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. // Don't propagate the error unless we have too many.
self.fd_error_push(fd.as_raw_fd(), e.into()).tap_err(|e| { self.fd_error_push(fd.as_raw_fd(), e.into()).tap_err(|e| {
error!("Accumulated too many errors for daemon fd {fd:?}: {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}")); self.dispatch_cmd(cmd).unwrap_or_else(|e| todo!("{e}"));
} }
cmd_buffer.clear();
let _ = mem::replace(&mut self.cmd_buffer, cmd_buffer);
Ok(()) 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(_) => { Ok(_) => {
trace!( trace!(
"mio::Poller::poll() got events: {:?}", "mio::Poller::poll() got events: {:?}",
events.iter().size_hint().0, events.iter().size_hint().0,
); );
if events.is_empty() { if events.is_empty() {
unreachable!( warn!("timeout expired");
"epoll_wait() with a \"forever\" timeout should never give empty events", 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 => { Err(e) if e.kind() == IoErrorKind::Interrupted => {
// EINTR is silly. // EINTR is silly.

View file

@ -130,7 +130,7 @@ impl From<OwnedFd> for OwnedFdWithFlags {
impl Read for &OwnedFdWithFlags { impl Read for &OwnedFdWithFlags {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, IoError> { fn read(&mut self, buf: &mut [u8]) -> Result<usize, IoError> {
debug_assert!(!buf.is_empty()); debug_assert!(buf.len() > 0);
loop { loop {
buf.fill(0); buf.fill(0);
match rustix::io::read(self.as_ref_owned(), &mut *buf) { match rustix::io::read(self.as_ref_owned(), &mut *buf) {

View file

@ -52,7 +52,7 @@ impl FdInfo {
match Self::guess_name(self.fd) { match Self::guess_name(self.fd) {
Ok(name) => { Ok(name) => {
let prev = self.name.set(name); let prev = self.name.set(Box::from(name));
debug_assert_eq!(prev, Ok(())); debug_assert_eq!(prev, Ok(()));
}, },
Err(e) => { Err(e) => {
@ -105,14 +105,13 @@ impl<'a> Display for FdInfoDisplay<'a> {
} }
#[derive(Copy)] #[derive(Copy)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[non_exhaustive] #[non_exhaustive]
pub enum FdKind { pub enum FdKind {
File, File,
Socket, Socket,
SockStream, SockStream,
Poller, Poller,
#[default]
Unknown, Unknown,
} }
@ -129,6 +128,12 @@ impl FdKind {
} }
} }
impl Default for FdKind {
fn default() -> FdKind {
FdKind::Unknown
}
}
#[derive(Copy)] #[derive(Copy)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TokenFd { pub struct TokenFd {

View file

@ -14,7 +14,7 @@ use tracing_subscriber::{EnvFilter, layer::SubscriberExt};
fn main_wrapped() -> Result<(), Box<dyn StdError + Send + Sync + 'static>> { fn main_wrapped() -> Result<(), Box<dyn StdError + Send + Sync + 'static>> {
// Default RUST_LOG to warn if it's not specified. // 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 { unsafe {
env::set_var("RUST_LOG", "warn"); env::set_var("RUST_LOG", "warn");
} }

View file

@ -5,27 +5,27 @@
#[allow(unused_imports)] #[allow(unused_imports)]
use crate::prelude::*; use crate::prelude::*;
//#[derive(Debug, Clone, PartialEq, Hash)] #[derive(Debug, Clone, PartialEq, Hash)]
//pub(crate) struct NixEvalExpr<E, A> { pub(crate) struct NixEvalExpr<E, A> {
// pub(crate) expr: E, pub(crate) expr: E,
// pub(crate) attrpath: A, pub(crate) attrpath: A,
//} }
//
//impl<E, A> NixEvalExpr<E, A> impl<E, A> NixEvalExpr<E, A>
//where where
// E: AsRef<OsStr>, E: AsRef<OsStr>,
// A: AsRef<OsStr>, A: AsRef<OsStr>,
//{ {
// pub(crate) fn into_command(self) -> Command { pub(crate) fn into_command(self) -> Command {
// let mut cmd = Command::new("nix-instantiate"); let mut cmd = Command::new("nix-instantiate");
// cmd.arg("--eval") cmd.arg("--eval")
// .arg("--json") .arg("--json")
// .arg("--strict") .arg("--strict")
// .arg("--expr") .arg("--expr")
// .arg(self.expr) .arg(self.expr)
// .arg("-A") .arg("-A")
// .arg(self.attrpath); .arg(self.attrpath);
//
// cmd cmd
// } }
//} }