Skip to content

Commit 5847557

Browse files
pvachonwycats
authored andcommitted
Add mmap, shm_open and other mman relatives
Add various wrappers to make interacting with Rust a bit more pleasant for memory management. Additionally, provide ftruncate(2), which is useful when working with shared memory. Allow managing CPU affinity of a Rust Task living in a system thread.
1 parent 19fae84 commit 5847557

File tree

4 files changed

+232
-4
lines changed

4 files changed

+232
-4
lines changed

src/sched.rs

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::mem;
2-
use libc::{c_int, c_uint, c_void};
2+
use libc::{c_int, c_uint, c_void, c_ulong};
33
use super::{SysResult, SysError};
44

55
pub type CloneFlags = c_uint;
@@ -27,10 +27,77 @@ pub static CLONE_NEWPID: CloneFlags = 0x20000000;
2727
pub static CLONE_NEWNET: CloneFlags = 0x40000000;
2828
pub static CLONE_IO: CloneFlags = 0x80000000;
2929

30+
// Support a maximum CPU set of 1024 nodes
31+
#[cfg(target_arch = "x86_64")]
32+
mod cpuset_attribs {
33+
use super::CpuMask;
34+
pub const CPU_SETSIZE: uint = 1024u;
35+
pub const CPU_MASK_BITS: uint = 64u;
36+
37+
#[inline]
38+
pub fn set_cpu_mask_flag(cur: CpuMask, bit: uint) -> CpuMask {
39+
cur | (1u64 << bit)
40+
}
41+
42+
#[inline]
43+
pub fn clear_cpu_mask_flag(cur: CpuMask, bit: uint) -> CpuMask {
44+
cur & !(1u64 << bit)
45+
}
46+
}
47+
48+
#[cfg(target_arch = "x86")]
49+
mod cpuset_attribs {
50+
use super::CpuMask;
51+
pub const CPU_SETSIZE: uint = 1024u;
52+
pub const CPU_MASK_BITS: uint = 32u;
53+
54+
#[inline]
55+
pub fn set_cpu_mask_flag(cur: CpuMask, bit: uint) -> CpuMask {
56+
cur | (1u32 << bit)
57+
}
58+
59+
#[inline]
60+
pub fn clear_cpu_mask_flag(cur: CpuMask, bit: uint) -> CpuMask {
61+
cur & !(1u32 << bit)
62+
}
63+
}
64+
3065
pub type CloneCb<'a> = ||:'a -> int;
3166

67+
// A single CPU mask word
68+
pub type CpuMask = c_ulong;
69+
70+
// Structure representing the CPU set to apply
71+
#[repr(C)]
72+
pub struct CpuSet {
73+
cpu_mask: [CpuMask, ..cpuset_attribs::CPU_SETSIZE/cpuset_attribs::CPU_MASK_BITS]
74+
}
75+
76+
impl CpuSet {
77+
pub fn new() -> CpuSet {
78+
CpuSet {
79+
cpu_mask: unsafe { mem::zeroed() }
80+
}
81+
}
82+
83+
pub fn set(&mut self, field: uint) {
84+
let word = field / cpuset_attribs::CPU_MASK_BITS;
85+
let bit = field % cpuset_attribs::CPU_MASK_BITS;
86+
87+
self.cpu_mask[word] = cpuset_attribs::set_cpu_mask_flag(self.cpu_mask[word], bit);
88+
}
89+
90+
pub fn unset(&mut self, field: uint) {
91+
let word = field / cpuset_attribs::CPU_MASK_BITS;
92+
let bit = field % cpuset_attribs::CPU_MASK_BITS;
93+
94+
self.cpu_mask[word] = cpuset_attribs::clear_cpu_mask_flag(self.cpu_mask[word], bit);
95+
}
96+
}
97+
3298
mod ffi {
33-
use libc::{c_void, c_int};
99+
use libc::{c_void, c_int, pid_t, size_t};
100+
use super::CpuSet;
34101

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

@@ -47,6 +114,23 @@ mod ffi {
47114
// disassociate parts of the process execution context
48115
// doc: http://man7.org/linux/man-pages/man2/unshare.2.html
49116
pub fn unshare(flags: super::CloneFlags) -> c_int;
117+
118+
// Set the current CPU set that a task is allowed to run on
119+
pub fn sched_setaffinity(__pid: pid_t, __cpusetsize: size_t, __cpuset: *const CpuSet) -> c_int;
120+
}
121+
}
122+
123+
pub fn sched_setaffinity(pid: int, cpuset: &CpuSet) -> SysResult<()> {
124+
use libc::{pid_t, size_t};
125+
126+
let res = unsafe {
127+
ffi::sched_setaffinity(pid as pid_t, mem::size_of::<CpuSet>() as size_t, mem::transmute(cpuset))
128+
};
129+
130+
if res != 0 {
131+
Err(SysError::last())
132+
} else {
133+
Ok(())
50134
}
51135
}
52136

