skynet1.0阅读笔记_skynet的启动
首先看skynet的启动,函数入口在 skynet_main.c 的main(),其中最重要的是:
skynet_start(&config);
在skynet_start中做了两个启动:
//启动了snlau服务,然后加载launch服务
bootstrap(ctx, config->bootstrap);
//创建monitor,timer,socket,worker线程等
start(config->thread);
下面我们逐步跟进函数
static void
bootstrap(struct skynet_context * logger, const char * cmdline) {
...
sscanf(cmdline, "%s %s", name, args);
struct skynet_context *ctx = skynet_context_new(name, args);
...
}
这里的cmdline就是 config配置里面的bootstrap那行,默认是为 "snlua bootstrap"
所以实际执行的是 skynet_context_new("snlua","bootstrap")
这里的skynet_context_new是很重要的一个函数,skynet每个lua服务创建,都是使用它来执行的。
skynet_context_new(const char * name="snlua", const char *param="bootstrap") {
//查询mod对象是否已存在,不存在就根据name查找文件加载创建
struct skynet_module * mod = skynet_module_query(name="snlua");
...
//调用mod的create()方法,这里调用了 snlua_create
void *inst = skynet_module_instance_create(mod);
//为lua服务new一个skynet_context的c对象
struct skynet_context * ctx = skynet_malloc(sizeof(*ctx));
...
//为服务的ctx创建一个message_queue
struct message_queue * queue = ctx->queue = skynet_mq_create(ctx->handle);
//调用对象的init方法,这里是 snlua_init(snlua_create(),ctx,"bootstrap")
int r = skynet_module_instance_init(mod, inst, ctx, param);
if(r==){ //0表示成功
//成功以后,把服务的message_queue放入global_queue全局队列中
skynet_globalmq_push(queue);
}
}
就是说,bootstrap的启动请求 现在交到service_snlua.c的snlua_init里面了,所以接着我们来看snlua_init的实现
snlua_init(struct snlua *l,struct skynet_context *ctx,args="bootstrap"){
...
//把ctx->cb=_launch, ctx->cb是worker线程取出skynet_message时的处理函数
skynet_callback(ctx, l , _launch);
//查询自己的handle id
const char * self = skynet_command(ctx, "REG", NULL);
uint32_t handle_id = strtoul(self+, NULL, );
...
memcpy(tmp, args, sz);
// it must be first message ,然后在这里立即投递第一个请求
skynet_send(ctx, ... , tmp="bootstrap", sz);
...
}
这里需要注意的是,skynet_command这里,实际上通过遍历查找,最终调用了cmd_reg,由于传入的param是NULL,实际是
skynet_command(ctx, "REG", NULL){
sprintf(context->result, ":%x", context->handle);
return context->result;
}
//返回的是自己的ctx的handle id.
也就是下面的skynet_send:
skynet_send(ctx, ... , tmp="bootstrap", sz);
是往自己的队列中投递了一个消息,worker线程拿到这个消息后,根据ctx->cb,调用callback函数: _launch
跟进 _launch:
_launch(..., const void* msg="bootstrap"){
//把context->cb设为NULL了
skynet_callback(context, NULL, NULL);
//_init这里面实际上就是找到要加载的lua文件,然后加载到lua虚拟机中
//在这里就是把 bootstrap.lua文件加在进来
_init(l, context, msg, sz);
...
}
那我们来看看 bootstrap.lua 这个文件
local skynet = require "skynet"
local harbor = require "skynet.harbor"
require "skynet.manager" -- import skynet.launch, ...
local memory = require "memory" skynet.start(function()
...
-- 这里面,使用skynet.newservice 启动了很多个服务 local launcher = assert(skynet.launch("snlua","launcher"))
skynet.name(".launcher", launcher) ... if harbor_id == then
local ok, slave = pcall(skynet.newservice, "cdummy")
skynet.name(".cslave", slave)
else
local ok, slave = pcall(skynet.newservice, "cslave")
skynet.name(".cslave", slave)
end
... if standalone then
local datacenter = skynet.newservice "datacenterd"
skynet.name("DATACENTER", datacenter)
end
...
end)
这里有两点要注意:
1. skynet.start 的function里面,用snlua启动了launcher服务,并用skynet.name把自己注册名字为".launcher"的服务
".launcher" 的调用 skynet.call(".launcher",...)
在后面将经常看到。".launcher"服务就是在这里注册的。
以.开头的名字,是表示这个服务只在当前skynet节点下有效,如果不带点,需要支持跨节点的额外开销,没必要都会带上它。
2.skynet.start 函数
function skynet.start(start_func)
//把回调函数注册为 skynet.dispatch_message
c.callback(skynet.dispatch_message)
//调用 skynet.init_service 调用了外面定义的 function 进行启动
skynet.timeout(, function()
skynet.init_service(start_func)
end)
end
到这里,就能明白,通过skynet_context_new 中的 snlua_init 和
_launch,skynet把请求的处理权从 c交到了 lua手上。
skynet1.0阅读笔记_skynet的启动的更多相关文章
- skynet1.0阅读笔记2_skynet的消息投递skynet.call
为了了解 skynet.call 的调用过程,需要先看看 skynet的队列是如何把包分到不同工作线程的.看下图 查看 global_queue 的skynet_globalmq_push和skyne ...
- The Implementation of Lua 5.0 阅读笔记(一)
没想到Lua的作者理论水平这么高,这篇文章读的我顿生高屋建瓴之感.云风分享了一篇中译:http://www.codingnow.com/2000/download/The%20Implementati ...
- Effective objective-c 2.0阅读笔记
这本书非常的好,看完后,感触挺深,总结纪录一下,针对ios开发的备忘: 注:分类和原著有些不同,自己总结学习用的,仅供参考. 系统篇: 了解oc起源:继承c,由Smalltalk演化而来.动态语言 ...
- The implementation of Lua 5.0 阅读笔记(二)
6 线程和协程 读完这篇文章我才意识到python的协程到底缺了什么,这个就是coroutine和semi-coroutine的区别了.区别就是,semi-coroutine只能返回(yield)到调 ...
- 《C# 6.0 本质论》 阅读笔记
<C# 6.0 本质论> 阅读笔记 阅读笔记不是讲述这本书的内容,只是提取了其中一部分我认为比较重要或者还没有掌握的知识,所以如果有错误或者模糊之处,请指正,谢谢! 对于C# 6.0才 ...
- Linux 0.11源码阅读笔记-文件管理
Linux 0.11源码阅读笔记-文件管理 文件系统 生磁盘 未安装文件系统的磁盘称之为生磁盘,生磁盘也可以作为文件读写,linux中一切皆文件. 磁盘分区 生磁盘可以被分区,分区中可以安装文件系统, ...
- Linux 0.11源码阅读笔记-中断过程
Linux 0.11源码阅读笔记-中断过程 是什么中断 中断发生时,计算机会停止当前运行的程序,转而执行中断处理程序,然后再返回原被中断的程序继续运行.中断包括硬件中断和软件中断,硬中断是由外设自动产 ...
- Linux 0.11源码阅读笔记-总览
Linux 0.11源码阅读笔记-总览 阅读源码的目的 加深对Linux操作系统的了解,了解Linux操作系统基本架构,熟悉进程管理.内存管理等主要模块知识. 通过阅读教复杂的代码,锻炼自己复杂项目代 ...
- Mongodb Manual阅读笔记:CH8 复制集
8 复制 Mongodb Manual阅读笔记:CH2 Mongodb CRUD 操作Mongodb Manual阅读笔记:CH3 数据模型(Data Models)Mongodb Manual阅读笔 ...
随机推荐
- 办公技巧:局域网内设置固定ip
第一步:查看自己现在的网络配置 打开命令行,输入:ipconfig /all 第二步:打开控制面板 - 网络配置 根据CMD命令的ipconfig信息对号入座填入即可. 然后,重启一下WIFI即可. ...
- Maker's Schedule, Manager's Schedule
http://www.paulgraham.com/makersschedule.html manager's schedule 随意性强,指随时安排会面,开会等活动的 schedule; maker ...
- PHP二维数组如何根据某个字段排序
分享下PHP二维数组如何根据某个字段排序的方法. 从两个不同的表中获取各自的4条数据,然后整合(array_merge)成一个数组,再根据数据的创建时间降序排序取前4条. 本文记录的要实现的功能类似于 ...
- C#使用CodeDom动态加载cs文件
public static object Create(string path) { var provOptions = new Dictionary<string, string>(); ...
- onethink迁移
修改applicattion下面的Common跟User里面的config.php文件两个
- express设置模板引擎
app.set('views', path.join(__dirname,'views')); app.set('view engine', 'ejs');
- maven(6)------maven坐标分析
在不使用maven管理项目,直接使用IDE开发项目时,一个web项目中会涉及到很多技术, 比如struts2,hibernate,spring,mybatis等等,这个时候,我们就需要去各大官网下载不 ...
- python(31) enumerate 的用法
例子一: b = "abcd" kv_dict = {} pre = 1234 for i, v in enumerate(b): kv_dict['%s-%d.jpg' %(pr ...
- java.lang.NoClassDefFoundError: Ljavax/enterprise/inject/spi/BeanManager;
java.lang.NoClassDefFoundError: Ljavax/enterprise/inject/spi/BeanManager; 删除Struts2-cdi-plug 的插件的jar ...
- 【转】批量删除redis中的key
1. DEL 直接加键名称 DEL key1 key2 key3 127.0.0.1:6379> DEL site_msg_99973 false site_msg_99974 fals ...