Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of a split crate scheme. #257

Merged
merged 7 commits into from
Apr 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@ jobs:
toolchain: ${{ matrix.toolchain }}

- name: Build
run: cargo +${{ matrix.toolchain }} build --verbose
run: cargo +${{ matrix.toolchain }} build --workspace --verbose
- name: Run tests
run: cargo +${{ matrix.toolchain }} test --all-features --verbose -- --skip _runsinglethread
run: cargo +${{ matrix.toolchain }} test --workspace --all-features --verbose -- --skip _runsinglethread
- name: Run tests (single-threaded tests)
run: cargo +${{ matrix.toolchain }} test --all-features --verbose -- _runsinglethread --test-threads 1
run: cargo +${{ matrix.toolchain }} test --workspace --all-features --verbose -- _runsinglethread --test-threads 1

- name: Build docs (all features)
run: cargo +${{ matrix.toolchain }} doc --all-features
run: cargo +${{ matrix.toolchain }} doc --workspace --all-features

- name: Build docs
run: cargo +${{ matrix.toolchain }} doc
run: cargo +${{ matrix.toolchain }} doc --workspace


check:
Expand All @@ -59,7 +59,7 @@ jobs:
target: i686-unknown-linux-gnu

- name: cargo check (aarch64)
run: cargo +${{ matrix.toolchain }} check --target aarch64-linux-android --all-features
run: cargo +${{ matrix.toolchain }} check --workspace --target aarch64-linux-android --all-features
- name: cargo check (i686)
run: cargo +${{ matrix.toolchain }} check --target i686-unknown-linux-gnu --all-features
run: cargo +${{ matrix.toolchain }} check --workspace --target i686-unknown-linux-gnu --all-features

40 changes: 7 additions & 33 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,41 +1,15 @@
[package]
name = "procfs"
[workspace]
members = [
"procfs",
"procfs-core",
]

[workspace.package]
version = "0.15.1"
authors = ["Andrew Chin <achin@eminence32.net>"]
repository = "/~https://github.com/eminence/procfs"
documentation = "https://docs.rs/procfs/"
description = "Interface to the linux procfs pseudo-filesystem"
readme = "README.md"
keywords = ["procfs", "proc", "linux", "process"]
categories = ["os::unix-apis", "filesystem"]
license = "MIT OR Apache-2.0"
edition = "2018"
rust-version = "1.48"

[features]
default = ["chrono", "flate2"]
serde1 = ["serde"]

[dependencies]
rustix = { version = "0.37.0", features = ["fs", "process", "param", "thread"] }
bitflags = "1.2"
lazy_static = "1.0.2"
chrono = {version = "0.4.20", optional = true, features = ["clock"], default-features = false }
byteorder = {version="1.2.3", features=["i128"]}
hex = "0.4"
flate2 = { version = "1.0.3", optional = true }
backtrace = { version = "0.3", optional = true }
serde = { version = "1.0", features = ["derive"], optional = true }

[dev-dependencies]
criterion = "0.4"
procinfo = "0.4.2"
failure = "0.1"
libc = "0.2.139"

[package.metadata.docs.rs]
all-features = true

[[bench]]
name = "cpuinfo"
harness = false
7 changes: 0 additions & 7 deletions examples/pressure.rs

This file was deleted.

27 changes: 27 additions & 0 deletions procfs-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[package]
name = "procfs-core"
documentation = "https://docs.rs/procfs-core/"
description = "Data structures and parsing for the linux procfs pseudo-filesystem"
readme = "../README.md"
version.workspace = true
authors.workspace = true
repository.workspace = true
keywords.workspace = true
categories.workspace = true
license.workspace = true
edition.workspace = true
rust-version.workspace = true

[features]
default = ["chrono"]
serde1 = ["serde"]

[dependencies]
backtrace = { version = "0.3", optional = true }
bitflags = "1.2"
chrono = { version = "0.4.20", optional = true, features = ["clock"], default-features = false }
hex = "0.4"
serde = { version = "1.0", features = ["derive"], optional = true }

