3

we are developing game server using lua.

the server is single threaded, we'll call lua from c++.

every c++ service will create a lua thread from a global lua state which is shared by all service.

the lua script executed by lua thread will call a c api which will make a rpc call to remote server.

then the lua thread is suspened, because it's c function never return.

when the rpc response get back, we'll continue the c code ,which will return to the lua script.

so, we will have multiple lua thread execute parallel on a same global lua state, but they will never run concurrently. and the suspend is not caused but lua yield function, but from the c side.

is it safe to do something like this?

#include <stdio.h>
#include <stdlib.h>
#include <ucontext.h>
#include "lua/lua.hpp"

static ucontext_t uctx_main, uctx_func1, uctx_func2;

lua_State* gLvm;
int gCallCnt = 0;

static int proc(lua_State *L) {
    int iID = atoi(lua_tostring(L, -1));

    printf("begin proc, %s\n", lua_tostring(L, -1));
    if(iID == 1)
    {
        swapcontext(&uctx_func1, &uctx_main);
    }
    else
    {
        swapcontext(&uctx_func2, &uctx_main);
    }
    printf("end proc, %s\n", lua_tostring(L, -1));
    return 0;  
}

static void func1(void)
{
    gCallCnt++;
    printf("hello, func1\n");

    lua_State*thread = lua_newthread (gLvm);

    lua_getglobal(thread, "proc");
    char szTmp[20];
    sprintf(szTmp, "%d", gCallCnt);
    lua_pushstring(thread, szTmp);
    int iRet = lua_resume(thread, gLvm, 1);
    printf("lua_resume return:%d\n", iRet);
}

static void func2(void)
{
    gCallCnt++;
    printf("hello, func2\n");

    lua_State*thread = lua_newthread (gLvm);

    lua_getglobal(thread, "proc");
    char szTmp[20];
    sprintf(szTmp, "%d", gCallCnt);
    lua_pushstring(thread, szTmp);
    int iRet = lua_resume(thread, gLvm, 1);
    printf("lua_resume return:%d\n", iRet);
}



int main(int argc, char *argv[]){
    int iRet = 0;

    gLvm = luaL_newstate();
    luaL_openlibs(gLvm);

    lua_pushcfunction(gLvm, proc);
    lua_setglobal(gLvm, "proc");

    char func1_stack[16384];
    char func2_stack[16384];
    getcontext(&uctx_func1);
    uctx_func1.uc_stack.ss_sp = func1_stack;
    uctx_func1.uc_stack.ss_size = sizeof(func1_stack);
    uctx_func1.uc_link = &uctx_main;
    makecontext(&uctx_func1, func1, 0);

    getcontext(&uctx_func2);
    uctx_func2.uc_stack.ss_sp = func2_stack;
    uctx_func2.uc_stack.ss_size = sizeof(func2_stack);
    uctx_func2.uc_link = &uctx_main;
    makecontext(&uctx_func2, func2, 0);

    swapcontext(&uctx_main, &uctx_func1);

    swapcontext(&uctx_main, &uctx_func2);

    swapcontext(&uctx_main, &uctx_func1);

    swapcontext(&uctx_main, &uctx_func2);

    printf("hello, main\n");

    return 0;
}
Henri Menke
  • 10,705
  • 1
  • 24
  • 42
kevin adam
  • 33
  • 4
  • it's asynchronous, using c coroutine, so it will not return to lua until rpc response arrives, will this cause something unexpected? – kevin adam Aug 02 '18 at 02:09
  • can you tell me why? from lua source code, i think it's ok to do something like this. test code is added. lua version is 5.3 – kevin adam Aug 02 '18 at 08:37
  • Just realized that your question is actually `Is my trick with Lua coroutines and safe?`. My previous comments were about another solution, not the one you are asking about. – Egor Skriptunoff Aug 02 '18 at 09:24
  • You are using C++ (hopefully C++11) so why don't you just use real threads and a lock guard for the Lua state? That is probably easier to implement than your manual context switches. – Henri Menke Aug 03 '18 at 06:25
  • it's just a sample code presenting what we are doing, optimization is not the primary issue here. – kevin adam Aug 06 '18 at 02:21

0 Answers0