Skip to content

Commit

Permalink
Merge #1090
Browse files Browse the repository at this point in the history
1090: Expose sched_yield on non-linux-like hosts r=asomers a=kubkon

Currently, `sched` module is compiled only for linux-like hosts. However, the recently added syscall `sched_yield` is universal to all *nixes. This PR pulls all linux-like functionality into a private `sched_linux_like` module which is enabled only for android and linux hosts, while `sched_yield` and `sched` modules are now compiled for all *nixes, thus, correctly exposing `sched_yield` to other non-linux hosts.

Co-authored-by: Jakub Konka <jakub.konka@golem.network>
  • Loading branch information
bors[bot] and Jakub Konka committed Jul 2, 2019
2 parents dc5f8ee + b9a21ab commit b23b77e
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 109 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
([#928](https://github.com/nix-rust/nix/pull/928))

### Fixed
- Enabled `sched_yield` for all nix hosts.
([#1090](https://github.com/nix-rust/nix/pull/1090))

### Removed

## [0.14.1] - 2019-06-06
Expand Down
2 changes: 0 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@ pub mod net;
pub mod poll;
#[deny(missing_docs)]
pub mod pty;
#[cfg(any(target_os = "android",
target_os = "linux"))]
pub mod sched;
pub mod sys;
// This can be implemented for other platforms as soon as libc
Expand Down
230 changes: 123 additions & 107 deletions src/sched.rs
Original file line number Diff line number Diff line change
@@ -1,131 +1,147 @@
use std::mem;
use std::os::unix::io::RawFd;
use std::option::Option;
use libc::{self, c_int, c_void};
use {Error, Result};
use errno::Errno;
use ::unistd::Pid;

// For some functions taking with a parameter of type CloneFlags,
// only a subset of these flags have an effect.
libc_bitflags!{
pub struct CloneFlags: 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_NEWCGROUP;
CLONE_NEWUTS;
CLONE_NEWIPC;
CLONE_NEWUSER;
CLONE_NEWPID;
CLONE_NEWNET;
CLONE_IO;
use libc;
use {Errno, Result};

#[cfg(any(target_os = "android", target_os = "linux"))]
pub use self::sched_linux_like::*;

#[cfg(any(target_os = "android", target_os = "linux"))]
mod sched_linux_like {
use errno::Errno;
use libc::{self, c_int, c_void};
use std::mem;
use std::option::Option;
use std::os::unix::io::RawFd;
use unistd::Pid;
use {Error, Result};

// For some functions taking with a parameter of type CloneFlags,
// only a subset of these flags have an effect.
libc_bitflags! {
pub struct CloneFlags: 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_NEWCGROUP;
CLONE_NEWUTS;
CLONE_NEWIPC;
CLONE_NEWUSER;
CLONE_NEWPID;
CLONE_NEWNET;
CLONE_IO;
}
}
}

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

#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct CpuSet {
cpu_set: libc::cpu_set_t,
}
pub type CloneCb<'a> = Box<FnMut() -> isize + 'a>;

impl CpuSet {
pub fn new() -> CpuSet {
CpuSet { cpu_set: unsafe { mem::zeroed() } }
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct CpuSet {
cpu_set: libc::cpu_set_t,
}

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) })
impl CpuSet {
pub fn new() -> CpuSet {
CpuSet {
cpu_set: unsafe { mem::zeroed() },
}
}
}

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

pub fn sched_setaffinity(pid: Pid, cpuset: &CpuSet) -> Result<()> {
let res = unsafe {
libc::sched_setaffinity(pid.into(),
mem::size_of::<CpuSet>() as libc::size_t,
&cpuset.cpu_set)
};
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) })
}
}
}

Errno::result(res).map(drop)
}
pub fn sched_setaffinity(pid: Pid, cpuset: &CpuSet) -> Result<()> {
let res = unsafe {
libc::sched_setaffinity(
pid.into(),
mem::size_of::<CpuSet>() as libc::size_t,
&cpuset.cpu_set,
)
};

/// Explicitly yield the processor to other threads.
///
/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_yield.html)
pub fn sched_yield() -> Result<()> {
let res = unsafe {
libc::sched_yield()
};
Errno::result(res).map(drop)
}

Errno::result(res).map(drop)
}
pub fn clone(
mut cb: CloneCb,
stack: &mut [u8],
flags: CloneFlags,
signal: Option<c_int>,
) -> Result<Pid> {
extern "C" fn callback(data: *mut CloneCb) -> c_int {
let cb: &mut CloneCb = unsafe { &mut *data };
(*cb)() as c_int
}

pub fn clone(mut cb: CloneCb,
stack: &mut [u8],
flags: CloneFlags,
signal: Option<c_int>)
-> Result<Pid> {
extern "C" fn callback(data: *mut CloneCb) -> c_int {
let cb: &mut CloneCb = unsafe { &mut *data };
(*cb)() as c_int
let res = unsafe {
let combined = flags.bits() | signal.unwrap_or(0);
let ptr = stack.as_mut_ptr().offset(stack.len() as isize);
let ptr_aligned = ptr.offset((ptr as usize % 16) as isize * -1);
libc::clone(
mem::transmute(
callback as extern "C" fn(*mut Box<::std::ops::FnMut() -> isize>) -> i32,
),
ptr_aligned as *mut c_void,
combined,
&mut cb as *mut _ as *mut c_void,
)
};

Errno::result(res).map(Pid::from_raw)
}

let res = unsafe {
let combined = flags.bits() | signal.unwrap_or(0);
let ptr = stack.as_mut_ptr().offset(stack.len() as isize);
let ptr_aligned = ptr.offset((ptr as usize % 16) as isize * -1);
libc::clone(mem::transmute(callback as extern "C" fn(*mut Box<::std::ops::FnMut() -> isize>) -> i32),
ptr_aligned as *mut c_void,
combined,
&mut cb as *mut _ as *mut c_void)
};

Errno::result(res).map(Pid::from_raw)
}
pub fn unshare(flags: CloneFlags) -> Result<()> {
let res = unsafe { libc::unshare(flags.bits()) };

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

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

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

pub fn setns(fd: RawFd, nstype: CloneFlags) -> Result<()> {
let res = unsafe { libc::setns(fd, nstype.bits()) };
/// Explicitly yield the processor to other threads.
///
/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_yield.html)
pub fn sched_yield() -> Result<()> {
let res = unsafe { libc::sched_yield() };

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

0 comments on commit b23b77e

Please sign in to comment.