Lua源码分析

您所在的位置:网站首页 lua语言工程师 Lua源码分析

Lua源码分析

2023-07-20 15:43| 来源: 网络整理| 查看: 265

目录

一、从main函数看整个状态机的初始化

二、全局状态机 - 数据结构lua_State和global_State

三、全局状态机 - 初始化lua_newstate

四、全局状态机 - 销毁lua_close

一、从main函数看整个状态机的初始化

Lua的main函数方法中,lua_State *L = luaL_newstate(); 主要用于创建全局状态机。

luaL_newstate主要用来为每一个LUA线程创建独立的函数栈和线程栈,以及线程执行过程中需要用到的内存管理、字符串管理、gc等信息。

全局状态机的初始化、销毁的实现,主要在lstate.c文件中。

int main (int argc, char **argv) { int status, result; /* 第一步:创建一个主线程栈数据结构 */ lua_State *L = luaL_newstate(); /* create state */ if (L == NULL) { l_message(argv[0], "cannot create state: not enough memory"); return EXIT_FAILURE; } lua_pushcfunction(L, &pmain); /* to call 'pmain' in protected mode */ lua_pushinteger(L, argc); /* 1st argument */ lua_pushlightuserdata(L, argv); /* 2nd argument */ status = lua_pcall(L, 2, 1, 0); /* do the call */ result = lua_toboolean(L, -1); /* get result */ report(L, status); lua_close(L); return (result && status == LUA_OK) ? EXIT_SUCCESS : EXIT_FAILURE; } 二、全局状态机 - 数据结构lua_State和global_State

Lua使用LG结构(lua_State *L)贯穿整个线程解析的生命周期的始终。

lua_newstate函数主要用于创建一个lua_State和global_State的数据结构。

lua_State:主线程栈结构global_State:全局状态机,维护全局字符串表、内存管理函数、gc等信息lua_State和global_State结构,通过LG的方式进行链接,将全局状态机global_State挂载到lua_State数据结构上global_State结构是完全感知不到的:我们无法用Lua公开的API获取到它的指针、句柄或引用lua_State和global_State之间通过 global_State *l_G 互相建立链接关系。

LUA语言没有实现独立的线程,但是实现了协程序,关于协程后续会单独开一章节讲解。

lua_State数据结构如下:

/* ** 'per thread' state ** Lua 主线程 栈 数据结构 ** 作用:管理整个栈和当前函数使用的栈的情况,最主要的功能就是函数调用以及和c的通信 */ struct lua_State { CommonHeader; lu_byte status; /* 解析容器的用于记录中间状态*/ /* 全局状态机 */ global_State *l_G; /* 调用栈:调用栈信息管理(CallInfo 为双向链表结构) */ unsigned short nci; /* number of items in 'ci' list - 存储一共多少个CallInfo */ CallInfo base_ci; /* CallInfo for first level (C calling Lua) - 调用栈的头部指针 */ CallInfo *ci; /* call info for current function - 当前运行函数信息 */ /* 数据栈:栈指针地址管理 StkId = TValue 的数组 */ StkId top; /* first free slot in the stack - 线程栈的栈顶指针 */ StkId stack_last; /* last free slot in the stack - 线程栈的最后一个位置 */ StkId stack; /* stack base - 栈的指针,当前执行的位置*/ const Instruction *oldpc; /* last pc traced 在当前thread 的解释执行指令的过程中,指向最后一次执行的指令的指针 */ UpVal *openupval; /* list of open upvalues in this stack */ GCObject *gclist; /* GC列表 */ struct lua_State *twups; /* list of threads with open upvalues */ struct lua_longjmp *errorJmp; /* current error recover point */ /* Hook 相关管理 - 服务于debug模块 */ volatile lua_Hook hook; ptrdiff_t errfunc; /* current error handling function (stack index) */ int stacksize; int basehookcount; int hookcount; l_signalT hookmask; lu_byte allowhook; /* 跟C语言通信 管理*/ unsigned short nCcalls; /* number of nested C calls */ unsigned short nny; /* number of non-yieldable calls in stack */ };

global_State数据结构如下:

