diff options
| author | Benoit Germain <benoit.germain@ubisoft.com> | 2024-11-20 12:47:41 +0100 |
|---|---|---|
| committer | Benoit Germain <benoit.germain@ubisoft.com> | 2024-11-20 12:47:41 +0100 |
| commit | 872826ecaca5370e3492385cff3795d995b33ec7 (patch) | |
| tree | 6604e8c27564b2fba6d183b304e188a2cf0cb12e | |
| parent | b8b4335dba57e1c6159b77d5cb7bbe91318664b4 (diff) | |
| download | lanes-872826ecaca5370e3492385cff3795d995b33ec7.tar.gz lanes-872826ecaca5370e3492385cff3795d995b33ec7.tar.bz2 lanes-872826ecaca5370e3492385cff3795d995b33ec7.zip | |
AllocatorDefinition implementation improvements
| -rw-r--r-- | lanes-4.0.0-0.rockspec | 1 | ||||
| -rw-r--r-- | src/Makefile | 2 | ||||
| -rw-r--r-- | src/allocator.cpp | 51 | ||||
| -rw-r--r-- | src/allocator.hpp | 39 | ||||
| -rw-r--r-- | src/state.cpp | 2 | ||||
| -rw-r--r-- | src/universe.cpp | 9 | ||||
| -rw-r--r-- | src/universe.hpp | 21 |
7 files changed, 101 insertions, 24 deletions
diff --git a/lanes-4.0.0-0.rockspec b/lanes-4.0.0-0.rockspec index 120cf51..dbe398a 100644 --- a/lanes-4.0.0-0.rockspec +++ b/lanes-4.0.0-0.rockspec | |||
| @@ -61,6 +61,7 @@ build = { | |||
| 61 | sources = | 61 | sources = |
| 62 | { | 62 | { |
| 63 | "src/_pch.cpp", | 63 | "src/_pch.cpp", |
| 64 | "src/allocator.cpp", | ||
| 64 | "src/cancel.cpp", | 65 | "src/cancel.cpp", |
| 65 | "src/compat.cpp", | 66 | "src/compat.cpp", |
| 66 | "src/deep.cpp", | 67 | "src/deep.cpp", |
diff --git a/src/Makefile b/src/Makefile index 5fc3482..f2e2eb5 100644 --- a/src/Makefile +++ b/src/Makefile | |||
| @@ -9,7 +9,7 @@ MODULE=lanes | |||
| 9 | 9 | ||
| 10 | CC= g++ -std=c++20 | 10 | CC= g++ -std=c++20 |
| 11 | 11 | ||
| 12 | SRC=_pch.cpp cancel.cpp compat.cpp deep.cpp intercopycontext.cpp keeper.cpp lane.cpp lanes.cpp linda.cpp lindafactory.cpp nameof.cpp state.cpp threading.cpp tools.cpp tracker.cpp universe.cpp | 12 | SRC=_pch.cpp allocator.cpp cancel.cpp compat.cpp deep.cpp intercopycontext.cpp keeper.cpp lane.cpp lanes.cpp linda.cpp lindafactory.cpp nameof.cpp state.cpp threading.cpp tools.cpp tracker.cpp universe.cpp |
| 13 | 13 | ||
| 14 | OBJ=$(SRC:.cpp=.o) | 14 | OBJ=$(SRC:.cpp=.o) |
| 15 | 15 | ||
diff --git a/src/allocator.cpp b/src/allocator.cpp new file mode 100644 index 0000000..84acde5 --- /dev/null +++ b/src/allocator.cpp | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | /* | ||
| 2 | * ALLOCATOR.CPP Copyright (c) 2017-2024, Benoit Germain | ||
| 3 | */ | ||
| 4 | |||
| 5 | /* | ||
| 6 | =============================================================================== | ||
| 7 | |||
| 8 | Copyright (C) 2017-2024 Benoit Germain <bnt.germain@gmail.com> | ||
| 9 | |||
| 10 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 11 | of this software and associated documentation files (the "Software"), to deal | ||
| 12 | in the Software without restriction, including without limitation the rights | ||
| 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 14 | copies of the Software, and to permit persons to whom the Software is | ||
| 15 | furnished to do so, subject to the following conditions: | ||
| 16 | |||
| 17 | The above copyright notice and this permission notice shall be included in | ||
| 18 | all copies or substantial portions of the Software. | ||
| 19 | |||
| 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 26 | THE SOFTWARE. | ||
| 27 | |||
| 28 | =============================================================================== | ||
| 29 | */ | ||
| 30 | |||
| 31 | #include "_pch.hpp" | ||
| 32 | #include "allocator.hpp" | ||
| 33 | |||
| 34 | namespace lanes | ||
| 35 | { | ||
| 36 | AllocatorDefinition& AllocatorDefinition::Validated(lua_State* const L_, StackIndex const idx_) | ||
| 37 | { | ||
| 38 | lanes::AllocatorDefinition* const _def{ luaG_tofulluserdata<lanes::AllocatorDefinition>(L_, idx_) }; | ||
| 39 | // raise an error and don't return if the full userdata at the specified index is not a valid AllocatorDefinition | ||
| 40 | if (!_def) { | ||
| 41 | raise_luaL_error(L_, "Bad config.allocator function, provided value is not a userdata"); | ||
| 42 | } | ||
| 43 | if (lua_rawlen(L_, idx_) < sizeof(lanes::AllocatorDefinition)) { | ||
| 44 | raise_luaL_error(L_, "Bad config.allocator function, provided value is too small to contain a valid AllocatorDefinition"); | ||
| 45 | } | ||
| 46 | if (_def->version != kAllocatorVersion) { | ||
| 47 | raise_luaL_error(L_, "Bad config.allocator function, AllocatorDefinition version mismatch"); | ||
| 48 | } | ||
| 49 | return *_def; | ||
| 50 | } | ||
| 51 | } | ||
diff --git a/src/allocator.hpp b/src/allocator.hpp index fa48c46..4fec044 100644 --- a/src/allocator.hpp +++ b/src/allocator.hpp | |||
| @@ -9,22 +9,30 @@ namespace lanes { | |||
| 9 | // everything we need to provide to lua_newstate() | 9 | // everything we need to provide to lua_newstate() |
| 10 | class AllocatorDefinition | 10 | class AllocatorDefinition |
| 11 | { | 11 | { |
| 12 | public: | 12 | private: |
| 13 | // xxh64 of string "kAllocatorVersion_1" generated at https://www.pelock.com/products/hash-calculator | 13 | // xxh64 of string "kAllocatorVersion_1" generated at https://www.pelock.com/products/hash-calculator |
| 14 | static constexpr uintptr_t kAllocatorVersion{ static_cast<uintptr_t>(0xCF9D321B0DFB5715ull) }; | 14 | static constexpr auto kAllocatorVersion{ static_cast<uintptr_t>(0xCF9D321B0DFB5715ull) }; |
| 15 | uintptr_t version{ kAllocatorVersion }; | 15 | |
| 16 | public: | ||
| 17 | using version_t = std::remove_const_t<decltype(kAllocatorVersion)>; | ||
| 18 | |||
| 19 | private: | ||
| 20 | // can't make these members const because we need to be able to copy an AllocatorDefinition into another | ||
| 21 | // so the members are not const, but they are private to avoid accidents. | ||
| 22 | version_t version{ kAllocatorVersion }; | ||
| 16 | lua_Alloc allocF{ nullptr }; | 23 | lua_Alloc allocF{ nullptr }; |
| 17 | void* allocUD{ nullptr }; | 24 | void* allocUD{ nullptr }; |
| 18 | 25 | ||
| 26 | public: | ||
| 27 | |||
| 19 | [[nodiscard]] static void* operator new(size_t const size_) noexcept = delete; // can't create one outside of a Lua state | 28 | [[nodiscard]] static void* operator new(size_t const size_) noexcept = delete; // can't create one outside of a Lua state |
| 20 | [[nodiscard]] static void* operator new(size_t const size_, lua_State* const L_) noexcept { return lua_newuserdatauv(L_, size_, UserValueCount{ 0 }); } | 29 | [[nodiscard]] static void* operator new(size_t const size_, lua_State* const L_) noexcept { return lua_newuserdatauv(L_, size_, UserValueCount{ 0 }); } |
| 21 | // always embedded somewhere else or "in-place constructed" as a full userdata | 30 | // always embedded somewhere else or "in-place constructed" as a full userdata |
| 22 | // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception | 31 | // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception |
| 23 | static void operator delete([[maybe_unused]] void* const p_, [[maybe_unused]] lua_State* const L_) {} | 32 | static void operator delete([[maybe_unused]] void* const p_, [[maybe_unused]] lua_State* const L_) {} |
| 24 | 33 | ||
| 25 | AllocatorDefinition(uintptr_t const version_, lua_Alloc const allocF_, void* const allocUD_) noexcept | 34 | AllocatorDefinition(lua_Alloc const allocF_, void* const allocUD_) noexcept |
| 26 | : version{ version_ } | 35 | : allocF{ allocF_ } |
| 27 | , allocF{ allocF_ } | ||
| 28 | , allocUD{ allocUD_ } | 36 | , allocUD{ allocUD_ } |
| 29 | { | 37 | { |
| 30 | } | 38 | } |
| @@ -36,16 +44,35 @@ namespace lanes { | |||
| 36 | AllocatorDefinition& operator=(AllocatorDefinition const& rhs_) = default; | 44 | AllocatorDefinition& operator=(AllocatorDefinition const& rhs_) = default; |
| 37 | AllocatorDefinition& operator=(AllocatorDefinition&& rhs_) = default; | 45 | AllocatorDefinition& operator=(AllocatorDefinition&& rhs_) = default; |
| 38 | 46 | ||
| 47 | static AllocatorDefinition& Validated(lua_State* L_, StackIndex idx_); | ||
| 48 | |||
| 39 | void initFrom(lua_State* const L_) | 49 | void initFrom(lua_State* const L_) |
| 40 | { | 50 | { |
| 41 | allocF = lua_getallocf(L_, &allocUD); | 51 | allocF = lua_getallocf(L_, &allocUD); |
| 42 | } | 52 | } |
| 43 | 53 | ||
| 54 | void installIn(lua_State* const L_) const | ||
| 55 | { | ||
| 56 | if (allocF) { | ||
| 57 | lua_setallocf(L_, allocF, allocUD); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | lua_State* newState() const | ||
| 62 | { | ||
| 63 | return lua_newstate(allocF, allocUD); | ||
| 64 | } | ||
| 65 | |||
| 44 | void* alloc(size_t const nsize_) | 66 | void* alloc(size_t const nsize_) |
| 45 | { | 67 | { |
| 46 | return allocF(allocUD, nullptr, 0, nsize_); | 68 | return allocF(allocUD, nullptr, 0, nsize_); |
| 47 | } | 69 | } |
| 48 | 70 | ||
| 71 | void* alloc(void* const ptr_, size_t const osize_, size_t const nsize_) | ||
| 72 | { | ||
| 73 | return allocF(allocUD, ptr_, osize_, nsize_); | ||
| 74 | } | ||
| 75 | |||
| 49 | void free(void* const ptr_, size_t const osize_) | 76 | void free(void* const ptr_, size_t const osize_) |
| 50 | { | 77 | { |
| 51 | std::ignore = allocF(allocUD, ptr_, osize_, 0); | 78 | std::ignore = allocF(allocUD, ptr_, osize_, 0); |
diff --git a/src/state.cpp b/src/state.cpp index 6c49694..88f406a 100644 --- a/src/state.cpp +++ b/src/state.cpp | |||
| @@ -159,7 +159,7 @@ namespace state { | |||
| 159 | return luaL_newstate(); | 159 | return luaL_newstate(); |
| 160 | } else { | 160 | } else { |
| 161 | lanes::AllocatorDefinition const _def{ U->resolveAllocator(from, hint) }; | 161 | lanes::AllocatorDefinition const _def{ U->resolveAllocator(from, hint) }; |
| 162 | return lua_newstate(_def.allocF, _def.allocUD); | 162 | return _def.newState(); |
| 163 | } | 163 | } |
| 164 | } | 164 | } |
| 165 | ) | 165 | ) |
diff --git a/src/universe.cpp b/src/universe.cpp index 357aa08..283747f 100644 --- a/src/universe.cpp +++ b/src/universe.cpp | |||
| @@ -263,7 +263,7 @@ void Universe::initializeAllocatorFunction(lua_State* const L_) | |||
| 263 | LUA_ASSERT(L_, lua_isstring(L_, kIdxTop)); // should be the case due to lanes.lua parameter validation | 263 | LUA_ASSERT(L_, lua_isstring(L_, kIdxTop)); // should be the case due to lanes.lua parameter validation |
| 264 | std::string_view const _allocator{ luaG_tostring(L_, kIdxTop) }; | 264 | std::string_view const _allocator{ luaG_tostring(L_, kIdxTop) }; |
| 265 | if (_allocator == "libc") { | 265 | if (_allocator == "libc") { |
| 266 | internalAllocator = lanes::AllocatorDefinition{ lanes::AllocatorDefinition::kAllocatorVersion, libc_lua_Alloc, nullptr }; | 266 | internalAllocator = lanes::AllocatorDefinition{ libc_lua_Alloc, nullptr }; |
| 267 | } else { | 267 | } else { |
| 268 | // use whatever the provider provides | 268 | // use whatever the provider provides |
| 269 | internalAllocator = resolveAllocator(L_, "internal"); | 269 | internalAllocator = resolveAllocator(L_, "internal"); |
| @@ -338,11 +338,8 @@ lanes::AllocatorDefinition Universe::resolveAllocator(lua_State* const L_, std:: | |||
| 338 | lua_pushcclosure(L_, provideAllocator, 0); // L_: provideAllocator() | 338 | lua_pushcclosure(L_, provideAllocator, 0); // L_: provideAllocator() |
| 339 | luaG_pushstring(L_, hint_); // L_: provideAllocator() "<hint>" | 339 | luaG_pushstring(L_, hint_); // L_: provideAllocator() "<hint>" |
| 340 | lua_call(L_, 1, 1); // L_: result | 340 | lua_call(L_, 1, 1); // L_: result |
| 341 | lanes::AllocatorDefinition* const _def{ luaG_tofulluserdata<lanes::AllocatorDefinition>(L_, kIdxTop) }; | 341 | // make sure we have a valid AllocatorDefinition on the stack (an error is raised instead if it is not the case) |
| 342 | if (!_def || _def->version != lanes::AllocatorDefinition::kAllocatorVersion) { | 342 | _ret = lanes::AllocatorDefinition::Validated(L_, kIdxTop); |
| 343 | raise_luaL_error(L_, "Bad config.allocator function, must provide a valid AllocatorDefinition"); | ||
| 344 | } | ||
| 345 | _ret = *_def; | ||
| 346 | lua_pop(L_, 1); // L_: | 343 | lua_pop(L_, 1); // L_: |
| 347 | STACK_CHECK(L_, 0); | 344 | STACK_CHECK(L_, 0); |
| 348 | return _ret; | 345 | return _ret; |
diff --git a/src/universe.hpp b/src/universe.hpp index a45ce86..77fbb52 100644 --- a/src/universe.hpp +++ b/src/universe.hpp | |||
| @@ -20,13 +20,16 @@ class ProtectedAllocator | |||
| 20 | : public lanes::AllocatorDefinition | 20 | : public lanes::AllocatorDefinition |
| 21 | { | 21 | { |
| 22 | private: | 22 | private: |
| 23 | |||
| 24 | using super = lanes::AllocatorDefinition; | ||
| 25 | |||
| 23 | std::mutex mutex; | 26 | std::mutex mutex; |
| 24 | 27 | ||
| 25 | [[nodiscard]] static void* protected_lua_Alloc(void* ud_, void* ptr_, size_t osize_, size_t nsize_) | 28 | [[nodiscard]] static void* protected_lua_Alloc(void* ud_, void* ptr_, size_t osize_, size_t nsize_) |
| 26 | { | 29 | { |
| 27 | ProtectedAllocator* const allocator{ static_cast<ProtectedAllocator*>(ud_) }; | 30 | ProtectedAllocator* const allocator{ static_cast<ProtectedAllocator*>(ud_) }; |
| 28 | std::lock_guard<std::mutex> guard{ allocator->mutex }; | 31 | std::lock_guard<std::mutex> guard{ allocator->mutex }; |
| 29 | return allocator->allocF(allocator->allocUD, ptr_, osize_, nsize_); | 32 | return allocator->alloc(ptr_, osize_, nsize_); |
| 30 | } | 33 | } |
| 31 | 34 | ||
| 32 | public: | 35 | public: |
| @@ -36,21 +39,19 @@ class ProtectedAllocator | |||
| 36 | 39 | ||
| 37 | AllocatorDefinition makeDefinition() | 40 | AllocatorDefinition makeDefinition() |
| 38 | { | 41 | { |
| 39 | return AllocatorDefinition{ version, protected_lua_Alloc, this }; | 42 | return AllocatorDefinition{ protected_lua_Alloc, this }; |
| 40 | } | 43 | } |
| 41 | 44 | ||
| 42 | void installIn(lua_State* L_) | 45 | void installIn(lua_State* const L_) const |
| 43 | { | 46 | { |
| 44 | lua_setallocf(L_, protected_lua_Alloc, this); | 47 | // install our replacement allocator function (this is a C function, we need to deconst ourselves) |
| 48 | lua_setallocf(L_, protected_lua_Alloc, static_cast<void*>(const_cast<ProtectedAllocator*>(this))); | ||
| 45 | } | 49 | } |
| 46 | 50 | ||
| 47 | void removeFrom(lua_State* L_) | 51 | void removeFrom(lua_State* const L_) const |
| 48 | { | 52 | { |
| 49 | // remove the protected allocator, if any | 53 | // restore the base allocator function |
| 50 | if (allocF != nullptr) { | 54 | super::installIn(L_); |
| 51 | // install the non-protected allocator | ||
| 52 | lua_setallocf(L_, allocF, allocUD); | ||
| 53 | } | ||
| 54 | } | 55 | } |
| 55 | }; | 56 | }; |
| 56 | 57 | ||
