#include #include #include #include #include #include "oct_timer.h" #include "oct_log.h" struct oct_timer_list_ oct_timer_list; int64_t prev_millis; int oct_timer_list_initialize() { OCT_LOG_INFO("Initializing timer list") oct_timer_list.size = 0; oct_timer_list.first = NULL; oct_timer_list.last = NULL; struct timespec now; timespec_get(&now, TIME_UTC); prev_millis = ((int64_t) now.tv_sec) * 1000 + ((int64_t) now.tv_nsec) / 1000000; return 1; } int oct_timer_list_deinitialize() { struct oct_timer_elem* crawler = oct_timer_list.first; while (crawler != NULL) { struct oct_timer_elem* temp = crawler->next; free(crawler); crawler = temp; } oct_timer_list.first = NULL; oct_timer_list.last = NULL; oct_timer_list.size = 0; return 1; } int oct_timer_register(lua_State *L) { // Gather the arguments char id[OCT_TIMER_MAXIMUM_ID_LENGTH]; int64_t millis; char function[OCT_TIMER_MAXIMUM_ID_LENGTH]; char argument[OCT_TIMER_MAXIMUM_ID_LENGTH]; strncpy(id, luaL_checkstring(L, -4), OCT_TIMER_MAXIMUM_ID_LENGTH); millis = luaL_checkinteger(L, -3); strncpy(function, luaL_checkstring(L, -2), OCT_TIMER_MAXIMUM_FUNCTION_NAME_LENGTH); strncpy(argument, luaL_checkstring(L, -1), OCT_TIMER_MAXIMUM_ARGUMENT_LENGTH); // Check for any duplicate ids in the list if (oct_timer_find(id)) { OCT_LOG_ERROR("Tried to register a timer with a duplicate ID"); lua_pushnil(L); return 1; } // We're good to go, insert at the end struct oct_timer_elem* e = (struct oct_timer_elem*)malloc(sizeof(struct oct_timer_elem)); strncpy(e->id, id, OCT_TIMER_MAXIMUM_ID_LENGTH); e->millis = millis; strncpy(e->lua_function, function, OCT_TIMER_MAXIMUM_FUNCTION_NAME_LENGTH); strncpy(e->lua_argument, argument, OCT_TIMER_MAXIMUM_ARGUMENT_LENGTH); if (!oct_timer_list.first) { oct_timer_list.first = e; } e->next = NULL; e->prev = oct_timer_list.last; if (oct_timer_list.last) { oct_timer_list.last->next = e; } oct_timer_list.last = e; oct_timer_list.size++; // not sure if i have to return something return 0; } struct oct_timer_elem* oct_timer_find(char* id) { struct oct_timer_elem* crawler = oct_timer_list.first; while (crawler != NULL) { if (strncmp(id, crawler->id, OCT_TIMER_MAXIMUM_ID_LENGTH) == 0) { return crawler; } crawler = crawler->next; } return NULL; } int oct_timer_unregister(char* id, int do_free) { struct oct_timer_elem* e = oct_timer_find(id); if (!e) { OCT_LOG_WARNING("Tried to unregister a nonexistent timer"); return 0; } if (e == oct_timer_list.first) { oct_timer_list.first = e->next; if (e->next) { e->next->prev = NULL; } } else if (e == oct_timer_list.last) { oct_timer_list.last = e->prev; if (e->prev) { e->prev->next = NULL; } } else { e->next->prev = e->prev; e->prev->next = e->next; } oct_timer_list.size--; if (do_free) { free(e); } // Not sure if I have to return something return 0; } int oct_timer_unregister_lua(lua_State *L) { char id[OCT_TIMER_MAXIMUM_ID_LENGTH]; strncpy(id, luaL_checkstring(L, -1), OCT_TIMER_MAXIMUM_ID_LENGTH); int res = oct_timer_unregister(id, 1); if (!res) { lua_pushnil(L); return 1; } return 0; } int oct_timer_initialize_lua(lua_State *L) { OCT_LOG_INFO("Exporting timer lua functions"); lua_pushcfunction(L, oct_timer_register); lua_setglobal(L, "oct_timer_register"); lua_pushcfunction(L, oct_timer_unregister_lua); lua_setglobal(L, "oct_timer_unregister"); // I don't think we need a metatable... return 1; } int oct_timer_tick(lua_State *L) { struct timespec now; timespec_get(&now, TIME_UTC); int64_t millis = ((int64_t) now.tv_sec) * 1000 + ((int64_t) now.tv_nsec) / 1000000; int64_t elapsed = millis - prev_millis; struct oct_timer_elem* crawler = oct_timer_list.first; while (crawler != NULL) { crawler->millis -= elapsed; if (crawler->millis <= 0) { struct oct_timer_elem* temp = crawler; crawler = crawler->next; // First, remove the timer // lua can add a timer at the end of the function, don't want to complicate things by making the developer come up with a unique name // So we unregister it, but don't free it yet oct_timer_unregister(temp->id, 0); // call lua function with argument lua_getglobal(L, temp->lua_function); lua_pushstring(L, temp->lua_argument); lua_call(L, 1, 0); // Now free the timer free(temp); } else { crawler = crawler->next; } } prev_millis = millis; return 0; }