/* ** 'global state', shared by all threads of this state ** lua 全局状态机 ** 作用:管理全局数据,全局字符串表、内存管理函数、 GC 把所有对象串联起来的信息、内存等 */ typedef struct global_State { /* 版本号 */ const lua_Number *version; /* pointer to version number */ /* 内存管理 */ lua_Alloc frealloc; /* Lua的全局内存分配器,用户可以替换成自己的 - function to reallocate memory */ void *ud; /* 分配器的userdata - auxiliary data to 'frealloc' */ /* 线程管理 */ struct lua_State *mainthread; /* 主线程 */ struct lua_State *twups; /* 闭包了当前线程变量的其他线程列表 - list of threads with open upvalues */ /* 字符串管理 */ stringtable strt; /* 字符串table Lua的字符串分短字符串和长字符串 - hash table for strings */ TString *strcache[STRCACHE_N][STRCACHE_M]; /* 字符串缓存 - cache for strings in API */ /* 虚函数表 */ TString *tmname[TM_N]; /* 预定义方法名字数组 - array with tag-method names */ struct Table *mt[LUA_NUMTAGS]; /* 每个基本类型一个metatable(整个Lua最重要的Hook机制) - metatables for basic types */ /* 错误处理 */ lua_CFunction panic; /* to be called in unprotected errors */ TString *memerrmsg; /* memory-error message */ /* GC管理 */ unsigned int gcfinnum; /* number of finalizers to call in each GC step */ int gcpause; /* size of pause between successive GCs */ int gcstepmul; /* GC 'granularity' */ l_mem totalbytes; /* number of bytes currently allocated - GCdebt */ l_mem GCdebt; /* bytes allocated not yet compensated by the collector */ lu_mem GCmemtrav; /* memory traversed by the GC */ lu_mem GCestimate; /* an estimate of the non-garbage memory in use */ TValue l_registry; unsigned int seed; /* randomized seed for hashes */ lu_byte currentwhite; lu_byte gcstate; /* state of garbage collector */ lu_byte gckind; /* kind of GC running */ lu_byte gcrunning; /* true if GC is running */ GCObject *allgc; /* list of all collectable objects */ GCObject **sweepgc; /* current position of sweep in list */ GCObject *finobj; /* list of collectable objects with finalizers */ GCObject *gray; /* list of gray objects */ GCObject *grayagain; /* list of objects to be traversed atomically */ GCObject *weak; /* list of tables with weak values */ GCObject *ephemeron; /* list of ephemeron tables (weak keys) */ GCObject *allweak; /* list of all-weak tables */ GCObject *tobefnz; /* list of userdata to be GC */ GCObject *fixedgc; /* list of objects not to be collected */ } global_State;

 

三、全局状态机 - 初始化lua_newstate

lua_newstate主要用于创建一个主线程栈结构。分配lua_State和global_State。

对外通过lua_State结构暴露给用户,而global_State挂载在lua_State结构上。

其中f_luaopen函数,非常重要,主要作用:初始化栈、初始化字符串结构、初始化原方法、初始化保留字实现、初始化注册表等。

lua_newstate主要做了3件事情:

新建一个global_state和一个lua_State初始化默认值,创建全局表等调用f_luaopen函数,初始化栈、字符串结构、元方法、保留字、注册表等重要部件 /** * 分配lua_State和global_State * 说明:global_State全局表会挂载在lua_State结构上,此方法分配的是主线程栈。如果实现协程,则通过lua_newthread分配新的lua_State栈 * 通过LG结构方式,每个线程会独立维护自己的线程栈和函数栈 * 对外通过lua_State结构暴露给用户,而global_State挂载在lua_State结构上 * 主要管理管理全局数据,全局字符串表、内存管理函数、 GC 把所有对象串联起来的信息、内存等 * global_State:全局状态机 * lua_State:主线程栈结构 */ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { int i; lua_State *L; global_State *g; /* 分配一块lua_State结构的内容块 */ LG *l = cast(LG *, (*f)(ud, NULL, LUA_TTHREAD, sizeof(LG))); if (l == NULL) return NULL; L = &l->l.l; g = &l->g; L->next = NULL; L->tt = LUA_TTHREAD; g->currentwhite = bitmask(WHITE0BIT); L->marked = luaC_white(g); /* 初始化一个线程的栈结构数据 */ preinit_thread(L, g); g->frealloc = f; g->ud = ud; g->mainthread = L; g->seed = makeseed(L); g->gcrunning = 0; /* no GC while building state */ g->GCestimate = 0; g->strt.size = g->strt.nuse = 0; g->strt.hash = NULL; setnilvalue(&g->l_registry); g->panic = NULL; g->version = NULL; g->gcstate = GCSpause; g->gckind = KGC_NORMAL; g->allgc = g->finobj = g->tobefnz = g->fixedgc = NULL; g->sweepgc = NULL; g->gray = g->grayagain = NULL; g->weak = g->ephemeron = g->allweak = NULL; g->twups = NULL; g->totalbytes = sizeof(LG); g->GCdebt = 0; g->gcfinnum = 0; g->gcpause = LUAI_GCPAUSE; g->gcstepmul = LUAI_GCMUL; for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL; if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) { //f_luaopen函数中调用了 stack_init 函数 /* memory allocation error: free partial state */ close_state(L); L = NULL; } return L; } /* ** open parts of the state that may cause memory-allocation errors. ** ('g->version' != NULL flags that the state was completely build) ** 启动Lua程序 ** 初始化栈、初始化字符串结构、初始化原方法、初始化保留字实现、初始化注册表 */ static void f_luaopen (lua_State *L, void *ud) { global_State *g = G(L); UNUSED(ud); stack_init(L, L); /* init stack */ init_registry(L, g); //初始化注册表 luaS_init(L); //字符串结构初始化 luaT_init(L); //元方法初始化 luaX_init(L); //保留字实现 g->gcrunning = 1; /* allow gc */ g->version = lua_version(NULL); luai_userstateopen(L); } 四、全局状态机 - 销毁lua_close

lua_close主要用于销毁主线程栈结构。

* * 关闭Lua栈 */ LUA_API void lua_close (lua_State *L) { L = G(L)->mainthread; /* only the main thread can be closed */ lua_lock(L); close_state(L); } /** * 释放Lua栈结构 */ static void close_state (lua_State *L) { global_State *g = G(L); luaF_close(L, L->stack); /* close all upvalues for this thread 释放Lua栈的upvalues */ luaC_freeallobjects(L); /* collect all objects 释放全部对象 */ if (g->version) /* closing a fully built state? */ luai_userstateclose(L); luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); freestack(L); lua_assert(gettotalbytes(g) == sizeof(LG)); (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */ }

 

 

 

 

 

 

 



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3