From e7b47e5d4b3678e384f7877fb3d4e65f5b7e7cb3 Mon Sep 17 00:00:00 2001 From: Blair Steven Date: Mon, 18 Sep 2023 15:42:25 +1200 Subject: [PATCH] Multithreaded Alfred With new lua instance locking functionality in Apteryx we can now load lua files and lua snippets from XML files into seperate lua stacks. This requires changes to the lua that is loaded - currently each lua file in the script directory will be loaded into its own lua state, and the XML files will all be loaded into a single state. --- alfred.c | 775 ++++++++++++++++++++++++++++++++++++++-------------- callbacks.c | 3 +- common.h | 5 +- 3 files changed, 578 insertions(+), 205 deletions(-) diff --git a/alfred.c b/alfred.c index 1d35fcf..fe64e64 100644 --- a/alfred.c +++ b/alfred.c @@ -45,7 +45,6 @@ bool apteryx_debug = false; struct alfred_instance_t { /* Lua state */ - lua_State *ls; /* List of watches based on path */ GList *watches; /* List of refreshers based on path */ @@ -61,9 +60,13 @@ typedef struct alfred_instance_t *alfred_instance; /* The one and only instance */ alfred_instance alfred_inst = NULL; -static int alfred_apteryx_fd = -1; +GHashTable *lua_instances = NULL; int luaopen_apteryx (lua_State *L); +int lua_apteryx_close (lua_State *L); +bool lua_apteryx_instance_lock (lua_State *L); +void lua_apteryx_instance_unlock (lua_State *L); +static lua_State *alfred_new_instance(const char *key); static void alfred_error (lua_State *ls, int res) @@ -173,16 +176,21 @@ watch_node_changed (const char *path, const char *value) scripts = (GList *) (long) cb->cb; for (script = g_list_first (scripts); script != NULL; script = g_list_next (script)) { - lua_pushstring (alfred_inst->ls, path); - lua_setglobal (alfred_inst->ls, "_path"); - lua_pushstring (alfred_inst->ls, value); - lua_setglobal (alfred_inst->ls, "_value"); - ret = alfred_exec (alfred_inst->ls, script->data, 0); + if (lua_apteryx_instance_lock (cb->instance)) + { + lua_pushstring (cb->instance, path); + lua_setglobal (cb->instance, "_path"); + lua_pushstring (cb->instance, value); + lua_setglobal (cb->instance, "_value"); + ret = alfred_exec (cb->instance, script->data, 0); + lua_gc (cb->instance, LUA_GCCOUNT, 0); + DEBUG ("LUA: Stack:%d Memory:%dkb\n", lua_gettop (cb->instance), + lua_gc (cb->instance, LUA_GCCOUNT, 0)); + lua_apteryx_instance_unlock (cb->instance); + } } } g_list_free_full (matches, (GDestroyNotify) cb_release); - DEBUG("LUA: Stack:%d Memory:%dkb\n", lua_gettop (alfred_inst->ls), - lua_gc (alfred_inst->ls, LUA_GCCOUNT, 0)); DEBUG ("ALFRED WATCH: %s = %s\n", path, value); return ret; } @@ -190,7 +198,7 @@ watch_node_changed (const char *path, const char *value) uint64_t refresh_node_changed (const char *path) { - uint64_t timeout; + uint64_t timeout = 0; GList *matches = NULL; char *script = NULL; cb_info_t *cb = NULL; @@ -205,24 +213,29 @@ refresh_node_changed (const char *path) cb = g_list_first (matches)->data; script = (char *) (long) cb->cb; - lua_pushstring (alfred_inst->ls, path); - lua_setglobal (alfred_inst->ls, "_path"); - s_0 = lua_gettop (alfred_inst->ls); - if (!alfred_exec (alfred_inst->ls, script, 1)) - { - ERROR ("Lua: Failed to execute refresh script for path: %s\n", path); - } - g_list_free_full (matches, (GDestroyNotify) cb_release); - /* The return value of luaL_dostring is the top value of the stack */ - timeout = lua_tonumber (alfred_inst->ls, -1); - lua_pop (alfred_inst->ls, 1); - DEBUG("LUA: Stack:%d Memory:%dkb\n", lua_gettop (alfred_inst->ls), - lua_gc (alfred_inst->ls, LUA_GCCOUNT, 0)); - if (lua_gettop (alfred_inst->ls) != s_0) + if(lua_apteryx_instance_lock (cb->instance)) { - ERROR ("Lua: Stack not zero(%d) after provide: %s\n", - lua_gettop (alfred_inst->ls), path); + lua_pushstring (cb->instance, path); + lua_setglobal (cb->instance, "_path"); + s_0 = lua_gettop (cb->instance); + if (!alfred_exec (cb->instance, script, 1)) + { + ERROR ("Lua: Failed to execute refresh script for path: %s\n", path); + } + g_list_free_full (matches, (GDestroyNotify) cb_release); + /* The return value of luaL_dostring is the top value of the stack */ + timeout = lua_tonumber (cb->instance, -1); + lua_pop (cb->instance, 1); + + DEBUG ("LUA: Stack:%d Memory:%dkb\n", lua_gettop (cb->instance), + lua_gc (cb->instance, LUA_GCCOUNT, 0)); + if (lua_gettop (cb->instance) != s_0) + { + ERROR ("Lua: Stack not zero(%d) after provide: %s\n", + lua_gettop (cb->instance), path); + } + lua_apteryx_instance_unlock (cb->instance); } return timeout; } @@ -246,24 +259,29 @@ provide_node_changed (const char *path) cb = g_list_first (matches)->data; script = (char *) (long) cb->cb; - lua_pushstring (alfred_inst->ls, path); - lua_setglobal (alfred_inst->ls, "_path"); - s_0 = lua_gettop (alfred_inst->ls); - if (!alfred_exec (alfred_inst->ls, script, 1)) - { - ERROR ("Lua: Failed to execute provide script for path: %s\n", path); - } - g_list_free_full (matches, (GDestroyNotify) cb_release); - /* The return value of luaL_dostring is the top value of the stack */ - const_value = lua_tostring (alfred_inst->ls, -1); - lua_pop (alfred_inst->ls, 1); - ret = g_strdup (const_value); - DEBUG("LUA: Stack:%d Memory:%dkb\n", lua_gettop (alfred_inst->ls), - lua_gc (alfred_inst->ls, LUA_GCCOUNT, 0)); - if (lua_gettop (alfred_inst->ls) != s_0) + + if (lua_apteryx_instance_lock (cb->instance)) { - ERROR ("Lua: Stack not zero(%d) after provide: %s\n", - lua_gettop (alfred_inst->ls), path); + lua_pushstring (cb->instance, path); + lua_setglobal (cb->instance, "_path"); + s_0 = lua_gettop (cb->instance); + if (!alfred_exec (cb->instance, script, 1)) + { + ERROR ("Lua: Failed to execute provide script for path: %s\n", path); + } + g_list_free_full (matches, (GDestroyNotify) cb_release); + /* The return value of luaL_dostring is the top value of the stack */ + const_value = lua_tostring (cb->instance, -1); + lua_pop (cb->instance, 1); + ret = g_strdup (const_value); + DEBUG("LUA: Stack:%d Memory:%dkb\n", lua_gettop (cb->instance), + lua_gc (cb->instance, LUA_GCCOUNT, 0)); + if (lua_gettop (cb->instance) != s_0) + { + ERROR ("Lua: Stack not zero(%d) after provide: %s\n", + lua_gettop (cb->instance), path); + } + lua_apteryx_instance_unlock(cb->instance); } return ret; } @@ -287,37 +305,41 @@ index_node_changed (const char *path) } cb = g_list_first (matches)->data; script = (char *) (long) cb->cb; - lua_pushstring (alfred_inst->ls, path); - lua_setglobal (alfred_inst->ls, "_path"); - s_0 = lua_gettop (alfred_inst->ls); - if (!alfred_exec (alfred_inst->ls, script, 1)) + if (lua_apteryx_instance_lock (cb->instance)) { - ERROR ("Lua: Failed to execute index script for path: %s\n", path); - } - g_list_free_full (matches, (GDestroyNotify) cb_release); + lua_pushstring (cb->instance, path); + lua_setglobal (cb->instance, "_path"); + s_0 = lua_gettop (cb->instance); + if (!alfred_exec (cb->instance, script, 1)) + { + ERROR ("Lua: Failed to execute index script for path: %s\n", path); + } + g_list_free_full (matches, (GDestroyNotify) cb_release); - if (lua_gettop (alfred_inst->ls)) - { - if (lua_istable(alfred_inst->ls, -1)) + if (lua_gettop (cb->instance)) { - lua_pushnil (alfred_inst->ls); - while (lua_next(alfred_inst->ls, -2) != 0) + if (lua_istable (cb->instance, -1)) { - tmp_path = lua_tostring (alfred_inst->ls, -1); - tmp_path2 = strdup (tmp_path); - ret = g_list_append (ret, tmp_path2); - /* Removes 'value'; keeps 'key' for next iteration */ - lua_pop (alfred_inst->ls, 1); + lua_pushnil (cb->instance); + while (lua_next(cb->instance, -2) != 0) + { + tmp_path = lua_tostring (cb->instance, -1); + tmp_path2 = strdup (tmp_path); + ret = g_list_append (ret, tmp_path2); + /* Removes 'value'; keeps 'key' for next iteration */ + lua_pop (cb->instance, 1); + } + lua_pop (cb->instance, 1); } - lua_pop (alfred_inst->ls, 1); } - } - DEBUG("LUA: Stack:%d Memory:%dkb\n", lua_gettop(alfred_inst->ls), - lua_gc (alfred_inst->ls, LUA_GCCOUNT, 0)); - if (lua_gettop (alfred_inst->ls) != s_0) - { - ERROR ("Lua: Stack not zero(%d) after index: %s\n", - lua_gettop (alfred_inst->ls), path); + DEBUG("LUA: Stack:%d Memory:%dkb\n", lua_gettop(cb->instance), + lua_gc (cb->instance, LUA_GCCOUNT, 0)); + if (lua_gettop (cb->instance) != s_0) + { + ERROR ("Lua: Stack not zero(%d) after index: %s\n", + lua_gettop (cb->instance), path); + } + lua_apteryx_instance_unlock (cb->instance); } return ret; } @@ -438,7 +460,7 @@ node_is_leaf (xmlNode *node) } static bool -process_node (alfred_instance alfred, xmlNode *node, char *parent) +process_node (alfred_instance alfred, lua_State *instance, xmlNode *node, char *parent) { xmlChar *name = NULL; const char *mapping = NULL; @@ -496,13 +518,16 @@ process_node (alfred_instance alfred, xmlNode *node, char *parent) if (matches == NULL) { scripts = g_list_append (scripts, tmp_content); - cb = cb_create (&alfred->watches, "", (const char *) path, 0, + cb = cb_create (&alfred->watches, instance, "", (const char *) path, 0, (uint64_t) (long) scripts); } else { /* A watch already exists on that exact path */ cb = matches->data; + /* Watch callbacks on the same path from a different XML instance + * need to do something different here...*/ + assert (cb->instance == instance); scripts = (GList *) (long) cb->cb; scripts = g_list_append (scripts, tmp_content); g_list_free_full (matches, (GDestroyNotify) cb_release); @@ -514,7 +539,7 @@ process_node (alfred_instance alfred, xmlNode *node, char *parent) bool ret = false; content = xmlNodeGetContent (node); DEBUG ("XML: %s: %s\n", node->name, content); - ret = alfred_exec (alfred->ls, (char *) content, 0); + ret = alfred_exec (instance, (char *) content, 0); if (!ret) { res = false; @@ -538,7 +563,7 @@ process_node (alfred_instance alfred, xmlNode *node, char *parent) } if (path) { - cb = cb_create (&alfred->refreshers, "", (const char *) path, 0, + cb = cb_create (&alfred->refreshers, instance, "", (const char *) path, 0, (uint64_t) (long) tmp_content); } } @@ -559,7 +584,7 @@ process_node (alfred_instance alfred, xmlNode *node, char *parent) } if (path) { - cb = cb_create (&alfred->provides, "", (const char *) path, 0, + cb = cb_create (&alfred->provides, instance, "", (const char *) path, 0, (uint64_t) (long) tmp_content); } } @@ -580,14 +605,14 @@ process_node (alfred_instance alfred, xmlNode *node, char *parent) } if (path) { - cb = cb_create (&alfred->indexes, "", (const char *) path, 0, + cb = cb_create (&alfred->indexes, instance, "", (const char *) path, 0, (uint64_t) (long) tmp_content); } } /* Process children */ for (xmlNode *n = node->children; n; n = n->next) { - if (!process_node (alfred, n, path)) + if (!process_node (alfred, instance, n, path)) { res = false; goto exit; @@ -689,6 +714,8 @@ load_config_files (alfred_instance alfred, const char *path) } rewinddir (dir); + lua_State *instance = alfred_new_instance ("xml-default"); + /* Load all XML files */ for (entry = readdir (dir); entry; entry = readdir (dir)) { @@ -699,7 +726,7 @@ load_config_files (alfred_instance alfred, const char *path) char *filename = g_strdup_printf ("%s%s%s", path, path[strlen (path) - 1] == '/' ? "" : "/", entry->d_name); - DEBUG ("ALFRED: Parse XML file \"%s\"\n", filename); + DEBUG ("ALFRED: Parse XML file \"%s\" into instance \"xml-default\"\n", filename); /* Parse the file */ xmlDoc *doc = xmlParseFile (filename); if (doc == NULL) @@ -709,7 +736,7 @@ load_config_files (alfred_instance alfred, const char *path) res = false; goto exit; } - res = process_node (alfred, xmlDocGetRootElement (doc), NULL); + res = process_node (alfred, instance, xmlDocGetRootElement (doc), NULL); xmlFreeDoc (doc); /* Stop processing files if there has been an error */ @@ -724,6 +751,9 @@ load_config_files (alfred_instance alfred, const char *path) } exit: + /* Set the LUA instance running... */ + lua_apteryx_instance_unlock (instance); + closedir (dir); return res; } @@ -735,6 +765,12 @@ load_script_files (alfred_instance alfred, const char *path) DIR *dir; bool res = true; + /* Mostly squashing a compiler warning - this is the default. */ + if (path == NULL) + { + path = "/usr/share/alfred"; + } + /* Find all the LUA files in this folder */ dir = opendir (path); if (dir == NULL) @@ -750,36 +786,37 @@ load_script_files (alfred_instance alfred, const char *path) const char *ext = strrchr (entry->d_name, '.'); if (ext && strcmp (".lua", ext) == 0) { - char *filename = g_strdup_printf ("%s/%s", path, entry->d_name); + char *filename = g_strdup_printf ("%s%s", path, entry->d_name); int error; + lua_State *instance = alfred_new_instance (filename); DEBUG ("ALFRED: Load Lua file \"%s\"\n", filename); /* Execute the script */ - lua_getglobal (alfred->ls, "debug"); - lua_getfield (alfred->ls, -1, "traceback"); - error = luaL_loadfile (alfred->ls, filename); + lua_getglobal (instance, "debug"); + lua_getfield (instance, -1, "traceback"); + error = luaL_loadfile (instance, filename); if (error == 0) - error = lua_pcall (alfred->ls, 0, 0, 0); + error = lua_pcall (instance, 0, 0, 0); if (error != 0) - alfred_error (alfred->ls, error); + alfred_error (instance, error); + + while (lua_gettop (instance)) + lua_pop (instance, 1); - while (lua_gettop (alfred->ls)) - lua_pop (alfred->ls, 1); + /* Set the LUA instance running... */ + lua_apteryx_instance_unlock (instance); /* Stop processing files if there has been an error */ if (error != 0) { CRITICAL ("ALFRED: Invalid file \"%s\"\n", filename); - g_free (filename); res = false; - goto exit; } g_free (filename); } } - exit: closedir (dir); return res; } @@ -789,13 +826,14 @@ struct delayed_work_s { guint id; int call; char *script; + lua_State *instance; }; static void dw_destroy (gpointer arg1) { struct delayed_work_s *dw = (struct delayed_work_s *) arg1; - luaL_unref (alfred_inst->ls, LUA_REGISTRYINDEX, dw->call); + luaL_unref (dw->instance, LUA_REGISTRYINDEX, dw->call); dw->call = LUA_NOREF; g_free (dw->script); g_free (dw); @@ -809,16 +847,24 @@ delayed_work_process (gpointer arg1) /* Remove the script to be run */ delayed_work = g_list_remove (delayed_work, dw); - if (dw->script) + if (lua_apteryx_instance_lock (dw->instance)) { - /* Execute the script */ - alfred_exec (alfred_inst->ls, dw->script, 0); + if (dw->script) + { + /* Execute the script */ + alfred_exec (dw->instance, dw->script, 0); + } + else + { + lua_rawgeti (dw->instance, LUA_REGISTRYINDEX, dw->call); + alfred_call (dw->instance, 0); + lua_pop (dw->instance, 0); + } + lua_apteryx_instance_unlock (dw->instance); } else { - lua_rawgeti (alfred_inst->ls, LUA_REGISTRYINDEX, dw->call); - alfred_call (alfred_inst->ls, 0); - lua_pop (alfred_inst->ls, 0); + DEBUG ("Delayed work executed after instance shutdown"); } return false; @@ -846,9 +892,10 @@ delayed_work_add (lua_State *ls, bool reset_timer) dw = (struct delayed_work_s *) iter->data; if (script) { - found = dw->script && strcmp (script, dw->script) == 0; + found = dw->instance == ls && dw->script && strcmp (script, dw->script) == 0; } else if (lua_isfunction (ls, 2) + && dw->instance == ls && dw->call != LUA_NOREF && dw->call != LUA_REFNIL) { size_t len; @@ -886,6 +933,7 @@ delayed_work_add (lua_State *ls, bool reset_timer) { struct delayed_work_s *dw = (struct delayed_work_s *) g_malloc0 (sizeof (struct delayed_work_s)); + dw->instance = ls; if (script) { dw->script = g_strdup (script); @@ -956,6 +1004,82 @@ after_quiet (lua_State *ls) return 0; } + +static lua_State * +alfred_new_instance (const char *key) +{ + /* Initialise the Lua state */ + lua_State *instance = luaL_newstate (); + if (!instance) + { + CRITICAL ("ALFRED: Failed to instantiate Lua interpreter\n"); + goto error; + } + + /* We may need to access this instance - this occurs during tests and + * when choosing an instance to load a XML / LUA file into. + */ + g_hash_table_insert (lua_instances, g_string_new(key), instance); + + /* Load required libraries */ + luaL_openlibs (instance); + if (luaopen_apteryx (instance)) + { + /* Provide global access to the Apteryx library */ + lua_setglobal (instance, "apteryx"); + } + + /* The Apteryx LUA code now has a lock held on this instance - no + * callbacks will be executed and the stack is protected until we + * call lua_apteryx_instance_unlock / apteryx_process. + */ + + /* Load the apteryx-xml API if available + api = require("apteryx.xml").api("/etc/apteryx/schema/") + */ + if (luaL_dostring (instance, "require('api')") != 0) + { + ERROR ("ALFRED: Failed to require('api')\n"); + } + + /* Add the rate_limit,after_quiet functions to a Lua table so it can be called using Lua */ + lua_newtable (instance); + lua_pushcfunction (instance, rate_limit); + lua_setfield (instance, -2, "rate_limit"); + lua_pushcfunction (instance, after_quiet); + lua_setfield (instance, -2, "after_quiet"); + lua_setglobal (instance, "Alfred"); +error: + return instance; +} + +static lua_State * +alfred_get_instance (const char *key) +{ + GString *needle = g_string_new (key); + lua_State *s = g_hash_table_lookup (lua_instances, needle); + g_string_free (needle, TRUE); + return s; +} + +static void +alfred_release_key (GString *key) +{ + g_string_free(key, TRUE); +} + +static void +alfred_destroy_instance(lua_State *state) +{ + /* TODO: Cancel all delayed work. + * Currently it will expire safely, but could be cancelled. + */ + lua_apteryx_instance_lock (state); + lua_apteryx_close (state); + lua_close (state); + return; +} + static void alfred_shutdown (void) { @@ -993,12 +1117,15 @@ alfred_shutdown (void) g_list_free (alfred_inst->indexes); } - if (alfred_inst->ls) - lua_close (alfred_inst->ls); - if (alfred_inst->map_hash_table) g_hash_table_destroy (alfred_inst->map_hash_table); + if (lua_instances) + { + g_hash_table_destroy (lua_instances); + lua_instances = NULL; + } + g_free (alfred_inst); alfred_inst = NULL; return; @@ -1015,43 +1142,25 @@ alfred_init (const char *config_dir, const char *script_dir) goto error; } - /* Initialise the Lua state */ - alfred_inst->ls = luaL_newstate (); - if (!alfred_inst->ls) + /* This table is used in the main thread to discover the lua instance for a given module. */ + if (lua_instances == NULL) { - CRITICAL ("ALFRED: Failed to instantiate Lua interpreter\n"); - goto error; + lua_instances = g_hash_table_new_full((GHashFunc)g_string_hash, + (GEqualFunc)g_string_equal, + (GDestroyNotify)alfred_release_key, + (GDestroyNotify)alfred_destroy_instance); } - /* Load required libraries */ - luaL_openlibs (alfred_inst->ls); - if (luaopen_apteryx (alfred_inst->ls)) - { - /* Provide global access to the Apteryx library */ - lua_setglobal (alfred_inst->ls, "apteryx"); - } - - /* Load the apteryx-xml API if available - api = require("apteryx.xml").api("/etc/apteryx/schema/") - */ - if (luaL_dostring (alfred_inst->ls, "require('api')") != 0) - { - ERROR ("ALFRED: Failed to require('api')\n"); - } - - /* Add the rate_limit,after_quiet functions to a Lua table so it can be called using Lua */ - lua_newtable (alfred_inst->ls); - lua_pushcfunction (alfred_inst->ls, rate_limit); - lua_setfield (alfred_inst->ls, -2, "rate_limit"); - lua_pushcfunction (alfred_inst->ls, after_quiet); - lua_setfield (alfred_inst->ls, -2, "after_quiet"); - lua_setglobal (alfred_inst->ls, "Alfred"); - /* Load alfred lua scripts first */ - if (script_dir && !load_script_files (alfred_inst, script_dir)) + if (script_dir == NULL) { goto error; } + else + { + /* We will load all possible scripts and log errors for those that fail. */ + load_script_files (alfred_inst, script_dir); + } /* Load schema with alfred tags second */ if (config_dir && !load_config_files (alfred_inst, config_dir)) @@ -1110,6 +1219,7 @@ test_simple_watch () " xsi:schemaLocation=\"https://github.com/alliedtelesis/apteryx\n" " https://github.com/alliedtelesis/apteryx/releases/download/v2.10/apteryx.xsd\">\n" " \n" + " \n" + " \n" + " return apteryx.get(\"/test/provided_node\")\n" + " \n" + " \n" + " test_node_change(_value)\n" + " \n" + " \n" + " refresh_node(_path)\n" + " \n" + " \n" + "\n"); + fclose (data); + } + + /* Init */ + alfred_init ("./", "./"); + g_assert (alfred_inst != NULL); + lua_State *xml_instance = alfred_get_instance ("xml-default"); + lua_State *native_instance = alfred_get_instance ("./alfred_test.lua"); + + apteryx_set ("/test/watched_node","watched_value"); + sleep (1); + + /* Check watches */ + /* XML watcher */ + lua_getglobal (xml_instance, "test_value"); + if (!lua_isnil (xml_instance, -1)) + { + test_str = strdup (lua_tostring (xml_instance, -1)); + } + lua_pop (xml_instance, 1); + g_assert (test_str && strcmp(test_str, "test_value")); + free (test_str); + test_str = NULL; + + /* LUA watcher */ + lua_getglobal (native_instance, "test_value"); + if (!lua_isnil (native_instance, -1)) + { + test_str = strdup (lua_tostring (native_instance, -1)); + } + lua_pop (native_instance, 1); + g_assert (test_str && strcmp(test_str, "test_value")); + free (test_str); + test_str = NULL; + + /* This provider requires a provide out of native module */ + test_str = apteryx_get ("/test/xml_provide"); + g_assert (test_str && strcmp ("provided value", test_str) == 0); + free (test_str); + + /* This provider requires a refresh out of native module */ + test_str = apteryx_get ("/test/xml_refreshed_node"); + g_assert (test_str && strcmp ("refreshed value", test_str) == 0); + free (test_str); + apteryx_prune ("/test"); + + /* Clean up */ + if (alfred_inst) + { + alfred_shutdown (); + } + unlink ("alfred_test.lua"); + unlink ("alfred_test.xml"); } static gboolean @@ -2165,9 +2533,9 @@ main (int argc, char *argv[]) /* Initialise Apteryx client library in single threaded mode */ apteryx_init (apteryx_debug); - alfred_apteryx_fd = apteryx_process (true); - g_io_add_watch (g_io_channel_unix_new (alfred_apteryx_fd), - G_IO_IN, process_apteryx, NULL); + // alfred_apteryx_fd = apteryx_process (true); + // g_io_add_watch (g_io_channel_unix_new (alfred_apteryx_fd), + // G_IO_IN, process_apteryx, NULL); cb_init (); @@ -2193,6 +2561,9 @@ main (int argc, char *argv[]) g_test_add_func ("/test_native_index", test_native_index); g_test_add_func ("/test_rate_limit", test_rate_limit); g_test_add_func ("/test_after_quiet", test_after_quiet); + g_test_add_func ("/test_native_memory", test_native_memory); + g_test_add_func ("/test_native_threading", test_native_threading); + g_test_add_func ("/test_intermodule_interaction", test_intermodule_interaction); loop = g_main_loop_new (NULL, true); g_unix_signal_add (SIGINT, termination_handler, loop); diff --git a/callbacks.c b/callbacks.c index be9a362..081dd18 100644 --- a/callbacks.c +++ b/callbacks.c @@ -27,11 +27,12 @@ GList *proxy_list = NULL; static pthread_mutex_t list_lock = PTHREAD_MUTEX_INITIALIZER; cb_info_t * -cb_create (GList **list, const char *guid, const char *path, +cb_create (GList **list, lua_State *instance, const char *guid, const char *path, uint64_t id, uint64_t callback) { cb_info_t *cb = (cb_info_t *) g_malloc0 (sizeof (cb_info_t)); cb->active = true; + cb->instance = instance; cb->guid = g_strdup (guid); cb->path = g_strdup (path); cb->id = id; diff --git a/common.h b/common.h index 43badf6..caa539e 100644 --- a/common.h +++ b/common.h @@ -32,6 +32,7 @@ #include #include #include +#include /* Default UNIX socket path */ #define APTERYX_SERVER "unix:///tmp/apteryx" @@ -117,7 +118,7 @@ static inline uint32_t htol32 (uint32_t v) typedef struct _cb_info_t { bool active; - + lua_State *instance; const char *guid; const char *path; const char *uri; @@ -129,7 +130,7 @@ typedef struct _cb_info_t uint32_t count; } cb_info_t; void cb_init (void); -cb_info_t * cb_create (GList **list, const char *guid, const char *path, uint64_t id, uint64_t callback); +cb_info_t * cb_create (GList **list, lua_State *instance, const char *guid, const char *path, uint64_t id, uint64_t callback); void cb_destroy (cb_info_t *cb); void cb_release (cb_info_t *cb); GList *cb_match (GList **list, const char *path, int critera);