risc-v中文社区

 找回密码
 立即注册
查看: 811|回复: 0

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

[复制链接]

347

主题

564

帖子

2237

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2237
发表于 2022-6-20 14:38:41 | 显示全部楼层 |阅读模式
目录

一、从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 = 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

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



Archiver|手机版|小黑屋|risc-v中文社区

GMT+8, 2024-5-6 05:13 , Processed in 0.023105 second(s), 17 queries .

risc-v中文社区论坛 官方网站

Copyright © 2018-2021, risc-v open source

快速回复 返回顶部 返回列表