Re: French translation updated & Yet Another Scripting Idea.
Nicolas Noble <[email protected]> Tue, 08 Nov 2005 17:14:21 +0100
| Newsgroups | gmane.network.lftp.devel |
|---|---|
| Message-ID | <[email protected]> |
Alexander V. Lukyanov wrote:
> The time format is `ls' specific. I don't think it is available in locale
> information.
>
>
Okay, my bad for not digging enough :)
>> The only thing I am a bit affraid of would be to make LUA's coroutine
>> to work nicely within lftp's built-in thread system. I'd need to go
>> back
>
>
> That can be a problem indeed. Are LUA routines blocking?
>
>
Actually, yes, but, any LUA call "shouldn't" last long, that is, should
be considered atomic, somehow. Of course, you can't know if it's not
gonna stall. Since LUA, like any other language, isn't computable, you
can't know if you're not enter any endless loop. Okay, so, this returns
immediately:
$ lua -e "function calc (a,b) return a+b end; x = calc(12,24); print(x)"
36
And this should loop forever without any "direct way" to stop it:
$ lua -e "while true do end"
(even though there are ways to break it).
Now, in the usual way Lua works, it should call any function that the
host software binded. There, the called C functions are free to yeild
the current LUA thread, that is, freeze the VM nicely, and return to the
main software. Therefore, the Lua VM shouldn't stall in any normal
usage. It should rather return "very quickly", or call the hosts's
functions and 'block' there.
The way I roughly see it is the following:
1) consider that running a simple "runnable Lua class" wouldn't block
(atomic calls, if we forget about endless loops yet - even though this
might get solved by itself afterward, since it's somewhat possible to
force it to yield every XX instructions for example, but yet I am not
100% sure if this is safe, so maybe it's better to keep it for later).
So that this runnable Lua class wouldn't directly set up any wake-up
condition.
2) the Lua VM itself might call back some of the Lftp's functions, which
in turn would probably want to yield and set up wake-up conditions.
These conditions should be fowarded to the Lua class so that it gets
woken up correctly and try to execute the Do method of the class which
caused the yield. If the class still wants to sleep, repeat. Otherwise,
resume the Lua VM with the correct return. Since code is usually better
than english words, if you want a better idea about how the Lua
threading system works, you can read a complete example here:
http://paste.nobis-crew.org/51 and its results when run at:
http://paste.nobis-crew.org/52
Actually, given your next paragraph, there's something I still didn't
understand correctly: does a SMTask object has to set a wake-up
condition for "I want to be woken-up as soon as this object is in state
MOVED" ? Or would each SMTask object be woken-up as soon as any object
goes in MOVED state ?
> An "runnable" class is a derivative of SMTask. It has to implement Do
> method
> which is non-blocking, i.e. does not wait for external events itself.
> Instead,
> it sets wake-up condition (poll on a file descriptor, a timeout) and
> returns.
> It can return MOVED if it's internal state has changed so that other
> objects
> can check for it. STALL means that internal state has not changed
> significantly.
>
>
Okay, so, if I understand correctly, the pseudo-code I describe above at
2) would be (very very roughly - I haven't had time to dig your code in
full yet) something like
class LuaJob : public SMTask {
public:
int state;
bool done;
SMTask * subjob;
LuaJob() : state(INITIAL), done(false), subjob(0) {}
bool Done() { return done; }
int Do() {
switch(state) {
case INITIAL:
[... some lua init ...]
m = MOVED;
state = RUN_CODE;
case RUN_CODE:
if (lua_resume() == LUA_DONE) {
done = true;
state = ALL_DONE;
return m;
} else {
state = WAIT_FOR_JOB;
}
case WAIT_FOR_JOB:
if (!subjob->Done())
return m;
state = RUN_CODE;
delete subjob; // didn't notice that in your code yet ;
are the SMTask garbage-collected in the Scheduler ?
}
}
}
and any Lua binding would set up the caller's subjob to the actual
SMTask object the engine is waiting at, using a wrapper:
int wrapper_for_some_binding(lua_State * L) {
LuaJob * lj = findparent(L);
lj->subjob = new the_luaSMTask_for_that_binding(L);
return lua_yield(L, 0);
}
The "drawback" of this is that we have to create a lots of SMTask class,
one for each binding. But it makes sense anyway: the binding has to be a
task anyway since it'll most probably fire up some more atomic
subcommands in order to process the Lua's request.
Well, I am in the right direction or completely wrong understanding how
it should be handled ? :)
Cheers,
-- Nicolas Noble