[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: coroutine.clone and stateful web applications
- From: Mike Pall <mikelu-0601@...>
- Date: Sat, 28 Jan 2006 23:14:25 +0100
Hi,
Markus Walther wrote:
> My central question therefore is: How difficult is it to make available
> the following new primitive
>
> independentCopyOfCo=coroutine.clone(co) ?
>
> It should be callable at any time during co's life.
See the attached experimental patch (relative to 5.1 rc). This
was a 10 minute hack, so I may not have gotten everything right.
Of course you can only clone suspended coroutines (after creation
or after yielding), i.e. not the currently running coroutine
(this would be like fork() -- doable, but not supported).
One semantic problem: open upvalues remain open only in the
original coroutine. This is usually what you want, but may yield
some semantic surprises (pun intended).
I suggest you play a little bit with it and report back to the
mailing list. I'd be interested to see the concept at work in a
non-trivial web application. Thank you!
Example program:
local resume, yield = coroutine.resume, coroutine.yield
local co1 = coroutine.create(function(x)
for i=1,10 do yield(x+i) end
return x+99
end)
local co2 = coroutine.clone(co1)
print("co1", resume(co1, 100))
print("co2", resume(co2, 200))
for i=1,5 do
print("co1", resume(co1))
print("co2", resume(co2))
end
local co3 = coroutine.clone(co2)
for i=1,5 do
print("co1", resume(co1))
print("co2", resume(co2))
print("co3", resume(co3))
end
Bye,
Mike
--- lua-5.1/src/lua.h 2006-01-10 13:50:13.000000000 +0100
+++ lua-5.1-clone/src/lua.h 2006-01-28 23:05:35.000000000 +0100
@@ -109,6 +109,7 @@
LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
LUA_API void (lua_close) (lua_State *L);
LUA_API lua_State *(lua_newthread) (lua_State *L);
+LUA_API lua_State *lua_clonethread (lua_State *L, lua_State *from);
LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
--- lua-5.1/src/lapi.c 2006-01-10 13:50:00.000000000 +0100
+++ lua-5.1-clone/src/lapi.c 2006-01-28 23:10:42.000000000 +0100
@@ -146,6 +146,46 @@
}
+LUA_API lua_State *lua_clonethread (lua_State *L, lua_State *from) {
+ lua_State *to;
+ lua_lock(L);
+ if (!(from->status == LUA_YIELD ||
+ (from->status == 0 && from->ci == from->base_ci)))
+ luaG_runerror(L, "attempt to clone uncloneable coroutine");
+ lua_unlock(L);
+ to = lua_newthread(L);
+ lua_lock(to);
+ luaD_reallocstack(to, from->stacksize - EXTRA_STACK - 1);
+ luaD_reallocCI(to, from->size_ci);
+ { /* Copy stack slots. */
+ TValue *f, *t;
+ for (f = from->stack, t = to->stack; f < from->top; f++, t++)
+ setobjs2s(to, t, f);
+ to->top = t;
+ for (; f < from->ci->top; f++, t++)
+ setnilvalue(t);
+ to->base = (from->base - from->stack) + to->stack;
+ }
+ { /* Copy frames. */
+ CallInfo *f, *t;
+ for (f = from->base_ci, t = to->base_ci; f <= from->ci; f++, t++) {
+ t->base = (f->base - from->stack) + to->stack;
+ t->func = (f->func - from->stack) + to->stack;
+ t->top = (f->top - from->stack) + to->stack;
+ t->nresults = f->nresults;
+ t->savedpc = f->savedpc;
+ t->tailcalls = f->tailcalls;
+ }
+ to->ci = (from->ci - from->base_ci) + to->base_ci;
+ }
+ /* Copy misc fields. Hooks are deliberately not copied. */
+ to->status = from->status;
+ to->savedpc = from->savedpc;
+ lua_unlock(to);
+ return to;
+}
+
+
/*
** basic stack manipulation
--- lua-5.1/src/lbaselib.c 2006-01-18 12:49:12.000000000 +0100
+++ lua-5.1-clone/src/lbaselib.c 2006-01-28 23:06:34.000000000 +0100
@@ -592,6 +592,14 @@
}
+static int luaB_clone (lua_State *L) {
+ lua_State *co = lua_tothread(L, 1);
+ luaL_argcheck(L, co, 1, "coroutine expected");
+ lua_clonethread(L, co);
+ return 1;
+}
+
+
static const luaL_Reg co_funcs[] = {
{"create", luaB_cocreate},
{"resume", luaB_coresume},
@@ -599,6 +607,7 @@
{"status", luaB_costatus},
{"wrap", luaB_cowrap},
{"yield", luaB_yield},
+ {"clone", luaB_clone},
{NULL, NULL}
};