[package.metadata.docs.rs]
all-features = true
103 changes: 37 additions & 66 deletions src/cgroups.rs → procfs-core/src/cgroups.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
use crate::ProcResult;

use super::process::Process;

#[cfg(feature = "serde1")]
use serde::{Deserialize, Serialize};
use std::io::BufRead;

#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
/// Container group controller information.
///
/// See also the [cgroups()] method.
pub struct CGroupController {
/// The name of the controller.
pub name: String,
Expand All @@ -28,49 +24,45 @@ pub struct CGroupController {
pub enabled: bool,
}

/// Information about the cgroup controllers that are compiled into the kernel
///
/// (since Linux 2.6.24)
// This is returning a vector, but if each subsystem name is unique, maybe this can be a hashmap
// instead
pub fn cgroups() -> ProcResult<Vec<CGroupController>> {
use std::fs::File;
use std::io::{BufRead, BufReader};
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
/// Container group controller information.
// This contains a vector, but if each subsystem name is unique, maybe this can be a
// hashmap instead
pub struct CGroupControllers(pub Vec<CGroupController>);

let file = File::open("/proc/cgroups")?;
let reader = BufReader::new(file);
impl crate::FromBufRead for CGroupControllers {
fn from_buf_read<R: BufRead>(reader: R) -> ProcResult<Self> {
let mut vec = Vec::new();

let mut vec = Vec::new();
for line in reader.lines() {
let line = line?;
if line.starts_with('#') {
continue;
}

for line in reader.lines() {
let line = line?;
if line.starts_with('#') {
continue;
}
let mut s = line.split_whitespace();
let name = expect!(s.next(), "name").to_owned();
let hierarchy = from_str!(u32, expect!(s.next(), "hierarchy"));
let num_cgroups = from_str!(u32, expect!(s.next(), "num_cgroups"));
let enabled = expect!(s.next(), "enabled") == "1";

let mut s = line.split_whitespace();
let name = expect!(s.next(), "name").to_owned();
let hierarchy = from_str!(u32, expect!(s.next(), "hierarchy"));
let num_cgroups = from_str!(u32, expect!(s.next(), "num_cgroups"));
let enabled = expect!(s.next(), "enabled") == "1";
vec.push(CGroupController {
name,
hierarchy,
num_cgroups,
enabled,
});
}

vec.push(CGroupController {
name,
hierarchy,
num_cgroups,
enabled,
});
Ok(CGroupControllers(vec))
}

Ok(vec)
}

/// Information about a process cgroup
///
/// See also the [Process::cgroups()] method.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct ProcessCgroup {
pub struct ProcessCGroup {
/// For cgroups version 1 hierarchies, this field contains a unique hierarchy ID number
/// that can be matched to a hierarchy ID in /proc/cgroups. For the cgroups version 2
/// hierarchy, this field contains the value 0.
Expand All @@ -88,16 +80,13 @@ pub struct ProcessCgroup {
pub pathname: String,
}

impl Process {
/// Describes control groups to which the process with the corresponding PID belongs.
///
/// The displayed information differs for cgroupsversion 1 and version 2 hierarchies.
pub fn cgroups(&self) -> ProcResult<Vec<ProcessCgroup>> {
use std::io::{BufRead, BufReader};

let file = self.open_relative("cgroup")?;
let reader = BufReader::new(file);
/// Information about process cgroups.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct ProcessCGroups(pub Vec<ProcessCGroup>);

impl crate::FromBufRead for ProcessCGroups {
fn from_buf_read<R: BufRead>(reader: R) -> ProcResult<Self> {
let mut vec = Vec::new();

for line in reader.lines() {
Expand All @@ -114,31 +103,13 @@ impl Process {
.collect();
let pathname = expect!(s.next(), "path").to_owned();

vec.push(ProcessCgroup {
vec.push(ProcessCGroup {
hierarchy,
controllers,
pathname,
});
}

Ok(vec)
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_cgroups() {
let groups = cgroups().unwrap();
println!("{:?}", groups);
}

#[test]
fn test_process_cgroups() {
let myself = Process::myself().unwrap();
let groups = myself.cgroups();
println!("{:?}", groups);
Ok(ProcessCGroups(vec))
}
}
44 changes: 14 additions & 30 deletions src/cpuinfo.rs → procfs-core/src/cpuinfo.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::{FileWrapper, ProcResult};
use crate::{expect, ProcResult};

#[cfg(feature = "serde1")]
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, io::Read};
use std::{collections::HashMap, io::BufRead};

/// Represents the data from `/proc/cpuinfo`.
///
Expand All @@ -20,20 +20,15 @@ pub struct CpuInfo {
pub cpus: Vec<HashMap<String, String>>,
}

impl CpuInfo {
/// Get CpuInfo from a custom Read instead of the default `/proc/cpuinfo`.
pub fn from_reader<R: Read>(r: R) -> ProcResult<CpuInfo> {
use std::io::{BufRead, BufReader};

let reader = BufReader::new(r);

impl crate::FromBufRead for CpuInfo {
fn from_buf_read<R: BufRead>(r: R) -> ProcResult<Self> {
let mut list = Vec::new();
let mut map = Some(HashMap::new());

// the first line of a cpu block must start with "processor"
let mut found_first = false;

for line in reader.lines().flatten() {
for line in r.lines().flatten() {
if !line.is_empty() {
let mut s = line.split(':');
let key = expect!(s.next());
Expand Down Expand Up @@ -88,12 +83,9 @@ impl CpuInfo {
cpus: list,
})
}
pub fn new() -> ProcResult<CpuInfo> {
let file = FileWrapper::open("/proc/cpuinfo")?;

CpuInfo::from_reader(file)
}
}

impl CpuInfo {
/// Get the total number of cpu cores.
///
/// This is the number of entries in the `/proc/cpuinfo` file.
Expand All @@ -115,6 +107,7 @@ impl CpuInfo {
.collect()
})
}

/// Get the content of a specific field associated to a CPU
///
/// Returns None if the requested cpu index is not found.
Expand All @@ -130,13 +123,16 @@ impl CpuInfo {
pub fn model_name(&self, cpu_num: usize) -> Option<&str> {
self.get_field(cpu_num, "model name")
}

pub fn vendor_id(&self, cpu_num: usize) -> Option<&str> {
self.get_field(cpu_num, "vendor_id")
}

/// May not be available on some older 2.6 kernels
pub fn physical_id(&self, cpu_num: usize) -> Option<u32> {
self.get_field(cpu_num, "physical id").and_then(|s| s.parse().ok())
}

pub fn flags(&self, cpu_num: usize) -> Option<Vec<&str>> {
self.get_field(cpu_num, "flags")
.map(|flags| flags.split_whitespace().collect())
Expand All @@ -147,20 +143,6 @@ impl CpuInfo {
mod tests {
use super::*;

#[test]
fn test_cpuinfo() {
let info = CpuInfo::new().unwrap();
println!("{:#?}", info.flags(0));
for num in 0..info.num_cores() {
info.model_name(num).unwrap();
info.vendor_id(num).unwrap();
// May not be available on some old kernels:
info.physical_id(num);
}

//assert_eq!(info.num_cores(), 8);
}

#[test]
fn test_cpuinfo_rpi() {
// My rpi system includes some stuff at the end of /proc/cpuinfo that we shouldn't parse
Expand Down Expand Up @@ -212,7 +194,9 @@ Model : Raspberry Pi 3 Model B Plus Rev 1.3

let r = std::io::Cursor::new(data.as_bytes());

let info = CpuInfo::from_reader(r).unwrap();
use crate::FromRead;

let info = CpuInfo::from_read(r).unwrap();
assert_eq!(info.num_cores(), 4);
let info = info.get_info(0).unwrap();
assert!(info.get("model name").is_some());
Expand Down
Loading