├── .gitignore ├── example.lua ├── README.md └── timer.lua /.gitignore: -------------------------------------------------------------------------------- 1 | /premake5.exe 2 | *.db 3 | *.opendb 4 | *.dll 5 | *.exp 6 | *.ilk 7 | *.lib 8 | *.pdb 9 | *.exe 10 | *.obj 11 | *.log 12 | *.tlog 13 | *.idb 14 | .vs/ 15 | bin/ 16 | obj/ 17 | -------------------------------------------------------------------------------- /example.lua: -------------------------------------------------------------------------------- 1 | local timer = require ('timer') 2 | 3 | local function co3() 4 | print("coroutine3 start",os.clock()) 5 | timer.sleep(5.5) 6 | print("coroutine3 5.5 second later",os.clock()) 7 | print("coroutine3 end") 8 | end 9 | 10 | --coroutine style timer 11 | timer.async(function() 12 | print("coroutine1 start",os.time()) 13 | timer.sleep(2) 14 | print("coroutine1 2 second later",os.time()) 15 | timer.async(co3) 16 | print("coroutine1 end") 17 | end) 18 | 19 | timer.async(function() 20 | print("coroutine2 start",os.time()) 21 | timer.sleep(1) 22 | print("coroutine2 1 second later",os.time()) 23 | timer.sleep(1) 24 | print("coroutine2 1 second later ",os.time()) 25 | timer.sleep(1) 26 | print("coroutine2 1 second later ",os.time()) 27 | timer.sleep(1) 28 | print("coroutine2 1 second later ",os.time() ) 29 | print("coroutine2 end") 30 | end) 31 | 32 | --callback style timer 33 | local stime = os.time() 34 | timer.timeout(1.5,function() 35 | print("timer expired", os.time() - stime) 36 | end) 37 | 38 | --remove a timer 39 | local ctx = timer.timeout(5,function() 40 | error("this timer shoud not expired") 41 | end) 42 | timer.remove(ctx) 43 | 44 | print("main thread noblock") 45 | --replace this while loop code, use your framework's update 46 | while true do 47 | timer.update() 48 | end 49 | 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lua_timer 2 | Pure lua implements timer ,support coroutine(with coroutine pool optimized) 3 | 4 | 5 | # Use 6 | 7 | **Call timer.update() in your framework's main loop/update** 8 | 9 | ```lua 10 | local os = require ('os') 11 | local timer = require ('timer') 12 | 13 | local function co3() 14 | print("coroutine3 start",os.clock()) 15 | timer.sleep(5.5) 16 | print("coroutine3 5.5 second later",os.clock()) 17 | print("coroutine3 end") 18 | end 19 | 20 | --coroutine style timer 21 | timer.async(function() 22 | print("coroutine1 start",os.time()) 23 | timer.sleep(2) 24 | print("coroutine1 2 second later",os.time()) 25 | timer.async(co3) 26 | print("coroutine1 end") 27 | end) 28 | 29 | timer.async(function() 30 | print("coroutine2 start",os.time()) 31 | timer.sleep(1) 32 | print("coroutine2 1 second later",os.time()) 33 | timer.sleep(1) 34 | print("coroutine2 1 second later ",os.time()) 35 | timer.sleep(1) 36 | print("coroutine2 1 second later ",os.time()) 37 | timer.sleep(1) 38 | print("coroutine2 1 second later ",os.time() ) 39 | print("coroutine2 end") 40 | end) 41 | 42 | --callback style timer 43 | local stime = os.time() 44 | timer.timeout(1.5,function() 45 | print("timer expired", os.time() - stime) 46 | end) 47 | 48 | --remove a timer 49 | local ctx = timer.timeout(5,function() 50 | error("this timer shoud not expired") 51 | end) 52 | timer.remove(ctx) 53 | 54 | print("main thread noblock") 55 | 56 | while true do 57 | timer.update() 58 | end 59 | 60 | ``` 61 | -------------------------------------------------------------------------------- /timer.lua: -------------------------------------------------------------------------------- 1 | local timers = {} 2 | 3 | local tbinsert = table.insert 4 | local tbremove = table.remove 5 | local ipairs = ipairs 6 | local xpcall = xpcall 7 | local traceback = debug.traceback 8 | 9 | local co_create = coroutine.create 10 | local co_running = coroutine.running 11 | local co_resume = coroutine.resume 12 | local co_yield = coroutine.yield 13 | 14 | ---you can replace this with your clock function 15 | local clock = os.clock 16 | 17 | local function insert_timer(sec, fn) 18 | local expiretime = clock() + sec 19 | local pos = 1 20 | for i, v in ipairs(timers) do 21 | if v.expiretime > expiretime then 22 | break 23 | end 24 | pos = i+1 25 | end 26 | local context = { expiretime =expiretime, fn = fn} 27 | tbinsert(timers, pos, context) 28 | return context 29 | end 30 | 31 | local co_pool = setmetatable({}, {__mode = "kv"}) 32 | 33 | local function coresume(co, ...) 34 | local ok, err = co_resume(co, ...) 35 | if not ok then 36 | error(traceback(co, err)) 37 | end 38 | return ok, err 39 | end 40 | 41 | local function routine(fn) 42 | local co = co_running() 43 | while true do 44 | fn() 45 | co_pool[#co_pool + 1] = co 46 | fn = co_yield() 47 | end 48 | end 49 | 50 | local M = {} 51 | 52 | function M.async(fn) 53 | local co = tbremove(co_pool) 54 | if not co then 55 | co = co_create(routine) 56 | end 57 | local _, res = coresume(co, fn) 58 | if res then 59 | return res 60 | end 61 | return co 62 | end 63 | 64 | ---@param seconds integer @duration in seconds,decimal part means millseconds 65 | ---@param fn function @ timeout callback 66 | function M.timeout(seconds, fn) 67 | return insert_timer(seconds, fn) 68 | end 69 | 70 | ---coroutine style 71 | ---@param seconds integer @duration in seconds,decimal part means millseconds 72 | function M.sleep(seconds) 73 | local co = co_running() 74 | insert_timer(seconds, function() 75 | co_resume(co) 76 | end) 77 | return co_yield() 78 | end 79 | 80 | function M.remove(ctx) 81 | ctx.remove = true 82 | end 83 | 84 | function M.update() 85 | while #timers >0 do 86 | local timer = timers[1] 87 | if timer.expiretime <= clock() then 88 | tbremove(timers,1) 89 | if not timer.remove then 90 | local ok, err = xpcall(timer.fn, traceback) 91 | if not ok then 92 | print("timer error:", err) 93 | end 94 | end 95 | else 96 | break 97 | end 98 | end 99 | end 100 | 101 | return M --------------------------------------------------------------------------------