首先看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的启动的更多相关文章

  1. skynet1.0阅读笔记2_skynet的消息投递skynet.call

    为了了解 skynet.call 的调用过程,需要先看看 skynet的队列是如何把包分到不同工作线程的.看下图 查看 global_queue 的skynet_globalmq_push和skyne ...

  2. The Implementation of Lua 5.0 阅读笔记(一)

    没想到Lua的作者理论水平这么高,这篇文章读的我顿生高屋建瓴之感.云风分享了一篇中译:http://www.codingnow.com/2000/download/The%20Implementati ...

  3. Effective objective-c 2.0阅读笔记

    这本书非常的好,看完后,感触挺深,总结纪录一下,针对ios开发的备忘: 注:分类和原著有些不同,自己总结学习用的,仅供参考.   系统篇: 了解oc起源:继承c,由Smalltalk演化而来.动态语言 ...

  4. The implementation of Lua 5.0 阅读笔记(二)

    6 线程和协程 读完这篇文章我才意识到python的协程到底缺了什么,这个就是coroutine和semi-coroutine的区别了.区别就是,semi-coroutine只能返回(yield)到调 ...

  5. 《C# 6.0 本质论》 阅读笔记

    <C# 6.0 本质论> 阅读笔记   阅读笔记不是讲述这本书的内容,只是提取了其中一部分我认为比较重要或者还没有掌握的知识,所以如果有错误或者模糊之处,请指正,谢谢! 对于C# 6.0才 ...

  6. Linux 0.11源码阅读笔记-文件管理

    Linux 0.11源码阅读笔记-文件管理 文件系统 生磁盘 未安装文件系统的磁盘称之为生磁盘,生磁盘也可以作为文件读写,linux中一切皆文件. 磁盘分区 生磁盘可以被分区,分区中可以安装文件系统, ...

  7. Linux 0.11源码阅读笔记-中断过程

    Linux 0.11源码阅读笔记-中断过程 是什么中断 中断发生时,计算机会停止当前运行的程序,转而执行中断处理程序,然后再返回原被中断的程序继续运行.中断包括硬件中断和软件中断,硬中断是由外设自动产 ...

  8. Linux 0.11源码阅读笔记-总览

    Linux 0.11源码阅读笔记-总览 阅读源码的目的 加深对Linux操作系统的了解,了解Linux操作系统基本架构,熟悉进程管理.内存管理等主要模块知识. 通过阅读教复杂的代码,锻炼自己复杂项目代 ...

  9. Mongodb Manual阅读笔记:CH8 复制集

    8 复制 Mongodb Manual阅读笔记:CH2 Mongodb CRUD 操作Mongodb Manual阅读笔记:CH3 数据模型(Data Models)Mongodb Manual阅读笔 ...

随机推荐

  1. C# 默认参数/可选参数需要注意

    在使用C#的默认参数/可选参数的时候,需要注意,参数的默认值是在编译的时候,自动加入调用方的. 如我有这样一个方法: public class Name { public void Test(Bool ...

  2. pythonl练习笔记——threading线程中的事件Event

    1 事件Event 使用方法:e = threading.Event() Event对象主要用于线程间通信,确切地说是用于主线程控制其他线程的执行. Event事件提供了三个方法:wait等待.cle ...

  3. 转 HTTP协议 (四) 缓存

    转自:http://www.cnblogs.com/TankXiao/archive/2012/11/28/2793365.html 缓存的概念 缓存这个东西真的是无处不在, 有浏览器端的缓存, 有服 ...

  4. Android vcard使用示例,生成vcf文件

     Android vcard使用示例,生成vcf文件 我们备份手机联系人时,导出到SD卡时,会在SD卡中生成一个vcf文件,用于保存联系人姓名,手机号码. vCard 规范容许公开交换个人数据交换 ( ...

  5. JAVA多线程和并发基础面试问答【转】

    JAVA多线程和并发基础面试问答 多线程和并发问题是Java技术面试中面试官比较喜欢问的问题之一.在这里,从面试的角度列出了大部分重要的问题,但是你仍然应该牢固的掌握Java多线程基础知识来对应日后碰 ...

  6. 关于HTTP协议(未完)

    转 : https://www.cnblogs.com/ranyonsue/p/5984001.html

  7. laravel5的Bcrypt加密方式对系统保存密码

    laravel5文档介绍 //对 A 密码使用Bcrypt 加密 $password = Hash::make('mima'); //你也可直接使用 bcrypt 的 function $passwo ...

  8. Spring Boot(一):初步认识

    简介 Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置 ...

  9. java Webservice(一)HttpClient远程调用

    我们将Web Service发布在Tomcat或者其他应用服务器上后,有很多方法可以调用该Web Service,常用的有两种: 1.通过浏览器HTTP调用,返回规范的XML文件内容      2.通 ...

  10. SQL 从查询结果里查询

    有orders表: 我想要从从表中查出每天电动车和手机各自的销售总额.这个需求还是蛮简单的,仅仅须要依据createtime和product group by即可了.以下是我写的SQL语句: SELE ...