From 08d6b2ad285c373e36f9cae1fe556898df0381de Mon Sep 17 00:00:00 2001 From: bjorn Date: Thu, 23 Nov 2023 17:07:44 -0800 Subject: [PATCH] Refcounted modules; This allows them to be initialized/destroyed from multiple threads in any order. Previously, the first thread to require a module had to be the last thread to use the module, otherwise it would be destroyed too early. There are still a few issues. If the main thread doesn't require a module, it won't pick up the conf.lua settings. Also graphics isn't handling the shader cache writing properly. And I think this breaks the headset-graphics refcounting. But these will be fixed in future commits. --- src/api/l_audio.c | 10 ++++------ src/api/l_event.c | 6 ++---- src/api/l_filesystem.c | 19 +++++++++---------- src/api/l_graphics.c | 11 ++++------- src/api/l_math.c | 5 ++--- src/api/l_physics.c | 5 ++--- src/api/l_thread.c | 5 ++--- src/api/l_timer.c | 5 ++--- src/modules/audio/audio.c | 10 +++++----- src/modules/event/event.c | 9 +++++---- src/modules/filesystem/filesystem.c | 8 ++++---- src/modules/graphics/graphics.c | 10 +++++----- src/modules/headset/headset.c | 10 +++++----- src/modules/math/math.c | 12 ++++++------ src/modules/physics/physics.c | 10 +++++----- src/modules/system/system.c | 8 ++++---- src/modules/thread/thread.c | 11 ++++++----- src/modules/timer/timer.c | 8 ++++---- 18 files changed, 76 insertions(+), 86 deletions(-) diff --git a/src/api/l_audio.c b/src/api/l_audio.c index 1f25678f..d0043d71 100644 --- a/src/api/l_audio.c +++ b/src/api/l_audio.c @@ -346,13 +346,11 @@ int luaopen_lovr_audio(lua_State* L) { } lua_pop(L, 1); - if (lovrAudioInit(spatializer, sampleRate)) { - luax_atexit(L, lovrAudioDestroy); - if (start) { - lovrAudioSetDevice(AUDIO_PLAYBACK, NULL, 0, NULL, AUDIO_SHARED); - lovrAudioStart(AUDIO_PLAYBACK); - } + if (lovrAudioInit(spatializer, sampleRate) && start) { + lovrAudioSetDevice(AUDIO_PLAYBACK, NULL, 0, NULL, AUDIO_SHARED); + lovrAudioStart(AUDIO_PLAYBACK); } + luax_atexit(L, lovrAudioDestroy); return 1; } diff --git a/src/api/l_event.c b/src/api/l_event.c index be634746..7235f011 100644 --- a/src/api/l_event.c +++ b/src/api/l_event.c @@ -280,9 +280,7 @@ int luaopen_lovr_event(lua_State* L) { lua_pushcfunction(L, nextEvent); pollRef = luaL_ref(L, LUA_REGISTRYINDEX); - if (lovrEventInit()) { - luax_atexit(L, lovrEventDestroy); - } - + lovrEventInit(); + luax_atexit(L, lovrEventDestroy); return 1; } diff --git a/src/api/l_filesystem.c b/src/api/l_filesystem.c index 0e0f05b3..604e435b 100644 --- a/src/api/l_filesystem.c +++ b/src/api/l_filesystem.c @@ -561,6 +561,13 @@ static int libLoaderAllInOne(lua_State* L) { extern const luaL_Reg lovrFile[]; int luaopen_lovr_filesystem(lua_State* L) { + lua_newtable(L); + luax_register(L, lovrFilesystem); + luax_registertype(L, File); + luax_registerloader(L, luaLoader, 2); + luax_registerloader(L, libLoader, 3); + luax_registerloader(L, libLoaderAllInOne, 4); + const char* archive = NULL; lua_getglobal(L, "arg"); @@ -571,15 +578,7 @@ int luaopen_lovr_filesystem(lua_State* L) { } lua_pop(L, 1); - if (lovrFilesystemInit(archive)) { - luax_atexit(L, lovrFilesystemDestroy); - } - - lua_newtable(L); - luax_register(L, lovrFilesystem); - luax_registertype(L, File); - luax_registerloader(L, luaLoader, 2); - luax_registerloader(L, libLoader, 3); - luax_registerloader(L, libLoaderAllInOne, 4); + lovrFilesystemInit(archive); + luax_atexit(L, lovrFilesystemDestroy); return 1; } diff --git a/src/api/l_graphics.c b/src/api/l_graphics.c index b85be278..f55c98f8 100644 --- a/src/api/l_graphics.c +++ b/src/api/l_graphics.c @@ -359,17 +359,14 @@ static int l_lovrGraphicsInitialize(lua_State* L) { config.cacheData = luax_readfile(".lovrshadercache", &config.cacheSize); } - if (lovrGraphicsInit(&config)) { - luax_atexit(L, lovrGraphicsDestroy); + lovrGraphicsInit(&config); + luax_atexit(L, lovrGraphicsDestroy); - // Finalizers run in the opposite order they were added, so this has to go last - if (shaderCache) { - luax_atexit(L, luax_writeshadercache); - } + if (shaderCache) { // Finalizers run in the opposite order they were added, so this has to go last + luax_atexit(L, luax_writeshadercache); } free(config.cacheData); - return 0; } diff --git a/src/api/l_math.c b/src/api/l_math.c index ab2f08cc..460eb03d 100644 --- a/src/api/l_math.c +++ b/src/api/l_math.c @@ -387,9 +387,8 @@ int luaopen_lovr_math(lua_State* L) { lua_pop(L, 1); // Module - if (lovrMathInit()) { - luax_atexit(L, lovrMathDestroy); - } + lovrMathInit(); + luax_atexit(L, lovrMathDestroy); // Each Lua state gets its own thread-local Pool pool = lovrPoolCreate(); diff --git a/src/api/l_physics.c b/src/api/l_physics.c index c0e11e02..49128e33 100644 --- a/src/api/l_physics.c +++ b/src/api/l_physics.c @@ -178,8 +178,7 @@ int luaopen_lovr_physics(lua_State* L) { luax_registertype(L, CylinderShape); luax_registertype(L, MeshShape); luax_registertype(L, TerrainShape); - if (lovrPhysicsInit()) { - luax_atexit(L, lovrPhysicsDestroy); - } + lovrPhysicsInit(); + luax_atexit(L, lovrPhysicsDestroy); return 1; } diff --git a/src/api/l_thread.c b/src/api/l_thread.c index ae19b88f..7b6c4078 100644 --- a/src/api/l_thread.c +++ b/src/api/l_thread.c @@ -88,8 +88,7 @@ int luaopen_lovr_thread(lua_State* L) { luax_register(L, lovrThreadModule); luax_registertype(L, Thread); luax_registertype(L, Channel); - if (lovrThreadModuleInit()) { - luax_atexit(L, lovrThreadModuleDestroy); - } + lovrThreadModuleInit(); + luax_atexit(L, lovrThreadModuleDestroy); return 1; } diff --git a/src/api/l_timer.c b/src/api/l_timer.c index 81529a51..c30a9378 100644 --- a/src/api/l_timer.c +++ b/src/api/l_timer.c @@ -45,8 +45,7 @@ static const luaL_Reg lovrTimer[] = { int luaopen_lovr_timer(lua_State* L) { lua_newtable(L); luax_register(L, lovrTimer); - if (lovrTimerInit()) { - luax_atexit(L, lovrTimerDestroy); - } + lovrTimerInit(); + luax_atexit(L, lovrTimerDestroy); return 1; } diff --git a/src/modules/audio/audio.c b/src/modules/audio/audio.c index 8b09078f..acade806 100644 --- a/src/modules/audio/audio.c +++ b/src/modules/audio/audio.c @@ -4,6 +4,7 @@ #include "core/maf.h" #include "util.h" #include "lib/miniaudio/miniaudio.h" +#include #include #include #include @@ -41,7 +42,7 @@ struct Source { }; static struct { - bool initialized; + uint32_t ref; ma_mutex lock; ma_context context; ma_device devices[2]; @@ -193,7 +194,7 @@ static Spatializer* spatializers[] = { // Entry bool lovrAudioInit(const char* spatializer, uint32_t sampleRate) { - if (state.initialized) return false; + if (atomic_fetch_add(&state.ref, 1)) return false; state.sampleRate = sampleRate; @@ -221,12 +222,11 @@ bool lovrAudioInit(const char* spatializer, uint32_t sampleRate) { state.absorption[2] = .0182f; quat_identity(state.orientation); - - return state.initialized = true; + return true; } void lovrAudioDestroy(void) { - if (!state.initialized) return; + if (atomic_fetch_sub(&state.ref, 1) != 1) return; for (size_t i = 0; i < 2; i++) { ma_device_uninit(&state.devices[i]); free(state.deviceInfo[i]); diff --git a/src/modules/event/event.c b/src/modules/event/event.c index ec123b60..03e4e4aa 100644 --- a/src/modules/event/event.c +++ b/src/modules/event/event.c @@ -1,11 +1,12 @@ #include "event/event.h" #include "thread/thread.h" #include "util.h" +#include #include #include static struct { - bool initialized; + uint32_t ref; arr_t(Event) events; size_t head; } state; @@ -20,13 +21,13 @@ void lovrVariantDestroy(Variant* variant) { } bool lovrEventInit(void) { - if (state.initialized) return false; + if (atomic_fetch_add(&state.ref, 1)) return false; arr_init(&state.events, arr_alloc); - return state.initialized = true; + return true; } void lovrEventDestroy(void) { - if (!state.initialized) return; + if (atomic_fetch_sub(&state.ref, 1) != 1) return; for (size_t i = state.head; i < state.events.length; i++) { Event* event = &state.events.data[i]; switch (event->type) { diff --git a/src/modules/filesystem/filesystem.c b/src/modules/filesystem/filesystem.c index 456539d2..4d0e3ae0 100644 --- a/src/modules/filesystem/filesystem.c +++ b/src/modules/filesystem/filesystem.c @@ -3,6 +3,7 @@ #include "core/os.h" #include "util.h" #include "lib/miniz/miniz_tinfl.h" +#include #include #include #include @@ -67,7 +68,7 @@ struct File { }; static struct { - bool initialized; + uint32_t ref; Archive* archives; size_t savePathLength; char savePath[1024]; @@ -132,8 +133,7 @@ static bool sanitize(const char* path, char* buffer, size_t* length) { } bool lovrFilesystemInit(const char* archive) { - if (state.initialized) return false; - state.initialized = true; + if (atomic_fetch_add(&state.ref, 1)) return false; lovrFilesystemSetRequirePath("?.lua;?/init.lua"); @@ -197,7 +197,7 @@ bool lovrFilesystemInit(const char* archive) { } void lovrFilesystemDestroy(void) { - if (!state.initialized) return; + if (atomic_fetch_sub(&state.ref, 1) != 1) return; Archive* archive = state.archives; while (archive) { Archive* next = archive->next; diff --git a/src/modules/graphics/graphics.c b/src/modules/graphics/graphics.c index be6a2495..d3e99710 100644 --- a/src/modules/graphics/graphics.c +++ b/src/modules/graphics/graphics.c @@ -14,6 +14,7 @@ #include "monkey.h" #include "shaders.h" #include +#include #include #include #include @@ -547,7 +548,7 @@ typedef struct { } ScratchTexture; static struct { - bool initialized; + uint32_t ref; bool active; bool presentable; bool timingEnabled; @@ -618,7 +619,7 @@ static void onMessage(void* context, const char* message, bool severe); // Entry bool lovrGraphicsInit(GraphicsConfig* config) { - if (state.initialized) return false; + if (atomic_fetch_add(&state.ref, 1)) return false; gpu_config gpu = { .debug = config->debug, @@ -803,12 +804,11 @@ bool lovrGraphicsInit(GraphicsConfig* config) { #ifdef LOVR_USE_GLSLANG glslang_initialize_process(); #endif - state.initialized = true; return true; } void lovrGraphicsDestroy(void) { - if (!state.initialized) return; + if (atomic_fetch_sub(&state.ref, 1) != 1) return; #ifndef LOVR_DISABLE_HEADSET // If there's an active headset session it needs to be stopped so it can clean up its Pass and // swapchain textures before gpu_destroy is called. This is really hacky and should be solved @@ -889,7 +889,7 @@ void lovrGraphicsDestroy(void) { } bool lovrGraphicsIsInitialized(void) { - return state.initialized; + return state.ref; } void lovrGraphicsGetDevice(GraphicsDevice* device) { diff --git a/src/modules/headset/headset.c b/src/modules/headset/headset.c index 9a534f4c..4389bcd3 100644 --- a/src/modules/headset/headset.c +++ b/src/modules/headset/headset.c @@ -1,12 +1,12 @@ #include "headset/headset.h" #include "util.h" +#include HeadsetInterface* lovrHeadsetInterface = NULL; -static bool initialized = false; +static uint32_t ref; bool lovrHeadsetInit(HeadsetConfig* config) { - if (initialized) return false; - initialized = true; + if (atomic_fetch_add(&ref, 1)) return false; for (size_t i = 0; i < config->driverCount; i++) { HeadsetInterface* interface = NULL; @@ -35,12 +35,12 @@ bool lovrHeadsetInit(HeadsetConfig* config) { } void lovrHeadsetDestroy(void) { - if (!initialized) return; - initialized = false; + if (atomic_fetch_sub(&ref, 1) != 1) return; if (lovrHeadsetInterface) { lovrHeadsetInterface->destroy(); lovrHeadsetInterface = NULL; } + ref = 0; } void lovrLayerDestroy(void* ref) { diff --git a/src/modules/math/math.c b/src/modules/math/math.c index 432f98be..f20f1535 100644 --- a/src/modules/math/math.c +++ b/src/modules/math/math.c @@ -3,12 +3,12 @@ #include "util.h" #include "lib/noise/simplexnoise1234.h" #include -#include +#include #include #include #include +#include #include -#include struct Curve { uint32_t ref; @@ -31,20 +31,20 @@ struct RandomGenerator { }; static struct { - bool initialized; + uint32_t ref; RandomGenerator* generator; } state; bool lovrMathInit(void) { - if (state.initialized) return false; + if (atomic_fetch_add(&state.ref, 1)) return false; state.generator = lovrRandomGeneratorCreate(); Seed seed = { .b64 = (uint64_t) time(0) }; lovrRandomGeneratorSetSeed(state.generator, seed); - return state.initialized = true; + return true; } void lovrMathDestroy(void) { - if (!state.initialized) return; + if (atomic_fetch_sub(&state.ref, 1) != 1) return; lovrRelease(state.generator, lovrRandomGeneratorDestroy); memset(&state, 0, sizeof(state)); } diff --git a/src/modules/physics/physics.c b/src/modules/physics/physics.c index 150e1e2a..1c62270a 100644 --- a/src/modules/physics/physics.c +++ b/src/modules/physics/physics.c @@ -1,6 +1,7 @@ #include "physics.h" #include "util.h" #include +#include #include struct World { @@ -138,21 +139,20 @@ static void onInfoMessage(int num, const char* format, va_list args) { lovrLog(LOG_INFO, "PHY", message); } -static bool initialized = false; +static uint32_t ref; bool lovrPhysicsInit(void) { - if (initialized) return false; + if (atomic_fetch_add(&ref, 1)) return false; dInitODE(); dSetErrorHandler(onErrorMessage); dSetDebugHandler(onDebugMessage); dSetMessageHandler(onInfoMessage); - return initialized = true; + return true; } void lovrPhysicsDestroy(void) { - if (!initialized) return; + if (atomic_fetch_sub(&ref, 1) != 1) return; dCloseODE(); - initialized = false; } World* lovrWorldCreate(float xg, float yg, float zg, bool allowSleep, const char** tags, uint32_t tagCount) { diff --git a/src/modules/system/system.c b/src/modules/system/system.c index c04643de..29b809af 100644 --- a/src/modules/system/system.c +++ b/src/modules/system/system.c @@ -2,10 +2,11 @@ #include "event/event.h" #include "core/os.h" #include "util.h" +#include #include static struct { - bool initialized; + uint32_t ref; bool keyRepeat; bool prevKeyState[OS_KEY_COUNT]; bool keyState[OS_KEY_COUNT]; @@ -84,20 +85,19 @@ static void onQuit(void) { } bool lovrSystemInit(void) { - if (state.initialized) return false; + if (atomic_fetch_add(&state.ref, 1)) return false; os_on_key(onKey); os_on_text(onText); os_on_mouse_button(onMouseButton); os_on_mouse_move(onMouseMove); os_on_mousewheel_move(onWheelMove); os_on_permission(onPermission); - state.initialized = true; os_get_mouse_position(&state.mouseX, &state.mouseY); return true; } void lovrSystemDestroy(void) { - if (!state.initialized) return; + if (atomic_fetch_sub(&state.ref, 1) != 1) return; os_on_key(NULL); os_on_text(NULL); os_on_permission(NULL); diff --git a/src/modules/thread/thread.c b/src/modules/thread/thread.c index 0ccc6a76..013f74e6 100644 --- a/src/modules/thread/thread.c +++ b/src/modules/thread/thread.c @@ -4,6 +4,7 @@ #include "core/os.h" #include "util.h" #include +#include #include #include #include @@ -32,20 +33,20 @@ struct Channel { }; static struct { - bool initialized; + uint32_t ref; mtx_t channelLock; map_t channels; } state; bool lovrThreadModuleInit(void) { - if (state.initialized) return false; + if (atomic_fetch_add(&state.ref, 1)) return false; mtx_init(&state.channelLock, mtx_plain); map_init(&state.channels, 0); - return state.initialized = true; + return true; } void lovrThreadModuleDestroy(void) { - if (!state.initialized) return; + if (atomic_fetch_sub(&state.ref, 1)) return; for (size_t i = 0; i < state.channels.size; i++) { if (state.channels.values[i] != MAP_NIL) { lovrRelease((Channel*) (uintptr_t) state.channels.values[i], lovrChannelDestroy); @@ -53,7 +54,7 @@ void lovrThreadModuleDestroy(void) { } mtx_destroy(&state.channelLock); map_free(&state.channels); - state.initialized = false; + memset(&state, 0, sizeof(state)); } Channel* lovrThreadGetChannel(const char* name) { diff --git a/src/modules/timer/timer.c b/src/modules/timer/timer.c index bfa6fc73..7d03ef34 100644 --- a/src/modules/timer/timer.c +++ b/src/modules/timer/timer.c @@ -1,9 +1,10 @@ #include "timer/timer.h" #include "core/os.h" +#include #include static struct { - bool initialized; + uint32_t ref; double epoch; double lastTime; double time; @@ -14,14 +15,13 @@ static struct { } state; bool lovrTimerInit(void) { - if (state.initialized) return false; - state.initialized = true; + if (atomic_fetch_add(&state.ref, 1)) return false; state.epoch = os_get_time(); return true; } void lovrTimerDestroy(void) { - if (!state.initialized) return; + if (atomic_fetch_sub(&state.ref, 1) != 1) return; memset(&state, 0, sizeof(state)); }