aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Germain <benoit.germain@ubisoft.com>2024-11-20 12:47:41 +0100
committerBenoit Germain <benoit.germain@ubisoft.com>2024-11-20 12:47:41 +0100
commit872826ecaca5370e3492385cff3795d995b33ec7 (patch)
tree6604e8c27564b2fba6d183b304e188a2cf0cb12e
parentb8b4335dba57e1c6159b77d5cb7bbe91318664b4 (diff)
downloadlanes-872826ecaca5370e3492385cff3795d995b33ec7.tar.gz
lanes-872826ecaca5370e3492385cff3795d995b33ec7.tar.bz2
lanes-872826ecaca5370e3492385cff3795d995b33ec7.zip
AllocatorDefinition implementation improvements
-rw-r--r--lanes-4.0.0-0.rockspec1
-rw-r--r--src/Makefile2
-rw-r--r--src/allocator.cpp51
-rw-r--r--src/allocator.hpp39
-rw-r--r--src/state.cpp2
-rw-r--r--src/universe.cpp9
-rw-r--r--src/universe.hpp21
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
10CC= g++ -std=c++20 10CC= g++ -std=c++20
11 11
12SRC=_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 12SRC=_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
14OBJ=$(SRC:.cpp=.o) 14OBJ=$(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
8Copyright (C) 2017-2024 Benoit Germain <bnt.germain@gmail.com>
9
10Permission is hereby granted, free of charge, to any person obtaining a copy
11of this software and associated documentation files (the "Software"), to deal
12in the Software without restriction, including without limitation the rights
13to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14copies of the Software, and to permit persons to whom the Software is
15furnished to do so, subject to the following conditions:
16
17The above copyright notice and this permission notice shall be included in
18all copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26THE SOFTWARE.
27
28===============================================================================
29*/
30
31#include "_pch.hpp"
32#include "allocator.hpp"
33
34namespace 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