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