diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/keeper.cpp | 12 | ||||
| -rw-r--r-- | src/lanes.cpp | 20 | ||||
| -rw-r--r-- | src/linda.cpp | 18 | ||||
| -rw-r--r-- | src/state.cpp | 4 | ||||
| -rw-r--r-- | src/tools.cpp | 87 | ||||
| -rw-r--r-- | src/tools.h | 1 | ||||
| -rw-r--r-- | src/universe.h | 86 |
7 files changed, 132 insertions, 96 deletions
diff --git a/src/keeper.cpp b/src/keeper.cpp index 19f6ae1..88bd4ff 100644 --- a/src/keeper.cpp +++ b/src/keeper.cpp | |||
| @@ -614,11 +614,8 @@ void close_keepers(Universe* U) | |||
| 614 | MUTEX_FREE(&U->keepers->keeper_array[i].keeper_cs); | 614 | MUTEX_FREE(&U->keepers->keeper_array[i].keeper_cs); |
| 615 | } | 615 | } |
| 616 | // free the keeper bookkeeping structure | 616 | // free the keeper bookkeeping structure |
| 617 | { | 617 | U->internal_allocator.free(U->keepers, sizeof(Keepers) + (nbKeepers - 1) * sizeof(Keeper)); |
| 618 | AllocatorDefinition* const allocD = &U->internal_allocator; | 618 | U->keepers = nullptr; |
| 619 | std::ignore = allocD->allocF(allocD->allocUD, U->keepers, sizeof(Keepers) + (nbKeepers - 1) * sizeof(Keeper), 0); | ||
| 620 | U->keepers = nullptr; | ||
| 621 | } | ||
| 622 | } | 619 | } |
| 623 | } | 620 | } |
| 624 | 621 | ||
| @@ -649,10 +646,7 @@ void init_keepers(Universe* U, lua_State* L) | |||
| 649 | // Keepers contains an array of 1 Keeper, adjust for the actual number of keeper states | 646 | // Keepers contains an array of 1 Keeper, adjust for the actual number of keeper states |
| 650 | { | 647 | { |
| 651 | size_t const bytes = sizeof(Keepers) + (nb_keepers - 1) * sizeof(Keeper); | 648 | size_t const bytes = sizeof(Keepers) + (nb_keepers - 1) * sizeof(Keeper); |
| 652 | { | 649 | U->keepers = static_cast<Keepers*>(U->internal_allocator.alloc(bytes)); |
| 653 | AllocatorDefinition* const allocD = &U->internal_allocator; | ||
| 654 | U->keepers = (Keepers*) allocD->allocF(allocD->allocUD, nullptr, 0, bytes); | ||
| 655 | } | ||
| 656 | if (U->keepers == nullptr) | 650 | if (U->keepers == nullptr) |
| 657 | { | 651 | { |
| 658 | (void) luaL_error(L, "init_keepers() failed while creating keeper array; out of memory"); | 652 | (void) luaL_error(L, "init_keepers() failed while creating keeper array; out of memory"); |
diff --git a/src/lanes.cpp b/src/lanes.cpp index 99c5812..5945a1a 100644 --- a/src/lanes.cpp +++ b/src/lanes.cpp | |||
| @@ -254,10 +254,7 @@ static void lane_cleanup( Lane* s) | |||
| 254 | } | 254 | } |
| 255 | #endif // HAVE_LANE_TRACKING() | 255 | #endif // HAVE_LANE_TRACKING() |
| 256 | 256 | ||
| 257 | { | 257 | s->U->internal_allocator.free(s, sizeof(Lane)); |
| 258 | AllocatorDefinition* const allocD = &s->U->internal_allocator; | ||
| 259 | (void) allocD->allocF(allocD->allocUD, s, sizeof(Lane), 0); | ||
| 260 | } | ||
| 261 | } | 258 | } |
| 262 | 259 | ||
| 263 | /* | 260 | /* |
| @@ -584,7 +581,7 @@ static int selfdestruct_gc( lua_State* L) | |||
| 584 | close_keepers( U); | 581 | close_keepers( U); |
| 585 | 582 | ||
| 586 | // remove the protected allocator, if any | 583 | // remove the protected allocator, if any |
| 587 | cleanup_allocator_function( U, L); | 584 | U->protected_allocator.removeFrom(L); |
| 588 | 585 | ||
| 589 | U->Universe::~Universe(); | 586 | U->Universe::~Universe(); |
| 590 | 587 | ||
| @@ -1036,10 +1033,6 @@ static constexpr UniqueKey GCCB_KEY{ 0xcfb1f046ef074e88ull }; | |||
| 1036 | // | 1033 | // |
| 1037 | LUAG_FUNC( lane_new) | 1034 | LUAG_FUNC( lane_new) |
| 1038 | { | 1035 | { |
| 1039 | lua_State* L2; | ||
| 1040 | Lane* s; | ||
| 1041 | Lane** ud; | ||
| 1042 | |||
| 1043 | char const* libs_str = lua_tostring( L, 2); | 1036 | char const* libs_str = lua_tostring( L, 2); |
| 1044 | bool const have_priority{ !lua_isnoneornil(L, 3) }; | 1037 | bool const have_priority{ !lua_isnoneornil(L, 3) }; |
| 1045 | int const priority = have_priority ? (int) lua_tointeger( L, 3) : THREAD_PRIO_DEFAULT; | 1038 | int const priority = have_priority ? (int) lua_tointeger( L, 3) : THREAD_PRIO_DEFAULT; |
| @@ -1066,7 +1059,7 @@ LUAG_FUNC( lane_new) | |||
| 1066 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); | 1059 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); |
| 1067 | 1060 | ||
| 1068 | // populate with selected libraries at the same time | 1061 | // populate with selected libraries at the same time |
| 1069 | L2 = luaG_newstate( U, L, libs_str); // L // L2 | 1062 | lua_State* const L2{ luaG_newstate(U, L, libs_str) }; // L // L2 |
| 1070 | 1063 | ||
| 1071 | STACK_GROW( L2, nargs + 3); // | 1064 | STACK_GROW( L2, nargs + 3); // |
| 1072 | STACK_CHECK_START_REL(L2, 0); | 1065 | STACK_CHECK_START_REL(L2, 0); |
| @@ -1219,11 +1212,8 @@ LUAG_FUNC( lane_new) | |||
| 1219 | // 's' is allocated from heap, not Lua, since its life span may surpass the handle's (if free running thread) | 1212 | // 's' is allocated from heap, not Lua, since its life span may surpass the handle's (if free running thread) |
| 1220 | // | 1213 | // |
| 1221 | // a Lane full userdata needs a single uservalue | 1214 | // a Lane full userdata needs a single uservalue |
| 1222 | ud = (Lane**) lua_newuserdatauv( L, sizeof( Lane*), 1); // func libs priority globals package required gc_cb lane | 1215 | Lane** const ud{ static_cast<Lane**>(lua_newuserdatauv(L, sizeof(Lane*), 1)) }; // func libs priority globals package required gc_cb lane |
| 1223 | { | 1216 | Lane* const s{ *ud = static_cast<Lane*>(U->internal_allocator.alloc(sizeof(Lane))) }; // don't forget to store the pointer in the userdata! |
| 1224 | AllocatorDefinition* const allocD = &U->internal_allocator; | ||
| 1225 | s = *ud = (Lane*) allocD->allocF(allocD->allocUD, nullptr, 0, sizeof(Lane)); | ||
| 1226 | } | ||
| 1227 | if( s == nullptr) | 1217 | if( s == nullptr) |
| 1228 | { | 1218 | { |
| 1229 | return luaL_error( L, "could not create lane: out of memory"); | 1219 | return luaL_error( L, "could not create lane: out of memory"); |
diff --git a/src/linda.cpp b/src/linda.cpp index f2e39a8..eb2349e 100644 --- a/src/linda.cpp +++ b/src/linda.cpp | |||
| @@ -759,7 +759,6 @@ static void* linda_id( lua_State* L, DeepOp op_) | |||
| 759 | { | 759 | { |
| 760 | case eDO_new: | 760 | case eDO_new: |
| 761 | { | 761 | { |
| 762 | struct s_Linda* s; | ||
| 763 | size_t name_len = 0; | 762 | size_t name_len = 0; |
| 764 | char const* linda_name = nullptr; | 763 | char const* linda_name = nullptr; |
| 765 | unsigned long linda_group = 0; | 764 | unsigned long linda_group = 0; |
| @@ -791,12 +790,9 @@ static void* linda_id( lua_State* L, DeepOp op_) | |||
| 791 | * One can use any memory allocation scheme. | 790 | * One can use any memory allocation scheme. |
| 792 | * just don't use L's allocF because we don't know which state will get the honor of GCing the linda | 791 | * just don't use L's allocF because we don't know which state will get the honor of GCing the linda |
| 793 | */ | 792 | */ |
| 794 | Universe* const U = universe_get(L); | 793 | Universe* const U{ universe_get(L) }; |
| 795 | { | 794 | struct s_Linda* s{ static_cast<struct s_Linda*>(U->internal_allocator.alloc(sizeof(struct s_Linda) + name_len)) }; // terminating 0 is already included |
| 796 | AllocatorDefinition* const allocD = &U->internal_allocator; | 795 | if (s) |
| 797 | s = (struct s_Linda*) allocD->allocF(allocD->allocUD, nullptr, 0, sizeof(struct s_Linda) + name_len); // terminating 0 is already included | ||
| 798 | } | ||
| 799 | if( s) | ||
| 800 | { | 796 | { |
| 801 | s->prelude.DeepPrelude::DeepPrelude(); | 797 | s->prelude.DeepPrelude::DeepPrelude(); |
| 802 | SIGNAL_INIT( &s->read_happened); | 798 | SIGNAL_INIT( &s->read_happened); |
| @@ -812,12 +808,11 @@ static void* linda_id( lua_State* L, DeepOp op_) | |||
| 812 | 808 | ||
| 813 | case eDO_delete: | 809 | case eDO_delete: |
| 814 | { | 810 | { |
| 815 | Keeper* K; | ||
| 816 | struct s_Linda* linda = (struct s_Linda*) lua_touserdata( L, 1); | 811 | struct s_Linda* linda = (struct s_Linda*) lua_touserdata( L, 1); |
| 817 | ASSERT_L( linda); | 812 | ASSERT_L( linda); |
| 818 | 813 | ||
| 819 | // Clean associated structures in the keeper state. | 814 | // Clean associated structures in the keeper state. |
| 820 | K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); | 815 | Keeper* const K{ keeper_acquire(linda->U->keepers, LINDA_KEEPER_HASHSEED(linda)) }; |
| 821 | if( K && K->L) // can be nullptr if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup) | 816 | if( K && K->L) // can be nullptr if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup) |
| 822 | { | 817 | { |
| 823 | // hopefully this won't ever raise an error as we would jump to the closest pcall site while forgetting to release the keeper mutex... | 818 | // hopefully this won't ever raise an error as we would jump to the closest pcall site while forgetting to release the keeper mutex... |
| @@ -829,10 +824,7 @@ static void* linda_id( lua_State* L, DeepOp op_) | |||
| 829 | SIGNAL_FREE( &linda->read_happened); | 824 | SIGNAL_FREE( &linda->read_happened); |
| 830 | SIGNAL_FREE( &linda->write_happened); | 825 | SIGNAL_FREE( &linda->write_happened); |
| 831 | linda->prelude.DeepPrelude::~DeepPrelude(); | 826 | linda->prelude.DeepPrelude::~DeepPrelude(); |
| 832 | { | 827 | linda->U->internal_allocator.free(linda, sizeof(struct s_Linda) + strlen(linda->name)); |
| 833 | AllocatorDefinition* const allocD = &linda->U->internal_allocator; | ||
| 834 | (void) allocD->allocF(allocD->allocUD, linda, sizeof(struct s_Linda) + strlen(linda->name), 0); | ||
| 835 | } | ||
| 836 | return nullptr; | 828 | return nullptr; |
| 837 | } | 829 | } |
| 838 | 830 | ||
diff --git a/src/state.cpp b/src/state.cpp index c66242c..7bdaec9 100644 --- a/src/state.cpp +++ b/src/state.cpp | |||
| @@ -260,14 +260,14 @@ lua_State* create_state( Universe* U, lua_State* from_) | |||
| 260 | lua_call( from_, 0, 1); | 260 | lua_call( from_, 0, 1); |
| 261 | { | 261 | { |
| 262 | AllocatorDefinition* const def = (AllocatorDefinition*) lua_touserdata( from_, -1); | 262 | AllocatorDefinition* const def = (AllocatorDefinition*) lua_touserdata( from_, -1); |
| 263 | L = lua_newstate( def->allocF, def->allocUD); | 263 | L = lua_newstate( def->m_allocF, def->m_allocUD); |
| 264 | } | 264 | } |
| 265 | lua_pop( from_, 1); | 265 | lua_pop( from_, 1); |
| 266 | } | 266 | } |
| 267 | else | 267 | else |
| 268 | { | 268 | { |
| 269 | // reuse the allocator provided when the master state was created | 269 | // reuse the allocator provided when the master state was created |
| 270 | L = lua_newstate( U->protected_allocator.definition.allocF, U->protected_allocator.definition.allocUD); | 270 | L = lua_newstate(U->protected_allocator.m_allocF, U->protected_allocator.m_allocUD); |
| 271 | } | 271 | } |
| 272 | #endif // LUAJIT_FLAVOR() == 64 | 272 | #endif // LUAJIT_FLAVOR() == 64 |
| 273 | 273 | ||
diff --git a/src/tools.cpp b/src/tools.cpp index 68846ba..89e5499 100644 --- a/src/tools.cpp +++ b/src/tools.cpp | |||
| @@ -156,105 +156,92 @@ void luaG_dump( lua_State* L) | |||
| 156 | // ################################################################################################ | 156 | // ################################################################################################ |
| 157 | 157 | ||
| 158 | // same as PUC-Lua l_alloc | 158 | // same as PUC-Lua l_alloc |
| 159 | static void* libc_lua_Alloc(void* ud, void* ptr, size_t osize, size_t nsize) | 159 | extern "C" static void* libc_lua_Alloc([[maybe_unused]] void* ud, [[maybe_unused]] void* ptr_, size_t osize_, size_t nsize_) |
| 160 | { | 160 | { |
| 161 | (void)ud; (void)osize; /* not used */ | 161 | if (nsize_ == 0) |
| 162 | if (nsize == 0) | ||
| 163 | { | 162 | { |
| 164 | free(ptr); | 163 | free(ptr_); |
| 165 | return nullptr; | 164 | return nullptr; |
| 166 | } | 165 | } |
| 167 | else | 166 | else |
| 168 | { | 167 | { |
| 169 | return realloc(ptr, nsize); | 168 | return realloc(ptr_, nsize_); |
| 170 | } | 169 | } |
| 171 | } | 170 | } |
| 172 | 171 | ||
| 173 | static void* protected_lua_Alloc( void *ud, void *ptr, size_t osize, size_t nsize) | 172 | // ################################################################################################# |
| 174 | { | ||
| 175 | void* p; | ||
| 176 | ProtectedAllocator* s = (ProtectedAllocator*) ud; | ||
| 177 | s->lock.lock(); | ||
| 178 | p = s->definition.allocF( s->definition.allocUD, ptr, osize, nsize); | ||
| 179 | s->lock.unlock(); | ||
| 180 | return p; | ||
| 181 | } | ||
| 182 | 173 | ||
| 183 | static int luaG_provide_protected_allocator( lua_State* L) | 174 | static int luaG_provide_protected_allocator(lua_State* L) |
| 184 | { | 175 | { |
| 185 | Universe* U = universe_get( L); | 176 | Universe* const U{ universe_get(L) }; |
| 186 | AllocatorDefinition* const def = (AllocatorDefinition*) lua_newuserdatauv( L, sizeof(AllocatorDefinition), 0); | 177 | // push a new full userdata on the stack, giving access to the universe's protected allocator |
| 187 | def->allocF = protected_lua_Alloc; | 178 | AllocatorDefinition* const def{ new (L) AllocatorDefinition{ U->protected_allocator.makeDefinition() } }; |
| 188 | def->allocUD = &U->protected_allocator; | ||
| 189 | return 1; | 179 | return 1; |
| 190 | } | 180 | } |
| 191 | 181 | ||
| 182 | // ################################################################################################# | ||
| 183 | |||
| 192 | // called once at the creation of the universe (therefore L is the master Lua state everything originates from) | 184 | // called once at the creation of the universe (therefore L is the master Lua state everything originates from) |
| 193 | // Do I need to disable this when compiling for LuaJIT to prevent issues? | 185 | // Do I need to disable this when compiling for LuaJIT to prevent issues? |
| 194 | void initialize_allocator_function( Universe* U, lua_State* L) | 186 | void initialize_allocator_function(Universe* U, lua_State* L) |
| 195 | { | 187 | { |
| 196 | STACK_CHECK_START_REL(L, 1); // settings | 188 | STACK_CHECK_START_REL(L, 1); // settings |
| 197 | lua_getfield( L, -1, "allocator"); // settings allocator|nil|"protected" | 189 | lua_getfield(L, -1, "allocator"); // settings allocator|nil|"protected" |
| 198 | if( !lua_isnil( L, -1)) | 190 | if (!lua_isnil(L, -1)) |
| 199 | { | 191 | { |
| 200 | // store C function pointer in an internal variable | 192 | // store C function pointer in an internal variable |
| 201 | U->provide_allocator = lua_tocfunction( L, -1); // settings allocator | 193 | U->provide_allocator = lua_tocfunction(L, -1); // settings allocator |
| 202 | if (U->provide_allocator != nullptr) | 194 | if (U->provide_allocator != nullptr) |
| 203 | { | 195 | { |
| 204 | // make sure the function doesn't have upvalues | 196 | // make sure the function doesn't have upvalues |
| 205 | char const* upname = lua_getupvalue( L, -1, 1); // settings allocator upval? | 197 | char const* upname = lua_getupvalue(L, -1, 1); // settings allocator upval? |
| 206 | if (upname != nullptr) // should be "" for C functions with upvalues if any | 198 | if (upname != nullptr) // should be "" for C functions with upvalues if any |
| 207 | { | 199 | { |
| 208 | (void) luaL_error( L, "config.allocator() shouldn't have upvalues"); | 200 | (void) luaL_error(L, "config.allocator() shouldn't have upvalues"); |
| 209 | } | 201 | } |
| 210 | // remove this C function from the config table so that it doesn't cause problems | 202 | // remove this C function from the config table so that it doesn't cause problems |
| 211 | // when we transfer the config table in newly created Lua states | 203 | // when we transfer the config table in newly created Lua states |
| 212 | lua_pushnil( L); // settings allocator nil | 204 | lua_pushnil(L); // settings allocator nil |
| 213 | lua_setfield( L, -3, "allocator"); // settings allocator | 205 | lua_setfield(L, -3, "allocator"); // settings allocator |
| 214 | } | 206 | } |
| 215 | else if( lua_type( L, -1) == LUA_TSTRING) // should be "protected" | 207 | else if (lua_type(L, -1) == LUA_TSTRING) // should be "protected" |
| 216 | { | 208 | { |
| 209 | ASSERT_L(strcmp(lua_tostring(L, -1), "protected") == 0); | ||
| 217 | // set the original allocator to call from inside protection by the mutex | 210 | // set the original allocator to call from inside protection by the mutex |
| 218 | U->protected_allocator.definition.allocF = lua_getallocf( L, &U->protected_allocator.definition.allocUD); | 211 | U->protected_allocator.initFrom(L); |
| 212 | U->protected_allocator.installIn(L); | ||
| 219 | // before a state is created, this function will be called to obtain the allocator | 213 | // before a state is created, this function will be called to obtain the allocator |
| 220 | U->provide_allocator = luaG_provide_protected_allocator; | 214 | U->provide_allocator = luaG_provide_protected_allocator; |
| 221 | |||
| 222 | lua_setallocf( L, protected_lua_Alloc, &U->protected_allocator); | ||
| 223 | } | 215 | } |
| 224 | } | 216 | } |
| 225 | else | 217 | else |
| 226 | { | 218 | { |
| 227 | // just grab whatever allocator was provided to lua_newstate | 219 | // just grab whatever allocator was provided to lua_newstate |
| 228 | U->protected_allocator.definition.allocF = lua_getallocf( L, &U->protected_allocator.definition.allocUD); | 220 | U->protected_allocator.initFrom(L); |
| 229 | } | 221 | } |
| 230 | lua_pop( L, 1); // settings | 222 | lua_pop(L, 1); // settings |
| 231 | STACK_CHECK(L, 1); | 223 | STACK_CHECK(L, 1); |
| 232 | 224 | ||
| 233 | lua_getfield( L, -1, "internal_allocator"); // settings "libc"|"allocator" | 225 | lua_getfield(L, -1, "internal_allocator"); // settings "libc"|"allocator" |
| 234 | { | 226 | { |
| 235 | char const* allocator = lua_tostring( L, -1); | 227 | char const* allocator = lua_tostring(L, -1); |
| 236 | if (strcmp(allocator, "libc") == 0) | 228 | if (strcmp(allocator, "libc") == 0) |
| 237 | { | 229 | { |
| 238 | U->internal_allocator.allocF = libc_lua_Alloc; | 230 | U->internal_allocator = AllocatorDefinition{ libc_lua_Alloc, nullptr }; |
| 239 | U->internal_allocator.allocUD = nullptr; | 231 | } |
| 232 | else if (U->provide_allocator = luaG_provide_protected_allocator) | ||
| 233 | { | ||
| 234 | // user wants mutex protection on the state's allocator. Use protection for our own allocations too, just in case. | ||
| 235 | U->internal_allocator = U->protected_allocator.makeDefinition(); | ||
| 240 | } | 236 | } |
| 241 | else | 237 | else |
| 242 | { | 238 | { |
| 243 | U->internal_allocator = U->protected_allocator.definition; | 239 | // no protection required, just use whatever we have as-is. |
| 240 | U->internal_allocator = U->protected_allocator; | ||
| 244 | } | 241 | } |
| 245 | } | 242 | } |
| 246 | lua_pop( L, 1); // settings | 243 | lua_pop(L, 1); // settings |
| 247 | STACK_CHECK( L, 1); | 244 | STACK_CHECK(L, 1); |
| 248 | } | ||
| 249 | |||
| 250 | void cleanup_allocator_function( Universe* U, lua_State* L) | ||
| 251 | { | ||
| 252 | // remove the protected allocator, if any | ||
| 253 | if (U->protected_allocator.definition.allocF != nullptr) | ||
| 254 | { | ||
| 255 | // install the non-protected allocator | ||
| 256 | lua_setallocf( L, U->protected_allocator.definition.allocF, U->protected_allocator.definition.allocUD); | ||
| 257 | } | ||
| 258 | } | 245 | } |
| 259 | 246 | ||
| 260 | // ################################################################################################ | 247 | // ################################################################################################ |
diff --git a/src/tools.h b/src/tools.h index 95324ee..5e6ce78 100644 --- a/src/tools.h +++ b/src/tools.h | |||
| @@ -38,7 +38,6 @@ int luaG_nameof( lua_State* L); | |||
| 38 | 38 | ||
| 39 | void populate_func_lookup_table( lua_State* L, int _i, char const* _name); | 39 | void populate_func_lookup_table( lua_State* L, int _i, char const* _name); |
| 40 | void initialize_allocator_function( Universe* U, lua_State* L); | 40 | void initialize_allocator_function( Universe* U, lua_State* L); |
| 41 | void cleanup_allocator_function( Universe* U, lua_State* L); | ||
| 42 | 41 | ||
| 43 | // ################################################################################################ | 42 | // ################################################################################################ |
| 44 | 43 | ||
diff --git a/src/universe.h b/src/universe.h index a6beb68..3aac20d 100644 --- a/src/universe.h +++ b/src/universe.h | |||
| @@ -27,17 +27,91 @@ struct Lane; | |||
| 27 | // ################################################################################################ | 27 | // ################################################################################################ |
| 28 | 28 | ||
| 29 | // everything we need to provide to lua_newstate() | 29 | // everything we need to provide to lua_newstate() |
| 30 | struct AllocatorDefinition | 30 | class AllocatorDefinition |
| 31 | { | 31 | { |
| 32 | lua_Alloc allocF{ nullptr }; | 32 | public: |
| 33 | void* allocUD{ nullptr }; | 33 | |
| 34 | lua_Alloc m_allocF{ nullptr }; | ||
| 35 | void* m_allocUD{ nullptr }; | ||
| 36 | |||
| 37 | static void* operator new(size_t size_, lua_State* L) noexcept { return lua_newuserdatauv(L, size_, 0); } | ||
| 38 | // always embedded somewhere else or "in-place constructed" as a full userdata | ||
| 39 | // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception | ||
| 40 | static void operator delete(void* p_, lua_State* L) { ASSERT_L(!"should never be called") }; | ||
| 41 | |||
| 42 | AllocatorDefinition(lua_Alloc allocF_, void* allocUD_) noexcept | ||
| 43 | : m_allocF{ allocF_ } | ||
| 44 | , m_allocUD{ allocUD_ } | ||
| 45 | { | ||
| 46 | } | ||
| 47 | AllocatorDefinition() = default; | ||
| 48 | AllocatorDefinition(AllocatorDefinition const& rhs_) = default; | ||
| 49 | AllocatorDefinition(AllocatorDefinition&& rhs_) = default; | ||
| 50 | AllocatorDefinition& operator=(AllocatorDefinition const& rhs_) = default; | ||
| 51 | AllocatorDefinition& operator=(AllocatorDefinition&& rhs_) = default; | ||
| 52 | |||
| 53 | void initFrom(lua_State* L) | ||
| 54 | { | ||
| 55 | m_allocF = lua_getallocf(L, &m_allocUD); | ||
| 56 | } | ||
| 57 | |||
| 58 | void* lua_alloc(void* ptr_, size_t osize_, size_t nsize_) | ||
| 59 | { | ||
| 60 | m_allocF(m_allocUD, ptr_, osize_, nsize_); | ||
| 61 | } | ||
| 62 | |||
| 63 | void* alloc(size_t nsize_) | ||
| 64 | { | ||
| 65 | return m_allocF(m_allocUD, nullptr, 0, nsize_); | ||
| 66 | } | ||
| 67 | |||
| 68 | void free(void* ptr_, size_t osize_) | ||
| 69 | { | ||
| 70 | std::ignore = m_allocF(m_allocUD, ptr_, osize_, 0); | ||
| 71 | } | ||
| 34 | }; | 72 | }; |
| 35 | 73 | ||
| 74 | // ################################################################################################ | ||
| 75 | |||
| 36 | // mutex-protected allocator for use with Lua states that share a non-threadsafe allocator | 76 | // mutex-protected allocator for use with Lua states that share a non-threadsafe allocator |
| 37 | struct ProtectedAllocator | 77 | class ProtectedAllocator : public AllocatorDefinition |
| 38 | { | 78 | { |
| 39 | AllocatorDefinition definition; | 79 | private: |
| 40 | std::mutex lock; | 80 | |
| 81 | std::mutex m_lock; | ||
| 82 | |||
| 83 | static void* protected_lua_Alloc(void* ud_, void* ptr_, size_t osize_, size_t nsize_) | ||
| 84 | { | ||
| 85 | ProtectedAllocator* const s{ static_cast<ProtectedAllocator*>(ud_) }; | ||
| 86 | std::lock_guard<std::mutex> guard{ s->m_lock }; | ||
| 87 | return s->m_allocF(s->m_allocUD, ptr_, osize_, nsize_); | ||
| 88 | } | ||
| 89 | |||
| 90 | public: | ||
| 91 | |||
| 92 | // we are not like our base class: we can't be created inside a full userdata (or we would have to install a metatable and __gc handler to destroy ourselves properly) | ||
| 93 | static void* operator new(size_t size_, lua_State* L) noexcept = delete; | ||
| 94 | static void operator delete(void* p_, lua_State* L) = delete; | ||
| 95 | |||
| 96 | AllocatorDefinition makeDefinition() | ||
| 97 | { | ||
| 98 | return AllocatorDefinition{ protected_lua_Alloc, this}; | ||
| 99 | } | ||
| 100 | |||
| 101 | void installIn(lua_State* L) | ||
| 102 | { | ||
| 103 | lua_setallocf(L, protected_lua_Alloc, this); | ||
| 104 | } | ||
| 105 | |||
| 106 | void removeFrom(lua_State* L) | ||
| 107 | { | ||
| 108 | // remove the protected allocator, if any | ||
| 109 | if (m_allocF != nullptr) | ||
| 110 | { | ||
| 111 | // install the non-protected allocator | ||
| 112 | lua_setallocf(L, m_allocF, m_allocUD); | ||
| 113 | } | ||
| 114 | } | ||
| 41 | }; | 115 | }; |
| 42 | 116 | ||
| 43 | // ################################################################################################ | 117 | // ################################################################################################ |
