[grilo-plugins] lua-factory: watchdog for lua-sources
- From: Bastien Nocera <hadess src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [grilo-plugins] lua-factory: watchdog for lua-sources
- Date: Mon, 21 Mar 2016 22:56:41 +0000 (UTC)
commit f2860cd6db83158c47a07d46d7b24f2218cd9d13
Author: Victor Toso <me victortoso com>
Date: Sun Mar 13 17:09:47 2016 +0100
lua-factory: watchdog for lua-sources
This commit allow us to track broken sources such as:
* sources that never call for grl.callback()
* sources that might call grl.callback() after the operation is
already finished
This is done by using a userdata in the top of the stack as a watchdog
for the current operation. We always push this userdata in
grl_lua_library_pcall function and it will be always freed by Lua's
garbage collection.
By attaching a finalize function into this userdata, we can check at
the time that lua_gc is called if the state of Operation is correct.
This idea was introduced by Morse in d809be39ed2bb so I modify those
functions to work as the watchdog we need instead of grl_l_callback
closure.
https://bugzilla.gnome.org/show_bug.cgi?id=763046
src/lua-factory/grl-lua-library-operations.c | 143 +++++++++++++++++++++++++-
src/lua-factory/grl-lua-library.c | 82 ---------------
2 files changed, 142 insertions(+), 83 deletions(-)
---
diff --git a/src/lua-factory/grl-lua-library-operations.c b/src/lua-factory/grl-lua-library-operations.c
index 961417d..47e256b 100644
--- a/src/lua-factory/grl-lua-library-operations.c
+++ b/src/lua-factory/grl-lua-library-operations.c
@@ -435,6 +435,139 @@ priv_state_operations_update (lua_State *L,
GRL_ERROR ("Ongoig operation not found (op-id: %d)", os->operation_id);
}
+/* ============== Watchdog related ========================================= */
+
+/**
+ * grl_util_operation_spec_gc
+ *
+ * This function is called when Lua GC is about to collect the userdata
+ * representing OperationSpec. Here we check that the finishing callback
+ * was done and free the memory.
+ *
+ * @L: LuaState where the data is stored.
+ * @return: 0, as the number of objects left on stack.
+ * It is important, for Lua stack to not be corrupted.
+ **/
+static int
+watchdog_operation_gc (lua_State *L)
+{
+ guint *pid = lua_touserdata (L, 1);
+ LuaSourceState state = priv_state_operations_source_get_state (L, *pid);
+ OperationSpec *os = priv_state_operations_source_get_op_data (L, *pid);
+ OperationSpec *current_os = priv_state_current_op_get_op_data (L);
+ const char *type;
+
+ GRL_DEBUG ("%s | %s (op-id: %u) current state is: %s (num-async-op: %u)", __func__,
+ grl_source_get_id (os->source),
+ os->operation_id,
+ source_op_state_str[state],
+ os->lua_source_waiting_ops);
+
+ switch (state) {
+ case LUA_SOURCE_RUNNING:
+ /* Check if waiting for async op, otherwise it is an error */
+ if (os->lua_source_waiting_ops > 0) {
+ GRL_DEBUG ("%s | %s (op-id: %u) awaiting for %u async operations", __func__,
+ grl_source_get_id (os->source),
+ os->operation_id,
+ os->lua_source_waiting_ops);
+ pid = NULL;
+ return 0;
+ }
+ break;
+
+ case LUA_SOURCE_WAITING:
+ /* Waiting for async op to finish, that's fine! */
+ pid = NULL;
+ return 0;
+ break;
+
+ case LUA_SOURCE_FINALIZED:
+ if (os->lua_source_waiting_ops > 0) {
+ GRL_WARNING ("Source '%s' is broken, as the finishing callback was called "
+ "while %u operations are still ongoing",
+ grl_source_get_id (os->source),
+ os->lua_source_waiting_ops);
+ pid = NULL;
+ return 0;
+ }
+
+ priv_state_operations_remove_source_state (L, os->operation_id);
+ if (current_os->operation_id == os->operation_id)
+ priv_state_current_op_remove (L);
+ free_operation_spec (os);
+ pid = NULL;
+ return 0;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ switch (os->op_type) {
+ case LUA_SEARCH:
+ type = "search";
+ break;
+ case LUA_BROWSE:
+ type = "browse";
+ break;
+ case LUA_QUERY:
+ type = "query";
+ break;
+ case LUA_RESOLVE:
+ type = "resolve";
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ GRL_WARNING ("Source '%s' is broken, as the finishing "
+ "callback was not called for %s operation",
+ grl_source_get_id (os->source),
+ type);
+ switch (os->op_type) {
+ case LUA_RESOLVE:
+ os->cb.resolve (os->source, os->operation_id, os->media, os->user_data, NULL);
+ break;
+
+ default:
+ os->cb.result (os->source, os->operation_id, NULL,
+ 0, os->user_data, NULL);
+ }
+
+ free_operation_spec (os);
+ pid = NULL;
+ return 0;
+}
+
+/**
+ * push_operation_spec_userdata
+ *
+ * Creates a userdata on top of the Lua stack, with the GC function
+ * assigned to it.
+ *
+ * @L: LuaState where the data is stored.
+ * @os: OperationSpec from which to create userdata.
+ * @return: Nothing.
+ **/
+static void
+watchdog_operation_push (lua_State *L, guint operation_id)
+{
+ gint *pid = lua_newuserdata (L, sizeof (guint));
+ *pid = operation_id;
+
+ /* create the metatable */
+ lua_createtable (L, 0, 1);
+ /* push the __gc key string */
+ lua_pushstring (L, "__gc");
+ /* push the __gc metamethod */
+ lua_pushcfunction (L, watchdog_operation_gc);
+ /* set the __gc field in the metatable */
+ lua_settable (L, -3);
+ /* set table as the metatable of the userdata */
+ lua_setmetatable (L, -2);
+}
+
/* =========================================================================
* Exported functions ======================================================
* ========================================================================= */
@@ -548,7 +681,14 @@ grl_lua_operations_pcall (lua_State *L,
grl_source_get_id (os->source),
os->operation_id);
- if (lua_pcall (L, nargs, 0, 0)) {
+ /* We control the GC during our function calls due the fact that we rely that
+ * watchdog's finalizer function is called after the lua_pcall, otherwise the
+ * watchdog fails to check for errors in the source and could lead to bugs */
+ lua_gc (L, LUA_GCSTOP, 0);
+
+ watchdog_operation_push (L, os->operation_id);
+ grl_lua_operations_set_source_state (L, LUA_SOURCE_RUNNING, os);
+ if (lua_pcall (L, nargs + 1, 0, 0)) {
*err = g_error_new_literal (GRL_CORE_ERROR,
os->error_code,
lua_tolstring (L, -1, NULL));
@@ -556,6 +696,7 @@ grl_lua_operations_pcall (lua_State *L,
}
lua_gc (L, LUA_GCCOLLECT, 0);
+ lua_gc (L, LUA_GCRESTART, 0);
return (*err == NULL);
}
diff --git a/src/lua-factory/grl-lua-library.c b/src/lua-factory/grl-lua-library.c
index 62401fc..b5345af 100644
--- a/src/lua-factory/grl-lua-library.c
+++ b/src/lua-factory/grl-lua-library.c
@@ -1668,88 +1668,6 @@ luaopen_grilo (lua_State *L)
/* ======= Lua-Library and Lua-Factory utilities ============= */
/**
- * grl_util_operation_spec_gc
- *
- * This function is called when Lua GC is about to collect the userdata
- * representing OperationSpec. Here we check that the finishing callback
- * was done and free the memory.
- *
- * @L: LuaState where the data is stored.
- * @return: 0, as the number of objects left on stack.
- * It is important, for Lua stack to not be corrupted.
- **/
-static int
-grl_util_operation_spec_gc (lua_State *L)
-{
- OperationSpec **userdata = lua_touserdata (L, 1);
- OperationSpec *os = *userdata;
-
- if (grl_lua_operations_get_current_op (L)) {
-
- const char *type;
- switch (os->op_type) {
- case LUA_SEARCH:
- type = "search";
- break;
- case LUA_BROWSE:
- type = "browse";
- break;
- case LUA_QUERY:
- type = "query";
- break;
- case LUA_RESOLVE:
- type = "resolve";
- break;
- default:
- g_assert_not_reached ();
- }
-
- GRL_WARNING ("Source '%s' is broken, as the finishing "
- "callback was not called for %s operation", grl_source_get_id (os->source), type);
- switch (os->op_type) {
- case LUA_RESOLVE:
- os->cb.resolve (os->source, os->operation_id, NULL, os->user_data, NULL);
- break;
-
- default:
- os->cb.result (os->source, os->operation_id, NULL,
- 0, os->user_data, NULL);
- }
- }
-
- grl_lua_operations_set_source_state (L, LUA_SOURCE_FINALIZED, os);
- *userdata = NULL;
- return 0;
-}
-/**
- * push_operation_spec_userdata
- *
- * Creates a userdata on top of the Lua stack, with the GC function
- * assigned to it.
- *
- * @L: LuaState where the data is stored.
- * @os: OperationSpec from which to create userdata.
- * @return: Nothing.
- **/
-static void
-push_operation_spec_userdata (lua_State *L, OperationSpec *os)
-{
- OperationSpec **userdata = lua_newuserdata (L, sizeof (OperationSpec *));
- *userdata = os;
-
- /* create the metatable */
- lua_createtable (L, 0, 1);
- /* push the __gc key string */
- lua_pushstring (L, "__gc");
- /* push the __gc metamethod */
- lua_pushcclosure (L, grl_util_operation_spec_gc, 0);
- /* set the __gc field in the metatable */
- lua_settable (L, -3);
- /* set table as the metatable of the userdata */
- lua_setmetatable (L, -2);
-}
-
-/**
* grl_lua_library_save_goa_data
*
* @L: LuaState where the data will be stored.
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]