From ad7258f68ce525845508fc0c4a329c282982ffa0 Mon Sep 17 00:00:00 2001 From: Benoit Germain Date: Wed, 9 Aug 2023 12:15:54 +0200 Subject: new .internal_allocator configuration IUNTESTED) new configuration option .internal_allocator to help LuaJIT users. THIS IS YET UNTESTED, USE AT YOUR OWN RISKS. --- .../7013d1f4-51ff-4696-9603-47b7bcd2f51f.vsidx | Bin 0 -> 400863 bytes CHANGES | 4 +++ docs/index.html | 34 +++++++++++++----- src/deep.c | 2 +- src/keeper.c | 20 +++-------- src/keeper.h | 2 +- src/lanes.c | 16 ++------- src/lanes.h | 2 +- src/lanes.lua | 8 ++++- src/linda.c | 14 ++------ src/macros_and_utils.h | 3 -- src/tools.c | 38 ++++++++++++++++++--- src/universe.h | 2 ++ 13 files changed, 83 insertions(+), 62 deletions(-) create mode 100644 .vs/Lanes/FileContentIndex/7013d1f4-51ff-4696-9603-47b7bcd2f51f.vsidx diff --git a/.vs/Lanes/FileContentIndex/7013d1f4-51ff-4696-9603-47b7bcd2f51f.vsidx b/.vs/Lanes/FileContentIndex/7013d1f4-51ff-4696-9603-47b7bcd2f51f.vsidx new file mode 100644 index 0000000..7c4c705 Binary files /dev/null and b/.vs/Lanes/FileContentIndex/7013d1f4-51ff-4696-9603-47b7bcd2f51f.vsidx differ diff --git a/CHANGES b/CHANGES index 3b333b2..3c7f356 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,9 @@ CHANGES: +CHANGE 156: BGe 9-Aug-23 + * new configuration option .internal_allocator to help LuaJIT users. + * internal version bumped to 3.16.1 + CHANGE 155: BGe 28-Jul-23 * tweaks to linux thread priority management: do nothing if not super-user. if super-user, do nothing if nothing is provided (instead of trying to force a prio when LINUX_SCHED_RR is defined). diff --git a/docs/index.html b/docs/index.html index 0e1a30b..b1c514d 100644 --- a/docs/index.html +++ b/docs/index.html @@ -64,13 +64,13 @@


- Copyright © 2007-22 Asko Kauppi, Benoit Germain. All rights reserved. + Copyright © 2007-23 Asko Kauppi, Benoit Germain. All rights reserved.
Lua Lanes is published under the same MIT license as Lua 5.1, 5.2, 5.3 and 5.4.

- This document was revised on 8-Feb-22, and applies to version 3.16.0. + This document was revised on 9-Aug-23, and applies to version 3.16.1.

