Skip to content

Commit

Permalink
Merge pull request #308 from forkgull/no-lazy
Browse files Browse the repository at this point in the history
Remove lazy-static dependency
  • Loading branch information
eminence authored May 6, 2024
2 parents 210c321 + 56b9485 commit a8fab66
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 42 deletions.
1 change: 0 additions & 1 deletion procfs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ serde1 = ["serde", "procfs-core/serde1"]
procfs-core = { path = "../procfs-core", version = "0.16.0-RC1", default-features = false }
rustix = { version = "0.38.19", features = ["fs", "process", "param", "system", "thread"] }
bitflags = { version = "2.0", default-features = false }
lazy_static = "1.0.2"
chrono = {version = "0.4.20", optional = true, features = ["clock"], default-features = false }
hex = "0.4"
flate2 = { version = "1.0.3", optional = true }
Expand Down
27 changes: 1 addition & 26 deletions procfs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@
pub use procfs_core::*;

use bitflags::bitflags;
use lazy_static::lazy_static;

use rustix::fd::AsFd;
use std::collections::HashMap;
Expand Down Expand Up @@ -205,28 +204,6 @@ pub use crate::sys::kernel::BuildInfo as KernelBuildInfo;
pub use crate::sys::kernel::Type as KernelType;
pub use crate::sys::kernel::Version as KernelVersion;

lazy_static! {
/// The number of clock ticks per second.
///
/// This is calculated from `sysconf(_SC_CLK_TCK)`.
static ref TICKS_PER_SECOND: u64 = {
ticks_per_second()
};
/// The version of the currently running kernel.
///
/// This is a lazily constructed static. You can also get this information via
/// [KernelVersion::new()].
static ref KERNEL: ProcResult<KernelVersion> = {
KernelVersion::current()
};
/// Memory page size, in bytes.
///
/// This is calculated from `sysconf(_SC_PAGESIZE)`.
static ref PAGESIZE: u64 = {
page_size()
};
}

