Review at  https://gerrit.osmocom.org/4772

WIP: First invocation of a primitive and callback into lua..

local timer = osmo.timeout(5, function()
        print("After timeout!!!")
end)
print("Timer", timer, type(timer))

<0011> @foo.lua:18 Timer<0011> @foo.lua:18      userdata
Connection to layer 1 failed!
Using configuration from ../../../doc/examples/mobile/default.cfg
VTY available on 127.0.0.1 4247
<0011> @foo.lua:16 After timeout!!!

Change-Id: I55603f71a1d2426622e3b601d2686903cb74a8e1
---
M src/host/layer23/include/osmocom/bb/mobile/primitives.h
M src/host/layer23/src/mobile/primitives.c
M src/host/layer23/src/mobile/script_lua.c
3 files changed, 138 insertions(+), 2 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/osmocom-bb refs/changes/72/4772/1

diff --git a/src/host/layer23/include/osmocom/bb/mobile/primitives.h 
b/src/host/layer23/include/osmocom/bb/mobile/primitives.h
index 0ba0cac..c5bceb5 100644
--- a/src/host/layer23/include/osmocom/bb/mobile/primitives.h
+++ b/src/host/layer23/include/osmocom/bb/mobile/primitives.h
@@ -16,6 +16,9 @@
 struct mobile_prim_intf {
        struct osmocom_ms *ms;
        void (*indication)(struct mobile_prim_intf *, struct osmo_prim_hdr 
*hdr);
+
+       /* Internal state */
+       struct llist_head timers;
 };
 
 /**
@@ -31,3 +34,4 @@
 
 struct mobile_prim_intf *mobile_prim_intf_alloc(struct osmocom_ms *ms);
 int mobile_prim_intf_req(struct mobile_prim_intf *intf, struct osmo_prim_hdr 
*hdr);
+void mobile_prim_intf_free(struct mobile_prim_intf *intf);
diff --git a/src/host/layer23/src/mobile/primitives.c 
b/src/host/layer23/src/mobile/primitives.c
index bdfbabb..71e4b63 100644
--- a/src/host/layer23/src/mobile/primitives.c
+++ b/src/host/layer23/src/mobile/primitives.c
@@ -25,6 +25,7 @@
 #include <osmocom/core/talloc.h>
 
 struct timer_closure {
+       struct llist_head entry;
        struct mobile_prim_intf *intf;
        struct osmo_timer_list timer;
        uint64_t id;
@@ -36,7 +37,21 @@
 
        intf = talloc_zero(ms, struct mobile_prim_intf);
        intf->ms = ms;
+
+       INIT_LLIST_HEAD(&intf->timers);
        return intf;
+}
+
+void mobile_prim_intf_free(struct mobile_prim_intf *intf)
+{
+       struct timer_closure *timer, *tmp;
+
+       llist_for_each_entry_safe(timer, tmp, &intf->timers, entry) {
+               osmo_timer_del(&timer->timer);
+               llist_del(&timer->entry);
+               talloc_free(timer);
+       }
+       talloc_free(intf);
 }
 
 static void timer_expired_cb(void *_closure)
@@ -47,6 +62,7 @@
 
        intf = closure->intf;
        prim.timer_id = closure->id;
+       llist_del(&closure->entry);
        talloc_free(closure);
 
        osmo_prim_init(&prim.hdr, 0, PRIM_MOB_TIMER, PRIM_OP_INDICATION, NULL);
@@ -64,6 +80,7 @@
        closure->id = prim->timer_id;
        closure->timer.cb = timer_expired_cb;
        closure->timer.data = closure;
+       llist_add_tail(&closure->entry, &intf->timers);
        osmo_timer_schedule(&closure->timer, prim->seconds, 0);
        return 0;
 }
diff --git a/src/host/layer23/src/mobile/script_lua.c 
b/src/host/layer23/src/mobile/script_lua.c
index 1cf9050..5e9859e 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,77 @@
        { NULL, NULL },
 };
 
+static void handle_timeout(struct mobile_prim_intf *intf, struct 
mobile_timer_prim *prim)
+{
+       struct timer_userdata *timer = (void *)(intptr_t) prim->timer_id;
+       lua_State *L = intf->ms->lua_state;
+
+       lua_rawgeti(L, LUA_REGISTRYINDEX, timer->cb_ref);
+       luaL_unref(L, LUA_REGISTRYINDEX, timer->cb_ref);
+       lua_pcall(L, 0, 0, 0);
+}
+
+static int lua_osmo_timeout(lua_State *L)
+{
+       struct mobile_timer_prim prim = { 0, };
+       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... */
+       osmo_prim_init(&prim.hdr, 0, PRIM_MOB_TIMER, PRIM_OP_REQUEST, NULL);
+       prim.timer_id = (intptr_t) timer;
+       prim.seconds = lua_tonumber(L, -3);
+       mobile_prim_intf_req(get_primitive(L), &prim.hdr);
+
+       return 1;
+}
+
+static int lua_timer_gc(lua_State *L)
+{
+       printf("GC...\n");
+       return 0;
+}
+
+static const struct luaL_Reg timer_funcs[] = {
+       { "__gc", lua_timer_gc },
+       { 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 osmo_prim_hdr 
*hdr)
+{
+       switch (OSMO_PRIM_HDR(hdr)) {
+       case OSMO_PRIM(PRIM_MOB_TIMER, PRIM_OP_INDICATION):
+               return handle_timeout(intf, (struct mobile_timer_prim *)hdr);
+               break;
+       default:
+               LOGP(DLUA, LOGL_ERROR, "Unknown primitive: %d\n", 
OSMO_PRIM_HDR(hdr));
+       };
+}
+
 /*
  *  Add functions to the global lua scope. Technically these are
  *  included in the _G table. The following lua code can be used
@@ -89,9 +179,29 @@
        lua_pop(state, 1);
 }
 
-static void add_runtime(lua_State *state, struct osmocom_ms *ms)
+static void add_runtime(lua_State *state, struct mobile_prim_intf *intf)
 {
        add_globals(state);
+
+       /* Add a osmo module/table. Seems an oldschool module? */
+       lua_newtable(state);
+       luaL_setfuncs(state, osmo_funcs, 0);
+       lua_setglobal(state, "osmo");
+
+       /* Create metatables so we can GC objects... */
+       luaL_newmetatable(state, "Timer");
+       lua_pushliteral(state, "__index");
+       lua_pushvalue(state, -2);
+       lua_rawset(state, -3);
+       luaL_setfuncs(state, timer_funcs, 0);
+       lua_pop(state, 1);
+
+
+       /* Remember the primitive pointer... store it in the registry */
+       lua_pushlightuserdata(state, lua_prim_key);
+       lua_pushlightuserdata(state, intf);
+       lua_settable(state, LUA_REGISTRYINDEX);
+
 }
 
 static void *talloc_lua_alloc(void *ctx, void *ptr, size_t osize, size_t nsize)
@@ -115,6 +225,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 +235,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 +248,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/4772
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I55603f71a1d2426622e3b601d2686903cb74a8e1
Gerrit-PatchSet: 1
Gerrit-Project: osmocom-bb
Gerrit-Branch: master
Gerrit-Owner: Holger Freyther <[email protected]>

Reply via email to