范文健康探索娱乐情感热点
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

skynet源码阅读系列01从main函数开始

  skynet 是C语言写的框架,我们采用学习过程中最基本的方式去阅读skynet,从C语言的main函数开始。
  首先我们找到框架的入口 main  函数,在 skynet/skynet-src/skynet_main.c 文件内。
  main函数的代码如下: int main(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 : https://github.com/cloudwu/skynet/wiki/Config "            "usage: skynet configfilename ");         return 1;     }      skynet_globalinit();     skynet_env_init();      sigign();      struct skynet_config config;  #ifdef LUA_CACHELIB     // init the lock of code cache     luaL_initcodecache(); #endif      struct lua_State *L = luaL_newstate();     luaL_openlibs(L);   // link lua lib      int 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 ",lua_tostring(L,-1));         lua_close(L);         return 1;     }     _init_env(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);      lua_close(L);      skynet_start(&config);     skynet_globalexit();      return 0; }
  我们一段一段查看 int main(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 : https://github.com/cloudwu/skynet/wiki/Config "             "usage: skynet configfilename ");         return 1;     }      //... }
  定义了一个指针, 指针指向常量,  const char* config_file  , config_file   赋值为启动时的第二个参数,也就是配置文件的路径。
  skynet_globalinit(); // skynet/skynet-src/skynet_server.c struct 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,可参考文章: https://www.jianshu.com/p/d78d93d46fc2
  skynet_initthread(THREAD_MAIN);   将当前线程状态由 THREAD_MAIN 切换为 THREAD_WORKER 状态并记录在handle_key。
  skynet_env_init(); // skynet/skynet-src/skynet_env.c struct skynet_env {     struct spinlock lock;     lua_State *L; };  static struct skynet_env *E = NULL;  void skynet_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   int 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.c static struct codecache CC; struct codecache {     struct spinlock lock;     lua_State *L; }; LUALIB_API void luaL_initcodecache(void) {     SPIN_INIT(&CC); } static const char * load_config = "     local result = {}      local function getenv(name) return assert(os.getenv(name), [[os.getenv() failed: ]] .. name) end      local sep = package.config:sub(1,1)      local current_path = [[.]]..sep      local function include(filename)          local last_path = current_path          local path, name = filename:match([[(.*]]..sep..[[)(.*)$]])          if path then              if path:sub(1,1) == sep then    -- root                  current_path = path              else                  current_path = current_path .. path              end          else              name = filename          end          local f = assert(io.open(current_path .. name))          local code = assert(f:read [[*a]])          code = string.gsub(code, [[%$([%w_%d]+)]], getenv)          f:close()          assert(load(code,[[@]]..filename,[[t]],result))()          current_path = last_path      end      setmetatable(result, { __index = { include = include } })      local config_name = ...      include(config_name)      setmetatable(result, nil)      return result  ";  struct lua_State *L = luaL_newstate(); luaL_openlibs(L);   // link lua lib  int 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 ",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 ");             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 ", key);                 exit(1);             }             skynet_setenv(key,value);         }         lua_pop(L,1);     }     lua_pop(L,1); }  // skynet/skynet-src/skynet_env.c void  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 int optint(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.c const 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 中定义的特殊的线程数据。

河南一家5口4人被杀,凶手是夫妻,妻子被判12年引发争议最近一段时间,媒体报道了河南一家五口一年前惨遭灭门的消息,其中一家五口,有四人被杀,而凶手竟然是另一个家庭的夫妻俩。看到这个消息,很多网友都感到非常震惊有什么深仇大恨,非要闹得如此60岁岳父灭了女婿一家三口,二审时死刑变死缓,啥仇这么大?今天我们要说的这个故事,发生在东三省的吉林一个60岁的老翁,竟然杀死了自己的女婿,以及女婿的父母,而女婿的父母也就是老翁的亲家,都是教师。而老翁的女婿只有33岁,正是人生的黄金年龄苏黎世联邦理工学院研究通过12个小型无线电磁传感器追踪人体姿态(映维网2021年10月12日)苏黎世联邦理工学院的先进交互技术实验室(AdvancedInteractiveTechnologiesAIT)专注于而研究机器学习计算机视觉和人机交比手机更靠谱的考生礼物?vivoTWS2成释放压力首选转瞬间已至年中六月,除了天气炎热外,这两天的高考氛围又为这炎炎夏日增添了一份热度。与很多家庭一样,我家里老妹也是今年的考生之一。回想起当年高考结束之后的我,仿佛心中还存有一丝惬意。武新制冷天然气管网压力能回收及冷能综合利用项目初步调试成功余压余冷等新常规能源的回收利用,是实现碳达峰碳中和的解决方案之一。2021年7月,顶着火热的夏日骄阳,冰山集团武新制冷设计并投资承建的武汉市三金潭调压站天然气管网压力能回收及冷能综音频剪辑无压力,分分钟教你搞定大家好,我是小编浩克,音频转换不会怎么办,相信很多小伙伴们都遇到过这种烦恼,迅捷音频转换器轻松好用,支持多种格式互换,还包括音频剪辑音频合并和音频提取功能分割方式多样功能丰富的软件大数据机构培训班学习效果好吗?学习之路是如此的漫长,有的人总想着还是要多掌握一门技能,大数据一词又是最近比较火热的词条之一,一部分人想着学也是学,不如学一学这大数据技术,那么问题又来了,当选择去大数据培训机构培大数据学习SparkRDD操作入门在Spark框架组件当中,核心部分不得不提到一个重要的概念,叫做RDD。而这个RDD,本身来说,也是Spark框架相比早期的HadoopMapReduce框架实现了性能提升的重要一猪队友促震荡利布局上周判断本周金融三兄弟将换岗式护盘,但证券却故意制造震荡,造成大盘摇摇欲坠之感,从而利于主力布局明春行情。上周说银行和证券是本周主角,但证券却成了猪样的队友,打击小散一致看多的心理大数据开发基础之SQL语句基本操作昨天我们把MySQL的基础知识大概说了一遍,所以接下来几篇文章我们都会细化的讲讲MySQL的一些内容,而今天就给大家带来大数据开发基础之SQL语句基本操作,在有了理论知识后也必须动大数据开发zookeeper命令操作本期又是大家最喜欢的命令合集,今天给大家带来的是大数据开发zookeeper命令操作。作为大数据开发学习的基础,最基本的可不能落下,下面就开始zookeeper的命令操作的学习吧!
一文读懂Python高阶函数高阶函数将函数作为参数传入,这样的函数称为高阶函数。函数式编程就是指这种高度抽象的编程范式。变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函排列五348期规律走势图记录12月28号开奖个人记录。。。。。晚报等等党完败!特斯拉3又涨价Switch塞尔达2即将推出嗨!尾巴们,晚上好,今天是12月31日晚报导读重磅新闻速看新品发布爆料先睹为快行业动态吐槽一起聊特斯拉上调Model3和ModelY售价搭载毫米波雷达!绿米发布人体存在传感器小米WiPhone充电头推荐,33w双插口。哇塞数码圈这一年2021年,本人新买了一个充电头。之前也推荐过,就是紫米的33w充电头。支持的充电电压电流之前我一直在用iPad附送的12w充电,用12w的充iPhone13,会感觉像雷军还在沉迷原神?又用原神测试新系统不服跑个原神今年3月29日,雷军在发布小米11Pro时,说出了一句业内名言不服跑个原神。确实,随着手机硬件性能的发展,纯粹的跑分用户已经有点看腻了。手机性能再好,都是为了体验服务的,一味堆硬件手机联名日本IP盘点高达EVA迪迦奥特曼龙珠你喜欢谁?realmeGT2系列手机定档明年1月4日发布,官方正式宣布高配版与日本知名IP龙珠联名,打造全球限量版手机。事实上,欧加系厂商非常喜欢与日本IP联名,目前至少有四大产品引发关注,苹果正式推出AirPodsPro虎年特别款,售价1999元IT之家1月1日消息,今日,苹果正式推出AirPodsPro虎年特别款,售价1999元。苹果表示,继牛年首次推出官方设计之后,继续为虎年打下独特印记,带来AirPodsPro充电盒学Python正则表达式,这一篇就够了正则表达式是一个特殊的字符序列,可以帮助您使用模式中保留的专门语法来匹配或查找其他字符串或字符串集。正则表达式在UNIX世界中被广泛使用。注很多开发人员觉得正则表达式比较难以理解,平原新城看顺义无人驾驶出租车来顺义了,快来免费体验吧顺义区融媒体中心消息白色红旗车,车顶上安装着摄像头和雷达,驾驶室里虽然坐着安全员,却不是驾驶员,车辆接到乘客后自动完成行驶躲避车辆靠边停车等动作近日,道路上时常能看到这样的车辆,自SQL审核SQLE1。2112。0来啦SQL审核工具SQLE1。2112。0于今天发布。一SQLE项目介绍爱可生开源社区的SQLE是一款面向数据库使用者和管理者,支持多场景审核,支持标准化上线流程,原生支持MySQL审腾讯员工坐标腾讯,组里俩应届生全部背星,真的难受坐标腾讯,组里俩应届生全部背星,真的难受有网友回复说,Offer给你很高,然后让你背星,少给的年终奖其实相当于抵扣了溢价的base有腾讯员工说,炫耀offer的时候可想到今天?有网