summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
author0scar <qgt268@alumni.ku.dk>2023-07-28 14:32:58 +0000
committer0scar <qgt268@alumni.ku.dk>2023-07-28 18:26:17 +0000
commit4cb29fbc2d20f20e9d605796b137b4b70363113a (patch)
tree9b5929ff4d16a7a2472bafac48196e5ddfabc7dd /src
parent5ee7f4b4b033de403f1861eedc942c7a5a0f31b6 (diff)
Implement hotloading
* This commit implements dltools.{c,h}: _A simple wrapper around libdl / dlfcn.h_ * Reload states when done initializing engine, if hotloading is enabled. * Adds general function types for state functions.
Diffstat (limited to 'src')
-rw-r--r--src/dltools.c62
-rw-r--r--src/engine.c13
-rw-r--r--src/state.c66
3 files changed, 134 insertions, 7 deletions
diff --git a/src/dltools.c b/src/dltools.c
new file mode 100644
index 0000000..de7c83b
--- /dev/null
+++ b/src/dltools.c
@@ -0,0 +1,62 @@
+#include <stdbool.h>
+#include <stdlib.h>
+
+#if defined (_WIN32) || defined (__WIN32__) || defined (WIN32)
+ /* include winapi */
+#else
+#include <dlfcn.h>
+#endif
+
+#include <engine/logging.h>
+#include <engine/dltools.h>
+
+bool
+dynamic_library_close(void* shared_library) {
+#if defined (_WIN32) || defined (__WIN32__) || defined (WIN32)
+ return true;
+#else
+ return dlclose(shared_library) == 0;
+#endif
+}
+
+void*
+dynamic_library_open(const char *library_path) {
+#if defined (_WIN32) || defined (__WIN32__) || defined (WIN32)
+ return NULL;
+#else
+ return dlopen(library_path, RTLD_NOW);
+#endif
+}
+
+char* dynamic_library_get_error(void) {
+#if defined (_WIN32) || defined (__WIN32__) || defined (WIN32)
+ return "unsupported on windows";
+#else
+ return dlerror();
+#endif
+}
+
+void*
+dynamic_library_reload(void* shared_library, const char *library_path) {
+ void* library_address = NULL;
+ if (!dynamic_library_close(shared_library)) {
+ ERROR("Failed to close shared library: %s", dynamic_library_get_error());
+ ERROR("Reloading dynamic library failed.");
+ return library_address;
+ }
+ if ((library_address = dynamic_library_open(library_path)) == NULL) {
+ ERROR("Failed to open shared library: %s", dynamic_library_get_error());
+ ERROR("Reloading dynamic library %s failed.", library_path);
+ }
+ return library_address;
+}
+
+
+void*
+dynamic_library_get_symbol(void *restrict shared_library, const char *symbol) {
+#if defined (_WIN32) || defined (__WIN32__) || defined (WIN32)
+ return NULL;
+#else
+ return dlsym(shared_library, symbol);
+#endif
+}
diff --git a/src/engine.c b/src/engine.c
index fa528c0..36eb349 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -379,6 +379,19 @@ Platform *engine_init(
GLOBAL_PLATFORM = p;
+
+#ifdef DAW_BUILD_HOTRELOAD
+
+#define State(name) \
+if (!State_reload(STATE_##name)) { \
+ ERROR("Failed to reload shared object file for state %s", #name ); \
+};
+
+#include <states/list_of_states.h>
+#undef State
+
+#endif
+
return p;
}
diff --git a/src/state.c b/src/state.c
index 853037f..1d59ad7 100644
--- a/src/state.c
+++ b/src/state.c
@@ -1,5 +1,6 @@
#include <engine/state.h>
#include <engine/logging.h>
+#include <engine/dltools.h>
typedef StateType state_update_t(void*);
@@ -17,18 +18,22 @@ typedef struct name##_state name##_state; \
typedef void (state_##name##_init_t)(name##_state*); \
typedef void (state_##name##_free_t)(name##_state*); \
typedef StateType (state_##name##_update_t)(name##_state*);
-#include <states/all_states.h>
+#include <states/list_of_states.h>
#undef State
#ifdef DAW_BUILD_HOTRELOAD
+
// When hotreloading is enabled, we want to assign state function pointers
// dynamically.
-#define State(name) \
-state_##name##_init_t *name##_init = NULL; \
-state_##name##_free_t *name##_free = NULL; \
-state_##name##_update_t *name##_update = NULL;
-
+#define State(name) \
+state_##name##_init_t *name##_init = NULL; \
+state_##name##_free_t *name##_free = NULL; \
+state_##name##_update_t *name##_update = NULL; \
+ \
+void* libstate_##name = NULL; \
+const char* libstate_##name##_str = "lib" #name ".so";
#else
+
// Otherwise we just declare them.
#define State(name) \
state_##name##_init_t name##_init; \
@@ -36,9 +41,11 @@ state_##name##_free_t name##_free; \
state_##name##_update_t name##_update;
#endif
-#include <states/all_states.h>
+#include <states/list_of_states.h>
#undef State
+#include <states/all_states.h>
+
void State_init(StateType type, memory *mem) {
switch (type) {
#define State(name) \
@@ -80,11 +87,19 @@ void State_free(StateType type, memory *mem) {
StateType (*State_updateFunc(StateType type))(void*) {
switch (type) {
+#ifdef DAW_BUILD_HOTRELOAD
+#define State(name) \
+ case (STATE_##name): { \
+ return (state_update_t*)name##_update; \
+ break; \
+ }
+#else
#define State(name) \
case (STATE_##name): { \
return (state_update_t*)&name##_update; \
break; \
}
+#endif
#include <states/list_of_states.h>
#undef State
case STATE_null:
@@ -116,3 +131,40 @@ StateType State_update(StateType type, memory *mem) {
}
return next_state;
}
+
+bool State_reload(StateType type) {
+#ifdef DAW_BUILD_HOTRELOAD
+ switch (type) {
+#define State(name) \
+ case (STATE_##name): { \
+ if (libstate_##name == NULL) { \
+ libstate_##name = dynamic_library_open(libstate_##name##_str); \
+ } else { \
+ libstate_##name = \
+ dynamic_library_reload(libstate_##name, libstate_##name##_str); \
+ } \
+ if (libstate_##name == NULL) { \
+ ERROR("Failed loading shared object: %s (%s)", \
+ libstate_##name##_str, \
+ dynamic_library_get_error()); \
+ return false; \
+ } \
+ \
+ name##_init = (state_##name##_init_t*)dynamic_library_get_symbol(libstate_##name, STR( name##_init ) ); \
+ name##_free = (state_##name##_free_t*)dynamic_library_get_symbol(libstate_##name, STR( name##_free ) ); \
+ name##_update = (state_##name##_update_t*)dynamic_library_get_symbol(libstate_##name, STR( name##_update ) ); \
+ break; \
+ }
+#include <states/list_of_states.h>
+#undef State
+ case STATE_null:
+ case STATE_quit:
+ ERROR("Invalid state");
+ DEBUG("Got %s state.\n", StateTypeStr[type]);
+ break;
+ default:
+ exit(EXIT_FAILURE);
+ }
+#endif
+ return true;
+}