diff --git a/README.md b/README.md index f68b7f7..764480f 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Automatic copy-on-write semantic memory slices for use in C (and C++) # Usage See `include/cow.h` for documentation on each function. -Each function, macro, and type definition in the header will be prefixed with `cow_` or `COW_`. +Each function, macro, and type definition in the header will be prefixed with `cow_` or `COW_`. Internal non-prototpyed items use the namespace `_cow_` or `_COW_`. ## Building Run `make` to build to build the `release` (optimised) target of the library. diff --git a/include/cow.h b/include/cow.h index af9fc4f..6249fdb 100644 --- a/include/cow.h +++ b/include/cow.h @@ -9,7 +9,7 @@ extern "C" { #include // Copy-on-write mapped memory. -typedef struct cow cow_t; +typedef struct cow_mapped_slice cow_t; /// Create a new copy-on-write area of `size` bytes. /// Writes to this instance pointer (`cow_ptr()`) are written to the allocated memory. diff --git a/src/cow.c b/src/cow.c index de79f11..cd5e95a 100644 --- a/src/cow.c +++ b/src/cow.c @@ -31,14 +31,8 @@ #define LASSERT(expr, msg) ASSERT(LIKELY(expr), "(unexpected) " msg) #define UASSERT(expr, msg) ASSERT(UNLIKELY(expr), "(expected) " msg) -struct cow { - void* origin; // ptr to mapped memory. This *MUST* be the first field and have an offset of 0. - - int fd; // Will be ORd with ~INT_MAX if it's a clone. Will be >0 if it's the original. - size_t size; -}; // cow_t, *cow - -_Static_assert(offsetof(cow_t, origin) == 0, "`cow_t.origin` must have an offset of 0."); +// struct cow { ... } +#include "cow_t.h" static __attribute__((noreturn)) __attribute__((noinline)) __attribute__((cold)) void die(const char* error) { @@ -92,7 +86,7 @@ size_t cow_size(const cow_t* cow) return cow->size; } -cow_t* cow_create(size_t size) +inline internal cow_t _cow_create_unboxed(size_t size) { cow_t ret; ret.size = size; @@ -101,15 +95,24 @@ cow_t* cow_create(size_t size) if(ret.origin == MAP_FAILED) die("cow_create:mmap"); TRACE("mapped new origin cow page of %lu size at %p (memfd %d)", size, ret.origin, ret.fd); - return box_value(ret); + return ret; +} +cow_t* cow_create(size_t size) +{ + return box_value(_cow_create_unboxed(size)); } -void cow_free(cow_t* restrict cow) +inline internal void _cow_free_unboxed(const cow_t* cow) { TRACE("unmapping %s cow of %lu size from %p (fd %d, real fd %d)", cow_is_fake(cow) ? "fake" : "and closing fd of origin", cow->size, cow->origin, cow->fd, cow_real_fd(cow)); munmap(cow->origin, cow->size); if(!cow_is_fake(cow)) close(cow->fd); +} + +void cow_free(cow_t* restrict cow) +{ + _cow_free_unboxed(cow); free(cow); } diff --git a/src/cow.cpp b/src/cow.cpp index af7ceb3..f7faf80 100644 --- a/src/cow.cpp +++ b/src/cow.cpp @@ -2,8 +2,13 @@ #include +#include "cow_t.h" + struct Cow::_inner { - cow_t* ptr; + cow_t cow; + + inline const cow_t* ptr() const { return &cow; } + inline cow_t* ptr() { return &cow; } ~_inner(); _inner(size_t sz); @@ -14,13 +19,13 @@ struct Cow::_inner { _inner() = delete; }; Cow::_inner::~_inner() { - if(ptr) { - cow_free(ptr); - ptr = nullptr; - } + _cow_free_unboxed(ptr()); +} +Cow::_inner::_inner(size_t sz) : cow(_cow_create_unboxed(sz)){} +Cow::_inner::_inner(cow_t* ptr) : cow(*ptr) +{ + free(ptr); } -Cow::_inner::_inner(size_t sz) : ptr(cow_create(sz)){} -Cow::_inner::_inner(cow_t* ptr) : ptr(ptr){} Cow::Cow(size_t size) : super(std::make_shared<_inner>(size)){} Cow::Cow(cow_t* raw) : super(std::make_shared<_inner>(raw)){} @@ -32,9 +37,9 @@ Cow::~Cow(){} Cow Cow::from_raw(cow_t* owned) { if(cow_is_fake(owned)) throw "Trying to create real from fake raw"; else return Cow(owned); } Cow::Fake Cow::clone() const { return Fake::from_real(*this); } -cow_t* Cow::get_raw() const { return super->ptr; } +cow_t* Cow::get_raw() const { return super->ptr(); } -Cow::Fake::Fake(const Cow& copy) : Cow(copy), fake(cow_clone(copy.super->ptr)){} +Cow::Fake::Fake(const Cow& copy) : Cow(copy), fake(cow_clone(copy.super->ptr())){} Cow::Fake::Fake(const Fake& copy) : Cow(copy), fake(cow_clone(copy.fake)){}//Fake(*static_cast(©)){} Cow::Fake::Fake(Fake&& move) : Cow(std::move(move)), fake(move.fake) { diff --git a/src/cow_t.h b/src/cow_t.h new file mode 100644 index 0000000..2267c62 --- /dev/null +++ b/src/cow_t.h @@ -0,0 +1,38 @@ +// Internal header for defining the `cow_t` concrete type to be used with the C and C++ APIs. +#ifndef _COW_T_H +#define _COW_T_H + +#define internal __attribute__((visibility("internal"))) + +#ifdef __cplusplus +#define restrict __restrict__ +extern "C" { +#endif + +#include + +#include + +struct cow_mapped_slice { + void* origin; // ptr to mapped memory. This *MUST* be the first field and have an offset of 0. + + int fd; // Will be ORd with ~INT_MAX if it's a clone. Will be >0 if it's the original. + size_t size; +}; // cow_t, *cow + +#ifdef __cplusplus +static_assert +#else +_Static_assert +#endif + (offsetof(cow_t, origin) == 0, "`cow_t.origin` must have an offset of 0."); + +cow_t _cow_create_unboxed(size_t size) internal; +void _cow_free_unboxed(const cow_t* cow) internal; + +#ifdef __cplusplus +} +#undef restruct +#endif + +#endif /* _COW_T_H */