src/sys/mman.rs

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
use errno::{SysResult, SysError};
2+
use std::io::FilePermission;
3+
use fcntl::{Fd, OFlag};
4+
use libc::{c_void, size_t, off_t, mode_t};
5+
6+
pub use self::consts::*;
7+
8+
#[cfg(target_os = "linux")]
9+
mod consts {
10+
use libc::c_int;
11+
12+
pub type MmapFlag = c_int;
13+
14+
pub const MAP_SHARED: MmapFlag = 0x00001;
15+
pub const MAP_PRIVATE: MmapFlag = 0x00002;
16+
pub const MAP_FIXED: MmapFlag = 0x00010;
17+
18+
pub const MAP_FILE: MmapFlag = 0x00000;
19+
pub const MAP_ANONYMOUS: MmapFlag = 0x00020;
20+
pub const MAP_ANON: MmapFlag = MAP_ANONYMOUS;
21+
pub const MAP_32BIT: MmapFlag = 0x00040;
22+
23+
pub const MAP_GROWSDOWN: MmapFlag = 0x00100;
24+
pub const MAP_DENYWRITE: MmapFlag = 0x00800;
25+
pub const MAP_EXECUTABLE: MmapFlag = 0x01000;
26+
pub const MAP_LOCKED: MmapFlag = 0x02000;
27+
pub const MAP_NORESERVE: MmapFlag = 0x04000;
28+
pub const MAP_POPULATE: MmapFlag = 0x08000;
29+
pub const MAP_NONBLOCK: MmapFlag = 0x10000;
30+
pub const MAP_STACK: MmapFlag = 0x20000;
31+
pub const MAP_HUGETLB: MmapFlag = 0x40000;
32+
33+
pub type MmapProt = c_int;
34+
35+
pub const PROT_READ: MmapProt = 0x1;
36+
pub const PROT_WRITE: MmapProt = 0x2;
37+
pub const PROT_EXEC: MmapProt = 0x4;
38+
pub const PROT_NONE: MmapProt = 0x0;
39+
pub const PROT_GROWSDOWN: MmapProt = 0x01000000;
40+
pub const PROT_GROWSUP: MmapProt = 0x02000000;
41+
42+
pub const MAP_FAILED: int = -1;
43+
}
44+
45+
#[cfg(target_os = "macos")]
46+
mod consts {
47+
use libc::c_int;
48+
49+
pub type MmapFlag = c_int;
50+
51+
pub const MAP_SHARED: MmapFlag = 0x00001;
52+
pub const MAP_PRIVATE: MmapFlag = 0x00002;
53+
pub const MAP_FIXED: MmapFlag = 0x00010;
54+
55+
pub const MAP_NOCACHE: MmapFlag = 0x00400;
56+
pub const MAP_JIT: MmapFlag = 0x00800;
57+
58+
pub type MmapProt = c_int;
59+
60+
pub const PROT_READ: MmapProt = 0x1;
61+
pub const PROT_WRITE: MmapProt = 0x2;
62+
pub const PROT_EXEC: MmapProt = 0x4;
63+
pub const PROT_NONE: MmapProt = 0x0;
64+
65+
pub const MAP_FAILED: int = -1;
66+
}
67+
68+
mod ffi {
69+
use libc::{c_void, size_t, c_int, c_char, mode_t};
70+
71+
pub use libc::{mmap, munmap};
72+
73+
74+
extern {
75+
pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t) -> c_int;
76+
pub fn shm_unlink(name: *const c_char) -> c_int;
77+
pub fn mlock(addr: *const c_void, len: size_t) -> c_int;
78+
pub fn munlock(addr: *const c_void, len: size_t) -> c_int;
79+
}
80+
}
81+
82+
pub unsafe fn mlock(addr: *const c_void, length: size_t) -> SysResult<()> {
83+
match ffi::mlock(addr, length) {
84+
0 => Ok(()),
85+
_ => Err(SysError::last())
86+
}
87+
}
88+
89+
pub fn munlock(addr: *const c_void, length: size_t) -> SysResult<()> {
90+
match unsafe { ffi::munlock(addr, length) } {
91+
0 => Ok(()),
92+
_ => Err(SysError::last())
93+
}
94+
}
95+
96+
/// Calls to mmap are inherently unsafe, so they must be made in an unsafe block. Typically
97+
/// a higher-level abstraction will hide the unsafe interactions with the mmap'd region.
98+
pub fn mmap(addr: *mut c_void, length: size_t, prot: MmapProt, flags: MmapFlag, fd: Fd, offset: off_t) -> SysResult<*mut c_void> {
99+
let ret = unsafe { ffi::mmap(addr, length, prot, flags, fd, offset) };
100+
101+
if ret as int == MAP_FAILED {
102+
Err(SysError::last())
103+
} else {
104+
Ok(ret)
105+
}
106+
}
107+
108+
pub fn munmap(addr: *mut c_void, len: size_t) -> SysResult<()> {
109+
match unsafe { ffi::munmap(addr, len) } {
110+
0 => Ok(()),
111+
_ => Err(SysError::last())
112+
}
113+
}
114+
115+
pub fn shm_open(name: &String, flag: OFlag, mode: FilePermission) -> SysResult<Fd> {
116+
let ret = unsafe { ffi::shm_open(name.to_c_str().as_ptr(), flag.bits(), mode.bits() as mode_t) };
117+
118+
if ret < 0 {
119+
Err(SysError::last())
120+
} else {
121+
Ok(ret)
122+
}
123+
}
124+
125+
pub fn shm_unlink(name: &String) -> SysResult<()> {
126+
let ret = unsafe { ffi::shm_unlink(name.to_c_str().as_ptr()) };
127+
128+
if ret < 0 {
129+
Err(SysError::last())
130+
} else {
131+
Ok(())
132+
}
133+
}
134+

