removed indirection layer in Cow origin by replacing _inner.ptr with a concrete cow_t _inner.cow

cpp
Avril 3 years ago
parent a9ba264f4b
commit b8699c78db
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -3,7 +3,7 @@ Automatic copy-on-write semantic memory slices for use in C (and C++)
# Usage # Usage
See `include/cow.h` for documentation on each function. 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 ## Building
Run `make` to build to build the `release` (optimised) target of the library. Run `make` to build to build the `release` (optimised) target of the library.

@ -9,7 +9,7 @@ extern "C" {
#include <stdlib.h> #include <stdlib.h>
// Copy-on-write mapped memory. // 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. /// Create a new copy-on-write area of `size` bytes.
/// Writes to this instance pointer (`cow_ptr()`) are written to the allocated memory. /// Writes to this instance pointer (`cow_ptr()`) are written to the allocated memory.

@ -31,14 +31,8 @@
#define LASSERT(expr, msg) ASSERT(LIKELY(expr), "(unexpected) " msg) #define LASSERT(expr, msg) ASSERT(LIKELY(expr), "(unexpected) " msg)
#define UASSERT(expr, msg) ASSERT(UNLIKELY(expr), "(expected) " msg) #define UASSERT(expr, msg) ASSERT(UNLIKELY(expr), "(expected) " msg)
struct cow { // struct cow { ... }
void* origin; // ptr to mapped memory. This *MUST* be the first field and have an offset of 0. #include "cow_t.h"
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.");
static __attribute__((noreturn)) __attribute__((noinline)) __attribute__((cold)) void die(const char* error) 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; return cow->size;
} }
cow_t* cow_create(size_t size) inline internal cow_t _cow_create_unboxed(size_t size)
{ {
cow_t ret; cow_t ret;
ret.size = size; ret.size = size;
@ -101,15 +95,24 @@ cow_t* cow_create(size_t size)
if(ret.origin == MAP_FAILED) die("cow_create:mmap"); 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); 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)); 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); munmap(cow->origin, cow->size);
if(!cow_is_fake(cow)) if(!cow_is_fake(cow))
close(cow->fd); close(cow->fd);
}
void cow_free(cow_t* restrict cow)
{
_cow_free_unboxed(cow);
free(cow); free(cow);
} }

@ -2,8 +2,13 @@
#include <utility> #include <utility>
#include "cow_t.h"
struct Cow::_inner { 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();
_inner(size_t sz); _inner(size_t sz);
@ -14,13 +19,13 @@ struct Cow::_inner {
_inner() = delete; _inner() = delete;
}; };
Cow::_inner::~_inner() { Cow::_inner::~_inner() {
if(ptr) { _cow_free_unboxed(ptr());
cow_free(ptr);
ptr = nullptr;
} }
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(size_t size) : super(std::make_shared<_inner>(size)){}
Cow::Cow(cow_t* raw) : super(std::make_shared<_inner>(raw)){} 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 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::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<const Cow*>(&copy)){} Cow::Fake::Fake(const Fake& copy) : Cow(copy), fake(cow_clone(copy.fake)){}//Fake(*static_cast<const Cow*>(&copy)){}
Cow::Fake::Fake(Fake&& move) : Cow(std::move(move)), fake(move.fake) Cow::Fake::Fake(Fake&& move) : Cow(std::move(move)), fake(move.fake)
{ {

@ -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 <stdlib.h>
#include <cow.h>
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 */
Loading…
Cancel
Save