@@ -338,9 +338,9 @@ nil/"protected"/function - (Since v3.13.0)
- If nil, Lua states are created with lua_newstate() and reuse the allocator from the master state.
- If "protected", The default allocator obtained from lua_getallocf() in the master state is wrapped inside a critical section and used in all newly created states.
+ (Since v3.13.0)
+ If nil, Lua states are created with lua_newstate() and reuse the allocator from the master state.
+ If "protected", The default allocator obtained from lua_getallocf() in the master state is wrapped inside a critical section and used in all newly created states.
If a function, this function is called prior to creating the state. It should return a full userdata containing the following structure: @@ -355,6 +355,22 @@ + + + + + + diff --git a/src/deep.c b/src/deep.c index c475dc5..9496477 100644 --- a/src/deep.c +++ b/src/deep.c @@ -389,7 +389,7 @@ int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc, int nuv_) DeepPrelude* prelude = idfunc( L, eDO_new); if( prelude == NULL) { - luaL_error( L, "idfunc(eDO_new) failed to create deep userdata (out of memory)"); + return luaL_error( L, "idfunc(eDO_new) failed to create deep userdata (out of memory)"); } if( prelude->magic.value != DEEP_VERSION.value) { diff --git a/src/keeper.c b/src/keeper.c index 19b9e1a..f4dde0a 100644 --- a/src/keeper.c +++ b/src/keeper.c @@ -580,7 +580,7 @@ int keepercall_count( lua_State* L) */ // called as __gc for the keepers array userdata -void close_keepers( Universe* U, lua_State* L) +void close_keepers( Universe* U) { if( U->keepers != NULL) { @@ -611,15 +611,8 @@ void close_keepers( Universe* U, lua_State* L) } // free the keeper bookkeeping structure { - // don't hijack the state allocator when running LuaJIT because it looks like LuaJIT does not expect it and might invalidate the memory unexpectedly -#if USE_LUA_STATE_ALLOCATOR() - { - AllocatorDefinition* const allocD = &U->protected_allocator.definition; - allocD->allocF( allocD->allocUD, U->keepers, sizeof( Keepers) + (nbKeepers - 1) * sizeof( Keeper), 0); - } -#else // USE_LUA_STATE_ALLOCATOR() - free(U->keepers); -#endif // USE_LUA_STATE_ALLOCATOR() + AllocatorDefinition* const allocD = &U->internal_allocator; + allocD->allocF( allocD->allocUD, U->keepers, sizeof( Keepers) + (nbKeepers - 1) * sizeof( Keeper), 0); U->keepers = NULL; } } @@ -653,15 +646,10 @@ void init_keepers( Universe* U, lua_State* L) // Keepers contains an array of 1 s_Keeper, adjust for the actual number of keeper states { size_t const bytes = sizeof( Keepers) + (nb_keepers - 1) * sizeof( Keeper); - // don't hijack the state allocator when running LuaJIT because it looks like LuaJIT does not expect it and might invalidate the memory unexpectedly -#if USE_LUA_STATE_ALLOCATOR() { - AllocatorDefinition* const allocD = &U->protected_allocator.definition; + AllocatorDefinition* const allocD = &U->internal_allocator; U->keepers = (Keepers*) allocD->allocF( allocD->allocUD, NULL, 0, bytes); } -#else // USE_LUA_STATE_ALLOCATOR() - U->keepers = (Keepers*)malloc(bytes); -#endif // USE_LUA_STATE_ALLOCATOR() if( U->keepers == NULL) { (void) luaL_error( L, "init_keepers() failed while creating keeper array; out of memory"); diff --git a/src/keeper.h b/src/keeper.h index 8c09322..d30aa36 100644 --- a/src/keeper.h +++ b/src/keeper.h @@ -27,7 +27,7 @@ struct s_Keepers typedef struct s_Keepers Keepers; void init_keepers( Universe* U, lua_State* L); -void close_keepers( Universe* U, lua_State* L); +void close_keepers( Universe* U); Keeper* which_keeper( Keepers* keepers_, ptrdiff_t magic_); Keeper* keeper_acquire( Keepers* keepers_, ptrdiff_t magic_); diff --git a/src/lanes.c b/src/lanes.c index 9f6a4d6..0aab244 100644 --- a/src/lanes.c +++ b/src/lanes.c @@ -253,15 +253,10 @@ static void lane_cleanup( Lane* s) } #endif // HAVE_LANE_TRACKING() - // don't hijack the state allocator when running LuaJIT because it looks like LuaJIT does not expect it and might invalidate the memory unexpectedly -#if USE_LUA_STATE_ALLOCATOR() { - AllocatorDefinition* const allocD = &s->U->protected_allocator.definition; + AllocatorDefinition* const allocD = &s->U->internal_allocator; allocD->allocF(allocD->allocUD, s, sizeof(Lane), 0); } -#else // USE_LUA_STATE_ALLOCATOR() - free(s); -#endif // USE_LUA_STATE_ALLOCATOR() } /* @@ -584,7 +579,7 @@ static int selfdestruct_gc( lua_State* L) U->timer_deep = NULL; } - close_keepers( U, L); + close_keepers( U); // remove the protected allocator, if any cleanup_allocator_function( U, L); @@ -1231,15 +1226,10 @@ LUAG_FUNC( lane_new) // // a Lane full userdata needs a single uservalue ud = lua_newuserdatauv( L, sizeof( Lane*), 1); // func libs priority globals package required gc_cb lane - // don't hijack the state allocator when running LuaJIT because it looks like LuaJIT does not expect it and might invalidate the memory unexpectedly -#if USE_LUA_STATE_ALLOCATOR() { - AllocatorDefinition* const allocD = &U->protected_allocator.definition; + AllocatorDefinition* const allocD = &U->internal_allocator; s = *ud = (Lane*)allocD->allocF(allocD->allocUD, NULL, 0, sizeof(Lane)); } -#else // USE_LUA_STATE_ALLOCATOR() - s = *ud = (Lane*) malloc(sizeof(Lane)); -#endif // USE_LUA_STATE_ALLOCATOR() if( s == NULL) { return luaL_error( L, "could not create lane: out of memory"); diff --git a/src/lanes.h b/src/lanes.h index 20524e6..420b31d 100644 --- a/src/lanes.h +++ b/src/lanes.h @@ -12,7 +12,7 @@ #define LANES_VERSION_MAJOR 3 #define LANES_VERSION_MINOR 16 -#define LANES_VERSION_PATCH 0 +#define LANES_VERSION_PATCH 1 #define LANES_MIN_VERSION_REQUIRED(MAJOR, MINOR, PATCH) ((LANES_VERSION_MAJOR>MAJOR) || (LANES_VERSION_MAJOR==MAJOR && (LANES_VERSION_MINOR>MINOR || (LANES_VERSION_MINOR==MINOR && LANES_VERSION_PATCH>=PATCH)))) #define LANES_VERSION_LESS_THAN(MAJOR, MINOR, PATCH) ((LANES_VERSION_MAJORprotected_allocator.definition; + AllocatorDefinition* const allocD = &U->internal_allocator; s = (struct s_Linda*)allocD->allocF(allocD->allocUD, NULL, 0, sizeof(struct s_Linda) + name_len); // terminating 0 is already included } -#else // USE_LUA_STATE_ALLOCATOR() - s = (struct s_Linda*)malloc(sizeof(struct s_Linda) + name_len); // terminating 0 is already included -#endif // USE_LUA_STATE_ALLOCATOR() if( s) { s->prelude.magic.value = DEEP_VERSION.value; @@ -837,17 +832,12 @@ static void* linda_id( lua_State* L, DeepOp op_) // There aren't any lanes waiting on these lindas, since all proxies have been gc'ed. Right? SIGNAL_FREE( &linda->read_happened); SIGNAL_FREE( &linda->write_happened); - // don't hijack the state allocator when running LuaJIT because it looks like LuaJIT does not expect it and might invalidate the memory unexpectedly -#if USE_LUA_STATE_ALLOCATOR() { Universe* const U = universe_get(L); - AllocatorDefinition* const allocD = &U->protected_allocator.definition; + AllocatorDefinition* const allocD = &U->internal_allocator; allocD->allocF(allocD->allocUD, linda, sizeof(struct s_Linda) + strlen(linda->name), 0); } -#else // USE_LUA_STATE_ALLOCATOR() - free(linda); -#endif // USE_LUA_STATE_ALLOCATOR() return NULL; } diff --git a/src/macros_and_utils.h b/src/macros_and_utils.h index 3ed234a..05a46b5 100644 --- a/src/macros_and_utils.h +++ b/src/macros_and_utils.h @@ -99,7 +99,4 @@ extern char const* debugspew_indent; #define LUAG_FUNC( func_name) int LG_##func_name( lua_State* L) -// after all, it looks like we can use the state allocator for our own usage when running LuaJIT, as long as we mutex-protect it -#define USE_LUA_STATE_ALLOCATOR() 1 // (LUAJIT_FLAVOR()==0) - #endif // MACROS_AND_UTILS_H diff --git a/src/tools.c b/src/tools.c index 626da2b..5a6ae92 100644 --- a/src/tools.c +++ b/src/tools.c @@ -155,6 +155,20 @@ void luaG_dump( lua_State* L) // ################################################################################################ +static void* libc_lua_Alloc(void* ud, void* ptr, size_t osize, size_t nsize) +{ + (void)ud; (void)osize; /* not used */ + if (nsize == 0) + { + free(ptr); + return NULL; + } + else + { + return realloc(ptr, nsize); + } +} + static void* protected_lua_Alloc( void *ud, void *ptr, size_t osize, size_t nsize) { void* p; @@ -217,6 +231,22 @@ void initialize_allocator_function( Universe* U, lua_State* L) U->protected_allocator.definition.allocF = lua_getallocf( L, &U->protected_allocator.definition.allocUD); } lua_pop( L, 1); // settings + STACK_MID(L, 0); + + lua_getfield( L, -1, "internal_allocator"); // settings "libc"|"allocator" + { + char const* allocator = lua_tostring( L, -1); + if (stricmp(allocator, "libc") == 0) + { + U->internal_allocator.allocF = libc_lua_Alloc; + U->internal_allocator.allocUD = NULL; + } + else + { + U->internal_allocator = U->protected_allocator.definition; + } + } + lua_pop( L, 1); // settings STACK_END( L, 0); } @@ -1337,17 +1367,17 @@ static void copy_cached_func( Universe* U, lua_State* L2, uint_t L2_cache_i, lua if( lua_isnil( L2, -1)) // function is unknown { - lua_pop( L2, 1); // ... {cache} ... p + lua_pop( L2, 1); // ... {cache} ... p // Set to 'true' for the duration of creation; need to find self-references // via upvalues // // pushes a copy of the func, stores a reference in the cache - copy_func( U, L2, L2_cache_i, L, i, mode_, upName_); // ... {cache} ... function + copy_func( U, L2, L2_cache_i, L, i, mode_, upName_); // ... {cache} ... function } else // found function in the cache { - lua_remove( L2, -2); // ... {cache} ... function + lua_remove( L2, -2); // ... {cache} ... function } STACK_END( L2, 1); ASSERT_L( lua_isfunction( L2, -1)); @@ -1725,9 +1755,7 @@ static bool_t inter_copy_function( Universe* U, lua_State* L2, uint_t L2_cache_i { DEBUGSPEW_CODE( fprintf( stderr, "FUNCTION %s\n", upName_)); DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); - STACK_CHECK( L2, 0); copy_cached_func( U, L2, L2_cache_i, L, source_i_, mode_, upName_); // ... f - STACK_END( L2, 1); DEBUGSPEW_CODE( -- U->debugspew_indent_depth); } STACK_END( L2, 1); diff --git a/src/universe.h b/src/universe.h index ba00e87..03c78cf 100644 --- a/src/universe.h +++ b/src/universe.h @@ -63,6 +63,8 @@ struct s_Universe // contains a mutex and the original allocator definition ProtectedAllocator protected_allocator; + AllocatorDefinition internal_allocator; + Keepers* keepers; // Initialized by 'init_once_LOCKED()': the deep userdata Linda object -- cgit v1.2.3-55-g6feb
+ .internal_allocator + + "libc"/"allocator" + + (Since v3.16.1)
+ Controls which allocator is used for Lanest internal allocations (for keeper and deep userdata management). + If "libc", Lanes uses realloc and free.
+ If "allocator", Lanes uses whatever was obtained from the "allocator" setting.
+ This option is mostly useful for embedders that want control all memory allocations, but have issues when Lanes tries to use the Lua State allocator for internal purposes (especially with LuaJIT). +
.demote_full_userdata @@ -390,18 +406,18 @@ If provided, will be called in every created Lua state right after initializing the base libraries. -
+
Keeper states will call it as well, but only if it is a C function (keeper states are not able to execute any user Lua code). -
+
Typical usage is twofold:
  • Tweak package.loaders
  • Load some additional C functions in the global space (of course only a C function will be able to do this).
That way, all changes in the state can be properly taken into account when building the function lookup database. Default is nil. -
+
(Since version 3.7.6) If on_state_create() is a Lua function, it will be transfered normally before the call. -
+
If it is a C function, a C closure will be reconstructed in the created state from the C pointer. Lanes will raise an error if the function has upvalues.