Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
mmap skeleton
  • Loading branch information
youknowone committed Jun 14, 2022
commit cc4583ef505ff69fcb9463f901f42b5e11f85de6
21 changes: 21 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions stdlib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ ahash = "0.7.6"
libz-sys = { version = "1.1.5", optional = true }
num_enum = "0.5.7"
ascii = "1.0.0"
memmap2 = "0.5.0"
page_size = "0.4.2"

[target.'cfg(all(unix, not(target_os = "redox")))'.dependencies]
termios = "0.3.3"
Expand Down
3 changes: 3 additions & 0 deletions stdlib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ mod gc;
mod hashlib;
mod json;
mod math;
#[cfg(unix)]
mod mmap;
mod platform;
mod pyexpat;
mod pystruct;
Expand Down Expand Up @@ -125,6 +127,7 @@ pub fn get_module_inits() -> impl Iterator<Item = (Cow<'static, str>, StdlibInit
{
"_posixsubprocess" => posixsubprocess::make_module,
"syslog" => syslog::make_module,
"mmap" => mmap::make_module,
}
#[cfg(target_os = "macos")]
{
Expand Down
156 changes: 156 additions & 0 deletions stdlib/src/mmap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
pub(crate) use mmap::make_module;

#[pymodule]
mod mmap {
use crate::vm::{
builtins::PyTypeRef, convert::ToPyResult, function::OptionalArg, types::Constructor,
FromArgs, PyObject, PyPayload, PyResult, TryFromBorrowedObject, VirtualMachine,
};
use memmap2::{MmapMut, MmapOptions};

#[repr(C)]
#[derive(PartialEq, Eq, Debug)]
enum AccessMode {
Default = 0,
Read = 1,
Write = 2,
Copy = 3,
}

impl TryFromBorrowedObject for AccessMode {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult<Self> {
let i = u32::try_from_borrowed_object(vm, obj)?;
Ok(match i {
0 => Self::Default,
1 => Self::Read,
2 => Self::Write,
3 => Self::Copy,
_ => return Err(vm.new_value_error("Not a valid AccessMode value".to_owned())),
})
}
}

#[pyattr]
use libc::{MAP_ANON, MAP_ANONYMOUS, MAP_PRIVATE, MAP_SHARED, PROT_READ, PROT_WRITE};
#[pyattr]
const ACCESS_DEFAULT: u32 = AccessMode::Default as u32;
#[pyattr]
const ACCESS_READ: u32 = AccessMode::Read as u32;
#[pyattr]
const ACCESS_WRITE: u32 = AccessMode::Write as u32;
#[pyattr]
const ACCESS_COPY: u32 = AccessMode::Copy as u32;

#[pyattr(name = "PAGESIZE")]
fn pagesize(vm: &VirtualMachine) -> usize {
page_size::get()
}

#[pyattr]
#[pyclass(name = "mmap")]
#[derive(Debug, PyPayload)]
struct PyMmap {
mmap: MmapMut,
exports: usize,
// PyObject *weakreflist;
access: AccessMode,
}

#[derive(FromArgs)]
struct MmapNewArgs {
#[pyarg(any)]
fileno: std::os::unix::io::RawFd,
#[pyarg(any)]
length: isize,
#[pyarg(any, default = "MAP_SHARED")]
flags: libc::c_int,
#[pyarg(any, default = "PROT_WRITE|PROT_READ")]
prot: libc::c_int,
#[pyarg(any, default = "AccessMode::Default")]
access: AccessMode,
#[pyarg(any, default = "0")]
offset: u64,
}

impl Constructor for PyMmap {
type Args = MmapNewArgs;

fn py_new(
cls: PyTypeRef,
MmapNewArgs {
fileno: fd,
length,
flags,
prot,
access,
offset,
}: Self::Args,
vm: &VirtualMachine,
) -> PyResult {
if length < 0 {
return Err(
vm.new_overflow_error("memory mapped length must be positive".to_owned())
);
}
// if offset < 0 {
// return Err(vm.new_overflow_error("memory mapped offset must be positive".to_owned()));
// }
if (access != AccessMode::Default)
&& ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ)))
{
return Err(vm.new_value_error(
"mmap can't specify both access and flags, prot.".to_owned(),
));
}

let (flags, prot, access) = match access {
AccessMode::Read => (MAP_SHARED, PROT_READ, access),
AccessMode::Write => (MAP_SHARED, PROT_READ | PROT_WRITE, access),
AccessMode::Copy => (MAP_PRIVATE, PROT_READ | PROT_WRITE, access),
AccessMode::Default => {
let access = if (prot & PROT_READ) != 0 && (prot & PROT_WRITE) != 0 {
access
} else if (prot & PROT_WRITE) != 0 {
AccessMode::Write
} else {
AccessMode::Read
};
(flags, prot, access)
}
_ => return Err(vm.new_value_error("mmap invalid access parameter.".to_owned())),
};

let mut mmap_opt = MmapOptions::new();
let mmap_opt = mmap_opt.offset(offset);
// .len(map_size)
let mmap = match access {
AccessMode::Write => unsafe { mmap_opt.map_mut(fd) },
// AccessMode::Read => mmap_opt.map(fd),
AccessMode::Copy => unsafe { mmap_opt.map_copy(fd) },
_ => unreachable!("access must be decided before here"),
}
.map_err(|_| vm.new_value_error("FIXME: mmap error".to_owned()))?;

let m_obj = Self {
mmap,
exports: 0,
access,
};

m_obj.to_pyresult(vm)
}
}

#[pyimpl]
impl PyMmap {
#[pymethod]
fn close(&self) -> PyResult<()> {
if self.exports > 0 {
// PyErr_SetString(PyExc_BufferError, "cannot close "\
// "exported pointers exist");
}
// self.mmap = MmapMut::map_anon(0).unwrap();
Ok(())
}
}
}