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

Replace parts of ffi module by libc functions ind sched.rs #402

Merged
merged 1 commit into from
Aug 29, 2016
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
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,25 @@ This project adheres to [Semantic Versioning](http://semver.org/).
([#405](https://github.com/nix-rust/nix/pull/405))
- Added `F_FULLFSYNC` to `FcntlArg` in `::nix::fcntl` for _apple_ targets.
([#407](https://github.com/nix-rust/nix/pull/407))
- Added `CpuSet::unset` in `::nix::sched`.
([#402](https://github.com/nix-rust/nix/pull/402))

### Changed
- Replaced the reexported integer constants for signals by the enumeration
`Signal` in `::nix::sys::signal`.
([#362](https://github.com/nix-rust/nix/pull/362))
- Renamed `EventFdFlag` to `EfdFlags` in `::nix::sys::eventfd`.
([#383](https://github.com/nix-rust/nix/pull/383))
- Changed the result types of `CpuSet::is_set` and `CpuSet::set` in
`::nix::sched` to `Result<bool>` and `Result<()>`, respectively. They now
return `EINVAL`, if an invalid argument for the `field` parameter is passed.
([#402](https://github.com/nix-rust/nix/pull/402))

### Removed
- Type alias `SigNum` from `::nix::sys::signal`.
([#362](https://github.com/nix-rust/nix/pull/362))
- Type alias `CpuMask` from `::nix::shed`.
([#402](https://github.com/nix-rust/nix/pull/402))

### Fixed
- Fixed the build problem for NetBSD (Note, that we currently do not support
Expand Down
226 changes: 66 additions & 160 deletions src/sched.rs
Original file line number Diff line number Diff line change
@@ -1,204 +1,110 @@
use std::mem;
use std::os::unix::io::RawFd;
use std::option::Option;
use libc::{self, c_int, c_void, c_ulong, pid_t};
use {Errno, Result};
use libc::{self, c_int, c_void, pid_t};
use {Errno, Error, Result};

// For some functions taking with a parameter of type CloneFlags,
// only a subset of these flags have an effect.
bitflags!{
flags CloneFlags: c_int {
const CLONE_VM = libc::CLONE_VM,
const CLONE_FS = libc::CLONE_FS,
const CLONE_FILES = libc::CLONE_FILES,
const CLONE_SIGHAND = libc::CLONE_SIGHAND,
const CLONE_PTRACE = libc::CLONE_PTRACE,
const CLONE_VFORK = libc::CLONE_VFORK,
const CLONE_PARENT = libc::CLONE_PARENT,
const CLONE_THREAD = libc::CLONE_THREAD,
const CLONE_NEWNS = libc::CLONE_NEWNS,
const CLONE_SYSVSEM = libc::CLONE_SYSVSEM,
const CLONE_SETTLS = libc::CLONE_SETTLS,
const CLONE_PARENT_SETTID = libc::CLONE_PARENT_SETTID,
const CLONE_CHILD_CLEARTID = libc::CLONE_CHILD_CLEARTID,
const CLONE_DETACHED = libc::CLONE_DETACHED,
const CLONE_UNTRACED = libc::CLONE_UNTRACED,
const CLONE_CHILD_SETTID = libc::CLONE_CHILD_SETTID,
// TODO: Once, we use a version containing
// https://github.com/rust-lang-nursery/libc/pull/147
// get rid of the casts.
const CLONE_NEWUTS = libc::CLONE_NEWUTS as c_int,
const CLONE_NEWIPC = libc::CLONE_NEWIPC as c_int,
const CLONE_NEWUSER = libc::CLONE_NEWUSER as c_int,
const CLONE_NEWPID = libc::CLONE_NEWPID as c_int,
const CLONE_NEWNET = libc::CLONE_NEWNET as c_int,
const CLONE_IO = libc::CLONE_IO as c_int,
}
}

// Support a maximum CPU set of 1024 nodes
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
mod cpuset_attribs {
use super::CpuMask;
pub const CPU_SETSIZE: usize = 1024;
pub const CPU_MASK_BITS: usize = 64;

#[inline]
pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
cur | (1u64 << bit)
}

#[inline]
pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
cur & !(1u64 << bit)
}
}

#[cfg(all(target_arch = "x86", target_os = "linux"))]
mod cpuset_attribs {
use super::CpuMask;
pub const CPU_SETSIZE: usize = 1024;
pub const CPU_MASK_BITS: usize = 32;

#[inline]
pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
cur | (1u32 << bit)
}

#[inline]
pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
cur & !(1u32 << bit)
}
}

#[cfg(all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")))]
mod cpuset_attribs {
use super::CpuMask;
pub const CPU_SETSIZE: usize = 1024;
pub const CPU_MASK_BITS: usize = 64;

#[inline]
pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
cur | (1u64 << bit)
}

#[inline]
pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
cur & !(1u64 << bit)
}
}

#[cfg(all(any(target_arch = "arm", target_arch = "mips"), target_os = "android"))]
mod cpuset_attribs {
use super::CpuMask;
// bionic only supports up to 32 independent CPUs, instead of 1024.
pub const CPU_SETSIZE: usize = 32;
pub const CPU_MASK_BITS: usize = 32;

#[inline]
pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
cur | (1u32 << bit)
}

#[inline]
pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
cur & !(1u32 << bit)
}
}

#[cfg(all(any(target_arch = "arm", target_arch = "mips"), target_os = "linux"))]
mod cpuset_attribs {
use super::CpuMask;
pub const CPU_SETSIZE: usize = 1024;
pub const CPU_MASK_BITS: usize = 32;

#[inline]
pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
cur | (1u32 << bit)
}

#[inline]
pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
cur & !(1u32 << bit)
libc_bitflags!{
flags CloneFlags: libc::c_int {
CLONE_VM,
CLONE_FS,
CLONE_FILES,
CLONE_SIGHAND,
CLONE_PTRACE,
CLONE_VFORK,
CLONE_PARENT,
CLONE_THREAD,
CLONE_NEWNS,
CLONE_SYSVSEM,
CLONE_SETTLS,
CLONE_PARENT_SETTID,
CLONE_CHILD_CLEARTID,
CLONE_DETACHED,
CLONE_UNTRACED,
CLONE_CHILD_SETTID,
CLONE_NEWUTS,
CLONE_NEWIPC,
CLONE_NEWUSER,
CLONE_NEWPID,
CLONE_NEWNET,
CLONE_IO,
}
}

pub type CloneCb<'a> = Box<FnMut() -> isize + 'a>;

// A single CPU mask word
pub type CpuMask = c_ulong;

// Structure representing the CPU set to apply
#[repr(C)]
#[derive(Clone, Copy)]
pub struct CpuSet {
cpu_mask: [CpuMask; cpuset_attribs::CPU_SETSIZE/cpuset_attribs::CPU_MASK_BITS]
cpu_set: libc::cpu_set_t,
}

impl CpuSet {
pub fn new() -> CpuSet {
CpuSet {
cpu_mask: unsafe { mem::zeroed() }
}
CpuSet { cpu_set: unsafe { mem::zeroed() } }
}

pub fn set(&mut self, field: usize) {
let word = field / cpuset_attribs::CPU_MASK_BITS;
let bit = field % cpuset_attribs::CPU_MASK_BITS;

self.cpu_mask[word] = cpuset_attribs::set_cpu_mask_flag(self.cpu_mask[word], bit);
pub fn is_set(&self, field: usize) -> Result<bool> {
if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
Err(Error::Sys(Errno::EINVAL))
} else {
Ok(unsafe { libc::CPU_ISSET(field, &self.cpu_set) })
}
}

pub fn unset(&mut self, field: usize) {
let word = field / cpuset_attribs::CPU_MASK_BITS;
let bit = field % cpuset_attribs::CPU_MASK_BITS;
pub fn set(&mut self, field: usize) -> Result<()> {
if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
Err(Error::Sys(Errno::EINVAL))
} else {
Ok(unsafe { libc::CPU_SET(field, &mut self.cpu_set) })
}
}

self.cpu_mask[word] = cpuset_attribs::clear_cpu_mask_flag(self.cpu_mask[word], bit);
pub fn unset(&mut self, field: usize) -> Result<()> {
if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
Err(Error::Sys(Errno::EINVAL))
} else {
Ok(unsafe { libc::CPU_CLR(field, &mut self.cpu_set) })
}
}
}

mod ffi {
use libc::{c_void, c_int, pid_t, size_t};
use super::CpuSet;
use libc::{c_void, c_int};

pub type CloneCb = extern "C" fn (data: *const super::CloneCb) -> c_int;
pub type CloneCb = extern "C" fn(data: *const super::CloneCb) -> c_int;

// We cannot give a proper #[repr(C)] to super::CloneCb
#[allow(improper_ctypes)]
extern {
extern "C" {
// create a child process
// doc: http://man7.org/linux/man-pages/man2/clone.2.html
pub fn clone(
cb: *const CloneCb,
child_stack: *mut c_void,
flags: c_int,
arg: *mut super::CloneCb,
...) -> c_int;

// disassociate parts of the process execution context
// doc: http://man7.org/linux/man-pages/man2/unshare.2.html
pub fn unshare(flags: c_int) -> c_int;

// reassociate thread with a namespace
// doc: http://man7.org/linux/man-pages/man2/setns.2.html
pub fn setns(fd: c_int, nstype: c_int) -> c_int;

// Set the current CPU set that a task is allowed to run on
pub fn sched_setaffinity(__pid: pid_t, __cpusetsize: size_t, __cpuset: *const CpuSet) -> c_int;
pub fn clone(cb: *const CloneCb,
child_stack: *mut c_void,
flags: c_int,
arg: *mut super::CloneCb,
...)
-> c_int;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be replaced with the libc clone?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably, but understanding what is happning and how clone is supposed to be used, was to much for me yesterday evening, so given that it does not share any types or code with the other functions in that file, I left it for another commit.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah there's some fanciness going on here to allow passing a Rust closure as the function to run in the new process. There's also #360 which is concerning.

}
}

pub fn sched_setaffinity(pid: isize, cpuset: &CpuSet) -> Result<()> {
use libc::{pid_t, size_t};

let res = unsafe {
ffi::sched_setaffinity(pid as pid_t, mem::size_of::<CpuSet>() as size_t, mem::transmute(cpuset))
libc::sched_setaffinity(pid as libc::pid_t,
mem::size_of::<CpuSet>() as libc::size_t,
mem::transmute(cpuset))
};

Errno::result(res).map(drop)
}

pub fn clone(mut cb: CloneCb, stack: &mut [u8], flags: CloneFlags, signal: Option<c_int>) -> Result<pid_t> {
pub fn clone(mut cb: CloneCb,
stack: &mut [u8],
flags: CloneFlags,
signal: Option<c_int>)
-> Result<pid_t> {
extern "C" fn callback(data: *mut CloneCb) -> c_int {
let cb: &mut CloneCb = unsafe { &mut *data };
(*cb)() as c_int
Expand All @@ -217,13 +123,13 @@ pub fn clone(mut cb: CloneCb, stack: &mut [u8], flags: CloneFlags, signal: Optio
}

pub fn unshare(flags: CloneFlags) -> Result<()> {
let res = unsafe { ffi::unshare(flags.bits()) };
let res = unsafe { libc::unshare(flags.bits()) };

Errno::result(res).map(drop)
}

pub fn setns(fd: RawFd, nstype: CloneFlags) -> Result<()> {
let res = unsafe { ffi::setns(fd, nstype.bits()) };
let res = unsafe { libc::setns(fd, nstype.bits()) };

Errno::result(res).map(drop)
}