#include "plugin.h" #include "foreign_intf.h" #include "wl.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_plugin_from_dl_(dlhandle_t dl, plugin_t *plug); static void lock(plugin_t *plugin) { pthread_mutex_lock(&plugin->lock); }; static void unlock(plugin_t *plugin) { pthread_mutex_unlock(&plugin->lock); }; static int plugin_hot_reload_same_state_action_(plugin_t *plugin, void *ignore) { return plugin_hot_reload_same_state(plugin); } void do_request_hot_reload(void *plugv) { plugin_t *plugin = plugv; size_t n = plugin->n_requested_actions++; if (n < 8) { plugin->requested_actions[n].action = plugin_hot_reload_same_state_action_; plugin->requested_actions[n].arg_dtor = NULL; } } static int plugin_do_log(plugin_t *plugin, void *chrs) { char *str = chrs; puts(str); return 0; } void do_request_log(void *plugv, const char *str) { plugin_t *plugin = plugv; size_t n = plugin->n_requested_actions++; if (n < 8) { plugin->requested_actions[n].action = plugin_do_log; plugin->requested_actions[n].str_arg = strdup(str); plugin->requested_actions[n].arg_dtor = free; } } static int plugin_do_exit(void *plugv, int ec) { exit(ec); return 0; } void do_request_exit(void *plugv, int ec) { plugin_t *plugin = plugv; size_t n = plugin->n_requested_actions++; if (n < 8) { plugin->requested_actions[n].action = (int (*)(plugin_t *, void *))plugin_do_exit; plugin->requested_actions[n].int_arg = ec; plugin->requested_actions[n].arg_dtor = NULL; } } static void* plugin_get_seat(void* ctx) { struct montis_server* server = wl_container_of(ctx, server, plugin); return server->seat; } static int load_plugin_from_file_(int argc, char **argv, const char *filename, plugin_t *plugin) { dlhandle_t lib = dlopen(filename, RTLD_LAZY); 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_plugin_from_dl_(lib, plugin); if (ec) { goto end; } strncpy(plugin->filename, filename, sizeof(plugin->filename)); plugin->argc = argc; plugin->argv = argv; plugin->foreign_intf.ctx = plugin; plugin->foreign_intf.request_hot_reload = do_request_hot_reload; plugin->foreign_intf.do_log = do_request_log; plugin->foreign_intf.request_exit = do_request_exit; plugin->foreign_intf.get_seat = plugin_get_seat; plugin->plugin_load(plugin->argc, plugin->argv, &plugin->foreign_intf); end: return ec; } static void maybe_run_metaload(int argc, char **argv, plugin_t *plugin) { static char *loaded_plugins[12]; int i; for (i = 0; i < 12 && loaded_plugins[i]; ++i) { if (strcmp(loaded_plugins[i], plugin->plugin_name) == 0) { return; // Plugin is already loaded } } loaded_plugins[i] = strdup(plugin->plugin_name); printf("First time loading %s, running metaload.\n", plugin->plugin_name); if (plugin->plugin_metaload) { plugin->plugin_metaload(argc, argv); } } int load_plugin_from_file(int argc, char **argv, const char *filename, plugin_t *plugin) { memset(plugin, 0, sizeof(*plugin)); 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(&plugin->lock, &attr)) { pthread_mutexattr_destroy(&attr); perror("pthread_mutexattr_init"); return 1; } pthread_mutexattr_destroy(&attr); int rc = load_plugin_from_file_(argc, argv, filename, plugin); if (rc == 0) { maybe_run_metaload(argc, argv, plugin); } return rc; } int plugin_hot_reload_same_state(plugin_t *plugin) { char filename_cpy[PATH_MAX]; strncpy(filename_cpy, plugin->filename, sizeof(filename_cpy)); return plugin_hot_reload(plugin->argc, plugin->argv, filename_cpy, plugin); } int plugin_hot_reload(int argc, char **argv, const char *filepath, plugin_t *plugin) { int ec = 0; uint32_t sz = 0; uint8_t *marshalled_state = NULL; printf("Hot Reloading %s\n", plugin->plugin_name); lock(plugin); printf("Marshalling state ...\n"); marshalled_state = plugin->plugin_marshal_state(plugin->state, &sz); printf("Calling teardown ...\n"); plugin->plugin_teardown(plugin->state); printf("State Marshalled:\n"); shx(marshalled_state, sz); printf("Unloading old library handle.\n"); if (dlclose(plugin->library_handle)) { printf("Could not close library handle: %s\n", dlerror()); } if ((ec = load_plugin_from_file_(argc, argv, filepath, plugin))) { goto fail; } printf("Hot starting plugin ...\n"); plugin->state = plugin->plugin_hot_start(marshalled_state, sz); fail: free(marshalled_state); unlock(plugin); return ec; } void plugin_run_requested_actions(plugin_t *plugin) { lock(plugin); requested_action_t requested_actions[MAX_QUEUED_ACTIONS]; size_t n_requested_actions = plugin->n_requested_actions; memcpy(&requested_actions, plugin->requested_actions, sizeof(requested_actions)); plugin->n_requested_actions = 0; unlock(plugin); size_t i; for (i = 0; i < n_requested_actions; ++i) { requested_actions[i].action(plugin, requested_actions[i].str_arg); if (requested_actions[i].arg_dtor) { requested_actions[i].arg_dtor(requested_actions[i].ptr_arg); } } } void plugin_cold_start(plugin_t *plugin) { lock(plugin); plugin->state = plugin->plugin_cold_start(); unlock(plugin); }