#include "soul.h" #include #include #include #include #include #include #include #include /* Utility function for showing the marshalled states as hex code */ static void shx(uint8_t *state, uint32_t sz) { uint32_t i = 0; while (i < sz) { for (int j = 0; j < 16; ++j) { if (i < sz) { printf("%02x ", (unsigned int)state[i]); } else { printf(" "); } ++i; } i -= 16; printf(" "); for (int j = 0; j < 16; ++j) { if (i < sz) { if (isprint(state[i]) && !isspace(state[i])) { printf("%c", state[i]); } else { printf("."); } } else { printf(" "); } ++i; } printf("\n"); } } int load_soul_from_dl_(dlhandle_t dl, soul_t *soul); static void lock(soul_t *soul) { pthread_mutex_lock(&soul->lock); }; static void unlock(soul_t *soul) { pthread_mutex_unlock(&soul->lock); }; static int load_soul_from_file_(int argc, char **argv, const char *filename, soul_t *soul) { dlhandle_t lib = dlopen(filename, RTLD_NOW | RTLD_GLOBAL); int ec = 0; if (!lib) { fprintf(stderr, "Failed to open library: %s: %s\n", filename, dlerror()); ec = 1; goto end; } printf("Loading file.\n"); ec = load_soul_from_dl_(lib, soul); if (ec) { goto end; } strncpy(soul->filename, filename, sizeof(soul->filename)); soul->argc = argc; soul->argv = argv; soul->arksoul_export_load(soul->argc, soul->argv); end: return ec; } static void maybe_run_metaload(int argc, char **argv, soul_t *soul) { static char *loaded_souls[12]; int i; for (i = 0; i < 12 && loaded_souls[i]; ++i) { if (strcmp(loaded_souls[i], soul->soul_name) == 0) { return; // Soul is already loaded } } loaded_souls[i] = strdup(soul->soul_name); printf("First time loading %s, running metaload.\n", soul->soul_name); if (soul->arksoul_export_metaload) { soul->arksoul_export_metaload(argc, argv); } } int load_soul_from_file(int argc, char **argv, const char *filename, soul_t *soul) { memset(soul, 0, sizeof(*soul)); pthread_mutexattr_t attr; if (pthread_mutexattr_init(&attr)) { perror("pthread_mutexattr_init"); return 1; } if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) { perror("pthread_mutexattr_settype"); return 1; } if (pthread_mutex_init(&soul->lock, &attr)) { pthread_mutexattr_destroy(&attr); perror("pthread_mutexattr_init"); return 1; } pthread_mutexattr_destroy(&attr); int rc = load_soul_from_file_(argc, argv, filename, soul); if (rc == 0) { maybe_run_metaload(argc, argv, soul); } return rc; } int soul_hot_reload_same_state(soul_t *soul) { char filename_cpy[PATH_MAX]; strncpy(filename_cpy, soul->filename, sizeof(filename_cpy)); return soul_hot_reload(soul->argc, soul->argv, filename_cpy, soul); } int soul_hot_reload(int argc, char **argv, const char *filepath, soul_t *soul) { int ec = 0; uint32_t sz = 0; uint8_t *marshalled_state = NULL; printf("Hot Reloading %s\n", soul->soul_name); lock(soul); printf("Marshalling state ...\n"); marshalled_state = soul->arksoul_export_preserve(soul->state, &sz); printf("Calling teardown ...\n"); soul->arksoul_export_release(soul->state); printf("State Marshalled:\n"); shx(marshalled_state, sz); printf("Unloading old library handle.\n"); if (dlclose(soul->library_handle)) { printf("Could not close library handle: %s\n", dlerror()); } if ((ec = load_soul_from_file_(argc, argv, filepath, soul))) { goto fail; } printf("Hot starting soul ...\n"); soul->state = soul->arksoul_export_rebirth(soul, marshalled_state, sz); fail: free(marshalled_state); unlock(soul); return ec; } void soul_run_requested_actions(soul_t *soul) { lock(soul); requested_action_t requested_actions[MAX_QUEUED_ACTIONS]; size_t n_requested_actions = soul->n_requested_actions; memcpy(&requested_actions, soul->requested_actions, sizeof(requested_actions)); soul->n_requested_actions = 0; unlock(soul); size_t i; for (i = 0; i < n_requested_actions; ++i) { requested_actions[i].action(soul, requested_actions[i].str_arg); if (requested_actions[i].arg_dtor) { requested_actions[i].arg_dtor(requested_actions[i].ptr_arg); } } } void soul_cold_start(soul_t *soul) { lock(soul); soul->state = soul->arksoul_export_ensoul(soul); unlock(soul); }