mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-01-27 02:28:22 +00:00
sys_util: add sys_util crate for misc system modules
This initial commit includes an mmap wrapper. TEST=cargo test BUG=None Change-Id: I9625bd446fcd4801b2e16188897e84714b4e4ce0 Reviewed-on: https://chromium-review.googlesource.com/496987 Commit-Ready: Dylan Reid <dgreid@chromium.org> Tested-by: Zach Reizner <zachr@chromium.org> Reviewed-by: Dylan Reid <dgreid@chromium.org>
This commit is contained in:
parent
303f86fa21
commit
00f90a4bba
4 changed files with 196 additions and 0 deletions
8
sys_util/Cargo.toml
Normal file
8
sys_util/Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "sys_util"
|
||||
version = "0.1.0"
|
||||
authors = ["The Chromium OS Authors"]
|
||||
|
||||
[dependencies]
|
||||
libc = "*"
|
||||
|
38
sys_util/src/errno.rs
Normal file
38
sys_util/src/errno.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
// Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
use std::result;
|
||||
|
||||
use libc::__errno_location;
|
||||
|
||||
/// An error number, retrieved from [errno](http://man7.org/linux/man-pages/man3/errno.3.html), set
|
||||
/// by a libc function that returned an error.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct Error(i32);
|
||||
pub type Result<T> = result::Result<T, Error>;
|
||||
|
||||
impl Error {
|
||||
/// Constructs a new error with the given errno.
|
||||
pub fn new(e: i32) -> Error {
|
||||
Error(e)
|
||||
}
|
||||
|
||||
/// Constructs an error from the current errno.
|
||||
///
|
||||
/// The result of this only has any meaning just after a libc call that returned a value
|
||||
/// indicating errno was set.
|
||||
pub fn last() -> Error {
|
||||
Error(unsafe { *__errno_location() })
|
||||
}
|
||||
|
||||
/// Gets the errno for this error
|
||||
pub fn errno(&self) -> i32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the last errno as a Result that is always an error.
|
||||
pub fn errno_result<T>() -> Result<T> {
|
||||
Err(Error::last())
|
||||
}
|
14
sys_util/src/lib.rs
Normal file
14
sys_util/src/lib.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
// Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
//! Small system utility modules for usage by other modules.
|
||||
|
||||
extern crate libc;
|
||||
|
||||
mod mmap;
|
||||
mod errno;
|
||||
|
||||
pub use mmap::*;
|
||||
pub use errno::{Error, Result};
|
||||
use errno::errno_result;
|
136
sys_util/src/mmap.rs
Normal file
136
sys_util/src/mmap.rs
Normal file
|
@ -0,0 +1,136 @@
|
|||
// Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
//! The mmap module provides a safe interface to mmap memory and ensures unmap is called when the
|
||||
//! mmap object leaves scope.
|
||||
|
||||
use std;
|
||||
use std::ptr::null_mut;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
use libc;
|
||||
|
||||
use {Result, errno_result};
|
||||
|
||||
/// Wraps an anonymous shared memory mapping in the current process.
|
||||
pub struct MemoryMapping {
|
||||
addr: *mut u8,
|
||||
size: usize,
|
||||
ref_count: Arc<AtomicUsize>,
|
||||
}
|
||||
|
||||
unsafe impl Send for MemoryMapping {}
|
||||
|
||||
impl MemoryMapping {
|
||||
/// Creates an anonymous shared mapping of `size` bytes.
|
||||
pub fn new(size: usize) -> Result<MemoryMapping> {
|
||||
// This is safe because we are creating an anonymous mapping in a place not already used by
|
||||
// any other area in this process.
|
||||
let addr = unsafe {
|
||||
libc::mmap(null_mut(),
|
||||
size,
|
||||
libc::PROT_READ | libc::PROT_WRITE,
|
||||
libc::MAP_ANONYMOUS | libc::MAP_SHARED | libc::MAP_NORESERVE,
|
||||
-1,
|
||||
0)
|
||||
};
|
||||
if addr == null_mut() {
|
||||
return errno_result();
|
||||
}
|
||||
Ok(MemoryMapping {
|
||||
addr: addr as *mut u8,
|
||||
size: size,
|
||||
ref_count: Arc::new(AtomicUsize::new(1)),
|
||||
})
|
||||
}
|
||||
|
||||
/// Maps the first `size` bytes of the given `fd`.
|
||||
pub fn from_fd(fd: &AsRawFd, size: usize) -> Result<MemoryMapping> {
|
||||
// This is safe because we are creating a mapping in a place not already used by any other
|
||||
// area in this process.
|
||||
let addr = unsafe {
|
||||
libc::mmap(null_mut(),
|
||||
size,
|
||||
libc::PROT_READ | libc::PROT_WRITE,
|
||||
libc::MAP_SHARED,
|
||||
fd.as_raw_fd(),
|
||||
0)
|
||||
};
|
||||
if addr == null_mut() {
|
||||
return errno_result();
|
||||
}
|
||||
Ok(MemoryMapping {
|
||||
addr: addr as *mut u8,
|
||||
size: size,
|
||||
ref_count: Arc::new(AtomicUsize::new(1)),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> *mut u8 {
|
||||
self.addr
|
||||
}
|
||||
|
||||
pub fn size(&self) -> usize {
|
||||
self.size
|
||||
}
|
||||
|
||||
#[deprecated(note="use volatile_read with the ptr instead")]
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
// This is safe because we mapped the area at addr ourselves, so this slice will not
|
||||
// overflow. However, it is possible to alias, hence the deprecation.
|
||||
unsafe { std::slice::from_raw_parts(self.addr, self.size) }
|
||||
}
|
||||
|
||||
#[deprecated(note="use volatile_write with the ptr instead")]
|
||||
pub fn as_mut_slice(&self) -> &mut [u8] {
|
||||
// This is safe because we mapped the area at addr ourselves, so this slice will not
|
||||
// overflow. However, it is possible to alias, hence the deprecation.
|
||||
unsafe { std::slice::from_raw_parts_mut(self.addr, self.size) }
|
||||
}
|
||||
|
||||
// TODO(zachr): remove when we no longer need it, clone is sketchy
|
||||
pub fn clone(&self) -> MemoryMapping {
|
||||
self.ref_count.fetch_add(1, Ordering::SeqCst);
|
||||
MemoryMapping {
|
||||
addr: self.addr,
|
||||
size: self.size,
|
||||
ref_count: self.ref_count.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for MemoryMapping {
|
||||
fn drop(&mut self) {
|
||||
if self.ref_count.fetch_sub(1, Ordering::SeqCst) == 1 {
|
||||
// This is safe because we mmap the area at addr ourselves, and the ref_count ensures
|
||||
// nobody else is holding a reference to it.
|
||||
unsafe {
|
||||
libc::munmap(self.addr as *mut libc::c_void, self.size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn basic_map() {
|
||||
let m = MemoryMapping::new(1024).unwrap();
|
||||
assert_eq!(1024, m.size());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mutate_slices() {
|
||||
let m = MemoryMapping::new(1024).unwrap();
|
||||
assert_eq!(1024, m.size());
|
||||
{
|
||||
m.as_mut_slice()[128] = 55;
|
||||
}
|
||||
assert_eq!(m.as_slice()[128], 55);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue