Skip to content

Commit

Permalink
Replace parts of ffi module by libc functions in sched.rs
Browse files Browse the repository at this point in the history
  • Loading branch information
fiveop committed Aug 29, 2016
1 parent e2d3495 commit 899a130
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 160 deletions.
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;
}
}

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)
}

0 comments on commit 899a130

Please sign in to comment.