/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * */ #include "suricata-common.h" #ifdef HAVE_LUAJIT #include "conf.h" #include "util-pool.h" #include "util-lua.h" #include "util-luajit.h" /** \brief lua_State pool * * Lua requires states to be alloc'd in memory <2GB. For this reason we * prealloc the states early during engine startup so we have a better chance * of getting the states. We protect the pool with a lock as the detect * threads access it during their init and cleanup. * * Pool size is automagically determined based on number of keyword occurrences, * cpus/cores and rule reloads being enabled or not. * * Alternatively, the "detect-engine.luajit-states" var can be set. */ static Pool *luajit_states = NULL; static pthread_mutex_t luajit_states_lock = SCMUTEX_INITIALIZER; static int luajit_states_cnt = 0; static int luajit_states_cnt_max = 0; static int luajit_states_size = 0; #define LUAJIT_DEFAULT_STATES 128 static void *LuaStatePoolAlloc(void) { return luaL_newstate(); } static void LuaStatePoolFree(void *d) { lua_State *s = (lua_State *)d; if (s != NULL) lua_close(s); } /** \brief Populate lua states pool * * \param num keyword instances * \param reloads bool indicating we have rule reloads enabled */ int LuajitSetupStatesPool(void) { int retval = 0; pthread_mutex_lock(&luajit_states_lock); if (luajit_states == NULL) { intmax_t cnt = 0; if (ConfGetInt("luajit.states", &cnt) != 1) { ConfNode *denode = NULL; ConfNode *decnf = ConfGetNode("detect-engine"); if (decnf != NULL) { TAILQ_FOREACH(denode, &decnf->head, next) { if (denode->val && strcmp(denode->val, "luajit-states") == 0) { ConfGetChildValueInt(denode, "luajit-states", &cnt); } } } } if (cnt == 0) { cnt = LUAJIT_DEFAULT_STATES; } luajit_states_size = cnt; luajit_states = PoolInit(0, cnt, 0, LuaStatePoolAlloc, NULL, NULL, NULL, LuaStatePoolFree); if (luajit_states == NULL) { SCLogError("luastate pool init failed, lua/luajit keywords won't work"); retval = -1; } if (retval == 0) { SCLogConfig("luajit states preallocated: %d", luajit_states_size); } } pthread_mutex_unlock(&luajit_states_lock); return retval; } void LuajitFreeStatesPool(void) { pthread_mutex_lock(&luajit_states_lock); if (luajit_states_cnt_max > luajit_states_size) { SCLogNotice("luajit states used %d is bigger than pool size %d. Set " "luajit.states to %d to avoid memory issues. " "See tickets #1577 and #1955.", luajit_states_cnt_max, luajit_states_size, luajit_states_cnt_max); } PoolFree(luajit_states); luajit_states = NULL; luajit_states_size = 0; luajit_states_cnt = 0; pthread_mutex_unlock(&luajit_states_lock); } lua_State *LuajitGetState(void) { lua_State *s = NULL; pthread_mutex_lock(&luajit_states_lock); if (luajit_states != NULL) { s = (lua_State *)PoolGet(luajit_states); if (s != NULL) { if (luajit_states_cnt == luajit_states_size) { SCLogWarning("luajit states pool size %d " "reached. Increase luajit.states config option. " "See tickets #1577 and #1955", luajit_states_size); } luajit_states_cnt++; if (luajit_states_cnt > luajit_states_cnt_max) luajit_states_cnt_max = luajit_states_cnt; } } pthread_mutex_unlock(&luajit_states_lock); return s; } void LuajitReturnState(lua_State *s) { if (s != NULL) { pthread_mutex_lock(&luajit_states_lock); PoolReturn(luajit_states, (void *)s); BUG_ON(luajit_states_cnt <= 0); luajit_states_cnt--; pthread_mutex_unlock(&luajit_states_lock); } } #endif /* HAVE_LUAJIT */