目录
二、全局状态机 - 数据结构lua_State和global_State
一、从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 */
}