/// A wrapper around a `File` that remembers the name of the path
struct FileWrapper {
inner: File,
Expand Down Expand Up @@ -527,9 +504,7 @@ mod tests {

#[test]
fn test_statics() {
println!("{:?}", *TICKS_PER_SECOND);
println!("{:?}", *KERNEL);
println!("{:?}", *PAGESIZE);
println!("{:?}", crate::sys::kernel::Version::cached());
}

#[test]
Expand Down
5 changes: 3 additions & 2 deletions procfs/src/process/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@

use super::*;
use crate::net::{TcpNetEntry, UdpNetEntry};
use crate::sys::kernel::Version;

pub use procfs_core::process::*;
use rustix::fd::{AsFd, BorrowedFd, OwnedFd, RawFd};
Expand Down Expand Up @@ -154,7 +155,7 @@ impl FDInfo {
let p = path.as_ref();
let root = base.as_ref().join(p);
// for 2.6.39 <= kernel < 3.6 fstat doesn't support O_PATH see https://github.com/eminence/procfs/issues/265
let flags = match *crate::KERNEL {
let flags = match Version::cached() {
Ok(v) if v < KernelVersion::new(3, 6, 0) => OFlags::NOFOLLOW | OFlags::CLOEXEC,
Ok(_) => OFlags::NOFOLLOW | OFlags::PATH | OFlags::CLOEXEC,
Err(_) => OFlags::NOFOLLOW | OFlags::PATH | OFlags::CLOEXEC,
Expand Down Expand Up @@ -224,7 +225,7 @@ impl Process {
/// Returns a `Process` based on a specified `/proc/<pid>` path.
pub fn new_with_root(root: PathBuf) -> ProcResult<Process> {
// for 2.6.39 <= kernel < 3.6 fstat doesn't support O_PATH see https://github.com/eminence/procfs/issues/265
let flags = match *crate::KERNEL {
let flags = match Version::cached() {
Ok(v) if v < KernelVersion::new(3, 6, 0) => OFlags::DIRECTORY | OFlags::CLOEXEC,
Ok(_) => OFlags::PATH | OFlags::DIRECTORY | OFlags::CLOEXEC,
Err(_) => OFlags::PATH | OFlags::DIRECTORY | OFlags::CLOEXEC,
Expand Down
40 changes: 38 additions & 2 deletions procfs/src/sys/kernel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
use std::cmp;
use std::collections::HashSet;
use std::str::FromStr;
use std::sync::atomic::{AtomicU32, Ordering};

use bitflags::bitflags;

use crate::{read_value, write_value, ProcError, ProcResult, KERNEL};
use crate::{read_value, write_value, ProcError, ProcResult};

pub mod keys;
pub mod random;
Expand All @@ -34,6 +35,41 @@ impl Version {
read_value("/proc/sys/kernel/osrelease")
}

/// Cached version of the kernel version.
pub(crate) fn cached() -> ProcResult<Self> {
const SENTINEL: u32 = 0;
static KERNEL: AtomicU32 = AtomicU32::new(SENTINEL);

// Try to load the kernel version.
let mut kernel = KERNEL.load(Ordering::Relaxed);

// If we haven't loaded the kernel version yet, try to here.
if kernel == SENTINEL {
kernel = Self::current()?.to_u32();

// Try to store it in the cache.
KERNEL.store(kernel, Ordering::Release);
}

Ok(Self::from_u32(kernel))
}

/// Convert kernel version to an arbitrary `u32` value.
fn to_u32(self) -> u32 {
let [lo, hi] = u16::to_ne_bytes(self.patch);
u32::from_ne_bytes([self.major, self.minor, lo, hi])
}

/// Convert kernel version from an arbitrary `u32` value.
fn from_u32(val: u32) -> Self {
let [major, minor, lo, hi] = u32::to_ne_bytes(val);
Self {
major,
minor,
patch: u16::from_ne_bytes([lo, hi])
}
}

/// Parses a kernel version string, in major.minor.release syntax.
///
/// Note that any extra information (stuff after a dash) is ignored.
Expand Down Expand Up @@ -447,7 +483,7 @@ pub fn threads_max() -> ProcResult<u32> {
/// Since Linux 4.1, this value is bounded, and must be in the range [THREADS_MIN]..=[THREADS_MAX].
/// This function will return an error if that is not the case.
pub fn set_threads_max(new_limit: u32) -> ProcResult<()> {
if let Ok(kernel) = *KERNEL {
if let Ok(kernel) = Version::cached() {
if kernel.major >= 4 && kernel.minor >= 1 && !(THREADS_MIN..=THREADS_MAX).contains(&new_limit) {
return Err(ProcError::Other(format!(
"{} is outside the THREADS_MIN..=THREADS_MAX range",
Expand Down
20 changes: 9 additions & 11 deletions procfs/src/sys/kernel/random.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@
//! Note that some of these entries are only documented in random(4), while some are also documented under proc(5)

use crate::{read_value, write_value, ProcError, ProcResult};
use lazy_static::lazy_static;
use std::path::Path;

lazy_static! {
static ref RANDOM_ROOT: std::path::PathBuf = std::path::PathBuf::from("/proc/sys/kernel/random");
}
const RANDOM_ROOT: &str = "/proc/sys/kernel/random";

/// This read-only file gives the available entropy, in bits. This will be a number in the range
/// 0 to 4096
pub fn entropy_avail() -> ProcResult<u16> {
read_value(RANDOM_ROOT.join("entropy_avail"))
read_value(Path::new(RANDOM_ROOT).join("entropy_avail"))
}

/// This file gives the size of the entropy pool
Expand All @@ -22,7 +20,7 @@ pub fn entropy_avail() -> ProcResult<u16> {
///
/// See `man random(4)` for more information
pub fn poolsize() -> ProcResult<u16> {
read_value(RANDOM_ROOT.join("poolsize"))
read_value(Path::new(RANDOM_ROOT).join("poolsize"))
}

/// This file contains the number of bits of entropy required for waking up processes that sleep waiting
Expand All @@ -33,10 +31,10 @@ pub fn poolsize() -> ProcResult<u16> {
/// This will first attempt to read from `/proc/sys/kernel/random/read_wakeup_threshold` but it
/// will fallback to `/proc/sys/kernel/random/write_wakeup_threshold` if the former file is not found.
pub fn read_wakeup_threshold() -> ProcResult<u32> {
match read_value(RANDOM_ROOT.join("read_wakeup_threshold")) {
match read_value(Path::new(RANDOM_ROOT).join("read_wakeup_threshold")) {
Ok(val) => Ok(val),
Err(err) => match err {
ProcError::NotFound(_) => read_value(RANDOM_ROOT.join("write_wakeup_threshold")),
ProcError::NotFound(_) => read_value(Path::new(RANDOM_ROOT).join("write_wakeup_threshold")),
err => Err(err),
},
}
Expand All @@ -45,17 +43,17 @@ pub fn read_wakeup_threshold() -> ProcResult<u32> {
/// This file contains the number of bits of entropy below which we wake up processes that do a
/// select(2) or poll(2) for write access to /dev/random. These values can be changed by writing to the file.
pub fn write_wakeup_threshold(new_value: u32) -> ProcResult<()> {
write_value(RANDOM_ROOT.join("write_wakeup_threshold"), new_value)
write_value(Path::new(RANDOM_ROOT).join("write_wakeup_threshold"), new_value)
}

/// This read-only file randomly generates a fresh 128-bit UUID on each read
pub fn uuid() -> ProcResult<String> {
read_value(RANDOM_ROOT.join("uuid"))
read_value(Path::new(RANDOM_ROOT).join("uuid"))
}

/// This is a read-only file containing a 128-bit UUID generated at boot
pub fn boot_id() -> ProcResult<String> {
read_value(RANDOM_ROOT.join("boot_id"))
read_value(Path::new(RANDOM_ROOT).join("boot_id"))
}

#[cfg(test)]
Expand Down

0 comments on commit a8fab66

Please sign in to comment.