diff --git a/plugins/lua/lua_plugin.c b/plugins/lua/lua_plugin.c index d892498d..d52d3959 100644 --- a/plugins/lua/lua_plugin.c +++ b/plugins/lua/lua_plugin.c @@ -5,117 +5,286 @@ #include #if LUA_VERSION_NUM < 502 -# define luaL_newuwsgilib(L,l) luaL_register(L, "uwsgi",l) # define lua_rawlen lua_objlen -#else -# define luaL_newuwsgilib(L,l) lua_newtable(L);luaL_setfuncs (L, l, 0);lua_pushvalue(L,-1);lua_setglobal(L,"uwsgi") #endif extern struct uwsgi_server uwsgi; struct uwsgi_lua { struct lua_State ***state; - char *shell; - char *filename; + struct lua_State **mulestate; + uint8_t shell; + uint8_t shell_oneshot; struct uwsgi_string_list *load; + char *wsapi; + struct uwsgi_string_list *postload; int gc_freq; - int gc_full; + uint8_t gc_perform; } ulua; #define ULUA_MYWID (uwsgi.mywid-1) +#define ULUA_MYMID (uwsgi.muleid-1) #define ULUA_WORKER_STATE ulua.state[ULUA_MYWID] +#define ULUA_MULE_STATE ulua.mulestate[ULUA_MYMID] +#define ULUA_LOG_HEADER "[uwsgi-lua]" + +#define ULUA_MULE_MSG_GET_BUFFER_SIZE 65536 + +#define ULUA_MULE_MSG_REF 1 + +#define ULUA_WSAPI_REF 1 +#define ULUA_SIGNAL_REF 2 +#define ULUA_RPC_REF 3 +#define ULUA_THREAD_REF 4 + +#define ULUA_OPTDEF_GC_FREQ 1 + +#define ulua_log(c, ar...) uwsgi_log(ULUA_LOG_HEADER" "c"\n", ##ar) + +#define ULUA_WORKER_ANYAPP (ulua.wsapi ||\ + ulua.load ||\ + ulua.postload ||\ + ulua.shell ||\ + ulua.shell_oneshot) struct uwsgi_plugin lua_plugin; -#define lca(L, n) ulua_check_args(L, __FUNCTION__, n) - static void uwsgi_opt_luashell(char *opt, char *value, void *foobar) { - - uwsgi.honour_stdin = 1; - if (value) { - ulua.shell = value; - } - else { - ulua.shell = ""; - } + uwsgi.honour_stdin = 1; + ulua.shell = 1; } +static void uwsgi_opt_luashell_oneshot(char *opt, char *value, void *foobar) { + // enable shell + uwsgi_opt_luashell(NULL, NULL, NULL); + ulua.shell_oneshot = 1; +} static struct uwsgi_option uwsgi_lua_options[] = { - {"lua", required_argument, 0, "load lua wsapi app", uwsgi_opt_set_str, &ulua.filename, 0}, - {"lua-load", required_argument, 0, "load a lua file", uwsgi_opt_add_string_list, &ulua.load, 0}, + {"lua", required_argument, 0, "load lua wsapi app", uwsgi_opt_set_str, &ulua.wsapi, 0}, + {"lua-load", required_argument, 0, "load a lua file before wsapi app", uwsgi_opt_add_string_list, &ulua.load, 0}, + {"lua-postload", required_argument, 0, "load a lua file after wsapi app", uwsgi_opt_add_string_list, &ulua.postload, 0}, {"lua-shell", no_argument, 0, "run the lua interactive shell (debug.debug())", uwsgi_opt_luashell, NULL, 0}, {"luashell", no_argument, 0, "run the lua interactive shell (debug.debug())", uwsgi_opt_luashell, NULL, 0}, - {"lua-gc-freq", no_argument, 0, "set the lua gc frequency (default: 0, runs after every request)", uwsgi_opt_set_int, &ulua.gc_freq, 0}, - {"lua-gc-full", no_argument, 0, "set the lua gc to perform a full garbage-collection cycle (default: 0, gc performs an incremental step of garbage collection)", uwsgi_opt_set_int, &ulua.gc_full, 0}, + {"lua-shell-oneshot", no_argument, 0, "run the lua interactive shell (debug.debug(), one-shot variant)", uwsgi_opt_luashell_oneshot, NULL, 0}, + {"luashell-oneshot", no_argument, 0, "run the lua interactive shell (debug.debug(), one-shot variant)", uwsgi_opt_luashell_oneshot, NULL, 0}, + {"lua-gc-freq", required_argument, 0, "set the lua gc frequency (default: 1, runs after every request)", uwsgi_opt_set_int, &ulua.gc_freq, 0}, + {"lua-gc-full", no_argument, 0, "set the lua gc to perform a full garbage-collection cycle (default: 0, gc performs an incremental step of garbage collection)", uwsgi_opt_set_int, &ulua.gc_perform, 0}, {0, 0, 0, 0}, }; -static void ulua_check_args(lua_State *L, const char *func, int n) { - int args = lua_gettop(L); - char error[1024]; - if (args != n) { - if (n == 1) { - snprintf(error, 1024, "uwsgi.%s takes 1 parameter", func+10); - } - else { - snprintf(error, 1024, "uwsgi.%s takes %d parameters", func+10, n); - } - lua_pushstring(L, error); - lua_error(L); +static int uwsgi_lua_metatable_tostring(lua_State *L, int obj) { + // replace table with __tostring result, or do nothing in case of fail + + if (!(luaL_getmetafield(L, obj, "__tostring"))) { + return 0; } + + if (!(lua_isfunction(L, -1))) { + ulua_log("__tostring is not a function"); + lua_pop(L, 1); + return 0; + } + + lua_pushvalue(L, --obj); + + if (lua_pcall(L, 1, 1, 0)) { + ulua_log("%s", lua_tostring(L, -1)); + lua_pop(L, 1); + return 0; + } + + if (lua_isstring(L, -1)) { + lua_replace(L, obj); + return 1; + } + + lua_pop(L, 1); + + return 0; } -static int uwsgi_api_log(lua_State *L) { + +static int uwsgi_lua_metatable_call(lua_State *L, int obj) { + // get __call attr and place it before table, or do nothing in case of fail + + if (!(luaL_getmetafield(L, obj, "__call"))) { + return 0; + } - const char *logline ; + if (!(lua_isfunction(L, -1))) { + ulua_log("__call is not a function"); + lua_pop(L, 1); + return 0; + } + + lua_insert(L, obj-1); + + return 1; +} - lca(L, 1); +static int uwsgi_api_metric_get(lua_State *L) { + + if (!(lua_gettop(L)) || !(lua_isstring(L, 1))) { + return 0; + } - if (lua_isstring(L, 1)) { - logline = lua_tostring(L, 1); - uwsgi_log( "%s\n", logline); + lua_pushnumber(L, uwsgi_metric_get((char *) lua_tostring(L, 1), NULL)); + + return 1; +} + +static int uwsgi_api_metric_set(lua_State *L) { + + if ((lua_gettop(L) < 2) || + !(lua_isstring(L, 1)) || + !(lua_isnumber(L, 2)) || + uwsgi_metric_set((char *) lua_tostring(L, 1), NULL, lua_tonumber(L, 2))) + { + return 0; + } + + lua_pushboolean(L, 1); + + return 1; +} + +static int uwsgi_lua_metric_do(lua_State *L, int metric_do(char*, char*, int64_t)) { + int64_t value = 1; + uint16_t argc = lua_gettop(L); + + if (!(argc) || !(lua_isstring(L, 1))) { + return 0; + } + + if (argc > 1 && lua_isnumber(L, 2)) { + value = lua_tonumber(L, 2); + } + + if (metric_do((char *) lua_tostring(L, 1), NULL, value)) { + return 0; + } + + lua_pushboolean(L, 1); + + return 1; +} + +static int uwsgi_api_metric_inc(lua_State *L) { + return uwsgi_lua_metric_do(L, uwsgi_metric_inc); +} + +static int uwsgi_api_metric_div(lua_State *L) { + return uwsgi_lua_metric_do(L, uwsgi_metric_div); +} + +static int uwsgi_api_metric_mul(lua_State *L) { + return uwsgi_lua_metric_do(L, uwsgi_metric_mul); +} + +static int uwsgi_api_metric_dec(lua_State *L) { + return uwsgi_lua_metric_do(L, uwsgi_metric_dec); +} + + +static int uwsgi_api_signal(lua_State *L) { + uint16_t argc = lua_gettop(L); + + if (argc > 0 && lua_isnumber(L, 1)) { + if (argc > 1 && lua_isstring(L, 2)) { + lua_pushnumber(L, uwsgi_remote_signal_send((char *) lua_tostring(L, -2), (uint8_t) lua_tonumber(L, 1))); + + return 1; + } else { + uwsgi_signal_send(uwsgi.signal_socket, (uint8_t) lua_tonumber(L, 1)); + } } return 0; } -static int uwsgi_api_rpc(lua_State *L) { - uint8_t argc = lua_gettop(L); +static int uwsgi_api_log(lua_State *L) { + uint16_t argc = lua_gettop(L); + uint16_t i; - if (argc < 2) { - lua_pushnil(L); - return 1; + const void *point; + int type; + + if (!(argc)) { + return 0; } - argc-=2; + uwsgi_log(ULUA_LOG_HEADER); + + for(i = 1; i <= argc; i++) { + type = lua_type(L, i); + + switch(type) { + case LUA_TNIL: uwsgi_log(" nil"); continue; + case LUA_TNONE: uwsgi_log(" none"); continue; + case LUA_TBOOLEAN: uwsgi_log(lua_toboolean(L, i) ? " true" : " false"); continue; + case LUA_TTABLE: if(!(uwsgi_lua_metatable_tostring(L, i - argc - 1))) break; + case LUA_TSTRING: + case LUA_TNUMBER: uwsgi_log(" %s", lua_tostring(L, i)); continue; + } + + point = lua_topointer(L, i); + + if (point) { + uwsgi_log(" <%s: %p>", lua_typename(L, type), point); + } else { + uwsgi_log(" <%s>", lua_typename(L, type)); + } + } + + uwsgi_log("\n"); + + return 0; +} + +static int uwsgi_api_rpc(lua_State *L) { + + uint16_t argc = lua_gettop(L); + uint8_t argnum; + uint8_t i; + uint64_t len; + + if (argc < 2) { + return 0; + } + + // take first 256 + argnum = (argc <= 256) ? (argc - 2) : 255; char **argv = NULL; uint16_t *argvs = NULL; - if (argc > 0) { - uint8_t i; - argv = (char **) uwsgi_malloc(sizeof(char *)*argc); - argvs = (uint16_t *) uwsgi_malloc(sizeof(uint16_t)*argc); + if (argnum > 0) { + + argv = (char **) uwsgi_malloc(sizeof(char *)*argnum); + argvs = (uint16_t *) uwsgi_malloc(sizeof(uint16_t)*argnum); - for(i = 0; i < argc; i++) { - argv[i] = (char *) lua_tolstring(L, i + 3, (size_t *) &argvs[i]); + for(i = 0; i < argnum; i++) { + if (lua_istable(L, i + 3)) { + uwsgi_lua_metatable_tostring(L, i + 2 - argc); + } + + argv[i] = (char *) lua_tolstring(L, i + 3, (size_t *) &argvs[i]); } } - uint64_t len; - char *str = uwsgi_do_rpc((char *) lua_tostring(L, 1), (char *) lua_tostring(L, 2), argc, argv, argvs, &len); + char *str = uwsgi_do_rpc((char *) lua_tostring(L, 1), (char *) lua_tostring(L, 2), argnum, argv, argvs, &len); - if (len == 0) { // fail?? + if (!(len)) { // fail?? lua_pushnil(L); } else { lua_pushlstring(L, str, len); } - if (argc > 0) { + if (argnum > 0) { free(argv); free(argvs); } @@ -125,199 +294,675 @@ static int uwsgi_api_rpc(lua_State *L) { return 1; } -static int uwsgi_api_register_rpc(lua_State *L) { +static int uwsgi_api_rpc_register_key(const char *key, size_t len) { - uint8_t argc = lua_gettop(L); - const char *name; - // a hack for 64bit; - int func; - long lfunc; - - if (argc < 2) { - lua_pushnil(L); - return 1; - } - - name = lua_tostring(L, 1); - - lua_pushvalue(L, 2); - func = luaL_ref(L, LUA_REGISTRYINDEX); - - //uwsgi_log("registered function %d in global table of lua_State %d\n", func, ULUA_MYWID); - lfunc = func; - - if (uwsgi_register_rpc((char *)name, &lua_plugin, 0, (void *) lfunc)) { - lua_pushnil(L); - } - else { - lua_pushboolean(L, 1); + // exists?? + size_t i; + int offset = uwsgi.mywid * uwsgi.rpc_max; + + for(i = 0; i < uwsgi.shared->rpc_count[uwsgi.mywid]; i++) { + if (!strcmp(key, (&uwsgi.rpc_table[offset + i])->name)) { + if ((&uwsgi.rpc_table[offset + i])->plugin == &lua_plugin) { + return 1; + } + + break; + } } + + // no + char *name = (char *) uwsgi_malloc(sizeof(char) * len); + + memcpy(name, key, sizeof(char) * len); + + if (uwsgi_register_rpc(name, &lua_plugin, 0, name)) { + // error + free(name); + return 0; + } return 1; } -static int uwsgi_api_cache_set(lua_State *L) { +static int uwsgi_api_register_rpc_newindex(lua_State *L) { + // 3 args: table, key(string or number), value(not nil) + + uint16_t argc = lua_gettop(L); + size_t len; + + if (argc != 3) { + return 0; + } + + const char *key = lua_tolstring(L, -2, &len); - uint8_t argc = lua_gettop(L); - const char *key ; - const char *value ; - uint64_t expires = 0; - size_t vallen; + if (len && !(lua_isnil(L, -1)) && uwsgi_api_rpc_register_key(key, len + 1)) { + lua_rawset(L, -3); + } + + return 0; +} + +static int uwsgi_api_register_rpc(lua_State *L) { + // legacy rpc register func + + uint16_t argc = lua_gettop(L); + + if (argc < 2) { + return 0; + } + + lua_rawgeti(L, LUA_REGISTRYINDEX, ULUA_RPC_REF); + lua_pushcfunction(L, uwsgi_api_register_rpc_newindex); + + lua_pushvalue(L, -2); + lua_pushvalue(L, 1); + lua_pushvalue(L, 2); + + lua_call(L, 3, 0); + + lua_pushvalue(L, 1); + lua_rawget(L, -2); + + if (!lua_isnil(L, -1)) { + lua_pushboolean(L, 1); + } + + return 1; +} + +static int uwsgi_lua_cache_set(lua_State *L, uint16_t argc, uint8_t flag) { + + char *cache = NULL; + uint64_t expires = 0; + + char *key; size_t keylen; - const char *cache = NULL; - - if (argc < 2) goto error; - - key = lua_tolstring(L, 1, &keylen); - value = lua_tolstring(L, 2, &vallen); + + char *value; + size_t valuelen; + + // key + key = (char *) lua_tolstring(L, 1, &keylen); + + // value + if (lua_istable(L, 2)) { + uwsgi_lua_metatable_tostring(L, -argc + 1); + } + + value = (char *) lua_tolstring(L, 2, &valuelen); + if (argc > 2) { expires = lua_tonumber(L, 3); if (argc > 3) { - cache = lua_tostring(L, 4); + cache = (char *) lua_tostring(L, 4); } } - - if (!uwsgi_cache_magic_set((char *)key, keylen, (char *)value, vallen, expires, 0, (char *) cache)) { + + if (!uwsgi_cache_magic_set(key, keylen, value, valuelen, expires, flag, cache)) { lua_pushboolean(L, 1); return 1; } -error: + + return 0; +} +static int uwsgi_lua_cache_set_table(lua_State *L, uint16_t argc, uint8_t flag) { + + size_t error = 0; + + char *cache = NULL; + uint64_t expires = 0; + + char *key; + size_t keylen; + + char *value; + size_t valuelen; + + if (argc > 1) { + expires = lua_tonumber(L, 2); + if (argc > 2) { + cache = (char *) lua_tostring(L, 3); + } + } + lua_pushnil(L); - return 1; + + while(lua_next(L, 1)) { + lua_pushvalue(L, -2); + + //key + key = (char *) lua_tolstring(L, -1, &keylen); + + //value + if (lua_istable(L, -2)) { + uwsgi_lua_metatable_tostring(L, -2); + } + + value = (char *) lua_tolstring(L, -2, &valuelen); + if (uwsgi_cache_magic_set(key, keylen, value, valuelen, expires, flag, cache)) { + ++error; + } + + lua_pop(L, 2); + } + + if (!error) { + lua_pushboolean(L, 1); + return 1; + } + + lua_pushnil(L); + lua_pushnumber(L, error); + + return 2; + +} + +static int uwsgi_api_cache_set(lua_State *L) { + uint16_t argc = lua_gettop(L); + + if (argc > 0 && lua_istable(L, 1)) { + return uwsgi_lua_cache_set_table(L, argc, 0); + } else if (argc > 1) { + return uwsgi_lua_cache_set(L, argc, 0); + } + + return 0; } static int uwsgi_api_cache_update(lua_State *L) { + uint16_t argc = lua_gettop(L); - uint8_t argc = lua_gettop(L); - const char *key ; - const char *value ; - uint64_t expires = 0; - size_t vallen; - size_t keylen; - const char *cache = NULL; - - if (argc < 2) goto error; - - key = lua_tolstring(L, 1, &keylen); - value = lua_tolstring(L, 2, &vallen); - if (argc > 2) { - expires = lua_tonumber(L, 3); - if (argc > 3) { - cache = lua_tostring(L, 4); - } - } - - if (!uwsgi_cache_magic_set((char *)key, keylen, (char *)value, vallen, expires, UWSGI_CACHE_FLAG_UPDATE, (char *)cache)) { - lua_pushboolean(L, 1); - return 1; - } -error: - - lua_pushnil(L); - return 1; - -} - - -static int uwsgi_api_register_signal(lua_State *L) { - - int args = lua_gettop(L); - uint8_t sig; - long lhandler; - const char *who; - - if (args >= 3) { - - sig = lua_tonumber(L, 1); - who = lua_tostring(L, 2); - lua_pushvalue(L, 3); - lhandler = luaL_ref(L, LUA_REGISTRYINDEX); - - uwsgi_register_signal(sig, (char *)who, (void *) lhandler, 6); + if (argc > 0 && lua_istable(L, 1)) { + return uwsgi_lua_cache_set_table(L, argc, UWSGI_CACHE_FLAG_UPDATE); + } else if (argc > 1) { + return uwsgi_lua_cache_set(L, argc, UWSGI_CACHE_FLAG_UPDATE); } - - lua_pushnil(L); - return 1; + + return 0; } +static int uwsgi_lua_cache_set_multi(lua_State *L, uint8_t flag) { + + uint16_t argc = lua_gettop(L); + uint16_t error = 0; + uint16_t i; + + char *cache; + uint64_t expires; + + char *key; + size_t keylen; + + char *value; + size_t valuelen; + + if (argc < 4) { + return 0; + } + + expires = lua_tonumber(L, 1); + cache = (char *) lua_tostring(L, 2); + + for (i = 4; i <= argc; i+=2) { + // key + key = (char *) lua_tolstring(L, i - 1, &keylen); + + // value + if (lua_istable(L, i)) { + uwsgi_lua_metatable_tostring(L, i - argc - 1); + } + + value = (char *) lua_tolstring(L, i, &valuelen); + + if (uwsgi_cache_magic_set(key, keylen, value, valuelen, expires, flag, cache)) { + ++error; + } + } + + if(!error) { + lua_pushboolean(L, 1); + return 1; + } + + lua_pushnil(L); + lua_pushnumber(L, error); + + return 2; +} + +static int uwsgi_api_cache_set_multi(lua_State *L) { + return uwsgi_lua_cache_set_multi(L, 0); +} + +static int uwsgi_api_cache_update_multi(lua_State *L) { + return uwsgi_lua_cache_set_multi(L, UWSGI_CACHE_FLAG_UPDATE); +} + + static int uwsgi_api_cache_clear(lua_State *L) { - const char *cache = NULL; - uint8_t argc = lua_gettop(L); + char *cache = NULL; - if (argc > 0) { - cache = lua_tostring(L, 2); - } - if (!uwsgi_cache_magic_clear((char *)cache)) { - lua_pushboolean(L, 1); - return 1; - } - - lua_pushnil(L); - return 1; + if (lua_gettop(L)) { + cache = (char *) lua_tostring(L, 1); + } + + if (!uwsgi_cache_magic_clear(cache)) { + lua_pushboolean(L, 1); + return 1; + } + return 0; } +static int uwsgi_lua_cache_del_exists(lua_State *L, int cache_do(char *, uint16_t, char *), uint8_t reverse) { + + size_t keylen; + char *key; + char *cache = NULL; + + size_t i, tlen; + size_t error = 0; + + uint16_t argc = lua_gettop(L); + + if (!(argc)) { + return 0; + } + + if (argc > 1) { + cache = (char *) lua_tostring(L, 2); + } + + // get the key + if (lua_istable(L, 1)) { + tlen = lua_rawlen(L, 1); + + for(i = 1; i <= tlen; i++) { + lua_rawgeti(L, 1, i); + + key = (char *) lua_tolstring(L, -1, &keylen); + + if (!keylen || (cache_do(key, keylen, cache) - reverse)) { + ++error; + } + + lua_pop(L, 1); + } + + } else { + key = (char *) lua_tolstring(L, 1, &keylen); + + if (!keylen || (cache_do(key, keylen, cache) - reverse)) { + lua_pushnil(L); + return 1; + } + } + + if (!error) { + lua_pushboolean(L, 1); + return 1; + } + + lua_pushnil(L); + lua_pushnumber(L, error); + + return 2; +} + static int uwsgi_api_cache_del(lua_State *L) { - - size_t keylen; - const char *key ; - const char *cache = NULL; - uint8_t argc = lua_gettop(L); - - if (argc == 0) goto error; - - if (lua_isstring(L, 1)) { - // get the key - key = lua_tolstring(L, 1, &keylen); - if (argc > 1) { - cache = lua_tostring(L, 2); - } - if (!uwsgi_cache_magic_del((char *)key, keylen, (char *)cache)) { - lua_pushboolean(L, 1); - return 1; - } - } - -error: - lua_pushnil(L); - return 1; - + return uwsgi_lua_cache_del_exists(L, uwsgi_cache_magic_del, 0); } - static int uwsgi_api_cache_exists(lua_State *L) { + return uwsgi_lua_cache_del_exists(L, uwsgi_cache_magic_exists, 1); +} - size_t keylen; - const char *key ; - const char *cache = NULL; - uint8_t argc = lua_gettop(L); +static int uwsgi_api_cache_del_multi(lua_State *L) { + + size_t keylen; + char *key; + char *cache; + + uint16_t argc = lua_gettop(L); + uint16_t error = 0; + uint16_t i; + + if (argc < 1) { + return 0; + } + + cache = (char *) lua_tostring(L, 1); + + for (i = 2; i <= argc; i++) { + key = (char *) lua_tolstring(L, i, &keylen); + + if (!keylen || uwsgi_cache_magic_del(key, keylen, cache)) { + ++error; + } + } + + if (!error) { + lua_pushboolean(L, 1); + return 1; + } + + lua_pushnil(L); + lua_pushnumber(L, error); - if (argc == 0) goto error; - - if (lua_isstring(L, 1)) { - // get the key - key = lua_tolstring(L, 1, &keylen); - if (argc > 1) { - cache = lua_tostring(L, 2); - } - if (uwsgi_cache_magic_exists((char *)key, keylen,(char *)cache)) { - lua_pushboolean(L, 1); - return 1; - } - } - -error: - lua_pushnil(L); - return 1; + return 2; } +static int uwsgi_api_cache_exists_multi(lua_State *L) { + + size_t keylen; + char *key; + char *cache; + + uint16_t argc = lua_gettop(L); + uint16_t i; + + if (argc < 2) { + return 0; + } + + cache = (char *) lua_tostring(L, 1); + + if (!lua_checkstack(L, argc - 1)) { + ulua_log("cache_exists_multi: too many items (%u) in the stack", argc - 1); + return 0; + } + + for (i = 2; i <= argc; i++) { + + key = (char *) lua_tolstring(L, i, &keylen); + + if (keylen && uwsgi_cache_magic_exists(key, keylen, cache)) { + lua_pushboolean(L, 1); + } else { + lua_pushnil(L); + } + + } + + return argc - 1; +} + + +static int uwsgi_api_signal_wait(lua_State *L) { + + struct wsgi_request *wsgi_req = current_wsgi_req(); + uint16_t args = lua_gettop(L); + int received_signal; + + wsgi_req->signal_received = -1; + + if (args > 0 && lua_isnumber(L, 1)) { + received_signal = uwsgi_signal_wait(wsgi_req, lua_tonumber(L, 1)); + } else { + received_signal = uwsgi_signal_wait(wsgi_req, -1); + } + + if (received_signal < 0) { + lua_pushnil(L); + } else { + wsgi_req->signal_received = received_signal; + lua_pushnumber(L, received_signal); + } + + return 1; +} + +static int uwsgi_api_signal_received(lua_State *L) { + + struct wsgi_request *wsgi_req = current_wsgi_req(); + + lua_pushnumber(L, wsgi_req->signal_received); + + return 1; +} + +static int uwsgi_api_signal_registered(lua_State *L) { + + uint16_t args = lua_gettop(L); + struct uwsgi_signal_entry *use; + uint8_t sig; + + if (args < 1 || !(lua_isnumber(L, 1))) { + return 0; + } + + sig = (uint8_t) lua_tonumber(L, 1); + use = &uwsgi.shared->signal_table[sig]; + + lua_pushboolean(L, use->handler ? 1 : 0); + lua_pushstring(L, use->receiver); + + if (uwsgi.mywid > 0) { + use = &uwsgi.shared->signal_table[sig + uwsgi.mywid*256]; + } + + lua_pushnumber(L, use->modifier1); + + return 3; +} + +static int uwsgi_api_register_signal(lua_State *L) { + + // !! This is plugin specific function !! + + uint16_t args = lua_gettop(L); + uint8_t sig; + struct uwsgi_signal_entry *use; + const char *who; + size_t len; + int i; + + if(!(uwsgi.master_process)) { + ulua_log("no master, no signals"); + return 0; + } + + if (args < 1 || !(lua_isnumber(L, 1))) { + return 0; + } + + sig = (uint8_t) lua_tonumber(L, 1); + who = lua_tolstring(L, 2, &len); + use = &uwsgi.shared->signal_table[sig]; + + if (len == 0) { + who = (const char *) &len; // len is zero anyway + } else if (len > 63) { + ulua_log("receiver lengh overflow: %s", who); + return 0; + } + + if (use->handler && use->modifier1 != 6) { + ulua_log("signal %s has already been taken, but not by lua-plugin", sig); + } + + // register signal's receiver on master + if (!(use->handler) || strcmp(use->receiver, who)) { + uwsgi_lock(uwsgi.signal_table_lock); + + // master-proc checks receiver + strcpy(use->receiver, who); + + // if master has not any handler + // if has, then only update receiver + if (!(use->handler)) { + use->handler = (void *) (1 /* unused */); // unsupported + use->modifier1 = 6; // for future checks + } + + // from non-lazy worker + if (uwsgi.mywid == 0 && uwsgi.muleid == 0) { + for(i = 1; i <= uwsgi.numproc; i++) { + use = &uwsgi.shared->signal_table[sig + i*256]; + if (!(use->handler)) { + use->handler = (void *) (1 /* unused */); // unsupported + use->modifier1 = 6; + } + } + } + + uwsgi_unlock(uwsgi.signal_table_lock); + } + + // lazy (or runtime) worker, just register handler and modifier1 + if (uwsgi.mywid > 0) { + use = &uwsgi.shared->signal_table[sig + uwsgi.mywid*256]; + + if (use->modifier1 != 6) { + uwsgi_lock(uwsgi.signal_table_lock); + + use->handler = (void *) (1 /* unused */); // unsupported + use->modifier1 = 6; + + uwsgi_unlock(uwsgi.signal_table_lock); + } + } + + if (args > 2) { + lua_rawgeti(L, LUA_REGISTRYINDEX, ULUA_SIGNAL_REF); + lua_pushvalue(L, 1); + lua_pushvalue(L, 3); + lua_settable(L, -3); + } + + ulua_log("signum %d registered (by %s %d, target: %s)", sig, + !uwsgi.muleid ? "wid" : "mule", uwsgi.muleid || uwsgi.mywid, len ? who : "default"); + + lua_pushboolean(L, 1); + return 1; +} + +static int uwsgi_api_add_file_monitor(lua_State *L) { + uint16_t args = lua_gettop(L); + uint8_t sig; + const char *file; + size_t len; + + if (args < 2 || !(lua_isnumber(L, 1))) { + return 0; + } + + sig = (uint8_t) lua_tonumber(L, 1); + file = lua_tolstring(L, 2, &len); + + if (!len) { + return 0; + } + + if (!(uwsgi_add_file_monitor(sig, (char *) file))) { + lua_pushboolean(L, 1); + return 1; + } + + return 0; + +} + +static int uwsgi_api_signal_add_timer(lua_State *L) { + uint16_t args = lua_gettop(L); + uint8_t sig; + int secs; + + if (args < 2 || !(lua_isnumber(L, 1) && lua_isnumber(L, 2))) { + return 0; + } + + sig = (uint8_t) lua_tonumber(L, 1); + secs = lua_tonumber(L, 2); + + if (!(uwsgi_add_timer(sig, secs))) { + lua_pushboolean(L, 1); + return 1; + } + + return 0; +} + +static int uwsgi_api_signal_add_rb_timer(lua_State *L) { + uint16_t args = lua_gettop(L); + uint8_t sig; + int secs, itrs; + + if (args < 3 || !(lua_isnumber(L, 1) && lua_isnumber(L, 2) && lua_isnumber(L, 3))) { + return 0; + } + + sig = (uint8_t) lua_tonumber(L, 1); + secs = lua_tonumber(L, 2); + itrs = lua_tonumber(L, 3); + + if (!(uwsgi_signal_add_rb_timer(sig, secs, itrs))) { + lua_pushboolean(L, 1); + return 1; + } + + return 0; +} + +static int uwsgi_api_signal_add_cron(lua_State *L) { + int date[] = {-1, -1, -1, -1, -1}; + uint16_t args = lua_gettop(L); + int i; + + if (args < 1 || !(lua_isnumber(L, 1))) { + return 0; + } + + if (args > 6) args = 6; + + for (i = 2; i <= args; i++) { + if (lua_isnumber(L, i)) { + date[i-2] = lua_tonumber(L, i); + } + } + + if (!(uwsgi_signal_add_cron((uint8_t) lua_tonumber(L, 1), + date[0], date[1], date[2], date[3], date[4]))) + { + lua_pushboolean(L, 1); + return 1; + } + + return 0; +} + +static int uwsgi_api_alarm(lua_State *L) { + uint16_t args = lua_gettop(L); + const char *msg; + size_t len; + + if (args < 2 || !(lua_isstring(L, 1))) { + return 0; + } + + if (lua_istable(L, 2)) { + uwsgi_lua_metatable_tostring(L, 1 - args); + } + + msg = lua_tolstring(L, 2, &len); + + if (len) { + uwsgi_alarm_trigger((char *) lua_tostring(L, 1), (char *) msg, len); + } + + return 0; +} + + static int uwsgi_api_async_sleep(lua_State *L) { - uint8_t argc = lua_gettop(L); + uint16_t argc = lua_gettop(L); if (argc == 0) goto end; struct wsgi_request *wsgi_req = current_wsgi_req(); @@ -333,7 +978,7 @@ end: } static int uwsgi_api_wait_fd_read(lua_State *L) { - uint8_t argc = lua_gettop(L); + uint16_t argc = lua_gettop(L); if (argc == 0) goto end; struct wsgi_request *wsgi_req = current_wsgi_req(); @@ -355,7 +1000,7 @@ end: } static int uwsgi_api_wait_fd_write(lua_State *L) { - uint8_t argc = lua_gettop(L); + uint16_t argc = lua_gettop(L); if (argc == 0) goto end; struct wsgi_request *wsgi_req = current_wsgi_req(); @@ -377,7 +1022,7 @@ end: } static int uwsgi_api_async_connect(lua_State *L) { - uint8_t argc = lua_gettop(L); + uint16_t argc = lua_gettop(L); if (argc == 0) goto end; int fd = uwsgi_connect((char *)lua_tostring(L, 1), 0, 1); @@ -389,7 +1034,7 @@ end: } static int uwsgi_api_is_connected(lua_State *L) { - uint8_t argc = lua_gettop(L); + uint16_t argc = lua_gettop(L); if (argc == 0) goto end; int fd = lua_tonumber(L, 1); if (uwsgi_is_connected(fd)) { @@ -404,7 +1049,7 @@ end: } static int uwsgi_api_close(lua_State *L) { - uint8_t argc = lua_gettop(L); + uint16_t argc = lua_gettop(L); if (argc == 0) goto end; int fd = lua_tonumber(L, 1); close(fd); @@ -422,7 +1067,7 @@ static int uwsgi_api_ready_fd(lua_State *L) { } static int uwsgi_api_websocket_handshake(lua_State *L) { - uint8_t argc = lua_gettop(L); + uint16_t argc = lua_gettop(L); const char *key = NULL, *origin = NULL, *proto = NULL; size_t key_len = 0, origin_len = 0, proto_len = 0; @@ -452,10 +1097,15 @@ error: } static int uwsgi_api_websocket_send(lua_State *L) { - uint8_t argc = lua_gettop(L); + uint16_t argc = lua_gettop(L); if (argc == 0) goto error; size_t message_len = 0; + + if (lua_istable(L, 1)) { + uwsgi_lua_metatable_tostring(L, -argc); + } + const char *message = lua_tolstring(L, 1, &message_len); struct wsgi_request *wsgi_req = current_wsgi_req(); @@ -471,10 +1121,15 @@ error: } static int uwsgi_api_websocket_send_binary(lua_State *L) { - uint8_t argc = lua_gettop(L); + uint16_t argc = lua_gettop(L); if (argc == 0) goto error; size_t message_len = 0; + + if (lua_istable(L, 1)) { + uwsgi_lua_metatable_tostring(L, -argc); + } + const char *message = lua_tolstring(L, 1, &message_len); struct wsgi_request *wsgi_req = current_wsgi_req(); @@ -490,7 +1145,7 @@ error: } static int uwsgi_api_websocket_send_from_sharedarea(lua_State *L) { - uint8_t argc = lua_gettop(L); + uint16_t argc = lua_gettop(L); if (argc < 2) goto error; int id = lua_tonumber(L, 1); @@ -513,7 +1168,7 @@ error: } static int uwsgi_api_websocket_send_binary_from_sharedarea(lua_State *L) { - uint8_t argc = lua_gettop(L); + uint16_t argc = lua_gettop(L); if (argc < 2) goto error; int id = lua_tonumber(L, 1); @@ -561,37 +1216,195 @@ static int uwsgi_api_websocket_recv_nb(lua_State *L) { return 1; } +static int uwsgi_api_chunked_read(lua_State *L) { + size_t len = 0; + int timeout = lua_gettop(L) ? lua_tonumber(L, 1) : 0; + struct wsgi_request *wsgi_req = current_wsgi_req(); + char *chunk = uwsgi_chunked_read(wsgi_req, &len, timeout, 0); + if (!chunk) { + lua_pushstring(L, "unable to receive chunked part"); + lua_error(L); + return 0; + } + lua_pushlstring(L, chunk, len); + return 1; +} + +static int uwsgi_api_chunked_read_nb(lua_State *L) { + size_t len = 0; + struct wsgi_request *wsgi_req = current_wsgi_req(); + char *chunk = uwsgi_chunked_read(wsgi_req, &len, 0, 1); + if (!chunk) { + lua_pushstring(L, "unable to receive chunked part"); + lua_error(L); + return 0; + } + lua_pushlstring(L, chunk, len); + return 1; +} + static int uwsgi_api_cache_get(lua_State *L) { - char *value ; - uint64_t valsize; + uint16_t argc = lua_gettop(L); + + char *value; + uint64_t valsize; + + char *key; size_t keylen; - const char *key ; - const char *cache = NULL; - uint8_t argc = lua_gettop(L); - if (argc == 0) goto error; - - if (lua_isstring(L, 1)) { - // get the key - key = lua_tolstring(L, 1, &keylen); - if (argc > 1) { - cache = lua_tostring(L, 2); - } - value = uwsgi_cache_magic_get((char *)key, keylen, &valsize, NULL, (char *)cache); - if (value) { - lua_pushlstring(L, value, valsize); - free(value); - return 1; - } + char *cache = NULL; + + size_t error; + size_t tlen; + size_t i; + + if (argc > 1) { + cache = (char *) lua_tostring(L, 2); + } else if (!argc) { + return 0; } + + if (lua_istable(L, 1)) { + + error = 0; + tlen = lua_rawlen(L, 1); + + lua_createtable(L, 0, tlen); + + for(i = 1; i <= tlen; i++) { + + lua_rawgeti(L, 1, i); + + key = (char *) lua_tolstring(L, -1, &keylen); -error: - lua_pushnil(L); - return 1; + value = (keylen) ? uwsgi_cache_magic_get(key, keylen, &valsize, NULL, cache) : NULL; + + if (value) { + lua_pushlstring(L, value, valsize); + free(value); + lua_rawset(L, -3); + } else { + ++error; + lua_pop(L, 1); + } + + } + + if (!error) { + return 1; + } + + lua_pushnumber(L, error); + return 2; + + } + + key = (char *) lua_tolstring(L, 1, &keylen); + + value = (keylen) ? uwsgi_cache_magic_get(key, keylen, &valsize, NULL, cache) : NULL; + + if (value) { + lua_pushlstring(L, value, valsize); + free(value); + } else { + lua_pushnil(L); + } + + return 1; } + +static int uwsgi_api_cache_get_multi(lua_State *L) { + + char *value ; + uint64_t valsize; + + char *key; + size_t keylen; + + char *cache; + + uint16_t argc = lua_gettop(L); + uint16_t i; + + if (argc < 2) { + return 0; + } + + if (!lua_checkstack(L, argc - 1)) { + ulua_log("cache_get_multi: too many items (%u) in the stack", argc - 1); + return 0; + } + + cache = (char *) lua_tostring(L, 1); + + for (i = 2; i <= argc; i++) { + + key = (char *) lua_tolstring(L, i, &keylen); + + value = (keylen) ? uwsgi_cache_magic_get(key, keylen, &valsize, NULL, cache) : NULL; + + if (value) { + lua_pushlstring(L, value, valsize); + free(value); + } else { + lua_pushnil(L); + } + } + + return argc - 1; +} + +static int uwsgi_api_cache_get_tmulti(lua_State *L) { + + char *value ; + uint64_t valsize; + + char *key; + size_t keylen; + + char *cache; + + uint16_t argc = lua_gettop(L); + uint16_t error = 0; + uint16_t i; + + if (argc < 2) { + return 0; + } + + cache = (char *) lua_tostring(L, 1); + + lua_createtable(L, 0, argc - 1); + + for (i = 2; i <= argc; i++) { + + key = (char *) lua_tolstring(L, i, &keylen); + + value = (keylen) ? uwsgi_cache_magic_get(key, keylen, &valsize, NULL, cache) : NULL; + + if (value) { + lua_pushlstring(L, value, valsize); + free(value); + lua_setfield(L, -2, key); + } else { + ++error; + } + + } + + if (!error) { + return 1; + } + + lua_pushnumber(L, error); + return 2; + +} + + static int uwsgi_api_req_fd(lua_State *L) { struct wsgi_request *wsgi_req = current_wsgi_req(); @@ -669,6 +1482,7 @@ static int uwsgi_lua_input(lua_State *L) { return 0; } + static int uwsgi_api_async_id_get(lua_State *L) { struct wsgi_request *wsgi_req = current_wsgi_req(); @@ -678,22 +1492,609 @@ static int uwsgi_api_async_id_get(lua_State *L) { return 1; } -static const luaL_Reg uwsgi_api[] = { +static int uwsgi_api_memory_usage(lua_State *L) { + + uint64_t rss = 0; + uint64_t vsz = 0; + + get_memusage(&rss, &vsz); + + lua_pushnumber(L, rss); + lua_pushnumber(L, vsz); + + return 2; +} + +static int uwsgi_api_setprocname(lua_State *L) { + + if (lua_gettop(L) > 0 && lua_isstring(L, 1)) { + uwsgi_set_processname((char *) lua_tostring(L, 1)); + } + + return 0; +} + +static int uwsgi_api_pid(lua_State *L) { + + int id = 0; + + if (lua_gettop(L) > 0) { + id = lua_tonumber(L, 1); + } + + if (id >= 0 && id <= uwsgi.numproc) { + lua_pushnumber(L, uwsgi.workers[id].pid); + return 1; + } + + return 0; + +} + +static int uwsgi_api_mypid(lua_State *L) { + + lua_pushnumber(L, uwsgi.mypid); + + return 1; +} + +static int uwsgi_api_mule_msg_get(lua_State *L) { + + uint16_t argc = lua_gettop(L); + + int manage_signals = 1; + int manage_farms = 1; + int timeout = -1; + + char *msg; + + size_t buffer_size = ULUA_MULE_MSG_GET_BUFFER_SIZE; + ssize_t len = 0; + + if (argc > 0 && lua_istable(L, 1)) { + lua_pop(L, argc - 1); + + lua_getfield(L, 1, "signals"); + lua_getfield(L, 1, "farms"); + lua_getfield(L, 1, "timeout"); + lua_getfield(L, 1, "buffer_size"); + + lua_remove(L, -5); + argc = 4; + } + + switch(argc > 4 ? 4 : argc) { + case 4: if (lua_isnumber(L, 4)) buffer_size = lua_tonumber(L, 4); + case 3: if (lua_isnumber(L, 3)) timeout = lua_tonumber(L, 3); + case 2: if (!lua_isnil(L, 2)) manage_farms = lua_toboolean(L, 2); + case 1: if (!lua_isnil(L, 1)) manage_signals = lua_toboolean(L, 1); + } + + msg = (char *) uwsgi_malloc(buffer_size); + + len = uwsgi_mule_get_msg(manage_signals, manage_farms, msg, buffer_size, timeout); + + if (len < 0) { + lua_pushnil(L); + } else { + lua_pushlstring(L, msg, len); + } + + free(msg); + + return 1; +} + +static int uwsgi_api_mule_msg(lua_State *L) { + + int fd; + int mule_id; + int type; + + size_t msglen; + char *msg; + + uint16_t argc = lua_gettop(L); + + if (argc < 1 || !lua_isstring(L, 1)) { + return 0; + } + + if (uwsgi.mules_cnt < 1) { + ulua_log("mule_msg: no mules. no send"); + return 0; + } + + msg = (char *) lua_tolstring(L, 1, &msglen); + + if (argc == 1) { + mule_send_msg(uwsgi.shared->mule_queue_pipe[0], msg, msglen); + } else { + type = lua_type(L, 2); + + if (type == LUA_TSTRING) { + + struct uwsgi_farm *uf = get_farm_by_name((char *)lua_tostring(L, 2)); + + if (!uf) { + ulua_log("mule_msg: unknown farm"); + return 0; + } + + fd = uf->queue_pipe[0]; + + } else if (type == LUA_TNUMBER) { + + mule_id = lua_tonumber(L, 2); + + if (mule_id < 0 && mule_id > uwsgi.mules_cnt) { + ulua_log("mule_msg: mule_id is out of range"); + return 0; + } + + if (mule_id == 0) { + fd = uwsgi.shared->mule_queue_pipe[0]; + } else { + fd = uwsgi.mules[mule_id-1].queue_pipe[0]; + } + + } else { + fd = -1; + ulua_log("mule_msg: invalid mule"); + } + + if (fd > -1) { + mule_send_msg(fd, msg, msglen); + } + } + + return 0; +} + +static int uwsgi_api_queue_push(lua_State *L) { + + size_t len; + char *str; + + uint16_t argc = lua_gettop(L); + uint16_t error = 0; + + char **list; + size_t *slen; + uint16_t i; + + + if (!argc || !uwsgi.queue_size) { + return 0; + } + + if (argc == 1) { + + if (lua_istable(L, 1)) { + uwsgi_lua_metatable_tostring(L, -1); + } + + str = (char *) lua_tolstring(L, 1, &len); + + if (len) { + uwsgi_wlock(uwsgi.queue_lock); + + if (uwsgi_queue_push(str, len)) { + ++error; + } + + uwsgi_rwunlock(uwsgi.queue_lock); + } else { + ++error; + } + + } else { + + list = (char **) uwsgi_malloc(sizeof(char *) * argc); + slen = (size_t *) uwsgi_malloc(sizeof(size_t) * argc); + + for (i = 1; i <= argc; ++i) { + + if (lua_istable(L, i)) { + uwsgi_lua_metatable_tostring(L, i - argc - 1); + } + + list[i] = (char *) lua_tolstring(L, i, &slen[i]); + + } + + uwsgi_wlock(uwsgi.queue_lock); + + for (i = 1; i <= argc; ++i) { + + if (!slen[i] || uwsgi_queue_push(list[i], slen[i])) { + ++error; + } + + } + + uwsgi_rwunlock(uwsgi.queue_lock); + + free(list); + free(slen); + + } + + if (!error) { + lua_pushboolean(L, 1); + return 1; + } + + lua_pushnil(L); + lua_pushnumber(L, error); + + return 2; + +} + +static int uwsgi_api_queue_set(lua_State *L) { + + uint64_t key; + uint64_t len; + char *str; + uint16_t i; + + uint16_t error = 0; + uint16_t argc = lua_gettop(L); + + if (!(argc && uwsgi.queue_size)) { + return 0; + } + + if (lua_istable(L, 1)) { + + lua_pushnil(L); + + while(lua_next(L, 1)) { + if (lua_isnumber(L, -2)) { + + if (lua_istable(L, -1)) { + uwsgi_lua_metatable_tostring(L, -1); + } + + str = (char *) lua_tolstring(L, -1, &len); + key = lua_tonumber(L, -2); + + if (len) { + uwsgi_wlock(uwsgi.queue_lock); + + if (!uwsgi_queue_set(key, str, len)) { + error++; + } + + uwsgi_rwunlock(uwsgi.queue_lock); + } else { + error++; + } + + } else { + error++; + } + + lua_pop(L, 1); + } + + } else { + + for (i = 2; i <= argc; i+=2) { + if (lua_isnumber(L, i - 1)) { + + if (lua_istable(L, i)) { + uwsgi_lua_metatable_tostring(L, i - argc - 1); + } + + key = lua_tonumber(L, i - 1); + str = (char *) lua_tolstring(L, i, &len); + + if (len) { + uwsgi_wlock(uwsgi.queue_lock); + + if (!uwsgi_queue_set(key, str, len)) { + error++; + } + + uwsgi_rwunlock(uwsgi.queue_lock); + } else { + error++; + } + + } else { + error++; + } + } + + } + + if (!error) { + lua_pushboolean(L, 1); + return 1; + } + + lua_pushnil(L); + lua_pushnumber(L, error); + + return 2; +} + +static int uwsgi_api_queue_slot(lua_State *L) { + + lua_pushnumber(L, uwsgi.queue_header->pos); + + return 1; +} + +static int uwsgi_api_queue_pull_slot(lua_State *L) { + + lua_pushnumber(L, uwsgi.queue_header->pull_pos); + + return 1; +} + +static int uwsgi_lua_queue_pull_pop(lua_State *L, char* queue(uint64_t*)) { + + char *str; + size_t len; + int i; + + int num = (lua_gettop(L) > 0) ? lua_tonumber(L, 1) : 1; + + if (!uwsgi.queue_size) { + return 0; + } + + if (!lua_checkstack(L, num)) { + ulua_log("queue_pop(pull): too many items (%u) in the stack", num); + return 0; + } + + uwsgi_wlock(uwsgi.queue_lock); + + for(i = num; i > 0; --i) { + + len = 0; + str = queue(&len); + + if (len) { + lua_pushlstring(L, str, len); + } else { + lua_pushnil(L); + } + } + + uwsgi_rwunlock(uwsgi.queue_lock); + + return num; +} + +static int uwsgi_api_queue_pull(lua_State *L) { + return uwsgi_lua_queue_pull_pop(L, uwsgi_queue_pull); +} + +static int uwsgi_api_queue_pop(lua_State *L) { + return uwsgi_lua_queue_pull_pop(L, uwsgi_queue_pop); +} + +static int uwsgi_api_queue_get(lua_State *L) { + + char *str; + size_t len; + + uint16_t i; + uint16_t argc = lua_gettop(L); + + uint64_t key; + uint64_t *list; + + if (!argc || !uwsgi.queue_size) { + return 0; + } + + if (argc == 1) { + key = lua_tonumber(L, 1); + + uwsgi_rlock(uwsgi.queue_lock); + + str = uwsgi_queue_get(key, &len); + + if (len) { + lua_pushlstring(L, str, len); + } else { + lua_pushnil(L); + } + + uwsgi_rwunlock(uwsgi.queue_lock); + } else { + + list = (uint64_t *) uwsgi_malloc(sizeof(uint64_t) * argc); + + for (i = 1; i <= argc; ++i) { + list[i] = lua_tonumber(L, i); + } + + lua_pop(L, argc); + + uwsgi_rlock(uwsgi.queue_lock); + + for (i = 1; i <= argc; ++i) { + str = uwsgi_queue_get(list[i], &len); + + if (len) { + lua_pushlstring(L, str, len); + } else { + lua_pushnil(L); + } + } + + uwsgi_rwunlock(uwsgi.queue_lock); + + free(list); + } + + return argc; +} + +static int uwsgi_api_queue_last(lua_State *L) { + + char *str; + size_t len; + uint64_t base; + + unsigned int left; + unsigned int count = lua_gettop(L) ? lua_tonumber(L, 1) : 0; + + if (uwsgi.queue_size) { + + uwsgi_rlock(uwsgi.queue_lock); + + base = uwsgi.queue_header->pos > 0 ? uwsgi.queue_header->pos-1 : uwsgi.queue_size-1; + + if (!(count)) { + + str = uwsgi_queue_get(base, &len); + + if (len) { + lua_pushlstring(L, str, len); + uwsgi_rwunlock(uwsgi.queue_lock); + return 1; + } + + uwsgi_rwunlock(uwsgi.queue_lock); + return 0; + } + + if (count > uwsgi.queue_size) { + count = uwsgi.queue_size; + } + + if (!lua_checkstack(L, count)) { + ulua_log("queue_last: too many items (%u) in the stack", count); + uwsgi_rwunlock(uwsgi.queue_lock); + return 0; + } + + left = count; + + while(left) { + str = uwsgi_queue_get(base, &len); + + if(len) { + lua_pushlstring(L, str, len); + } else { + lua_pushnil(L); + } + + if (base > 0) { + --base; + } else { + base = uwsgi.queue_size-1; + } + + --left; + } + + uwsgi_rwunlock(uwsgi.queue_lock); + return count; + } + + return 0; +} + +static int uwsgi_api_mule_msg_hook(lua_State *L) { + + if (!lua_gettop(L)) { + lua_pushnil(L); + } else { + lua_pushvalue(L, 1); + } + + lua_rawseti(L, LUA_REGISTRYINDEX, ULUA_MULE_MSG_REF); + + return 0; +} + +// basic api list +static const luaL_Reg uwsgi_api_base[] = { {"log", uwsgi_api_log}, - {"connection_fd", uwsgi_api_req_fd}, + {"metric_get", uwsgi_api_metric_get}, + {"metric_set", uwsgi_api_metric_set}, + {"metric_inc", uwsgi_api_metric_inc}, + {"metric_div", uwsgi_api_metric_div}, + {"metric_mul", uwsgi_api_metric_mul}, + {"metric_dec", uwsgi_api_metric_dec}, + {"cache_get", uwsgi_api_cache_get}, + {"cache_get_multi", uwsgi_api_cache_get_multi}, + {"cache_get_tmulti", uwsgi_api_cache_get_tmulti}, {"cache_set", uwsgi_api_cache_set}, + {"cache_set_multi", uwsgi_api_cache_set_multi}, {"cache_update", uwsgi_api_cache_update}, + {"cache_update_multi", uwsgi_api_cache_update_multi}, {"cache_del", uwsgi_api_cache_del}, + {"cache_del_multi", uwsgi_api_cache_del_multi}, {"cache_exists", uwsgi_api_cache_exists}, + {"cache_exists_multi", uwsgi_api_cache_exists_multi}, {"cache_clear", uwsgi_api_cache_clear}, - + + {"queue_push", uwsgi_api_queue_push}, + {"queue_set", uwsgi_api_queue_set}, + {"queue_slot", uwsgi_api_queue_slot}, + {"queue_pull_slot", uwsgi_api_queue_pull_slot}, + {"queue_pop",uwsgi_api_queue_pop}, + {"queue_get",uwsgi_api_queue_get}, + {"queue_pull",uwsgi_api_queue_pull}, + {"queue_last",uwsgi_api_queue_last}, + {"register_signal", uwsgi_api_register_signal}, + {"signal_registered", uwsgi_api_signal_registered}, + {"signal_wait", uwsgi_api_signal_wait}, + {"signal_received", uwsgi_api_signal_received}, + {"add_file_monitor", uwsgi_api_add_file_monitor}, + {"add_timer", uwsgi_api_signal_add_timer}, + {"add_rb_timer", uwsgi_api_signal_add_rb_timer}, + {"add_cron", uwsgi_api_signal_add_cron}, + + {"alarm", uwsgi_api_alarm}, + {"signal", uwsgi_api_signal}, + + {"mem", uwsgi_api_memory_usage}, + {"pid", uwsgi_api_pid}, + {"mypid", uwsgi_api_mypid}, + + {"setprocname", uwsgi_api_setprocname}, + + {"lock", uwsgi_api_lock}, + {"unlock", uwsgi_api_unlock}, + + {"mule_msg", uwsgi_api_mule_msg}, + + {NULL, NULL} +}; + +// worker only adds +static const luaL_Reg uwsgi_api_worker[] = { + + {"connection_fd", uwsgi_api_req_fd}, + {"register_rpc", uwsgi_api_register_rpc}, {"rpc", uwsgi_api_rpc}, + {"req_input_read", uwsgi_lua_input}, - + {"chunked_read", uwsgi_api_chunked_read}, + {"chunked_read_nb", uwsgi_api_chunked_read_nb}, + + {"async_sleep", uwsgi_api_async_sleep}, + {"async_connect", uwsgi_api_async_connect}, + {"async_id_get", uwsgi_api_async_id_get}, + {"is_connected", uwsgi_api_is_connected}, + {"wait_fd_read", uwsgi_api_wait_fd_read}, + {"wait_fd_write", uwsgi_api_wait_fd_write}, + {"websocket_handshake", uwsgi_api_websocket_handshake}, {"websocket_recv", uwsgi_api_websocket_recv}, {"websocket_recv_nb", uwsgi_api_websocket_recv_nb}, @@ -701,59 +2102,94 @@ static const luaL_Reg uwsgi_api[] = { {"websocket_send_from_sharedarea", uwsgi_api_websocket_send_from_sharedarea}, {"websocket_send_binary", uwsgi_api_websocket_send_binary}, {"websocket_send_binary_from_sharedarea", uwsgi_api_websocket_send_binary_from_sharedarea}, - - {"lock", uwsgi_api_lock}, - {"unlock", uwsgi_api_unlock}, - - {"async_sleep", uwsgi_api_async_sleep}, - {"async_connect", uwsgi_api_async_connect}, - {"async_id_get", uwsgi_api_async_id_get}, - {"is_connected", uwsgi_api_is_connected}, + {"close", uwsgi_api_close}, - {"wait_fd_read", uwsgi_api_wait_fd_read}, - {"wait_fd_write", uwsgi_api_wait_fd_write}, {"ready_fd", uwsgi_api_ready_fd}, {NULL, NULL} }; +// mule only adds +static const luaL_Reg uwsgi_api_mule[] = { + + {"mule_msg_get", uwsgi_api_mule_msg_get}, + {"mule_msg_hook", uwsgi_api_mule_msg_hook}, + + {NULL, NULL} +}; + +static void uwsgi_lua_api_newglobaltable(lua_State *L, const char *name) { + lua_newtable(L); + lua_pushvalue(L, -1); + lua_setglobal(L, name); +} + +static void uwsgi_lua_api_push(lua_State *L, int target, const luaL_Reg *api) { + for (; api->name; api++) { + lua_pushstring(L, api->name); + lua_pushcfunction(L, api->func); + lua_rawset(L, target - 2); + } +} + +static int uwsgi_lua_init() { -static int uwsgi_lua_init(){ int i; - uwsgi_log("Initializing Lua environment... "); - - ulua.state = uwsgi_malloc(sizeof(lua_State**) * uwsgi.numproc); - - for (i=0;i 0) { + uwsgi_log(ULUA_LOG_HEADER " Initializing Mule's Lua environment... "); + + ulua.mulestate = uwsgi_malloc(sizeof(lua_State*) * uwsgi.mules_cnt); + + for (i = 0; i 0) { + + lua_createtable(L, cores - 1, 0); + + for(i = 1; i < cores; i++) { + // create thread and save it + Ls[i] = lua_newthread(L); + lua_rawseti(L, -2, i); + + } + + } else { + lua_pushboolean(L, 0); + } + + luaL_ref(L, LUA_REGISTRYINDEX); // ref 4 for threads + // init main app uslnargs = lua_gettop(L); struct uwsgi_string_list *usl = ulua.load; + while(usl) { if (luaL_dofile(L, usl->value)) { - uwsgi_log("unable to load Lua file %s: %s\n", usl->value, lua_tostring(L, -1)); + ulua_log("unable to load Lua file %s: %s", usl->value, lua_tostring(L, -1)); lua_pop(L, 1); } usl = usl->next; @@ -782,99 +2258,116 @@ static void uwsgi_lua_init_state(lua_State **Ls, int wid, int sid, int cores) { uslnargs = lua_gettop(L) - uslnargs; - if (ulua.filename) { - if (luaL_loadfile(L, ulua.filename)) { - uwsgi_log("unable to load Lua file %s: %s\n", ulua.filename, lua_tostring(L, -1)); - lua_pop(L, 1); + if (ulua.wsapi) { + if (luaL_loadfile(L, ulua.wsapi)) { + ulua_log("unable to load Lua file %s: %s", ulua.wsapi, lua_tostring(L, -1)); + lua_pop(L, uslnargs + 1); + uslnargs = 0; } else { - if (lua_pcall(L, uslnargs, 1, 0) != 0) { - uwsgi_log("%s\n", lua_tostring(L, -1)); + // put function before args + if (uslnargs > 0) { + lua_insert(L, -uslnargs - 1); + } + + if (lua_pcall(L, uslnargs, 1, 0)) { + ulua_log("unable to load Lua file %s: %s", ulua.wsapi, lua_tostring(L, -1)); lua_pop(L, 1); uslnargs = 0; } else { uslnargs = 1; } } - } - - //we need only one, the last one - if (uslnargs > 1) { - lua_replace(L, -uslnargs); - - if (uslnargs > 2) { - lua_pop(L, uslnargs - 2); - } + } else { + lua_pop(L, uslnargs); + uslnargs = 0; } // table ?? - if (lua_istable(L, -1)) { + if (uslnargs > 0 && lua_istable(L, -1)) { lua_pushstring(L, "run"); lua_gettable(L, -1); lua_replace(L, -1); } // no app ??? - if (uslnargs == 0 || !lua_isfunction(L, -1)) { - // loading dummy - if (uslnargs > 0) { - lua_pop(L, uslnargs); - } - - uwsgi_log("Can't find WSAPI entry point (no function, nor a table with function'run').\n"); - i = luaL_dostring(L, "return function() return '500'; end"); + if (!uslnargs || !lua_isfunction(L, -1)) { + lua_pop(L, uslnargs); + ulua_log("Can't find WSAPI entry point (no function, nor a table with function'run')."); + ulua.wsapi = 0; + } else { + lua_rawseti(L, LUA_REGISTRYINDEX, ULUA_WSAPI_REF); } - lua_rawseti(L, LUA_REGISTRYINDEX, 1); - - //init additional threads for current worker - if(cores > 0) { - - lua_newtable(L); - - for(i=1;ivalue) || lua_pcall(L, 0, 0, 0)) { + ulua_log("unable to load Lua file %s: %s", usl->value, lua_tostring(L, -1)); + lua_pop(L, 1); } - - lua_setfield(L, -2, "luathreads"); + usl = usl->next; } - - // and the worker is ready! - //lua_remove(L, -2); - lua_pop(L, 1); + // and the worker is ready! lua_gc(L, LUA_GCCOLLECT, 0); +} + +static void uwsgi_lua_request_headers_nested_tables(lua_State *L, int8_t table, struct wsgi_request *wsgi_req, char *header, size_t len) { + + size_t i, rlen; + char *rheader; + + size_t tlen = lua_rawlen(L, table); - uwsgi_log("inited lua_State %d for worker %d\n", sid, wid); + for (i = 1; i <= tlen; i++) { + lua_rawgeti(L, table, i); + + if (lua_istable(L, -1)) { + uwsgi_lua_request_headers_nested_tables(L, -1, wsgi_req, header, len); + } else { + rheader = (char *) lua_tolstring(L, -1, &rlen); + uwsgi_response_add_header(wsgi_req, header, len, rheader, rlen); + } + + lua_pop(L, 1); + } } static int uwsgi_lua_request(struct wsgi_request *wsgi_req) { - int i; const char *http, *http2; - size_t slen, slen2; + size_t i, slen, slen2; + + if(!ulua.wsapi) { + ulua_log("worker%d[%d]: No WSAPI App. skip.", uwsgi.mywid, wsgi_req->async_id); + return -1; + } + lua_State *L = ULUA_WORKER_STATE[wsgi_req->async_id]; + /* Standard WSAPI request */ + if (!wsgi_req->len) { + ulua_log("worker%d[%d]: Empty lua request. skip.", uwsgi.mywid, wsgi_req->async_id); + return -1; + } + if (wsgi_req->async_status == UWSGI_AGAIN) { - if (lua_type(L, -1) != LUA_TFUNCTION) { - // wrong async_status status! - return -1; - } -async_coroutine: - while (lua_pcall(L, 0, 1, 0) == 0) { - if (lua_isstring(L, -1)) { - http = lua_tolstring(L, -1, &slen); - uwsgi_response_write_body_do(wsgi_req, (char *)http, slen); - } else if (lua_isnil(L, -1)) { // posible dead coroutine - lua_pop(L, 1); - lua_pushvalue(L, -1); - continue; // retry + while (!lua_pcall(L, 0, 1, 0)) { + switch(lua_type(L, -1)) { + case LUA_TNIL: // posible dead coroutine + + lua_pop(L, 1); + lua_pushvalue(L, -1); + continue; // retry + + case LUA_TTABLE: if(!(uwsgi_lua_metatable_tostring(L, -1))) break; + case LUA_TSTRING: + case LUA_TNUMBER: + + http = lua_tolstring(L, -1, &slen); + uwsgi_response_write_body_do(wsgi_req, (char *)http, slen); + } lua_pop(L, 1); @@ -884,126 +2377,155 @@ async_coroutine: goto clear; } - /* Standard WSAPI request */ - if (!wsgi_req->len) { - uwsgi_log( "Empty lua request. skip.\n"); - return -1; - } - if (uwsgi_parse_vars(wsgi_req)) { return -1; } // put function in the stack - //lua_getfield(L, LUA_GLOBALSINDEX, "run"); - lua_rawgeti(L, LUA_REGISTRYINDEX, 1); - //lua_pushvalue(L, -1); + lua_rawgeti(L, LUA_REGISTRYINDEX, ULUA_WSAPI_REF); // put cgi vars in the stack - - lua_newtable(L); + lua_createtable(L, 0, wsgi_req->var_cnt + 2); + lua_pushstring(L, ""); lua_setfield(L, -2, "CONTENT_TYPE"); - for(i=0;ivar_cnt;i+=2) { + for(i = 0; i < wsgi_req->var_cnt; i+=2) { lua_pushlstring(L, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len); lua_pushlstring(L, wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len); lua_rawset(L, -3); } - // put "input" table - lua_newtable(L); + lua_createtable(L, 0, 1); lua_pushcfunction(L, uwsgi_lua_input); lua_setfield(L, -2, "read"); lua_setfield(L, -2, "input"); #ifdef UWSGI_DEBUG - uwsgi_log("stack pos %d\n", lua_gettop(L)); + ulua_log("stack pos %d", lua_gettop(L)); #endif // call function - - if (lua_pcall(L, 1, 3, 0) != 0) { - uwsgi_log("%s\n", lua_tostring(L, -1)); + if (lua_pcall(L, 1, 4, 0)) { + ulua_log("worker%d[%d]: %s", uwsgi.mywid, wsgi_req->async_id, lua_tostring(L, -1)); lua_pop(L, 1); - lua_pushvalue(L, -1); goto clear2; } - //uwsgi_log("%d %s %s %s\n",i,lua_typename(L, lua_type(L, -3)), lua_typename(L, lua_type(L, -2)) , lua_typename(L, lua_type(L, -1))); +#ifdef UWSGI_DEBUG + ulua_log("%s %s %s %s", lua_typename(L, lua_type(L, -4)), lua_typename(L, lua_type(L, -3)), lua_typename(L, lua_type(L, -2)) , lua_typename(L, lua_type(L, -1))); +#endif // send status - if (lua_isstring(L, -3)) { - http = lua_tolstring(L, -3, &slen); - if (uwsgi_response_prepare_headers(wsgi_req, (char *) http, slen)) - goto clear2; + http = lua_tolstring(L, -4, &slen); + + if (!slen) { + ulua_log("worker%d[%d]: invalid response status!", uwsgi.mywid, wsgi_req->async_id); } - else { - uwsgi_log("[uwsgi-lua] invalid response status !!!\n"); - // let's continue + + if (uwsgi_response_prepare_headers(wsgi_req, (char *) http, slen)) { + lua_pop(L, 4); + return -1; } // send headers - if (lua_type(L, -2) == LUA_TTABLE) { + if (lua_istable(L, -3)) { + lua_pushnil(L); - while(lua_next(L, -3) != 0) { - http = lua_tolstring(L, -2, &slen); + + while(lua_next(L, -4)) { + + // lua_tolstring may change the 'lua_next' sequence, if the key is not a string, by modifying it + lua_pushvalue(L, -2); + // so -1 is key, -2 is value + http = lua_tolstring(L, -1, &slen); - if (lua_type(L, -1) == LUA_TTABLE) { - for (i = 1; /*empty*/ ; ++i) { - lua_rawgeti(L, -1, i); - - if (lua_isnil(L, -1)) { - lua_pop(L, 1); - break; - } - - http2 = lua_tolstring(L, -1, &slen2); - uwsgi_response_add_header(wsgi_req, (char *) http, slen, (char *) http2, slen2); - lua_pop(L, 1); - } - } - else { - http2 = lua_tolstring(L, -1, &slen2); + if (lua_istable(L, -2)) { + + uwsgi_lua_request_headers_nested_tables(L, -2, wsgi_req, (char *) http, slen); + } else { + + http2 = lua_tolstring(L, -2, &slen2); uwsgi_response_add_header(wsgi_req, (char *) http, slen, (char *) http2, slen2); } - lua_pop(L, 1); + + lua_pop(L, 2); } } // send body with coroutine or copy from string - lua_pushvalue(L, -1); - if (lua_type(L, -1) == LUA_TFUNCTION) { - if (uwsgi.async > 0) { - goto async_coroutine; - } - - while ( lua_pcall(L, 0, 1, 0) == 0) { - if (lua_isstring(L, -1)) { - http = lua_tolstring(L, -1, &slen); - uwsgi_response_write_body_do(wsgi_req, (char *)http, slen); + switch(lua_type(L, -2)) { + case LUA_TFUNCTION: + + // initing coroutine: + // pushing first argument of coroutine and call it fisrt time: + + lua_pushvalue(L, -2); + lua_pushvalue(L, -2); + + if(!lua_pcall(L, 1, 1, 0)) { + switch(lua_type(L, -1)) { + case LUA_TTABLE: if(!(uwsgi_lua_metatable_tostring(L, -1))) break; + case LUA_TSTRING: + case LUA_TNUMBER: + + http = lua_tolstring(L, -1, &slen); + uwsgi_response_write_body_do(wsgi_req, (char *) http, slen); + + } + } else { + ulua_log("worker%d[%d]: init-coroutine: %s", uwsgi.mywid, wsgi_req->async_id, lua_tostring(L, -1)); + lua_pop(L, 1); + break; } - lua_pop(L, 1); + lua_pop(L, 2); lua_pushvalue(L, -1); - } - } - else if (lua_isstring(L, -1)) { - http = lua_tolstring(L, -1, &slen); - uwsgi_response_write_body_do(wsgi_req, (char *) http, slen); + + // continue coroutine + + if (uwsgi.async > 0) { + return UWSGI_AGAIN; + } + + while (!lua_pcall(L, 0, 1, 0)) { + switch(lua_type(L, -1)) { + + case LUA_TTABLE: if(!(uwsgi_lua_metatable_tostring(L, -1))) break; + case LUA_TSTRING: + case LUA_TNUMBER: + + http = lua_tolstring(L, -1, &slen); + uwsgi_response_write_body_do(wsgi_req, (char *) http, slen); + + } + + lua_pop(L, 1); + lua_pushvalue(L, -1); + } + + break; + + case LUA_TTABLE: if(!(uwsgi_lua_metatable_tostring(L, -2))) break; + case LUA_TSTRING: + case LUA_TNUMBER: + + http = lua_tolstring(L, -2, &slen); + uwsgi_response_write_body_do(wsgi_req, (char *) http, slen); } clear: lua_pop(L, 4); clear2: // set frequency - if (!ulua.gc_freq || + if (ulua.gc_freq && (ulua.gc_freq == 1 || (uwsgi.threads == 1 && uwsgi.workers[uwsgi.mywid].requests % ulua.gc_freq == 0) || - (uwsgi.threads > 1 && uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].requests % ulua.gc_freq == 0)) { - lua_gc(L, ulua.gc_full, 0); + (uwsgi.threads > 1 && uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].requests % ulua.gc_freq == 0))) + { + lua_gc(L, ulua.gc_perform, 0); } return UWSGI_OK; @@ -1018,15 +2540,13 @@ static void uwsgi_lua_after_request(struct wsgi_request *wsgi_req) { static int uwsgi_lua_magic(char *mountpoint, char *lazy) { - if (!strcmp(lazy+strlen(lazy)-4, ".lua")) { - ulua.filename = lazy; - return 1; - } - else if (!strcmp(lazy+strlen(lazy)-3, ".ws")) { - ulua.filename = lazy; - return 1; - } - + if( !strcmp(lazy+strlen(lazy)-4, ".lua") || + !strcmp(lazy+strlen(lazy)-5, ".luac") || + !strcmp(lazy+strlen(lazy)-3, ".ws")) + { + ulua.wsapi = lazy; + return 1; + } return 0; } @@ -1039,14 +2559,14 @@ static char *uwsgi_lua_code_string(char *id, char *code, char *func, char *key, L = luaL_newstate(); luaL_openlibs(L); if (luaL_loadfile(L, code) || lua_pcall(L, 0, 0, 0)) { - uwsgi_log("unable to load file %s: %s\n", code, lua_tostring(L, -1)); + ulua_log("unable to load file %s: %s", code, lua_tostring(L, -1)); lua_close(L); L = NULL; return NULL; } lua_getglobal(L, func); if (!lua_isfunction(L,-1)) { - uwsgi_log("unable to find %s function in lua file %s\n", func, code); + ulua_log("unable to find %s function in lua file %s", func, code); lua_close(L); L = NULL; return NULL; @@ -1061,11 +2581,11 @@ static char *uwsgi_lua_code_string(char *id, char *code, char *func, char *key, lua_pushlstring(L, key, keylen); #ifdef UWSGI_DEBUG - uwsgi_log("stack pos %d %.*s\n", lua_gettop(L), keylen, key); + ulua_log("stack pos %d %.*s", lua_gettop(L), keylen, key); #endif - if (lua_pcall(L, 1, 1, 0) != 0) { - uwsgi_log("error running function `f': %s", lua_tostring(L, -1)); + if (lua_pcall(L, 1, 1, 0)) { + ulua_log("error running function `f': %s", lua_tostring(L, -1)); return NULL; } @@ -1080,71 +2600,108 @@ static char *uwsgi_lua_code_string(char *id, char *code, char *func, char *key, static int uwsgi_lua_signal_handler(uint8_t sig, void *handler) { - struct wsgi_request *wsgi_req = current_wsgi_req(); + lua_State *L = NULL; - lua_State *L = ULUA_WORKER_STATE[wsgi_req->async_id]; - + if (uwsgi.mywid == 0) { + if (!uwsgi.muleid) { + return -1; + } + + L = ULUA_MULE_STATE; + + if (!L) { // mule without lua_State + ulua_log("signal: can't handle signal on mule%d without lua_State", uwsgi.muleid); + return -1; + } + + } else { + + if (!ulua.state) { + ulua_log("signal: can't handle signal on worker%d without lua_State(s)", uwsgi.mywid); + return -1; + } + + struct wsgi_request *wsgi_req = current_wsgi_req(); + + L = ULUA_WORKER_STATE[wsgi_req->async_id]; + #ifdef UWSGI_DEBUG - uwsgi_log("managing signal handler on core %d\n", wsgi_req->async_id); + ulua_log("managing signal handler on core %d", wsgi_req->async_id); #endif + } - lua_rawgeti(L, LUA_REGISTRYINDEX, (long) handler); - + int type; + + lua_rawgeti(L, LUA_REGISTRYINDEX, ULUA_SIGNAL_REF); lua_pushnumber(L, sig); + lua_gettable(L, -2); - if (lua_pcall(L, 1, 1, 0) != 0) { - uwsgi_log("error running function `f': %s", - lua_tostring(L, -1)); + type = lua_type(L, -1); + if (!(type == LUA_TFUNCTION) && !(type == LUA_TTABLE && uwsgi_lua_metatable_call(L, -1))) { + ulua_log("signal: attempt to call a %s value", lua_typename(L, type)); + lua_pop(L, 2); return -1; } + lua_pushnumber(L, sig); + + if (lua_pcall(L, 1 + (type == LUA_TTABLE), 0, 0)) { + ulua_log("signal: error running signal function: %s", lua_tostring(L, -1)); + lua_pop(L, 2); + return -1; + } + + lua_pop(L, 2); return 0; - } static uint64_t uwsgi_lua_rpc(void * func, uint8_t argc, char **argv, uint16_t argvs[], char **buffer) { - uint8_t i; - const char *sv; - size_t sl; - long lfunc = (long) func; - int ifunc = lfunc; + uint8_t i; + const char *sv; + size_t sl; + int type; struct wsgi_request *wsgi_req = current_wsgi_req(); lua_State *L = ULUA_WORKER_STATE[wsgi_req->async_id]; - -#ifdef UWSGI_DEBUG - uwsgi_log("get function %d\n", ifunc); -#endif - lua_rawgeti(L, LUA_REGISTRYINDEX, ifunc); - - for(i=0;i 0) { - *buffer = uwsgi_malloc(sl); - memcpy(*buffer, sv, sl); - lua_pop(L, 1); - return sl; + *buffer = uwsgi_malloc(sizeof(char) * sl); + memcpy(*buffer, sv, sizeof(char) * sl); } - lua_pop(L, 1); - return 0; - + lua_pop(L, 2); + + return sl; } static void uwsgi_lua_configurator_array(lua_State *L) { @@ -1206,7 +2763,7 @@ static void uwsgi_lua_configurator(char *filename, char *magic_table[]) { char *value = uwsgi_str((char *)lua_tostring(L, -1)); add_exported_option(key, value, 0); lua_pop(L, 1); - } + } } else { char *value = uwsgi_str((char *)lua_tostring(L, -1)); @@ -1220,38 +2777,69 @@ static void uwsgi_lua_configurator(char *filename, char *magic_table[]) { lua_close(L); } -static void uwsgi_register_lua_features() { +static void uwsgi_register_lua_features() { + uwsgi_register_configurator(".luac", uwsgi_lua_configurator); uwsgi_register_configurator(".lua", uwsgi_lua_configurator); + + // non zero or non inited defaults: + ulua.gc_freq = ULUA_OPTDEF_GC_FREQ; } static void uwsgi_lua_hijack(void) { - if (ulua.shell && uwsgi.mywid == 1) { - uwsgi.workers[uwsgi.mywid].hijacked = 1; - uwsgi.workers[uwsgi.mywid].hijacked_count++; - // re-map stdin to stdout and stderr if we are logging to a file - if (uwsgi.logfile) { - if (dup2(0, 1) < 0) { - uwsgi_error("dup2()"); - } - if (dup2(0, 2) < 0) { - uwsgi_error("dup2()"); - } - } - int ret = -1; + + if (ulua.shell && uwsgi.mywid == 1) { + + if (ulua.shell_oneshot && uwsgi.workers[uwsgi.mywid].hijacked_count > 0) { + uwsgi.workers[uwsgi.mywid].hijacked = 0; + return; + } + + uwsgi.workers[uwsgi.mywid].hijacked = 1; + uwsgi.workers[uwsgi.mywid].hijacked_count++; + // re-map stdin to stdout and stderr if we are logging to a file + if (uwsgi.logfile) { + if (dup2(0, 1) < 0) { + uwsgi_error("dup2()"); + } + if (dup2(0, 2) < 0) { + uwsgi_error("dup2()"); + } + } + // run in the first state lua_State *L = ULUA_WORKER_STATE[0]; lua_getglobal(L, "debug"); lua_getfield(L, -1, "debug"); - ret = lua_pcall(L, 0, 0, 0); - if (ret == 0) { - exit(UWSGI_QUIET_CODE); - } - exit(0); - } + + ulua_log("Hallo, this is lua debug.debug() aka lua_debug, use Control+D to %s", + (ulua.shell_oneshot || uwsgi.master_process) ? "resume" : "exit"); + + if (lua_pcall(L, 0, 0, 0)) { + ulua_log("unable to call 'debug.debug()': %s", lua_tostring(L, -1)); + } + if (ulua.shell_oneshot || uwsgi.master_process) { // master will respawn it anyway + + uwsgi.workers[uwsgi.mywid].hijacked = 0; + + uwsgi_log("\n"); + ulua_log("worker %d has been resumed...", uwsgi.mywid); + + return; + } + + exit(UWSGI_QUIET_CODE); + + } } + static void uwsgi_lua_init_apps() { + + if (!ULUA_WORKER_ANYAPP) { + return; + } + int i,j,sid; //cores per lua thread @@ -1264,6 +2852,7 @@ static void uwsgi_lua_init_apps() { uwsgi_lua_init_state(&(ULUA_WORKER_STATE[i]), uwsgi.mywid, sid + i, cores); } + ulua_log("inited %d lua_State(s) for worker %d", uwsgi.threads, uwsgi.mywid); } else { for(j=0;j