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){        //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+1, NULL, 16);
        ...
        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 == 0 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(0, function()
            skynet.init_service(start_func)
        end)
    end

到这里,就能明白,通过skynet_context_new 中的 snlua_init 和
_launch,skynet把请求的处理权从 c交到了 lua手上。

时间: 2024-12-17 22:38:30

skynet1.0阅读笔记_skynet的启动的相关文章

Effective objective-c 2.0阅读笔记

这本书非常的好,看完后,感触挺深,总结纪录一下,针对ios开发的备忘: 注:分类和原著有些不同,自己总结学习用的,仅供参考. 系统篇: 了解oc起源:继承c,由Smalltalk演化而来.动态语言,运行期决.需要熟悉c语言. 6.  理解变量属性 a.原子性 b.读写 c.内存管理语义 d.方法名 .尽量少用atomic .注意使用copy属性避免数据安全问题. 还有oc动态语言特性,硬编码问题.类内部不要直接访问变量. 7.  还是重复了上一篇:在对象内部尽量直接访问实例变量.a.快,没有派发

刚刚汉化了一个app——NoteBox V1.0汉化版---随机阅读笔记的app

NoteBox V1.0汉化版---随机阅读笔记的app大小:950KB软件性质:免费无广告 软件简介:NoteBox 可以创建和编辑笔记.NoteBox 可以随机的展示你的笔记给你阅读.NoteBox 功能作用:-保存心里鸡汤给自己加油打气-保存笔记随机阅读,提高你的记忆力-当你犯选择困难症的时候可以把你需要选择的东西记录下来,随机选择-选择你将要吃什么饭喝什么饮料啦-决定应该看什么电影听什么歌曲啦...和其他任何你所想到的事情都可以随机!如果在使用中遇到错误.有建议.或其他任何东西想法随时与

蓝牙4.0核心文档阅读笔记

一.蓝牙技术介绍 蓝牙无线通讯包括两种模式:基础模式(BR, Basic Rate)和低功耗模式(LE, Low Energy). 蓝牙系统包括一个Host和多个Controllers,Host包括在HCI(Host Controller Interface)与应用程序之间,Controller指HCI以下的层.典型的BLE(Bluetooth Low Energy)协议栈结构如下图所示. 二.低功耗蓝牙4.0(BLE)概述 BLE具有两种多路通信方式:频分多址(FDMA,Frequency d

Hadoop 2.2.0 Job源代码阅读笔记

本文所有涉及的内容均为2.2.0版本中呈现. 概述: Job在创建Job并且提交的人的眼中,可以在创建的时候通过配置Job的内容,控制Job的执行,以及查询Job的运行状态.一旦Job提交以后,将不能对其进行配置,否则将会出现IllegalStateException异常. 正常情况下用户通过Job类来创建.描述.提交Job,以及监控Job的处理过程.下面是一个简单的例子: // Create a new Job Job job = new Job(new Configuration()); j

socketserver.py代码阅读笔记

socketserver.py源码阅读笔记 前言 一直想弄清楚一个http server和Web框架的工作原理.但以我目前的实力,阅读一个http server或web框架代码还是太难了.后来又对异步IO.并发产生的兴趣.前几天做一个大作业需要写几个各种不同并发模型的TCP Server,写完才想起Python有现成的socketsever模块可以用,完全不需要自己写.于是对比了一下我写的代码和socketsever.py,发现我写的真没socketsever写的好.我的代码经验还是太少了.于是

《STL源码剖析》---stl_alloc.h阅读笔记

这一节是讲空间的配置与释放,但不涉及对象的构造和析构,只是讲解对象构造前空前的申请以及对象析构后空间怎么释放. SGI版本的STL对空间的的申请和释放做了如下考虑: 1.向堆申请空间 2.考虑了多线程.但是这节目的只是讲解空间配置与释放,因此忽略了多线程,集中学习空间的申请和释放. 3.内存不足时的应变措施 4.考虑到了内存碎片的问题.多次申请释放小块内存可能会造成内存碎片. 在C++中,内存的申请和释放是通过operator new函数和operator delete函数,这两个函数相当于C语

《第一行代码》书籍阅读笔记

注:书籍阅读笔记,方便查看第1章 开始启程,你的第一行Android代码 第2章 先从看得到的入手,探究活动 1.隐藏标题栏 在onCreate()方法中添加: requestWindowFeature(Window.FEATURE_NO_TITLE);//不在活动中显示标题栏. 需要在setContentView()之前执行. 2.Intent是Android程序中各组件之间进行交互的一种重要方式,它不仅可以指明当前组件想要执行的动作,还可以在不同组件之间传递数据.Intent一般可被用于启动

IOS测试框架之:athrun的InstrumentDriver源码阅读笔记

athrun的InstrumentDriver源码阅读笔记 作者:唯一 athrun是淘宝的开源测试项目,InstrumentDriver是ios端的实现,之前在公司项目中用过这个框架,没有深入了解,现在回来记录下. 官方介绍:http://code.taobao.org/p/athrun/wiki/instrumentDriver/ 优点:这个框架是对UIAutomation的java实现,在代码提示.用例维护方面比UIAutomation强多了,借junit4的光,我们可以通过junit4的

面对软件错误构建可靠的分布式系统(阅读笔记)

阅读笔记 joe Armstrong 段先德 译 核心问题:如何在存在软件错误的情况下编写具有合理行为的软件 ,如何避免像死锁.死循环等问题 ERLANG的世界观,一切皆进程.将任务分离成层次化的一系列任务,强隔离的进程负责来执行每个具体化的任务,进程之间不共享状态(实际上ETS跨越了这个准则). 只能通过消息传递来通信,必须注意进程消息的堵塞问题 工作者和监督者构成一个完整的系统,监督者的作用就是监控整个系统的运行状况.并对突发情况进行可靠的处理. behaviour库的设计思想就是将程序的并