lua-users home
lua-l archive

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


>>>>> "Lubos" == Lubos Uhliarik <luhliari@redhat.com> writes:

 Lubos> The problem is, httpd is not possible to build with new Lua 5.4,
 Lubos> since in mod_lua there are like 5 lua_resume calls. There is
 Lubos> already macro:

 Lubos> #define lua_resume(a,b)    lua_resume(a, NULL, b)

 Lubos> Is there any chance, to solve this issue only by using macro?
 Lubos> Something like:

 Lubos> #if LUA_VERSION_NUM > 503
 Lubos> #define lua_resume(a,b)    lua_resume(a, NULL, b, NULL)
 Lubos> #else
 Lubos> #define lua_resume(a,b)    lua_resume(a, NULL, b)
 Lubos> #endif

The right way to do this is to do it the other way round: rewrite the
code as if it were for lua 5.4, and then use macros to emulate the _new_
behavior on older systems.

/*
 * Handle API differences for lua_resume by emulating the 5.4 API on earlier
 * versions.
 */
#if LUA_VERSION_NUM < 504
static inline int
my_lua_resume(lua_State *L, lua_State *from, int nargs, int *nret)
{
#if LUA_VERSION_NUM == 501
        int rc = (lua_resume)(L, nargs);
#else
        int rc = (lua_resume)(L, from, nargs);
#endif
        *nret = lua_gettop(L);
        return rc;
}
#define lua_resume(L_,f_,a_,r_) (my_lua_resume(L_,f_,a_,r_))
#endif

But it looks like mod_lua is making several assumptions that will cause
problems with 5.4. The minor one is in passing NULL as the "from"
parameter in lua_resume; in 5.4 this will cause the coroutine to be
invoked with only a very small limit (8 calls) for the C stack nesting
depth, which now impacts the maximum function call nesting in pure Lua
code as well (80 calls).

The major one is that it's assuming that the first yielded value, if
any, from a coroutine is ending up in stack position 1. e.g.:

        /* If Lua yielded, it means we have something to pass on */
        if (lua_resume(L, 0) == LUA_YIELD) {
            size_t olen;
            const char* output = lua_tolstring(L, 1, &olen);

So I think what I'd have done here is to create a resume_and_adjust
wrapper that resumes the coroutine and then adjusts the number of
results to the expected value, like lua_call does:

static inline int
resume_and_adjust(lua_State *L, lua_State *from, int nargs, int nret)
{
#if LUA_VERSION_NUM >= 504
    int actual_ret;
    int rc = (lua_resume)(L, from, nargs, &actual_ret);
    if (rc == 0 || rc == LUA_YIELD) {
        if (nret > actual_ret)
            luaL_checkstack(L, nret - actual_ret, NULL);
        lua_settop(L, lua_gettop(L) + nret - actual_ret);
    }
    return rc;
#else
#if LUA_VERSION_NUM == 501
    int rc = (lua_resume)(L, nargs);
#else
    int rc = (lua_resume)(L, from, nargs);
#endif
    if (rc == 0 || rc == LUA_YIELD)
        lua_settop(L, nret);
    return rc;
#endif
}
    
With this in hand, one can write:

        if (resume_and_adjust(L, from, 0, 1) == LUA_YIELD) {
            size_t olen;
            const char *output = lua_tolstring(L, -1, &olen);
            ...

BTW, I don't see anywhere in mod_lua that is actually cleaning up the
stack on this code path... not sure what's going on with that.

-- 
Andrew.