[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: kill coroutine
- From: Rici Lake <lua@...>
- Date: Sun, 21 Aug 2005 10:32:00 -0500
On 21-Aug-05, at 8:18 AM, Mike Pall wrote:
But IMHO this only hides violations of
the referential model a bit longer. Not holding a reference
to a coroutine is a bug.
It's certainly a bug if you're planning on resuming the coroutine. If,
for some reason, you know that you're never going to resume the
coroutine, it's completely legitimate IMHO. (For example, you may have
a contract with the coroutine that it gets called with a special
message telling it to clean up because it is about to be terminated.)
Making the crash more likely (by
letting it happen even while the coroutine is running) may
lead to earlier discovery of the bug.
If the coroutine is running, then it's reachable, so the garbage
collector should mark it. Not doing so would be a violation of the gc
contract.
Unfortunately, just marking the currently running thread is not enough.
If I resume a luathread for which I have not kept a reference, and that
luathread uses the coroutine mechanism itself, then the atomic phase of
the garbage collection could take place in a subthread, as it were. The
subthread does not retain a reference to the invoking thread as far as
I can see, so it would then crash when it yielded.
This can't happen with a Lua program for the simple reason that it is
impossible to resume a coroutine without pushing the thread object (or
a wrapper to it) onto the stack, where it stays until the coroutine
yields. Consequently, there must be a chain of references from the main
thread's stack to the currently running thread.
So the root problem here is that luathreads (lua_State *) are the only
Lua internal object exposed to the API without being wrapped into the
Lua universe. Lua cannot know what lua_State*'s might be floating
around in a C executable, and so the gc cannot guarantee to mark them
all.
One possible workaround might be to change a luathread from a lua_State
* to a lua_State ** (but opaquely to the C program, so as not to tempt
fate). This would change the appearance of a program which used threads
a bit:
current:
lua_State *L1 = lua_newthread(L);
//...
lua_resume(L1, 0);
changes to:
lua_Thread *th = lua_newthread(L);
//...
lua_resume(lua_thread2state(L, th), 0);
where we have something like:
lua_State *lua_thread2state(lua_State *L, lua_Thread *th) {
if (**th == NULL)
lua_pushstring(L, "You seem to have lost the thread");
lua_error(L);
}
return **th;
}
Then the garbage collector could clear the lua_Thread handle when it
collected the lua_thread, and an error would be thrown if an attempt
were made to use it.