X Tutup
/* $%BEGINLICENSE%$ Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $%ENDLICENSE%$ */ #include #include #include #include #include #include /* got g_stat() */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_LUA_H #include #include #include #endif #include "lua-load-factory.h" #include "lua-scope.h" #include "chassis-stats.h" static int proxy_lua_panic (lua_State *L); static void *chassis_lua_alloc(void *userdata, void *ptr, size_t osize, size_t nsize); /** * @deprecated will be removed in 1.0 * @see lua_scope_new() */ lua_scope *lua_scope_init(void) { return lua_scope_new(); } lua_scope *lua_scope_new(void) { lua_scope *sc; sc = g_new0(lua_scope, 1); #ifdef HAVE_LUA_H sc->L = lua_newstate(chassis_lua_alloc, NULL); luaL_openlibs(sc->L); lua_atpanic(sc->L, proxy_lua_panic); #endif sc->mutex = g_mutex_new(); /*remove lock*/ return sc; } void lua_scope_free(lua_scope *sc) { if (!sc) return; #ifdef HAVE_LUA_H /** * enforce that the stack is clean * * we still have items on the stack */ if (lua_gettop(sc->L) != 0) { g_critical("%s: lua-scope has %d items on the stack", G_STRLOC, lua_gettop(sc->L)); } /* FIXME: we might want to cleanup the cached-scripts in the registry */ lua_close(sc->L); #endif g_mutex_free(sc->mutex); /*remove lock*/ g_free(sc); } void lua_scope_get(lua_scope *sc, const char G_GNUC_UNUSED* pos) { /* g_warning("%s: === waiting for lua-scope", pos); */ g_mutex_lock(sc->mutex); /* g_warning("%s: +++ got lua-scope", pos); */ #ifdef HAVE_LUA_H sc->L_top = lua_gettop(sc->L); #endif return; } void lua_scope_release(lua_scope *sc, const char* pos) { #ifdef HAVE_LUA_H if (lua_gettop(sc->L) != sc->L_top) { g_critical("%s: lua-stack out of sync: is %d, should be %d", pos, lua_gettop(sc->L), sc->L_top); } #endif g_mutex_unlock(sc->mutex); /* g_warning("%s: --- released lua scope", pos); */ return; } #ifdef HAVE_LUA_H /** * load the lua script * * wraps luaL_loadfile and prints warnings when needed * * on success we leave a function on the stack, otherwise a error-msg * * @see luaL_loadfile * @returns the lua_State */ lua_State *lua_scope_load_script(lua_scope *sc, const gchar *name) { lua_State *L = sc->L; int stack_top = lua_gettop(L); /** * check if the script is in the cache already * * if it is and is fresh, duplicate it * otherwise load it and put it in the cache */ #if 1 lua_getfield(L, LUA_REGISTRYINDEX, "cachedscripts"); /* sp += 1 */ if (lua_isnil(L, -1)) { /** oops, not there yet */ lua_pop(L, 1); /* sp -= 1 */ lua_newtable(L); /* reg.cachedscripts = { } sp += 1 */ lua_setfield(L, LUA_REGISTRYINDEX, "cachedscripts"); /* sp -= 1 */ lua_getfield(L, LUA_REGISTRYINDEX, "cachedscripts"); /* sp += 1 */ } g_assert(lua_istable(L, -1)); /** the script-cache should be on the stack now */ g_assert(lua_gettop(L) == stack_top + 1); /** * reg. * cachedscripts. <- on the stack * . * mtime * func */ lua_getfield(L, -1, name); if (lua_istable(L, -1)) { struct stat st; time_t cached_mtime; off_t cached_size; /** the script cached, check that it is fresh */ if (0 != g_stat(name, &st)) { gchar *errmsg; /* stat() failed, ... not good */ lua_pop(L, 2); /* cachedscripts. + cachedscripts. */ errmsg = g_strdup_printf("%s: stat(%s) failed: %s (%d)", G_STRLOC, name, g_strerror(errno), errno); lua_pushstring(L, errmsg); g_free(errmsg); g_assert(lua_isstring(L, -1)); g_assert(lua_gettop(L) == stack_top + 1); return L; } /* get the mtime from the table */ lua_getfield(L, -1, "mtime"); g_assert(lua_isnumber(L, -1)); cached_mtime = lua_tonumber(L, -1); lua_pop(L, 1); /* get the mtime from the table */ lua_getfield(L, -1, "size"); g_assert(lua_isnumber(L, -1)); cached_size = lua_tonumber(L, -1); lua_pop(L, 1); if (st.st_mtime != cached_mtime || st.st_size != cached_size) { lua_pushnil(L); lua_setfield(L, -2, "func"); /* zap the old function on the stack */ if (0 != luaL_loadfile_factory(L, name)) { /* log a warning and leave the error-msg on the stack */ g_warning("%s: reloading '%s' failed", G_STRLOC, name); /* cleanup a bit */ lua_remove(L, -2); /* remove the cachedscripts. */ lua_remove(L, -2); /* remove cachedscripts-table */ g_assert(lua_isstring(L, -1)); g_assert(lua_gettop(L) == stack_top + 1); return L; } lua_setfield(L, -2, "func"); /* not fresh, reload */ lua_pushinteger(L, st.st_mtime); lua_setfield(L, -2, "mtime"); /* t.mtime = ... */ lua_pushinteger(L, st.st_size); lua_setfield(L, -2, "size"); /* t.size = ... */ } } else if (lua_isnil(L, -1)) { struct stat st; lua_pop(L, 1); /* remove the nil, aka not found */ /** not known yet */ lua_newtable(L); /* t = { } */ if (0 != g_stat(name, &st)) { gchar *errmsg; /* stat() failed, ... not good */ errmsg = g_strdup_printf("%s: stat(%s) failed: %s (%d)", G_STRLOC, name, g_strerror(errno), errno); lua_pop(L, 2); /* cachedscripts. + cachedscripts. */ lua_pushstring(L, errmsg); g_free(errmsg); g_assert(lua_isstring(L, -1)); g_assert(lua_gettop(L) == stack_top + 1); return L; } if (0 != luaL_loadfile_factory(L, name)) { /* leave the error-msg on the stack */ /* cleanup a bit */ lua_remove(L, -2); /* remove the t = { } */ lua_remove(L, -2); /* remove cachedscripts-table */ g_assert(lua_isstring(L, -1)); g_assert(lua_gettop(L) == stack_top + 1); return L; } lua_setfield(L, -2, "func"); lua_pushinteger(L, st.st_mtime); lua_setfield(L, -2, "mtime"); /* t.mtime = ... */ lua_pushinteger(L, st.st_size); lua_setfield(L, -2, "size"); /* t.size = ... */ lua_setfield(L, -2, name); /* reg.cachedscripts. = t */ lua_getfield(L, -1, name); } else { /* not good */ lua_pushstring(L, "stack is out of sync"); g_return_val_if_reached(L); } /* -- the cache is fresh now, get the script from it */ g_assert(lua_istable(L, -1)); lua_getfield(L, -1, "func"); g_assert(lua_isfunction(L, -1)); /* cachedscripts and are still on the stack */ #if 0 g_debug("(load) [-3] %s", lua_typename(L, lua_type(L, -3))); g_debug("(load) [-2] %s", lua_typename(L, lua_type(L, -2))); g_debug("(load) [-1] %s", lua_typename(L, lua_type(L, -1))); #endif lua_remove(L, -2); /* remove the reg.cachedscripts. */ lua_remove(L, -2); /* remove the reg.cachedscripts */ /* create a copy of the script for us: * * f = function () * return function () *
X Tutup