[MERGED] osmocom-bb[master]: mobile: Add osmo.timeout for lua code to have timeouts

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

Holger Freyther gerrit-no-reply at lists.osmocom.org
Sun Dec 3 18:09:44 UTC 2017


Holger Freyther has submitted this change and it was merged.

Change subject: mobile: Add osmo.timeout for lua code to have timeouts
......................................................................


mobile: Add osmo.timeout for lua code to have timeouts

Allow to callback into lua code after a user configured timeout. Make
it only work on seconds (truncate double to int).

Change-Id: I355d2f8d15aeaa13abb1c5e4a8e0c958e5faf7f3
---
M src/host/layer23/src/mobile/script_lua.c
1 file changed, 134 insertions(+), 2 deletions(-)

Approvals:
  Harald Welte: Looks good to me, approved
  Jenkins Builder: Verified



diff --git a/src/host/layer23/src/mobile/script_lua.c b/src/host/layer23/src/mobile/script_lua.c
index b3b9c99..cd7e8bc 100644
--- a/src/host/layer23/src/mobile/script_lua.c
+++ b/src/host/layer23/src/mobile/script_lua.c
@@ -25,7 +25,26 @@
 #include <osmocom/bb/common/osmocom_data.h>
 #include <osmocom/bb/common/logging.h>
 
+#include <osmocom/bb/mobile/primitives.h>
+
 #include <osmocom/vty/misc.h>
+
+struct timer_userdata {
+	int cb_ref;
+};
+
+static char lua_prim_key[] = "osmocom.org-mobile-prim";
+
+static struct mobile_prim_intf *get_primitive(lua_State *L)
+{
+	struct mobile_prim_intf *intf;
+
+	lua_pushlightuserdata(L, lua_prim_key);
+	lua_gettable(L, LUA_REGISTRYINDEX);
+	intf = (void *) lua_topointer(L, -1);
+	lua_pop(L, 1);
+	return intf;
+}
 
 static int lua_osmo_do_log(lua_State *L, int loglevel)
 {
@@ -75,6 +94,94 @@
 	{ NULL, NULL },
 };
 
