joe 发表于 2022-6-20 14:38:41

Lua源码分析 - 基础篇 - 全局状态机的实现(02)

目录

一、从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, "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语言没有实现独立的线程,但是实现了协程序,关于协程后续会单独开一章节讲解。
https://img-blog.csdnimg.cn/20200513173915148.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2luaXRwaHA=,size_16,color_FFFFFF,t_70


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;/* 字符串缓存 - cache for strings in API */

/* 虚函数表 */
TString *tmname;/* 预定义方法名字数组 -array with tag-method names */
struct Table *mt;/* 每个基本类型一个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 = 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 */
}







————————————————
版权声明:本文为CSDN博主「老码农zhuli」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/initphp/article/details/88393885

页: [1]
查看完整版本: Lua源码分析 - 基础篇 - 全局状态机的实现(02)