aboutsummaryrefslogtreecommitdiff
path: root/rt/src/plugin.c
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2026-01-01 18:04:40 -0700
committerJosh Rahm <joshuarahm@gmail.com>2026-01-01 18:04:40 -0700
commit628174c992a5a740feb4dc119adf8dfb1f89f992 (patch)
tree683361b27cf4b6df2c5cc782d70de9bdf5fd38a8 /rt/src/plugin.c
parentbe1ef8cee5f68eb9afecca94071069a1ff82825e (diff)
downloadmontis-628174c992a5a740feb4dc119adf8dfb1f89f992.tar.gz
montis-628174c992a5a740feb4dc119adf8dfb1f89f992.tar.bz2
montis-628174c992a5a740feb4dc119adf8dfb1f89f992.zip
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
Diffstat (limited to 'rt/src/plugin.c')
-rw-r--r--rt/src/plugin.c266
1 files changed, 266 insertions, 0 deletions
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 <sys/stat.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <dlfcn.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* 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);
+}