lua-users home
lua-l archive

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


Hi list,

I'm trying to port to C a framework of mine that is basically a
coroutine scheduler hidden under a pseudo-blocking I/O API (not mature
enough to be released, but ask for a URL if interested). I have
several pure-Lua implementations (with various backend dependencies),
and I'm trying to re-implement it in C. That was the perfect occasion
to dive into Lua 5.2's new lua_yieldk feature. But I'm faced with an
oddity, which I believe is either a bug or a documentation problem.

When a first call to lua_resume returns, only the yielded values are
on the stack. Any other values in the thread stack (in the
lua_CFunction that called lua_yieldk) are not accessible (but will be
in the continuation). So far so good. However if I let those return
values there, push a couple other ones, and call lua_resume with nargs
equal to 1 or 2, the continuation receives 1) the non returned value
from the initial coroutine resume at the bottom, 2) the nargs values
passed to the second resume at the top, but also 3) any other yielded
values, and any other pushed values before the second call to
lua_resume. In other words it seems the nargs of a second lua_resume
seems to be ignored, and all values on the thread stack at the moment
of the resume are passed to the continuation function.

Here is a small program showing the problem:

#include <lua.h>
#include <lauxlib.h>
#include <stdlib.h>

static int func_k1(lua_State* L)
{
    int i;
    printf("continuation got %d values\n", lua_gettop(L));
    for (i=1; i<=lua_gettop(L); ++i)
    {
        printf("\t%s %s\n", luaL_typename(L, i), lua_type(L,
i)==LUA_TSTRING ? lua_tostring(L, i) : "");
    }
    return 0;
}

static int func(lua_State* L)
{
    int i;
    lua_pushstring(L, "data 1");
    lua_pushstring(L, "data 2");
    lua_pushstring(L, "yielded value 1");
    lua_pushstring(L, "yielded value 2");
    printf("coroutine yields %d values out of %d:\n", 2, lua_gettop(L));
    for (i=1; i<=lua_gettop(L); ++i)
    {
        printf("\t%s %s\n", luaL_typename(L, i), lua_type(L,
i)==LUA_TSTRING ? lua_tostring(L, i) : "");
    }
    return lua_yieldk(L, 2, 0, func_k1);
}

int main()
{
    lua_State* L,* T;
    int result, i;
    L = luaL_newstate();
    T = lua_newthread(L);
    lua_pushcfunction(T, func);
    lua_pushstring(T, "starting value 1");
    lua_pushstring(T, "starting value 2");
    result = lua_resume(T, L, 2);
    if (result != 0 && result != LUA_YIELD)
        printf("error in first resume: %s\n", lua_tostring(T, -1));
    else
    {
        printf("main thread got %d values:\n", lua_gettop(T));
        for (i=1; i<=lua_gettop(T); ++i)
        {
            printf("\t%s %s\n", luaL_typename(T, i), lua_type(T,
i)==LUA_TSTRING ? lua_tostring(T, i) : "");
        }
    }
    lua_pushstring(T, "resumed value 1");
    lua_pushstring(T, "resumed value 2");
    printf("resuming with 1 argument out of %d:\n", lua_gettop(T));
    for (i=1; i<=lua_gettop(T); ++i)
    {
        printf("\t%s %s\n", luaL_typename(T, i), lua_type(T,
i)==LUA_TSTRING ? lua_tostring(T, i) : "");
    }
    result = lua_resume(T, L, 1);
    if (result != 0 && result != LUA_YIELD)
        printf("error in second resume: %s\n", lua_tostring(T, -1));
    lua_close(L);
    return 0;
}

And here is the output I get:

coroutine yields 2 values out of 6:
        string starting value 1
        string starting value 2
        string data 1
        string data 2
        string yielded value 1
        string yielded value 2
main thread got 2 values:
        string yielded value 1
        string yielded value 2
resuming with 1 argument out of 4:
        string yielded value 1
        string yielded value 2
        string resumed value 1
        string resumed value 2
continuation got 8 values
        string starting value 1
        string starting value 2
        string data 1
        string data 2
        string yielded value 1
        string yielded value 2
        string resumed value 1
        string resumed value 2

Instead I expected the last section to read:
continuation got 5 values
        string starting value 1
        string starting value 2
        string data 1
        string data 2
        string resumed value 2

Did I misinterpret something, or is there a problem somewhere (with
lua_resume, lua_yieldk, or the doc of one of these)?

Doub.