lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Disclaimer: I do not expect the following to be adopted by the Lua
team, but for those of use implementing it for ourselves, I would like
to initiate discussion on what the best implementation would be.

Hi Lua list,
I liked that disclaimer so much, I had to use it here again.

I work on a project where pre-emptive scheduling is needed for two reasons. Responding to external events (something like interrupts) and "bad" written code. It has to be said, that I have no control over the code that is run, so I can't avoid someone writing a "busy polling without yield" in his task. So don't try to convince my into using cooperative scheduling, it is not my decision anyway.

So what I did for Lua 5.1 is to patch the interpreter to implement what I needed. This worked, but had some problems (which I don't want to discuss here).
As in Lua 5.2 yielding is possible over pcalls and meta methods I tried a different approach here. I wrote a C hook that yields either when the task has run for to long or if an event is in the queue:

void l_counthook (lua_State *L, lua_Debug *ar)
{	
  if(HasEvent() ||
      (number_of_active_tasks>  1&&
       GetElapsedTaskTime()>   SliceTime)) {
  {
    lua_yield(L, 0);
  }
}

The code is quite straight forward, GetElapsedTaskTime returns the time that has been used by the C-Task that runs the interpreter.
The scheduler is quite simple as well:

void Scheduler() {
  while(HasEvent()) {
    ProcessEvent();
    while (NoActiveTasks() != 0&&  !HasEvent()) {
      ResetElapsedTime();
      lua_State *L = GetNextTask();
      switch(lua_resume(L, 0, 0)) {
        case LUA_OK:
          RemoveTask(L);
          break;
        case LUA_ERRRUN:
        case LUA_ERRMEM:
        case LUA_ERRGCMM:
        case LUA_ERRERR:
          PostError(L);
          break;
	default: break;
      }
   }
}

In reality the code is more complicated, but I tried to write down the essence of it.
ProcessEvent() removes the event from the queue, it might add a new Lua Task registers l_counthook and prepares the function to be called on the top of the stack.

So far my results are good with this approach. It works in all our programs I tested it so far, and it is as fast as my patched 5.1 Lua interpreter. I still wonder if there could be some pitfalls. Maybe there is any program state where the yield/resume could fail?

What I will do for certain is to patch a call l_counthook right into lvm.c luaV_execute for two reasons:
- I won't need the hook any more, so I can use hooks for my debugging functionality.
- I could make a little bit more efficient implementation as I can bypass all the hook conditions.

As I said, I am not asking for an implementation of this, I just would like to hear if there are some pitfalls that I should watch out for, or if anyone has some ideas for improvement.

Thomas