[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Lua and preemptive scheduling for coroutines
- From: Tim Hill <drtimhill@...>
- Date: Thu, 28 Mar 2013 20:35:09 -0700
You're not going to be able to pull that one off. The fundamental structure of coroutines is different from threads, and nothing you do can really change that (aside from a VERY significant reworking of the Lua code base).
--Tim
On Mar 28, 2013, at 8:20 PM, Leo Romanoff <romixlev@yahoo.com> wrote:
> Hi,
>
> I'm a newbie to Lua and find the language and its implementation very interesting. In particular, I'm very interested in coroutines, because I think they can be nicely used to implement something like Erlang's actors or Akka's actors.
>
> I did a few tests to see what is possible with coroutines and what kind of overhead they introduce. So far I was able to create about 4 millions of coroutines on my development machine, which is not bad. The memory overhead per coroutine seems to be about 400 bytes for LuaJIT and a bit more for Lua.
>
> But now I have a usual question, which people ask when they start playing with coroutines - how can one implement the preemptive scheduling???
>
> Here is a list of my requirements:
>
> 1) I'd like to be able to introduce preemptive multitasking, i.e. transparently taking control from one coroutine and giving it to the other coroutine when a certain event happens. The event can be an external event or a timeout or may be a certain number of instructions executed. I don't like coroutines to explicitly call yield(). I'd like to "inject" it upon receiving such an event.
>
> 2) I'd like all this to be done in Lua, i.e. my coroutines are defined and implemented in Lua code. The scheduler or some of the hooks can be implemented in C, as a library that I use from Lua. But I'd like to avoid creating all the coroutines in C or doing any new development in C every time I write an application using preemptive coroutines.
>
> Of course, the most obvious way is to try achieving the goal by means of a "count" debug hook. And of course, when I try it out, I immediately run into the well-known "attempt to yield across metamethod/C-call boundary" error...
>
> I searched through the mailing list archives and I've seen that lua_yield() and lua_resume() in the C code could solve the preemption problem. But as far as I understand, it would require the inversion of control, so to say. I.e. my main code would be in C and this C code would create coroutines and perform scheduling. But this contradicts my requirement number 2. I'd really like to hide/eliminate the C part completely, if possible.
>
> So, I'd like to ask the question again:
> - Is it somehow possible to achieve both (1) and (2) at the same time?
>
> - As far as I understand, debug hooks are called not as usual Lua functions, but as C functions and this is the reason why coroutine.yield cannot be invoked from them. Is it correct understanding? But what if Lua could do something like this: debug_hook can set a certain flag, which is known to the Lua VM. After the hook returns (i.e. no C stack frames are active any more), the VM checks this flag before continuing execution of the Lua code as it usually does after hook invocations. If this flag is set, then Lua VM would simply execute coroutine.yield() in the context of a current coroutine, as if it is a next instruction in this coroutine. Would it work at all? Or may be there are some very subtle details, which I overlook?
>
> - Another idea could be to generalize the previous paragraph in the following way: Imagine, that when you define a debug hook you could optionally provide pre-processing and post-processing actions for a hook. Such actions are usual Lua functions. They are supposed to be executed before/after the hook is invoked in the context of the currently executed coroutine. If this would be possible, then my proposal from the previous paragraph would be as easy to implement as:
>
> -- Executed on the C-stack
> local function debug_hook()
> do_yield_flag = 1
> end
>
> -- Executed in the scope of current coroutine
> local function post_debug_hook()
> if (do_yield_flag) then coroutine.yield() end
> end
>
> local function pre_debug_hook()
> end
>
>
> -- Extended sethook API: pre and post hooks can be specified.
> -- They will be executed in the scope of the currently executed coroutine, when the debug hook is to be invoked
> debug.sethook(mycoroutine, debug_hook, pre_debug_hook, post_debug_hook, "count", 1000)
>
>
> BTW, with this solution the Lua VM does not even need to know about this special flag. It simply needs to execute a post-processing hook, if it was specified.
>
> Let me know what do you think of this?
>
> I do not say, it should be included into the official Lua VM implementation, though if it works it would be nice. I'm just asking if such a solution what be technically possible and feasible.
>
> Of course, suggestions of any alternative solutions are very welcome as well!
>
> Thanks,
> Leo
>
>