cgroup: support to set threaded mode in cgroup v2

Support to set threaded mode in cgroup v2. The premise of switching to threaded mode is that only the cgroup of cpuset, cpu and pids is supported.

Fixes: #90

Signed-off-by: yaoyinnan <yaoyinnan@foxmail.com>
This commit is contained in:
yaoyinnan
2022-12-30 12:46:50 +08:00
parent 0348f0a95e
commit c9d02afe33
14 changed files with 421 additions and 82 deletions

View File

@@ -36,14 +36,18 @@ pub struct Cgroup {
/// The hierarchy.
hier: Box<dyn Hierarchy>,
path: String,
/// List of controllers specifically enabled in the control group.
specified_controllers: Option<Vec<String>>,
}
impl Clone for Cgroup {
fn clone(&self) -> Self {
Cgroup {
subsystems: self.subsystems.clone(),
path: self.path.clone(),
hier: crate::hierarchies::auto(),
path: self.path.clone(),
specified_controllers: None,
}
}
}
@@ -54,48 +58,67 @@ impl Default for Cgroup {
subsystems: Vec::new(),
hier: crate::hierarchies::auto(),
path: "".to_string(),
specified_controllers: None,
}
}
}
impl Cgroup {
pub fn v2(&self) -> bool {
self.hier.v2()
}
/// Create this control group.
fn create(&self) {
fn create(&self) -> Result<()> {
if self.hier.v2() {
let _ret = create_v2_cgroup(self.hier.root(), &self.path);
create_v2_cgroup(self.hier.root(), &self.path, &self.specified_controllers)
} else {
for subsystem in &self.subsystems {
subsystem.to_controller().create();
}
Ok(())
}
}
pub fn v2(&self) -> bool {
self.hier.v2()
}
/// Create a new control group in the hierarchy `hier`, with name `path`.
///
/// Returns a handle to the control group that can be used to manipulate it.
pub fn new<P: AsRef<Path>>(hier: Box<dyn Hierarchy>, path: P) -> Cgroup {
pub fn new<P: AsRef<Path>>(hier: Box<dyn Hierarchy>, path: P) -> Result<Cgroup> {
let cg = Cgroup::load(hier, path);
cg.create();
cg
cg.create()?;
Ok(cg)
}
/// Create a new control group in the hierarchy `hier`, with name `path`.
///
/// Returns a handle to the control group that can be used to manipulate it.
pub fn new_with_specified_controllers<P: AsRef<Path>>(
hier: Box<dyn Hierarchy>,
path: P,
specified_controllers: Option<Vec<String>>,
) -> Result<Cgroup> {
let cg = if let Some(sc) = specified_controllers {
Cgroup::load_with_specified_controllers(hier, path, sc)
} else {
Cgroup::load(hier, path)
};
cg.create()?;
Ok(cg)
}
/// Create a new control group in the hierarchy `hier`, with name `path` and `relative_paths`
///
/// Returns a handle to the control group that can be used to manipulate it.
///
/// Note that this method is only meaningful for cgroup v1, call it is equivalent to call `new` in the v2 mode
/// Note that this method is only meaningful for cgroup v1, call it is equivalent to call `new` in the v2 mode.
pub fn new_with_relative_paths<P: AsRef<Path>>(
hier: Box<dyn Hierarchy>,
path: P,
relative_paths: HashMap<String, String>,
) -> Cgroup {
) -> Result<Cgroup> {
let cg = Cgroup::load_with_relative_paths(hier, path, relative_paths);
cg.create();
cg
cg.create()?;
Ok(cg)
}
/// Create a handle for a control group in the hierarchy `hier`, with name `path`.
@@ -116,6 +139,34 @@ impl Cgroup {
path: path.to_str().unwrap().to_string(),
subsystems,
hier,
specified_controllers: None,
}
}
/// Create a handle for a specified control group in the hierarchy `hier`, with name `path`.
///
/// Returns a handle to the control group (that possibly does not exist until `create()` has
/// been called on the cgroup.
pub fn load_with_specified_controllers<P: AsRef<Path>>(
hier: Box<dyn Hierarchy>,
path: P,
specified_controllers: Vec<String>,
) -> Cgroup {
let path = path.as_ref();
let mut subsystems = hier.subsystems();
if path.as_os_str() != "" {
subsystems = subsystems
.into_iter()
.filter(|x| specified_controllers.contains(&x.controller_name()))
.map(|x| x.enter(path))
.collect::<Vec<_>>();
}
Cgroup {
path: path.to_str().unwrap().to_string(),
subsystems,
hier,
specified_controllers: Some(specified_controllers),
}
}
@@ -159,6 +210,7 @@ impl Cgroup {
subsystems,
hier,
path: path.to_str().unwrap().to_string(),
specified_controllers: None,
}
}
@@ -233,36 +285,102 @@ impl Cgroup {
None
}
/// Removes tasks from the control group by thread group id.
///
/// Note that this means that the task will be moved back to the root control group in the
/// hierarchy and any rules applied to that control group will _still_ apply to the proc.
pub fn remove_task_by_tgid(&self, tgid: CgroupPid) -> Result<()> {
self.hier.root_control_group().add_task_by_tgid(tgid)
}
/// Removes a task from the control group.
///
/// Note that this means that the task will be moved back to the root control group in the
/// hierarchy and any rules applied to that control group will _still_ apply to the task.
pub fn remove_task(&self, pid: CgroupPid) {
let _ = self.hier.root_control_group().add_task(pid);
pub fn remove_task(&self, tid: CgroupPid) -> Result<()> {
self.hier.root_control_group().add_task(tid)
}
/// Moves tasks to the parent control group by thread group id.
pub fn move_task_to_parent_by_tgid(&self, tgid: CgroupPid) -> Result<()> {
self.hier
.parent_control_group(&self.path)
.add_task_by_tgid(tgid)
}
/// Moves a task to the parent control group.
pub fn move_task_to_parent(&self, tid: CgroupPid) -> Result<()> {
self.hier.parent_control_group(&self.path).add_task(tid)
}
/// Return a handle to the parent control group in the hierarchy.
pub fn parent_control_group(&self) -> Cgroup {
self.hier.parent_control_group(&self.path)
}
/// Attach a task to the control group.
pub fn add_task(&self, pid: CgroupPid) -> Result<()> {
pub fn add_task(&self, tid: CgroupPid) -> Result<()> {
if self.v2() {
let subsystems = self.subsystems();
if !subsystems.is_empty() {
let c = subsystems[0].to_controller();
c.add_task(&pid)
c.add_task(&tid)
} else {
Ok(())
Err(Error::new(SubsystemsEmpty))
}
} else {
self.subsystems()
.iter()
.try_for_each(|sub| sub.to_controller().add_task(&pid))
.try_for_each(|sub| sub.to_controller().add_task(&tid))
}
}
/// Attach a task to the control group by thread group id.
pub fn add_task_by_tgid(&self, pid: CgroupPid) -> Result<()> {
self.subsystems()
.iter()
.try_for_each(|sub| sub.to_controller().add_task_by_tgid(&pid))
/// Attach tasks to the control group by thread group id.
pub fn add_task_by_tgid(&self, tgid: CgroupPid) -> Result<()> {
if self.v2() {
let subsystems = self.subsystems();
if !subsystems.is_empty() {
let c = subsystems[0].to_controller();
c.add_task_by_tgid(&tgid)
} else {
Err(Error::new(SubsystemsEmpty))
}
} else {
self.subsystems()
.iter()
.try_for_each(|sub| sub.to_controller().add_task_by_tgid(&tgid))
}
}
/// set cgroup.type
pub fn set_cgroup_type(&self, cgroup_type: &str) -> Result<()> {
if self.v2() {
let subsystems = self.subsystems();
if !subsystems.is_empty() {
let c = subsystems[0].to_controller();
c.set_cgroup_type(cgroup_type)
} else {
Err(Error::new(SubsystemsEmpty))
}
} else {
Err(Error::new(CgroupVersion))
}
}
/// get cgroup.type
pub fn get_cgroup_type(&self) -> Result<String> {
if self.v2() {
let subsystems = self.subsystems();
if !subsystems.is_empty() {
let c = subsystems[0].to_controller();
let cgroup_type = c.get_cgroup_type()?;
Ok(cgroup_type)
} else {
Err(Error::new(SubsystemsEmpty))
}
} else {
Err(Error::new(CgroupVersion))
}
}
/// Set notify_on_release to the control group.
@@ -281,6 +399,33 @@ impl Cgroup {
.try_for_each(|sub| sub.to_controller().set_release_agent(path))
}
/// Returns an Iterator that can be used to iterate over the procs that are currently in the
/// control group.
pub fn procs(&self) -> Vec<CgroupPid> {
// Collect the procs from all subsystems
let mut v = if self.v2() {
let subsystems = self.subsystems();
if !subsystems.is_empty() {
let c = subsystems[0].to_controller();
c.procs()
} else {
vec![]
}
} else {
self.subsystems()
.iter()
.map(|x| x.to_controller().procs())
.fold(vec![], |mut acc, mut x| {
acc.append(&mut x);
acc
})
};
v.sort();
v.dedup();
v
}
/// Returns an Iterator that can be used to iterate over the tasks that are currently in the
/// control group.
pub fn tasks(&self) -> Vec<CgroupPid> {
@@ -328,9 +473,22 @@ fn supported_controllers() -> Vec<String> {
.collect::<Vec<String>>()
}
fn create_v2_cgroup(root: PathBuf, path: &str) -> Result<()> {
fn create_v2_cgroup(
root: PathBuf,
path: &str,
specified_controllers: &Option<Vec<String>>,
) -> Result<()> {
// controler list ["memory", "cpu"]
let controllers = supported_controllers();
let controllers = if let Some(s_controllers) = specified_controllers.clone() {
if verify_supported_controllers(s_controllers.as_ref()) {
s_controllers
} else {
return Err(Error::new(ErrorKind::SpecifiedControllers));
}
} else {
supported_controllers()
};
let mut fp = root;
// enable for root
@@ -358,6 +516,16 @@ fn create_v2_cgroup(root: PathBuf, path: &str) -> Result<()> {
Ok(())
}
pub fn verify_supported_controllers(controllers: &[String]) -> bool {
let sc = supported_controllers();
for controller in controllers.iter() {
if !sc.contains(controller) {
return false;
}
}
true
}
pub fn get_cgroups_relative_paths() -> Result<HashMap<String, String>> {
let path = "/proc/self/cgroup".to_string();
get_cgroups_relative_paths_by_path(path)

View File

@@ -57,11 +57,11 @@
//! .read(6, 1, 10)
//! .write(11, 1, 100)
//! .done()
//! .build(h);
//! .build(h).unwrap();
//! ```
use crate::{
BlkIoDeviceResource, BlkIoDeviceThrottleResource, Cgroup, DeviceResource, Hierarchy,
BlkIoDeviceResource, BlkIoDeviceThrottleResource, Cgroup, DeviceResource, Error, Hierarchy,
HugePageResource, MaxValue, NetworkPriority, Resources,
};
@@ -80,6 +80,8 @@ pub struct CgroupBuilder {
name: String,
/// Internal, unsupported field: use the associated builders instead.
resources: Resources,
/// List of controllers specifically enabled in the control group.
specified_controllers: Option<Vec<String>>,
}
impl CgroupBuilder {
@@ -90,6 +92,7 @@ impl CgroupBuilder {
CgroupBuilder {
name: name.to_owned(),
resources: Resources::default(),
specified_controllers: None,
}
}
@@ -134,10 +137,22 @@ impl CgroupBuilder {
}
/// Finalize the control group, consuming the builder and creating the control group.
pub fn build(self, hier: Box<dyn Hierarchy>) -> Cgroup {
let cg = Cgroup::new(hier, self.name);
let _ret = cg.apply(&self.resources);
cg
pub fn build(self, hier: Box<dyn Hierarchy>) -> Result<Cgroup, Error> {
if let Some(controllers) = self.specified_controllers {
let cg = Cgroup::new_with_specified_controllers(hier, self.name, Some(controllers))?;
cg.apply(&self.resources)?;
Ok(cg)
} else {
let cg = Cgroup::new(hier, self.name)?;
cg.apply(&self.resources)?;
Ok(cg)
}
}
/// Specifically enable some controllers in the control group.
pub fn set_specified_controllers(mut self, specified_controllers: Vec<String>) -> Self {
self.specified_controllers = Some(specified_controllers);
self
}
}

View File

@@ -51,6 +51,18 @@ pub enum ErrorKind {
#[error("invalid bytes size")]
InvalidBytesSize,
/// The specified controller is not in the list of supported controllers.
#[error("specified controller is not in the list of supported controllers")]
SpecifiedControllers,
/// Using method in wrong cgroup version.
#[error("using method in wrong cgroup version")]
CgroupVersion,
/// Subsystems is empty.
#[error("subsystems is empty")]
SubsystemsEmpty,
/// An unknown error has occured.
#[error("an unknown error")]
Other,

View File

@@ -12,7 +12,7 @@
use std::fs;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use crate::blkio::BlkIoController;
use crate::cpu::CpuController;
@@ -173,6 +173,12 @@ impl Hierarchy for V1 {
Cgroup::load(auto(), "")
}
fn parent_control_group(&self, path: &str) -> Cgroup {
let path = Path::new(path);
let parent_path = path.parent().unwrap().to_string_lossy().to_string();
Cgroup::load(auto(), &parent_path)
}
fn root(&self) -> PathBuf {
self.mountinfo
.iter()
@@ -249,6 +255,12 @@ impl Hierarchy for V2 {
Cgroup::load(auto(), "")
}
fn parent_control_group(&self, path: &str) -> Cgroup {
let path = Path::new(path);
let parent_path = path.parent().unwrap().to_string_lossy().to_string();
Cgroup::load(auto(), &parent_path)
}
fn root(&self) -> PathBuf {
PathBuf::from(self.root.clone())
}

View File

@@ -280,9 +280,18 @@ pub trait Controller {
/// Attach a task to this controller.
fn add_task_by_tgid(&self, pid: &CgroupPid) -> Result<()>;
/// set cgroup type.
fn set_cgroup_type(&self, cgroup_type: &str) -> Result<()>;
/// get cgroup type.
fn get_cgroup_type(&self) -> Result<String>;
/// Get the list of tasks that this controller has.
fn tasks(&self) -> Vec<CgroupPid>;
/// Get the list of procs that this controller has.
fn procs(&self) -> Vec<CgroupPid>;
fn v2(&self) -> bool;
}
@@ -317,6 +326,9 @@ where
/// Set notify_on_release
fn set_notify_on_release(&self, enable: bool) -> Result<()> {
if self.is_v2() {
return Err(Error::new(ErrorKind::CgroupVersion));
}
self.open_path("notify_on_release", true)
.and_then(|mut file| {
write!(file, "{}", enable as i32).map_err(|e| {
@@ -330,6 +342,9 @@ where
/// Set release_agent
fn set_release_agent(&self, path: &str) -> Result<()> {
if self.is_v2() {
return Err(Error::new(ErrorKind::CgroupVersion));
}
self.open_path("release_agent", true).and_then(|mut file| {
file.write_all(path.as_bytes()).map_err(|e| {
Error::with_cause(
@@ -373,7 +388,7 @@ where
fn add_task(&self, pid: &CgroupPid) -> Result<()> {
let mut file_name = "tasks";
if self.is_v2() {
file_name = "cgroup.procs";
file_name = "cgroup.threads";
}
self.open_path(file_name, true).and_then(|mut file| {
file.write_all(pid.pid.to_string().as_ref()).map_err(|e| {
@@ -387,23 +402,21 @@ where
/// Attach a task to this controller by thread group id.
fn add_task_by_tgid(&self, pid: &CgroupPid) -> Result<()> {
self.open_path("cgroup.procs", true).and_then(|mut file| {
let file_name = "cgroup.procs";
self.open_path(file_name, true).and_then(|mut file| {
file.write_all(pid.pid.to_string().as_ref()).map_err(|e| {
Error::with_cause(
ErrorKind::WriteFailed("cgroup.procs".to_string(), pid.pid.to_string()),
ErrorKind::WriteFailed(file_name.to_string(), pid.pid.to_string()),
e,
)
})
})
}
/// Get the list of tasks that this controller has.
fn tasks(&self) -> Vec<CgroupPid> {
let mut file = "tasks";
if self.is_v2() {
file = "cgroup.procs";
}
self.open_path(file, false)
/// Get the list of procs that this controller has.
fn procs(&self) -> Vec<CgroupPid> {
let file_name = "cgroup.procs";
self.open_path(file_name, false)
.map(|file| {
let bf = BufReader::new(file);
let mut v = Vec::new();
@@ -421,6 +434,64 @@ where
.unwrap_or_default()
}
/// Get the list of tasks that this controller has.
fn tasks(&self) -> Vec<CgroupPid> {
let mut file_name = "tasks";
if self.is_v2() {
file_name = "cgroup.threads";
}
self.open_path(file_name, false)
.map(|file| {
let bf = BufReader::new(file);
let mut v = Vec::new();
for line in bf.lines() {
match line {
Ok(line) => {
let n = line.trim().parse().unwrap_or(0u64);
v.push(n);
}
Err(_) => break,
}
}
v.into_iter().map(CgroupPid::from).collect()
})
.unwrap_or_default()
}
/// set cgroup.type
fn set_cgroup_type(&self, cgroup_type: &str) -> Result<()> {
if !self.is_v2() {
return Err(Error::new(ErrorKind::CgroupVersion));
}
let file_name = "cgroup.type";
self.open_path(file_name, true).and_then(|mut file| {
file.write_all(cgroup_type.as_bytes()).map_err(|e| {
Error::with_cause(
ErrorKind::WriteFailed(file_name.to_string(), cgroup_type.to_string()),
e,
)
})
})
}
/// get cgroup.type
fn get_cgroup_type(&self) -> Result<String> {
if !self.is_v2() {
return Err(Error::new(ErrorKind::CgroupVersion));
}
let file_name = "cgroup.type";
self.open_path(file_name, false).and_then(|mut file: File| {
let mut string = String::new();
match file.read_to_string(&mut string) {
Ok(_) => Ok(string.trim().to_owned()),
Err(e) => Err(Error::with_cause(
ErrorKind::ReadFailed(file_name.to_string()),
e,
)),
}
})
}
fn v2(&self) -> bool {
self.is_v2()
}
@@ -468,6 +539,9 @@ pub trait Hierarchy: std::fmt::Debug + Send + Sync {
/// Return a handle to the root control group in the hierarchy.
fn root_control_group(&self) -> Cgroup;
/// Return a handle to the parent control group in the hierarchy.
fn parent_control_group(&self, path: &str) -> Cgroup;
fn v2(&self) -> bool;
}

View File

@@ -22,7 +22,8 @@ pub fn test_cpu_res_build() {
.cpu()
.shares(85)
.done()
.build(h);
.build(h)
.unwrap();
{
let cpu: &CpuController = cg.controller_of().unwrap();
@@ -42,7 +43,8 @@ pub fn test_memory_res_build() {
.swappiness(70)
.memory_hard_limit(1024 * 1024 * 1024)
.done()
.build(h);
.build(h)
.unwrap();
{
let c: &MemController = cg.controller_of().unwrap();
@@ -64,7 +66,8 @@ pub fn test_pid_res_build() {
.pid()
.maximum_number_of_processes(MaxValue::Value(123))
.done()
.build(h);
.build(h)
.unwrap();
{
let c: &PidController = cg.controller_of().unwrap();
@@ -83,7 +86,8 @@ pub fn test_devices_res_build() {
.devices()
.device(1, 6, DeviceType::Char, true, vec![DevicePermissions::Read])
.done()
.build(h);
.build(h)
.unwrap();
{
let c: &DevicesController = cg.controller_of().unwrap();
@@ -113,7 +117,8 @@ pub fn test_network_res_build() {
.network()
.class_id(1337)
.done()
.build(h);
.build(h)
.unwrap();
{
let c: &NetClsController = cg.controller_of().unwrap();
@@ -134,7 +139,8 @@ pub fn test_hugepages_res_build() {
.hugepages()
.limit("2MB".to_string(), 4 * 2 * 1024 * 1024)
.done()
.build(h);
.build(h)
.unwrap();
{
let c: &HugeTlbController = cg.controller_of().unwrap();
@@ -152,7 +158,8 @@ pub fn test_blkio_res_build() {
.blkio()
.weight(100)
.done()
.build(h);
.build(h)
.unwrap();
{
let c: &BlkIoController = cg.controller_of().unwrap();

View File

@@ -10,28 +10,25 @@ use cgroups_rs::Controller;
use cgroups_rs::{Cgroup, CgroupPid, Subsystem};
#[test]
fn test_tasks_iterator() {
fn test_procs_iterator_cgroup() {
let h = cgroups_rs::hierarchies::auto();
let pid = libc::pid_t::from(nix::unistd::getpid()) as u64;
let cg = Cgroup::new(h, String::from("test_tasks_iterator"));
let cg = Cgroup::new(h, String::from("test_procs_iterator_cgroup")).unwrap();
{
// Add a task to the control group.
cg.add_task(CgroupPid::from(pid)).unwrap();
cg.add_task_by_tgid(CgroupPid::from(pid)).unwrap();
use std::{thread, time};
thread::sleep(time::Duration::from_millis(100));
let mut tasks = cg.tasks().into_iter();
// Verify that the task is indeed in the control group
assert_eq!(tasks.next(), Some(CgroupPid::from(pid)));
assert_eq!(tasks.next(), None);
let mut procs = cg.procs().into_iter();
// Verify that the task is indeed in the xcontrol group
assert_eq!(procs.next(), Some(CgroupPid::from(pid)));
assert_eq!(procs.next(), None);
// Now, try removing it.
cg.remove_task(CgroupPid::from(pid));
tasks = cg.tasks().into_iter();
cg.remove_task_by_tgid(CgroupPid::from(pid)).unwrap();
procs = cg.procs().into_iter();
// Verify that it was indeed removed.
assert_eq!(tasks.next(), None);
assert_eq!(procs.next(), None);
}
cg.delete().unwrap();
}
@@ -83,7 +80,7 @@ fn test_cgroup_v2() {
return;
}
let h = cgroups_rs::hierarchies::auto();
let cg = Cgroup::new(h, String::from("test_v2"));
let cg = Cgroup::new(h, String::from("test_v2")).unwrap();
let mem_controller: &MemController = cg.controller_of().unwrap();
let (mem, swp, rev) = (4 * 1024 * 1000, 2 * 1024 * 1000, 1024 * 1000);
@@ -103,3 +100,57 @@ fn test_cgroup_v2() {
cg.delete().unwrap();
}
#[test]
fn test_tasks_iterator_cgroup_threaded_mode() {
if !cgroups_rs::hierarchies::is_cgroup2_unified_mode() {
return;
}
let h = cgroups_rs::hierarchies::auto();
let pid = libc::pid_t::from(nix::unistd::getpid()) as u64;
let cg = Cgroup::new(h, String::from("test_tasks_iterator_cgroup_threaded_mode")).unwrap();
let h = cgroups_rs::hierarchies::auto();
let specified_controllers = vec![String::from("cpuset"), String::from("cpu")];
let cg_threaded = Cgroup::new_with_specified_controllers(
h,
String::from("test_tasks_iterator_cgroup_threaded_mode/threaded"),
Some(specified_controllers),
)
.unwrap();
cg_threaded.set_cgroup_type("threaded").unwrap();
{
// Add a task to the control group.
cg.add_task_by_tgid(CgroupPid::from(pid)).unwrap();
let mut procs = cg.procs().into_iter();
// Verify that the task is indeed in the xcontrol group
assert_eq!(procs.next(), Some(CgroupPid::from(pid)));
assert_eq!(procs.next(), None);
// Add a task to the sub control group.
cg_threaded.add_task(CgroupPid::from(pid)).unwrap();
let mut tasks = cg_threaded.tasks().into_iter();
// Verify that the task is indeed in the xcontrol group
assert_eq!(tasks.next(), Some(CgroupPid::from(pid)));
assert_eq!(tasks.next(), None);
// Now, try move it to parent.
cg_threaded
.move_task_to_parent(CgroupPid::from(pid))
.unwrap();
tasks = cg_threaded.tasks().into_iter();
// Verify that it was indeed removed.
assert_eq!(tasks.next(), None);
// Now, try removing it.
cg.remove_task_by_tgid(CgroupPid::from(pid)).unwrap();
procs = cg.procs().into_iter();
// Verify that it was indeed removed.
assert_eq!(procs.next(), None);
}
cg_threaded.delete().unwrap();
cg.delete().unwrap();
}

View File

@@ -10,7 +10,7 @@ use cgroups_rs::Cgroup;
#[test]
fn test_cfs_quota_and_periods() {
let h = cgroups_rs::hierarchies::auto();
let cg = Cgroup::new(h, String::from("test_cfs_quota_and_periods"));
let cg = Cgroup::new(h, String::from("test_cfs_quota_and_periods")).unwrap();
let cpu_controller: &CpuController = cg.controller_of().unwrap();

View File

@@ -13,7 +13,7 @@ use std::fs;
#[test]
fn test_cpuset_memory_pressure_root_cg() {
let h = cgroups_rs::hierarchies::auto();
let cg = Cgroup::new(h, String::from("test_cpuset_memory_pressure_root_cg"));
let cg = Cgroup::new(h, String::from("test_cpuset_memory_pressure_root_cg")).unwrap();
{
let cpuset: &CpuSetController = cg.controller_of().unwrap();
@@ -27,7 +27,7 @@ fn test_cpuset_memory_pressure_root_cg() {
#[test]
fn test_cpuset_set_cpus() {
let h = cgroups_rs::hierarchies::auto();
let cg = Cgroup::new(h, String::from("test_cpuset_set_cpus"));
let cg = Cgroup::new(h, String::from("test_cpuset_set_cpus")).unwrap();
{
let cpuset: &CpuSetController = cg.controller_of().unwrap();
@@ -64,7 +64,7 @@ fn test_cpuset_set_cpus() {
#[test]
fn test_cpuset_set_cpus_add_task() {
let h = cgroups_rs::hierarchies::auto();
let cg = Cgroup::new(h, String::from("test_cpuset_set_cpus_add_task/sub-dir"));
let cg = Cgroup::new(h, String::from("test_cpuset_set_cpus_add_task/sub-dir")).unwrap();
let cpuset: &CpuSetController = cg.controller_of().unwrap();
let set = cpuset.cpuset();
@@ -77,13 +77,13 @@ fn test_cpuset_set_cpus_add_task() {
// Add a task to the control group.
let pid_i = libc::pid_t::from(nix::unistd::getpid()) as u64;
let _ = cg.add_task(CgroupPid::from(pid_i));
let _ = cg.add_task_by_tgid(CgroupPid::from(pid_i));
let tasks = cg.tasks();
assert!(!tasks.is_empty());
println!("tasks after added: {:?}", tasks);
// remove task
cg.remove_task(CgroupPid::from(pid_i));
cg.remove_task_by_tgid(CgroupPid::from(pid_i)).unwrap();
let tasks = cg.tasks();
println!("tasks after deleted: {:?}", tasks);
assert_eq!(0, tasks.len());

View File

@@ -17,7 +17,7 @@ fn test_devices_parsing() {
}
let h = cgroups_rs::hierarchies::auto();
let cg = Cgroup::new(h, String::from("test_devices_parsing"));
let cg = Cgroup::new(h, String::from("test_devices_parsing")).unwrap();
{
let devices: &DevicesController = cg.controller_of().unwrap();

View File

@@ -17,7 +17,7 @@ fn test_hugetlb_sizes() {
}
let h = cgroups_rs::hierarchies::auto();
let cg = Cgroup::new(h, String::from("test_hugetlb_sizes"));
let cg = Cgroup::new(h, String::from("test_hugetlb_sizes")).unwrap();
{
let hugetlb_controller: &HugeTlbController = cg.controller_of().unwrap();
let _ = hugetlb_controller.get_sizes();

View File

@@ -11,7 +11,7 @@ use cgroups_rs::{Cgroup, MaxValue};
#[test]
fn test_disable_oom_killer() {
let h = cgroups_rs::hierarchies::auto();
let cg = Cgroup::new(h, String::from("test_disable_oom_killer"));
let cg = Cgroup::new(h, String::from("test_disable_oom_killer")).unwrap();
{
let mem_controller: &MemController = cg.controller_of().unwrap();
@@ -40,7 +40,7 @@ fn set_kmem_limit_v1() {
return;
}
let cg = Cgroup::new(h, String::from("set_kmem_limit_v1"));
let cg = Cgroup::new(h, String::from("set_kmem_limit_v1")).unwrap();
{
let mem_controller: &MemController = cg.controller_of().unwrap();
mem_controller.set_kmem_limit(1).unwrap();
@@ -55,7 +55,7 @@ fn set_mem_v2() {
return;
}
let cg = Cgroup::new(h, String::from("set_mem_v2"));
let cg = Cgroup::new(h, String::from("set_mem_v2")).unwrap();
{
let mem_controller: &MemController = cg.controller_of().unwrap();

View File

@@ -17,7 +17,7 @@ use libc::pid_t;
#[test]
fn create_and_delete_cgroup() {
let h = cgroups_rs::hierarchies::auto();
let cg = Cgroup::new(h, String::from("create_and_delete_cgroup"));
let cg = Cgroup::new(h, String::from("create_and_delete_cgroup")).unwrap();
{
let pidcontroller: &PidController = cg.controller_of().unwrap();
pidcontroller.set_pid_max(MaxValue::Value(1337)).unwrap();
@@ -31,7 +31,7 @@ fn create_and_delete_cgroup() {
#[test]
fn test_pids_current_is_zero() {
let h = cgroups_rs::hierarchies::auto();
let cg = Cgroup::new(h, String::from("test_pids_current_is_zero"));
let cg = Cgroup::new(h, String::from("test_pids_current_is_zero")).unwrap();
{
let pidcontroller: &PidController = cg.controller_of().unwrap();
let current = pidcontroller.get_pid_current();
@@ -43,7 +43,7 @@ fn test_pids_current_is_zero() {
#[test]
fn test_pids_events_is_zero() {
let h = cgroups_rs::hierarchies::auto();
let cg = Cgroup::new(h, String::from("test_pids_events_is_zero"));
let cg = Cgroup::new(h, String::from("test_pids_events_is_zero")).unwrap();
{
let pidcontroller: &PidController = cg.controller_of().unwrap();
let events = pidcontroller.get_pid_events();
@@ -56,7 +56,7 @@ fn test_pids_events_is_zero() {
#[test]
fn test_pid_events_is_not_zero() {
let h = cgroups_rs::hierarchies::auto();
let cg = Cgroup::new(h, String::from("test_pid_events_is_not_zero"));
let cg = Cgroup::new(h, String::from("test_pid_events_is_not_zero")).unwrap();
{
let pids: &PidController = cg.controller_of().unwrap();
let before = pids.get_pid_events();
@@ -65,7 +65,7 @@ fn test_pid_events_is_not_zero() {
match unsafe { fork() } {
Ok(ForkResult::Parent { child, .. }) => {
// move the process into the control group
let _ = pids.add_task(&(pid_t::from(child) as u64).into());
let _ = pids.add_task_by_tgid(&(pid_t::from(child) as u64).into());
println!("added task to cg: {:?}", child);

View File

@@ -11,7 +11,7 @@ use cgroups_rs::{Cgroup, MaxValue, PidResources, Resources};
#[test]
fn pid_resources() {
let h = cgroups_rs::hierarchies::auto();
let cg = Cgroup::new(h, String::from("pid_resources"));
let cg = Cgroup::new(h, String::from("pid_resources")).unwrap();
{
let res = Resources {
pid: PidResources {