From 7b623e0fdf8b389502542eb26abe6298885fa099 Mon Sep 17 00:00:00 2001 From: Avril Date: Sat, 12 Jun 2021 00:48:43 +0100 Subject: [PATCH 1/3] rust bindings: start --- .gitignore | 2 ++ cowslice/Cargo.lock | 34 ++++++++++++++++++++++++++++++++++ cowslice/Cargo.toml | 11 +++++++++++ cowslice/build.rs | 27 +++++++++++++++++++++++++++ cowslice/src/ffi.rs | 29 +++++++++++++++++++++++++++++ cowslice/src/lib.rs | 25 +++++++++++++++++++++++++ 6 files changed, 128 insertions(+) create mode 100644 cowslice/Cargo.lock create mode 100644 cowslice/Cargo.toml create mode 100644 cowslice/build.rs create mode 100644 cowslice/src/ffi.rs create mode 100644 cowslice/src/lib.rs diff --git a/.gitignore b/.gitignore index 036690b..c2afdd8 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ cow-* obj/ *~ vgcore.* +target/ +!cowslice/*.a diff --git a/cowslice/Cargo.lock b/cowslice/Cargo.lock new file mode 100644 index 0000000..8534f00 --- /dev/null +++ b/cowslice/Cargo.lock @@ -0,0 +1,34 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cowslice" +version = "0.1.0" +dependencies = [ + "rustc_version", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" diff --git a/cowslice/Cargo.toml b/cowslice/Cargo.toml new file mode 100644 index 0000000..423fbbd --- /dev/null +++ b/cowslice/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "cowslice" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +[build-dependencies] +rustc_version = "0.2" diff --git a/cowslice/build.rs b/cowslice/build.rs new file mode 100644 index 0000000..ff8ed17 --- /dev/null +++ b/cowslice/build.rs @@ -0,0 +1,27 @@ + +extern crate rustc_version; +use rustc_version::{version, version_meta, Channel}; + +fn main() { + // Assert we haven't travelled back in time + assert!(version().unwrap().major >= 1); + + // Set cfg flags depending on release channel + match version_meta().unwrap().channel { + Channel::Stable => { + println!("cargo:rustc-cfg=stable"); + } + Channel::Beta => { + println!("cargo:rustc-cfg=beta"); + } + Channel::Nightly => { + println!("cargo:rustc-cfg=nightly"); + } + Channel::Dev => { + println!("cargo:rustc-cfg=dev"); + } + } + // Link to `libcow.a` + println!(r"cargo:rustc-link-search=./lib"); + println!(r"cargo:rustc-link-lib=cow"); +} diff --git a/cowslice/src/ffi.rs b/cowslice/src/ffi.rs new file mode 100644 index 0000000..cba37ef --- /dev/null +++ b/cowslice/src/ffi.rs @@ -0,0 +1,29 @@ +//! Interfaces with the C library +use core::ffi::c_void; + +/// Raw `cow_t*` +/// +/// This is, essentially, a pointer to the origin (`void*`) pointer. +/// So is represented as `*mut RawHandle == void**`. +pub type RawHandle = *mut c_void; + +extern "C" { + pub fn cow_create(sz: usize) -> *mut RawHandle; + pub fn cow_free(cow: *mut RawHandle); + pub fn cow_clone(cow: *const RawHandle) -> *mut RawHandle; + + pub fn cow_is_fake(cow: *const RawHandle) -> i32; + pub fn cow_size(cow: *const RawHandle) -> usize; + + pub fn cow_err() -> i32; + pub fn cow_err_msg(kind: i32) -> *const *const u8; +} + +#[inline(always)] pub unsafe fn cow_area_mut(cow: *mut RawHandle) -> *mut c_void +{ + *cow +} +#[inline(always)] pub unsafe fn cow_area(cow: *const RawHandle) -> *const c_void +{ + (*cow) as *const _ +} diff --git a/cowslice/src/lib.rs b/cowslice/src/lib.rs new file mode 100644 index 0000000..2945950 --- /dev/null +++ b/cowslice/src/lib.rs @@ -0,0 +1,25 @@ + +#![allow(dead_code)] + +mod ffi; + +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } + #[test] + fn link_works() { + + unsafe { + let raw_h = super::ffi::cow_create(100); + assert_ne!(raw_h as usize, 0); + println!("Raw handle pointer is {:p}", raw_h); + super::ffi::cow_free(raw_h); + } + unsafe { + assert_eq!(super::ffi::cow_err(), 1, "There was an error in `cow_free`"); + } + } +} From 2d4ebc3142e8cfb873eb9e64018e23a958de3916 Mon Sep 17 00:00:00 2001 From: Avril Date: Sun, 13 Jun 2021 00:14:22 +0100 Subject: [PATCH 2/3] error type --- cowslice/src/error.rs | 41 +++++++++++++++++++++++++++++++++++++++++ cowslice/src/lib.rs | 8 +++----- 2 files changed, 44 insertions(+), 5 deletions(-) create mode 100644 cowslice/src/error.rs diff --git a/cowslice/src/error.rs b/cowslice/src/error.rs new file mode 100644 index 0000000..df468c7 --- /dev/null +++ b/cowslice/src/error.rs @@ -0,0 +1,41 @@ +use super::*; +use std::{error, fmt}; +use std::ffi::CStr; + +/// A `libcow` error object. +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[repr(transparent)] +pub struct Error(i32); + +impl Error +{ + /// The last error in `libcow`. + #[inline(always)] pub fn last() -> Self + { + Self(unsafe {ffi::cow_err()}) + } +} + +impl error::Error for Error{} +impl fmt::Display for Error +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + const DEFAULT: &'static [u8] = b"unknown\0"; // must be `nul`'d + let cstr = unsafe { + let ptr = ffi::cow_err_msg(self.0); + if ptr.is_null() { + CStr::from_bytes_with_nul_unchecked(DEFAULT) + } else { + let ptr = *ptr; + if ptr.is_null() { + CStr::from_bytes_with_nul_unchecked(DEFAULT) + } else { + CStr::from_ptr(ptr as *const i8) + } + } + }; + write!(f, "{}", cstr.to_string_lossy()) + } +} + diff --git a/cowslice/src/lib.rs b/cowslice/src/lib.rs index 2945950..5726c79 100644 --- a/cowslice/src/lib.rs +++ b/cowslice/src/lib.rs @@ -3,15 +3,13 @@ mod ffi; +pub mod error; +pub use error::Error; + #[cfg(test)] mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } #[test] fn link_works() { - unsafe { let raw_h = super::ffi::cow_create(100); assert_ne!(raw_h as usize, 0); From 0d082f5b6fb48dddcaf669e9d30e0be18f4512f2 Mon Sep 17 00:00:00 2001 From: Avril Date: Tue, 3 Jan 2023 14:29:53 +0000 Subject: [PATCH 3/3] Added `cow_create_fd(fd, size)`: Create a `cow_t*` over an already existing file descriptor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fortune for libcow's current commit: Half curse − 半凶 --- Makefile | 2 +- include/cow.h | 7 +++++++ include/cow.hpp | 2 ++ src/cow.c | 13 ++++++++++--- src/cow.cpp | 6 +++++- src/cow_t.h | 2 +- 6 files changed, 26 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index f9c7442..94d2c9f 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ PROJECT=cow AUTHOR=Avril (Flanchan) VERSION_MAJOR=0 -VERSION_MINOR=2.0 +VERSION_MINOR=3.0 VERSION=$(VERSION_MAJOR).$(VERSION_MINOR) ifeq ($(PREFIX),) diff --git a/include/cow.h b/include/cow.h index f522720..b00490a 100644 --- a/include/cow.h +++ b/include/cow.h @@ -35,6 +35,13 @@ typedef struct cow_mapped_slice cow_t; /// Writes to this instance pointer (`cow_ptr()`) are written to the allocated memory. /// Writes to any cloned instances do not propagate to this instance. cow_t* cow_create(size_t size); +/// Create a new copy-on-write area of `size` bytes from file `fd`. +/// Writes to this instance pointer (`cow_ptr()`) are written to the allocated memory. +/// Writes to any cloned instances do not propagate to this instance. +/// +/// The resulting object does not own `fd`, but does own a duplicate of it. +cow_t* cow_create_fd(int fd, size_t size); + /// Free a cow area. This should be called on all clones before the parent of those clones is freed. void cow_free(cow_t* restrict cow); /// Create a clone of this instance. Any writes to the returned pointer will not be propagated to the input one. diff --git a/include/cow.hpp b/include/cow.hpp index e0202bf..d7b6649 100644 --- a/include/cow.hpp +++ b/include/cow.hpp @@ -21,7 +21,9 @@ struct Cow : public _cow_util::Span { struct Fake; Cow() = delete; + Cow(int fd, size_t size); explicit Cow(size_t size); + Cow(Cow&& m); virtual ~Cow(); diff --git a/src/cow.c b/src/cow.c index 2e8d355..88f6712 100644 --- a/src/cow.c +++ b/src/cow.c @@ -76,13 +76,13 @@ size_t cow_size(const cow_t* cow) return cow->size; } -inline internal cow_t _cow_create_unboxed(size_t size) +inline internal cow_t _cow_create_unboxed(int _fd, size_t size) { cow_t ret; ret.size = size; if( (ret.poisoned = - ((ret.fd = shm_fd(size)) == -1)) + ((ret.fd = _fd < 0 ? shm_fd(size) : _fd) == -1)) ) { ret.origin = NULL; return ret; @@ -96,7 +96,14 @@ inline internal cow_t _cow_create_unboxed(size_t size) } cow_t* cow_create(size_t size) { - return box_value(_cow_create_unboxed(size)); + return box_value(_cow_create_unboxed(-1, size)); +} + +cow_t* cow_create_fd(int fd, size_t size) +{ + fd = dup(fd); + if(__builtin_expect(fd < 0, false)) return NULL; + return box_value(_cow_create_unboxed(fd, size)); } inline internal void _cow_free_unboxed(const cow_t* cow) diff --git a/src/cow.cpp b/src/cow.cpp index d84df09..d521365 100644 --- a/src/cow.cpp +++ b/src/cow.cpp @@ -15,6 +15,7 @@ struct Cow::_inner { ~_inner(); _inner(size_t sz); + _inner(int fd, size_t sz); _inner(cow_t* ptr); _inner(const _inner& copy) = delete; @@ -27,10 +28,12 @@ Cow::_inner::~_inner() { _cow_free_unboxed(ptr()); cow.poisoned=true; } -Cow::_inner::_inner(size_t sz) : cow(_cow_create_unboxed(sz)){ +Cow::_inner::_inner(int fd, size_t sz) : cow(_cow_create_unboxed(fd, sz)){ if(UNLIKELY(cow.poisoned)) throw CowException(cow_err()); } +Cow::_inner::_inner(size_t sz) : _inner(-1, sz) {} + Cow::_inner::_inner(cow_t* ptr) : cow(*ptr) { free(ptr); @@ -38,6 +41,7 @@ Cow::_inner::_inner(cow_t* ptr) : cow(*ptr) } Cow::Cow(size_t size) : super(std::make_shared<_inner>(size)){} +Cow::Cow(int fd, size_t size) : super(std::make_shared<_inner>(fd, size)){} Cow::Cow(cow_t* raw) : super(std::make_shared<_inner>(raw)){} Cow::Cow(Cow&& m) : super(std::move(*const_cast*>(&m.super))){} diff --git a/src/cow_t.h b/src/cow_t.h index 003bbfe..122323d 100644 --- a/src/cow_t.h +++ b/src/cow_t.h @@ -44,7 +44,7 @@ _Static_assert (offsetof(cow_t, size) == sizeof(void*), "`cow_t.size` should have an offset equal to `sizeof(void*)` or cow_size_unsafe() becomes UB."); #endif -cow_t _cow_create_unboxed(size_t size) internal; +cow_t _cow_create_unboxed(int rfd, size_t size) internal; void _cow_free_unboxed(const cow_t* cow) internal; #ifdef __cplusplus