From cc4583ef505ff69fcb9463f901f42b5e11f85de6 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 9 Mar 2022 01:07:36 +0900 Subject: [PATCH] mmap skeleton --- Cargo.lock | 21 ++++++ stdlib/Cargo.toml | 2 + stdlib/src/lib.rs | 3 + stdlib/src/mmap.rs | 156 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 182 insertions(+) create mode 100644 stdlib/src/mmap.rs diff --git a/Cargo.lock b/Cargo.lock index be1bdd540..072d12200 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -996,6 +996,15 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +[[package]] +name = "memmap2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "057a3db23999c867821a7a59feb06a578fcb03685e983dff90daf9e7d24ac08f" +dependencies = [ + "libc", +] + [[package]] name = "memoffset" version = "0.6.5" @@ -1190,6 +1199,16 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978aa494585d3ca4ad74929863093e87cac9790d81fe7aba2b3dc2890643a0fc" +[[package]] +name = "page_size" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eebde548fbbf1ea81a99b128872779c437752fb99f217c45245e1a61dcd9edcd" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "parking_lot" version = "0.12.0" @@ -1719,6 +1738,7 @@ dependencies = [ "libz-sys", "md-5", "memchr", + "memmap2", "mt19937", "nix", "num-bigint", @@ -1729,6 +1749,7 @@ dependencies = [ "openssl", "openssl-probe", "openssl-sys", + "page_size", "paste", "puruspe", "rand", diff --git a/stdlib/Cargo.toml b/stdlib/Cargo.toml index 5e9127866..bbb22e862 100644 --- a/stdlib/Cargo.toml +++ b/stdlib/Cargo.toml @@ -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" diff --git a/stdlib/src/lib.rs b/stdlib/src/lib.rs index 44ca0ef94..6159b6a24 100644 --- a/stdlib/src/lib.rs +++ b/stdlib/src/lib.rs @@ -16,6 +16,8 @@ mod gc; mod hashlib; mod json; mod math; +#[cfg(unix)] +mod mmap; mod platform; mod pyexpat; mod pystruct; @@ -125,6 +127,7 @@ pub fn get_module_inits() -> impl Iterator, StdlibInit { "_posixsubprocess" => posixsubprocess::make_module, "syslog" => syslog::make_module, + "mmap" => mmap::make_module, } #[cfg(target_os = "macos")] { diff --git a/stdlib/src/mmap.rs b/stdlib/src/mmap.rs new file mode 100644 index 000000000..4cda3395a --- /dev/null +++ b/stdlib/src/mmap.rs @@ -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 { + 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(()) + } + } +}