Fix module destruction;

There is a problem when a Thread stops: it destroys all of the modules
that it required.  This is because we unconditionally call luax_atexit
when modules are required, and when the thread lua_State dies it takes
all of the modules with it.  To fix this, lovr<Module>Init will return
whether or not initialization successfully happened, which provides us
with enough info to know if we should place the luax_atexit destructor
This commit is contained in:
bjorn 2018-11-19 08:08:56 -08:00 committed by Bjorn Swenson
parent 465e5c2010
commit 0e99d47394
27 changed files with 69 additions and 54 deletions

View File

@ -223,9 +223,10 @@ static const luaL_Reg lovrAudio[] = {
int luaopen_lovr_audio(lua_State* L) { int luaopen_lovr_audio(lua_State* L) {
lua_newtable(L); lua_newtable(L);
luaL_register(L, NULL, lovrAudio); luaL_register(L, NULL, lovrAudio);
luax_atexit(L, lovrAudioDestroy);
luax_registertype(L, "Microphone", lovrMicrophone); luax_registertype(L, "Microphone", lovrMicrophone);
luax_registertype(L, "Source", lovrSource); luax_registertype(L, "Source", lovrSource);
lovrAudioInit(); if (lovrAudioInit()) {
luax_atexit(L, lovrAudioDestroy);
}
return 1; return 1;
} }

View File

@ -178,12 +178,14 @@ static const luaL_Reg lovrEvent[] = {
int luaopen_lovr_event(lua_State* L) { int luaopen_lovr_event(lua_State* L) {
lua_newtable(L); lua_newtable(L);
luaL_register(L, NULL, lovrEvent); luaL_register(L, NULL, lovrEvent);
luax_atexit(L, lovrEventDestroy);
// Store nextEvent in the registry to avoid creating a closure every time we poll for events. // Store nextEvent in the registry to avoid creating a closure every time we poll for events.
lua_pushcfunction(L, nextEvent); lua_pushcfunction(L, nextEvent);
pollRef = luaL_ref(L, LUA_REGISTRYINDEX); pollRef = luaL_ref(L, LUA_REGISTRYINDEX);
lovrEventInit(); if (lovrEventInit()) {
luax_atexit(L, lovrEventDestroy);
}
return 1; return 1;
} }

View File

@ -360,10 +360,6 @@ static const luaL_Reg lovrFilesystem[] = {
}; };
int luaopen_lovr_filesystem(lua_State* L) { int luaopen_lovr_filesystem(lua_State* L) {
lua_newtable(L);
luaL_register(L, NULL, lovrFilesystem);
luax_atexit(L, lovrFilesystemDestroy);
lua_getglobal(L, "arg"); lua_getglobal(L, "arg");
if (lua_istable(L, -1)) { if (lua_istable(L, -1)) {
lua_getfield(L, -1, "exe"); lua_getfield(L, -1, "exe");
@ -372,13 +368,19 @@ int luaopen_lovr_filesystem(lua_State* L) {
const char* argGame = lua_tostring(L, -1); const char* argGame = lua_tostring(L, -1);
lua_getfield(L, -3, "root"); lua_getfield(L, -3, "root");
const char* argRoot = luaL_optstring(L, -1, NULL); const char* argRoot = luaL_optstring(L, -1, NULL);
lovrFilesystemInit(argExe, argGame, argRoot); if (lovrFilesystemInit(argExe, argGame, argRoot)) {
luax_atexit(L, lovrFilesystemDestroy);
}
lua_pop(L, 4); lua_pop(L, 4);
} else { } else {
lua_pop(L, 1); lua_pop(L, 1);
lovrFilesystemInit(NULL, NULL, NULL); if (lovrFilesystemInit(NULL, NULL, NULL)) {
luax_atexit(L, lovrFilesystemDestroy);
}
} }
lua_newtable(L);
luaL_register(L, NULL, lovrFilesystem);
luax_registerloader(L, moduleLoader, 2); luax_registerloader(L, moduleLoader, 2);
luax_registerloader(L, libraryLoader, 3); luax_registerloader(L, libraryLoader, 3);
return 1; return 1;

View File

@ -299,6 +299,7 @@ static int l_lovrGraphicsSetWindow(lua_State* L) {
lua_pop(L, 1); lua_pop(L, 1);
lovrGraphicsSetWindow(&flags); lovrGraphicsSetWindow(&flags);
luax_atexit(L, lovrGraphicsDestroy); // The lua_State that creates the window shall be the one to destroy it
lovrRelease(textureData); lovrRelease(textureData);
return 0; return 0;
} }
@ -1390,7 +1391,6 @@ static const luaL_Reg lovrGraphics[] = {
int luaopen_lovr_graphics(lua_State* L) { int luaopen_lovr_graphics(lua_State* L) {
lua_newtable(L); lua_newtable(L);
luaL_register(L, NULL, lovrGraphics); luaL_register(L, NULL, lovrGraphics);
luax_atexit(L, lovrGraphicsDestroy);
luax_registertype(L, "Animator", lovrAnimator); luax_registertype(L, "Animator", lovrAnimator);
luax_registertype(L, "Font", lovrFont); luax_registertype(L, "Font", lovrFont);
luax_registertype(L, "Material", lovrMaterial); luax_registertype(L, "Material", lovrMaterial);

View File

@ -349,7 +349,6 @@ static const luaL_Reg lovrHeadset[] = {
int luaopen_lovr_headset(lua_State* L) { int luaopen_lovr_headset(lua_State* L) {
lua_newtable(L); lua_newtable(L);
luaL_register(L, NULL, lovrHeadset); luaL_register(L, NULL, lovrHeadset);
luax_atexit(L, lovrHeadsetDestroy);
luax_registertype(L, "Controller", lovrController); luax_registertype(L, "Controller", lovrController);
luax_pushconf(L); luax_pushconf(L);
@ -391,7 +390,10 @@ int luaopen_lovr_headset(lua_State* L) {
lua_pop(L, 1); lua_pop(L, 1);
} }
lovrHeadsetInit(drivers.data, drivers.length, offset, msaa); if (lovrHeadsetInit(drivers.data, drivers.length, offset, msaa)) {
luax_atexit(L, lovrHeadsetDestroy);
}
lovrHeadsetDriver->setMirrored(mirror, mirrorEye); lovrHeadsetDriver->setMirrored(mirror, mirrorEye);
vec_deinit(&drivers); vec_deinit(&drivers);

View File

@ -181,10 +181,11 @@ static const luaL_Reg lovrMath[] = {
int luaopen_lovr_math(lua_State* L) { int luaopen_lovr_math(lua_State* L) {
lua_newtable(L); lua_newtable(L);
luaL_register(L, NULL, lovrMath); luaL_register(L, NULL, lovrMath);
luax_atexit(L, lovrMathDestroy);
luax_registertype(L, "Curve", lovrCurve); luax_registertype(L, "Curve", lovrCurve);
luax_registertype(L, "RandomGenerator", lovrRandomGenerator); luax_registertype(L, "RandomGenerator", lovrRandomGenerator);
luax_registertype(L, "Transform", lovrTransform); luax_registertype(L, "Transform", lovrTransform);
lovrMathInit(); if (lovrMathInit()) {
luax_atexit(L, lovrMathDestroy);
}
return 1; return 1;
} }

View File

@ -150,7 +150,6 @@ static const luaL_Reg lovrPhysics[] = {
int luaopen_lovr_physics(lua_State* L) { int luaopen_lovr_physics(lua_State* L) {
lua_newtable(L); lua_newtable(L);
luaL_register(L, NULL, lovrPhysics); luaL_register(L, NULL, lovrPhysics);
luax_atexit(L, lovrPhysicsDestroy);
luax_registertype(L, "World", lovrWorld); luax_registertype(L, "World", lovrWorld);
luax_registertype(L, "Collider", lovrCollider); luax_registertype(L, "Collider", lovrCollider);
luax_extendtype(L, "Joint", "BallJoint", lovrJoint, lovrBallJoint); luax_extendtype(L, "Joint", "BallJoint", lovrJoint, lovrBallJoint);
@ -161,6 +160,8 @@ int luaopen_lovr_physics(lua_State* L) {
luax_extendtype(L, "Shape", "BoxShape", lovrShape, lovrBoxShape); luax_extendtype(L, "Shape", "BoxShape", lovrShape, lovrBoxShape);
luax_extendtype(L, "Shape", "CapsuleShape", lovrShape, lovrCapsuleShape); luax_extendtype(L, "Shape", "CapsuleShape", lovrShape, lovrCapsuleShape);
luax_extendtype(L, "Shape", "CylinderShape", lovrShape, lovrCylinderShape); luax_extendtype(L, "Shape", "CylinderShape", lovrShape, lovrCylinderShape);
lovrPhysicsInit(); if (lovrPhysicsInit()) {
luax_atexit(L, lovrPhysicsDestroy);
}
return 1; return 1;
} }

View File

@ -66,10 +66,11 @@ static const luaL_Reg lovrThreadModule[] = {
int luaopen_lovr_thread(lua_State* L) { int luaopen_lovr_thread(lua_State* L) {
lua_newtable(L); lua_newtable(L);
luax_atexit(L, lovrThreadDeinit);
luaL_register(L, NULL, lovrThreadModule); luaL_register(L, NULL, lovrThreadModule);
luax_registertype(L, "Thread", lovrThread); luax_registertype(L, "Thread", lovrThread);
luax_registertype(L, "Channel", lovrChannel); luax_registertype(L, "Channel", lovrChannel);
lovrThreadInit(); if (lovrThreadInit()) {
luax_atexit(L, lovrThreadDeinit);
}
return 1; return 1;
} }

View File

@ -45,7 +45,8 @@ static const luaL_Reg lovrTimer[] = {
int luaopen_lovr_timer(lua_State* L) { int luaopen_lovr_timer(lua_State* L) {
lua_newtable(L); lua_newtable(L);
luaL_register(L, NULL, lovrTimer); luaL_register(L, NULL, lovrTimer);
luax_atexit(L, lovrTimerDestroy); if (lovrTimerInit()) {
lovrTimerInit(); luax_atexit(L, lovrTimerDestroy);
}
return 1; return 1;
} }

View File

@ -19,8 +19,8 @@ ALenum lovrAudioConvertFormat(int bitDepth, int channelCount) {
return 0; return 0;
} }
void lovrAudioInit() { bool lovrAudioInit() {
if (state.initialized) return; if (state.initialized) return false;
ALCdevice* device = alcOpenDevice(NULL); ALCdevice* device = alcOpenDevice(NULL);
lovrAssert(device, "Unable to open default audio device"); lovrAssert(device, "Unable to open default audio device");
@ -46,7 +46,7 @@ void lovrAudioInit() {
quat_set(state.orientation, 0, 0, 0, -1); quat_set(state.orientation, 0, 0, 0, -1);
vec3_set(state.position, 0, 0, 0); vec3_set(state.position, 0, 0, 0);
vec3_set(state.velocity, 0, 0, 0); vec3_set(state.velocity, 0, 0, 0);
state.initialized = true; return state.initialized = true;
} }
void lovrAudioDestroy() { void lovrAudioDestroy() {

View File

@ -23,7 +23,7 @@ typedef struct {
ALenum lovrAudioConvertFormat(int bitDepth, int channelCount); ALenum lovrAudioConvertFormat(int bitDepth, int channelCount);
void lovrAudioInit(); bool lovrAudioInit();
void lovrAudioDestroy(); void lovrAudioDestroy();
void lovrAudioUpdate(); void lovrAudioUpdate();
void lovrAudioAdd(Source* source); void lovrAudioAdd(Source* source);

View File

@ -5,13 +5,13 @@
static EventState state; static EventState state;
void lovrEventInit() { bool lovrEventInit() {
if (state.initialized) return; if (state.initialized) return false;
vec_init(&state.pumps); vec_init(&state.pumps);
vec_init(&state.events); vec_init(&state.events);
lovrEventAddPump(lovrPlatformPollEvents); lovrEventAddPump(lovrPlatformPollEvents);
atexit(lovrEventDestroy); atexit(lovrEventDestroy);
state.initialized = true; return state.initialized = true;
} }
void lovrEventDestroy() { void lovrEventDestroy() {

View File

@ -90,7 +90,7 @@ typedef struct {
vec_event_t events; vec_event_t events;
} EventState; } EventState;
void lovrEventInit(); bool lovrEventInit();
void lovrEventDestroy(); void lovrEventDestroy();
void lovrEventAddPump(EventPump pump); void lovrEventAddPump(EventPump pump);
void lovrEventRemovePump(EventPump pump); void lovrEventRemovePump(EventPump pump);

View File

@ -31,8 +31,8 @@ const char lovrDirSep = '/';
static FilesystemState state; static FilesystemState state;
void lovrFilesystemInit(const char* argExe, const char* argGame, const char* argRoot) { bool lovrFilesystemInit(const char* argExe, const char* argGame, const char* argRoot) {
if (state.initialized) return; if (state.initialized) return false;
state.initialized = true; state.initialized = true;
if (!PHYSFS_init(argExe)) { if (!PHYSFS_init(argExe)) {
@ -55,13 +55,15 @@ void lovrFilesystemInit(const char* argExe, const char* argGame, const char* arg
if (argGame) { if (argGame) {
strncpy(state.source, argGame, LOVR_PATH_MAX); strncpy(state.source, argGame, LOVR_PATH_MAX);
if (!lovrFilesystemMount(state.source, NULL, 1, argRoot)) { // Attempt to load from arg. If success, init is done if (!lovrFilesystemMount(state.source, NULL, 1, argRoot)) { // Attempt to load from arg. If success, init is done
return; return true;
} }
} }
free(state.source); // Couldn't load from argProject, so apparently it isn't the source free(state.source); // Couldn't load from argProject, so apparently it isn't the source
state.source = NULL; state.source = NULL;
} }
return true;
} }
void lovrFilesystemDestroy() { void lovrFilesystemDestroy() {

View File

@ -22,7 +22,7 @@ typedef struct {
vec_str_t requirePattern[2]; vec_str_t requirePattern[2];
} FilesystemState; } FilesystemState;
void lovrFilesystemInit(const char* argExe, const char* argGame, const char* argRoot); bool lovrFilesystemInit(const char* argExe, const char* argGame, const char* argRoot);
void lovrFilesystemDestroy(); void lovrFilesystemDestroy();
int lovrFilesystemCreateDirectory(const char* path); int lovrFilesystemCreateDirectory(const char* path);
int lovrFilesystemGetAppdataDirectory(char* dest, unsigned int size); int lovrFilesystemGetAppdataDirectory(char* dest, unsigned int size);

View File

@ -24,8 +24,9 @@ static void onResizeWindow(int width, int height) {
// Base // Base
void lovrGraphicsInit(bool gammaCorrect) { bool lovrGraphicsInit(bool gammaCorrect) {
state.gammaCorrect = gammaCorrect; state.gammaCorrect = gammaCorrect;
return false;
} }
void lovrGraphicsDestroy() { void lovrGraphicsDestroy() {

View File

@ -154,7 +154,7 @@ typedef struct {
} GraphicsState; } GraphicsState;
// Base // Base
void lovrGraphicsInit(bool gammaCorrect); bool lovrGraphicsInit(bool gammaCorrect);
void lovrGraphicsDestroy(); void lovrGraphicsDestroy();
void lovrGraphicsPresent(); void lovrGraphicsPresent();
void lovrGraphicsSetWindow(WindowFlags* flags); void lovrGraphicsSetWindow(WindowFlags* flags);

View File

@ -4,8 +4,8 @@
HeadsetInterface* lovrHeadsetDriver = NULL; HeadsetInterface* lovrHeadsetDriver = NULL;
static bool initialized = false; static bool initialized = false;
void lovrHeadsetInit(HeadsetDriver* drivers, int count, float offset, int msaa) { bool lovrHeadsetInit(HeadsetDriver* drivers, int count, float offset, int msaa) {
if (initialized) return; if (initialized) return false;
initialized = true; initialized = true;
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
@ -37,6 +37,7 @@ void lovrHeadsetInit(HeadsetDriver* drivers, int count, float offset, int msaa)
} }
lovrAssert(lovrHeadsetDriver, "No headset driver available, check t.headset.drivers in conf.lua"); lovrAssert(lovrHeadsetDriver, "No headset driver available, check t.headset.drivers in conf.lua");
return true;
} }
void lovrHeadsetDestroy() { void lovrHeadsetDestroy() {

View File

@ -110,5 +110,5 @@ extern HeadsetInterface lovrHeadsetOculusMobileDriver;
// Active driver // Active driver
extern HeadsetInterface* lovrHeadsetDriver; extern HeadsetInterface* lovrHeadsetDriver;
void lovrHeadsetInit(HeadsetDriver* drivers, int count, float offset, int msaa); bool lovrHeadsetInit(HeadsetDriver* drivers, int count, float offset, int msaa);
void lovrHeadsetDestroy(); void lovrHeadsetDestroy();

View File

@ -7,12 +7,12 @@
static MathState state; static MathState state;
void lovrMathInit() { bool lovrMathInit() {
if (state.initialized) return; if (state.initialized) return false;
state.generator = lovrRandomGeneratorCreate(); state.generator = lovrRandomGeneratorCreate();
Seed seed = { .b64 = (uint64_t) time(0) }; Seed seed = { .b64 = (uint64_t) time(0) };
lovrRandomGeneratorSetSeed(state.generator, seed); lovrRandomGeneratorSetSeed(state.generator, seed);
state.initialized = true; return state.initialized = true;
} }
void lovrMathDestroy() { void lovrMathDestroy() {

View File

@ -9,7 +9,7 @@ typedef struct {
RandomGenerator* generator; RandomGenerator* generator;
} MathState; } MathState;
void lovrMathInit(); bool lovrMathInit();
void lovrMathDestroy(); void lovrMathDestroy();
RandomGenerator* lovrMathGetRandomGenerator(); RandomGenerator* lovrMathGetRandomGenerator();
void lovrMathOrientationToDirection(float angle, float ax, float ay, float az, vec3 v); void lovrMathOrientationToDirection(float angle, float ax, float ay, float az, vec3 v);

View File

@ -31,10 +31,10 @@ static void raycastCallback(void* data, dGeomID a, dGeomID b) {
static bool initialized = false; static bool initialized = false;
void lovrPhysicsInit() { bool lovrPhysicsInit() {
if (initialized) return; if (initialized) return false;
dInitODE(); dInitODE();
initialized = true; return initialized = true;
} }
void lovrPhysicsDestroy() { void lovrPhysicsDestroy() {

View File

@ -85,7 +85,7 @@ typedef struct {
void* userdata; void* userdata;
} RaycastData; } RaycastData;
void lovrPhysicsInit(); bool lovrPhysicsInit();
void lovrPhysicsDestroy(); void lovrPhysicsDestroy();
World* lovrWorldCreate(float xg, float yg, float zg, bool allowSleep, const char** tags, int tagCount); World* lovrWorldCreate(float xg, float yg, float zg, bool allowSleep, const char** tags, int tagCount);

View File

@ -4,10 +4,10 @@
static ThreadState state; static ThreadState state;
void lovrThreadInit() { bool lovrThreadInit() {
if (state.initialized) return; if (state.initialized) return false;
map_init(&state.channels); map_init(&state.channels);
state.initialized = true; return state.initialized = true;
} }
void lovrThreadDeinit() { void lovrThreadDeinit() {

View File

@ -22,7 +22,7 @@ typedef struct {
bool running; bool running;
} Thread; } Thread;
void lovrThreadInit(); bool lovrThreadInit();
void lovrThreadDeinit(); void lovrThreadDeinit();
struct Channel* lovrThreadGetChannel(const char* name); struct Channel* lovrThreadGetChannel(const char* name);

View File

@ -4,10 +4,10 @@
static TimerState state; static TimerState state;
void lovrTimerInit() { bool lovrTimerInit() {
if (state.initialized) return; if (state.initialized) return false;
lovrTimerDestroy(); lovrTimerDestroy();
state.initialized = true; return state.initialized = true;
} }
void lovrTimerDestroy() { void lovrTimerDestroy() {

View File

@ -16,7 +16,7 @@ typedef struct {
int fps; int fps;
} TimerState; } TimerState;
void lovrTimerInit(); bool lovrTimerInit();
void lovrTimerDestroy(); void lovrTimerDestroy();
double lovrTimerGetDelta(); double lovrTimerGetDelta();
double lovrTimerGetTime(); double lovrTimerGetTime();