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);