#include "world.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_world_from_dl_(dlhandle_t dl, world_t *world); static void lock(world_t *world) { pthread_mutex_lock(&world->lock); }; static void unlock(world_t *world) { pthread_mutex_unlock(&world->lock); }; static int load_world_from_file_(int argc, char **argv, const char *filename, world_t *world) { 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_world_from_dl_(lib, world); if (ec) { goto end; } strncpy(world->filename, filename, sizeof(world->filename)); world->argc = argc; world->argv = argv; world->arkworld_export_load(world->argc, world->argv); end: return ec; } static void maybe_run_metaload(int argc, char **argv, world_t *world) { static char *loaded_worlds[12]; int i; for (i = 0; i < 12 && loaded_worlds[i]; ++i) { if (strcmp(loaded_worlds[i], world->world_name) == 0) { return; // World is already loaded } } loaded_worlds[i] = strdup(world->world_name); printf("First time loading %s, running metaload.\n", world->world_name); if (world->arkworld_export_metaload) { world->arkworld_export_metaload(argc, argv); } } int load_world_from_file(int argc, char **argv, const char *filename, world_t *world) { memset(world, 0, sizeof(*world)); 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(&world->lock, &attr)) { pthread_mutexattr_destroy(&attr); perror("pthread_mutexattr_init"); return 1; } pthread_mutexattr_destroy(&attr); int rc = load_world_from_file_(argc, argv, filename, world); if (rc == 0) { maybe_run_metaload(argc, argv, world); } return rc; } int world_hot_reload_same_state(world_t *world) { char filename_cpy[PATH_MAX]; strncpy(filename_cpy, world->filename, sizeof(filename_cpy)); return world_hot_reload(world->argc, world->argv, filename_cpy, world); } int world_hot_reload(int argc, char **argv, const char *filepath, world_t *world) { int ec = 0; uint32_t sz = 0; uint8_t *marshalled_state = NULL; printf("Hot Reloading %s\n", world->world_name); lock(world); printf("Marshalling state ...\n"); marshalled_state = world->arkworld_export_preserve(world->state, &sz); printf("Calling teardown ...\n"); world->arkworld_export_release(world->state); printf("State Marshalled:\n"); shx(marshalled_state, sz); printf("Unloading old library handle.\n"); if (dlclose(world->library_handle)) { printf("Could not close library handle: %s\n", dlerror()); } if ((ec = load_world_from_file_(argc, argv, filepath, world))) { goto fail; } printf("Hot starting world ...\n"); world->state = world->arkworld_export_rebirth(world, marshalled_state, sz); fail: free(marshalled_state); unlock(world); return ec; } void world_run_requested_actions(world_t *world) { lock(world); requested_action_t requested_actions[MAX_QUEUED_ACTIONS]; size_t n_requested_actions = world->n_requested_actions; memcpy(&requested_actions, world->requested_actions, sizeof(requested_actions)); world->n_requested_actions = 0; unlock(world); size_t i; for (i = 0; i < n_requested_actions; ++i) { requested_actions[i].action(world, requested_actions[i].str_arg); if (requested_actions[i].arg_dtor) { requested_actions[i].arg_dtor(requested_actions[i].ptr_arg); } } } void world_cold_start(world_t *world) { lock(world); world->state = world->arkworld_export_enworld(world); unlock(world); }