nfqws2: accept string or function in timer_set()

This commit is contained in:
bol-van
2026-06-22 19:45:43 +03:00
parent 8afe88dea7
commit c54533bbb2
7 changed files with 59 additions and 32 deletions
+4
View File
@@ -307,3 +307,7 @@ v0.9.4.3
1.0.2
* nfqws2: fix 60 msec lua-gc default to 60 sec
1.0.3
* nfqws2: accept string or function in timer_set(). remember function as a function, not as a string.
+2 -2
View File
@@ -2424,7 +2424,7 @@ function timer_set(name, func, period, oneshot, data)
```
* name - a unique timer name. If a timer with this name already exists, it is deleted and replaced with a new one. When replaced, the countdown restarts.
* func - the timer function name (string)
* func - the timer function. string or function. if it's a string function is resolved during timer_set call and remembered as a function, not as a string.
* period - the timer call frequency in milliseconds
* oneshot - a bool indicating whether the timer is single-shot (true) or periodic (false)
* data - an arbitrary variable passed to the [timer-function](#timer-function-prototype)
@@ -2451,7 +2451,7 @@ Returns table in case of success, nil otherwise.
| Field | Type | Description |
| :------ | :----- | :------------------ |
| name | string | unique timer name |
| func | string | timer function name |
| func | function | timer function |
| oneshot | bool | true = single shot timer, false = periodic timer |
| period | number | timer period in msec |
| fires | number | number of timer calls made |
+2 -2
View File
@@ -2584,7 +2584,7 @@ function timer_set(name, func, period, oneshot, data)
```
* name - уникальное имя таймера. если таймер с таким именем уже есть, он удаляется и замещается новым. При замещении отсчет времени начинается заново.
* func - имя таймер функции (string)
* func - таймер функция. string или function. в случае string функция ищется по имени в момент вызова timer_set и запоминается по ссылке, а не как строка.
* period - периодичность вызова таймера в миллисекундах
* oneshot - bool признак является ли таймер однократным (true) или периодическим (false)
* data - произвольная переменная, передаваемая [таймер-функции](#прототип-функции-таймера)
@@ -2611,7 +2611,7 @@ function timer_info(name)
| Поле | Тип | Описание |
| :------ | :----- | :------------------ |
| name | string | уникальное имя таймера |
| func | string | имя таймер функции |
| func | function | таймер функция |
| oneshot | bool | true = однократный таймер, false = периодический |
| period | number | период таймера в мсек |
| fires | number | количество выполненных вызовов таймера |
+10 -2
View File
@@ -914,7 +914,6 @@ function print_current_time()
end
function timer_info_print(tinfo)
print(" timer_info.name="..tinfo.name)
print(" timer_info.func="..tinfo.func)
print(" timer_info.period="..tinfo.period)
print(" timer_info.oneshot="..tostring(tinfo.oneshot))
print(" timer_info.fires="..tinfo.fires)
@@ -939,8 +938,17 @@ function timer2(name, data)
end
end
function test_timer(opts)
timer_set("t1","timer1",500,true,"sample_data");
-- anonymous function
timer_set("t0",function(name,data)
print("timer "..name.." fired. anonymous timer function")
print_current_time()
end,
100,true)
-- pass function as function
timer_set("t1",timer1,500,true,"sample_data");
local tbl = {n=0}
-- pass function through string name
timer_set("t2","timer2",700,false,tbl);
print("* timers\n")
+34 -9
View File
@@ -3795,16 +3795,31 @@ static int luacall_timer_set(lua_State *L)
LUA_STACK_GUARD_ENTER(L)
int argc=lua_gettop(L);
const char *name = luaL_checkstring(L,1);
const char *func = luaL_checkstring(L,2);
lua_Integer period = luaL_checkinteger(L,3);
if (period<10) luaL_error(L,"invalid timer period. must be >=10 ms");
bool oneshot = argc>=4 && lua_toboolean(L,4);
lua_getglobal(L, func);
bool is_f = lua_isfunction(L, -1);
lua_pop(L, 1);
if (!is_f) luaL_error(L, "timer function '%s' does not exist", func);
const char *func;
switch(lua_type(L,2))
{
case LUA_TSTRING:
func = lua_tostring(L,2);
lua_getglobal(L, func);
if (!lua_isfunction(L, -1))
{
lua_pop(L, 1);
luaL_error(L, "timer function '%s' does not exist", func);
}
break;
case LUA_TFUNCTION:
lua_pushvalue(L, 2);
break;
default:
luaL_error(L,"invalid timer function type");
}
const char *action;
timer_pool *timer = TimerPoolSearch(params.timers, name);
@@ -3816,15 +3831,20 @@ static int luacall_timer_set(lua_State *L)
else
action = "created";
timer = TimerPoolAdd(&params.timers, name, func, period, oneshot);
if (!timer) luaL_error(L,"could not create timer");
timer = TimerPoolAdd(&params.timers, name, period, oneshot);
if (!timer)
{
lua_pop(L, 1);
luaL_error(L,"could not create timer");
}
timer->func_ref = luaL_ref(L, LUA_REGISTRYINDEX);
if (argc>=5)
{
lua_pushvalue(L, 5);
timer->lua_ref = luaL_ref(L, LUA_REGISTRYINDEX);
}
DLOG("timer: '%s' %s. function '%s' period %llu oneshot %u\n", timer->str, action, timer->func, timer->period, timer->oneshot);
DLOG("timer: '%s' %s. period %llu oneshot %u\n", timer->str, action, timer->period, timer->oneshot);
params.timers_dirty = true;
LUA_STACK_GUARD_RETURN(L,0)
@@ -3853,7 +3873,12 @@ static void lua_push_timer_info(lua_State *L, const timer_pool *timer)
{
lua_newtable(L);
if (timer->str) lua_pushf_str(L, "name", timer->str);
if (timer->func) lua_pushf_str(L, "func", timer->func);
if (timer->func_ref!=LUA_NOREF)
{
lua_pushliteral(L, "func");
lua_rawgeti(L, LUA_REGISTRYINDEX, timer->func_ref);
lua_rawset(L,-3);
}
lua_pushf_lint(L, "period", timer->period);
lua_pushf_bool(L, "oneshot", timer->oneshot);
lua_pushf_lint(L, "fires", timer->fires);
+5 -15
View File
@@ -19,8 +19,8 @@ static unsigned int timer_n=0;
static void TimerPoolDestroyItem(timer_pool *elem)
{
free(elem->str);
free(elem->func);
luaL_unref(params.L, LUA_REGISTRYINDEX, elem->lua_ref);
luaL_unref(params.L, LUA_REGISTRYINDEX, elem->func_ref);
}
void TimerPoolDel(timer_pool **pp, timer_pool *p)
{
@@ -39,15 +39,11 @@ struct timer_pool *TimerPoolSearch(timer_pool *p, const char *str)
HASH_FIND_STR(p, str, elem_find);
return elem_find;
}
struct timer_pool *TimerPoolAdd(timer_pool **pp, const char *str, const char *func, uint64_t period, bool oneshot)
struct timer_pool *TimerPoolAdd(timer_pool **pp, const char *str, uint64_t period, bool oneshot)
{
ADD_STR_POOL(timer_pool, pp, str, strlen(str))
elem->lua_ref = LUA_NOREF;
if (!(elem->func = strdup(func)))
{
TimerPoolDel(pp,elem);
return NULL;
}
elem->func_ref = LUA_NOREF;
elem->period = period;
elem->oneshot = oneshot;
elem->bt_next = boottime_ms() + elem->period;
@@ -58,17 +54,11 @@ struct timer_pool *TimerPoolAdd(timer_pool **pp, const char *str, const char *fu
static bool TimerPoolRunTimer(timer_pool *p)
{
lua_getglobal(params.L, p->func);
if (!lua_isfunction(params.L, -1))
{
lua_pop(params.L, 1);
DLOG_ERR("timer: '%s' function '%s' does not exist\n",p->str,p->func);
return false;
}
lua_rawgeti(params.L, LUA_REGISTRYINDEX, p->func_ref);
lua_pushstring(params.L, p->str);
lua_rawgeti(params.L, LUA_REGISTRYINDEX, p->lua_ref);
p->fires++;
DLOG("\ntimer: '%s' function '%s' period %llu oneshot %u fires=%u\n",p->str,p->func,p->period,p->oneshot,p->fires);
DLOG("\ntimer: '%s' period %llu oneshot %u fires=%u\n",p->str,p->period,p->oneshot,p->fires);
int status = lua_pcall(params.L, 2, 0, 0);
if (status)
{
+2 -2
View File
@@ -7,7 +7,7 @@
typedef struct timer_pool {
char *str; /* key */
char *func;
int func_ref;
uint64_t period;
bool oneshot;
int lua_ref;
@@ -18,7 +18,7 @@ typedef struct timer_pool {
void TimerPoolDestroy(timer_pool **pp);
struct timer_pool *TimerPoolSearch(timer_pool *p, const char *str);
struct timer_pool *TimerPoolAdd(timer_pool **pp, const char *str, const char *func, uint64_t period, bool oneshot);
struct timer_pool *TimerPoolAdd(timer_pool **pp, const char *str, uint64_t period, bool oneshot);
void TimerPoolDel(timer_pool **pp, timer_pool *p);
// return next timer fire time
uint64_t TimerPoolRun(timer_pool **pp, bool *dirty, uint64_t bt);