Its About Time – TINN Timers

The last time I wrote about time: Hurry Up and Wait –  TINN Timing the focus was on introducing the wait() function and explaining how that fits into the TINN scheduler in general.

Having a wait() function is a great low level primitive.  It allows you to pause execution for an amount of time, in a synchronous manner.  That will work well when you’re doing something serially and need to take break at specified intervals.  What if your usage pattern is more complex though?  More likely than not, if you’re writing a web server of some sort, you’ll be doing this sort of sequence:

if codeNotDoneAfter sometime then

cancel code


do other stuff while waiting

Basically, I need to do something like send off a web request.  If the request has not been satisfied within a specified amount of time, I want to cancel the operation.  I need to be able to do this asynchronously because I may have many requests in flight.  So, what to do?  I obviously need a Timer of some sort that will deal with this for me.

local Task = require("IOProcessor")

local Timer = {}
setmetatable(Timer, {
  __call = function(self, ...)
    return self:create(...)

local Timer_mt = {
  __index = Timer;

Timer.init = function(self,params)
  local obj = {
    Delay = params.Delay;
    Period = params.Period;
    Running = false;
    TimerFunc = params.TimerFunc;
  setmetatable(obj, Timer_mt);

  if self.Running then

  return obj;

Timer.create = function(self, ...)
  return self:init(...);

Timer.start = function(self)
  self.Running = true;

  local function closure()
    if self.Delay then

    if not self.Period then

    while self.Running do


Timer.stop = function(self)
  self.Running = false;

return Timer

To dissect, basically an object that provides easy wrapper convenience for the wait() function. You specify an initial delay, and a period and call the start() function. Start will spawn the actual function that is involved in doing the waiting and executing of the specified function.

Here is a simple use case:

-- test_Timer.lua

local Timer = require("Timer")

local function printThis(timer)

local function main()
  local timer = Timer {Delay = 1*1000, Period = 300, TimerFunc = printThis}


  -- wait a few seconds, then stop the time
  print("wait 4 seconds...")
  print("stop timer")

  -- Wait a few more seconds then exit
  print("wait 2 seconds...")


In this case, I create a timer that has an initial 1 second delay, and a period of 300 milliseconds. So, after the initial delay, the printThis() function will be called. Then every 300 milliseconds after that, it will be called again.

In the sample, the timer is started, which causes it to run independently of the main task. Within the main task, wait 4 seconds, then call the stop() function on the time. Wait two more seconds, and finally exit altogether. This shows that a timer can run independently. The function that is called can be anything. If you want the function to have some parameters, it is itself probably a closure (function within a function). Additionally, since the function is passed the timer as the only parameter, it can cause the timer to stop. Here’s another example where a timer is running, and will stop after a certain number has been reached.

local count = 0;
local function counter(timer)
  count = count + 1;
  if count >= 5 then
  print("counter: ",count)

local testCounter = function()
  local timer = Timer {Period = 200, TimerFunc = counter, Running=true}


The counter function is simple. Basically, increment a counter. Once it reaches 5, stop the time. Starting the counter in the first place is also fairly easy. Just set a period (forget the initial delay), tell it which function is to be executed every period, and set it to run automatically (without requiring an explicit ‘start()’).

This will call the function once every 200 milliseconds, and then quit. Nice to have.

With this little component in hand, you can probably imagine how I/O might be accomplished with timeouts. Basically, any I/O operation would look like:

function cancel(ioperator)
  local function closure(timer)
  return closure;

op = startioop(someparams)
timer=Timer{Delay=1000, TimerFunc=cancel(op), Running=true}

Here, a timer is created with a delay of one second. After one second, the timer fires and the cancel.closure() function is called. The operation is cancelled, if it’s not already done, and that’s the end of things. This assumes that there is no harm in canceling an already finished transaction.

Well, that’s just great. I/O with timeouts fully implemented in user space, asynchronous, and all that. This is a great thing for timers, io, and TINN code in general.

The only thing missing is the ability to do async on more than just sockets. So, next up is async ‘file’ I/O in general, of which sockets are a specialized subset.

Hurry Up and Wait – TINN Timing

Moving right along. First I needed to do basic networking. Starting at the lowest level of socket interaction, advancing up the stack through specific TCP and HTTP uses. Then back down to UDP.

With basic async networking covered, the next thing that comes up is timing. The general socket IO is covered. You can basically build an entire service using nothing more than asynchronous socket calls. But, most servers are more interesting than that. There are situations where you’ll want to cancel out an async operation if it’s taking too long, or you might want to perform some operation over time, repeatedly. So, clearly the TINN system needs some concept of time management.

Here’s the kind of code I would like to write in order to do something every 500 milliseconds:

require ("IOProcessor");

local test_wait = function(interval)
  while true do
    print(string.format("interval: %d", IOProcessor.Clock:Milliseconds()));


Basically, there is a new ‘wait()’ function. You give it a number of milliseconds, and it will suspend the coroutine you’re currently in for the given amount of time. This capability comes courtesy of some changes to the base scheduler. The changes are the following:

wait = function(millis)
  local nextTime = IOProcessor.Clock:Milliseconds() + millis;
  return IOProcessor:yieldUntilTime(nextTime);

IOProcessor.yieldUntilTime = function(self, atime)
  if self.CurrentFiber ~= nil then
    self.CurrentFiber.DueTime = atime;
    tabutils.binsert(self.FibersAwaitingTime, self.CurrentFiber, compareTaskDueTime);

    return self:yield();
  return false;

The yieldUntilTime() function will take the currently running fiber (coroutine) and put it into the list of FibersAwaitingTime. This is simply a table which is maintained in sorted order from lowest to highest. Once a fiber is placed on this list, it is no longer in the list of currently active fibers. it will sit on this list until it’s DueTime has passed.

The main scheduling loop will step through the fibers that are sitting in the AwaitingTime list using the following:

IOProcessor.stepTimeEvents = function(self)
  local currentTime = self.Clock:Milliseconds();

  -- traverse through the fibers that are waiting
  -- on time
  local nAwaiting = #self.FibersAwaitingTime;
  for i=1,nAwaiting do

    local fiber = self.FibersAwaitingTime[1];
    if fiber.DueTime <= currentTime then
      -- put it back into circulation
      fiber.DueTime = 0;

      -- Remove the fiber from the list of fibers that are
      -- waiting on time
      table.remove(self.FibersAwaitingTime, 1);

Basically, step through the list of fibers that are waiting for their wait time to expire. For all those that qualify, put them back into the list of active fibers by calling the ‘shcheduleFiber()’ function.

This begins to get very interesting I think. Of course once you create a timer, or even async i/o, you probably also want the ability to cancel such operations. But, that’s another matter.

Doing this little exercise, the scheduler begins to take on some more of the attributes of what you might find in the core OS. The big difference is that everything is done in the Lua space, and does not rely on OS primitives, so it is actually somewhat portable to other architectures. That’s a nice idea to have such a nice scheduler available across multiple LuaJIT environments.

While going through this exercise, I also started looking at other features of schedulers, thinking about priorities, and other factors that might go into a really good scheduler. So, at least one thing becomes apparent to me. Having this scheduler readily available and transformable in the Lua space makes it relatively easy to try out different scheduling techniques that will match the particular situation at hand. There is even the possibility of changing the scheduling algorithm dynamically based on attributes of the running system.

Exciting times.