-
Notifications
You must be signed in to change notification settings - Fork 679
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Expose sched_yield on non-linux-like hosts
- Loading branch information
Jakub Konka
committed
Jun 24, 2019
1 parent
7fa4f23
commit 255e897
Showing
2 changed files
with
122 additions
and
108 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 Result; | ||
|
||
#[cfg(any(target_os = "android", target_os = "linux"))] | ||
pub use sched_linux_like::*; | ||
|
||
#[cfg(any(target_os = "android", target_os = "linux"))] | ||
mod sched_linux_like { | ||
use libc::{c_int, c_void}; | ||
use std::mem; | ||
use std::option::Option; | ||
use std::os::unix::io::RawFd; | ||
use unistd::Pid; | ||
use Error; | ||
|
||
// 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) | ||
} |