src/sys/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,5 @@ pub mod stat;
2121
pub mod utsname;
2222

2323
pub mod wait;
24+
25+
pub mod mman;

src/unistd.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::{mem, ptr};
22
use std::c_str::{CString, ToCStr};
3-
use libc::{c_char, c_void, c_int, size_t, pid_t};
3+
use libc::{c_char, c_void, c_int, size_t, pid_t, off_t};
44
use fcntl::{fcntl, Fd, OFlag, O_NONBLOCK, O_CLOEXEC, FD_CLOEXEC, F_SETFD, F_SETFL};
55
use errno::{SysResult, SysError, from_ffi};
66
use core::raw::Slice as RawSlice;
@@ -11,7 +11,7 @@ pub use self::linux::*;
1111
mod ffi {
1212
use super::{IovecR,IovecW};
1313
use libc::{c_char, c_int, size_t, ssize_t};
14-
pub use libc::{close, read, write, pipe};
14+
pub use libc::{close, read, write, pipe, ftruncate};
1515
pub use libc::funcs::posix88::unistd::fork;
1616
use fcntl::Fd;
1717

@@ -393,6 +393,14 @@ fn pipe2_setflags(fd1: Fd, fd2: Fd, flags: OFlag) -> SysResult<()> {
393393
}
394394
}
395395

396+
pub fn ftruncate(fd: Fd, len: off_t) -> SysResult<()> {
397+
if unsafe { ffi::ftruncate(fd, len) } < 0 {
398+
Err(SysError::last())
399+
} else {
400+
Ok(())
401+
}
402+
}
403+
396404
#[cfg(target_os = "linux")]
397405
mod linux {
398406
use std::path::Path;

0 commit comments

Comments
 (0)