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阅读笔 ...
随机推荐
- sql server分配某个用户只对某一个数据库有权限 转载 http://blog.sina.com.cn/s/blog_13554ebc70102wi3h.html
sql server 2008新建用户只能访问指定数据库 新装的sql Server 2008,想让指定的用户可以访问sql Server客户端,sa的权限太大,所以最好禁用掉, 然后我们需要 ...
- Uri编码,包括javascript前端与C#服务器端
URI编码的方法汇总 javascript中的编码有三种方法:escape.encodeURI.encodeURIComponent C#中编码的主要方法:HttpUtility.UrlEncode. ...
- Decorator - 装饰模式
1. 概述 若你从事过面向对象开发,实现给一个类或对象增加行为,使用继承机制,这是所有面向对象语言的一个基本特性.如果已经存在的一个类缺少某些方法,或者须要给方法添加更多的功能(魅力),你也许会仅仅继 ...
- struts2.xml中所有constant详解--大全
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-/ ...
- 零基础学python》(第二版)
---恢复内容开始--- 零基础学python>(第二版) python学习手册 可以离线下载, .chn格式, 插入小幽默笑话,在学习累的时候看看笑话 放松一下 欢迎下载转载,请注明出处,谢 ...
- 利用ichart绘制网页图表
首先,最好的教程在这里:ichartjs 有了这个网站,要绘制网页图表简直方便愉快! 接下来说一下使用方法~~~ 进入网站,点击在线设计器 在线设计器的使用方法就不说了,摸索一下就会了!关键在于两个地 ...
- sliverlight资源文件的URI调用
这里主要介绍三种方式:1.将文件编译进dll:2.打包在XAP中:3.放在XAP包外,其所在目录下. 这里就将三张图片以不同的方式调用来作为例子: 一.编译进DLL 默认情况下,复制到项目中的资源都是 ...
- perl的内置函数scalar
scalar可以求数组的长度,但是,在scalar的说明里面并没有这一项. Forces EXPR to be interpreted in scalar context and returns th ...
- JS格式化数字保留两位小数点示例代码
格式化数字保留两位小数点实现的方法有很多,在接下来的文章中将为大家详细介绍下如何使用js来实现 a = a.toFixed(2);//保留2位但结果为一个String类型 a = parseFloat ...
- 五个你必须知道的javascript和web debug技术
转:http://js8.in/2013/11/20/%E4%BA%94%E4%B8%AA%E4%BD%A0%E5%BF%85%E9%A1%BB%E7%9F%A5%E9%81%93%E7%9A%84j ...