From 628174c992a5a740feb4dc119adf8dfb1f89f992 Mon Sep 17 00:00:00 2001 From: Josh Rahm Date: Thu, 1 Jan 2026 18:04:40 -0700 Subject: Have Meson orchestrate the whole build rather than stack. As a part of this, I changed the file layout to: rt/ - the Montis runtime plug/ - the Montis plugin wlroots/ - wlroots --- rt/src/plugin.c | 266 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100644 rt/src/plugin.c (limited to 'rt/src/plugin.c') diff --git a/rt/src/plugin.c b/rt/src/plugin.c new file mode 100644 index 0000000..37a6dd3 --- /dev/null +++ b/rt/src/plugin.c @@ -0,0 +1,266 @@ +#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); +} -- cgit