+static void handle_timeout(struct mobile_prim_intf *intf, struct mobile_timer_param *param)
+{
+	struct timer_userdata *timer = (void *)(intptr_t) param->timer_id;
+	lua_State *L = intf->ms->lua_state;
+	int err;
+
+	lua_rawgeti(L, LUA_REGISTRYINDEX, timer->cb_ref);
+	luaL_unref(L, LUA_REGISTRYINDEX, timer->cb_ref);
+
+	err = lua_pcall(L, 0, 0, 0);
+	if (err) {
+		LOGP(DLUA, LOGL_ERROR, "lua error: %s\n", lua_tostring(L, -1));
+		lua_pop(L, 1);
+	}
+}
+
+static int lua_osmo_timeout(lua_State *L)
+{
+	struct mobile_prim *prim;
+	struct timer_userdata *timer;
+
+	if(lua_gettop(L) != 2) {
+		lua_pushliteral(L, "Need two arguments");
+		lua_error(L);
+		return 0;
+	}
+
+	luaL_argcheck(L, lua_isnumber(L, -2), 1, "Timeout needs to be a number");
+	luaL_argcheck(L, lua_isfunction(L, -1), 2, "Callback needs to be a function");
+
+	/*
+	 * Create a handle to prevent the function to be GCed while we run the
+	 * timer. Add a metatable to the object so itself will be GCed properly.
+	 */
+	timer = lua_newuserdata(L, sizeof(*timer));
+	luaL_getmetatable(L, "Timer");
+	lua_setmetatable(L, -2);
+
+	lua_pushvalue(L, -2);
+	timer->cb_ref = luaL_ref(L, LUA_REGISTRYINDEX);
+
+	/* Take the address of the user data... */
+	prim = mobile_prim_alloc(PRIM_MOB_TIMER, PRIM_OP_REQUEST);
+	prim->u.timer.timer_id = (intptr_t) timer;
+	prim->u.timer.seconds = lua_tonumber(L, -3);
+	mobile_prim_intf_req(get_primitive(L), prim);
+
+	return 1;
+}
+
+static int lua_timer_cancel(lua_State *L)
+{
+	struct mobile_prim *prim;
+	struct timer_userdata *timer;
+
+	luaL_argcheck(L, lua_isuserdata(L, -1), 1, "No userdata");
+	timer = lua_touserdata(L, -1);
+
+	prim = mobile_prim_alloc(PRIM_MOB_TIMER_CANCEL, PRIM_OP_REQUEST);
+	prim->u.timer.timer_id = (intptr_t) timer;
+	mobile_prim_intf_req(get_primitive(L), prim);
+	return 0;
+}
+
+static const struct luaL_Reg timer_funcs[] = {
+	{ "cancel", lua_timer_cancel },
+	{ "__gc", lua_timer_cancel },
+	{ NULL, NULL },
+};
+
+static const struct luaL_Reg osmo_funcs[] = {
+	{ "timeout",	lua_osmo_timeout },
+	{ NULL, NULL },
+};
+
+static void lua_prim_ind(struct mobile_prim_intf *intf, struct mobile_prim *prim)
+{
+	switch (OSMO_PRIM_HDR(&prim->hdr)) {
+	case OSMO_PRIM(PRIM_MOB_TIMER, PRIM_OP_INDICATION):
+		handle_timeout(intf, (struct mobile_timer_param *) &prim->u.timer);
+		break;
+	default:
+		LOGP(DLUA, LOGL_ERROR, "Unknown primitive: %d\n", OSMO_PRIM_HDR(&prim->hdr));
+	};
+
+	msgb_free(prim->hdr.msg);
+}
+
 /*
  *  Add functions to the global lua scope. Technically these are
  *  included in the _G table. The following lua code can be used
@@ -89,9 +196,29 @@
 	lua_pop(L, 1);
 }
 
-static void add_runtime(lua_State *L, struct osmocom_ms *ms)
+static void add_runtime(lua_State *L, struct mobile_prim_intf *intf)
 {
 	add_globals(L);
+
+	/* Add a osmo module/table. Seems an oldschool module? */
+	lua_newtable(L);
+	luaL_setfuncs(L, osmo_funcs, 0);
+	lua_setglobal(L, "osmo");
+
+	/* Create metatables so we can GC objects... */
+	luaL_newmetatable(L, "Timer");
+	lua_pushliteral(L, "__index");
+	lua_pushvalue(L, -2);
+	lua_rawset(L, -3);
+	luaL_setfuncs(L, timer_funcs, 0);
+	lua_pop(L, 1);
+
+
+	/* Remember the primitive pointer... store it in the registry */
+	lua_pushlightuserdata(L, lua_prim_key);
+	lua_pushlightuserdata(L, intf);
+	lua_settable(L, LUA_REGISTRYINDEX);
+
 }
 
 static void *talloc_lua_alloc(void *ctx, void *ptr, size_t osize, size_t nsize)
@@ -115,6 +242,7 @@
 
 int script_lua_load(struct vty *vty, struct osmocom_ms *ms, const char *filename)
 {
+	struct mobile_prim_intf *intf;
 	int err;
 
 	if (ms->lua_state)
@@ -124,6 +252,11 @@
 		return -1;
 
 	luaL_openlibs(ms->lua_state);
+
+	intf = mobile_prim_intf_alloc(ms);
+	intf->indication = lua_prim_ind;
+	add_runtime(ms->lua_state, intf);
+
 	err = luaL_loadfilex(ms->lua_state, filename, NULL);
 	if (err) {
 		vty_out(vty, "%% LUA load error: %s%s",
@@ -132,7 +265,6 @@
 		return -2;
 	}
 
-	add_runtime(ms->lua_state, ms);
 
 	err = lua_pcall(ms->lua_state, 0, 0, 0);
 	if (err) {

-- 
To view, visit https://gerrit.osmocom.org/4839
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I355d2f8d15aeaa13abb1c5e4a8e0c958e5faf7f3
Gerrit-PatchSet: 7
Gerrit-Project: osmocom-bb
Gerrit-Branch: master
Gerrit-Owner: Holger Freyther <holger at freyther.de>
Gerrit-Reviewer: Harald Welte <laforge at gnumonks.org>
Gerrit-Reviewer: Holger Freyther <holger at freyther.de>
Gerrit-Reviewer: Jenkins Builder



More information about the gerrit-log mailing list