skynet源码浏览系列从main函数开始(自己收集的skynet教程)
首发

skynet源码浏览系列从main函数开始(自己收集的skynet教程)

优质
请用语音读文章

skynet 是C语言编辑 的框架。人类 选用 学习过程中最基本 的方法 去浏览 skynet。从C语言的main函数开始。

首先人类 找到 框架的入口main函数。在 skynet/skynet-src/skynet_main.c 文件内。

main函数的代码如下:

intmain(int argc, char *argv[]) { const char * config_file = NULL ; if (argc 1) { config_file = argv[1]; } else { fprintf(stderr, "Need a config file. Please read skynet wiki : ;}人类 一段一段查就这样看

intmain(int argc, char *argv[]) { const char * config_file = NULL ; if (argc 1) { config_file = argv[1]; } else { fprintf(stderr, "Need a config file. Please read skynet wiki : 赋值为启动时的第二个参数。也就是配置文件的路径。

skynet_globalinit();

// skynet/skynet-src/skynet_server.cstruct skynet_node { ATOM_INT total; int init; uint32_t monitor_exit; pthread_key_t handle_key; bool profile; // default is off};static struct skynet_node G_NODE;void skynet_globalinit(void) { ATOM_INIT(&G_NODE.total , 0); G_NODE.monitor_exit = 0; G_NODE.init = 1; if (pthread_key_create(&G_NODE.handle_key, NULL)) { fprintf(stderr, "pthread_key_create failed"); exit(1); } // skynet/skynet-src/skynet_imp.h /* #define THREAD_WORKER 0 #define THREAD_MAIN 1 #define THREAD_SOCKET 2 #define THREAD_TIMER 3 #define THREAD_MONITOR 4 */ skynet_initthread(THREAD_MAIN);}skynet_initthread(int m) { // skynet/skynet-src/atomic.h // #define ATOM_POINTER volatile uintptr_t uintptr_t v = (uint32_t)(-m); pthread_setspecific(G_NODE.handle_key, (void *)v);}初始化全局节点信息 。total 为0。monitor_exit 为0。init 1。

pthread_key_create(&G_NODE.handle_key, NULL) 创建了一个多线程私有资料 handle_key:

skynet_initthread(THREAD_MAIN); 将目前 线程情况 由 THREAD_MAIN 更换 为 THREAD_WORKER 情况 并记录在handle_key。

skynet_env_init();

// skynet/skynet-src/skynet_env.cstruct skynet_env { struct spinlock lock; lua_State *L;};static struct skynet_env *E = NULL;voidskynet_env_init() { E = skynet_malloc(sizeof(*E)); SPIN_INIT(E) E-L = luaL_newstate();}E 一个skynet_env结构体。结构体内包含一个 spinlock 自旋锁。一个lua虚拟机指针。

skynet_malloc 为结构体E分配内存。skynet_malloc内部暂时不细究。

SPIN_INIT(E)

通过查找代码得知, 这是在 skynet/skynet-src/spinlick.h 中定义的一个宏。#define SPIN_INIT(q) spinlock_init(&(q)-lock);对E中的lock 进行初始化。

E-L = luaL_newstate(); L绑定了一个lua虚拟机。

sigign();

#include signal.hint sigign() { struct sigaction sa; sa.sa_handler = SIG_IGN; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sigaction(SIGPIPE, &sa, 0); return 0;}main 函数同文件下的 sigign() 函数。

定义了一个 sigaction 结构体。将 sa_handler 设置为 SIG_IGN。表示要忽略信号的发生 的动作。

sigaction(SIGPIPE, &sa, 0); 将 SIGPIPE的行为代替 为 sa 结构体定义的形式。表示目前 进程忽略 SIGPIPE 信号。

这里简单记录了一下 sigaction 的资料。

01ext_sigaction

struct skynet_config config;

定义了结构体 config

struct skynet_config { int thread; int harbor; int profile; const char * daemon; const char * module_path; const char * bootstrap; const char * logger; const char * logservice;};luaL_initcodecache();

// skynet/skynet-src/skynet_main.c#ifdef LUA_CACHELIB luaL_initcodecache();#endif// skynet/3rd/lauxlib.cstatic struct codecache CC;struct codecache { struct spinlock lock; lua_State *L;};LUALIB_API voidluaL_initcodecache(void) { SPIN_INIT(&CC);}static const char * load_config = "\ local result = {}\n\ local function getenv(name) return assert(os.getenv(name), [[os.getenv() failed: ]] .. name) end\n\ local sep = package.config:sub(1,1)\n\ local current_path = [[.]]..sep\n\ local function include(filename)\n\ local last_path = current_path\n\ local path, name = filename:match([[(.*]]..sep..[[)(.*)$]])\n\ if path then\n\ if path:sub(1,1) == sep then — root\n\ current_path = path\n\ else\n\ current_path = current_path .. path\n\ end\n\ else\n\ name = filename\n\ end\n\ local f = assert(io.open(current_path .. name))\n\ local code = assert(f:read [[*a]])\n\ code = string.gsub(code, [[%$([%w_%d]+)]], getenv)\n\ f:close()\n\ assert(load(code,[[@]]..filename,[[t]],result))()\n\ current_path = last_path\n\ end\n\ setmetatable(result, { __index = { include = include } })\n\ local config_name = …\n\ include(config_name)\n\ setmetatable(result, nil)\n\ return result\n\&#34struct lua_State *L = luaL_newstate();luaL_openlibs(L); // link lua libint err = luaL_loadbufferx(L, load_config, strlen(load_config), "=[skynet config]", "t");assert(err == LUA_OK);lua_pushstring(L, config_file);err = lua_pcall(L, 1, 1, 0);if (err) { fprintf(stderr,"%s\n",lua_tostring(L,-1)); lua_close(L); return 1;}luaL_loadbufferx(L, load_config, strlen(load_config), "=[skynet config]", "t");

加载了一段lua代码到内存里。并压入lua栈内。

load_config 这段代码实现的功能: 将配置文件内的 $var 代替 成了环境变量的内容, 并返回了一个result表。

lua_pcall(L, 1, 1, 0);

执行压入的 load_config 代码块。第二个参数1 表示压入的栈的个数为1。lua_pushstring(L, config_file); 被压栈的配置文件名。 执行完函数之后。函数和参数全自动 出栈。此时 栈为空。 函数的返回值被压栈。此时 栈内只有一个表 result, result 内内含了 配置在 config_file 内的键值对。

_init_env(L);

static void_init_env(lua_State *L) { lua_pushnil(L); /* first key */ while (lua_next(L, -2) != 0) { int keyt = lua_type(L, -2); if (keyt != LUA_TSTRING) { fprintf(stderr, "Invalid config table\n"); exit(1); } const char * key = lua_tostring(L,-2); if (lua_type(L,-1) == LUA_TBOOLEAN) { int b = lua_toboolean(L,-1); skynet_setenv(key,b ? "true" : "false" ); } else { const char * value = lua_tostring(L,-1); if (value == NULL) { fprintf(stderr, "Invalid config table key = %s\n", key); exit(1); } skynet_setenv(key,value); } lua_pop(L,1); } lua_pop(L,1);}// skynet/skynet-src/skynet_env.cvoid skynet_setenv(const char *key, const char *value) { SPIN_LOCK(E) lua_State *L = E-L; lua_getglobal(L, key); assert(lua_isnil(L, -1)); lua_pop(L,1); lua_pushstring(L,value); lua_setglobal(L,key); SPIN_UNLOCK(E)}// 从堆栈上弹出一个值。并将其设为全局变量 name 的新值。void lua_setglobal (lua_State *L, const char *name);// 把全局变量 name 里的值压栈。返回该值的类别 。int lua_getglobal (lua_State *L, const char *name);将lua栈表内的键值对设置到 &E-L 的全局环境中。

config.thread = optint("thread",8);config.module_path = optstring("cpath","./cservice/?.so");config.harbor = optint("harbor", 1);config.bootstrap = optstring("bootstrap","snlua bootstrap");config.daemon = optstring("daemon", NULL);config.logger = optstring("logger", NULL);config.logservice = optstring("logservice", "logger");config.profile = optboolean("profile", 1);static intoptint(const char *key, int opt) { const char * str = skynet_getenv(key); if (str == NULL) { char tmp[20]; sprintf(tmp,"%d",opt); skynet_setenv(key, tmp); return opt; } return strtol(str, NULL, 10);}// skynet/skynet-src/skynet_env.cconst char * skynet_getenv(const char *key) { SPIN_LOCK(E) lua_State *L = E-L; lua_getglobal(L, key); const char * result = lua_tostring(L, -1); lua_pop(L, 1); SPIN_UNLOCK(E) return result;}optint, optstring, optboolean 从 &E-L 的全局环境中取得对应键的值。如果全局环境内未定义。则第二个参数 opt 设为 key的默认值。

lua_close(L);

关闭main函数内创建的 lua 虚拟机。

skynet_start(&config);

下一节的内容。

skynet_globalexit();

void skynet_globalexit(void) { pthread_key_delete(G_NODE.handle_key);}删除在 skynet_initthread 中定义的固定 的线程资料 。

以上就是由优质生活领域创作者 生活常识网 整理编辑的,如果觉得有帮助欢迎收藏转发~

分享到 :
相关推荐

什么牌子的硅胶奶瓶好(硅胶奶瓶好吗)

请用语音读文章奶瓶是每个妈妈在宝宝出生前都会准备的必备物品。也是入门的东西。他们[&...

适合暴雨天发的朋友圈说说(关于雨天的朋友圈文案)

请用语音读文章  1、尼玛下雨就下雨呗!银家的鞋排着队去游泳。  2、那些年错过[&...

2013年的歌曲有哪些歌(60年代的歌曲有哪些)

请用语音读文章2013年发行的金曲好歌有哪些。下面我给你推荐一下我认知里的十首歌曲[...

平安顺遂是什么意思(万事胜意是什么意思)

请用语音读文章平安顺随。喜乐无忧平安顺遂的出自曾国藩《求阙斋记》:曾氏严于[&hel...

发表评论

您的电子邮箱地址不会被公开。